@4399ywkf/editor 0.8.0 → 0.9.0
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 +58 -27
- package/dist/SheetView-YFK7BUS5.js +3 -0
- package/dist/{SheetView-SDBRSTVS.js.map → SheetView-YFK7BUS5.js.map} +1 -1
- package/dist/{chunk-KRP5V7VF.js → chunk-2DI4FJPC.js} +10 -3
- package/dist/chunk-2DI4FJPC.js.map +1 -0
- package/dist/{chunk-DGUNVCOM.js → chunk-3QTRZBIK.js} +111 -26
- package/dist/chunk-3QTRZBIK.js.map +1 -0
- package/dist/chunk-JWHQF2CZ.js +257 -0
- package/dist/chunk-JWHQF2CZ.js.map +1 -0
- package/dist/{chunk-WF7PIIFR.js → chunk-JZ67Q3QI.js} +4 -4
- package/dist/chunk-JZ67Q3QI.js.map +1 -0
- package/dist/{chunk-SBTKDJAL.js → chunk-SDVGDHC4.js} +45 -3
- package/dist/chunk-SDVGDHC4.js.map +1 -0
- package/dist/{chunk-HPSPOM2O.js → chunk-XB6FEC4I.js} +3 -3
- package/dist/chunk-XB6FEC4I.js.map +1 -0
- package/dist/{csv-parse-D0zTBvDB.d.ts → csv-parse-DXlwzoZ6.d.ts} +28 -1
- package/dist/csv.d.ts +2 -2
- package/dist/csv.js +4 -4
- package/dist/import-O7RUERND.js +6 -0
- package/dist/{import-GVZDLWA2.js.map → import-O7RUERND.js.map} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/pdf.d.ts +1 -1
- package/dist/pptx.d.ts +1 -1
- package/dist/{registry-CYKivRDh.d.ts → registry-BQ5T1Yko.d.ts} +9 -16
- package/dist/sheet-runtime.d.ts +10 -8
- package/dist/sheet-runtime.js +6 -14
- package/dist/sheet-runtime.js.map +1 -1
- package/dist/sheet.d.ts +4 -3
- package/dist/sheet.js +1 -1
- package/dist/xlsx.d.ts +12 -11
- package/dist/xlsx.js +121 -32
- package/dist/xlsx.js.map +1 -1
- package/package.json +71 -27
- package/dist/SheetView-SDBRSTVS.js +0 -3
- package/dist/chunk-DGUNVCOM.js.map +0 -1
- package/dist/chunk-HPSPOM2O.js.map +0 -1
- package/dist/chunk-KRP5V7VF.js.map +0 -1
- package/dist/chunk-SBTKDJAL.js.map +0 -1
- package/dist/chunk-SYCK6Y5F.js +0 -89
- package/dist/chunk-SYCK6Y5F.js.map +0 -1
- package/dist/chunk-WF7PIIFR.js.map +0 -1
- package/dist/import-GVZDLWA2.js +0 -6
package/dist/xlsx.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { W as WorkbookData, a as CsvParseOptions } from './csv-parse-
|
|
2
|
-
export { C as CellData, e as CellRange, f as CellValue, g as ColumnData, b as CsvToSnapshotResult, R as RowData, S as StyleData, c as WorksheetData, d as csvToSnapshot, p as parseCsv } from './csv-parse-
|
|
1
|
+
import { W as WorkbookData, a as CsvParseOptions } from './csv-parse-DXlwzoZ6.js';
|
|
2
|
+
export { C as CellData, e as CellRange, f as CellValue, g as ColumnData, b as CsvToSnapshotResult, R as RowData, S as StyleData, c as WorksheetData, d as csvToSnapshot, p as parseCsv } from './csv-parse-DXlwzoZ6.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Univer 快照 → xlsx 的各个 XML 部件。
|
|
@@ -7,9 +7,10 @@ export { C as CellData, e as CellRange, f as CellValue, g as ColumnData, b as Cs
|
|
|
7
7
|
* 纯函数、无 DOM、无引擎依赖:Node 里拿一份 JSON 就能出文件,
|
|
8
8
|
* 不需要把 871KB 的 Univer 渲染引擎拉起来。
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* **能保住的**:多工作表、值与类型、公式(含共享公式、数组公式、动态数组与缓存值)、
|
|
11
|
+
* 1904 日期系统、数字格式、字体/颜色/填充/边框/对齐/换行/旋转/缩小字体填充、会计用下划线、
|
|
12
|
+
* 合并单元格、行高列宽、隐藏行列、冻结窗格、网格线开关、标签颜色、工作表隐藏与深度隐藏、
|
|
13
|
+
* 工作表背景图(data URL 形式的)。
|
|
13
14
|
*
|
|
14
15
|
* **保不住的**:图片、图表、透视表、条件格式、数据校验、筛选、批注、超链接。
|
|
15
16
|
* 它们不在 `cellData` 里,而是各插件自己序列化进 `resources` 的私有结构 ——
|
|
@@ -113,12 +114,13 @@ declare function importSheetSource(source: string | Blob | File, options?: Impor
|
|
|
113
114
|
* (fflate + 原生 DOMParser)和 Node(任意 zip 库 + @xmldom/xmldom)
|
|
114
115
|
* 共用这一份实现,不存在两份真相 —— 和 `docx/parse.ts` 同一套约定。
|
|
115
116
|
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
117
|
+
* **能保住的**:多工作表(含顺序、隐藏与深度隐藏)、值与类型、
|
|
118
|
+
* 公式(普通/共享/数组/动态数组)、1904 日期系统、数字格式、
|
|
119
|
+
* 字体/颜色/填充/边框/对齐/换行/旋转/缩小字体填充、会计用下划线、合并单元格、
|
|
120
|
+
* 行高列宽、隐藏行列、冻结窗格、网格线开关、标签颜色、工作表背景图、quotePrefix(强制文本)。
|
|
119
121
|
*
|
|
120
122
|
* **保不住的**:图片、图表、透视表、条件格式、数据校验、筛选、批注、
|
|
121
|
-
*
|
|
123
|
+
* 超链接、主题色、模拟运算表的定义(只留结果)。它们要么住在独立部件里(drawing / pivot / comments),
|
|
122
124
|
* 要么需要把 Excel 的主题模型抄一遍(theme + tint)。这里不假装支持,
|
|
123
125
|
* 而是逐个探测、**如实报告丢了什么**(见 `warnings`)—— 让宿主能把话
|
|
124
126
|
* 原样告诉用户,而不是打开表格才发现少了东西。
|
|
@@ -149,8 +151,7 @@ declare function parseXlsx(entries: XlsxEntries, options: ParseXlsxOptions): Par
|
|
|
149
151
|
|
|
150
152
|
/**
|
|
151
153
|
* 参数类型是 `unknown` 而不是 `FUniver`:`@univerjs/presets` 是可选 peer,
|
|
152
|
-
* 写成具体类型会让没装它的项目 typecheck
|
|
153
|
-
* 方法名依次试探(`getSnapshot` 是新名字,`save` 是旧的)。
|
|
154
|
+
* 写成具体类型会让没装它的项目 typecheck 直接红。
|
|
154
155
|
*/
|
|
155
156
|
declare function snapshotFromUniver(univerAPI: unknown): WorkbookData;
|
|
156
157
|
|
package/dist/xlsx.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { importCsv, importSheetSource, importXlsx, parseXlsx } from './chunk-
|
|
2
|
-
import {
|
|
3
|
-
import { toSnapshot } from './chunk-
|
|
4
|
-
export { snapshotFromUniver } from './chunk-
|
|
5
|
-
import { H_ALIGN, V_ALIGN, CELL_TYPE, WRAP } from './chunk-
|
|
6
|
-
export { csvToSnapshot, parseCsv } from './chunk-
|
|
1
|
+
export { importCsv, importSheetSource, importXlsx, parseXlsx } from './chunk-3QTRZBIK.js';
|
|
2
|
+
import { parseRange, cellRef, pxToPoints, escapeXml, pxToColumnWidth, columnName, toArgb, XML_DECL, escapeAttr, imageMimeOf, dataUrlToImage } from './chunk-SDVGDHC4.js';
|
|
3
|
+
import { toSnapshot } from './chunk-JZ67Q3QI.js';
|
|
4
|
+
export { snapshotFromUniver } from './chunk-JZ67Q3QI.js';
|
|
5
|
+
import { H_ALIGN, V_ALIGN, UNDERLINE, FORMULA_TYPE, CELL_TYPE, WRAP } from './chunk-2DI4FJPC.js';
|
|
6
|
+
export { csvToSnapshot, parseCsv } from './chunk-2DI4FJPC.js';
|
|
7
7
|
import { numericKeys, richTextToPlain } from './chunk-5HMKRNIH.js';
|
|
8
8
|
import { zipSync } from 'fflate';
|
|
9
9
|
|
|
@@ -37,6 +37,18 @@ var V_ALIGN_NAME = {
|
|
|
37
37
|
[V_ALIGN.MIDDLE]: "center",
|
|
38
38
|
[V_ALIGN.BOTTOM]: "bottom"
|
|
39
39
|
};
|
|
40
|
+
var UNDERLINE_NAME = {
|
|
41
|
+
[UNDERLINE.DOUBLE]: "double",
|
|
42
|
+
[UNDERLINE.SINGLE_ACCOUNTING]: "singleAccounting",
|
|
43
|
+
[UNDERLINE.DOUBLE_ACCOUNTING]: "doubleAccounting"
|
|
44
|
+
};
|
|
45
|
+
function underlineOf(s) {
|
|
46
|
+
if (!s.ul?.s) return void 0;
|
|
47
|
+
return UNDERLINE_NAME[s.ul.t ?? UNDERLINE.SINGLE] ?? "single";
|
|
48
|
+
}
|
|
49
|
+
function fontNameOf(s) {
|
|
50
|
+
return s.ff ?? s.eastAsiaFontFamily ?? "Calibri";
|
|
51
|
+
}
|
|
40
52
|
var FIRST_CUSTOM_NUMFMT_ID = 164;
|
|
41
53
|
function createStyleTable(defaultStyle) {
|
|
42
54
|
const numFmts = /* @__PURE__ */ new Map();
|
|
@@ -58,11 +70,11 @@ function createStyleTable(defaultStyle) {
|
|
|
58
70
|
xfs.set("0|0|0|0||0", 0);
|
|
59
71
|
function fontKey(s) {
|
|
60
72
|
return JSON.stringify([
|
|
61
|
-
s
|
|
73
|
+
fontNameOf(s),
|
|
62
74
|
s.fs ?? null,
|
|
63
75
|
s.bl ?? 0,
|
|
64
76
|
s.it ?? 0,
|
|
65
|
-
s
|
|
77
|
+
underlineOf(s) ?? null,
|
|
66
78
|
s.st?.s ?? 0,
|
|
67
79
|
s.va ?? 0,
|
|
68
80
|
toArgb(s.cl) ?? null
|
|
@@ -73,13 +85,14 @@ function createStyleTable(defaultStyle) {
|
|
|
73
85
|
if (s.bl) parts.push("<b/>");
|
|
74
86
|
if (s.it) parts.push("<i/>");
|
|
75
87
|
if (s.st?.s) parts.push("<strike/>");
|
|
76
|
-
|
|
88
|
+
const underline = underlineOf(s);
|
|
89
|
+
if (underline) parts.push(`<u val="${underline}"/>`);
|
|
77
90
|
if (s.va === 1) parts.push('<vertAlign val="superscript"/>');
|
|
78
91
|
else if (s.va === 2) parts.push('<vertAlign val="subscript"/>');
|
|
79
92
|
parts.push(`<sz val="${s.fs ?? 11}"/>`);
|
|
80
93
|
const color = toArgb(s.cl);
|
|
81
94
|
if (color) parts.push(`<color rgb="${color}"/>`);
|
|
82
|
-
parts.push(`<name val="${escapeAttr(s
|
|
95
|
+
parts.push(`<name val="${escapeAttr(fontNameOf(s))}"/>`);
|
|
83
96
|
return `<font>${parts.join("")}</font>`;
|
|
84
97
|
}
|
|
85
98
|
function fontId(s) {
|
|
@@ -142,6 +155,7 @@ function createStyleTable(defaultStyle) {
|
|
|
142
155
|
if (s.ht && H_ALIGN_NAME[s.ht]) a.horizontal = H_ALIGN_NAME[s.ht];
|
|
143
156
|
if (s.vt && V_ALIGN_NAME[s.vt]) a.vertical = V_ALIGN_NAME[s.vt];
|
|
144
157
|
if (s.tb === WRAP.WRAP) a.wrapText = true;
|
|
158
|
+
if (s.stf === 1) a.shrinkToFit = true;
|
|
145
159
|
const angle = s.tr?.a;
|
|
146
160
|
if (s.tr?.v === 1) {
|
|
147
161
|
a.textRotation = 255;
|
|
@@ -174,7 +188,7 @@ function createStyleTable(defaultStyle) {
|
|
|
174
188
|
if (border) attrs.push('applyBorder="1"');
|
|
175
189
|
if (align) attrs.push('applyAlignment="1"');
|
|
176
190
|
if (quotePrefix) attrs.push('quotePrefix="1"');
|
|
177
|
-
const body = align ? `<alignment${align.horizontal ? ` horizontal="${align.horizontal}"` : ""}${align.vertical ? ` vertical="${align.vertical}"` : ""}${align.wrapText ? ' wrapText="1"' : ""}${align.textRotation !== void 0 ? ` textRotation="${align.textRotation}"` : ""}/>` : "";
|
|
191
|
+
const body = align ? `<alignment${align.horizontal ? ` horizontal="${align.horizontal}"` : ""}${align.vertical ? ` vertical="${align.vertical}"` : ""}${align.wrapText ? ' wrapText="1"' : ""}${align.textRotation !== void 0 ? ` textRotation="${align.textRotation}"` : ""}${align.shrinkToFit ? ' shrinkToFit="1"' : ""}/>` : "";
|
|
178
192
|
const id = xfXml.length;
|
|
179
193
|
xfXml.push(body ? `<xf ${attrs.join(" ")}>${body}</xf>` : `<xf ${attrs.join(" ")}/>`);
|
|
180
194
|
xfs.set(key, id);
|
|
@@ -203,9 +217,11 @@ var RESOURCE_LABELS = {
|
|
|
203
217
|
SHEET_WORKSHEET_PROTECTION_PLUGIN: "工作表保护"
|
|
204
218
|
};
|
|
205
219
|
var BAD_SHEET_NAME = /[\\/?*[\]:]/g;
|
|
220
|
+
var SHEET_STATE = { 1: "hidden", 2: "veryHidden" };
|
|
206
221
|
var RELS_NS = 'xmlns="http://schemas.openxmlformats.org/package/2006/relationships"';
|
|
207
222
|
var MAIN_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
|
|
208
223
|
var DOC_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
224
|
+
var DYNAMIC_ARRAY_METADATA = `${XML_DECL}<metadata xmlns="${MAIN_NS}" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray"><metadataTypes count="1"><metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/></metadataTypes><futureMetadata name="XLDAPR" count="1"><bk><extLst><ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}"><xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/></ext></extLst></bk></futureMetadata><cellMetadata count="1"><bk><rc t="1" v="0"/></bk></cellMetadata></metadata>`;
|
|
209
225
|
function serializeXlsx(workbook, options = {}) {
|
|
210
226
|
const { cachedFormulaValues = true, creator = "@4399ywkf/editor", created = /* @__PURE__ */ new Date() } = options;
|
|
211
227
|
const warnings = [];
|
|
@@ -261,24 +277,50 @@ function serializeXlsx(workbook, options = {}) {
|
|
|
261
277
|
}
|
|
262
278
|
return unique;
|
|
263
279
|
};
|
|
280
|
+
const imageExts = /* @__PURE__ */ new Set();
|
|
281
|
+
let dynamicArrays = 0;
|
|
282
|
+
let dataTableCells = 0;
|
|
264
283
|
order.forEach((sheetId, index) => {
|
|
265
284
|
const sheet = workbook.sheets?.[sheetId];
|
|
266
285
|
const name = safeName(sheet.name, index);
|
|
267
286
|
const path = `xl/worksheets/sheet${index + 1}.xml`;
|
|
268
|
-
sheets.push({ name,
|
|
269
|
-
put(path, buildSheetXml(sheet));
|
|
287
|
+
sheets.push({ name, state: SHEET_STATE[sheet.hidden ?? 0], path });
|
|
288
|
+
put(path, buildSheetXml(sheet, index, name));
|
|
270
289
|
stats.sheets++;
|
|
271
290
|
});
|
|
272
291
|
if (!sheets.length) {
|
|
273
|
-
sheets.push({ name: "Sheet1",
|
|
274
|
-
put("xl/worksheets/sheet1.xml", buildSheetXml({}));
|
|
292
|
+
sheets.push({ name: "Sheet1", path: "xl/worksheets/sheet1.xml" });
|
|
293
|
+
put("xl/worksheets/sheet1.xml", buildSheetXml({}, 0, "Sheet1"));
|
|
275
294
|
stats.sheets++;
|
|
276
295
|
}
|
|
277
|
-
function
|
|
296
|
+
function backgroundPictureXml(sheet, index, name) {
|
|
297
|
+
const bg = sheet.backgroundImage;
|
|
298
|
+
if (!bg?.source) return "";
|
|
299
|
+
const image = bg.imageSourceType === "BASE64" ? dataUrlToImage(bg.source) : void 0;
|
|
300
|
+
if (!image) {
|
|
301
|
+
warnings.push(
|
|
302
|
+
bg.imageSourceType === "BASE64" ? `工作表「${name}」的背景图格式不支持(只认 png / jpg / gif / bmp),未随 xlsx 导出` : `工作表「${name}」的背景图是${bg.imageSourceType === "URL" ? "外链地址" : "图床里的图片"},导出不联网取图,未随 xlsx 导出`
|
|
303
|
+
);
|
|
304
|
+
return "";
|
|
305
|
+
}
|
|
306
|
+
const file = `background${index + 1}.${image.ext}`;
|
|
307
|
+
files[`xl/media/${file}`] = image.bytes;
|
|
308
|
+
imageExts.add(image.ext);
|
|
309
|
+
put(
|
|
310
|
+
`xl/worksheets/_rels/sheet${index + 1}.xml.rels`,
|
|
311
|
+
`${XML_DECL}<Relationships ${RELS_NS}><Relationship Id="rId1" Type="${DOC_REL}/image" Target="../media/${file}"/></Relationships>`
|
|
312
|
+
);
|
|
313
|
+
stats.backgroundImages = (stats.backgroundImages ?? 0) + 1;
|
|
314
|
+
return '<picture r:id="rId1"/>';
|
|
315
|
+
}
|
|
316
|
+
function buildSheetXml(sheet, index, name) {
|
|
278
317
|
const cellData = sheet.cellData ?? {};
|
|
279
318
|
const rowData = sheet.rowData ?? {};
|
|
280
319
|
const columnData = sheet.columnData ?? {};
|
|
281
320
|
const sheetDefault = resolveStyle(sheet.defaultStyle);
|
|
321
|
+
const merges = (sheet.mergeData ?? []).filter(
|
|
322
|
+
(m) => m && (m.endRow > m.startRow || m.endColumn > m.startColumn)
|
|
323
|
+
);
|
|
282
324
|
const rows = [.../* @__PURE__ */ new Set([...numericKeys(cellData), ...numericKeys(rowData)])].sort(
|
|
283
325
|
(a, b) => a - b
|
|
284
326
|
);
|
|
@@ -317,6 +359,38 @@ function serializeXlsx(workbook, options = {}) {
|
|
|
317
359
|
}
|
|
318
360
|
sharedIndex.set(si, sharedIndex.size);
|
|
319
361
|
}
|
|
362
|
+
const arrayRefs = /* @__PURE__ */ new Map();
|
|
363
|
+
const arrayConflict = (range, r0, c0) => {
|
|
364
|
+
for (let r = range.startRow; r <= range.endRow; r++) {
|
|
365
|
+
for (const c of numericKeys(cellData[r])) {
|
|
366
|
+
if (c < range.startColumn || c > range.endColumn || r === r0 && c === c0) continue;
|
|
367
|
+
const other = cellData[r]?.[c];
|
|
368
|
+
if (other?.f || other?.si) return `区域里的 ${cellRef(r, c)} 另有公式`;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
const overlapsMerge = merges.some(
|
|
372
|
+
(m) => m.startRow <= range.endRow && m.endRow >= range.startRow && m.startColumn <= range.endColumn && m.endColumn >= range.startColumn
|
|
373
|
+
);
|
|
374
|
+
return overlapsMerge ? "区域和合并单元格相交" : void 0;
|
|
375
|
+
};
|
|
376
|
+
for (const r of numericKeys(cellData)) {
|
|
377
|
+
for (const c of numericKeys(cellData[r])) {
|
|
378
|
+
const cell = cellData[r]?.[c];
|
|
379
|
+
if (!cell?.f || !cell.ref || cell.ft != null && cell.ft !== FORMULA_TYPE.ARRAY) continue;
|
|
380
|
+
const range = parseRange(cell.ref);
|
|
381
|
+
const reason = !range || range.startRow !== r || range.startColumn !== c ? `引用范围 ${cell.ref} 不以它为左上角` : arrayConflict(range, r, c);
|
|
382
|
+
if (reason || !range) {
|
|
383
|
+
warnings.push(
|
|
384
|
+
`${cellRef(r, c)} 是数组公式,${reason},已降级成普通公式(区域内的值按静态值写出)`
|
|
385
|
+
);
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
arrayRefs.set(
|
|
389
|
+
`${r},${c}`,
|
|
390
|
+
`${cellRef(range.startRow, range.startColumn)}:${cellRef(range.endRow, range.endColumn)}`
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
320
394
|
const rowXml = [];
|
|
321
395
|
for (const r of rows) {
|
|
322
396
|
const cols = numericKeys(cellData[r]);
|
|
@@ -348,20 +422,28 @@ function serializeXlsx(workbook, options = {}) {
|
|
|
348
422
|
const forceString = cell.t === CELL_TYPE.FORCE_STRING;
|
|
349
423
|
const styleIndex = style || forceString ? styles.xf(style, forceString) : 0;
|
|
350
424
|
const s = styleIndex ? ` s="${styleIndex}"` : "";
|
|
351
|
-
if (cell.
|
|
352
|
-
warnings.push(`${ref} 是数组公式,已降级成普通公式(溢出区域的值按静态值写出)`);
|
|
353
|
-
}
|
|
425
|
+
if (cell.ft === FORMULA_TYPE.DATA_TABLE) dataTableCells++;
|
|
354
426
|
const formula = cell.f?.replace(/^=/, "");
|
|
355
427
|
if (formula || cell.si) {
|
|
356
428
|
stats.cells++;
|
|
357
429
|
const si = cell.si ? sharedIndex.get(cell.si) : void 0;
|
|
358
430
|
const group = cell.si ? groups.get(cell.si) : void 0;
|
|
431
|
+
const arrayRef = arrayRefs.get(`${r},${c}`);
|
|
359
432
|
let fXml = "";
|
|
433
|
+
let cm = "";
|
|
360
434
|
if (formula && si !== void 0 && group) {
|
|
361
435
|
const range = `${cellRef(group.minR, group.minC)}:${cellRef(group.maxR, group.maxC)}`;
|
|
362
436
|
fXml = `<f t="shared" ref="${range}" si="${si}">${escapeXml(formula)}</f>`;
|
|
363
437
|
stats.formulas++;
|
|
364
438
|
stats.sharedFormulas++;
|
|
439
|
+
} else if (formula && arrayRef) {
|
|
440
|
+
fXml = `<f t="array" ref="${arrayRef}">${escapeXml(formula)}</f>`;
|
|
441
|
+
stats.formulas++;
|
|
442
|
+
stats.arrayFormulas = (stats.arrayFormulas ?? 0) + 1;
|
|
443
|
+
if (cell.fd === 1) {
|
|
444
|
+
cm = ' cm="1"';
|
|
445
|
+
dynamicArrays++;
|
|
446
|
+
}
|
|
365
447
|
} else if (formula) {
|
|
366
448
|
fXml = `<f>${escapeXml(formula)}</f>`;
|
|
367
449
|
stats.formulas++;
|
|
@@ -371,7 +453,7 @@ function serializeXlsx(workbook, options = {}) {
|
|
|
371
453
|
}
|
|
372
454
|
const cached = cachedFormulaValues ? formulaValue(cell) : "";
|
|
373
455
|
const t = cachedFormulaValues && typeof cell.v === "string" ? ' t="str"' : "";
|
|
374
|
-
return `<c r="${ref}"${s}${t}>${fXml}${cached}</c>`;
|
|
456
|
+
return `<c r="${ref}"${s}${t}${cm}>${fXml}${cached}</c>`;
|
|
375
457
|
}
|
|
376
458
|
const rich = richTextToPlain(cell);
|
|
377
459
|
if (rich !== void 0) {
|
|
@@ -397,18 +479,15 @@ function serializeXlsx(workbook, options = {}) {
|
|
|
397
479
|
if (typeof v === "number") return Number.isFinite(v) ? `<v>${v}</v>` : "";
|
|
398
480
|
return `<v>${escapeXml(String(v))}</v>`;
|
|
399
481
|
}
|
|
400
|
-
const merges = (sheet.mergeData ?? []).filter(
|
|
401
|
-
(m) => m && (m.endRow > m.startRow || m.endColumn > m.startColumn)
|
|
402
|
-
);
|
|
403
482
|
for (const m of merges) track(m.endRow, m.endColumn);
|
|
404
483
|
stats.merges += merges.length;
|
|
405
484
|
const mergeXml = merges.length ? `<mergeCells count="${merges.length}">${merges.map(
|
|
406
485
|
(m) => `<mergeCell ref="${cellRef(m.startRow, m.startColumn)}:${cellRef(m.endRow, m.endColumn)}"/>`
|
|
407
486
|
).join("")}</mergeCells>` : "";
|
|
408
|
-
const colsXml = numericKeys(columnData).map((
|
|
409
|
-
const col = columnData[
|
|
487
|
+
const colsXml = numericKeys(columnData).map((index2) => {
|
|
488
|
+
const col = columnData[index2];
|
|
410
489
|
if (!col) return "";
|
|
411
|
-
const attrs = [`min="${
|
|
490
|
+
const attrs = [`min="${index2 + 1}"`, `max="${index2 + 1}"`];
|
|
412
491
|
if (col.w) attrs.push(`width="${pxToColumnWidth(col.w)}"`, 'customWidth="1"');
|
|
413
492
|
if (col.hd === 1) attrs.push('hidden="1"');
|
|
414
493
|
const colStyle = resolveStyle(col.s);
|
|
@@ -430,24 +509,34 @@ function serializeXlsx(workbook, options = {}) {
|
|
|
430
509
|
const dimension = maxRow < 0 ? "A1" : `A1:${columnName(Math.max(maxCol, 0))}${maxRow + 1}`;
|
|
431
510
|
const tabColor = toArgb(sheet.tabColor);
|
|
432
511
|
const sheetPr = tabColor ? `<sheetPr><tabColor rgb="${tabColor}"/></sheetPr>` : "";
|
|
433
|
-
return `${XML_DECL}<worksheet xmlns="${MAIN_NS}" xmlns:r="${DOC_REL}">` + sheetPr + `<dimension ref="${dimension}"/>` + sheetViewXml + `<sheetFormatPr ${formatAttrs.join(" ")}/>` + (colsXml ? `<cols>${colsXml}</cols>` : "") + `<sheetData>${rowXml.join("")}</sheetData>` + mergeXml + "</worksheet>";
|
|
512
|
+
return `${XML_DECL}<worksheet xmlns="${MAIN_NS}" xmlns:r="${DOC_REL}">` + sheetPr + `<dimension ref="${dimension}"/>` + sheetViewXml + `<sheetFormatPr ${formatAttrs.join(" ")}/>` + (colsXml ? `<cols>${colsXml}</cols>` : "") + `<sheetData>${rowXml.join("")}</sheetData>` + mergeXml + backgroundPictureXml(sheet, index, name) + "</worksheet>";
|
|
434
513
|
}
|
|
435
514
|
const sheetEntries = sheets.map(
|
|
436
|
-
(s, i) => `<sheet name="${escapeAttr(s.name)}" sheetId="${i + 1}"${s.
|
|
515
|
+
(s, i) => `<sheet name="${escapeAttr(s.name)}" sheetId="${i + 1}"${s.state ? ` state="${s.state}"` : ""} r:id="rId${i + 1}"/>`
|
|
437
516
|
).join("");
|
|
517
|
+
if (dataTableCells) {
|
|
518
|
+
warnings.push(
|
|
519
|
+
`${dataTableCells} 个模拟运算表(数据表)单元格按静态值导出:快照里没有模拟运算表的定义`
|
|
520
|
+
);
|
|
521
|
+
}
|
|
438
522
|
put(
|
|
439
523
|
"xl/workbook.xml",
|
|
440
|
-
`${XML_DECL}<workbook xmlns="${MAIN_NS}" xmlns:r="${DOC_REL}"
|
|
524
|
+
`${XML_DECL}<workbook xmlns="${MAIN_NS}" xmlns:r="${DOC_REL}">` + (workbook.dateSystem === "date1904" ? '<workbookPr date1904="1"/>' : "<workbookPr/>") + `<sheets>${sheetEntries}</sheets>` + // 没写缓存值时必须让 Excel 打开就重算,否则整列公式显示成空白。
|
|
441
525
|
// 写了缓存值就别加:fullCalcOnLoad 会把文件标脏,用户没改动也会被问「是否保存」
|
|
442
526
|
(cachedFormulaValues ? "" : '<calcPr calcId="0" fullCalcOnLoad="1"/>') + "</workbook>"
|
|
443
527
|
);
|
|
444
528
|
const stylesRelId = sheets.length + 1;
|
|
445
529
|
const sstRelId = sheets.length + 2;
|
|
530
|
+
const metadataRelId = sheets.length + 3;
|
|
531
|
+
if (dynamicArrays) {
|
|
532
|
+
put("xl/metadata.xml", DYNAMIC_ARRAY_METADATA);
|
|
533
|
+
stats.dynamicArrays = dynamicArrays;
|
|
534
|
+
}
|
|
446
535
|
put(
|
|
447
536
|
"xl/_rels/workbook.xml.rels",
|
|
448
537
|
`${XML_DECL}<Relationships ${RELS_NS}>` + sheets.map(
|
|
449
538
|
(s, i) => `<Relationship Id="rId${i + 1}" Type="${DOC_REL}/worksheet" Target="worksheets/${s.path.split("/").pop()}"/>`
|
|
450
|
-
).join("") + `<Relationship Id="rId${stylesRelId}" Type="${DOC_REL}/styles" Target="styles.xml"/><Relationship Id="rId${sstRelId}" Type="${DOC_REL}/sharedStrings" Target="sharedStrings.xml"
|
|
539
|
+
).join("") + `<Relationship Id="rId${stylesRelId}" Type="${DOC_REL}/styles" Target="styles.xml"/><Relationship Id="rId${sstRelId}" Type="${DOC_REL}/sharedStrings" Target="sharedStrings.xml"/>` + (dynamicArrays ? `<Relationship Id="rId${metadataRelId}" Type="${DOC_REL}/sheetMetadata" Target="metadata.xml"/>` : "") + "</Relationships>"
|
|
451
540
|
);
|
|
452
541
|
put(
|
|
453
542
|
"xl/sharedStrings.xml",
|
|
@@ -456,9 +545,9 @@ function serializeXlsx(workbook, options = {}) {
|
|
|
456
545
|
put("xl/styles.xml", styles.xml());
|
|
457
546
|
put(
|
|
458
547
|
"[Content_Types].xml",
|
|
459
|
-
`${XML_DECL}<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"
|
|
548
|
+
`${XML_DECL}<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/>` + [...imageExts].map((ext) => `<Default Extension="${ext}" ContentType="${imageMimeOf(`x.${ext}`)}"/>`).join("") + '<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>' + sheets.map(
|
|
460
549
|
(s) => `<Override PartName="/${s.path}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>`
|
|
461
|
-
).join("") + '<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/><Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"
|
|
550
|
+
).join("") + '<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/><Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>' + (dynamicArrays ? '<Override PartName="/xl/metadata.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml"/>' : "") + '<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/></Types>'
|
|
462
551
|
);
|
|
463
552
|
put(
|
|
464
553
|
"_rels/.rels",
|