Jelajahi Sumber

feat:添加需求大厅关注农场和搜索区域位置接口

wangsisi 2 minggu lalu
induk
melakukan
e179390ecb

+ 16 - 1
src/api/modules/z_farm_work_record.js

@@ -46,5 +46,20 @@ module.exports = {
     getOrderReceivingSimpleList:{
         url: url + "/getOrderReceivingSimpleList",
         type: "get",
-    }
+    },
+    //根据城市的坐标返回区县列表
+    getDistrictListByCity:{
+        url: config.base_dev_url + "city/districtListbyPoint",
+        type: "get",
+    },
+    //农资关注农场
+    followFarm: {
+        url: config.base_dev_url + "z_agricultural_store_farm/follow",
+        type: "post",
+    },
+    //农资取消关注农场
+    unfollowFarm: {
+        url: config.base_dev_url + "z_agricultural_store_farm/unfollow",
+        type: "post",
+    },
 }

+ 123 - 0
src/components/pageComponents/LocationSearch.vue

@@ -0,0 +1,123 @@
+<template>
+    <el-select
+        v-model="locationVal"
+        filterable
+        remote
+        clearable
+        reserve-keyword
+        placeholder="搜索位置"
+        :remote-method="remoteMethod"
+        :loading="loading"
+        @change="handleSearchRes"
+        popper-class="location-search-popper"
+        :class="customClass"
+        @clear="handleClear"
+    >
+        <el-option
+            v-for="(item, index) in locationOptions.list"
+            :key="index"
+            :label="item.title"
+            :value="{ value: item.point, item }"
+        >
+            <span>{{ item.title }}</span>
+            <span class="sub-title">{{ item.province }}{{ item.city }}{{ item.district }}</span>
+        </el-option>
+    </el-select>
+</template>
+
+<script setup>
+import { ref, reactive } from "vue";
+import { transformFromGCJToWGS } from "@/utils/WSCoordinate.js";
+
+const MAP_KEY = "CZLBZ-LJICQ-R4A5J-BN62X-YXCRJ-GNBUT";
+
+const props = defineProps({
+    userLocation: {
+        type: String,
+        default: "113.61702297075017,23.584863449735067",
+    },
+    customClass: {
+        type: String,
+        default: "",
+    },
+});
+
+const emit = defineEmits(["change"]);
+
+const locationVal = ref(null);
+const locationOptions = reactive({
+    list: [],
+});
+const loading = ref(false);
+
+const remoteMethod = async (keyword) => {
+    if (keyword) {
+        locationOptions.list = [];
+        loading.value = true;
+        const params = {
+            key: MAP_KEY,
+            keyword,
+            location: props.userLocation,
+        };
+        await VE_API.old_mini_map.getCtiyList({ word: keyword }).then(({ data }) => {
+            if (data && data.length) {
+                data.forEach((item) => {
+                    item.point = item.location.lat + "," + item.location.lng;
+                    locationOptions.list.push(item);
+                });
+            }
+        });
+        VE_API.old_mini_map.search(params).then(({ data }) => {
+            loading.value = false;
+            data.forEach((item) => {
+                item.point = item.location.lat + "," + item.location.lng;
+                locationOptions.list.push(item);
+            });
+        });
+    } else {
+        locationOptions.list = [];
+    }
+};
+
+const handleSearchRes = (v) => {
+    if (!v) return;
+    const parts = v.value.split(",");
+    let { latitude, longitude } = transformFromGCJToWGS(parseFloat(parts[0]), parseFloat(parts[1]));
+    const coordinateArray = [longitude, latitude];
+    
+    emit("change", {
+        coordinateArray,
+        point: `POINT (${coordinateArray[0]} ${coordinateArray[1]})`,
+        address: v.item?.title || v.item?.address,
+        pointAddress: v.item?.province + v.item?.city + v.item?.district,
+        city: v.item?.city + v.item?.district || '',
+        item: v.item,
+    });
+};
+
+const handleClear = () => {
+    emit("change", {
+        coordinateArray: null,
+        point: null,
+        address: null,
+    });
+    locationVal.value = null;
+    locationOptions.list = [];
+    loading.value = false;
+};
+</script>
+
+<style lang="scss">
+.location-search-popper {
+    .el-select-dropdown__list {
+        max-width: 96vw;
+        overflow-x: auto;
+    }
+    .sub-title {
+        padding-left: 6px;
+        font-size: 12px;
+        color: #ccc;
+    }
+}
+</style>
+

+ 154 - 104
src/components/taskItem.vue

@@ -1,11 +1,13 @@
 <template>
-    <div class="farm-item" :class="{'done': status, 'hall': isHall}">
+    <div class="farm-item" :class="{ done: status, hall: isHall }">
         <div class="item-top">
             <div class="top-l">
                 <div class="item-name">{{ itemData?.farmWorkName }}</div>
                 <div class="item-time">{{ itemData?.executeDate }}</div>
             </div>
