董国庆
2026-04-21 e591908e408b42a552949b35e125dd4b6af5ca7c
screen/src/view/projectHome/index.vue
@@ -106,72 +106,60 @@
                "
              >
                <div class="flex2 flex">
                  <div class="label dept">
                    设备租赁单位
                  </div>
                  <div class="label dept">设备租赁单位</div>
                  <div class="value" v-if="filteredRentalUnits.length >= 1">
                    {{
                      filteredRentalUnits[0][
                        "工程起重机械租赁单位"
                      ] || "-"
                    }}
                    {{ filteredRentalUnits[0]["工程起重机械租赁单位"] || "-" }}
                  </div>
                    <el-tooltip
                      style="margin-left: 10px"
                      v-if="filteredRentalUnits.length > 1"
                      placement="top"
                      effect="dark"
                    >
                      <div slot="content" class="tooltip-content">
                        <div
                          v-for="(item, index) in filteredRentalUnits"
                          :key="index"
                          class="tooltip-item"
                        >
                          <div class="tooltip-label">单位{{ index + 1 }}:</div>
                          <div class="tooltip-value">
                            {{ item["工程起重机械租赁单位"] || "-" }}
                          </div>
                  <el-tooltip
                    style="margin-left: 10px"
                    v-if="filteredRentalUnits.length > 1"
                    placement="top"
                    effect="dark"
                  >
                    <div slot="content" class="tooltip-content">
                      <div
                        v-for="(item, index) in filteredRentalUnits"
                        :key="index"
                        class="tooltip-item"
                      >
                        <div class="tooltip-label">单位{{ index + 1 }}:</div>
                        <div class="tooltip-value">
                          {{ item["工程起重机械租赁单位"] || "-" }}
                        </div>
                      </div>
                      <span class="count-badge">{{
                        filteredRentalUnits.length
                      }}</span>
                    </el-tooltip>
                    </div>
                    <span class="count-badge">{{
                      filteredRentalUnits.length
                    }}</span>
                  </el-tooltip>
                </div>
                <div class="flex1 flex">
                  <div class="label">
                    联系人
                  </div>
                  <div class="label">联系人</div>
                  <div class="value" v-if="filteredContacts.length >= 1">
                    {{
                      filteredContacts[0]["联系人"] || "-"
                    }}
                    {{ filteredContacts[0]["联系人"] || "-" }}
                  </div>
                    <el-tooltip
                      style="margin-left: 10px"
                      v-if="filteredContacts.length > 1"
                      placement="top"
                      effect="dark"
                    >
                      <div slot="content" class="tooltip-content">
                        <div
                          v-for="(item, index) in filteredContacts"
                          :key="index"
                          class="tooltip-item"
                        >
                          <div class="tooltip-label">
                            联系人{{ index + 1 }}:
                          </div>
                          <div class="tooltip-value">
                            {{ item["联系人"] || "-" }}
                          </div>
                  <el-tooltip
                    style="margin-left: 10px"
                    v-if="filteredContacts.length > 1"
                    placement="top"
                    effect="dark"
                  >
                    <div slot="content" class="tooltip-content">
                      <div
                        v-for="(item, index) in filteredContacts"
                        :key="index"
                        class="tooltip-item"
                      >
                        <div class="tooltip-label">联系人{{ index + 1 }}:</div>
                        <div class="tooltip-value">
                          {{ item["联系人"] || "-" }}
                        </div>
                      </div>
                      <span class="count-badge">{{
                        filteredContacts.length
                      }}</span>
                    </el-tooltip>
                    </div>
                    <span class="count-badge">{{
                      filteredContacts.length
                    }}</span>
                  </el-tooltip>
                </div>
              </div>
              <div class="info-item11">
@@ -371,7 +359,6 @@
            </div>
          </div>
        </div>
      </div>
      <div
        v-if="permissionProject.includes('12')"
@@ -614,8 +601,8 @@
</template>
<script>
import HeaderBox from '../header/index.vue'
import moment from 'moment'
import HeaderBox from "../header/index.vue";
import moment from "moment";
import {
  getLoginInfo,
  getProjectDetail,
@@ -627,50 +614,50 @@
  getProjectSource,
  getDangerTrend,
  getProjectDangerousTrend,
  getProjectLatestProgress
} from './service.js'
  getProjectLatestProgress,
} from "./service.js";
import { transformRiskSourceData } from '@/utils/riskSourceMap.js'
import * as echarts from 'echarts'
import { transformRiskSourceData } from "@/utils/riskSourceMap.js";
import * as echarts from "echarts";
export default {
  components: {
    HeaderBox
    HeaderBox,
  },
  data () {
  data() {
    return {
      mapView: null,
      mapPromise: null,
      _AMap: null,
      _mapInitPromise: null,
      _mapResizeHandler: null,
      _lastMarkerPosKey: '',
      _lastMarkerPosKey: "",
      currentMarker: null, // 保存当前的 marker 实例
      dateRange: [
        moment().subtract(5, 'months').startOf('month'),
        moment().endOf('month')
        moment().subtract(5, "months").startOf("month"),
        moment().endOf("month"),
      ], // 默认近6个月
      markers: [],
      projectId: '',
      projectName: '',
      projectId: "",
      projectName: "",
      // 项目详情信息
      projectInfo: {
        addressInfo: {},
        address: '',
        address: "",
        constructionCompanyInfo: {},
        developmentCompanyInfo: {},
        supervisorCompanyInfo: {},
        properties: []
        properties: [],
      }, // 项目信息
      dangerCount: {
        serious: 0,
        rectified: 0,
        unRectified: 0
        unRectified: 0,
      }, // 危险源统计
      dangerCountTab: 'serious',
      dangerCountTab: "serious",
      dangerCountLoading: false,
      dangerCountCache: {
        all: null,
        serious: null
        serious: null,
      },
      deviceTypeList: [], // 设备类型列表
@@ -679,7 +666,7 @@
      // pie数据
      legendData: [],
      dateTxt: '',
      dateTxt: "",
      dangerTrendList: [], // 分项隐患趋势数据
      dangerSortType: 1, // 排序类型:1-隐患数量,2-趋势
      dangerSortDesc: true, // 是否倒序
@@ -689,11 +676,11 @@
      riskTrendData: {
        xAxisData: [],
        seriesData: [],
        statusData: []
        statusData: [],
      },
      // 9各分项隐患趋势 10隐患数量 11设备数量 12查看报告入口 13人员在岗率 14重大风险源 15 项目风险趋势
      permissionProject:
        JSON.parse(sessionStorage.getItem('permissionProject')) || [],
        JSON.parse(sessionStorage.getItem("permissionProject")) || [],
      // 项目进度相关
      progressVisible: false, // 进度弹窗显示状态
@@ -703,36 +690,36 @@
      progressMediaList: [], // 处理后的媒体列表(包含类型信息)
      // 预览相关
      previewVisible: false, // 预览弹窗显示状态
      previewUrl: '', // 预览的URL
      previewType: 'image', // 预览类型:'image' 或 'video'
      clientName: '', // 客户名称
      clientLogo: '' // 客户logo
    }
      previewUrl: "", // 预览的URL
      previewType: "image", // 预览类型:'image' 或 'video'
      clientName: "", // 客户名称
      clientLogo: "", // 客户logo
    };
  },
  computed: {
    dangerCountTabName () {
      return this.dangerCountTab === 'all' ? '所有隐患数' : '重大隐患数'
    dangerCountTabName() {
      return this.dangerCountTab === "all" ? "所有隐患数" : "重大隐患数";
    },
    // 处理风险源数据,添加合并单元格的逻辑
    riskSourceList () {
    riskSourceList() {
      if (!this.riskSourceData || this.riskSourceData.length === 0) {
        return []
        return [];
      }
      const result = []
      let i = 0
      const result = [];
      let i = 0;
      while (i < this.riskSourceData.length) {
        const currentRiskScale = this.riskSourceData[i].riskScale
        let rowspan = 1
        const currentRiskScale = this.riskSourceData[i].riskScale;
        let rowspan = 1;
        // 计算相同风险规模的行数
        for (let j = i + 1; j < this.riskSourceData.length; j++) {
          if (this.riskSourceData[j].riskScale === currentRiskScale) {
            rowspan++
            rowspan++;
          } else {
            break
            break;
          }
        }
@@ -740,740 +727,739 @@
        result.push({
          ...this.riskSourceData[i],
          showRiskScale: true,
          rowspan: rowspan
        })
          rowspan: rowspan,
        });
        // 添加后续相同风险规模的行,不显示风险规模
        for (let k = 1; k < rowspan; k++) {
          result.push({
            ...this.riskSourceData[i + k],
            showRiskScale: false,
            rowspan: 0
          })
            rowspan: 0,
          });
        }
        i += rowspan
        i += rowspan;
      }
      return result
      return result;
    },
    filteredProperties () {
    filteredProperties() {
      if (
        !this.projectInfo.properties ||
        this.projectInfo.properties.length === 0
      ) {
        return []
        return [];
      }
      const uniqueProperties = []
      const seen = new Set()
      const uniqueProperties = [];
      const seen = new Set();
      this.projectInfo.properties.forEach((itemStr) => {
        try {
          const item = JSON.parse(itemStr)
          const rentalUnit = item['工程起重机械租赁单位']
          const contact = item['联系电话']
          const item = JSON.parse(itemStr);
          const rentalUnit = item["工程起重机械租赁单位"];
          const contact = item["联系电话"];
          if (rentalUnit || contact) {
            const key = `${rentalUnit}-${contact}`
            const key = `${rentalUnit}-${contact}`;
            if (!seen.has(key)) {
              seen.add(key)
              uniqueProperties.push(item)
              seen.add(key);
              uniqueProperties.push(item);
            }
          }
        } catch (e) {
          console.error('Parsing project properties failed:', e)
          console.error("Parsing project properties failed:", e);
        }
      })
      console.log('uniqueProperties uniqueProperties', uniqueProperties)
      });
      console.log("uniqueProperties uniqueProperties", uniqueProperties);
      return uniqueProperties
      return uniqueProperties;
    },
    filteredRentalUnits () {
    filteredRentalUnits() {
      if (
        !this.projectInfo.properties ||
        this.projectInfo.properties.length === 0
      ) {
        return []
        return [];
      }
      const list = []
      const seen = new Set()
      const list = [];
      const seen = new Set();
      this.projectInfo.properties.forEach((itemStr) => {
        try {
          const item = JSON.parse(itemStr)
          const rentalUnit = item['工程起重机械租赁单位']
          if (!rentalUnit) return
          const key = String(rentalUnit).trim()
          if (!key) return
          if (seen.has(key)) return
          seen.add(key)
          list.push({ '工程起重机械租赁单位': rentalUnit })
        } catch (e) {
        }
      })
      return list
          const item = JSON.parse(itemStr);
          const rentalUnit = item["工程起重机械租赁单位"];
          if (!rentalUnit) return;
          const key = String(rentalUnit).trim();
          if (!key) return;
          if (seen.has(key)) return;
          seen.add(key);
          list.push({ 工程起重机械租赁单位: rentalUnit });
        } catch (e) {}
      });
      return list;
    },
    filteredContacts () {
    filteredContacts() {
      if (
        !this.projectInfo.properties ||
        this.projectInfo.properties.length === 0
      ) {
        return []
        return [];
      }
      const list = []
      const seen = new Set()
      const list = [];
      const seen = new Set();
      this.projectInfo.properties.forEach((itemStr) => {
        try {
          const item = JSON.parse(itemStr)
          const name = item['联系人']
          if (!name) return
          const key = String(name).trim()
          if (!key) return
          if (seen.has(key)) return
          seen.add(key)
          list.push({ '联系人': name })
        } catch (e) {
          const item = JSON.parse(itemStr);
          const name = item["联系人"];
          if (!name) return;
          const key = String(name).trim();
          if (!key) return;
          if (seen.has(key)) return;
          seen.add(key);
          list.push({ 联系人: name });
        } catch (e) {}
      });
        }
      })
      return list
    }
      return list;
    },
  },
  watch: {
    dateRange: {
      handler (newVal, oldVal) {
      handler(newVal, oldVal) {
        if (newVal.length > 0) {
          this.dateTxt =
            moment(newVal[0]).format('YYYY -MM') +
            ' - ' +
            moment(newVal[1]).format('YYYY -MM')
            moment(newVal[0]).format("YYYY -MM") +
            " - " +
            moment(newVal[1]).format("YYYY -MM");
          // 当日期范围改变时,重新获取风险趋势数据
          if (this.projectId) {
            this.getProjectRiskTrend()
            this.getProjectRiskTrend();
          }
        }
      },
      immediate: true
    }
      immediate: true,
    },
  },
  created () {
  created() {
    this.mapPromise = AMapLoader.load({
      key: '232929db1cb31f26d42b3645a7456154',
      version: '2.0',
      zoom: 25
    })
      key: "232929db1cb31f26d42b3645a7456154",
      version: "2.0",
      zoom: 25,
    });
    if (this.$route.query.projectId) {
      this.projectId = this.$route.query.projectId || ''
      this.projectId = this.$route.query.projectId || "";
      // 添加错误处理,确保登录信息获取失败不影响其他模块
      getLoginInfo({ id: this.projectId, type: 2 })
        .then((res) => {
          this.projectName = res.projectName
          if (sessionStorage.getItem('userInfo')) {
          this.projectName = res.projectName;
          if (sessionStorage.getItem("userInfo")) {
            this.permissionProject =
              JSON.parse(sessionStorage.getItem('permissionProject')) || []
              JSON.parse(sessionStorage.getItem("permissionProject")) || [];
          } else {
            const permissions = res.permissionProject
              ? res.permissionProject.split(',')
              : []
            this.permissionProject = permissions
              ? res.permissionProject.split(",")
              : [];
            this.permissionProject = permissions;
            sessionStorage.setItem(
              'permissionProject',
              "permissionProject",
              JSON.stringify(permissions)
            )
            );
          }
          sessionStorage.setItem('deviceTemplateId', res.deviceTemplateId) // 设备模板id
          sessionStorage.setItem('deviceTemplateName', res.deviceTemplateName) // 设备模板id
          sessionStorage.setItem('safetyId', res.safetyId) // 安全报告模板id
          sessionStorage.setItem('safetyName', res.safetyName)
          sessionStorage.setItem('bigHiddenDanger', res.bigHiddenDanger) // 1开启 2关闭 重大隐患
          sessionStorage.setItem("deviceTemplateId", res.deviceTemplateId); // 设备模板id
          sessionStorage.setItem("deviceTemplateName", res.deviceTemplateName); // 设备模板id
          sessionStorage.setItem("safetyId", res.safetyId); // 安全报告模板id
          sessionStorage.setItem("safetyName", res.safetyName);
          sessionStorage.setItem("bigHiddenDanger", res.bigHiddenDanger); // 1开启 2关闭 重大隐患
          sessionStorage.setItem(
            'generalHiddenDanger',
            "generalHiddenDanger",
            res.generalHiddenDanger
          ) // 1开启 2关闭 一般隐患
          sessionStorage.setItem('commentType', res.commentType) // 1模糊评价 2打分评价
          sessionStorage.setItem('clientName', res.name)
          sessionStorage.setItem('clientLogo', res.logo)
          sessionStorage.setItem('clientId', res.clientId)
          this.clientName = res.name
          this.clientLogo = res.logo
          ); // 1开启 2关闭 一般隐患
          sessionStorage.setItem("commentType", res.commentType); // 1模糊评价 2打分评价
          sessionStorage.setItem("clientName", res.name);
          sessionStorage.setItem("clientLogo", res.logo);
          sessionStorage.setItem("clientId", res.clientId);
          this.clientName = res.name;
          this.clientLogo = res.logo;
        })
        .catch((err) => {
          console.error('获取登录信息失败:', err)
          console.error("获取登录信息失败:", err);
          // 设置默认值,确保页面可以继续渲染
          this.projectName = '项目详情'
          this.projectName = "项目详情";
          // this.permissionProject = []
        })
      this.getDetail()
      this.getDangerTrendList()
      this.getProjectRiskTrend()
        });
      this.getDetail();
      this.getDangerTrendList();
      this.getProjectRiskTrend();
    }
  },
  mounted () {
  mounted() {
    setTimeout(() => {
      this.initRiskChart()
    }, 1000)
      this.initRiskChart();
    }, 1000);
  },
  activated () {
  activated() {
    // 当从其他页面返回时,重新设置地图 marker
    if (this.mapView && this.projectInfo.type !== undefined) {
      this.updateMapMarker()
      this.updateMapMarker();
    }
  },
  beforeDestroy () {
  beforeDestroy() {
    if (this._mapResizeHandler) {
      window.removeEventListener('resize', this._mapResizeHandler)
      this._mapResizeHandler = null
      window.removeEventListener("resize", this._mapResizeHandler);
      this._mapResizeHandler = null;
    }
    if (this.mapView) {
      this.mapView.destroy()
      this.mapView = null
      this.mapView.destroy();
      this.mapView = null;
    }
    this.currentMarker = null
    this._lastMarkerPosKey = ''
    this.currentMarker = null;
    this._lastMarkerPosKey = "";
  },
  methods: {
    // 打开项目进度弹窗
    toProjectDetail () {
      this.progressVisible = true
      this.getLatestProgress()
    toProjectDetail() {
      this.progressVisible = true;
      this.getLatestProgress();
    },
    // 获取最新进度
    async getLatestProgress () {
      this.progressLoading = true
    async getLatestProgress() {
      this.progressLoading = true;
      try {
        const res = await getProjectLatestProgress(this.projectId)
        const res = await getProjectLatestProgress(this.projectId);
        if (res) {
          this.latestProgress = res
          this.latestProgress = res;
          // 解析并检测媒体文件类型
          await this.detectMediaTypes(res.url)
          await this.detectMediaTypes(res.url);
        } else {
          this.latestProgress = {}
          this.progressMediaList = []
          this.latestProgress = {};
          this.progressMediaList = [];
        }
      } catch (error) {
        console.error('获取最新进度失败:', error)
        this.$message.error('获取最新进度失败')
        this.latestProgress = {}
        this.progressMediaList = []
        console.error("获取最新进度失败:", error);
        this.$message.error("获取最新进度失败");
        this.latestProgress = {};
        this.progressMediaList = [];
      } finally {
        this.progressLoading = false
        this.progressLoading = false;
      }
    },
    // 关闭进度弹窗
    closeProgressDialog () {
      this.progressVisible = false
      this.latestProgress = {}
    closeProgressDialog() {
      this.progressVisible = false;
      this.latestProgress = {};
    },
    // 跳转到历史进度页面
    toProgressHistory () {
      this.progressVisible = false
    toProgressHistory() {
      this.progressVisible = false;
      this.$router.push({
        path: '/projectProgress',
        path: "/projectProgress",
        query: {
          projectId: this.projectId,
          projectName: this.projectName
        }
      })
          projectName: this.projectName,
        },
      });
    },
    // 格式化进度时间
    formatProgressTime (time) {
      return time ? moment(time).format('YYYY-MM-DD HH:mm:ss') : '-'
    formatProgressTime(time) {
      return time ? moment(time).format("YYYY-MM-DD HH:mm:ss") : "-";
    },
    // 通过 Content-Type 检测媒体文件类型(加载时检测所有文件)
    async detectMediaTypes (urlStr) {
    async detectMediaTypes(urlStr) {
      if (!urlStr) {
        this.progressMediaList = []
        return
        this.progressMediaList = [];
        return;
      }
      try {
        let fileIds = []
        let fileIds = [];
        // 如果是数组,直接使用
        if (Array.isArray(urlStr)) {
          fileIds = urlStr
          fileIds = urlStr;
        }
        // 如果是逗号分隔的字符串
        else if (typeof urlStr === 'string' && urlStr.includes(',')) {
          fileIds = urlStr.split(',').filter((item) => item.trim())
        else if (typeof urlStr === "string" && urlStr.includes(",")) {
          fileIds = urlStr.split(",").filter((item) => item.trim());
        }
        // 如果是单个字符串
        else if (typeof urlStr === 'string' && urlStr.trim()) {
          fileIds = [urlStr.trim()]
        else if (typeof urlStr === "string" && urlStr.trim()) {
          fileIds = [urlStr.trim()];
        }
        // 并发检测所有文件的类型
        const mediaPromises = fileIds.map(async (id) => {
          let url = ''
          let url = "";
          // 如果已经是完整的URL(http或https开头),直接使用
          if (id.startsWith('http://') || id.startsWith('https://')) {
            url = id
          if (id.startsWith("http://") || id.startsWith("https://")) {
            url = id;
          } else {
            // 否则拼接为下载URL
            url = `${this.VUE_APP_BASE_URL}/project/download/${id}`
            url = `${this.VUE_APP_BASE_URL}/public/file/download/${id}`;
          }
          // 先尝试从扩展名判断
          let type = 'image'
          let type = "image";
          if (url.match(/\.(mp4|webm|ogg|avi|mov)$/i)) {
            type = 'video'
            type = "video";
          } else {
            // 如果没有扩展名,通过 Content-Type 检测
            type = await this.getFileTypeByContentType(url)
            type = await this.getFileTypeByContentType(url);
          }
          return {
            url: url,
            type: type, // 'image' 或 'video'
            id: id
          }
        })
            id: id,
          };
        });
        this.progressMediaList = await Promise.all(mediaPromises)
        this.progressMediaList = await Promise.all(mediaPromises);
      } catch (error) {
        console.error('检测媒体文件类型失败:', error)
        this.progressMediaList = []
        console.error("检测媒体文件类型失败:", error);
        this.progressMediaList = [];
      }
    },
    // 通过 Content-Type 判断文件类型(使用 GET 请求,和后台管理保持一致)
    async getFileTypeByContentType (url) {
    async getFileTypeByContentType(url) {
      try {
        // 使用 GET 请求获取响应头(和 React 后台管理一致)
        const response = await fetch(url, {
          method: 'GET',
          mode: 'cors'
        })
          method: "GET",
          mode: "cors",
        });
        const contentType = response.headers.get('Content-Type') || ''
        const contentType = response.headers.get("Content-Type") || "";
        // 判断是否为视频
        if (contentType.startsWith('video/')) {
          return 'video'
        if (contentType.startsWith("video/")) {
          return "video";
        }
        // 判断是否为图片
        else if (contentType.startsWith('image/')) {
          return 'image'
        else if (contentType.startsWith("image/")) {
          return "image";
        }
        // 默认当作图片处理
        else {
          return 'image'
          return "image";
        }
      } catch (error) {
        console.error('获取文件 Content-Type 失败:', url, error)
        console.error("获取文件 Content-Type 失败:", url, error);
        // 如果请求失败,默认当作图片处理
        return 'image'
        return "image";
      }
    },
    // 预览进度媒体(图片或视频)- 弹窗预览
    previewProgressMedia (item) {
    previewProgressMedia(item) {
      if (item && item.url) {
        this.previewUrl = item.url
        this.previewType = item.type || 'image'
        this.previewVisible = true
        this.previewUrl = item.url;
        this.previewType = item.type || "image";
        this.previewVisible = true;
      }
    },
    // 关闭预览弹窗
    closePreview () {
      this.previewVisible = false
      this.previewUrl = ''
      this.previewType = 'image'
    closePreview() {
      this.previewVisible = false;
      this.previewUrl = "";
      this.previewType = "image";
    },
    // 图片加载失败处理
    handleImageError (e) {
      e.target.src = require('../../assets/img/logo.png')
    handleImageError(e) {
      e.target.src = require("../../assets/img/logo.png");
    },
    // 视频加载失败处理
    handleVideoError (e) {
      console.error('视频加载失败:', e)
    handleVideoError(e) {
      console.error("视频加载失败:", e);
      // 可以在这里添加视频加载失败的处理逻辑
    },
    normalizeDangerCount (res) {
    normalizeDangerCount(res) {
      return {
        serious: res && res.serious !== undefined ? res.serious : 0,
        rectified: res && res.rectified !== undefined ? res.rectified : 0,
        unRectified: res && res.unRectified !== undefined
          ? res.unRectified
          : 0
      }
        unRectified: res && res.unRectified !== undefined ? res.unRectified : 0,
      };
    },
    async loadDangerCount (tab = this.dangerCountTab, force = false) {
      const cacheData = this.dangerCountCache[tab]
    async loadDangerCount(tab = this.dangerCountTab, force = false) {
      const cacheData = this.dangerCountCache[tab];
      if (!force && cacheData) {
        this.dangerCount = { ...cacheData }
        return
        this.dangerCount = { ...cacheData };
        return;
      }
      this.dangerCountLoading = true
      this.dangerCountLoading = true;
      try {
        const requestApi = tab === 'all' ? getDangerCountAll : getDangerCount
        const res = await requestApi(this.projectId)
        const countData = this.normalizeDangerCount(res)
        this.dangerCount = countData
        this.dangerCountCache[tab] = { ...countData }
        const requestApi = tab === "all" ? getDangerCountAll : getDangerCount;
        const res = await requestApi(this.projectId);
        const countData = this.normalizeDangerCount(res);
        this.dangerCount = countData;
        this.dangerCountCache[tab] = { ...countData };
      } catch (err) {
        console.error(
          `获取${tab === 'all' ? '所有隐患数量' : '重大隐患数量'}失败:`,
          `获取${tab === "all" ? "所有隐患数量" : "重大隐患数量"}失败:`,
          err
        )
        this.dangerCount = this.normalizeDangerCount()
        );
        this.dangerCount = this.normalizeDangerCount();
      } finally {
        this.dangerCountLoading = false
        this.dangerCountLoading = false;
      }
    },
    handleDangerTabChange (tab) {
      if (this.dangerCountTab === tab) return
      this.dangerCountTab = tab
      this.loadDangerCount(tab)
    handleDangerTabChange(tab) {
      if (this.dangerCountTab === tab) return;
      this.dangerCountTab = tab;
      this.loadDangerCount(tab);
    },
    // 获取项目详情
    getDetail () {
    getDetail() {
      this.dangerCountCache = {
        all: null,
        serious: null
      }
        serious: null,
      };
      // 设备类型 - 添加错误处理
      deviceTypes()
        .then((res) => {
          this.deviceTypeList = res
          this.deviceTypeList = res;
        })
        .catch((err) => {
          console.error('获取设备类型失败:', err)
          this.deviceTypeList = []
        })
          console.error("获取设备类型失败:", err);
          this.deviceTypeList = [];
        });
      // 获取项目详情 - 添加错误处理
      getProjectDetail(this.projectId)
        .then((res) => {
          const addressInfo = res.addressInfo
            ? JSON.parse(res.addressInfo)
            : {}
            : {};
          const constructionCompanyInfo = res.constructionCompanyInfo
            ? JSON.parse(res.constructionCompanyInfo)
            : {}
            : {};
          const developmentCompanyInfo = res.developmentCompanyInfo
            ? JSON.parse(res.developmentCompanyInfo)
            : {}
            : {};
          const supervisorCompanyInfo = res.supervisorCompanyInfo
            ? JSON.parse(res.supervisorCompanyInfo)
            : {}
            : {};
          this.projectInfo = {
            ...res,
            addressInfo: addressInfo,
            address:
              (addressInfo.province || '') +
              (addressInfo.city || '') +
              (addressInfo.district || '') +
              (addressInfo.detail || ''),
              (addressInfo.province || "") +
              (addressInfo.city || "") +
              (addressInfo.district || "") +
              (addressInfo.detail || ""),
            constructionCompanyInfo: constructionCompanyInfo,
            developmentCompanyInfo: developmentCompanyInfo,
            supervisorCompanyInfo: supervisorCompanyInfo
          }
            supervisorCompanyInfo: supervisorCompanyInfo,
          };
          this.$nextTick(() => {
            this.setMapload().then(() => {
              this.updateMapMarker()
            })
          })
              this.updateMapMarker();
            });
          });
        })
        .catch((err) => {
          console.error('获取项目详情失败:', err)
          console.error("获取项目详情失败:", err);
          // 设置默认值
          this.projectInfo = {
            addressInfo: {},
            address: '',
            address: "",
            constructionCompanyInfo: {},
            developmentCompanyInfo: {},
            supervisorCompanyInfo: {},
            properties: []
          }
        })
            properties: [],
          };
        });
      // 设备数量 - 添加错误处理
      getProjectDeviceCount(this.projectId)
        .then((res) => {
          this.equipment = 0
          this.equipment = 0;
          this.legendData = res.map((item) => {
            this.equipment += item.count
            const deviceType = this.deviceTypeList[item.type]
            this.equipment += item.count;
            const deviceType = this.deviceTypeList[item.type];
            return {
              ...item,
              value: item.count || 0,
              name:
                deviceType && deviceType.name ? deviceType.name : '未知设备',
              itemStyle: { color: this.generateRandomColor() }
            }
          })
          this.initPie3D()
                deviceType && deviceType.name ? deviceType.name : "未知设备",
              itemStyle: { color: this.generateRandomColor() },
            };
          });
          this.initPie3D();
        })
        .catch((err) => {
          console.error('获取设备数量失败:', err)
          this.equipment = 0
          this.legendData = []
        })
          console.error("获取设备数量失败:", err);
          this.equipment = 0;
          this.legendData = [];
        });
      this.loadDangerCount(this.dangerCountTab, true)
      this.loadDangerCount(this.dangerCountTab, true);
      // 项目人员信息 - 添加错误处理
      getProjectPersonInfo({ projectId: this.projectId })
        .then((res) => {
          this.peopleList = res || []
          this.peopleList = res || [];
        })
        .catch((err) => {
          console.error('获取人员信息失败:', err)
          this.peopleList = []
        })
          console.error("获取人员信息失败:", err);
          this.peopleList = [];
        });
      // 获取项目风险源 - 添加错误处理
      getProjectSource({ projectId: this.projectId })
        .then((res) => {
          const riskSourceList = []
          const riskSourceList = [];
          // 处理超危大工程
          if (res.superDangerousOptions) {
            try {
              const superDangerousArray = JSON.parse(res.superDangerousOptions)
              const superDangerousArray = JSON.parse(res.superDangerousOptions);
              const transformedData = transformRiskSourceData(
                superDangerousArray,
                'superDangerous',
                '超危大工程'
              )
              riskSourceList.push(...transformedData)
                "superDangerous",
                "超危大工程"
              );
              riskSourceList.push(...transformedData);
            } catch (e) {
              console.error('解析超危大工程数据失败:', e)
              console.error("解析超危大工程数据失败:", e);
            }
          }
          // 处理危大工程
          if (res.dangerousOptions) {
            try {
              const dangerousArray = JSON.parse(res.dangerousOptions)
              const dangerousArray = JSON.parse(res.dangerousOptions);
              const transformedData = transformRiskSourceData(
                dangerousArray,
                'dangerous',
                '危大工程'
              )
              riskSourceList.push(...transformedData)
                "dangerous",
                "危大工程"
              );
              riskSourceList.push(...transformedData);
            } catch (e) {
              console.error('解析危大工程数据失败:', e)
              console.error("解析危大工程数据失败:", e);
            }
          }
          // 处理风险源
          if (res.hazardSource) {
            try {
              const hazardSourceArray = JSON.parse(res.hazardSource)
              const hazardSourceArray = JSON.parse(res.hazardSource);
              const transformedData = transformRiskSourceData(
                hazardSourceArray,
                'hazardSource',
                '风险源'
              )
              riskSourceList.push(...transformedData)
                "hazardSource",
                "风险源"
              );
              riskSourceList.push(...transformedData);
            } catch (e) {
              console.error('解析风险源数据失败:', e)
              console.error("解析风险源数据失败:", e);
            }
          }
          this.riskSourceData = riskSourceList
          this.riskSourceData = riskSourceList;
        })
        .catch((err) => {
          console.error('获取项目风险源失败:', err)
          this.riskSourceData = []
        })
          console.error("获取项目风险源失败:", err);
          this.riskSourceData = [];
        });
    },
    // 获取隐患趋势
    getDangerTrendList () {
    getDangerTrendList() {
      let params = {
        projectId: this.projectId,
        type: this.dangerSortType, // 1数量 2 趋势
        desc: this.dangerSortDesc // 是否倒序
      }
        desc: this.dangerSortDesc, // 是否倒序
      };
      getDangerTrend(params)
        .then((res) => {
          this.dangerTrendList = res || []
          this.dangerTrendList = res || [];
        })
        .catch((err) => {
          console.error('获取隐患趋势失败:', err)
          this.dangerTrendList = []
        })
          console.error("获取隐患趋势失败:", err);
          this.dangerTrendList = [];
        });
    },
    // 切换隐患排序方式
    changeDangerSort (type) {
    changeDangerSort(type) {
      if (this.dangerSortType === type) {
        // 如果点击的是当前排序类型,则切换升序/降序
        this.dangerSortDesc = !this.dangerSortDesc
        this.dangerSortDesc = !this.dangerSortDesc;
      } else {
        // 如果点击的是不同的排序类型,则切换类型并默认倒序
        this.dangerSortType = type
        this.dangerSortDesc = true
        this.dangerSortType = type;
        this.dangerSortDesc = true;
      }
      // 重新请求数据
      this.getDangerTrendList()
      this.getDangerTrendList();
    },
    // 计算进度条宽度
    getBarWidth (current, compare) {
      const max = Math.max(current, compare)
      if (max === 0) return '0px'
      const percentage = (current / max) * 100
      const maxWidth = 114 // 最大宽度
      return `${(percentage / 100) * maxWidth}px`
    getBarWidth(current, compare) {
      const max = Math.max(current, compare);
      if (max === 0) return "0px";
      const percentage = (current / max) * 100;
      const maxWidth = 114; // 最大宽度
      return `${(percentage / 100) * maxWidth}px`;
    },
    // 人员在岗率
    toPersonnelOnDuty () {
    toPersonnelOnDuty() {
      this.$router.push({
        path: '/personnelOnDuty',
        path: "/personnelOnDuty",
        query: {
          projectId: this.projectId,
          projectName: this.projectName
        }
      })
          projectName: this.projectName,
        },
      });
    },
    // 跳转隐患列表
    toHiddenDanger (type) {
    toHiddenDanger(type) {
      this.$router.push({
        path: '/hiddenDanger',
        path: "/hiddenDanger",
        query: {
          projectId: this.projectId,
          projectName: this.projectName,
          activeTab: type,
          type: 2
        }
      })
          type: 2,
        },
      });
    },
    // 跳转设备列表
    toEquipmentInfo () {
    toEquipmentInfo() {
      this.$router.push({
        path: '/equipmentList',
        query: {
          projectId: this.projectId,
          projectName: this.projectName
        }
      })
    },
    // 跳转重大危险源
    toMajorRiskList () {
      this.$router.push({
        path: '/majorRisk',
        query: {
          projectId: this.projectId,
          projectName: this.projectName
        }
      })
    },
    toPlanOfAudit () {
      this.$router.push({
        path: '/planOfAudit',
        path: "/equipmentList",
        query: {
          projectId: this.projectId,
          projectName: this.projectName,
          type: 2
        }
      })
        },
      });
    },
    setMapload () {
    // 跳转重大危险源
    toMajorRiskList() {
      this.$router.push({
        path: "/majorRisk",
        query: {
          projectId: this.projectId,
          projectName: this.projectName,
        },
      });
    },
    toPlanOfAudit() {
      this.$router.push({
        path: "/planOfAudit",
        query: {
          projectId: this.projectId,
          projectName: this.projectName,
          type: 2,
        },
      });
    },
    setMapload() {
      if (!this.mapPromise) {
        this.mapPromise = AMapLoader.load({
          key: '232929db1cb31f26d42b3645a7456154',
          version: '2.0'
        })
          key: "232929db1cb31f26d42b3645a7456154",
          version: "2.0",
        });
      }
      if (this._mapInitPromise) {
        return this._mapInitPromise
        return this._mapInitPromise;
      }
      this._mapInitPromise = this.mapPromise
        .then((AMap) => {
          this._AMap = AMap
          this._AMap = AMap;
          if (this.mapView) {
            this.mapView.resize()
            this.mapView.resize();
            if (!this._mapResizeHandler) {
              this._mapResizeHandler = () => {
                if (this.mapView) this.mapView.resize()
              }
              window.addEventListener('resize', this._mapResizeHandler)
                if (this.mapView) this.mapView.resize();
              };
              window.addEventListener("resize", this._mapResizeHandler);
            }
            return AMap
            return AMap;
          }
          const satellite = new AMap.TileLayer.Satellite()
          const satellite = new AMap.TileLayer.Satellite();
          // 获取经纬度
          let center = [104.065617, 30.65695] // 默认中心点
          let longitude = null
          let latitude = null
          let center = [104.065617, 30.65695]; // 默认中心点
          let longitude = null;
          let latitude = null;
          if (this.projectInfo && this.projectInfo.addressInfo) {
            longitude = Number(this.projectInfo.addressInfo.longitude)
            latitude = Number(this.projectInfo.addressInfo.latitude)
            longitude = Number(this.projectInfo.addressInfo.longitude);
            latitude = Number(this.projectInfo.addressInfo.latitude);
            if (!isNaN(longitude) && !isNaN(latitude) && longitude !== 0 && latitude !== 0) {
              center = [longitude, latitude]
            if (
              !isNaN(longitude) &&
              !isNaN(latitude) &&
              longitude !== 0 &&
              latitude !== 0
            ) {
              center = [longitude, latitude];
            }
          }
          this.mapView = new AMap.Map('projectContainer', {
          this.mapView = new AMap.Map("projectContainer", {
            zoom: 17,
            center: center,
            layers: [satellite]
          })
            layers: [satellite],
          });
          this.mapView.resize()
          this.mapView.resize();
          if (!this._mapResizeHandler) {
            this._mapResizeHandler = () => {
              if (this.mapView) this.mapView.resize()
            }
            window.addEventListener('resize', this._mapResizeHandler)
              if (this.mapView) this.mapView.resize();
            };
            window.addEventListener("resize", this._mapResizeHandler);
          }
          return AMap
          return AMap;
        })
        .catch((e) => {
          console.error(e)
          throw e
          console.error(e);
          throw e;
        })
        .finally(() => {
          this._mapInitPromise = null
        })
          this._mapInitPromise = null;
        });
      return this._mapInitPromise
      return this._mapInitPromise;
    },
    // 更新地图 marker
    updateMapMarker () {
      if (!this.mapView) return
    updateMapMarker() {
      if (!this.mapView) return;
      const AMap = this._AMap || window.AMap
      if (!AMap) return
      const AMap = this._AMap || window.AMap;
      if (!AMap) return;
      // 根据项目类型选择图标
      const iconImages = [
        require('../../assets/img/home/f4.png'),
        require('../../assets/img/home/s4.png'),
        require('../../assets/img/home/z4.png')
      ]
      const iconImage = iconImages[this.projectInfo.type] || iconImages[0]
        require("../../assets/img/home/new-mark.png"),
        require("../../assets/img/home/s4.png"),
        require("../../assets/img/home/z4.png"),
      ];
      // const iconImage = iconImages[this.projectInfo.type] || iconImages[0];
      const iconImage = iconImages[0];
      const tryRenderMarker = (lng, lat) => {
        if (
          typeof lng !== 'number' ||
          typeof lat !== 'number' ||
          typeof lng !== "number" ||
          typeof lat !== "number" ||
          isNaN(lng) ||
          isNaN(lat)
        ) {
          return false
          return false;
        }
        const nextKey = `${lng},${lat}`
        const nextKey = `${lng},${lat}`;
        if (this.currentMarker && this._lastMarkerPosKey === nextKey) {
          return true
          return true;
        }
        if (!this.currentMarker) {
@@ -1481,60 +1467,60 @@
            position: [lng, lat],
            icon: new AMap.Icon({
              image: iconImage,
              size: new AMap.Size(30, 30),
              imageSize: new AMap.Size(30, 30)
              size: new AMap.Size(60, 60),
              imageSize: new AMap.Size(60, 60),
            }),
            offset: new AMap.Pixel(-15, -15),
            zoom: 17
          })
          this.mapView.add(this.currentMarker)
        } else if (typeof this.currentMarker.setPosition === 'function') {
          this.currentMarker.setPosition([lng, lat])
            offset: new AMap.Pixel(-30, -30),
            zoom: 17,
          });
          this.mapView.add(this.currentMarker);
        } else if (typeof this.currentMarker.setPosition === "function") {
          this.currentMarker.setPosition([lng, lat]);
        } else {
          this.mapView.remove(this.currentMarker)
          this.mapView.remove(this.currentMarker);
          this.currentMarker = new AMap.Marker({
            position: [lng, lat],
            icon: new AMap.Icon({
              image: iconImage,
              size: new AMap.Size(30, 30),
              imageSize: new AMap.Size(30, 30)
              imageSize: new AMap.Size(30, 30),
            }),
            offset: new AMap.Pixel(-15, -15),
            zoom: 17
          })
          this.mapView.add(this.currentMarker)
            zoom: 17,
          });
          this.mapView.add(this.currentMarker);
        }
        if (typeof this.mapView.setZoomAndCenter === 'function') {
        if (typeof this.mapView.setZoomAndCenter === "function") {
          if (!this._lastMarkerPosKey) {
            this.mapView.setZoomAndCenter(17, [lng, lat])
          } else if (typeof this.mapView.setCenter === 'function') {
            this.mapView.setCenter([lng, lat])
            this.mapView.setZoomAndCenter(17, [lng, lat]);
          } else if (typeof this.mapView.setCenter === "function") {
            this.mapView.setCenter([lng, lat]);
          } else {
            this.mapView.setZoomAndCenter(17, [lng, lat])
            this.mapView.setZoomAndCenter(17, [lng, lat]);
          }
        }
        this._lastMarkerPosKey = nextKey
        return true
      }
        this._lastMarkerPosKey = nextKey;
        return true;
      };
      // 1) 优先使用后端返回的经纬度(如果有)
      const info = this.projectInfo.addressInfo || {}
      let lng = null
      let lat = null
      const info = this.projectInfo.addressInfo || {};
      let lng = null;
      let lat = null;
      if (info.longitude && info.latitude) {
        lng = Number(info.longitude)
        lat = Number(info.latitude)
        lng = Number(info.longitude);
        lat = Number(info.latitude);
      } else {
        const lonLatStr = typeof info.lonLat === 'string' ? info.lonLat : ''
        const lonLatParts = lonLatStr.split(',')
        lng = lonLatParts[0] ? Number(lonLatParts[0]) : null
        lat = lonLatParts[1] ? Number(lonLatParts[1]) : null
        const lonLatStr = typeof info.lonLat === "string" ? info.lonLat : "";
        const lonLatParts = lonLatStr.split(",");
        lng = lonLatParts[0] ? Number(lonLatParts[0]) : null;
        lat = lonLatParts[1] ? Number(lonLatParts[1]) : null;
      }
      if (tryRenderMarker(lng, lat)) {
        return
        return;
      }
      // 2) 无经纬度时,使用地址进行地理编码
@@ -1544,149 +1530,149 @@
          info && info.province,
          info && info.city,
          info && info.district,
          info && info.detail
          info && info.detail,
        ]
          .filter(Boolean)
          .join('')
          .join("");
      if (address && this.mapPromise) {
        this.mapPromise
          .then(() => {
            const Geocoder =
              (window.AMap && window.AMap.Geocoder) ||
              (typeof AMap !== 'undefined' && AMap.Geocoder)
            if (!Geocoder) return
              (typeof AMap !== "undefined" && AMap.Geocoder);
            if (!Geocoder) return;
            const geocoder = new Geocoder({
              city: (info && (info.city || info.province)) || ''
            })
              city: (info && (info.city || info.province)) || "",
            });
            geocoder.getLocation(address, (status, result) => {
              if (
                status === 'complete' &&
                status === "complete" &&
                result &&
                result.geocodes &&
                result.geocodes.length > 0
              ) {
                const loc = result.geocodes[0].location
                const lnglat = [loc.lng, loc.lat]
                tryRenderMarker(lnglat[0], lnglat[1])
                const loc = result.geocodes[0].location;
                const lnglat = [loc.lng, loc.lat];
                tryRenderMarker(lnglat[0], lnglat[1]);
              } else {
                // 回退到默认中心点
                tryRenderMarker(104.065617, 30.65695)
                tryRenderMarker(104.065617, 30.65695);
              }
            })
            });
          })
          .catch(() => {
            // 加载失败时回退到默认中心点
            tryRenderMarker(104.065617, 30.65695)
          })
            tryRenderMarker(104.065617, 30.65695);
          });
      } else {
        // 3) 地址不可用时,回退到默认中心点
        tryRenderMarker(104.065617, 30.65695)
        tryRenderMarker(104.065617, 30.65695);
      }
    },
    // 初始化 3D 环饼图(echarts-gl)
    initPie3D () {
      const el = this.$refs.pieChart
      if (!el) return
      this._pie = echarts.init(el)
    initPie3D() {
      const el = this.$refs.pieChart;
      if (!el) return;
      this._pie = echarts.init(el);
      // 使用动态数据或默认数据
      const data = this.legendData.length > 0 ? this.legendData : []
      const data = this.legendData.length > 0 ? this.legendData : [];
      // 生成 3D 饼图 option(internalDiameterRatio 控制环形内径比)
      this.legendData = data // 用于右侧自定义 legend
      const series = this.getPie3D(data, 0.7)
      this.legendData = data; // 用于右侧自定义 legend
      const series = this.getPie3D(data, 0.7);
      const option = {
        legend: {
          tooltip: {
            show: true
            show: true,
          },
          data: data.map((item) => item.name),
          right: '2%',
          top: 'center',
          orient: 'vertical',
          right: "2%",
          top: "center",
          orient: "vertical",
          itemGap: 20,
          textStyle: {
            color: '#fff',
            fontSize: 12
            color: "#fff",
            fontSize: 12,
          },
          show: false
          show: false,
        },
        graphic: {
          elements: [
            {
              type: 'circle',
              type: "circle",
              shape: {
                cx: '50%',
                cy: '50%',
                r: '35%'
                cx: "50%",
                cy: "50%",
                r: "35%",
              },
              style: {
                fill: 'transparent',
                fill: "transparent",
                shadowBlur: 20,
                shadowColor: 'rgba(0, 191, 255, 0.4)',
                opacity: 0.6
                shadowColor: "rgba(0, 191, 255, 0.4)",
                opacity: 0.6,
              },
              z: -1
            }
          ]
              z: -1,
            },
          ],
        },
        animation: true,
        tooltip: {
          formatter: (params) => {
            if (
              params.seriesName !== 'mouseoutSeries' &&
              params.seriesName !== 'pie2d'
              params.seriesName !== "mouseoutSeries" &&
              params.seriesName !== "pie2d"
            ) {
              const series = option.series[params.seriesIndex]
              const series = option.series[params.seriesIndex];
              if (series && series.pieData) {
                return `${params.seriesName}<br/><span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>${series.pieData.value}`
                return `${params.seriesName}<br/><span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>${series.pieData.value}`;
              }
            }
          },
          textStyle: {
            fontSize: 12
          }
            fontSize: 12,
          },
        },
        title: {
          x: 'center',
          top: '20',
          x: "center",
          top: "20",
          textStyle: {
            color: '#fff',
            fontSize: 12
          }
            color: "#fff",
            fontSize: 12,
          },
        },
        backgroundColor: 'transparent',
        backgroundColor: "transparent",
        labelLine: {
          show: false,
          lineStyle: {
            color: 'transparent'
          }
            color: "transparent",
          },
        },
        label: {
          show: false,
          color: 'transparent',
          position: 'outside',
          formatter: '{b} \n{c} {d}%'
          color: "transparent",
          position: "outside",
          formatter: "{b} \n{c} {d}%",
        },
        xAxis3D: {
          min: -1,
          max: 1
          max: 1,
        },
        yAxis3D: {
          min: -1,
          max: 1
          max: 1,
        },
        zAxis3D: {
          min: -1,
          max: 1
          max: 1,
        },
        grid3D: {
          show: false,
          boxHeight: 2,
          bottom: '-10%',
          left: '-15%',
          bottom: "-10%",
          left: "-15%",
          viewControl: {
            alpha: 18,
            beta: 50,
@@ -1694,32 +1680,32 @@
            autoRotate: true,
            rotateSensitivity: 0,
            zoomSensitivity: 0,
            panSensitivity: 0
          }
            panSensitivity: 0,
          },
        },
        series: series
      }
        series: series,
      };
      this._pie.clear()
      this._pie.setOption(option)
      this._pie.clear();
      this._pie.setOption(option);
      // 鼠标事件交互
      let selectedIndex = ''
      let hoveredIndex = ''
      let selectedIndex = "";
      let hoveredIndex = "";
      this._pie.on('click', (params) => {
        if (params.seriesName === 'mouseoutSeries') return
        const s = option.series[params.seriesIndex]
        if (!s || !s.pieData || !s.pieStatus) return
      this._pie.on("click", (params) => {
        if (params.seriesName === "mouseoutSeries") return;
        const s = option.series[params.seriesIndex];
        if (!s || !s.pieData || !s.pieStatus) return;
        const isSelected = !s.pieStatus.selected
        const isHovered = s.pieStatus.hovered
        const k = s.pieStatus.k
        const startRatio = s.pieData.startRatio
        const endRatio = s.pieData.endRatio
        const isSelected = !s.pieStatus.selected;
        const isHovered = s.pieStatus.hovered;
        const k = s.pieStatus.k;
        const startRatio = s.pieData.startRatio;
        const endRatio = s.pieData.endRatio;
        if (selectedIndex !== '' && selectedIndex !== params.seriesIndex) {
          const prev = option.series[selectedIndex]
        if (selectedIndex !== "" && selectedIndex !== params.seriesIndex) {
          const prev = option.series[selectedIndex];
          if (prev && prev.pieData && prev.pieStatus) {
            prev.parametricEquation = this.getParametricEquation(
              prev.pieData.startRatio,
@@ -1728,8 +1714,8 @@
              false,
              k,
              prev.pieData.value
            )
            prev.pieStatus.selected = false
            );
            prev.pieStatus.selected = false;
          }
        }
@@ -1740,21 +1726,21 @@
          isHovered,
          k,
          s.pieData.value
        )
        s.pieStatus.selected = isSelected
        if (isSelected) selectedIndex = params.seriesIndex
        );
        s.pieStatus.selected = isSelected;
        if (isSelected) selectedIndex = params.seriesIndex;
        this._pie.setOption(option)
      })
        this._pie.setOption(option);
      });
      this._pie.on('mouseover', (params) => {
        if (hoveredIndex === params.seriesIndex) return
      this._pie.on("mouseover", (params) => {
        if (hoveredIndex === params.seriesIndex) return;
        // 取消之前的高亮
        if (hoveredIndex !== '') {
          let prev = option.series[hoveredIndex]
        if (hoveredIndex !== "") {
          let prev = option.series[hoveredIndex];
          if (prev && prev.pieData && prev.pieStatus) {
            const k = prev.pieStatus.k
            const k = prev.pieStatus.k;
            prev.parametricEquation = this.getParametricEquation(
              prev.pieData.startRatio,
              prev.pieData.endRatio,
@@ -1762,17 +1748,17 @@
              false,
              k,
              prev.pieData.value
            )
            prev.pieStatus.hovered = false
            hoveredIndex = ''
            );
            prev.pieStatus.hovered = false;
            hoveredIndex = "";
          }
        }
        // 当前高亮(排除透明圆环)
        if (params.seriesName !== 'mouseoutSeries') {
          let cur = option.series[params.seriesIndex]
        if (params.seriesName !== "mouseoutSeries") {
          let cur = option.series[params.seriesIndex];
          if (cur && cur.pieData && cur.pieStatus) {
            const k = cur.pieStatus.k
            const k = cur.pieStatus.k;
            cur.parametricEquation = this.getParametricEquation(
              cur.pieData.startRatio,
              cur.pieData.endRatio,
@@ -1780,20 +1766,20 @@
              true,
              k,
              cur.pieData.value
            )
            cur.pieStatus.hovered = true
            hoveredIndex = params.seriesIndex
            );
            cur.pieStatus.hovered = true;
            hoveredIndex = params.seriesIndex;
          }
        }
        this._pie.setOption(option)
      })
        this._pie.setOption(option);
      });
      this._pie.on('globalout', () => {
        if (hoveredIndex !== '') {
          let prev = option.series[hoveredIndex]
      this._pie.on("globalout", () => {
        if (hoveredIndex !== "") {
          let prev = option.series[hoveredIndex];
          if (prev && prev.pieData && prev.pieStatus) {
            const k = prev.pieStatus.k
            const k = prev.pieStatus.k;
            prev.parametricEquation = this.getParametricEquation(
              prev.pieData.startRatio,
              prev.pieData.endRatio,
@@ -1801,23 +1787,23 @@
              false,
              k,
              prev.pieData.value
            )
            prev.pieStatus.hovered = false
            hoveredIndex = ''
            this._pie.setOption(option)
            );
            prev.pieStatus.hovered = false;
            hoveredIndex = "";
            this._pie.setOption(option);
          }
        }
      })
      });
    },
    // 生成随机颜色
    generateRandomColor () {
      const h = Math.floor(Math.random() * 360)
      const s = Math.floor(Math.random() * 30) + 60 // 60-90%
      const l = Math.floor(Math.random() * 20) + 50 // 50-70%
      return `hsl(${h}, ${s}%, ${l}%)`
    generateRandomColor() {
      const h = Math.floor(Math.random() * 360);
      const s = Math.floor(Math.random() * 30) + 60; // 60-90%
      const l = Math.floor(Math.random() * 20) + 50; // 50-70%
      return `hsl(${h}, ${s}%, ${l}%)`;
    },
    // 生成扇形的曲面参数方程
    getParametricEquation (
    getParametricEquation(
      startRatio,
      endRatio,
      isSelected,
@@ -1826,135 +1812,135 @@
      height
    ) {
      // 计算
      let midRatio = (startRatio + endRatio) / 2
      let midRatio = (startRatio + endRatio) / 2;
      let startRadian = startRatio * Math.PI * 2
      let endRadian = endRatio * Math.PI * 2
      let midRadian = midRatio * Math.PI * 2
      let startRadian = startRatio * Math.PI * 2;
      let endRadian = endRatio * Math.PI * 2;
      let midRadian = midRatio * Math.PI * 2;
      // 如果只有一个扇形,则不实现选中效果。
      if (startRatio === 0 && endRatio === 1) {
        isSelected = false
        isSelected = false;
      }
      // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)
      k = typeof k !== 'undefined' ? k : 1 / 3
      k = typeof k !== "undefined" ? k : 1 / 3;
      // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)
      let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0
      let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0
      let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
      let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
      // 计算高亮效果的放大比例(未高亮,则比例为 1)
      let hoverRate = isHovered ? 1.05 : 1
      let hoverRate = isHovered ? 1.05 : 1;
      // 返回曲面参数方程
      return {
        u: {
          min: -Math.PI,
          max: Math.PI * 3,
          step: Math.PI / 32
          step: Math.PI / 32,
        },
        v: {
          min: 0,
          max: Math.PI * 2,
          step: Math.PI / 20
          step: Math.PI / 20,
        },
        x: function (u, v) {
          if (u < startRadian) {
            return (
              offsetX +
              Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate
            )
            );
          }
          if (u > endRadian) {
            return (
              offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate
            )
            );
          }
          return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate
          return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
        },
        y: function (u, v) {
          if (u < startRadian) {
            return (
              offsetY +
              Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate
            )
            );
          }
          if (u > endRadian) {
            return (
              offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate
            )
            );
          }
          return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate
          return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
        },
        z: function (u, v) {
          if (u < -Math.PI * 0.5) {
            return Math.sin(u)
            return Math.sin(u);
          }
          if (u > Math.PI * 2.5) {
            return Math.sin(u)
            return Math.sin(u);
          }
          return Math.sin(v) > 0 ? 0.6 * height : -0.6
        }
      }
          return Math.sin(v) > 0 ? 0.6 * height : -0.6;
        },
      };
    },
    // 生成模拟 3D 饼图的配置项
    getPie3D (pieData, internalDiameterRatio) {
      let series = []
      let sumValue = 0
      let startValue = 0
      let endValue = 0
      let legendData = []
    getPie3D(pieData, internalDiameterRatio) {
      let series = [];
      let sumValue = 0;
      let startValue = 0;
      let endValue = 0;
      let legendData = [];
      let k =
        typeof internalDiameterRatio !== 'undefined'
        typeof internalDiameterRatio !== "undefined"
          ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio)
          : 1 / 3
          : 1 / 3;
      // 为每一个饼图数据,生成一个 series-surface 配置
      for (let i = 0; i < pieData.length; i++) {
        sumValue += pieData[i].value
        sumValue += pieData[i].value;
        let seriesItem = {
          name:
            typeof pieData[i].name === 'undefined'
            typeof pieData[i].name === "undefined"
              ? `series${i}`
              : pieData[i].name,
          type: 'surface',
          type: "surface",
          parametric: true,
          wireframe: {
            show: false
            show: false,
          },
          pieData: pieData[i],
          pieStatus: {
            selected: false,
            hovered: false,
            k: k
          }
        }
            k: k,
          },
        };
        if (typeof pieData[i].itemStyle !== 'undefined') {
          let itemStyle = {}
        if (typeof pieData[i].itemStyle !== "undefined") {
          let itemStyle = {};
          typeof pieData[i].itemStyle.color !== 'undefined'
          typeof pieData[i].itemStyle.color !== "undefined"
            ? (itemStyle.color = pieData[i].itemStyle.color)
            : null
          typeof pieData[i].itemStyle.opacity !== 'undefined'
            : null;
          typeof pieData[i].itemStyle.opacity !== "undefined"
            ? (itemStyle.opacity = pieData[i].itemStyle.opacity)
            : null
            : null;
          seriesItem.itemStyle = itemStyle
          seriesItem.itemStyle = itemStyle;
        }
        series.push(seriesItem)
        series.push(seriesItem);
      }
      // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
      // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
      for (let i = 0; i < series.length; i++) {
        endValue = startValue + series[i].pieData.value
        endValue = startValue + series[i].pieData.value;
        series[i].pieData.startRatio = startValue / sumValue
        series[i].pieData.endRatio = endValue / sumValue
        series[i].pieData.startRatio = startValue / sumValue;
        series[i].pieData.endRatio = endValue / sumValue;
        series[i].parametricEquation = this.getParametricEquation(
          series[i].pieData.startRatio,
          series[i].pieData.endRatio,
@@ -1962,11 +1948,11 @@
          false,
          k,
          series[i].pieData.value
        )
        );
        startValue = endValue
        startValue = endValue;
        legendData.push(series[i].name)
        legendData.push(series[i].name);
      }
      // series.push({
      //   name: 'mouseoutSeries',
@@ -2001,343 +1987,343 @@
      //     },
      //   },
      // });
      return series
      return series;
    },
    // 风险等级转换为数值 (A->3, B->2, C->1)
    levelToValue (level) {
      if (!level) return null
      const levelStr = String(level).toUpperCase().trim()
    levelToValue(level) {
      if (!level) return null;
      const levelStr = String(level).toUpperCase().trim();
      // 处理 A、B、C 或 A类、B类、C类
      if (levelStr === 'A' || levelStr === 'A类') return 3
      if (levelStr === 'B' || levelStr === 'B类') return 2
      if (levelStr === 'C' || levelStr === 'C类') return 1
      if (levelStr === "A" || levelStr === "A类") return 3;
      if (levelStr === "B" || levelStr === "B类") return 2;
      if (levelStr === "C" || levelStr === "C类") return 1;
      return null
      return null;
    },
    // 数值转换为风险等级显示 (3->A类, 2->B类, 1->C类)
    valueToLevel (value) {
      if (value === 3) return 'A类'
      if (value === 2) return 'B类'
      if (value === 1) return 'C类'
      return ''
    valueToLevel(value) {
      if (value === 3) return "A类";
      if (value === 2) return "B类";
      if (value === 1) return "C类";
      return "";
    },
    // 获取项目风险趋势数据
    async getProjectRiskTrend () {
    async getProjectRiskTrend() {
      if (!this.dateRange || this.dateRange.length !== 2) {
        return
        return;
      }
      const params = {
        projectId: this.projectId,
        startTime: moment(this.dateRange[0]).format('YYYY-MM'),
        endTime: moment(this.dateRange[1]).format('YYYY-MM')
      }
        startTime: moment(this.dateRange[0]).format("YYYY-MM"),
        endTime: moment(this.dateRange[1]).format("YYYY-MM"),
      };
      try {
        const res = await getProjectDangerousTrend(params)
        const res = await getProjectDangerousTrend(params);
        if (res && Array.isArray(res)) {
          // 处理接口返回的数据
          this.riskTrendData.xAxisData = res.map((item) => item.time || '')
          this.riskTrendData.xAxisData = res.map((item) => item.time || "");
          // 将A、B、C转换为数值 3、2、1
          this.riskTrendData.seriesData = res.map((item) => {
            const value = this.levelToValue(item.level)
            const value = this.levelToValue(item.level);
            return value
          })
          this.riskTrendData.statusData = res.map((item) => item.status)
            return value;
          });
          this.riskTrendData.statusData = res.map((item) => item.status);
          // 更新图表
          this.updateRiskChart()
          this.updateRiskChart();
        }
      } catch (error) {
        console.error('获取项目风险趋势失败:', error)
        console.error("获取项目风险趋势失败:", error);
        // 设置默认值,确保图表可以正常显示
        this.riskTrendData.xAxisData = []
        this.riskTrendData.seriesData = []
        this.riskTrendData.statusData = []
        this.riskTrendData.xAxisData = [];
        this.riskTrendData.seriesData = [];
        this.riskTrendData.statusData = [];
      }
    },
    // 更新风险趋势图表
    updateRiskChart () {
      const chartDom = document.getElementById('riskTrendChart')
    updateRiskChart() {
      const chartDom = document.getElementById("riskTrendChart");
      if (!chartDom) {
        console.warn('风险趋势图表DOM不存在,可能是权限限制导致该模块未渲染')
        return
        console.warn("风险趋势图表DOM不存在,可能是权限限制导致该模块未渲染");
        return;
      }
      const riskChart = echarts.getInstanceByDom(chartDom)
      const riskChart = echarts.getInstanceByDom(chartDom);
      if (!riskChart) {
        console.warn('风险趋势图表实例不存在')
        return
        console.warn("风险趋势图表实例不存在");
        return;
      }
      // 文本换行处理函数
      const formatLabel = (text, maxWidth = 4) => {
        if (!text) return ''
        const textStr = String(text)
        if (!text) return "";
        const textStr = String(text);
        // 如果文本长度超过最大宽度,进行换行
        if (textStr.length > maxWidth) {
          let result = ''
          let result = "";
          for (let i = 0; i < textStr.length; i += maxWidth) {
            result += textStr.substring(i, i + maxWidth) + '\n'
            result += textStr.substring(i, i + maxWidth) + "\n";
          }
          return result.trim()
          return result.trim();
        }
        return textStr
      }
        return textStr;
      };
      const self = this
      const self = this;
      const option = {
        tooltip: {
          trigger: 'axis',
          trigger: "axis",
          show: true,
          backgroundColor: 'rgba(0, 0, 0, 0.7)',
          borderColor: '#32C5FF',
          backgroundColor: "rgba(0, 0, 0, 0.7)",
          borderColor: "#32C5FF",
          borderWidth: 1,
          textStyle: {
            color: '#fff',
            fontSize: 12
            color: "#fff",
            fontSize: 12,
          },
          formatter: function (params) {
            if (params && params.length > 0) {
              const param = params[0]
              const levelText = self.valueToLevel(param.value)
              return `${param.name}<br/>${param.seriesName}: ${levelText}`
              const param = params[0];
              const levelText = self.valueToLevel(param.value);
              return `${param.name}<br/>${param.seriesName}: ${levelText}`;
            }
            return ''
          }
            return "";
          },
        },
        legend: {
          show: false
          show: false,
        },
        grid: {
          top: '10%',
          bottom: '10%',
          left: '10%',
          right: '5%',
          containLabel: true
          top: "10%",
          bottom: "10%",
          left: "10%",
          right: "5%",
          containLabel: true,
        },
        xAxis: {
          data: this.riskTrendData.xAxisData,
          axisTick: { show: true, alignWithLabel: true },
          axisLine: {
            lineStyle: {
              color: '#666'
            }
              color: "#666",
            },
          },
          axisLabel: {
            color: (value, index) => {
              const status =
                Array.isArray(this.riskTrendData.statusData) &&
                typeof index === 'number'
                typeof index === "number"
                  ? this.riskTrendData.statusData[index]
                  : undefined
              return Number(status) === 2 ? '#999' : '#fff'
                  : undefined;
              return Number(status) === 2 ? "#999" : "#fff";
            },
            fontSize: 12,
            interval: 0,
            rotate: 0,
            formatter: function (value) {
              return formatLabel(value, 7)
              return formatLabel(value, 7);
            },
            align: 'center',
            verticalAlign: 'top',
            align: "center",
            verticalAlign: "top",
            lineHeight: 14,
            width: 60,
            overflow: 'break'
          }
            overflow: "break",
          },
        },
        yAxis: {
          type: 'value',
          type: "value",
          min: 1,
          max: 3,
          interval: 1,
          splitLine: {
            show: true,
            lineStyle: {
              type: 'dashed',
              color: 'rgba(255, 255, 255, .2)'
            }
              type: "dashed",
              color: "rgba(255, 255, 255, .2)",
            },
          },
          axisLine: {
            show: false
            show: false,
          },
          axisTick: {
            show: false
            show: false,
          },
          axisLabel: {
            color: '#fff',
            color: "#fff",
            fontSize: 12,
            formatter: function (value) {
              // Y轴自定义显示:1->C类, 2->B类, 3->A类
              if (value === 1) return 'C类'
              if (value === 2) return 'B类'
              if (value === 3) return 'A类'
              return ''
              if (value === 1) return "C类";
              if (value === 2) return "B类";
              if (value === 3) return "A类";
              return "";
            },
            align: 'right',
            verticalAlign: 'middle',
            align: "right",
            verticalAlign: "middle",
            lineHeight: 14,
            width: 30
          }
            width: 30,
          },
        },
        series: [
          {
            name: '风险等级',
            type: 'line',
            name: "风险等级",
            type: "line",
            data: this.riskTrendData.seriesData,
            smooth: false,
            showSymbol: true,
            symbol: 'circle',
            symbol: "circle",
            symbolSize: 8,
            itemStyle: {
              color: '#32C5FF',
              borderColor: '#32C5FF',
              borderWidth: 2
              color: "#32C5FF",
              borderColor: "#32C5FF",
              borderWidth: 2,
            },
            lineStyle: {
              width: 5,
              color: {
                type: 'linear',
                type: "linear",
                x: 0,
                y: 0,
                x2: 1,
                y2: 0,
                colorStops: [
                  { offset: 0, color: 'rgba(36, 81, 242, 1)' },
                  { offset: 0.5, color: 'rgba(11, 204, 254, 1)' },
                  { offset: 1, color: 'rgba(199, 160, 254, 1)' }
                ]
              }
            }
          }
        ]
      }
                  { offset: 0, color: "rgba(36, 81, 242, 1)" },
                  { offset: 0.5, color: "rgba(11, 204, 254, 1)" },
                  { offset: 1, color: "rgba(199, 160, 254, 1)" },
                ],
              },
            },
          },
        ],
      };
      riskChart.setOption(option)
      riskChart.setOption(option);
    },
    // 初始化折线图
    initRiskChart () {
      const chartDom = document.getElementById('riskTrendChart')
    initRiskChart() {
      const chartDom = document.getElementById("riskTrendChart");
      if (!chartDom) {
        console.warn('风险趋势图表DOM不存在,可能是权限限制导致该模块未渲染')
        return
        console.warn("风险趋势图表DOM不存在,可能是权限限制导致该模块未渲染");
        return;
      }
      const riskChart = echarts.init(chartDom)
      const riskChart = echarts.init(chartDom);
      // 文本换行处理函数
      const formatLabel = (text, maxWidth = 4) => {
        if (!text) return ''
        const textStr = String(text)
        if (!text) return "";
        const textStr = String(text);
        // 如果文本长度超过最大宽度,进行换行
        if (textStr.length > maxWidth) {
          let result = ''
          let result = "";
          for (let i = 0; i < textStr.length; i += maxWidth) {
            result += textStr.substring(i, i + maxWidth) + '\n'
            result += textStr.substring(i, i + maxWidth) + "\n";
          }
          return result.trim()
          return result.trim();
        }
        return textStr
      }
        return textStr;
      };
      let option = {
        tooltip: {
          trigger: 'axis',
          show: false
          trigger: "axis",
          show: false,
        },
        legend: {
          show: false
          show: false,
        },
        grid: {
          top: '5%',
          bottom: '5%',
          left: '5%',
          right: '5%',
          containLabel: true
          top: "5%",
          bottom: "5%",
          left: "5%",
          right: "5%",
          containLabel: true,
        },
        xAxis: {
          data:
            this.riskTrendData.xAxisData.length > 0
              ? this.riskTrendData.xAxisData
              : [
                '2025年1月检查',
                '2025年2月检查',
                '2025年3月检查',
                '2025年4月检查',
                '2025年5月检查'
              ],
                  "2025年1月检查",
                  "2025年2月检查",
                  "2025年3月检查",
                  "2025年4月检查",
                  "2025年5月检查",
                ],
          axisTick: { show: true, alignWithLabel: true },
          axisLine: {
            lineStyle: {
              color: '#666'
            }
              color: "#666",
            },
          },
          axisLabel: {
            color: (value, index) => {
              const status =
                Array.isArray(this.riskTrendData.statusData) &&
                typeof index === 'number'
                typeof index === "number"
                  ? this.riskTrendData.statusData[index]
                  : undefined
              return Number(status) === 2 ? '#999' : '#fff'
                  : undefined;
              return Number(status) === 2 ? "#999" : "#fff";
            },
            fontSize: 12,
            interval: 0, // 强制显示所有标签
            rotate: 0, // 不旋转
            formatter: function (value) {
              // X轴标签格式化,最多7个字符,超出换行
              return formatLabel(value, 7)
              return formatLabel(value, 7);
            },
            // 文本对齐方式
            align: 'center',
            verticalAlign: 'top',
            align: "center",
            verticalAlign: "top",
            lineHeight: 14,
            // 设置标签的最大宽度
            width: 60,
            overflow: 'break' // 超出换行
          }
            overflow: "break", // 超出换行
          },
        },
        yAxis: {
          type: 'value',
          type: "value",
          min: 1,
          max: 3,
          interval: 1,
          splitLine: {
            show: true,
            lineStyle: {
              type: 'dashed', // 虚线
              color: 'rgba(255, 255, 255, .2)' // 固定灰色
            }
              type: "dashed", // 虚线
              color: "rgba(255, 255, 255, .2)", // 固定灰色
            },
          },
          axisLine: {
            show: false
            show: false,
          },
          axisTick: {
            show: false
            show: false,
          },
          axisLabel: {
            color: '#fff',
            color: "#fff",
            fontSize: 12,
            formatter: function (value) {
              // Y轴自定义显示:1->C类, 2->B类, 3->A类
              if (value === 1) return 'C类'
              if (value === 2) return 'B类'
              if (value === 3) return 'A类'
              return ''
              if (value === 1) return "C类";
              if (value === 2) return "B类";
              if (value === 3) return "A类";
              return "";
            },
            // 文本对齐方式
            align: 'right',
            verticalAlign: 'middle',
            align: "right",
            verticalAlign: "middle",
            lineHeight: 14,
            // 设置标签的最大宽度
            width: 30
          }
            width: 30,
          },
        },
        series: [
          {
            name: '风险等级',
            type: 'line',
            name: "风险等级",
            type: "line",
            data:
              this.riskTrendData.seriesData.length > 0
                ? this.riskTrendData.seriesData
@@ -2347,35 +2333,35 @@
            lineStyle: {
              width: 5, // 线条宽度
              color: {
                type: 'linear',
                type: "linear",
                x: 0,
                y: 0,
                x2: 1,
                y2: 0,
                colorStops: [
                  { offset: 0, color: 'rgba(36, 81, 242, 1)' }, // 起始颜色
                  { offset: 0.5, color: 'rgba(11, 204, 254, 1)' }, // 中间颜色
                  { offset: 1, color: 'rgba(199, 160, 254, 1)' } // 结束颜色
                ]
              }
            }
          }
        ]
      }
      riskChart.setOption(option)
                  { offset: 0, color: "rgba(36, 81, 242, 1)" }, // 起始颜色
                  { offset: 0.5, color: "rgba(11, 204, 254, 1)" }, // 中间颜色
                  { offset: 1, color: "rgba(199, 160, 254, 1)" }, // 结束颜色
                ],
              },
            },
          },
        ],
      };
      riskChart.setOption(option);
    },
    // 处理风险趋势时间选择器点击
    handleRiskPickerClick () {
      this.$refs.riskDatePicker.focus()
    handleRiskPickerClick() {
      this.$refs.riskDatePicker.focus();
    },
    toRiskTrend () {
    toRiskTrend() {
      this.$router.push({
        path: '/subentry',
        query: { projectId: this.projectId, projectName: this.projectName }
      })
    }
  }
}
        path: "/subentry",
        query: { projectId: this.projectId, projectName: this.projectName },
      });
    },
  },
};
</script>
<style lang="less" scoped>
@@ -2875,7 +2861,6 @@
      }
      .mid-img {
        width: 90px;
        height: 90px;
        margin-right: 20px;