@nocobase/plugin-action-export 2.1.15 → 2.1.18

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.
@@ -10,20 +10,20 @@
10
10
  module.exports = {
11
11
  "@formily/react": "2.3.7",
12
12
  "@formily/shared": "2.3.7",
13
- "@nocobase/client": "2.1.15",
13
+ "@nocobase/client": "2.1.18",
14
14
  "react": "18.2.0",
15
15
  "@formily/antd-v5": "1.2.3",
16
16
  "react-i18next": "11.18.6",
17
17
  "lodash": "4.18.1",
18
18
  "antd": "5.24.2",
19
- "@nocobase/flow-engine": "2.1.15",
20
- "@nocobase/client-v2": "2.1.15",
19
+ "@nocobase/flow-engine": "2.1.18",
20
+ "@nocobase/client-v2": "2.1.18",
21
21
  "@emotion/css": "11.13.0",
22
- "@nocobase/server": "2.1.15",
23
- "@nocobase/logger": "2.1.15",
24
- "@nocobase/actions": "2.1.15",
25
- "@nocobase/database": "2.1.15",
22
+ "@nocobase/server": "2.1.18",
23
+ "@nocobase/logger": "2.1.18",
24
+ "@nocobase/actions": "2.1.18",
25
+ "@nocobase/database": "2.1.18",
26
26
  "async-mutex": "0.5.0",
27
- "@nocobase/data-source-manager": "2.1.15",
28
- "@nocobase/utils": "2.1.15"
27
+ "@nocobase/data-source-manager": "2.1.18",
28
+ "@nocobase/utils": "2.1.18"
29
29
  };
