下发任务

This commit is contained in:
给我
2026-03-13 17:20:07 +08:00
parent cda1058362
commit bb9ad84539
8 changed files with 1222 additions and 545 deletions

View File

@ -0,0 +1,266 @@
<script setup>
import TopNav from "@/components/topNav.vue";
import { onMounted, ref, reactive, onUnmounted } from "vue";
import { useRoute } from "vue-router";
import { selectByBBdId, fetchSelectListByBddxlrwId } from "@/api/patrolList";
import { qcckGet } from "@/api/qcckApi";
import { getBase64, hintToast } from "@/utils/tools";
import { ImagePreview } from "vant";
import MapWrapper from "@/pages/clockInPage/components/mapWrapper.vue";
import emitter from "@/utils/eventBus";
const route = useRoute();
const info = reactive({
fgId: "",
rwRq: "",
dkjgsj: "",
bddList: []
});
const points = ref([]);
const imageMap = new Map();
const getImageUrl = async (fileId) => {
if (!fileId) return null;
if (imageMap.has(fileId)) return imageMap.get(fileId);
const res = await qcckGet({}, `/mosty-base/minio/file/download/${fileId}`);
if (res?.url) {
const base64 = await getBase64("", res.url);
imageMap.set(fileId, base64);
return base64;
}
return null;
};
const preview = (url) => {
if (url) ImagePreview([url]);
};
const loadData = async () => {
const id = route.query.id || "";
const detail = await selectByBBdId({ bbdId: id });
if (detail) {
info.fgId = detail.fgId;
info.rwRq = detail.rwRq;
info.dkjgsj = detail.dkjgsj;
info.bddList = detail.bddList || [];
}
const res = await fetchSelectListByBddxlrwId({ bddxlrwId: id });
if (Array.isArray(res)) {
const arr = [];
const mapPoints = [];
for (const item of res) {
const imgUrl = item.dkJsFj ? await getImageUrl(item.dkJsFj) : null;
arr.push({
title: "*************点位",
dkKsSj: item.dkKsSj,
dkJsSj: item.dkJsSj, // Use end time as check-in time for display if available
isChecked: !!item.dkJsFj, // Assume checked in if there is an image
imgUrlDkJsFj: imgUrl
});
// Collect coordinates for map
if (item.dkJsJd && item.dkJsWd) {
mapPoints.push({ jd: item.dkJsJd, wd: item.dkJsWd });
}
}
points.value = arr;
// Plot on map
if (mapPoints.length > 0) {
setTimeout(() => {
emitter.emit("deletePointArea", "historyPoints");
emitter.emit("addPointArea", {
coords: mapPoints,
icon: require("@/assets/images/11.png"), // Reuse existing icon or use a generic one
flag: "historyPoints",
});
// Center map on first point
emitter.emit("setMapCenter", {
location: [mapPoints[0].jd, mapPoints[0].wd],
zoomLevel: 14
});
}, 500);
}
}
};
onMounted(async () => {
await loadData();
});
onUnmounted(() => {
emitter.emit("deletePointArea", "historyPoints");
});
</script>
<template>
<div class="page-container">
<TopNav nav-title="任务详情" show-left />
<div class="content">
<!-- Header Card -->
<div class="card header-card">
<div class="title">*************任务</div>
<div class="row info-row">
<div class="sub">方格编号{{ info.fgId || '04' }}</div>
<div class="sub">任务日期{{ info.rwRq }}</div>
</div>
<div class="sub">打卡间隔时间{{ info.dkjgsj ? info.dkjgsj + 'min' : '100min' }}</div>
</div>
<!-- Point List -->
<div class="list">
<div v-for="(item, index) in points" :key="index" class="card point-card">
<div class="row header-row">
<div class="name">{{ item.title }}</div>
<div v-if="item.isChecked" class="status-tag">已打卡</div>
</div>
<!-- Checked In: Show Image -->
<div v-if="item.isChecked && item.imgUrlDkJsFj" class="img-container" @click="preview(item.imgUrlDkJsFj)">
<img :src="item.imgUrlDkJsFj" alt="打卡图片" />
<div class="time-overlay">{{ item.dkJsSj }}</div>
</div>
<!-- Not Checked In: Show Button (Visual only) -->
<div v-else class="btn-container">
<div class="btn">打卡拍照</div>
</div>
</div>
</div>
<!-- Map Section -->
<div class="card map-card">
<div class="map-title">当前位置</div>
<div class="map-box">
<MapWrapper />
</div>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.page-container {
min-height: 100vh;
background: #F5F7FA;
padding-bottom: 5vw;
}
.content {
padding: 16vw 3vw 5vw; // Top padding for fixed nav
}
.card {
background: #fff;
border-radius: 3.73vw;
padding: 4vw;
margin-bottom: 3vw;
box-shadow: 0 1.6vw 4vw rgba(0, 0, 0, 0.04);
}
.header-card {
.title {
font-size: 4.2vw;
font-weight: bold;
color: #333;
margin-bottom: 3vw;
}
.info-row {
display: flex;
justify-content: space-between;
margin-bottom: 1.5vw;
}
.sub {
font-size: 3.4vw;
color: #999;
}
}
.point-card {
.header-row {
display: flex;
justify-content: flex-start;
align-items: center;
margin-bottom: 3vw;
.name {
font-size: 4vw;
font-weight: bold;
color: #333;
margin-right: 2vw;
}
.status-tag {
font-size: 3vw;
color: #3E6EE8;
border: 1px solid #3E6EE8;
padding: 0.5vw 1.5vw;
border-radius: 1vw;
}
}
.img-container {
position: relative;
width: 100%;
height: 40vw;
border-radius: 2vw;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
.time-overlay {
position: absolute;
top: 2vw;
left: 2vw;
color: #fff;
font-size: 3.5vw;
text-shadow: 0 1px 2px rgba(0,0,0,0.5);
}
}
.btn-container {
margin-top: 2vw;
.btn {
height: 11vw;
line-height: 11vw;
text-align: center;
border-radius: 6vw;
color: #ffffff;
background: linear-gradient(90deg, #28A5FF 0%, #3E6EE8 100%);
font-size: 4vw;
box-shadow: 0 2vw 4vw rgba(62, 110, 232, 0.3);
}
}
}
.map-card {
padding: 0; // Remove default padding for map card to let map fill or have custom padding
overflow: hidden;
.map-title {
padding: 4vw;
font-size: 4vw;
font-weight: bold;
color: #333;
border-bottom: 1px solid #eee;
}
.map-box {
height: 50vw;
width: 100%;
position: relative;
// Adjust MapWrapper internal style via deep selector if needed,
// but MapWrapper has fixed height in its scoped style usually.
// We might need to override it.
:deep(.mapWrapper) {
margin-top: 0;
height: 100%;
}
}
}
</style>