Selaa lähdekoodia

feat(components): 新增五个维度组件(体面、舒适、满意、明白、安心)

refactor(Footer): 移除不必要的nextTick调用

fix(useTaskDetail): 优化事件监听器清理和异步执行逻辑

docs(index): 更新页面标题为"五心联护"智慧养老服务平台
easyforever 1 viikko sitten
vanhempi
commit
fa9ad8a168

+ 1 - 1
index.html

@@ -4,7 +4,7 @@
     <meta charset="UTF-8" />
     <link rel="icon" type="image/svg+xml" href="/vite.svg" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>淮阳区纪检同步·养老老五数字化治理中心</title>
+    <title>淮阳区“五心联护”智慧养老服务平台</title>
   </head>
   <body>
     <div id="app"></div>

+ 673 - 0
src/components/ClothingSatisfactionDimension.vue

@@ -0,0 +1,673 @@
+<template>
+  <div class="dimension-item">
+    <h4 class="detection-title">衣穿得舒适</h4>
+
+    <!-- 第一行:统计数字 -->
+    <div class="stats-row">
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="clothingStats.totalExpenditure"
+            :thousands="true"
+            unit="元"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">本期衣物购总支出</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="clothingStats.perCapitaExpenditure"
+            :thousands="true"
+            unit="元"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">人均衣物支出</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="clothingStats.perCapitaCompliance"
+            :decimals="1"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">人均配备达标率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="clothingStats.distributionRate"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">发放到位率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="clothingStats.averageInterval"
+            unit="天"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">平均发放间隔时间</div>
+      </div>
+    </div>
+
+    <!-- 第二行:图表和衣物展示 -->
+    <div class="charts-section">
+      <div class="chart-item clothing-quarterly-chart">
+        <div class="chart-title">衣物季度发放</div>
+        <div id="clothingQuarterlyChart" class="chart-container"></div>
+      </div>
+      <div class="chart-item purchase-content-chart">
+        <div class="chart-title">采购内容分析</div>
+        <div id="purchaseContentChart" class="chart-container"></div>
+      </div>
+      <div class="chart-item supplier-chart">
+        <div class="chart-title">采购供应商分析</div>
+        <div id="supplierChart" class="chart-container"></div>
+      </div>
+      <div class="chart-item clothing-display">
+        <div class="chart-title">衣物发放</div>
+        <div class="clothing-images-grid">
+          <div class="clothing-image-item" v-for="i in 4" :key="i">
+            <div class="clothing-image-placeholder"></div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 第三行:衣物采购情况和问题数据 -->
+    <div class="menu-container">
+      <!-- 衣物采购情况表格 -->
+      <div class="table-section">
+        <div class="table-title">衣物采购情况:</div>
+        <DataTable
+          :columns="clothingPurchaseTableColumns"
+          :data="clothingPurchaseTableData"
+          :border="true"
+          :large-font="true"
+        >
+          <template #quantity="{ row }">
+            <div class="table-cell">{{ row.quantity }}件</div>
+          </template>
+          <template #unitPrice="{ row }">
+            <div class="table-cell">¥{{ row.unitPrice }}</div>
+          </template>
+          <template #totalAmount="{ row }">
+            <div class="table-cell">¥{{ row.totalAmount }}</div>
+          </template>
+        </DataTable>
+      </div>
+
+      <!-- 机器人和问题数据部分 -->
+      <div class="robot-section">
+        <!-- 机器人 -->
+        <div class="robot-items">
+          <div class="robot-item">
+            <el-image
+              :src="robotWarningSupervisor"
+              :alt="'廉政风险AI监督员'"
+              class="robot-image"
+            ></el-image>
+            <div class="robot-name">廉政风险AI监督员</div>
+          </div>
+        </div>
+
+        <!-- 数据统计 -->
+        <div class="data-stats">
+          <div class="stat-item">
+            <img src="../assets/icons/icon-checked.png" alt="已审核" class="stat-icon" />
+            <span>
+              已核查采购订单{{ clothingStatistics.checkedOrders }}份,比对市场价格{{
+                clothingStatistics.marketPriceComparisons
+              }}次,审核供应商资质{{ clothingStatistics.supplierQualityAnalysis }}家,分析采购明细{{
+                clothingStatistics.purchaseDetailsAnalysis
+              }}项;
+            </span>
+          </div>
+          <div class="stat-item">
+            <img src="../assets/icons/icon-checkedRate.png" alt="审核通过率" class="stat-icon" />
+            <span>
+              实时识别采购异常、支出偏差等问题{{
+                clothingStatistics.identifiedIssues
+              }}起,覆盖在院老人{{ clothingStatistics.affectedSeniors }}人,涉及资金{{
+                clothingStatistics.involvedFunds
+              }}元;
+            </span>
+          </div>
+          <div class="stat-item">
+            <img src="../assets/icons/icon-checking.png" alt="待审核" class="stat-icon" />
+            <span>
+              待处置预警{{ clothingStatistics.pendingAlerts }}条,直接反馈{{
+                clothingStatistics.directFeedback
+              }}条,发布廉政令要求整改{{
+                clothingStatistics.rectificationRequirements
+              }}条,整改完成率{{ clothingStatistics.rectificationRate }}%。
+            </span>
+          </div>
+        </div>
+      </div>
+
+      <!-- 问题数据表格 -->
+      <div class="table-section" style="margin-top: 30px">
+        <DataTable
+          :columns="clothingProblemTableColumns"
+          :data="clothingProblemTableData"
+          :border="true"
+          :large-font="true"
+        >
+          <template #riskLevel="{ row }">
+            <div class="risk-icon" :class="row.riskLevel"></div>
+          </template>
+
+          <template #operation="{ row }">
+            <i v-if="row.status === '未处置'" class="iconfont icon-command"></i>
+            <el-link
+              v-else-if="row.status === '处置中'"
+              type="primary"
+              underline="always"
+              class="operation-link"
+            >
+              催促
+            </el-link>
+            <el-link v-else type="primary" underline="always" class="operation-link">
+              查看详情
+            </el-link>
+          </template>
+        </DataTable>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { onMounted, nextTick } from 'vue'
+import NumberAnimation from './NumberAnimation.vue'
+import DataTable from './DataTable.vue'
+import * as echarts from 'echarts'
+import { institutionDetailData } from '../data/institutionDetail'
+
+import robotWarningSupervisor from '@/assets/images/robot_warningSupervisor.png'
+
+interface Props {
+  visible?: boolean
+}
+
+const props = defineProps<Props>()
+
+const clothingStats = institutionDetailData.clothingStats
+const clothingProblemTableColumns = institutionDetailData.clothingProblemTableColumns
+const clothingProblemTableData = institutionDetailData.clothingProblemTableData
+const clothingPurchaseTableData = institutionDetailData.clothingPurchaseTableData
+const clothingStatistics = institutionDetailData.clothingStatistics
+const clothingPurchaseTableColumns = institutionDetailData.clothingPurchaseTableColumns
+const initCharts = () => {
+  // 衣物季度发放图表
+  const clothingQuarterlyDom = document.getElementById('clothingQuarterlyChart')
+  if (!clothingQuarterlyDom) return
+  const clothingQuarterlyChart = echarts.init(clothingQuarterlyDom)
+  clothingQuarterlyChart.setOption({
+    tooltip: {
+      trigger: 'item',
+      formatter: '{a} <br/>{b}: {c}元',
+    },
+    grid: {
+      left: '3%',
+      right: '4%',
+      bottom: '3%',
+      containLabel: true,
+    },
+    xAxis: {
+      type: 'category',
+      data: institutionDetailData.clothingQuarterlyData.map((item) => item.quarter),
+      axisLine: {
+        show: false,
+      },
+      axisLabel: {
+        color: '#4E9A96',
+        fontSize: 22,
+        margin: 16,
+      },
+      axisTick: {
+        show: false,
+      },
+    },
+    yAxis: {
+      type: 'value',
+      axisLine: {
+        lineStyle: {
+          color: '#00FFE6',
+        },
+      },
+      axisLabel: {
+        color: '#4E9A96',
+        fontSize: 22,
+        margin: 16,
+      },
+      splitLine: {
+        lineStyle: {
+          type: 'dashed',
+          color: 'rgba(0, 255, 230, 0.1)',
+        },
+      },
+    },
+    series: [
+      {
+        name: '衣物支出',
+        type: 'bar',
+        data: institutionDetailData.clothingQuarterlyData.map((item) => item.amount),
+        itemStyle: {
+          color: '#00FFE6',
+          borderRadius: [20, 20, 0, 0],
+        },
+        barWidth: '60%',
+        label: {
+          show: true,
+          position: 'top',
+          color: '#06BBAD',
+          fontSize: 26,
+          margin: 20,
+        },
+      },
+    ],
+  })
+
+  // 采购内容分析图表
+  const purchaseContentDom = document.getElementById('purchaseContentChart')
+  if (!purchaseContentDom) return
+  const purchaseContentChart = echarts.init(purchaseContentDom)
+  purchaseContentChart.setOption({
+    tooltip: {
+      trigger: 'item',
+    },
+
+    series: [
+      {
+        name: '采购内容',
+        type: 'pie',
+        radius: ['30%', '70%'],
+        center: ['50%', '55%'],
+        avoidLabelOverlap: false,
+        padAngle: 3,
+        itemStyle: {
+          borderRadius: 10,
+        },
+        label: {
+          show: true,
+          position: 'outside',
+          formatter: '{b} {d}%',
+          fontSize: 22,
+          distance: 50,
+          color: '#06BBAD',
+        },
+        labelLine: {
+          show: true,
+          length: 20,
+          length2: 20,
+          lineStyle: {
+            width: 2,
+            color: '#00FFE6',
+          },
+        },
+        data: institutionDetailData.clothingPurchaseContentData,
+        color: ['#00FFE6', '#1E90FF', '#FFD700', '#FF8C00', '#FF6347'],
+      },
+    ],
+  })
+
+  // 采购供应商分析图表
+  const colorList = ['#00FFE6', '#1E90FF', '#FFD700', '#FF8C00', '#FF6347']
+  const supplierDom = document.getElementById('supplierChart')
+  if (!supplierDom) return
+  const supplierChart = echarts.init(supplierDom)
+  supplierChart.setOption({
+    tooltip: {
+      trigger: 'item',
+      formatter: '{b}: {c}%',
+    },
+    polar: {
+      radius: [30, '90%'],
+      center: ['50%', '55%'],
+    },
+    angleAxis: {
+      max: Math.max(...institutionDetailData.clothingSupplierData.map((item) => item.value)) + 15,
+      startAngle: 90,
+      clockwise: false,
+      axisLine: {
+        lineStyle: {
+          color: '#066462',
+        },
+      },
+      axisLabel: {
+        show: false,
+      },
+      axisTick: {
+        show: false,
+      },
+      splitLine: {
+        show: false,
+      },
+    },
+    radiusAxis: {
+      type: 'category',
+      data: institutionDetailData.clothingSupplierData.map((item) => item.name),
+      axisTick: {
+        show: false,
+      },
+      axisLine: {
+        show: false,
+        lineStyle: {
+          color: '#00FFE6',
+        },
+      },
+      axisLabel: {
+        show: true,
+        color: (name: string) => {
+          return colorList[
+            institutionDetailData.clothingSupplierData.findIndex((item) => item.name === name)
+          ]
+        },
+        fontSize: 24,
+        interval: 0,
+        align: 'left',
+        margin: -16,
+      },
+      splitLine: {
+        show: false,
+      },
+    },
+    series: [
+      {
+        name: '供应商',
+        type: 'bar',
+        data: institutionDetailData.clothingSupplierData.map((item) => item.value),
+        coordinateSystem: 'polar',
+        itemStyle: {
+          color: (params: any) => {
+            return colorList[params.dataIndex]
+          },
+        },
+        label: {
+          show: true,
+          position: 'middle',
+          formatter: '{c}%',
+          color: 'rgba(0, 0, 0, 0.6)',
+          fontSize: 22,
+        },
+        barWidth: '80%',
+      },
+    ],
+  })
+
+  window.addEventListener('resize', () => {
+    clothingQuarterlyChart.resize()
+    purchaseContentChart.resize()
+    supplierChart.resize()
+  })
+}
+
+onMounted(() => {
+  nextTick(() => {
+    initCharts()
+  })
+})
+</script>
+
+<style lang="scss" scoped>
+$neon-cyan: #00ffe6;
+
+.dimension-item {
+  padding: 0 20px;
+  border: 1px solid $neon-cyan;
+  border-left-color: #086f6a;
+  border-right-color: #086f6a;
+
+  .detection-title {
+    width: calc(100% + 40px);
+    margin-left: -20px;
+    font-size: 32px;
+    font-weight: 500;
+    color: $neon-cyan;
+    line-height: 72px;
+    letter-spacing: 1px;
+    text-align: center;
+    background: linear-gradient(to right, rgba(0, 255, 230, 0.1) 0%, rgba(255, 255, 255, 0) 180%);
+  }
+}
+
+.stats-row {
+  display: flex;
+  justify-content: space-between;
+  width: 80%;
+  margin: 60px auto 100px;
+
+  .stat-item {
+    position: relative;
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+
+    &:not(:last-child) {
+      padding-right: 38px;
+    }
+
+    &:not(:last-child)::after {
+      content: '';
+      position: absolute;
+      right: 0;
+      top: 0;
+      height: 100%;
+      width: 2px;
+      margin: 0 18px;
+      background: url('@/assets/images/vertical_line.png') center no-repeat;
+      background-size: 100% 100%;
+    }
+
+    .stat-value {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 48px;
+      font-weight: 500;
+      color: $neon-cyan;
+      line-height: 56px;
+      letter-spacing: 2px;
+      margin-bottom: 8px;
+    }
+
+    .stat-label {
+      font-size: 26px;
+      color: rgba(1, 255, 230, 0.7);
+      text-align: center;
+      white-space: nowrap;
+    }
+  }
+}
+
+.charts-section {
+  display: flex;
+  gap: 30px;
+  margin-bottom: 40px;
+
+  .chart-item {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: space-between;
+    padding: 20px;
+
+    &.clothing-quarterly-chart {
+      flex: 1.2;
+    }
+
+    &.clothing-display {
+      flex: 1.2;
+    }
+
+    .chart-title {
+      font-size: 30px;
+      color: $neon-cyan;
+      margin-bottom: 20px;
+      font-weight: 600;
+      line-height: 1;
+      letter-spacing: 1px;
+    }
+
+    .chart-container {
+      width: 100%;
+      height: 466px;
+    }
+
+    .clothing-images-grid {
+      display: grid;
+      grid-template-columns: repeat(2, 1fr);
+      gap: 30px 39px;
+      height: 448px;
+
+      .clothing-image-item {
+        width: 375px;
+        height: 200px;
+        background: rgba(0, 255, 230, 0.1);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+    }
+  }
+}
+
+.menu-container {
+  margin-top: 80px;
+  margin-bottom: 30px;
+  padding: 36px;
+
+  .table-title {
+    font-size: 36px;
+    color: $neon-cyan;
+    font-weight: 400;
+    margin-bottom: 30px;
+  }
+}
+
+.robot-section {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  gap: 100px;
+  width: 80%;
+  margin: 60px auto;
+
+  .robot-items {
+    display: flex;
+    gap: 80px;
+  }
+
+  .robot-item {
+    text-align: center;
+
+    .robot-image {
+      width: auto;
+      height: 202px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-bottom: 10px;
+
+      span {
+        color: #00ffe6;
+        font-size: 20px;
+      }
+    }
+
+    .robot-name {
+      color: #00ffe6;
+      font-size: 30px;
+    }
+  }
+
+  .data-stats {
+    flex: 1;
+    padding: 36px 60px;
+    background: rgba(255, 255, 255, 0.01);
+    box-shadow:
+      inset 0px -2px 0px 0px rgba(0, 255, 230, 0.5),
+      inset 0px 2px 0px 0px rgba(0, 255, 230, 0.5),
+      inset 20px 20px 80px 0px rgba(0, 255, 230, 0.08),
+      inset -20px -20px 80px 0px rgba(0, 255, 230, 0.08);
+    border-radius: 20px 20px 20px 20px;
+    border: 2px solid rgba(0, 255, 230, 0.3);
+
+    .stat-item {
+      display: flex;
+      align-items: center;
+      margin-bottom: 30px;
+      color: #00d6c0;
+      font-size: 32px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .stat-icon {
+        width: 76px;
+        margin-right: 30px;
+      }
+    }
+  }
+}
+
+.table-section {
+  font-size: 32px;
+  color: $neon-cyan;
+
+  .empty-text {
+    color: rgba(0, 255, 230, 0.7);
+    padding: 0 20px 30px;
+    text-align: center;
+  }
+
+  .icon-command {
+    font-size: 50px;
+    color: #cf311d;
+    cursor: pointer;
+  }
+
+  .operation-link {
+    font-weight: 400;
+    font-size: 32px;
+    color: #0099ff;
+    letter-spacing: 1px;
+  }
+}
+
+.risk-icon {
+  width: 38px;
+  height: 34px;
+  margin: 0 auto;
+  background-size: auto;
+  background-repeat: no-repeat;
+  background-position: center;
+}
+
+.risk-icon.high {
+  background-image: url('@/assets/icons/icon-warning-red.png');
+}
+
+.risk-icon.medium {
+  background-image: url('@/assets/icons/icon-warning-orange.png');
+}
+
+.risk-icon.low {
+  background-image: url('@/assets/icons/icon-warning-orange.png');
+}
+</style>

+ 683 - 0
src/components/DignityDimension.vue

@@ -0,0 +1,683 @@
+<template>
+  <div class="dimension-item">
+    <h4 class="detection-title">人活得体面</h4>
+
+    <!-- 第一行:统计数字 -->
+    <div class="stats-row">
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="dignityStats.healthInspectionRate"
+            :decimals="1"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">卫生抽查达标率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="dignityStats.disinfectionTimes"
+            unit="次"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">消毒次数</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="dignityStats.avgDisinfectionInterval"
+            unit="天"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">平均消毒间隔时间</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="dignityStats.activityCount"
+            unit="次"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">活动开展合计</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="dignityStats.monthlyActivityCount"
+            unit="次"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">月均开展活动次数</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="dignityStats.physicalExamCoverage"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">体检覆盖率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="dignityStats.avgExamInterval"
+            unit="天"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">体检间隔时间</div>
+      </div>
+    </div>
+
+    <!-- 第二行:图表和活动展示 -->
+    <div class="charts-section">
+      <div class="chart-item activity-type-chart">
+        <div class="chart-title">常见组织活动类型</div>
+        <div id="activityTypeChart" class="chart-container"></div>
+      </div>
+      <div class="chart-item disinfection-chart">
+        <div class="chart-title">每月消毒次数</div>
+        <div id="disinfectionChart" class="chart-container"></div>
+      </div>
+      <div class="chart-item disease-chart">
+        <div class="chart-title">老年人常见病分析</div>
+        <div id="diseaseChart" class="chart-container"></div>
+      </div>
+      <div class="chart-item activity-display">
+        <div class="chart-title">活动展示</div>
+        <div class="activity-images-grid">
+          <div class="activity-image-item" v-for="i in 4" :key="i">
+            <div class="activity-image-placeholder"></div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 第三行:活动参与情况和问题数据 -->
+    <div class="menu-container">
+      <!-- 活动参与情况表格 -->
+      <div class="table-section">
+        <div class="table-title">活动参与情况:</div>
+        <DataTable
+          :columns="activityParticipationTableColumns"
+          :data="activityParticipationTableData"
+          :border="true"
+          :large-font="true"
+        />
+      </div>
+
+      <!-- 机器人和问题数据部分 -->
+      <div class="robot-section">
+        <!-- 机器人 -->
+        <div class="robot-items">
+          <div class="robot-item">
+            <el-image
+              :src="robotCoordinatedDispatcher"
+              :alt="'AI协同调度员'"
+              class="robot-image"
+            ></el-image>
+            <div class="robot-name">AI协同调度员</div>
+          </div>
+          <div class="robot-item">
+            <el-image
+              :src="robotFamilyLiaison"
+              :alt="'AI家属联络员'"
+              class="robot-image"
+            ></el-image>
+            <div class="robot-name">AI家属联络员</div>
+          </div>
+        </div>
+
+        <!-- 数据统计 -->
+        <div class="data-stats">
+          <div class="stat-item">
+            <img src="../assets/icons/icon-checked.png" alt="已完成" class="stat-icon" />
+            <span>
+              已实时抓拍活动、消毒等{{
+                dignityStatistics.activitiesMonitored
+              }}余次,已核验年度体检{{
+                dignityStatistics.physicalExamsCompleted
+              }}人,查收家属相关投诉建议{{ dignityStatistics.familySuggestionsCollected }}条;
+            </span>
+          </div>
+          <div class="stat-item">
+            <img src="../assets/icons/icon-checkedRate.png" alt="识别问题" class="stat-icon" />
+            <span>
+              实时识别服务超时、活动次数不足、体检覆盖不达标、就医响应延迟等异常问题{{
+                dignityStatistics.issuesIdentified
+              }}起,覆盖在院老人{{ dignityStatistics.affectedSeniors }}人,家属{{
+                dignityStatistics.familyMembers
+              }}人;
+            </span>
+          </div>
+          <div class="stat-item">
+            <img src="../assets/icons/icon-checking.png" alt="待处置" class="stat-icon" />
+            <span>
+              待处置预警{{ dignityStatistics.pendingAlerts }}条,直接反馈{{
+                dignityStatistics.directFeedback
+              }}条,发布廉政令要求整改{{
+                dignityStatistics.rectificationRequirements
+              }}条,整改完成率{{ dignityStatistics.rectificationRate }}%。
+            </span>
+          </div>
+        </div>
+      </div>
+
+      <!-- 问题数据表格 -->
+      <div class="table-section" style="margin-top: 30px">
+        <DataTable
+          :columns="dignityProblemTableColumns"
+          :data="dignityProblemTableData"
+          :border="true"
+          :large-font="true"
+        >
+          <template #riskLevel="{ row }">
+            <div class="risk-icon" :class="row.riskLevel"></div>
+          </template>
+
+          <template #operation="{ row }">
+            <i v-if="row.status === '未处置'" class="iconfont icon-command"></i>
+            <el-link
+              v-else-if="row.status === '整改中'"
+              type="primary"
+              underline="always"
+              class="operation-link"
+            >
+              催促
+            </el-link>
+            <el-link v-else type="primary" underline="always" class="operation-link">
+              查看详情
+            </el-link>
+          </template>
+        </DataTable>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { onMounted, nextTick } from 'vue'
+import NumberAnimation from './NumberAnimation.vue'
+import DataTable from './DataTable.vue'
+import * as echarts from 'echarts'
+import { institutionDetailData } from '../data/institutionDetail'
+
+import robotCoordinatedDispatcher from '@/assets/images/robot_coordinatedDispatcher.png'
+import robotFamilyLiaison from '@/assets/images/robot_familyLiaison.png'
+
+interface Props {
+  visible?: boolean
+}
+
+const props = defineProps<Props>()
+
+const dignityStats = institutionDetailData.dignityStats
+const dignityProblemTableColumns = institutionDetailData.dignityProblemTableColumns
+const dignityProblemTableData = institutionDetailData.dignityProblemTableData
+const activityParticipationTableData = institutionDetailData.activityParticipationTableData
+const dignityStatistics = institutionDetailData.dignityStatistics
+const activityParticipationTableColumns = institutionDetailData.activityParticipationTableColumns
+
+const initCharts = () => {
+  // 常见组织活动类型图表 - 横向柱状图
+  const activityTypeDom = document.getElementById('activityTypeChart')
+  if (!activityTypeDom) return
+  const activityTypeChart = echarts.init(activityTypeDom)
+  activityTypeChart.setOption({
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'shadow',
+      },
+      formatter: '{b}: {c}次',
+    },
+    grid: {
+      left: '3%',
+      right: '4%',
+      bottom: '3%',
+      containLabel: true,
+    },
+    xAxis: {
+      type: 'value',
+      axisLine: {
+        lineStyle: {
+          color: '#00FFE6',
+        },
+      },
+      axisLabel: {
+        color: '#4E9A96',
+        fontSize: 22,
+      },
+      splitLine: {
+        lineStyle: {
+          type: 'dashed',
+          color: 'rgba(0, 255, 230, 0.1)',
+        },
+      },
+    },
+    yAxis: {
+      type: 'category',
+      data: institutionDetailData.activityTypeData.map((item) => item.name),
+      axisLine: {
+        lineStyle: {
+          color: '#066462',
+        },
+      },
+      axisLabel: {
+        color: '#4E9A96',
+        fontSize: 22,
+      },
+      axisTick: {
+        show: false,
+      },
+    },
+    series: [
+      {
+        name: '活动次数',
+        type: 'bar',
+        data: institutionDetailData.activityTypeData.map((item) => item.value),
+        itemStyle: {
+          color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+            { offset: 0, color: '#00FFE6' },
+            { offset: 1, color: '#1E90FF' },
+          ]),
+        },
+        barWidth: '60%',
+        label: {
+          show: true,
+          position: 'right',
+          color: '#06BBAD',
+          fontSize: 26,
+        },
+      },
+    ],
+  })
+
+  // 每月消毒次数图表 - 柱状图
+  const disinfectionDom = document.getElementById('disinfectionChart')
+  if (!disinfectionDom) return
+  const disinfectionChart = echarts.init(disinfectionDom)
+  disinfectionChart.setOption({
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'shadow',
+      },
+      formatter: '{b}: {c}次',
+    },
+    grid: {
+      left: '3%',
+      right: '4%',
+      bottom: '3%',
+      containLabel: true,
+    },
+    xAxis: {
+      type: 'category',
+      data: institutionDetailData.monthlyDisinfectionData.months,
+      axisLine: {
+        lineStyle: {
+          color: '#066462',
+        },
+      },
+      axisLabel: {
+        color: '#4E9A96',
+        fontSize: 22,
+      },
+      axisTick: {
+        show: false,
+      },
+    },
+    yAxis: {
+      type: 'value',
+      axisLine: {
+        lineStyle: {
+          color: '#00FFE6',
+        },
+      },
+      axisLabel: {
+        color: '#4E9A96',
+        fontSize: 22,
+      },
+      splitLine: {
+        lineStyle: {
+          type: 'dashed',
+          color: 'rgba(0, 255, 230, 0.1)',
+        },
+      },
+    },
+    series: [
+      {
+        name: '消毒次数',
+        type: 'bar',
+        data: institutionDetailData.monthlyDisinfectionData.values,
+        itemStyle: {
+          color: '#00FFE6',
+          borderRadius: [20, 20, 0, 0],
+        },
+        barWidth: '60%',
+        label: {
+          show: true,
+          position: 'top',
+          color: '#06BBAD',
+          fontSize: 26,
+        },
+      },
+    ],
+  })
+
+  // 老年人常见病分析图表 - 饼图
+  const diseaseDom = document.getElementById('diseaseChart')
+  if (!diseaseDom) return
+  const diseaseChart = echarts.init(diseaseDom)
+  diseaseChart.setOption({
+    tooltip: {
+      trigger: 'item',
+      formatter: '{b}: {d}%',
+    },
+    series: [
+      {
+        name: '常见病',
+        type: 'pie',
+        radius: ['30%', '70%'],
+        center: ['50%', '55%'],
+        avoidLabelOverlap: false,
+        padAngle: 3,
+        itemStyle: {
+          borderRadius: 10,
+        },
+        label: {
+          show: true,
+          position: 'outside',
+          formatter: '{b} {d}%',
+          fontSize: 20,
+          distance: 20,
+          color: '#06BBAD',
+        },
+        labelLine: {
+          show: true,
+          length: 15,
+          length2: 15,
+          lineStyle: {
+            width: 2,
+            color: '#00FFE6',
+          },
+        },
+        data: institutionDetailData.commonDiseaseData,
+        color: ['#00FFE6', '#1E90FF', '#FFD700', '#FF8C00', '#FF6347', '#9932CC', '#808080'],
+      },
+    ],
+  })
+
+  window.addEventListener('resize', () => {
+    activityTypeChart.resize()
+    disinfectionChart.resize()
+    diseaseChart.resize()
+  })
+}
+
+onMounted(() => {
+  nextTick(() => {
+    initCharts()
+  })
+})
+</script>
+
+<style lang="scss" scoped>
+$neon-cyan: #00ffe6;
+
+.dimension-item {
+  padding: 0 20px;
+  border: 1px solid $neon-cyan;
+  border-left-color: #086f6a;
+  border-right-color: #086f6a;
+
+  .detection-title {
+    width: calc(100% + 40px);
+    margin-left: -20px;
+    font-size: 32px;
+    font-weight: 500;
+    color: $neon-cyan;
+    line-height: 72px;
+    letter-spacing: 1px;
+    text-align: center;
+    background: linear-gradient(to right, rgba(0, 255, 230, 0.1) 0%, rgba(255, 255, 255, 0) 180%);
+  }
+}
+
+.stats-row {
+  display: flex;
+  justify-content: space-between;
+  width: 90%;
+  margin: 60px auto 100px;
+
+  .stat-item {
+    position: relative;
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+
+    &:not(:last-child) {
+      padding-right: 38px;
+    }
+
+    &:not(:last-child)::after {
+      content: '';
+      position: absolute;
+      right: 0;
+      top: 0;
+      height: 100%;
+      width: 2px;
+      margin: 0 18px;
+      background: url('@/assets/images/vertical_line.png') center no-repeat;
+      background-size: 100% 100%;
+    }
+
+    .stat-value {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 48px;
+      font-weight: 500;
+      color: $neon-cyan;
+      line-height: 56px;
+      letter-spacing: 2px;
+      margin-bottom: 8px;
+    }
+
+    .stat-label {
+      font-size: 26px;
+      color: rgba(1, 255, 230, 0.7);
+      text-align: center;
+      white-space: nowrap;
+    }
+  }
+}
+
+.charts-section {
+  display: flex;
+  gap: 30px;
+  margin-bottom: 40px;
+
+  .chart-item {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: space-between;
+    padding: 20px;
+
+    &.activity-type-chart {
+      flex: 1.2;
+    }
+
+    &.activity-display {
+      flex: 1.2;
+    }
+
+    .chart-title {
+      font-size: 30px;
+      color: $neon-cyan;
+      margin-bottom: 20px;
+      font-weight: 600;
+      line-height: 1;
+      letter-spacing: 1px;
+    }
+
+    .chart-container {
+      width: 100%;
+      height: 466px;
+    }
+
+    .activity-images-grid {
+      display: grid;
+      grid-template-columns: repeat(2, 1fr);
+      gap: 30px 39px;
+      height: 448px;
+
+      .activity-image-item {
+        width: 375px;
+        height: 200px;
+        background: rgba(0, 255, 230, 0.1);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+    }
+  }
+}
+
+.menu-container {
+  margin-top: 80px;
+  margin-bottom: 30px;
+  padding: 36px;
+
+  .table-title {
+    font-size: 36px;
+    color: $neon-cyan;
+    font-weight: 400;
+    margin-bottom: 30px;
+  }
+}
+
+.robot-section {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  gap: 100px;
+  width: 80%;
+  margin: 60px auto;
+
+  .robot-items {
+    display: flex;
+    gap: 80px;
+  }
+
+  .robot-item {
+    text-align: center;
+
+    .robot-image {
+      width: auto;
+      height: 202px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-bottom: 10px;
+
+      span {
+        color: #00ffe6;
+        font-size: 20px;
+      }
+    }
+
+    .robot-name {
+      color: #00ffe6;
+      font-size: 30px;
+    }
+  }
+
+  .data-stats {
+    flex: 1;
+    padding: 36px 60px;
+    background: rgba(255, 255, 255, 0.01);
+    box-shadow:
+      inset 0px -2px 0px 0px rgba(0, 255, 230, 0.5),
+      inset 0px 2px 0px 0px rgba(0, 255, 230, 0.5),
+      inset 20px 20px 80px 0px rgba(0, 255, 230, 0.08),
+      inset -20px -20px 80px 0px rgba(0, 255, 230, 0.08);
+    border-radius: 20px 20px 20px 20px;
+    border: 2px solid rgba(0, 255, 230, 0.3);
+
+    .stat-item {
+      display: flex;
+      align-items: center;
+      margin-bottom: 30px;
+      color: #00d6c0;
+      font-size: 32px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .stat-icon {
+        width: 76px;
+        margin-right: 30px;
+      }
+    }
+  }
+}
+
+.table-section {
+  font-size: 32px;
+  color: $neon-cyan;
+
+  .empty-text {
+    color: rgba(0, 255, 230, 0.7);
+    padding: 0 20px 30px;
+    text-align: center;
+  }
+
+  .icon-command {
+    font-size: 50px;
+    color: #cf311d;
+    cursor: pointer;
+  }
+
+  .operation-link {
+    font-weight: 400;
+    font-size: 32px;
+    color: #0099ff;
+    letter-spacing: 1px;
+  }
+}
+
+.risk-icon {
+  width: 38px;
+  height: 34px;
+  margin: 0 auto;
+  background-size: auto;
+  background-repeat: no-repeat;
+  background-position: center;
+}
+
+.risk-icon.high {
+  background-image: url('@/assets/icons/icon-warning-red.png');
+}
+
+.risk-icon.medium {
+  background-image: url('@/assets/icons/icon-warning-orange.png');
+}
+
+.risk-icon.low {
+  background-image: url('@/assets/icons/icon-warning-orange.png');
+}
+</style>

+ 845 - 0
src/components/FinanceDimension.vue

@@ -0,0 +1,845 @@
+<template>
+  <div class="dimension-item">
+    <h4 class="detection-title">钱花得明白</h4>
+
+    <!-- 第一行:统计数字 -->
+    <div class="stats-row">
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="financeStats.income"
+            :thousands="true"
+            unit="元"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">机构本级收入</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="financeStats.expenditure"
+            :thousands="true"
+            unit="元"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">机构运营支出</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="financeStats.disclosureRate"
+            :decimals="1"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">公示信息达标率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="financeStats.fundUsageRate"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">资金用途达标率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="financeStats.serviceRate"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">养老服务达标率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="financeStats.procurementRate"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">采购过程达标率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="financeStats.ratingRate"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">等级评定达标率</div>
+      </div>
+    </div>
+
+    <!-- 第二行:图表和资金公示 -->
+    <div class="charts-section">
+      <div class="chart-item">
+        <div class="chart-title">机构本级收入情况</div>
+        <div id="incomeChart" class="chart-container"></div>
+      </div>
+      <div class="chart-item">
+        <div class="chart-title">特困供养资金支出情况</div>
+        <div id="expenseChart" class="chart-container"></div>
+      </div>
+      <div class="chart-item line-chart">
+        <div class="chart-title">特困供养机构资金发放情况</div>
+        <div id="distributionChart" class="chart-container"></div>
+      </div>
+      <div class="chart-item fund-show">
+        <div class="chart-title">资金公示</div>
+        <div class="fund-images-grid">
+          <div class="fund-image-item" v-for="i in 4" :key="i">
+            <div class="fund-image-placeholder"></div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 第三行:Tabs容器 -->
+    <div class="tabs-container">
+      <div class="tabs-header">
+        <div
+          v-for="(tab, index) in ['特困供养资金', '照料护理费', '高龄津贴', '零用钱']"
+          :key="index"
+          class="tab-item"
+          :class="{ active: activeTab === index }"
+          @click="switchTab(index)"
+        >
+          {{ tab }}
+        </div>
+      </div>
+      <div class="tabs-content">
+        <!-- 特困供养资金内容 -->
+        <div class="tab-panel" :class="{ active: activeTab === 0 }">
+          <!-- 第一个表格:特困供养资金 -->
+          <div class="table-section">
+            <DataTable
+              :columns="fundTableColumns"
+              :data="fundTableData"
+              :border="true"
+              :large-font="true"
+            />
+          </div>
+
+          <!-- 机器人和问题数据部分 -->
+          <div class="robot-section">
+            <!-- 机器人 -->
+            <div class="robot-items">
+              <div class="robot-item">
+                <el-image :src="robotAuditor" :alt="'AI审计员'" class="robot-image"> </el-image>
+                <div class="robot-name">AI审计员</div>
+              </div>
+
+              <div class="robot-item">
+                <el-image :src="robotWarningSupervisor" :alt="'AI预警与督办员'" class="robot-image">
+                </el-image>
+                <div class="robot-name">AI预警与督办员</div>
+              </div>
+            </div>
+
+            <!-- 数据统计 -->
+            <div class="data-stats">
+              <div class="stat-item">
+                <img src="../assets/icons/icon-checked.png" alt="已审核" class="stat-icon" />
+                <span>
+                  已审核申请:146份,已静默认证生存状态:237人,智能比对数据:8680项,覆盖老人:287人;
+                </span>
+              </div>
+              <div class="stat-item">
+                <img
+                  src="../assets/icons/icon-checkedRate.png"
+                  alt="审核通过率"
+                  class="stat-icon"
+                />
+                <span> 资金申请审核通过率:98.9%,识别申请异常:9人,涉及资金:3600元; </span>
+              </div>
+              <div class="stat-item">
+                <img src="../assets/icons/icon-checking.png" alt="待审核" class="stat-icon" />
+                <span>
+                  待处置预警:8条,直接反馈:5条,发布廉政要求整改:3条,整改完成率:78.4%。
+                </span>
+              </div>
+            </div>
+          </div>
+
+          <!-- 第二个表格:问题数据 -->
+          <div class="table-section" style="margin-top: 30px">
+            <DataTable
+              :columns="problemTableColumns"
+              :data="problemTableData"
+              :border="true"
+              :large-font="true"
+            >
+              <template #riskLevel="{ row }">
+                <div class="risk-icon" :class="row.riskLevel"></div>
+              </template>
+
+              <template #operation="{ row }">
+                <i v-if="row.status === '未处置'" class="iconfont icon-command"></i>
+                <el-link
+                  v-else-if="row.status === '处置中'"
+                  type="primary"
+                  underline="always"
+                  class="operation-link"
+                >
+                  催促
+                </el-link>
+                <el-link v-else type="primary" underline="always" class="operation-link">
+                  查看详情
+                </el-link>
+              </template>
+            </DataTable>
+          </div>
+        </div>
+        <!-- 其他标签页内容 -->
+        <div class="tab-panel" :class="{ active: activeTab === 1 }">
+          <div class="table-section">
+            <p class="empty-text">照料护理费内容</p>
+          </div>
+        </div>
+        <div class="tab-panel" :class="{ active: activeTab === 2 }">
+          <div class="table-section">
+            <p class="empty-text">高龄津贴内容</p>
+          </div>
+        </div>
+        <div class="tab-panel" :class="{ active: activeTab === 3 }">
+          <div class="table-section">
+            <p class="empty-text">零用钱内容</p>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, nextTick } from 'vue'
+import NumberAnimation from './NumberAnimation.vue'
+import DataTable from './DataTable.vue'
+import * as echarts from 'echarts'
+import { institutionDetailData } from '../data/institutionDetail'
+
+import robotAuditor from '@/assets/images/robot_auditor.png'
+import robotWarningSupervisor from '@/assets/images/robot_warningSupervisor.png'
+
+interface Props {
+  visible?: boolean
+}
+
+const props = defineProps<Props>()
+
+const financeStats = institutionDetailData.financeStats
+const fundTableColumns = institutionDetailData.fundTableColumns
+const problemTableColumns = institutionDetailData.problemTableColumns
+const fundTableData = institutionDetailData.fundTableData
+const problemTableData = institutionDetailData.problemTableData
+
+const activeTab = ref(0)
+
+const switchTab = (index: number) => {
+  activeTab.value = index
+}
+
+const initCharts = () => {
+  console.log('initCharts')
+  const incomeDom = document.getElementById('incomeChart')
+  if (!incomeDom) return
+  const incomeChart = echarts.init(incomeDom)
+  incomeChart.setOption({
+    tooltip: {
+      trigger: 'item',
+    },
+    series: [
+      {
+        name: '收入来源',
+        type: 'pie',
+        radius: ['30%', '80%'],
+        center: ['45%', '55%'],
+        roseType: 'radius',
+        avoidLabelOverlap: false,
+        itemStyle: {
+          borderWidth: 0,
+        },
+        label: {
+          show: true,
+          position: 'outside',
+          formatter: '{b}',
+          fontSize: 22,
+          distance: 50,
+          color: '#06BBAD',
+        },
+        labelLine: {
+          show: true,
+          length: 20,
+          length2: 10,
+          lineStyle: {
+            width: 2,
+            color: '#00FFE6',
+          },
+        },
+        data: institutionDetailData.incomeData,
+        color: ['#00FFE6', '#1E90FF', '#FFD700'],
+      },
+      {
+        name: '中心圆环',
+        type: 'pie',
+        radius: ['30%', '38%'],
+        center: ['45%', '55%'],
+        itemStyle: {
+          color: 'rgba(0, 0, 0, 0.3)',
+        },
+        data: [{ value: 1, name: '' }],
+        label: {
+          show: false,
+        },
+        labelLine: {
+          show: false,
+        },
+        tooltip: {
+          show: false,
+        },
+        emphasis: {
+          disabled: true,
+        },
+      },
+    ],
+  })
+
+  const expenseChart = echarts.init(document.getElementById('expenseChart'))
+  expenseChart.setOption({
+    tooltip: {
+      trigger: 'item',
+    },
+    legend: {
+      orient: 'vertical',
+      right: 0,
+      top: '33%',
+      textStyle: {
+        color: '#06BBAD',
+        fontSize: 22,
+        wrap: true,
+        wordWrap: 'break-word',
+      },
+      itemWidth: 30,
+      itemHeight: 20,
+    },
+    series: [
+      {
+        name: '支出项目',
+        type: 'pie',
+        radius: ['30%', '80%'],
+        center: ['30%', '55%'],
+        avoidLabelOverlap: false,
+        itemStyle: {
+          borderWidth: 0,
+        },
+        label: {
+          show: false,
+        },
+        labelLine: {
+          show: false,
+        },
+        data: institutionDetailData.expenseData,
+        color: ['#1E90FF', '#00FFE6', '#FFD700', '#FF8C00', '#FF6347', '#9370DB', '#4169E1'],
+      },
+      {
+        name: '中心圆环',
+        type: 'pie',
+        radius: ['30%', '38%'],
+        center: ['30%', '55%'],
+        itemStyle: {
+          color: 'rgba(0, 0, 0, 0.3)',
+        },
+        data: [{ value: 1, name: '' }],
+        label: {
+          show: false,
+        },
+        labelLine: {
+          show: false,
+        },
+        tooltip: {
+          show: false,
+        },
+        emphasis: {
+          disabled: true,
+        },
+      },
+    ],
+  })
+
+  const distributionChart = echarts.init(document.getElementById('distributionChart'))
+  distributionChart.setOption({
+    tooltip: {
+      trigger: 'axis',
+    },
+    legend: {
+      data: ['收入', '支出'],
+      left: 80,
+      itemWidth: 50,
+      textStyle: {
+        color: '#06BBAD',
+        fontSize: 26,
+      },
+      itemStyle: {
+        color: 'inherit',
+        borderColor: 'inherit',
+        borderWidth: 4,
+      },
+      lineStyle: {
+        color: 'inherit',
+        width: 3,
+      },
+    },
+    grid: {
+      left: '3%',
+      right: '4%',
+      bottom: '3%',
+      containLabel: true,
+    },
+    xAxis: {
+      type: 'category',
+      boundaryGap: false,
+      data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
+      axisLine: {
+        lineStyle: {
+          color: '#066462',
+        },
+      },
+      axisLabel: {
+        color: '#4E9A96',
+        fontSize: 22,
+        margin: 16,
+      },
+      axisTick: {
+        show: false,
+      },
+    },
+    yAxis: {
+      type: 'value',
+      axisLine: {
+        lineStyle: {
+          color: '#00FFE6',
+        },
+      },
+      axisLabel: {
+        color: '#4E9A96',
+        fontSize: 22,
+        margin: 16,
+      },
+      splitLine: {
+        lineStyle: {
+          type: 'dashed',
+          color: 'rgba(0, 255, 230, 0.1)',
+        },
+      },
+    },
+    series: [
+      {
+        name: '支出',
+        type: 'line',
+        smooth: true,
+        data: institutionDetailData.distributionData.actual,
+        lineStyle: {
+          color: '#01AB9B',
+          width: 3,
+        },
+        itemStyle: {
+          color: '#00D1BD',
+          borderColor: 'rgba(0, 209, 189, 0.30)',
+          borderWidth: 4,
+        },
+        symbol: 'circle',
+        symbolSize: 12,
+        areaStyle: {
+          color: {
+            type: 'linear',
+            x: 0,
+            y: 0,
+            x2: 0,
+            y2: 1,
+            colorStops: [
+              {
+                offset: 0,
+                color: 'rgba(0,255,230,0.4)',
+              },
+              {
+                offset: 1,
+                color: 'rgba(217,217,217,0)',
+              },
+            ],
+          },
+        },
+      },
+      {
+        name: '收入',
+        type: 'line',
+        smooth: true,
+        data: institutionDetailData.distributionData.planned,
+        lineStyle: {
+          color: '#00AEFF',
+          width: 3,
+        },
+        itemStyle: {
+          color: '#42C3FF',
+          borderColor: 'rgba(66, 195, 255, 0.30)',
+          borderWidth: 4,
+        },
+        symbol: 'circle',
+        symbolSize: 12,
+        areaStyle: {
+          color: {
+            type: 'linear',
+            x: 0,
+            y: 0,
+            x2: 0,
+            y2: 1,
+            colorStops: [
+              {
+                offset: 0,
+                color: 'rgba(0,174,255,0.4)',
+              },
+              {
+                offset: 1,
+                color: 'rgba(217,217,217,0)',
+              },
+            ],
+          },
+          shadowBlur: 8,
+          shadowColor: 'rgba(0,0,0,0.25)',
+        },
+      },
+    ],
+  })
+
+  window.addEventListener('resize', () => {
+    incomeChart.resize()
+    expenseChart.resize()
+    distributionChart.resize()
+  })
+}
+
+onMounted(() => {
+  nextTick(() => {
+    initCharts()
+  })
+})
+</script>
+
+<style lang="scss" scoped>
+$neon-cyan: #00ffe6;
+
+.dimension-item {
+  padding: 0 20px;
+  border: 1px solid $neon-cyan;
+  border-left-color: #086f6a;
+  border-right-color: #086f6a;
+
+  .detection-title {
+    width: calc(100% + 40px);
+    margin-left: -20px;
+    font-size: 32px;
+    font-weight: 500;
+    color: $neon-cyan;
+    line-height: 72px;
+    letter-spacing: 1px;
+    text-align: center;
+    background: linear-gradient(to right, rgba(0, 255, 230, 0.1) 0%, rgba(255, 255, 255, 0) 180%);
+  }
+}
+
+.stats-row {
+  display: flex;
+  justify-content: space-between;
+  width: 80%;
+  margin: 60px auto 100px;
+
+  .stat-item {
+    position: relative;
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+
+    &:not(:last-child) {
+      padding-right: 38px;
+    }
+
+    &:not(:last-child)::after {
+      content: '';
+      position: absolute;
+      right: 0;
+      top: 0;
+      height: 100%;
+      width: 2px;
+      margin: 0 18px;
+      background: url('@/assets/images/vertical_line.png') center no-repeat;
+      background-size: 100% 100%;
+    }
+
+    .stat-value {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 48px;
+      font-weight: 500;
+      color: $neon-cyan;
+      line-height: 56px;
+      letter-spacing: 2px;
+      margin-bottom: 8px;
+    }
+
+    .stat-label {
+      font-size: 26px;
+      color: rgba(1, 255, 230, 0.7);
+      text-align: center;
+      white-space: nowrap;
+    }
+  }
+}
+
+.charts-section {
+  display: flex;
+  gap: 30px;
+  margin-bottom: 40px;
+
+  .chart-item {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    padding: 20px;
+
+    &.line-chart {
+      flex: 1.5;
+      width: 900px;
+    }
+
+    &.fund-show {
+      flex: 1;
+    }
+
+    .chart-title {
+      font-size: 30px;
+      color: $neon-cyan;
+      margin-bottom: 20px;
+      font-weight: 600;
+      line-height: 1;
+      letter-spacing: 1px;
+    }
+
+    .chart-container {
+      width: 100%;
+      height: 466px;
+    }
+
+    .fund-images-grid {
+      display: grid;
+      grid-template-columns: repeat(2, 1fr);
+      gap: 10px;
+      height: 466px;
+
+      .fund-image-item {
+        width: 178px;
+        height: 228px;
+        background: rgba(0, 255, 230, 0.1);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+    }
+  }
+}
+
+.tabs-container {
+  margin-top: 80px;
+  margin-bottom: 30px;
+  border: 1px solid #056e6c;
+  background: radial-gradient(ellipse at center, transparent 60%, rgba(9, 51, 56, 0.8) 100%);
+  box-shadow: inset 0 0 60px 6px rgba(255, 255, 255, 0.1);
+
+  .tabs-header {
+    display: flex;
+    height: 92px;
+    border-bottom: 1px solid rgba(0, 255, 230, 0.2);
+
+    .tab-item {
+      flex: 1;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 40px;
+      color: rgba(0, 255, 230, 0.7);
+      cursor: pointer;
+      position: relative;
+      transition: color 0.3s ease;
+      background: radial-gradient(
+        50% 50% at 50% 50%,
+        rgba(255, 255, 255, 0) 0%,
+        rgba(0, 255, 230, 0.1) 100%
+      );
+
+      &:hover {
+        color: #00ffe6;
+        background: radial-gradient(
+          50% 50% at 50% 50%,
+          rgba(255, 255, 255, 0) 0%,
+          rgba(0, 255, 230, 0.2) 100%
+        );
+      }
+
+      &.active {
+        color: #00ffe6;
+
+        &::after {
+          content: '';
+          position: absolute;
+          bottom: 0;
+          left: 0;
+          right: 0;
+          height: 4px;
+          background: linear-gradient(
+            90deg,
+            rgba(78, 251, 234, 0),
+            rgba(78, 251, 234, 1),
+            rgba(78, 251, 234, 0.04)
+          );
+        }
+      }
+    }
+  }
+
+  .tabs-content {
+    padding-top: 36px;
+
+    .tab-panel {
+      display: none;
+
+      &.active {
+        display: block;
+      }
+    }
+  }
+}
+
+.robot-section {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  gap: 100px;
+  width: 80%;
+  margin: 60px auto;
+
+  .robot-items {
+    display: flex;
+    gap: 80px;
+  }
+
+  .robot-item {
+    text-align: center;
+
+    .robot-image {
+      width: auto;
+      height: 202px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-bottom: 10px;
+
+      span {
+        color: #00ffe6;
+        font-size: 20px;
+      }
+    }
+
+    .robot-name {
+      color: #00ffe6;
+      font-size: 30px;
+    }
+  }
+
+  .data-stats {
+    flex: 1;
+    padding: 36px 60px;
+    background: rgba(255, 255, 255, 0.01);
+    box-shadow:
+      inset 0px -2px 0px 0px rgba(0, 255, 230, 0.5),
+      inset 0px 2px 0px 0px rgba(0, 255, 230, 0.5),
+      inset 20px 20px 80px 0px rgba(0, 255, 230, 0.08),
+      inset -20px -20px 80px 0px rgba(0, 255, 230, 0.08);
+    border-radius: 20px 20px 20px 20px;
+    border: 2px solid rgba(0, 255, 230, 0.3);
+
+    .stat-item {
+      display: flex;
+      align-items: center;
+      margin-bottom: 30px;
+      color: #00d6c0;
+      font-size: 32px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .stat-icon {
+        width: 76px;
+        margin-right: 30px;
+      }
+    }
+  }
+}
+
+.table-section {
+  font-size: 32px;
+  color: $neon-cyan;
+
+  .empty-text {
+    color: rgba(0, 255, 230, 0.7);
+    padding: 0 20px 30px;
+    text-align: center;
+  }
+
+  .icon-command {
+    font-size: 50px;
+    color: #cf311d;
+    cursor: pointer;
+  }
+
+  .operation-link {
+    font-weight: 400;
+    font-size: 32px;
+    color: #0099ff;
+    letter-spacing: 1px;
+  }
+}
+
+.risk-icon {
+  width: 38px;
+  height: 34px;
+  margin: 0 auto;
+  background-size: auto;
+  background-repeat: no-repeat;
+  background-position: center;
+}
+
+.risk-icon.high {
+  background-image: url('@/assets/icons/icon-warning-red.png');
+}
+
+.risk-icon.medium {
+  background-image: url('@/assets/icons/icon-warning-orange.png');
+}
+
+.risk-icon.low {
+  background-image: url('@/assets/icons/icon-warning-orange.png');
+}
+</style>

+ 825 - 0
src/components/FoodSatisfactionDimension.vue

@@ -0,0 +1,825 @@
+<template>
+  <div class="dimension-item">
+    <h4 class="detection-title">饭吃得满意</h4>
+
+    <!-- 第一行:统计数字 -->
+    <div class="stats-row">
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="foodStats.totalExpenditure"
+            :thousands="true"
+            unit="元"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">本年度餐饮总支出</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="foodStats.dailyStandard"
+            :decimals="1"
+            unit="元/人"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">日均标准</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="foodStats.foodCostRatio"
+            :decimals="1"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">餐费占比</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="foodStats.recipeCompliance"
+            :decimals="1"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">食谱达标率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="foodStats.dailyFoodCompliance"
+            :decimals="1"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">每日菜品达标率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="foodStats.foodSafetyCompliance"
+            :decimals="1"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">食品安全达标率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="foodStats.kitchenTransparencyCompliance"
+            :decimals="1"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">明厨亮灶达标率</div>
+      </div>
+    </div>
+
+    <!-- 第二行:图表和菜品展示 -->
+    <div class="charts-section">
+      <div class="chart-item food-cost-ratio-chart">
+        <div class="chart-title">餐费占比情况</div>
+        <div id="foodCostRatioChart" class="chart-container"></div>
+      </div>
+      <div class="chart-item nutrition-chart">
+        <div class="chart-title">膳食营养分析</div>
+        <div id="nutritionChart" class="chart-container"></div>
+      </div>
+      <div class="chart-item food-display">
+        <div class="chart-title">菜品展示</div>
+        <div class="food-images-grid">
+          <div class="food-image-item" v-for="i in 6" :key="i">
+            <div class="food-image-placeholder"></div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 第三行:每周菜谱和问题数据 -->
+    <div class="menu-container">
+      <!-- 每周菜谱标题和周选择器 -->
+      <div class="menu-header">
+        <div class="menu-title">每周菜谱</div>
+        <div class="week-selector">
+          <el-select v-model="selectedWeek" size="large" class="week-select">
+            <el-option label="上周" value="last"></el-option>
+            <el-option label="本周" value="current"></el-option>
+            <el-option label="下周" value="next"></el-option>
+          </el-select>
+        </div>
+      </div>
+
+      <!-- 每周菜谱表格 -->
+      <div class="table-section">
+        <div class="menu-table">
+          <table>
+            <thead>
+              <tr>
+                <th>餐别</th>
+                <th v-for="day in weekDays" :key="day">{{ day }}</th>
+              </tr>
+            </thead>
+            <tbody>
+              <tr v-for="(meals, mealType) in weeklyMenu" :key="mealType">
+                <td class="meal-type">{{ mealType }}</td>
+                <td v-for="day in weekDays" :key="day">{{ (meals as any)[day] }}</td>
+              </tr>
+            </tbody>
+          </table>
+        </div>
+      </div>
+
+      <!-- 机器人和问题数据部分 -->
+      <div class="robot-section">
+        <!-- 机器人 -->
+        <div class="robot-items">
+          <div class="robot-item">
+            <el-image
+              :src="robotDietaryNutritionist"
+              :alt="'AI膳食营养员'"
+              class="robot-image"
+            ></el-image>
+            <div class="robot-name">AI膳食营养员</div>
+          </div>
+
+          <div class="robot-item">
+            <el-image :src="robotWarningSupervisor" :alt="'AI预警与督办员'" class="robot-image">
+            </el-image>
+            <div class="robot-name">AI预警与督办员</div>
+          </div>
+        </div>
+
+        <!-- 数据统计 -->
+        <div class="data-stats">
+          <div class="stat-item">
+            <img src="../assets/icons/icon-checked.png" alt="已审核" class="stat-icon" />
+            <span>
+              已审核菜谱{{ foodStatistics.checkedMeals }}份,已分析菜品{{
+                foodStatistics.analyzedDishes
+              }}道,实时监控食堂{{ foodStatistics.realTimeChecks }}家,检查食材批次{{
+                foodStatistics.foodSafetyChecks
+              }}次,核对餐费占比{{ foodStatistics.costRatioChecks }}次;
+            </span>
+          </div>
+          <div class="stat-item">
+            <img src="../assets/icons/icon-checkedRate.png" alt="审核通过率" class="stat-icon" />
+            <span>
+              识别菜品数量、种类、食物安全等异常{{
+                foodStatistics.identifiedIssues
+              }}起,覆盖在院老人{{ foodStatistics.affectedSeniors }}人,涉及到{{
+                foodStatistics.involvedMeals
+              }}次餐食;
+            </span>
+          </div>
+          <div class="stat-item">
+            <img src="../assets/icons/icon-checking.png" alt="待审核" class="stat-icon" />
+            <span>
+              待处置预警{{ foodStatistics.pendingAlerts }}条,(直接反馈{{
+                foodStatistics.directFeedback
+              }}条,发布廉政令{{ foodStatistics.rectificationOrders }}条),整改完成率{{
+                foodStatistics.rectificationRate
+              }}%。
+            </span>
+          </div>
+        </div>
+      </div>
+
+      <!-- 问题数据表格 -->
+      <div class="table-section" style="margin-top: 30px">
+        <DataTable
+          :columns="foodProblemTableColumns"
+          :data="foodProblemTableData"
+          :border="true"
+          :large-font="true"
+        >
+          <template #riskLevel="{ row }">
+            <div class="risk-icon" :class="row.riskLevel"></div>
+          </template>
+
+          <template #operation="{ row }">
+            <i v-if="row.status === '未处置'" class="iconfont icon-command"></i>
+            <el-link
+              v-else-if="row.status === '处置中'"
+              type="primary"
+              underline="always"
+              class="operation-link"
+            >
+              催促
+            </el-link>
+            <el-link v-else type="primary" underline="always" class="operation-link">
+              查看详情
+            </el-link>
+          </template>
+        </DataTable>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, nextTick } from 'vue'
+import NumberAnimation from './NumberAnimation.vue'
+import DataTable from './DataTable.vue'
+import * as echarts from 'echarts'
+import { institutionDetailData } from '../data/institutionDetail'
+
+import robotDietaryNutritionist from '@/assets/images/robot_dietaryNutritionist.png'
+import robotWarningSupervisor from '@/assets/images/robot_warningSupervisor.png'
+
+interface Props {
+  visible?: boolean
+}
+
+const props = defineProps<Props>()
+
+const foodStats = institutionDetailData.foodStats
+const foodProblemTableColumns = institutionDetailData.foodProblemTableColumns
+const foodProblemTableData = institutionDetailData.foodProblemTableData
+const weeklyMenu = institutionDetailData.weeklyMenu
+const foodStatistics = institutionDetailData.foodStatistics
+
+const weekDays = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
+
+const selectedWeek = ref('current')
+
+const initCharts = () => {
+  // 餐费占比图表
+  const foodCostRatioDom = document.getElementById('foodCostRatioChart')
+  if (!foodCostRatioDom) return
+  const foodCostRatioChart = echarts.init(foodCostRatioDom)
+  foodCostRatioChart.setOption({
+    tooltip: {
+      trigger: 'item',
+      formatter: '{a} <br/>{b}: {c}%',
+    },
+    grid: {
+      left: '3%',
+      right: '4%',
+      bottom: '3%',
+      containLabel: true,
+    },
+    xAxis: {
+      type: 'category',
+      data: institutionDetailData.foodCostRatioData.map((item) => item.month),
+      axisLine: {
+        lineStyle: {
+          color: '#066462',
+        },
+      },
+      axisLabel: {
+        color: '#4E9A96',
+        fontSize: 22,
+        margin: 16,
+      },
+      axisTick: {
+        show: false,
+      },
+    },
+    yAxis: {
+      type: 'value',
+      axisLine: {
+        lineStyle: {
+          color: '#00FFE6',
+        },
+      },
+      axisLabel: {
+        color: '#4E9A96',
+        fontSize: 22,
+        margin: 16,
+      },
+      splitLine: {
+        lineStyle: {
+          type: 'dashed',
+          color: 'rgba(0, 255, 230, 0.1)',
+        },
+      },
+    },
+    series: [
+      {
+        name: '100%',
+        type: 'bar',
+        data: Array(institutionDetailData.foodCostRatioData.length).fill(100),
+        itemStyle: {
+          color: 'rgba(0, 255, 230, 0.1)',
+        },
+        barWidth: '60%',
+        barGap: '-100%',
+        z: 0,
+      },
+      {
+        name: '餐费占比',
+        type: 'bar',
+        data: institutionDetailData.foodCostRatioData.map((item) => item.ratio),
+        itemStyle: {
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: '#00FFE6' },
+            { offset: 1, color: '#1E90FF' },
+          ]),
+        },
+        barWidth: '60%',
+        barGap: '-100%',
+        z: 1,
+      },
+    ],
+  })
+
+  // 膳食营养分析图表
+  const nutritionDom = document.getElementById('nutritionChart')
+  if (!nutritionDom) return
+  const nutritionChart = echarts.init(nutritionDom)
+  nutritionChart.setOption({
+    tooltip: {
+      trigger: 'item',
+    },
+    radar: {
+      indicator: institutionDetailData.nutritionData.map((item) => ({
+        name: item.name,
+        max: 100,
+      })),
+      center: ['50%', '55%'],
+      radius: '90%',
+      shape: 'polygon',
+      splitNumber: 5,
+      axisName: {
+        color: '#06BBAD',
+        fontSize: 22,
+      },
+      splitLine: {
+        lineStyle: {
+          color: 'rgba(0, 255, 230, 0.2)',
+        },
+      },
+      splitArea: {
+        show: true,
+        areaStyle: {
+          color: ['rgba(0, 255, 230, 0.05)', 'rgba(0, 255, 230, 0.1)'],
+        },
+      },
+      axisLine: {
+        lineStyle: {
+          color: 'rgba(0, 255, 230, 0.3)',
+        },
+      },
+    },
+    series: [
+      {
+        name: '营养分析',
+        type: 'radar',
+        data: [
+          {
+            value: institutionDetailData.nutritionData.map((item) => item.value),
+            name: '营养达标率',
+            areaStyle: {
+              color: 'rgba(0, 255, 230, 0.3)',
+            },
+            lineStyle: {
+              color: '#00FFE6',
+              width: 3,
+            },
+            itemStyle: {
+              color: '#00FFE6',
+            },
+          },
+        ],
+      },
+    ],
+  })
+
+  window.addEventListener('resize', () => {
+    foodCostRatioChart.resize()
+    nutritionChart.resize()
+  })
+}
+
+onMounted(() => {
+  nextTick(() => {
+    initCharts()
+  })
+})
+</script>
+
+<style lang="scss" scoped>
+$neon-cyan: #00ffe6;
+
+.dimension-item {
+  padding: 0 20px;
+  border: 1px solid $neon-cyan;
+  border-left-color: #086f6a;
+  border-right-color: #086f6a;
+
+  .detection-title {
+    width: calc(100% + 40px);
+    margin-left: -20px;
+    font-size: 32px;
+    font-weight: 500;
+    color: $neon-cyan;
+    line-height: 72px;
+    letter-spacing: 1px;
+    text-align: center;
+    background: linear-gradient(to right, rgba(0, 255, 230, 0.1) 0%, rgba(255, 255, 255, 0) 180%);
+  }
+}
+
+.stats-row {
+  display: flex;
+  justify-content: space-between;
+  width: 80%;
+  margin: 60px auto 100px;
+
+  .stat-item {
+    position: relative;
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+
+    &:not(:last-child) {
+      padding-right: 38px;
+    }
+
+    &:not(:last-child)::after {
+      content: '';
+      position: absolute;
+      right: 0;
+      top: 0;
+      height: 100%;
+      width: 2px;
+      margin: 0 18px;
+      background: url('@/assets/images/vertical_line.png') center no-repeat;
+      background-size: 100% 100%;
+    }
+
+    .stat-value {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 48px;
+      font-weight: 500;
+      color: $neon-cyan;
+      line-height: 56px;
+      letter-spacing: 2px;
+      margin-bottom: 8px;
+    }
+
+    .stat-label {
+      font-size: 26px;
+      color: rgba(1, 255, 230, 0.7);
+      text-align: center;
+      white-space: nowrap;
+    }
+  }
+}
+
+.charts-section {
+  display: flex;
+  gap: 30px;
+  margin-bottom: 40px;
+
+  .chart-item {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    padding: 20px;
+
+    &.food-cost-ratio-chart {
+      flex: 1.5;
+    }
+
+    &.food-display {
+      flex: 1.2;
+    }
+
+    .chart-title {
+      font-size: 30px;
+      color: $neon-cyan;
+      margin-bottom: 20px;
+      font-weight: 600;
+      line-height: 1;
+      letter-spacing: 1px;
+    }
+
+    .chart-container {
+      width: 100%;
+      height: 466px;
+    }
+
+    .food-images-grid {
+      display: grid;
+      grid-template-columns: repeat(3, 1fr);
+      gap: 15px;
+      height: 466px;
+
+      .food-image-item {
+        width: 300px;
+        height: 228px;
+        background: rgba(0, 255, 230, 0.1);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+    }
+  }
+}
+
+.menu-container {
+  margin-top: 80px;
+  margin-bottom: 30px;
+  // border: 1px solid #056e6c;
+  // background: radial-gradient(ellipse at center, transparent 60%, rgba(9, 51, 56, 0.8) 100%);
+  // box-shadow: inset 0 0 60px 6px rgba(255, 255, 255, 0.1);
+  padding: 36px;
+
+  .menu-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 30px;
+
+    .menu-title {
+      font-size: 36px;
+      color: $neon-cyan;
+      font-weight: 400;
+    }
+
+    .week-selector {
+      .week-select {
+        width: 240px;
+        font-size: 32px;
+        color: $neon-cyan;
+
+        :deep(.el-select__selection) {
+          height: 100%;
+        }
+
+        :deep(.el-select__input) {
+          color: $neon-cyan;
+          font-size: 30px;
+        }
+
+        :deep(.el-select__caret) {
+          color: $neon-cyan;
+          font-size: 24px;
+        }
+
+        :deep(.el-select__wrapper) {
+          background: rgba(0, 32, 48, 0.5);
+          border: 1px solid rgba(0, 255, 230, 0.3);
+          border-radius: 4px;
+          height: 72px;
+          font-size: 30px;
+
+          &:hover {
+            border-color: rgba(0, 255, 230, 0.5);
+          }
+
+          &.is-focus {
+            border-color: rgba(0, 255, 230, 0.8);
+            box-shadow: 0 0 0 2px rgba(0, 255, 230, 0.2);
+          }
+
+          .el-select__selected-item {
+            color: $neon-cyan;
+            height: 100%;
+            line-height: 54px;
+          }
+        }
+      }
+    }
+  }
+}
+
+.tabs-container {
+  margin-top: 80px;
+  margin-bottom: 30px;
+  border: 1px solid #056e6c;
+  background: radial-gradient(ellipse at center, transparent 60%, rgba(9, 51, 56, 0.8) 100%);
+  box-shadow: inset 0 0 60px 6px rgba(255, 255, 255, 0.1);
+
+  .tabs-header {
+    display: flex;
+    height: 92px;
+    border-bottom: 1px solid rgba(0, 255, 230, 0.2);
+
+    .tab-item {
+      flex: 1;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 40px;
+      color: rgba(0, 255, 230, 0.7);
+      cursor: pointer;
+      position: relative;
+      transition: color 0.3s ease;
+      background: radial-gradient(
+        50% 50% at 50% 50%,
+        rgba(255, 255, 255, 0) 0%,
+        rgba(0, 255, 230, 0.1) 100%
+      );
+
+      &:hover {
+        color: #00ffe6;
+        background: radial-gradient(
+          50% 50% at 50% 50%,
+          rgba(255, 255, 255, 0) 0%,
+          rgba(0, 255, 230, 0.2) 100%
+        );
+      }
+
+      &.active {
+        color: #00ffe6;
+
+        &::after {
+          content: '';
+          position: absolute;
+          bottom: 0;
+          left: 0;
+          right: 0;
+          height: 4px;
+          background: linear-gradient(
+            90deg,
+            rgba(78, 251, 234, 0),
+            rgba(78, 251, 234, 1),
+            rgba(78, 251, 234, 0.04)
+          );
+        }
+      }
+    }
+  }
+
+  .tabs-content {
+    padding-top: 36px;
+
+    .tab-panel {
+      display: none;
+
+      &.active {
+        display: block;
+      }
+    }
+  }
+}
+
+.menu-table {
+  width: 100%;
+  overflow-x: auto;
+
+  table {
+    width: 100%;
+    border-collapse: collapse;
+
+    th,
+    td {
+      padding: 20px;
+      text-align: center;
+      border: 1px solid rgba(0, 255, 230, 0.3);
+      color: $neon-cyan;
+      font-size: 28px;
+    }
+
+    th {
+      background: rgba(0, 255, 230, 0.1);
+      font-weight: 600;
+    }
+
+    .meal-type {
+      background: rgba(0, 255, 230, 0.05);
+      font-weight: 600;
+      white-space: nowrap;
+    }
+
+    /* 确保weekDays的每一列宽度相同 */
+    th:not(:first-child),
+    td:not(:first-child) {
+      width: calc(100% / 7);
+    }
+
+    td:not(:first-child) {
+      text-align: left;
+      line-height: 1.5;
+    }
+  }
+}
+
+.robot-section {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  gap: 100px;
+  width: 80%;
+  margin: 60px auto;
+
+  .robot-items {
+    display: flex;
+    gap: 80px;
+  }
+
+  .robot-item {
+    text-align: center;
+
+    .robot-image {
+      width: auto;
+      height: 202px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-bottom: 10px;
+
+      span {
+        color: #00ffe6;
+        font-size: 20px;
+      }
+    }
+
+    .robot-name {
+      color: #00ffe6;
+      font-size: 30px;
+    }
+  }
+
+  .data-stats {
+    flex: 1;
+    padding: 36px 60px;
+    background: rgba(255, 255, 255, 0.01);
+    box-shadow:
+      inset 0px -2px 0px 0px rgba(0, 255, 230, 0.5),
+      inset 0px 2px 0px 0px rgba(0, 255, 230, 0.5),
+      inset 20px 20px 80px 0px rgba(0, 255, 230, 0.08),
+      inset -20px -20px 80px 0px rgba(0, 255, 230, 0.08);
+    border-radius: 20px 20px 20px 20px;
+    border: 2px solid rgba(0, 255, 230, 0.3);
+
+    .stat-item {
+      display: flex;
+      align-items: center;
+      margin-bottom: 30px;
+      color: #00d6c0;
+      font-size: 32px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .stat-icon {
+        width: 76px;
+        margin-right: 30px;
+      }
+    }
+  }
+}
+
+.table-section {
+  font-size: 32px;
+  color: $neon-cyan;
+
+  .empty-text {
+    color: rgba(0, 255, 230, 0.7);
+    padding: 0 20px 30px;
+    text-align: center;
+  }
+
+  .icon-command {
+    font-size: 50px;
+    color: #cf311d;
+    cursor: pointer;
+  }
+
+  .operation-link {
+    font-weight: 400;
+    font-size: 32px;
+    color: #0099ff;
+    letter-spacing: 1px;
+  }
+}
+
+.risk-icon {
+  width: 38px;
+  height: 34px;
+  margin: 0 auto;
+  background-size: auto;
+  background-repeat: no-repeat;
+  background-position: center;
+}
+
+.risk-icon.high {
+  background-image: url('@/assets/icons/icon-warning-red.png');
+}
+
+.risk-icon.medium {
+  background-image: url('@/assets/icons/icon-warning-orange.png');
+}
+
+.risk-icon.low {
+  background-image: url('@/assets/icons/icon-warning-orange.png');
+}
+</style>

