ソースを参照

新增查询组件;新增分页组件;新增路口列表面板;修改路口监控的列表模式下的弹窗切换功能;

画安 2 週間 前
コミット
fc63f65dc1
共有4 個のファイルを変更した800 個の追加5 個の削除を含む
  1. 344 0
      src/components/ui/CrossingListPanel.vue
  2. 199 0
      src/components/ui/TechFilterBar.vue
  3. 233 0
      src/components/ui/TechPagination.vue
  4. 24 5
      src/views/StatusMonitoring.vue

+ 344 - 0
src/components/ui/CrossingListPanel.vue

@@ -0,0 +1,344 @@
+<template>
+    <div class="crossing-list-panel">
+
+        <div class="header-section">
+            <TechFilterBar :config="filterConfig" v-model="searchParams" @search="handleSearch" @reset="handleReset" />
+        </div>
+
+        <div class="table-section">
+
+            <div class="tech-loading-mask" v-show="loading">
+                <div class="spinner"></div>
+                <span class="loading-text">正在同步路口数据...</span>
+            </div>
+
+            <TechTable :columns="tableColumns" :data="tableList" height="100%">
+                <template #phaseStatus="{ row }">
+                    <div class="mini-chart-wrapper">
+                        <SignalTimingChart :phaseData="row.phaseData" :cycleLength="row.cycle" :currentTime="0"
+                            :isMiniMode="true" />
+                    </div>
+                </template>
+
+                <template #actions="{ row }">
+                    <div class="action-buttons">
+                        <span class="btn primary" @click="handleAction('upgrade', row)">升级</span>
+                        <span class="btn primary" @click="handleAction('restart', row)">重启</span>
+                        <span class="btn primary" @click="handleAction('view', row)">查看</span>
+                    </div>
+                </template>
+            </TechTable>
+        </div>
+
+        <div class="footer-section">
+            <TechPagination :total="pagination.total" :currentPage.sync="pagination.currentPage"
+                :pageSize.sync="pagination.pageSize" @current-change="fetchData" @size-change="handleSizeChange" />
+        </div>
+
+    </div>
+</template>
+
+<script>
+// 引入四个核心组件 (请确保这里的路径与你的实际项目路径一致)
+import TechFilterBar from '@/components/ui/TechFilterBar.vue';
+import TechTable from '@/components/ui/TechTable.vue';
+import SignalTimingChart from '@/components/ui/SignalTimingChart.vue';
+import TechPagination from '@/components/ui/TechPagination.vue';
+
+export default {
+    name: 'IntersectionManage',
+    components: {
+        TechFilterBar,
+        TechTable,
+        SignalTimingChart,
+        TechPagination
+    },
+    data() {
+        return {
+            loading: false, // 控制加载遮罩层的显示与隐藏
+
+            // === 表单查询相关 ===
+            searchParams: {
+                name: '',
+                subArea: '',
+                status: '',
+                timeOffset: '',
+                isKey: ''
+            },
+            // 查询栏的动态配置
+            filterConfig: [
+                { type: 'input', label: '路口名称', key: 'name', placeholder: '请输入路口名' },
+                {
+                    type: 'select', label: '子区', key: 'subArea',
+                    options: [
+                        { label: '全部', value: '' },
+                        { label: '石景山区', value: 'shijingshan' },
+                        { label: '海淀区', value: 'haidian' }
+                    ]
+                },
+                {
+                    type: 'select', label: '状态', key: 'status',
+                    options: [
+                        { label: '全部', value: '' },
+                        { label: '在线', value: 'online' },
+                        { label: '离线', value: 'offline' }
+                    ]
+                },
+                {
+                    type: 'select', label: '时间偏差', key: 'timeOffset',
+                    options: [
+                        { label: '无偏差', value: 'none' },
+                        { label: '有偏差', value: 'has' }
+                    ]
+                },
+                {
+                    type: 'select', label: '关键路口', key: 'isKey',
+                    options: [
+                        { label: '请选择', value: '' },
+                        { label: '是', value: 'yes' },
+                        { label: '否', value: 'no' }
+                    ]
+                }
+            ],
+
+            // === 表格与分页相关 ===
+            tableColumns: [
+                { label: '序号', key: 'index', width: '60px' },
+                { label: '路口名', key: 'name', width: '150px' },
+                { label: '子区', key: 'subArea', width: '100px' },
+                { label: 'IP地址', key: 'ip', width: '130px' },
+                { label: '状态', key: 'status', width: '80px' },
+                { label: '时间偏差', key: 'timeOffset', width: '100px' },
+                { label: '周期', key: 'cycle', width: '80px' },
+                { label: '相位状态', key: 'phaseStatus', width: '280px' },
+                { label: '版本信息', key: 'version', width: '180px' },
+                { label: '操作', key: 'actions', width: '150px' }
+            ],
+            tableList: [],
+            pagination: {
+                total: 0,
+                currentPage: 1,
+                pageSize: 10
+            }
+        };
+    },
+    mounted() {
+        this.fetchData(); // 初始化拉取数据
+    },
+    methods: {
+        // 模拟接口请求
+        async fetchData() {
+            this.loading = true; // 开启 Loading 遮罩
+            try {
+                const apiParams = {
+                    ...this.searchParams,
+                    page: this.pagination.currentPage,
+                    size: this.pagination.pageSize
+                };
+                console.log('发起请求,参数:', apiParams);
+
+                // 模拟网络延迟 (500ms),让你能看清 Loading 动画
+                await new Promise(resolve => setTimeout(resolve, 500));
+
+                // 模拟生成列表数据
+                this.tableList = Array.from({ length: this.pagination.pageSize }).map((_, index) => {
+                    const actualIndex = (this.pagination.currentPage - 1) * this.pagination.pageSize + index + 1;
+                    return {
+                        id: `uuid-${Date.now()}-${index}`,
+                        index: actualIndex,
+                        name: '北京路南京路',
+                        subArea: '石景山区',
+                        ip: '41.32.32.131',
+                        status: '在线',
+                        timeOffset: '无偏差',
+                        cycle: 120,
+                        version: '54827345623452756',
+                        // 模拟相位图表数据
+                        phaseData: [
+                            [0, 0, 30, '阶段1', 30, 'green', 'UP'],
+                            [0, 30, 35, '阶段2', 5, 'yellow', ''],
+                            [0, 35, 60, '阶段3', 25, 'green', 'TURN_LEFT']
+                        ]
+                    };
+                });
+
+                this.pagination.total = 32;
+            } catch (error) {
+                console.error('获取列表失败', error);
+            } finally {
+                this.loading = false; // 关闭 Loading 遮罩
+            }
+        },
+
+        // 搜索事件
+        handleSearch() {
+            this.pagination.currentPage = 1;
+            this.fetchData();
+        },
+
+        // 重置事件
+        handleReset() {
+            this.pagination.currentPage = 1;
+            this.fetchData();
+        },
+
+        // 切换每页条数
+        handleSizeChange() {
+            this.pagination.currentPage = 1;
+            this.fetchData();
+        },
+
+        // 统一处理操作列按钮点击
+        handleAction(type, row) {
+            if (type === 'upgrade') {
+                console.log('执行升级:', row.name);
+            } else if (type === 'restart') {
+                console.log('执行重启:', row.name);
+            } else if (type === 'view') {
+                console.log('查看详情:', row.name);
+                this.$emit('crossing-view-detail', row);
+            }
+        }
+    }
+};
+</script>
+
+<style scoped>
+/* 页面主容器:深色背景,铺满视口 */
+.crossing-list-panel {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    box-sizing: border-box;
+    color: #fff;
+    overflow: hidden;
+}
+
+/* 顶部查询区域 */
+.header-section {
+    margin-bottom: 16px;
+    flex-shrink: 0;
+}
+
+/* ================= 表格主体区域与 Loading 遮罩 ================= */
+.table-section {
+    flex: 1;
+    min-height: 0;
+    position: relative;
+    overflow: hidden;
+    padding: 10px 0;
+    display: flex;
+    flex-direction: column;
+}
+
+/* 科技风 Loading 遮罩 */
+.tech-loading-mask {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(11, 22, 44, 0.7);
+    /* 半透明深色底 */
+    backdrop-filter: blur(3px);
+    /* 增加背景模糊质感 */
+    z-index: 50;
+    /* 层级高于表格内容 */
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+}
+
+.spinner {
+    width: 40px;
+    height: 40px;
+    border: 3px solid rgba(77, 168, 255, 0.1);
+    border-top-color: #4da8ff;
+    /* 蓝色高亮条 */
+    border-radius: 50%;
+    animation: spin 1s linear infinite;
+    margin-bottom: 16px;
+    box-shadow: 0 0 15px rgba(77, 168, 255, 0.3);
+}
+
+.loading-text {
+    color: #4da8ff;
+    font-size: 14px;
+    letter-spacing: 2px;
+    animation: pulse 1.5s ease-in-out infinite;
+}
+
+@keyframes spin {
+    to {
+        transform: rotate(360deg);
+    }
+}
+
+@keyframes pulse {
+
+    0%,
+    100% {
+        opacity: 0.5;
+        text-shadow: none;
+    }
+
+    50% {
+        opacity: 1;
+        text-shadow: 0 0 8px rgba(77, 168, 255, 0.8);
+    }
+}
+
+/* 底部分页区域 */
+.footer-section {
+    margin-top: 16px;
+    flex-shrink: 0;
+}
+
+/* ================= 针对插槽内容的样式 ================= */
+
+/* 控制相位图表在表格内的高度 */
+.mini-chart-wrapper {
+    height: 28px;
+    width: 100%;
+    border-radius: 2px;
+    overflow: hidden;
+    display: flex;
+    align-items: center;
+}
+
+/* 操作列按钮布局 */
+.action-buttons {
+    display: flex;
+    justify-content: center;
+    gap: 12px;
+}
+
+.action-buttons .btn {
+    font-size: 13px;
+    cursor: pointer;
+    transition: all 0.2s ease;
+    user-select: none;
+}
+
+/* 主操作按钮 (蓝色) */
+.action-buttons .btn.primary {
+    color: #4da8ff;
+}
+
+.action-buttons .btn.primary:hover {
+    color: #80c4ff;
+    text-decoration: underline;
+}
+
+/* 默认操作按钮 (灰色/淡蓝色) */
+.action-buttons .btn.default {
+    color: #a3b8cc;
+}
+
+.action-buttons .btn.default:hover {
+    color: #ffffff;
+    text-decoration: underline;
+}
+</style>