-            <div class="top-r" @click="toDetail(status, itemData.id, itemData.farmWorkLibId)">{{ status === 0 ? "查看处方" : "查看详情" }}</div>
+            <div class="top-r" @click="toDetail(status, itemData.id, itemData.farmWorkLibId)">
+                {{ status === 0 ? "查看处方" : "查看详情" }}
+            </div>
         </div>
         <div class="item-box" v-if="status === 0">
             <!-- <div class="title-wrap">
@@ -47,13 +49,15 @@
             <div class="img-text-wrap">
                 <div class="left-wrap">
                     <div class="left-img">
-                        <img src="@/assets/img/home/farm.png" alt="">
+                        <img src="@/assets/img/home/farm.png" alt="" />
                     </div>
                     <div class="right-text">
                         <div class="farm-info">
                             {{ itemData?.farmName }}
                             <div class="info-tag-wrap">
-                                <div class="tag-item second" v-if="itemData?.farmArea">{{ formatArea(itemData?.farmArea) }}亩</div>
+                                <div class="tag-item second" v-if="itemData?.farmArea">
+                                    {{ formatArea(itemData?.farmArea) }}亩
+                                </div>
                                 <div class="tag-item primary">{{ itemData?.typeName }}</div>
                             </div>
                         </div>
@@ -61,8 +65,11 @@
                     </div>
                 </div>
                 <div class="right-wrap" v-if="isHall">
-                    <el-icon><Plus /></el-icon>
-                    <span>关注</span>
+                    <div class="click-item" v-if="!itemData?.isFollow" @click="handleFollow(itemData)">
+                        <el-icon><Plus /></el-icon>
+                        <span>关注</span>
+                    </div>
+                    <span v-else class="follow-text" @click="handleFollow(itemData)">已关注</span>
                 </div>
             </div>
             <slot name="footer"></slot>
@@ -78,34 +85,46 @@
                 <div class="desc-info two-text" v-if="!expiredDay">
                     <div class="desc-info-item">
                         <div>复核成效</div>
-                        <span class="value">促进分蘖芽萌发、加快分蘖生长,同时补充氮素等关键养分,增强植株长势,为形成足够穗数、提高群体产量打基础。</span>
+                        <span class="value"
+                            >促进分蘖芽萌发、加快分蘖生长,同时补充氮素等关键养分,增强植株长势,为形成足够穗数、提高群体产量打基础。</span
+                        >
                     </div>
                 </div>
                 <div class="review-image" v-if="!expiredDay">
                     <div class="review-image-item" v-if="triggerImg.length">
                         <div class="review-image-item-title">农事前</div>
                         <photo-provider :photo-closable="true">
-                                <photo-consumer v-for="src in [triggerImg[triggerImg.length - 1].cloudFilename]" intro="农事前照片" :key="src" :src="base_img_url2 + src">
-                                    <div class="img-item">
-                                        <img :src="base_img_url2 + src + resize" class="view-box">
-                                    </div>
-                                </photo-consumer>
+                            <photo-consumer
+                                v-for="src in [triggerImg[triggerImg.length - 1].cloudFilename]"
+                                intro="农事前照片"
+                                :key="src"
+                                :src="base_img_url2 + src"
+                            >
+                                <div class="img-item">
+                                    <img :src="base_img_url2 + src + resize" class="view-box" />
+                                </div>
+                            </photo-consumer>
                         </photo-provider>
                     </div>
                     <div class="review-image-item" v-if="detailItem?.reviewImage?.length">
                         <div class="review-image-item-title">农事后</div>
                         <photo-provider :photo-closable="true">
-                                <photo-consumer v-for="src in [detailItem.reviewImage[detailItem.reviewImage.length - 1]]" intro="农事后照片" :key="src" :src="base_img_url2 + src">
-                                    <div class="img-item">
-                                        <img :src="base_img_url2 + src + resize" class="view-box">
-                                    </div>
-                                </photo-consumer>
+                            <photo-consumer
+                                v-for="src in [detailItem.reviewImage[detailItem.reviewImage.length - 1]]"
+                                intro="农事后照片"
+                                :key="src"
+                                :src="base_img_url2 + src"
+                            >
+                                <div class="img-item">
+                                    <img :src="base_img_url2 + src + resize" class="view-box" />
+                                </div>
+                            </photo-consumer>
                         </photo-provider>
                     </div>
                 </div>
 
                 <!-- 过期农事 -->
-                 <div v-if="expiredDay">
+                <div v-if="expiredDay">
                     <div class="desc-info pt-10">
                         <div class="desc-info-item">
                             <span>复核时间:</span>
@@ -118,32 +137,29 @@
                             距离农事执行已 <span class="val-text">15</span>天,提醒用户拍照,增加信誉度!
                         </div>
                     </div>
-                 </div>
+                </div>
             </div>
-            
+
             <slot name="footer"></slot>
 
             <div class="item-footer" v-if="status === 1">
