|
@@ -0,0 +1,442 @@
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <div class="map-box">
|
|
|
+ <!-- 地图 -->
|
|
|
+ <div
|
|
|
+ id="mapDiv"
|
|
|
+ ></div>
|
|
|
+ <!-- 查询表单与列表展示 -->
|
|
|
+ <div class="site-search-data-box">
|
|
|
+ <!-- 查询表单区域 -->
|
|
|
+ <div class="search-input-box">
|
|
|
+ <!-- 查询表单区域 -->
|
|
|
+ <div class="search-input-box">
|
|
|
+ <a-input-search
|
|
|
+ v-model:value="siteUserSearchParam.siteUserName"
|
|
|
+ placeholder="请输入驿站工作人员姓名"
|
|
|
+ enter-button
|
|
|
+ :loading="searchLoading"
|
|
|
+ style="width: 100%"
|
|
|
+ @search="onSearch"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 数据列表 -->
|
|
|
+ <div class="select-data-box">
|
|
|
+ <!-- 下拉框查询部分 -->
|
|
|
+ <div class="select-input-box flex-box items-center" style="flex-wrap: wrap">
|
|
|
+ <a-date-picker style="width: 50%;" v-model:value="siteUserSearchParam.startDate" value-format="YYYY-MM-DD"
|
|
|
+ placeholder="请选择开始日期" :allow-clear="false" @change="changeRegion"/>
|
|
|
+ <a-date-picker style="width: 50%;" v-model:value="siteUserSearchParam.endDate" value-format="YYYY-MM-DD"
|
|
|
+ placeholder="请选择结束日期" :allow-clear="false" @change="changeRegion"/>
|
|
|
+ <a-select
|
|
|
+ style="width: 50%;"
|
|
|
+ v-model:value="siteUserSearchParam.regionCode"
|
|
|
+ :allow-clear="true"
|
|
|
+ :options="regionList"
|
|
|
+ :field-names="{ label: 'name', value: 'code' }"
|
|
|
+ :bordered="false"
|
|
|
+ placeholder="所属县区"
|
|
|
+ @change="changeRegion"
|
|
|
+ >
|
|
|
+ </a-select>
|
|
|
+ <a-select
|
|
|
+ style="width: 50%;"
|
|
|
+ v-model:value="siteUserSearchParam.siteID"
|
|
|
+ :options="siteDicList"
|
|
|
+ :field-names="{ label: 'siteName', value: 'siteID' }"
|
|
|
+ :allow-clear="true"
|
|
|
+ :bordered="false"
|
|
|
+ :disabled="searchType == 'site'"
|
|
|
+ placeholder="所属驿站"
|
|
|
+ @change="onSearch"
|
|
|
+ >
|
|
|
+ </a-select>
|
|
|
+ </div>
|
|
|
+ <!-- 数据列表部分 -->
|
|
|
+ <div class="list-box">
|
|
|
+ <!-- 驿站人员数据 -->
|
|
|
+ <div v-if="siteUserList.length > 0" class="site-data"
|
|
|
+ :class="{'check-site':nowCheckSiteUser.siteUserID == siteUser.siteUserID || nowMouseenterSiteUser.siteUserID == siteUser.siteUserID}"
|
|
|
+ v-for="(siteUser,siteIndex) in siteUserList"
|
|
|
+ :key="siteIndex"
|
|
|
+ @click="checkSiteUser(siteUser)"
|
|
|
+ @mouseenter="siteUserMouseenter(siteUser)"
|
|
|
+ @mouseleave="siteUserMouseenter({siteUserID:null})"
|
|
|
+ >
|
|
|
+ <p class="site-name">
|
|
|
+ {{ siteUser.siteUserName }}
|
|
|
+ </p>
|
|
|
+ <p class="label-text">
|
|
|
+ 工号:{{ siteUser.userNo }}
|
|
|
+ </p>
|
|
|
+ <p class="label-text">
|
|
|
+ 联系电话:{{ siteUser.mobile }}
|
|
|
+ </p>
|
|
|
+ <p class="label-text">
|
|
|
+ 所属驿站:{{ siteUser.siteName }}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ v-if="searchType == 'siteUser' && siteUserList.length == 0"
|
|
|
+ class="empty-box">
|
|
|
+ <a-empty/>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 分页控件 -->
|
|
|
+ <div class="pagination-box">
|
|
|
+ <span>共{{ paginationTotal }}人</span>
|
|
|
+ <a-pagination v-model:current="siteUserSearchParam.pageIndex" :total="paginationTotal"
|
|
|
+ v-model:pageSize="siteUserSearchParam.pageSize" :disabled="searchLoading"
|
|
|
+ show-less-items @change="onSearch" simple :show-size-changer="false"/>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 驿站人员信息详情 -->
|
|
|
+ <div class="site-user-info-box" v-if="nowCheckSiteUser.siteUserID != null">
|
|
|
+ <div class="user-info-box margin-bottom-10">
|
|
|
+ <p class="font-size-18 margin-bottom-8" style="font-weight: 600; text-align: center">
|
|
|
+ {{ nowCheckSiteUser.siteUserName }}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <!-- 服务记录时间轴 -->
|
|
|
+ <div v-if="nowCheckSiteUser.signinList.length > 0" class="serviceRecords-list">
|
|
|
+ <p class="margin-bottom-10">服务记录</p>
|
|
|
+ <a-timeline>
|
|
|
+ <a-timeline-item v-for="(service, key) in nowCheckSiteUser.signinList" :key="key" position="left">
|
|
|
+ <p>{{ dayjs(service.signinTime).format('YYYY-MM-DD HH:mm') }}</p>
|
|
|
+ <p v-if="service.signinType == 1">走访{{ service.companyName }}</p>
|
|
|
+ <p v-if="service.signinType == 2">走访{{ service.jobUserName }}人员信息</p>
|
|
|
+ <p v-if="service.signinType == 3">外出走访({{ service.content }})</p>
|
|
|
+ </a-timeline-item>
|
|
|
+ </a-timeline>
|
|
|
+ </div>
|
|
|
+ <div v-else class="empty-box">
|
|
|
+ <a-empty description="暂无服务记录"/>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import huiZhouGeoJSON from "./geo"
|
|
|
+import {onMounted, reactive, ref} from "vue";
|
|
|
+import {setBoundary} from "@/utils/position";
|
|
|
+import type {SelectProps} from "ant-design-vue";
|
|
|
+import {getSiteList} from "@/api/baseSettings/siteInfo";
|
|
|
+import {getRegionCodeList} from "@/api/system/area/index";
|
|
|
+import redTh from "@/assets/images/redTh.png"
|
|
|
+import dayjs from "dayjs";
|
|
|
+import {getDataMapListBySiteUserWorkMap} from "@/api/baseSettings/userInfo";
|
|
|
+
|
|
|
+const T = (window as any).T;
|
|
|
+const zoom = 9;
|
|
|
+let map = null;
|
|
|
+// 天地图默认中心点坐标
|
|
|
+const centerLngLat = new T.LngLat(114.416110, 23.111582);
|
|
|
+// 地图标记点
|
|
|
+let markerList = ref<Array<any>>([]);
|
|
|
+// 地图画线
|
|
|
+let lineList = ref<Array<any>>([]);
|
|
|
+
|
|
|
+// 驿站人员查询数据
|
|
|
+const siteUserSearchParam = reactive({
|
|
|
+ pageIndex: 1,
|
|
|
+ pageSize: 100,
|
|
|
+ siteUserName: "",
|
|
|
+ regionCode: null,
|
|
|
+ siteID: null,
|
|
|
+ startDate: dayjs(new Date()).format('YYYY-MM-DD'),
|
|
|
+ endDate: dayjs(new Date()).format('YYYY-MM-DD'),
|
|
|
+});
|
|
|
+// 驿站人员列表
|
|
|
+const siteUserList = ref<Array<any>>([]);
|
|
|
+// 查询加载动画
|
|
|
+const searchLoading = ref(false);
|
|
|
+// 县区数据
|
|
|
+const regionList = ref<SelectProps['options']>();
|
|
|
+// 驿站下拉框数据
|
|
|
+const siteDicList = ref<any>([]);
|
|
|
+// 选中的驿站人员
|
|
|
+const nowCheckSiteUser = ref<any>({siteUserID: null})
|
|
|
+// 鼠标经过的驿站
|
|
|
+const nowMouseenterSiteUser = ref<any>({siteUserID: null});
|
|
|
+// 驿站总条数
|
|
|
+const paginationTotal = ref(0)
|
|
|
+
|
|
|
+// 地图初始化
|
|
|
+const initMap = () => {
|
|
|
+ // 初始化容器
|
|
|
+ map = new T.Map('mapDiv');
|
|
|
+ if (map != null) {
|
|
|
+ // 设置地图显示中心点为惠州市人民政府
|
|
|
+ (map as any).centerAndZoom(centerLngLat, zoom);
|
|
|
+ (map as any).setMinZoom(5);
|
|
|
+ (map as any).setMaxZoom(14);
|
|
|
+ }
|
|
|
+ // 设置城市边界
|
|
|
+ setBoundary(map, T, huiZhouGeoJSON);
|
|
|
+};
|
|
|
+
|
|
|
+// 查询方法
|
|
|
+async function onSearch() {
|
|
|
+ // 清除地图标记点
|
|
|
+ delMapInfo();
|
|
|
+ await getDataMapListBySiteUserWorkMap({...siteUserSearchParam}).then((result: any) => {
|
|
|
+ siteUserList.value = result.list;
|
|
|
+ paginationTotal.value = result.total;
|
|
|
+
|
|
|
+ // 初始化地图标点图标
|
|
|
+ const icon_red = new T.Icon({
|
|
|
+ iconUrl: redTh,
|
|
|
+ iconSize: new T.Point(20, 20)
|
|
|
+ })
|
|
|
+
|
|
|
+ // 绘制地图标点
|
|
|
+ result.list.forEach((siteUser: any) => {
|
|
|
+ if (siteUser.signinList.length > 0) {
|
|
|
+ const points = new Array<any>();
|
|
|
+
|
|
|
+ siteUser.signinList.forEach((signin) => {
|
|
|
+ if (signin.longitude && signin.latitude) {
|
|
|
+ // 保存坐标点
|
|
|
+ points.push(new T.LngLat(signin.longitude, signin.latitude))
|
|
|
+
|
|
|
+ const point = new T.LngLat(signin.longitude, signin.latitude)
|
|
|
+ const marker = new T.Marker(point, {
|
|
|
+ icon: icon_red
|
|
|
+ }); // 创建标注
|
|
|
+ (map as any).addOverLay(marker);// 将标注添加到地图中
|
|
|
+ markerList.value.push(marker);
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // 在地图上画线
|
|
|
+ const line = new T.Polyline(points, {
|
|
|
+ color: "#c00020"
|
|
|
+ });
|
|
|
+ (map as any).addOverLay(line); //向地图上添加线
|
|
|
+ lineList.value.push(line);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+// 查询县区
|
|
|
+const getRegionList = async function () {
|
|
|
+ regionList.value = await getRegionCodeList();
|
|
|
+}
|
|
|
+// 县区变更事件
|
|
|
+const changeRegion = async function () {
|
|
|
+ if (siteUserSearchParam.regionCode) {
|
|
|
+ getSiteList({pageIndex: 1, pageSize: 9999, regionCode: siteUserSearchParam.regionCode}).then((result: any) => {
|
|
|
+ siteDicList.value = result.list;
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ siteDicList.value = [];
|
|
|
+ }
|
|
|
+ await onSearch();
|
|
|
+}
|
|
|
+
|
|
|
+// 选择站点人员
|
|
|
+async function checkSiteUser(siteUser: any) {
|
|
|
+ nowCheckSiteUser.value = JSON.parse(JSON.stringify(siteUser));
|
|
|
+ // 清除地图标其他记点
|
|
|
+ delMapInfo();
|
|
|
+ if (siteUser.signinList.length >= 0) {
|
|
|
+ // 设置中心点
|
|
|
+ (map as any).centerAndZoom(new T.LngLat(siteUser.signinList[0].longitude, siteUser.signinList[0].latitude), 14);
|
|
|
+ // 绘制当前选择驿站人员的画线
|
|
|
+ const icon_red = new T.Icon({
|
|
|
+ iconUrl: redTh,
|
|
|
+ iconSize: new T.Point(20, 20)
|
|
|
+ })
|
|
|
+ const points = new Array<any>();
|
|
|
+ siteUser.signinList.forEach((signin) => {
|
|
|
+ if (signin.longitude && signin.latitude) {
|
|
|
+ // 保存坐标点
|
|
|
+ points.push(new T.LngLat(signin.longitude, signin.latitude))
|
|
|
+
|
|
|
+ const point = new T.LngLat(signin.longitude, signin.latitude)
|
|
|
+ const marker = new T.Marker(point, {
|
|
|
+ icon: icon_red
|
|
|
+ }); // 创建标注
|
|
|
+ (map as any).addOverLay(marker);// 将标注添加到地图中
|
|
|
+ markerList.value.push(marker);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ // 在地图上画线
|
|
|
+ const line = new T.Polyline(points, {
|
|
|
+ color: "#c00020"
|
|
|
+ });
|
|
|
+ (map as any).addOverLay(line); //向地图上添加线
|
|
|
+ lineList.value.push(line);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 站点人员鼠标经过事件
|
|
|
+function siteUserMouseenter(siteUser: any) {
|
|
|
+ nowMouseenterSite.value = siteUser;
|
|
|
+}
|
|
|
+
|
|
|
+// 清空地图标点
|
|
|
+function delMapInfo() {
|
|
|
+ // 删除已有标点
|
|
|
+ if (markerList.value.length > 0) {
|
|
|
+ for (let i = 0; i < markerList.value.length; i++) {
|
|
|
+ (map as any).removeOverLay(markerList.value[i]);
|
|
|
+ }
|
|
|
+ markerList.value = [];
|
|
|
+ }
|
|
|
+ if (lineList.value.length > 0) {
|
|
|
+ for (let i = 0; i < lineList.value.length; i++) {
|
|
|
+ (map as any).removeOverLay(lineList.value[i]);
|
|
|
+ }
|
|
|
+ lineList.value = [];
|
|
|
+ }
|
|
|
+ (map as any).closeInfoWindow();
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ // 获取当前日期与7天前的日期
|
|
|
+ // 获取当天日期
|
|
|
+ const today = dayjs();
|
|
|
+ // 获取7天前的日期
|
|
|
+ const sevenDaysAgo = today.subtract(7, 'day');
|
|
|
+ siteUserSearchParam.startDate = sevenDaysAgo.format('YYYY-MM-DD');
|
|
|
+ siteUserSearchParam.endDate = today.format('YYYY-MM-DD');
|
|
|
+
|
|
|
+ initMap();
|
|
|
+ getRegionList();
|
|
|
+ onSearch();
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<script lang="ts">
|
|
|
+// 设置页面名称进行组件缓存
|
|
|
+export default {
|
|
|
+ name: "SiteUserWorkDataMap"
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="less">
|
|
|
+.map-box {
|
|
|
+ width: 100vw;
|
|
|
+ height: 100vh;
|
|
|
+ position: relative;
|
|
|
+ border: 1px rgba(173, 173, 173, 0.8) solid;
|
|
|
+ box-sizing: border-box;
|
|
|
+
|
|
|
+ #mapDiv {
|
|
|
+ position: absolute;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ z-index: 100;
|
|
|
+ }
|
|
|
+
|
|
|
+ .site-search-data-box {
|
|
|
+ width: 360px;
|
|
|
+ position: absolute;
|
|
|
+ top: 15px;
|
|
|
+ bottom: 5px;
|
|
|
+ left: 15px;
|
|
|
+ right: 390px;
|
|
|
+ z-index: 110;
|
|
|
+
|
|
|
+ .search-input-box {
|
|
|
+ width: 100%;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .select-data-box {
|
|
|
+ height: calc(100% - 95px);
|
|
|
+ background-color: #F8F8F8;
|
|
|
+ border-radius: 10px 10px 0 0;
|
|
|
+ padding: 10px;
|
|
|
+
|
|
|
+ .select-input-box {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ background-color: white;
|
|
|
+ padding: 5px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ border-radius: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .list-box {
|
|
|
+ max-height: calc(100% - 100px);
|
|
|
+ overflow: hidden;
|
|
|
+ overflow-y: auto;
|
|
|
+
|
|
|
+ .site-data {
|
|
|
+ background-color: white;
|
|
|
+ border-radius: 10px;
|
|
|
+ padding: 8px;
|
|
|
+ cursor: pointer;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ box-shadow: 0 5px 5px -5px rgba(0, 0, 0, 0.3);
|
|
|
+ box-sizing: border-box;
|
|
|
+ border: 1px solid white;
|
|
|
+ }
|
|
|
+
|
|
|
+ .check-site {
|
|
|
+ border-color: #007EFF;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .site-user-info-box {
|
|
|
+ width: 300px;
|
|
|
+ position: absolute;
|
|
|
+ top: 15px;
|
|
|
+ left: calc(100% - 330px);
|
|
|
+ right: 15px;
|
|
|
+ bottom: 15px;
|
|
|
+ z-index: 110;
|
|
|
+ border-radius: 10px;
|
|
|
+ background-color: white;
|
|
|
+ padding: 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .pagination-box {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ padding: 10px 10px;
|
|
|
+ background-color: #F8F8F8;
|
|
|
+ border-radius: 0 0 10px 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .empty-box {
|
|
|
+ width: 100%;
|
|
|
+ height: 450px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ant-btn, .ant-input, .ant-picker, .ant-picker-input, .ant-picker-focused {
|
|
|
+ border: none !important;
|
|
|
+ box-shadow: none !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ input {
|
|
|
+ height: 32px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ant-select:not(.ant-select-customize-input) .ant-select-selector,
|
|
|
+ .ant-select:not(.ant-select-customize-input) .ant-select-selector,
|
|
|
+ .ant-input-affix-wrapper, .ant-select-selector {
|
|
|
+ border: none !important;
|
|
|
+ box-shadow: none !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ant-select:not(.ant-select-disabled).ant-select:not(.ant-select-customize-input) > .ant-select-selector {
|
|
|
+ border-color: transparent;
|
|
|
+ box-shadow: none;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|