Browse Source

feat:对接 我的农场和认证农资功能

wangsisi 3 tuần trước cách đây
mục cha
commit
82ba9c943a

+ 5 - 0
src/api/modules/farm.js

@@ -37,4 +37,9 @@ module.exports = {
         url: config.base_dev_url + "z_farm_work_lib/get",
         type: "get",
     },
+    //删除农场
+    deleteFarm: {
+        url: config.base_dev_url + "v2/farm/deleteFarm",
+        type: "get",
+    },
 }

+ 9 - 0
src/api/modules/mine.js

@@ -0,0 +1,9 @@
+const config = require("../config")
+
+module.exports = {
+    //农资注册接口
+    register: {
+        url: config.base_dev_url + "z_agricultural_store/register",
+        type: "post",
+    },
+}

+ 1 - 1
src/components/pageComponents/FarmInfoCard.vue

@@ -5,7 +5,7 @@
                 <img class="map-img" :src="data.mapImage || '/map.png'" alt="地图" />
                 <div class="item-info">
                     <div class="item-header">
-                        <div class="farm-name van-ellipsis">{{ data.farmName }}</div>
+                        <div class="farm-name van-ellipsis" :style="{ maxWidth: data.maxWidth }">{{ data.farmName }}</div>
                         <div class="tags">
                             <span class="tag tag-area">{{ data.area }}</span>
                             <span class="tag tag-variety">{{ data.variety }}</span>

+ 6 - 1
src/components/weatherInfo.vue

@@ -219,6 +219,11 @@ onActivated(() => {
     getFarmList();
 });
 
+// 暴露刷新方法供父组件调用
+defineExpose({
+    refreshFarmList: getFarmList
+});
+
 const handleAddGarden = () => {
     router.push(`/create_farm?isReload=true&from=monitor`)
 }
