This commit is contained in:
2026-04-11 19:11:45 +08:00
parent afa0be792a
commit f0c5ed9557
3 changed files with 164 additions and 24 deletions

View File

@ -124,6 +124,10 @@ export function MapUtil(map) {
let textTitle = item.jzMc ? item.jzMc : item.fzrXm + '警组';
if(flag == 'sbwz_car' || flag == 'sbwz_sb' ) textTitle = item.sbmc;
if(flag == 'gapText') textTitle = text
// 支持打卡点名称
if(item.bxdMc) textTitle = item.bxdMc;
// 支持通用标题字段
if(item.title) textTitle = item.title;
// 设置样式
const el = document.createElement('div');
el.className = 'makerTitle';

View File

@ -8,12 +8,25 @@
<PrpcPopup ref="prpc" :key="pcKey + 'pc'" />
</template>
<script setup>
import { ref, onMounted,nextTick } from "vue";
import { ref, onMounted, nextTick } from "vue";
import { useRouter, useRoute } from "vue-router";
import PrpcPopup from "../spsHome/components/prpcPopup.vue";
import { getMybbTodayNew } from "@/api/common";
import { getItem, setItem } from "@/utils/storage";
const router = useRouter();
const pcKey = ref(0);
const prpc = ref(null);
const userInfo = getItem("userInfo") || {};
onMounted(() => {
getMybbTodayNew().then((res) => {
if (!res) return;
userInfo.bbId = res.id;
userInfo.jzId = res.jzId;
userInfo.jzMc = res.jzMc;
setItem("userInfo", userInfo);
});
});
const listData = ref([
{
text: '勤务报备',
@ -27,12 +40,6 @@ const listData = ref([
type: 'rcpc',
path: '/yyzx/xfbb/addXfbb'
},
{
text: '巡逻打卡',
imgUrl: require("@/assets/home/xldk.png"),
type: 'xldk',
path: '/patrolList'
},
{
text: '任务中心',
imgUrl: require("@/assets/home/xldk.png"),
@ -45,12 +52,6 @@ const listData = ref([
type: 'zllz',
path: '/yyzx/zlzx/zlzxIndex'
},
{
text: '必到点采集',
imgUrl: require("@/assets/home/bddcj.png"),
type: 'bddcj',
path: '/collectPage'
},
{
text: '处警报送',
imgUrl: require("@/assets/home/dqwz.png"),
@ -67,11 +68,9 @@ const listData = ref([
const changeOpen = (val) => {
switch (val.type) {
case 'qwbb':
case 'xldk':
case 'zllz':
case 'grxx':
case 'cjbs':
case 'bddcj':
case 'rwzx':
case 'clockIn':
router.push(val.path)

View File

@ -17,6 +17,12 @@ const listQuery = ref({
jd: "",
wd: "",
});
const leaveQuery = ref({
id: "",
lkjd: "",
lkwd: "",
lktp: "",
});
const zxdksj = ref("");
const dwIndex = ref();
const imageMap = new Map();
@ -66,10 +72,11 @@ const loadData = async () => {
linecolor: "#1C97FF",
});
emitter.emit("setMapCenter", { location: centerPoint, zoomLevel: 12 });
// 获取所有唯一的图片ID
// 获取所有唯一的图片ID(打卡图片和离开图片)
const uniqueImageIds = new Set();
detail.bxds?.forEach((item) => {
if (item?.dktp) uniqueImageIds.add(item.dktp);
if (item?.lktp) uniqueImageIds.add(item.lktp);
});
// 批量获取图片URL
const imageEntries = await Promise.allSettled(
@ -93,11 +100,31 @@ const loadData = async () => {
pointsList.value = detail.bxds.map((item, index) => ({
...item,
imgUrlDkFj: item?.dktp ? imageMap.get(item.dktp) : null,
lkImgUrl: item?.lktp ? imageMap.get(item.lktp) : null,
}));
// 为每个必到点添加图片URL
zxdksj.value = detail.zxdksj;
info.value = detail.fgrw;
listQuery.value.fgrwid = info.value.id;
// 在地图上显示打卡点
const dkPoints = detail.bxds
?.filter((item) => item.jd && item.wd)
.map((item) => ({
jd: item.jd,
wd: item.wd,
bxdMc: item.bxdMc,
dkzt: item.dkzt,
}));
if (dkPoints && dkPoints.length > 0) {
emitter.emit("deletePointArea", "historyPoints");
emitter.emit("addPointArea", {
coords: dkPoints,
icon: require("../../assets/images/11.png"),
flag: "historyPoints",
showTitle: true,
});
}
}
};
//获取当前位置信息
@ -134,8 +161,20 @@ function isInThirtyMinutes(targetTime, jgsj) {
}
return flag
}
// 检查是否存在已打卡但未离开的点
const hasUnfinishedCheckIn = () => {
// dksj: 打卡时间lksj: 离开时间
// 已打卡且有打卡时间,但没有离开时间,说明未完成
return pointsList.value.some((item) => item.dksj && !item.lksj);
};
// 点击上传
const photoFn = (val, index) => {
// 检查是否存在已打卡但未离开的点
const unfinishedPoint = pointsList.value.find((item) => item.dksj && !item.lksj);
if (unfinishedPoint) {
hintToast(`请先完成【${unfinishedPoint.bxdMc || '上一个点'}】的离开打卡`);
return;
}
dwIndex.value = index;
listQuery.value.bxdid = val.bxdid;
// 判断此任务最新打卡时间如果在打卡间隔时间之后才能继续打卡
@ -181,14 +220,76 @@ const handleClick = () => {
loadData()
});
};
// 检查是否可以离开打卡(当前时间要大于打卡时间+打卡间隔时间)
const canLeave = (dksj, dkjgsj) => {
if (!dksj) return false;
const now = new Date();
const dkTime = new Date(dksj);
const minLeaveTime = new Date(dkTime.getTime() + Number(dkjgsj || 0) * 60 * 1000);
return now.getTime() >= minLeaveTime.getTime();
};
// 获取剩余等待时间(分钟)
const getLeaveWaitTime = (dksj, dkjgsj) => {
if (!dksj) return 0;
const now = new Date();
const dkTime = new Date(dksj);
const minLeaveTime = new Date(dkTime.getTime() + Number(dkjgsj || 0) * 60 * 1000);
const diff = minLeaveTime.getTime() - now.getTime();
return Math.ceil(diff / 1000 / 60);
};
// 离开打卡拍照
const leavePhotoFn = (item, index) => {
// 判断时间间隔
if (!canLeave(item.dksj, info.value.dkjgsj)) {
const waitMin = getLeaveWaitTime(item.dksj, info.value.dkjgsj);
hintToast(`请于${waitMin}分钟后离开打卡`);
return;
}
dwIndex.value = index;
leaveQuery.value.id = item.id;
const { lng, lat } = getLocation();
leaveQuery.value.lkjd = lng;
leaveQuery.value.lkwd = lat;
try {
bridge.pZ("leavePhoto");
} catch (err) {
console.log(err, "err");
}
};
// 离开打卡提交
const handleLeaveSubmit = () => {
qcckPost(leaveQuery.value, "/mosty-yjzl/tbZdyrw/zdyLkdk")
.then((res) => {
if (res) {
hintToast(`离开打卡成功`);
loadData();
}
})
.catch((err) => {
console.log(err, "err");
hintToast("离开打卡失败");
});
};
function setimage_base64(pzid, base64) {
pointsList.value[dwIndex.value].imgUrlDkFj = `data:image/jpeg;base64,${base64}`;
qcckPost({ base64: base64 }, "/mosty-base/minio/image/upload/base64").then(
(res) => {
listQuery.value.dktp = res;
handleClick();
},
);
if (pzid === "leavePhoto") {
// 离开打卡
pointsList.value[dwIndex.value].lkImgUrl = `data:image/jpeg;base64,${base64}`;
qcckPost({ base64: base64 }, "/mosty-base/minio/image/upload/base64").then(
(res) => {
leaveQuery.value.lktp = res;
handleLeaveSubmit();
},
);
} else {
// 打卡
pointsList.value[dwIndex.value].imgUrlDkFj = `data:image/jpeg;base64,${base64}`;
qcckPost({ base64: base64 }, "/mosty-base/minio/image/upload/base64").then(
(res) => {
listQuery.value.dktp = res;
handleClick();
},
);
}
}
onMounted(async () => {
await loadData();
@ -228,12 +329,23 @@ onUnmounted(() => {
<!-- Checked In: Show Image -->
<div v-if="item.imgUrlDkFj" class="img-container" @click="preview(item.imgUrlDkFj)">
<img :src="item.imgUrlDkFj" alt="打卡图片" />
<div class="time-overlay">{{ item.dksj }}</div>
<div class="time-overlay">打卡{{ item.dksj }}</div>
</div>
<!-- Not Checked In: Show Button (Visual only) -->
<div v-else class="btn-container">
<div class="btn" @click="photoFn(item, index)">打卡拍照</div>
</div>
<!-- Leave Check-in Button: Show after checked in and not left yet -->
<div v-if="item.imgUrlDkFj && !item.lkjd" class="btn-container leave-btn-container">
<div class="btn leave-btn" @click="leavePhotoFn(item, index)">离开打卡</div>
</div>
<!-- Leave Image: Show if already left -->
<div v-if="item.lkjd && item.lkImgUrl" class="img-container leave-img" @click="preview(item.lkImgUrl)">
<img :src="item.lkImgUrl" alt="离开图片" />
<div class="time-overlay leave-time-overlay">离开{{ item.lksj }}</div>
</div>
<!-- Leave time without image -->
<div v-else-if="item.lkjd && !item.lkImgUrl" class="leave-time">离开时间{{ item.lksj }}</div>
</div>
</div>
<!-- Map Section -->
@ -332,6 +444,16 @@ onUnmounted(() => {
}
}
.leave-img {
margin-top: 2vw;
.leave-time-overlay {
background: rgba(255, 107, 53, 0.8);
padding: 0.5vw 1.5vw;
border-radius: 1vw;
}
}
.btn-container {
margin-top: 2vw;
@ -346,6 +468,21 @@ onUnmounted(() => {
box-shadow: 0 2vw 4vw rgba(62, 110, 232, 0.3);
}
}
.leave-btn-container {
margin-top: 2vw;
.leave-btn {
background: linear-gradient(90deg, #ff8c28 0%, #ff6b35 100%);
box-shadow: 0 2vw 4vw rgba(255, 107, 53, 0.3);
}
}
.leave-time {
margin-top: 2vw;
font-size: 3.4vw;
color: #ff6b35;
}
}
.map-card {