소스 검색

feat:对接农事列表接口和新增农场逻辑

wangsisi 2 주 전
부모
커밋
0611f6bc5a
3개의 변경된 파일과 122개의 추가작업 그리고 83개의 파일을 삭제
  1. 3 8
      src/api/modules/questionnaire.js
  2. 57 6
      src/views/old_mini/entry_information/components/baInformation.vue
  3. 62 69
      src/views/old_mini/work_execute/index.vue

+ 3 - 8
src/api/modules/questionnaire.js

@@ -31,14 +31,9 @@ module.exports = {
         url: config.base_new_url + "report/county_phenophase",
         type: "get",
     },
-    // 标准农事列表
-    standardAgronomy: {
-        url: config.base_new_url + "report/standard_agronomy",
-        type: "get",
-    },
-    // 预警农事列表
-    warningAgronomy: {
-        url: config.base_new_url + "report/warning_agronomy",
+    // 用户农事列表
+    userWork: {
+        url: config.base_new_url + "report/user_work",
         type: "get",
     },
 }

+ 57 - 6
src/views/old_mini/entry_information/components/baInformation.vue

@@ -309,6 +309,10 @@ function toFiniteNumber(value, fallback) {
     return Number.isFinite(n) ? n : fallback;
 }
 
+function formatDateYMD(date = new Date()) {
+    return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
+}
+
 /** 邀请管理员 id:优先路由参数 */
 function resolveAdminId() {
     return toFiniteNumber(route.query.adminId ?? route.query.admin_id, 1);
@@ -334,6 +338,46 @@ function resolveMachineIds() {
     }
 }
 