+ 1 - 2
src/components/Footer.vue

@@ -39,9 +39,8 @@ const currentRobotType = ref('')
 const robots = robotConfig
 
 // 显示任务详情
-const showTaskDetail = async (robotType: string) => {
+const showTaskDetail = (robotType: string) => {
   currentRobotType.value = robotType
-  await nextTick()
   taskDetailVisible.value = true
 }
 

+ 862 - 0
src/components/HouseSafetyDimension.vue

@@ -0,0 +1,862 @@
+<template>
+  <div class="dimension-item">
+    <h4 class="detection-title">房住得安全</h4>
+
+    <!-- 第一行:统计数字 -->
+    <div class="stats-row">
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="houseSafetyStats.fireMonitors"
+            unit="个"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">消防监控</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="houseSafetyStats.fireMonitorCoverage"
+            :decimals="1"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">消防监控覆盖率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="houseSafetyStats.fireFacilityOnlineRate"
+            :decimals="1"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">消防设施在线率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="houseSafetyStats.continuousMonitoring"
+            unit="天"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">持续监控</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="houseSafetyStats.houseSafetyCompliance"
+            :decimals="1"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">房屋安全合规率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="houseSafetyStats.dutyCompliance"
+            :decimals="1"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">24小时值班达标率</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="houseSafetyStats.hiddenDangersFound"
+            unit="处"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">隐患发现</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">
+          <NumberAnimation
+            :value="houseSafetyStats.rectificationRate"
+            unit="%"
+            :unit-style="{ fontSize: '30px' }"
+          />
+        </div>
+        <div class="stat-label">安全隐患整改率</div>
+      </div>
+    </div>
+
+    <!-- 第二行:图表和安全隐患展示 -->
+    <div class="charts-section">
+      <div class="chart-item fire-safety-issue-chart">
+        <div class="chart-title">消防安全问题类型分布</div>
+        <div id="fireSafetyIssueChart" class="chart-container"></div>
+      </div>
+      <div class="chart-item safety-trend-chart">
+        <div class="chart-title">安全隐患趋势</div>
+        <div id="safetyTrendChart" class="chart-container"></div>
+      </div>
+      <div class="chart-item duty-status-chart">
+        <div class="chart-title">24小时值班达成率情况</div>
+        <div id="dutyStatusChart" class="chart-container"></div>
+      </div>
+      <div class="chart-item safety-hazard-display">
+        <div class="chart-title">安全隐患</div>
+        <div class="safety-hazard-images-grid">
+          <div class="safety-hazard-image-item" v-for="i in 4" :key="i">
+            <div class="safety-hazard-image-placeholder"></div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 第三行:智能巡检情况和问题数据 -->
+    <div class="menu-container">
+      <!-- 智能巡检情况表格 -->
+      <div class="table-section">
+        <div class="table-title">智能巡检情况:</div>
+        <DataTable
+          :columns="smartInspectionTableColumns"
+          :data="smartInspectionTableData"
+          :border="true"
+          :large-font="true"
+        />
+      </div>
+
+      <!-- 机器人和问题数据部分 -->
+      <div class="robot-section">
+        <!-- 机器人 -->
+        <div class="robot-items">
+          <div class="robot-item">
+            <el-image
+              :src="robotSafetyInspector"
+              :alt="'AI安全巡查员'"
+              class="robot-image"
+            ></el-image>
+            <div class="robot-name">AI安全巡查员</div>
+          </div>
+          <div class="robot-item">
+            <el-image
+              :src="robotWarningSupervisor"
+              :alt="'AI预警与督办员'"
+              class="robot-image"
+            ></el-image>
+            <div class="robot-name">AI预警与督办员</div>
+          </div>
+        </div>
+
+        <!-- 数据统计 -->
+        <div class="data-stats">
+          <div class="stat-item">
+            <img src="../assets/icons/icon-checked.png" alt="已审核" class="stat-icon" />
+            <span>
+              实时监控点位{{ houseSafetyStatistics.realTimeMonitoringPoints }}个,已巡检{{
+                houseSafetyStatistics.inspectionTimes
+              }}次,分析监控视频{{ houseSafetyStatistics.videoAnalysisMinutes }}分钟;
+            </span>
+          </div>
+          <div class="stat-item">
+            <img src="../assets/icons/icon-checkedRate.png" alt="审核通过率" class="stat-icon" />
+            <span>
+              实时识别异常墙皮脱落{{
+                houseSafetyStatistics.abnormalBehaviorsDetected
+              }}处、通道杂物占用{{ houseSafetyStatistics.blockedCorridors }}处、值班脱岗{{
+                houseSafetyStatistics.monitoringIssues
+              }}起,覆盖在院老人{{ houseSafetyStatistics.affectedSeniors }}人,涉及房间{{
+                houseSafetyStatistics.affectedRooms
+              }}间;
+            </span>
+          </div>
+          <div class="stat-item">
+            <img src="../assets/icons/icon-checking.png" alt="待审核" class="stat-icon" />
+            <span>
+              待处置预警{{ houseSafetyStatistics.pendingAlerts }}条,直接反馈{{
+                houseSafetyStatistics.directFeedback
+              }}条,发布廉政令要求整改{{
+                houseSafetyStatistics.rectificationRequirements
+              }}条,整改完成率{{ houseSafetyStatistics.rectificationRate }}%。
+            </span>
+          </div>
+        </div>
+      </div>
+
+      <!-- 问题数据表格 -->
+      <div class="table-section" style="margin-top: 30px">
+        <DataTable
+          :columns="houseSafetyProblemTableColumns"
+          :data="houseSafetyProblemTableData"
+          :border="true"
+          :large-font="true"
+        >
+          <template #riskLevel="{ row }">
+            <div class="risk-icon" :class="row.riskLevel"></div>
+          </template>
+
+          <template #operation="{ row }">
+            <i v-if="row.status === '未处置'" class="iconfont icon-command"></i>
+            <el-link
+              v-else-if="row.status === '处置中'"
+              type="primary"
+              underline="always"
+              class="operation-link"
+            >
+              催促
+            </el-link>
+            <el-link v-else type="primary" underline="always" class="operation-link">
+              查看详情
+            </el-link>
+          </template>
+        </DataTable>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, nextTick } from 'vue'
+import NumberAnimation from './NumberAnimation.vue'
+import DataTable from './DataTable.vue'
+import * as echarts from 'echarts'
+import { institutionDetailData } from '../data/institutionDetail'
+
+import robotSafetyInspector from '@/assets/images/robot_safetyInspector.png'
+import robotWarningSupervisor from '@/assets/images/robot_warningSupervisor.png'
+
+interface Props {
+  visible?: boolean
+}
+
+const props = defineProps<Props>()
+
+const houseSafetyStats = institutionDetailData.houseSafetyStats
+const houseSafetyProblemTableColumns = institutionDetailData.houseSafetyProblemTableColumns
+const houseSafetyProblemTableData = institutionDetailData.houseSafetyProblemTableData
+const smartInspectionTableColumns = institutionDetailData.smartInspectionTableColumns
+const smartInspectionTableData = institutionDetailData.smartInspectionTableData
+const houseSafetyStatistics = institutionDetailData.houseSafetyStatistics
+
+const initCharts = () => {
+  // 消防安全问题类型分布图表
+  const fireSafetyIssueDom = document.getElementById('fireSafetyIssueChart')
+  if (!fireSafetyIssueDom) return
+  const fireSafetyIssueChart = echarts.init(fireSafetyIssueDom)
+  fireSafetyIssueChart.setOption({
+    tooltip: {
+      trigger: 'item',
+      formatter: '{a} <br/>{b}: {c} ({d}%)',
+    },
+
+    series: [
+      {
+        name: '消防安全问题',
+        type: 'pie',
+        roseType: 'radius',
+        radius: ['30%', '80%'],
+        center: ['50%', '50%'],
+        avoidLabelOverlap: false,
+        itemStyle: {
+          borderWidth: 0,
+        },
+        label: {
+          position: 'outside',
+          formatter: '{b}',
+          fontSize: 22,
+          distance: 50,
+          color: '#06BBAD',
+        },
+        labelLine: {
+          show: true,
+          length: 20,
+          length2: 10,
+          lineStyle: {
+            width: 2,
+            color: '#00FFE6',
+          },
+        },
+        data: institutionDetailData.fireSafetyIssueTypeData,
+        color: ['#00FFE6', '#1E90FF', '#FFD700', '#FF8C00', '#FF6347'],
+      },
+      {
+        name: '中心圆环',
+        type: 'pie',
+        radius: ['30%', '38%'],
+        center: ['50%', '50%'],
+        itemStyle: {
+          color: 'rgba(0, 0, 0, 0.3)',
+        },
+        data: [{ value: 1, name: '' }],
+        label: {
+          show: false,
+        },
+        labelLine: {
+          show: false,
+        },
+        tooltip: {
+          show: false,
+        },
+        emphasis: {
+          disabled: true,
+        },
+      },
+    ],
+  })
+
+  // 安全隐患趋势图表
+  const safetyTrendDom = document.getElementById('safetyTrendChart')
+  if (!safetyTrendDom) return
+  const safetyTrendChart = echarts.init(safetyTrendDom)
+  safetyTrendChart.setOption({
+    tooltip: {
+      trigger: 'axis',
+      formatter: '{a} <br/>{b}: {c}',
+    },
+    grid: {
+      left: '3%',
+      right: '4%',
+      bottom: '3%',
+      containLabel: true,
+    },
+    xAxis: {
+      type: 'category',
+      data: institutionDetailData.safetyTrendData.months,
+      boundaryGap: true,
+      axisLine: {
+        lineStyle: {
+          color: '#066462',
+        },
+      },
+      axisLabel: {
+        color: '#4E9A96',
+        fontSize: 22,
+        margin: 16,
+      },
+      axisTick: {
+        show: false,
+      },
+    },
+    yAxis: {
+      type: 'value',
+      axisLine: {
+        lineStyle: {
+          color: '#00FFE6',
+        },
+      },
+      axisLabel: {
+        color: '#4E9A96',
+        fontSize: 22,
+        margin: 16,
+      },
+      splitLine: {
+        lineStyle: {
+          type: 'dashed',
+          color: 'rgba(0, 255, 230, 0.1)',
+        },
+      },
+    },
+    series: [
+      {
+        name: '安全隐患',
+        type: 'line',
+        data: institutionDetailData.safetyTrendData.values,
+        smooth: true,
+        itemStyle: {
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: '#00FFE6' },
+            { offset: 1, color: '#1E90FF' },
+          ]),
+          borderColor: 'rgba(0, 209, 189, 0.30)',
+          borderWidth: 6,
+        },
+        areaStyle: {
+          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: 'rgba(0, 255, 230, 0.3)' },
+            { offset: 1, color: 'rgba(30, 144, 255, 0.1)' },
+          ]),
+        },
+        lineStyle: {
+          width: 4,
+        },
+        symbol: 'circle',
+        symbolSize: 20,
+      },
+    ],
+  })
+
+  // 24小时值班达成率情况图表 - 使用自定义图形实现伪3D效果
+  const dutyStatusDom = document.getElementById('dutyStatusChart')
+  if (!dutyStatusDom) return
+  const dutyStatusChart = echarts.init(dutyStatusDom)
+
+  // 定义偏移量
+  const offsetX = 18
+  const offsetY = 10
+
+  // 绘制左侧面
+  const CubeLeft = echarts.graphic.extendShape({
+    shape: {
+      x: 0,
+      y: 0,
+    },
+    buildPath: function (ctx: any, shape: any) {
+      const xAxisPoint = shape.xAxisPoint
+      const c0 = [shape.x, shape.y]
+      const c1 = [shape.x - offsetX, shape.y - offsetY]
+      const c2 = [xAxisPoint[0] - offsetX, xAxisPoint[1] - offsetY]
+      const c3 = [xAxisPoint[0], xAxisPoint[1]]
+      ctx
+        .moveTo(c0[0], c0[1])
+        .lineTo(c1[0], c1[1])
+        .lineTo(c2[0], c2[1])
+        .lineTo(c3[0], c3[1])
+        .closePath()
+    },
+  })
+
+  // 绘制右侧面
+  const CubeRight = echarts.graphic.extendShape({
+    shape: {
+      x: 0,
+      y: 0,
+    },
+    buildPath: function (ctx: any, shape: any) {
+      const xAxisPoint = shape.xAxisPoint
+      const c1 = [shape.x, shape.y]
+      const c2 = [xAxisPoint[0], xAxisPoint[1]]
+      const c3 = [xAxisPoint[0] + offsetX, xAxisPoint[1] - offsetY]
+      const c4 = [shape.x + offsetX, shape.y - offsetY]
+      ctx
+        .moveTo(c1[0], c1[1])
+        .lineTo(c2[0], c2[1])
+        .lineTo(c3[0], c3[1])
+        .lineTo(c4[0], c4[1])
+        .closePath()
+    },
+  })
+
+  // 绘制顶面
+  const CubeTop = echarts.graphic.extendShape({
+    shape: {
+      x: 0,
+      y: 0,
+    },
+    buildPath: function (ctx: any, shape: any) {
+      const c1 = [shape.x, shape.y]
+      const c2 = [shape.x + offsetX, shape.y - offsetY]
+      const c3 = [shape.x, shape.y - offsetY * 2]
+      const c4 = [shape.x - offsetX, shape.y - offsetY]
+      ctx
+        .moveTo(c1[0], c1[1])
+        .lineTo(c2[0], c2[1])
+        .lineTo(c3[0], c3[1])
+        .lineTo(c4[0], c4[1])
+        .closePath()
+    },
+  })
+
+  // 注册三个面图形
+  echarts.graphic.registerShape('CubeLeft', CubeLeft)
+  echarts.graphic.registerShape('CubeRight', CubeRight)
+  echarts.graphic.registerShape('CubeTop', CubeTop)
+
+  dutyStatusChart.setOption({
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'shadow',
+      },
+      formatter: function (params: any) {
+        const data = params[0]
+        const month = institutionDetailData.dutyStatusData.months[data.data[0]]
+        const value = data.data[1]
+        return `${month}: ${value}%`
+      },
+    },
+    grid: {
+      left: '3%',
+      right: '4%',
+      bottom: '3%',
+      top: '15%',
+      containLabel: true,
+    },
+    xAxis: {
+      type: 'category',
+      data: institutionDetailData.dutyStatusData.months,
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: '#066462',
+        },
+      },
+      axisLabel: {
+        color: '#4E9A96',
+        fontSize: 22,
+        textStyle: {
+          color: '#4E9A96',
+        },
+      },
+      axisTick: {
+        show: false,
+      },
+    },
+    yAxis: {
+      type: 'value',
+      name: '达成率(%)',
+      nameGap: 26,
+      nameTextStyle: {
+        color: '#4E9A96',
+        fontSize: 22,
+      },
+      axisLine: {
+        show: true,
+        lineStyle: {
+          color: '#00FFE6',
+        },
+      },
+      axisLabel: {
+        color: '#4E9A96',
+        fontSize: 22,
+      },
+      axisTick: {
+        show: false,
+      },
+      splitLine: {
+        show: true,
+        lineStyle: {
+          color: 'rgba(0, 255, 230, 0.1)',
+          type: 'dashed',
+        },
+      },
+    },
+    series: [
+      {
+        type: 'custom',
+        yAxisIndex: 0,
+        renderItem: function (_: any, api: any) {
+          const location = api.coord([api.value(0), api.value(1)])
+          return {
+            type: 'group',
+            children: [
+              {
+                type: 'CubeLeft',
+                shape: {
+                  api,
+                  xValue: api.value(0),
+                  yValue: api.value(1),
+                  x: location[0],
+                  y: location[1],
+                  xAxisPoint: api.coord([api.value(0), 0]),
+                },
+                style: {
+                  fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                    { offset: 0, color: '#008080' },
+                    { offset: 1, color: '#004d4d' },
+                  ]),
+                },
+              },
+              {
+                type: 'CubeRight',
+                shape: {
+                  api,
+                  xValue: api.value(0),
+                  yValue: api.value(1),
+                  x: location[0],
+                  y: location[1],
+                  xAxisPoint: api.coord([api.value(0), 0]),
+                },
+                style: {
+                  fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                    { offset: 0, color: '#00FFE6' },
+                    { offset: 1, color: '#009999' },
+                  ]),
+                },
+              },
+              {
+                type: 'CubeTop',
+                shape: {
+                  api,
+                  xValue: api.value(0),
+                  yValue: api.value(1),
+                  x: location[0],
+                  y: location[1],
+                },
+                style: {
+                  fill: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+                    { offset: 0, color: '#00CCCC' },
+                    { offset: 1, color: '#00FFE6' },
+                  ]),
+                },
+              },
+            ],
+          }
+        },
+        data: institutionDetailData.dutyStatusData.values.map((value: number, index: number) => [
+          index,
+          value,
+        ]),
+      },
+    ],
+  })
+
+  window.addEventListener('resize', () => {
+    fireSafetyIssueChart.resize()
+    safetyTrendChart.resize()
+    dutyStatusChart.resize()
+  })
+}
+
+onMounted(() => {
+  nextTick(() => {
+    initCharts()
+  })
+})
+</script>
+
+<style lang="scss" scoped>
+$neon-cyan: #00ffe6;
+
+.dimension-item {
+  padding: 0 20px;
+  border: 1px solid $neon-cyan;
+  border-left-color: #086f6a;
+  border-right-color: #086f6a;
+
+  .detection-title {
+    width: calc(100% + 40px);
+    margin-left: -20px;
+    font-size: 32px;
+    font-weight: 500;
+    color: $neon-cyan;
+    line-height: 72px;
+    letter-spacing: 1px;
+    text-align: center;
+    background: linear-gradient(to right, rgba(0, 255, 230, 0.1) 0%, rgba(255, 255, 255, 0) 180%);
+  }
+}
+
+.stats-row {
+  display: flex;
+  justify-content: space-between;
+  flex-wrap: wrap;
+  width: 90%;
+  margin: 60px auto 100px;
+
+  .stat-item {
+    position: relative;
+    width: calc(100% / 8);
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    margin-bottom: 40px;
+
+    &:not(:last-child) {
+      padding-right: 38px;
+    }
+
+    &:not(:last-child)::after {
+      content: '';
+      position: absolute;
+      right: 0;
+      top: 0;
+      height: 100%;
+      width: 2px;
+      margin: 0 18px;
+      background: url('@/assets/images/vertical_line.png') center no-repeat;
+      background-size: 100% 100%;
+    }
+
+    .stat-value {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 48px;
+      font-weight: 500;
+      color: $neon-cyan;
+      line-height: 56px;
+      letter-spacing: 2px;
+      margin-bottom: 8px;
+    }
+
+    .stat-label {
+      font-size: 26px;
+      color: rgba(1, 255, 230, 0.7);
+      text-align: center;
+      white-space: nowrap;
+    }
+  }
+}
+
+.charts-section {
+  display: flex;
+  gap: 30px;
+  margin-bottom: 40px;
+
+  .chart-item {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: space-between;
+    padding: 20px;
+
+    .chart-title {
+      font-size: 30px;
+      color: $neon-cyan;
+      margin-bottom: 20px;
+      font-weight: 600;
+      line-height: 1;
+      letter-spacing: 1px;
+    }
+
+    .chart-container {
+      width: 100%;
+      height: 466px;
+    }
+
+    .safety-hazard-images-grid {
+      display: grid;
+      grid-template-columns: repeat(2, 1fr);
+      gap: 20px;
+      height: 448px;
+
+      .safety-hazard-image-item {
+        width: 300px;
+        height: 200px;
+        background: rgba(0, 255, 230, 0.1);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+    }
+  }
+}
+
+.menu-container {
+  margin-top: 80px;
+  margin-bottom: 30px;
+  padding: 36px;
+
+  .table-title {
+    font-size: 36px;
+    color: $neon-cyan;
+    font-weight: 400;
+    margin-bottom: 30px;
+  }
+}
+
+.robot-section {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  gap: 100px;
+  width: 80%;
+  margin: 60px auto;
+
+  .robot-items {
+    display: flex;
+    gap: 80px;
+  }
+
+  .robot-item {
+    text-align: center;
+
+    .robot-image {
+      width: auto;
+      height: 202px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-bottom: 10px;
+
+      span {
+        color: #00ffe6;
+        font-size: 20px;
+      }
+    }
+
+    .robot-name {
+      color: #00ffe6;
+      font-size: 30px;
+    }
+  }
+
+  .data-stats {
+    flex: 1;
+    padding: 36px 60px;
+    background: rgba(255, 255, 255, 0.01);
+    box-shadow:
+      inset 0px -2px 0px 0px rgba(0, 255, 230, 0.5),
+      inset 0px 2px 0px 0px rgba(0, 255, 230, 0.5),
+      inset 20px 20px 80px 0px rgba(0, 255, 230, 0.08),
+      inset -20px -20px 80px 0px rgba(0, 255, 230, 0.08);
+    border-radius: 20px 20px 20px 20px;
+    border: 2px solid rgba(0, 255, 230, 0.3);
+
+    .stat-item {
+      display: flex;
+      align-items: center;
+      margin-bottom: 30px;
+      color: #00d6c0;
+      font-size: 32px;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .stat-icon {
+        width: 76px;
+        margin-right: 30px;
+      }
+    }
+  }
+}
+
+.table-section {
+  font-size: 32px;
+  color: $neon-cyan;
+
+  .empty-text {
+    color: rgba(0, 255, 230, 0.7);
+    padding: 0 20px 30px;
+    text-align: center;
+  }
+
+  .icon-command {
+    font-size: 50px;
+    color: #cf311d;
+    cursor: pointer;
+  }
+
+  .operation-link {
+    font-weight: 400;
+    font-size: 32px;
+    color: #0099ff;
+    letter-spacing: 1px;
+  }
+}
+
+.risk-icon {
+  width: 38px;
+  height: 34px;
+  margin: 0 auto;
+  background-size: auto;
+  background-repeat: no-repeat;
+  background-position: center;
+}
+
+.risk-icon.high {
+  background-image: url('@/assets/icons/icon-warning-red.png');
+}
+
+.risk-icon.medium {
+  background-image: url('@/assets/icons/icon-warning-orange.png');
+}
+
+.risk-icon.low {
+  background-image: url('@/assets/icons/icon-warning-orange.png');
+}
+</style>

+ 14 - 883
src/components/InstitutionDetailModal.vue

@@ -164,240 +164,15 @@
 
         <div class="five-dimensions">
           <!-- 钱花得明白 -->
-          <div class="dimension-item">
-            <h4 class="detection-title">钱花得明白</h4>
-
-            <!-- 第一行:统计数字 -->
-            <div class="stats-row">
-              <div class="stat-item">
-                <div class="stat-value">
-                  <NumberAnimation
-                    :value="institutionDetailData.financeStats.income"
-                    :thousands="true"
-                    unit="元"
-                    :unit-style="{ fontSize: '30px' }"
-                  />
-                </div>
-                <div class="stat-label">机构本级收入</div>
-              </div>
-              <div class="stat-item">
-                <div class="stat-value">
-                  <NumberAnimation
-                    :value="institutionDetailData.financeStats.expenditure"
-                    :thousands="true"
-                    unit="元"
-                    :unit-style="{ fontSize: '30px' }"
-                  />
-                </div>
-                <div class="stat-label">机构运营支出</div>
-              </div>
-              <div class="stat-item">
-                <div class="stat-value">
-                  <NumberAnimation
-                    :value="institutionDetailData.financeStats.disclosureRate"
-                    :decimals="1"
-                    unit="%"
-                    :unit-style="{ fontSize: '30px' }"
-                  />
-                </div>
-                <div class="stat-label">公示信息达标率</div>
-              </div>
-              <div class="stat-item">
-                <div class="stat-value">
-                  <NumberAnimation
-                    :value="institutionDetailData.financeStats.fundUsageRate"
-                    unit="%"
-                    :unit-style="{ fontSize: '30px' }"
-                  />
-                </div>
-                <div class="stat-label">资金用途达标率</div>
-              </div>
-              <div class="stat-item">
-                <div class="stat-value">
-                  <NumberAnimation
-                    :value="institutionDetailData.financeStats.serviceRate"
-                    unit="%"
-                    :unit-style="{ fontSize: '30px' }"
-                  />
-                </div>
-                <div class="stat-label">养老服务达标率</div>
-              </div>
-              <div class="stat-item">
-                <div class="stat-value">
-                  <NumberAnimation
-                    :value="institutionDetailData.financeStats.procurementRate"
-                    unit="%"
-                    :unit-style="{ fontSize: '30px' }"
-                  />
-                </div>
-                <div class="stat-label">采购过程达标率</div>
-              </div>
-              <div class="stat-item">
-                <div class="stat-value">
-                  <NumberAnimation
-                    :value="institutionDetailData.financeStats.ratingRate"
-                    unit="%"
-                    :unit-style="{ fontSize: '30px' }"
-                  />
-                </div>
-                <div class="stat-label">等级评定达标率</div>
-              </div>
-            </div>
-
-            <!-- 第二行:图表和资金公示 -->
-            <div class="charts-section">
-              <div class="chart-item">
-                <div class="chart-title">机构本级收入情况</div>
-                <div id="incomeChart" class="chart-container"></div>
-              </div>
-              <div class="chart-item">
-                <div class="chart-title">特困供养资金支出情况</div>
-                <div id="expenseChart" class="chart-container"></div>
-              </div>
-              <div class="chart-item line-chart">
-                <div class="chart-title">特困供养机构资金发放情况</div>
-                <div id="distributionChart" class="chart-container"></div>
-              </div>
-              <div class="chart-item fund-show">
-                <div class="chart-title">资金公示</div>
-                <div class="fund-images-grid">
-                  <div class="fund-image-item" v-for="i in 4" :key="i">
-                    <div class="fund-image-placeholder"></div>
-                  </div>
-                </div>
-              </div>
-            </div>
-
-            <!-- 第三行:Tabs容器 -->
-            <div class="tabs-container">
-              <div class="tabs-header">
-                <div
-                  v-for="(tab, index) in ['特困供养资金', '照料护理费', '高龄津贴', '零用钱']"
-                  :key="index"
-                  class="tab-item"
-                  :class="{ active: activeTab === index }"
-                  @click="switchTab(index)"
-                >
-                  {{ tab }}
-                </div>
-              </div>
-              <div class="tabs-content">
-                <!-- 特困供养资金内容 -->
-                <div class="tab-panel" :class="{ active: activeTab === 0 }">
-                  <!-- 第一个表格:特困供养资金 -->
-                  <div class="table-section">
-                    <DataTable
-                      :columns="fundTableColumns"
-                      :data="fundTableData"
-                      :border="true"
-                      :large-font="true"
-                    />
-                  </div>
-
-                  <!-- 机器人和问题数据部分 -->
-                  <div class="robot-section">
-                    <!-- 机器人 -->
-                    <div class="robot-items">
-                      <div class="robot-item">
-                        <el-image :src="robotAuditor" :alt="'AI审计员'" class="robot-image">
-                        </el-image>
-                        <div class="robot-name">AI审计员</div>
-                      </div>
-
-                      <div class="robot-item">
-                        <el-image
-                          :src="robotWarningSupervisor"
-                          :alt="'AI预警与督办员'"
-                          class="robot-image"
-                        >
-                        </el-image>
-                        <div class="robot-name">AI预警与督办员</div>
-                      </div>
-                    </div>
-
-                    <!-- 数据统计 -->
-                    <div class="data-stats">
-                      <div class="stat-item">
-                        <img
-                          src="../assets/icons/icon-checked.png"
-                          alt="已审核"
-                          class="stat-icon"
-                        />
-                        <span>
-                          已审核申请:146份,已静默认证生存状态:237人,智能比对数据:8680项,覆盖老人:287人;
-                        </span>
-                      </div>
-                      <div class="stat-item">
-                        <img
-                          src="../assets/icons/icon-checkedRate.png"
-                          alt="审核通过率"
-                          class="stat-icon"
-                        />
-                        <span>
-                          资金申请审核通过率:98.9%,识别申请异常:9人,涉及资金:3600元;
-                        </span>
-                      </div>
-                      <div class="stat-item">
-                        <img
-                          src="../assets/icons/icon-checking.png"
-                          alt="待审核"
-                          class="stat-icon"
-                        />
-                        <span>
-                          待处置预警:8条,直接反馈:5条,发布廉政要求整改:3条,整改完成率:78.4%。
-                        </span>
-                      </div>
-                    </div>
-                  </div>
-
-                  <!-- 第二个表格:问题数据 -->
-                  <div class="table-section" style="margin-top: 30px">
-                    <DataTable
-                      :columns="problemTableColumns"
-                      :data="problemTableData"
-                      :border="true"
-                      :large-font="true"
-                    >
-                      <template #riskLevel="{ row }">
-                        <div class="risk-icon" :class="row.riskLevel"></div>
-                      </template>
-
-                      <template #operation="{ row }">
-                        <i v-if="row.status === '未处置'" class="iconfont icon-command"></i>
-                        <el-link
-                          v-else-if="row.status === '处置中'"
-                          type="primary"
-                          underline="always"
-                          class="operation-link"
-                        >
-                          催促
-                        </el-link>
-                        <el-link v-else type="primary" underline="always" class="operation-link">
-                          查看详情
-                        </el-link>
-                      </template>
-                    </DataTable>
-                  </div>
-                </div>
-                <!-- 其他标签页内容 -->
-                <div class="tab-panel" :class="{ active: activeTab === 1 }">
-                  <div class="table-section">
-                    <p class="empty-text">照料护理费内容</p>
-                  </div>
-                </div>
-                <div class="tab-panel" :class="{ active: activeTab === 2 }">
-                  <div class="table-section">
-                    <p class="empty-text">高龄津贴内容</p>
-                  </div>
-                </div>
-                <div class="tab-panel" :class="{ active: activeTab === 3 }">
-                  <div class="table-section">
-                    <p class="empty-text">零用钱内容</p>
-                  </div>
-                </div>
-              </div>
-            </div>
-          </div>
+          <FinanceDimension :visible="visible" />
+          <!-- 饭吃得满意 -->
+          <FoodSatisfactionDimension :visible="visible" style="margin-top: 60px" />
+          <!-- 衣穿得舒适 -->
+          <ClothingSatisfactionDimension :visible="visible" style="margin-top: 60px" />
+          <!-- 房住得安全 -->
+          <HouseSafetyDimension :visible="visible" style="margin-top: 60px" />
+          <!-- 人活得体面 -->
+          <DignityDimension :visible="visible" style="margin-top: 60px" />
         </div>
       </div>
     </div>
@@ -405,15 +180,13 @@
 </template>
 
 <script setup lang="ts">
-import { ref, watch, onMounted, nextTick } from 'vue'
 import ModalDialog from './ModalDialog.vue'
 import NumberAnimation from './NumberAnimation.vue'
-import DataTable from './DataTable.vue'
-import * as echarts from 'echarts'
-import { institutionDetailData } from '../data/institutionDetail'
-
-import robotAuditor from '@/assets/images/robot_auditor.png'
-import robotWarningSupervisor from '@/assets/images/robot_warningSupervisor.png'
+import FinanceDimension from './FinanceDimension.vue'
+import FoodSatisfactionDimension from './FoodSatisfactionDimension.vue'
+import ClothingSatisfactionDimension from './ClothingSatisfactionDimension.vue'
+import HouseSafetyDimension from './HouseSafetyDimension.vue'
+import DignityDimension from './DignityDimension.vue'
 
 interface Props {
   visible: boolean
@@ -425,336 +198,9 @@ const emit = defineEmits<{
   close: []
 }>()
 
-let isMounted = false
-
 const handleClose = () => {
   emit('close')
 }
-
-// Tabs切换逻辑
-const activeTab = ref(0)
-
-const switchTab = (index: number) => {
-  activeTab.value = index
-}
-
-// 第一个表格:特困供养资金数据
-const fundTableColumns = institutionDetailData.fundTableColumns
-
-// 第二个表格:问题数据
-const problemTableColumns = institutionDetailData.problemTableColumns
-
-// 问题数据
-const problemTableData = institutionDetailData.problemTableData
-
-const initCharts = () => {
-  console.log('initCharts')
-  // 机构本级收入情况 - 南丁格尔玫瑰图
-  const incomeDom = document.getElementById('incomeChart')
-  if (!incomeDom) return
-  const incomeChart = echarts.init(incomeDom)
-  incomeChart.setOption({
-    tooltip: {
-      trigger: 'item',
-    },
-    series: [
-      // 南丁格尔玫瑰图
-      {
-        name: '收入来源',
-        type: 'pie',
-        radius: ['30%', '80%'],
-        center: ['45%', '55%'],
-        roseType: 'radius',
-        avoidLabelOverlap: false,
-        itemStyle: {
-          borderWidth: 0,
-        },
-        label: {
-          show: true,
-          position: 'outside',
-          formatter: '{b}',
-          fontSize: 22,
-          distance: 50,
-          color: '#06BBAD',
-        },
-        labelLine: {
-          show: true,
-          length: 20,
-          length2: 10,
-          lineStyle: {
-            width: 2,
-            color: '#00FFE6',
-          },
-        },
-        data: institutionDetailData.incomeData,
-        color: ['#00FFE6', '#1E90FF', '#FFD700'],
-      },
-      // 中间黑色圆环
-      {
-        name: '中心圆环',
-        type: 'pie',
-        radius: ['30%', '38%'],
-        center: ['45%', '55%'],
-        itemStyle: {
-          color: 'rgba(0, 0, 0, 0.3)',
-        },
-        data: [{ value: 1, name: '' }],
-        label: {
-          show: false,
-        },
-        labelLine: {
-          show: false,
-        },
-        tooltip: {
-          show: false,
-        },
-        emphasis: {
-          disabled: true,
-        },
-      },
-    ],
-  })
-
-  // 特困供养资金支出情况 - 环形图
-  const expenseChart = echarts.init(document.getElementById('expenseChart'))
-  expenseChart.setOption({
-    tooltip: {
-      trigger: 'item',
-    },
-    legend: {
-      orient: 'vertical',
-      right: 0,
-      top: '33%',
-      textStyle: {
-        color: '#06BBAD',
-        fontSize: 22,
-        wrap: true,
-        wordWrap: 'break-word',
-      },
-      itemWidth: 30,
-      itemHeight: 20,
-    },
-    series: [
-      // 环形图
-      {
-        name: '支出项目',
-        type: 'pie',
-        radius: ['30%', '80%'],
-        center: ['30%', '55%'],
-        avoidLabelOverlap: false,
-        itemStyle: {
-          borderWidth: 0,
-        },
-        label: {
-          show: false,
-        },
-        labelLine: {
-          show: false,
-        },
-        data: institutionDetailData.expenseData,
-        color: ['#1E90FF', '#00FFE6', '#FFD700', '#FF8C00', '#FF6347', '#9370DB', '#4169E1'],
-      },
-      // 中间黑色圆环
-      {
-        name: '中心圆环',
-        type: 'pie',
-        radius: ['30%', '38%'],
-        center: ['30%', '55%'],
-        itemStyle: {
-          color: 'rgba(0, 0, 0, 0.3)',
-        },
-        data: [{ value: 1, name: '' }],
-        label: {
-          show: false,
-        },
-        labelLine: {
-          show: false,
-        },
-        tooltip: {
-          show: false,
-        },
-        emphasis: {
-          disabled: true,
-        },
-      },
-    ],
-  })
-
-  // 特困供养机构资金发放情况 - 线图
-  const distributionChart = echarts.init(document.getElementById('distributionChart'))
-  distributionChart.setOption({
-    tooltip: {
-      trigger: 'axis',
-    },
-    legend: {
-      data: ['收入', '支出'],
-      left: 80,
-      itemWidth: 50,
-      textStyle: {
-        color: '#06BBAD',
-        fontSize: 26,
-      },
-      itemStyle: {
-        color: 'inherit',
-        borderColor: 'inherit',
-        borderWidth: 4,
-      },
-      lineStyle: {
-        color: 'inherit',
-        width: 3,
-      },
-    },
-    grid: {
-      left: '3%',
-      right: '4%',
-      bottom: '3%',
-      containLabel: true,
-    },
-    xAxis: {
-      type: 'category',
-      boundaryGap: false,
-      data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
-      axisLine: {
-        lineStyle: {
-          color: '#066462',
-        },
-      },
-      axisLabel: {
-        color: '#4E9A96',
-        fontSize: 22,
-        margin: 16,
-      },
-      axisTick: {
-        show: false,
-      },
-    },
-    yAxis: {
-      type: 'value',
-      axisLine: {
-        lineStyle: {
-          color: '#00FFE6',
-        },
-      },
-      axisLabel: {
-        color: '#4E9A96',
-        fontSize: 22,
-        margin: 16,
-      },
-      splitLine: {
-        lineStyle: {
-          type: 'dashed',
-          color: 'rgba(0, 255, 230, 0.1)',
-        },
-      },
-    },
-    series: [
-      {
-        name: '支出',
-        type: 'line',
-        smooth: true,
-        data: institutionDetailData.distributionData.actual,
-        lineStyle: {
-          color: '#01AB9B',
-          width: 3,
-        },
-        itemStyle: {
-          color: '#00D1BD',
-          borderColor: 'rgba(0, 209, 189, 0.30)',
-          borderWidth: 4,
-        },
-        symbol: 'circle',
-        symbolSize: 12,
-        areaStyle: {
-          color: {
-            type: 'linear',
-            x: 0,
-            y: 0,
-            x2: 0,
-            y2: 1,
-            colorStops: [
-              {
-                offset: 0,
-                color: 'rgba(0,255,230,0.4)',
-              },
-              {
-                offset: 1,
-                color: 'rgba(217,217,217,0)',
-              },
-            ],
-          },
-        },
-      },
-      {
-        name: '收入',
-        type: 'line',
-        smooth: true,
-        data: institutionDetailData.distributionData.planned,
-        lineStyle: {
-          color: '#00AEFF',
-          width: 3,
-        },
-        itemStyle: {
-          color: '#42C3FF',
-          borderColor: 'rgba(66, 195, 255, 0.30)',
-          borderWidth: 4,
-        },
-        symbol: 'circle',
-        symbolSize: 12,
-        areaStyle: {
-          color: {
-            type: 'linear',
-            x: 0,
-            y: 0,
-            x2: 0,
-            y2: 1,
-            colorStops: [
-              {
-                offset: 0,
-                color: 'rgba(0,174,255,0.4)',
-              },
-              {
-                offset: 1,
-                color: 'rgba(217,217,217,0)',
-              },
-            ],
-          },
-          shadowBlur: 8,
-          shadowColor: 'rgba(0,0,0,0.25)',
-        },
-      },
-    ],
-  })
-
-  // 响应式处理
-  window.addEventListener('resize', () => {
-    incomeChart.resize()
-    expenseChart.resize()
-    distributionChart.resize()
-  })
-}
-
-// 模拟表格数据
-const fundTableData = institutionDetailData.fundTableData
-
-// 监听弹窗显示,初始化图表
-watch(
-  () => props.visible,
-  (newVisible) => {
-    if (newVisible && isMounted) {
-      // 延迟初始化图表,确保DOM已渲染
-      setTimeout(() => {
-        initCharts()
-      }, 100)
-    }
-  }
-)
-
-onMounted(() => {
-  isMounted = true
-  nextTick(() => {
-    initCharts()
-  })
-})
 </script>
 
 <style lang="scss" scoped>
@@ -1026,321 +472,6 @@ $neon-cyan: #00ffe6;
     display: flex;
     flex-direction: column;
     gap: 30px;
-
-    .dimension-item {
-      padding: 0 20px;
-      border: 1px solid $neon-cyan;
-      border-left-color: #086f6a;
-      border-right-color: #086f6a;
-
-      .detection-title {
-        width: calc(100% + 40px);
-        margin-left: -20px;
-        font-size: 32px;
-        font-weight: 500;
-        color: $neon-cyan;
-        line-height: 72px;
-        letter-spacing: 1px;
-        text-align: center;
-        background: linear-gradient(
-          to right,
-          rgba(0, 255, 230, 0.1) 0%,
-          rgba(255, 255, 255, 0) 180%
-        );
-      }
-    }
-  }
-
-  .stats-row {
-    display: flex;
-    justify-content: space-between;
-    width: 80%;
-    margin: 60px auto 100px;
-
-    .stat-item {
-      position: relative;
-      flex: 1;
-      display: flex;
-      flex-direction: column;
-      align-items: center;
-      justify-content: center;
-
-      &:not(:last-child) {
-        padding-right: 38px;
-      }
-
-      &:not(:last-child)::after {
-        content: '';
-        position: absolute;
-        right: 0;
-        top: 0;
-        height: 100%;
-        width: 2px;
-        margin: 0 18px;
-        background: url('@/assets/images/vertical_line.png') center no-repeat;
-        background-size: 100% 100%;
-      }
-
-      .stat-value {
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        font-size: 44px;
-        font-weight: 500;
-        color: $neon-cyan;
-        line-height: 56px;
-        letter-spacing: 2px;
-        margin-bottom: 8px;
-      }
-
-      .stat-label {
-        font-size: 26px;
-        color: rgba(1, 255, 230, 0.7);
-        text-align: center;
-        white-space: nowrap;
-      }
-    }
-  }
-
-  // 调整图表区域布局
-  .charts-section {
-    display: flex;
-    gap: 30px;
-    margin-bottom: 40px;
-
-    .chart-item {
-      flex: 1;
-      display: flex;
-      flex-direction: column;
-      align-items: center;
-      justify-content: center;
-      padding: 20px;
-
-      &.line-chart {
-        flex: 1.5;
-        width: 900px;
-      }
-
-      &.fund-show {
-        flex: 1;
-      }
-
-      .chart-title {
-        font-size: 30px;
-        color: $neon-cyan;
-        margin-bottom: 20px;
-        font-weight: 600;
-        line-height: 1;
-        letter-spacing: 1px;
-      }
-
-      .chart-container {
-        width: 100%;
-        height: 466px;
-      }
-
-      // 资金公示图片网格
-      .fund-images-grid {
-        display: grid;
-        grid-template-columns: repeat(2, 1fr);
-        gap: 10px;
-        height: 466px;
-
-        .fund-image-item {
-          width: 178px;
-          height: 228px;
-          background: rgba(0, 255, 230, 0.1);
-          display: flex;
-          align-items: center;
-          justify-content: center;
-        }
-      }
-    }
-  }
-
-  // Tabs容器样式
-  .tabs-container {
-    margin-top: 80px;
-    margin-bottom: 30px;
-    border: 1px solid #056e6c;
-    background: radial-gradient(ellipse at center, transparent 60%, rgba(9, 51, 56, 0.8) 100%);
-    box-shadow: inset 0 0 60px 6px rgba(255, 255, 255, 0.1);
-
-    .tabs-header {
-      display: flex;
-      height: 92px;
-      border-bottom: 1px solid rgba(0, 255, 230, 0.2);
-
-      .tab-item {
-        flex: 1;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        font-size: 40px;
-        color: rgba(0, 255, 230, 0.7);
-        cursor: pointer;
-        position: relative;
-        transition: color 0.3s ease;
-        background: radial-gradient(
-          50% 50% at 50% 50%,
-          rgba(255, 255, 255, 0) 0%,
-          rgba(0, 255, 230, 0.1) 100%
-        );
-
-        &:hover {
-          color: #00ffe6;
-          background: radial-gradient(
-            50% 50% at 50% 50%,
-            rgba(255, 255, 255, 0) 0%,
-            rgba(0, 255, 230, 0.2) 100%
-          );
-        }
-
-        &.active {
-          color: #00ffe6;
-
-          &::after {
-            content: '';
-            position: absolute;
-            bottom: 0;
-            left: 0;
-            right: 0;
-            height: 4px;
-            background: linear-gradient(
-              90deg,
-              rgba(78, 251, 234, 0),
-              rgba(78, 251, 234, 1),
-              rgba(78, 251, 234, 0.04)
-            );
-          }
-        }
-      }
-    }
-
-    .tabs-content {
-      padding-top: 36px;
-
-      .tab-panel {
-        display: none;
-
-        &.active {
-          display: block;
-        }
-      }
-    }
   }
-
-  .robot-section {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    gap: 100px;
-    width: 80%;
-    margin: 60px auto;
-
-    .robot-items {
-      display: flex;
-      gap: 80px;
-    }
-
-    .robot-item {
-      text-align: center;
-
-      .robot-image {
-        width: auto;
-        height: 202px;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        margin-bottom: 10px;
-
-        span {
-          color: #00ffe6;
-          font-size: 20px;
-        }
-      }
-
-      .robot-name {
-        color: #00ffe6;
-        font-size: 30px;
-      }
-    }
-
-    .data-stats {
-      flex: 1;
-      padding: 36px 60px;
-      background: rgba(255, 255, 255, 0.01);
-      box-shadow:
-        inset 0px -2px 0px 0px rgba(0, 255, 230, 0.5),
-        inset 0px 2px 0px 0px rgba(0, 255, 230, 0.5),
-        inset 20px 20px 80px 0px rgba(0, 255, 230, 0.08),
-        inset -20px -20px 80px 0px rgba(0, 255, 230, 0.08);
-      border-radius: 20px 20px 20px 20px;
-      border: 2px solid rgba(0, 255, 230, 0.3);
-
-      .stat-item {
-        display: flex;
-        align-items: center;
-        margin-bottom: 30px;
-        color: #00d6c0;
-        font-size: 32px;
-
-        &:last-child {
-          margin-bottom: 0;
-        }
-
-        .stat-icon {
-          width: 76px;
-          margin-right: 30px;
-        }
-      }
-    }
-  }
-
-  .table-section {
-    font-size: 32px;
-    color: $neon-cyan;
-
-    .empty-text {
-      color: rgba(0, 255, 230, 0.7);
-      padding: 0 20px 30px;
-      text-align: center;
-    }
-
-    .icon-command {
-      font-size: 50px;
-      color: #cf311d;
-      cursor: pointer;
-    }
-
-    .operation-link {
-      font-weight: 400;
-      font-size: 32px;
-      color: #0099ff;
-      letter-spacing: 1px;
-    }
-  }
-}
-
-/* 风险图标样式 */
-.risk-icon {
-  width: 38px;
-  height: 34px;
-  margin: 0 auto;
-  background-size: auto;
-  background-repeat: no-repeat;
-  background-position: center;
-}
-
-.risk-icon.high {
-  background-image: url('@/assets/icons/icon-warning-red.png');
-}
-
-.risk-icon.medium {
-  background-image: url('@/assets/icons/icon-warning-orange.png');
-}
-
-.risk-icon.low {
-  background-image: url('@/assets/icons/icon-warning-orange.png');
 }
 </style>

