Sfoglia il codice sorgente

feat:修改农事列表显示

wangsisi 2 settimane fa
parent
commit
50db1da330

+ 157 - 9
src/views/old_mini/work_detail/index.vue

@@ -106,6 +106,17 @@
                 </div>
 
                 <div class="box-wrap stage-card">
+                    <div class="method-switch" v-if="methodTabs.length">
+                        <div
+                            v-for="tab in methodTabs"
+                            :key="tab.value"
+                            class="method-switch__item"
+                            :class="{ active: executeMethod === tab.value }"
+                            @click="handleMethodSwitch(tab.value)"
+                        >
+                            {{ tab.label }}
+                        </div>
+                    </div>
                     <div class="work-info">
                         <div class="info-item">
                             <div class="info-title"><span class="title-block"></span>{{ $t('workDetail.prescription') }}
@@ -295,8 +306,86 @@ function readWorkAgronomyPayload() {
 }
 
 /** 列表带入:agronomy_detail 原样 + 列表上的类型/状态标签 */
+const methodTabs = ref([]);
+const executeMethod = ref("");
+/** 切换方式时保留列表标签等元信息 */
+const farmMeta = ref({});
+
+function pickGroupRecord(group) {
+    const records = group?.work_records;
+    if (Array.isArray(records) && records.length > 0) return records[0];
+    return null;
+}
+
+function applyGroupDetail(group, meta = farmMeta.value) {
+    const record = pickGroupRecord(group);
+    const detail = record?.agronomy_detail;
+    if (!detail) return false;
+    const workType = record.work_type ?? meta.work_type;
+    const isWeather = workType === "weather_warning" || workType === "warning";
+    farmData.value = {
+        ...detail,
+        work_id: record.work_id ?? detail.id,
+        work_type: workType,
+        work_status: record.work_status ?? meta.work_status,
+        status: meta.status,
+        isNormal: meta.isNormal ?? (!isWeather && workType === "standard"),
+        isAbnormal: meta.isAbnormal ?? false,
+        isWeather: meta.isWeather ?? isWeather,
+        isHighRisk: meta.isHighRisk ?? isWeather,
+        cornerTip: meta.cornerTip || "",
+    };
+    return true;
+}
+
+function buildMethodTabs(groups) {
+    if (!Array.isArray(groups)) return [];
+    return groups
+        .map((group, index) => {
+            const label = group?.fw_type || `方案${index + 1}`;
+            return {
+                label,
+                value: String(index),
+                group,
+            };
+        })
+        .filter((tab) => pickGroupRecord(tab.group)?.agronomy_detail);
+}
+
+function handleMethodSwitch(value) {
+    if (executeMethod.value === value) return;
+    const tab = methodTabs.value.find((item) => item.value === value);
+    if (!tab) return;
+    executeMethod.value = value;
+    applyGroupDetail(tab.group);
+}
+
 function applyAgronomyDetailPayload(payload) {
     if (!payload || typeof payload !== "object") return false;
+
+    const groups = Array.isArray(payload.fw_type_groups) ? payload.fw_type_groups : [];
+    const tabs = buildMethodTabs(groups);
+    methodTabs.value = tabs;
+
+    const workType = payload.work_type;
+    const isWeather = workType === "weather_warning" || workType === "warning";
+    farmMeta.value = {
+        work_type: workType,
+        work_status: payload.work_status,
+        status: payload.status,
+        isNormal: payload.isNormal ?? (!isWeather && workType === "standard"),
+        isAbnormal: payload.isAbnormal ?? false,
+        isWeather: payload.isWeather ?? isWeather,
+        isHighRisk: payload.isHighRisk ?? isWeather,
+        cornerTip: payload.cornerTip || "",
+    };
+
+    // 有方案分组:默认选第 0 个
+    if (tabs.length > 0) {
+        executeMethod.value = tabs[0].value;
+        return applyGroupDetail(tabs[0].group, farmMeta.value);
+    }
+
     const detail =
         payload.agronomy_detail && typeof payload.agronomy_detail === "object"
             ? payload.agronomy_detail
@@ -304,26 +393,26 @@ function applyAgronomyDetailPayload(payload) {
               ? payload
               : null;
     if (!detail) return false;
-    const workType = payload.work_type;
-    const isWeather = workType === "weather_warning" || workType === "warning";
     farmData.value = {
         ...detail,
         work_id: payload.work_id ?? detail.id,
         work_type: workType,
         work_status: payload.work_status,
         status: payload.status,
-        // 与列表卡片标签一致
-        isNormal: payload.isNormal ?? (!isWeather && workType === "standard"),
-        isAbnormal: payload.isAbnormal ?? false,
-        isWeather: payload.isWeather ?? isWeather,
-        isHighRisk: payload.isHighRisk ?? isWeather,
-        cornerTip: payload.cornerTip || "",
+        isNormal: farmMeta.value.isNormal,
+        isAbnormal: farmMeta.value.isAbnormal,
+        isWeather: farmMeta.value.isWeather,
+        isHighRisk: farmMeta.value.isHighRisk,
+        cornerTip: farmMeta.value.cornerTip,
     };
+    executeMethod.value = "";
     return true;
 }
 
 const wktFmt = new WKT();
 const MAP_CENTER_FALLBACK = "POINT(113.1093017627431 22.57454083668)";
+const ENTRY_FARM_DATA_KEY = "ENTRY_FARM_DATA";
+const MAP_POINT_STORAGE_KEY = "GROWTH_REPORT_MAP_POINT";
 
 const farmZones = computed(() => {
     const zones = farmData.value?.zones;
@@ -333,6 +422,37 @@ const farmZones = computed(() => {
     );
 });
 
+const isPointWkt = (value) => typeof value === "string" && /^POINT\s*\(/i.test(value.trim());
+
+/** 优先用户选中点位(录入 / 长势报告 / 农场) */
+function resolveUserMapPoint() {
+    try {
+        const entry = JSON.parse(localStorage.getItem(ENTRY_FARM_DATA_KEY) || "null");
+        if (isPointWkt(entry?.point)) return entry.point.trim();
+        if (Array.isArray(entry?.coordinate) && entry.coordinate.length === 2) {
+            return `POINT(${entry.coordinate[0]} ${entry.coordinate[1]})`;
+        }
+    } catch {
+        // ignore
+    }
+
+    const growthPoint = localStorage.getItem(MAP_POINT_STORAGE_KEY);
+    if (isPointWkt(growthPoint)) return growthPoint.trim();
+
+    const selectedPoint = localStorage.getItem("selectedFarmPoint");
+    if (isPointWkt(selectedPoint)) return selectedPoint.trim();
+
+    try {
+        const farm = JSON.parse(localStorage.getItem("selectedFarmData") || "{}");
+        const wkt = farm.wkt || farm.geom_wkt || farm.farm_location;
+        if (isPointWkt(wkt)) return wkt.trim();
+    } catch {
+        // ignore
+    }
+
+    return "";
+}
+
 /** 从地块 WKT 取首坐标作为初始中心,initZones 会 fit 到全部地块 */
 function wktCenterPointFromZones(zones) {
     const list = Array.isArray(zones) ? zones : [];
@@ -357,8 +477,10 @@ function initWorkDetailMap() {
     nextTick(() => {
         if (!mapContainer.value) return;
         const zones = farmZones.value;
+        // 默认定位用户选中点;无点位再用地块 / 兜底
+        const center = resolveUserMapPoint() || wktCenterPointFromZones(zones);
         areaMap.destroyMap();
-        areaMap.initMap(wktCenterPointFromZones(zones), mapContainer.value);
+        areaMap.initMap(center, mapContainer.value);
         areaMap.initZones(zones);
     });
 }
@@ -1119,6 +1241,32 @@ const areaMap = new AreaMap();
 }
 
 .stage-card {
+    .method-switch {
+        display: flex;
+        gap: 10px;
+        margin-bottom: 10px;
+
+        .method-switch__item {
+            height: 28px;
+            line-height: 28px;
+            padding: 0 12px;
+            text-align: center;
+            font-size: 12px;
+            color: #8E8E8E;
+            background: #fff;
+            border: 1px solid #fff;
+            border-radius: 2px;
+            box-sizing: border-box;
+            white-space: nowrap;
+
+            &.active {
+                color: #2199F8;
+                background: rgba(33, 153, 248, 0.1);
+                border-color: #2199f8;
+            }
+        }
+    }
+
     .stage-header {
         padding-bottom: 12px;
         display: flex;

+ 53 - 12
src/views/old_mini/work_execute/index.vue

@@ -146,23 +146,54 @@ function formatWorkTime(workTime) {
     return formatExecuteDate(d);
 }
 
+/**
+ * 解析单条农事记录(默认第 0 组第 0 条)
+ * 新结构:fw_type_groups[0].work_records[0]
+ * 兼容:work_records[0] / 旧扁平结构
+ */
+function resolveWorkRecord(item) {
+    const groups = item?.fw_type_groups;
+    if (Array.isArray(groups) && groups.length > 0) {
+        for (const group of groups) {
+            const records = group?.work_records;
+            if (Array.isArray(records) && records.length > 0) {
+                return {
+                    ...records[0],
+                    _fwType: group.fw_type,
+                    _parentFwName: item.fw_name,
+                };
+            }
+        }
+    }
+    if (Array.isArray(item?.work_records) && item.work_records.length > 0) {
+        return {
+            ...item.work_records[0],
+            _parentFwName: item.fw_name,
+        };
+    }
+    return item;
+}
+
 /** user_work 单条 → 列表卡片 */
 function mapUserWorkToTask(item, index, centerWkt) {
-    const detail = item?.agronomy_detail || {};
+    const record = resolveWorkRecord(item) || {};
+    const detail = record.agronomy_detail || {};
     const coord = convertPointToArray(centerWkt);
     const lng = Number(coord?.[0]);
     const lat = Number(coord?.[1]);
     const dx = ((index % 3) - 1) * 0.0012;
     const dy = (Math.floor(index / 3) - 0.5) * 0.001;
     const hasCoord = Number.isFinite(lng) && Number.isFinite(lat);
-    const title = detail.fw_name || "";
-    const executeDate = formatWorkTime(item.work_time);
-    const isWarning = item.work_type === "weather_warning" || item.work_type === "warning";
+    const baseName = detail.fw_name || record._parentFwName || item.fw_name || "";
+    const title = baseName;
+    const executeDate = formatWorkTime(record.work_time || item.work_time);
+    const workType = record.work_type || item.work_type;
+    const isWarning = workType === "weather_warning" || workType === "warning";
     // 接口约定:0 未完成,1 已完成(兼容拼写 work_stauts)
-    const rawStatus = item.work_status ?? item.work_stauts;
+    const rawStatus = record.work_status ?? record.work_stauts ?? item.work_status ?? item.work_stauts;
     const isCompleted = Number(rawStatus) === 1;
     return {
-        id: item.work_id ?? detail.id ?? `work-${index}`,
+        id: record.work_id ?? item.work_id ?? detail.id ?? `work-${index}`,
         status: isCompleted ? "completed" : "pending",
         title,
         farmName: title,
@@ -174,18 +205,18 @@ function mapUserWorkToTask(item, index, centerWkt) {
         analysisSummary: detail.fw_explain_simple || detail.fw_explain || "",
         areaCode: detail.crop_category_name || "分区一",
         executeDate,
-        workTime: item.work_time,
+        workTime: record.work_time || item.work_time,
         phenophaseCode: detail.phenophase_code,
         phenophaseName: detail.phenophase_name,
         fwExplain: detail.fw_explain,
         fwAtten: detail.fw_atten,
         fwParams: detail.fw_params,
         fwPrecrip: detail.fw_precrip,
-        workType: item.work_type,
+        workType,
         workStatus: rawStatus,
         agronomyType: isWarning ? "warning" : "standard",
-        // 点击进详情原样带入
-        agronomy_detail: item?.agronomy_detail || null,
+        agronomy_detail: record.agronomy_detail || null,
+        fwTypeGroups: Array.isArray(item?.fw_type_groups) ? item.fw_type_groups : null,
         wkt: hasCoord ? `POINT(${lng + dx} ${lat + dy})` : "",
     };
 }
@@ -209,7 +240,16 @@ async function requestUserWork(centerWkt, workTime) {
         ElMessage.error(res?.message || res?.msg || "获取农事列表失败");
         return [];
     }
-    const list = Array.isArray(res?.data) ? res.data : [];
+    const data = res?.data;
+    let list = [];
+    if (Array.isArray(data)) {
+        list = data;
+    } else if (Array.isArray(data?.work_records)) {
+        // 整包只有 work_records 时,直接按记录列表映射
+        list = data.work_records;
+    } else if (data) {
+        list = [data];
+    }
     return list.map((item, index) => mapUserWorkToTask(item, index, centerWkt));
 }
 
@@ -282,7 +322,7 @@ const handleForward = (item) => {
 };
 
 const handleViewDetail = (item) => {
-    if (item?.agronomy_detail) {
+    if (item?.agronomy_detail || item?.fwTypeGroups?.length) {
         sessionStorage.setItem(
             WORK_AGRONOMY_DETAIL_KEY,
             JSON.stringify({
@@ -297,6 +337,7 @@ const handleViewDetail = (item) => {
                 isWeather: item.isWeather,
                 isHighRisk: item.isHighRisk,
                 cornerTip: item.cornerTip || "",
+                fw_type_groups: item.fwTypeGroups || [],
             })
         );
     }