@@ -1 +1 @@
1
- {"name":"exceljs","version":"4.4.0","description":"Excel Workbook Manager - Read and Write xlsx and csv Files.","private":false,"license":"MIT","author":{"name":"Guyon Roche","email":"guyon@live.com"},"repository":{"type":"git","url":"https://github.com/exceljs/exceljs.git"},"engines":{"node":">=8.3.0"},"main":"./excel.js","browser":"./dist/exceljs.min.js","types":"./index.d.ts","files":["dist","lib","excel.js","LICENSE","README.md","README_zh.md","index.ts","index.d.ts"],"scripts":{"test":"npm run test:full","test:es5":"export EXCEL_BUILD=es5 && npm run test:full","test:full":"npm run build && npm run test:unit && npm run test:integration && npm run test:end-to-end && npm run test:jasmine","test:version":"npm run build && npm run test:unit && npm run test:integration && npm run test:end-to-end && npm run test:browser && npm run test:dist","test:all":"npm run test:native && npm run test:es5","test:native":"npm run test:full","test:unit":"mocha --require spec/config/setup --require spec/config/setup-unit spec/unit --recursive","test:integration":"mocha --require spec/config/setup spec/integration --recursive","test:end-to-end":"mocha --require spec/config/setup spec/end-to-end --recursive","test:browser":"if [ ! -f .disable-test-browser ]; then npm run build && npm run test:jasmine; fi","test:jasmine":"grunt jasmine","test:unit:es5":"export EXCEL_BUILD=es5 && npm run test:unit","test:integration:es5":"export EXCEL_BUILD=es5 && npm run test:integration","test:end-to-end:es5":"export EXCEL_BUILD=es5 && npm run test:end-to-end","test:dist":"mocha --require spec/config/setup spec/dist --recursive","test:manual":"node spec/manual/app.js","test:typescript":"mocha -r ts-node/register spec/typescript/**/*.spec.ts","clean-build":"npm run clean && npm run build","lint":"eslint --format node_modules/eslint-friendly-formatter .","lint:fix":"prettier-eslint --write $(pwd)'/**/*.js'","lint:staged":"lint-staged","clean":"rm -rf build/ && rm -rf dist","benchmark":"node --expose-gc benchmark","benchmark:debug":"node --expose-gc --inspect-brk --trace-deopt benchmark","build":"grunt build","install-build":"npm install && grunt build","preversion":"npm run clean && npm run build && npm run test:version","postversion":"git push --no-verify && git push --tags --no-verify"},"husky":{"hooks":{"pre-commit":"lint-staged"}},"lint-staged":{"*.js":["prettier-eslint --write","eslint --format node_modules/eslint-friendly-formatter","git add"]},"keywords":["xlsx","json","csv","excel","font","border","fill","number","format","number format","alignment","office","spreadsheet","workbook","defined names","data validations","rich text","in-cell format","outlineLevel","views","frozen","split","pageSetup"],"dependencies":{"archiver":"^5.0.0","dayjs":"^1.8.34","fast-csv":"^4.3.1","jszip":"^3.10.1","readable-stream":"^3.6.0","saxes":"^5.0.1","tmp":"^0.2.0","unzipper":"^0.10.11","uuid":"^8.3.0"},"devDependencies":{"@babel/cli":"^7.10.5","@babel/core":"^7.11.4","@babel/preset-env":"^7.11.0","@types/chai":"^4.2.12","@types/mocha":"^8.0.3","@types/node":"^14.11.2","babelify":"^10.0.0","browserify":"^16.5.2","chai":"^4.2.0","chai-datetime":"^1.7.0","chai-xml":"^0.3.2","core-js":"^3.6.5","dirty-chai":"^2.0.1","eslint":"^6.5.1","eslint-config-airbnb-base":"^14.2.0","eslint-config-prettier":"^6.12.0","eslint-friendly-formatter":"^4.0.1","eslint-plugin-import":"^2.22.0","eslint-plugin-node":"^11.1.0","express":"^4.16.4","got":"^9.0.0","grunt":"^1.3.0","grunt-babel":"^8.0.0","grunt-browserify":"^5.3.0","grunt-contrib-copy":"^1.0.0","grunt-contrib-jasmine":"^2.2.0","grunt-contrib-watch":"^1.1.0","grunt-exorcise":"^2.1.1","grunt-terser":"^1.0.0","husky":"^4.3.0","lint-staged":"^10.2.13","mocha":"^7.2.0","prettier-eslint":"^11.0.0","prettier-eslint-cli":"^5.0.0","regenerator-runtime":"^0.13.7","sax":"^1.2.4","ts-node":"^8.10.2","typescript":"^3.9.7"},"_lastModified":"2026-06-30T14:45:20.619Z"}
1
+ {"name":"exceljs","version":"4.4.0","description":"Excel Workbook Manager - Read and Write xlsx and csv Files.","private":false,"license":"MIT","author":{"name":"Guyon Roche","email":"guyon@live.com"},"repository":{"type":"git","url":"https://github.com/exceljs/exceljs.git"},"engines":{"node":">=8.3.0"},"main":"./excel.js","browser":"./dist/exceljs.min.js","types":"./index.d.ts","files":["dist","lib","excel.js","LICENSE","README.md","README_zh.md","index.ts","index.d.ts"],"scripts":{"test":"npm run test:full","test:es5":"export EXCEL_BUILD=es5 && npm run test:full","test:full":"npm run build && npm run test:unit && npm run test:integration && npm run test:end-to-end && npm run test:jasmine","test:version":"npm run build && npm run test:unit && npm run test:integration && npm run test:end-to-end && npm run test:browser && npm run test:dist","test:all":"npm run test:native && npm run test:es5","test:native":"npm run test:full","test:unit":"mocha --require spec/config/setup --require spec/config/setup-unit spec/unit --recursive","test:integration":"mocha --require spec/config/setup spec/integration --recursive","test:end-to-end":"mocha --require spec/config/setup spec/end-to-end --recursive","test:browser":"if [ ! -f .disable-test-browser ]; then npm run build && npm run test:jasmine; fi","test:jasmine":"grunt jasmine","test:unit:es5":"export EXCEL_BUILD=es5 && npm run test:unit","test:integration:es5":"export EXCEL_BUILD=es5 && npm run test:integration","test:end-to-end:es5":"export EXCEL_BUILD=es5 && npm run test:end-to-end","test:dist":"mocha --require spec/config/setup spec/dist --recursive","test:manual":"node spec/manual/app.js","test:typescript":"mocha -r ts-node/register spec/typescript/**/*.spec.ts","clean-build":"npm run clean && npm run build","lint":"eslint --format node_modules/eslint-friendly-formatter .","lint:fix":"prettier-eslint --write $(pwd)'/**/*.js'","lint:staged":"lint-staged","clean":"rm -rf build/ && rm -rf dist","benchmark":"node --expose-gc benchmark","benchmark:debug":"node --expose-gc --inspect-brk --trace-deopt benchmark","build":"grunt build","install-build":"npm install && grunt build","preversion":"npm run clean && npm run build && npm run test:version","postversion":"git push --no-verify && git push --tags --no-verify"},"husky":{"hooks":{"pre-commit":"lint-staged"}},"lint-staged":{"*.js":["prettier-eslint --write","eslint --format node_modules/eslint-friendly-formatter","git add"]},"keywords":["xlsx","json","csv","excel","font","border","fill","number","format","number format","alignment","office","spreadsheet","workbook","defined names","data validations","rich text","in-cell format","outlineLevel","views","frozen","split","pageSetup"],"dependencies":{"archiver":"^5.0.0","dayjs":"^1.8.34","fast-csv":"^4.3.1","jszip":"^3.10.1","readable-stream":"^3.6.0","saxes":"^5.0.1","tmp":"^0.2.0","unzipper":"^0.10.11","uuid":"^8.3.0"},"devDependencies":{"@babel/cli":"^7.10.5","@babel/core":"^7.11.4","@babel/preset-env":"^7.11.0","@types/chai":"^4.2.12","@types/mocha":"^8.0.3","@types/node":"^14.11.2","babelify":"^10.0.0","browserify":"^16.5.2","chai":"^4.2.0","chai-datetime":"^1.7.0","chai-xml":"^0.3.2","core-js":"^3.6.5","dirty-chai":"^2.0.1","eslint":"^6.5.1","eslint-config-airbnb-base":"^14.2.0","eslint-config-prettier":"^6.12.0","eslint-friendly-formatter":"^4.0.1","eslint-plugin-import":"^2.22.0","eslint-plugin-node":"^11.1.0","express":"^4.16.4","got":"^9.0.0","grunt":"^1.3.0","grunt-babel":"^8.0.0","grunt-browserify":"^5.3.0","grunt-contrib-copy":"^1.0.0","grunt-contrib-jasmine":"^2.2.0","grunt-contrib-watch":"^1.1.0","grunt-exorcise":"^2.1.1","grunt-terser":"^1.0.0","husky":"^4.3.0","lint-staged":"^10.2.13","mocha":"^7.2.0","prettier-eslint":"^11.0.0","prettier-eslint-cli":"^5.0.0","regenerator-runtime":"^0.13.7","sax":"^1.2.4","ts-node":"^8.10.2","typescript":"^3.9.7"},"_lastModified":"2026-07-02T03:47:49.149Z"}
@@ -10,6 +10,10 @@
10
10
  import { FindOptions, ICollection, ICollectionManager, IField, IModel, IRepository } from '@nocobase/data-source-manager';
