|
|
@@ -77,7 +77,7 @@
|
|
|
import { computed, nextTick, onActivated, ref } from "vue";
|
|
|
import { useStore } from "vuex";
|
|
|
import { useRouter } from "vue-router";
|
|
|
-import { ElMessage } from "element-plus";
|
|
|
+import { ElMessage, ElMessageBox } from "element-plus";
|
|
|
import IndexMap from "./index";
|
|
|
import customCalendar from "./components/calendar.vue";
|
|
|
import farmHeader from "@/components/farmHeader.vue";
|
|
|
@@ -105,47 +105,14 @@ const filterDate = ref(formatDateYMD());
|
|
|
|
|
|
const ENTRY_FARM_DATA_KEY = "ENTRY_FARM_DATA";
|
|
|
const MAP_POINT_STORAGE_KEY = "GROWTH_REPORT_MAP_POINT";
|
|
|
+/** 农事详情:列表点击时带入的 agronomy_detail */
|
|
|
+const WORK_AGRONOMY_DETAIL_KEY = "WORK_AGRONOMY_DETAIL";
|
|
|
const DEFAULT_MAP_POINT = "POINT(113.6142086995688 23.585836479509055)";
|
|
|
|
|
|
-/**
|
|
|
- * 假数据模板(已完成 tab 兜底):wkt 相对中心点偏移
|
|
|
- */
|
|
|
-const COMPLETED_MOCK_TEMPLATE = [
|
|
|
- {
|
|
|
- id: "mock-c-4",
|
|
|
- status: "completed",
|
|
|
- title: "病虫害巡查",
|
|
|
- isHighRisk: false,
|
|
|
- isNormal: true,
|
|
|
- isAbnormal: false,
|
|
|
- isWeather: false,
|
|
|
- isByMyself: true,
|
|
|
- cornerTip: "已完成",
|
|
|
- analysisSummary: "新梢与果实表面未见明显异常斑点",
|
|
|
- areaCode: "分区一",
|
|
|
- farmName: "病虫害巡查",
|
|
|
- executeDate: "08/05",
|
|
|
- offset: [0.0004, -0.0003],
|
|
|
- },
|
|
|
- {
|
|
|
- id: "mock-c-5",
|
|
|
- status: "completed",
|
|
|
- title: "修剪整枝",
|
|
|
- isHighRisk: false,
|
|
|
- isNormal: true,
|
|
|
- isAbnormal: false,
|
|
|
- isWeather: false,
|
|
|
- cornerTip: "已完成",
|
|
|
- analysisSummary: "已清理过密枝条,改善通风透光",
|
|
|
- areaCode: "分区一",
|
|
|
- farmName: "修剪整枝",
|
|
|
- executeDate: "08/04",
|
|
|
- offset: [-0.0024, 0.0004],
|
|
|
- },
|
|
|
-];
|
|
|
-
|
|
|
-/** status: pending 待执行 / completed 已完成 */
|
|
|
+/** status: pending 待执行 / completed 已完成(下方列表,按日期筛选) */
|
|
|
const taskList = ref([]);
|
|
|
+/** 地图气泡:不传日期,展示全部农事 */
|
|
|
+const mapTaskList = ref([]);
|
|
|
|
|
|
function readEntryFarmData() {
|
|
|
try {
|
|
|
@@ -179,22 +146,6 @@ function formatWorkTime(workTime) {
|
|
|
return formatExecuteDate(d);
|
|
|
}
|
|
|
|
|
|
-/** 根据中心点生成附近任务点位(已完成 mock) */
|
|
|
-const buildCompletedNearCenter = (centerWkt) => {
|
|
|
- const coord = convertPointToArray(centerWkt);
|
|
|
- const lng = Number(coord?.[0]);
|
|
|
- const lat = Number(coord?.[1]);
|
|
|
- if (!Number.isFinite(lng) || !Number.isFinite(lat)) return [];
|
|
|
- return COMPLETED_MOCK_TEMPLATE.map((item) => {
|
|
|
- const [dx = 0, dy = 0] = item.offset || [];
|
|
|
- const { offset, ...rest } = item;
|
|
|
- return {
|
|
|
- ...rest,
|
|
|
- wkt: `POINT(${lng + dx} ${lat + dy})`,
|
|
|
- };
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
/** user_work 单条 → 列表卡片 */
|
|
|
function mapUserWorkToTask(item, index, centerWkt) {
|
|
|
const detail = item?.agronomy_detail || {};
|
|
|
@@ -207,7 +158,9 @@ function mapUserWorkToTask(item, index, centerWkt) {
|
|
|
const title = detail.fw_name || "";
|
|
|
const executeDate = formatWorkTime(item.work_time);
|
|
|
const isWarning = item.work_type === "weather_warning" || item.work_type === "warning";
|
|
|
- const isCompleted = Number(item.work_status) === 1;
|
|
|
+ // 接口约定:0 未完成,1 已完成(兼容拼写 work_stauts)
|
|
|
+ const rawStatus = item.work_status ?? item.work_stauts;
|
|
|
+ const isCompleted = Number(rawStatus) === 1;
|
|
|
return {
|
|
|
id: item.work_id ?? detail.id ?? `work-${index}`,
|
|
|
status: isCompleted ? "completed" : "pending",
|
|
|
@@ -221,6 +174,7 @@ function mapUserWorkToTask(item, index, centerWkt) {
|
|
|
analysisSummary: detail.fw_explain_simple || detail.fw_explain || "",
|
|
|
areaCode: detail.crop_category_name || "分区一",
|
|
|
executeDate,
|
|
|
+ workTime: item.work_time,
|
|
|
phenophaseCode: detail.phenophase_code,
|
|
|
phenophaseName: detail.phenophase_name,
|
|
|
fwExplain: detail.fw_explain,
|
|
|
@@ -228,35 +182,63 @@ function mapUserWorkToTask(item, index, centerWkt) {
|
|
|
fwParams: detail.fw_params,
|
|
|
fwPrecrip: detail.fw_precrip,
|
|
|
workType: item.work_type,
|
|
|
- workStatus: item.work_status,
|
|
|
+ workStatus: rawStatus,
|
|
|
agronomyType: isWarning ? "warning" : "standard",
|
|
|
+ // 点击进详情原样带入
|
|
|
+ agronomy_detail: item?.agronomy_detail || null,
|
|
|
wkt: hasCoord ? `POINT(${lng + dx} ${lat + dy})` : "",
|
|
|
};
|
|
|
}
|
|
|
|
|
|
-/** 拉取用户农事列表(report/user_work) */
|
|
|
-async function fetchUserWorkTasks(centerWkt) {
|
|
|
+/**
|
|
|
+ * 拉取用户农事(report/user_work)
|
|
|
+ * @param {string} centerWkt
|
|
|
+ * @param {string} [workTime] YYYY-MM-DD;不传则返回全部(地图用)
|
|
|
+ */
|
|
|
+async function requestUserWork(centerWkt, workTime) {
|
|
|
const tel = resolveUserTel();
|
|
|
- if (!tel) {
|
|
|
- taskList.value = buildCompletedNearCenter(centerWkt);
|
|
|
- return;
|
|
|
+ if (!tel) return [];
|
|
|
+
|
|
|
+ const params = { tel };
|
|
|
+ if (workTime) params.work_time = workTime;
|
|
|
+
|
|
|
+ const raw = await VE_API.questionnaire.userWork(params);
|
|
|
+ const res = Array.isArray(raw) ? raw[0] : raw;
|
|
|
+ const code = Number(res?.code);
|
|
|
+ if (!(code === 200 || code === 0 || code === 1)) {
|
|
|
+ ElMessage.error(res?.message || res?.msg || "获取农事列表失败");
|
|
|
+ return [];
|
|
|
}
|
|
|
+ const list = Array.isArray(res?.data) ? res.data : [];
|
|
|
+ return list.map((item, index) => mapUserWorkToTask(item, index, centerWkt));
|
|
|
+}
|
|
|
+
|
|
|
+/** 地图:不传日期,全量 */
|
|
|
+async function fetchMapTasks(centerWkt) {
|
|
|
try {
|
|
|
- const raw = await VE_API.questionnaire.userWork({ tel });
|
|
|
- const res = Array.isArray(raw) ? raw[0] : raw;
|
|
|
- const code = Number(res?.code);
|
|
|
- if (!(code === 200 || code === 0 || code === 1)) {
|
|
|
- ElMessage.error(res?.message || res?.msg || "获取农事列表失败");
|
|
|
- taskList.value = buildCompletedNearCenter(centerWkt);
|
|
|
- return;
|
|
|
- }
|
|
|
- const list = Array.isArray(res?.data) ? res.data : [];
|
|
|
- const mapped = list.map((item, index) => mapUserWorkToTask(item, index, centerWkt));
|
|
|
- const hasCompleted = mapped.some((item) => item.status === "completed");
|
|
|
- taskList.value = hasCompleted ? mapped : [...mapped, ...buildCompletedNearCenter(centerWkt)];
|
|
|
+ mapTaskList.value = await requestUserWork(centerWkt);
|
|
|
+ syncCalendarBadges();
|
|
|
+ } catch {
|
|
|
+ ElMessage.error("获取农事地图数据失败,请稍后再试");
|
|
|
+ mapTaskList.value = [];
|
|
|
+ syncCalendarBadges();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** 用全量农事刷新日期角标数量 */
|
|
|
+function syncCalendarBadges() {
|
|
|
+ nextTick(() => {
|
|
|
+ calendarRef.value?.setSolarTerm?.(mapTaskList.value);
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+/** 下方列表:传选中日期 */
|
|
|
+async function fetchListTasks(centerWkt, workTime) {
|
|
|
+ try {
|
|
|
+ taskList.value = await requestUserWork(centerWkt, workTime || undefined);
|
|
|
} catch {
|
|
|
ElMessage.error("获取农事列表失败,请稍后再试");
|
|
|
- taskList.value = buildCompletedNearCenter(centerWkt);
|
|
|
+ taskList.value = [];
|
|
|
}
|
|
|
}
|
|
|
const activeTab = ref("pending");
|
|
|
@@ -275,8 +257,11 @@ const handleTabChange = (key) => {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
-const handleDateSelect = (date) => {
|
|
|
- filterDate.value = date ?? formatDateYMD();
|
|
|
+const handleDateSelect = async (date) => {
|
|
|
+ // null:取消筛选,列表也不传日期
|
|
|
+ filterDate.value = date || "";
|
|
|
+ const center = mapPoint.value || resolveMapPoint();
|
|
|
+ await fetchListTasks(center, filterDate.value);
|
|
|
};
|
|
|
|
|
|
const handleForward = (item) => {
|
|
|
@@ -297,6 +282,24 @@ const handleForward = (item) => {
|
|
|
};
|
|
|
|
|
|
const handleViewDetail = (item) => {
|
|
|
+ if (item?.agronomy_detail) {
|
|
|
+ sessionStorage.setItem(
|
|
|
+ WORK_AGRONOMY_DETAIL_KEY,
|
|
|
+ JSON.stringify({
|
|
|
+ agronomy_detail: item.agronomy_detail,
|
|
|
+ work_id: item.id,
|
|
|
+ work_time: item.workTime || item.executeDate,
|
|
|
+ work_type: item.workType,
|
|
|
+ work_status: item.workStatus,
|
|
|
+ status: item.status,
|
|
|
+ isNormal: item.isNormal,
|
|
|
+ isAbnormal: item.isAbnormal,
|
|
|
+ isWeather: item.isWeather,
|
|
|
+ isHighRisk: item.isHighRisk,
|
|
|
+ cornerTip: item.cornerTip || "",
|
|
|
+ })
|
|
|
+ );
|
|
|
+ }
|
|
|
router.push({
|
|
|
path: "/work_detail",
|
|
|
query: {
|
|
|
@@ -306,9 +309,46 @@ const handleViewDetail = (item) => {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
-const handleComplete = (item) => {
|
|
|
- // TODO: 对接完成农事接口
|
|
|
- ElMessage.success("农事已完成");
|
|
|
+const handleComplete = async (item) => {
|
|
|
+ const tel = resolveUserTel();
|
|
|
+ const workId = item?.id;
|
|
|
+ if (!tel) {
|
|
|
+ ElMessage.error("缺少手机号,无法完成农事");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (workId == null || workId === "") {
|
|
|
+ ElMessage.error("缺少农事信息,无法完成");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ await ElMessageBox.confirm("确认将该农事标记为已完成?", "提示", {
|
|
|
+ confirmButtonText: "确认",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning",
|
|
|
+ });
|
|
|
+ } catch {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const raw = await VE_API.questionnaire.updateWorkStatus({
|
|
|
+ work_type: item.workType || "standard",
|
|
|
+ work_id: workId,
|
|
|
+ tel,
|
|
|
+ });
|
|
|
+ const res = Array.isArray(raw) ? raw[0] : raw;
|
|
|
+ const code = Number(res?.code);
|
|
|
+ if (!(code === 200 || code === 0 || code === 1)) {
|
|
|
+ ElMessage.error(res?.message || res?.msg || "完成农事失败");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ElMessage.success("农事已完成");
|
|
|
+ const center = mapPoint.value || resolveMapPoint();
|
|
|
+ const listDate = filterDate.value || formatDateYMD();
|
|
|
+ await Promise.all([fetchMapTasks(center), fetchListTasks(center, listDate)]);
|
|
|
+ refreshMapMarkers();
|
|
|
+ } catch {
|
|
|
+ ElMessage.error("完成农事失败,请稍后再试");
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
const goCompleteFarmInfo = () => {
|
|
|
@@ -356,7 +396,9 @@ const resolveMapPoint = () => {
|
|
|
return DEFAULT_MAP_POINT;
|
|
|
};
|
|
|
|
|
|
-const getMapMarkerList = () => displayTaskList.value.filter((item) => item.wkt);
|
|
|
+/** 地图只展示待执行农事(不按日期、不跟已完成 tab) */
|
|
|
+const getMapMarkerList = () =>
|
|
|
+ mapTaskList.value.filter((item) => item.status === "pending" && item.wkt);
|
|
|
|
|
|
const refreshMapMarkers = () => {
|
|
|
if (!mapContainer.value) return;
|
|
|
@@ -374,7 +416,11 @@ const refreshMapMarkers = () => {
|
|
|
const loadWorkPage = async () => {
|
|
|
if (!mapContainer.value) return;
|
|
|
mapPoint.value = resolveMapPoint();
|
|
|
- await fetchUserWorkTasks(mapPoint.value);
|
|
|
+ const listDate = filterDate.value || formatDateYMD();
|
|
|
+ await Promise.all([
|
|
|
+ fetchMapTasks(mapPoint.value),
|
|
|
+ fetchListTasks(mapPoint.value, listDate),
|
|
|
+ ]);
|
|
|
refreshMapMarkers();
|
|
|
if (mapContainer.value && indexMap.kmap?.map) {
|
|
|
const checkAndUpdateSize = () => {
|