下发任务 修改任务处理

This commit is contained in:
maojiacai
2025-09-07 21:33:05 +08:00
parent 5cd52c4d2c
commit 8aad9f302f
20 changed files with 1248 additions and 36 deletions

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

12
.idea/dy_app.iml generated Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/dy_app.iml" filepath="$PROJECT_DIR$/.idea/dy_app.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

35
src/api/collectPage.js Normal file
View File

@ -0,0 +1,35 @@
import {service} from "@/utils/request";
const api = "/mosty-yjzl"
// 查询分页
export function getSelectPage(params) {
return service({
url: `${api}/tbZdxlFgdwBdd/selectPage`,
params
})
}
// 新增数据
export function addSaveData(data) {
return service({
url: `${api}/tbZdxlFgdwBdd/save`,
method: 'POST',
data
})
}
// 获取方格列表
export function getSelectAllList(params) {
return service({
url: `${api}/tbZdxlFgdw/selectAllList`,
params
})
}
// 获取方格列表
export function getSelectList(params) {
return service({
url: `${api}/tbZdxlFgdw/selectList`,
params
})
}

18
src/api/patrolList.js Normal file
View File

@ -0,0 +1,18 @@
import {service} from "@/utils/request";
const api = `/mosty-yjzl`
// 获取巡逻列表
export function fetchPatrolList(params) {
return service({
url: `${api}/tbZdxlFgxlrw/selectRwPage`,
params
})
}
export function fetchSelectListByBddxlrwId(params) {
return service({
url: `${api}/tbZdxlFgdwBddxlrwJl/selectListByBddxlrwId`,
params
})
}

BIN
src/assets/home/bddcj.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -93,6 +93,7 @@ onMounted(() => {
}) })
// zoomTarget.value = map.mapboxGLMap.getZoom(); // zoomTarget.value = map.mapboxGLMap.getZoom();
}); });
mapUtil.value = new MapUtil(map); mapUtil.value = new MapUtil(map);
// mapUtil.value.Drawplot(); //初始化加载绘制工具 // mapUtil.value.Drawplot(); //初始化加载绘制工具
@ -106,7 +107,6 @@ onMounted(() => {
// 撒点 // 撒点
emitter.on("addPointArea", (obj) => { emitter.on("addPointArea", (obj) => {
console.log(obj,'obj'); console.log(obj,'obj');
mapUtil.value.makerSki(obj); mapUtil.value.makerSki(obj);
}); });
// 鼠标滑过提示文字的点位 // 鼠标滑过提示文字的点位
@ -162,6 +162,7 @@ onMounted(() => {
}); });
// 聚合撒点 // 聚合撒点
emitter.on("addPoint", (obj) => { emitter.on("addPoint", (obj) => {
console.log(obj, 'obj');
mapUtil.value.aggregateScatteringPoint(obj); mapUtil.value.aggregateScatteringPoint(obj);
}); });
@ -198,6 +199,12 @@ onMounted(() => {
let coords = [centerPoint.lng, centerPoint.lat]; let coords = [centerPoint.lng, centerPoint.lat];
emitter.emit("getcentercoord", coords); emitter.emit("getcentercoord", coords);
}); });
// 获取点击经纬度
emitter.on("getMapClickCoordinates", (res) => {
mapUtil.value.enableClickEvents()
console.log(res)
})
}); });
//切换地图底图 //切换地图底图
const onMapImageChange = (val) => { const onMapImageChange = (val) => {
@ -278,6 +285,7 @@ onUnmounted(() => {
emitter.off("diffusionCircle"); emitter.off("diffusionCircle");
emitter.off("SsCircle"); emitter.off("SsCircle");
emitter.off("ClearssCircle"); emitter.off("ClearssCircle");
emitter.off("getMapClickCoordinates");
}); });
</script> </script>

View File