+ 26 - 10
src/composables/useTaskDetail.ts

@@ -419,6 +419,8 @@ export function useTaskDetail(props: Props) {
       clearInterval(sseInterval)
       sseInterval = undefined
     }
+    // 清理鼠标拖动事件监听器
+    cleanupMouseDrag()
   }
 
   // 数字滚动动画
@@ -505,12 +507,23 @@ export function useTaskDetail(props: Props) {
     isDragging = false
   }
 
-  const handleMouseDrag = async () => {
-    await nextTick()
-    if (!taskListContainer.value) return
-    taskListContainer.value.addEventListener('mousedown', handleMouseDown)
-    document.addEventListener('mousemove', handleMouseMove)
-    document.addEventListener('mouseup', handleMouseUp)
+  // 清理鼠标拖动事件监听器
+  const cleanupMouseDrag = () => {
+    if (taskListContainer.value) {
+      taskListContainer.value.removeEventListener('mousedown', handleMouseDown)
+    }
+    document.removeEventListener('mousemove', handleMouseMove)
+    document.removeEventListener('mouseup', handleMouseUp)
+  }
+
+  const handleMouseDrag = () => {
+    // 使用微任务异步添加事件监听,避免阻塞弹窗渲染
+    queueMicrotask(() => {
+      if (!taskListContainer.value) return
+      taskListContainer.value.addEventListener('mousedown', handleMouseDown)
+      document.addEventListener('mousemove', handleMouseMove)
+      document.addEventListener('mouseup', handleMouseUp)
+    })
   }
 
   // 初始化或重置模拟和动画(带防抖保护)
@@ -534,10 +547,13 @@ export function useTaskDetail(props: Props) {
     isAnimationComplete = false
     isSimulationComplete = false
 
-    // 开始模拟
-    startSimulation()
-    // 启动数字动画
-    animateNumbers(taskData.value.workTaskCount, taskData.value.problemCount)
+    // 使用微任务异步执行,避免阻塞弹窗渲染
+    queueMicrotask(() => {
+      // 开始模拟
+      startSimulation()
+      // 启动数字动画
+      animateNumbers(taskData.value.workTaskCount, taskData.value.problemCount)
+    })
   }
 
   // 监听机器人类型变化

+ 608 - 26
src/data/institutionDetail.ts

@@ -13,7 +13,7 @@ export const institutionDetailData = {
     staffCount: 50,
     establishedDate: '2018-01-01',
     businessLicense: '91410100MA44444444',
-    serviceScope: '为老年人提供生活照料、康复护理、精神慰藉、文化娱乐等服务'
+    serviceScope: '为老年人提供生活照料、康复护理、精神慰藉、文化娱乐等服务',
   },
 
   // 摄像头数据
@@ -22,20 +22,20 @@ export const institutionDetailData = {
       type: '消防安全摄像头',
       count: 5,
       onlineCount: 3,
-      offlineCount: 2
+      offlineCount: 2,
     },
     {
       type: '明厨亮灶摄像头',
       count: 4,
       onlineCount: 4,
-      offlineCount: 0
+      offlineCount: 0,
     },
     {
       type: '活动场所摄像头',
       count: 2,
       onlineCount: 2,
-      offlineCount: 0
-    }
+      offlineCount: 0,
+    },
   ],
 
   // 钱花得明白 - 统计数字
