| | |
| | | </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, // 滚动定时器 |
| | |
| | | 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 = { |
| | |
| | | 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 |
| | |
| | | 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 = ( |
| | |
| | | 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) => { |
| | |
| | | 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. 渲染区 |
| | | // 策略: |
| | |
| | | // - 如果区不在 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 |
| | | } |
| | | } |
| | | } |
| | |
| | | // 有数据:默认高亮,无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> |