@ -1,8 +1,8 @@
import emitter from "@/utils/eventBus.js"; import emitter from "@/utils/eventBus.js";
export function MapUtil(map) { export function MapUtil(map) {
let _that = this; let _that = this;
_that.mMap = map; //地图对象 _that.mMap = map; //地图对象
_that.heatmapOverlay = {}; //热力图层对象 _that.heatmapOverlay = {}; //热力图层对象
_that.markerClusterers = null; //聚合图层对象 _that.markerClusterers = null; //聚合图层对象
_that.flagSircle = []; //自定义HTML _that.flagSircle = []; //自定义HTML
@ -24,7 +24,7 @@ export function MapUtil(map) {
}; };
/** /**
* 撒点.鼠标滑动展示内容 * 撒点.鼠标滑动展示内容
* @param {*} coords 坐标 geojson * @param {*} coords 坐标 geojson
* @param {*} icon 图标 * @param {*} icon 图标
* @param {*} flag 标识 * @param {*} flag 标识
@ -44,7 +44,7 @@ export function MapUtil(map) {
} }
if(it.jd && it.wd) return obj; if(it.jd && it.wd) return obj;
}); });
const point = map.createdPoint(pointList,{ const point = map.createdPoint(pointList,{
image:icon,//对应上面的图片名称 image:icon,//对应上面的图片名称
scale:0.6, scale:0.6,
@ -69,7 +69,7 @@ export function MapUtil(map) {
/** /**
* 撒点 * 撒点
* @param {*} coords 坐标 geojson * @param {*} coords 坐标 geojson
* @param {*} icon 图标 * @param {*} icon 图标
* @param {*} flag 标识 * @param {*} flag 标识
* @param {*} isBounds 点击图标是否变大方法 * @param {*} isBounds 点击图标是否变大方法
* @param {*} showTitle 是否展示标题 * @param {*} showTitle 是否展示标题
@ -77,8 +77,8 @@ export function MapUtil(map) {
MapUtil.prototype.makerSki = (res) => { MapUtil.prototype.makerSki = (res) => {
console.log(res,'resres'); console.log(res,'resres');
let { coords,icon,flag, isBounds , showTitle} = res let { coords,icon,flag, isBounds , showTitle, coordinates} = res
if (!coords) return; if (!coords) return;
if(!_that._self[flag]) _that._self[flag] = []; //存储地图标识的容器 if(!_that._self[flag]) _that._self[flag] = []; //存储地图标识的容器
if(!_that.idsBox[flag]) _that.idsBox[flag] = []; //存储id的容器 if(!_that.idsBox[flag]) _that.idsBox[flag] = []; //存储id的容器
@ -158,8 +158,8 @@ export function MapUtil(map) {
/** /**
* 装备图标 * 装备图标
* @param {点位数据} data * @param {点位数据} data
* @param {点} point * @param {点} point
*/ */
MapUtil.prototype.shouIcon = (data, point) => { MapUtil.prototype.shouIcon = (data, point) => {
if(!_that._self.gpsZb) _that._self.gpsZb = [] if(!_that._self.gpsZb) _that._self.gpsZb = []
@ -215,8 +215,8 @@ export function MapUtil(map) {
/** /**
* 聚合撒点 * 聚合撒点
* @param {*} coords 点位数据 geojson lng lat * @param {*} coords 点位数据 geojson lng lat
* @param {*} icon 点位图 * @param {*} icon 点位图
*/ */
MapUtil.prototype.aggregateScatteringPoint = (obj) => { MapUtil.prototype.aggregateScatteringPoint = (obj) => {
let { coords, icon, flag,isclear,scale } = obj; let { coords, icon, flag,isclear,scale } = obj;
@ -245,11 +245,11 @@ export function MapUtil(map) {
// 聚合的点击一个 // 聚合的点击一个
maker.addEventListener("click", (val) => { maker.addEventListener("click", (val) => {
_that.openInfoDetail(flag,[val]) //点击打开详情 _that.openInfoDetail(flag,[val]) //点击打开详情
}) })
// 聚合的多个 // 聚合的多个
maker.addEventListener("clusterClick", (val) => { maker.addEventListener("clusterClick", (val) => {
_that.openInfoDetail(flag,val) //点击打开详情 _that.openInfoDetail(flag,val) //点击打开详情
}) })
}; };
@ -291,7 +291,7 @@ export function MapUtil(map) {
}) })
_that.heatmapOverlay[flag] = [] _that.heatmapOverlay[flag] = []
}; };
/** /**
* 删除图层要素 * 删除图层要素
* @param {*} layer 唯一标识 * @param {*} layer 唯一标识
@ -306,7 +306,7 @@ export function MapUtil(map) {
_that._self.gpsZb[key] = [] _that._self.gpsZb[key] = []
} }
} }
} }
// 其他图层 // 其他图层
if (!_that._self[layer]) return false; if (!_that._self[layer]) return false;
if(layer !== 'gpsZb'){ if(layer !== 'gpsZb'){
@ -315,7 +315,7 @@ export function MapUtil(map) {
el.destroy()//destory()销毁 , show(false) false:隐藏 true :展示 el.destroy()//destory()销毁 , show(false) false:隐藏 true :展示
} }
_that._self[layer] = []; _that._self[layer] = [];
// d带标题的撒点 // d带标题的撒点
let flagT = layer+'Title'; let flagT = layer+'Title';
if (!_that._self[flagT]) return false; if (!_that._self[flagT]) return false;
@ -360,7 +360,7 @@ export function MapUtil(map) {
} catch (err) {} } catch (err) {}
} }
} }
// 绘制数据的初始化 // 绘制数据的初始化
MapUtil.prototype.Drawplot = (color) => { MapUtil.prototype.Drawplot = (color) => {
const {point,line,polygon,circle,rectangle,geoJson,remove,enableEdit } = map.draw({ const {point,line,polygon,circle,rectangle,geoJson,remove,enableEdit } = map.draw({
@ -374,7 +374,7 @@ export function MapUtil(map) {
} }
/** /**
* 绘制工具 * 绘制工具
* @param {*} type 绘制形状 * @param {*} type 绘制形状
* (point 点, line 线, circle 圆, polygon 多边形, rectangle 矩形) , * (point 点, line 线, circle 圆, polygon 多边形, rectangle 矩形) ,
* geoJson:根据geojson回显图 * geoJson:根据geojson回显图
*/ */
@ -452,8 +452,8 @@ export function MapUtil(map) {
} }
/** /**
* 创建线 * 创建线
* @param {*} type 回显形状 * @param {*} type 回显形状
* (solid 实线, dash 虚线, FlowColor 彩虹线, RoadLine 流线 * (solid 实线, dash 虚线, FlowColor 彩虹线, RoadLine 流线
*/ */
MapUtil.prototype.createLine = (res) => { MapUtil.prototype.createLine = (res) => {
let { type , coords , isclear ,flag ,color,width} = res; let { type , coords , isclear ,flag ,color,width} = res;
@ -498,9 +498,9 @@ export function MapUtil(map) {
/** /**
* 回显平面- 圆 - 多边形 - 矩形 * 回显平面- 圆 - 多边形 - 矩形
* @param {*} type 回显形状 * @param {*} type 回显形状
* type: 'polygon', 'rectangle * type: 'polygon', 'rectangle
coords = [{ coords = [{
position:[[[jd,wd],[jd,wd] ---]], //三维数组 position:[[[jd,wd],[jd,wd] ---]], //三维数组
text,//展示的文字 text,//展示的文字
id, //唯一标识 id, //唯一标识
@ -508,10 +508,10 @@ export function MapUtil(map) {
userData:{} //存储数据 userData:{} //存储数据
}] }]
* type:circle * type:circle
coords:[jd,wd] radius:半径 coords:[jd,wd] radius:半径
* @param {*} text 展示的文字 * @param {*} text 展示的文字
*/ */
MapUtil.prototype.echoPlane = (res) => { MapUtil.prototype.echoPlane = (res) => {
let { type , coords ,fontColor, text = '' ,radius = 0, isclear ,flag ,id = 1 , color , linecolor} = res; let { type , coords ,fontColor, text = '' ,radius = 0, isclear ,flag ,id = 1 , color , linecolor} = res;
@ -535,7 +535,7 @@ export function MapUtil(map) {
let maker ; let maker ;
// 圆 // 圆
if(type == 'circle'){ if(type == 'circle'){
let params = [{ center:coords,radius, text, id }] let params = [{ center:coords,radius, text, id }]
maker = map.createCircle(params,style); maker = map.createCircle(params,style);
} }
@ -544,7 +544,7 @@ export function MapUtil(map) {
// 多边形 // 多边形
if(type == 'polygon') maker = map.createPolygon(coords,style); if(type == 'polygon') maker = map.createPolygon(coords,style);
_that._self[flag].push(maker); _that._self[flag].push(maker);
maker.addEventListener("click", (val) => { maker.addEventListener("click", (val) => {
if( flag == 'xfq'){ if( flag == 'xfq'){
maker.highlight(val.id) //高亮展示 maker.highlight(val.id) //高亮展示
@ -557,7 +557,7 @@ export function MapUtil(map) {
}) })
} }
// 分割线展示文字 // 分割线展示文字
MapUtil.prototype.gapText = (obj) => { MapUtil.prototype.gapText = (obj) => {
let { points, text ,flag} = obj let { points, text ,flag} = obj
@ -668,7 +668,7 @@ export function MapUtil(map) {
_that.polygonGeo.destroy() _that.polygonGeo.destroy()
} }
// 打开详情弹窗 // 打开详情弹窗
MapUtil.prototype.openInfoDetail = (flag,data) => { MapUtil.prototype.openInfoDetail = (flag,data) => {
switch (flag) { switch (flag) {
case "rx": case "rx":
@ -699,6 +699,31 @@ export function MapUtil(map) {
break; break;
} }
} }
/** 获取经纬度*/
MapUtil.prototype.enableClickEvents = function() {
const _that = this;
if (_that.clickEventHandler) {
console.log('点击事件已经启用');
return;
}
// 添加点击事件处理函数
_that.clickEventHandler = (e) => {
const lng = e.lngLat.lng;
const lat = e.lngLat.lat;
emitter.emit("mapClickCoordinates", {
lng,
lat,
coordinates: [lng, lat],
timestamp: new Date().getTime()
});
};
_that.mMap.mapboxGLMap.on('click', _that.clickEventHandler);
};
} }
// 获取uuid 作为边界图层ID // 获取uuid 作为边界图层ID
function getUUid() { function getUUid() {

View File

@ -0,0 +1,97 @@
<template>
<div class="info-container">
<div class="item" v-for="(item, index) in data" :key="index">
<div class="point"></div>
<div class="line" v-if="index + 1 != data.length"></div>
<div class="info-right">
<div class="name">{{item.name}}</div>
<div class="time">打卡时间<text>{{ item.time }}</text></div>
<div class="image">
<img src="../../../assets/home/bddcj.png" alt="">
</div>
<div class="address">
<van-icon name="location-o" color="#1DB1FF" />
<div class="name">四川省成都市</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
const props = defineProps({
data: {
type: Array,
default: []
}
})
</script>
<style lang="scss" scoped>
.info-container {
padding: 0 2.67vw;
margin-top: 4vw;
.item {
color: #666;
display: flex;
align-content: center;
position: relative;
height: auto;
border-left: 0.53vw dashed #1DB1FF;
max-height: 46.93vw;
padding-bottom: 2.67vw;
.point {
position: absolute;
width: 3.2vw;
height: 3.2vw;
background: #1DB1FF;
border-radius: 50%;
flex-shrink: 0;
left: -1.665vw;
}
.info-right {
margin-left: 5.33vw;
font-family: PingFang HK, PingFang HK;
.name {
font-weight: 400;
font-size: 3.73vw;
color: #707070;
}
.image {
margin-top: 2.13vw;
width: 33.87vw;
height: 18.67vw;
}
.time {
margin-top: 2.13vw;
text {
color: #0386FB;
}
}
.address {
margin-top: 2.13vw;
display: flex;
align-items: center;
color: #75787F;
div {
font-size: 2.67vw;
}
.name {
margin-left: 1.33vw;
}
}
}
}
}
</style>

View File

@ -0,0 +1,305 @@
<script setup>
import TopNav from "@/components/topNav.vue";
import {onMounted, reactive, ref} from "vue";
import { useRoute } from "vue-router";
import Timeline from "@/pages/clockInPage/components/Timeline.vue";
import {fetchSelectListByBddxlrwId} from "@/api/patrolList";
const route = useRoute();
const activeName = ref("0")
const baseUrl = ref("")
const data = reactive({
tabsList: [],
info: []
})
const timeList = [
{
time:'09:24:34',
name: '第一次打卡 开始',
person:'李小明',
content:'签收订单, 订单状态变更为待回单, 签收备注为\'无\'',
},
{
time:'2020-03-26 12:30:12',
name: '吾悦广场',
person:'李小明',
content:'创建了订单, 并添加了跟踪方式, 电子设备或快递单号: 854654875',
},
{
time:'2020-03-26 12:30:12',
name: '吾悦广场',
person:'李小明',
content:'签收订单, 订单状态变更为待回单, 签收备注为\'无\'',
}
]
const clearImage = () => {}
const onClickImg = () => {}
const photoFn = () => {}
const count = (item) => {
if (!item || !item.dkSx) return undefined;
const numbers = ['一', '二', '三', '四'];
const index = item.dkSx - 1; // 假设 dkSx 是从1开始的数字
return numbers[index];
};
const getData = async (bddxlrwId = '') => {
const res = await fetchSelectListByBddxlrwId({ bddxlrwId })
if (res) {
data.info = res
}
}
onMounted(() => {
if (route.query.item) {
data.tabsList = JSON.parse(route.query.item)
console.log(data.tabsList)
}
getData(data.tabsList[0]?.id)
})
</script>
<template>
<div>
<top-nav navTitle="打卡" :showLeft="true" />
<div class="clockInWrapper">
<van-tabs v-model="activeName">
<template v-for="(item, index) in data.tabsList" :key="item?.id">
<van-tab :name="index" :title="item?.bddMc" />
</template>
</van-tabs>
<div class="clockInList">
<template v-for="(item, index) in data.info" :key="index">
<div class="clockInList_item">
<div class="label">{{ `${count(item)}次打卡` }}</div>
<div class="dec">开始</div>
<div class="dec">离开</div>
</div>
</template>
<!-- <div class="clockInList_item">-->
<!-- <div class="label">第一次打卡</div>-->
<!-- <div class="dec">开始</div>-->
<!-- <div class="dec">离开</div>-->
<!-- </div>-->
<!-- <div class="clockInList_item">-->
<!-- <div class="label">第一次打卡</div>-->
<!-- <div class="dec">开始</div>-->
<!-- <div class="dec">离开</div>-->
<!-- </div>-->
</div>
<div class="upload_box">
<div class="image_box" v-if="baseUrl">
<van-icon name="close" class="close_icon" @click="clearImage" color="#000" size="24px" />
<van-image :src="baseUrl" @click="onClickImg(baseUrl)" style="flex: 1">
<template v-slot:loading>
<van-loading type="spinner" size="20" />
</template>
</van-image>
</div>
<div class="upload_icon_box" v-else>
<van-icon @click="photoFn" color="#1DB1FF" name="plus" />
<span>点击拍照</span>
</div>
<!-- <van-uploader v-model="clockList" :max-count="1" :after-read="afterRead" capture="camera"
:before-read="beforeRead" accept="image/*" /> -->
<div class="upload_tip"><span style="color: red;">*</span>须拍摄实景图才可进行打卡</div>
</div>
<div class="clockWrapper">
<div class="circleWrapper">
<div class="time">100000</div>
<div class="title">开始</div>
<div class="info">第一次打卡</div>
</div>
<div class="circleWrapperTip">
<van-icon name="success" color="#FFFFFF" />
<div>已进入考勤范围打卡点1德阳市某某某</div>
</div>
</div>
<timeline :data="timeList" />
</div>
</div>
</template>
<style scoped lang="scss">
.clockInWrapper {
margin-top: 13vw;
padding: 2vw;
.clockWrapper {
margin-top: 23.47vw;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.circleWrapperTip {
display: flex;
align-items: center;
justify-content: center;
margin-top: 7.2vw;
font-family: PingFang HK, PingFang HK;
font-weight: 400;
font-size: 3.73vw;
color: #707070;
::v-deep {
.van-icon-success {
margin-right: 1.33vw;
display: flex;
align-items: center;
justify-content: center;
width: 3.73vw;
height: 3.73vw;
background: #11AA66;
border-radius: 13.33vw;
}
}
}
.circleWrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 42.67vw;
height: 42.67vw;
background: linear-gradient( 180deg, #1DB1FF 0%, #007DE9 100%);
border-radius: 26.67vw;
color: #fff;
font-family: PingFang HK, PingFang HK;
.time {
font-weight: 400;
font-size: 4.8vw;
}
.title {
font-weight: 400;
font-size: 4.8vw;
}
.info {
font-weight: 400;
font-size: 3.73vw;
}
}
}
.upload_box {
margin-top: 4vw;
display: flex;
padding-bottom: 4vw;
border-bottom: 0.27vw solid #D9D9D9;
.upload_tip {
color: #999999;
font-size: 2.67vw;
margin-left: 2.67vw;
}
.image_box {
position: relative;
width: 42.67vw;
height: 26.67vw;
.close_icon {
position: absolute;
right: 0;
top: 0;
z-index: 20;
}
::v-deep .van-image {
width: 100%;
}
}
.upload_icon_box {
font-size: 3.2vw;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #1DB1FF;
border: 0.27vw dashed #1DB1FF;
text-align: center;
width: 29.33vw;
height: 16.53vw;
border-radius: 2.67vw;
}
}
.clockInList {
display: flex;
justify-content: space-between;
margin-top: 4vw;
.clockInList_item {
padding: 4vw 2vw;
width: 43vw;
height: 18vw;
background: #EDEDED;
border-radius: 2.67vw;
.label {
font-weight: 400;
font-size: 4.27vw;
}
.dec {
color: #75787F;
font-size: 3.73vw;
margin-top: 1.33vw;
}
}
}
::v-deep {
.van-tabs__nav--line {
padding-bottom: 0 !important;
}
.van-tabs__wrap {
height: auto !important;
}
.van-tabs__line {
display: none;
}
.van-tab {
flex: initial;
font-size: 4vw;
width: auto !important;
height: 9.33vw;
padding: 0 2.67vw;
border: 0.27vw solid #EDEDED;
color: #75787F;
flex-shrink: 0;
border-radius: 2vw;
margin-right: 2vw;
&:last-child {
margin-right: 0 !important;
}
}
.van-tab--active {
background: rgba(62,110,232,0.2);
border: 0.27vw solid #3E6EE8;
color: #3E6EE8 !important;
}
}
}
</style>

View File

@ -0,0 +1,172 @@
<script setup>
import emitter from "@/utils/eventBus";
import TopNav from "@/components/topNav.vue";
import {onMounted, ref} from "vue";
import CustomPopup from "@/pages/collectPage/copmonents/customPopup.vue";
import GdMap from "@/components/GdMap/index.vue"
import {addSaveData} from "@/api/collectPage";
import {hintToast} from "@/utils/tools";
import router from "@/router";
const loading = ref(false)
const disabled = ref(false)
const visible = ref(false)
const formData = ref({})
const onSubmit = async (data) => {
try {
loading.value = true;
const res = await addSaveData(formData.value)
if (res) {
hintToast(res?.msg || '新增成功')
setTimeout(async () => {
await router.push(`/collectPage`)
}, 500)
}
} catch (error) {
console.log(error)
hintToast(error?.msg || "新增失败")
} finally {
setTimeout(() => {
loading.value = false
}, 1000)
}
}
// 获取方格
const handleChange = (val) => {
formData.value.mc = val?.mc
formData.value.fgdwId = val?.id
}
onMounted(() => {
// 获取经纬度
emitter.emit("getMapClickCoordinates");
// 更新地图标注位置
emitter.on("mapClickCoordinates", async (res) => {
emitter.emit("deletePointArea")
formData.value.jd = res.lng
formData.value.wd = res.lat
emitter.emit("addPointArea", {
coords: [{ jd: res.lng, wd: res.lat }],
coordinates: res?.coordinates,
icon: require("../../assets/lz/dw.png"),
sizeX: 30,
sizeY: 35
});
})
})
</script>
<template>
<div>
<TopNav navTitle="必到点采集新增" :showLeft="true" />
<div class="formWrapper">
<van-form @submit="onSubmit" class="form" :disabled="disabled">
<!-- <van-field-->
<!-- v-model="formData.cjsbQk"-->
<!-- readonly-->
<!-- label="所属部门"-->
<!-- placeholder="请输入必到点名称"-->
<!-- />-->
<van-field
v-model="formData.bddMc"
name="bddMc"
required
label="必到点名称"
placeholder="请输入必到点名称"
:rules="[{ required: true, message: '请输入必到点名称' }]"
/>
<van-field
v-model="formData.mc"
name="mc"
required
is-link
readonly
label="所属方格"
placeholder="请输入必到点名称"
:rules="[{ required: true, message: '请输入必到点名称' }]"
@click="visible = true"
/>
<van-field
v-model="formData.bddDz"
name="bddDz"
required
label="地址"
placeholder="请输入必到点名称"
:rules="[{ required: true, message: '请输入必到点名称' }]"
/>
<van-field
v-model="formData.jd"
name="jd"
required
label="经度"
placeholder="请输入经度"
:rules="[{ required: true, message: '请输入经度' }]"
/>
<van-field
v-model="formData.wd"
name="wd"
required
label="纬度"
placeholder="请输入纬度"
:rules="[{ required: true, message: '请输入纬度' }]"
/>
<div class="mapWrapper">
<div class="label">地图选点</div>
<div style="height: 40vh; margin-top: 2vw">
<gd-map />
</div>
</div>
<div class="btn">
<van-button
round
block
type="primary"
native-type="submit"
:loading="loading"
loading-type="spinner"
loading-text="保存中..."
>保存</van-button>
</div>
</van-form>
</div>
<custom-popup v-model="visible" @change="handleChange" />
</div>
</template>
<style scoped lang="scss">
.formWrapper {
margin-top: 13vw;
.mapWrapper {
padding: var(--van-cell-vertical-padding) var(--van-cell-horizontal-padding);
font-size: var(--van-cell-font-size);
color: var(--van-field-label-color);
.label {
margin-right: var(--van-field-label-margin-right);
width: var(--van-field-label-width);
}
.context {
margin-top: 2vw;
}
}
.btn {
position: fixed;
padding: 2vw;
bottom: 0;
left: 0;
width: calc(100% - 4vw);
}
}
</style>

View File

@ -0,0 +1,96 @@
<script setup>
import {computed, onMounted, ref} from "vue";
import Search from "@/components/search.vue";
import {getSelectList} from "@/api/collectPage";
import emitter from "@/utils/eventBus";
const props = defineProps({
modelValue: {
type: Boolean,
default: false
},
position: {
type: String,
default: 'bottom'
},
})
const emits = defineEmits(["update:modelValue", "change"]);
const visible = computed({
get: function () {
return props.modelValue;
},
set: function (val) {
emits("update:modelValue", val)
}
})
const visibleEmpty = ref(false)
const searchValue = ref("")
const radioChecked = ref("")
const list = ref([])
const onSearch = (value) => {
list.value = []
getSelectListData(value)
}
const onRadionChange = (value) => {
emits('change', value)
const { x1, y1, x2, y2, id, zxX, zxY, mc } = value
const centerPoint = [zxX, zxY]
const position = [[Number(x1),Number(y1)],[Number(x2),Number(y2)]]
const text = mc
const obj = [{ position: position, text, id, userData: value}]
emitter.emit("echoPlane", { fontColor:'#12fdb8',coords: obj, type:'rectangle', flag:'zdxl_fzyc', color:'rgba(2,20,51,0.5)', linecolor:'#1C97FF'})
emitter.emit("setMapCenter", { location: centerPoint, zoomLevel: 14 });
}
// 获取数据
const getSelectListData = async (mc) => {
try {
const res = await getSelectList({ mc });
if (res?.length > 0) {
list.value = res || []
visibleEmpty.value = false
} else {
visibleEmpty.value = true
}
} catch (error) {
visibleEmpty.value = true
}
}
onMounted(() => {
getSelectListData()
})
</script>
<template>
<van-popup v-model:show="visible" :position="position">
<search placeholder="请输入方格名称" v-model="searchValue" @update:modelValue="onSearch" />
<div class="selectWrapper">
<van-radio-group v-model="radioChecked">
<van-cell-group>
<van-cell v-for="item in list" clickable :key="item" :title="item?.mc" :border="false">
<template #right-icon>
<van-radio :name="item?.id" @click="onRadionChange(item)" />
</template>
</van-cell>
</van-cell-group>
</van-radio-group>
<van-empty description="没有数据" image="default" v-if="list.length <= 0 && visibleEmpty" />
</div>
</van-popup>
</template>
<style scoped lang="scss">
.selectWrapper {
height: 80vw;
overflow: auto;
}
</style>

View File

@ -0,0 +1,52 @@
<script setup>
const props = defineProps({
list: {
type: Array,
required: true,
default: () => []
}
})
const emits = defineEmits(["onConfirm"]);
</script>
<template>
<div class="item-wrapper">
<template v-for="(item, index) in list" :key="index">
<div class="item">
<div class="title">{{ item.bddMc }}</div>
<div class="infoWrapper">
<!-- <div class="mt">所属部门{{ item.sssgaj }}</div>-->
<div class="mt">所属方格{{ item?.fgdwMc }}</div>
<div class="mt">地址{{ item.bddDz }}</div>
</div>
</div>
</template>
</div>
</template>
<style scoped lang="scss">
.item-wrapper {
margin: 2vw;
.item {
padding: 2vw;
border-top: 0.13333vw solid #f4f5f1;
.title {
font-size: 14px;
}
.mt {
margin-top: 2vw;
}
.infoWrapper {
font-size: 12px;
color: #999999;
}
}
}
</style>

View File

@ -0,0 +1,129 @@
<script setup>
import TopNav from "@/components/topNav.vue";
import Search from "@/components/search.vue";
import {onMounted, reactive, ref} from "vue";
import ListItemWrapper from "@/pages/collectPage/copmonents/listItemWrapper.vue";
import router from "@/router";
import {getSelectPage} from "@/api/collectPage";
const finished = ref(false);
const loading = ref(false);
const loadingRefresh = ref(false);
const searchValue = ref("")
const pageData = reactive({
pageSize: 10,
pageCurrent: 1,
total: 0,
})
const data = reactive({
list: []
})
const onSearch = (value) => {
loading.value = true;
pageData.pageCurrent = 1;
data.list = []
getData()
}
const onRefresh = () => {
loading.value = false;
loadingRefresh.value = true;
finished.value = false;
pageData.pageCurrent = 1;
data.list = []
getData()
}
const getData = async () => {
try {
const { total, ...ret } = pageData
const res = await getSelectPage({ ...ret, bddMc: searchValue.value })
if (res?.records.length > 0) {
data.list = data.list.concat(res?.records) || []
pageData.total = res?.total
loading.value = false;
}
loadingRefresh.value = false;
} catch (error) {
loading.value = false;
loadingRefresh.value = false;
}
}
const onLoad = () => {
if (data.list.length >= pageData?.total) {
finished.value = true;
return
}
pageData.pageCurrent++
getData()
}
onMounted(() => {
data.list = []
getData()
})
const handleTo = () => {
router.push("/collectAndAdd")
}
</script>
<template>
<div>
<TopNav navTitle="必到点采集列表" :showLeft="true" />
<van-sticky>
<div class="header">
<search placeholder="请输入部门、所属方格或必到点名称进行查询"
v-model="searchValue"
@update:modelValue="onSearch"
/>
</div>
</van-sticky>
<div class="content">
<van-pull-refresh v-model="loadingRefresh" @refresh="onRefresh">
<van-list v-model:loading="loading" :finished="finished" finished-text="" @load="onLoad" offset="1" :immediate-check="false">
<list-item-wrapper :list="data.list" />
<van-empty description="暂无采集数据" image="default" v-if="data.list.length <= 0 && loadingRefresh === false" />
</van-list>
</van-pull-refresh>
</div>
<div class="footer" @click="handleTo">
<van-button
round
native-type="submit"
block
type="primary"
>
新增必到点采集
</van-button>
</div>
</div>
</template>
<style scoped lang="scss">
@import "@/assets/styles/mixin.scss";
.header {
margin-top: 13vw;
@include bg_color($background-color-theme);
}
.content {
margin-bottom: 16vw;
}
.footer {
position: fixed;
padding: 2vw;
bottom: 0;
left: 0;
width: calc(100% - 4vw);
}
</style>

View File

@ -31,7 +31,7 @@ const listData = ref([
text: '巡逻打卡', text: '巡逻打卡',
imgUrl: require("@/assets/home/xldk.png"), imgUrl: require("@/assets/home/xldk.png"),
type: 'xldk', type: 'xldk',
path: '/clock' path: '/patrolList'
}, },
{ {
text: '信息交互', text: '信息交互',
@ -39,6 +39,12 @@ const listData = ref([
type: 'zllz', type: 'zllz',
path: '/yyzx/zlzx/zlzxIndex' path: '/yyzx/zlzx/zlzxIndex'
}, },
{
text: '必到点采集',
imgUrl: require("@/assets/home/bddcj.png"),
type: 'bddcj',
path: '/collectPage'
},
{ {
text: '处警报送', text: '处警报送',
imgUrl: require("@/assets/home/dqwz.png"), imgUrl: require("@/assets/home/dqwz.png"),
@ -59,6 +65,8 @@ const changeOpen = (val) => {
case 'zllz': case 'zllz':
case 'grxx': case 'grxx':
case 'cjbs': case 'cjbs':
case 'bddcj':
case 'clockIn':
router.push(val.path) router.push(val.path)
break break
case 'rcpc': case 'rcpc':
@ -79,6 +87,7 @@ ul {
box-sizing: border-box; box-sizing: border-box;
overflow: hidden; overflow: hidden;
height: 100vh; height: 100vh;
overflow: auto;
li { li {
width: 48%; width: 48%;
@ -91,4 +100,4 @@ ul {
margin-bottom: 10px; margin-bottom: 10px;
} }
} }
</style> </style>

View File

@ -0,0 +1,76 @@
<script setup>
import router from "@/router";
const props = defineProps({
list: {
type: Array,
required: true,
default: () => []
}
})
const emits = defineEmits(["onConfirm"]);
const handleClockInPage = (item) => {
router.push({ path: '/clockInPage', query: { item: JSON.stringify(item?.bddList), id: item.id } });
}
</script>
<template>
<div class="item-wrapper">
<template v-for="(item, index) in list" :key="index">
<div class="item" @click="handleClockInPage(item)">
<div class="rowWrapper">
<div class="title">{{ item?.fgMc }}</div>
<div class="progress">50%</div>
</div>
<div class="rowWrapper mt co99 fz12">
<div>预警等级{{ item?.fgYjdj }}</div>
<div>任务日期{{ item?.rwRq }}</div>
</div>
<div class="rowWrapper mt co99 fz12">
<div>高发类型{{ item?.fgJqtjLx }}</div>
</div>
</div>
</template>
</div>
</template>
<style scoped lang="scss">
.item-wrapper {
margin: 2vw;
.item {
padding: 2vw;
border-top: 0.13333vw solid #f4f5f1;
.rowWrapper {
display: flex;
justify-content: space-between;
align-items: center;
.title {
font-size: 14px;
}
.progress {
font-weight: 400;
font-size: 3.73vw;
color: #3E6EE8;
}
}
.fz12 {
font-size: 3.2vw;
}
.co99 {
color: #999999;
}
.mt {
margin-top: 2vw;
}
}
}
</style>

View File

@ -0,0 +1,136 @@
<script setup>
import { ref, reactive, onMounted } from "vue";
import TopNav from "@/components/topNav.vue";
import Search from "@/components/search.vue";
import PatrolWrapper from "@/pages/patrolList/copmonents/patrolWrapper.vue";
import {fetchPatrolList} from "@/api/patrolList";
const finished = ref(false);
const loading = ref(false);
const loadingRefresh = ref(false);
const searchValue = ref("")
const pageData = reactive({
pageSize: 10,
pageCurrent: 1,
total: 0,
})
const data = reactive({
list: []
})
const onSearch = () => {
loading.value = true;
pageData.pageCurrent = 1;
data.list = []
getData()
}
const onRefresh = () => {
loading.value = false;
loadingRefresh.value = true;
finished.value = false;
pageData.pageCurrent = 1;
data.list = []
getData()
}
const onLoad = () => {
if (data.list.length >= pageData?.total) {
finished.value = true;
return
}
pageData.pageCurrent++
getData()
}
const parseAndJoinLx = (jsonString, type = 'lx') => {
if (!jsonString) return '';
try {
let data = jsonString;
// 如果是字符串尝试解析为JSON
if (typeof jsonString === 'string') {
data = JSON.parse(jsonString);
}
// 处理数组情况
if (Array.isArray(data)) {
return data.map(item => item?.[type]).filter(Boolean).join(",");
}
// 处理对象情况
if (typeof data === 'object' && data !== null) {
return data?.[type] || '';
}
return '';
} catch (error) {
console.warn('数据处理失败:', error);
return '';
}
};
const getData = async () => {
const { total, ...ret } = pageData
try {
const res = await fetchPatrolList({ ...ret, fgMc: searchValue.value })
if (res?.records.length > 0) {
data.list = data.list.concat(res?.records)?.map((item) => ({
...item,
fgJqtjLx: parseAndJoinLx(item?.fgJqtjLx, 'lx')
})) || []
pageData.total = res?.total
loading.value = false;
}
loadingRefresh.value = false;
} catch (error) {
loading.value = false;
loadingRefresh.value = false;
}
}
onMounted(() => {
getData()
})
</script>
<template>
<div>
<TopNav nav-title="巡逻列表" show-left />
<van-sticky>
<div class="header">
<search
:isSx="true"
placeholder="请输入方格名称进行查询"
v-model="searchValue"
@update:modelValue="onSearch"
/>
</div>
</van-sticky>
<div class="content">
<van-pull-refresh v-model="loadingRefresh" @refresh="onRefresh">
<van-list v-model:loading="loading" :finished="finished" finished-text="" @load="onLoad" offset="1" :immediate-check="false">
<patrol-wrapper :list="data?.list" />
<van-empty description="暂无采集数据" image="default" v-if="data.list.length <= 0 && loadingRefresh === false" />
</van-list>
</van-pull-refresh>
</div>
</div>
</template>
<style scoped lang="scss">
.header {
margin-top: 13vw;
}
.content {
margin-bottom: 16vw;
}
</style>

View File

@ -61,6 +61,26 @@ const routes = [{
name: "my", name: "my",
component: () => import("../pages/my/index"), component: () => import("../pages/my/index"),
}, },
{
path: "/collectPage",
name: "collectPage",
component: () => import("../pages/collectPage/index"),
},
{
path: "/collectAndAdd",
name: "collectAndAdd",
component: () => import("../pages/collectPage/collectAndAdd"),
},
{
path: "/clockInPage",
name: "clockInPage",
component: () => import("../pages/clockInPage/index"),
},
{
path: "/patrolList",
name: "patrolList",
component: () => import("../pages/patrolList/index"),
},
{ {
path: "/dqLocation", path: "/dqLocation",
name: "dqLocation", name: "dqLocation",
@ -499,4 +519,4 @@ const router = createRouter({
} }
}) })
export default router; export default router;

View File

@ -12,8 +12,8 @@ module.exports = {
port: 9528, port: 9528,
proxy: { proxy: {
'/mosty-api': { '/mosty-api': {
target: "http://118.122.165.45:35623", // target: "http://118.122.165.45:35623",
// target: "http://172.20.19.54:8006", target: "http://192.168.1.8:8006",
changeOrigin: true, changeOrigin: true,
}, },
} }
@ -29,4 +29,4 @@ module.exports = {
} }
} }
}, },
}; };