@@ -46,14 +46,14 @@ export const institutionDetailData = {
     fundUsageRate: 100,
     serviceRate: 100,
     procurementRate: 100,
-    ratingRate: 100
+    ratingRate: 100,
   },
 
   // 钱花得明白 - 收入数据
   incomeData: [
     { value: 5000, name: '特困人员供养金' },
     { value: 3300, name: '照料补贴费' },
-    { value: 2600, name: '机构运转经费' }
+    { value: 2600, name: '机构运转经费' },
   ],
 
   // 钱花得明白 - 支出数据
@@ -64,14 +64,14 @@ export const institutionDetailData = {
     { value: 1500, name: '娱乐支出' },
     { value: 1200, name: '维修支出' },
     { value: 1000, name: '培训支出' },
-    { value: 800, name: '其他支出' }
+    { value: 800, name: '其他支出' },
   ],
 
   // 钱花得明白 - 发放数据
   distributionData: {
     months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
     actual: [12000, 13200, 10100, 13400, 9000, 23000, 21000, 18000, 19000, 20000, 22000, 25000],
-    planned: [10000, 12000, 11000, 12000, 10000, 20000, 18000, 16000, 17000, 18000, 20000, 22000]
+    planned: [10000, 12000, 11000, 12000, 10000, 20000, 18000, 16000, 17000, 18000, 20000, 22000],
   },
 
   // 钱花得明白 - 表格列配置
