diff --git a/packages/plugins/@nocobase/plugin-action-import/src/server/__tests__/xlsx-importer.test.ts b/packages/plugins/@nocobase/plugin-action-import/src/server/__tests__/xlsx-importer.test.ts index 3f9b66379b8..e89658e7bf7 100644 --- a/packages/plugins/@nocobase/plugin-action-import/src/server/__tests__/xlsx-importer.test.ts +++ b/packages/plugins/@nocobase/plugin-action-import/src/server/__tests__/xlsx-importer.test.ts @@ -2299,6 +2299,63 @@ describe('basic importer', () => { expect(users[1].get('email')).toBe('test2@test.com'); }); + it('should generate different sort values for imported rows', async () => { + await app.destroy(); + app = await createMockServer({ + plugins: ['field-sort', 'data-source-main', 'error-handler'], + }); + + const Task = app.db.collection({ + name: 'tasks', + fields: [ + { + type: 'string', + name: 'name', + }, + { + type: 'sort', + name: 'sort', + }, + ], + }); + + await app.db.sync(); + + const columns = [ + { + dataIndex: ['name'], + defaultTitle: 'Name', + }, + ]; + + const templateCreator = new TemplateCreator({ + collection: Task, + columns, + }); + + const template = (await templateCreator.run({ returnXLSXWorkbook: true })) as XLSX.WorkBook; + const worksheet = template.Sheets[template.SheetNames[0]]; + + XLSX.utils.sheet_add_aoa(worksheet, [['task1'], ['task2'], ['task3']], { + origin: 'A2', + }); + + const importer = new XlsxImporter({ + collectionManager: app.mainDataSource.collectionManager, + collection: Task, + columns, + workbook: template, + }); + + await importer.run(); + + const tasks = await Task.repository.find({ + sort: ['id'], + }); + + expect(tasks.map((task) => task.get('sort'))).toEqual([1, 2, 3]); + }); + describe('template creator', () => { it('should create template with explain and field descriptions', async () => { const User = app.db.collection({ diff --git a/packages/plugins/@nocobase/plugin-field-sort/src/server/sort-field.ts b/packages/plugins/@nocobase/plugin-field-sort/src/server/sort-field.ts index d931670e166..f97b2db7745 100644 --- a/packages/plugins/@nocobase/plugin-field-sort/src/server/sort-field.ts +++ b/packages/plugins/@nocobase/plugin-field-sort/src/server/sort-field.ts @@ -24,33 +24,42 @@ export class SortField extends Field { const { model } = this.context.collection; instances = Array.isArray(instances) ? instances : [instances]; - for (const instance of instances) { - if (from == 'create' && isNumber(instance.get(name))) { - continue; - } - if (isNumber(instance.get(name)) && instance._previousDataValues[scopeKey] == instance[scopeKey]) { - continue; - } + await (this.constructor).lockManager.runExclusive( + this.context.collection.name, + async () => { + const maxCache = new Map(); - const where = {}; + for (const instance of instances) { + if (from == 'create' && isNumber(instance.get(name))) { + continue; + } + if (isNumber(instance.get(name)) && instance._previousDataValues[scopeKey] == instance[scopeKey]) { + continue; + } - if (scopeKey) { - const value = instance.get(scopeKey); - if (value !== undefined && value !== null) { - where[scopeKey] = value; - } - } + const where = {}; + let cacheKey = '__default__'; - await (this.constructor).lockManager.runExclusive( - this.context.collection.name, - async () => { - const max = await model.max(name, { ...options, where }); - const newValue = (max || 0) + 1; + if (scopeKey) { + const value = instance.get(scopeKey); + if (value !== undefined && value !== null) { + where[scopeKey] = value; + cacheKey = `${typeof value}:${String(value)}`; + } + } + + if (!maxCache.has(cacheKey)) { + const max = await model.max(name, { ...options, where }); + maxCache.set(cacheKey, max || 0); + } + + const newValue = (maxCache.get(cacheKey) ?? 0) + 1; + maxCache.set(cacheKey, newValue); instance.set(name, newValue); - }, - 2000, - ); - } + } + }, + 2000, + ); }; onScopeChange = async (instance, options) => {