董国庆
2026-06-11 0aa66dcedffba1073dc51b1a3ab558cd1ffbf197
screen/src/view/home/index.vue
@@ -743,39 +743,39 @@
</template>
<script>
import HeaderBox from "../header/index.vue";
import moment from "moment";
import s1 from "../../assets/img/home/s1.png";
import s2 from "../../assets/img/home/s2.png";
import s3 from "../../assets/img/home/s3.png";
import f1 from "../../assets/img/home/f1.png";
import f2 from "../../assets/img/home/f2.png";
import f3 from "../../assets/img/home/f3.png";
import z1 from "../../assets/img/home/assets1.png";
import z2 from "../../assets/img/home/assets2.png";
import z3 from "../../assets/img/home/assets3.png";
import s4 from "../../assets/img/home/s4.png";
import f4 from "../../assets/img/home/f4.png";
import z4 from "../../assets/img/home/z4.png";
import HeaderBox from '../header/index.vue'
import moment from 'moment'
import s1 from '../../assets/img/home/s1.png'
import s2 from '../../assets/img/home/s2.png'
import s3 from '../../assets/img/home/s3.png'
import f1 from '../../assets/img/home/f1.png'
import f2 from '../../assets/img/home/f2.png'
import f3 from '../../assets/img/home/f3.png'
import z1 from '../../assets/img/home/assets1.png'
import z2 from '../../assets/img/home/assets2.png'
import z3 from '../../assets/img/home/assets3.png'
import s4 from '../../assets/img/home/s4.png'
import f4 from '../../assets/img/home/f4.png'
import z4 from '../../assets/img/home/z4.png'
import {
  getStatistics,
  getStoryList,
  getProjectSelect,
  getWorkPresentationList,
  getprojectTooltip,
} from "./service";
import { getLoginInfo } from "../projectHome/service";
  getprojectTooltip
} from './service'
import { getLoginInfo } from '../projectHome/service'
export default {
  components: {
    HeaderBox,
    HeaderBox
  },
  data() {
  data () {
    return {
      mapView: null,
      mapPromise: null,
      dateRange: [moment().startOf("month"), moment().endOf("month")], // 默认本月
      dateTxt: "",
      dateRange: [moment().startOf('month'), moment().endOf('month')], // 默认本月
      dateTxt: '',
      activeTab: 1,
      scrollData: [], // 存储滚动数据
      scrollTimer: null, // 滚动定时器
@@ -785,638 +785,638 @@
      categoryFilter: {
        municipal: true,
        house: true,
        assets: true,
        assets: true
      },
      levelFilter: {
        A: true,
        B: true,
        C: true,
        C: true
      },
      markers: [],
      // 2项目总数(在建工程) 3大型机械设备数(在建工程) 4重大隐患数(在建工程) 5项目总数(固定资产) 6重大隐患数(固定资产) 7事故简讯 8工作展示
      permissionClient: JSON.parse(sessionStorage.getItem("permissionClient")),
      permissionClient: JSON.parse(sessionStorage.getItem('permissionClient')),
      // 9各分项隐患趋势 10隐患数量 11设备数量 12查看报告入口 13人员在岗率 14重大风险源 15 项目风险趋势
      permissionProject: JSON.parse(
        sessionStorage.getItem("permissionProject")
        sessionStorage.getItem('permissionProject')
      ),
      screenData: {},
      searchTabs: ["本周", "本月", "本季度", "本年"],
      activeTabs: "本年",
      searchTabs: ['本周', '本月', '本季度', '本年'],
      activeTabs: '本年',
      workListData: [],
      VUE_APP_IMAGE_BASE_URL:
        process.env.VUE_APP_IMAGE_BASE_URL + "/project/download/",
        process.env.VUE_APP_IMAGE_BASE_URL + '/public/file/download/',
      projectList: [],
      tooltipVisible: false,
      tooltipPos: { left: 0, top: 0 },
      tooltipData: {},
      tooltipLoading: false,
      tooltipError: false,
      boundaryPolygons: [],
    };
      boundaryPolygons: []
    }
  },
  watch: {
    dateRange: {
      handler(newVal, oldVal) {
      handler (newVal, oldVal) {
        if (newVal.length > 0) {
          this.dateTxt =
            moment(newVal[0]).format("YYYY年MM月DD日") +
            " ~ " +
            moment(newVal[1]).format("YYYY年MM月DD日");
            moment(newVal[0]).format('YYYY年MM月DD日') +
            ' ~ ' +
            moment(newVal[1]).format('YYYY年MM月DD日')
        } else {
          this.dateTxt = "";
          this.dateTxt = ''
        }
        this.$nextTick(() => {
          this.getScreenData();
        });
          this.getScreenData()
        })
      },
      immediate: true,
    },
      immediate: true
    }
  },
  created() {
  created () {
    if (this.$route.query.clientId) {
      // alert(this.$route.query.clientId)
      getLoginInfo({ id: this.$route.query.clientId, type: 1 }).then((r) => {
        if (r) {
          this.permissionProject =  r.permissionProject ? r.permissionProject.split(",") : [];
          this.permissionClient =  r.permissionClient ? r.permissionClient.split(",") : [];
          this.permissionProject = r.permissionProject ? r.permissionProject.split(',') : []
          this.permissionClient = r.permissionClient ? r.permissionClient.split(',') : []
          sessionStorage.setItem(
            "permissionClient",
            'permissionClient',
            JSON.stringify(
              r.permissionClient ? r.permissionClient.split(",") : []
              r.permissionClient ? r.permissionClient.split(',') : []
            )
          );
          )
          sessionStorage.setItem(
            "permissionProject",
            'permissionProject',
            JSON.stringify(
              r.permissionProject ? r.permissionProject.split(",") : []
              r.permissionProject ? r.permissionProject.split(',') : []
            )
          );
          sessionStorage.setItem("clientId", params.get("clientId"));
          sessionStorage.setItem("clientName", params.get("clientName"));
          sessionStorage.setItem("clientLogo", r.logo);
          sessionStorage.setItem("deviceTemplateName", r.deviceTemplateName); // 设备模板id
          sessionStorage.setItem("deviceTemplateId", r.deviceTemplateId); // 设备模板id
          sessionStorage.setItem("safetyId", r.safetyId); // 安全报告模板id
          sessionStorage.setItem("safetyName", r.safetyName); // 安全报告模板id
          sessionStorage.setItem("bigHiddenDanger", r.bigHiddenDanger); // 1开启 2关闭 重大隐患
          sessionStorage.setItem("generalHiddenDanger", r.generalHiddenDanger); // 1开启 2关闭 一般隐患
          sessionStorage.setItem("commentType", r.commentType); // 1模糊评价 2打分评价
          )
          sessionStorage.setItem('clientId', params.get('clientId'))
          sessionStorage.setItem('clientName', params.get('clientName'))
          sessionStorage.setItem('clientLogo', r.logo)
          sessionStorage.setItem('deviceTemplateName', r.deviceTemplateName) // 设备模板id
          sessionStorage.setItem('deviceTemplateId', r.deviceTemplateId) // 设备模板id
          sessionStorage.setItem('safetyId', r.safetyId) // 安全报告模板id
          sessionStorage.setItem('safetyName', r.safetyName) // 安全报告模板id
          sessionStorage.setItem('bigHiddenDanger', r.bigHiddenDanger) // 1开启 2关闭 重大隐患
          sessionStorage.setItem('generalHiddenDanger', r.generalHiddenDanger) // 1开启 2关闭 一般隐患
          sessionStorage.setItem('commentType', r.commentType) // 1模糊评价 2打分评价
        }
      });
      })
    }
    if (sessionStorage.getItem("activeTab")) {
      this.activeTab = Number(sessionStorage.getItem("activeTab"));
    if (sessionStorage.getItem('activeTab')) {
      this.activeTab = Number(sessionStorage.getItem('activeTab'))
    }
    this.mapPromise = window.AMapLoader.load({
      key: "232929db1cb31f26d42b3645a7456154",
      version: "2.0",
      plugins: ["AMap.DistrictSearch", "AMap.Geocoder"],
      key: '6edc6798d22e5a46660ff46560b1e612',
      version: '2.0',
      plugins: ['AMap.DistrictSearch', 'AMap.Geocoder'],
      AMapUI: {
        version: "1.1",
        plugins: ["geo/DistrictExplorer"],
      },
    });
    this.getStoryData();
        version: '1.1',
        plugins: ['geo/DistrictExplorer']
      }
    })
    this.getStoryData()
    getWorkPresentationList({
      clientId: sessionStorage.getItem("clientId"),
      clientId: sessionStorage.getItem('clientId'),
      state: 1,
      pageNum: 1,
      pageSize: 9999,
      pageSize: 9999
    }).then((res) => {
      this.workListData = res.records;
    });
      this.workListData = res.records
    })
  },
  mounted() {
  mounted () {
    this.$nextTick(() => {
      this.scrollContainer = this.$refs.scrollContainer;
    });
      this.scrollContainer = this.$refs.scrollContainer
    })
  },
  beforeDestroy() {
    sessionStorage.setItem("activeTab", this.activeTab);
    this.stopAutoScroll();
  beforeDestroy () {
    sessionStorage.setItem('activeTab', this.activeTab)
    this.stopAutoScroll()
    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
    }
  },
  methods: {
    handleTabClick(tab) {
      this.activeTabs = tab;
      this.getStoryData();
    handleTabClick (tab) {
      this.activeTabs = tab
      this.getStoryData()
    },
    changeTab(type) {
      if (this.activeTab === type) return;
      this.activeTab = type;
      this.getScreenData();
    changeTab (type) {
      if (this.activeTab === type) return
      this.activeTab = type
      this.getScreenData()
    },
    getStoryData() {
      let startTime = moment();
      let endTime = moment();
      if (this.activeTabs === "本周") {
        startTime = moment().startOf("isoWeek");
        endTime = moment().endOf("isoWeek");
      } else if (this.activeTabs === "本月") {
        startTime = moment().startOf("month");
        endTime = moment().endOf("month");
      } else if (this.activeTabs === "本季度") {
        startTime = moment().startOf("quarter");
        endTime = moment().endOf("quarter");
      } else if (this.activeTabs === "本年") {
        startTime = moment().startOf("year");
        endTime = moment().endOf("year");
    getStoryData () {
      let startTime = moment()
      let endTime = moment()
      if (this.activeTabs === '本周') {
        startTime = moment().startOf('isoWeek')
        endTime = moment().endOf('isoWeek')
      } else if (this.activeTabs === '本月') {
        startTime = moment().startOf('month')
        endTime = moment().endOf('month')
      } else if (this.activeTabs === '本季度') {
        startTime = moment().startOf('quarter')
        endTime = moment().endOf('quarter')
      } else if (this.activeTabs === '本年') {
        startTime = moment().startOf('year')
        endTime = moment().endOf('year')
      }
      let time =
        startTime.format("YYYY-MM-DD") + " - " + endTime.format("YYYY-MM-DD");
        startTime.format('YYYY-MM-DD') + ' - ' + endTime.format('YYYY-MM-DD')
      getStoryList({
        time: time,
        time: time
      }).then((res) => {
        this.scrollData = res;
        this.scrollData = res
        if (this.scrollData.length > 4) {
          this.initScrollData();
          this.initScrollData()
        }
      });
      })
    },
    getScreenData() {
    getScreenData () {
      let params = {
        projectCategory: ["ongoing", "fixed"][this.activeTab - 1],
        startDate: "",
        endDate: "",
        clientId: sessionStorage.getItem("clientId"),
      };
        projectCategory: ['ongoing', 'fixed'][this.activeTab - 1],
        startDate: '',
        endDate: '',
        clientId: sessionStorage.getItem('clientId')
      }
      if (this.dateRange.length) {
        params.startDate = moment(this.dateRange[0]).format("YYYY-MM-DD");
        params.endDate = moment(this.dateRange[1]).format("YYYY-MM-DD");
        params.startDate = moment(this.dateRange[0]).format('YYYY-MM-DD')
        params.endDate = moment(this.dateRange[1]).format('YYYY-MM-DD')
      }
      getProjectSelect(params).then((res) => {
        this.projectList = res;
      });
        this.projectList = res
      })
      getStatistics(params).then((res) => {
        this.screenData = res.ongoingProject || res.fixedAsset;
        this.setMapload();
      });
        this.screenData = res.ongoingProject || res.fixedAsset
        this.setMapload()
      })
    },
    toAccidentCaseDetail(item) {
    toAccidentCaseDetail (item) {
      this.$router.push({
        path: "/accidentCase/detail",
        path: '/accidentCase/detail',
        query: {
          id: item.id,
        },
      });
          id: item.id
        }
      })
    },
    toAccidentCaseList() {
      this.$router.push("/accidentCase");
    toAccidentCaseList () {
      this.$router.push('/accidentCase')
    },
    toWorkDetail(item) {
    toWorkDetail (item) {
      this.$router.push({
        path: "/workList/detail",
        path: '/workList/detail',
        query: {
          id: item.id,
        },
      });
          id: item.id
        }
      })
    },
    toWorkList() {
      this.$router.push("/workList");
    toWorkList () {
      this.$router.push('/workList')
    },
    toPorjectList() {
    toPorjectList () {
      const query = {
        projectCategory: ["ongoing", "fixed"][this.activeTab - 1],
      };
      // 如果有选择日期范围,则传递开始和结束时间
      if (this.dateRange && this.dateRange.length === 2) {
        query.startTime = moment(this.dateRange[0]).format(
          "YYYY-MM-DD HH:mm:ss"
        );
        query.endTime = moment(this.dateRange[1]).format("YYYY-MM-DD HH:mm:ss");
        projectCategory: ['ongoing', 'fixed'][this.activeTab - 1]
      }
      // 如果有选择日期范围,则传递开始和结束时间
      // if (this.dateRange && this.dateRange.length === 2) {
      //   query.startTime = moment(this.dateRange[0]).format(
      //     "YYYY-MM-DD HH:mm:ss"
      //   );
      //   query.endTime = moment(this.dateRange[1]).format("YYYY-MM-DD HH:mm:ss");
      // }
      this.$router.push({
        path: "/projectList",
        query: query,
      });
        path: '/projectList',
        query: query
      })
    },
    toEquipmentList() {
      const query = {};
    toEquipmentList () {
      const query = {}
      // 如果有选择日期范围,则传递开始和结束时间
      if (this.dateRange && this.dateRange.length === 2) {
        query.startTime = moment(this.dateRange[0]).format(
          "YYYY-MM-DD HH:mm:ss"
        );
        query.endTime = moment(this.dateRange[1]).format("YYYY-MM-DD HH:mm:ss");
      }
      // if (this.dateRange && this.dateRange.length === 2) {
      //   query.startTime = moment(this.dateRange[0]).format(
      //     "YYYY-MM-DD HH:mm:ss"
      //   );
      //   query.endTime = moment(this.dateRange[1]).format("YYYY-MM-DD HH:mm:ss");
      // }
      this.$router.push({
        path: "/equipmentList",
        query: query,
      });
        path: '/equipmentList',
        query: query
      })
    },
    toHiddenDanger() {
    toHiddenDanger () {
      const query = {
        projectCategory: ["ongoing", "fixed"][this.activeTab - 1],
      };
      // 如果有选择日期范围,则传递开始和结束时间
      if (this.dateRange && this.dateRange.length === 2) {
        query.startTime = moment(this.dateRange[0]).format(
          "YYYY-MM-DD HH:mm:ss"
        );
        query.endTime = moment(this.dateRange[1]).format("YYYY-MM-DD HH:mm:ss");
        projectCategory: ['ongoing', 'fixed'][this.activeTab - 1]
      }
      // 如果有选择日期范围,则传递开始和结束时间
      // if (this.dateRange && this.dateRange.length === 2) {
      //   query.startTime = moment(this.dateRange[0]).format(
      //     "YYYY-MM-DD HH:mm:ss"
      //   );
      //   query.endTime = moment(this.dateRange[1]).format("YYYY-MM-DD HH:mm:ss");
      // }
      this.$router.push({
        path: "/hiddenDanger",
        query: query,
      });
        path: '/hiddenDanger',
        query: query
      })
    },
    // 切换活动索引
    changeActiveIndex(index) {
      this.activeIndex = index;
      this.$refs.carousel.setActiveItem(index);
    changeActiveIndex (index) {
      this.activeIndex = index
      this.$refs.carousel.setActiveItem(index)
    },
    // 切换活动索引
    handleChangeCarousel(index) {
      this.activeIndex = index;
    handleChangeCarousel (index) {
      this.activeIndex = index
    },
    handleClick() {
      this.$refs.datePicker.focus();
    handleClick () {
      this.$refs.datePicker.focus()
    },
    handleSearch() {
    handleSearch () {
      if (!this.projectId) {
        return;
        return
      }
      const target = this.screenData.projectMapPoints.find(
        (item) => item.projectId === this.projectId
      );
      )
      if (!target || Object.keys(target).length === 0) {
        this.$message.warning("无此项目地图点位");
        return;
        this.$message.warning('无此项目地图点位')
        return
      }
      if (target.longitude && target.latitude) {
        // 定位地图
        this.mapView.setZoomAndCenter(15, [
          Number(target.longitude),
          Number(target.latitude),
        ]);
          Number(target.latitude)
        ])
        // 显示悬浮窗
        setTimeout(() => {
          this.showTooltip(null, {
            projectId: target.projectId,
            position: [Number(target.longitude), Number(target.latitude)],
          });
        }, 1000);
            position: [Number(target.longitude), Number(target.latitude)]
          })
        }, 1000)
      } else {
        this.$message.warning("该项目暂无位置信息");
        this.$message.warning('该项目暂无位置信息')
      }
    },
    // 初始化滚动数据
    initScrollData() {
      this.stopAutoScroll();
      if (!this.scrollData || this.scrollData.length === 0) return;
    initScrollData () {
      this.stopAutoScroll()
      if (!this.scrollData || this.scrollData.length === 0) return
      // 为了实现无缝滚动,复制2份数据
      this.scrollData = [...this.scrollData, ...this.scrollData];
      this.scrollData = [...this.scrollData, ...this.scrollData]
      // 开始滚动
      this.$nextTick(() => {
        this.startAutoScroll();
      });
        this.startAutoScroll()
      })
    },
    // 开始自动滚动
    startAutoScroll() {
      this.stopAutoScroll();
    startAutoScroll () {
      this.stopAutoScroll()
      if (!this.scrollContainer || !this.scrollData.length) return;
      if (!this.scrollContainer || !this.scrollData.length) return
      const originalDataLength = this.scrollData.length / 2;
      const originalDataLength = this.scrollData.length / 2
      // 动态计算高度
      let firstHalfHeight = 0;
      const wrapper = this.scrollContainer.children[0];
      let firstHalfHeight = 0
      const wrapper = this.scrollContainer.children[0]
      if (wrapper && wrapper.children.length) {
        for (let i = 0; i < originalDataLength; i++) {
          if (wrapper.children[i]) {
            firstHalfHeight += wrapper.children[i].offsetHeight;
            firstHalfHeight += wrapper.children[i].offsetHeight
          }
        }
      }
      // 兜底
      if (firstHalfHeight === 0) firstHalfHeight = originalDataLength * 102;
      if (firstHalfHeight === 0) firstHalfHeight = originalDataLength * 102
      // 判断是否需要跳转的标志
      let shouldJump = false;
      let shouldJump = false
      const scroll = () => {
        let currentScrollTop = this.scrollContainer.scrollTop;
        let currentScrollTop = this.scrollContainer.scrollTop
        // 当滚动到第二份的末尾时
        if (currentScrollTop >= firstHalfHeight) {
          // 计算当前滚动位置相对于第二份数据开始的偏移量
          const offset = currentScrollTop - firstHalfHeight;
          const offset = currentScrollTop - firstHalfHeight
          // 直接跳到第一份数据相同偏移量的位置
          this.scrollContainer.scrollTop = offset;
          this.scrollContainer.scrollTop = offset
          // 设置标志表示刚刚进行过跳转
          shouldJump = true;
          shouldJump = true
        } else {
          // 如果在跳转后,并且位置重置到了0附近,重置标志
          if (shouldJump && currentScrollTop < 2) {
            shouldJump = false;
            shouldJump = false
          }
        }
        // 只有在不处于跳转状态时才继续滚动
        if (!shouldJump) {
          this.scrollContainer.scrollTop += 1;
          this.scrollContainer.scrollTop += 1
        }
        this.scrollTimer = requestAnimationFrame(scroll);
      };
        this.scrollTimer = requestAnimationFrame(scroll)
      }
      // 开始滚动
      this.scrollTimer = requestAnimationFrame(scroll);
      this.scrollTimer = requestAnimationFrame(scroll)
    },
    // 停止自动滚动
    stopAutoScroll() {
    stopAutoScroll () {
      if (this.scrollTimer) {
        cancelAnimationFrame(this.scrollTimer);
        this.scrollTimer = null;
        cancelAnimationFrame(this.scrollTimer)
        this.scrollTimer = null
      }
    },
    // 鼠标进入容器时暂停滚动
    handleMouseEnter() {
      this.stopAutoScroll();
    handleMouseEnter () {
      this.stopAutoScroll()
    },
    // 鼠标离开容器时恢复滚动
    handleMouseLeave() {
      this.startAutoScroll();
    handleMouseLeave () {
      this.startAutoScroll()
    },
    // 处理滚轮事件
    handleWheel(event) {
      event.preventDefault();
      this.scrollContainer.scrollTop += event.deltaY;
    handleWheel (event) {
      event.preventDefault()
      this.scrollContainer.scrollTop += event.deltaY
    },
    setMapload() {
    setMapload () {
      if (!this.mapPromise) {
        this.mapPromise = window.AMapLoader.load({
          key: "232929db1cb31f26d42b3645a7456154",
          version: "2.0",
          plugins: ["AMap.DistrictSearch", "AMap.Geocoder"],
          key: '6edc6798d22e5a46660ff46560b1e612',
          version: '2.0',
          plugins: ['AMap.DistrictSearch', 'AMap.Geocoder'],
          AMapUI: {
            version: "1.1",
            plugins: ["geo/DistrictExplorer"],
          },
        });
            version: '1.1',
            plugins: ['geo/DistrictExplorer']
          }
        })
      }
      this.mapPromise
        .then((AMap) => {
          this.mapView = new AMap.Map("container", {
          this.mapView = new AMap.Map('container', {
            zoom: 13,
            center: [104.065617, 30.656952], // 初始化地图中心点
            mapStyle: "amap://styles/darkblue",
          });
          this.mapView.resize();
            mapStyle: 'amap://styles/darkblue'
          })
          this.mapView.resize()
          this._mapResizeHandler = () => {
            if (this.mapView) {
              this.mapView.resize();
              this.mapView.resize()
            }
          };
          window.addEventListener("resize", this._mapResizeHandler);
          }
          window.addEventListener('resize', this._mapResizeHandler)
          // this.infoWindow = new AMap.InfoWindow({
          //   isCustom: true,
          //   offset: new AMap.Pixel(0, -30),
          // });
          this.initCategoryMarkers(AMap);
          this.renderAllBoundaries();
          this.initCategoryMarkers(AMap)
          this.renderAllBoundaries()
        })
        .catch((e) => {
          console.error(e); // 加载错误提示
        });
          console.error(e) // 加载错误提示
        })
    },
    initCategoryMarkers(AMap) {
    initCategoryMarkers (AMap) {
      if (!this.mapView) {
        return;
        return
      }
      const points = this.screenData.projectMapPoints.map((item) => {
        let category;
        let category
        if (this.activeTab === 2) {
          category = "assets";
          category = 'assets'
        } else {
          category = ["house", "municipal", "assets"][item.projectType];
          category = ['house', 'municipal', 'assets'][item.projectType]
        }
        return {
          ...item,
          position: [Number(item.longitude), Number(item.latitude)],
          category: category,
          level: item.category,
        };
      });
      const markers = [];
          level: item.category
        }
      })
      const markers = []
      points.forEach((item) => {
        const marker = this.createCategoryMarker(AMap, item);
        const marker = this.createCategoryMarker(AMap, item)
        if (marker) {
          this.mapView.add(marker);
          markers.push(marker);
          this.mapView.add(marker)
          markers.push(marker)
        }
      });
      this.markers = markers;
      this.updateMarkerVisibility();
      })
      this.markers = markers
      this.updateMarkerVisibility()
    },
    createCategoryMarker(AMap, item) {
    createCategoryMarker (AMap, item) {
      if (!item || !item.position) {
        return null;
        return null
      }
      let image = null;
      let level = item.level;
      if (item.category === "municipal") {
        if (item.level === "A") {
          image = s1;
        } else if (item.level === "B") {
          image = s3;
        } else if (item.level === "C") {
          image = s2;
      let image = null
      let level = item.level
      if (item.category === 'municipal') {
        if (item.level === 'A') {
          image = s1
        } else if (item.level === 'B') {
          image = s3
        } else if (item.level === 'C') {
          image = s2
        } else {
          image = s4;
          image = s4
        }
      } else if (item.category === "house") {
        if (item.level === "A") {
          image = f1;
        } else if (item.level === "B") {
          image = f3;
        } else if (item.level === "C") {
          image = f2;
      } else if (item.category === 'house') {
        if (item.level === 'A') {
          image = f1
        } else if (item.level === 'B') {
          image = f3
        } else if (item.level === 'C') {
          image = f2
        } else {
          image = f4;
          image = f4
        }
      } else if (item.category === "assets") {
        if (item.level === "A") {
          image = z1;
        } else if (item.level === "B") {
          image = z3;
        } else if (item.level === "C") {
          image = z2;
      } else if (item.category === 'assets') {
        if (item.level === 'A') {
          image = z1
        } else if (item.level === 'B') {
          image = z3
        } else if (item.level === 'C') {
          image = z2
        } else {
          image = z4;
          image = z4
        }
      }
      if (!image) {
        return null;
        return null
      }
      const icon = new AMap.Icon({
        image,
        size: new AMap.Size(30, 30),
        imageSize: new AMap.Size(30, 30),
      });
        imageSize: new AMap.Size(30, 30)
      })
      const marker = new AMap.Marker({
        position: item.position,
        icon,
        offset: new AMap.Pixel(-12, -12),
        extData: {
          category: item.category,
          level: level,
        },
      });
      marker.on("mouseover", (e) => {
        this.showTooltip(e, item);
      });
      marker.on("mouseout", () => {
        this.hideTooltip();
      });
      marker.on("click", () => {
          level: level
        }
      })
      marker.on('mouseover', (e) => {
        this.showTooltip(e, item)
      })
      marker.on('mouseout', () => {
        this.hideTooltip()
      })
      marker.on('click', () => {
        this.$router.push({
          path: "/projectHome",
          path: '/projectHome',
          query: {
            projectId: item.projectId,
            projectName: item.projectName,
          },
        });
      });
      return marker;
            projectName: item.projectName
          }
        })
      })
      return marker
    },
    updateMarkerVisibility() {
    updateMarkerVisibility () {
      if (!this.markers || !this.markers.length) {
        return;
        return
      }
      this.markers.forEach((marker) => {
        if (!marker) {
          return;
          return
        }
        const data = marker.getExtData ? marker.getExtData() : null;
        const data = marker.getExtData ? marker.getExtData() : null
        if (!data) {
          return;
          return
        }
        const categoryVisible = this.categoryFilter[data.category];
        const levelVisible = !data.level || this.levelFilter[data.level];
        const categoryVisible = this.categoryFilter[data.category]
        const levelVisible = !data.level || this.levelFilter[data.level]
        if (categoryVisible && levelVisible) {
          marker.show();
          marker.show()
        } else {
          marker.hide();
          marker.hide()
        }
      });
      })
    },
    toggleCategory(type) {
    toggleCategory (type) {
      if (!this.categoryFilter.hasOwnProperty(type)) {
        return;
        return
      }
      this.categoryFilter[type] = !this.categoryFilter[type];
      this.updateMarkerVisibility();
      this.categoryFilter[type] = !this.categoryFilter[type]
      this.updateMarkerVisibility()
    },
    toggleLevel(level) {
    toggleLevel (level) {
      if (!this.levelFilter.hasOwnProperty(level)) {
        return;
        return
      }
      this.levelFilter[level] = !this.levelFilter[level];
      this.updateMarkerVisibility();
      this.levelFilter[level] = !this.levelFilter[level]
      this.updateMarkerVisibility()
    },
    showTooltip(e, item) {
      if (!this.mapView) return;
    showTooltip (e, item) {
      if (!this.mapView) return
      const pixel = this.mapView.lngLatToContainer(item.position);
      const pixel = this.mapView.lngLatToContainer(item.position)
      // 获取当前缩放比例
      let scaleX = 1;
      let scaleY = 1;
      const app = document.querySelector("#app");
      let scaleX = 1
      let scaleY = 1
      const app = document.querySelector('#app')
      if (app) {
        const rect = app.getBoundingClientRect();
        const rect = app.getBoundingClientRect()
        // offsetWidth 是元素的布局宽度(不包含 transform)
        // rect.width 是元素的渲染宽度(包含 transform)
        if (app.offsetWidth > 0) {
          scaleX = rect.width / app.offsetWidth;
          scaleX = rect.width / app.offsetWidth
        }
        if (app.offsetHeight > 0) {
          scaleY = rect.height / app.offsetHeight;
          scaleY = rect.height / app.offsetHeight
        }
      }
      this.tooltipPos = { left: pixel.x / scaleX, top: pixel.y / scaleY - 60 };
      this.tooltipVisible = true;
      this.tooltipLoading = true;
      this.tooltipError = false;
      this.tooltipData = {};
      this.tooltipPos = { left: pixel.x / scaleX, top: pixel.y / scaleY - 60 }
      this.tooltipVisible = true
      this.tooltipLoading = true
      this.tooltipError = false
      this.tooltipData = {}
      getprojectTooltip(item.projectId)
        .then((res) => {
          let address = "-";
          let constructionCompanyInfo = "-";
          let supervisorCompanyInfo = "-";
          let developmentCompanyInfo = "-";
          let address = '-'
          let constructionCompanyInfo = '-'
          let supervisorCompanyInfo = '-'
          let developmentCompanyInfo = '-'
          try {
            if (res.addressInfo) {
              const addressInfo = JSON.parse(res.addressInfo);
              const addressInfo = JSON.parse(res.addressInfo)
              address =
                (addressInfo.province || "") +
                (addressInfo.city || "") +
                (addressInfo.district || "") +
                (addressInfo.detail || "");
                (addressInfo.province || '') +
                (addressInfo.city || '') +
                (addressInfo.district || '') +
                (addressInfo.detail || '')
            }
            if (res.constructionCompanyInfo) {
              constructionCompanyInfo = JSON.parse(res.constructionCompanyInfo);
              constructionCompanyInfo = JSON.parse(res.constructionCompanyInfo)
            }
            if (res.supervisorCompanyInfo) {
              supervisorCompanyInfo = JSON.parse(res.supervisorCompanyInfo);
              supervisorCompanyInfo = JSON.parse(res.supervisorCompanyInfo)
            }
            if (res.developmentCompanyInfo) {
              developmentCompanyInfo = JSON.parse(res.developmentCompanyInfo);
              developmentCompanyInfo = JSON.parse(res.developmentCompanyInfo)
            }
          } catch (error) {
            console.error("Parse error", error);
            console.error('Parse error', error)
          }
          // 对设备租赁单位进行去重处理
          let uniqueProperties = [];
          let uniqueProperties = []
          if (res.properties && res.properties.length > 0) {
            const seenNames = new Set();
            const seenNames = new Set()
            uniqueProperties = res.properties.filter((item) => {
              try {
                const parsed = JSON.parse(item);
                const companyName = parsed["工程起重机械租赁单位"];
                const parsed = JSON.parse(item)
                const companyName = parsed['工程起重机械租赁单位']
                if (companyName && !seenNames.has(companyName)) {
                  seenNames.add(companyName);
                  return true;
                  seenNames.add(companyName)
                  return true
                }
                return false;
                return false
              } catch (e) {
                return false;
                return false
              }
            });
            })
          }
          this.tooltipData = {
@@ -1425,107 +1425,107 @@
            constructionCompanyInfo,
            supervisorCompanyInfo,
            developmentCompanyInfo,
            properties: uniqueProperties,
          };
          this.tooltipLoading = false;
            properties: uniqueProperties
          }
          this.tooltipLoading = false
        })
        .catch(() => {
          this.tooltipLoading = false;
          this.tooltipError = true;
        });
          this.tooltipLoading = false
          this.tooltipError = true
        })
    },
    hideTooltip() {
      this.tooltipVisible = false;
    hideTooltip () {
      this.tooltipVisible = false
    },
    clearBoundary() {
    clearBoundary () {
      if (this.boundaryPolygons.length) {
        this.mapView.remove(this.boundaryPolygons);
        this.boundaryPolygons = [];
        this.mapView.remove(this.boundaryPolygons)
        this.boundaryPolygons = []
      }
    },
    async renderAllBoundaries() {
      this.clearBoundary();
      if (!this.mapView || !this.screenData.projectMapPoints) return;
    async renderAllBoundaries () {
      this.clearBoundary()
      if (!this.mapView || !this.screenData.projectMapPoints) return
      // 确保 AMapUI 已加载
      if (!window.AMapUI) {
        console.warn("AMapUI not loaded");
        return;
        console.warn('AMapUI not loaded')
        return
      }
      const provinceSet = new Set();
      const districtSet = new Set();
      const citySet = new Set(); // 显式收集有数据的城市
      const pointsToGeocode = [];
      const provinceSet = new Set()
      const districtSet = new Set()
      const citySet = new Set() // 显式收集有数据的城市
      const pointsToGeocode = []
      // 1. 收集数据
      this.screenData.projectMapPoints.forEach((point) => {
        let hasData = false;
        let hasData = false
        if (point.addressInfo) {
          try {
            const info = JSON.parse(point.addressInfo);
            const info = JSON.parse(point.addressInfo)
            if (info.province) {
              provinceSet.add(info.province);
              hasData = true;
              provinceSet.add(info.province)
              hasData = true
            }
            if (info.district) {
              districtSet.add(info.district);
              hasData = true;
              districtSet.add(info.district)
              hasData = true
            }
            // 如果只有市没有区,或者需要单独渲染市
            if (info.city) {
              citySet.add(info.city);
              hasData = true;
              citySet.add(info.city)
              hasData = true
            }
          } catch (e) {
            // ignore
          }
        }
        if (!hasData) {
          pointsToGeocode.push([point.longitude, point.latitude]);
          pointsToGeocode.push([point.longitude, point.latitude])
        }
      });
      })
      // 2. 逆地理编码补充缺失数据
      if (pointsToGeocode.length > 0) {
        const geocoder = new window.AMap.Geocoder();
        const batchSize = 20;
        const batches = [];
        const geocoder = new window.AMap.Geocoder()
        const batchSize = 20
        const batches = []
        for (let i = 0; i < pointsToGeocode.length; i += batchSize) {
          batches.push(pointsToGeocode.slice(i, i + batchSize));
          batches.push(pointsToGeocode.slice(i, i + batchSize))
        }
        await Promise.all(
          batches.map((batch) => {
            return new Promise((resolve) => {
              geocoder.getAddress(batch, (status, result) => {
                if (status === "complete" && result.regeocodes) {
                if (status === 'complete' && result.regeocodes) {
                  result.regeocodes.forEach((geo) => {
                    if (geo.addressComponent) {
                      const { district, city, province } = geo.addressComponent;
                      if (province) provinceSet.add(province);
                      if (city) citySet.add(city);
                      if (district) districtSet.add(district);
                      const { district, city, province } = geo.addressComponent
                      if (province) provinceSet.add(province)
                      if (city) citySet.add(city)
                      if (district) districtSet.add(district)
                    }
                  });
                  })
                }
                resolve();
              });
            });
                resolve()
              })
            })
          })
        );
        )
      }
      // 初始化 DistrictExplorer
      let districtExplorer = null;
      let districtExplorer = null
      try {
        districtExplorer = new window.AMapUI.DistrictExplorer({
          map: this.mapView,
          eventSupport: false, // 我们自己绘制,不需要它的事件
        });
          eventSupport: false // 我们自己绘制,不需要它的事件
        })
      } catch (e) {
        console.error("Init DistrictExplorer failed", e);
        return;
        console.error('Init DistrictExplorer failed', e)
        return
      }
      // 辅助函数:根据名称查找 adcode
