diff --git a/packages/model-design/src/components/design-code-editor/design-code-editor.tsx b/packages/model-design/src/components/design-code-editor/design-code-editor.tsx index 0b47ea41e478cd01ea08629d37070c7be907b75a..7b9805a7cbaa1f74066b213ae4f56cf80ae8f511 100644 --- a/packages/model-design/src/components/design-code-editor/design-code-editor.tsx +++ b/packages/model-design/src/components/design-code-editor/design-code-editor.tsx @@ -1,3 +1,4 @@ +/* eslint-disable no-useless-escape */ /* eslint-disable import/no-extraneous-dependencies */ import { useNamespace, useUIStore } from '@ibiz-template/vue3-util'; import { @@ -125,6 +126,28 @@ export default defineComponent({ return; } monacoEditor = loaderMonaco.editor; + // 手动注册 Groovy 语言 + loaderMonaco.languages.register({ id: 'groovy' }); + loaderMonaco.languages.setMonarchTokensProvider('groovy', { + tokenizer: { + root: [ + [/\/\/.*$/, 'comment'], // 单行注释 + [/\/\*/, 'comment', '@comment'], // 多行注释 + [ + /(println|def|return|if|else|for|while|psdelogic|psdelogicparam|psdelogicnode|psdelogiclink)\b/, + 'keyword', + ], // 关键字 + [/"[^"]*"/, 'string'], // 双引号字符串 + [/'[^']*'/, 'string'], // 单引号字符串 + [/\d+/, 'number'], // 数字 + [/[\+\-\*\/=<>!]+/, 'operator'], // 操作符 + ], + comment: [ + [/.*?\*\//, 'comment', '@pop'], + [/.*/, 'comment'], + ], + }, + }); editor = monacoEditor.create(editorRef.value, { language: currentLanguage.value, theme: getMonacoTheme(UIStore.theme), diff --git a/packages/model-design/src/components/dsl-model-clipboard-import-view/dsl-model-clipboard-import-view.scss b/packages/model-design/src/components/dsl-model-clipboard-import-view/dsl-model-clipboard-import-view.scss new file mode 100644 index 0000000000000000000000000000000000000000..0aa2622ed10558dc387d479aa3a393718068eac3 --- /dev/null +++ b/packages/model-design/src/components/dsl-model-clipboard-import-view/dsl-model-clipboard-import-view.scss @@ -0,0 +1,176 @@ +/* stylelint-disable selector-class-pattern */ +@include b(dsl-model-clipboard-import-view) { + width: 100%; + height: 100%; + font-size: 14px; + line-height: 1.5; + color: getCssVar(color, text, 1); + + .el-card__header { + padding: 0 10px; + } + + .el-card__body { + height: calc(100% - 40px); + padding: 6px; + } + + .el-loading-mask { + color: var(--el-color-primary); + + svg { + fill: currentcolor; + } + } +} + +@include b(dsl-model-clipboard-import-view-header) { + display: flex; + align-items: center; + justify-content: space-between; + height: 40px; +} + +@include b(dsl-model-clipboard-import-view-content) { + display: flex; + height: 100%; +} + +@include b(dsl-model-clipboard-import-view-import-warp) { + flex-grow: 1; + padding: 0 6px 0 0; +} + +@include b(dsl-model-clipboard-import-view-drop-area) { + position: relative; + height: 100px; + border: 1px solid getCssVar(color, border); + border-radius: 5px; +} + +@include b(dsl-model-clipboard-import-view-drop-area-draggable) { + display: flex; + height: 100%; + padding: 6px; + overflow: auto; + + @include b(dsl-model-clipboard-import-view-model-material-item) { + flex: 0 0 auto; + height: 100%; + padding: 3px 24px 3px 3px; + margin-right: 6px; + margin-bottom: 0; + + @include b(dsl-model-clipboard-import-view-model-material-item-title) { + font-weight: normal; + } + } +} + +@include b(dsl-model-clipboard-import-view-model-drag-item) { + position: relative; + flex: 0 0 auto; + height: 100%; + padding: 3px 24px 3px 3px; + margin-right: 6px; + border: 1px solid getCssVar(color, border); + border-radius: 5px; +} + +@include b(dsl-model-clipboard-import-view-model-drag-item-actions) { + position: absolute; + top: 6px; + right: 5px; + display: flex; + align-items: center; +} + +@include b(dsl-model-clipboard-import-view-model-drag-item-action-item) { + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; + cursor: pointer; +} + +@include b(dsl-model-clipboard-import-view-drop-tooltip) { + position: absolute; + top: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + font-size: 24px; + font-weight: 700; +} + +@include b(dsl-model-clipboard-import-view-model-edit) { + position: relative; + height: calc(100% - 106px); + margin-top: 6px; + border: 1px solid getCssVar(color, border); + border-radius: 5px; +} + +@include b(dsl-model-clipboard-import-view-edit-actions) { + margin: 0 8px 0 5px; + + .el-button { + --el-button-text-color: #{getCssVar(color, text, 3)}; + + + .el-button { + margin-left: 5px; + } + } +} + +@include b(dsl-model-clipboard-import-view-model-material-warp) { + position: relative; + display: flex; + flex-direction: column; + flex-shrink: 0; + width: 200px; + border: 1px solid getCssVar(color, border); + border-radius: 5px; +} + +@include b(dsl-model-clipboard-import-view-model-material-title) { + flex: 0 0 auto; + padding: 6px; + font-weight: 700; + text-align: center; + border-bottom: 1px solid getCssVar(color, border); +} + +@include b(dsl-model-clipboard-import-view-model-material-content) { + flex: 1 1 0; + padding: 6px; + overflow: auto; +} + +@include b(dsl-model-clipboard-import-view-model-material-item) { + padding: 3px 5px; + margin-bottom: 5px; + cursor: move; + border: 1px solid getCssVar(color, border); + border-radius: 5px; +} + +@include b(dsl-model-clipboard-import-view-model-material-item-title) { + font-weight: 700; +} + +@include b(dsl-model-clipboard-import-view-model-material-tooltip) { + position: absolute; + top: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + font-size: 24px; + font-weight: 700; +} diff --git a/packages/model-design/src/components/dsl-model-clipboard-import-view/dsl-model-clipboard-import-view.tsx b/packages/model-design/src/components/dsl-model-clipboard-import-view/dsl-model-clipboard-import-view.tsx new file mode 100644 index 0000000000000000000000000000000000000000..7a93e9f9b071632843435f50a0bf346f868ec2d7 --- /dev/null +++ b/packages/model-design/src/components/dsl-model-clipboard-import-view/dsl-model-clipboard-import-view.tsx @@ -0,0 +1,349 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable no-await-in-loop */ +import { IModal } from '@ibiz-template/runtime'; +import { PropType, computed, defineComponent } from 'vue'; +import { useNamespace } from '@ibiz-template/vue3-util'; +import draggable from 'vuedraggable'; +import { ClipboardData } from '../../model'; +import './dsl-model-clipboard-import-view.scss'; + +export default defineComponent({ + name: 'IBizDSLModelClipboardImportView', + components: { + draggable, + }, + props: { + context: { type: Object as PropType, default: () => ({}) }, + params: { type: Object as PropType, default: () => ({}) }, + modal: { type: Object as PropType }, + }, + setup(props) { + const ns = useNamespace('dsl-model-clipboard-import-view'); + // 模型粘贴板控制器 + const modelClipboardController = ibiz.modelClipboard; + // 模型导入视图控制器 + const c = ibiz.dslModelClipboardImportView; + + // 重置模型 + const initModel = (val: string) => { + c.state.modelStr = val; + c.state.isModelChange = false; + }; + + // 清除当前已计算模型 + const clearModel = async () => { + if (c.state.isModelChange) { + const result = await ibiz.confirm.warning({ + title: '确认清除?', + desc: '模型数据已变更,将同已拖入模型一同清空,确认清除吗?', + }); + if (result) { + c.clearAllData(); + } + } else { + c.clearAllData(); + } + }; + + // 关闭当前视图 + const closeView = async () => { + if (c.state.isModelChange) { + const result = await ibiz.confirm.warning({ + title: '确认关闭', + desc: '模型数据已变更,确认关闭吗?', + }); + if (result) { + props.modal?.dismiss(); + c.clearAllData(); + } + } else { + props.modal?.dismiss(); + } + }; + + // 模型编辑变更 + const modelChange = (val: string) => { + if (!Object.is(c.state.modelStr, val)) { + c.state.modelStr = val; + c.state.isModelChange = true; + } + }; + + // 计算模型文本内容 + const calcModeStr = () => { + ibiz.message.warning('编辑框内,模型内容已重新计算!'); + c.state.models = []; + try { + c.state.items.forEach(item => { + const models = item.models.filter(m => !!m.dsl).map(m => m.dsl); + c.state.models.push(...models); + }); + // 多个模型使用换行符隔开 + initModel(c.state.models.join('\n')); + } catch (error) { + ibiz.log.error(error); + } + }; + + // 删除拖拽项 + const deleteDropItem = (i: number) => { + c.state.items.splice(i, 1); + calcModeStr(); + }; + + // 拖入模型变更 + const dropModelChange = async (e: IData) => { + if (c.state.isModelChange) { + const result = await ibiz.confirm.warning({ + title: '确认操作?', + desc: '检测到输入框内容已手动修改,该操作后输入框内容将重新计算,确认操作吗?', + }); + if (result) { + calcModeStr(); + } else if (e && e.added && e.added.newIndex != null) { + c.state.items.splice(e.added.newIndex, 1); + } + } else { + calcModeStr(); + } + }; + + // 素材项 + const materialItem = computed(() => { + return modelClipboardController.state.items.filter(item => { + if ( + item.type !== 'dsl' || + !Object.is(c.state.params.codeName, item.codeName) || + c.state.items.findIndex(self => Object.is(self.uuid, item.uuid)) !== + -1 + ) { + return false; + } + return item; + }); + }); + + // 保存模型 + const saveModel = async () => { + c.state.isLoading = true; + let isError: boolean = false; + const entity = await ibiz.hub.getAppDataEntity( + c.state.params.codeName, + props.context.srfappid, + ); + const app = ibiz.hub.getApp(props.context.srfappid); + const service = await app.deService.getService(props.context, entity.id!); + try { + const res = await service.exec( + 'CompileModelDSL', + props.context, + { + build: true, + dsl: c.state.modelStr, + }, + props.params, + ); + if (res.ok && res.data) { + c.state.isModelChange = false; + } else { + ibiz.message.error(res.statusText); + isError = true; + } + } catch (error: any) { + ibiz.message.error( + error?.message || + error?.data?.message || + error?.statusText || + ibiz.i18n.t('core.error.networkAbnormality'), + ); + isError = true; + } + if (!isError) { + const result = await ibiz.confirm.warning({ + title: '关闭导入界面?', + desc: '已导入完毕,确认关闭导入界面!', + }); + if (result) { + props.modal?.dismiss(); + } + } + setTimeout(() => { + c.state.isLoading = false; + }, 300); + }; + + return { + c, + ns, + modelClipboardController, + materialItem, + closeView, + clearModel, + modelChange, + deleteDropItem, + dropModelChange, + saveModel, + }; + }, + render() { + const { isLoading, items, modelStr } = this.c.state; + return ( + + {{ + header: () => { + return ( +
+ 模型导入 + this.closeView()} + > + 关闭 + +
+ ); + }, + default: () => { + return ( +
+
+
+ this.dropModelChange(evt)} + > + {{ + item: ({ + element, + index, + }: { + element: ClipboardData; + index: number; + }) => { + const item = element; + + return ( +
+
+
this.deleteDropItem(index)} + > + +
+
+
+ {item.title} +
+
+ {item.createdDate} +
+
+ ); + }, + }} +
+
+ 请从右侧素材区拖入 +
+
+
+ + this.modelChange(val) + } + > + {{ + rightToolbar: () => { + return ( +
+ this.clearModel()} + > + 清空 + + this.saveModel()} + > + 导入 + +
+ ); + }, + }} +
+
+
+
+
模型素材
+ + {{ + item: ({ element }: { element: ClipboardData }) => { + const item = element; + + return ( +
+
+ {item.title} +
+
+ {item.createdDate} +
+
+ ); + }, + }} +
+
+ 暂无数据 +
+
+
+ ); + }, + }} +
+ ); + }, +}); diff --git a/packages/model-design/src/components/dsl-model-edit-view/dsl-model-edit-view.scss b/packages/model-design/src/components/dsl-model-edit-view/dsl-model-edit-view.scss new file mode 100644 index 0000000000000000000000000000000000000000..d74c38ca0fa6d5b10afc591d17f774234ce5c7ef --- /dev/null +++ b/packages/model-design/src/components/dsl-model-edit-view/dsl-model-edit-view.scss @@ -0,0 +1,58 @@ +/* stylelint-disable selector-class-pattern */ +@include b(dsl-model-edit-view) { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + overflow: auto; +} + +@include b(dsl-model-edit-view-header) { + display: flex; + flex: 0 0 auto; + align-items: center; + height: 36px; + font-size: 16px; + font-weight: 700; + background: getCssVar(color, fill, 1); +} + +@include b(dsl-model-edit-view-header-back-btn) { + display: flex; + flex: 0 0 auto; + align-items: center; + justify-content: center; + margin-top: 1px; + cursor: pointer; +} + +@include b(dsl-model-edit-view-header-caption) { + flex: 1 1 0; + padding-left: 7px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +@include b(dsl-model-edit-view-header-toolbar) { + flex: 0 0 auto; + + .el-button + .el-button { + margin-left: 4px; + } +} + +@include b(dsl-model-edit-view-header-close-btn) { + display: flex; + flex: 0 0 auto; + align-items: center; + justify-content: center; + padding-right: 10px; + padding-left: 20px; + font-size: 20px; + cursor: pointer; +} + +@include b(dsl-model-edit-view-content) { + flex: 1 1 0; +} diff --git a/packages/model-design/src/components/dsl-model-edit-view/dsl-model-edit-view.tsx b/packages/model-design/src/components/dsl-model-edit-view/dsl-model-edit-view.tsx new file mode 100644 index 0000000000000000000000000000000000000000..db7c7bd92d97230e89bad3b83f1e8629b8643f20 --- /dev/null +++ b/packages/model-design/src/components/dsl-model-edit-view/dsl-model-edit-view.tsx @@ -0,0 +1,179 @@ +import { defineComponent, PropType, ref } from 'vue'; +import { IModal } from '@ibiz-template/runtime'; +import { useNamespace } from '@ibiz-template/vue3-util'; +import './dsl-model-edit-view.scss'; + +export default defineComponent({ + name: 'IBizDSLModelEditView', + props: { + context: { type: Object as PropType, default: () => ({}) }, + params: { type: Object as PropType, default: () => ({}) }, + modal: { type: Object as PropType }, + caption: { type: String, default: '' }, + codeName: { type: String, required: true }, + readonly: { type: Boolean }, + }, + setup(props) { + const ns = useNamespace('dsl-model-edit-view'); + + // 是否保存过 + const isSave = ref(false); + + // 模型编辑值 + const value = ref(''); + + // 关闭 + const closeView = () => { + props.modal?.dismiss({ ok: true, params: { isSave: isSave.value } }); + }; + + // 是否正在加载 + const loading = ref(false); + + // 加载文本 + const loadingText = ref(''); + + // 保存 + const save = async (isClose: boolean = false) => { + isSave.value = true; + try { + loading.value = true; + loadingText.value = '保存中...'; + const entity = await ibiz.hub.getAppDataEntity( + props.codeName, + props.context.srfappid, + ); + const app = ibiz.hub.getApp(props.context.srfappid); + const service = await app.deService.getService( + props.context, + entity.id!, + ); + const deName = entity.codeName?.toLowerCase() || ''; + // 最后一行添加 option(update:"true") + const res = await service.exec( + 'CompileModelDSL', + props.context, + { + build: true, + dsl: value.value.replace(/\s*(\})/, '\noption(update:"true")\n$1'), + srfkey: props.context[deName], + }, + props.params, + ); + if (res.status !== 200) { + ibiz.message.error( + res.data?.message || + res.statusText || + ibiz.i18n.t('core.error.networkAbnormality'), + ); + } else if (isClose) { + closeView(); + } + } catch (err) { + const error = err as IData; + ibiz.message.error( + error?.message || + error?.data?.message || + error?.statusText || + ibiz.i18n.t('core.error.networkAbnormality'), + ); + } finally { + loading.value = false; + } + }; + + // 加载数据 + const load = async () => { + try { + loading.value = true; + loadingText.value = '加载中...'; + const entity = await ibiz.hub.getAppDataEntity( + props.codeName, + props.context.srfappid, + ); + const app = ibiz.hub.getApp(props.context.srfappid); + const service = await app.deService.getService( + props.context, + entity.id!, + ); + const res = await service.exec( + 'ExportModelDSL', + props.context, + {}, + props.params, + ); + if (res.status === 200 && res.data && res.data.dsl) { + value.value = res.data.dsl; + } + } catch (err) { + const error = err as IData; + ibiz.message.error( + error.message || ibiz.i18n.t('core.error.networkAbnormality'), + ); + } finally { + loading.value = false; + } + }; + + load(); + + return { + ns, + value, + loading, + loadingText, + closeView, + save, + }; + }, + render() { + return ( +
+
+
this.closeView()} + > + + 返回 +
+
{this.caption}
+
+ {this.readonly + ? null + : [ + this.save(true)}> + 保存并关闭 + , + this.save()}> + 保存 + , + ]} + this.closeView()}> + 关闭 + +
+
this.closeView()} + > + +
+
+
+ +
+
+ ); + }, +}); diff --git a/packages/model-design/src/components/index.ts b/packages/model-design/src/components/index.ts index d845b9e0962c3c1b86346aa7cba3a18d21f4c5c0..cb2cab598353a835f0508bf275d949f59abbbe2d 100644 --- a/packages/model-design/src/components/index.ts +++ b/packages/model-design/src/components/index.ts @@ -8,6 +8,8 @@ import IBizModelEditView from './model-edit-view/model-edit-view'; import IBizModelTree from './model-tree/model-tree'; import IBizModelRuntime from './model-runtime/model-runtime'; import IBizModelClone from './model-clone/model-clone'; +import IBizDSLModelClipboardImportView from './dsl-model-clipboard-import-view/dsl-model-clipboard-import-view'; +import IBizDSLModelEditView from './dsl-model-edit-view/dsl-model-edit-view'; export default { install(app: App) { @@ -20,5 +22,10 @@ export default { app.component('IBizModelTree', IBizModelTree); app.component('IBizModelRuntime', IBizModelRuntime); app.component('IBizModelClone', IBizModelClone); + app.component( + 'IBizDSLModelClipboardImportView', + IBizDSLModelClipboardImportView, + ); + app.component('IBizDSLModelEditView', IBizDSLModelEditView); }, }; diff --git a/packages/model-design/src/components/model-clipboard-item/model-clipboard-item.tsx b/packages/model-design/src/components/model-clipboard-item/model-clipboard-item.tsx index dfa1331edca4a478e81c5372b4e3dabc61ec1f7f..c0af37212041e141ac89cde35c9c1bbef844b0a7 100644 --- a/packages/model-design/src/components/model-clipboard-item/model-clipboard-item.tsx +++ b/packages/model-design/src/components/model-clipboard-item/model-clipboard-item.tsx @@ -8,6 +8,15 @@ import { ClipboardData } from '../../model'; import { IModelData } from '../../interface'; import './model-clipboard-item.scss'; +/** + * 导出数据类型映射行为接口 + */ +const actionMap = { + advanced: 'CopyModel', + dsl: 'ExportModelDSL', + default: 'ExportModelV2', +}; + export default defineComponent({ name: 'IBizModelClipboardItem', props: { @@ -59,7 +68,7 @@ export default defineComponent({ entity.id!, ); const res = await service.exec( - props.data.type === 'advanced' ? 'CopyModel' : 'ExportModelV2', + actionMap[props.data.type], { ...props.context, [entity.deapicodeName!]: item.srfkey, diff --git a/packages/model-design/src/components/model-clipboard/model-clipboard.tsx b/packages/model-design/src/components/model-clipboard/model-clipboard.tsx index 45515a0699ee1261c93a7b1f3a192fa3fe4dd513..d580c45affd163f904ba434f7b65a48a1fed7cee 100644 --- a/packages/model-design/src/components/model-clipboard/model-clipboard.tsx +++ b/packages/model-design/src/components/model-clipboard/model-clipboard.tsx @@ -10,7 +10,7 @@ export default defineComponent({ params: { type: Object as PropType, default: () => ({}) }, modal: { type: Object as PropType }, type: { - type: String as PropType<'default' | 'advanced'>, + type: String as PropType<'default' | 'advanced' | 'dsl'>, default: 'default', }, }, diff --git a/packages/model-design/src/controller/dsl-model-clipbodard-import-view-controller/dsl-model-clipbodard-import-view-controller.ts b/packages/model-design/src/controller/dsl-model-clipbodard-import-view-controller/dsl-model-clipbodard-import-view-controller.ts new file mode 100644 index 0000000000000000000000000000000000000000..8173e29f8b564debff39837a1044343da06c9d69 --- /dev/null +++ b/packages/model-design/src/controller/dsl-model-clipbodard-import-view-controller/dsl-model-clipbodard-import-view-controller.ts @@ -0,0 +1,49 @@ +import { DSLModelClipboardImportViewState } from './dsl-model-clipbodard-import-view-state'; + +/** + * DSL模型粘贴板导出视图控制器 + * + * @export + * @class DSLModelClipboardImportViewController + */ +export class DSLModelClipboardImportViewController { + /** + * 模型导入视图状态 + * + * @memberof DSLModelClipboardImportViewController + */ + state = new DSLModelClipboardImportViewState(); + + /** + * 更新参数 + * + * @param {IParams} params + * @memberof DSLModelClipboardImportViewController + */ + updateParams(params: IParams): void { + if ( + params && + !Object.is(JSON.stringify(params), JSON.stringify(this.state.params)) + ) { + this.state.params = params; + this.clearAllData(); + } + } + + /** + * 清理数据 + * + * @memberof DSLModelClipboardImportViewController + */ + clearAllData(): void { + this.state.isLoading = false; + this.state.items = []; + this.state.importItems = []; + this.state.models = []; + this.state.modelStr = ''; + this.state.isModelChange = false; + } +} + +export const dslModelClipboardImportViewController = + new DSLModelClipboardImportViewController(); diff --git a/packages/model-design/src/controller/dsl-model-clipbodard-import-view-controller/dsl-model-clipbodard-import-view-state.ts b/packages/model-design/src/controller/dsl-model-clipbodard-import-view-controller/dsl-model-clipbodard-import-view-state.ts new file mode 100644 index 0000000000000000000000000000000000000000..c86c54487a4d304eec608538e4aee159bc6206d7 --- /dev/null +++ b/packages/model-design/src/controller/dsl-model-clipbodard-import-view-controller/dsl-model-clipbodard-import-view-state.ts @@ -0,0 +1,59 @@ +import { ClipboardData } from '../../model'; + +export class DSLModelClipboardImportViewState { + /** + * 是否正在加载 + * + * @type {boolean} + * @memberof ModelClipboardImportViewState + */ + isLoading: boolean = false; + + /** + * 已拖入的剪切板数据 + * + * @type {ClipboardData[]} + * @memberof ModelClipboardImportViewState + */ + items: ClipboardData[] = []; + + /** + * 已导入的模型 + * + * @type {IData[]} + * @memberof ModelClipboardImportViewState + */ + importItems: IData[] = []; + + /** + * 当前编辑的模型 + * + * @type {IData[]} + * @memberof ModelClipboardImportViewState + */ + models: string[] = []; + + /** + * 模型json + * + * @type {string} + * @memberof ModelClipboardImportViewState + */ + modelStr: string = ''; + + /** + * 是否在代码编辑器更改过模型json + * + * @type {boolean} + * @memberof ModelClipboardImportViewState + */ + isModelChange: boolean = false; + + /** + * 参数 + * + * @type {IData} + * @memberof ModelClipboardImportViewState + */ + params: IData = {}; +} diff --git a/packages/model-design/src/controller/index.ts b/packages/model-design/src/controller/index.ts index a44150b56d03810c24bad055a4d7d5ae41fe140d..8ed06af8b1f468997996ca3a30173c6f15e18563 100644 --- a/packages/model-design/src/controller/index.ts +++ b/packages/model-design/src/controller/index.ts @@ -1,3 +1,4 @@ export { modelClipboardController } from './model-clipboard-controller/model-clipboard-controller'; export { modelClipboardImportViewController } from './model-clipboard-import-view-controller/model-clipboard-import-view-controller'; export { modelClipboardPasteViewController } from './model-clipboard-paste-view-controller/model-clipboard-paste-view-controller'; +export { dslModelClipboardImportViewController } from './dsl-model-clipbodard-import-view-controller/dsl-model-clipbodard-import-view-controller'; diff --git a/packages/model-design/src/controller/model-clipboard-import-view-controller/model-clipboard-import-view-controller.ts b/packages/model-design/src/controller/model-clipboard-import-view-controller/model-clipboard-import-view-controller.ts index b88ecd1c944da99f4de7bee8a6b246f477e40a35..b398d8de7726b8a3f1e49711c07c7d39272eab25 100644 --- a/packages/model-design/src/controller/model-clipboard-import-view-controller/model-clipboard-import-view-controller.ts +++ b/packages/model-design/src/controller/model-clipboard-import-view-controller/model-clipboard-import-view-controller.ts @@ -1,5 +1,11 @@ import { ModelClipboardImportViewState } from './model-clipboard-import-view-state'; +/** + * 模型粘贴板导出视图控制器 + * + * @export + * @class ModelClipboardImportViewController + */ export class ModelClipboardImportViewController { /** * 模型导入视图状态 diff --git a/packages/model-design/src/controller/model-clipboard-paste-view-controller/model-clipboard-paste-view-controller.ts b/packages/model-design/src/controller/model-clipboard-paste-view-controller/model-clipboard-paste-view-controller.ts index 1f6d06edba977642a30e30e9191e048e70209103..ba3db8e6e82fca33f88a79885170630e10822208 100644 --- a/packages/model-design/src/controller/model-clipboard-paste-view-controller/model-clipboard-paste-view-controller.ts +++ b/packages/model-design/src/controller/model-clipboard-paste-view-controller/model-clipboard-paste-view-controller.ts @@ -1,5 +1,11 @@ import { ModelClipboardPasteViewState } from './model-clipboard-paste-view-state'; +/** + * 模型粘贴版粘贴视图控制器 + * + * @export + * @class ModelClipboardPasteViewController + */ export class ModelClipboardPasteViewController { /** * 模型粘贴视图状态 diff --git a/packages/model-design/src/index.ts b/packages/model-design/src/index.ts index ed07bd3744093f45c8cbd476ab6a5a6f2fe3943e..d469e3c5e29a6d7a4e8101952f0e27f4a744750c 100644 --- a/packages/model-design/src/index.ts +++ b/packages/model-design/src/index.ts @@ -10,6 +10,7 @@ import { modelClipboardController, modelClipboardImportViewController, modelClipboardPasteViewController, + dslModelClipboardImportViewController, } from './controller'; declare module '@ibiz-template/core' { @@ -39,6 +40,14 @@ declare module '@ibiz-template/core' { * @memberof IBizSys */ modelClipboardPasteView: typeof modelClipboardPasteViewController; + + /** + * dsl模型导入视图控制器 + * + * @type {typeof dslModelClipboardImportViewController} + * @memberof IBizSys + */ + dslModelClipboardImportView: typeof dslModelClipboardImportViewController; } } @@ -65,5 +74,11 @@ export default { ); ibiz.modelClipboardPasteView = modelClipboardPasteViewController; } + if (!ibiz.dslModelClipboardImportView) { + dslModelClipboardImportViewController.state = reactive( + dslModelClipboardImportViewController.state, + ); + ibiz.dslModelClipboardImportView = dslModelClipboardImportViewController; + } }, }; diff --git a/packages/model-design/src/interface/i-clipboard-params.ts b/packages/model-design/src/interface/i-clipboard-params.ts index 33ae472682f0956689a06a239ffd5dfb934f75bb..b166ea71797e21b86da6fb780db18b48511945ad 100644 --- a/packages/model-design/src/interface/i-clipboard-params.ts +++ b/packages/model-design/src/interface/i-clipboard-params.ts @@ -33,8 +33,8 @@ export interface IClipboardParams { /** * 类型 * - * @type {('default' | 'advanced')}(默认 | 高级) + * @type {('default' | 'advanced')}(默认 | 高级 | dsl) * @memberof IModelParams */ - type?: 'default' | 'advanced'; + type?: 'default' | 'advanced' | 'dsl'; } diff --git a/packages/model-design/src/interface/i-model-data.ts b/packages/model-design/src/interface/i-model-data.ts index 52b89982e3e842b861571ab91393ef46b55349d7..8e7513e853c166739e263996922fd6b52d7b0440 100644 --- a/packages/model-design/src/interface/i-model-data.ts +++ b/packages/model-design/src/interface/i-model-data.ts @@ -26,4 +26,11 @@ export interface IModelData { * @memberof ICopyModel */ requires: IData; + /** + * dsl模型(groovy代码) + * + * @type {IData} + * @memberof IModelData + */ + dsl: string; } diff --git a/packages/model-design/src/model/clipboard-data.ts b/packages/model-design/src/model/clipboard-data.ts index 030cca5b728c1dab83097cc31c4a6f03084a7833..98fe2381637546a19277e9d7eb81cab0dfc30359 100644 --- a/packages/model-design/src/model/clipboard-data.ts +++ b/packages/model-design/src/model/clipboard-data.ts @@ -83,10 +83,10 @@ export class ClipboardData { /** * 类型 * - * @type {('default' | 'advanced')}(默认 | 高级) + * @type {('default' | 'advanced')}(默认 | 高级 | dsl) * @memberof ModelData */ - type: 'default' | 'advanced' = 'default'; + type: 'default' | 'advanced' | 'dsl' = 'default'; /** * Creates an instance of ModelData. diff --git a/packages/model-design/src/ui-action/dsl-model-edit-provider.ts b/packages/model-design/src/ui-action/dsl-model-edit-provider.ts new file mode 100644 index 0000000000000000000000000000000000000000..84bb6345eb0a7d8a29b3cade8917343e55fbad35 --- /dev/null +++ b/packages/model-design/src/ui-action/dsl-model-edit-provider.ts @@ -0,0 +1,116 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { h, resolveComponent } from 'vue'; +import { + IModal, + IModalData, + IUIActionResult, + IUILogicParams, + SysUIActionTag, + UIActionProviderBase, + calcDeCodeNameById, + convertNavData, + formatMultiData, +} from '@ibiz-template/runtime'; +import { IAppDEUIAction } from '@ibiz/model-core'; +import { createUUID, notNilEmpty } from 'qx-util'; + +/** + * dsl模型编辑 + * + * @export + * @class DSLModelEditProvider + * @extends {UIActionProviderBase} + */ +export class DSLModelEditProvider extends UIActionProviderBase { + async execAction( + action: IAppDEUIAction, + args: IUILogicParams, + ): Promise { + const { context, params, view, data } = args; + const readonly = action.uiactionParamJO?.readonly === 'true'; + if (!readonly) { + const uiDomain = ibiz.uiDomainManager.get(view.context.srfsessionid); + if (uiDomain?.dataModification) { + const res = await view.call(SysUIActionTag.SAVE); + + // 适配编辑视图保存成功后返回值为null + if (!res && res !== null) { + return {}; + } + } + } + // 是否是多数据 + const isMultiData = + ['MULTIKEY', 'MULTIDATA'].includes(action.actionTarget!) && + data.length > 0; + // 处理自定义导航上下文 + const resultContext = context.clone(); + const id = createUUID(); + const domain = ibiz.uiDomainManager.create(id); + resultContext.srfsessionid = domain.id; + const navContexts = [...(action.navigateContexts || [])]; + const deName = calcDeCodeNameById(view.model.appDataEntityId!); + if (deName && action.actionTarget !== 'NONE') { + const key = deName; + const valueKey = 'srfkey'; + navContexts.unshift({ + appId: view.model.appId, + key, + value: valueKey, + rawValue: false, + }); + } + if (notNilEmpty(navContexts)) { + Object.assign( + resultContext, + convertNavData( + navContexts, + isMultiData ? formatMultiData(navContexts, data) : data[0] || {}, + params, + context, + ), + ); + } + // 处理自定义导航参数 + const resultParams = {}; + const navParams = action.navigateParams; + if (notNilEmpty(navParams)) { + Object.assign( + resultParams, + convertNavData( + navParams, + isMultiData ? formatMultiData(navParams, data) : data[0] || {}, + params, + context, + ), + ); + } + const appEntity = await ibiz.hub.getAppDataEntity( + view.model.appDataEntityId!, + view.model.appId, + ); + const overlay = ibiz.overlay.createDrawer( + (modal: IModal) => { + return h(resolveComponent('IBizDSLModelEditView'), { + modal, + context: resultContext, + params: resultParams, + caption: view.model.caption || action.caption, + codeName: appEntity?.codeName, + readonly, + }); + }, + undefined, + { placement: 'top', showClose: false } as any, + ); + overlay.present(); + const result: IModalData = await overlay.onWillDismiss(); + ibiz.uiDomainManager.destroy(id); + const actionResult: IUIActionResult = {}; + if (result.ok && result.params && result.params.isSave) { + actionResult.refresh = true; + actionResult.refreshMode = 1; + } + return actionResult; + } +} diff --git a/packages/model-design/src/ui-action/dsl-model-export-provider.ts b/packages/model-design/src/ui-action/dsl-model-export-provider.ts new file mode 100644 index 0000000000000000000000000000000000000000..826aef327efb75d33478ad4f23457c5e8e3fb8f6 --- /dev/null +++ b/packages/model-design/src/ui-action/dsl-model-export-provider.ts @@ -0,0 +1,87 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { h, resolveComponent } from 'vue'; +import { + IModal, + IUIActionResult, + IUILogicParams, + UIActionProviderBase, + convertNavData, + formatMultiData, +} from '@ibiz-template/runtime'; +import { IAppDEUIAction } from '@ibiz/model-core'; +import { notNilEmpty } from 'qx-util'; + +/** + * DSL模型导出 + * + * @export + * @class DSLModelExportProvider + * @extends {UIActionProviderBase} + */ +export class DSLModelExportProvider extends UIActionProviderBase { + async execAction( + action: IAppDEUIAction, + args: IUILogicParams, + ): Promise { + const { context, params, data, view } = args; + if (!ibiz.modelClipboard) return {}; + if (!Array.isArray(data) || data.length === 0) return {}; + // 是否是多数据 + const isMultiData = + ['MULTIKEY', 'MULTIDATA'].includes(action.actionTarget!) && + data.length > 0; + // 处理自定义导航上下文 + const resultContext = context.clone(); + const navContexts = action.navigateContexts; + if (notNilEmpty(navContexts)) { + Object.assign( + resultContext, + convertNavData( + navContexts, + isMultiData ? formatMultiData(navContexts, data) : data[0] || {}, + params, + context, + ), + ); + } + // 处理自定义导航参数 + const resultParams = {}; + const navParams = action.navigateParams; + if (notNilEmpty(navParams)) { + Object.assign( + resultParams, + convertNavData( + navParams, + isMultiData ? formatMultiData(navParams, data) : data[0] || {}, + params, + context, + ), + ); + } + const entity = await ibiz.hub.getAppDataEntity( + view.model.appDataEntityId!, + view.model.appId, + ); + ibiz.modelClipboard.createItem({ + type: 'dsl', + title: `${entity.logicName}-${entity.codeName}`, + codeName: entity.codeName!, + items: data, + }); + const overlay = ibiz.overlay.createDrawer( + (modal: IModal) => { + return h(resolveComponent('IBizModelClipboard'), { + modal, + type: 'dsl', + context: resultContext, + params: resultParams, + }); + }, + undefined, + { placement: 'right', width: 500, showClose: false } as any, + ); + overlay.present(); + await overlay.onWillDismiss(); + return {}; + } +} diff --git a/packages/model-design/src/ui-action/dsl-model-import-provider.ts b/packages/model-design/src/ui-action/dsl-model-import-provider.ts new file mode 100644 index 0000000000000000000000000000000000000000..7a7c44cb7331d676de61751a8f8bfe13b657fa7a --- /dev/null +++ b/packages/model-design/src/ui-action/dsl-model-import-provider.ts @@ -0,0 +1,82 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { h, resolveComponent } from 'vue'; +import { + IModal, + IUIActionResult, + IUILogicParams, + UIActionProviderBase, + convertNavData, + formatMultiData, +} from '@ibiz-template/runtime'; +import { IAppDEUIAction } from '@ibiz/model-core'; +import { notNilEmpty } from 'qx-util'; + +/** + * DSL模型导入 + * + * @export + * @class DSLModelImportProvider + * @extends {UIActionProviderBase} + */ +export class DSLModelImportProvider extends UIActionProviderBase { + async execAction( + action: IAppDEUIAction, + args: IUILogicParams, + ): Promise { + const { context, params, data, view } = args; + if (!ibiz.dslModelClipboardImportView) return {}; + // 是否是多数据 + const isMultiData = + ['MULTIKEY', 'MULTIDATA'].includes(action.actionTarget!) && + data.length > 0; + // 处理自定义导航上下文 + const resultContext = context.clone(); + const navContexts = action.navigateContexts; + if (notNilEmpty(navContexts)) { + Object.assign( + resultContext, + convertNavData( + navContexts, + isMultiData ? formatMultiData(navContexts, data) : data[0] || {}, + params, + context, + ), + ); + } + // 处理自定义导航参数 + const resultParams = {}; + const navParams = action.navigateParams; + if (notNilEmpty(navParams)) { + Object.assign( + resultParams, + convertNavData( + navParams, + isMultiData ? formatMultiData(navParams, data) : data[0] || {}, + params, + context, + ), + ); + } + const entity = await ibiz.hub.getAppDataEntity( + view.model.appDataEntityId!, + view.model.appId, + ); + ibiz.dslModelClipboardImportView.updateParams({ + codeName: entity.codeName, + }); + const overlay = ibiz.overlay.createDrawer( + (modal: IModal) => { + return h(resolveComponent('IBizDSLModelClipboardImportView'), { + modal, + context: resultContext, + params: resultParams, + }); + }, + undefined, + { placement: 'top', showClose: false } as any, + ); + overlay.present(); + await overlay.onWillDismiss(); + return { refresh: true, refreshMode: 1 }; + } +} diff --git a/packages/model-design/src/ui-action/index.ts b/packages/model-design/src/ui-action/index.ts index 630a4bd335906bc455a24963b1f181c7613792f2..da14e04292f21c09d9db0859bdd69658feb506b3 100644 --- a/packages/model-design/src/ui-action/index.ts +++ b/packages/model-design/src/ui-action/index.ts @@ -6,6 +6,9 @@ import { ModelCopyProvider } from './model-copy-provider'; import { ModelPasteProvider } from './model-paste-provider'; import { ModelCloneProvider } from './model-clone-provider'; import { OpenModelRuntimeProvider } from './open-model-runtime'; +import { DSLModelExportProvider } from './dsl-model-export-provider'; +import { DSLModelImportProvider } from './dsl-model-import-provider'; +import { DSLModelEditProvider } from './dsl-model-edit-provider'; export default { install(): void { @@ -38,5 +41,17 @@ export default { 'DEUIACTION_OPEN_MODEL_RUNTIME', () => openModelRuntimeProvider, ); + const dslModelExportProvider = new DSLModelExportProvider(); + registerUIActionProvider( + 'DEUIACTION_DSL_EXPORT', + () => dslModelExportProvider, + ); + const dslModelImportProvider = new DSLModelImportProvider(); + registerUIActionProvider( + 'DEUIACTION_DSL_IMPORT', + () => dslModelImportProvider, + ); + const dslModelEditProvider = new DSLModelEditProvider(); + registerUIActionProvider('DEUIACTION_DSL_EDIT', () => dslModelEditProvider); }, };