-                <div class="footer-l farm-name-text van-ellipsis" :style="{ width: detailItem?.reviewImage?.length ? 'calc(100% - 85px)' : 'calc(100% - 180px)' }">
-                    来自<span class="name-text">{{ itemData.farmName || '未知农场' }}</span>
+                <div
+                    class="footer-l farm-name-text van-ellipsis"
+                    :style="{ width: detailItem?.reviewImage?.length ? 'calc(100% - 85px)' : 'calc(100% - 180px)' }"
+                >
+                    来自<span class="name-text">{{ itemData.farmName || "未知农场" }}</span>
                 </div>
                 <div class="footer-r">
-                    <div class="btn warning" v-if="detailItem?.reviewImage?.length" @click="shareResult">
-                        分享成果
-                    </div>
+                    <div class="btn warning" v-if="detailItem?.reviewImage?.length" @click="shareResult">分享成果</div>
                     <template v-else>
-                        <div class="btn secondary-text" @click="remindUser">
-                            提醒用户拍照
-                        </div>
-                        <div class="btn photo-text" @click="handleUploadPhoto">
-                            上传照片
-                        </div>
+                        <div class="btn secondary-text" @click="remindUser">提醒用户拍照</div>
+                        <div class="btn photo-text" @click="handleUploadPhoto">上传照片</div>
                     </template>
                 </div>
             </div>
         </div>
     </div>
-    
+
     <!-- 处方卡片 -->
     <Teleport to="body">
         <detail-dialog ref="detailDialogRef" />
@@ -154,14 +170,15 @@
 
     <upload-execute ref="uploadExecuteRef" :onlyShare="true" />
 
-     <!-- 上传照片弹窗 -->
-     <review-upload-popup v-model="showUpload" :record-id="sectionId" @success="handleUploadSuccess" />
+    <!-- 上传照片弹窗 -->
+    <review-upload-popup v-model="showUpload" :record-id="sectionId" @success="handleUploadSuccess" />
 </template>
 
 <script setup>
-import { onMounted, ref } from 'vue';
+import { onMounted, ref } from "vue";
 import { useRouter } from "vue-router";
 import { base_img_url2 } from "@/api/config";
+import { ElMessage, ElMessageBox } from "element-plus";
 import detailDialog from "@/components/detailDialog.vue";
 import uploadExecute from "@/views/old_mini/task_condition/components/uploadExecute.vue";
 import reviewPopup from "@/views/old_mini/task_condition/components/reviewPopup.vue";
@@ -172,47 +189,71 @@ const resize = "?x-oss-process=image/resize,p_120/format,webp/quality,q_100";
 const props = defineProps({
     status: {
         type: Number,
-        default: 0
+        default: 0,
     },
     itemData: {
         type: Object,
-        default: () => ({})
+        default: () => ({}),
     },
     isHall: {
         type: Boolean,
-        default: false
-    }
-})
+        default: false,
+    },
+});
 
-const expiredDay = ref(0) // 过期天数
+const expiredDay = ref(0); // 过期天数
 const uploadExecuteRef = ref(null);
 const router = useRouter();
 const detailDialogRef = ref(null);
 const reviewPopupRef = ref(null);
 const toPage = () => {
-    router.push("/report_detail")
-}
+    router.push("/report_detail");
+};
+
+const handleFollow = ({ farmId, isFollow }) => {
+    ElMessageBox.confirm(`${isFollow ? "确定要取消关注该农场吗?" : "确定要关注该农场吗?"}`, "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+    })
+        .then(() => {
+            const api = isFollow ? VE_API.z_farm_work_record.unfollowFarm : VE_API.z_farm_work_record.followFarm;
+            api({ farmId }).then(({ code,msg }) => {
+                if (code === 0) {
+                    ElMessage.success(msg);
+                    emit("handleFollowSuccess");
+                } else {
+                    ElMessage.error(msg);
+                }
+            });
+        })
+        .catch(() => {});
+};
 
 const shareResult = () => {
     if (detailItem.value?.reviewImage?.length) {
-        const preImg = triggerImg.value.length ? base_img_url2 + triggerImg.value[triggerImg.value.length - 1].cloudFilename : '';
-        const resImg = detailItem.value?.reviewImage?.length ? base_img_url2 + detailItem.value.reviewImage[detailItem.value.reviewImage.length - 1] : '';
+        const preImg = triggerImg.value.length
+            ? base_img_url2 + triggerImg.value[triggerImg.value.length - 1].cloudFilename
+            : "";
+        const resImg = detailItem.value?.reviewImage?.length
+            ? base_img_url2 + detailItem.value.reviewImage[detailItem.value.reviewImage.length - 1]
+            : "";
         reviewPopupRef.value.handleShowPopup(detailItem.value.id, preImg, resImg);
     }
-}
+};
 
 const remindUser = () => {
-    uploadExecuteRef.value.showPopup({...props.itemData, type: 'remindUser'});
-}
+    uploadExecuteRef.value.showPopup({ ...props.itemData, type: "remindUser" });
+};
 
 const showUpload = ref(false);
 const sectionId = ref(null);
 const handleUploadPhoto = () => {
     showUpload.value = true;
     sectionId.value = props.itemData.id;
-}
+};
 
