From 573f1a2c17b7e7bd8fce7280d84a01892d2d8ae9 Mon Sep 17 00:00:00 2001 From: roymondchen Date: Mon, 21 Aug 2023 16:57:18 +0800 Subject: [PATCH] =?UTF-8?q?feat(cli,data-source,editor,playground,runtime)?= =?UTF-8?q?:=20=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 - packages/cli/src/Core.ts | 4 + packages/cli/src/types.ts | 12 +- packages/cli/src/utils/prepareEntryFile.ts | 36 +- packages/cli/src/utils/resolveAppPackages.ts | 327 +++++++++++------- packages/data-source/src/DataSourceManager.ts | 12 +- packages/editor/src/editorProps.ts | 33 +- packages/editor/src/initService.ts | 33 ++ .../data-source/DataSourceConfigPanel.vue | 12 +- packages/editor/src/services/dataSource.ts | 17 +- packages/editor/src/services/props.ts | 4 +- packages/editor/src/type.ts | 7 +- .../src/utils/data-source/formConfigs/base.ts | 65 ++-- .../editor/src/utils/data-source/index.ts | 18 +- playground/src/pages/Editor.vue | 14 +- pnpm-lock.yaml | 9 + runtime/react/build.vite.config.ts | 28 +- runtime/react/package.json | 14 +- runtime/react/page/main.tsx | 7 + runtime/react/playground/main.tsx | 6 + runtime/vue2/build.vite.config.ts | 30 +- runtime/vue2/package.json | 14 +- runtime/vue2/page/main.ts | 22 +- runtime/vue2/playground/main.ts | 11 +- runtime/vue3/build.vite.config.ts | 30 +- runtime/vue3/package.json | 14 +- runtime/vue3/page/main.ts | 6 + runtime/vue3/playground/main.ts | 11 +- 28 files changed, 528 insertions(+), 269 deletions(-) diff --git a/package.json b/package.json index d7ee57a4..167279b7 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "playground:react": "pnpm --filter \"runtime-react\" --filter \"tmagic-playground\" dev:react", "pg:react": "pnpm playground:react", "build": "pnpm --filter \"@tmagic/*\" build", - "build:runtime:admin": "pnpm --filter \"runtime-*\" build:admin", "build:playground": "pnpm --filter \"runtime-vue3\" build && pnpm --filter \"tmagic-playground\" build", "docs:dev": "vitepress dev docs", "docs:serve": "vitepress serve docs", diff --git a/packages/cli/src/Core.ts b/packages/cli/src/Core.ts index 27ee792a..0a8f350a 100644 --- a/packages/cli/src/Core.ts +++ b/packages/cli/src/Core.ts @@ -16,6 +16,10 @@ export default class Core { configMap: {}, valueMap: {}, eventMap: {}, + datasourceMap: {}, + dsConfigMap: {}, + dsValueMap: {}, + dsEventMap: {}, }; public dir = { diff --git a/packages/cli/src/types.ts b/packages/cli/src/types.ts index 53add63b..bfd90658 100644 --- a/packages/cli/src/types.ts +++ b/packages/cli/src/types.ts @@ -5,15 +5,20 @@ export type App = Core; export enum EntryType { CONFIG = 'config', VALUE = 'value', - COMPONENT = 'component', EVENT = 'event', + COMPONENT = 'component', PLUGIN = 'plugin', + DS_CONFIG = 'dsConfig', + DS_VALUE = 'dsValue', + DS_EVENT = 'dsEvent', + DATASOURCE = 'datasource', } export enum PackageType { COMPONENT = '1', PLUGIN = '2', COMPONENT_PACKAGE = '3', + DATASOURCE = '4', } export interface Entry { @@ -21,6 +26,7 @@ export interface Entry { [EntryType.VALUE]?: string; [EntryType.COMPONENT]?: string; [EntryType.EVENT]?: string; + [EntryType.DATASOURCE]?: string; } export interface OptionEntry { @@ -52,6 +58,10 @@ export interface ModuleMainFilePath { configMap: Record; valueMap: Record; eventMap: Record; + datasourceMap: Record; + dsConfigMap: Record; + dsValueMap: Record; + dsEventMap: Record; } export interface UserConfig { diff --git a/packages/cli/src/utils/prepareEntryFile.ts b/packages/cli/src/utils/prepareEntryFile.ts index d9b615aa..8ac4e187 100644 --- a/packages/cli/src/utils/prepareEntryFile.ts +++ b/packages/cli/src/utils/prepareEntryFile.ts @@ -4,39 +4,49 @@ import type App from '../Core'; import { EntryType } from '../types'; export const prepareEntryFile = async (app: App) => { - const { componentMap = {}, pluginMap = {}, configMap = {}, valueMap = {}, eventMap = {} } = app.moduleMainFilePath; - const { componentFileAffix, dynamicImport, hooks, useTs } = app.options; + const { moduleMainFilePath, options } = app; + const { componentFileAffix, dynamicImport, hooks, useTs } = options; let contentMap: Record = { - 'comp-entry': generateContent(useTs, EntryType.COMPONENT, componentMap, componentFileAffix), - 'async-comp-entry': generateContent(useTs, EntryType.COMPONENT, componentMap, componentFileAffix, dynamicImport), - 'plugin-entry': generateContent(useTs, EntryType.PLUGIN, pluginMap), - 'async-plugin-entry': generateContent(useTs, EntryType.PLUGIN, pluginMap, '', dynamicImport), - 'config-entry': generateContent(useTs, EntryType.CONFIG, configMap), - 'value-entry': generateContent(useTs, EntryType.VALUE, valueMap), - 'event-entry': generateContent(useTs, EntryType.EVENT, eventMap), + 'comp-entry': generateContent(useTs, EntryType.COMPONENT, moduleMainFilePath.componentMap, componentFileAffix), + 'async-comp-entry': generateContent( + useTs, + EntryType.COMPONENT, + moduleMainFilePath.componentMap, + componentFileAffix, + dynamicImport, + ), + 'plugin-entry': generateContent(useTs, EntryType.PLUGIN, moduleMainFilePath.pluginMap), + 'async-plugin-entry': generateContent(useTs, EntryType.PLUGIN, moduleMainFilePath.pluginMap, '', dynamicImport), + 'config-entry': generateContent(useTs, EntryType.CONFIG, moduleMainFilePath.configMap), + 'value-entry': generateContent(useTs, EntryType.VALUE, moduleMainFilePath.valueMap), + 'event-entry': generateContent(useTs, EntryType.EVENT, moduleMainFilePath.eventMap), + 'datasource-entry': generateContent(useTs, EntryType.DATASOURCE, moduleMainFilePath.datasourceMap), + 'ds-config-entry': generateContent(useTs, EntryType.DS_CONFIG, moduleMainFilePath.dsConfigMap), + 'ds-value-entry': generateContent(useTs, EntryType.DS_VALUE, moduleMainFilePath.dsValueMap), + 'ds-event-entry': generateContent(useTs, EntryType.DS_EVENT, moduleMainFilePath.dsEventMap), }; if (typeof hooks?.beforeWriteEntry === 'function') { contentMap = await hooks.beforeWriteEntry(contentMap, app); } - Object.keys(contentMap).forEach((file: string) => { + Object.entries(contentMap).forEach(([file, content]) => { let fileName = `${file}.ts`; if (useTs) { - app.writeTemp(fileName, contentMap[file]); + app.writeTemp(fileName, content); } else { fileName = `${file}.js`; app.writeTemp(`${file}.d.ts`, `const type: Record;\n\nexport default type;`); } - app.writeTemp(fileName, contentMap[file]); + app.writeTemp(fileName, content); }); }; const generateContent = ( useTs: boolean, type: EntryType, - map: Record, + map: Record = {}, componentFileAffix = '', dynamicImport = false, ) => { diff --git a/packages/cli/src/utils/resolveAppPackages.ts b/packages/cli/src/utils/resolveAppPackages.ts index 6d267309..215365a0 100644 --- a/packages/cli/src/utils/resolveAppPackages.ts +++ b/packages/cli/src/utils/resolveAppPackages.ts @@ -6,134 +6,34 @@ import fs from 'fs-extra'; import * as recast from 'recast'; import type App from '../Core'; -import { Entry, EntryType, ModuleMainFilePath, NpmConfig, PackageType } from '../types'; +import { EntryType, ModuleMainFilePath, NpmConfig, PackageType } from '../types'; import { error, execInfo, info } from './logger'; + +type Ast = any; + interface TypeAssertion { type: string; imports: any[]; } interface ParseEntryOption { - ast: any; + ast: Ast; package: string; indexPath: string; } +interface TypeAssertionOption { + ast: Ast; + indexPath: string; + componentFileAffix?: string; +} + +const isFile = (filePath: string) => fs.existsSync(filePath) && fs.lstatSync(filePath).isFile(); +const isDirectory = (filePath: string) => fs.existsSync(filePath) && fs.lstatSync(filePath).isDirectory(); + const getRelativePath = (str: string, base: string) => (path.isAbsolute(str) ? path.relative(base, str) : str); -export const resolveAppPackages = (app: App): ModuleMainFilePath => { - const componentMap: Record = {}; - const configMap: Record = {}; - const eventMap: Record = {}; - const valueMap: Record = {}; - const pluginMap: Record = {}; - - const dependencies: Record = {}; - - const setPackages = (cwd: string, tmp: string, packagePath: string, key?: string) => { - const { name: moduleName } = splitNameVersion(packagePath); - - if (!moduleName) throw Error('packages中包含非法配置'); - - const indexPath = execSync(`node -e "console.log(require.resolve('${moduleName.replace(/\\/g, '/')}'))"`, { cwd }) - .toString() - .replace('\n', ''); - const indexCode = fs.readFileSync(indexPath, { encoding: 'utf-8', flag: 'r' }); - const ast = recast.parse(indexCode, { parser: require('recast/parsers/typescript') }); - const result = typeAssertion({ ast, indexPath }); - - const setItem = (key: string, entry: Entry) => { - if (entry.component) componentMap[key] = getRelativePath(entry.component, tmp); - if (entry.config) configMap[key] = getRelativePath(entry.config, tmp); - if (entry.event) eventMap[key] = getRelativePath(entry.event, tmp); - if (entry.value) valueMap[key] = getRelativePath(entry.value, tmp); - }; - - if (result.type === PackageType.COMPONENT && key) { - // 组件 - setItem(key, parseEntry({ ast, package: moduleName, indexPath })); - } else if (result.type === PackageType.PLUGIN && key) { - // 插件 - pluginMap[key] = moduleName; - } else if (result.type === PackageType.COMPONENT_PACKAGE) { - // 组件&插件包 - result.imports.forEach((i) => { - const affixReg = new RegExp(`${app.options.componentFileAffix}$`); - if (affixReg.test(i.indexPath)) { - componentMap[i.type] = i.indexPath; - return; - } - const indexCode = fs.readFileSync(i.indexPath, { encoding: 'utf-8', flag: 'r' }); - const ast = recast.parse(indexCode, { parser: require('recast/parsers/typescript') }); - if (typeAssertion({ ast, indexPath }).type === PackageType.PLUGIN) { - // 插件 - pluginMap[i.type] = i.indexPath; - } else { - // 组件 - setItem(i.type, parseEntry({ ast, package: `${module} | ${i.name}`, indexPath: i.indexPath })); - } - }); - } - }; - - const getDependencies = (packagePath: string) => { - if (fs.existsSync(packagePath)) return; - const { name: moduleName, version } = splitNameVersion(packagePath); - if (!moduleName) return; - dependencies[moduleName] = version; - }; - - const { packages = [], npmConfig = {} } = app.options; - - packages.forEach((item) => { - if (typeof item === 'object') { - Object.entries(item).forEach(([, packagePath]) => { - getDependencies(packagePath); - }); - } else { - getDependencies(item); - } - }); - - if (npmConfig.autoInstall && Object.keys(dependencies).length) { - if (!npmConfig.keepPackageJsonClean) { - npmInstall(dependencies, app.options.source, app.options.npmConfig); - } else { - const packageFile = path.join(app.options.source, 'package.json'); - const packageBakFile = path.join(app.options.source, 'package.json.bak'); - if (fs.existsSync(packageFile)) { - fs.copyFileSync(packageFile, packageBakFile); - } - - npmInstall(dependencies, app.options.source, app.options.npmConfig); - - if (fs.existsSync(packageBakFile)) { - fs.unlinkSync(packageFile); - fs.renameSync(packageBakFile, packageFile); - } - } - } - - packages.forEach((item) => { - if (typeof item === 'object') { - Object.entries(item).forEach(([key, packagePath]) => { - setPackages(app.options.source, app.options.temp, packagePath, key); - }); - } else { - setPackages(app.options.source, app.options.temp, item); - } - }); - - return { - componentMap, - configMap, - eventMap, - valueMap, - pluginMap, - }; -}; - const npmInstall = function (dependencies: Record, cwd: string, npmConfig: NpmConfig = {}) { try { const { client = 'npm', registry } = npmConfig; @@ -162,28 +62,52 @@ const npmInstall = function (dependencies: Record, cwd: string, }; /** - * 1 判断是否组件&插件包 - * 2 判断是组件还是插件 - * 3 组件插件分开写入 comp-entry.ts + * 1 判断是否组件&插件&数据源包 + * 2 判断是组件还是插件还是数据源 + * 3 组件插件数据源分开写入 comp-entry.ts + * + * export default 是对象字面量并且有install方法则为插件 + * + * export default 是类并且superClass为DataSource则为数据源 + * + * 其他情况为组件或者包 + * * @param {*} ast * @param {String} indexPath * @return {Object} { type: '', imports: [] } 返回传入组件的类型。如果是组件包,imports 中包含所有子组件的入口文件路径 */ -const typeAssertion = function ({ ast, indexPath }: { ast: any; indexPath: string }): TypeAssertion { +const typeAssertion = function ({ ast, indexPath, componentFileAffix }: TypeAssertionOption): TypeAssertion { const n = recast.types.namedTypes; - const result = { + const result: TypeAssertion = { type: '', imports: [], }; - const { importDeclarations, variableDeclarations, exportDefaultName, exportDefaultNode } = + const { importDeclarations, variableDeclarations, exportDefaultName, exportDefaultNode, exportDefaultClass } = getAssertionTokenByTraverse(ast); if (exportDefaultName) { importDeclarations.every((node) => { const [specifier] = node.specifiers; + const defaultFile = getIndexPath(path.resolve(path.dirname(indexPath), node.source.value)); + if (componentFileAffix && !['.js', '.ts'].includes(componentFileAffix)) { + if (node.source.value?.endsWith(componentFileAffix) || isFile(`${defaultFile}${componentFileAffix}`)) { + result.type = PackageType.COMPONENT; + return false; + } + } + + if (isFile(defaultFile)) { + const defaultCode = fs.readFileSync(defaultFile, { encoding: 'utf-8', flag: 'r' }); + const ast = recast.parse(defaultCode, { parser: require('recast/parsers/typescript') }); + if (isDatasource(ast.program.body.find((node: any) => node.type === 'ExportDefaultDeclaration')?.declaration)) { + result.type = PackageType.DATASOURCE; + return false; + } + } + // 从 import 语句中找到 export default 的变量,认为是组件 if (n.ImportDefaultSpecifier.check(specifier) && specifier.local?.name === exportDefaultName) { result.type = PackageType.COMPONENT; @@ -230,6 +154,10 @@ const typeAssertion = function ({ ast, indexPath }: { ast: any; indexPath: strin } } + if (isDatasource(exportDefaultClass)) { + result.type = PackageType.DATASOURCE; + } + return result; }; @@ -240,6 +168,7 @@ const getAssertionTokenByTraverse = (ast: any) => { let exportDefaultName = ''; let exportDefaultNode = undefined; + let exportDefaultClass = undefined; recast.types.visit(ast, { visitImportDeclaration(p) { @@ -264,6 +193,11 @@ const getAssertionTokenByTraverse = (ast: any) => { exportDefaultNode = declaration; } + // 导出的是类 + if (n.ClassDeclaration.check(declaration)) { + exportDefaultClass = declaration; + } + this.traverse(p); }, }); @@ -273,6 +207,7 @@ const getAssertionTokenByTraverse = (ast: any) => { variableDeclarations, exportDefaultName, exportDefaultNode, + exportDefaultClass, }; }; @@ -282,6 +217,8 @@ const isPlugin = function (properties: any[]) { return !!match; }; +const isDatasource = (exportDefaultClass: any) => exportDefaultClass?.superClass?.name === 'DataSource'; + const getComponentPackageImports = function ({ result, properties, @@ -322,11 +259,14 @@ const getComponentPackageImports = function ({ }; const getIndexPath = function (entry: string) { - if (fs.lstatSync(entry).isFile()) { - return entry; + for (const affix of ['', '.js', '.ts']) { + const filePath = `${entry}${affix}`; + if (isFile(filePath)) { + return filePath; + } } - if (fs.lstatSync(entry).isDirectory()) { + if (isDirectory(entry)) { const files = fs.readdirSync(entry); const [index] = files.filter((file) => file.split('.')[0] === 'index'); @@ -346,16 +286,16 @@ const parseEntry = function ({ ast, package: module, indexPath }: ParseEntryOpti let { config, value, event, component } = tokens; if (!config) { - info(`${module} ${EntryType.CONFIG} 文件声明缺失`); + info(`${module} 表单配置文件声明缺失`); } if (!value) { - info(`${module} ${EntryType.VALUE} 文件声明缺失`); + info(`${module} 初始化数据文件声明缺失`); } if (!event) { - info(`${module} ${EntryType.EVENT} 文件声明缺失`); + info(`${module} 事件声明文件声明缺失`); } if (!component) { - info(`${module} ${EntryType.COMPONENT} 文件声明不合法`); + info(`${module} 组件或数据源文件声明不合法`); exit(1); } @@ -467,3 +407,136 @@ const splitNameVersion = function (str: string) { version, }; }; + +const getDependencies = (dependencies: Record, packagePath: string) => { + if (fs.existsSync(packagePath)) return; + + const { name: moduleName, version } = splitNameVersion(packagePath); + + if (!moduleName) return; + + dependencies[moduleName] = version; +}; + +const setPackages = (packages: ModuleMainFilePath, app: App, packagePath: string, key?: string) => { + const { options } = app; + const { temp, source, componentFileAffix } = options; + + let { name: moduleName } = splitNameVersion(packagePath); + + if (!moduleName) throw Error('packages中包含非法配置'); + + if (fs.lstatSync(moduleName).isDirectory()) { + if (!fs.existsSync(path.join(moduleName, './package.json'))) { + ['index.js', 'index.ts'].forEach((index) => { + const indexFile = path.join(moduleName!, `./${index}`); + if (fs.existsSync(indexFile)) { + moduleName = indexFile; + return; + } + }); + } + } + + // 获取完整路径 + const indexPath = execSync(`node -e "console.log(require.resolve('${moduleName.replace(/\\/g, '/')}'))"`, { + cwd: source, + }) + .toString() + .replace('\n', ''); + + const indexCode = fs.readFileSync(indexPath, { encoding: 'utf-8', flag: 'r' }); + const ast: Ast = recast.parse(indexCode, { parser: require('recast/parsers/typescript') }); + const result = typeAssertion({ ast, indexPath, componentFileAffix }); + + // 组件&插件&数据源包 + if (result.type === PackageType.COMPONENT_PACKAGE) { + result.imports.forEach((i) => { + setPackages(packages, app, i.indexPath, i.type); + }); + + return; + } + + if (!key) return; + + if (result.type === PackageType.COMPONENT) { + // 组件 + const entry = parseEntry({ ast, package: moduleName, indexPath }); + + if (entry.component) packages.componentMap[key] = getRelativePath(entry.component, temp); + if (entry.config) packages.configMap[key] = getRelativePath(entry.config, temp); + if (entry.event) packages.eventMap[key] = getRelativePath(entry.event, temp); + if (entry.value) packages.valueMap[key] = getRelativePath(entry.value, temp); + } else if (result.type === PackageType.DATASOURCE) { + // 数据源 + const entry = parseEntry({ ast, package: moduleName, indexPath }); + + if (entry.component) packages.datasourceMap[key] = getRelativePath(entry.component, temp); + if (entry.config) packages.dsConfigMap[key] = getRelativePath(entry.config, temp); + if (entry.event) packages.dsEventMap[key] = getRelativePath(entry.event, temp); + if (entry.value) packages.dsValueMap[key] = getRelativePath(entry.value, temp); + } else if (result.type === PackageType.PLUGIN) { + // 插件 + packages.pluginMap[key] = getRelativePath(moduleName, temp); + } +}; + +const flattenPackagesConfig = (packages: (string | Record)[]) => { + const packagesConfig: ([string] | [string, string])[] = []; + packages.forEach((item) => { + if (typeof item === 'object') { + Object.entries(item).forEach(([key, packagePath]) => { + packagesConfig.push([packagePath, key]); + }); + } else if (typeof item === 'string') { + packagesConfig.push([item]); + } + }); + return packagesConfig; +}; + +export const resolveAppPackages = (app: App): ModuleMainFilePath => { + const dependencies: Record = {}; + + const { packages = [], npmConfig = {}, source } = app.options; + + const packagePaths = flattenPackagesConfig(packages); + + packagePaths.forEach(([packagePath]) => getDependencies(dependencies, packagePath)); + + if (npmConfig.autoInstall && Object.keys(dependencies).length) { + if (!npmConfig.keepPackageJsonClean) { + npmInstall(dependencies, source, npmConfig); + } else { + const packageFile = path.join(source, 'package.json'); + const packageBakFile = path.join(source, 'package.json.bak'); + if (fs.existsSync(packageFile)) { + fs.copyFileSync(packageFile, packageBakFile); + } + + npmInstall(dependencies, source, npmConfig); + + if (fs.existsSync(packageBakFile)) { + fs.unlinkSync(packageFile); + fs.renameSync(packageBakFile, packageFile); + } + } + } + + const packagesMap: ModuleMainFilePath = { + componentMap: {}, + configMap: {}, + eventMap: {}, + valueMap: {}, + pluginMap: {}, + datasourceMap: {}, + dsConfigMap: {}, + dsEventMap: {}, + dsValueMap: {}, + }; + + packagePaths.forEach(([packagePath, key]) => setPackages(packagesMap, app, packagePath, key)); + + return packagesMap; +}; diff --git a/packages/data-source/src/DataSourceManager.ts b/packages/data-source/src/DataSourceManager.ts index eedd5a6d..fd2d0a34 100644 --- a/packages/data-source/src/DataSourceManager.ts +++ b/packages/data-source/src/DataSourceManager.ts @@ -100,15 +100,21 @@ class DataSourceManager extends EventEmitter { } } }); + + this.change(ds); }); ds.on('change', () => { - Object.assign(this.data[ds.id], ds.data); - - this.emit('change', ds.id); + this.change(ds); }); } + public change(ds: DataSource) { + Object.assign(this.data[ds.id], ds.data); + + this.emit('change', ds.id); + } + public removeDataSource(id: string) { this.get(id)?.destroy(); delete this.data[id]; diff --git a/packages/editor/src/editorProps.ts b/packages/editor/src/editorProps.ts index ad2b1662..342fd28d 100644 --- a/packages/editor/src/editorProps.ts +++ b/packages/editor/src/editorProps.ts @@ -2,7 +2,7 @@ import type { PropType } from 'vue'; import type { EventOption } from '@tmagic/core'; import type { FormConfig, FormState } from '@tmagic/form'; -import type { MApp, MNode } from '@tmagic/schema'; +import type { DataSourceSchema, MApp, MNode } from '@tmagic/schema'; import StageCore, { CONTAINER_HIGHLIGHT_CLASS_NAME, ContainerHighlightType, @@ -11,7 +11,15 @@ import StageCore, { UpdateDragEl, } from '@tmagic/stage'; -import type { ComponentGroup, MenuBarData, MenuButton, MenuComponent, SideBarData, StageRect } from './type'; +import type { + ComponentGroup, + DatasourceTypeOption, + MenuBarData, + MenuButton, + MenuComponent, + SideBarData, + StageRect, +} from './type'; export default { /** 页面初始值 */ @@ -27,6 +35,12 @@ export default { default: () => [], }, + /** 左侧面板中的组件列表 */ + datasourceList: { + type: Array as PropType, + default: () => [], + }, + /** 左侧面板配置 */ sidebar: { type: Object as PropType, @@ -69,7 +83,7 @@ export default { /** 添加组件时的默认值 */ propsValues: { - type: Object as PropType>, + type: Object as PropType>>, default: () => ({}), }, @@ -79,6 +93,19 @@ export default { default: () => ({}), }, + /** 组件的属性配置表单的dsl */ + datasourceConfigs: { + type: Object as PropType>, + default: () => ({}), + }, + + /** 添加数据源时的默认值 */ + datasourceValues: { + type: Object as PropType>>, + default: () => ({}), + }, + + /** 数据源的属性配置表单的dsl */ dataScourceConfigs: { type: Object as PropType>, default: () => ({}), diff --git a/packages/editor/src/initService.ts b/packages/editor/src/initService.ts index 0759f743..3b2e28d2 100644 --- a/packages/editor/src/initService.ts +++ b/packages/editor/src/initService.ts @@ -31,6 +31,7 @@ export const initServiceState = ( uiService, codeBlockService, keybindingService, + dataSourceService, }: Services, ) => { // 初始值变化,重新设置节点信息 @@ -52,6 +53,14 @@ export const initServiceState = ( }, ); + watch( + () => props.datasourceList, + (datasourceList) => dataSourceService.set('datasourceTypeList', datasourceList), + { + immediate: true, + }, + ); + watch( () => props.propsConfigs, (configs) => propsService.setPropsConfigs(configs), @@ -87,6 +96,30 @@ export const initServiceState = ( }, ); + watch( + () => props.datasourceConfigs, + (configs) => { + Object.entries(configs).forEach(([key, value]) => { + dataSourceService.setFormConfig(key, value); + }); + }, + { + immediate: true, + }, + ); + + watch( + () => props.datasourceValues, + (values) => { + Object.entries(values).forEach(([key, value]) => { + dataSourceService.setFormValue(key, value); + }); + }, + { + immediate: true, + }, + ); + watch( () => props.defaultSelected, (defaultSelected) => defaultSelected && editorService.select(defaultSelected), diff --git a/packages/editor/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue b/packages/editor/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue index 047db8ff..9c729e18 100644 --- a/packages/editor/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +++ b/packages/editor/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue @@ -16,6 +16,7 @@