本文内容学习自 哲玄前端 《大前端全栈实践》课程
接第三章所述
{
// 2.1 当 moduleType == schema 时
schemaConfig: {
api: '', // 数据源 API (遵循 RESTFUL 规范)
schema: {
// 模块数据结构
type: 'object',
properties: {
prop: {
...schema, // 标准 schema 结构
type: '', // 字段类型
label: '', // 字段中文名
// 字段在 table 中的相关配置
tableOption: {},
// 字段在 search-bar 中的相关配置
searchOption: {},
// 字段在 create-form 中的相关配置
createFormOption: {
...elComponentConfig, // 标准 el-component 配置
componentType: '', // 配置组件类型, 枚举值: 'input' | 'input-number' | 'select'
visible: true, // 是否展示, 默认 true(false则不在表格展示)
disabled: false, // 是否禁用, 默认 false
default: '', // 默认值
// componentType === 'select' 时, 可填
enumList: [{ label: '', value: '' }], // 下拉框选项
},
// 字段在 edit-form 中的相关配置
editFormOption: {
...elComponentConfig, // 标准 el-component 配置
componentType: '', // 配置组件类型, 枚举值: 'input' | 'input-number' | 'select'
visible: true, // 是否展示, 默认 true(false则不在表格展示)
disabled: false, // 是否禁用, 默认 false
default: '', // 默认值
// componentType === 'select' 时, 可填
enumList: [{ label: '', value: '' }], // 下拉框选项
},
// 字段在 detail-panel 中的相关配置
detailPanelOption: {
...elComponentConfig, // 标准 el-component 配置
},
},
},
},
// table 相关配置
tableConfig: {
headerButtons: [
{
...elButtonConfig, // 标准 el-button 配置
label: '', // 按钮名称
eventKey: '', // 按钮事件名称
// 按钮具体配置
eventOption: {
// eventKey === 'showComponent'
componentName: '', // 可以填动态组件名称
},
},
],
rowButtons: [
{
...elButtonConfig, // 标准 el-button 配置
label: '', // 按钮名称
eventKey: '', // 按钮事件名称
// 按钮具体配置
eventOption: {
// eventKey === 'showComponent'
componentName: '', // 可以填动态组件名称
// eventKey === 'remove'
params: {
// paramKey 为参数的键值,
// rowValueKey 为参数值(格式为 schema::tableKey 时, 到 table 中找相应字段)
paramKey: rowValueKey,
},
},
},
],
},
// search-bar 相关配置
searchConfig: {},
// 动态组件相关配置
componentConfig: {
// create-form 相关配置
createForm: {
title: '', //表单标题
saveButtonText: '', // 保存按钮文案
},
// edit-form 相关配置
editForm: {
mainKey: '', // 表单主键, 唯一标识要修改的数据对象
title: '', //表单标题
saveButtonText: '', // 保存按钮文案
},
// detail-panel 相关配置
detailPanel: {
mainKey: '', // 表单主键, 唯一标识要修改的数据对象
title: '', //表单标题
},
},
},
},
字段在不同动态组件中的相关配置, Option前缀对应 componentConfig 中的键值
- 例如: componentOption.createFormOption, 字段中的配置就是 createFormOption
components = { componentKey: { schema: {}, config: {} } }
通过在DSL模板中添加 componentConfig,并且在字段中添加对应的 ${componentName}Option 配置(可以在buttons里面的 componentName 配置对应组件进行调用),再通过解析 schema hooks进行配置的具体解析获取到各个 option 和 config。
import { nextTick, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import { useMenuStore } from '$store/menu'
// 构建 schema 方法, 提取 {optionName}Option
const buildDtoSchema = (_schema, optionName) => {
if (!_schema.properties) return
const dtoSchema = {
type: 'object',
properties: {},
}
// 处理 required 字段
const required = new Set(_schema.required || [])
for (const prop in _schema.properties) {
const schemaProp = _schema.properties[prop]
if (schemaProp[`${optionName}Option`]) {
let dtoProp = {}
for (const key in schemaProp) {
if (key.endsWith('Option')) continue
dtoProp[key] = schemaProp[key]
}
dtoProp = Object.assign({}, dtoProp, { option: schemaProp[`${optionName}Option`] })
if (required.has(prop)) dtoProp.option.required = true
dtoSchema.properties[prop] = dtoProp
}
}
return dtoSchema
}
export const useSchema = () => {
const route = useRoute()
const menuStore = useMenuStore()
const api = ref('')
const tableSchema = ref({})
const tableConfig = ref()
const searchSchema = ref({})
const searchConfig = ref()
const components = ref({})
// 构造 schemaConfig 相关配置, 给 schema-view 解析
const buildData = () => {
// 先根据 sider_key, 再根据 key
const { key, sider_key } = route.query
const menuItem = menuStore.findMenuItem({
key: 'key',
value: sider_key ?? key,
})
if (menuItem && menuItem.schemaConfig) {
const { schemaConfig } = menuItem
const schema = JSON.parse(JSON.stringify(schemaConfig.schema))
api.value = schemaConfig.api ?? ''
// 先清空再赋值
tableSchema.value = {}
tableConfig.value = undefined
searchSchema.value = {}
searchConfig.value = undefined
components.value = {}
// nextTick 确保清空操作完成并等待一个 DOM 更新周期后, 再执行新数据的赋值
nextTick(() => {
// 构造 tableSchema, tableConfig
tableSchema.value = buildDtoSchema(schema, 'table')
tableConfig.value = schemaConfig.tableConfig
// 构造 searchSchema, searchConfig
const dtoSearchSchema = buildDtoSchema(schema, 'search')
for (const prop in dtoSearchSchema.properties) {
// 如果路由中存在该字段, 则设置默认值
if (route.query[prop] !== undefined) dtoSearchSchema.properties[prop].option.default = route.query[prop]
}
searchSchema.value = dtoSearchSchema
searchConfig.value = schemaConfig.searchConfig
// 构造 components = { componentKey: { schema: {}, config: {} } }
const { componentConfig } = schemaConfig
const componentKeys = Object.keys(componentConfig)
if (componentConfig && componentKeys.length > 0) {
components.value = componentKeys.reduce((dtoComponents, componentKey) => {
return {
...dtoComponents,
[componentKey]: {
schema: buildDtoSchema(schema, componentKey),
config: componentConfig[componentKey],
},
}
}, {})
}
})
}
}
buildData()
watch(
[() => route.query.key, () => route.query.sider_key, () => menuStore.menuList],
() => {
buildData()
},
{ deep: true }
)
return { api, tableConfig, tableSchema, searchConfig, searchSchema, components }
}
config 是针对整个组件的配置, 而 option 是针对字段在组件中的配置(hook 中的 schema),两者需要区分。