diff --git a/packages/core/database/src/fields/number-field.ts b/packages/core/database/src/fields/number-field.ts index 4e65057c391..fed7655ef84 100644 --- a/packages/core/database/src/fields/number-field.ts +++ b/packages/core/database/src/fields/number-field.ts @@ -10,7 +10,7 @@ import { DataTypes } from 'sequelize'; import { BaseColumnFieldOptions, Field } from './field'; -abstract class NumberField extends Field {} +export abstract class NumberField extends Field {} export class IntegerField extends NumberField { get dataType() { diff --git a/packages/plugins/@nocobase/plugin-action-export/src/server/__tests__/export-to-xlsx.test.ts b/packages/plugins/@nocobase/plugin-action-export/src/server/__tests__/export-to-xlsx.test.ts index 152253fee0d..1068180ff53 100644 --- a/packages/plugins/@nocobase/plugin-action-export/src/server/__tests__/export-to-xlsx.test.ts +++ b/packages/plugins/@nocobase/plugin-action-export/src/server/__tests__/export-to-xlsx.test.ts @@ -31,6 +31,77 @@ describe('export to xlsx with preset', () => { await app.destroy(); }); + it('should export number field with cell format', async () => { + const Post = app.db.collection({ + name: 'posts', + fields: [ + { type: 'string', name: 'title' }, + { type: 'integer', name: 'integer' }, + { type: 'float', name: 'float' }, + ], + }); + + await app.db.sync(); + + await Post.repository.create({ + values: [ + { + title: 'p1', + integer: 123, + float: 123.456, + }, + { + title: 'p2', + integer: 456, + float: 456.789, + }, + ], + }); + + const exporter = new XlsxExporter({ + collectionManager: app.mainDataSource.collectionManager, + collection: Post, + chunkSize: 10, + columns: [ + { dataIndex: ['title'], defaultTitle: 'title' }, + { + dataIndex: ['integer'], + defaultTitle: 'integer', + }, + { + dataIndex: ['float'], + defaultTitle: 'float', + }, + ], + }); + + const wb = await exporter.run(); + const xlsxFilePath = path.resolve(__dirname, `t_${uid()}.xlsx`); + + try { + XLSX.writeFile(wb, xlsxFilePath); + + // read xlsx file + const workbook = XLSX.readFile(xlsxFilePath); + const firstSheet = workbook.Sheets[workbook.SheetNames[0]]; + + // cell type should be number + const cellA2 = firstSheet['A2']; + expect(cellA2.t).toBe('s'); + expect(cellA2.v).toBe('p1'); + + const cellB2 = firstSheet['B2']; + expect(cellB2.t).toBe('n'); + expect(cellB2.v).toBe(123); + + const cellC2 = firstSheet['C2']; + expect(cellC2.t).toBe('n'); + expect(cellC2.v).toBe(123.456); + } finally { + fs.unlinkSync(xlsxFilePath); + } + }); + it('should export with map field', async () => { const Post = app.db.collection({ name: 'posts', diff --git a/packages/plugins/@nocobase/plugin-action-export/src/server/xlsx-exporter.ts b/packages/plugins/@nocobase/plugin-action-export/src/server/xlsx-exporter.ts index ed941d14a13..fd153439488 100644 --- a/packages/plugins/@nocobase/plugin-action-export/src/server/xlsx-exporter.ts +++ b/packages/plugins/@nocobase/plugin-action-export/src/server/xlsx-exporter.ts @@ -18,6 +18,7 @@ import { import XLSX from 'xlsx'; import { deepGet } from './utils/deep-get'; +import { NumberField } from '@nocobase/database'; type ExportColumn = { dataIndex: Array; @@ -84,6 +85,23 @@ class XlsxExporter { }, }); + for (const col of columns) { + const field = this.findFieldByDataIndex(col.dataIndex); + if (field instanceof NumberField) { + // set column cell type to number + const colIndex = columns.indexOf(col); + const cellRange = XLSX.utils.decode_range(worksheet['!ref']); + + for (let r = 1; r <= cellRange.e.r; r++) { + const cell = worksheet[XLSX.utils.encode_cell({ c: colIndex, r })]; + // if cell and cell.v is a number, set cell.t to 'n' + if (cell && typeof cell.v === 'number') { + cell.t = 'n'; + } + } + } + } + XLSX.utils.book_append_sheet(workbook, worksheet, 'Data'); return workbook; }