@@ -1533,18 +1533,18 @@
        return new Promise((resolve) => {
          const search = new window.AMap.DistrictSearch({
            subdistrict: 1, // 获取下一级以便后续逻辑使用(如省查市)
            extensions: "base", // 这里只需要 adcode,不需要详细边界
            level: level,
          });
            extensions: 'base', // 这里只需要 adcode,不需要详细边界
            level: level
          })
          search.search(name, (status, result) => {
            if (status === "complete" && result.districtList.length > 0) {
              resolve(result.districtList[0]);
            if (status === 'complete' && result.districtList.length > 0) {
              resolve(result.districtList[0])
            } else {
              resolve(null);
              resolve(null)
            }
          });
        });
      };
          })
        })
      }
      // 辅助函数:使用 DistrictExplorer 加载并绘制区域
      const renderAreaNode = (
@@ -1557,23 +1557,23 @@
        return new Promise((resolve) => {
          districtExplorer.loadAreaNode(adcode, (error, areaNode) => {
            if (error || !areaNode) {
              resolve();
              return;
              resolve()
              return
            }
            // 获取父级区域的 GeoJSON (ParentFeature)
            // 这包含了正确的孔洞信息
            const feature = areaNode.getParentFeature();
            const feature = areaNode.getParentFeature()
            if (!feature || !feature.geometry) {
              resolve();
              return;
              resolve()
              return
            }
            const geometry = feature.geometry;
            const geometry = feature.geometry
            const types =
              geometry.type === "MultiPolygon"
              geometry.type === 'MultiPolygon'
                ? geometry.coordinates
                : [geometry.coordinates];
                : [geometry.coordinates]
            // 遍历所有多边形(处理 MultiPolygon)
            types.forEach((coords) => {
@@ -1586,120 +1586,120 @@
                path: coords, // 直接使用 GeoJSON 的坐标数组
                strokeColor: style.strokeColor,
                strokeWeight: 2,
                fillColor: style.fillColor || "transparent",
                fillColor: style.fillColor || 'transparent',
                fillOpacity:
                  style.fillOpacity !== undefined ? style.fillOpacity : 0.2,
                zIndex: style.zIndex,
                bubble: true,
                cursor:
                  level === "district" && (isActive || isHoverable)
                    ? "pointer"
                    : "default",
                extData: { level, isActive },
              });
                  level === 'district' && (isActive || isHoverable)
                    ? 'pointer'
                    : 'default',
                extData: { level, isActive }
              })
              // 添加 hover 事件
              if (level === "district" && (isActive || isHoverable)) {
                const baseFillColor = style.fillColor || "transparent";
              if (level === 'district' && (isActive || isHoverable)) {
                const baseFillColor = style.fillColor || 'transparent'
                const baseFillOpacity =
                  style.fillOpacity !== undefined ? style.fillOpacity : 0.2;
                const baseStrokeColor = style.strokeColor;
                  style.fillOpacity !== undefined ? style.fillOpacity : 0.2
                const baseStrokeColor = style.strokeColor
                const hoverStyle = isActive
                  ? {
                      fillColor: "#00b3ff",
                      fillOpacity: 0.35,
                      strokeColor: "#00b3ff",
                      strokeWeight: 3,
                    }
                    fillColor: '#00b3ff',
                    fillOpacity: 0.35,
                    strokeColor: '#00b3ff',
                    strokeWeight: 3
                  }
                  : {
                      fillColor: "#00b3ff",
                      fillOpacity: 0.2,
                    };
                    fillColor: '#00b3ff',
                    fillOpacity: 0.2
                  }
                polygon.on("mouseover", () => {
                  polygon.setOptions(hoverStyle);
                });
                polygon.on("mouseout", () => {
                polygon.on('mouseover', () => {
                  polygon.setOptions(hoverStyle)
                })
                polygon.on('mouseout', () => {
                  polygon.setOptions({
                    fillColor: baseFillColor,
                    fillOpacity: baseFillOpacity,
                    strokeColor: baseStrokeColor,
                    strokeWeight: 2,
                  });
                });
                    strokeWeight: 2
                  })
                })
              }
              this.mapView.add(polygon);
              this.boundaryPolygons.push(polygon);
            });
              this.mapView.add(polygon)
              this.boundaryPolygons.push(polygon)
            })
            resolve();
          });
        });
      };
            resolve()
          })
        })
      }
      // 3. 处理省份:渲染省界,并收集其下属的所有城市 adcode
      const cityCodesFromProvinces = new Set();
      const cityAdcodeToNameMap = new Map(); // 辅助Map,用于判断是否在citySet中
      const cityCodesFromProvinces = new Set()
      const cityAdcodeToNameMap = new Map() // 辅助Map,用于判断是否在citySet中
      const provincePromises = Array.from(provinceSet).map(
        async (provinceName) => {
          const result = await resolveAdcode(provinceName, "province");
          const result = await resolveAdcode(provinceName, 'province')
          if (result) {
            // 渲染省 - 无填充
            renderAreaNode(
              result.adcode,
              {
                strokeColor: "#5470C6",
                fillColor: "",
                strokeColor: '#5470C6',
                fillColor: '',
                fillOpacity: 0,
                zIndex: 8,
                zIndex: 8
              },
              "province",
              'province',
              false
            );
            )
            // 收集该省下的所有市(用于渲染市界)
            if (result.districtList && result.districtList.length) {
              result.districtList.forEach((city) => {
                cityCodesFromProvinces.add(city.adcode);
                cityAdcodeToNameMap.set(city.adcode, city.name);
              });
                cityCodesFromProvinces.add(city.adcode)
                cityAdcodeToNameMap.set(city.adcode, city.name)
              })
            }
          }
        }
      );
      )
      await Promise.all(provincePromises);
      await Promise.all(provincePromises)
      // 4. 渲染市
      // 合并 "省份下属的市" 和 "直接出现在数据中的市"
      const allCityAdcodes = new Set([...cityCodesFromProvinces]);
      const allCityAdcodes = new Set([...cityCodesFromProvinces])
      // 处理直接出现的市名称
      const cityResolutionPromises = Array.from(citySet).map(
        async (cityName) => {
          const result = await resolveAdcode(cityName, "city");
          const result = await resolveAdcode(cityName, 'city')
          if (result) {
            allCityAdcodes.add(result.adcode);
            cityAdcodeToNameMap.set(result.adcode, cityName);
            allCityAdcodes.add(result.adcode)
            cityAdcodeToNameMap.set(result.adcode, cityName)
          }
        }
      );
      await Promise.all(cityResolutionPromises);
      )
      await Promise.all(cityResolutionPromises)
      const cityRenderPromises = Array.from(allCityAdcodes).map((adcode) => {
        // 渲染所有市 - 无填充 (仅轮廓)
        // 注意:isActive设为false,因为我们只希望聚焦在具体的区或标点上
        return renderAreaNode(
          adcode,
          { strokeColor: "#FAC858", fillColor: "", fillOpacity: 0, zIndex: 9 },
          "city",
          { strokeColor: '#FAC858', fillColor: '', fillOpacity: 0, zIndex: 9 },
          'city',
          false
        );
      });
        )
      })
      await Promise.all(cityRenderPromises);
      await Promise.all(cityRenderPromises)
      // 5. 渲染区
      // 策略:
@@ -1708,23 +1708,23 @@
      //    - 如果区不在 districtSet 中 (无数据):透明 + Hover效果 (isActive=false)
      // 2. 遍历 districtSet,处理可能漏掉的区 (比如没有对应的city信息的孤立区数据)
      const renderedDistrictAdcodes = new Set();
      const renderedDistrictAdcodes = new Set()
      const cityDistrictPromises = Array.from(citySet).map(async (cityName) => {
        const result = await resolveAdcode(cityName, "city");
        const result = await resolveAdcode(cityName, 'city')
        if (result && result.districtList) {
          const subDistricts = result.districtList;
          const subDistricts = result.districtList
          const subPromises = subDistricts.map((sub) => {
            renderedDistrictAdcodes.add(sub.adcode);
            renderedDistrictAdcodes.add(sub.adcode)
            // 检查该区是否有数据
            // 模糊匹配:districtSet中的名字可能不带"区"字
            let hasData = false;
            let hasData = false
            if (sub.name) {
              for (let d of districtSet) {
                if (sub.name.includes(d) || d.includes(sub.name)) {
                  hasData = true;
                  break;
                  hasData = true
                  break
                }
              }
            }
@@ -1733,75 +1733,75 @@
              // 有数据:默认高亮,无Hover特效
              return renderAreaNode(
                sub.adcode,
                { strokeColor: "#00ffd2", fillColor: "#00ffd2", zIndex: 10 },
                "district",
                { strokeColor: '#00ffd2', fillColor: '#00ffd2', zIndex: 10 },
                'district',
                true,
                false
              );
              )
            } else {
              // 无数据:默认透明,有Hover特效
              return renderAreaNode(
                sub.adcode,
                {
                  strokeColor: "#00ffd2",
                  fillColor: "",
                  strokeColor: '#00ffd2',
                  fillColor: '',
                  fillOpacity: 0,
                  zIndex: 10,
                  zIndex: 10
                },
                "district",
                'district',
                false,
                true
              );
              )
            }
          });
          return Promise.all(subPromises);
          })
          return Promise.all(subPromises)
        }
      });
      })
      await Promise.all(cityDistrictPromises);
      await Promise.all(cityDistrictPromises)
      // 处理可能遗漏的区 (districtSet 中有,但没在上面的循环中渲染过)
      const orphanDistrictPromises = Array.from(districtSet).map(
        async (districtName) => {
          // 先检查是否已经渲染过 (需要先resolve adcode才能精确匹配,但这里先用名字简单过滤一下,减少请求)
          // 由于上面是根据adcode记录的,这里还是得resolve一下比较稳妥
          const result = await resolveAdcode(districtName, "district");
          const result = await resolveAdcode(districtName, 'district')
          if (result && !renderedDistrictAdcodes.has(result.adcode)) {
            // 既然在districtSet里,肯定是有数据的
            return renderAreaNode(
              result.adcode,
              { strokeColor: "#00ffd2", fillColor: "#00ffd2", zIndex: 10 },
              "district",
              { strokeColor: '#00ffd2', fillColor: '#00ffd2', zIndex: 10 },
              'district',
              true,
              false
            );
            )
          }
        }
      );
      )
      await Promise.all(orphanDistrictPromises);
      await Promise.all(orphanDistrictPromises)
      // 6. 自动调整视野
      const targetOverlays = [];
      const targetOverlays = []
      if (this.markers && this.markers.length > 0) {
        targetOverlays.push(...this.markers);
        targetOverlays.push(...this.markers)
      }
      if (this.boundaryPolygons.length > 0) {
        // 只保留 isActive 为 true 的区域用于缩放 (即有数据的区)
        const activePolygons = this.boundaryPolygons.filter((p) => {
          const data = p.getExtData();
          return data && data.isActive;
        });
        targetOverlays.push(...activePolygons);
          const data = p.getExtData()
          return data && data.isActive
        })
        targetOverlays.push(...activePolygons)
      }
      if (targetOverlays.length > 0) {
        this.mapView.setFitView(targetOverlays, false, [60, 60, 60, 60]);
        this.mapView.setFitView(targetOverlays, false, [60, 60, 60, 60])
      }
    },
  },
};
    }
  }
}
</script>
<style lang="less" scoped>