11
11
  import EventEmitter from 'events';
12
12
  import { Logger } from '@nocobase/logger';
13
+ type FieldResolution = {
14
+ field?: IField;
15
+ collection?: ICollection;
16
+ };
13
17
  export type ExportOptions = {
14
18
  collectionManager: ICollectionManager;
15
19
  collection: ICollection;
@@ -45,11 +49,18 @@ declare abstract class BaseExporter<T extends ExportOptions = ExportOptions> ext
45
49
  private removePathAfterFileField;
46
50
  protected getAppendOptionsFromFields(ctx?: any): string[];
47
51
  protected getFindOptions(ctx?: any): any;
52
+ protected resolveFieldByDataIndex(dataIndex: Array<string>): FieldResolution;
48
53
  protected findFieldByDataIndex(dataIndex: Array<string>): IField;
49
54
  protected renderRawValue(value: any): any;
50
- protected getFieldRenderer(field?: IField, ctx?: any): (value: any) => any;
55
+ protected getFieldRenderer(field?: IField, ctx?: any, dataIndex?: Array<string>): (value: any) => any;
51
56
  protected formatValue(rowData: IModel, dataIndex: Array<string>, ctx?: any): any;
52
- protected normalizeRenderedValue(value: any, field?: IField): any;
57
+ protected normalizeRenderedValue(value: any, field?: IField, dataIndex?: Array<string>): any;
58
+ protected shouldExportAsText(field?: IField, dataIndex?: Array<string>): boolean;
59
+ protected isKeyField(field?: IField, dataIndex?: Array<string>): boolean;
60
+ protected getFieldCollection(field?: IField): ICollection | undefined;
61
+ protected isForeignKeyField(field?: IField): boolean;
62
+ protected normalizeTextCellValue(value: any): any;
63
+ protected shouldApplyTextCellFormat(value: any, field?: IField, dataIndex?: Array<string>): boolean;
53
64
  generateOutputPath(prefix?: string, ext?: string, destination?: string): string;
54
65
  }
