diff --git a/src/components/TreeView.vue b/src/components/TreeView.vue index 405d8d0..2e6e36d 100644 --- a/src/components/TreeView.vue +++ b/src/components/TreeView.vue @@ -174,7 +174,7 @@ const treeDataSource = [ ] }, { - name: "Main Tree", + name: "Standards", children: [ { name: "Product Scenario", children: [] }, { @@ -638,35 +638,22 @@ const operationDialog = ref({ show: false, mode: 'copy' as 'copy' | 'clone' | 'branch', sourceNodeId: '', - selectedSourceIds: [] as string[] + selectedSourceIds: [] as string[], + owner: 'admin' // default owner }) const toggleSourceSelection = (node: TreeNode) => { + // Only allow terminal nodes + if (!isTerminalNode(node)) return + const ids = operationDialog.value.selectedSourceIds - // Collect ALL terminal descendant IDs (exclude folders from selection list) - let terminalsToToggle: string[] = [] - - if (isTerminalNode(node)) { - terminalsToToggle = [node.id] + if (ids.includes(node.id)) { + // Toggle off if already selected + operationDialog.value.selectedSourceIds = [] } else { - terminalsToToggle = getAllTerminalDescendants(node) - } - - // If node is a folder with no terminal children, do nothing or just ignore - if (terminalsToToggle.length === 0) return - - const allSelected = terminalsToToggle.every(id => ids.includes(id)) - - if (allSelected) { - operationDialog.value.selectedSourceIds = ids.filter(id => !terminalsToToggle.includes(id)) - } else { - // Add missing - const newIds = [...ids] - terminalsToToggle.forEach(id => { - if (!newIds.includes(id)) newIds.push(id) - }) - operationDialog.value.selectedSourceIds = newIds + // Single select: replace any existing selection + operationDialog.value.selectedSourceIds = [node.id] } } @@ -916,11 +903,15 @@ const closeContextMenu = () => { } const openOperationDialog = (mode: 'copy' | 'clone' | 'branch') => { + const currentSourceNodeId = contextMenu.value?.nodeId || '' + const currentNode = findNode(mockTreeData.value, currentSourceNodeId) + operationDialog.value = { show: true, mode, - sourceNodeId: contextMenu.value?.nodeId || '', - selectedSourceIds: [] + sourceNodeId: currentSourceNodeId, + selectedSourceIds: [], + owner: currentNode?.owner || 'admin' } dialogExpandedIds.value = new Set(expandedIds.value) closeContextMenu() @@ -1199,6 +1190,7 @@ const executeOperation = () => { if (mode === 'copy') { const newNode = cloneNode(sourceNode, `${destinationNode.id}-${Date.now()}-${processedCount}`) newNode.label = `${newNode.label} (Copy)` + newNode.owner = operationDialog.value.owner addChildNode(targetParent, newNode) } else if (mode === 'clone') { const newNode: TreeNode = { @@ -1206,13 +1198,15 @@ const executeOperation = () => { id: `${destinationNode.id}-${Date.now()}-${processedCount}`, label: `${sourceNode.label} (Clone)`, isClone: true, - cloneSourceId: sourceNode.id + cloneSourceId: sourceNode.id, + owner: operationDialog.value.owner } addChildNode(targetParent, newNode) } else if (mode === 'branch') { // Even if source is terminal, "Branch" op might function like copy const newNode = cloneNode(sourceNode, `${destinationNode.id}-${Date.now()}-${processedCount}`) newNode.label = `${newNode.label} (Branch)` + newNode.owner = operationDialog.value.owner addChildNode(targetParent, newNode) } processedCount++ @@ -1511,6 +1505,7 @@ defineExpose({ type="checkbox" :checked="isIdsSelected(node)" :indeterminate.prop="isIdsIndeterminate(node)" + :disabled="!isTerminalNode(node)" @change="toggleSourceSelection(node)" style="margin-right: 6px;" /> @@ -1528,10 +1523,16 @@ defineExpose({ @@ -1973,12 +1974,43 @@ defineExpose({ .dialog-footer { display: flex; - justify-content: flex-end; - gap: 12px; + justify-content: space-between; + align-items: center; padding: 16px 20px; border-top: 1px solid #e0e0e0; } +.owner-input-group { + display: flex; + align-items: center; + gap: 8px; +} + +.owner-input-group label { + font-size: 13px; + font-weight: 500; + color: #333; +} + +.dialog-input { + padding: 6px 8px; + border: 1px solid #ddd; + border-radius: 4px; + font-size: 13px; + width: 150px; + outline: none; + transition: border-color 0.2s; +} + +.dialog-input:focus { + border-color: #0078d4; +} + +.dialog-actions { + display: flex; + gap: 12px; +} + .btn { padding: 8px 16px; border-radius: 4px; diff --git a/src/components/views/ProjectDeptView.vue b/src/components/views/ProjectDeptView.vue index a16a756..565ec58 100644 --- a/src/components/views/ProjectDeptView.vue +++ b/src/components/views/ProjectDeptView.vue @@ -16,7 +16,7 @@ const findNodeByName = (nodes: TreeNode[], name: string): TreeNode | undefined = return nodes.find(n => n.label === name) } -const mainTreeNode = computed(() => findNodeByName(props.treeData, 'Main Tree')) +const mainTreeNode = computed(() => findNodeByName(props.treeData, 'Standards')) const attributesNodes = computed(() => { if (!mainTreeNode.value || !mainTreeNode.value.children) return [] diff --git a/src/components/views/ReleaseView.vue b/src/components/views/ReleaseView.vue index 3f96606..64647cb 100644 --- a/src/components/views/ReleaseView.vue +++ b/src/components/views/ReleaseView.vue @@ -69,7 +69,7 @@ const initReviewHistory = () => { // 获取可release的版本详情(包含审核信息) const releasableVersionsDetails = computed(() => { return reviewHistory.value - .filter((item: any) => item.status === 'approved') + .filter((item: any) => item.status === 'accepted') .map((item: any) => { // 尝试从节点历史版本中获取真实内容 const versionData = props.selectedNode?.versions?.find((v: any) => v.version === item.version) @@ -150,7 +150,7 @@ const nodeForModal = computed(() => { return { ...props.selectedNode, version: selectedVersionDetail.value.version, - status: 'Approved', + status: 'Accepted', lastChangedBy: selectedVersionDetail.value.reviewer, lastChangedDate: selectedVersionDetail.value.approvedDate, comment: selectedVersionDetail.value.comment,