wangrong
2026-08-30 8954db4cf4969166961c72569dfa24645276b947
src/modules/report/views/screen/operation.vue
@@ -1,39 +1,35 @@
<template>
   <div class="screen-page">
      <el-row :gutter="10" class="kpi-row">
         <el-col :lg="3" :sm="8" :xs="12">
            <kpi-card label="在线分拣员" :value="data.kpis.sorterOnline"
               :hint="`${data.kpis.sorterOnline} / ${data.kpis.sorterTotal}`"
               :demo="isDemoField('kpis.sorterOnline')" />
         </el-col>
         <el-col :lg="3" :sm="8" :xs="12">
            <kpi-card label="在线车辆" :value="data.kpis.vehicleOnline"
               :hint="`${data.kpis.vehicleOnline} / ${data.kpis.vehicleTotal}`"
               :demo="isDemoField('kpis.vehicleOnline')" />
         </el-col>
         <el-col :lg="3" :sm="8" :xs="12">
            <kpi-card label="在线分拣点" :value="data.kpis.siteOnline"
               :hint="`${data.kpis.siteOnline} / ${data.kpis.siteTotal},按站点启用`"
               :demo="isDemoField('kpis.siteOnline')" />
         </el-col>
         <el-col :lg="3" :sm="8" :xs="12">
            <kpi-card label="今日回收订单" :value="data.kpis.todayOrders" :demo="isDemoField('kpis.todayOrders')" />
         </el-col>
         <el-col :lg="4" :sm="8" :xs="12">
            <kpi-card label="今日预约 / 待处理" :value="data.kpis.todayAppointments"
               :hint="`待处理 ${data.kpis.pendingAppointments}`"
               :demo="isDemoField('kpis.todayAppointments')" />
         </el-col>
         <el-col :lg="4" :sm="8" :xs="12">
            <kpi-card label="异常告警" :value="data.kpis.alerts" alert
               :hint="`健康异常 ${data.kpis.healthAlerts},不展示隐私体征`"
               :demo="isDemoField('kpis.alerts')" />
         </el-col>
         <el-col :lg="4" :sm="8" :xs="12">
            <kpi-card label="车辆安全事件" :value="safetyCount" hint="超速 / 急刹等,来自车辆日汇总"
               :demo="isDemoSection('vehicles')" />
         </el-col>
      </el-row>
      <div class="kpi-grid" style="--kpi-cols: 7">
         <kpi-card
            label="在线分拣员"
            :value="data.kpis.sorterOnline"
            :hint="`${data.kpis.sorterOnline} / ${data.kpis.sorterTotal}`"
         />
         <kpi-card
            label="在线车辆"
            :value="data.kpis.vehicleOnline"
            :hint="`${data.kpis.vehicleOnline} / ${data.kpis.vehicleTotal}`"
         />
         <kpi-card
            label="在线分拣点"
            :value="data.kpis.siteOnline"
            :hint="`${data.kpis.siteOnline} / ${data.kpis.siteTotal},按站点启用`"
         />
         <kpi-card label="今日回收订单" :value="data.kpis.todayOrders" />
         <kpi-card
            label="今日预约 / 待处理"
            :value="data.kpis.todayAppointments"
            :hint="`待处理 ${data.kpis.pendingAppointments}`"
         />
         <kpi-card
            label="异常告警"
            :value="data.kpis.alerts"
            alert
            :hint="`健康异常 ${data.kpis.healthAlerts},不展示隐私体征`"
         />
         <kpi-card label="车辆安全事件" :value="safetyCount" hint="超速 / 急刹等,来自车辆日汇总" />
      </div>
      <el-row :gutter="10" class="mid-row">
         <el-col :lg="14" :xs="24">
@@ -58,7 +54,7 @@
         </el-col>
      </el-row>
      <el-row :gutter="10">
      <el-row :gutter="10" class="bottom-row">
         <el-col :lg="8" :xs="24">
            <panel-card title="分拣员状态" sub="来自分拣员日表,只汇总状态,不展示体征明细" :demo="isDemoSection('sorterStatus')">
               <div class="status-list">
