@ims-view/server 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -1
- package/lib/excel/excel-parse.worker.cjs +279 -0
- package/lib/server/src/app.module.js.map +1 -0
- package/lib/server/src/config/env.d.ts +40 -0
- package/lib/server/src/config/env.js +35 -0
- package/lib/server/src/config/env.js.map +1 -0
- package/lib/server/src/excel/dto/excel-task-id.dto.d.ts +19 -0
- package/lib/server/src/excel/dto/excel-task-id.dto.js +17 -0
- package/lib/server/src/excel/dto/excel-task-id.dto.js.map +1 -0
- package/lib/server/src/excel/dto/export-excel.dto.d.ts +67 -0
- package/lib/server/src/excel/dto/export-excel.dto.js +48 -0
- package/lib/server/src/excel/dto/export-excel.dto.js.map +1 -0
- package/lib/server/src/excel/excel-storage.service.d.ts +54 -0
- package/lib/server/src/excel/excel-storage.service.js +258 -0
- package/lib/server/src/excel/excel-storage.service.js.map +1 -0
- package/lib/server/src/excel/excel.controller.d.ts +17 -0
- package/lib/{excel → server/src/excel}/excel.controller.js +40 -11
- package/lib/server/src/excel/excel.controller.js.map +1 -0
- package/lib/server/src/excel/excel.converter.d.ts +15 -0
- package/lib/server/src/excel/excel.converter.js +53 -0
- package/lib/server/src/excel/excel.converter.js.map +1 -0
- package/lib/{excel → server/src/excel}/excel.module.js +3 -2
- package/lib/server/src/excel/excel.module.js.map +1 -0
- package/lib/server/src/excel/excel.service.d.ts +33 -0
- package/lib/server/src/excel/excel.service.js +244 -0
- package/lib/server/src/excel/excel.service.js.map +1 -0
- package/lib/server/src/excel/types.d.ts +6 -0
- package/lib/server/src/excel/types.js +44 -0
- package/lib/server/src/excel/types.js.map +1 -0
- package/lib/server/src/index.d.ts +12 -0
- package/lib/server/src/index.js +32 -0
- package/lib/server/src/index.js.map +1 -0
- package/lib/server/src/main.d.ts +1 -0
- package/lib/{main.js → server/src/main.js} +55 -2
- package/lib/server/src/main.js.map +1 -0
- package/lib/server/src/shared/create-zod-base-model.d.ts +29 -0
- package/lib/server/src/shared/create-zod-base-model.js +55 -0
- package/lib/server/src/shared/create-zod-base-model.js.map +1 -0
- package/lib/server/src/shared/index.d.ts +5 -0
- package/lib/server/src/shared/index.js +16 -0
- package/lib/server/src/shared/index.js.map +1 -0
- package/lib/server/src/shared/response-entity.d.ts +32 -0
- package/lib/server/src/shared/response-entity.js +74 -0
- package/lib/server/src/shared/response-entity.js.map +1 -0
- package/lib/server/src/shared/zod-exception.filter.d.ts +5 -0
- package/lib/server/src/shared/zod-exception.filter.js +25 -0
- package/lib/server/src/shared/zod-exception.filter.js.map +1 -0
- package/lib/server/src/shared/zod-validation.pipe.d.ts +4 -0
- package/lib/server/src/shared/zod-validation.pipe.js +25 -0
- package/lib/server/src/shared/zod-validation.pipe.js.map +1 -0
- package/lib/utils/src/excel/converter.d.ts +8 -0
- package/lib/utils/src/excel/converter.js +144 -0
- package/lib/utils/src/excel/converter.js.map +1 -0
- package/lib/utils/src/excel/exceljsChunked.d.ts +75 -0
- package/lib/utils/src/excel/exceljsChunked.js +338 -0
- package/lib/utils/src/excel/exceljsChunked.js.map +1 -0
- package/lib/utils/src/excel/index.d.ts +9 -0
- package/lib/utils/src/excel/index.js +39 -0
- package/lib/utils/src/excel/index.js.map +1 -0
- package/lib/utils/src/excel/luckyexcel.d.ts +9 -0
- package/lib/utils/src/excel/luckyexcel.js +137 -0
- package/lib/utils/src/excel/luckyexcel.js.map +1 -0
- package/lib/utils/src/excel/sheetjsConverter.d.ts +6 -0
- package/lib/utils/src/excel/sheetjsConverter.js +224 -0
- package/lib/utils/src/excel/sheetjsConverter.js.map +1 -0
- package/lib/utils/src/excel/types.d.ts +88 -0
- package/lib/utils/src/excel/types.js +11 -0
- package/lib/utils/src/excel/types.js.map +1 -0
- package/lib/utils/src/excel/workbookChunked.d.ts +13 -0
- package/lib/utils/src/excel/workbookChunked.js +152 -0
- package/lib/utils/src/excel/workbookChunked.js.map +1 -0
- package/package.json +10 -5
- package/lib/app.module.js.map +0 -1
- package/lib/excel/excel.controller.d.ts +0 -13
- package/lib/excel/excel.controller.js.map +0 -1
- package/lib/excel/excel.converter.d.ts +0 -2
- package/lib/excel/excel.converter.js +0 -11
- package/lib/excel/excel.converter.js.map +0 -1
- package/lib/excel/excel.module.js.map +0 -1
- package/lib/excel/excel.service.d.ts +0 -9
- package/lib/excel/excel.service.js +0 -33
- package/lib/excel/excel.service.js.map +0 -1
- package/lib/excel/types.d.ts +0 -6
- package/lib/excel/types.js +0 -6
- package/lib/excel/types.js.map +0 -1
- package/lib/index.d.ts +0 -7
- package/lib/index.js +0 -14
- package/lib/index.js.map +0 -1
- package/lib/main.d.ts +0 -1
- package/lib/main.js.map +0 -1
- /package/lib/{app.module.d.ts → server/src/app.module.d.ts} +0 -0
- /package/lib/{app.module.js → server/src/app.module.js} +0 -0
- /package/lib/{excel → server/src/excel}/excel.module.d.ts +0 -0
package/README.md
CHANGED
|
@@ -33,12 +33,16 @@ npx ims-view-server
|
|
|
33
33
|
IMS_SERVER_PORT=3010 npx ims-view-server
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
仓库内开发(默认热重载,改 `packages/server/src` / `packages/utils/src/excel` 会自动重启):
|
|
37
37
|
|
|
38
38
|
```shell
|
|
39
39
|
IMS_SERVER_PORT=3010 pnpm start:server
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
不需要热重载时:`pnpm --dir packages/server start:once`
|
|
43
|
+
|
|
44
|
+
请求体校验使用 Zod(`createZodBaseModel` + `ZodValidationPipe`),JSON 接口统一 `ResponseEntity`:`{ code, data, msg }`(`code === 0` 成功)。`POST /excel/export` 仍直接返回 xlsx 二进制。
|
|
45
|
+
|
|
42
46
|
## 嵌入 Nest 应用
|
|
43
47
|
|
|
44
48
|
```ts
|
|
@@ -57,9 +61,22 @@ export class AppModule {}
|
|
|
57
61
|
| ---- | ---- | ---- |
|
|
58
62
|
| `IMS_SERVER_PORT` | 服务端口(优先) | `3010` |
|
|
59
63
|
| `PORT` | 兼容通用端口变量 | - |
|
|
64
|
+
| `IMS_SERVER_BODY_LIMIT` | JSON body 体积上限 | `50mb` |
|
|
65
|
+
| `IMS_SERVER_GZIP_THRESHOLD` | 响应 gzip 压缩阈值(字节) | `1024` |
|
|
66
|
+
| `IMS_EXCEL_UPLOAD_DIR` | 上传文件目录 | `os.tmpdir()/ims-excel-uploads` |
|
|
67
|
+
| `IMS_EXCEL_UPLOAD_TTL_MS` | 上传文件保留时长 | `3600000`(1h) |
|
|
68
|
+
| `IMS_EXCEL_UPLOAD_CLEANUP_MS` | 定时清理间隔 | `600000`(10min) |
|
|
69
|
+
| `IMS_EXCEL_CHUNK_BYTES` | 超过该体积走分块挂载(LuckyExcel 解析后切块) | `2097152`(2MB) |
|
|
70
|
+
| `IMS_EXCEL_BLOCK_ROWS` | 渐进挂载每块行数(不是总行上限) | `5000` |
|
|
71
|
+
| `IMS_EXCEL_MAX_ROWS` | 大文件导入行上限(`0`=不截断) | `150000` |
|
|
72
|
+
| `IMS_EXCEL_PARSE_TIMEOUT_MS` | 单次解析超时 | `600000`(10min) |
|
|
60
73
|
|
|
61
74
|
前端对接:`IMS_EXCHANGE_ENDPOINT=http://localhost:3010`
|
|
62
75
|
|
|
76
|
+
## 导入策略
|
|
77
|
+
|
|
78
|
+
- **小文件**:LuckyExcel → `{id}.snapshot.json`,前端一次 `createWorkbook`
|
|
79
|
+
- **大文件(默认 >2MB)**:同一套 **LuckyExcel** 解析 → `{id}.meta.json` + blocks,前端骨架(含 styles/resources)+ 分批 `setValues`
|
|
63
80
|
## API
|
|
64
81
|
|
|
65
82
|
见文档站:
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker 入口(纯 CJS):ExcelJS 分块写盘,不依赖 tsx。
|
|
3
|
+
* 由 excel.service 用 worker_threads 拉起。
|
|
4
|
+
*/
|
|
5
|
+
const { parentPort, workerData } = require('worker_threads');
|
|
6
|
+
const { readFile, writeFile } = require('fs/promises');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { createRequire } = require('module');
|
|
9
|
+
|
|
10
|
+
const requireFromHere = createRequire(__filename);
|
|
11
|
+
|
|
12
|
+
const resolveExcelJS = () => {
|
|
13
|
+
const candidates = [
|
|
14
|
+
() => requireFromHere.resolve('exceljs'),
|
|
15
|
+
() =>
|
|
16
|
+
requireFromHere.resolve('exceljs', {
|
|
17
|
+
paths: [path.resolve(__dirname, '../../../utils')],
|
|
18
|
+
}),
|
|
19
|
+
() =>
|
|
20
|
+
requireFromHere.resolve('exceljs', {
|
|
21
|
+
paths: [path.resolve(__dirname, '../../../../node_modules')],
|
|
22
|
+
}),
|
|
23
|
+
];
|
|
24
|
+
for (const tryResolve of candidates) {
|
|
25
|
+
try {
|
|
26
|
+
// eslint-disable-next-line import/no-dynamic-require
|
|
27
|
+
return require(tryResolve());
|
|
28
|
+
} catch {
|
|
29
|
+
// continue
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
throw new Error('无法解析 exceljs,请确认 monorepo 依赖已安装');
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const ExcelJS = resolveExcelJS();
|
|
36
|
+
|
|
37
|
+
const CellValueType = {
|
|
38
|
+
STRING: 1,
|
|
39
|
+
NUMBER: 2,
|
|
40
|
+
BOOLEAN: 3,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const argbToRgb = (argb) => {
|
|
44
|
+
if (!argb || typeof argb !== 'string') return undefined;
|
|
45
|
+
const hex = argb.replace(/^#/, '');
|
|
46
|
+
if (hex.length === 8) return `#${hex.slice(2)}`;
|
|
47
|
+
if (hex.length === 6) return `#${hex}`;
|
|
48
|
+
return undefined;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const excelColorToRgb = (color) => {
|
|
52
|
+
if (!color) return undefined;
|
|
53
|
+
if (color.argb) return argbToRgb(color.argb);
|
|
54
|
+
return undefined;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const cellFromExcelJs = (cell) => {
|
|
58
|
+
const value = cell.value;
|
|
59
|
+
if (value == null || value === '') return null;
|
|
60
|
+
|
|
61
|
+
let mapped = null;
|
|
62
|
+
|
|
63
|
+
if (typeof value === 'object' && value !== null && 'formula' in value) {
|
|
64
|
+
const formula = String(value.formula || '').replace(/^=/, '');
|
|
65
|
+
const result = value.result;
|
|
66
|
+
mapped = {
|
|
67
|
+
f: `=${formula}`,
|
|
68
|
+
v: result,
|
|
69
|
+
t:
|
|
70
|
+
typeof result === 'number'
|
|
71
|
+
? CellValueType.NUMBER
|
|
72
|
+
: typeof result === 'boolean'
|
|
73
|
+
? CellValueType.BOOLEAN
|
|
74
|
+
: CellValueType.STRING,
|
|
75
|
+
};
|
|
76
|
+
} else if (typeof value === 'object' && value !== null && 'richText' in value) {
|
|
77
|
+
const text = (value.richText || []).map((part) => part.text || '').join('');
|
|
78
|
+
if (!text) return null;
|
|
79
|
+
mapped = { v: text, t: CellValueType.STRING };
|
|
80
|
+
} else if (typeof value === 'object' && value !== null && 'text' in value && 'hyperlink' in value) {
|
|
81
|
+
mapped = { v: String(value.text || ''), t: CellValueType.STRING };
|
|
82
|
+
} else if (typeof value === 'object' && value !== null && 'error' in value) {
|
|
83
|
+
mapped = { v: String(value.error), t: CellValueType.STRING };
|
|
84
|
+
} else if (value instanceof Date) {
|
|
85
|
+
mapped = { v: value.toISOString(), t: CellValueType.STRING };
|
|
86
|
+
} else if (typeof value === 'number') {
|
|
87
|
+
mapped = { v: value, t: CellValueType.NUMBER };
|
|
88
|
+
} else if (typeof value === 'boolean') {
|
|
89
|
+
mapped = { v: value, t: CellValueType.BOOLEAN };
|
|
90
|
+
} else {
|
|
91
|
+
const text = String(value);
|
|
92
|
+
if (!text) return null;
|
|
93
|
+
mapped = { v: text, t: CellValueType.STRING };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const style = {};
|
|
97
|
+
const font = cell.font;
|
|
98
|
+
if (font) {
|
|
99
|
+
if (font.bold) style.bl = 1;
|
|
100
|
+
if (font.italic) style.it = 1;
|
|
101
|
+
if (font.size) style.fs = font.size;
|
|
102
|
+
if (font.name) style.ff = font.name;
|
|
103
|
+
const fc = excelColorToRgb(font.color);
|
|
104
|
+
if (fc) style.cl = { rgb: fc };
|
|
105
|
+
}
|
|
106
|
+
const fill = cell.fill;
|
|
107
|
+
if (fill && fill.type === 'pattern' && fill.fgColor) {
|
|
108
|
+
const bg = excelColorToRgb(fill.fgColor);
|
|
109
|
+
if (bg) style.bg = { rgb: bg };
|
|
110
|
+
}
|
|
111
|
+
if (Object.keys(style).length) mapped.s = style;
|
|
112
|
+
return mapped;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const collectMerges = (worksheet, maxRowExclusive) => {
|
|
116
|
+
const merges = [];
|
|
117
|
+
const raw = worksheet.model && worksheet.model.merges;
|
|
118
|
+
if (!Array.isArray(raw)) return merges;
|
|
119
|
+
raw.forEach((ref) => {
|
|
120
|
+
try {
|
|
121
|
+
const [start, end] = String(ref).split(':');
|
|
122
|
+
if (!start) return;
|
|
123
|
+
const startCell = worksheet.getCell(start);
|
|
124
|
+
const endCell = worksheet.getCell(end || start);
|
|
125
|
+
const top = Number(startCell.row) - 1;
|
|
126
|
+
const left = Number(startCell.col) - 1;
|
|
127
|
+
const bottom = Number(endCell.row) - 1;
|
|
128
|
+
const right = Number(endCell.col) - 1;
|
|
129
|
+
if (top >= maxRowExclusive) return;
|
|
130
|
+
merges.push({
|
|
131
|
+
startRow: top,
|
|
132
|
+
startColumn: left,
|
|
133
|
+
endRow: Math.min(bottom, maxRowExclusive - 1),
|
|
134
|
+
endColumn: right,
|
|
135
|
+
});
|
|
136
|
+
} catch {
|
|
137
|
+
// ignore
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
return merges;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const post = (msg) => {
|
|
144
|
+
if (parentPort) parentPort.postMessage(msg);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const main = async () => {
|
|
148
|
+
const data = workerData || {};
|
|
149
|
+
const {
|
|
150
|
+
id,
|
|
151
|
+
xlsxPath,
|
|
152
|
+
uploadDir,
|
|
153
|
+
fileName = 'workbook.xlsx',
|
|
154
|
+
blockRowSize = 2000,
|
|
155
|
+
maxRows = 100000,
|
|
156
|
+
} = data;
|
|
157
|
+
|
|
158
|
+
if (!id || !xlsxPath || !uploadDir) {
|
|
159
|
+
throw new Error('workerData 缺少 id / xlsxPath / uploadDir');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const effectiveMaxRows = maxRows === 0 ? Number.POSITIVE_INFINITY : maxRows;
|
|
163
|
+
const buffer = await readFile(xlsxPath);
|
|
164
|
+
|
|
165
|
+
post({ type: 'progress', percent: 5, parsedBlocks: 0, totalBlocks: 0 });
|
|
166
|
+
|
|
167
|
+
const workbook = new ExcelJS.Workbook();
|
|
168
|
+
await workbook.xlsx.load(buffer);
|
|
169
|
+
|
|
170
|
+
post({ type: 'progress', percent: 20, parsedBlocks: 0, totalBlocks: 0 });
|
|
171
|
+
|
|
172
|
+
const sheetsMeta = [];
|
|
173
|
+
const sheetOrder = [];
|
|
174
|
+
let truncated = false;
|
|
175
|
+
let emittedBlocks = 0;
|
|
176
|
+
|
|
177
|
+
const sheetInfos = workbook.worksheets.map((worksheet, sheetIndex) => {
|
|
178
|
+
const sheetId = `sheet-${sheetIndex}`;
|
|
179
|
+
const actualRowCount = worksheet.rowCount || 0;
|
|
180
|
+
const cappedRows = Math.min(actualRowCount, effectiveMaxRows);
|
|
181
|
+
if (actualRowCount > effectiveMaxRows) truncated = true;
|
|
182
|
+
const blockCount = Math.max(1, Math.ceil(Math.max(cappedRows, 1) / blockRowSize));
|
|
183
|
+
return { worksheet, sheetIndex, sheetId, cappedRows, blockCount };
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const totalBlocks = sheetInfos.reduce((sum, info) => sum + info.blockCount, 0) || 1;
|
|
187
|
+
|
|
188
|
+
for (const info of sheetInfos) {
|
|
189
|
+
const { worksheet, sheetIndex, sheetId, cappedRows, blockCount } = info;
|
|
190
|
+
sheetOrder.push(sheetId);
|
|
191
|
+
|
|
192
|
+
let maxCol = 0;
|
|
193
|
+
const mergeData = collectMerges(worksheet, cappedRows);
|
|
194
|
+
|
|
195
|
+
for (let blockIndex = 0; blockIndex < blockCount; blockIndex += 1) {
|
|
196
|
+
const startRow = blockIndex * blockRowSize;
|
|
197
|
+
const endRow = Math.min(cappedRows, startRow + blockRowSize) - 1;
|
|
198
|
+
const cellData = {};
|
|
199
|
+
|
|
200
|
+
if (cappedRows > 0 && endRow >= startRow) {
|
|
201
|
+
for (let excelRow = startRow + 1; excelRow <= endRow + 1; excelRow += 1) {
|
|
202
|
+
const row = worksheet.getRow(excelRow);
|
|
203
|
+
row.eachCell({ includeEmpty: false }, (cell, colNumber) => {
|
|
204
|
+
const mapped = cellFromExcelJs(cell);
|
|
205
|
+
if (!mapped) return;
|
|
206
|
+
const r = excelRow - 1;
|
|
207
|
+
const c = colNumber - 1;
|
|
208
|
+
if (!cellData[r]) cellData[r] = {};
|
|
209
|
+
cellData[r][c] = mapped;
|
|
210
|
+
maxCol = Math.max(maxCol, colNumber);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const blockName = `${id}.block.${sheetIndex}.${blockIndex}.json`;
|
|
216
|
+
await writeFile(
|
|
217
|
+
path.join(uploadDir, blockName),
|
|
218
|
+
JSON.stringify({
|
|
219
|
+
sheetId,
|
|
220
|
+
sheetIndex,
|
|
221
|
+
blockIndex,
|
|
222
|
+
startRow: Math.max(0, startRow),
|
|
223
|
+
endRow: Math.max(0, endRow),
|
|
224
|
+
cellData,
|
|
225
|
+
}),
|
|
226
|
+
'utf8',
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
emittedBlocks += 1;
|
|
230
|
+
const percent = Math.min(95, 20 + Math.round((emittedBlocks / totalBlocks) * 75));
|
|
231
|
+
post({
|
|
232
|
+
type: 'progress',
|
|
233
|
+
percent,
|
|
234
|
+
parsedBlocks: emittedBlocks,
|
|
235
|
+
totalBlocks,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
sheetsMeta.push({
|
|
240
|
+
id: sheetId,
|
|
241
|
+
name: worksheet.name || `Sheet${sheetIndex + 1}`,
|
|
242
|
+
rowCount: Math.max(cappedRows, 1),
|
|
243
|
+
columnCount: Math.max(maxCol, 1),
|
|
244
|
+
blockCount,
|
|
245
|
+
mergeData: mergeData.length ? mergeData : undefined,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const meta = {
|
|
250
|
+
parseEngine: 'exceljs',
|
|
251
|
+
fileName,
|
|
252
|
+
name: String(fileName).replace(/\.xlsx$/i, '') || 'workbook',
|
|
253
|
+
sheetOrder,
|
|
254
|
+
sheets: sheetsMeta,
|
|
255
|
+
blockRowSize,
|
|
256
|
+
truncated: truncated || undefined,
|
|
257
|
+
maxRows: Number.isFinite(effectiveMaxRows) ? effectiveMaxRows : undefined,
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const metaFileName = `${id}.meta.json`;
|
|
261
|
+
await writeFile(path.join(uploadDir, metaFileName), JSON.stringify(meta), 'utf8');
|
|
262
|
+
|
|
263
|
+
post({
|
|
264
|
+
type: 'done',
|
|
265
|
+
metaPath: metaFileName,
|
|
266
|
+
metaFileName,
|
|
267
|
+
parsedBlocks: emittedBlocks,
|
|
268
|
+
totalBlocks,
|
|
269
|
+
truncated: meta.truncated,
|
|
270
|
+
});
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
main().catch((error) => {
|
|
274
|
+
post({
|
|
275
|
+
type: 'error',
|
|
276
|
+
message: error instanceof Error ? error.message : String(error),
|
|
277
|
+
});
|
|
278
|
+
process.exitCode = 1;
|
|
279
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../../../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,uDAAmD;AAK5C,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IAHrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,0BAAW,CAAC;KACvB,CAAC;GACW,SAAS,CAAG"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const serverEnvSchema: z.ZodObject<{
|
|
3
|
+
IMS_SERVER_PORT: z.ZodDefault<z.ZodNumber>;
|
|
4
|
+
PORT: z.ZodEffects<z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>, number | undefined, string | number | undefined>;
|
|
5
|
+
IMS_SERVER_BODY_LIMIT: z.ZodDefault<z.ZodString>;
|
|
6
|
+
IMS_SERVER_GZIP_THRESHOLD: z.ZodDefault<z.ZodNumber>;
|
|
7
|
+
IMS_EXCEL_UPLOAD_DIR: z.ZodOptional<z.ZodString>;
|
|
8
|
+
IMS_EXCEL_UPLOAD_TTL_MS: z.ZodDefault<z.ZodNumber>;
|
|
9
|
+
IMS_EXCEL_UPLOAD_CLEANUP_MS: z.ZodDefault<z.ZodNumber>;
|
|
10
|
+
IMS_EXCEL_CHUNK_BYTES: z.ZodDefault<z.ZodNumber>;
|
|
11
|
+
IMS_EXCEL_BLOCK_ROWS: z.ZodDefault<z.ZodNumber>;
|
|
12
|
+
IMS_EXCEL_MAX_ROWS: z.ZodDefault<z.ZodNumber>;
|
|
13
|
+
IMS_EXCEL_PARSE_TIMEOUT_MS: z.ZodDefault<z.ZodNumber>;
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
IMS_EXCEL_UPLOAD_TTL_MS: number;
|
|
16
|
+
IMS_EXCEL_UPLOAD_CLEANUP_MS: number;
|
|
17
|
+
IMS_EXCEL_CHUNK_BYTES: number;
|
|
18
|
+
IMS_EXCEL_PARSE_TIMEOUT_MS: number;
|
|
19
|
+
IMS_EXCEL_BLOCK_ROWS: number;
|
|
20
|
+
IMS_EXCEL_MAX_ROWS: number;
|
|
21
|
+
IMS_SERVER_PORT: number;
|
|
22
|
+
IMS_SERVER_BODY_LIMIT: string;
|
|
23
|
+
IMS_SERVER_GZIP_THRESHOLD: number;
|
|
24
|
+
IMS_EXCEL_UPLOAD_DIR?: string | undefined;
|
|
25
|
+
PORT?: number | undefined;
|
|
26
|
+
}, {
|
|
27
|
+
IMS_EXCEL_UPLOAD_DIR?: string | undefined;
|
|
28
|
+
IMS_EXCEL_UPLOAD_TTL_MS?: number | undefined;
|
|
29
|
+
IMS_EXCEL_UPLOAD_CLEANUP_MS?: number | undefined;
|
|
30
|
+
IMS_EXCEL_CHUNK_BYTES?: number | undefined;
|
|
31
|
+
IMS_EXCEL_PARSE_TIMEOUT_MS?: number | undefined;
|
|
32
|
+
IMS_EXCEL_BLOCK_ROWS?: number | undefined;
|
|
33
|
+
IMS_EXCEL_MAX_ROWS?: number | undefined;
|
|
34
|
+
IMS_SERVER_PORT?: number | undefined;
|
|
35
|
+
PORT?: string | number | undefined;
|
|
36
|
+
IMS_SERVER_BODY_LIMIT?: string | undefined;
|
|
37
|
+
IMS_SERVER_GZIP_THRESHOLD?: number | undefined;
|
|
38
|
+
}>;
|
|
39
|
+
export type ServerEnv = z.infer<typeof serverEnvSchema>;
|
|
40
|
+
export declare const loadServerEnv: (env?: NodeJS.ProcessEnv) => ServerEnv;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadServerEnv = exports.serverEnvSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.serverEnvSchema = zod_1.z.object({
|
|
6
|
+
IMS_SERVER_PORT: zod_1.z.coerce.number().int().positive().default(3010),
|
|
7
|
+
PORT: zod_1.z
|
|
8
|
+
.union([zod_1.z.string(), zod_1.z.number()])
|
|
9
|
+
.optional()
|
|
10
|
+
.transform((value) => {
|
|
11
|
+
if (value === undefined || value === '')
|
|
12
|
+
return undefined;
|
|
13
|
+
const num = typeof value === 'number' ? value : Number(value);
|
|
14
|
+
return Number.isFinite(num) && num > 0 ? num : undefined;
|
|
15
|
+
}),
|
|
16
|
+
IMS_SERVER_BODY_LIMIT: zod_1.z.string().default('50mb'),
|
|
17
|
+
IMS_SERVER_GZIP_THRESHOLD: zod_1.z.coerce.number().int().nonnegative().default(1024),
|
|
18
|
+
IMS_EXCEL_UPLOAD_DIR: zod_1.z.string().optional(),
|
|
19
|
+
IMS_EXCEL_UPLOAD_TTL_MS: zod_1.z.coerce.number().int().positive().default(60 * 60 * 1000),
|
|
20
|
+
IMS_EXCEL_UPLOAD_CLEANUP_MS: zod_1.z.coerce.number().int().positive().default(10 * 60 * 1000),
|
|
21
|
+
IMS_EXCEL_CHUNK_BYTES: zod_1.z.coerce.number().int().positive().default(2 * 1024 * 1024),
|
|
22
|
+
IMS_EXCEL_BLOCK_ROWS: zod_1.z.coerce.number().int().min(100).default(5_000),
|
|
23
|
+
IMS_EXCEL_MAX_ROWS: zod_1.z.coerce.number().int().nonnegative().default(150_000),
|
|
24
|
+
IMS_EXCEL_PARSE_TIMEOUT_MS: zod_1.z.coerce.number().int().positive().default(10 * 60 * 1000),
|
|
25
|
+
});
|
|
26
|
+
const loadServerEnv = (env = process.env) => {
|
|
27
|
+
const result = exports.serverEnvSchema.safeParse(env);
|
|
28
|
+
if (!result.success) {
|
|
29
|
+
const message = result.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join('; ');
|
|
30
|
+
throw new Error(`[@ims-view/server] 环境变量校验失败: ${message}`);
|
|
31
|
+
}
|
|
32
|
+
return result.data;
|
|
33
|
+
};
|
|
34
|
+
exports.loadServerEnv = loadServerEnv;
|
|
35
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../../../src/config/env.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAMX,QAAA,eAAe,GAAG,OAAC,CAAC,MAAM,CAAC;IACtC,eAAe,EAAE,OAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACjE,IAAI,EAAE,OAAC;SACJ,KAAK,CAAC,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC;SAC/B,QAAQ,EAAE;SACV,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;QACnB,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;YAAE,OAAO,SAAS,CAAC;QAC1D,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9D,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3D,CAAC,CAAC;IACJ,qBAAqB,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IACjD,yBAAyB,EAAE,OAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAC9E,oBAAoB,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3C,uBAAuB,EAAE,OAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACnF,2BAA2B,EAAE,OAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAEvF,qBAAqB,EAAE,OAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;IAElF,oBAAoB,EAAE,OAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IAErE,kBAAkB,EAAE,OAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IAE1E,0BAA0B,EAAE,OAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;CACvF,CAAC,CAAC;AAII,MAAM,aAAa,GAAG,CAAC,MAAyB,OAAO,CAAC,GAAG,EAAa,EAAE;IAC/E,MAAM,MAAM,GAAG,uBAAe,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC9C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/F,MAAM,IAAI,KAAK,CAAC,gCAAgC,OAAO,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC,CAAC;AAPW,QAAA,aAAa,iBAOxB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const excelTaskIdSchema: z.ZodObject<{
|
|
3
|
+
id: z.ZodString;
|
|
4
|
+
}, "strip", z.ZodTypeAny, {
|
|
5
|
+
id: string;
|
|
6
|
+
}, {
|
|
7
|
+
id: string;
|
|
8
|
+
}>;
|
|
9
|
+
declare const ExcelTaskIdDto_base: import("../../shared/create-zod-base-model").ZodBaseModel<z.ZodObject<{
|
|
10
|
+
id: z.ZodString;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
id: string;
|
|
13
|
+
}, {
|
|
14
|
+
id: string;
|
|
15
|
+
}>>;
|
|
16
|
+
export declare class ExcelTaskIdDto extends ExcelTaskIdDto_base {
|
|
17
|
+
}
|
|
18
|
+
export type ExcelTaskIdPlain = z.infer<typeof excelTaskIdSchema>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExcelTaskIdDto = exports.excelTaskIdSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const create_zod_base_model_1 = require("../../shared/create-zod-base-model");
|
|
6
|
+
exports.excelTaskIdSchema = zod_1.z.object({
|
|
7
|
+
id: zod_1.z
|
|
8
|
+
.string()
|
|
9
|
+
.trim()
|
|
10
|
+
.min(1, '任务 id 不能为空')
|
|
11
|
+
.regex(/^[a-zA-Z0-9_-]+$/, '任务 id 格式无效')
|
|
12
|
+
.describe('解析任务 id'),
|
|
13
|
+
});
|
|
14
|
+
class ExcelTaskIdDto extends (0, create_zod_base_model_1.createZodBaseModel)(exports.excelTaskIdSchema) {
|
|
15
|
+
}
|
|
16
|
+
exports.ExcelTaskIdDto = ExcelTaskIdDto;
|
|
17
|
+
//# sourceMappingURL=excel-task-id.dto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"excel-task-id.dto.js","sourceRoot":"","sources":["../../../../../src/excel/dto/excel-task-id.dto.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AACxB,8EAAwE;AAE3D,QAAA,iBAAiB,GAAG,OAAC,CAAC,MAAM,CAAC;IACxC,EAAE,EAAE,OAAC;SACF,MAAM,EAAE;SACR,IAAI,EAAE;SACN,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC;SACpB,KAAK,CAAC,kBAAkB,EAAE,YAAY,CAAC;SACvC,QAAQ,CAAC,SAAS,CAAC;CACvB,CAAC,CAAC;AAEH,MAAa,cAAe,SAAQ,IAAA,0CAAkB,EAAC,yBAAiB,CAAC;CAAG;AAA5E,wCAA4E"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const exportExcelSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
3
|
+
data: z.ZodOptional<z.ZodAny>;
|
|
4
|
+
fileName: z.ZodOptional<z.ZodString>;
|
|
5
|
+
}, "strip", z.ZodTypeAny, {
|
|
6
|
+
data?: any;
|
|
7
|
+
fileName?: string | undefined;
|
|
8
|
+
}, {
|
|
9
|
+
data?: any;
|
|
10
|
+
fileName?: string | undefined;
|
|
11
|
+
}>, {
|
|
12
|
+
data?: any;
|
|
13
|
+
fileName?: string | undefined;
|
|
14
|
+
}, {
|
|
15
|
+
data?: any;
|
|
16
|
+
fileName?: string | undefined;
|
|
17
|
+
}>, {
|
|
18
|
+
fileName: string | undefined;
|
|
19
|
+
data: z.objectOutputType<{
|
|
20
|
+
id: z.ZodOptional<z.ZodString>;
|
|
21
|
+
name: z.ZodOptional<z.ZodString>;
|
|
22
|
+
appVersion: z.ZodOptional<z.ZodString>;
|
|
23
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
24
|
+
sheetOrder: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
25
|
+
sheets: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
26
|
+
styles: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
27
|
+
resources: z.ZodOptional<z.ZodArray<z.ZodAny, "many">>;
|
|
28
|
+
}, z.ZodTypeAny, "passthrough">;
|
|
29
|
+
}, {
|
|
30
|
+
data?: any;
|
|
31
|
+
fileName?: string | undefined;
|
|
32
|
+
}>;
|
|
33
|
+
declare const ExportExcelDto_base: import("../../shared/create-zod-base-model").ZodBaseModel<z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
34
|
+
data: z.ZodOptional<z.ZodAny>;
|
|
35
|
+
fileName: z.ZodOptional<z.ZodString>;
|
|
36
|
+
}, "strip", z.ZodTypeAny, {
|
|
37
|
+
data?: any;
|
|
38
|
+
fileName?: string | undefined;
|
|
39
|
+
}, {
|
|
40
|
+
data?: any;
|
|
41
|
+
fileName?: string | undefined;
|
|
42
|
+
}>, {
|
|
43
|
+
data?: any;
|
|
44
|
+
fileName?: string | undefined;
|
|
45
|
+
}, {
|
|
46
|
+
data?: any;
|
|
47
|
+
fileName?: string | undefined;
|
|
48
|
+
}>, {
|
|
49
|
+
fileName: string | undefined;
|
|
50
|
+
data: z.objectOutputType<{
|
|
51
|
+
id: z.ZodOptional<z.ZodString>;
|
|
52
|
+
name: z.ZodOptional<z.ZodString>;
|
|
53
|
+
appVersion: z.ZodOptional<z.ZodString>;
|
|
54
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
55
|
+
sheetOrder: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
56
|
+
sheets: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
57
|
+
styles: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
58
|
+
resources: z.ZodOptional<z.ZodArray<z.ZodAny, "many">>;
|
|
59
|
+
}, z.ZodTypeAny, "passthrough">;
|
|
60
|
+
}, {
|
|
61
|
+
data?: any;
|
|
62
|
+
fileName?: string | undefined;
|
|
63
|
+
}>>;
|
|
64
|
+
export declare class ExportExcelDto extends ExportExcelDto_base {
|
|
65
|
+
}
|
|
66
|
+
export type ExportExcelPlain = z.infer<typeof exportExcelSchema>;
|
|
67
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExportExcelDto = exports.exportExcelSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const create_zod_base_model_1 = require("../../shared/create-zod-base-model");
|
|
6
|
+
const workbookDataSchema = zod_1.z
|
|
7
|
+
.object({
|
|
8
|
+
id: zod_1.z.string().optional(),
|
|
9
|
+
name: zod_1.z.string().optional(),
|
|
10
|
+
appVersion: zod_1.z.string().optional(),
|
|
11
|
+
locale: zod_1.z.string().optional(),
|
|
12
|
+
sheetOrder: zod_1.z.array(zod_1.z.string()).optional(),
|
|
13
|
+
sheets: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(),
|
|
14
|
+
styles: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(),
|
|
15
|
+
resources: zod_1.z.array(zod_1.z.any()).optional(),
|
|
16
|
+
})
|
|
17
|
+
.passthrough();
|
|
18
|
+
exports.exportExcelSchema = zod_1.z
|
|
19
|
+
.object({
|
|
20
|
+
data: zod_1.z.any().optional().describe('工作簿 snapshot'),
|
|
21
|
+
fileName: zod_1.z.string().trim().min(1, '文件名不能为空').optional().describe('导出文件名'),
|
|
22
|
+
})
|
|
23
|
+
.superRefine((value, ctx) => {
|
|
24
|
+
if (value.data == null || typeof value.data !== 'object' || Array.isArray(value.data)) {
|
|
25
|
+
ctx.addIssue({
|
|
26
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
27
|
+
path: ['data'],
|
|
28
|
+
message: '缺少工作簿数据 data',
|
|
29
|
+
});
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const parsed = workbookDataSchema.safeParse(value.data);
|
|
33
|
+
if (!parsed.success) {
|
|
34
|
+
ctx.addIssue({
|
|
35
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
36
|
+
path: ['data'],
|
|
37
|
+
message: parsed.error.issues[0]?.message || 'data 格式无效',
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
.transform((value) => ({
|
|
42
|
+
fileName: value.fileName,
|
|
43
|
+
data: workbookDataSchema.parse(value.data),
|
|
44
|
+
}));
|
|
45
|
+
class ExportExcelDto extends (0, create_zod_base_model_1.createZodBaseModel)(exports.exportExcelSchema) {
|
|
46
|
+
}
|
|
47
|
+
exports.ExportExcelDto = ExportExcelDto;
|
|
48
|
+
//# sourceMappingURL=export-excel.dto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-excel.dto.js","sourceRoot":"","sources":["../../../../../src/excel/dto/export-excel.dto.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AACxB,8EAAwE;AAExE,MAAM,kBAAkB,GAAG,OAAC;KACzB,MAAM,CAAC;IACN,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACzB,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,UAAU,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC1C,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE;IAChD,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE;IAChD,SAAS,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE;CACvC,CAAC;KACD,WAAW,EAAE,CAAC;AAGJ,QAAA,iBAAiB,GAAG,OAAC;KAC/B,MAAM,CAAC;IACN,IAAI,EAAE,OAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;IACjD,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;CAC3E,CAAC;KACD,WAAW,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAC1B,IAAI,KAAK,CAAC,IAAI,IAAI,IAAI,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtF,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,IAAI,EAAE,CAAC,MAAM,CAAC;YACd,OAAO,EAAE,cAAc;SACxB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,kBAAkB,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,IAAI,EAAE,CAAC,MAAM,CAAC;YACd,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,WAAW;SACxD,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC;KACD,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC,QAAQ;IACxB,IAAI,EAAE,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;CAC3C,CAAC,CAAC,CAAC;AAEN,MAAa,cAAe,SAAQ,IAAA,0CAAkB,EAAC,yBAAiB,CAAC;CAAG;AAA5E,wCAA4E"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { OnModuleDestroy, OnModuleInit } from '@nestjs/common';
|
|
2
|
+
export declare const getExcelUploadDir: () => string;
|
|
3
|
+
export declare const EXCEL_STATIC_PREFIX = "/excel/static";
|
|
4
|
+
export declare const preserveUploadFileName: (raw?: string) => string;
|
|
5
|
+
export type StoredExcelFile = {
|
|
6
|
+
id: string;
|
|
7
|
+
fileName: string;
|
|
8
|
+
path: string;
|
|
9
|
+
size: number;
|
|
10
|
+
expiresAt: number;
|
|
11
|
+
};
|
|
12
|
+
export type ExcelParseTaskStatus = 'pending' | 'done' | 'error';
|
|
13
|
+
export type ExcelParseMode = 'snapshot' | 'chunked';
|
|
14
|
+
export type ExcelParseTask = {
|
|
15
|
+
id: string;
|
|
16
|
+
status: ExcelParseTaskStatus;
|
|
17
|
+
mode?: ExcelParseMode;
|
|
18
|
+
fileName: string;
|
|
19
|
+
xlsxPath: string;
|
|
20
|
+
snapshotPath?: string;
|
|
21
|
+
metaPath?: string;
|
|
22
|
+
progress?: number;
|
|
23
|
+
parsedBlocks?: number;
|
|
24
|
+
totalBlocks?: number;
|
|
25
|
+
truncated?: boolean;
|
|
26
|
+
error?: string;
|
|
27
|
+
startedAt: number;
|
|
28
|
+
finishedAt?: number;
|
|
29
|
+
};
|
|
30
|
+
export declare class ExcelStorageService implements OnModuleInit, OnModuleDestroy {
|
|
31
|
+
private readonly logger;
|
|
32
|
+
private readonly uploadDir;
|
|
33
|
+
private cleanupTimer;
|
|
34
|
+
private readonly tasks;
|
|
35
|
+
onModuleInit(): Promise<void>;
|
|
36
|
+
onModuleDestroy(): void;
|
|
37
|
+
getUploadDir(): string;
|
|
38
|
+
getTask(id: string): ExcelParseTask | undefined;
|
|
39
|
+
getXlsxFullPath(id: string): string;
|
|
40
|
+
saveXlsx(buffer: Buffer, originalName: string): Promise<StoredExcelFile>;
|
|
41
|
+
setTaskMode(id: string, mode: ExcelParseMode): void;
|
|
42
|
+
updateTaskProgress(id: string, progress: number, parsedBlocks?: number, totalBlocks?: number): void;
|
|
43
|
+
saveSnapshot(id: string, workbookData: unknown): Promise<string>;
|
|
44
|
+
markTaskChunkedDone(id: string, metaFileName: string, extras?: {
|
|
45
|
+
parsedBlocks?: number;
|
|
46
|
+
totalBlocks?: number;
|
|
47
|
+
truncated?: boolean;
|
|
48
|
+
}): string;
|
|
49
|
+
markTaskError(id: string, error: string): void;
|
|
50
|
+
readSnapshot(id: string): Promise<unknown | null>;
|
|
51
|
+
private isManagedFile;
|
|
52
|
+
private idFromFileName;
|
|
53
|
+
cleanupExpired(): Promise<number>;
|
|
54
|
+
}
|