@@ -86,7 +86,7 @@ export const institutionDetailData = {
     { prop: 'status2', label: '民政计划纳入', width: 280, align: 'center' },
     { prop: 'status3', label: '财政拨付状态', width: 280, align: 'center' },
     { prop: 'status4', label: '机构到账状态', width: 280, align: 'center' },
-    { prop: 'date', label: '到账时间', width: 312, align: 'center' }
+    { prop: 'date', label: '到账时间', width: 312, align: 'center' },
   ],
 
   // 钱花得明白 - 表格数据
@@ -102,7 +102,7 @@ export const institutionDetailData = {
       status2: '已纳入',
       status3: '已拨付',
       status4: '已到账',
-      date: '2026-03-10'
+      date: '2026-03-10',
     },
     {
       id: 2,
@@ -115,7 +115,7 @@ export const institutionDetailData = {
       status2: '已纳入',
       status3: '已拨付',
       status4: '已到账',
-      date: '2026-03-10'
+      date: '2026-03-10',
     },
     {
       id: 3,
@@ -128,8 +128,8 @@ export const institutionDetailData = {
       status2: '已纳入',
       status3: '已拨付',
       status4: '已到账',
-      date: '2026-03-10'
-    }
+      date: '2026-03-10',
+    },
   ],
 
   // 钱花得明白 - 问题表格列配置
