diff --git a/src/components/SimpleProcessDesignerV2/src/SimpleProcessModel.vue b/src/components/SimpleProcessDesignerV2/src/SimpleProcessModel.vue index 23f2d791..ad0c7b19 100644 --- a/src/components/SimpleProcessDesignerV2/src/SimpleProcessModel.vue +++ b/src/components/SimpleProcessDesignerV2/src/SimpleProcessModel.vue @@ -51,6 +51,7 @@ import { SimpleFlowNode, NodeType, NODE_DEFAULT_TEXT } from './consts' import { useWatchNode } from './node' import { ZoomOut, ZoomIn, ScaleToOriginal } from '@element-plus/icons-vue' import { isString } from '@/utils/is' +import download from "@/utils/download"; defineOptions({ name: 'SimpleProcessModel' @@ -174,18 +175,7 @@ defineExpose({ /** 导出 JSON */ // TODO @zws:增加一个 download 里面搞个 json 更好 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 对象 + download.json(new Blob([JSON.stringify(processNodeTree.value)]), 'model.json') } /** 导入 JSON */ @@ -200,6 +190,7 @@ const importLocalFile = () => { reader.onload = function () { if (isString(this.result)) { processNodeTree.value = JSON.parse(this.result) + emits('save', processNodeTree.value) } } } diff --git a/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue b/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue index 5b3d14f4..83d40fbf 100644 --- a/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue +++ b/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue @@ -547,6 +547,7 @@ const importLocalFile = () => { reader.onload = function () { let xmlStr = this.result createNewDiagram(xmlStr) + emit('save', xmlStr) } } /* ------------------------------------------------ refs methods ------------------------------------------------------ */ diff --git a/src/components/bpmnProcessDesigner/package/penal/base/ElementBaseInfo.vue b/src/components/bpmnProcessDesigner/package/penal/base/ElementBaseInfo.vue index 70ad4f8b..3172338d 100644 --- a/src/components/bpmnProcessDesigner/package/penal/base/ElementBaseInfo.vue +++ b/src/components/bpmnProcessDesigner/package/penal/base/ElementBaseInfo.vue @@ -152,6 +152,9 @@ watch( handleKeyUpdate(props.model.key) handleNameUpdate(props.model.name) } + }, + { + immediate: true } ) diff --git a/src/layout/components/TagsView/src/TagsView.vue b/src/layout/components/TagsView/src/TagsView.vue index 3bfb69df..ce041b2b 100644 --- a/src/layout/components/TagsView/src/TagsView.vue +++ b/src/layout/components/TagsView/src/TagsView.vue @@ -12,6 +12,11 @@ import { useDesign } from '@/hooks/web/useDesign' import { useTemplateRefsList } from '@vueuse/core' import { ElScrollbar } from 'element-plus' import { useScrollTo } from '@/hooks/event/useScrollTo' +import { useTagsView } from '@/hooks/web/useTagsView' +import { cloneDeep } from 'lodash-es' + + +defineOptions({ name: 'TagsView' }) const { getPrefixCls } = useDesign() @@ -19,7 +24,9 @@ const prefixCls = getPrefixCls('tags-view') const { t } = useI18n() -const { currentRoute, push, replace } = useRouter() +const { currentRoute, push } = useRouter() + +const { closeAll, closeLeft, closeRight, closeOther, closeCurrent, refreshPage } = useTagsView() const permissionStore = usePermissionStore() @@ -31,6 +38,10 @@ const visitedViews = computed(() => tagsViewStore.getVisitedViews) const affixTagArr = ref([]) +const selectedTag = computed(() => tagsViewStore.getSelectedTag) + +const setSelectTag = tagsViewStore.setSelectedTag + const appStore = useAppStore() const tagsViewImmerse = computed(() => appStore.getTagsViewImmerse) @@ -45,66 +56,30 @@ const initTags = () => { for (const tag of unref(affixTagArr)) { // Must have tag name if (tag.name) { - tagsViewStore.addVisitedView(tag) + tagsViewStore.addVisitedView(cloneDeep(tag)) } } } -const selectedTag = ref() - // 新增tag const addTags = () => { const { name } = unref(currentRoute) if (name) { - selectedTag.value = unref(currentRoute) + setSelectTag(unref(currentRoute)) tagsViewStore.addView(unref(currentRoute)) } - return false } // 关闭选中的tag const closeSelectedTag = (view: RouteLocationNormalizedLoaded) => { - if (view?.meta?.affix) return - tagsViewStore.delView(view) - if (isActive(view)) { - toLastView() - } -} - -// 关闭全部 -const closeAllTags = () => { - tagsViewStore.delAllViews() - toLastView() -} - -// 关闭其它 -const closeOthersTags = () => { - tagsViewStore.delOthersViews(unref(selectedTag) as RouteLocationNormalizedLoaded) -} - -// 重新加载 -const refreshSelectedTag = async (view?: RouteLocationNormalizedLoaded) => { - if (!view) return - tagsViewStore.delCachedView() - const { path, query } = view - await nextTick() - replace({ - path: '/redirect' + path, - query: query + closeCurrent(view, () => { + if (isActive(view)) { + toLastView() + } }) } -// 关闭左侧 -const closeLeftTags = () => { - tagsViewStore.delLeftViews(unref(selectedTag) as RouteLocationNormalizedLoaded) -} - -// 关闭右侧 -const closeRightTags = () => { - tagsViewStore.delRightViews(unref(selectedTag) as RouteLocationNormalizedLoaded) -} - -// 跳转到最后一个 +// 去最后一个 const toLastView = () => { const visitedViews = tagsViewStore.getVisitedViews const latestView = visitedViews.slice(-1)[0] @@ -118,11 +93,38 @@ const toLastView = () => { addTags() return } - // TODO: You can set another route - push('/') + // You can set another route + push(permissionStore.getAddRouters[0].path) } } +// 关闭全部 +const closeAllTags = () => { + closeAll(() => { + toLastView() + }) +} + +// 关闭其它 +const closeOthersTags = () => { + closeOther() +} + +// 重新加载 +const refreshSelectedTag = async (view?: RouteLocationNormalizedLoaded) => { + refreshPage(view) +} + +// 关闭左侧 +const closeLeftTags = () => { + closeLeft() +} + +// 关闭右侧 +const closeRightTags = () => { + closeRight() +} + // 滚动到选中的tag const moveToCurrentTag = async () => { await nextTick() @@ -209,13 +211,14 @@ const isActive = (route: RouteLocationNormalizedLoaded): boolean => { // 所有右键菜单组件的元素 const itemRefs = useTemplateRefsList>() -// 右键菜单装填改变的时候 +// 右键菜单状态改变的时候 const visibleChange = (visible: boolean, tagItem: RouteLocationNormalizedLoaded) => { if (visible) { for (const v of unref(itemRefs)) { const elDropdownMenuRef = v.elDropdownMenuRef if (tagItem.fullPath !== v.tagItem.fullPath) { elDropdownMenuRef?.handleClose() + setSelectTag(tagItem) } } } @@ -243,6 +246,16 @@ const move = (to: number) => { start() } +const canShowIcon = (item: RouteLocationNormalizedLoaded) => { + if ( + (item?.matched?.[1]?.meta?.icon && unref(tagsViewIcon)) || + (item?.meta?.affix && unref(tagsViewIcon) && item?.meta?.icon) + ) { + return true + } + return false +} + onBeforeMount(() => { initTags() addTags() diff --git a/src/store/modules/tagsView.ts b/src/store/modules/tagsView.ts index 4368efe0..f565ef95 100644 --- a/src/store/modules/tagsView.ts +++ b/src/store/modules/tagsView.ts @@ -4,16 +4,19 @@ import { getRawRoute } from '@/utils/routerHelper' import { defineStore } from 'pinia' import { store } from '../index' import { findIndex } from '@/utils' +import { useUserStoreWithOut } from './user' export interface TagsViewState { visitedViews: RouteLocationNormalizedLoaded[] cachedViews: Set + selectedTag?: RouteLocationNormalizedLoaded } export const useTagsViewStore = defineStore('tagsView', { state: (): TagsViewState => ({ visitedViews: [], - cachedViews: new Set() + cachedViews: new Set(), + selectedTag: undefined }), getters: { getVisitedViews(): RouteLocationNormalizedLoaded[] { @@ -21,6 +24,9 @@ export const useTagsViewStore = defineStore('tagsView', { }, getCachedViews(): string[] { return Array.from(this.cachedViews) + }, + getSelectedTag(): RouteLocationNormalizedLoaded | undefined { + return this.selectedTag } }, actions: { @@ -98,8 +104,12 @@ export const useTagsViewStore = defineStore('tagsView', { }, // 删除所有tag delAllVisitedViews() { + const userStore = useUserStoreWithOut() + // const affixTags = this.visitedViews.filter((tag) => tag.meta.affix) - this.visitedViews = [] + this.visitedViews = userStore.getUser + ? this.visitedViews.filter((tag) => tag?.meta?.affix) + : [] }, // 删除其他 delOthersViews(view: RouteLocationNormalizedLoaded) { @@ -145,6 +155,18 @@ export const useTagsViewStore = defineStore('tagsView', { break } } + }, + // 设置当前选中的tag + setSelectedTag(tag: RouteLocationNormalizedLoaded) { + this.selectedTag = tag + }, + setTitle(title: string, path?: string) { + for (const v of this.visitedViews) { + if (v.path === (path ?? this.selectedTag?.path)) { + v.meta.title = title + break + } + } } }, persist: false diff --git a/src/utils/download.ts b/src/utils/download.ts index a2a6b49e..32fc624b 100644 --- a/src/utils/download.ts +++ b/src/utils/download.ts @@ -33,6 +33,10 @@ const download = { markdown: (data: Blob, fileName: string) => { download0(data, fileName, 'text/markdown') }, + // 下载 Json 方法 + json: (data: Blob, fileName: string) => { + download0(data, fileName, 'application/json') + }, // 下载图片(允许跨域) image: ({ url, diff --git a/src/views/bpm/model/CategoryDraggableModel.vue b/src/views/bpm/model/CategoryDraggableModel.vue index 99302a9d..1a2416b0 100644 --- a/src/views/bpm/model/CategoryDraggableModel.vue +++ b/src/views/bpm/model/CategoryDraggableModel.vue @@ -262,6 +262,7 @@ import { checkPermi } from '@/utils/permission' import { useUserStoreWithOut } from '@/store/modules/user' import { useAppStore } from '@/store/modules/app' import { cloneDeep } from 'lodash-es' +import {useTagsView} from "@/hooks/web/useTagsView"; defineOptions({ name: 'BpmModel' }) @@ -498,6 +499,7 @@ const handleDeleteCategory = async () => { } catch {} } +const tagsView = useTagsView(); /** 添加流程模型弹窗 */ const modelFormRef = ref() const openModelForm = (type: string, id?: number) => { @@ -507,6 +509,10 @@ const openModelForm = (type: string, id?: number) => { push({ name: 'BpmModelUpdate', params: { id, type } + }).then((_) => { + if (type === 'copy') { + tagsView.setTitle('复制流程') + } }) } } diff --git a/src/views/bpm/model/editor/index.vue b/src/views/bpm/model/editor/index.vue index b91c250e..1076cf56 100644 --- a/src/views/bpm/model/editor/index.vue +++ b/src/views/bpm/model/editor/index.vue @@ -12,6 +12,8 @@ :additionalModel="controlForm.additionalModel" :model="model" @save="save" + :process-id="modelKey" + :process-name="modelName" /> () // 流程模型的信息 /** 初始化 modeler */ // TODO @zws:需要初始化,不然首次创建后,无法发布!相当于说,key、name 要去赋值下 const initModeler = async (item) => { + //先初始化模型数据 + model.value = modelData.value modeler.value = item } diff --git a/src/views/bpm/model/form/index.vue b/src/views/bpm/model/form/index.vue index 0d20e7ce..43e5c0a7 100644 --- a/src/views/bpm/model/form/index.vue +++ b/src/views/bpm/model/form/index.vue @@ -145,6 +145,7 @@ const formData: any = ref({ const processData = ref() provide('processData', processData) +provide('modelData', formData) // 数据列表 const formList = ref([]) @@ -160,6 +161,8 @@ const initData = async () => { // 复制场景 if (route.params.type === 'copy') { delete formData.value.id + formData.value.name += '副本' + formData.value.key += '_copy' } } else { // 新增场景