+ 199 - 0
src/components/ui/TechFilterBar.vue

@@ -0,0 +1,199 @@
+<template>
+  <div class="tech-filter-bar">
+    <div class="filter-items">
+      <div 
+        class="filter-item" 
+        v-for="(item, index) in config" 
+        :key="index"
+      >
+        <label>{{ item.label }}</label>
+
+        <input 
+          v-if="item.type === 'input'"
+          type="text" 
+          v-model="localFormData[item.key]" 
+          :placeholder="item.placeholder || '请输入'" 
+          class="tech-input" 
+        />
+
+        <DropdownSelect
+          v-else-if="item.type === 'select'"
+          v-model="localFormData[item.key]"
+          :options="item.options"
+          :placeholder="item.placeholder || '全部'"
+          theme="bordered" 
+        />
+      </div>
+    </div>
+
+    <div class="filter-actions">
+      <button class="btn btn-view" @click="handleReset">重置</button>
+      <button class="btn btn-view" @click="handleSearch">查询</button>
+    </div>
+  </div>
+</template>
+
+<script>
+// 引入你自定义的下拉组件 (请确保路径正确)
+import DropdownSelect from '@/components/ui/DropdownSelect.vue';
+
+export default {
+  name: 'TechFilterBar',
+  components: {
+    DropdownSelect
+  },
+  props: {
+    // 核心配置数组,控制渲染哪些表单项
+    config: {
+      type: Array,
+      required: true,
+      // 格式示例: [{ type: 'input', label: '姓名', key: 'name' }]
+    },
+    // 支持 v-model 绑定表单数据
+    value: {
+      type: Object,
+      default: () => ({})
+    }
+  },
+  data() {
+    return {
+      // 内部维护一份数据,防止直接修改 props 报错
+      localFormData: { ...this.value }
+    };
+  },
+  watch: {
+    // 监听外部传入的 v-model 变化
+    value: {
+      deep: true,
+      immediate: true,
+      handler(newVal) {
+        // 【关键防御】对比字符串,只有当内外数据真的不一致时,才用外部的数据覆盖内部
+        if (JSON.stringify(newVal) !== JSON.stringify(this.localFormData)) {
+          // 使用深拷贝断开引用
+          this.localFormData = JSON.parse(JSON.stringify(newVal || {}));
+        }
+      }
+    },
+    // 监听内部表单数据的变化
+    localFormData: {
+      deep: true,
+      handler(newVal) {
+        // 【关键防御】只有内部修改导致内外数据不一致时,才向外派发更新
+        if (JSON.stringify(newVal) !== JSON.stringify(this.value)) {
+          this.$emit('input', JSON.parse(JSON.stringify(newVal)));
+        }
+      }
+    }
+  },
+  methods: {
+    handleSearch() {
+      // 触发查询事件
+      this.$emit('search', { ...this.localFormData });
+    },
+    handleReset() {
+      // 根据 config 动态重置表单对象
+      const resetData = {};
+      this.config.forEach(item => {
+        // 如果配置了 defaultValue 则重置为默认值,否则清空为空字符串
+        resetData[item.key] = item.defaultValue !== undefined ? item.defaultValue : '';
+      });
+      this.localFormData = resetData;
+      
+      this.$emit('reset');
+      this.$emit('search', { ...this.localFormData });
+    }
+  }
+};
+</script>
+
+<style scoped>
+.tech-filter-bar {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 20px;
+  background-color: transparent;
+  flex-wrap: wrap;
+  gap: 15px;
+}
+
+.filter-items {
+  display: flex;
+  gap: 20px;
+  flex-wrap: wrap;
+  align-items: center; /* 确保输入框和下拉框垂直居中对齐 */
+}
+
+.filter-item {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.filter-item label {
+  color: #a3b8cc;
+  font-size: 14px;
+  white-space: nowrap;
+}
+
+/* 统一输入框样式 */
+.tech-input {
+  background-color: rgba(20, 40, 75, 0.6);
+  border: 1px solid rgba(100, 130, 190, 0.6); /* 边框颜色与 DropdownSelect 统一 */
+  color: #ffffff;
+  height: 32px; /* 高度与 DropdownSelect 触发器保持一致 */
+  padding: 0 12px;
+  border-radius: 4px;
+  font-size: 14px;
+  outline: none;
+  transition: all 0.3s ease;
+  box-sizing: border-box;
+  width: 140px; /* 给输入框一个默认宽度 */
+}
+
+.tech-input::placeholder {
+  color: #5c7599;
+}
+
+.tech-input:focus {
+  border-color: rgba(140, 180, 255, 0.9);
+  box-shadow: 0 0 8px rgba(77, 168, 255, 0.3);
+}
+
+/* 按钮样式 */
+.filter-actions {
+  display: flex;
+  gap: 12px;
+}
+
+.tech-btn {
+  height: 32px;
+  padding: 0 20px;
+  border-radius: 4px;
+  font-size: 14px;
+  cursor: pointer;
+  transition: all 0.3s;
+  outline: none;
+}
+
+.tech-btn.primary {
+  background-color: #165dff;
+  border: 1px solid #165dff;
+  color: #fff;
+}
+.tech-btn.primary:hover {
+  background-color: #4080ff;
+  border-color: #4080ff;
+  box-shadow: 0 0 10px rgba(22, 93, 255, 0.4);
+}
+
+.tech-btn.ghost {
+  background-color: transparent;
+  border: 1px solid rgba(100, 130, 190, 0.6);
+  color: #a3b8cc;
+}
+.tech-btn.ghost:hover {
+  border-color: #4da8ff;
+  color: #4da8ff;
+}
+</style>

+ 233 - 0
src/components/ui/TechPagination.vue

@@ -0,0 +1,233 @@
+<template>
+  <div class="tech-pagination-wrapper">
+    <div class="pagination-pages">
+      <button 
+        class="page-btn nav-btn" 
+        :disabled="currentPage === 1"
+        @click="changePage(currentPage - 1)"
+      >
+        &lt;
+      </button>
+
+      <button 
+        v-for="page in visiblePages" 
+        :key="page"
+        class="page-btn" 
+        :class="{ active: page === currentPage }"
+        @click="changePage(page)"
+      >
+        {{ page }}
+      </button>
+
+      <button 
+        class="page-btn nav-btn" 
+        :disabled="currentPage === totalPages || totalPages === 0"
+        @click="changePage(currentPage + 1)"
+      >
+        &gt;
+      </button>
+
+      <div class="jumper">
+        <span>前往</span>
+        <input 
+          type="number" 
+          v-model.number="jumpPageInput" 
+          @keyup.enter="handleJump"
+          @blur="handleJump"
+          class="jump-input" 
+          min="1" 
+          :max="totalPages" 
+        />
+        <span>页</span>
+      </div>
+    </div>
+
+    <div class="pagination-info">
+      <div class="size-changer">
+        <span>展示数量:</span>
+        <select v-model="internalPageSize" @change="handleSizeChange" class="size-select">
+          <option :value="10">10条/页</option>
+          <option :value="20">20条/页</option>
+          <option :value="50">50条/页</option>
+        </select>
+      </div>
+      <div class="total-count">共 {{ total }} 条</div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'TechPagination',
+  props: {
+    total: { type: Number, default: 0 },
+    currentPage: { type: Number, default: 1 },
+    pageSize: { type: Number, default: 10 }
+  },
+  data() {
+    return {
+      internalPageSize: this.pageSize,
+      jumpPageInput: this.currentPage
+    };
+  },
+  computed: {
+    totalPages() {
+      return Math.ceil(this.total / this.internalPageSize) || 1;
+    },
+    // 计算需要显示的页码数组 (比如只显示当前页前后的几个页码)
+    visiblePages() {
+      const pages = [];
+      let start = Math.max(1, this.currentPage - 2);
+      let end = Math.min(this.totalPages, start + 4);
+      
+      if (end - start < 4) {
+        start = Math.max(1, end - 4);
+      }
+      
+      for (let i = start; i <= end; i++) {
+        pages.push(i);
+      }
+      return pages;
+    }
+  },
+  watch: {
+    currentPage(newVal) {
+      this.jumpPageInput = newVal;
+    },
+    pageSize(newVal) {
+      this.internalPageSize = newVal;
+    }
+  },
+  methods: {
+    changePage(page) {
+      if (page < 1 || page > this.totalPages || page === this.currentPage) return;
+      this.$emit('update:currentPage', page);
+      this.$emit('current-change', page);
+    },
+    handleJump() {
+      let page = Number(this.jumpPageInput);
+      if (isNaN(page) || page < 1) page = 1;
+      if (page > this.totalPages) page = this.totalPages;
+      
+      this.jumpPageInput = page; // 格式化输入框显示
+      if (page !== this.currentPage) {
+        this.changePage(page);
+      }
+    },
+    handleSizeChange() {
+      // 切换每页条数时,通常重置回第一页
+      this.$emit('update:pageSize', this.internalPageSize);
+      this.$emit('size-change', this.internalPageSize);
+      this.changePage(1); 
+    }
+  }
+};
+</script>
+
+<style scoped>
+.tech-pagination-wrapper {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 15px 20px;
+  color: #a3b8cc;
+  font-size: 14px;
+  user-select: none;
+}
+
+.pagination-pages, .pagination-info {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+/* 页码按钮 */
+.page-btn {
+  min-width: 32px;
+  height: 32px;
+  background-color: #ffffff; /* 截图里未激活的按钮是白底黑字 */
+  border: 1px solid #d9d9d9;
+  border-radius: 4px;
+  color: #333;
+  font-size: 14px;
+  cursor: pointer;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  transition: all 0.2s;
+}
+
+.page-btn:hover:not(:disabled) {
+  border-color: #165dff;
+  color: #165dff;
+}
+
+.page-btn.active {
+  background-color: #165dff;
+  border-color: #165dff;
+  color: #ffffff;
+}
+
+.page-btn:disabled {
+  background-color: #f5f5f5;
+  color: #b8b8b8;
+  cursor: not-allowed;
+  border-color: #d9d9d9;
+}
+
+/* 导航按钮 (< >) 稍微调整一下样式保持协调 */
+.nav-btn {
+  font-weight: bold;
+}
+
+/* 跳转输入框 */
+.jumper {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  margin-left: 10px;
+}
+.jump-input {
+  width: 40px;
+  height: 32px;
+  background-color: transparent;
+  border: 1px solid #2b4c7e;
+  border-radius: 4px;
+  color: #fff;
+  text-align: center;
+  outline: none;
+}
+.jump-input:focus {
+  border-color: #4da8ff;
+}
+/* 隐藏输入框的上下箭头 */
+.jump-input::-webkit-outer-spin-button,
+.jump-input::-webkit-inner-spin-button {
+  -webkit-appearance: none;
+  margin: 0;
+}
+
+/* 右侧控制区 */
+.size-changer {
+  display: flex;
+  align-items: center;
+}
+.size-select {
+  background-color: transparent;
+  border: 1px solid #2b4c7e;
+  color: #fff;
+  height: 32px;
+  padding: 0 10px;
+  border-radius: 4px;
+  outline: none;
+  cursor: pointer;
+}
+.size-select option {
+  background-color: #112446;
+}
+
+.total-count {
+  margin-left: 15px;
+  color: #a3b8cc;
+}
+</style>

+ 24 - 5
src/views/StatusMonitoring.vue

@@ -56,7 +56,7 @@
                 :enableDblclickExpand="dialog.enableDblclickExpand" :noPadding="dialog.noPadding"
                 @close="handleDialogClose(dialog.id)" @expand="handleDoubleClickExpend(dialog.data)">
 
-                <component :is="dialog.componentName" v-bind="dialog.data"></component>
+                <component :is="dialog.componentName" v-bind="dialog.data" @crossing-view-detail="handleCrossingViewDetail"></component>
             </SmartDialog>
         </template>
 
@@ -80,6 +80,7 @@ import RingDonutChart from '@/components/ui/RingDonutChart.vue';
 import CrossingPanel from '@/components/ui/CrossingPanel.vue';
 import CrossingDetailPanel from '@/components/ui/CrossingDetailPanel.vue';
 import ButtonGroup from '@/components/ui/ButtonGroup.vue';
+import CrossingListPanel from '@/components/ui/CrossingListPanel.vue';
 import { getIntersectionData, makeTrafficTimeSpaceData } from '@/mock/data';
 
 
@@ -101,7 +102,8 @@ export default {
         RingDonutChart,
         CrossingPanel,
         CrossingDetailPanel,
-        ButtonGroup
+        ButtonGroup,
+        CrossingListPanel
     },
     data() {
         return {
@@ -246,7 +248,7 @@ export default {
         // this.openDialog({
         //         id: 'test', // 这里的 ID 可以根据实际业务场景动态生成,例如 'dev-security-route' 代表特勤安保路线弹窗
         //         title: 'dddd',
-        //         component: 'CrossingDetailPanel',
+        //         component: 'CrossingListPanel',
         //         width: 1315,
         //         height: 682,
         //         center: true,
@@ -347,7 +349,19 @@ export default {
 
             // 列表模式弹窗
             if (this.currentView === 'list-mode') {
-                
+                this.openDialog({
+                    id: 'crossing-list' + nodeData.id, // 这里的 ID 可以根据实际业务场景动态生成
+                    title: nodeData.label,
+                    component: 'CrossingListPanel',
+                    width: 1315,
+                    height: 682,
+                    center: true,
+                    showClose: true,
+                    // position: { x: 750, y: 130 },
+                    noPadding: false,
+                    enableDblclickExpand: false,
+                    data: {}
+                });
                 return;
             }
 
@@ -414,7 +428,7 @@ export default {
             console.log('显示干线弹窗组', nodeData.id, nodeData.label);
             this.openDialog({
                 id: 'crossing_detail' + nodeData.id, // 这里的 ID 可以根据实际业务场景动态生成,例如 'dev-security-route' 代表特勤安保路线弹窗
-                title: nodeData.label,
+                title: nodeData.label || nodeData.name,
                 component: 'CrossingDetailPanel',
                 width: 1315,
                 height: 682,
@@ -426,6 +440,11 @@ export default {
                 data: nodeData
             });
         },
+        // 路口列表模式下弹窗
+        handleCrossingViewDetail(rowData) {
+            console.log('显示路口列表查看', rowData);
+            this.showCrossingDetailDialogs(rowData);
+        },
         // 显示干线弹窗组
         showTrunkLineDalogs(nodeData) {
             console.log('显示干线弹窗组', nodeData.id, nodeData.label);