|
|
@@ -0,0 +1,837 @@
|
|
|
+<template>
|
|
|
+ <div class="task-page" :style="{ height: `calc(100vh - ${tabBarHeight}px)` }">
|
|
|
+ <div class="task-top">
|
|
|
+ <div class="map-container" ref="mapContainer"></div>
|
|
|
+ </div>
|
|
|
+ <div class="task-list">
|
|
|
+ <div class="list-filter">
|
|
|
+ <div class="filter-item" :class="{ active: activeIndex === 0 }" @click="handleActiveFilter(0)">
|
|
|
+ 待确认({{ taskCounts[0] || 0 }})
|
|
|
+ </div>
|
|
|
+ <div class="filter-item" :class="{ active: activeIndex === 2 }" @click="handleActiveFilter(2)">
|
|
|
+ 已确认({{ taskCounts[2] || 0 }})
|
|
|
+ </div>
|
|
|
+ <div class="filter-item" :class="{ active: activeIndex === 3 }" @click="handleActiveFilter(3)">
|
|
|
+ 待提醒({{ taskCounts[3] || 0 }})
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="select-group">
|
|
|
+ <el-select
|
|
|
+ class="select-item"
|
|
|
+ v-model="selectParma.farmWorkTypeId"
|
|
|
+ placeholder="用户类型"
|
|
|
+ @change="getSimpleList"
|
|
|
+ >
|
|
|
+ <el-option v-for="item in farmWorkTypeList" :key="item.id" :label="item.name" :value="item.id" />
|
|
|
+ </el-select>
|
|
|
+ <el-select
|
|
|
+ class="select-item"
|
|
|
+ v-model="selectParma.districtCode"
|
|
|
+ placeholder="切换作物"
|
|
|
+ @change="getSimpleList"
|
|
|
+ >
|
|
|
+ <el-option v-for="item in districtList" :key="item.code" :label="item.name" :value="item.code" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <!-- 任务列表 -->
|
|
|
+ <div class="work-task-list" v-loading="loading" element-loading-background="rgba(0, 0, 0, 0.3)">
|
|
|
+ <div class="task-item" v-for="(item, index) in taskList" :key="index" :class="isTimeoutItem(index) ? 'timeout-item' : ''" @click="handleItem(item, index)">
|
|
|
+ <div class="item-title">
|
|
|
+ <img class="task-icon" src="@/assets/img/home/task.png" alt="">
|
|
|
+ <span class="title-text">{{ item.operation?.name }}</span>
|
|
|
+ <span class="task-status" :class="`task-status--${item.operation?.type}`">{{ item.operation?.typeName }}</span>
|
|
|
+ </div>
|
|
|
+ <span class="task-tag timeout" v-if="isTimeoutItem(index)">
|
|
|
+ <el-icon><WarningFilled /></el-icon>
|
|
|
+ {{ getTimeoutText() }}
|
|
|
+ </span>
|
|
|
+ <span class="task-tag" v-else>
|
|
|
+ {{ activeStatus }}
|
|
|
+ </span>
|
|
|
+ <div class="item-content">
|
|
|
+ <div class="item-info">
|
|
|
+ <div class="info-item">
|
|
|
+ <div class="info-name">负责人:</div><span class="val-text">
|
|
|
+ 某某某、某某某</span>
|
|
|
+ </div>
|
|
|
+ <div class="info-item">
|
|
|
+ <div class="info-name">农情研判:</div><span class="val-text">
|
|
|
+ {{ item.operation?.work_reason }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="info-item" v-if="mode !== 'review'">
|
|
|
+ <div class="info-name">药物处方:</div><span class="val-text">
|
|
|
+ {{ item.operation?.drug }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="excutor-info">
|
|
|
+ <div class="excutor-info-top">
|
|
|
+ <executor-header :name="getExecutorName(index)" :phone="getExecutorPhone(index)"
|
|
|
+ :avatar="getExecutorAvatar(index)" />
|
|
|
+ </div>
|
|
|
+ <div class="executor-stats">
|
|
|
+ <div class="stat-cell">
|
|
|
+ <div class="stat-value">
|
|
|
+ {{ item.time ? formatGMTToYMD(item.time) : "--" }}
|
|
|
+ </div>
|
|
|
+ <div class="stat-label">执行时间</div>
|
|
|
+ </div>
|
|
|
+ <div class="cell-line"></div>
|
|
|
+ <div class="stat-cell">
|
|
|
+ <div class="stat-value">{{ item.geohash_sample || "--" }}</div>
|
|
|
+ <div class="stat-label">执行区域</div>
|
|
|
+ </div>
|
|
|
+ <div class="cell-line"></div>
|
|
|
+ <div class="stat-cell">
|
|
|
+ <div class="stat-value">{{ item.operation?.machine_code || "--" }}</div>
|
|
|
+ <div class="stat-label">执行农机</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="unqualified-reason" v-if="activeStatus === '未达标'">
|
|
|
+ 未达标原因:{{ item.operation?.reason || "未在合适时间执行,药液未充分喷撒吸收" }}
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div
|
|
|
+ class="compare-imgs"
|
|
|
+ v-if="activeStatus === '未达标' && (item.beforeImage || item.afterImage)"
|
|
|
+ @click.stop
|
|
|
+ >
|
|
|
+ <div class="img-tag">前</div>
|
|
|
+ <div class="img-tag right-tag">后</div>
|
|
|
+ <div class="img-item" v-if="item.beforeImage">
|
|
|
+ <img :src="getWorkImageUrl(item.beforeImage)" alt="" />
|
|
|
+ </div>
|
|
|
+ <div class="img-item" v-if="item.afterImage">
|
|
|
+ <img :src="getWorkImageUrl(item.afterImage)" alt="" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="btn-group" v-if="getItemStatusButtons(index).length">
|
|
|
+ <div v-for="btn in getItemStatusButtons(index)" :key="btn.label" class="edit-btn" :class="btn.type"
|
|
|
+ @click.stop="handleStatusBtn(btn, item, index)">
|
|
|
+ {{ btn.label }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="empty-tip" v-if="!loading && taskList.length === 0">暂无数据</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- <upload-execute ref="uploadExecuteRef" :onlyShare="onlyShare" @uploadSuccess="handleUploadSuccess" /> -->
|
|
|
+ <!-- 服务报价单 -->
|
|
|
+ <!-- <price-sheet-popup :key="activeIndex" ref="priceSheetPopupRef"></price-sheet-popup> -->
|
|
|
+ <!-- 新增:激活上传弹窗 -->
|
|
|
+ <!-- <active-upload-popup ref="activeUploadPopupRef" @handleUploadSuccess="handleUploadSuccess"></active-upload-popup> -->
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { computed, nextTick, onActivated, onMounted, ref, watch } from "vue";
|
|
|
+import { useRoute } from "vue-router";
|
|
|
+import { useStore } from "vuex";
|
|
|
+import IndexMap from "../farm_manage/map/index";
|
|
|
+import { useRouter } from "vue-router";
|
|
|
+import { WarningFilled } from "@element-plus/icons-vue";
|
|
|
+import { ElMessage } from "element-plus";
|
|
|
+import ExecutorHeader from "./components/ExecutorHeader.vue";
|
|
|
+import config from "@/api/config.js";
|
|
|
+
|
|
|
+const store = useStore();
|
|
|
+const router = useRouter();
|
|
|
+const route = useRoute();
|
|
|
+const indexMap = new IndexMap();
|
|
|
+const mapContainer = ref(null);
|
|
|
+const tabBarHeight = computed(() => store.state.home.tabBarHeight);
|
|
|
+const selectParma = ref({
|
|
|
+ farmWorkTypeId: null,
|
|
|
+ districtCode: null,
|
|
|
+});
|
|
|
+
|
|
|
+// 任务列表数据(用于显示,可能被筛选)
|
|
|
+const taskList = ref([
|
|
|
+ {
|
|
|
+ time: "Fri, 22 May 2026 00:00:00 GMT",
|
|
|
+ geohash_sample: "ws0gs49ns213",
|
|
|
+ operation: {
|
|
|
+ name: "冬季清园",
|
|
|
+ type: "1",
|
|
|
+ typeName: "标准类",
|
|
|
+ work_reason: "近期气温回升,需及时清理园内枯枝落叶,减少病虫越冬基数",
|
|
|
+ drug: "石硫合剂 500倍液",
|
|
|
+ machine_code: "DJI-T40-001",
|
|
|
+ work_id: 5001,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ time: "Mon, 26 May 2026 00:00:00 GMT",
|
|
|
+ geohash_sample: "ws0gefxm68u5",
|
|
|
+ operation: {
|
|
|
+ name: "施肥促花",
|
|
|
+ type: "2",
|
|
|
+ typeName: "感知类",
|
|
|
+ work_reason: "花芽分化期养分需求增加,需补充磷钾肥",
|
|
|
+ drug: "磷酸二氢钾 0.3%",
|
|
|
+ machine_code: "DJI-T50-003",
|
|
|
+ work_id: 5002,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ time: "Wed, 28 May 2026 00:00:00 GMT",
|
|
|
+ geohash_sample: "ws0gefzjqqqw",
|
|
|
+ operation: {
|
|
|
+ name: "病虫害防治",
|
|
|
+ type: "1",
|
|
|
+ typeName: "复核类",
|
|
|
+ work_reason: "监测到蚜虫活动增多,建议及时喷药防治",
|
|
|
+ drug: "吡虫啉 1500倍液",
|
|
|
+ machine_code: "DJI-T40-002",
|
|
|
+ work_id: 5003,
|
|
|
+ },
|
|
|
+ },
|
|
|
+]);
|
|
|
+const mode = "execute";
|
|
|
+const activeStatus = ref("待接受");
|
|
|
+
|
|
|
+const STATUS_BTN_MAP = {
|
|
|
+ 待接受: [
|
|
|
+ { label: "重新派发", type: "normal", action: "redispatch" },
|
|
|
+ { label: "提醒接受", type: "primary", action: "remindAccept" },
|
|
|
+ ],
|
|
|
+ 已接受: [{ label: "提醒执行", type: "primary", action: "remindExecute" }],
|
|
|
+ 执行中: [{ label: "提醒完成", type: "primary", action: "remindComplete" }],
|
|
|
+ 已超时: [
|
|
|
+ { label: "重新派发", type: "normal", action: "redispatch" },
|
|
|
+ { label: "提醒接受", type: "primary", action: "remindAccept" },
|
|
|
+ ],
|
|
|
+ 未达标: [{ label: "重新下发", type: "primary", action: "redispatch" }],
|
|
|
+};
|
|
|
+
|
|
|
+const nameArr = ["张扬", "王明", "詹金华"];
|
|
|
+const phoneArr = ["13939189356", "13800138000", "13712345678"];
|
|
|
+const avatarArr = [
|
|
|
+ "https://birdseye-img.sysuimars.com/shuichan/image.png",
|
|
|
+ "",
|
|
|
+ "",
|
|
|
+];
|
|
|
+
|
|
|
+const getExecutorName = (index) => nameArr[index % nameArr.length];
|
|
|
+const getExecutorPhone = (index) => phoneArr[index % phoneArr.length];
|
|
|
+const getExecutorAvatar = (index) => avatarArr[index % avatarArr.length] || "";
|
|
|
+
|
|
|
+const isTimeoutItem = (index) => index === 0;
|
|
|
+
|
|
|
+const getTimeoutRemindBtn = () => {
|
|
|
+ const map = {
|
|
|
+ 待接受: { label: "提醒接受", type: "primary", action: "remindAccept" },
|
|
|
+ 已接受: { label: "提醒执行", type: "primary", action: "remindExecute" },
|
|
|
+ 执行中: { label: "提醒完成", type: "primary", action: "remindComplete" },
|
|
|
+ };
|
|
|
+ return map[activeStatus.value];
|
|
|
+};
|
|
|
+
|
|
|
+const getItemStatusButtons = (index) => {
|
|
|
+ const baseButtons = STATUS_BTN_MAP[activeStatus.value] || [];
|
|
|
+ if (!isTimeoutItem(index)) {
|
|
|
+ return baseButtons;
|
|
|
+ }
|
|
|
+ if (activeStatus.value === "待接受") {
|
|
|
+ return baseButtons;
|
|
|
+ }
|
|
|
+ const remindBtn = getTimeoutRemindBtn();
|
|
|
+ if (remindBtn) {
|
|
|
+ return [
|
|
|
+ { label: "重新派发", type: "normal", action: "redispatch" },
|
|
|
+ remindBtn,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ return [{ label: "重新派发", type: "normal", action: "redispatch" }, ...baseButtons];
|
|
|
+};
|
|
|
+
|
|
|
+const getTimeoutText = () => {
|
|
|
+ switch (activeStatus.value) {
|
|
|
+ case "待接受":
|
|
|
+ return "接受超时";
|
|
|
+ case "已接受":
|
|
|
+ return "执行超时";
|
|
|
+ case "执行中":
|
|
|
+ return "完成超时";
|
|
|
+ default:
|
|
|
+ return "已超时";
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const formatGMTToYMD = (gmtString) => {
|
|
|
+ const date = new Date(gmtString);
|
|
|
+ return date.toISOString().split("T")[0];
|
|
|
+};
|
|
|
+
|
|
|
+const getWorkImageUrl = (image) => {
|
|
|
+ if (!image?.cloud_filename) return "";
|
|
|
+ return config.base_img_url3 + image.cloud_filename;
|
|
|
+};
|
|
|
+
|
|
|
+const handleItem = (item, index) => {
|
|
|
+ router.push({
|
|
|
+ path: "/work_detail",
|
|
|
+ query: {
|
|
|
+ miniJson: JSON.stringify({
|
|
|
+ id: item.operation?.work_id,
|
|
|
+ name: getExecutorName(index),
|
|
|
+ phone: getExecutorPhone(index),
|
|
|
+ avatar: getExecutorAvatar(index),
|
|
|
+ status: activeStatus.value,
|
|
|
+ time: item.time,
|
|
|
+ geohash_sample: item.geohash_sample,
|
|
|
+ machine_code: item.operation?.machine_code,
|
|
|
+ }),
|
|
|
+ },
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const handleStatusBtn = (btn, item, index) => {
|
|
|
+ if (btn.action === "redispatch") {
|
|
|
+ ElMessage.info(`重新派发:${item.operation?.name}`);
|
|
|
+ } else {
|
|
|
+ ElMessage.success("提醒成功!");
|
|
|
+ }
|
|
|
+};
|
|
|
+// 各状态任务数量
|
|
|
+const taskCounts = ref([0, 0, 0]);
|
|
|
+// 当前选中的筛选索引
|
|
|
+const activeIndex = ref(2);
|
|
|
+const noData = ref(false);
|
|
|
+const loading = ref(false);
|
|
|
+// 分页相关
|
|
|
+const page = ref(0);
|
|
|
+const limit = ref(10);
|
|
|
+const loadingMore = ref(false);
|
|
|
+const finished = ref(false);
|
|
|
+
|
|
|
+// 查询未来农事预警
|
|
|
+const getFutureFarmWorkWarning = async (item) => {
|
|
|
+ const res = await VE_API.home.listFutureFarmWorkWarning({ farmId: item.farmId });
|
|
|
+ item.timelineList = res.data || [];
|
|
|
+};
|
|
|
+
|
|
|
+const cityCode = ref("");
|
|
|
+//根据城市的坐标返回区县列表
|
|
|
+const districtList = ref([]);
|
|
|
+function getDistrictListByCity() {
|
|
|
+ VE_API.z_farm_work_record.getDistrictListByCity({ point: mapPoint.value }).then(({ data }) => {
|
|
|
+ districtList.value = data || [];
|
|
|
+ // cityCode.value = data[0].code.slice(0, -2);
|
|
|
+ cityCode.value = "";
|
|
|
+ districtList.value.unshift({ code: cityCode.value, name: "全部" });
|
|
|
+ selectParma.value.districtCode = cityCode.value;
|
|
|
+ resetAndLoad();
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+//农事类型列表
|
|
|
+const farmWorkTypeList = ref([]);
|
|
|
+function getFarmWorkTypeList() {
|
|
|
+ VE_API.z_farm_work_record.getFarmWorkTypeList().then(({ data }) => {
|
|
|
+ farmWorkTypeList.value = data;
|
|
|
+ farmWorkTypeList.value.unshift({ id: 0, name: "全部" });
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+const mapPoint = ref(null);
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ mapPoint.value = store.state.home.miniUserLocationPoint;
|
|
|
+ // getDistrictListByCity();
|
|
|
+ resetAndLoad();
|
|
|
+ getFarmWorkTypeList();
|
|
|
+ nextTick(() => {
|
|
|
+ indexMap.initMap(mapPoint.value, mapContainer.value, true);
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+onActivated(() => {
|
|
|
+ if (route.query.noReload) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 确保地图已初始化,使用 nextTick 等待 DOM 更新
|
|
|
+ nextTick(() => {
|
|
|
+ // 检查地图实例是否已初始化
|
|
|
+ if (!indexMap.kmap) {
|
|
|
+ // 如果地图未初始化,重新初始化
|
|
|
+ if (mapContainer.value) {
|
|
|
+ mapPoint.value = store.state.home.miniUserLocationPoint;
|
|
|
+ indexMap.initMap(mapPoint.value, mapContainer.value, true);
|
|
|
+ // 等待地图初始化完成后再加载数据
|
|
|
+ setTimeout(() => {
|
|
|
+ resetAndLoad();
|
|
|
+ }, 300);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 如果地图已初始化,需要等待 tab 切换完成,容器完全可见后再更新尺寸
|
|
|
+ // Tab 切换时容器可能被隐藏,需要更长的延迟确保容器可见
|
|
|
+ if (mapContainer.value && indexMap.kmap.map) {
|
|
|
+ // 检查容器是否可见
|
|
|
+ const checkAndUpdateSize = () => {
|
|
|
+ const container = mapContainer.value;
|
|
|
+ if (container) {
|
|
|
+ const rect = container.getBoundingClientRect();
|
|
|
+ // 如果容器可见(有宽度和高度),更新地图尺寸
|
|
|
+ if (rect.width > 0 && rect.height > 0) {
|
|
|
+ indexMap.kmap.map.updateSize();
|
|
|
+ } else {
|
|
|
+ // 如果容器不可见,继续等待
|
|
|
+ setTimeout(checkAndUpdateSize, 100);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ // 延迟检查,确保 tab 切换完成
|
|
|
+ setTimeout(checkAndUpdateSize, 200);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ resetAndLoad();
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+// 监听 activeIndex 变化,重新加载数据
|
|
|
+watch(activeIndex, () => {
|
|
|
+ resetAndLoad();
|
|
|
+});
|
|
|
+
|
|
|
+// 加载列表数据(支持分页)
|
|
|
+async function getSimpleList(isLoadMore = false) {
|
|
|
+ if (!isLoadMore) {
|
|
|
+ // 重置分页
|
|
|
+ page.value = 0;
|
|
|
+ finished.value = false;
|
|
|
+ // taskList.value = [];
|
|
|
+ loading.value = true;
|
|
|
+ } else {
|
|
|
+ loadingMore.value = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ const params = {
|
|
|
+ ...selectParma.value,
|
|
|
+ page: page.value,
|
|
|
+ limit: limit.value,
|
|
|
+ flowStatus: 5,
|
|
|
+ };
|
|
|
+
|
|
|
+ try {
|
|
|
+ const { data } = await VE_API.home.listUnansweredFarms(params);
|
|
|
+
|
|
|
+ if (data && data.length > 0) {
|
|
|
+ // 为每个item初始化timelineList
|
|
|
+ const newItems = data.map((item) => {
|
|
|
+ let sourceData = item?.latestPhenologyProgressBroadcast?.sourceData;
|
|
|
+ if (sourceData) {
|
|
|
+ try {
|
|
|
+ sourceData = JSON.parse(sourceData);
|
|
|
+ } catch (e) {
|
|
|
+ console.error("解析sourceData失败:", e);
|
|
|
+ sourceData = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ ...item,
|
|
|
+ sourceData,
|
|
|
+ timelineList: [],
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ // 串行请求,为每个农场获取时间轴数据
|
|
|
+ for (let i = 0; i < newItems.length; i++) {
|
|
|
+ await getFutureFarmWorkWarning(newItems[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 追加数据
|
|
|
+ // const newTaskList = [...taskList.value, ...newItems];
|
|
|
+ // taskList.value = newTaskList.filter(item => item.timelineList.length > 0);
|
|
|
+
|
|
|
+ // 更新分页
|
|
|
+ page.value += 1;
|
|
|
+
|
|
|
+ // 判断是否还有更多数据
|
|
|
+ if (data.length < limit.value) {
|
|
|
+ finished.value = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新地图数据
|
|
|
+ indexMap.initData(taskList.value,'','farmPoint');
|
|
|
+ } else {
|
|
|
+ finished.value = true;
|
|
|
+ if (taskList.value.length === 0) {
|
|
|
+ noData.value = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据处理完成后再设置loading为false
|
|
|
+ if (!isLoadMore) {
|
|
|
+ loading.value = false;
|
|
|
+ } else {
|
|
|
+ loadingMore.value = false;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("获取任务列表失败:", error);
|
|
|
+ if (!isLoadMore) {
|
|
|
+ loading.value = false;
|
|
|
+ } else {
|
|
|
+ loadingMore.value = false;
|
|
|
+ }
|
|
|
+ finished.value = true;
|
|
|
+ if (taskList.value.length === 0) {
|
|
|
+ noData.value = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 滚动加载更多
|
|
|
+const onLoad = () => {
|
|
|
+ if (!finished.value && !loadingMore.value) {
|
|
|
+ getSimpleList(true);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 重置并重新加载
|
|
|
+const resetAndLoad = () => {
|
|
|
+ getSimpleList(false);
|
|
|
+};
|
|
|
+
|
|
|
+function handleActiveFilter(i) {
|
|
|
+ activeIndex.value = i;
|
|
|
+ selectParma.value.districtCode = cityCode.value;
|
|
|
+ selectParma.value.farmWorkTypeId = null;
|
|
|
+ const statusMap = { 0: "待接受", 2: "已接受", 3: "执行中" };
|
|
|
+ activeStatus.value = statusMap[i] || "待接受";
|
|
|
+}
|
|
|
+
|
|
|
+function handleRemindCustomer(item) {
|
|
|
+ // 接受
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.task-page {
|
|
|
+ width: 100%;
|
|
|
+ height: calc(100vh - 50px - 50px);
|
|
|
+ overflow: auto;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background: #f5f7fb;
|
|
|
+ .map-container {
|
|
|
+ width: 100%;
|
|
|
+ height: 162px;
|
|
|
+ clip-path: inset(0px round 8px);
|
|
|
+ }
|
|
|
+
|
|
|
+ .select-group {
|
|
|
+ display: flex;
|
|
|
+ padding: 0px 12px 0 12px;
|
|
|
+ .select-item {
|
|
|
+ width: 100%;
|
|
|
+ ::v-deep {
|
|
|
+ .el-select__wrapper {
|
|
|
+ text-align: center;
|
|
|
+ gap: 2px;
|
|
|
+ box-shadow: none;
|
|
|
+ justify-content: center;
|
|
|
+ background: none;
|
|
|
+ }
|
|
|
+ .el-select__selection {
|
|
|
+ flex: none;
|
|
|
+ width: fit-content;
|
|
|
+ }
|
|
|
+ .el-select__placeholder {
|
|
|
+ position: static;
|
|
|
+ transform: none;
|
|
|
+ width: fit-content;
|
|
|
+ color: rgba(0, 0, 0, 0.2);
|
|
|
+ }
|
|
|
+ .el-select__caret {
|
|
|
+ color: rgba(0, 0, 0, 0.2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-top {
|
|
|
+ padding: 10px 12px 0 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-content-loading {
|
|
|
+ height: 80px;
|
|
|
+ border-radius: 8px;
|
|
|
+ position: absolute;
|
|
|
+ top: 60px;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-content {
|
|
|
+ min-height: 80px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .empty-data {
|
|
|
+ text-align: center;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #6f7274;
|
|
|
+ padding: 20px 0;
|
|
|
+ }
|
|
|
+ .task-list {
|
|
|
+ position: relative;
|
|
|
+ background: #fff;
|
|
|
+ padding: 12px 12px 8px 12px;
|
|
|
+ }
|
|
|
+ .list-filter {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-around;
|
|
|
+ .filter-item {
|
|
|
+ padding: 0 12px;
|
|
|
+ height: 28px;
|
|
|
+ color: rgba(0, 0, 0, 0.5);
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 28px;
|
|
|
+ border-radius: 20px;
|
|
|
+ &.active {
|
|
|
+ color: #2199f8;
|
|
|
+ background: rgba(33, 153, 248, 0.2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .work-task-list {
|
|
|
+ margin-top: 10px;
|
|
|
+
|
|
|
+ .task-item {
|
|
|
+ margin-top: 10px;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 12px 16px;
|
|
|
+ border: 1px solid rgba(0, 0, 0, 0.08);
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ &.timeout-item {
|
|
|
+ border: 1px solid #f74e4e;
|
|
|
+ }
|
|
|
+
|
|
|
+ .item-title {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding-bottom: 10px;
|
|
|
+ border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
|
|
+ color: #1d2129;
|
|
|
+ font-size: 16px;
|
|
|
+
|
|
|
+ .task-icon {
|
|
|
+ width: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .title-text {
|
|
|
+ padding-left: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-status {
|
|
|
+ margin-left: 8px;
|
|
|
+ border-radius: 2px;
|
|
|
+ height: 20px;
|
|
|
+ line-height: 18px;
|
|
|
+ padding: 1px 6px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #ffb32f;
|
|
|
+ background: rgba(255, 179, 47, 0.1);
|
|
|
+
|
|
|
+ &.task-status--1 {
|
|
|
+ background: rgba(33, 153, 248, 0.1);
|
|
|
+ color: #2199f8;
|
|
|
+ }
|
|
|
+ &.task-status--2 {
|
|
|
+ background: rgba(255, 179, 47, 0.1);
|
|
|
+ color: #FFB32F;
|
|
|
+ }
|
|
|
+ &.task-status--3 {
|
|
|
+ background: rgba(58, 173, 148, 0.1);
|
|
|
+ color: #3AAD94;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .task-tag {
|
|
|
+ position: absolute;
|
|
|
+ right: 0;
|
|
|
+ top: 0;
|
|
|
+ background: rgba(33, 153, 248, 0.1);
|
|
|
+ color: #2199f8;
|
|
|
+ font-size: 12px;
|
|
|
+ padding: 0 6px;
|
|
|
+ height: 25px;
|
|
|
+ line-height: 25px;
|
|
|
+ border-radius: 0 8px 0 8px;
|
|
|
+
|
|
|
+ &.timeout {
|
|
|
+ background: #ff4747;
|
|
|
+ color: #fff;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 2px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .item-content {
|
|
|
+ padding: 12px 0;
|
|
|
+
|
|
|
+ .excutor-info {
|
|
|
+ margin-top: 12px;
|
|
|
+ background: rgba(189, 189, 189, 0.1);
|
|
|
+ border-radius: 6px;
|
|
|
+ padding-bottom: 12px;
|
|
|
+
|
|
|
+ .excutor-info-top {
|
|
|
+ padding: 12px 12px 0 12px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .executor-stats {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding-top: 10px;
|
|
|
+ justify-content: space-around;
|
|
|
+ }
|
|
|
+
|
|
|
+ .cell-line {
|
|
|
+ height: 20px;
|
|
|
+ width: 1px;
|
|
|
+ background: #e5e6eb;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-value {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #1d2129;
|
|
|
+ margin-bottom: 4px;
|
|
|
+ word-break: break-all;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-label {
|
|
|
+ font-size: 10px;
|
|
|
+ line-height: 20px;
|
|
|
+ color: #86909c;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .item-info {
|
|
|
+ color: #86909c;
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 18px;
|
|
|
+
|
|
|
+ .info-item {
|
|
|
+ display: flex;
|
|
|
+
|
|
|
+ .info-name {
|
|
|
+ flex: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .val-text {
|
|
|
+ color: #1d2129;
|
|
|
+ }
|
|
|
+
|
|
|
+ .info-item + .info-item {
|
|
|
+ padding-top: 12px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn-group {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: end;
|
|
|
+ width: 100%;
|
|
|
+ gap: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .edit-btn {
|
|
|
+ flex: 1;
|
|
|
+ width: 100%;
|
|
|
+ height: 30px;
|
|
|
+ border-radius: 4px;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 30px;
|
|
|
+ font-size: 14px;
|
|
|
+ border: 0.5px solid transparent;
|
|
|
+
|
|
|
+ &.normal {
|
|
|
+ flex: none;
|
|
|
+ width: 131px;
|
|
|
+ background: #fff;
|
|
|
+ border: 0.5px solid rgba(0, 0, 0, 0.2);
|
|
|
+ color: #1d2129;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.primary {
|
|
|
+ background: #2199f8;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .compare-imgs {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ position: relative;
|
|
|
+ margin: 10px 0;
|
|
|
+
|
|
|
+ .img-tag {
|
|
|
+ position: absolute;
|
|
|
+ z-index: 10;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #fff;
|
|
|
+ background: rgba(0, 0, 0, 0.7);
|
|
|
+ border-radius: 5px 0 5px 0;
|
|
|
+ padding: 0 8px;
|
|
|
+ height: 15px;
|
|
|
+ line-height: 15px;
|
|
|
+
|
|
|
+ &.right-tag {
|
|
|
+ right: 0;
|
|
|
+ left: auto;
|
|
|
+ border-radius: 0 5px 0 5px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .img-item {
|
|
|
+ flex: 1;
|
|
|
+ height: 120px;
|
|
|
+ overflow: hidden;
|
|
|
+ border: 0.5px solid rgba(0, 0, 0, 0.1);
|
|
|
+ border-radius: 5px;
|
|
|
+
|
|
|
+ img {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ border-radius: 5px;
|
|
|
+ object-fit: cover;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .unqualified-reason {
|
|
|
+ color: #f74e4e;
|
|
|
+ font-size: 12px;
|
|
|
+ padding: 4px 10px;
|
|
|
+ background: rgba(247, 78, 78, 0.08);
|
|
|
+ border-radius: 4px;
|
|
|
+ line-height: 18px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .empty-tip {
|
|
|
+ text-align: center;
|
|
|
+ color: #86909c;
|
|
|
+ font-size: 14px;
|
|
|
+ padding: 20px 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|