@@ -72,14 +68,16 @@
         </el-col>
         <el-col :lg="8" :xs="24">
            <panel-card title="车辆运行" sub="公司领导看运力与安全,不进校领导首页" :demo="isDemoSection('vehicles')">
               <div class="table table--vehicle">
                  <div class="table__head">
                     <span>车牌</span>
                     <span>里程km</span>
                     <span>怠速分</span>
                     <span>超速</span>
                     <span>状态</span>
                  </div>
               <screen-auto-scroll class="table table--vehicle" :watch-key="vehicleWatchKey">
                  <template #head>
                     <div class="table__head">
                        <span>车牌</span>
                        <span>里程km</span>
                        <span>怠速分</span>
                        <span>超速</span>
                        <span>状态</span>
                     </div>
                  </template>
                  <div v-for="item in data.vehicles" :key="item.no" class="table__row">
                     <span>{{ item.no }}</span>
                     <span>{{ item.km }}</span>
@@ -87,23 +85,25 @@
                     <span>{{ item.overspeed }}</span>
                     <span :class="item.status === '在线' ? 'is-on' : 'is-off'">{{ item.status }}</span>
                  </div>
               </div>
               </screen-auto-scroll>
            </panel-card>
         </el-col>
         <el-col :lg="8" :xs="24">
            <panel-card title="分拣点吞吐" sub="运营维度才下钻到点位" :demo="isDemoSection('sites')">
               <div class="table table--site">
                  <div class="table__head">
                     <span>收集点</span>
                     <span>今日kg</span>
                     <span>在线</span>
                  </div>
               <screen-auto-scroll class="table table--site" :watch-key="siteWatchKey">
                  <template #head>
                     <div class="table__head">
                        <span>收集点</span>
                        <span>今日kg</span>
                        <span>在线</span>
                     </div>
                  </template>
                  <div v-for="item in data.sites" :key="item.name" class="table__row">
                     <span>{{ item.name }}</span>
                     <span>{{ item.weight }}</span>
                     <span :class="item.online ? 'is-on' : 'is-off'">{{ item.online ? '在线' : '离线' }}</span>
                  </div>
               </div>
               </screen-auto-scroll>
            </panel-card>
         </el-col>
      </el-row>
@@ -118,13 +118,16 @@
import { computed } from 'vue';
import KpiCard from '../../components/kpi-card.vue';
import PanelCard from '../../components/panel-card.vue';
import ScreenAutoScroll from '../../components/screen-auto-scroll.vue';
import { useChartTheme, useScreenData, useScreenFieldSource } from '../../hooks/use-screen';
const { data } = useScreenData();
const { isDemoField, isDemoSection } = useScreenFieldSource();
const { isDemoSection } = useScreenFieldSource();
const { mutedColor, splitColor, tooltip } = useChartTheme();
const safetyCount = computed(() => data.value.vehicles.reduce((s, e) => s + e.overspeed, 0));
const vehicleWatchKey = computed(() => data.value.vehicles.map(e => e.no).join('|'));
const siteWatchKey = computed(() => data.value.sites.map(e => e.name).join('|'));
function funnelWidth(value: number) {
   const max = data.value.appointmentFlow[0]?.value || 1;
@@ -165,17 +168,11 @@
</script>
<style lang="scss" scoped>
.screen-page {
@import '../../styles/screen-kpi.scss';
   .kpi-row,
.screen-page {
   .mid-row {
      margin-bottom: 10px;
   }
   .kpi-row {
      :deep(.el-col) {
         margin-bottom: 10px;
      }
   }
   .mid-row,
@@ -272,32 +269,47 @@
      }
   }
   .table {
      padding: 8px 12px 16px;
      font-size: 13px;
   .bottom-row {
      :deep(.panel-card) {
         min-height: 280px;
      }
      &--vehicle &__head,
      &--vehicle &__row {
      :deep(.panel-card__body) {
         display: flex;
         flex-direction: column;
         min-height: 0;
         overflow: hidden;
      }
   }
   .table {
      padding: 8px 12px 12px;
      font-size: 13px;
      height: 100%;
      min-height: 0;
      &--vehicle :deep(.table__head),
      &--vehicle .table__row {
         grid-template-columns: 1.4fr repeat(4, 0.8fr);
      }
      &--site &__head,
      &--site &__row {
      &--site :deep(.table__head),
      &--site .table__row {
         grid-template-columns: 1.6fr 0.8fr 0.6fr;
      }
      &__head,
      &__row {
      :deep(.table__head),
      .table__row {
         display: grid;
         gap: 8px;
         padding: 10px 4px;
      }
      &__head {
      :deep(.table__head) {
         color: var(--el-text-color-secondary);
      }
      &__row {
      .table__row {
         border-top: 1px solid var(--el-border-color-extra-light);
      }