55
66
  export { BaseExporter };
@@ -45,6 +45,54 @@ var import_path = __toESM(require("path"));
45
45
  var import_lodash = __toESM(require("lodash"));
46
46
  var import_database = require("@nocobase/database");
47
47
  var import_utils = require("@nocobase/utils");
48
+ const TEXT_EXPORT_INTERFACES = /* @__PURE__ */ new Set([
49
+ "attachmentURL",
50
+ "chinaRegion",
51
+ "code",
52
+ "input",
53
+ "textarea",
54
+ "richText",
55
+ "richtext",
56
+ "markdown",
57
+ "vditor",
58
+ "select",
59
+ "radio",
60
+ "radioGroup",
61
+ "multipleSelect",
62
+ "checkboxGroup",
63
+ "checkboxes",
64
+ "url",
65
+ "email",
66
+ "phone",
67
+ "password",
68
+ "color",
69
+ "icon",
70
+ "attachment"
71
+ ]);
72
+ const IDENTIFIER_EXPORT_INTERFACES = /* @__PURE__ */ new Set(["id", "uuid", "nanoid", "snowflakeId", "tableoid"]);
73
+ const NON_TEXT_EXPORT_INTERFACES = /* @__PURE__ */ new Set([
74
+ "boolean",
75
+ "checkbox",
76
+ "createdAt",
77
+ "date",
78
+ "datetime",
79
+ "datetimeNoTz",
80
+ "formula",
81
+ "integer",
82
+ "json",
83
+ "number",
84
+ "percent",
85
+ "time",
86
+ "unixTimestamp",
87
+ "updatedAt",
88
+ "sort",
89
+ "point",
90
+ "circle",
91
+ "polygon",
92
+ "lineString"
93
+ ]);
94
+ const TEXT_EXPORT_TYPES = /* @__PURE__ */ new Set(["string", "text", "uid", "uuid", "nanoid", "password"]);
95
+ const FORMULA_INJECTION_PREFIX_RE = /^\s*[=+\-@]/;
48
96
  class BaseExporter extends import_events.default {
49
97
  constructor(options) {
50
98
  super();
@@ -179,21 +227,26 @@ class BaseExporter extends import_events.default {
179
227
  }
180
228
  return findOptions;
181
229
  }
182
- findFieldByDataIndex(dataIndex) {
230
+ resolveFieldByDataIndex(dataIndex) {
183
231
  const { collection } = this.options;
184
- let currentField = collection.getField(dataIndex[0]);
232
+ let currentCollection = collection;
233
+ let currentField = currentCollection.getField(dataIndex[0]);
185
234
  if (dataIndex.length === 1) {
186
- return currentField;
235
+ return { field: currentField, collection: currentCollection };
187
236
  }
188
237
  let targetCollection = currentField.targetCollection();
189
238
  for (let i = 1; i < dataIndex.length; i++) {
239
+ currentCollection = targetCollection;
190
240
  currentField = targetCollection.getField(dataIndex[i]);
191
241
  const isLast = i === dataIndex.length - 1;
192
242
  if (!isLast && currentField instanceof import_database.RelationField) {
193
243
  targetCollection = currentField.targetCollection();
194
244
  }
195
245
  }
196
- return currentField;
246
+ return { field: currentField, collection: currentCollection };
247
+ }
248
+ findFieldByDataIndex(dataIndex) {
249
+ return this.resolveFieldByDataIndex(dataIndex).field;
197
250
  }
198
251
  renderRawValue(value) {
199
252
  if (typeof value === "object" && value !== null) {
@@ -201,23 +254,25 @@ class BaseExporter extends import_events.default {
201
254
  }
202
255
  return value;
203
256
  }
204
- getFieldRenderer(field, ctx) {
257
+ getFieldRenderer(field, ctx, dataIndex) {
205
258
  var _a;
206
259
  const InterfaceClass = this.options.collectionManager.getFieldInterface((_a = field == null ? void 0 : field.options) == null ? void 0 : _a.interface);
207
260
  if (!InterfaceClass) {
208
- return this.renderRawValue;
261
+ return (value) => {
262
+ return this.normalizeRenderedValue(this.renderRawValue(value), field, dataIndex);
263
+ };
209
264
  }
210
265
  const fieldInterface = new InterfaceClass(field == null ? void 0 : field.options);
211
266
  return (value) => {
212
267
  const renderedValue = fieldInterface.toString(value, ctx);
213
- return this.normalizeRenderedValue(renderedValue, field);
268
+ return this.normalizeRenderedValue(renderedValue, field, dataIndex);
214
269
  };
215
270
  }
216
271
  formatValue(rowData, dataIndex, ctx) {
217
272
  rowData = rowData.toJSON();
218
273
  const value = rowData[dataIndex[0]];
219
274
  const field = this.findFieldByDataIndex(dataIndex);
220
- const render = this.getFieldRenderer(field, ctx);
275
+ const render = this.getFieldRenderer(field, ctx, dataIndex);
221
276
  if (dataIndex.length > 1) {
222
277
  const deepValue = (0, import_deep_get.deepGet)(rowData, dataIndex);
223
278
  if (Array.isArray(deepValue)) {
@@ -227,7 +282,10 @@ class BaseExporter extends import_events.default {
227
282
  }
228
283
  return render(value);
229
284
  }
230
- normalizeRenderedValue(value, field) {
285
+ normalizeRenderedValue(value, field, dataIndex) {
286
+ if (this.shouldExportAsText(field, dataIndex)) {
287
+ return this.normalizeTextCellValue(value);
288
+ }
231
289
  if (!this.options.collectionManager.isNumericField(field)) {
232
290
  return value;
233
291
  }
@@ -246,6 +304,81 @@ class BaseExporter extends import_events.default {
246
304
  }
247
305
  return value;
248
306
  }
307
+ shouldExportAsText(field, dataIndex) {
308
+ var _a, _b, _c;
309
+ const fieldInterface = (_a = field == null ? void 0 : field.options) == null ? void 0 : _a.interface;
310
+ const fieldType = (_b = field == null ? void 0 : field.options) == null ? void 0 : _b.type;
311
+ const formulaDataType = (_c = field == null ? void 0 : field.options) == null ? void 0 : _c.dataType;
312
+ if (this.isKeyField(field, dataIndex)) {
313
+ return true;
314
+ }
315
+ if (this.isForeignKeyField(field)) {
316
+ return true;
317
+ }
318
+ if (fieldType === "formula") {
319
+ return formulaDataType === "string";
320
+ }
321
+ if (typeof fieldInterface === "string") {
322
+ if (TEXT_EXPORT_INTERFACES.has(fieldInterface) || IDENTIFIER_EXPORT_INTERFACES.has(fieldInterface)) {
323
+ return true;
324
+ }
325
+ if (NON_TEXT_EXPORT_INTERFACES.has(fieldInterface)) {
326
+ return false;
327
+ }
328
+ }
329
+ return typeof fieldType === "string" && TEXT_EXPORT_TYPES.has(fieldType);
330
+ }
331
+ isKeyField(field, dataIndex) {
332
+ var _a, _b, _c;
333
+ const fieldName = (_a = field == null ? void 0 : field.options) == null ? void 0 : _a.name;
334
+ if (!fieldName) {
335
+ return false;
336
+ }
337
+ const fieldCollection = dataIndex ? this.resolveFieldByDataIndex(dataIndex).collection : this.getFieldCollection(field);
338
+ const primaryKeyAttributes = (_b = fieldCollection == null ? void 0 : fieldCollection.model) == null ? void 0 : _b.primaryKeyAttributes;
339
+ if (Array.isArray(primaryKeyAttributes) && primaryKeyAttributes.includes(fieldName)) {
340
+ return true;
341
+ }
342
+ const filterTargetKey = fieldCollection == null ? void 0 : fieldCollection.filterTargetKey;
343
+ if (Array.isArray(filterTargetKey)) {
344
+ return filterTargetKey.includes(fieldName);
345
+ }
346
+ if (typeof filterTargetKey === "string" && filterTargetKey === fieldName) {
347
+ return true;
348
+ }
349
+ return ((_c = field.options) == null ? void 0 : _c.primaryKey) === true;
350
+ }
351
+ getFieldCollection(field) {
352
+ return field == null ? void 0 : field.collection;
353
+ }
354
+ isForeignKeyField(field) {
355
+ var _a;
356
+ const fieldName = (_a = field == null ? void 0 : field.options) == null ? void 0 : _a.name;
357
+ const fieldCollection = this.getFieldCollection(field);
358
+ if (!fieldName || !fieldCollection) {
359
+ return false;
360
+ }
361
+ return fieldCollection.getFields().some((candidate) => {
362
+ var _a2;
363
+ if (!candidate.isRelationField()) {
364
+ return false;
365
+ }
366
+ const relationForeignKey = candidate.foreignKey ?? ((_a2 = candidate.options) == null ? void 0 : _a2.foreignKey);
367
+ return relationForeignKey === fieldName;
368
+ });
369
+ }
370
+ normalizeTextCellValue(value) {
371
+ if (value == null || value === "") {
372
+ return value;
373
+ }
374
+ return String(value);
375
+ }
376
+ shouldApplyTextCellFormat(value, field, dataIndex) {
377
+ if (!this.shouldExportAsText(field, dataIndex) || value == null || value === "") {
378
+ return false;
379
+ }
380
+ return FORMULA_INJECTION_PREFIX_RE.test(String(value));
381
+ }
249
382
  generateOutputPath(prefix = "export", ext = "", destination = (0, import_utils.storagePathJoin)("tmp")) {
250
383
  const fileName = `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}${ext}`;
251
384
  return import_path.default.join(destination, fileName);
@@ -86,7 +86,14 @@ class XlsxExporter extends import_base_exporter.BaseExporter {
86
86
  const rowData = this.options.columns.map((col) => {
87
87
  return this.formatValue(row, col.dataIndex, ctx);
88
88
  });
89
- this.worksheet.addRow(rowData).commit();
89
+ const xlsxRow = this.worksheet.addRow(rowData);
90
+ this.options.columns.forEach((col, index) => {
91
+ const field = this.findFieldByDataIndex(col.dataIndex);
92
+ if (this.shouldApplyTextCellFormat(rowData[index], field, col.dataIndex)) {
93
+ xlsxRow.getCell(index + 1).numFmt = "@";
94
+ }
95
+ });
96
+ xlsxRow.commit();
90
97
  }
91
98
  async finalize() {
92
99
  await this.worksheet.commit();
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "description": "Export filtered records to excel, you can configure which fields to export.",
7
7
  "description.ru-RU": "Экспорт в Excel: можно настроить, какие поля будут экспортироваться.",
8
8
  "description.zh-CN": "导出筛选后的记录到 Excel 中,可以配置导出哪些字段。",
9
- "version": "2.1.15",
9
+ "version": "2.1.18",
10
10
  "license": "Apache-2.0",
11
11
  "main": "./dist/server/index.js",
12
12
  "homepage": "https://docs.nocobase.com/handbook/action-export",
@@ -40,7 +40,7 @@
40
40
  "@nocobase/test": "2.x",
41
41
  "@nocobase/utils": "2.x"
42
42
  },
43
- "gitHead": "1219585bbb4f5ebb6378be99fa2ff04b3376e6a2",
43
+ "gitHead": "2234b42b21c96d22a4b65a1f16a65ae61f434779",
44
44
  "keywords": [
45
45
  "Actions"
46
46
  ]