fix: dialog内联+v-show替代v-if(绕过组件导入的v-if渲染bug)
This commit is contained in:
@@ -112,18 +112,56 @@
|
|||||||
@delete-connection="onDeleteConnection"
|
@delete-connection="onDeleteConnection"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 节点编辑弹窗 -->
|
<!-- 节点编辑弹窗(内联,v-show替代v-if) -->
|
||||||
<NodeEditDialog
|
<div v-show="showNodeDialog" class="mc-dialog-overlay-fix" @click.self="showNodeDialog=false">
|
||||||
:key="'ned-' + dialogRefreshKey"
|
<div class="mc-dialog-box">
|
||||||
:visible="showNodeDialog"
|
<div class="mc-dialog-header">
|
||||||
:form="editingNodeData || { name: '', description: '', icon: 'target', kpis: [] }"
|
<span>{{ editingNodeData?._index != null ? '编辑目标' : '添加目标' }}</span>
|
||||||
:dim-key="editingLayerKey"
|
<button class="mc-dialog-close" @click="showNodeDialog=false">×</button>
|
||||||
@close="showNodeDialog = false"
|
</div>
|
||||||
@save="onNodeSave"
|
<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-box" style="width:620px;">
|
||||||
<div class="mc-dialog-header">
|
<div class="mc-dialog-header">
|
||||||
<span>版本历史</span>
|
<span>版本历史</span>
|
||||||
@@ -235,7 +273,6 @@ import KnowledgePanel from '../components/KnowledgePanel.vue'
|
|||||||
import api from "../api/index"
|
import api from "../api/index"
|
||||||
import { LAYER_CONFIG, LAYER_KEYS, getLayerList } from "../config/layers"
|
import { LAYER_CONFIG, LAYER_KEYS, getLayerList } from "../config/layers"
|
||||||
import StrategyLayer from "../components/strategy-map/StrategyLayer.vue"
|
import StrategyLayer from "../components/strategy-map/StrategyLayer.vue"
|
||||||
import NodeEditDialog from "../components/strategy-map/NodeEditDialog.vue"
|
|
||||||
import ConnectionLines from "../components/strategy/ConnectionLines.vue"
|
import ConnectionLines from "../components/strategy/ConnectionLines.vue"
|
||||||
|
|
||||||
// ── 四层泳道配置 ──
|
// ── 四层泳道配置 ──
|
||||||
@@ -280,6 +317,17 @@ const showNodeDialog = ref(false)
|
|||||||
const editingNodeData = ref<any>(null)
|
const editingNodeData = ref<any>(null)
|
||||||
const editingLayerKey = ref('')
|
const editingLayerKey = ref('')
|
||||||
const dialogRefreshKey = ref(0)
|
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 showVersions = ref(false)
|
||||||
const versions = ref<any[]>([])
|
const versions = ref<any[]>([])
|
||||||
|
|
||||||
@@ -561,6 +609,15 @@ function onDeleteConnection(idx: number) {
|
|||||||
function openAddDialog(layerKey: string) {
|
function openAddDialog(layerKey: string) {
|
||||||
editingLayerKey.value = layerKey
|
editingLayerKey.value = layerKey
|
||||||
editingNodeData.value = null
|
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++
|
dialogRefreshKey.value++
|
||||||
showNodeDialog.value = true
|
showNodeDialog.value = true
|
||||||
}
|
}
|
||||||
@@ -993,4 +1050,25 @@ onUnmounted(() => {
|
|||||||
.mc-btn-warn { color:#e6a23c; border-color:#e6a23c; }
|
.mc-btn-warn { color:#e6a23c; border-color:#e6a23c; }
|
||||||
.mc-btn-warn:hover { background:#e6a23c; color:#fff; }
|
.mc-btn-warn:hover { background:#e6a23c; color:#fff; }
|
||||||
.mc-btn:hover { opacity:0.85; }
|
.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>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user