diff --git a/vue/src/system/GraphStyle.vue b/vue/src/system/GraphStyle.vue index 95f5560..4b74f7a 100644 --- a/vue/src/system/GraphStyle.vue +++ b/vue/src/system/GraphStyle.vue @@ -270,7 +270,7 @@ - + - + @@ -304,7 +304,7 @@ import { deleteGraphStyle, batchDeleteGraphStyle, deleteGraphStyleGroup, - applyGraphStyleGroup // 新增导入 + applyGraphStyleGroup } from '@/api/style'; import {ElMessageBox, ElMessage} from 'element-plus'; import {markRaw} from 'vue'; @@ -597,19 +597,18 @@ export default { })) })); - // --- 核心改动:初始加载同步逻辑 --- - this.activeCollapseNames = []; - this.usingConfigIds = []; - - this.styleGroups.forEach(group => { - if (group.is_active) { - // 1. 自动展开激活方案 - this.activeCollapseNames.push(group.id); - // 2. 将激活方案下的所有配置加入渲染列表 - const ids = group.configs.map(c => c.id); - this.usingConfigIds = [...this.usingConfigIds, ...ids]; - } - }); + // 仅在初始加载且没有选中项时执行自动同步逻辑 + if (this.usingConfigIds.length === 0) { + this.styleGroups.forEach(group => { + if (group.is_active) { + if (!this.activeCollapseNames.includes(group.id)) { + this.activeCollapseNames.push(group.id); + } + const ids = group.configs.map(c => c.id); + this.usingConfigIds = [...this.usingConfigIds, ...ids]; + } + }); + } this.updateAllElements(); } @@ -638,25 +637,63 @@ export default { } this.updateAllElements(); }, + + /** + * 修改后的应用全案方法 + * 逻辑:保留当前已手动选中的配置,新方案中冲突的配置不予应用 + */ async applyWholeGroup(group) { try { - // 1. 调用后端接口更新激活状态 + // 1. 获取当前正在使用的所有配置项对象 + const currentlyUsingConfigs = []; + this.styleGroups.forEach(g => { + g.configs.forEach(c => { + if (this.usingConfigIds.includes(c.id)) { + currentlyUsingConfigs.push(c); + } + }); + }); + + // 2. 提取出当前已选中的标签列表 (例如: ['疾病', '药品']) + const currentlySelectedLabels = currentlyUsingConfigs.map(c => c.current_label); + + // 3. 过滤新方案:如果新方案里的配置标签 已经存在于当前已选列表中,则剔除 + const filteredNewConfigIds = group.configs + .filter(newConf => !currentlySelectedLabels.includes(newConf.current_label)) + .map(newConf => newConf.id); + + // 4. 将过滤后的新 ID 追加到现有的选中列表中 + this.usingConfigIds = [...this.usingConfigIds, ...filteredNewConfigIds]; + + // 5. 调用后端接口更新激活状态(保持后端数据同步) const res = await applyGraphStyleGroup(group.id); if (res.code === 200) { - // 2. 刷新列表(fetchConfigs 会自动同步 usingConfigIds 和 expanded 状态) + // 重新获取列表以刷新 UI 状态(如“已应用”按钮状态) await this.fetchConfigs(); - ElMessage.success(`方案【${group.group_name}】已成功应用全案`); + ElMessage.success(`方案【${group.group_name}】已应用,已保留您手动选择的标签`); } } catch (err) { + console.error(err); ElMessage.error("应用全案失败"); } }, + handleSaveClick() { this.fetchGroupNames(); - this.saveForm.canvas_name = Date.now().toString(); + this.saveForm.canvas_name = `${this.activeTags}_${Date.now()}`; this.saveDialogVisible = true; }, async confirmSave() { + if (!this.saveForm.group_name || !this + .saveForm.group_name.trim()) { + return this.$message.warning("请选择或输入方案名称" + ); + } + if (!this.saveForm.canvas_name || !this + .saveForm.canvas_name.trim()) { + return this.$message.warning("请输入配置名称" + ); + } const payload = { canvas_name: this.saveForm.canvas_name, group_name: this.saveForm.group_name, @@ -779,30 +816,32 @@ export default { .knowledge-graph-container { display: flex; height: 100vh; - background-color: #f3f3f3; /* 全局背景改为 f3f3f3 */ + background-color: #f3f3f3; overflow: hidden; } .control-panel { width: 260px; background: #ffffff; - border-right: 1px solid #e2e8f0; + box-shadow: 4px 0 12px rgba(0, 0, 0, 0.08); padding: 10px; display: flex; flex-direction: column; overflow-y: auto; flex-shrink: 0; + z-index: 5; } .config-list-panel { width: 320px; background: #ffffff; - border-left: 1px solid #ffffff; + box-shadow: -4px 0 12px rgba(0, 0, 0, 0.08); padding: 18px; display: flex; flex-direction: column; flex-shrink: 0; position: relative; + z-index: 5; } .panel-header-container { @@ -1037,7 +1076,8 @@ export default { } .config-card:hover { - background-color: #e2e4e6 !important; + background-color: #eff6ff !important; + outline: 1.5px solid #1559f3; } .card-using { @@ -1052,22 +1092,23 @@ export default { .card-left { display: flex; + flex-direction: column; align-items: flex-start; flex: 1; min-width: 0; + gap: 8px; } .checkbox-wrapper { display: flex; align-items: center; - justify-content: center; - margin-right: 12px; - padding-right: 10px; - border-right: 1px solid #d1d5db; + justify-content: flex-start; + margin-right: 0; + padding-right: 0; + border-right: none; flex-shrink: 0; - height: 20px; + height: auto; } - .config-checkbox { margin: 0; cursor: pointer; @@ -1234,6 +1275,31 @@ export default { background-color: #1559f3 !important; border-color: #1559f3 !important; } + + +:deep(.el-dialog) { + --el-color-primary: #ebf0ff !important; + --el-input-hover-border-color: #ebf0ff !important; + --el-input-focus-border-color: #ebf0ff !important; + --el-border-color-hover: #ebf0ff !important; +} + +:deep(.el-dialog .el-input__wrapper) { + box-shadow: 0 0 0 1px #ebf0ff inset !important; + background-color: #ffffff !important; +} + +:deep(.el-dialog .el-input.is-focus .el-input__wrapper), +:deep(.el-dialog .el-input__wrapper.is-focus), +:deep(.el-dialog .el-select .el-input__wrapper.is-focus), +:deep(.el-dialog .el-select:hover .el-input__wrapper) { + box-shadow: 0 0 0 1px #ebf0ff inset !important; +} + + +:deep(.el-dialog .el-input__inner) { + outline: none !important; +}