@@ -381,7 +386,7 @@ const currentDateText = computed(() => {
     overflow-y: auto;
     &.el-dropdown__popper {
         .el-dropdown__list {
-            max-width: 240px;
+            max-width: 250px;
         }
         .el-dropdown-menu__item{
             background-color: transparent !important;

+ 1 - 1
src/views/old_mini/dev_login.vue

@@ -37,7 +37,7 @@ onMounted(async () => {
     store.commit("home/SET_MINI_USER_LOCATION", route.query.point);
     store.commit("home/SET_MINI_USER_ID", userId);
     store.commit("home/SET_MINI_USER_LOCATION_POINT", `POINT(${pointXy[0]} ${pointXy[1]})`);
-    router.push(targetUrl);
+    router.push(`${targetUrl}?miniJson=${JSON.stringify(route.query)}`);
 })
 </script>
 

+ 1 - 1
src/views/old_mini/mine/index.vue

@@ -159,7 +159,7 @@ const cellItems = computed(() => {
             },
             {
                 title: "认证农资",
-                path: "/register?identity=NZ&role=2",
+                path: "/register?identity=NZ",
             },
             {
                 title: "退出登录",

+ 83 - 27
src/views/old_mini/mine/pages/farm.vue

@@ -2,24 +2,26 @@
     <div class="farm-page">
         <custom-header name="我的农场"></custom-header>
         <div class="farm-list">
-            <div class="list-item" v-for="item in 3" :key="item">
+            <div class="list-item" v-for="item in farmList" :key="item.id" @click="handleItemClick(item)">
                 <div class="item-info">
                     <div class="item-top">
-                        <img class="left-img" src="@/assets/img/home/farm.png" alt="">
+                        <img class="left-img" src="@/assets/img/home/farm.png" alt="" />
                         <div class="left-content">
                             <div class="content-title">
-                                <span>荔枝博览园</span>
-                                <div class="content-tag" v-if="item === 1">默认</div>
-                                <div class="content-text" v-else>设为默认</div>
+                                <div class="title-left">
+                                    <span class="title-text van-ellipsis">{{ item.name }}</span>
+                                    <div class="content-tag" v-if="item.defaultOption">默认</div>
+                                    <div class="content-text" v-else @click.stop="handleSetDefault(item)">设为默认</div>
+                                </div>
+                                <div class="item-btn">查看详情</div>
                             </div>
                             <div class="content-desc">
-                                <div>服务作物:荔枝-妃子笑、桂味</div>
-                                <div>农场位置:广东省广州市从化区</div>
+                                <div>服务作物:{{ item.speciesName }}</div>
+                                <div>农场位置:{{ item.address }}</div>
                             </div>
                         </div>
                     </div>
                 </div>
-                <div class="item-btn">查看详情</div>
             </div>
         </div>
     </div>
@@ -27,8 +29,46 @@
 
 <script setup>
 import customHeader from "@/components/customHeader.vue";
-import { ref } from "vue";
+import { ref, onMounted } from "vue";
+import { ElMessageBox } from "element-plus";
+import { useRouter } from "vue-router";
+const router = useRouter();
+const farmList = ref([]);
+onMounted(() => {
+    getFarmList();
+});
 
+const handleSetDefault = async ({id}) => {
+    ElMessageBox.confirm('确定将该农场设为默认农场吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+    }).then(async () => {
+        const { code } = await VE_API.farm.updateFarm({
+            farmId: id,
+            defaultFarm: 1,
+        });  
+        if(code === 0){
+            getFarmList();
+        }
+    }).catch(() => {});
+};
+
+const getFarmList = async () => {
+    const { data } = await VE_API.farm.userFarmSelectOption();
+    farmList.value = data || [];
+};
+
+const handleItemClick = (item) => {
+    router.push({
+        path: '/monitor',
+        query: {
+            farmId: item.id,
+            defaultFarm: item.defaultOption,
+            isHeaderShow: true,
+        },
+    });
+};
 </script>
 
 <style scoped lang="scss">
@@ -37,18 +77,22 @@ import { ref } from "vue";
     height: 100vh;
     .farm-list {
         width: 100%;
-        height: 100%;
+        height: calc(100% - 40px);
         background-color: #f7f7f7;
         padding: 12px;
         box-sizing: border-box;
+        overflow: auto;
         .list-item {
             background-color: #fff;
             border-radius: 10px;
             padding: 10px;
             display: flex;
-            justify-content: space-between;
+            width: 100%;
+            box-sizing: border-box;
             .item-info {
+                width: 100%;
                 .item-top {
+                    width: 100%;
                     display: flex;
                     align-items: center;
                     gap: 12px;
@@ -58,27 +102,42 @@ import { ref } from "vue";
                         border-radius: 8px;
                     }
                     .left-content {
+                        width: calc(100% - 68px - 12px);
                         .content-title {
                             display: flex;
                             align-items: center;
-                            gap: 10px;
+                            justify-content: space-between;
                             margin-bottom: 4px;
                             font-size: 16px;
                             font-weight: 500;
-                            .content-tag {
-                                background-color: #2199f8;
-                                color: #fff;
-                                padding: 2px 8px;
-                                border-radius: 15px;
-                                font-size: 12px;
-                                font-weight: 400;
-                            }
-                            .content-text {
-                                font-size: 12px;
-                                color: #2199F8;
-                                font-weight: 400;
+                            .title-left{
+                                display: flex;
+                                align-items: center;
+                                gap: 10px;
+                                width: calc(100% - 62px);
+                                .title-text{
+                                    max-width: calc(100% - 60px);
+                                }
+                                .content-tag {
+                                    background-color: #2199f8;
+                                    color: #fff;
+                                    padding: 2px 8px;
+                                    border-radius: 15px;
+                                    font-size: 12px;
+                                    font-weight: 400;
+                                }
+                                .content-text {
+                                    font-size: 12px;
+                                    color: #2199f8;
+                                    font-weight: 400;
+                                }
                             }
                         }
+                        .item-btn {
+                            color: #a8a8a8;
+                            font-size: 14px;
+                            font-weight: 400;
+                        }
                         .content-desc {
                             font-size: 12px;
                             color: #999999;
@@ -87,9 +146,6 @@ import { ref } from "vue";
                     }
                 }
             }
-            .item-btn {
-                color: #a8a8a8;
-            }
         }
         .list-item + .list-item {
             margin-top: 12px;

+ 5 - 5
src/views/old_mini/mine/pages/register.vue

@@ -25,7 +25,7 @@
                         />
                         <field
                             v-show="pageType === 'NZ'"
-                            v-model="value"
+                            v-model="formData.subjectName"
                             label="主体名称"
                             placeholder="请输入主体名称"
                         />
@@ -189,10 +189,12 @@ const router = useRouter();
 
 const formRef  = ref(null)
 const formData = ref({
-    role: "",
     name: "",
     tel: "",
+    subjectName:'',
     point: "",
+    serviceCropsJson:[],
+    agriculturalEquipmentJson:[]
 });
 
 const validatorTel = (val) =>{
@@ -202,8 +204,7 @@ const validatorTel = (val) =>{
 
 const onSubmit = () => {
     formData.value.point = "POINT(113.1093017627431 22.574540836684672)"
-    formData.value.role = formData.value.role*1
-    VE_API.app.register(formData.value).then(res =>{
+    VE_API.mine.register(formData.value).then(res =>{
         if(res.code===0){
             ElMessage.success('注册成功,待审核')
             router.push('/mine')
@@ -282,7 +283,6 @@ onActivated(() => {
     pageType.value = route.query.identity;
     formData.value = {}
     resetForm()
-    formData.value.role = route.query.role;
 });
 </script>
 

+ 121 - 46
src/views/old_mini/monitor/index.vue

@@ -1,9 +1,11 @@
 <template>
+    <custom-header v-if="isHeaderShow" name="农场详情"></custom-header>
     <div class="monitor-index" :style="{ height: `calc(100vh - ${tabBarHeight}px)` }">
         <!-- 天气遮罩 -->
         <div class="weather-mask" v-show="isExpanded"></div>
         <!-- 天气 -->
         <weather-info
+            ref="weatherInfoRef"
             class="weather-info"
             @weatherExpanded="weatherExpanded"
             @changeGarden="changeGarden"
@@ -11,7 +13,7 @@
             :gardenId="defaultGardenId"
         ></weather-info>
         <!-- 操作按钮 -->
-        <div class="operation-button">
+        <div class="operation-button" :style="{ top: isHeaderShow ? '157px' : '117px' }">
             <div class="button-group">
                 <div class="button-item" @click="toFarmInfo">
                     <img class="button-icon" src="@/assets/img/tab_bar/home-active.png" alt="" />
@@ -63,12 +65,9 @@
                 finished-text="暂无更多播报"
                 @load="onLoad"
                 class="broadcast-list"
+                :style="{ height: !isHeaderShow ? 'calc(100vh - 460px)' : 'calc(100vh - 510px)' }"
             >
-                <div
-                    v-for="(item, index) in broadcastList"
-                    :key="index"
-                    class="broadcast-item"
-                >
+                <div v-for="(item, index) in broadcastList" :key="index" class="broadcast-item">
                     <div class="item-content">
                         <div class="content-top">
                             <div class="item-icon">
@@ -93,62 +92,117 @@
         v-model:show="showFarmPopup"
         :type="showFarmPopupType"
         :text="textPopup"
-        :overlay-style="{'backdrop-filter': 'blur(4px)'}"
+        :overlay-style="{ 'backdrop-filter': 'blur(4px)' }"
         :close-on-click-overlay="false"
         @confirm="toCreateFarm"
     />
+
+    <!-- 农场详情操作按钮 -->
+    <div class="custom-bottom-fixed-btns" v-if="isHeaderShow">
+        <div class="bottom-btn secondary-btn" @click="handleFarm('delete')">删除农场</div>
+        <div v-if="!isDefaultFarm" class="bottom-btn primary-btn" @click="handleFarm('setDefault')">
+            设为默认农场
+        </div>
+        <div v-else class="bottom-btn btn-text">当前已是 默认农场</div>
+    </div>
 </template>
 
 <script setup>
-import { ref, computed, onUnmounted, onActivated } from "vue";
+import customHeader from "@/components/customHeader.vue";
+import { ref, computed, onActivated, onDeactivated } from "vue";
 import { useStore } from "vuex";
 import { Badge, List } from "vant";
 import weatherInfo from "@/components/weatherInfo.vue";
 import { useRouter, useRoute } from "vue-router";
 import farmInfoPopup from "../home/components/farmInfoPopup.vue";
 import tipPopup from "@/components/popup/tipPopup.vue";
-import { ElMessage } from "element-plus";
+import { ElMessage, ElMessageBox } from "element-plus";
 
 const showFarmPopup = ref(false);
 const showFarmPopupType = ref("create");
-const textPopup = ref(['您当前还没有农场', '请先创建农场']);
+const textPopup = ref(["您当前还没有农场", "请先创建农场"]);
 
 const toCreateFarm = () => {
-    if(showFarmPopupType.value == "create"){
+    if (showFarmPopupType.value == "create") {
         router.push("/create_farm?isReload=true&from=monitor");
     }
 };
 
 const defaultGardenId = ref(null);
-onActivated(()=>{
-    showFarmPopup.value = false;
-    if(route.query.json){
-        localStorage.setItem('showSuccess', true);
-        const json = JSON.parse(route.query.json);
-        if(json.showSuccess){
-            receiveFarm(json)
+const isHeaderShow = ref(false);
+const isDefaultFarm = ref(false);
+const weatherInfoRef = ref(null);
+
+onActivated(() => {
+    // 用来接收小程序页面跳转的内容和逻辑
+    if (route.query.miniJson) {
+        localStorage.setItem("showSuccess", true);
+        const json = JSON.parse(route.query.miniJson);
+        if (json.showSuccess) {
+            receiveFarm(json);
         }
     }
-    if(localStorage.getItem('isGarden') != 'true'){
+    if (localStorage.getItem("isGarden") != "true") {
         showFarmPopup.value = true;
     }
-})
+
+    // 用来接收我的农场跳转过来的农场详情逻辑
+    if (route.query.isHeaderShow) {
+        isHeaderShow.value = true;
+        defaultGardenId.value = route.query.farmId;
+        // 统一转换为布尔值
+        isDefaultFarm.value = route.query.defaultFarm === 'true' || route.query.defaultFarm === true;
+    }
+});
 
 const receiveFarm = (json) => {
-    VE_API.monitor.receiveFarm({
-        agriculturalStoreId: json.agriculturalStoreId,
-        farmId: json.farmId,
-    }).then((res) => {
-        if(res.code === 0){
-            showFarmPopupType.value = "success";
-            showFarmPopup.value = true;
-            textPopup.value = '农场领取成功';
-            defaultGardenId.value = json.farmId;
-        }else{
-            ElMessage.warning(res.msg);
-        }
-    });
-}
+    VE_API.monitor
+        .receiveFarm({
+            agriculturalStoreId: json.agriculturalStoreId,
+            farmId: json.farmId,
+        })
+        .then((res) => {
+            if (res.code === 0) {
+                showFarmPopupType.value = "success";
+                showFarmPopup.value = true;
+                textPopup.value = "农场领取成功";
+                defaultGardenId.value = json.farmId;
+            } else {
+                ElMessage.warning(res.msg);
+            }
+        });
+};
+
+const handleFarm = (optionType) => {
+    ElMessageBox.confirm(optionType === "delete" ? "确定删除该农场吗?" : "确定将该农场设为默认农场吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+    })
+        .then(() => {
+            const apiCall =
+                optionType === "delete"
+                    ? VE_API.farm.deleteFarm({ farmId: defaultGardenId.value })
+                    : VE_API.farm.updateFarm({ farmId: defaultGardenId.value, defaultFarm: 1 });
+            apiCall.then((res) => {
+                if (res.code === 0) {
+                    ElMessage.success(optionType === "delete" ? "删除成功" : "设为默认农场成功");
+                    if (optionType === "delete") {
+                        router.back();
+                    } else {
+                        isDefaultFarm.value = true;
+                        // 刷新 weatherInfo 组件的农场列表,确保显示最新的默认农场状态
+                        if (weatherInfoRef.value && weatherInfoRef.value.refreshFarmList) {
+                            weatherInfoRef.value.refreshFarmList();
+                        }
+                    }
+                } else {
+                    ElMessage.error(res.msg);
+                }
+            });
+        })
+        .catch(() => {});
+};
 
 const store = useStore();
 const tabBarHeight = computed(() => store.state.home.tabBarHeight);
@@ -245,7 +299,7 @@ const onLoad = () => {
 // 卡片点击事件
 const handleCardClick = (card) => {
     const params = {
-        farmId: gardenId.value
+        farmId: gardenId.value,
     };
     router.push({
         path: card.route,
@@ -267,7 +321,7 @@ const handleBroadcast = () => {
 
     // 构建播报文本
     let broadcastText = "实时播报:";
-    
+
     if (broadcastList.value.length === 0) {
         broadcastText += "暂无更多播报";
     } else {
@@ -278,9 +332,9 @@ const handleBroadcast = () => {
 
     // 创建语音合成对象
     const utterance = new SpeechSynthesisUtterance(broadcastText);
-    
+
     // 设置语音参数
-    utterance.lang = 'zh-CN';
+    utterance.lang = "zh-CN";
     utterance.rate = 0.8; // 语速
     utterance.pitch = 1; // 音调
     utterance.volume = 1; // 音量
@@ -306,7 +360,9 @@ const handleBroadcast = () => {
 };
 
 // 组件卸载时停止语音播放
-onUnmounted(() => {
+onDeactivated(() => {
+    showFarmPopup.value = false;
+    isDefaultFarm.value = false;
     if (isSpeaking.value) {
         speechSynthesis.cancel();
         isSpeaking.value = false;
@@ -319,10 +375,10 @@ const weatherExpanded = (isExpandedValue) => {
 };
 
 const gardenId = ref(store.state.home.gardenId);
-const changeGarden = ({id}) => {
+const changeGarden = ({ id }) => {
     gardenId.value = id;
     // 更新 store 中的状态
-    store.commit('home/SET_GARDEN_ID', id);
+    store.commit("home/SET_GARDEN_ID", id);
     // 重置分页状态
     currentPage.value = 1;
     finished.value = false;
@@ -335,8 +391,8 @@ function handlePage(url) {
     router.push({
         path: url,
         query: {
-            farmId: gardenId.value
-        }
+            farmId: gardenId.value,
+        },
     });
 }
 </script>
@@ -515,14 +571,22 @@ function handlePage(url) {
                 }
 
                 @keyframes pulse {
-                    0% { transform: scale(1); }
-                    50% { transform: scale(1.1); }
-                    100% { transform: scale(1); }
+                    0% {
+                        transform: scale(1);
+                    }
+                    50% {
+                        transform: scale(1.1);
+                    }
+                    100% {
+                        transform: scale(1);
+                    }
                 }
             }
         }
 
         .broadcast-list {
+            height: calc(100vh - 460px);
+            overflow: auto;
             .broadcast-item {
                 display: flex;
                 align-items: center;
@@ -591,4 +655,15 @@ function handlePage(url) {
         }
     }
 }
+.custom-bottom-fixed-btns {
+    z-index: 99999;
+    .primary-btn {
+        background: rgba(33, 153, 248, 0.1);
+        color: #2199f8;
+        border: none;
+    }
+    .btn-text {
+        color: #666666;
+    }
+}
 </style>

+ 1 - 1
src/views/old_mini/user/farmDetails.vue

@@ -9,7 +9,7 @@
                     variety: farmDetail.typeName,
                     address: farmDetail.address,
                     mapImage: '/map.png',
-                    maxWidth:'58px',
+                    maxWidth:'70px',
                 }"
             >
                 <template #right>

+ 8 - 4
src/views/old_mini/user/index.vue

@@ -1,5 +1,5 @@
 <template>
-    <div class="user-index">
+    <div class="user-index" :style="{ height: `calc(100vh - ${tabBarHeight}px)` }">
         <div class="user-header">
             <el-input class="search" v-model="input" placeholder="搜索">
                 <template #prefix>
@@ -56,12 +56,15 @@
 
 <script setup>
 import { Collapse, CollapseItem } from "vant";
-import { ref, onMounted } from "vue";
+import { ref, onMounted, computed } from "vue";
 import wx from 'weixin-js-sdk';
 import { useRouter } from "vue-router";
 import addPopup from "./components/addPopup.vue";
 import FarmInfoCard from "@/components/pageComponents/FarmInfoCard.vue";
+import { useStore } from "vuex";
 const router = useRouter();
+const store = useStore();
+const tabBarHeight = computed(() => store.state.home.tabBarHeight);
 
 onMounted(() => {
     getUserList();
@@ -120,7 +123,7 @@ const handleChat = (data) => {
 
 // 处理列表项点击
 const handleItemClick = (data) => {
-    router.push(`/farm_details?farmId=${data.farmId}`);
+    router.push(`/farm_details?farmId=${data.id}`);
 };
 </script>
 
@@ -170,8 +173,9 @@ const handleItemClick = (data) => {
     .list {
         width: 100%;
         margin-top: 12px;
+        height: calc(100% - 90px);
         .collapse-list{
-            height: calc(100vh - 100px - 60px);
+            height: 100%;
             overflow: auto;
         }
         .text {