-const emit = defineEmits(["handleUploadSuccess"]);
+const emit = defineEmits(["handleUploadSuccess", "handleFollowSuccess"]);
 
 const triggerImg = ref([]);
 const detailItem = ref({});
@@ -220,25 +261,25 @@ const getTriggerImg = async () => {
     if (!detailItem.value?.id) return;
     const { data } = await VE_API.z_farm_work_record.getTriggerImg({ farmWorkRecordId: detailItem.value.id });
     triggerImg.value = data || [];
-}
+};
 
 // 更新触发图片(上传成功后调用)
 const updateTriggerImg = async () => {
     if (!props.itemData?.id) return;
-    
+
     // 重新获取详情
     await getItemDetail(props.itemData.id);
-    
+
     // 如果是已完成状态(status === 1),需要重新获取触发图片
     if (props.status === 1) {
         await getTriggerImg();
     }
     // 如果是待完成状态(status === 0),详情已经更新,itemData 会在 getSimpleList 后更新
-}
+};
 
-const handleUploadSuccess = async () => { 
+const handleUploadSuccess = async () => {
     emit("handleUploadSuccess");
-}
+};
 
 onMounted(async () => {
     // 若已带处方列表,直接生成;否则在需要时拉取详情后生成
@@ -252,25 +293,26 @@ onMounted(async () => {
 
         getTriggerImg();
     }
-})
+});
 
 // 将所有需要暴露的方法放在 defineExpose 中
 defineExpose({
-    updateTriggerImg
-})
-const prescriptionText = ref('');
+    updateTriggerImg,
+});
+const prescriptionText = ref("");
 function buildPrescriptionText(list) {
     try {
         return list
-            .map(group => (group.pesticideFertilizerList || [])
-                .map(p => p.defaultName || p.pesticideFertilizerName || '')
-                .filter(Boolean)
-                .join('+')
+            .map((group) =>
+                (group.pesticideFertilizerList || [])
+                    .map((p) => p.defaultName || p.pesticideFertilizerName || "")
+                    .filter(Boolean)
+                    .join("+")
             )
             .filter(Boolean)
-            .join('+');
+            .join("+");
     } catch {
-        return '';
+        return "";
     }
 }
 async function getItemDetail(id) {
@@ -282,7 +324,7 @@ async function getItemDetail(id) {
 const getPrescriptionInfo = () => prescriptionText.value;
 
 function formatArea(val) {
-    const num = typeof val === 'number' ? val : parseFloat(val);
+    const num = typeof val === "number" ? val : parseFloat(val);
     if (Number.isNaN(num)) return val;
     return Number.isInteger(num) ? num : num.toFixed(2);
 }
@@ -292,23 +334,23 @@ const toDetail = (status, id, farmWorkId) => {
         // 复核成效
         router.push({
             path: "/review_work",
-            query: { json: JSON.stringify({ id, goBack: true }) }
+            query: { json: JSON.stringify({ id, goBack: true }) },
         });
     } else {
-        detailDialogRef.value.showDialog(farmWorkId, '', false);
+        detailDialogRef.value.showDialog(farmWorkId, "", false);
     }
-}
+};
 </script>
 
 <style lang="scss" scoped>
 .farm-item {
-    background: #CFE9FF;
+    background: #cfe9ff;
     border-radius: 14px;
     &.done {
-        background: #EBEBEB;
+        background: #ebebeb;
         .item-top {
             .item-name {
-                background: #C5C5C5;
+                background: #c5c5c5;
                 border: none;
                 color: #fff;
             }
@@ -321,7 +363,7 @@ const toDetail = (status, id, farmWorkId) => {
         }
     }
     &.hall {
-        background: #CFE9FF;
+        background: #cfe9ff;
         .item-top {
             .item-name {
                 color: #ffffff;
@@ -345,11 +387,11 @@ const toDetail = (status, id, farmWorkId) => {
         }
         .item-name {
             margin-right: 8px;
-            color: #2199F8;
+            color: #2199f8;
             padding: 0 10px;
             height: 29px;
             border-radius: 4px;
-            border: 1px solid #2199F8;
+            border: 1px solid #2199f8;
             line-height: 29px;
             background: #fff;
         }
@@ -360,7 +402,7 @@ const toDetail = (status, id, farmWorkId) => {
         border: 1px solid rgba(183, 183, 183, 0.1);
         padding: 10px 12px;
     }
-.item-footer {
+    .item-footer {
         margin-top: 10px;
         padding-top: 11px;
         border-top: 1px solid rgba(0, 0, 0, 0.1);
@@ -369,12 +411,12 @@ const toDetail = (status, id, farmWorkId) => {
         justify-content: space-between;
         font-size: 12px;
         .footer-l {
-            color: #8B8B8B;
+            color: #8b8b8b;
             font-size: 12px;
             &.primary-btn {
                 display: inline-flex;
                 align-items: center;
-                border: 1px solid #2199F8;
+                border: 1px solid #2199f8;
                 background: rgba(33, 153, 248, 0.1);
                 padding: 0 12px;
                 height: 32px;
@@ -382,7 +424,7 @@ const toDetail = (status, id, farmWorkId) => {
                 display: flex;
                 align-items: center;
                 border-radius: 20px;
-                color: #2199F8;
+                color: #2199f8;
                 .share-icon {
                     width: 12px;
                     padding-right: 4px;
@@ -390,7 +432,7 @@ const toDetail = (status, id, farmWorkId) => {
             }
             &.farm-name-text {
                 font-size: 14px;
-                color: #6F7274;
+                color: #6f7274;
                 width: calc(100% - 180px);
                 .name-text {
                     padding-left: 4px;
@@ -411,27 +453,27 @@ const toDetail = (status, id, farmWorkId) => {
                 &.second {
                     // border: 1px solid #8B8B8B;
                     // color: #8B8B8B;
-                    color: #2199F8;
+                    color: #2199f8;
                     background: rgba(33, 153, 248, 0.1);
                 }
                 &.primary {
-                    background: #2199F8;
+                    background: #2199f8;
                     color: #fff;
                 }
                 .btn-icon {
                     padding-right: 4px;
                 }
                 &.warning {
-                    color: #FF953D;
+                    color: #ff953d;
                     background: #fff;
-                    border: 1px solid #FF953D;
+                    border: 1px solid #ff953d;
                 }
                 &.secondary-text {
-                    color: #2199F8;
-                    border: 1px solid #2199F8;
+                    color: #2199f8;
+                    border: 1px solid #2199f8;
                 }
-                &.photo-text{
-                    background: #2199F8;
+                &.photo-text {
+                    background: #2199f8;
                     color: #fff;
                 }
             }
@@ -459,7 +501,7 @@ const toDetail = (status, id, farmWorkId) => {
         }
         .text-more {
             padding-left: 10px;
-            color: #2199F8;
+            color: #2199f8;
             white-space: nowrap;
         }
     }
@@ -484,7 +526,7 @@ const toDetail = (status, id, farmWorkId) => {
                 padding-left: 8px;
                 .farm-info {
                     font-size: 14px;
-                    color: #1D2129;
+                    color: #1d2129;
                     display: flex;
                     align-items: center;
                     .info-tag-wrap {
@@ -499,12 +541,12 @@ const toDetail = (status, id, farmWorkId) => {
                             border-radius: 2px;
                             font-size: 12px;
                             &.second {
-                                color: #1D2129;
-                                background: #F4F4F4;
+                                color: #1d2129;
+                                background: #f4f4f4;
                             }
                             &.primary {
-                                color: #2199F8;
-                                background: #E8F3FF;
+                                color: #2199f8;
+                                background: #e8f3ff;
                             }
                         }
                     }
@@ -512,15 +554,23 @@ const toDetail = (status, id, farmWorkId) => {
                 .farm-addr {
                     padding-top: 2px;
                     font-size: 12px;
-                    color: #86909C;
+                    color: #86909c;
                 }
             }
         }
         .right-wrap {
             display: flex;
             align-items: center;
-            color: #FF953D;
+            color: #ff953d;
             font-size: 12px;
+            .click-item {
+                display: flex;
+                align-items: center;
+                gap: 2px;
+            }
+            .follow-text {
+                color: #d0d0d0;
+            }
         }
     }
     .title-wrap {
@@ -565,18 +615,18 @@ const toDetail = (status, id, farmWorkId) => {
                 }
             }
             .expired-day {
-                color: #FF953D;
+                color: #ff953d;
             }
             .expired-text {
                 margin-top: 4px;
                 padding: 6px 8px;
-                background: linear-gradient(90deg,rgba(33, 153, 248, 0.2), rgba(33, 153, 248, 0));
+                background: linear-gradient(90deg, rgba(33, 153, 248, 0.2), rgba(33, 153, 248, 0));
                 border-radius: 4px;
-                color: #2E2E2E;
+                color: #2e2e2e;
                 font-size: 12px;
                 width: 100%;
                 .val-text {
-                    color: #2199F8;
+                    color: #2199f8;
                 }
             }
         }
@@ -586,7 +636,7 @@ const toDetail = (status, id, farmWorkId) => {
         .pt-10 {
             padding-top: 10px;
         }
-        
+
         .review-image {
             display: flex;
             align-items: center;
@@ -635,7 +685,7 @@ const toDetail = (status, id, farmWorkId) => {
         }
         .report-text {
             margin-top: 10px;
-            color: #FF953D;
+            color: #ff953d;
             font-size: 12px;
             height: 32px;
             line-height: 32px;
@@ -645,7 +695,7 @@ const toDetail = (status, id, farmWorkId) => {
             padding-left: 11px;
             background: linear-gradient(90deg, rgba(255, 149, 61, 0.1), rgba(255, 149, 61, 0));
             .done-icon {
-                background: #FF953D;
+                background: #ff953d;
                 width: 10px;
                 height: 10px;
                 border-radius: 50%;

+ 171 - 127
src/views/old_mini/farm_manage/components/demandHall.vue

@@ -4,12 +4,10 @@
         <div class="map-container" ref="mapContainer"></div>
 
         <div class="search-wrap">
-            <el-input
+            <location-search
                 class="search"
-                v-model="searchValue"
-                placeholder="搜索位置"
-                @search="search"
-                :prefix-icon="Search"
+                user-location="113.61702297075017,23.584863449735067"
+                @change="handleLocationChange"
             />
         </div>
 
@@ -23,7 +21,12 @@
             <template #header>
                 <div class="header-bar"></div>
                 <div class="select-group">
-                    <el-select class="select-item" v-model="selectParma.farmWorkTypeId" placeholder="农事类型" @change="getSimpleList">
+                    <el-select
+                        class="select-item"
+                        v-model="selectParma.farmWorkTypeId"
+                        placeholder="农事类型"
+                        @change="getSimpleList"
+                    >
                         <el-option
                             v-for="item in farmWorkTypeList"
                             :key="item.id"
@@ -31,36 +34,37 @@
                             :value="item.id"
                         />
                     </el-select>
-                    <el-select class="select-item" v-model="areaValue1" placeholder="Select">
+                    <el-select
+                        class="select-item"
+                        v-model="selectParma.districtCode"
+                        placeholder="区域筛选"
+                        @change="getSimpleList"
+                    >
                         <el-option
-                            v-for="item in areaOptions1"
-                            :key="item.value"
-                            :label="item.label"
-                            :value="item.value"
+                            v-for="item in districtList"
+                            :key="item.code"
+                            :label="item.name"
+                            :value="item.code"
                         />
                     </el-select>
                 </div>
                 <div class="user-btn" v-if="height === anchors[0]" @click.stop="toPage">
-                    <img class="user-icon" src="@/assets/img/home/user-icon.png" alt="">
+                    <img class="user-icon" src="@/assets/img/home/user-icon.png" alt="" />
                     新增用户
                 </div>
             </template>
             <div class="hall-content">
                 <div class="farm-list" ref="cardContentRef" :style="{ height: `${cardContentHeight}px` }">
                     <div class="task-item" v-for="item in taskList" :key="item">
-                        <task-item :item-data="item" :isHall="true">
+                        <task-item :item-data="item" :isHall="true" @handleFollowSuccess="getSimpleList">
                             <template #footer>
                                 <div class="item-footer">
-                                    <div class="footer-l" @click="toDetail(item)">
-                                        查看详情
-                                    </div>
+                                    <div class="footer-l" @click="toDetail(item)">查看详情</div>
                                     <div class="footer-r">
                                         <!-- <div class="btn second">
                                             转发给客户
                                         </div> -->
-                                        <div class="btn primary" @click="showPriceSheetPopup(item)">
-                                            生成报价单
-                                        </div>
+                                        <div class="btn primary" @click="showPriceSheetPopup(item)">生成报价单</div>
                                     </div>
                                 </div>
                             </template>
@@ -82,15 +86,18 @@ import { computed, nextTick, onMounted, ref } from "vue";
 import { useStore } from "vuex";
 import IndexMap from "../map/index";
 import taskItem from "@/components/taskItem.vue";
-import { Search } from "@element-plus/icons-vue";
 import priceSheetPopup from "@/components/popup/priceSheetPopup.vue";
 import { useRouter } from "vue-router";
+import LocationSearch from "@/components/pageComponents/LocationSearch.vue";
+import { Point } from "ol/geom";
+import Feature from "ol/Feature";
+import { convertPointToArray } from "@/utils/index";
 const props = defineProps({
     isCapital: {
         type: Boolean,
-        default: false
-    }
-})
+        default: false,
+    },
+});
 
 const store = useStore();
 const tabBarHeight = computed(() => store.state.home.tabBarHeight);
@@ -100,58 +107,74 @@ const router = useRouter();
 const anchors = ref([310 + tabBarHeight.value, Math.round(1 * window.innerHeight) - 44]);
 const height = ref(anchors.value[0]);
 
-
 const indexMap = new IndexMap();
 const mapContainer = ref(null);
+const mapPoint = ref(null);
 
 onMounted(() => {
-    const point = store.state.home.miniUserLocationPoint;
+    mapPoint.value = store.state.home.miniUserLocationPoint;
     getFarmWorkTypeList();
-    getSimpleList()
+    getSimpleList();
+    getDistrictListByCity();
     nextTick(() => {
-        indexMap.initMap(point, mapContainer.value, props.isCapital);
-        getStatisticsAreaByDistrict()
+        indexMap.initMap(mapPoint.value, mapContainer.value, props.isCapital);
+        getStatisticsAreaByDistrict();
     });
-})
+});
 
 defineExpose({
-    getSimpleList
-})
+    getSimpleList,
+});
+
+//根据城市的坐标返回区县列表
+const districtList = ref([]);
+function getDistrictListByCity() {
+    VE_API.z_farm_work_record.getDistrictListByCity({ point: mapPoint.value }).then(({ data }) => {
+        districtList.value = data || [];
+        districtList.value.unshift({ code: 0, name: "全部" });
+    });
+}
 
+//农事类型列表
 const farmWorkTypeList = ref([]);
 function getFarmWorkTypeList() {
-    VE_API.z_farm_work_record.getFarmWorkTypeList().then(({data}) => {
+    VE_API.z_farm_work_record.getFarmWorkTypeList().then(({ data }) => {
         farmWorkTypeList.value = data;
+        farmWorkTypeList.value.unshift({ id: 0, name: "全部" });
     });
 }
 const selectParma = ref({
     farmWorkTypeId: null,
-    areaValue1: null
+    districtCode: null,
 });
+
+//需求大厅接单简单农事记录列表
 const taskList = ref([]);
 function getSimpleList() {
-    const location = store.state.home.miniUserLocationPoint;
     const params = {
-        ...selectParma.value,
-        location,
-    }
-    VE_API.z_farm_work_record.getOrderReceivingSimpleList(params).then(({data}) => {
-        if (Array.isArray(data) && data.length > 0) {
+        farmWorkTypeId: selectParma.value.farmWorkTypeId || null,
+        districtCode: selectParma.value.districtCode || null,
+        location: mapPoint.value,
+    };
+    VE_API.z_farm_work_record
+        .getOrderReceivingSimpleList(params)
+        .then(({ data }) => {
             taskList.value = data || [];
-        }
-    }).catch((error) => {
-        taskList.value = [];
-    });
+        })
+        .catch((error) => {
+            taskList.value = [];
+        });
 }
 
 const toPage = () => {
     router.push("/create_farm?type=client&isReload=true&from=task_condition");
-}
+};
 
+//按区县统计服务亩数
 function getStatisticsAreaByDistrict() {
-    VE_API.z_farm_work_record.statisticsAreaByDistrict({flowStatus:'1,2,3'}).then(({data}) => {
-        if(data && data.length > 0) {
-            indexMap.initDataHall(data)
+    VE_API.z_farm_work_record.statisticsAreaByDistrict({ flowStatus: "1,2,3" }).then(({ data }) => {
+        if (data && data.length > 0) {
+            indexMap.initDataHall(data);
         }
     });
 }
@@ -159,22 +182,45 @@ function getStatisticsAreaByDistrict() {
 function toDetail(item) {
     router.push({
         path: "/completed_work",
-        query: { json: JSON.stringify({ id: item.id }) }
+        query: { json: JSON.stringify({ id: item.id }) },
     });
 }
 
 const cardContentHeight = ref(230);
-const searchValue = ref("");
-const search = () => {
-    console.log(searchValue.value);
-};
 
-const areaValue1 = ref("1");
-const areaOptions1 = [
-    { value: "1", label: "区域筛选" },
-    { value: "2", label: "2" },
-    { value: "3", label: "3" },
-];
+// 处理位置搜索变化
+function handleLocationChange(data) {
+    if (data && data.coordinateArray) {
+        mapPoint.value = data.point;
+        // 更新地图位置
+        if (indexMap && indexMap.kmap) {
+            indexMap.kmap.getView().animate({
+                center: data.coordinateArray,
+                zoom: 16,
+                duration: 500,
+            });
+            // 更新点击点
+            if (indexMap.clickPointLayer) {
+                indexMap.clickPointLayer.source.clear();
+                const point = new Feature(new Point(data.coordinateArray));
+                indexMap.clickPointLayer.addFeature(point);
+            }
+        }
+        // 更新区县列表
+        getDistrictListByCity();
+        // 重新获取列表
+        getSimpleList();
+    } else {
+        // 重置为初始位置
+        mapPoint.value = store.state.home.miniUserLocationPoint;
+        indexMap.clickPointLayer.source.clear();
+        // 更新区县列表
+        getDistrictListByCity();
+        // 重新获取列表
+        getSimpleList();
+        getStatisticsAreaByDistrict();
+    }
+}
 
 const cardContentRef = ref(null);
 const handleHeightChange = ({ height }) => {
@@ -186,7 +232,6 @@ const handleHeightChange = ({ height }) => {
     }
 };
 
-
 const priceSheetPopupRef = ref(null);
 const showPriceSheetPopup = (item) => {
     VE_API.z_farm_work_record.getDetail({ id: item.id }).then(({ data }) => {
@@ -194,8 +239,6 @@ const showPriceSheetPopup = (item) => {
         priceSheetPopupRef.value.handleShowPopup(res);
     });
 };
-
-
 </script>
 
 <style lang="scss" scoped>
@@ -215,7 +258,8 @@ const showPriceSheetPopup = (item) => {
         width: calc(100% - 24px);
         left: 12px;
         ::v-deep {
-            .el-input__wrapper {
+            .el-input__wrapper,
+            .el-select__wrapper {
                 box-shadow: none;
                 border-radius: 20px;
             }
@@ -264,61 +308,61 @@ const showPriceSheetPopup = (item) => {
             color: #999999;
             padding-top: 20px;
         }
-        
-    .item-footer {
-        margin-top: 10px;
-        padding-top: 11px;
-        border-top: 1px solid rgba(0, 0, 0, 0.1);
-        display: flex;
-        align-items: center;
-        justify-content: space-between;
-        font-size: 12px;
-        .footer-l {
-            // display: inline-flex;
-            // align-items: center;
-            // border: 1px solid #2199F8;
-            // background: rgba(33, 153, 248, 0.1);
-            // padding: 0 12px;
-            // height: 32px;
-            // box-sizing: border-box;
-            // display: flex;
-            // align-items: center;
-            // border-radius: 20px;
-            // color: #2199F8;
-            color: #8B8B8B;
-            font-size: 12px;
-            .share-icon {
-                width: 12px;
-                padding-right: 4px;
-            }
-        }
-        .footer-r {
+
+        .item-footer {
+            margin-top: 10px;
+            padding-top: 11px;
+            border-top: 1px solid rgba(0, 0, 0, 0.1);
             display: flex;
             align-items: center;
-            gap: 8px;
-            .btn {
-                height: 32px;
-                line-height: 32px;
-                padding: 0 12px;
-                border-radius: 20px;
+            justify-content: space-between;
+            font-size: 12px;
+            .footer-l {
+                // display: inline-flex;
+                // align-items: center;
+                // border: 1px solid #2199F8;
+                // background: rgba(33, 153, 248, 0.1);
+                // padding: 0 12px;
+                // height: 32px;
+                // box-sizing: border-box;
+                // display: flex;
+                // align-items: center;
+                // border-radius: 20px;
+                // color: #2199F8;
+                color: #8b8b8b;
+                font-size: 12px;
+                .share-icon {
+                    width: 12px;
+                    padding-right: 4px;
+                }
+            }
+            .footer-r {
                 display: flex;
                 align-items: center;
-                box-sizing: border-box;
-                &.second {
-                    // border: 1px solid #8B8B8B;
-                    // color: #8B8B8B;
-                    color: #2199F8;
-                    background: rgba(33, 153, 248, 0.1);
-                }
-                &.primary {
-                    background: #2199F8;
-                    color: #fff;
+                gap: 8px;
+                .btn {
+                    height: 32px;
+                    line-height: 32px;
+                    padding: 0 12px;
+                    border-radius: 20px;
+                    display: flex;
+                    align-items: center;
+                    box-sizing: border-box;
+                    &.second {
+                        // border: 1px solid #8B8B8B;
+                        // color: #8B8B8B;
+                        color: #2199f8;
+                        background: rgba(33, 153, 248, 0.1);
+                    }
+                    &.primary {
+                        background: #2199f8;
+                        color: #fff;
+                    }
                 }
             }
-            }
         }
     }
-    
+
     .select-group {
         display: flex;
         padding: 0 12px;
@@ -357,24 +401,24 @@ const showPriceSheetPopup = (item) => {
         background: #969799;
     }
 }
-        .user-btn {
-            position: absolute;
-            z-index: 10;
-            top: -42px;
-            right: 12px;
-            background: #fff;
-            height: 32px;
-            display: flex;
-            align-items: center;
-            border-radius: 5px;
-            padding: 0 8px;
-            font-size: 12px;
-            color: #2199F8;
-            .user-icon {
-                width: 16px;
-                margin-right: 4px;
-            }
-        }
+.user-btn {
+    position: absolute;
+    z-index: 10;
+    top: -42px;
+    right: 12px;
+    background: #fff;
+    height: 32px;
+    display: flex;
+    align-items: center;
+    border-radius: 5px;
+    padding: 0 8px;
+    font-size: 12px;
+    color: #2199f8;
+    .user-icon {
+        width: 16px;
+        margin-right: 4px;
+    }
+}
 
 .floating-panel {
     width: 100%;

+ 1 - 1
src/views/old_mini/farm_manage/map/index.js

@@ -21,7 +21,7 @@ class IndexMap {
       style: (f) => {
         return new Style({
           image: new Icon({
-            src: require("@/assets/img/home/farm-point.png"),
+            src: require("@/assets/img/home/garden-point.png"),
             scale: 0.5,
             anchor: [0.5, 1],
           }),