* Copyright (c) 2023 - present TinyEngine Authors.
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
import { getController } from '../render'
const NAME_PREFIX = {
loop: 'loop',
table: 'getTableData',
page: 'pageConfig',
grid: 'tinyGrid',
tree: 'tinyTree',
select: 'tinySelect'
}
const genRemoteMethodToLifeSetup = (variableName, sourceRef, pageSchema) => {
if (sourceRef.value.data?.option) {
const setupFn = pageSchema.lifeCycles?.setup?.value
const fetchBody = `
this.state.${variableName} = []
this.dataSourceMap.${sourceRef.value.name}.load().then(data=>{ this.state.${variableName}=data })`
if (!setupFn) {
pageSchema.lifeCycles = pageSchema.lifeCycles || {}
pageSchema.lifeCycles.setup = {
type: 'JSFunction',
value: `function setup({ props, state, watch, onMounted }) {${fetchBody}}`
}
} else {
pageSchema.lifeCycles.setup.value = setupFn.trim().replace(/\}$/, fetchBody + '}')
}
}
}
const removeState = (pageSchema, variableName) => {
delete pageSchema.state[variableName]
const { parse, traverse, generate } = getController().ast
const setupFn = pageSchema.lifeCycles?.setup?.value
try {
const ast = parse(setupFn)
traverse(ast, {
ExpressionStatement(path) {
if (path.toString().includes(variableName)) {
path.remove()
}
}
})
pageSchema.lifeCycles.setup.value = generate(ast).code
} catch (error) {
}
}
const setStateWithSourceRef = (pageSchema, variableName, sourceRef, data) => {
pageSchema.state[variableName] = data
if (sourceRef.value.data?.option?.isSync) {
genRemoteMethodToLifeSetup(variableName, sourceRef, pageSchema)
}
}
const defaultHandlerTemplate = ({ node, sourceRef, schemaId, pageSchema }) => {
const genVarName = (schemaId) => `${NAME_PREFIX.loop}${schemaId}`
const updateNode = () => {
const { configure } = getController().getMaterial(node?.componentName)
if (!configure?.loop) {
return
}
const variableName = genVarName(schemaId)
setStateWithSourceRef(pageSchema, variableName, sourceRef, sourceRef.value.data?.data)
node.loop = {
type: 'JSExpression',
value: `this.state.${variableName}`
}
}
const clearBindVar = () => {
const variableName = genVarName(schemaId)
removeState(pageSchema, variableName)
}
return {
updateNode,
clearBindVar
}
}
const generateAssignColumns = (newColumns, oldColumns) => {
newColumns.forEach((item) => {
const targetColumn = oldColumns.find((value) => value.field === item.field)
if (targetColumn) {
Object.assign(item, targetColumn)
}
})
return newColumns
}
const askShouldImportData = ({ node, sourceRef, updateKey }) => {
const { publish } = getController().useMessage()
getController()
.useModal()
.confirm({
message: '检测到表格存在配置的数据,是否需要引入?',
exec() {
try {
const sourceColumns = sourceRef.value?.data?.columns?.map(({ title, field }) => ({ title, field })) || []
node.props.columns = generateAssignColumns(sourceColumns, node.props.columns)
publish({ topic: 'schemaChange', data: {} })
updateKey.value++
} catch (error) {
getController().useNotify({
type: 'error',
message: '引入配置数据失败'
})
}
},
cancel() {
node.props.columns = [...(sourceRef.value.data?.columns || [])]
publish({ topic: 'schemaChange', data: {} })
}
})
}
const updateNodeHandler = ({ node, sourceRef, pageSchema, sourceName, methodName, updateKey }) => {
if (!node || !node.props || !sourceName) {
return
}
delete node?.props?.data
if (node.props.columns.length) {
askShouldImportData({ node, sourceRef, updateKey })
} else {
node.props.columns = [...(sourceRef.value.data?.columns || [])]
}
const pageConfig = {
attrs: {
currentPage: 1,
pageSize: 50,
pageSizes: [10, 20, 50],
total: 0,
layout: 'sizes,total, prev, pager, next, jumper'
}
}
node.props.pager = pageConfig
pageSchema.methods[methodName] = {
type: 'JSFunction',
value: `function ${methodName}({ page, sort, sortBy, filters}) {
/**
* @param {Object} sort 排序数据
* @param {Array} sortBy 排序方式
* @param {Object} page 分页数据
* @param {Array} filters 筛选数据
* @returns {Object} 返回一个promise对象,并且resolve格式为{ result: Array, page: { total: Number } }
*/
return new Promise((resolve, reject) => {
this.dataSourceMap.${sourceName}.load().then((res) => {
// 如果按照数据源面板的建议格式编写dataHandler
// 那么dataSourceMap的res格式应该是:{ code: string, msg: string, data: {items: any[], total: number} }
resolve({ result: res?.data?.items || res?.data?.data || res?.data, page: { total: res?.data?.total || res?.data?.data?.length || res?.data?.length } });
});
});
}`
}
}
const extraHandlerMap = {
TinyGrid: ({ node, sourceRef, schemaId, pageSchema, updateKey }) => {
const sourceName = sourceRef.value?.name
const methodName = `${NAME_PREFIX.table}${schemaId}`
node.props.fetchData = {
type: 'JSExpression',
value: `{ api: this.${methodName} }`
}
const updateNode = () => updateNodeHandler({ node, sourceRef, pageSchema, sourceName, methodName, updateKey })
const clearBindVar = () => {
delete pageSchema.methods[methodName]
}
return {
updateNode,
clearBindVar
}
},
TinyTree: ({ node, sourceRef, schemaId, pageSchema }) => {
const genVarName = (schemaId) => `${NAME_PREFIX.tree}${schemaId}`
const updateNode = () => {
const variableName = genVarName(schemaId)
const arrayToTree = (data) => {
const map = {}
const tree = []
let node = null
let i = 0
for (i = 0; i < data.length; i++) {
map[data[i].id] = data[i]
data[i].children = []
}
for (i = 0; i < data.length; i++) {
node = data[i]
if (node.pid !== '') {
map[node.pid]?.children?.push(node)
} else {
tree.push(node)
}
}
return tree
}
setStateWithSourceRef(pageSchema, variableName, sourceRef, arrayToTree(sourceRef.value.data?.data))
node.props.data = {
type: 'JSExpression',
value: `this.state.${variableName}`
}
}
const clearBindVar = () => {
const variableName = genVarName(schemaId)
removeState(pageSchema, variableName)
}
return {
updateNode,
clearBindVar
}
},
TinySelect: ({ node, sourceRef, schemaId, pageSchema }) => {
const genVarName = (schemaId) => `${NAME_PREFIX.select}${schemaId}`
const updateNode = () => {
const variableName = genVarName(schemaId)
setStateWithSourceRef(pageSchema, variableName, sourceRef, sourceRef.value.data?.data)
node.props.options = {
type: 'JSExpression',
value: `this.state.${variableName}`
}
}
const clearBindVar = () => {
const variableName = genVarName(schemaId)
removeState(pageSchema, variableName)
}
return {
updateNode,
clearBindVar
}
}
}
export const getHandler = ({ node, sourceRef, schemaId, pageSchema, updateKey }) =>
extraHandlerMap[node.componentName]
? extraHandlerMap[node.componentName]({ node, sourceRef, schemaId, pageSchema, updateKey })
: defaultHandlerTemplate({ node, sourceRef, schemaId, pageSchema })