Ver código fonte

新增首页表格组件;

画安 3 dias atrás
pai
commit
d9ce096794
2 arquivos alterados com 265 adições e 3 exclusões
  1. 146 0
      src/components/ui/TechTable.vue
  2. 119 3
      src/views/Home.vue

+ 146 - 0
src/components/ui/TechTable.vue

@@ -0,0 +1,146 @@
+<template>
+    <div class="tech-table-wrapper" :style="{ maxHeight: height }">
+        <table class="tech-table" cellspacing="0" cellpadding="0">
+
+            <thead>
+                <tr>
+                    <th v-for="(col, index) in columns" :key="index"
+                        :style="{ width: col.width, textAlign: col.align || 'center' }">
+                        {{ col.label }}
+                    </th>
+                </tr>
+            </thead>
+
+            <tbody>
+                <tr v-if="!data || data.length === 0">
+                    <td :colspan="columns.length" class="empty-text">暂无数据</td>
+                </tr>
+
+                <tr v-for="(row, rowIndex) in data" :key="rowIndex" class="table-row"
+                    @click="handleRowClick(row, rowIndex)">
+                    <td v-for="(col, colIndex) in columns" :key="colIndex"
+                        :style="{ textAlign: col.align || 'center' }">
+                        <slot :name="col.key" :row="row" :index="rowIndex">
+                            {{ row[col.key] }}
+                        </slot>
+                    </td>
+                </tr>
+            </tbody>
+
+        </table>
+    </div>
+</template>
+
+<script>
+
+export default {
+    name: 'TechTable',
+    props: {
+        // 表头配置:[{ label: '名称', key: 'name', width: '100px' }]
+        columns: {
+            type: Array,
+            required: true
+        },
+        // 表格数据
+        data: {
+            type: Array,
+            default: () => []
+        },
+       // 允许父组件传入高度来限制表格大小并开启滚动
+        height: { 
+            type: String, 
+            default: 'auto' // 默认不限制高度
+        }
+    },
+    methods: {
+        // 处理行点击并向外派发事件
+        handleRowClick(row, index) {
+            this.$emit('row-click', { row, index });
+        }
+    }
+}
+</script>
+
+<style scoped>
+.tech-table-wrapper {
+    width: 100%;
+    height: 100%;
+    overflow-x: auto;
+    overflow-y: auto;
+}
+
+.tech-table {
+    width: 100%;
+    border-collapse: collapse;
+    table-layout: fixed;
+    /* 让宽度分配更稳定 */
+}
+
+/* 如果你想让表格内部的滚动条也保持你 base.css 里的科技感,可以加上这个 */
+.tech-table-wrapper::-webkit-scrollbar {
+  width: 1px; /* 表格滚动条可以稍微细一点 */
+}
+
+/* ================= 表头样式 ================= */
+.tech-table thead th {
+    position: sticky;
+    top: 0;
+    z-index: 10;
+    color: #6CFFD2;
+    font-size: 14px;
+    font-weight: 600;
+    padding: 10px 10px;
+    box-shadow: inset 0 -1px 0 rgba(255, 255, 255, 0.05);
+    background-color: #112446;
+}
+
+/* ================= 表体样式 ================= */
+.tech-table tbody td {
+    color: #ffffff;
+    font-size: 14px;
+    padding: 10px 10px;
+    /* 文字超出省略号 */
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+/* 斑马纹:奇数行和偶数行背景色区分 */
+.tech-table tbody tr:nth-child(odd) {
+    background-color: #152C57;
+    /* 偏亮的深蓝色 */
+}
+
+.tech-table tbody tr:nth-child(even) {
+    background-color: transparent;
+    /* 保持底色 */
+}
+
+/* 鼠标悬浮高亮反馈 */
+.tech-table tbody tr:hover {
+    background-color: rgba(43, 220, 255, 0.1);
+}
+
+.empty-text {
+    text-align: center;
+    color: #64748b;
+    padding: 30px !important;
+}
+
+/* 给数据行增加鼠标手型 */
+.tech-table tbody .table-row {
+    cursor: pointer;
+    transition: background-color 0.2s;
+    /* 增加背景色过渡动画 */
+}
+
+/* 斑马纹和 hover 效果保持你原来的即可 */
+.tech-table tbody .table-row:nth-child(odd) {
+    background-color: rgba(30, 50, 90, 0.4);
+}
+
+.tech-table tbody .table-row:hover {
+    background-color: rgba(43, 220, 255, 0.15);
+    /* 稍微调亮一点 hover 颜色反馈更好 */
+}
+</style>

+ 119 - 3
src/views/Home.vue

@@ -18,7 +18,7 @@
         <div class="panel-item">
           <PanelContainer title="在线状态">
   
-            <TechTabs v-model="onlineStatusActiveTab" type="segmented"  @tab-click="handleTabClick">
+            <TechTabs v-model="onlineStatusActiveTab" type="segmented" autoPlay  @tab-click="handleTabClick">
               <TechTabPane label="信号机" name="signalMachine" style="height: 100%;">
                 <DynamicDonutChart v-if="onlineStatusDisplayData" :chartData="onlineStatusDisplayData.chartData"
                   :centerTitle="onlineStatusDisplayData.centerTitle" :centerSubTitle="onlineStatusDisplayData.centerSubTitle" />
@@ -56,6 +56,69 @@
       </div>
     </template>
 
+    <template #right>
+      <div class="panel-list">
+        <div class="panel-item">
+          <PanelContainer title="在线状态">
+  
+            <TechTabs v-model="onlineStatusActiveTab" type="segmented" autoPlay @tab-click="handleTabClick">
+              <TechTabPane label="信号机" name="signalMachine" style="height: 100%;">
+                <DynamicDonutChart v-if="onlineStatusDisplayData" :chartData="onlineStatusDisplayData.chartData"
+                  :centerTitle="onlineStatusDisplayData.centerTitle" :centerSubTitle="onlineStatusDisplayData.centerSubTitle" />
+              </TechTabPane>
+              <TechTabPane label="检测器" name="detector">
+                <DynamicDonutChart v-if="onlineStatusDisplayData" :chartData="onlineStatusDisplayData.chartData"
+                  :centerTitle="onlineStatusDisplayData.centerTitle" :centerSubTitle="onlineStatusDisplayData.centerSubTitle" />
+              </TechTabPane>
+              <TechTabPane label="红路灯" name="trafficLight">
+                <DynamicDonutChart v-if="onlineStatusDisplayData" :chartData="onlineStatusDisplayData.chartData"
+                  :centerTitle="onlineStatusDisplayData.centerTitle" :centerSubTitle="onlineStatusDisplayData.centerSubTitle" />
+              </TechTabPane>
+            </TechTabs>
+  
+          </PanelContainer>
+        </div>
+        <div class="panel-item">
+          <PanelContainer title="勤务执行" class="table-panel">
+            <TechTable :columns="tableColumns" :data="tableData" height="263px">
+      
+              <template #level="{ row }">
+                <span :style="{ color: row.level === '二级' ? '#FFDF0C' : 'inherit' }">
+                  {{ row.level }}
+                </span>
+              </template>
+
+              <template #status="{ row }">
+                <span :style="{ color: row.status === '进行中' ? '#FFDF0C' : 'inherit' }">
+                  {{ row.status }}
+                </span>
+              </template>
+
+              <template #action="{ row }">
+                <span 
+                  class="action-btn" 
+                  @click="handleView(row)"
+                >
+                  查看
+                </span>
+              </template>
+
+            </TechTable>
+          </PanelContainer>
+        </div>
+        <div class="panel-item">
+          <PanelContainer title="关键路口" class="table-panel">
+            <TechTable 
+              :columns="keyIntersectionColumns" 
+              :data="keyIntersectionData"
+              height="263px"
+              @row-click="onIntersectionRowClick"
+            />
+          </PanelContainer>
+        </div>
+      </div>
+    </template>
+
   </DashboardLayout>
 </template>
 
@@ -69,6 +132,7 @@ import TechTabs from '@/components/ui/TechTabs.vue';
 import TechTabPane from '@/components/ui/TechTabPane.vue';
 import TickDonutChart from '@/components/ui/TickDonutChart.vue';
 import AlarmMessageList from '@/components/ui/AlarmMessageList.vue';
+import TechTable from '@/components/ui/TechTable.vue';
 
 
 const mockDeviceData = {
@@ -110,7 +174,8 @@ export default {
     TechTabs,
     TechTabPane,
     TickDonutChart,
-    AlarmMessageList
+    AlarmMessageList,
+    TechTable
   },
   data() {
     return {
@@ -127,6 +192,7 @@ export default {
         { name: '中心控制',   value: null,color: '#8b5cf6' }, // 紫色
         { name: '全红控制',   value: null,color: '#f43f5e' }  // 红色
       ],
+      // 消息模拟数据
       alarmData: [
         {
           id: '1',
@@ -149,6 +215,35 @@ export default {
           time: '16:28:28',
           description: '中关村大街-科学院南路口-设备离线'
         }
+      ],
+      // 1. 表头
+      tableColumns: [
+        { label: '序号', key: 'id', width: '60px' },
+        { label: '名称', key: 'name' },
+        { label: '执行人', key: 'executor' },
+        { label: '等级', key: 'level' },
+        { label: '状态', key: 'status' },
+        { label: '操作', key: 'action', width: '80px' }
+      ],
+      // 2. 模拟数据源
+      tableData: [
+        { id: 1, name: '测试', executor: '测试', level: '一级', status: '未开始' },
+        { id: 2, name: '张飞', executor: '张飞', level: '一级', status: '未开始' },
+        { id: 3, name: '关将', executor: '关将', level: '二级', status: '进行中' },
+        { id: 4, name: '刘备', executor: '刘备', level: '一级', status: '未开始' },
+        { id: 5, name: '孙权', executor: '孙权', level: '一级', status: '未开始' },
+      ],
+      // 1. 表头
+      keyIntersectionColumns: [
+        { label: '路口', key: 'intersection', align: 'left' }, // 路口名称较长,建议左对齐更好看
+        { label: '运营模式', key: 'mode', width: '120px' },
+        { label: '方案号', key: 'plan', width: '80px' }
+      ],
+      // 2. 模拟数据源 (完美还原截图内容)
+      keyIntersectionData: [
+        { intersection: '实行东街双园路交叉路口', mode: '定周期控制', plan: '4' },
+        { intersection: '实行东街双园路交叉路口', mode: '自适应控制', plan: '1' },
+        { intersection: '实行东街双园路交叉路口', mode: '感应控制', plan: '5' }
       ]
     };
   },
@@ -175,6 +270,14 @@ export default {
     onAlarmView({ item, index }) {
       console.log('点击了查看:', item.title);
       // 这里可以触发打开一个弹窗 (调用你之前的 SmartDialog 或者路由跳转)
+    },
+    handleView(row) {
+      console.log('点击了查看,当前行数据:', row);
+      // 这里可以触发弹窗或路由跳转
+    },
+    onIntersectionRowClick({ row, index }) {
+      console.log(`用户点击了第 ${index + 1} 行,路口名称是:`, row.intersection);
+      
     }
   }
 }
@@ -186,6 +289,19 @@ export default {
   gap: 16px;
 }
 .panel-item {
-  max-height: 263px;
+  height: 254px;
+}
+.table-panel ::v-deep .panel-content {
+  padding: 0;
+}
+.action-btn {
+  color: #c4d7f0;
+  cursor: pointer;
+  transition: color 0.3s;
+  user-select: none;
+}
+.action-btn:hover {
+  color: #32F6F8;
+  text-decoration: underline;
 }
 </style>