diff --git a/packages/core/client/src/collection-manager/templates/components/PreviewTable.tsx b/packages/core/client/src/collection-manager/templates/components/PreviewTable.tsx index 02fd705f4..8be105ed0 100644 --- a/packages/core/client/src/collection-manager/templates/components/PreviewTable.tsx +++ b/packages/core/client/src/collection-manager/templates/components/PreviewTable.tsx @@ -6,6 +6,7 @@ import { EllipsisWithTooltip, useCompile } from '../../../'; import { useAPIClient } from '../../../api-client'; import { useCollectionManager } from '../../hooks/useCollectionManager'; +const mapFields = ['lineString', 'point', 'circle', 'polygon']; export const PreviewTable = (props) => { const { databaseView, schema, viewName, fields } = props; const [previewColumns, setPreviewColumns] = useState([]); @@ -20,7 +21,7 @@ export const PreviewTable = (props) => { if (databaseView) { getPreviewData(); } - }, [databaseView]); + }, [form.values.fields]); useEffect(() => { const pColumns = formatPreviewColumns(fields); @@ -28,10 +29,16 @@ export const PreviewTable = (props) => { }, [form.values.fields]); const getPreviewData = () => { + const fieldTypes = {}; + form.values.fields.map((v) => { + if (mapFields.includes(v.type)) { + fieldTypes[v.name] = v.type; + } + }); setLoading(true); api .resource(`dbViews`) - .query({ filterByTk: viewName, schema }) + .query({ filterByTk: viewName, schema, fieldTypes }) .then(({ data }) => { if (data) { setLoading(false); @@ -58,7 +65,13 @@ export const PreviewTable = (props) => { const objSchema: any = { type: 'object', properties: { - [item.name]: { ...schema, default: content, 'x-read-pretty': true, title: null }, + [item.name]: { + name: `${item.name}`, + 'x-component': schema && fieldSource ? 'CollectionField' : 'Input', + 'x-read-pretty': true, + 'x-collection-field': fieldSource?.join('.'), + default: content, + }, }, }; return ( @@ -98,7 +111,7 @@ export const PreviewTable = (props) => { columns={previewColumns} dataSource={previewData} scroll={{ x: 1000, y: 300 }} - key={viewName} + key={`${viewName}-preview`} /> )} diff --git a/packages/core/client/src/schema-component/antd/association-field/InternalViewer.tsx b/packages/core/client/src/schema-component/antd/association-field/InternalViewer.tsx index a3cc29695..ef039e817 100644 --- a/packages/core/client/src/schema-component/antd/association-field/InternalViewer.tsx +++ b/packages/core/client/src/schema-component/antd/association-field/InternalViewer.tsx @@ -27,7 +27,7 @@ export const ReadPrettyInternalViewer: React.FC = observer( (props: any) => { const fieldSchema = useFieldSchema(); const recordCtx = useRecord(); - const { enableLink } = fieldSchema['x-component-props']; + const { enableLink } = fieldSchema['x-component-props'] || {}; // value 做了转换,但 props.value 和原来 useField().value 的值不一致 const field = useField(); const fieldNames = useFieldNames(props); diff --git a/packages/plugins/collection-manager/src/server/__tests__/http-api/view-collection.test.ts b/packages/plugins/collection-manager/src/server/__tests__/http-api/view-collection.test.ts index 6cd240d77..8c9bb7d0e 100644 --- a/packages/plugins/collection-manager/src/server/__tests__/http-api/view-collection.test.ts +++ b/packages/plugins/collection-manager/src/server/__tests__/http-api/view-collection.test.ts @@ -1,4 +1,4 @@ -import { Database, Repository } from '@nocobase/database'; +import { Database, Repository, Field, DataTypes } from '@nocobase/database'; import { MockServer } from '@nocobase/test'; import { uid } from '@nocobase/utils'; import { createApp } from '../index'; @@ -54,6 +54,73 @@ SELECT * FROM numbers; await app.destroy(); }); + it('should support preview field with getter', async () => { + class TestField extends Field { + get dataType() { + return DataTypes.STRING; + } + + constructor(options: any, context: any) { + const { name } = options; + super( + { + get() { + return 'test_' + this.getDataValue(name); + }, + ...options, + }, + context, + ); + } + } + + db.registerFieldTypes({ + test: TestField, + }); + + const C1 = db.collection({ + name: 'c1', + fields: [ + { + type: 'test', + name: 'test_field', + }, + ], + }); + + await db.sync(); + + await C1.repository.create({ + values: { + test_field: '1', + }, + }); + + const c1 = await C1.repository.findOne(); + expect(c1.get('test_field')).toEqual('test_1'); + + // create view from C1 + const viewName = `test_view_${uid(6)}`; + await db.sequelize.query(`DROP VIEW IF EXISTS ${viewName}`); + + const createSQL = `CREATE VIEW ${viewName} AS SELECT * FROM ${C1.quotedTableName()}`; + + await db.sequelize.query(createSQL); + + const response = await agent.resource('dbViews').query({ + filterByTk: viewName, + pageSize: 20, + fieldTypes: { + test_field: 'test', + }, + }); + + expect(response.status).toBe(200); + const data = response.body.data; + const firstRow = data[0]; + expect(firstRow.test_field).toEqual('test_1'); + }); + it('should list views', async () => { const response = await agent.resource('dbViews').list(); expect(response.status).toBe(200); diff --git a/packages/plugins/collection-manager/src/server/__tests__/view/view-collection.test.ts b/packages/plugins/collection-manager/src/server/__tests__/view/view-collection.test.ts index 80d1fa8b9..90c3413a1 100644 --- a/packages/plugins/collection-manager/src/server/__tests__/view/view-collection.test.ts +++ b/packages/plugins/collection-manager/src/server/__tests__/view/view-collection.test.ts @@ -1,4 +1,4 @@ -import Database, { Repository, ViewCollection, ViewFieldInference } from '@nocobase/database'; +import Database, { Field, Repository, ViewCollection, ViewFieldInference, DataTypes } from '@nocobase/database'; import Application from '@nocobase/server'; import { uid } from '@nocobase/utils'; import { createApp } from '../index'; diff --git a/packages/plugins/collection-manager/src/server/resourcers/views.ts b/packages/plugins/collection-manager/src/server/resourcers/views.ts index 6e1c9a866..ea0294127 100644 --- a/packages/plugins/collection-manager/src/server/resourcers/views.ts +++ b/packages/plugins/collection-manager/src/server/resourcers/views.ts @@ -56,7 +56,7 @@ export default { }, async query(ctx, next) { - const { filterByTk, schema = 'public', page = 1, pageSize = 10 } = ctx.action.params; + const { filterByTk, fieldTypes, schema = 'public', page = 1, pageSize = 10 } = ctx.action.params; const offset = (page - 1) * pageSize; const limit = 1 * pageSize; @@ -66,7 +66,34 @@ export default { ctx.app.db.utils.addSchema(filterByTk, schema), )} LIMIT ${limit} OFFSET ${offset}`; - ctx.body = await ctx.app.db.sequelize.query(sql, { type: 'SELECT' }); + const rawValues = await ctx.app.db.sequelize.query(sql, { type: 'SELECT' }); + + if (fieldTypes) { + for (const raw of rawValues) { + const fakeInstance = { + dataValues: raw, + getDataValue: (key) => raw[key], + }; + + for (const fieldName of Object.keys(fieldTypes)) { + const fieldType = fieldTypes[fieldName]; + const FieldClass = ctx.app.db.fieldTypes.get(fieldType); + + const fieldOptions = new FieldClass( + { name: fieldName }, + { + db: ctx.app.db, + }, + ).options; + + if (fieldOptions.get) { + const newValue = fieldOptions.get.apply(fakeInstance); + raw[fieldName] = newValue; + } + } + } + } + ctx.body = rawValues; await next(); }, },