Commit 7f4a27c3 by pangchong

chore(deps): 移除项目中过时的bpmn相关依赖

- 从 package-lock.json 中删除了 bpmn-js 及其相关包
- 移除了 camunda-bpmn-moddle 和 bpmn-js-properties-panel
- 同时清理了与 bpmn 生态相关的多个子依赖
- 删除了一些与 bpmn 无关的冗余依赖如 docx-preview
- 优化了依赖列表,减小包体积和复杂度
parent 6ddae59a
......@@ -17,16 +17,11 @@
},
"dependencies": {
"@alova/scene-vue": "^1.6.2",
"@bpmn-io/properties-panel": "^3.40.4",
"@vicons/ionicons5": "^0.13.0",
"@vueuse/core": "^14.3.0",
"alova": "^3.5.0",
"bpmn-js": "^17.11.1",
"bpmn-js-properties-panel": "^5.53.0",
"camunda-bpmn-moddle": "^7.0.1",
"dayjs": "^1.11.19",
"diff": "^7.0.0",
"docx-preview": "^0.3.7",
"less": "^4.5.1",
"lodash-es": "^4.18.1",
"mammoth": "^1.11.0",
......@@ -38,8 +33,7 @@
"vue": "^3.5.25",
"vue-i18n": "^11.2.8",
"vue-router": "^5.0.3",
"vuedraggable": "^4.1.0",
"xlsx": "^0.18.5"
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@commitlint/cli": "^19.8.0",
......
......@@ -605,6 +605,107 @@ export const useEditorStore = defineStore('editor', {
return newNodes.length
},
insertXmlNodeFragment(fragment: XmlNode, mode: 'above' | 'below' | 'inside' | 'replace', targetNodeId?: string) {
const targetId = targetNodeId || this.selectedNodeId
if (!this.xmlTree || !targetId) {
throw new Error('请先选择一个目标节点!')
}
const appStore = useAppStore()
if (!appStore.autoExpandOnInsert) {
this.skipExpandOnSelect = true
}
const item = this.nodeMap.get(targetId)
if (!item) {
throw new Error('当前的目标节点无效!')
}
const { node: targetNode, parent: parentNode } = item
// 深度复制一份片段以消除响应式副作用,并且生成全新的 UUID
const deepCloneWithNewIds = (node: XmlNode, newParentId: string | null): XmlNode => {
const idMap = new Map<string, string>()
const clone = (n: XmlNode, parentId: string | null): XmlNode => {
const newId = crypto.randomUUID()
idMap.set(n.id, newId)
const children = n.children.map((child) => clone(child, newId))
const mixedContent = n.mixedContent.map((m) => {
if (m.type === 'element' && m.nodeId) {
return { ...m, nodeId: idMap.get(m.nodeId) || m.nodeId }
}
return { ...m }
})
return {
...n,
id: newId,
parentId,
attributes: { ...n.attributes },
mixedContent,
children
}
}
return clone(node, newParentId)
}
// 确定被插入的目标父节点
let destParentNode: XmlNode
if (mode === 'above' || mode === 'below' || mode === 'replace') {
if (!parentNode) {
throw new Error('无法操作根节点')
}
destParentNode = parentNode
} else {
destParentNode = targetNode
}
// 严格校验 DTD 规则约束
const tagName = fragment.tagName
const existingCount = destParentNode.children.filter((c) => c.tagName === tagName).length
if (!canAddChild(destParentNode.tagName, tagName, existingCount)) {
throw new Error(`DTD 校验失败: 节点 <${destParentNode.tagName}> 无法接受子元素 <${tagName}>`)
}
// 进行复制与 parentId 关联
const clonedNode = deepCloneWithNewIds(fragment, destParentNode.id)
this.saveSnapshot()
// 追加或替换到指定位置并调整选中焦点
if (mode === 'above') {
const index = destParentNode.children.findIndex((c) => c.id === targetId)
if (index !== -1) {
destParentNode.children.splice(index, 0, clonedNode)
} else {
destParentNode.children.unshift(clonedNode)
}
} else if (mode === 'below') {
const index = destParentNode.children.findIndex((c) => c.id === targetId)
if (index !== -1) {
destParentNode.children.splice(index + 1, 0, clonedNode)
} else {
destParentNode.children.push(clonedNode)
}
} else if (mode === 'replace') {
const index = destParentNode.children.findIndex((c) => c.id === targetId)
if (index !== -1) {
destParentNode.children.splice(index, 1, clonedNode)
}
} else {
// inside
destParentNode.children.push(clonedNode)
}
this.selectedNodeId = clonedNode.id
this.handleNodeInsertion(clonedNode)
this.rebuildNodeMap()
if (!appStore.autoExpandOnInsert) {
nextTick(() => {
this.skipExpandOnSelect = false
})
}
},
setXmlTree(tree: XmlNode) {
this.xmlTree = tree
this.selectedNodeId = tree.id
......
import type { XmlNode } from '@/types/xmlNode'
import type { StashState, StashItem } from './types'
export const useStashStore = defineStore('stash', {
state: (): StashState => ({
items: []
}),
actions: {
addStash(name: string, type: 'full' | 'fragment', node: XmlNode) {
const timeStr = formatDateTime(new Date())
const newItem: StashItem = {
id: crypto.randomUUID(),
name: name.trim() || `${type === 'full' ? '完整XML' : '片段'} - ${node.tagName} (${timeStr})`,
type,
time: timeStr,
xmlNode: JSON.parse(JSON.stringify(node))
}
this.items.unshift(newItem)
return newItem
},
removeStash(id: string) {
this.items = this.items.filter((item) => item.id !== id)
},
renameStash(id: string, newName: string) {
const item = this.items.find((i) => i.id === id)
if (item && newName.trim()) {
item.name = newName.trim()
}
},
clearStash() {
this.items = []
}
},
persist: true
})
export * from './types'
import type { XmlNode } from '@/types/xmlNode'
export interface StashItem {
id: string
name: string
type: 'full' | 'fragment'
time: string
xmlNode: XmlNode
}
export interface StashState {
items: StashItem[]
}
export const FRAGMENT_OPTIONS = [
{ label: '作为当前节点子元素插入 (内部)', key: 'inside' },
{ label: '替换当前选中的节点', key: 'replace' },
{ label: '在当前节点上方插入 (兄弟)', key: 'above' },
{ label: '在当前节点下方插入 (兄弟)', key: 'below' }
]
......@@ -304,6 +304,14 @@
<n-icon class="text-base"><git-compare-outline /></n-icon>
<span class="text-xs font-medium">对比工卡</span>
</button>
<button
type="button"
class="toolbar-btn flex items-center gap-1.5 px-2.5 h-7 rounded text-color2 hover:bg-fill-2 active:bg-fill-3 transition-colors select-none focus:outline-none flex-shrink-0"
@click="stashModalRef?.open()"
>
<n-icon class="text-base"><archive-outline /></n-icon>
<span class="text-xs font-medium">本地暂存</span>
</button>
</div>
<div class="w-px h-5 flex-shrink-0 mx-3" style="background: #d0d0d0"></div>
......@@ -452,6 +460,9 @@
<!-- 插入模板弹窗 -->
<TemplateSelectModal ref="templateSelectModalRef" />
<!-- 本地暂存历史弹窗 -->
<StashModal ref="stashModalRef" />
</div>
</template>
......@@ -471,7 +482,8 @@ import {
SyncOutline,
CheckmarkCircleOutline,
SettingsOutline,
GitCompareOutline
GitCompareOutline,
ArchiveOutline
} from '@vicons/ionicons5'
import { useEditorToolbar } from './functionals'
import { GREEN_BUTTONS } from './constants'
......@@ -486,6 +498,7 @@ import ExtractTranslateModal from './components/ExtractTranslateModal/index.vue'
import SearchTranslateModal from './components/SearchTranslateModal/index.vue'
import CompareModal from './components/CompareModal/index.vue'
import TemplateSelectModal from './components/TemplateSelectModal/index.vue'
import StashModal from './components/StashModal/index.vue'
const emit = defineEmits(['save', 'validate', 'export', 'preview', 'download-html'])
......@@ -519,6 +532,7 @@ const {
const insertFragmentModalRef = ref<any>(null)
const compareModalRef = ref<any>(null)
const stashModalRef = ref<any>(null)
</script>
<style scoped>
......
import { useStashStore } from '@/store/stash'
import type { XmlNode } from '@/types/xmlNode'
import {
stashModalVisible,
stashNodeName,
stashDefaultName,
stashTargetNode
} from '../../../functionals'
export const useStashNodeModal = () => {
const handleConfirm = () => {
if (!stashTargetNode.value) return
const stashStore = useStashStore()
const stashName = stashNodeName.value.trim() || stashDefaultName.value
stashStore.addStash(stashName, 'fragment', stashTargetNode.value)
window.$message?.success(`已本地暂存片段:${stashTargetNode.value.tagName === '#text' ? '文本节点' : stashTargetNode.value.tagName}`)
stashModalVisible.value = false
}
const open = (defaultName: string, node: XmlNode) => {
stashDefaultName.value = defaultName
stashNodeName.value = ''
stashTargetNode.value = node
stashModalVisible.value = true
}
return {
stashModalVisible,
stashNodeName,
stashDefaultName,
handleConfirm,
open
}
}
<template>
<CommonModal
v-model="stashModalVisible"
title="新建本地暂存"
:width="400"
@confirm="handleConfirm"
>
<div class="pt-3">
<n-input v-model:value="stashNodeName" :placeholder="stashDefaultName" autofocus />
</div>
</CommonModal>
</template>
<script setup lang="ts">
import { useStashNodeModal } from './functionals'
const { stashModalVisible, stashNodeName, stashDefaultName, handleConfirm, open } = useStashNodeModal()
defineExpose({ open })
</script>
......@@ -13,10 +13,12 @@ import {
FolderOpenOutline,
DocumentTextOutline,
CodeWorkingOutline,
LanguageOutline
LanguageOutline,
ArchiveOutline
} from '@vicons/ionicons5'
import { useEditorStore } from '@/store/editor'
import { useAppStore } from '@/store/app'
import { useStashStore } from '@/store/stash'
import type { XmlNode } from '@/types/xmlNode'
import type { CheckRuleData, InsertMode, FlatNode, TranslationResponse } from '../constants'
import { DOCUMENT_LIKE_TAGS } from '../constants'
......@@ -56,6 +58,15 @@ export const addNodeModalRef = ref<any>(null)
export const copyNodeCache = ref<XmlNode | null>(null)
// ══════════════════════════════════════════════════════════
// 全局共享状态:本地暂存弹窗
// ══════════════════════════════════════════════════════════
export const stashModalVisible = ref(false)
export const stashNodeName = ref('')
export const stashDefaultName = ref('')
export const stashTargetNode = ref<XmlNode | null>(null)
export const stashNodeModalRef = ref<any>(null)
// ══════════════════════════════════════════════════════════
// 全局共享状态:智能翻译中的节点 ID
// ══════════════════════════════════════════════════════════
export const translatingNodeId = ref<string | null>(null)
......@@ -779,6 +790,13 @@ export function useNodeTree(
icon: icon(CopyOutline)
})
// 本地暂存
options.push({
label: '本地暂存',
key: 'localStash',
icon: icon(ArchiveOutline)
})
// 粘贴节点(有缓存时显示)
if (copyNodeCache.value) {
const pasteChildren: DropdownOption[] = isVirtual
......@@ -984,6 +1002,14 @@ export function useNodeTree(
break
}
// ── 本地暂存 ──
case 'localStash': {
const timeStr = formatDateTime(new Date())
const defaultName = isVirtual ? `片段 - 文本节点 (${timeStr})` : `片段 - ${node.tagName} (${timeStr})`
stashNodeModalRef.value?.open(defaultName, node)
break
}
// ── 粘贴到上方 ──
case 'pasteAbove': {
if (!copyNodeCache.value || !parent) break
......
......@@ -193,6 +193,9 @@
<!-- 批量删除确认弹窗 -->
<BatchDeleteConfirmModal ref="batchDeleteConfirmModalRef" @confirm="clearBatchSelection" />
<!-- 本地暂存弹窗 -->
<StashNodeModal :ref="(el) => (stashNodeModalRef = el)" />
<!-- 回到顶部悬浮球 -->
<Transition name="fade">
<div
......@@ -217,13 +220,16 @@ import {
translatingNodeId,
checkRuleModalRef,
viewXmlModalRef,
addNodeModalRef
addNodeModalRef,
stashModalVisible,
stashNodeModalRef
} from './functionals'
import CheckRuleModal from './components/CheckRuleModal/index.vue'
import AddNodeModal from './components/AddNodeModal/index.vue'
import ViewXmlModal from './components/ViewXmlModal/index.vue'
import InsertFragmentModal from '../EditorToolbar/components/InsertFragmentModal/index.vue'
import BatchDeleteConfirmModal from './components/BatchDeleteConfirmModal/index.vue'
import StashNodeModal from './components/StashNodeModal/index.vue'
const props = defineProps<{
expandedKeys: string[]
......@@ -235,7 +241,7 @@ const editorStore = useEditorStore()
const insertFragmentModalRef = ref<any>(null)
const isAnyModalVisible = computed(() => {
return checkRuleVisible.value || viewXmlVisible.value || addNodeVisible.value || !!insertFragmentModalRef.value?.visible
return checkRuleVisible.value || viewXmlVisible.value || addNodeVisible.value || stashModalVisible.value || !!insertFragmentModalRef.value?.visible
})
const {
......
......@@ -62,7 +62,7 @@ export function useEditor() {
const exportXml = (): void => {
if (!store.xmlTree) return
try {
const xml = serializeTreeToXml(store.xmlTree, 0, true)
const xml = '<?xml version="1.0" encoding="utf-8"?>\n' + serializeTreeToXml(store.xmlTree, 0, true)
const blob = new Blob([xml], { type: 'application/xml;charset=utf-8;' })
openDownloadModal({
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment