董国庆
2026-06-11 0aa66dcedffba1073dc51b1a3ab558cd1ffbf197
screen/src/view/projectHome/index.vue
@@ -106,70 +106,60 @@
                "
              >
                <div class="flex2 flex">
                  <div class="label dept">
                    设备租赁单位
                    <el-tooltip
                      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 class="label dept">设备租赁单位</div>
                  <div class="value" v-if="filteredRentalUnits.length >= 1">
                    {{ 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>
                      </div>
                      <span class="count-badge">{{
                        filteredRentalUnits.length
                      }}</span>
                    </el-tooltip>
                  </div>
                  <div class="value" v-if="filteredProperties.length ==1">
                    {{
                      filteredProperties[0][
                        "工程起重机械租赁单位"
                      ] || "-"
                    }}
                  </div>
                    </div>
                    <span class="count-badge">{{
                      filteredRentalUnits.length
                    }}</span>
                  </el-tooltip>
                </div>
                <div class="flex1 flex">
                  <div class="label">
                    联系人
                    <el-tooltip
                      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 class="label">联系人</div>
                  <div class="value" v-if="filteredContacts.length >= 1">
                    {{ 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>
                      </div>
                      <span class="count-badge">{{
                        filteredContacts.length
                      }}</span>
                    </el-tooltip>
                  </div>
                  <div class="value" v-if="filteredContacts.length ==1">
                    {{
                      filteredProperties[0]["联系电话"] || "-"
                    }}
                  </div>
                    </div>
                    <span class="count-badge">{{
                      filteredContacts.length
                    }}</span>
                  </el-tooltip>
                </div>
              </div>
              <div class="info-item11">
@@ -334,14 +324,29 @@
        <div class="flex a--center">
          <div @click.stop="toHiddenDanger(2)" class="mid-title">隐患数量</div>
          <div class="flex a--center tab-border">
            <div class="mid-tab">所有隐患数</div>
            <div class="mid-tab active-tab">重大隐患数</div>
            <div
              class="mid-tab"
              :class="{ 'active-tab': dangerCountTab === 'all' }"
              @click.stop="handleDangerTabChange('all')"
            >
              所有隐患数
            </div>
            <div
              class="mid-tab"
              :class="{ 'active-tab': dangerCountTab === 'serious' }"
              @click.stop="handleDangerTabChange('serious')"
            >
              重大隐患数
            </div>
          </div>
        </div>
        <div class="mid-content">
        <div
          class="mid-content"
          :class="{ 'mid-content-switching': dangerCountLoading }"
        >
          <div class="mid-img">
            <div class="number">{{ dangerCount.serious || 0 }}</div>
            <div class="name">所有隐患数</div>
            <div class="name">{{ dangerCountTabName }}</div>
          </div>
          <div class="mid-total">
            <div class="mid-item">
@@ -603,6 +608,7 @@
  getProjectDetail,
  getProjectDeviceCount,
  getDangerCount,
  getDangerCountAll,
  deviceTypes,
  getProjectPersonInfo,
  getProjectSource,
@@ -610,6 +616,7 @@
  getProjectDangerousTrend,
  getProjectLatestProgress
} from './service.js'
import { transformRiskSourceData } from '@/utils/riskSourceMap.js'
import * as echarts from 'echarts'
export default {
@@ -646,6 +653,13 @@
        rectified: 0,
        unRectified: 0
      }, // 危险源统计
      dangerCountTab: 'serious',
      dangerCountLoading: false,
      dangerCountCache: {
        all: null,
        serious: null
      },
      deviceTypeList: [], // 设备类型列表
      equipment: 0, // 设备数量
      peopleList: [], // 人员列表
@@ -683,7 +697,11 @@
    }
  },
  computed: {
    dangerCountTabName () {
      return this.dangerCountTab === 'all' ? '所有隐患数' : '重大隐患数'
    },
    // 处理风险源数据,添加合并单元格的逻辑
    riskSourceList () {
      if (!this.riskSourceData || this.riskSourceData.length === 0) {
        return []
@@ -772,20 +790,15 @@
      this.projectInfo.properties.forEach((itemStr) => {
        try {
          const item = JSON.parse(itemStr)
          console.log('item item', item)
          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) {
        }
          list.push({ 工程起重机械租赁单位: rentalUnit })
        } catch (e) {}
      })
      console.log('1111111111111', list)
      return list
    },
    filteredContacts () {
@@ -802,16 +815,14 @@
      this.projectInfo.properties.forEach((itemStr) => {
        try {
          const item = JSON.parse(itemStr)
          const contact = item['联系电话']
          if (!contact) return
          const key = String(contact).trim()
          const name = item['联系人']
          if (!name) return
          const key = String(name).trim()
          if (!key) return
          if (seen.has(key)) return
          seen.add(key)
          list.push({ '联系电话': contact })
        } catch (e) {
        }
          list.push({ 联系人: name })
        } catch (e) {}
      })
      return list
@@ -835,10 +846,14 @@
    }
  },
  created () {
    this.mapPromise = AMapLoader.load({
      key: '232929db1cb31f26d42b3645a7456154',
    const loader =
      window.AMapLoader ||
      (typeof AMapLoader !== 'undefined' ? AMapLoader : null)
    if (!loader) return
    this.mapPromise = loader.load({
      key: '6edc6798d22e5a46660ff46560b1e612',
      version: '2.0',
      zoom: 25
      plugins: ['AMap.Geocoder']
    })
    if (this.$route.query.projectId) {
      this.projectId = this.$route.query.projectId || ''
@@ -899,6 +914,7 @@
    }
  },
  beforeDestroy () {
    this._mapDestroyed = true
    if (this._mapResizeHandler) {
      window.removeEventListener('resize', this._mapResizeHandler)
      this._mapResizeHandler = null
@@ -989,7 +1005,7 @@
            url = id
          } else {
            // 否则拼接为下载URL
            url = `${this.VUE_APP_BASE_URL}/project/download/${id}`
            url = `${this.VUE_APP_BASE_URL}/public/file/download/${id}`
          }
          // 先尝试从扩展名判断
@@ -1066,8 +1082,49 @@
      console.error('视频加载失败:', e)
      // 可以在这里添加视频加载失败的处理逻辑
    },
    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
      }
    },
    async loadDangerCount (tab = this.dangerCountTab, force = false) {
      const cacheData = this.dangerCountCache[tab]
      if (!force && cacheData) {
        this.dangerCount = { ...cacheData }
        return
      }
      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 }
      } catch (err) {
        console.error(
          `获取${tab === 'all' ? '所有隐患数量' : '重大隐患数量'}失败:`,
          err
        )
        this.dangerCount = this.normalizeDangerCount()
      } finally {
        this.dangerCountLoading = false
      }
    },
    handleDangerTabChange (tab) {
      if (this.dangerCountTab === tab) return
      this.dangerCountTab = tab
      this.loadDangerCount(tab)
    },
    // 获取项目详情
    getDetail () {
      this.dangerCountCache = {
        all: null,
        serious: null
      }
      // 设备类型 - 添加错误处理
      deviceTypes()
        .then((res) => {
@@ -1148,21 +1205,10 @@
          this.legendData = []
        })
      // 隐患数量 - 添加错误处理
      getDangerCount(this.projectId)
        .then((res) => {
          this.dangerCount = res
        })
        .catch((err) => {
          console.error('获取隐患数量失败:', err)
          this.dangerCount = {
            serious: 0,
            rectified: 0,
            unRectified: 0
          }
        })
      this.loadDangerCount(this.dangerCountTab, true)
      // 项目人员信息 - 添加错误处理
      getProjectPersonInfo({ projectId: this.projectId })
        .then((res) => {
          this.peopleList = res || []
@@ -1320,9 +1366,16 @@
    },
    setMapload () {
      if (!this.mapPromise) {
        this.mapPromise = AMapLoader.load({
          key: '232929db1cb31f26d42b3645a7456154',
          version: '2.0'
        const loader =
          window.AMapLoader ||
          (typeof AMapLoader !== 'undefined' ? AMapLoader : null)
        if (!loader) {
          return Promise.reject(new Error('AMapLoader is not available'))
        }
        this.mapPromise = loader.load({
          key: '6edc6798d22e5a46660ff46560b1e612',
          version: '2.0',
          plugins: ['AMap.Geocoder']
        })
      }
      if (this._mapInitPromise) {
@@ -1331,6 +1384,7 @@
      this._mapInitPromise = this.mapPromise
        .then((AMap) => {
          if (this._mapDestroyed) return AMap
          this._AMap = AMap
          if (this.mapView) {
@@ -1345,6 +1399,7 @@
          }
          const satellite = new AMap.TileLayer.Satellite()
          const roadNet = new AMap.TileLayer.RoadNet()
          // 获取经纬度
          let center = [104.065617, 30.65695] // 默认中心点
@@ -1355,15 +1410,20 @@
            longitude = Number(this.projectInfo.addressInfo.longitude)
            latitude = Number(this.projectInfo.addressInfo.latitude)
            if (!isNaN(longitude) && !isNaN(latitude) && longitude !== 0 && latitude !== 0) {
            if (
              !isNaN(longitude) &&
              !isNaN(latitude) &&
              longitude !== 0 &&
              latitude !== 0
            ) {
              center = [longitude, latitude]
            }
          }
          this.mapView = new AMap.Map('projectContainer', {
            zoom: 17,
            zoom: 16,
            center: center,
            layers: [satellite]
            layers: [satellite, roadNet]
          })
          this.mapView.resize()
@@ -1395,12 +1455,12 @@
      // 根据项目类型选择图标
      const iconImages = [
        require('../../assets/img/home/f4.png'),
        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[this.projectInfo.type] || iconImages[0];
      const iconImage = iconImages[0]
      const tryRenderMarker = (lng, lat) => {
        if (
@@ -1421,11 +1481,11 @@
            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
            offset: new AMap.Pixel(-30, -30),
            zoom: 16
          })
          this.mapView.add(this.currentMarker)
        } else if (typeof this.currentMarker.setPosition === 'function') {
@@ -1440,18 +1500,18 @@
              imageSize: new AMap.Size(30, 30)
            }),
            offset: new AMap.Pixel(-15, -15),
            zoom: 17
            zoom: 16
          })
          this.mapView.add(this.currentMarker)
        }
        if (typeof this.mapView.setZoomAndCenter === 'function') {
          if (!this._lastMarkerPosKey) {
            this.mapView.setZoomAndCenter(17, [lng, lat])
            this.mapView.setZoomAndCenter(16, [lng, lat])
          } else if (typeof this.mapView.setCenter === 'function') {
            this.mapView.setCenter([lng, lat])
          } else {
            this.mapView.setZoomAndCenter(17, [lng, lat])
            this.mapView.setZoomAndCenter(16, [lng, lat])
          }
        }
        this._lastMarkerPosKey = nextKey
@@ -2777,14 +2837,24 @@
    .tab-border {
      border: 1px solid rgba(50, 197, 255, 0.22);
      border-radius: 4px;
      overflow: hidden;
    }
    .mid-tab {
      cursor: pointer;
      user-select: none;
      border-radius: 4px;
      padding: 6px 5px;
      padding: 6px 8px;
      font-weight: 400;
      font-size: 12px;
      color: #ffffff;
      transition: background 0.25s ease, box-shadow 0.25s ease,
        transform 0.25s ease;
      &:hover {
        background: rgba(6, 0, 228, 0.2);
      }
    }
    .active-tab {
@@ -2797,6 +2867,12 @@
      display: flex;
      align-items: center;
      justify-content: center;
      transition: opacity 0.25s ease, transform 0.25s ease;
      &.mid-content-switching {
        opacity: 0.68;
        transform: translateY(4px);
      }
      .mid-img {
        width: 90px;