前面介绍了如何使用中国
的城市
数据字典,在这里我们再讲述如何实现国家
和城市
的数据联动。具体而言,当用户选择了美国
,就显示美国的城市
数据字典;选择了中国
,就显示中国的城市
数据字典
1. 前端表单渲染
1.1 JSON Schema配置
为了实现数据联动,我们需要实现一个自定义渲染组件,首先修改一下JSON Schema
的配置:
src/suite-vendor/test-party/modules/test-party/backend/src/config/validation/schema/party.js
- 1const moduleInfo = app.meta.mockUtil.parseInfoFromPackage(__dirname);
- 2schemas.party = {
- 3 type: 'object',
- 4 properties: {
- 5 ...
- 6 partyCity: {
- 7 type: 'string',
- 8 ebType: 'component',
- 9 ebTitle: 'Party City',
- 10 ebRender: {
- 11 module: moduleInfo.relativeName,
- 12 name: 'renderPartyCity',
- 13 },
- 14 ebParams: {
- 15 separator: '/',
- 16 leafOnly: true,
- 17 },
- 18 },
- 19 ...
- 20 },
- 21 };
名称 | 说明 |
---|---|
type | 字段类型 |
ebType | 字段渲染类型,用于标示前端渲染组件类型。component 是使用自定义渲染组件 |
ebTitle | 字段标题,用于前端渲染,支持国际化 |
ebRender | 自定义渲染组件的信息 |
ebParams | 渲染参数,具体内容由渲染组件决定 |
- ebRender
名称 | 说明 |
---|---|
module | 自定义渲染组件所属的模块名称,可以通过moduleInfo.relativeName 动态获取当前模块名称,在这里的值就是test-party |
name | 自定义渲染组件的名称 |
- ebParams
名称 | 说明 |
---|---|
separator | 多级字典项的title 在合并时所采用的分隔符 |
leafOnly | 当选择字典项时,是否只能选择叶子结点 |
1.2 定义渲染组件
关于前端自定义组件的概念,请参见:模块前端开发-Component
src/suite-vendor/test-party/modules/test-party/front/src/components/renderPartyCity.jsx
- 1export default {
- 2 props: {
- 3 context: {
- 4 type: Object,
- 5 },
- 6 },
- 7 data() {
- 8 return {};
- 9 },
- 10 watch: {
- 11 partyCountry() {
- 12 this.context.setValue(null);
- 13 },
- 14 },
- 15 computed: {
- 16 partyCountry() {
- 17 return this.context.getValue('partyCountry');
- 18 },
- 19 },
- 20 created() {},
- 21 methods: {},
- 22 render() {
- 23 const { parcel, key, property } = this.context;
- 24 // only support 1/86
- 25 const partyCountry = this.partyCountry;
- 26 if (partyCountry !== '1' && partyCountry !== '86') return null;
- 27 // render
- 28 const propertyNew = this.$meta.util.extend({}, property, {
- 29 ebType: 'dict',
- 30 ebParams: {
- 31 dictKey: partyCountry === '1' ? 'a-dictbooster:citiesUSA' : 'a-dictbooster:citiesChina',
- 32 mode: 'tree',
- 33 },
- 34 ebRender: null,
- 35 });
- 36 return <eb-list-item-validate parcel={parcel} dataKey={key} property={propertyNew}></eb-list-item-validate>;
- 37 },
- 38};
-
行3:由于该组件是在表单渲染时使用的,因此表单渲染引擎会向该组件传入
prop: context
。通过context
,既可以取得当前字段的信息,也可以取得表单渲染引擎的信息 -
行16:创建一个
计算属性:
partyCountry
,该属性的值可以通过context
动态获取 -
行11:创建一个
watch: partyCountry
,当计算属性partyCountry
变更时清除当前城市的值 -
行25/26:取得当前
partyCountry
的值。出于演示目的,只支持美国
和中国
-
行28:根据
partyCountry
的当前值,使用不同的dictKey
,与字段的property
进行合并,从而产生新的property
-
行36:使用新的
property
配置重新渲染当前字段。其中,eb-list-item-validate
是CabloyJS前端的内置组件
1.3 注册渲染组件
由于前面定义的渲染组件renderPartyCity.jsx
在模块test-party
中,为了让表单渲染引擎可以找到该组件,需要在模块的components
清单中注册
src/suite-vendor/test-party/modules/test-party/front/src/components.js
- 1import renderPartyCity from './components/renderPartyCity.jsx';
- 2
- 3export default {
- 4 renderPartyCity,
- 5};
2. 后端code/title转换
2.1 meta配置
由于城市
的数据字典是不固定的,因此需要禁用
系统默认的转换逻辑,而由我们自行转换,需要在宴会
的meta
信息中配置一下:
src/suite-vendor/test-party/modules/test-party/backend/src/meta.js
- 1 base: {
- 2 atoms: {
- 3 party: {
- 4 info: {
- 5 ...
- 6 dict: {
- 7 fields: {
- 8 ...
- 9 partyCity: {
- 10 translate: false,
- 11 },
- 12 ...
- 13 },
- 14 },
- 15 },
- 16 },
- 17 },
- 18 },
- dict.fields.partyCity
名称 | 说明 |
---|---|
translate | 设置为false ,从而禁用系统默认的转换逻辑 |
2.2 code/title转换
我们知道,用户查看宴会列表
或者宴会条目
最终都会执行后端的方法ctx.bean.atom.select
和ctx.bean.atom.read
。而这两个方法最终会调用指定原子类型bean组件中的方法:select/read
。因此,我们需要在这两个方法中进行code/title
转换
src/suite-vendor/test-party/modules/test-party/backend/src/bean/atom.party.js
- 1module.exports = app => {
- 2 class Atom extends app.meta.AtomCmsBase {
- 3 ...
- 4 async read({ atomClass, options, key, user }) {
- 5 // super
- 6 const item = await super.read({ atomClass, options, key, user });
- 7 if (!item) return null;
- 8 // read
- 9 await this._translate(item);
- 10 await this._getMeta(item, options);
- 11 // ok
- 12 return item;
- 13 }
- 14
- 15 async select({ atomClass, options, items, user }) {
- 16 // super
- 17 await super.select({ atomClass, options, items, user });
- 18 // select
- 19 for (const item of items) {
- 20 await this._translate(item);
- 21 await this._getMeta(item, options);
- 22 }
- 23 }
- 24 ...
- 25 async _translate(item) {
- 26 // dictKey
- 27 const partyCountry = item.partyCountry;
- 28 if (partyCountry !== '1' && partyCountry !== '86') return;
- 29 const dictKey = partyCountry === '1' ? 'a-dictbooster:citiesUSA' : 'a-dictbooster:citiesChina';
- 30 // code
- 31 const code = item.partyCity;
- 32 if (!code) return;
- 33 // findItem
- 34 const res = await this.ctx.bean.dict.findItem({
- 35 dictKey,
- 36 code,
- 37 options: { separator: '/' },
- 38 });
- 39 if (res) {
- 40 item._partyCityTitle = res.titleFull;
- 41 item._partyCityTitleLocale = res.titleLocaleFull;
- 42 }
- 43 }
- 44 ...
- 45 }
- 46
- 47 return Atom;
- 48};
-
行10:read调用
this._getMeta
-
行21:select调用
this._getMeta
-
行29:根据
partyCountry
的当前值使用不同的城市
数据字典 -
行34:调用
this.ctx.bean.dict.findItem
获取对应字典项的信息 -
行40/41:将
title
的完整路径和国际化值写入数据,从而完成code/title
转换
3. 前端显示Title
由于我们前面自行完成的code/title
转换,向数据注入值的规则与系统默认的一致,因此在前端显示title
的逻辑也没有变化。故从略
评论: