Kaynağa Gözat

feat:修改编辑信息弹窗和农情互动bug

wangsisi 1 gün önce
ebeveyn
işleme
2bf7661677

+ 4 - 4
src/views/old_mini/create_farm/index.vue

@@ -40,7 +40,7 @@
                                     </el-form-item>
                                     <el-form-item label="种植作物" prop="speciesItem">
                                         <div class="select-wrap specie-wrap">
-                                            <el-select v-model="ruleForm.speciesItem" class="select-item specie-select"
+                                            <el-select v-model="ruleForm.speciesItem" filterable class="select-item specie-select"
                                                 multiple :max-collapse-tags="3" collapse-tags placeholder="种植作物(可多选)" @change="changeSpecie">
                                                 <el-option v-for="(item, index) in specieList" :key="index"
                                                     :label="item.name" :value="{ value: item.id, ...item }" />
@@ -513,7 +513,7 @@ const submitForm = (formEl) => {
             //     // pageData = JSON.parse(json.paramsPage);
             // }
 
-            // if (route.query.type === "add" || pageData?.type === 'add' || route.query.type === "farmer") {
+            if (route.query.type !== "edit") {
                 // 处理 geom 参数,如果是数组需要序列化
                 const queryParams = {
                     ...params,
@@ -538,7 +538,7 @@ const submitForm = (formEl) => {
                     query: queryParams,
                 });
                 return;
-            // }
+            }
 
             // const apiCall = route.query.type === "edit" ? VE_API.basic_farm.saveBasicFarmInfoByExpertV3({...params, expertMiniUserId: '81881'}) : VE_API.farm.saveFarm(params);
 
@@ -1151,7 +1151,7 @@ function handleMianjiInput(value) {
                     //     }
                     // }
 
-                    // width: 86%;
+                    width: 100%;
                     ::v-deep {
                         .el-input__wrapper {
                             background: none;

+ 169 - 105
src/views/old_mini/home/components/farmInfoPopup.vue

@@ -1,57 +1,65 @@
 <template>
-    <Popup
-        v-model:show="show"
-        :overlay-style="{ zIndex: 9999 }"
-        teleport="body"
-        class="farm-info-popup"
-        closeable>
+    <Popup v-model:show="show" :overlay-style="{ zIndex: 9999 }" teleport="body" class="farm-info-popup" closeable>
         <div class="popup-content-box">
             <div class="popup-title">基本信息</div>
             <div class="popup-content">
-                <div class="map-box">
+                <!-- <div class="map-box">
                     <div class="map" ref="mapContainer"></div>
-                    <!-- <div class="map-text" @click="handleEditMap">点击编辑地块</div> -->
-                </div>
+                </div> -->
                 <cell-group inset class="cell-group">
-                    <field v-model="farmInfo.name" readonly label="农场名称" />
+                    <field v-model="farmInfo.subjectName" label="农场名称" />
                     <field readonly label="农场面积">
                         <template #input>
-                            <span>{{ farmInfo.mianji }}亩</span>
+                            <span>{{ farmInfo.farmArea }}亩</span>
                         </template>
                     </field>
-                    <field readonly label="种植作物">
+                    <field readonly label="种植作物" class="crop-field">
                         <template #input>
-                            <span>{{ farmInfo.speciesName }}-{{ farmInfo.typeName }}</span>
+                            <template v-if="farmInfo.regionList && farmInfo.regionList.length">
+                                <template v-for="(item, index) in farmInfo.regionList" :key="index">
+                                    <span>{{ item.regionName }}</span>
+                                    <span v-if="index !== farmInfo.regionList.length - 1">、</span>
+                                </template>
+                            </template>
+                            <template v-else>
+                                <span>-</span>
+                            </template>
                         </template>
                     </field>
-                    <!-- <field v-model="farmInfo.userType" readonly label="客户类型">
+                    <field v-model="farmInfo.contactName" label="联系人" />
+                    <field
+                        ref="contactPhoneFieldRef"
+                        v-model="farmInfo.contactPhone"
+                        label="联系电话"
+                        type="tel"
+                        maxlength="11"
+                        :rules="contactPhoneRules"
+                    />
+                    <field class="address-field" v-model="farmInfo.farmAddress" readonly label="农场位置" />
+                    <field label="基地类别" class="base-type-field">
                         <template #input>
-                            <span>{{ userTypeMap[farmInfo.userType] }}</span>
-                        </template>
-                    </field> -->
-                    <field v-model="farmInfo.fzr" readonly label="联系人" />
-                    <field v-model="farmInfo.tel" readonly label="联系电话" />
-                    <field class="address-field" v-model="farmInfo.address" readonly label="农场位置" />
-                    
-                    <field v-model="farmInfo.baseType" readonly label="基地类别">
-                        <template #input>
-                            <!-- <span>{{ userTypeMap[farmInfo.userType] }}</span> -->
-                            <span>{{ baseTypeMap[farmInfo?.baseType] }}</span>
+                            <el-select
+                                v-model="farmInfo.baseType"
+                                placeholder="请选择"
+                                class="base-type-select"
+                                autocomplete="off"
+                                teleported
+                                popper-class="farm-info-base-type-popper"
+                            >
+                                <el-option
+                                    v-for="opt in baseTypeOptions"
+                                    :key="opt.id"
+                                    :label="opt.name"
+                                    :value="opt.id"
+                                />
+                            </el-select>
                         </template>
                     </field>
-                    <checkbox
-                        v-if="!showBtn"
-                        class="checkbox"
-                        icon-size="16px"
-                        shape="square"
-                        v-model="farmInfo.defaultOption"
-                        >是否勾选为默认农场</checkbox
-                    >
                 </cell-group>
             </div>
-            <div class="popup-footer" v-if="!showBtn || showEditBtn">
+            <div class="popup-footer">
                 <div class="footer-btn no-btn" @click="handleCancel">取消</div>
-                <div class="footer-btn yes-btn" @click="handleEdit">去编辑</div>
+                <div class="footer-btn yes-btn" @click="handleEdit">确认修改</div>
             </div>
         </div>
     </Popup>
@@ -63,17 +71,23 @@ import { ref, nextTick } from "vue";
 import { useRouter } from "vue-router";
 import IndexMap from "../map/index.js";
 import { useStore } from "vuex";
+import { ElMessage } from "element-plus";
 
-const userTypeMap = {
-    1: "普通用户",
-    2: "托管用户",
-    3: "优质客户",
-};
+/** 与 create_farm 联系电话规则一致 */
+const contactPhoneRules = [
+    { required: true, message: "请输入联系电话" },
+    {
+        pattern: /^1[3-9]\d{9}$/,
+        message: "请输入正确的手机号码",
+    },
+];
 
-const baseTypeMap = {
-    1: "农民专业合作组织",
-    2: "农业企业",
-    3: "家庭农场",
+const baseTypeOptions = ref([]);
+function getBaseTypeList() {
+    return VE_API.farm.fetchBaseTypeList().then(({ data }) => {
+        baseTypeOptions.value = data || [];
+        return data;
+    });
 }
 
 const props = defineProps({
@@ -81,89 +95,96 @@ const props = defineProps({
         type: [Number, String],
         default: null,
     },
-    showBtn: {
-        type: Boolean,
-        default: false,
-    },
-    showEditBtn: {
-        type: Boolean,
-        default: false,
-    },
 });
 
 const store = useStore();
 const router = useRouter();
 const show = ref(false);
 const mapContainer = ref(null);
+const contactPhoneFieldRef = ref(null);
 const indexMap = new IndexMap();
 
 // 农场信息
 const farmInfo = ref();
 const handleShow = () => {
-    VE_API.farm.getFarmDetail({ farmId: props.farmId }).then((res) => {
+    VE_API.basic_farm.fetchFarmSubjectDetail({ subjectId: props.farmId }).then((res) => {
         if (res.code === 0) {
             farmInfo.value = res.data;
+            getBaseTypeList();
             show.value = true;
-            nextTick(() => {
-                const point = farmInfo.value.pointWkt;
-                const geometryArr = farmInfo.value.geomWkt;
-
-                // 如果地图已经初始化,则更新中心点和地块;否则初始化地图
-                if (indexMap.kmap) {
-                    indexMap.updateCenter(point);
-                    // 如果有地块数据,则添加地块
-                    if (geometryArr && geometryArr.length > 0) {
-                        indexMap.setAreaGeometry([geometryArr]);
-                    }
-                } else {
-                    indexMap.initMap(point, mapContainer.value);
-                    // 初始化地图后,如果有地块数据,则添加地块
-                    if (geometryArr && geometryArr.length > 0) {
-                        indexMap.setAreaGeometry([geometryArr]);
-                    }
-                }
-            });
+            // nextTick(() => {
+            //     const point = farmInfo.value.farmLocation;
+            //     let geometryArr = [];
+
+            //     if (Array.isArray(farmInfo.value.regionList) && farmInfo.value.regionList.length > 0) {
+            //         farmInfo.value.regionList.forEach((item) => {
+            //             if (item?.geom) {
+            //                 geometryArr.push(item?.geom)
+            //             }
+            //         });
+            //     }
+
+            //     console.log('geometryArr', geometryArr);
+            //     // 如果地图已经初始化,则更新中心点和地块;否则初始化地图
+            //     if (indexMap.kmap) {
+            //         indexMap.updateCenter(point);
+            //         // 如果有地块数据,则添加地块
+            //         if (geometryArr && geometryArr.length > 0) {
+            //             indexMap.setAreaGeometry([geometryArr]);
+            //         }
+            //     } else {
+            //         indexMap.initMap(point, mapContainer.value);
+            //         // 初始化地图后,如果有地块数据,则添加地块
+            //         if (geometryArr && geometryArr.length > 0) {
+            //             indexMap.setAreaGeometry([geometryArr]);
+            //         }
+            //     }
+            // });
         }
     });
 };
 
-const handleEditMap = () => {
-    // 在跳转前,将当前农场的地块数据存储到store中
-    if (farmInfo.value.geomWkt) {
-        const polygonData = {
-            geometryArr: [farmInfo.value.geomWkt],
-            isConfirmed: false,
-        };
-        store.commit("home/SET_FARM_POLYGON", polygonData);
-    }
-
-    router.push(
-        `/edit_map?mapCenter=${farmInfo.value.pointWkt}&pointName=${farmInfo.value.address}&pointAddress=${JSON.parse(
-            farmInfo.value.district
-        )}&type=edit`
-    );
-};
+const emit = defineEmits(['success']);
 
-const handleEdit = () => {
-    setTimeout(() => {
-        show.value = false;
-    }, 150);
-
-    // 在跳转前,将当前农场的地块数据存储到store中
-    if (farmInfo.value.geomWkt) {
-        const polygonData = {
-            geometryArr: [farmInfo.value.geomWkt],
-            mianji: farmInfo.value.mianji,
-            isConfirmed: true, // 编辑模式下标记为已确认
-        };
-        store.commit("home/SET_FARM_POLYGON", polygonData);
+const handleEdit = async () => {
+    const phoneErr = await contactPhoneFieldRef.value?.validate();
+    if (phoneErr?.message) {
+        return;
     }
+    const paramsData = {
+        id: props.farmId,
+        name: farmInfo.value.subjectName,
+        fzr: farmInfo.value.contactName,
+        tel: farmInfo.value.contactPhone,
+        baseType: farmInfo.value.baseType,
+        expertMiniUserId: 81881,
+    }
+    VE_API.basic_farm.saveBasicFarmInfoByExpertV3(paramsData).then((res) => {
+        if (res.code === 0) {
+            ElMessage.success('修改成功');
+            show.value = false;
+            emit('success');
+        }
+    });
+    // setTimeout(() => {
+    //     show.value = false;
+    // }, 150);
+
+    // // 在跳转前,将当前农场的地块数据存储到store中
+    // if (farmInfo.value.geomWkt) {
+    //     const polygonData = {
+    //         geometryArr: [farmInfo.value.geomWkt],
+    //         mianji: farmInfo.value.mianji,
+    //         isConfirmed: true, // 编辑模式下标记为已确认
+    //     };
+    //     store.commit("home/SET_FARM_POLYGON", polygonData);
+    // }
 
-    // 将农场数据存储到store中,供编辑页面使用
-    store.commit("home/SET_EDIT_FARM_DATA", farmInfo.value);
+    // // 将农场数据存储到store中,供编辑页面使用
+    // store.commit("home/SET_EDIT_FARM_DATA", farmInfo.value);
 
-    const from = props.showEditBtn ? "details" : "monitor";
-    router.push(`/create_farm?type=edit&farmId=${props.farmId}&from=${from}`);
+    // const from = props.showEditBtn ? "details" : "monitor";
+    // router.push(`/create_farm?type=edit&farmId=${props.farmId}&from=${from}`);
 };
 
 const handleCancel = () => {
@@ -179,32 +200,39 @@ defineExpose({ handleShow });
     border-radius: 8px;
     z-index: 9999 !important;
     overflow: hidden;
+
     .popup-content-box {
         background: url("@/assets/img/home/popup-mask.png") no-repeat center left / 100% 100%;
         padding: 20px;
     }
+
     ::v-deep {
         .van-popup__close-icon {
             color: #000;
         }
     }
+
     .popup-title {
         text-align: center;
         font-size: 24px;
         font-family: "PangMenZhengDao";
     }
+
     .popup-content {
         margin: 12px 0;
+
         .map-box {
             width: 100%;
             height: 150px;
             position: relative;
+
             .map {
                 width: 100%;
                 height: 100%;
                 clip-path: inset(0px round 5px);
                 pointer-events: none;
             }
+
             .map-text {
                 position: absolute;
                 right: 6px;
@@ -217,10 +245,34 @@ defineExpose({ handleShow });
                 border: 1px solid rgba(255, 255, 255, 0.5);
             }
         }
+
         .cell-group {
             margin: 12px 0 0;
+
+            .crop-field {
+                ::v-deep {
+                    .van-field__control--custom {
+                        flex-wrap: wrap;
+                    }
+                }
+            }
+
+            .base-type-field {
+                ::v-deep {
+                    .el-select {
+                        width: 100%;
+                    }
+                    .el-select__wrapper {
+                        min-height: 24px;
+                        box-shadow: none;
+                        padding-left: 0;
+                    }
+                }
+            }
+
             .address-field {
                 position: relative;
+
                 &::before {
                     position: absolute;
                     box-sizing: border-box;
@@ -235,23 +287,28 @@ defineExpose({ handleShow });
             }
         }
     }
+
     .checkbox {
         pointer-events: none;
         padding: 12px 14px;
     }
+
     .popup-footer {
         display: flex;
         gap: 13px;
+
         .footer-btn {
             text-align: center;
             flex: 1;
             padding: 8px 0;
             border-radius: 25px;
         }
+
         .no-btn {
             color: #666666;
             border: 1px solid #999999;
         }
+
         .yes-btn {
             background: #2199f8;
             color: #fff;
@@ -259,3 +316,10 @@ defineExpose({ handleShow });
     }
 }
 </style>
+
+<!-- 下拉挂载在 body,需非 scoped 才能盖住 van-popup(z-index: 9999) -->
+<style lang="scss">
+.farm-info-base-type-popper {
+    z-index: 10050 !important;
+}
+</style>

+ 0 - 1
src/views/old_mini/home/map/index.js

@@ -21,7 +21,6 @@ class IndexMap {
           image: new Icon({
             src: require("@/assets/img/home/garden-point.png"),
             scale: 0.5,
-            anchor: [0.5, 1],
           }),
         });
       },

+ 1 - 2
src/views/old_mini/home/subPages/prescriptionPage.vue

@@ -476,9 +476,8 @@ function handleSubmit() {
 
     // 收集灌溉方式(获取选中的 code)
     const irrigationMethods = (basicFarmFormData.value.irrigationMethods || [])
-        .filter(item => item.selected)
+        .filter(item => item.selected || item.custom)
         .map(item => item.code || item.id);
-
     // 收集农机设备(包含 code 和 quantity)
     const machineryWithQuantity = (basicFarmFormData.value.machinery || [])
         .filter(item => item.selected && item.quantity)

+ 70 - 21
src/views/old_mini/interactionList/index.vue

@@ -128,11 +128,22 @@
 
                     <!-- 按钮区域 -->
                     <div class="button-group" v-show="item.questionStatus === 3">
-                        <div class="btn-not-reached" @click="handleConfirm(item, false)">{{ item.cancelButtonName }}</div>
-                        <div class="btn-default"
-                            :class="{ 'btn-confirm': item.imagePaths.length > 0, 'btn-loading': isItemSubmitting(item) }"
-                            @click="handleConfirm(item, true)">
-                            {{ isItemSubmitting(item) ? '提交中...' : '确认提交' }}
+                        <div
+                            class="btn-not-reached"
+                            :class="{ 'btn-loading': isItemSubmittingCancel(item) }"
+                            @click="handleConfirm(item, false)"
+                        >
+                            {{ isItemSubmittingCancel(item) ? '提交中...' : item.cancelButtonName }}
+                        </div>
+                        <div
+                            class="btn-default"
+                            :class="{
+                                'btn-confirm': item.imagePaths.length > 0,
+                                'btn-loading': isItemSubmittingConfirm(item),
+                            }"
+                            @click="handleConfirm(item, true)"
+                        >
+                            {{ isItemSubmittingConfirm(item) ? '提交中...' : '确认提交' }}
                         </div>
                     </div>
 
@@ -277,11 +288,37 @@ const itemSubmittingMap = ref({});
 const confirmUploadLoading = ref(false);
 
 const getItemSubmitKey = (item) => String(item?.id ?? "");
+/** 任意一种提交进行中(用于防重复点击) */
 const isItemSubmitting = (item) => {
     const key = getItemSubmitKey(item);
     if (!key) return false;
     return !!itemSubmittingMap.value[key];
 };
+const isItemSubmittingConfirm = (item) => {
+    const key = getItemSubmitKey(item);
+    return key ? itemSubmittingMap.value[key] === "confirm" : false;
+};
+const isItemSubmittingCancel = (item) => {
+    const key = getItemSubmitKey(item);
+    return key ? itemSubmittingMap.value[key] === "cancel" : false;
+};
+
+/** 接口长时间无响应时结束等待,避免按钮一直「提交中」 */
+const SUBMIT_API_TIMEOUT_MS = 120000;
+const raceWithTimeout = (promise, ms = SUBMIT_API_TIMEOUT_MS) =>
+    Promise.race([
+        Promise.resolve(promise),
+        new Promise((_, reject) =>
+            setTimeout(() => reject(new Error("请求超时,请稍后重试")), ms)
+        ),
+    ]);
+
+const clearItemSubmittingKey = (key) => {
+    if (!key) return;
+    const next = { ...itemSubmittingMap.value };
+    delete next[key];
+    itemSubmittingMap.value = next;
+};
 
 const renderRegionFromSession = () => {
     if (!drawRegionMap.kmap) return;
@@ -581,28 +618,33 @@ const handleConfirm = async (item, isConfirm) => {
         regionId: ''
     }
     const key = getItemSubmitKey(item);
+    const submitKind = isConfirm ? "confirm" : "cancel";
     if (key) {
-        itemSubmittingMap.value[key] = true;
+        itemSubmittingMap.value = { ...itemSubmittingMap.value, [key]: submitKind };
     }
+    let needRefresh = false;
     try {
-        await VE_API.home.uploadAnswerData(parmas);
-        const { code, msg } = await VE_API.home.uploadAnswer(parmas);
+        await raceWithTimeout(VE_API.home.uploadAnswerData(parmas));
+        const { code, msg } = await raceWithTimeout(VE_API.home.uploadAnswer(parmas));
         if (code === 0) {
             ElMessage.success("上传成功");
-            // 清空上传数据
             uploadData.value = [];
-            // 刷新列表
-            await refreshList();
             sessionStorage.removeItem("drawRegionPolygonData");
             sessionStorage.removeItem("drawRegionInteractionId");
+            needRefresh = true;
         } else {
-            ElMessage.error(msg || '上传失败');
+            ElMessage.error(msg || "上传失败");
         }
     } catch (error) {
-        ElMessage.error("上传失败,请稍后重试");
+        ElMessage.error(error?.message || "上传失败,请稍后重试");
     } finally {
-        if (key) {
-            itemSubmittingMap.value[key] = false;
+        clearItemSubmittingKey(key);
+    }
+    if (needRefresh) {
+        try {
+            await refreshList();
+        } catch (e) {
+            ElMessage.error("列表刷新失败,请下拉重试");
         }
     }
 };
@@ -633,25 +675,31 @@ const handleConfirmUpload = async () => {
         answerValues: answerVals,
     }
     confirmUploadLoading.value = true;
+    let needRefresh = false;
     try {
-        const { code, msg } = await VE_API.home.uploadAnswerData(parmas);
+        const { code, msg } = await raceWithTimeout(VE_API.home.uploadAnswerData(parmas));
         if (code === 0) {
             ElMessage.success("确认成功");
-            // 清空上传数据及勾画关联
             uploadData.value = [];
             sessionStorage.removeItem("drawRegionPolygonData");
             sessionStorage.removeItem("drawRegionInteractionId");
             showUploadProgressPopup.value = false;
-            // 刷新列表
-            await refreshList();
+            needRefresh = true;
         } else {
-            ElMessage.error(msg || '确认失败');
+            ElMessage.error(msg || "确认失败");
         }
     } catch (error) {
-        ElMessage.error("确认失败,请稍后重试");
+        ElMessage.error(error?.message || "确认失败,请稍后重试");
     } finally {
         confirmUploadLoading.value = false;
     }
+    if (needRefresh) {
+        try {
+            await refreshList();
+        } catch (e) {
+            ElMessage.error("列表刷新失败,请下拉重试");
+        }
+    }
 };
 
 // 切换展开/收起
@@ -1104,6 +1152,7 @@ const handleSubmitAll = () => {
                     max-width: fit-content;
                     background: #fff;
                     color: #585858;
+                    min-width: 98px;
                     border: 1px solid rgba(88, 88, 88, 0.2);
                 }
 

+ 17 - 12
src/views/old_mini/monitor/subPages/farmInfo.vue

@@ -88,6 +88,7 @@
             </div>
         </div>
     </div>
+    <FarmInfoPopup ref="farmInfoPopupRef" :farmId="route.query.subjectId" @success="fetchFarmSubjectDetail" />
 </template>
 
 <script setup>
@@ -98,6 +99,7 @@ import DrawRegionMap from "@/views/old_mini/interactionList/map/drawRegionMap.js
 import * as util from "@/common/ol_common.js";
 import { ElMessage } from "element-plus";
 import { useStore } from "vuex";
+import FarmInfoPopup from "@/views/old_mini/home/components/farmInfoPopup.vue";
 
 const router = useRouter();
 const route = useRoute();
@@ -179,6 +181,7 @@ function fetchBasicFarmFormData() {
     });
 }
 
+const farmInfoPopupRef = ref(null);
 const handleEditFarmInfo = () => {
     // // 回显地块:存到 polygonData,创建页会优先使用这里的数据
     // if (data.geomWkt) {
@@ -192,20 +195,22 @@ const handleEditFarmInfo = () => {
     //     store.commit("home/SET_FARM_POLYGON", null);
     // }
 
-    const params = {
-        ...farmInfo.value,
-        name: farmInfo.value.subjectName,
-        fzr: farmInfo.value.contactName,
-        tel: farmInfo.value.contactPhone,
-        mianji: farmInfo.value.farmArea,
-        address: farmInfo.value.farmAddress,
-    };
+    // const params = {
+    //     ...farmInfo.value,
+    //     name: farmInfo.value.subjectName,
+    //     fzr: farmInfo.value.contactName,
+    //     tel: farmInfo.value.contactPhone,
+    //     mianji: farmInfo.value.farmArea,
+    //     address: farmInfo.value.farmAddress,
+    // };
 
-    // 回显其他表单字段
-    store.commit("home/SET_EDIT_FARM_DATA", params);
+    // // 回显其他表单字段
+    // store.commit("home/SET_EDIT_FARM_DATA", params);
 
-    // 带上 from=details,创建页提交/取消后能正确返回
-    router.push(`/create_farm?type=edit&farmId=${route.query.subjectId}&from=details`);
+    // // 带上 from=details,创建页提交/取消后能正确返回
+    // router.push(`/create_farm?type=edit&farmId=${route.query.subjectId}&from=details`);
+
+    farmInfoPopupRef.value.handleShow();
 };
 
 const handleEditFarmFacility = () => {