fix: dialog内联+v-show替代v-if(绕过组件导入的v-if渲染bug)

This commit is contained in:
Hermes CI Fix
2026-07-14 12:00:48 +08:00
parent 1db0e76204
commit cc9398cdcc
+89 -11
View File
@@ -112,18 +112,56 @@
@delete-connection="onDeleteConnection"
/>
<!-- 节点编辑弹窗 -->
<NodeEditDialog
:key="'ned-' + dialogRefreshKey"
:visible="showNodeDialog"
:form="editingNodeData || { name: '', description: '', icon: 'target', kpis: [] }"
:dim-key="editingLayerKey"
@close="showNodeDialog = false"
@save="onNodeSave"
/>
<!-- 节点编辑弹窗(内联,v-show替代v-if -->
<div v-show="showNodeDialog" class="mc-dialog-overlay-fix" @click.self="showNodeDialog=false">
<div class="mc-dialog-box">
<div class="mc-dialog-header">
<span>{{ editingNodeData?._index != null ? '编辑目标' : '添加目标' }}</span>
<button class="mc-dialog-close" @click="showNodeDialog=false">×</button>
</div>
<div class="mc-dialog-body">
<div class="mc-form-item">
<label>目标名称 <span class="mc-required">*</span></label>
<input v-model="dialogForm.name" class="mc-input" placeholder="请输入目标名称" ref="dialogNameRef" />
</div>
<div class="mc-form-item">
<label>描述</label>
<textarea v-model="dialogForm.description" class="mc-input mc-textarea" rows="3" placeholder="目标描述可选"></textarea>
</div>
<div class="mc-form-item">
<label>图标</label>
<div class="mc-icon-picker">
<button v-for="(ico, key) in iconOptions" :key="key"
class="mc-icon-btn" :class="{ active: dialogForm.icon === key }"
@click="dialogForm.icon = key" :title="ico">{{ iconEmoji(key) }}</button>
</div>
</div>
<div class="mc-form-item">
<label>目标值 <span class="mc-hint">CMA字段)</span></label>
<input v-model="dialogForm.targetValue" class="mc-input" type="number" placeholder="目标值" />
</div>
<div class="mc-row">
<input v-model="dialogForm.currentValue" class="mc-input mc-input-half" type="number" placeholder="当前值" />
<input v-model="dialogForm.unit" class="mc-input mc-input-half" placeholder="单位%万元" />
</div>
<div class="mc-row">
<input v-model="dialogForm.owner" class="mc-input" placeholder="责任人" />
</div>
<div class="mc-form-item">
<label>指标类型</label>
<label class="mc-radio-label"><input type="radio" v-model="dialogForm.isLeading" :value="false" /> 滞后指标(结果)</label>
<label class="mc-radio-label"><input type="radio" v-model="dialogForm.isLeading" :value="true" /> 领先指标(驱动)</label>
</div>
</div>
<div class="mc-dialog-footer">
<button class="mc-btn" @click="showNodeDialog=false">取消</button>
<button class="mc-btn mc-btn-primary" @click="onSaveDialog">保存</button>
</div>
</div>
</div>
<!-- 版本历史弹窗 -->
<div v-if="showVersions" :key="'ver-' + dialogRefreshKey" class="mc-dialog-overlay" @click.self="showVersions=false">
<div v-show="showVersions" class="mc-dialog-overlay" @click.self="showVersions=false">
<div class="mc-dialog-box" style="width:620px;">
<div class="mc-dialog-header">
<span>版本历史</span>
@@ -235,7 +273,6 @@ import KnowledgePanel from '../components/KnowledgePanel.vue'
import api from "../api/index"
import { LAYER_CONFIG, LAYER_KEYS, getLayerList } from "../config/layers"
import StrategyLayer from "../components/strategy-map/StrategyLayer.vue"
import NodeEditDialog from "../components/strategy-map/NodeEditDialog.vue"
import ConnectionLines from "../components/strategy/ConnectionLines.vue"
// ── 四层泳道配置 ──
@@ -280,6 +317,17 @@ const showNodeDialog = ref(false)
const editingNodeData = ref<any>(null)
const editingLayerKey = ref('')
const dialogRefreshKey = ref(0)
const dialogForm = reactive({ name: '', description: '', icon: 'target', targetValue: null, currentValue: null, unit: '%', owner: '', isLeading: false, kpis: [] as string[] })
const iconOptions: Record<string, string> = { target: '目标', star: '星级', rocket: '火箭', chart: '图表', team: '团队', light: '灯泡', shield: '盾牌', gear: '齿轮', handshake: '握手', medal: '奖牌' }
function iconEmoji(key: string): string {
const m: Record<string, string> = { target: '🎯', star: '⭐', rocket: '🚀', chart: '📊', team: '👥', light: '💡', shield: '🛡️', gear: '⚙️', handshake: '🤝', medal: '🏅' }
return m[key] || '📌'
}
function onSaveDialog() {
if (!dialogForm.name?.trim()) { ElMessage.warning('请输入目标名称'); return }
onNodeSave({ ...dialogForm, name: dialogForm.name.trim(), layer: editingLayerKey.value })
showNodeDialog.value = false
}
const showVersions = ref(false)
const versions = ref<any[]>([])
@@ -561,6 +609,15 @@ function onDeleteConnection(idx: number) {
function openAddDialog(layerKey: string) {
editingLayerKey.value = layerKey
editingNodeData.value = null
dialogForm.name = ''
dialogForm.description = ''
dialogForm.icon = 'target'
dialogForm.targetValue = null
dialogForm.currentValue = null
dialogForm.unit = '%'
dialogForm.owner = ''
dialogForm.isLeading = false
dialogForm.kpis = []
dialogRefreshKey.value++
showNodeDialog.value = true
}
@@ -993,4 +1050,25 @@ onUnmounted(() => {
.mc-btn-warn { color:#e6a23c; border-color:#e6a23c; }
.mc-btn-warn:hover { background:#e6a23c; color:#fff; }
.mc-btn:hover { opacity:0.85; }
/* 内联dialog样式 */
.mc-dialog-overlay-fix {
position: fixed; top:0; left:0; right:0; bottom:0;
background:rgba(0,0,0,0.5); z-index:9999;
display:flex; align-items:center; justify-content:center;
}
.mc-form-item { margin-bottom:16px; }
.mc-form-item label { display:block; font-size:13px; color:#666; margin-bottom:6px; font-weight:500; }
.mc-required { color:#f56c6c; margin-left:2px; }
.mc-hint { font-weight:400; color:#999; font-size:12px; }
.mc-input { width:100%; padding:8px 12px; border:1px solid #dcdfe6; border-radius:6px; font-size:14px; outline:none; box-sizing:border-box; }
.mc-input:focus { border-color:#409eff; }
.mc-input-half { width:48%; }
.mc-row { display:flex; gap:4%; margin-bottom:16px; }
.mc-icon-picker { display:flex; flex-wrap:wrap; gap:6px; }
.mc-icon-btn { width:40px; height:40px; display:flex; align-items:center; justify-content:center; font-size:20px; border:2px solid #e8e8e8; border-radius:8px; background:#fff; cursor:pointer; }
.mc-icon-btn:hover { border-color:#409eff; transform:scale(1.1); }
.mc-icon-btn.active { border-color:#409eff; background:#ecf5ff; }
.mc-radio-label { display:inline-flex; align-items:center; gap:4px; margin-right:16px; font-size:13px; color:#666; cursor:pointer; }
.mc-radio-label input { margin:0; }
</style>