diff --git a/packages/app/package.json b/packages/app/package.json index 3c5f31d70..291169823 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -30,6 +30,7 @@ "@nocobase/database": "^0.3.0-alpha.0", "@nocobase/father-build": "^0.3.0-alpha.0", "@nocobase/plugin-action-logs": "^0.3.0-alpha.0", + "@nocobase/plugin-china-region": "^0.3.0-alpha.0", "@nocobase/plugin-collections": "^0.3.0-alpha.0", "@nocobase/plugin-pages": "^0.3.0-alpha.0", "@nocobase/server": "^0.3.0-alpha.0", diff --git a/packages/app/src/api/app.ts b/packages/app/src/api/app.ts index 9542a1c02..129e09954 100644 --- a/packages/app/src/api/app.ts +++ b/packages/app/src/api/app.ts @@ -68,5 +68,6 @@ api.registerPlugin('plugin-users', [path.resolve(__dirname, '../../../plugin-use api.registerPlugin('plugin-file-manager', [path.resolve(__dirname, '../../../plugin-file-manager'), {}]); api.registerPlugin('plugin-permissions', [path.resolve(__dirname, '../../../plugin-permissions'), {}]); api.registerPlugin('plugin-automations', [path.resolve(__dirname, '../../../plugin-automations'), {}]); +api.registerPlugin('plugin-china-region', [path.resolve(__dirname, '../../../plugin-china-region'), {}]); export default api; diff --git a/packages/app/src/api/migrations/add-china-region-data.ts b/packages/app/src/api/migrations/add-china-region-data.ts new file mode 100644 index 000000000..4497f58fe --- /dev/null +++ b/packages/app/src/api/migrations/add-china-region-data.ts @@ -0,0 +1,13 @@ +import { init } from '@nocobase/plugin-china-region/src/db/seeders'; +import api from '../app'; + +(async () => { + await api.loadPlugins(); + await api.database.sync(); + await init(api); +})().then(() => { + process.exit(0); +}).catch(err => { + console.error(err); + process.exit(1); +}); diff --git a/packages/app/src/api/migrations/init.ts b/packages/app/src/api/migrations/init.ts index fda913996..24c2fd149 100644 --- a/packages/app/src/api/migrations/init.ts +++ b/packages/app/src/api/migrations/init.ts @@ -6,8 +6,9 @@ global.sync = { }, }; -import api from '../app'; import Database from '@nocobase/database'; +import { init as chinaRegionSeederInit } from '@nocobase/plugin-china-region/src/db/seeders'; +import api from '../app'; const data = [ { @@ -234,6 +235,9 @@ const data = [ await Action.bulkCreate([ ]); + // 导入地域数据 + await chinaRegionSeederInit(api); + await database.getModel('collections').import(require('./collections/example').default); await database.getModel('collections').import(require('./collections/authors').default); await database.getModel('collections').import(require('./collections/books').default); diff --git a/packages/app/src/components/form.fields/cascader/index.tsx b/packages/app/src/components/form.fields/cascader/index.tsx new file mode 100644 index 000000000..1f094399b --- /dev/null +++ b/packages/app/src/components/form.fields/cascader/index.tsx @@ -0,0 +1,125 @@ +import React, { useEffect, useState } from 'react'; +import { connect } from '@formily/react-schema-renderer' +import { Cascader as AntdCascader } from 'antd' +import { useRequest } from 'umi'; +import api from '@/api-client'; +import { + transformDataSourceKey, + mapStyledProps, + mapTextComponent +} from '../shared' + +function findTreeNode(tree, values, { value = 'value', children = 'children' }) { + let node, i; + for (node = tree, i = 0; node && values[i]; i++ ) { + node = (node[children] || []).find(item => item[value] === values[i][value]); + } + + return node; +} + +export const Cascader = connect({ + getProps: mapStyledProps, + getComponent: mapTextComponent, +})(function (props) { + const { + disabled, + target, + labelField, + valueField = 'id', + parentField, + maxLevel, + changeOnSelect, + value = [], + onChange, + // TODO(feature): 增加静态数据支持 + // dataSource: [] + } = props; + const fieldNames = { + label: labelField, + value: valueField, + children: 'children' + }; + const [options, setOptions] = useState([]); + + const { loading, run } = useRequest(async (selectedOptions = []) => { + if (maxLevel != null && selectedOptions.length >= maxLevel) { + return; + } + + const last = selectedOptions[selectedOptions.length - 1] || null; + if (last) { + if (last.isLeaf) { + return; + } + last.loading = true; + } + + return api.resource(target).list({ + filter: { + [parentField]: last && last[valueField] + }, + perPage: -1, + sort: [valueField] + }); + // TODO(bug): 关联资源加载问题较多,暂时先用 filter 解决 + // return api.resource(`${target}.${target}`).list({ + // associatedKey: last, + // perPage: -1 + // }); + }, { + manual: true, + onSuccess(result, [selectedOptions = []]) { + if (!result) { + return; + } + + const data = result.map(item => ({ + ...item, + isLeaf: maxLevel != null && item.level >= maxLevel + })); + // 找到已有值指向的 options 节点 + const root = { [fieldNames.children]: options }; + const node = findTreeNode(root, selectedOptions, fieldNames); + + if (node && node !== root) { + node.children = data; + node.loading = false; + // use spread array to avoid popup to be collapsed + setOptions([...options]); + } else { + setOptions(data); + } + } + }); + + // 根据 value 的值,按需预加载相应的数据 + useEffect(() => { + if (value.length) { + value.reduce((promise, option, i) => promise.then(() => run(value.slice(0, i))), Promise.resolve()); + } else { + run([]); + } + }, []); + + return ( + item[valueField])} + onChange={(v, selected) => { + if (maxLevel != null && v.length < maxLevel) { + run(selected); + } + if (changeOnSelect || !v.length || v.length >= maxLevel) { + onChange(selected); + } + }} + loadData={run} + changeOnSelect={changeOnSelect} + fieldNames={fieldNames} + /> + ); +}) + +export default Cascader diff --git a/packages/app/src/components/form.fields/cascader/style.ts b/packages/app/src/components/form.fields/cascader/style.ts new file mode 100644 index 000000000..56cdb0607 --- /dev/null +++ b/packages/app/src/components/form.fields/cascader/style.ts @@ -0,0 +1 @@ +import 'antd/lib/cascader/style/index' diff --git a/packages/app/src/components/form.fields/registry.ts b/packages/app/src/components/form.fields/registry.ts index f6295c39b..192938940 100644 --- a/packages/app/src/components/form.fields/registry.ts +++ b/packages/app/src/components/form.fields/registry.ts @@ -17,6 +17,7 @@ import { Filter } from './filter' import { RemoteSelect } from './remote-select' import { DrawerSelect } from './drawer-select' import { SubTable } from './sub-table' +import { Cascader } from './cascader' import { Icon } from './icons' import { ColorSelect } from './color-select' import { Permissions } from './permissions' @@ -29,6 +30,7 @@ export const setup = () => { time: TimePicker, timerange: TimePicker.RangePicker, transfer: Transfer, + cascader: Cascader, boolean: Checkbox, switch: Switch, checkbox: Checkbox, diff --git a/packages/app/src/components/form.fields/shared.tsx b/packages/app/src/components/form.fields/shared.tsx index a85ae71b8..f3106654d 100644 --- a/packages/app/src/components/form.fields/shared.tsx +++ b/packages/app/src/components/form.fields/shared.tsx @@ -44,12 +44,12 @@ const createEnum = (enums: any) => { } export const Select: React.FC = styled((props: SelectProps) => { - const { dataSource = [], onChange, value, ...others } = props + const { dataSource = [], onChange, value, ...others } = props; const children = createEnum(dataSource).map(item => { - const { label, value, children = [], ...others } = item + const { label, value, key, children = [], ...others } = item; if (children.length) { return ( - + {children.map(({value, label, ...others}: any) => ( {data[labelField]} - { e.stopPropagation(); }} className={'noco-drawer'} - bodyStyle={{padding: 0}} + bodyStyle={{padding: 0}} width={'40%'} title={`查看${title}详情`} visible={visible} @@ -361,20 +361,34 @@ export function AttachmentFieldItem(props: any) { ); } -function LogField(props) { +export function LogField(props) { const { value = {} } = props; return (
{value.title||value.name}
) } -function LogFieldValue(props) { +export function LogFieldValue(props) { const { value, schema, data } = props; return (
{JSON.stringify(value)}
) } +export function ChinaRegion(props: any) { + const { schema, value } = props; + if (!value) { + return null; + } + const values = (Array.isArray(value) ? value : [value]) + .sort((a, b) => a.level !== b.level ? a.level - b.level : a.sort - b.sort); + return ( +
+ {values.map(item => item.name).join('/')} +
+ ); +} + registerFieldComponents({ string: StringField, textarea: TextareaField, @@ -396,6 +410,7 @@ registerFieldComponents({ attachment: AttachmentField, 'logs.field': LogField, 'logs.fieldValue': LogFieldValue, + chinaRegion: ChinaRegion, }); export default function Field(props: any) { diff --git a/packages/plugin-china-region/package.json b/packages/plugin-china-region/package.json new file mode 100644 index 000000000..733eb80e1 --- /dev/null +++ b/packages/plugin-china-region/package.json @@ -0,0 +1,10 @@ +{ + "name": "@nocobase/plugin-china-region", + "version": "0.3.0-alpha.0", + "main": "lib/index.js", + "license": "MIT", + "dependencies": { + "@nocobase/database": "^0.3.0-alpha.0", + "china-division": "2.3.1" + } +} diff --git a/packages/plugin-china-region/src/collections/china_regions.ts b/packages/plugin-china-region/src/collections/china_regions.ts new file mode 100644 index 000000000..18eed590b --- /dev/null +++ b/packages/plugin-china-region/src/collections/china_regions.ts @@ -0,0 +1,47 @@ +import { TableOptions } from '@nocobase/database'; + +export default { + name: 'china_regions', + title: '中国行政区划', + internal: true, + developerMode: true, + fields: [ + // 如使用代码作为 id 可能更节省,但由于代码数字最长为 12 字节,除非使用 bigint(64) 才够放置 + { + name: 'code', + title: '代码', + interface: 'string', + type: 'string', + unique: true, + }, + { + name: 'name', + title: '名称', + interface: 'string', + type: 'string', + }, + { + name: 'parent', + title: '从属', + interface: 'linkTo', + type: 'belongsTo', + target: 'china_regions', + targetKey: 'code', + foreignKey: 'parent_code', + }, + { + name: 'children', + title: '下辖', + interface: 'linkTo', + type: 'hasMany', + target: 'china_regions', + sourceKey: 'code', + foreignKey: 'parent_code' + }, + { + name: 'level', + title: '层级', + type: 'integer' + } + ] +} as TableOptions; diff --git a/packages/plugin-china-region/src/db/seeders/index.ts b/packages/plugin-china-region/src/db/seeders/index.ts new file mode 100644 index 000000000..63ffc9d14 --- /dev/null +++ b/packages/plugin-china-region/src/db/seeders/index.ts @@ -0,0 +1 @@ +export { default as init } from './init'; diff --git a/packages/plugin-china-region/src/db/seeders/init.ts b/packages/plugin-china-region/src/db/seeders/init.ts new file mode 100644 index 000000000..126a683a9 --- /dev/null +++ b/packages/plugin-china-region/src/db/seeders/init.ts @@ -0,0 +1,47 @@ +import { provinces, cities, areas, streets, villages } from 'china-division'; + +export default async function({ database }) { + const Model = database.getModel('china_regions'); + // TODO(feature): 可以考虑再加一级大区,编码规则应该是支持的 + // 华北、东北、华东、华南、西南、西北、华中 + const timer = Date.now(); + + await Model.bulkCreate(provinces.map(item => ({ + code: item.code, + name: item.name, + level: 1 + }))); + + await Model.bulkCreate(cities.map(item => ({ + code: item.code, + name: item.name, + level: 2, + parent_code: item.provinceCode + }))); + + await Model.bulkCreate(areas.map(item => ({ + code: item.code, + name: item.name, + level: 3, + parent_code: item.cityCode + }))); + + // 乡级数据 2856 条 + await Model.bulkCreate(streets.map(item => ({ + code: item.code, + name: item.name, + level: 4, + parent_code: item.areaCode + }))); + + // 村级数据 658001 条 + await Model.bulkCreate(villages.map(item => ({ + code: item.code, + name: item.name, + level: 5, + parent_code: item.streetCode + }))); + + const count = await Model.count(); + console.log(`${count} rows of region data imported in ${(Date.now() - timer) / 1000}s`); +}; diff --git a/packages/plugin-china-region/src/server.ts b/packages/plugin-china-region/src/server.ts new file mode 100644 index 000000000..6de78467d --- /dev/null +++ b/packages/plugin-china-region/src/server.ts @@ -0,0 +1,18 @@ +import path from 'path'; +// import actions from '@nocobase/actions'; + +// 不从主入口导出,考虑到加载的数据量太大比较占内存,只在迁移时处理 +// export * as seeders from './db/seeders'; + +export default async function (options = {}) { + const { database, resourcer } = this; + + database.import({ + directory: path.resolve(__dirname, 'collections'), + }); + + // resourcer.define({ + // name: 'china_regions.china_regions', + // actions: actions.common + // }); +} diff --git a/packages/plugin-collections/src/__tests__/models/field.test.ts b/packages/plugin-collections/src/__tests__/models/field.test.ts index 606b1500f..a38f9d854 100644 --- a/packages/plugin-collections/src/__tests__/models/field.test.ts +++ b/packages/plugin-collections/src/__tests__/models/field.test.ts @@ -1,7 +1,6 @@ import { Agent, getAgent, getApp } from '../'; import { Application } from '@nocobase/server'; -import { options, types } from '../../interfaces'; -import { FieldModel } from '../../models'; +import { types } from '../../interfaces'; describe('models.field', () => { let app: Application; diff --git a/packages/plugin-collections/src/collections/fields.ts b/packages/plugin-collections/src/collections/fields.ts index 154e216fd..604adf7bc 100644 --- a/packages/plugin-collections/src/collections/fields.ts +++ b/packages/plugin-collections/src/collections/fields.ts @@ -1,5 +1,5 @@ import { TableOptions } from '@nocobase/database'; -import { options } from '../interfaces'; +import { types, getOptions } from '../interfaces'; export default { name: 'fields', @@ -57,7 +57,7 @@ export default { name: 'interface', title: '字段类型', required: true, - dataSource: options, + dataSource: getOptions(), createOnly: true, component: { type: 'select', @@ -65,6 +65,17 @@ export default { showInDetail: true, showInForm: true, "x-linkages": [ + // TODO(draft): 统一解决字段类型和配置参数联动的一种方式 + // { + // type: 'value:schema', + // target: 'options', + // schema: { + // 'x-component-props': { + // fields: '{{ $self.values[1].fields || [] }}' + // } + // }, + // condition: '{{ !!$self.value }}' + // }, { "type": "value:visible", "target": "precision", @@ -130,9 +141,31 @@ export default { "target": "required", "condition": "{{ ['createdAt', 'updatedAt', 'createdBy', 'updatedBy'].indexOf($self.value) === -1 }}" }, + { + "type": "value:visible", + "target": "maxLevel", + "condition": "{{ ['chinaRegion'].includes($self.value) }}" + }, + { + "type": "value:visible", + "target": "incompletely", + "condition": "{{ ['chinaRegion'].includes($self.value) }}" + }, ], }, }, + // TODO(draft): 将 options 作为集合字段开放出来,可以动态的解决字段参数的配置表单联动问题 + // { + // interface: 'json', + // type: 'json', + // name: 'options', + // title: '配置信息', + // defaultValue: {}, + // component: { + // type: 'subFields', + // showInForm: true, + // }, + // }, { interface: 'subTable', type: 'virtual', @@ -250,6 +283,33 @@ export default { default: 'HH:mm:ss', }, }, + // TODO(refactor): 此部分类型相关的参数,后期应拆分出去 + { + name: 'maxLevel', + title: '可选层级', + interface: 'radio', + type: 'virtual', + dataSource: [ + { value: 1, label: '省' }, + { value: 2, label: '市' }, + { value: 3, label: '区/县' }, + { value: 4, label: '乡镇/街道' }, + { value: 5, label: '村/居委会' }, + ], + component: { + showInForm: true, + default: 3 + } + }, + { + name: 'incompletely', + title: '可部分选择', + interface: 'boolean', + type: 'virtual', + component: { + showInForm: true, + } + }, { interface: 'linkTo', multiple: false, diff --git a/packages/plugin-collections/src/interfaces/index.ts b/packages/plugin-collections/src/interfaces/index.ts index e5d02ce3b..9909dd66a 100644 --- a/packages/plugin-collections/src/interfaces/index.ts +++ b/packages/plugin-collections/src/interfaces/index.ts @@ -4,90 +4,44 @@ import * as types from './types'; export * as types from './types'; -export const options = [ - { - key: 'basic', - title: '基本类型', - children: [ - types.string, - types.textarea, - types.phone, - types.email, - types.number, - types.percent, - ], - }, - { - key: 'media', - title: '多媒体类型', - children: [ - types.wysiwyg, - types.attachment, - ], - }, - { - key: 'choices', - title: '选择类型', - children: [ - types.boolean, - types.select, - types.multipleSelect, - types.radio, - types.checkboxes, - ], - }, - { - key: 'datetime', - title: '日期和时间', - children: [ - types.datetime, - types.time, - ], - }, - { - key: 'relation', - title: '关系类型', - children: [ - types.subTable, - types.linkTo, - ], - }, - { - key: 'systemInfo', - title: '系统信息', - children: [ - types.createdAt, - types.updatedAt, - types.createdBy, - types.updatedBy, - ], - }, - { - key: 'developerMode', - title: '开发者模式', - children: [ - types.primaryKey, - types.sort, - types.password, - types.json, - types.icon, - ], - }, - { - key: 'others', - title: '其他', - children: [ - types.description, - ], - } -].map(({key, title, children}: any) => ({ - key, - label: title, - children: children.map(child => ({ - label: child.title, - value: child.options.interface, - disabled: child.disabled, - })), -})); +export const groupLabelMap = { + basic: '基本类型', + media: '多媒体类型', + choices: '选择类型', + datetime: '日期和时间', + relation: '关系类型', + systemInfo: '关系类型', + developerMode: '开发者模式', + others: '其他' +}; -export default options; +export function getOptions() { + return Object.keys(groupLabelMap).map(key => ({ + key, + label: groupLabelMap[key], + children: Object.values(types) + .filter(type => type['group'] === key) + .map(type => ({ + label: type.title, + value: type.options.interface, + // TODO(draft): 配置信息一并存到数据库方便字段配置时取出参与联动计算 + // properties: type.properties, + disabled: type['disabled'], + })) + })); +} + +export type interfaceType = { + title: string, + group?: string, + options: { + [key: string]: any + }, + disabled?: boolean +}; + +// TODO(draft) +// 目前仅在内存中注册,应用启动时需要解决扩展字段读取并注册到内存 +export function register(type: interfaceType) { + types[type.options.interface] = type; +} diff --git a/packages/plugin-collections/src/interfaces/types.ts b/packages/plugin-collections/src/interfaces/types.ts index 138a2019f..c7a52586b 100644 --- a/packages/plugin-collections/src/interfaces/types.ts +++ b/packages/plugin-collections/src/interfaces/types.ts @@ -7,6 +7,7 @@ // TODO: interface 的修改 export const string = { title: '单行文本', + group: 'basic', options: { interface: 'string', type: 'string', @@ -19,6 +20,7 @@ export const string = { export const textarea = { title: '多行文本', + group: 'basic', options: { interface: 'textarea', type: 'text', @@ -31,6 +33,7 @@ export const textarea = { export const phone = { title: '手机号码', + group: 'basic', options: { interface: 'phone', type: 'string', @@ -45,6 +48,7 @@ export const phone = { export const email = { title: '邮箱', + group: 'basic', options: { interface: 'email', type: 'string', @@ -62,6 +66,7 @@ export const email = { */ export const number = { title: '数字', + group: 'basic', options: { interface: 'number', type: 'float', @@ -80,6 +85,7 @@ export const number = { */ export const percent = { title: '百分比', + group: 'basic', options: { interface: 'percent', type: 'float', @@ -94,6 +100,7 @@ export const percent = { export const wysiwyg = { title: '可视化编辑器', + group: 'media', disabled: true, options: { interface: 'wysiwyg', @@ -109,6 +116,7 @@ export const wysiwyg = { */ export const attachment = { title: '附件', + group: 'media', // disabled: true, options: { interface: 'attachment', @@ -129,6 +137,7 @@ export const attachment = { */ export const select = { title: '下拉选择(单选)', + group: 'choices', options: { interface: 'select', type: 'string', @@ -152,6 +161,7 @@ export const select = { */ export const multipleSelect = { title: '下拉选择(多选)', + group: 'choices', options: { interface: 'multipleSelect', type: 'json', // json 过滤 @@ -167,6 +177,7 @@ export const multipleSelect = { export const radio = { title: '单选框', + group: 'choices', options: { interface: 'radio', type: 'string', @@ -180,6 +191,7 @@ export const radio = { export const checkboxes = { title: '多选框', + group: 'choices', options: { interface: 'checkboxes', type: 'json', @@ -194,6 +206,7 @@ export const checkboxes = { export const boolean = { title: '是/否', + group: 'choices', options: { interface: 'boolean', type: 'boolean', @@ -210,6 +223,7 @@ export const boolean = { */ export const datetime = { title: '日期', + group: 'datetime', options: { interface: 'datetime', type: 'date', @@ -222,10 +236,34 @@ export const datetime = { type: 'date', }, }, + // TODO(draft): 配置参数的一种描述方式 + // properties: [ + // { + // name: 'showTime', + // title: '显示时间', + // interface: 'boolean', + // component: { + // 'x-linkages': [ + // { + // type: 'value:visible', + // target: 'timeFormat', + // condition: '{{ $value }}' + // } + // ] + // } + // }, + // { + // interface: 'string', + // name: 'timeFormat', + // title: '时间格式', + // filterable: false + // } + // ] }; export const time = { title: '时间', + group: 'datetime', options: { interface: 'time', type: 'time', @@ -275,6 +313,7 @@ export const time = { // }); export const subTable = { title: '子表格', + group: 'relation', // disabled: true, options: { interface: 'subTable', @@ -329,6 +368,7 @@ export const subTable = { export const linkTo = { title: '关联数据', + group: 'relation', // disabled: true, options: { interface: 'linkTo', @@ -346,6 +386,7 @@ export const linkTo = { export const createdAt = { title: '创建时间', + group: 'systemInfo', options: { interface: 'createdAt', type: 'date', @@ -365,6 +406,7 @@ export const createdAt = { export const updatedAt = { title: '修改时间', + group: 'systemInfo', options: { interface: 'updatedAt', type: 'date', @@ -384,6 +426,7 @@ export const updatedAt = { export const createdBy = { title: '创建人', + group: 'systemInfo', // disabled: true, options: { interface: 'createdBy', @@ -402,6 +445,7 @@ export const createdBy = { export const updatedBy = { title: '修改人', + group: 'systemInfo', // disabled: true, options: { interface: 'updatedBy', @@ -438,6 +482,7 @@ export const group = { export const description = { title: '说明文字', + group: 'others', options: { interface: 'description', // name: 'id', @@ -453,6 +498,7 @@ export const description = { */ export const primaryKey = { title: '主键', + group: 'developerMode', options: { interface: 'primaryKey', name: 'id', @@ -474,6 +520,7 @@ export const primaryKey = { */ export const sort = { title: '排序', + group: 'developerMode', options: { interface: 'sort', type: 'integer', @@ -487,6 +534,7 @@ export const sort = { export const password = { title: '密码', + group: 'developerMode', options: { interface: 'password', type: 'password', @@ -499,6 +547,7 @@ export const password = { export const json = { title: 'JSON', + group: 'developerMode', options: { interface: 'json', type: 'json', @@ -512,6 +561,7 @@ export const json = { export const icon = { title: '图标', + group: 'developerMode', options: { interface: 'icon', type: 'string', @@ -520,3 +570,32 @@ export const icon = { }, }, }; + +export const chinaRegion = { + title: '中国行政区划', + group: 'choices', + options: { + interface: 'chinaRegion', + type: 'belongsToMany', + // 数据来源的数据表,与 dataSource 不同,需要从表数据加载后转化成 dataSource + target: 'china_regions', + targetKey: 'code', + // 值字段 + // valueField: 'code', + // 名称字段 + labelField: 'name', + // TODO(refactor): 等 toWhere 重构完成后要改成 parent + // 上级字段名 + parentField: 'parent_code', + // 深度限制,默认:-1(代表不控制,即如果是数据表,则无限加载) + // limit: -1, + // 可选层级,默认:-1(代表可选的最深层级) + // maxLevel: null, + // 是否可以不选择到最深一级 + // 'x-component-props': { changeOnSelect: true } + incompletely: false, + component: { + type: 'cascader', + } + } +}; diff --git a/packages/plugin-pages/src/actions/getView.ts b/packages/plugin-pages/src/actions/getView.ts index 475533a46..d7ebb09ac 100644 --- a/packages/plugin-pages/src/actions/getView.ts +++ b/packages/plugin-pages/src/actions/getView.ts @@ -152,6 +152,14 @@ const transforms = { if (['radio', 'select', 'multipleSelect', 'checkboxes'].includes(interfaceType)) { prop.enum = field.get('dataSource'); } + if (interfaceType === 'chinaRegion') { + set(prop, 'x-component-props.target', field.get('target')); + set(prop, 'x-component-props.labelField', field.get('labelField')); + set(prop, 'x-component-props.valueField', field.get('targetKey')); + set(prop, 'x-component-props.parentField', field.get('parentField')); + set(prop, 'x-component-props.maxLevel', field.get('maxLevel')); + set(prop, 'x-component-props.changeOnSelect', field.get('incompletely')); + } schema[field.name] = { id: field.id, ...prop, @@ -362,7 +370,7 @@ export default async (ctx, next) => { } for (const field of fields) { - if (!['subTable', 'linkTo', 'attachment', 'createdBy', 'updatedBy'].includes(field.get('interface'))) { + if (!['subTable', 'linkTo', 'attachment', 'createdBy', 'updatedBy', 'chinaRegion'].includes(field.get('interface'))) { continue; } let showInKey;