@@ -142,7 +142,7 @@ export const institutionDetailData = {
     { prop: 'time', label: '预警时间', width: 320, align: 'center' },
     { prop: 'source', label: '来源', width: 360, align: 'center' },
     { prop: 'status', label: '状态', width: 220, align: 'center' },
-    { prop: 'operation', label: '操作', width: 280, align: 'center' }
+    { prop: 'operation', label: '操作', width: 280, align: 'center' },
   ],
 
   // 钱花得明白 - 问题表格数据
@@ -155,7 +155,7 @@ export const institutionDetailData = {
       riskLevel: 'high',
       time: '2026-04-13 11:05',
       source: '津贴补贴AI审核员',
-      status: '未处置'
+      status: '未处置',
     },
     {
       id: 2,
@@ -165,7 +165,7 @@ export const institutionDetailData = {
       riskLevel: 'medium',
       time: '2026-04-13 11:06',
       source: '津贴补贴AI审核员',
-      status: '未处置'
+      status: '未处置',
     },
     {
       id: 3,
@@ -175,7 +175,7 @@ export const institutionDetailData = {
       riskLevel: 'high',
       time: '2026-04-13 11:05',
       source: '津贴补贴AI审核员',
-      status: '处置中'
+      status: '处置中',
     },
     {
       id: 4,
@@ -185,20 +185,20 @@ export const institutionDetailData = {
       riskLevel: 'high',
       time: '2026-04-13 11:05',
       source: '津贴补贴AI审核员',
-      status: '已整改'
-    }
+      status: '已整改',
+    },
   ],
 
   // 机器人数据
   robots: [
     {
       name: 'AI审计员',
-      image: '/src/assets/images/robot_auditor.png'
+      image: '/src/assets/images/robot_auditor.png',
     },
     {
       name: 'AI预警与督办员',
-      image: '/src/assets/images/robot_warningSupervisor.png'
-    }
+      image: '/src/assets/images/robot_warningSupervisor.png',
+    },
   ],
 
   // 统计信息
