下发任务
This commit is contained in:
BIN
node_modules.zip
BIN
node_modules.zip
Binary file not shown.
@ -8,6 +8,13 @@ export function fetchPatrolList(params) {
|
|||||||
params
|
params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 获取任务中心列表
|
||||||
|
export function fetchTaskList(params) {
|
||||||
|
return service({
|
||||||
|
url: `${api}/tbZdxlFgxlrw/selectPage`,
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
// 获取巡逻详情
|
// 获取巡逻详情
|
||||||
export function selectByBBdId(params) {
|
export function selectByBBdId(params) {
|
||||||
return service({
|
return service({
|
||||||
|
|||||||
@ -33,6 +33,12 @@ const listData = ref([
|
|||||||
type: 'xldk',
|
type: 'xldk',
|
||||||
path: '/patrolList'
|
path: '/patrolList'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: '任务中心',
|
||||||
|
imgUrl: require("@/assets/home/xldk.png"),
|
||||||
|
type: 'rwzx',
|
||||||
|
path: '/taskList'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: '信息交互',
|
text: '信息交互',
|
||||||
imgUrl: require("@/assets/home/zllz.png"),
|
imgUrl: require("@/assets/home/zllz.png"),
|
||||||
@ -66,6 +72,7 @@ const changeOpen = (val) => {
|
|||||||
case 'grxx':
|
case 'grxx':
|
||||||
case 'cjbs':
|
case 'cjbs':
|
||||||
case 'bddcj':
|
case 'bddcj':
|
||||||
|
case 'rwzx':
|
||||||
case 'clockIn':
|
case 'clockIn':
|
||||||
router.push(val.path)
|
router.push(val.path)
|
||||||
break
|
break
|
||||||
|
|||||||
@ -4,6 +4,10 @@ const props = defineProps({
|
|||||||
type: Array,
|
type: Array,
|
||||||
required: true,
|
required: true,
|
||||||
default: () => []
|
default: () => []
|
||||||
|
},
|
||||||
|
showReceive: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -17,19 +21,13 @@ const handleClockInPage = (item) => {
|
|||||||
<template>
|
<template>
|
||||||
<div class="item-wrapper">
|
<div class="item-wrapper">
|
||||||
<template v-for="(item, index) in list" :key="index">
|
<template v-for="(item, index) in list" :key="index">
|
||||||
<div class="item" @click="handleClockInPage(item)">
|
<div class="card" @click="handleClockInPage(item)">
|
||||||
<div class="rowWrapper">
|
<div class="title">*************任务</div>
|
||||||
<div class="title">{{ item?.fgMc }}</div>
|
<div class="row">
|
||||||
<div class="progress">{{ item?.bddAllProgress || 0 }}%</div>
|
<div class="col">方格编号:{{ item?.fgId || '04' }}</div>
|
||||||
</div>
|
<div class="col right">任务日期:{{ item?.rwRq }}</div>
|
||||||
|
|
||||||
<div class="rowWrapper mt co99 fz12">
|
|
||||||
<div>预警等级:{{ item?.fgYjdjLabel }}</div>
|
|
||||||
<div>任务日期:{{ item?.rwRq }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="rowWrapper mt co99 fz12">
|
|
||||||
<div>高发类型:{{ item?.fgJqtjLx }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="btn" v-if="showReceive" @click.stop="handleClockInPage(item)">领取</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@ -37,37 +35,50 @@ const handleClockInPage = (item) => {
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.item-wrapper {
|
.item-wrapper {
|
||||||
margin: 2vw;
|
padding: 3vw;
|
||||||
|
|
||||||
.item {
|
.card {
|
||||||
padding: 2vw;
|
background: #fff;
|
||||||
border-top: 0.13333vw solid #f4f5f1;
|
border-radius: 3.73vw;
|
||||||
|
padding: 4vw;
|
||||||
|
margin-bottom: 3vw;
|
||||||
|
box-shadow: 0 1.6vw 4vw rgba(0, 0, 0, 0.04);
|
||||||
|
|
||||||
.rowWrapper {
|
.title {
|
||||||
|
font-size: 4vw;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 3vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
margin-bottom: 4vw;
|
||||||
.title {
|
font-size: 3.4vw;
|
||||||
font-size: 14px;
|
color: #999;
|
||||||
}
|
|
||||||
|
|
||||||
.progress {
|
.col {
|
||||||
font-weight: 400;
|
&.right {
|
||||||
font-size: 3.73vw;
|
text-align: right;
|
||||||
color: #3E6EE8;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.fz12 {
|
.btn {
|
||||||
font-size: 3.2vw;
|
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);
|
||||||
|
|
||||||
.co99 {
|
&.disabled {
|
||||||
color: #999999;
|
background: #ccc;
|
||||||
}
|
box-shadow: none;
|
||||||
|
}
|
||||||
.mt {
|
|
||||||
margin-top: 2vw;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
89
src/pages/taskList/copmonents/patrolWrapper.vue
Normal file
89
src/pages/taskList/copmonents/patrolWrapper.vue
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
showReceive: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emits = defineEmits(["click", "claim"]);
|
||||||
|
|
||||||
|
const handleClockInPage = (item) => {
|
||||||
|
emits("click", item);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClaim = (item) => {
|
||||||
|
emits("claim", item);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="item-wrapper">
|
||||||
|
<template v-for="(item, index) in list" :key="index">
|
||||||
|
<div class="card" @click="handleClockInPage(item)">
|
||||||
|
<div class="title">*************任务</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">方格编号:{{ item?.fgId || '04' }}</div>
|
||||||
|
<div class="col right">任务日期:{{ item?.rwRq }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="btn" v-if="showReceive" @click.stop="handleClaim(item)">领取</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.item-wrapper {
|
||||||
|
padding: 3vw;
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 3.73vw;
|
||||||
|
padding: 4vw;
|
||||||
|
margin-bottom: 3vw;
|
||||||
|
box-shadow: 0 1.6vw 4vw rgba(0, 0, 0, 0.04);
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 4vw;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 3vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 4vw;
|
||||||
|
font-size: 3.4vw;
|
||||||
|
color: #999;
|
||||||
|
|
||||||
|
.col {
|
||||||
|
&.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
background: #ccc;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
266
src/pages/taskList/historyDetail.vue
Normal file
266
src/pages/taskList/historyDetail.vue
Normal 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>
|
||||||
289
src/pages/taskList/index.vue
Normal file
289
src/pages/taskList/index.vue
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, reactive, onMounted } from "vue";
|
||||||
|
import TopNav from "@/components/topNav.vue";
|
||||||
|
import Tabs from "@/components/tabs.vue";
|
||||||
|
import Search from "@/components/search.vue";
|
||||||
|
import PatrolWrapper from "./copmonents/patrolWrapper.vue";
|
||||||
|
import {fetchTaskList} from "@/api/patrolList";
|
||||||
|
import {getDictListByCode} from "@/api/common";
|
||||||
|
import router from "@/router";
|
||||||
|
import SxPopup from "@/components/SxPopup.vue";
|
||||||
|
import SelectTime from "@/components/SelectTime.vue";
|
||||||
|
import { hintToast } from "@/utils/tools";
|
||||||
|
const tabsIndex = ref(1);
|
||||||
|
const showPopup = ref(false);
|
||||||
|
const timeShow = ref(false);
|
||||||
|
const finished = ref(false);
|
||||||
|
const loading = ref(false);
|
||||||
|
const rwlx=ref('1')
|
||||||
|
const loadingRefresh = ref(false);
|
||||||
|
const searchValue = ref("")
|
||||||
|
const tabs = ref([
|
||||||
|
{
|
||||||
|
name: "警情任务",
|
||||||
|
value: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "自定义任务",
|
||||||
|
value: "2",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const pageData = reactive({
|
||||||
|
pageSize: 10,
|
||||||
|
pageCurrent: 1,
|
||||||
|
total: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
list: [],
|
||||||
|
dictList: [],
|
||||||
|
startTime: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const onSearch = () => {
|
||||||
|
loading.value = true;
|
||||||
|
pageData.pageCurrent = 1;
|
||||||
|
data.list = []
|
||||||
|
getData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const onRefresh = () => {
|
||||||
|
tabsIndex.value++;
|
||||||
|
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 handleClaim = (item) => {
|
||||||
|
hintToast("领取成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClockInPage = (item) => {
|
||||||
|
if (activeTab.value === 'history') {
|
||||||
|
router.push({ path: '/taskHistoryDetail', query: { id: item.id } });
|
||||||
|
} else {
|
||||||
|
router.push({ path: '/clockInPage', query: { id: item.id, current: pageData.pageCurrent } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const res = await fetchTaskList({ ...ret, fgMc: searchValue.value, rwRq: data.startTime,rwlx:rwlx.value })
|
||||||
|
if (res?.records.length > 0) {
|
||||||
|
data.list = data.list.concat(res?.records)?.map((item) => ({
|
||||||
|
...item,
|
||||||
|
fgJqtjLx: parseAndJoinLx(item?.fgJqtjLx, 'lx'),
|
||||||
|
fgYjdjLabel: data.dictList?.find(i => i.dm === item.fgYjdj)?.zdmc || item.fgYjdj
|
||||||
|
})) || []
|
||||||
|
|
||||||
|
pageData.total = res?.total
|
||||||
|
loading.value = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
loadingRefresh.value = false;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
loading.value = false;
|
||||||
|
loadingRefresh.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getDictList = async () => {
|
||||||
|
const res = await getDictListByCode({ dictCode: 'D_ZDXL_FGXLRW_YJDJ' })
|
||||||
|
if (res && res?.itemList?.length > 0) {
|
||||||
|
data.dictList = res?.itemList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//按类型查询
|
||||||
|
function onSelect(val) {
|
||||||
|
data.list = [];
|
||||||
|
pageData.pageCurrent = 1;
|
||||||
|
switch (val) {
|
||||||
|
case 0:
|
||||||
|
rwlx.value="1"
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rwlx.value="2"
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
getData();
|
||||||
|
finished.value = false;
|
||||||
|
}
|
||||||
|
const onSelectTime = (val) => {
|
||||||
|
data.startTime = val;
|
||||||
|
timeShow.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClickTime = () => {
|
||||||
|
timeShow.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeTab = ref('today');
|
||||||
|
const formatDate = (date) => {
|
||||||
|
const y = date.getFullYear();
|
||||||
|
const m = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
|
const d = String(date.getDate()).padStart(2, '0');
|
||||||
|
return `${y}-${m}-${d}`;
|
||||||
|
};
|
||||||
|
const setTab = (tab) => {
|
||||||
|
activeTab.value = tab;
|
||||||
|
// if (tab === 'today') {
|
||||||
|
// data.startTime = formatDate(new Date());
|
||||||
|
// } else {
|
||||||
|
// data.startTime = '';
|
||||||
|
// }
|
||||||
|
// pageData.pageCurrent = 1;
|
||||||
|
// data.list = [];
|
||||||
|
// getData();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onConfirm = () => {
|
||||||
|
pageData.pageCurrent = 1;
|
||||||
|
data.list = []
|
||||||
|
getData()
|
||||||
|
showPopup.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleReset = () => {
|
||||||
|
data.startTime = ""
|
||||||
|
onConfirm()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await getDictList()
|
||||||
|
await getData()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<TopNav nav-title="任务中心" show-left />
|
||||||
|
<van-sticky>
|
||||||
|
<div class="sticky_box">
|
||||||
|
<div class="segment">
|
||||||
|
<div class="segment-bg">
|
||||||
|
<div class="segment-item" :class="{ active: activeTab === 'today' }" @click="setTab('today')">当日任务</div>
|
||||||
|
<div class="segment-item" :class="{ active: activeTab === 'history' }" @click="setTab('history')">历史任务</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<search
|
||||||
|
:isSx="true"
|
||||||
|
placeholder="请输入方格名称进行查询"
|
||||||
|
v-model="searchValue"
|
||||||
|
@update:sx="showPopup = !showPopup"
|
||||||
|
@update:modelValue="onSearch"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</van-sticky>
|
||||||
|
|
||||||
|
<sx-popup :showPopup="showPopup" :p_top="110" @update:close="showPopup = false"
|
||||||
|
@update:onConfirm="onConfirm" @reset="handleReset">
|
||||||
|
<div class="time_box">
|
||||||
|
<van-field
|
||||||
|
v-model="data.startTime"
|
||||||
|
label-width="60px"
|
||||||
|
placeholder="请选择时间"
|
||||||
|
input-align="left"
|
||||||
|
right-icon="arrow-down"
|
||||||
|
readonly
|
||||||
|
@click.stop="onClickTime"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</sx-popup>
|
||||||
|
|
||||||
|
<select-time v-if="timeShow" time-type="选择任务日期" @update:time="onSelectTime" @update:cancelTime="timeShow = false" />
|
||||||
|
|
||||||
|
<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" :show-receive="activeTab === 'today'" @click="handleClockInPage" @claim="handleClaim" />
|
||||||
|
|
||||||
|
<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">
|
||||||
|
.time_box {
|
||||||
|
padding: 0 3vw 3vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.segment {
|
||||||
|
padding: 0 4vw 3vw;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-top: 13.5vw;
|
||||||
|
.segment-bg {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
background: #f2f3f5;
|
||||||
|
border-radius: 6vw;
|
||||||
|
padding: 1vw;
|
||||||
|
}
|
||||||
|
.segment-item {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
padding: 2.5vw 0;
|
||||||
|
border-radius: 5vw;
|
||||||
|
font-size: 3.73vw;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
.segment-item.active {
|
||||||
|
color: #ffffff;
|
||||||
|
background: linear-gradient(90deg, #28A5FF 0%, #3E6EE8 100%);
|
||||||
|
box-shadow: 0 1vw 2vw rgba(62, 110, 232, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
margin-top: 13vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin-bottom: 16vw;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
1026
src/router/index.js
1026
src/router/index.js
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user