Просмотр исходного кода

新增CrossingDetailPanel路口详情面板组件;完成路口的双击弹窗详情的功能;调整SegmentedRadio的样式;

画安 дней назад: 4
Родитель
Сommit
f07475b84e

+ 687 - 0
src/components/ui/CrossingDetailPanel.vue

@@ -0,0 +1,687 @@
+<template>
+    <div class="crossing-detail-panel">
+        <div class="detail-panel-left">
+            <div class="intersection-video-wrap">
+                <IntersectionMapVideos :mapData="intersectionData" :videoUrls="currentRoute.cornerVideos" />
+            </div>
+            <div class="signal-timing-wrap">
+                <div class="header">
+                    <div class="title-area">
+                        <span class="main-title">方案状态</span>
+                        <span class="sub-info">(周期: {{ cycleLength }} 相位差: 0 协调时间: 0)</span>
+                    </div>
+                    <div class="checkbox-area">
+                        <div class="checkbox-mock" :class="{ 'is-checked': followPhase }"
+                            @click="followPhase = !followPhase">
+                            <span v-if="followPhase" style="color: #fff; font-size: 12px; margin-left: 1px;">✓</span>
+                        </div>
+                        <span>跟随相位</span>
+                    </div>
+                </div>
+
+                <SignalTimingChart :cycleLength="cycleLength" :currentTime="currentSec" :phaseData="mockPhaseData" />
+            </div>
+        </div>
+
+        <div class="detail-panel-right">
+            <form class="detail-right-form" @submit.prevent>
+                <div class="form-group">
+                    <div class="control-method">
+                        <div class="control-label-wrap">
+                            <span class="control-label">控制方式</span>
+                            <div class="control-operation">
+                                <div class="operation-btn" 
+                                     :class="{ 'is-active': isManualMode }"
+                                     @click="toggleManualMode">
+                                    {{ isManualMode ? '退出手动控制' : '手动控制' }}
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="form-interactive-area" :class="{ 'is-disabled': !isManualMode }">
+                        <div class="control-method-content">
+                            <SegmentedRadio v-model="currentMethod" />
+                        </div>
+
+                        <div class="control-scheme">
+                            <div class="control-label-wrap">
+                                <span class="control-label">控制方案</span>
+                                <DropdownSelect v-model="currentScheme" :options="schemeOptions" />
+                            </div>
+                            
+                            <div class="current-stage">
+                                <div class="current-stage-warp">
+                                    <div class="current-stage-label">当前阶段:</div>
+                                    <div v-for="(item, index) in currentStageList" :key="index" class="stage-item-wrapper">
+                                        <img :src="require(`@/assets/${item.img}`)" alt="stage"
+                                            :class="{ 'stage-img': true, 'stage-active': item.value === currentStage }" />
+                                        <input 
+                                            type="number" 
+                                            v-model.number="item.time" 
+                                            class="stage-input"
+                                            :disabled="currentMethod !== 'temp'"
+                                            :title="currentMethod !== 'temp' ? '仅临时方案可修改' : '修改阶段时间'"
+                                        />
+                                        <span class="unit">s</span>
+                                    </div>
+                                </div>
+                            </div>
+
+                            <transition name="fade">
+                                <div class="lock-time" v-if="showLockTime">
+                                    <div class="lock-time-label-wrap glow-header">
+                                        <div class="lock-time-label">锁定时间</div>
+                                        <div class="lock-time-close" @click="showLockTime = false">✕</div>
+                                    </div>
+                                    <div class="lock-time-options">
+                                        <div class="lock-time-option">
+                                            <label>
+                                                <input type="radio" v-model="lockTimeType" value="continuous" /> 持续放行
+                                            </label>
+                                        </div>
+                                        <div class="lock-time-option">
+                                            <label>
+                                                <input type="radio" v-model="lockTimeType" value="timer" /> 放行
+                                                <DropdownSelect placeholder="锁定时间" v-model="currentLocktime" :options="locktimeOptions"
+                                                    @click.native.prevent />
+                                                秒解锁
+                                            </label>
+                                        </div>
+                                    </div>
+                                </div>
+                            </transition>
+                        </div>
+                    </div>
+
+                    <div class="button-group" v-show="isManualMode">
+                        <div>
+                            <button type="button" class="btn btn-cancel" @click="onCancel()">取消</button>
+                            <button type="button" class="btn btn-confirm" @click="onConfirm()">确认</button>
+                        </div>
+                    </div>
+
+                </div>
+            </form>
+        </div>
+    </div>
+</template>
+
+<script>
+import SignalTimingChart from '@/components/ui/SignalTimingChart.vue';
+import IntersectionMapVideos from '@/components/ui/IntersectionMapVideos.vue';
+import SegmentedRadio from '@/components/ui/SegmentedRadio.vue';
+import DropdownSelect from '@/components/ui/DropdownSelect.vue';
+
+import { getIntersectionData } from '@/mock/data';
+
+export default {
+    name: 'CrossingPanel',
+    components: {
+        SignalTimingChart,
+        IntersectionMapVideos,
+        SegmentedRadio,
+        DropdownSelect
+    },
+    data() {
+        return {
+            // 核心状态控制
+            isManualMode: false, // 是否处于手动控制模式
+            showLockTime: false, // 是否显示锁定时间弹窗
+            lockTimeType: 'continuous', // 锁定时间类型
+
+            followPhase: false,
+            intersectionData: {},
+            currentRoute: {
+                id: 1, name: '靖远路与北公路交叉口 1', level: '一级', mode: '快进', time: '30s',
+                mainVideo: require('@/assets/videos/video1.mp4'),
+                cornerVideos: { nw: require('@/assets/videos/video1.mp4'), ne: require('@/assets/videos/video2.mp4'), sw: require('@/assets/videos/video2.mp4'), se: require('@/assets/videos/video1.mp4') }
+            },
+            cycleLength: 140,
+            currentSec: 15,
+            mockPhaseData: [
+                // ================= 上轨道 (Track 0) =================
+                // S1阶段 (0-30s): P1 直行
+                [0, 0, 23, 'P1', 30, 'green', 'UP'],
+                [0, 23, 26, '', 3, 'stripe', ''],
+                [0, 26, 29, '', 3, 'yellow', ''],
+                [0, 29, 30, '', 1, 'red', ''],
+
+                // S2阶段 (30-60s): P2 左转
+                [0, 30, 53, 'P2', 30, 'green', 'TURN_LEFT'],
+                [0, 53, 56, '', 3, 'stripe', ''],
+                [0, 56, 59, '', 3, 'yellow', ''],
+                [0, 59, 60, '', 1, 'red', ''],
+
+                // S3阶段 (60-110s): P3 侧向左转 (使用向左箭头)
+                [0, 60, 103, 'P3', 50, 'green', 'TURN_LEFT'],
+                [0, 103, 106, '', 3, 'stripe', ''],
+                [0, 106, 109, '', 3, 'yellow', ''],
+                [0, 109, 110, '', 1, 'red', ''],
+
+                // S4阶段 (110-140s): P4 掉头
+                [0, 110, 133, 'P4', 30, 'green', 'UTURN'],
+                [0, 133, 136, '', 3, 'stripe', ''],
+                [0, 136, 139, '', 3, 'yellow', ''],
+                [0, 139, 140, '', 1, 'red', ''],
+
+                // ================= 下轨道 (Track 1) =================
+                // S1阶段 (0-30s): P5 直行
+                [1, 0, 23, 'P5', 30, 'green', 'UP'],
+                [1, 23, 26, '', 3, 'stripe', ''],
+                [1, 26, 29, '', 3, 'yellow', ''],
+                [1, 29, 30, '', 1, 'red', ''],
+
+                // S2阶段 (30-60s): P6 左转
+                [1, 30, 53, 'P6', 30, 'green', 'TURN_LEFT'],
+                [1, 53, 56, '', 3, 'stripe', ''],
+                [1, 56, 59, '', 3, 'yellow', ''],
+                [1, 59, 60, '', 1, 'red', ''],
+
+                // S3阶段 (60-110s): P7 侧向右转 (使用向右箭头)
+                [1, 60, 103, 'P7', 50, 'green', 'TURN_RIGHT'],
+                [1, 103, 106, '', 3, 'stripe', ''],
+                [1, 106, 109, '', 3, 'yellow', ''],
+                [1, 109, 110, '', 1, 'red', ''],
+
+                // S4阶段 (110-140s): P8 左转
+                [1, 110, 133, 'P8', 30, 'green', 'TURN_LEFT'],
+                [1, 133, 136, '', 3, 'stripe', ''],
+                [1, 136, 139, '', 3, 'yellow', ''],
+                [1, 139, 140, '', 1, 'red', '']
+            ],
+            
+            // 控制方式数据
+            currentMethod: 'temp',
+            currentScheme: 'early_peak',
+            schemeOptions: [
+                { label: '早高峰', value: 'early_peak' },
+                { label: '晚高峰', value: 'evening_peak' },
+                { label: '平峰', value: 'normal' }
+            ],
+            currentLocktime: 50,
+            locktimeOptions: [
+                { label: '50', value: 50 },
+                { label: '100', value: 100 },
+                { label: '300', value: 300 }
+            ],
+            currentStage: '1', 
+            // 补充了 time 属性,用于双向绑定输入框的时间
+            currentStageList: [
+                { value: '1', time: 30, img: 'test_img1.png' },
+                { value: '2', time: 30, img: 'test_img1.png' },
+                { value: '3', time: 50, img: 'test_img1.png' },
+                { value: '4', time: 30, img: 'test_img1.png' }
+            ]
+        }
+    },
+    watch: {
+        // 监听控制方式切换
+        currentMethod(newVal) {
+            // 需求4:切换步进方案策略时,出现锁定时间弹窗
+            if (newVal === 'step') {
+                this.showLockTime = true;
+            } else {
+                this.showLockTime = false;
+            }
+
+            // 模拟需求1:根据不同模式,切换对应的控制方案数据 (Mock 逻辑)
+            this.updateSchemeDataByMethod(newVal);
+        }
+    },
+    async mounted() {
+        this.intersectionData = await getIntersectionData();
+    },
+    methods: {
+        // 切换手动控制模式
+        toggleManualMode() {
+            this.isManualMode = !this.isManualMode;
+            if (!this.isManualMode) {
+                // 如果退出手动模式,可选择重置表单状态
+                this.showLockTime = false;
+            }
+        },
+        
+        // 模拟:根据控制方式改变下拉方案的数据
+        updateSchemeDataByMethod(method) {
+            if (method === 'system') {
+                this.schemeOptions = [
+                    { label: '系统优化方案A', value: 'sys_a' },
+                    { label: '系统优化方案B', value: 'sys_b' }
+                ];
+                this.currentScheme = 'sys_a';
+            } else {
+                this.schemeOptions = [
+                    { label: '早高峰', value: 'early_peak' },
+                    { label: '晚高峰', value: 'evening_peak' },
+                    { label: '平峰', value: 'normal' }
+                ];
+                this.currentScheme = 'early_peak';
+            }
+        },
+
+        // 取消按钮
+        onCancel() { 
+            this.isManualMode = false;
+            this.showLockTime = false;
+            // 可以在此添加回滚初始数据的逻辑
+        },
+
+        // 需求5:点击确认按钮提交 + 表单验证
+        onConfirm() { 
+            // 验证1:临时方案必须检查时间是否有效
+            if (this.currentMethod === 'temp') {
+                const isInvalid = this.currentStageList.some(item => !item.time || item.time <= 0);
+                if (isInvalid) {
+                    alert('请输入有效的阶段时间 (必须大于0)!');
+                    return;
+                }
+            }
+
+            // 验证2:步进方案必须选择锁定类型
+            if (this.currentMethod === 'step') {
+                if (this.lockTimeType === 'timer' && !this.currentLocktime) {
+                    alert('请选择解锁时间!');
+                    return;
+                }
+            }
+
+            // 构造提交参数
+            const submitData = {
+                method: this.currentMethod,
+                scheme: this.currentScheme,
+                stages: this.currentMethod === 'temp' ? this.currentStageList : null,
+                lockConfig: this.currentMethod === 'step' ? {
+                    type: this.lockTimeType,
+                    time: this.lockTimeType === 'timer' ? this.currentLocktime : null
+                } : null
+            };
+
+            console.log('提交的数据:', submitData);
+            
+            // 提交完成后可根据业务决定是否退出手动模式
+            // this.isManualMode = false;
+        }
+    }
+}
+</script>
+
+<style scoped>
+.crossing-detail-panel {
+    display: flex;
+    flex-direction: row;
+    gap: 20px;
+    /* padding: 20px; */
+    height: 100%;
+    min-height: 0;
+}
+
+.detail-panel-left {
+    display: flex;
+    flex-direction: column;
+    width: 685px;
+    min-height: 0;
+}
+
+.detail-panel-right {
+    flex: 1;
+    min-width: 0;
+    min-height: 0;
+}
+
+
+.intersection-video-wrap {
+    width: 100%;
+    height: 300px;
+    flex: auto;
+}
+
+.signal-timing-wrap {
+    flex: 1;
+    --s: 1;
+    width: 100%;
+    height: 80px;
+    min-width: 0;
+    background-color: transparent;
+    box-sizing: border-box;
+    position: relative;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+    padding: calc(var(--s) * 10px);
+}
+
+.header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: calc(var(--s) * 15px);
+    color: #e0e6f1;
+    flex-shrink: 0;
+}
+
+.title-area {
+    font-size: calc(var(--s) * 16px);
+}
+
+.main-title {
+    font-size: calc(var(--s) * 18px);
+    font-weight: bold;
+    margin-right: calc(var(--s) * 10px);
+}
+
+.sub-info {
+    font-size: calc(var(--s) * 12px);
+    opacity: 0.8;
+}
+
+.checkbox-area {
+    font-size: calc(var(--s) * 12px);
+    display: flex;
+    align-items: center;
+    cursor: pointer;
+    opacity: 0.7;
+    user-select: none;
+}
+
+.checkbox-area:hover {
+    opacity: 1;
+}
+
+.checkbox-mock {
+    width: calc(var(--s) * 14px);
+    height: calc(var(--s) * 14px);
+    border: 1px solid rgba(255, 255, 255, 0.5);
+    margin-right: calc(var(--s) * 6px);
+    border-radius: 2px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+.checkbox-mock.is-checked {
+    background-color: #4da8ff;
+    border-color: #4da8ff;
+}
+
+.chart-container {
+    width: 100%;
+    min-width: 0;
+    flex: 1;
+    min-height: 80px;
+    overflow: hidden;
+}
+
+.loading-overlay {
+    flex: 1;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    color: #758599;
+    font-size: 14px;
+}
+
+/** 控制方法 */
+.control-method {
+    color: #ffffff;
+}
+
+.control-label-wrap {
+    display: flex;
+    align-items: center;
+    margin-bottom: 20px;
+    column-gap: 20px;
+}
+
+.control-label {
+    font-size: 28px;
+    color: #ffffff;
+}
+
+.control-label-wrap span {
+    display: inline-block;
+}
+
+.operation-btn {
+    font-size: 14px;
+    cursor: pointer;
+    user-select: none;
+}
+.operation-btn:hover {
+    text-decoration: underline;
+}
+.operation-btn.is-active {
+    text-decoration: underline;
+}
+
+.control-method .control-label-wrap {
+    justify-content: space-between;
+}
+
+.control-scheme {
+    margin-top: 20px;
+
+}
+
+.lock-time {
+    width: 40%;
+    border-radius: 8px;
+    box-shadow:
+        inset 0px 0px 10px 0px rgba(88, 146, 255, 0.4),
+        inset 20px 0px 30px -10px rgba(88, 146, 255, 0.15);
+
+}
+
+.lock-time-label-wrap {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 10px;
+    border-radius: 8px 8px 0 0;
+    color: #ffffff;
+}
+
+.lock-time-label {
+    font-size: 16px;
+    color: #ffffff;
+}
+
+.lock-time-options {
+    display: flex;
+    flex-direction: column;
+    row-gap: 10px;
+    font-size: 14px;
+    padding: 10px;
+    color: #ffffff;
+}
+
+.lock-time-option {}
+
+.lock-time-close {
+    cursor: pointer;
+}
+
+.glow-header {
+    background: linear-gradient(180deg,
+            rgba(65, 115, 205, 0.6) 0%,
+            rgba(40, 70, 130, 0.1) 100%);
+
+    backdrop-filter: blur(10px);
+}
+
+.current-stage {
+    background-color: rgba(65, 115, 205, 0.2);
+    border: 1px solid #3660a5;
+    margin-bottom: 20px;
+    display: flex;
+    justify-content: center;
+}
+
+.current-stage-warp {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    gap: 10px;
+    padding: 32px;
+    color: #ffffff;
+}
+.current-stage-label {
+    font-size: 14px;
+    width: 100px;
+}
+
+.stage-img {
+    border-radius: 5px;
+    width: 65px;
+    height: 65px;
+}
+
+.stage-active {
+    background-blend-mode: multiply;
+    background-color: rgba(17, 23, 29, .5);
+}
+
+.stage-input {
+    width: 65px;
+    border: 1px solid rgba(161,190,255,0.7);
+    background-color: transparent;
+    padding: 5px;
+    color: #ffffff;
+    text-align: center;
+}
+
+/** 按钮 */
+/* 按钮基础通用样式 */
+.btn {
+    display: inline-flex;
+    justify-content: center;
+    align-items: center;
+    height: 36px;
+    padding: 0 32px;
+    font-size: 14px;
+    border-radius: 4px;
+    cursor: pointer;
+    user-select: none;
+    transition: all 0.2s ease-in-out;
+    box-sizing: border-box;
+}
+
+/* --- 取消按钮 (幽灵按钮) --- */
+.btn-cancel {
+    background-color: transparent;
+    color: #d1d5db;
+    border: 1px solid rgba(130, 150, 190, 0.4);
+}
+
+.btn-cancel:hover {
+    color: #ffffff;
+    border-color: rgba(130, 150, 190, 0.8);
+    background-color: rgba(255, 255, 255, 0.05);
+}
+
+.btn-cancel:active {
+    background-color: rgba(255, 255, 255, 0.1);
+}
+
+/* --- 确认按钮 (实心主按钮) --- */
+.btn-confirm {
+    background-color: #3b74ff;
+    color: #ffffff;
+    border: 1px solid #3b74ff;
+}
+
+.btn-confirm:hover {
+    background-color: #5a8bff;
+    border-color: #5a8bff;
+    box-shadow: 0 2px 8px rgba(59, 116, 255, 0.3);
+}
+
+.btn-confirm:active {
+    background-color: #265bed;
+    border-color: #265bed;
+    box-shadow: none;
+}
+
+.button-group {
+    display: flex;
+    justify-content: flex-end;
+    margin-top: 20px;
+}
+
+.button-group>div {
+    display: flex;
+    gap: 12px;
+}
+
+/* 禁用状态:未点击手动控制时,使表单只读 */
+.form-interactive-area {
+    transition: opacity 0.3s;
+}
+
+.form-interactive-area.is-disabled {
+    opacity: 0.6;
+    pointer-events: none; /* 核心:禁止鼠标事件,无法点击下拉框、单选和输入框 */
+}
+
+/* 当前阶段输入框微调 */
+.stage-item-wrapper {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    gap: 6px;
+    position: relative;
+}
+
+.stage-input {
+    width: 65px;
+    border: 1px solid rgba(161,190,255,0.7);
+    background-color: transparent;
+    padding: 5px;
+    color: #ffffff;
+    text-align: center;
+    border-radius: 4px;
+}
+
+.stage-input:disabled {
+    border-color: rgba(255, 255, 255, 0.2);
+    color: rgba(255, 255, 255, 0.5);
+    background-color: rgba(0, 0, 0, 0.2);
+}
+
+.stage-item-wrapper .unit {
+    position: absolute;
+    bottom: 6px;
+    right: 8px;
+    color: #77A1FF;
+    font-size: 12px;
+    pointer-events: none;
+}
+
+/* 弹窗过渡动画 */
+.fade-enter-active, .fade-leave-active {
+    transition: opacity 0.3s, transform 0.3s;
+}
+.fade-enter, .fade-leave-to {
+    opacity: 0;
+    transform: translateY(-10px);
+}
+
+/* 原有 lock-time 样式调整使其能绝对定位,类似弹窗 */
+.lock-time {
+    margin-top: 15px;
+    width: 60%;
+    border-radius: 8px;
+    box-shadow:
+        inset 0px 0px 10px 0px rgba(88, 146, 255, 0.4),
+        inset 20px 0px 30px -10px rgba(88, 146, 255, 0.15);
+    background-color: rgba(20, 30, 50, 0.9); /* 增加背景色防止透明穿透 */
+}
+
+/* 单选框基础对齐 */
+.lock-time-option label {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    cursor: pointer;
+}
+</style>

+ 0 - 14
src/components/ui/CrossingPanel.vue

@@ -4,20 +4,6 @@
             <IntersectionMapVideos :mapData="intersectionData" :videoUrls="currentRoute.cornerVideos" />
         </div>
         <div class="signal-timing-wrap">
-            <div class="header" v-if="false">
-                <div class="title-area">
-                    <span class="main-title">方案状态</span>
-                    <span class="sub-info">(周期: {{ cycleLength }} 相位差: 0 协调时间: 0)</span>
-                </div>
-                <div class="checkbox-area" v-if="false">
-                    <div class="checkbox-mock" :class="{ 'is-checked': followPhase }"
-                        @click="followPhase = !followPhase">
-                        <span v-if="followPhase" style="color: #fff; font-size: 12px; margin-left: 1px;">✓</span>
-                    </div>
-                    <span>跟随相位</span>
-                </div>
-            </div>
-
             <SignalTimingChart :cycleLength="cycleLength" :currentTime="currentSec" :phaseData="mockPhaseData" />
         </div>
     </div>

+ 8 - 16
src/components/SegmentedRadio.vue

@@ -1,12 +1,7 @@
 <template>
   <div class="segmented-radio-group">
-    <div
-      v-for="(item, index) in options"
-      :key="item.value"
-      class="radio-item"
-      :class="{ 'is-active': currentValue === item.value }"
-      @click="handleSelect(item.value)"
-    >
+    <div v-for="(item, index) in options" :key="item.value" class="radio-item"
+      :class="{ 'is-active': currentValue === item.value }" @click="handleSelect(item.value)">
       {{ item.label }}
     </div>
   </div>
@@ -76,7 +71,7 @@ export default {
   position: relative;
   padding: 6px 5px;
   font-size: 14px;
-  color: #ffffff;
+  color: rgba(255, 255, 255, 0.65);
   /* 半透明的底色 */
   background-color: rgba(65, 115, 205, 0.2);
   /* 基础边框颜色 */
@@ -84,7 +79,7 @@ export default {
   cursor: pointer;
   user-select: none;
   transition: all 0.2s ease;
-  
+
   /* 核心技巧:利用负边距让相邻的边框重叠,避免出现双倍宽度的边框 */
   margin-left: -1px;
   flex: 1;
@@ -101,18 +96,15 @@ export default {
   background-color: rgba(65, 115, 205, 0.4);
   /* 悬浮时层级稍微提高,确保边框能完整显示 */
   z-index: 1;
+  color: #ffffff;
 }
 
 /* 选中状态 (高亮) */
 .radio-item.is-active {
-    background: linear-gradient(180deg, rgba(15, 30, 60, 0.9) 0%, rgba(40, 80, 150, 0.9) 100%);
-  /* 更亮的边框颜色 */
-  border-color: #82a9f4;
-  /* 微微加粗字重 */
-  font-weight: bold;
+  background: linear-gradient( 180deg, rgba(119,161,255,0) 0%, #77A1FF 100%);
+  border: 1px solid rgba(161,190,255,0.7);
   /* 选中状态层级最高,确保高亮边框盖住相邻未选中项的普通边框 */
   z-index: 2;
-  /* 可选:加一点内阴影让质感更好 */
-  box-shadow: inset 0 0 2px rgba(255, 255, 255, 0.3);
+  color: #ffffff;
 }
 </style>

+ 41 - 11
src/views/StatusMonitoring.vue

@@ -53,7 +53,7 @@
                 :title="dialog.title" :defaultWidth="dialog.width || 400" :defaultHeight="dialog.height || 300"
                 :center="dialog.center !== false" :position="dialog.position" :showClose="dialog.showClose" :enableDblclickExpand="dialog.enableDblclickExpand" :noPadding="dialog.noPadding"
 
-                @close="handleDialogClose(dialog.id)" @expand="handleDoubleClickExpend(dialog.id)">
+                @close="handleDialogClose(dialog.id)" @expand="handleDoubleClickExpend(dialog.data)">
 
                 <component :is="dialog.componentName" v-bind="dialog.data"></component>
             </SmartDialog>
@@ -77,6 +77,7 @@ import TrafficTimeSpace from '@/components/ui/TrafficTimeSpace.vue';
 import MenuItem from '@/components/ui/MenuItem.vue';
 import RingDonutChart from '@/components/ui/RingDonutChart.vue';
 import CrossingPanel from '@/components/ui/CrossingPanel.vue';
+import CrossingDetailPanel from '@/components/ui/CrossingDetailPanel.vue';
 import { getIntersectionData, makeTrafficTimeSpaceData } from '@/mock/data';
 
 
@@ -96,7 +97,8 @@ export default {
         IntersectionMapVideos,
         TrafficTimeSpace,
         RingDonutChart,
-        CrossingPanel
+        CrossingPanel,
+        CrossingDetailPanel
     },
     data() {
         return {
@@ -235,13 +237,14 @@ export default {
         // this.openDialog({
         //         id: 'test', // 这里的 ID 可以根据实际业务场景动态生成,例如 'dev-security-route' 代表特勤安保路线弹窗
         //         title: 'dddd',
-        //         component: 'CrossingPanel',
-        //         width: 260,
-        //         height: 260,
-        //         center: false,
+        //         component: 'CrossingDetailPanel',
+        //         width: 1315,
+        //         height: 682,
+        //         center: true,
         //         showClose: true,
-        //         position: { x: 750, y: 130 },
-        //         noPadding: true,
+        //         // position: { x: 750, y: 130 },
+        //         noPadding: false,
+        //         enableDblclickExpand: false,
         //         data: {}
         //     });
     },
@@ -273,8 +276,18 @@ export default {
 
         },
         // 处理弹窗双击事件
-        handleDoubleClickExpend(id) {
-            console.log('处理弹窗双击事件', id);
+        handleDoubleClickExpend(nodeData) {
+            console.log('处理弹窗双击事件', nodeData);
+            // 根据Tab来显示不同的弹窗内容
+            if (this.activeLeftTab === 'overview') { // 总览
+
+            } else if (this.activeLeftTab === 'crossing') { // 路口
+                this.showCrossingDetailDialogs(nodeData);
+            } else if (this.activeLeftTab === 'trunkLine') { // 干线
+                
+            } else if (this.activeLeftTab === 'specialDuty') { // 特勤
+               
+            }
         },
         openDialog(config) {
             // 1. 防止重复打开同一个弹窗 (根据 id 判断)
@@ -371,11 +384,28 @@ export default {
                 showClose: true,
                 position: { x: 950, y: 430 },
                 noPadding: false,
-                data: {}
+                data: nodeData
             });
 
 
         },
+
+        showCrossingDetailDialogs(nodeData) {
+            console.log('显示干线弹窗组', nodeData.id, nodeData.label);
+             this.openDialog({
+                id: 'crossing_detail' + nodeData.id, // 这里的 ID 可以根据实际业务场景动态生成,例如 'dev-security-route' 代表特勤安保路线弹窗
+                title: nodeData.label,
+                component: 'CrossingDetailPanel',
+                width: 1315,
+                height: 682,
+                center: true,
+                showClose: true,
+                // position: { x: 750, y: 130 },
+                noPadding: false,
+                enableDblclickExpand: false,
+                data: nodeData
+            });
+        },
         // 显示干线弹窗组
         showTrunkLineDalogs(nodeData) {
             console.log('显示干线弹窗组', nodeData.id, nodeData.label);