@@ -213,6 +213,588 @@ export const institutionDetailData = {
     pendingAlerts: 8,
     directFeedback: 5,
     rectificationRequirements: 3,
-    rectificationRate: 78.4
-  }
-}
+    rectificationRate: 78.4,
+  },
+
+  // 饭吃得满意 - 统计数字
+  foodStats: {
+    totalExpenditure: 196800,
+    dailyStandard: 13.5,
+    foodCostRatio: 65.5,
+    recipeCompliance: 96.7,
+    dailyFoodCompliance: 95.3,
+    foodSafetyCompliance: 94.4,
+    kitchenTransparencyCompliance: 94.3,
+  },
+
+  // 饭吃得满意 - 餐费占比数据
+  foodCostRatioData: [
+    { month: '1月', ratio: 60 },
+    { month: '2月', ratio: 65 },
+    { month: '3月', ratio: 68 },
+    { month: '4月', ratio: 70 },
+    { month: '5月', ratio: 69 },
+    { month: '6月', ratio: 67 },
+    { month: '7月', ratio: 66 },
+    { month: '8月', ratio: 65 },
+    { month: '9月', ratio: 64 },
+    { month: '10月', ratio: 63 },
+    { month: '11月', ratio: 64 },
+    { month: '12月', ratio: 65 },
+  ],
+
+  // 饭吃得满意 - 营养分析数据
+  nutritionData: [
+    { name: '蛋白质', value: 85 },
+    { name: '脂肪', value: 65 },
+    { name: '碳水化合物', value: 90 },
+    { name: '维生素', value: 75 },
+    { name: '膳食纤维', value: 80 },
+  ],
+
+  // 饭吃得满意 - 每周菜谱
+  weeklyMenu: {
+    早餐: {
+      星期一: '馒头、肉末豆腐、鸡蛋、小米粥、米饭',
+      星期二: '馒头、肉丝炒豆芽、鸡蛋一个、牛奶',
+      星期三: '馒头、芹菜炒肉粉条、鸡蛋一个、稀饭',
+      星期四: '馒头、番茄鸡蛋汤、红薯、小米稀饭',
+      星期五: '馒头、肉末豆腐、鸡蛋一个、小米稀饭',
+      星期六: '馒头、萝卜丝肉丝、鸡蛋一个、小米粥',
+      星期日: '馒头、火腿冬瓜、鸡蛋一个、白米粥',
+    },
+    午餐: {
+      星期一: '肉片蘑菇、青椒烧虹豆',
+      星期二: '红烧鱼块、粉条肉小白菜',
+      星期三: '面条/馒头、土豆烧肉块、西蓝花炒鸡蛋',
+      星期四: '面条、芹菜炒肉、西红柿米饭、番茄鸡蛋汤',
+      星期五: '馒头、白萝卜炒肉片、生物炒菜',
+      星期六: '水饺、菠菜蛋汤、胡萝卜丝',
+      星期日: '米饭、炒莴苣、炒土豆丝、水饺',
+    },
+    晚餐: {
+      星期一: '馒头、鸡块炖洋芋、绿豆豆、白米粥',
+      星期二: '馒头、花菜炒肉锅、耗油菜瓜、白米',
+      星期三: '馒头、土豆并肉片、蒲白、稀饭',
+      星期四: '馒头、肉丝绿豆芽、炒红薯、白米',
+      星期五: '馒头、土豆烧鸡脚、手馏包、红枣粥',
+      星期六: '馒头、香菇胡萝卜丝、银耳馒头、肉丝银耳、炒土豆丝、水饺',
+      星期日: '稀饭、肉片、粉丝、白菜',
+    },
+  },
+
+  // 饭吃得满意 - 问题表格列配置
+  foodProblemTableColumns: [
+    { prop: 'id', label: '序号', width: 150, align: 'center' },
+    { prop: 'type', label: '问题类别', width: 200, align: 'center' },
+    { prop: 'problem', label: '问题', width: 330, align: 'center' },
+    { prop: 'description', label: '问题描述', minWidth: 400, align: 'left' },
+    { prop: 'riskLevel', label: '风险等级', width: 200, align: 'center' },
+    { prop: 'time', label: '预警时间', width: 320, align: 'center' },
+    { prop: 'source', label: '来源', width: 300, align: 'center' },
+    { prop: 'status', label: '状态', width: 200, align: 'center' },
+    { prop: 'operation', label: '操作', width: 200, align: 'center' },
+  ],
+
+  // 饭吃得满意 - 问题表格数据
+  foodProblemTableData: [
+    {
+      id: 1,
+      type: '膳食营养',
+      problem: '午餐菜品数量不足',
+      description: '4月15日全天仅提供3个菜品(土豆烧牛肉、炒青菜、馒头),未达到每日不少于4菜标准',
+      riskLevel: 'medium',
+      time: '2026-04-18 08:30',
+      source: 'AI膳食营养员',
+      status: '未处置',
+    },
+    {
+      id: 2,
+      type: '食品安全',
+      problem: '后厨人员未戴口罩',
+      description: '4月15日10:32监控画面显示后厨2名工作人员未戴口罩进行切配操作',
+      riskLevel: 'medium',
+      time: '2026-04-15 10:32',
+      source: 'AI膳食营养员',
+      status: '未处置',
+    },
+    {
+      id: 3,
+      type: '食品安全',
+      problem: '午餐菜品不符合要求',
+      description: '4月12日全天的菜品只有肉没有蛋,不符合每日有肉有蛋的标准',
+      riskLevel: 'medium',
+      time: '2026-04-13 08:30',
+      source: 'AI膳食营养员',
+      status: '已整改',
+    },
+    {
+      id: 4,
+      type: '食品采购',
+      problem: '食材采购价格异常',
+      description: '4月14日采购清单猪肉38元/斤,比市场近期平均价(26元/斤)高46%,疑似价格过高',
+      riskLevel: 'high',
+      time: '2026-04-14 09:00',
+      source: 'AI膳食营养员',
+      status: '未处置',
+    },
+  ],
+
+  // 饭吃得满意 - 统计信息
+  foodStatistics: {
+    checkedMeals: 112,
+    analyzedDishes: 84,
+    realTimeChecks: 1,
+    foodSafetyChecks: 36,
+    costRatioChecks: 12,
+    identifiedIssues: 6,
+    affectedSeniors: 75,
+    involvedMeals: 10,
+    pendingAlerts: 23,
+    directFeedback: 1,
+    rectificationOrders: 12,
+    rectificationRate: 68.8,
+  },
+
+  // 衣穿得舒适 - 统计数字
+  clothingStats: {
+    totalExpenditure: 62800,
+    perCapitaExpenditure: 1200,
+    perCapitaCompliance: 96.7,
+    distributionRate: 100,
+    averageInterval: 60,
+  },
+
+  // 衣穿得舒适 - 衣物季度发放数据
+  clothingQuarterlyData: [
+    { quarter: '第一季度', amount: 8800 },
+    { quarter: '第二季度', amount: 2000 },
+    { quarter: '第三季度', amount: 13400 },
+    { quarter: '第四季度', amount: 38600 },
+  ],
+
+  // 衣穿得舒适 - 采购内容分析数据
+  clothingPurchaseContentData: [
+    { value: 35, name: '棉衣' },
+    { value: 25, name: '夏季服装' },
+    { value: 20, name: '鞋帽' },
+    { value: 15, name: '床单被罩' },
+    { value: 5, name: '其他' },
+  ],
+
+  // 衣穿得舒适 - 采购供应商分析数据
+  clothingSupplierData: [
+    { value: 10, name: '其他供应商' },
+    { value: 20, name: '周口鑫源服装有限公司' },
+    { value: 30, name: '河南恒源祥服饰有限公司' },
+    { value: 40, name: '周口晨风服装有限公司' },
+  ],
+
+  clothingPurchaseTableColumns: [
+    { prop: 'purchaseDate', label: '采购日期', width: 300, align: 'center' },
+    { prop: 'item', label: '采购物品', width: 500, align: 'center' },
+    { prop: 'supplier', label: '供应商', minWidth: 500, align: 'center' },
+    { prop: 'quantity', label: '数量', width: 300, align: 'center' },
+    { prop: 'unitPrice', label: '单价', width: 300, align: 'center' },
+    { prop: 'totalAmount', label: '总金额', width: 300, align: 'center' },
+    { prop: 'purchaser', label: '采购人', width: 300, align: 'center' },
+    { prop: 'status', label: '验收状态', width: 300, align: 'center' },
+  ],
+
+  // 衣穿得舒适 - 衣物采购情况表格数据
+  clothingPurchaseTableData: [
+    {
+      id: 1,
+      purchaseDate: '2026-03-10',
+      item: '春季外套',
+      supplier: '周口晨风服装有限公司',
+      quantity: 37,
+      unitPrice: 85,
+      totalAmount: 3145,
+      purchaser: '李一鸣',
+      status: '已验收',
+    },
+    {
+      id: 2,
+      purchaseDate: '2026-03-10',
+      item: '棉鞋',
+      supplier: '周口鑫源服装有限公司',
+      quantity: 37,
+      unitPrice: 45,
+      totalAmount: 1665,
+      purchaser: '李一鸣',
+      status: '已验收',
+    },
+    {
+      id: 3,
+      purchaseDate: '2026-01-15',
+      item: '冬季棉衣',
+      supplier: '周口鑫源服装有限公司',
+      quantity: 37,
+      unitPrice: 120,
+      totalAmount: 4440,
+      purchaser: '王闻闻',
+      status: '已验收',
+    },
+  ],
+
+  // 衣穿得舒适 - 问题表格列配置
+  clothingProblemTableColumns: [
+    { prop: 'id', label: '序号', width: 150, align: 'center' },
+    { prop: 'type', label: '问题类别', width: 280, align: 'center' },
+    { prop: 'problem', label: '问题', width: 400, align: 'center' },
+    { prop: 'description', label: '问题描述', minWidth: 400, align: 'left' },
+    { prop: 'riskLevel', label: '风险等级', width: 200, align: 'center' },
+    { prop: 'time', label: '预警时间', width: 320, align: 'center' },
+    { prop: 'source', label: '来源', width: 300, align: 'center' },
+    { prop: 'status', label: '状态', width: 200, align: 'center' },
+    { prop: 'operation', label: '操作', width: 200, align: 'center' },
+  ],
+
+  // 衣穿得舒适 - 问题表格数据
+  clothingProblemTableData: [
+    {
+      id: 1,
+      type: '采购数量异常',
+      problem: '单峰采购数量不足',
+      description:
+        '2026年第一季度采购春秋37套,同期在院老人75人,单人配置率49%,不足人均1.2/底标准',
+      riskLevel: 'high',
+      time: '2026-04-15 08:15',
+      source: '廉政风险AI监督员',
+      status: '未处置',
+    },
+    {
+      id: 2,
+      type: '人均支出异常',
+      problem: '人均衣物支出偏高',
+      description: '2026年第一季度人均衣物支出1588元,超出市分区乡镇平均水平5.5万元',
+      riskLevel: 'high',
+      time: '2026-04-10 14:50',
+      source: '廉政风险AI监督员',
+      status: '未处置',
+    },
+    {
+      id: 3,
+      type: '采购数量异常',
+      problem: '冬季棉衣采购数量远超越实际需求',
+      description: '2026年1月15日采购冬季棉衣120件,同期在院老人75人,多余采购45件,涉及金额5400元',
+      riskLevel: 'high',
+      time: '2026-01-20 10:30',
+      source: '廉政风险AI监督员',
+      status: '处置中',
+    },
+    {
+      id: 4,
+      type: '衣物采购',
+      problem: '供应商疑似关联关系',
+      description:
+        '发现机构连续5次采购该供应商(代理人与机构负责人存在亲属关系(同属且地址相近)),涉嫌利益输送',
+      riskLevel: 'high',
+      time: '2026-03-19 13:25',
+      source: '廉政风险AI监督员',
+      status: '处置中',
+    },
+  ],
+
+  // 衣穿得舒适 - 统计信息
+  clothingStatistics: {
+    checkedOrders: 16,
+    marketPriceComparisons: 42,
+    supplierQualityAnalysis: 12,
+    purchaseDetailsAnalysis: 156,
+    identifiedIssues: 5,
+    affectedSeniors: 75,
+    involvedFunds: 8600,
+    pendingAlerts: 5,
+    directFeedback: 1,
+    rectificationRequirements: 4,
+    rectificationRate: 62.5,
+  },
+
+  // 房住得安全 - 统计数字
+  houseSafetyStats: {
+    fireMonitors: 5,
+    fireMonitorCoverage: 80.1,
+    fireFacilityOnlineRate: 96.5,
+    continuousMonitoring: 192,
+    houseSafetyCompliance: 97.8,
+    dutyCompliance: 91.8,
+    hiddenDangersFound: 8,
+    rectificationRate: 100,
+  },
+
+  // 房住得安全 - 消防安全问题类型分布
+  fireSafetyIssueTypeData: [
+    { value: 5, name: '楼道堆积物' },
+    { value: 12, name: '楼道堵塞' },
+    { value: 9, name: '其他' },
+    { value: 11, name: '消防通道堵塞' },
+    { value: 8, name: '其他问题' },
+  ],
+
+  // 房住得安全 - 安全隐患趋势
+  safetyTrendData: {
+    months: ['1月', '2月', '3月', '4月', '5月', '6月'],
+    values: [10, 8, 6, 4, 8, 6],
+  },
+
+  // 房住得安全 - 24小时值班情况
+  dutyStatusData: {
+    months: ['1月', '2月', '3月', '4月', '5月', '6月'],
+    values: [85, 90, 95, 92, 94, 96],
+  },
+
+  smartInspectionTableColumns: [
+    { prop: 'id', label: '序号', width: 150, align: 'center' },
+    { prop: 'inspectionTime', label: '巡检时间', minWidth: 300, align: 'center' },
+    { prop: 'cameraLocation', label: '摄像头所在位置', minWidth: 400, align: 'center' },
+    { prop: 'inspectionItem', label: '巡检项', minWidth: 300, align: 'center' },
+    { prop: 'result', label: '巡检结果', minWidth: 200, align: 'center' },
+  ],
+
+  // 房住得安全 - 智能巡检情况表格数据
+  smartInspectionTableData: [
+    {
+      id: 1,
+      inspectionTime: '2026-04-17 11:30',
+      cameraLocation: '消防控制室',
+      inspectionItem: '人员在岗',
+      result: '正常',
+    },
+    {
+      id: 2,
+      inspectionTime: '2026-04-17 10:00',
+      cameraLocation: '3号楼2层东走廊',
+      inspectionItem: '疏散通道占用',
+      result: '正常',
+    },
+    {
+      id: 3,
+      inspectionTime: '2026-04-17 09:15',
+      cameraLocation: '1号楼大厅北侧',
+      inspectionItem: '电动车违规入楼',
+      result: '正常',
+    },
+  ],
+
+  // 房住得安全 - 问题表格列配置
+  houseSafetyProblemTableColumns: [
+    { prop: 'id', label: '序号', width: 150, align: 'center' },
+    { prop: 'type', label: '问题类别', width: 250, align: 'center' },
+    { prop: 'problem', label: '问题', width: 350, align: 'center' },
+    { prop: 'description', label: '问题描述', minWidth: 400, align: 'left' },
+    { prop: 'riskLevel', label: '风险等级', width: 200, align: 'center' },
+    { prop: 'time', label: '预警时间', width: 320, align: 'center' },
+    { prop: 'source', label: '来源', width: 300, align: 'center' },
+    { prop: 'status', label: '状态', width: 200, align: 'center' },
+    { prop: 'operation', label: '操作', width: 200, align: 'center' },
+  ],
+
+  // 房住得安全 - 问题表格数据
+  houseSafetyProblemTableData: [
+    {
+      id: 1,
+      type: '日常管理',
+      problem: '电动车违规入楼',
+      description: '1号楼大厅监控拍到电动车推楼,堵塞疏散通道',
+      riskLevel: 'medium',
+      time: '2026-04-18 14:30',
+      source: '消防安全管理员',
+      status: '未处置',
+    },
+    {
+      id: 2,
+      type: '值班管理',
+      problem: '消控室人员离岗',
+      description: '消控室值班人员离取超过1小时无人值守',
+      riskLevel: 'medium',
+      time: '2026-04-18 09:15',
+      source: '消防安全管理员',
+      status: '未处置',
+    },
+    {
+      id: 3,
+      type: '建筑安全',
+      problem: '墙壁脱落',
+      description: '1号楼2层走廊顶墙壁脱落约2㎡,有发霉痕迹',
+      riskLevel: 'medium',
+      time: '2026-04-15 08:30',
+      source: '消防安全管理员',
+      status: '已整改',
+    },
+    {
+      id: 4,
+      type: '疏散通道',
+      problem: '通道杂物占用',
+      description: '夏发现疏散通道杂物占用且疏散不到位',
+      riskLevel: 'high',
+      time: '2026-03-28 10:30',
+      source: '廉政风险AI监督员',
+      status: '已整改',
+    },
+  ],
+
+  // 房住得安全 - 统计信息
+  houseSafetyStatistics: {
+    realTimeMonitoringPoints: 5,
+    inspectionTimes: 168,
+    videoAnalysisMinutes: 7200,
+    abnormalBehaviorsDetected: 3,
+    blockedCorridors: 2,
+    monitoringIssues: 1,
+    affectedSeniors: 75,
+    affectedRooms: 20,
+    pendingAlerts: 3,
+    directFeedback: 2,
+    rectificationRequirements: 1,
+    rectificationRate: 72.7,
+  },
+
+  // 人活得体面 - 统计数字
+  dignityStats: {
+    healthInspectionRate: 93.7,
+    disinfectionTimes: 10,
+    avgDisinfectionInterval: 10,
+    activityCount: 10,
+    monthlyActivityCount: 2,
+    physicalExamCoverage: 100,
+    avgExamInterval: 401,
+  },
+
+  // 人活得体面 - 常见组织活动类型数据
+  activityTypeData: [
+    { value: 3, name: '棋牌活动' },
+    { value: 3, name: '手工活动' },
+    { value: 2, name: '文艺表演' },
+    { value: 1, name: '健康讲座' },
+    { value: 1, name: '生日庆祝' },
+  ],
+
+  // 人活得体面 - 每月消毒次数数据
+  monthlyDisinfectionData: {
+    months: ['1月', '2月', '3月', '4月', '5月', '6月'],
+    values: [8, 12, 10, 11, 10, 10],
+  },
+
+  // 人活得体面 - 老年人常见病分析数据
+  commonDiseaseData: [
+    { value: 35, name: '高血压' },
+    { value: 25, name: '糖尿病' },
+    { value: 15, name: '视力障碍' },
+    { value: 10, name: '关节炎' },
+    { value: 8, name: '心脏病' },
+    { value: 5, name: '听力下降' },
+    { value: 2, name: '其他' },
+  ],
+
+  // 人活得体面 - 活动参与情况表格列配置
+  activityParticipationTableColumns: [
+    { prop: 'id', label: '序号', width: 150, align: 'center' },
+    { prop: 'activityTime', label: '活动时间', minWidth: 300, align: 'center' },
+    { prop: 'activityContent', label: '活动内容', minWidth: 350, align: 'center' },
+    { prop: 'participantCount', label: '活动参与人数', minWidth: 250, align: 'center' },
+    { prop: 'participationRate', label: '活动参与率', minWidth: 200, align: 'center' },
+    { prop: 'location', label: '活动地点(摄像头位置)', minWidth: 300, align: 'center' },
+  ],
+
+  // 人活得体面 - 活动参与情况表格数据
+  activityParticipationTableData: [
+    {
+      id: 1,
+      activityTime: '2026-04-18 15:00',
+      activityContent: '棋牌比赛',
+      participantCount: '42人',
+      participationRate: '56.0%',
+      location: '活动室',
+    },
+    {
+      id: 2,
+      activityTime: '2026-04-10 14:30',
+      activityContent: '手工编织课',
+      participantCount: '26人',
+      participationRate: '34.7%',
+      location: '活动室',
+    },
+    {
+      id: 3,
+      activityTime: '2026-03-28 15:30',
+      activityContent: '健康讲座',
+      participantCount: '35人',
+      participationRate: '46.7%',
+      location: '活动室',
+    },
+  ],
+
+  // 人活得体面 - 问题表格列配置
+  dignityProblemTableColumns: [
+    { prop: 'id', label: '序号', width: 150, align: 'center' },
+    { prop: 'type', label: '问题类别', width: 250, align: 'center' },
+    { prop: 'problem', label: '问题', width: 350, align: 'center' },
+    { prop: 'description', label: '问题描述', minWidth: 400, align: 'left' },
+    { prop: 'riskLevel', label: '风险等级', width: 200, align: 'center' },
+    { prop: 'time', label: '预警时间', width: 320, align: 'center' },
+    { prop: 'source', label: '来源', width: 300, align: 'center' },
+    { prop: 'status', label: '状态', width: 200, align: 'center' },
+    { prop: 'operation', label: '操作', width: 200, align: 'center' },
+  ],
+
+  // 人活得体面 - 问题表格数据
+  dignityProblemTableData: [
+    {
+      id: 1,
+      type: '精神文化',
+      problem: '月度活动次数未达标',
+      description: '2026年2月仅开展1次集体活动,未达到"每月至少组织2次活动"的治理要求',
+      riskLevel: 'medium',
+      time: '2026-04-01',
+      source: 'AI协同调度监管员',
+      status: '未处置',
+    },
+    {
+      id: 2,
+      type: '医疗保障',
+      problem: '年度体检覆盖率不足',
+      description: '机构在院老人75人,仅69人完成年度体检,6人未体检,覆盖率92%未达标',
+      riskLevel: 'medium',
+      time: '2026-03-20',
+      source: 'AI协同调度监管员',
+      status: '整改中',
+    },
+    {
+      id: 3,
+      type: '居住环境',
+      problem: '月度消毒次数不足',
+      description: '监控抓拍超过50天未准备消毒的行为或准备相关设备,未落实"每月消毒1次"要求',
+      riskLevel: 'medium',
+      time: '2026-03-18',
+      source: 'AI协同调度监管员',
+      status: '整改中',
+    },
+    {
+      id: 4,
+      type: '医疗保障',
+      problem: '24小时就医通道不畅',
+      description: '家属通过平台反映,老人突发不适申请就医,等待35分钟无人对接,绿色通道响应失效',
+      riskLevel: 'high',
+      time: '2026-03-15',
+      source: '家属沟通AI联络员',
+      status: '未处置',
+    },
+  ],
+
+  // 人活得体面 - 统计信息
+  dignityStatistics: {
+    activitiesMonitored: 50,
+    disinfectionsMonitored: 50,
+    physicalExamsCompleted: 69,
+    familySuggestionsCollected: 23,
+    issuesIdentified: 12,
+    affectedSeniors: 75,
+    familyMembers: 108,
+    pendingAlerts: 4,
+    directFeedback: 3,
+    rectificationRequirements: 1,
+    rectificationRate: 85.7,
+  },
+}