diff --git a/package.json b/package.json index 34417e8e6..ff94abd74 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "animate.css": "^4.1.1", "axios": "^1.6.8", "benz-amr-recorder": "^1.1.5", - "bpmn-js-token-simulation": "^0.10.0", + "bpmn-js-token-simulation": "^0.36.0", "camunda-bpmn-moddle": "^7.0.1", "cropperjs": "^1.6.1", "crypto-js": "^4.2.0", @@ -47,7 +47,7 @@ "driver.js": "^1.3.1", "echarts": "^5.5.0", "echarts-wordcloud": "^2.1.0", - "element-plus": "2.8.4", + "element-plus": "2.9.1", "fast-xml-parser": "^4.3.2", "highlight.js": "^11.9.0", "jsencrypt": "^3.3.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 226b5c237..50e9bf968 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -72,8 +72,8 @@ dependencies: specifier: ^2.1.0 version: 2.1.0(echarts@5.5.1) element-plus: - specifier: 2.8.4 - version: 2.8.4(vue@3.5.12) + specifier: 2.9.1 + version: 2.9.1(vue@3.5.12) fast-xml-parser: specifier: ^4.3.2 version: 4.5.0 @@ -2122,7 +2122,7 @@ packages: '@form-create/element-ui': 3.2.14(vue@3.5.12) '@form-create/utils': 3.2.14 codemirror: 6.65.7 - element-plus: 2.8.4(vue@3.5.12) + element-plus: 2.9.1(vue@3.5.12) vue: 3.5.12(typescript@5.3.3) vuedraggable: 4.1.0(vue@3.5.12) transitivePeerDependencies: @@ -5795,8 +5795,8 @@ packages: resolution: {integrity: sha512-nz88NNBsD7kQSAGGJyp8hS6xSPtWwqNogA0mjtc2nUYeEf3nURK9qpV18TuBdDmEDgVWotS8Wkzf+V52dSQ/LQ==, tarball: https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.5.67.tgz} dev: true - /element-plus@2.8.4(vue@3.5.12): - resolution: {integrity: sha512-ZlVAdUOoJliv4kW3ntWnnSHMT+u/Os7mXJjk2xzOlqNeHaI2/ozlF+R58ZCEak8ZnDi6+5A2viWEYRsq64IuiA==, tarball: https://registry.npmmirror.com/element-plus/-/element-plus-2.8.4.tgz} + /element-plus@2.9.1(vue@3.5.12): + resolution: {integrity: sha512-9Agqf/jt4Ugk7EZ6C5LME71sgkvauPCsnvJN12Xid2XVobjufxMGpRE4L7pS4luJMOmFAH3J0NgYEGZT5r+NDg==, tarball: https://registry.npmmirror.com/element-plus/-/element-plus-2.9.1.tgz} peerDependencies: vue: ^3.2.0 dependencies: diff --git a/src/api/login/index.ts b/src/api/login/index.ts index 33fddcabd..8c69d9bc9 100644 --- a/src/api/login/index.ts +++ b/src/api/login/index.ts @@ -22,11 +22,6 @@ export const register = (data: RegisterVO) => { return request.post({ url: '/system/auth/register', data }) } -// 刷新访问令牌 -export const refreshToken = () => { - return request.post({ url: '/system/auth/refresh-token?refreshToken=' + getRefreshToken() }) -} - // 使用租户名,获得租户编号 export const getTenantIdByName = (name: string) => { return request.get({ url: '/system/tenant/get-id-by-name?name=' + name }) @@ -76,12 +71,17 @@ export const socialAuthRedirect = (type: number, redirectUri: string) => { }) } // 获取验证图片以及 token -export const getCode = (data) => { +export const getCode = (data: any) => { debugger return request.postOriginal({ url: 'system/captcha/get', data }) } // 滑动或者点选验证 -export const reqCheck = (data) => { +export const reqCheck = (data: any) => { return request.postOriginal({ url: 'system/captcha/check', data }) } + +// 通过短信重置密码 +export const smsResetPassword = (data: any) => { + return request.post({ url: '/system/auth/sms-reset-password', data }) +} diff --git a/src/components/Echart/src/Echart.vue b/src/components/Echart/src/Echart.vue index fd3342dd0..bf22b864e 100644 --- a/src/components/Echart/src/Echart.vue +++ b/src/components/Echart/src/Echart.vue @@ -9,6 +9,10 @@ import { useAppStore } from '@/store/modules/app' import { isString } from '@/utils/is' import { useDesign } from '@/hooks/web/useDesign' +import 'echarts/lib/component/markPoint' +import 'echarts/lib/component/markLine' +import 'echarts/lib/component/markArea' + defineOptions({ name: 'EChart' }) const { getPrefixCls, variables } = useDesign() diff --git a/src/components/RouterSearch/index.vue b/src/components/RouterSearch/index.vue index ed2a08cc2..42a41744d 100644 --- a/src/components/RouterSearch/index.vue +++ b/src/components/RouterSearch/index.vue @@ -79,9 +79,14 @@ function remoteMethod(data) { function handleChange(path) { router.push({ path }) + hiddenSearch() hiddenTopSearch() } +function hiddenSearch() { + showSearch.value = false +} + function hiddenTopSearch() { showTopSearch.value = false } diff --git a/src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue b/src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue index 22e6073f4..ad42696ba 100644 --- a/src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue +++ b/src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue @@ -40,7 +40,7 @@ defineOptions({ name: 'SimpleProcessDesigner' }) -const emits = defineEmits(['success', 'init-finished']) // 保存成功事件 +const emits = defineEmits(['success']) // 保存成功事件 const props = defineProps({ modelId: { @@ -59,13 +59,12 @@ const props = defineProps({ startUserIds : { type: Array, required: false - }, - value: { - type: [String, Object], - required: false } }) +const processData = inject('processData') as Ref + + const loading = ref(false) const formFields = ref([]) const formType = ref(20) @@ -76,9 +75,6 @@ const deptOptions = ref([]) // 部门列表 const deptTreeOptions = ref() const userGroupOptions = ref([]) // 用户组列表 -// 添加当前值的引用 -const currentValue = ref() - provide('formFields', formFields) provide('formType', formType) provide('roleList', roleOptions) @@ -88,7 +84,8 @@ provide('deptList', deptOptions) provide('userGroupList', userGroupOptions) provide('deptTree', deptTreeOptions) provide('startUserIds', props.startUserIds) - +provide('tasks', []) +provide('processInstance', {}) const message = useMessage() // 国际化 const processNodeTree = ref() const errorDialogVisible = ref(false) @@ -112,70 +109,14 @@ const updateModel = () => { } } -// 加载流程数据 -const loadProcessData = async (data: any) => { - try { - if (data) { - const parsedData = typeof data === 'string' ? JSON.parse(data) : data - processNodeTree.value = parsedData - currentValue.value = parsedData - // 确保数据加载后刷新视图 - await nextTick() - if (simpleProcessModelRef.value?.refresh) { - await simpleProcessModelRef.value.refresh() - } - } - } catch (error) { - console.error('加载流程数据失败:', error) - } -} - -// 监听属性变化 -watch( - () => props.value, - async (newValue, oldValue) => { - if (newValue && newValue !== oldValue) { - await loadProcessData(newValue) - } - }, - { immediate: true, deep: true } -) - -// 监听流程节点树变化,自动保存 -watch( - () => processNodeTree.value, - async (newValue, oldValue) => { - if (newValue && oldValue && JSON.stringify(newValue) !== JSON.stringify(oldValue)) { - await saveSimpleFlowModel(newValue) - } - }, - { deep: true } -) const saveSimpleFlowModel = async (simpleModelNode: SimpleFlowNode) => { if (!simpleModelNode) { return } - // 校验节点 - errorNodes = [] - validateNode(simpleModelNode, errorNodes) - if (errorNodes.length > 0) { - errorDialogVisible.value = true - return - } - try { - if (props.modelId) { - // 编辑模式 - const data = { - id: props.modelId, - simpleModel: simpleModelNode - } - await updateBpmSimpleModel(data) - } - // 无论是编辑还是新建模式,都更新当前值并触发事件 - currentValue.value = simpleModelNode + processData.value = simpleModelNode emits('success', simpleModelNode) } catch (error) { console.error('保存失败:', error) @@ -246,61 +187,20 @@ onMounted(async () => { deptTreeOptions.value = handleTree(deptOptions.value as DeptApi.DeptVO[], 'id') // 获取用户组列表 userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList() - // 加载流程数据 - if (props.modelId) { - // 获取 SIMPLE 设计器模型 - const result = await getBpmSimpleModel(props.modelId) - if (result) { - await loadProcessData(result) - } else { - updateModel() - } - } else if (props.value) { - await loadProcessData(props.value) + if (processData.value) { + processNodeTree.value = processData?.value } else { updateModel() } } finally { loading.value = false - emits('init-finished') } }) const simpleProcessModelRef = ref() -/** 获取当前流程数据 */ -const getCurrentFlowData = async () => { - try { - if (simpleProcessModelRef.value) { - const data = await simpleProcessModelRef.value.getCurrentFlowData() - if (data) { - currentValue.value = data - return data - } - } - return currentValue.value - } catch (error) { - console.error('获取流程数据失败:', error) - return currentValue.value - } -} - -// 刷新方法 -const refresh = async () => { - try { - if (currentValue.value) { - await loadProcessData(currentValue.value) - } - } catch (error) { - console.error('刷新失败:', error) - } -} defineExpose({ - getCurrentFlowData, - updateModel, - loadProcessData, - refresh }) diff --git a/src/components/SimpleProcessDesignerV2/src/SimpleProcessModel.vue b/src/components/SimpleProcessDesignerV2/src/SimpleProcessModel.vue index ccd1f10d2..b9a264751 100644 --- a/src/components/SimpleProcessDesignerV2/src/SimpleProcessModel.vue +++ b/src/components/SimpleProcessDesignerV2/src/SimpleProcessModel.vue @@ -3,11 +3,31 @@
+ 导出 + 导入 + + {{ scaleValue }}% + + + + + + + + +
@@ -33,7 +53,8 @@ import ProcessNodeTree from './ProcessNodeTree.vue' import { SimpleFlowNode, NodeType, NODE_DEFAULT_TEXT } from './consts' import { useWatchNode } from './node' -import { ZoomOut, ZoomIn, ScaleToOriginal } from '@element-plus/icons-vue' +import { ZoomOut, ZoomIn, ScaleToOriginal, Select } from '@element-plus/icons-vue' +import { isString } from '@/utils/is' defineOptions({ name: 'SimpleProcessModel' @@ -85,6 +106,16 @@ const processReZoom = () => { const errorDialogVisible = ref(false) let errorNodes: SimpleFlowNode[] = [] +const saveSimpleFlowModel = async () => { + errorNodes = [] + validateNode(processNodeTree.value, errorNodes) + if (errorNodes.length > 0) { + errorDialogVisible.value = true + return + } + emits('save', processNodeTree.value) +} + // 校验节点设置。 暂时以 showText 为空 未节点错误配置 const validateNode = (node: SimpleFlowNode | undefined, errorNodes: SimpleFlowNode[]) => { if (node) { @@ -143,6 +174,36 @@ const getCurrentFlowData = async () => { defineExpose({ getCurrentFlowData }) + +const exportJson = () => { + const blob = new Blob([JSON.stringify(processNodeTree.value)]); + const tempLink = document.createElement('a'); // 创建a标签 + const href = window.URL.createObjectURL(blob); // 创建下载的链接 + //filename + const fileName = `model.json`; + tempLink.href = href; + tempLink.target = '_blank'; + tempLink.download = fileName; + document.body.appendChild(tempLink); + tempLink.click(); // 点击下载 + document.body.removeChild(tempLink); // 下载完成移除元素 + window.URL.revokeObjectURL(href); // 释放掉blob对象 +} +const importJson = () => { + refFile.value.click() +} +const refFile = ref() +// 加载本地文件 +const importLocalFile = () => { + const file = refFile.value.files[0] + const reader = new FileReader() + reader.readAsText(file) + reader.onload = function () { + if (isString(this.result)) { + processNodeTree.value = JSON.parse(this.result) + } + } +} diff --git a/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue b/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue index 9d2fa5ba6..5b3d14f43 100644 --- a/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue +++ b/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue @@ -308,28 +308,6 @@ const props = defineProps({ } }) -// 监听value变化,重新加载流程图 -watch( - () => props.value, - (newValue) => { - if (newValue && bpmnModeler) { - createNewDiagram(newValue) - } - }, - { immediate: true } -) - -// 监听processId和processName变化 -watch( - [() => props.processId, () => props.processName], - ([newId, newName]) => { - if (newId && newName && !props.value) { - createNewDiagram(null) - } - }, - { immediate: true } -) - provide('configGlobal', props) let bpmnModeler: any = null const defaultZoom = ref(1) @@ -480,6 +458,7 @@ const initModelListeners = () => { emit('commandStack-changed', event) emit('input', xml) emit('change', xml) + emit('save', xml) } catch (e: any) { console.error(`[Process Designer Warn]: ${e.message || e}`) } diff --git a/src/components/bpmnProcessDesigner/package/theme/process-designer.scss b/src/components/bpmnProcessDesigner/package/theme/process-designer.scss index b1ff0af3c..bca0258c2 100644 --- a/src/components/bpmnProcessDesigner/package/theme/process-designer.scss +++ b/src/components/bpmnProcessDesigner/package/theme/process-designer.scss @@ -1,6 +1,4 @@ @use 'bpmn-js-token-simulation/assets/css/bpmn-js-token-simulation.css'; -@use 'bpmn-js-token-simulation/assets/css/font-awesome.min.css'; -@use 'bpmn-js-token-simulation/assets/css/normalize.css'; // 边框被 token-simulation 样式覆盖了 .djs-palette { @@ -97,12 +95,12 @@ box-sizing: border-box; } } - svg { - width: 100%; - height: 100%; - min-height: 100%; - overflow: hidden; - } + // svg { + // width: 100%; + // height: 100%; + // min-height: 100%; + // overflow: hidden; + // } } } diff --git a/src/directives/permission/hasPermi.ts b/src/directives/permission/hasPermi.ts index 931f44b30..02e2fbc7e 100644 --- a/src/directives/permission/hasPermi.ts +++ b/src/directives/permission/hasPermi.ts @@ -5,18 +5,10 @@ const { t } = useI18n() // 国际化 export function hasPermi(app: App) { app.directive('hasPermi', (el, binding) => { - const { wsCache } = useCache() const { value } = binding - const all_permission = '*:*:*' - const userInfo = wsCache.get(CACHE_KEY.USER) - const permissions = userInfo?.permissions || [] if (value && value instanceof Array && value.length > 0) { - const permissionFlag = value - - const hasPermissions = permissions.some((permission: string) => { - return all_permission === permission || permissionFlag.includes(permission) - }) + const hasPermissions = hasPermission(value) if (!hasPermissions) { el.parentNode && el.parentNode.removeChild(el) @@ -26,3 +18,14 @@ export function hasPermi(app: App) { } }) } + +export const hasPermission = (permission: string[]) => { + const { wsCache } = useCache() + const all_permission = '*:*:*' + const userInfo = wsCache.get(CACHE_KEY.USER) + const permissions = userInfo?.permissions || [] + + return permissions.some((p: string) => { + return all_permission === p || permission.includes(p) + }) +} \ No newline at end of file diff --git a/src/layout/components/Footer/src/Footer.vue b/src/layout/components/Footer/src/Footer.vue index 62302fca0..98ce7e56b 100644 --- a/src/layout/components/Footer/src/Footer.vue +++ b/src/layout/components/Footer/src/Footer.vue @@ -12,6 +12,9 @@ const prefixCls = getPrefixCls('footer') const appStore = useAppStore() const title = computed(() => appStore.getTitle) + +// 添加当前年份计算属性 +const currentYear = computed(() => new Date().getFullYear()) diff --git a/src/layout/components/TagsView/src/TagsView.vue b/src/layout/components/TagsView/src/TagsView.vue index dcbb90fdb..3bfb69df8 100644 --- a/src/layout/components/TagsView/src/TagsView.vue +++ b/src/layout/components/TagsView/src/TagsView.vue @@ -243,7 +243,7 @@ const move = (to: number) => { start() } -onMounted(() => { +onBeforeMount(() => { initTags() addTags() }) diff --git a/src/locales/en.ts b/src/locales/en.ts index 6562c9b75..505cfd80d 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -140,7 +140,10 @@ export default { btnQRCode: 'QR code sign in', qrcode: 'Scan the QR code to log in', btnRegister: 'Sign up', - SmsSendMsg: 'code has been sent' + SmsSendMsg: 'code has been sent', + resetPassword: "Reset Password", + resetPasswordSuccess: "Reset Password Success", + invalidTenantName:"Invalid Tenant Name" }, captcha: { verification: 'Please complete security verification', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index b9deb3f24..130d56528 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -141,7 +141,10 @@ export default { btnQRCode: '二维码登录', qrcode: '扫描二维码登录', btnRegister: '注册', - SmsSendMsg: '验证码已发送' + SmsSendMsg: '验证码已发送', + resetPassword: "重置密码", + resetPasswordSuccess: "重置密码成功", + invalidTenantName: "无效的租户名称" }, captcha: { verification: '请完成安全验证', diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index 806f954da..344660794 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -344,7 +344,7 @@ const remainingRouter: AppRouteRecordRaw[] = [ } }, { - path: 'manager/model/update/:id', + path: 'manager/model/:type/:id', component: () => import('@/views/bpm/model/form/index.vue'), name: 'BpmModelUpdate', meta: { diff --git a/src/utils/routerHelper.ts b/src/utils/routerHelper.ts index b65f93a0c..f9f95c43e 100644 --- a/src/utils/routerHelper.ts +++ b/src/utils/routerHelper.ts @@ -73,7 +73,7 @@ export const generateRoute = (routes: AppCustomRouteRecordRaw[]): AppRouteRecord noCache: !route.keepAlive, alwaysShow: route.children && - route.children.length === 1 && + route.children.length > 0 && (route.alwaysShow !== undefined ? route.alwaysShow : true) } as any // 特殊逻辑:如果后端配置的 MenuDO.component 包含 ?,则表示需要传递参数 @@ -100,7 +100,6 @@ export const generateRoute = (routes: AppCustomRouteRecordRaw[]): AppRouteRecord //处理顶级非目录路由 if (!route.children && route.parentId == 0 && route.component) { data.component = Layout - data.meta = {} data.name = toCamelCase(route.path, true) + 'Parent' data.redirect = '' meta.alwaysShow = true diff --git a/src/views/Login/Login.vue b/src/views/Login/Login.vue index ff6f068a7..b2ff3809c 100644 --- a/src/views/Login/Login.vue +++ b/src/views/Login/Login.vue @@ -59,6 +59,8 @@ + +
@@ -73,7 +75,7 @@ import { useAppStore } from '@/store/modules/app' import { ThemeSwitch } from '@/layout/components/ThemeSwitch' import { LocaleDropdown } from '@/layout/components/LocaleDropdown' -import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue } from './components' +import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue, ForgetPasswordForm } from './components' defineOptions({ name: 'Login' }) diff --git a/src/views/Login/components/ForgetPasswordForm.vue b/src/views/Login/components/ForgetPasswordForm.vue new file mode 100644 index 000000000..0b6c56a72 --- /dev/null +++ b/src/views/Login/components/ForgetPasswordForm.vue @@ -0,0 +1,278 @@ + + + + diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue index 21ecd824c..193f47817 100644 --- a/src/views/Login/components/LoginForm.vue +++ b/src/views/Login/components/LoginForm.vue @@ -59,7 +59,13 @@ - {{ t('login.forgetPassword') }} + + {{ t('login.forgetPassword') }} + diff --git a/src/views/Login/components/index.ts b/src/views/Login/components/index.ts index 204ad73d0..7c42415ce 100644 --- a/src/views/Login/components/index.ts +++ b/src/views/Login/components/index.ts @@ -4,5 +4,6 @@ import LoginFormTitle from './LoginFormTitle.vue' import RegisterForm from './RegisterForm.vue' import QrCodeForm from './QrCodeForm.vue' import SSOLoginVue from './SSOLogin.vue' +import ForgetPasswordForm from './ForgetPasswordForm.vue' -export { LoginForm, MobileForm, LoginFormTitle, RegisterForm, QrCodeForm, SSOLoginVue } +export { LoginForm, MobileForm, LoginFormTitle, RegisterForm, QrCodeForm, SSOLoginVue, ForgetPasswordForm } diff --git a/src/views/bpm/model/CategoryDraggableModel.vue b/src/views/bpm/model/CategoryDraggableModel.vue index f3b5a422f..8fe6e14d5 100644 --- a/src/views/bpm/model/CategoryDraggableModel.vue +++ b/src/views/bpm/model/CategoryDraggableModel.vue @@ -163,6 +163,15 @@ > 修改 + + 复制 + { } else { push({ name: 'BpmModelUpdate', - params: { id } + params: { id, type } }) } } diff --git a/src/views/bpm/model/editor/index.vue b/src/views/bpm/model/editor/index.vue index 37eff739e..101ea1b87 100644 --- a/src/views/bpm/model/editor/index.vue +++ b/src/views/bpm/model/editor/index.vue @@ -15,7 +15,7 @@ /> () @@ -51,10 +51,11 @@ const formType = ref(20) provide('formFields', formFields) provide('formType', formType) -const xmlString = ref('') // BPMN XML +//注入 流程数据 +const xmlString = inject('processData') as Ref + const modeler = shallowRef() // BPMN Modeler const processDesigner = ref() -const isModelerReady = ref(false) const controlForm = ref({ simulation: true, labelEditing: false, @@ -65,154 +66,27 @@ const controlForm = ref({ }) const model = ref() // 流程模型的信息 -// 初始化 bpmnInstances -const initBpmnInstances = () => { - if (!modeler.value) return false - try { - const instances = { - modeler: modeler.value, - modeling: modeler.value.get('modeling'), - moddle: modeler.value.get('moddle'), - eventBus: modeler.value.get('eventBus'), - bpmnFactory: modeler.value.get('bpmnFactory'), - elementFactory: modeler.value.get('elementFactory'), - elementRegistry: modeler.value.get('elementRegistry'), - replace: modeler.value.get('replace'), - selection: modeler.value.get('selection') - } - - // 检查所有实例是否都存在 - return Object.values(instances).every((instance) => instance) - } catch (error) { - console.error('初始化 bpmnInstances 失败:', error) - return false - } -} /** 初始化 modeler */ const initModeler = async (item) => { - try { - modeler.value = item - // 等待 modeler 初始化完成 - await nextTick() - - // 确保 modeler 的所有实例都已经准备好 - if (initBpmnInstances()) { - isModelerReady.value = true - emit('init-finished') - - // 初始化完成后,设置初始值 - if (props.modelId) { - // 编辑模式 - const data = await ModelApi.getModel(props.modelId) - model.value = { - ...data, - bpmnXml: undefined // 清空 bpmnXml 属性 - } - xmlString.value = data.bpmnXml || getDefaultBpmnXml(data.key, data.name) - } else if (props.modelKey && props.modelName) { - // 新建模式 - xmlString.value = props.value || getDefaultBpmnXml(props.modelKey, props.modelName) - model.value = { - key: props.modelKey, - name: props.modelName - } as ModelApi.ModelVO - } - - // 导入XML并刷新视图 - await nextTick() - try { - await modeler.value.importXML(xmlString.value) - if (processDesigner.value?.refresh) { - processDesigner.value.refresh() - } - } catch (error) { - console.error('导入XML失败:', error) - } - } else { - console.error('modeler 实例未完全初始化') - } - } catch (error) { - console.error('初始化 modeler 失败:', error) - } + modeler.value = item } -/** 获取默认的BPMN XML */ -const getDefaultBpmnXml = (key: string, name: string) => { - return ` - - - - - -` -} /** 添加/修改模型 */ const save = async (bpmnXml: string) => { try { xmlString.value = bpmnXml - if (props.modelId) { - // 编辑模式 - const data = { - ...model.value, - bpmnXml: bpmnXml - } as unknown as ModelApi.ModelVO - await ModelApi.updateModelBpmn(data) - emit('success') - } else { - // 新建模式,直接返回XML - emit('success', bpmnXml) - } + emit('success', bpmnXml) } catch (error) { console.error('保存失败:', error) message.error('保存失败') } } -// 监听 key、name 和 value 的变化 -watch( - [() => props.modelKey, () => props.modelName, () => props.value], - async ([newKey, newName, newValue]) => { - if (!props.modelId && isModelerReady.value) { - let shouldRefresh = false - - if (newKey && newName) { - const newXml = newValue || getDefaultBpmnXml(newKey, newName) - if (newXml !== xmlString.value) { - xmlString.value = newXml - shouldRefresh = true - } - model.value = { - ...model.value, - key: newKey, - name: newName - } as ModelApi.ModelVO - } else if (newValue && newValue !== xmlString.value) { - xmlString.value = newValue - shouldRefresh = true - } - - if (shouldRefresh) { - // 确保更新后重新渲染 - await nextTick() - if (processDesigner.value?.refresh) { - try { - await modeler.value?.importXML(xmlString.value) - processDesigner.value.refresh() - } catch (error) { - console.error('导入XML失败:', error) - } - } - } - } - }, - { deep: true } -) // 在组件卸载时清理 onBeforeUnmount(() => { - isModelerReady.value = false modeler.value = null // 清理全局实例 const w = window as any @@ -221,54 +95,7 @@ onBeforeUnmount(() => { } }) -/** 获取 XML 字符串 */ -const saveXML = async () => { - if (!modeler.value) { - return { xml: xmlString.value } - } - try { - const result = await modeler.value.saveXML({ format: true }) - xmlString.value = result.xml - return result - } catch (error) { - console.error('获取XML失败:', error) - return { xml: xmlString.value } - } -} -/** 获取SVG字符串 */ -const saveSVG = async () => { - if (!modeler.value) { - return { svg: undefined } - } - try { - return await modeler.value.saveSVG() - } catch (error) { - console.error('获取SVG失败:', error) - return { svg: undefined } - } -} - -/** 刷新视图 */ -const refresh = async () => { - if (processDesigner.value?.refresh && modeler.value) { - try { - await modeler.value.importXML(xmlString.value) - processDesigner.value.refresh() - } catch (error) { - console.error('刷新视图失败:', error) - } - } -} - -// 暴露必要的属性和方法给父组件 -defineExpose({ - modeler, - isModelerReady, - saveXML, - saveSVG, - refresh -}) diff --git a/src/views/infra/file/index.vue b/src/views/infra/file/index.vue index 3fcda6e8d..e67ad51b7 100644 --- a/src/views/infra/file/index.vue +++ b/src/views/infra/file/index.vue @@ -95,6 +95,9 @@ />