+/**
+ * 组装 crops:优先已选品种草稿,否则用当前品类 + 点位
+ * 结构对齐 add_plot_info 文档
+ */
+function buildCropsPayload(point, selectedCrop, cropName) {
+    try {
+        const varietyList = JSON.parse(sessionStorage.getItem("ENTRY_SELECTED_VARIETY_LIST") || "[]");
+        if (Array.isArray(varietyList) && varietyList.length) {
+            return varietyList.map((item) => ({
+                crop_type: item.categoryName || cropName || "",
+                crop_id: toFiniteNumber(item.categoryId, 0),
+                variety_list: item.id != null ? [String(item.id)] : [],
+                phenophase:
+                    item.phenophase ||
+                    item.phenologyName ||
+                    (item.phenologyId != null ? String(item.phenologyId) : "") ||
+                    selectedCrop?.code ||
+                    "",
+                start_time: item.startTime || formatDateYMD(),
+                plant_area: toFiniteNumber(item.area, 0),
+                point: item.location || point || "",
+            }));
+        }
+    } catch {
+        // ignore
+    }
+
+    return [
+        {
+            crop_type: cropName || "",
+            crop_id: toFiniteNumber(selectedCrop?.cropId, 0),
+            variety_list: [],
+            phenophase: selectedCrop?.code || "",
+            start_time: formatDateYMD(),
+            plant_area: 0,
+            point: point || "",
+        },
+    ];
+}
+
 const handleNext = async () => {
     if (!formRef.value || submitting.value) return;
     try {
@@ -360,16 +404,21 @@ const handleNext = async () => {
 
     submitting.value = true;
     try {
-        const res = await VE_API.questionnaire.addPlotInfo({
+        const raw = await VE_API.questionnaire.addPlotInfo({
             user_name: form.name,
             tel: form.phone,
             admin_id: resolveAdminId(),
             user_id: resolveUserId(),
             machine_id: resolveMachineIds(),
             county_code: countyCode,
+            crops: buildCropsPayload(point, selectedCrop, crop),
         });
-        if (res?.code != null && res.code !== 200) {
-            ElMessage.error(res.msg || "提交失败,请稍后再试");
+        // 兼容 {code,data} 或 [{code,data}, status]
+        const res = Array.isArray(raw) ? raw[0] : raw;
+        const code = Number(res?.code);
+        const ok = code === 200 || code === 0 || code === 1;
+        if (!ok) {
+            ElMessage.error(res?.message || res?.msg || "提交失败,请稍后再试");
             return;
         }
 
@@ -384,18 +433,20 @@ const handleNext = async () => {
             adcode: saved?.adcode || String(countyCode),
             weatherRisk: weatherMeta.weatherRisk,
             weatherStress: weatherMeta.weatherStress,
+            farmId: res?.data?.farm_id ?? null,
         };
         localStorage.setItem(ENTRY_FARM_DATA_KEY, JSON.stringify(farmData));
         if (point) {
             localStorage.setItem("GROWTH_REPORT_MAP_POINT", point);
             localStorage.setItem("selectedFarmPoint", point);
         }
-        VE_API.questionnaire.generateReport({ region, crop, tel: form.phone }).catch(() => {});
         localStorage.setItem(HAS_FARM_KEY, "1");
+        VE_API.questionnaire.generateReport({ region, crop, tel:form.phone }).catch(() => {});
         clearFormDraft();
+        ElMessage.success(res?.message || res?.msg || "上传成功,报告正在生成中...");
         router.replace("/growth_report");
-        ElMessage.success("上传成功,报告正在生成中...");
-    } catch {
+    } catch (e) {
+        console.error("addPlotInfo failed", e);
         ElMessage.error("提交失败,请稍后再试");
     } finally {
         submitting.value = false;

+ 62 - 69
src/views/old_mini/work_execute/index.vue

@@ -155,10 +155,30 @@ function readEntryFarmData() {
     }
 }
 
+/** 农事列表用手机号:优先录入信息 */
+function resolveUserTel() {
+    const entry = readEntryFarmData();
+    if (entry?.phone) return String(entry.phone).trim();
+    try {
+        const userInfo = JSON.parse(localStorage.getItem("localUserInfo") || "{}");
+        return String(userInfo.tel || userInfo.phone || userInfo.mobile || "").trim();
+    } catch {
+        return "";
+    }
+}
+
 function formatExecuteDate(date = new Date()) {
     return `${String(date.getMonth() + 1).padStart(2, "0")}/${String(date.getDate()).padStart(2, "0")}`;
 }
 
+/** work_time → MM/DD */
+function formatWorkTime(workTime) {
+    if (!workTime) return formatExecuteDate();
+    const d = new Date(workTime);
+    if (Number.isNaN(d.getTime())) return formatExecuteDate();
+    return formatExecuteDate(d);
+}
+
 /** 根据中心点生成附近任务点位(已完成 mock) */
 const buildCompletedNearCenter = (centerWkt) => {
     const coord = convertPointToArray(centerWkt);
@@ -175,96 +195,69 @@ const buildCompletedNearCenter = (centerWkt) => {
     });
 };
 
-/**
- * 接口农事 → 列表卡片
- * @param {'standard' | 'warning'} type 标准 / 预警
- */
-function mapAgronomyToTask(item, index, centerWkt, type = "standard") {
+/** user_work 单条 → 列表卡片 */
+function mapUserWorkToTask(item, index, centerWkt) {
+    const detail = item?.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 = item.fw_name || "";
-    const isWarning = type === "warning";
+    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;
     return {
-        id: item.id ?? `${type}-${index}`,
-        status: "pending",
+        id: item.work_id ?? detail.id ?? `work-${index}`,
+        status: isCompleted ? "completed" : "pending",
         title,
         farmName: title,
         isHighRisk: isWarning,
         isNormal: !isWarning,
         isAbnormal: false,
         isWeather: isWarning,
-        cornerTip: isWarning ? "建议执行" : "待执行",
-        analysisSummary: item.fw_explain_simple || item.fw_explain || "",
-        areaCode: item.crop_category_name || "分区一",
-        executeDate: formatExecuteDate(),
-        phenophaseCode: item.phenophase_code,
-        phenophaseName: item.phenophase_name,
-        fwExplain: item.fw_explain,
-        fwAtten: item.fw_atten,
-        fwParams: item.fw_params,
-        fwPrecrip: item.fw_precrip,
-        agronomyType: type,
+        cornerTip: isCompleted ? "已完成" : isWarning ? "建议执行" : "待执行",
+        analysisSummary: detail.fw_explain_simple || detail.fw_explain || "",
+        areaCode: detail.crop_category_name || "分区一",
+        executeDate,
+        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,
+        workStatus: item.work_status,
+        agronomyType: isWarning ? "warning" : "standard",
         wkt: hasCoord ? `POINT(${lng + dx} ${lat + dy})` : "",
     };
 }
 
-/** 拉取单类农事,失败返回空数组(不阻断另一类) */
-async function requestAgronomyList(apiFn, params, errorMsg) {
+/** 拉取用户农事列表(report/user_work) */
+async function fetchUserWorkTasks(centerWkt) {
+    const tel = resolveUserTel();
+    if (!tel) {
+        taskList.value = buildCompletedNearCenter(centerWkt);
+        return;
+    }
     try {
-        const res = await apiFn(params);
-        if (res?.code != null && res.code !== 200) {
-            ElMessage.error(res.msg || errorMsg);
-            return [];
+        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;
         }
-        return Array.isArray(res?.data) ? res.data : [];
+        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)];
     } catch {
-        ElMessage.error(errorMsg);
-        return [];
-    }
-}
-
-/** 并行拉取标准农事 + 预警农事 */
-async function fetchAgronomyTasks(centerWkt) {
-    const entry = readEntryFarmData();
-    const cropType = entry?.crop;
-    const phenophaseCode = entry?.cropCode;
-    const riskName = entry?.weatherRisk;
-    if (!cropType || !phenophaseCode) {
+        ElMessage.error("获取农事列表失败,请稍后再试");
         taskList.value = buildCompletedNearCenter(centerWkt);
-        return;
     }
-
-    const baseParams = {
-        crop_type: cropType,
-        phenophase_code: phenophaseCode,
-    };
-
-    const standardPromise = requestAgronomyList(
-        VE_API.questionnaire.standardAgronomy,
-        baseParams,
-        "获取标准农事失败"
-    );
-
-    const warningPromise = riskName
-        ? requestAgronomyList(
-              VE_API.questionnaire.warningAgronomy,
-              { ...baseParams, risk_name: riskName },
-              "获取预警农事失败"
-          )
-        : Promise.resolve([]);
-
-    const [standardList, warningList] = await Promise.all([standardPromise, warningPromise]);
-    const pending = [
-        ...standardList.map((item, index) => mapAgronomyToTask(item, index, centerWkt, "standard")),
-        ...warningList.map((item, index) =>
-            mapAgronomyToTask(item, standardList.length + index, centerWkt, "warning")
-        ),
-    ];
-    taskList.value = [...pending, ...buildCompletedNearCenter(centerWkt)];
 }
 const activeTab = ref("pending");
 const pendingCount = computed(() => taskList.value.filter((item) => item.status === "pending").length);
@@ -381,7 +374,7 @@ const refreshMapMarkers = () => {
 const loadWorkPage = async () => {
     if (!mapContainer.value) return;
     mapPoint.value = resolveMapPoint();
-    await fetchAgronomyTasks(mapPoint.value);
+    await fetchUserWorkTasks(mapPoint.value);
     refreshMapMarkers();
     if (mapContainer.value && indexMap.kmap?.map) {
         const checkAndUpdateSize = () => {