diff --git a/frontend/src/views/MapCanvas.vue b/frontend/src/views/MapCanvas.vue index f08b491c..9827b9a7 100644 --- a/frontend/src/views/MapCanvas.vue +++ b/frontend/src/views/MapCanvas.vue @@ -112,18 +112,56 @@ @delete-connection="onDeleteConnection" /> - - + +
+
+
+ {{ editingNodeData?._index != null ? '编辑目标' : '添加目标' }} + +
+
+
+ + +
+
+ + +
+
+ +
+ +
+
+
+ + +
+
+ + +
+
+ +
+
+ + + +
+
+ +
+
-
+
版本历史 @@ -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(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 = { target: '目标', star: '星级', rocket: '火箭', chart: '图表', team: '团队', light: '灯泡', shield: '盾牌', gear: '齿轮', handshake: '握手', medal: '奖牌' } +function iconEmoji(key: string): string { + const m: Record = { 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([]) @@ -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; }