Browse Source

feat:注册农资修改,添加用户管理播报接口

wangsisi 2 weeks ago
parent
commit
0364dd25c4

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

@@ -42,4 +42,9 @@ module.exports = {
         url: config.base_dev_url + "v2/farm/deleteFarm",
         type: "get",
     },
+    //查询单个农事编排信息
+    getFarmWorkArrangeDetail: {
+        url: config.base_dev_url + "container_farm_work_arrange/get",
+        type: "get",
+    },
 }

+ 6 - 1
src/api/modules/user.js

@@ -30,5 +30,10 @@ module.exports = {
     getFarmPastServiceCost: {
         url: config.base_dev_url + "z_farm_work_record_cost/statistics",
         type: "get",
-    }
+    },
+    //农资查询服务农场的最新广播
+    getLatestBroadcast: {
+        url: config.base_dev_url + "farm_broadcast/latestByServiceFarm",
+        type: "post",
+    },
 }

+ 25 - 27
src/components/pageComponents/FarmInfoCard.vue

@@ -30,34 +30,29 @@
             </slot>
         </div>
         <!-- 底部提示框:需求信息和预计收益 -->
-        <template v-if="showBottomTip">
+        <template v-if="data.broadcasts && data.broadcasts.length > 0">
             <slot name="bottomTip">
-                <div class="item-footer remind-footer" v-if="data.day">
-                    <div>
-                        距离农事执行已
-                        <span class="service-count">{{ data.day }}</span>
-                        天,提醒用户拍照!
-                    </div>
+                <div class="item-footer remind-footer">
+                    <div class="remind-cont" v-html="data.broadcasts[0].content"></div>
                     <span class="remind-text" @click.stop="handleRemind">提醒他</span>
                 </div>
-                <div class="item-footer item-bottom-tip" v-if="data.estimatedIncome">
+                <!-- <div class="item-footer item-bottom-tip" v-if="data.estimatedIncome">
                     <div>
                         当前农场有 <span>{{ data.farmInfo }}</span> 的农情需求
                     </div>
                     <div class="income-text">
                         预计收益 <span>{{ data.estimatedIncome }}元</span>
                     </div>
-                </div>
+                </div> -->
             </slot>
         </template>
-        <share-sheet class="share-sheet" teleport="#app" v-model:show="showShare" title="立即分享给好友" :options="options" @select="onSelect" />
+        <upload-execute ref="uploadExecuteRef" :onlyShare="true" />
     </div>
 </template>
 
 <script setup>
 import { computed, useSlots, ref } from "vue";
-import { ShareSheet } from "vant";
-
+import uploadExecute from "@/views/old_mini/task_condition/components/uploadExecute.vue";
 const props = defineProps({
     data: {
         type: Object,
@@ -83,25 +78,19 @@ const hasRightSlot = computed(() => {
     return !!slots.right;
 });
 
-const showBottomTip = computed(() => {
-    return props.data.day !== undefined || props.data.estimatedIncome !== undefined || !!slots.bottomTip;
-});
-
 const handleClick = () => {
     emit("click", props.data);
 };
 
-const showShare = ref(false);
-const options = [
-    { name: "飞鸟用户", icon: "https://birdseye-img.sysuimars.com/birdseye-look-mini/Group%201321316260.png" },
-    { name: "微信", icon: "wechat" },
-];
-const onSelect = (option) => {
-    showShare.value = false;
-    console.log(option);
-};
+const uploadExecuteRef = ref(null);
 const handleRemind = () => {
-    showShare.value = true;
+    // const data = {
+    //     ...props.data,
+    //     farmMiniUserId: props.data.receiveUserId,
+    //     farmId: props.data.id,
+    //     type: "remindUser"
+    // }
+    // uploadExecuteRef.value.showPopup(data);
 };
 </script>
 
@@ -193,9 +182,18 @@ const handleRemind = () => {
         &.remind-footer {
             justify-content: space-between;
         }
-        span {
+        .remind-cont{
+            width: calc(100% - 42px);
+            ::v-deep{
+                p{
+                    margin: 0;
+                }
+            }
+        }
+        .remind-text {
             color: #2199f8;
             font-weight: 500;
+            width: 40px;
         }
         .service-count {
             margin: 0 2px;

+ 324 - 0
src/components/pageComponents/ServiceInfo.vue

@@ -0,0 +1,324 @@
+<template>
+    <div class="service-info">
+        <div class="main-content">
+            <div class="service-title">
+                <img class="label-icon" src="@/assets/img/home/label-icon.png" alt="">
+                服务信息
+            </div>
+            <div class="service-content">
+                <div class="service-item">
+                    <div class="sub-title">服务作物</div>
+                    <div class="tag-group" v-if="!isEdit">
+                        <div class="tag-item" v-for="(item, idx) in crops" :key="'c-'+idx">{{ item.name }}</div>
+                    </div>
+                    <div class="tag-group add-tag-group" v-else>
+                        <div class="tag-item" :class="{ self: item.isSelf === 1 }" v-for="(item, idx) in crops" :key="'ce-'+idx">
+                            <span class="text">{{ item.name }}<el-icon @click.stop="handleEdit(item.name, 'crops')" v-if="item.isSelf===1" class="edit-icon"><Edit /></el-icon></span>
+                            <el-icon v-if="item.isSelf===1" class="del-icon" @click.stop="handleDelete('crops', idx)"><Close /></el-icon>
+                        </div>
+                        <div class="tag-item last-add" @click="handleAdd('作物')"><el-icon class="add-icon"><Plus /></el-icon>作物</div>
+                    </div>
+                </div>
+                <div class="service-item">
+                    <div class="sub-title">服务类型</div>
+                    <div class="tag-group" v-if="!isEdit">
+                        <div class="tag-item" v-for="(item, idx) in serviceTypes" :key="'t-'+idx">{{ item.name }}</div>
+                    </div>
+                    <div class="tag-group add-tag-group" v-else>
+                        <div class="tag-item" :class="{ self: item.isSelf === 1 }" v-for="(item, idx) in serviceTypes" :key="'te-'+idx">
+                            <span class="text">{{ item.name }}<el-icon @click.stop="handleEdit(item.name, 'serviceTypes')" v-if="item.isSelf===1" class="edit-icon"><Edit /></el-icon></span>
+                            <el-icon v-if="item.isSelf===1" class="del-icon" @click.stop="handleDelete('serviceTypes', idx)"><Close /></el-icon>
+                        </div>
+                        <div class="tag-item last-add" @click="handleAdd('类型')"><el-icon class="add-icon"><Plus /></el-icon>类型</div>
+                    </div>
+                </div>
+                <div class="service-item">
+                    <div class="sub-title">农机设备</div>
+                    <div class="tag-group" v-if="!isEdit">
+                        <div class="tag-item" v-for="(item, idx) in machines" :key="'m-'+idx">{{ item.name }}</div>
+                    </div>
+                    <div class="tag-group add-tag-group" v-else>
+                        <div class="tag-item" :class="{ self: item.isSelf === 1 }" v-for="(item, idx) in machines" :key="'me-'+idx">
+                            <span class="text">{{ item.name }}<el-icon @click.stop="handleEdit(item.name, 'machines')" v-if="item.isSelf===1" class="edit-icon"><Edit /></el-icon></span>
+                            <el-icon v-if="item.isSelf===1" class="del-icon" @click.stop="handleDelete('machines', idx)"><Close /></el-icon>
+                        </div>
+                        <div class="tag-item last-add" @click="handleAdd('设备')"><el-icon class="add-icon"><Plus /></el-icon>设备</div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <popup class="add-tag-popup" round v-model:show="showAddPopup">
+            <div class="popup-title" v-if="isEditPopup">编辑标签</div>
+            <div class="popup-title" v-else>添加{{addTypeName}}<span class="ml-2">标签</span></div>
+            <el-input class="popup-input" v-model="input" placeholder="标签" size="large" />
+            <div class="popup-button">
+                <div class="cancel" @click="showAddPopup = false">取消</div>
+                <div @click="handleConfirm">{{isEditPopup ? '确定' : '添加'}}</div>
+            </div>
+        </popup>
+    </div>
+</template>
+
+<script setup>
+import { ref } from "vue";
+import { Popup } from "vant";
+import { Edit, Close, Plus } from '@element-plus/icons-vue'
+
+const props = defineProps({
+    crops: {
+        type: Array,
+        default: () => []
+    },
+    serviceTypes: {
+        type: Array,
+        default: () => []
+    },
+    machines: {
+        type: Array,
+        default: () => []
+    },
+    isEdit: {
+        type: Boolean,
+        default: false
+    }
+});
+
+const emit = defineEmits(['update:crops', 'update:serviceTypes', 'update:machines', 'update:isEdit']);
+
+const showAddPopup = ref(false);
+const input = ref("");
+const addTypeName = ref("");
+const isEditPopup = ref(false);
+const currentCategory = ref('');
+const currentEditIndex = ref(-1);
+const currentEditName = ref('');
+
+function handleAdd(type) {
+    isEditPopup.value = false;
+    addTypeName.value = type;
+    input.value = "";
+    showAddPopup.value = true;
+    // 根据类型设置当前分类
+    if (type === '作物') {
+        currentCategory.value = 'crops';
+    } else if (type === '类型') {
+        currentCategory.value = 'serviceTypes';
+    } else if (type === '设备') {
+        currentCategory.value = 'machines';
+    }
+    currentEditIndex.value = -1;
+}
+
+function handleDelete(category, index) {
+    if (category === 'crops') {
+        const newCrops = [...props.crops];
+        newCrops.splice(index, 1);
+        emit('update:crops', newCrops);
+    }
+    if (category === 'serviceTypes') {
+        const newServiceTypes = [...props.serviceTypes];
+        newServiceTypes.splice(index, 1);
+        emit('update:serviceTypes', newServiceTypes);
+    }
+    if (category === 'machines') {
+        const newMachines = [...props.machines];
+        newMachines.splice(index, 1);
+        emit('update:machines', newMachines);
+    }
+}
+
+function handleEdit(val, category) {
+    isEditPopup.value = true;
+    input.value = val;
+    showAddPopup.value = true;
+    currentCategory.value = category;
+    currentEditName.value = val;
+    // 找到对应的索引
+    let targetArray = [];
+    if (category === 'crops') {
+        targetArray = props.crops;
+    } else if (category === 'serviceTypes') {
+        targetArray = props.serviceTypes;
+    } else if (category === 'machines') {
+        targetArray = props.machines;
+    }
+    currentEditIndex.value = targetArray.findIndex(item => item.name === val && item.isSelf === 1);
+}
+
+function handleConfirm() {
+    if (!input.value.trim()) {
+        return;
+    }
+    
+    if (isEditPopup.value && currentEditIndex.value >= 0) {
+        // 编辑模式
+        if (currentCategory.value === 'crops') {
+            const newCrops = [...props.crops];
+            newCrops[currentEditIndex.value].name = input.value.trim();
+            emit('update:crops', newCrops);
+        } else if (currentCategory.value === 'serviceTypes') {
+            const newServiceTypes = [...props.serviceTypes];
+            newServiceTypes[currentEditIndex.value].name = input.value.trim();
+            emit('update:serviceTypes', newServiceTypes);
+        } else if (currentCategory.value === 'machines') {
+            const newMachines = [...props.machines];
+            newMachines[currentEditIndex.value].name = input.value.trim();
+            emit('update:machines', newMachines);
+        }
+    } else {
+        // 添加模式
+        const newItem = { name: input.value.trim(), isSelf: 1 };
+        if (currentCategory.value === 'crops') {
+            const newCrops = [...props.crops, newItem];
+            emit('update:crops', newCrops);
+        } else if (currentCategory.value === 'serviceTypes') {
+            const newServiceTypes = [...props.serviceTypes, newItem];
+            emit('update:serviceTypes', newServiceTypes);
+        } else if (currentCategory.value === 'machines') {
+            const newMachines = [...props.machines, newItem];
+            emit('update:machines', newMachines);
+        }
+    }
+    
+    showAddPopup.value = false;
+    input.value = "";
+    currentEditIndex.value = -1;
+    currentEditName.value = '';
+}
+</script>
+
+<style lang="scss" scoped>
+.service-info {
+    .main-content {
+        max-height: calc(100% - 40px);
+        overflow: auto;
+        padding: 15px 12px;
+        margin: 14px 12px;
+        border-radius: 12px;
+        background: #fff;
+        .service-title {
+            font-size: 18px;
+            color: #222222;
+            font-weight: 500;
+            margin-bottom: 10px;
+            .label-icon {
+                width: 14px;
+                padding-right: 5px;
+            }
+        }
+        .service-content {
+            margin-top: 12px;
+            padding-top: 12px;
+            border-top: 1px solid #F5F5F5;
+            .service-item {
+                .sub-title {
+                    font-size: 16px;
+                    font-weight: 500;
+                    color: rgba(0, 0, 0, 0.9);
+                }
+                .tag-group {
+                    display: flex;
+                    align-items: center;
+                    flex-wrap: wrap;
+                    gap: 0 12px;
+                    font-size: 16px;
+                    .tag-item {
+                        margin-top: 10px;
+                        position: relative;
+                        background: #E8F5FF;
+                        border-radius: 8px;
+                        color: #2199f8;
+                        padding: 0 12px;
+                        box-sizing: border-box;
+                        min-width: 26vw;
+                        height: 48px;
+                        text-align: center;
+                        line-height: 48px;
+                        .text { display: inline-flex; align-items: center; }
+                        .edit-icon { margin-left: 8px; }
+                        .del-icon {
+                            position: absolute;
+                            right: -8px;
+                            top: -8px;
+                            background: #2199F8;
+                            border-radius: 50%;
+                            width: 16px; height: 16px;
+                            font-size: 10px;
+                            display: flex; align-items: center; justify-content: center;
+                            color: #fff;
+                        }
+                    }
+                    &.add-tag-group {
+                        .tag-item {
+                            color: #000000;
+                            background: none;
+                            border: 1px solid #999999;
+                            &.self {
+                                border: 1px solid #2199F8;
+                                background: #E8F5FF;
+                                color: #2199F8;
+                            }
+                            &.last-add {
+                                background: #F7F7F7;
+                                color: #343434;
+                                border: none;
+                                display: flex;
+                                align-items: center;
+                                justify-content: center;
+                                .add-icon {
+                                    font-size: 14px;
+                                    font-weight: bold;
+                                    margin-right: 3px;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            .service-item + .service-item {
+                margin-top: 20px;
+            }
+        }
+    }
+}
+
+.add-tag-popup{
+    width: 90%;
+    padding: 20px 16px;
+    .popup-title{
+        font-size: 18px;
+        font-weight: 500;
+        text-align: center;
+        margin-bottom: 12px;
+    }
+    .ml-2 {
+        margin-left: 3px;
+    }
+    .popup-input{
+        margin-bottom: 30px;
+    }
+    .popup-button{
+        display: flex;
+        padding-top: 20px;
+        border-top: 1px solid rgba(0, 0, 0, 0.1);
+        div{
+            flex: 1;
+            font-size: 16px;
+            padding: 9px;
+            border-radius: 20px;
+            background: #2199F8;
+            color: #fff;
+            text-align: center;
+            cursor: pointer;
+        }
+        .cancel{
+            margin-right: 20px;
+            color: #000;
+            background: #fff;
+            border: 1px solid #999999;
+        }
+    }
+}
+</style>
+

+ 31 - 14
src/components/popup/reviewUploadPopup.vue

@@ -1,9 +1,9 @@
 <template>
     <popup v-model:show="show" closeable :close-on-click-overlay="false" class="upload-popup" @closed="handleClosed">
         <div class="upload-content">
-            <div class="upload-tips"><span class="required">*</span>请上传复核照片</div>
-            <upload exampleImg class="upload-wrap" @handleUpload="handleUpload">
-                <img class="example" src="@/assets/img/home/example-4.png" alt="" />
+            <div class="upload-tips"><span class="required">*</span>{{ tipText }}</div>
+            <upload :exampleImg="showExampleImg" :maxCount="maxCount" class="upload-wrap" @handleUpload="handleUpload">
+                <img v-if="showExampleImg" class="example" src="@/assets/img/home/example-4.png" alt="" />
                 <img class="example" src="@/assets/img/home/plus.png" alt="" />
             </upload>
             <div class="upload-footer">
@@ -29,6 +29,18 @@ const props = defineProps({
         type: [String, Number],
         default: null,
     },
+    tipText: {
+        type: String,
+        default: "请上传复核照片",
+    },
+    showExampleImg: {
+        type: Boolean,
+        default: true,
+    },
+    maxCount: {
+        type: Number,
+        default: 3,
+    },
 });
 
 const emit = defineEmits(["update:modelValue", "success"]);
@@ -60,17 +72,22 @@ const handleUploadConfirm = () => {
         ElMessage.warning("请上传照片");
         return;
     }
-    const params = {
-        recordId: props.recordId,
-        executeEvidence: images.value,
-    };
-    VE_API.monitor.addReviewImg(params).then((res) => {
-        if (res.code === 0) {
-            ElMessage.success("上传成功");
-            show.value = false;
-            emit("success");
-        }
-    });
+    if(props.recordId){
+        const params = {
+            recordId: props.recordId,
+            executeEvidence: images.value,
+        };
+        VE_API.monitor.addReviewImg(params).then((res) => {
+            if (res.code === 0) {
+                ElMessage.success("上传成功");
+                show.value = false;
+                emit("success");
+            }
+        });
+    }else{
+        show.value = false;
+        emit("success", images.value);  
+    }
 };
 
 const handleClosed = () => {

+ 10 - 1
src/components/upload.vue

@@ -7,7 +7,7 @@
             <el-icon class="icon" size="16"><Warning /></el-icon>
             <span>上传照片可精准预测最佳病虫防治时间</span>
         </div>
-        <uploader class="uploader" v-model="fileList" multiple :max-count="3" :after-read="afterRead" @delete="deleteImg">
+        <uploader class="uploader" v-model="fileList" :multiple="props.maxCount > 1" :max-count="props.maxCount" :after-read="afterRead" @delete="deleteImg">
             <template v-if="exampleImg">
                 <slot v-if="!fileList.length"></slot>
                 <img class="plus" v-else src="@/assets/img/home/plus.png" alt="">
@@ -45,6 +45,10 @@ const props = defineProps({
     type: Boolean,
     default: false
   },
+  maxCount: {
+    type: Number,
+    default: 3
+  },
 })
 
 
@@ -63,6 +67,11 @@ const afterRead = async (files) => {
     if (!Array.isArray(files)) {
       files = [files];
     }
+    // 如果 maxCount 为 1,先清空之前的图片数组
+    if (props.maxCount === 1) {
+      fileArr.value = [];
+      imgArr.value = [];
+    }
     for(let file of files){
       // 将文件上传至服务器
       let fileVal = file.file;

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

@@ -182,11 +182,11 @@ const cellItems = computed(() => {
             },
             {
                 title: "报价维护",
-                path: "/offer_price?identity=NZ&role=2",
+                path: "/offer_price",
             },
             {
                 title: "服务维护",
-                path: "/service_manage?identity=NZ&role=2",
+                path: "/service_manage",
             },
         ];
     }

+ 92 - 148
src/views/old_mini/mine/pages/register.vue

@@ -20,7 +20,7 @@
                             type="tel"
                             name="tel"
                             label="联系电话"
-                            :rules="[{ required: true,validator: validatorTel, message: '请输入电话号码'}]"
+                            :rules="[{ required: true, validator: validatorTel, message: '请输入电话号码' }]"
                             placeholder="请输入电话号码"
                         />
                         <field
@@ -90,12 +90,7 @@
                             </field>
                         </template>
                         <div class="flex" v-else>
-                            <field
-                                v-model="formData.address"
-                                label="服务区域"
-                                readonly
-                                placeholder="默认位置"
-                            />
+                            <field v-model="formData.address" label="服务区域" readonly placeholder="默认位置" />
                             <el-dropdown trigger="click">
                                 <div class="el-dropdown-link">
                                     {{ dropdownName }}
@@ -116,6 +111,11 @@
                                 </template>
                             </el-dropdown>
                         </div>
+                        <upload v-show="pageType === 'NZ'" exampleImg :maxCount="1" class="upload-wrap" @handleUpload="handleUploadSuccess">
+                            <div class="upload-btn">
+                                点击上传营业执照
+                            </div>
+                        </upload>
                     </div>
                 </div>
                 <div class="card" v-if="pageType == 'EXPERT'">
@@ -127,51 +127,14 @@
                         <el-input v-model="input" :rows="5" type="textarea" placeholder="描述:" />
                     </div>
                 </div>
-                <div class="card" v-else>
-                    <div class="card-title">
-                        <img src="@/assets/img/mine/label-icon.png" alt="" />
-                        <span>服务信息</span>
-                    </div>
-                    <div class="checkbox-group">
-                        <div class="name">服务作物</div>
-                        <el-checkbox-group v-model="checkboxGroup" size="large">
-                            <el-checkbox-button
-                                @change="(e) => changeCheckBox(e, index)"
-                                v-for="(item, index) in cities"
-                                :key="index"
-                                :value="item.name"
-                            >
-                                {{ item.name }}
-                            </el-checkbox-button>
-                        </el-checkbox-group>
-                    </div>
-                    <div class="checkbox-group">
-                        <div class="name">服务类型</div>
-                        <el-checkbox-group v-model="checkboxGroup1" size="large">
-                            <el-checkbox-button
-                                @change="(e) => changeCheckBox1(e, index)"
-                                v-for="(item, index) in cities1"
-                                :key="index"
-                                :value="item.name"
-                            >
-                                {{ item.name }}
-                            </el-checkbox-button>
-                        </el-checkbox-group>
-                    </div>
-                    <div class="checkbox-group">
-                        <div class="name">农机设备</div>
-                        <el-checkbox-group v-model="checkboxGroup2" size="large">
-                            <el-checkbox-button
-                                @change="(e) => changeCheckBox2(e, index)"
-                                v-for="(item, index) in cities2"
-                                :key="index"
-                                :value="item.name"
-                            >
-                                {{ item.name }}
-                            </el-checkbox-button>
-                        </el-checkbox-group>
-                    </div>
-                </div>
+                <template v-else>
+                    <ServiceInfo 
+                        v-model:crops="crops"
+                        v-model:serviceTypes="serviceTypes"
+                        v-model:machines="machines"
+                        v-model:isEdit="isEdit"
+                    />
+                </template>
                 <Button class="button" round block type="primary" native-type="submit"> 提交 </Button>
             </Form>
         </div>
@@ -182,28 +145,35 @@
 import customHeader from "@/components/customHeader.vue";
 import { Field, Form, Button } from "vant";
 import { onActivated, ref } from "vue";
-import { useRoute ,useRouter} from "vue-router";
-import { ElMessage } from 'element-plus'
+import { useRoute, useRouter } from "vue-router";
+import { ElMessage } from "element-plus";
+import upload from "@/components/upload";
+import ServiceInfo from "@/components/pageComponents/ServiceInfo.vue";
 const route = useRoute();
 const router = useRouter();
 
-const formRef  = ref(null)
+const formRef = ref(null);
 const formData = ref({
     name: "",
     tel: "",
-    subjectName:'',
+    subjectName: "",
     point: "",
-    serviceCropsJson:[],
-    agriculturalEquipmentJson:[]
+    serviceCropsJson: [],
+    agriculturalEquipmentJson: [],
+    licenseImg: [],
 });
 
-const validatorTel = (val) =>{
+const validatorTel = (val) => {
     const phoneRegex = /^1[3-9]\d{9}$/;
-    if(!phoneRegex.test(val)) return '请输入正确的电话号码'
-}
+    if (!phoneRegex.test(val)) return "请输入正确的电话号码";
+};
 
 const onSubmit = () => {
-    formData.value.point = "POINT(113.1093017627431 22.574540836684672)"
+    formData.value.point = "POINT(113.1093017627431 22.574540836684672)";
+    if (pageType.value === "NZ" && !formData.value.licenseImg) {
+        ElMessage.warning("请上传营业执照");
+        return;
+    }
     VE_API.mine.register(formData.value).then(res =>{
         if(res.code===0){
             ElMessage.success('注册成功,待审核')
@@ -214,9 +184,9 @@ const onSubmit = () => {
     })
 };
 
-const resetForm = () =>{
-    formRef.value.resetValidation()
-}
+const resetForm = () => {
+    formRef.value.resetValidation();
+};
 
 const number = ref("请选择");
 const numberList = ["请选择", "10", "20", "30", "40"];
@@ -242,7 +212,6 @@ const handleDropdown = (item, index) => {
     active.value = index;
 };
 
-const value = ref("");
 const input = ref("");
 
 const pageName = ref("");
@@ -253,36 +222,31 @@ const identityTyepe = {
 };
 // NF: "农服",
 
-const checkboxGroup = ref(["荔枝", "龙眼"]);
-const cities = ref([{ name: "荔枝" }, { name: "龙眼" }]);
-const changeCheckBox = (e, i) => {
-    console.log("e", i, e);
-    if (e === false) {
-        cities.value.splice(i, 1);
-    }
-};
+// 服务信息数据,转换为 ServiceInfo 组件需要的格式
+const isEdit = ref(true); // 默认编辑状态
+const crops = ref([
+    { name: "荔枝", isSelf: 0 },
+    { name: "龙眼", isSelf: 1 }
+]);
+const serviceTypes = ref([
+    { name: "播种", isSelf: 1 },
+    { name: "收获", isSelf: 0 }
+]);
+const machines = ref([
+    { name: "收割机", isSelf: 1 },
+    { name: "灌溉机", isSelf: 0 }
+]);
 
-const checkboxGroup1 = ref(["播种"]);
-const cities1 = ref([{ name: "播种" }, { name: "收获" }]);
-const changeCheckBox1 = (e, i) => {
-    if (e === false) {
-        cities.value.splice(i, 1);
-    }
+const handleUploadSuccess = (data) => {
+    formData.value.licenseImg = data.imgArr[0];
 };
 
-const checkboxGroup2 = ref(["收割机"]);
-const cities2 = ref([{ name: "收割机" }, { name: "灌溉机" }]);
-const changeCheckBox2 = (e, i) => {
-    if (e === false) {
-        cities.value.splice(i, 1);
-    }
-};
 
 onActivated(() => {
     pageName.value = identityTyepe[route.query.identity];
     pageType.value = route.query.identity;
-    formData.value = {}
-    resetForm()
+    formData.value = {};
+    resetForm();
 });
 </script>
 
@@ -291,6 +255,11 @@ onActivated(() => {
     width: 100%;
     height: 100vh;
     background-color: #f5f7fb;
+    ::v-deep{
+        .main-content {
+            margin: 12px 0;
+        }
+    }
     .content {
         height: calc(100% - 40px);
         padding: 12px;
@@ -358,14 +327,27 @@ onActivated(() => {
                         font-size: 12px;
                         padding: 14px 0;
                         border-radius: 8px;
-                        border: 1px solid #2199f8;
-                        background: #f5f5f5;
+                        border: 1px solid rgba(33, 153, 248, 0.2);
+                        background: #fff;
                         margin-left: 5px;
                     }
                 }
                 .el-icon--right {
                     margin-left: 4px;
                 }
+                .upload-btn {
+                    color: #2199f8;
+                    font-size: 16px;
+                    padding: 12px 0;
+                    text-align: center;
+                    width: 170px;
+                    border-radius: 8px;
+                    border: 1px solid #2199f8;
+                    background: #fff;
+                }
+                .upload-wrap{
+                    margin-top: 12px;
+                }
             }
         }
         .card + .card {
@@ -396,63 +378,6 @@ onActivated(() => {
                 font-size: 14px;
             }
         }
-        .checkbox-group {
-            .name {
-                font-size: 16px;
-                color: rgba(0, 0, 0, 0.9);
-                margin-bottom: 10px;
-            }
-            ::v-deep {
-                .el-checkbox-group {
-                    .el-checkbox-button {
-                        margin-right: 12px;
-                        margin-bottom: 10px;
-                        .el-checkbox-button__inner {
-                            border-radius: 8px;
-                            background: #fff;
-                            color: #000;
-                            border: 1px solid #999999;
-                            box-shadow: none;
-                            font-size: 16px;
-                            padding: 15px;
-                            width: 101px;
-                            box-sizing: border-box;
-                        }
-                    }
-                    .is-checked {
-                        .el-checkbox-button__inner {
-                            background: #e8f5ff;
-                            color: #2199f8;
-                            border: 1px solid #2199f8;
-                            position: relative;
-                            &::before {
-                                content: "x";
-                                position: absolute;
-                                top: -10px;
-                                right: -10px;
-                                width: 20px;
-                                height: 20px;
-                                border-radius: 50%;
-                                font-size: 12px;
-                                text-align: center;
-                                line-height: 16px;
-                                color: #ffffff;
-                                background: #2199f8;
-                            }
-                        }
-                    }
-                }
-            }
-            .btn {
-                background: #2199f8;
-                border-radius: 20px;
-                color: #fff;
-                padding: 0 10px;
-                font-size: 12px;
-                height: 24px;
-                line-height: 24px;
-            }
-        }
 
         .button {
             border-radius: 8px;
@@ -474,4 +399,23 @@ onActivated(() => {
         color: #2199f8;
     }
 }
+
+.image-preview {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: rgba(0, 0, 0, 0.8);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    z-index: 1000;
+}
+
+.image-preview img {
+    max-width: 90%;
+    max-height: 90%;
+    object-fit: contain;
+}
 </style>

+ 11 - 1
src/views/old_mini/modify_work/completedWork.vue

@@ -180,7 +180,7 @@
                             <el-icon><ArrowRight /></el-icon>
                         </div> -->
                     </div>
-                    <div class="info-content">水稻移栽后返青成活(新根萌发、心叶展开),进入分蘖始期</div>
+                    <div class="info-content">{{ farmStatusText }}</div>
                 </div>
                 <div class="box-wrap farm-photo" v-if="triggerImg.length">
                     <div class="photo-list">
@@ -570,6 +570,9 @@ onActivated(async () => {
     if (id) {
         await getDetail(id);
         getTriggerImg(id);
+
+        //查询农场现状信息
+        getFarmWorkArrangeDetail(detailData.value.farmWorkArrangeId);
     }
     parmasPage.value = {
         farmMiniUserId: curRole.value == 2 ? detailData.value.farmMiniUserId : detailData.value.users[0]?.userId,
@@ -714,6 +717,13 @@ onActivated(async () => {
     // }
 });
 
+const farmStatusText = ref('');
+const getFarmWorkArrangeDetail = (id) => {
+    VE_API.farm.getFarmWorkArrangeDetail({ id }).then(({ data }) => {
+        farmStatusText.value = data.farmStatus;
+    });
+};
+
 function getServiceCost(cost, area) {
     if (!cost || !area) return "--";
     return (parseFloat(cost) * parseFloat(area)).toFixed(2);

+ 3 - 1
src/views/old_mini/plan/index.vue

@@ -73,7 +73,9 @@ const containerId = ref(null);
 const handleTabChange = (id, item) => {
     containerId.value = item.containerId;
     active.value = id;
-    isEditVal.value = id ? true : false;
+    if(!route.query.containerId){
+        isEditVal.value = id ? true : false;
+    }
 };
 
 onActivated(() => {

+ 7 - 212
src/views/old_mini/service_manage/index.vue

@@ -1,53 +1,12 @@
 <template>
     <div class="service-manage">
         <custom-header name="服务维护"></custom-header>
-        <div class="main-content">
-            <div class="service-title">
-                <img class="label-icon" src="@/assets/img/home/label-icon.png" alt="">
-                服务信息
-            </div>
-            <div class="service-content">
-                <div class="service-item">
-                    <div class="sub-title">服务作物</div>
-                    <div class="tag-group" v-if="!isEdit">
-                        <div class="tag-item" v-for="(item, idx) in crops" :key="'c-'+idx">{{ item.name }}</div>
-                    </div>
-                    <div class="tag-group add-tag-group" v-else>
-                        <div class="tag-item" :class="{ self: item.isSelf === 1 }" v-for="(item, idx) in crops" :key="'ce-'+idx">
-                            <span class="text">{{ item.name }}<el-icon @click.stop="handleEdit(item.name)" v-if="item.isSelf===1" class="edit-icon"><Edit /></el-icon></span>
-                            <el-icon v-if="item.isSelf===1" class="del-icon" @click.stop="handleDelete('crops', idx)"><Close /></el-icon>
-                        </div>
-                        <div class="tag-item last-add" @click="handleAdd('作物')"><el-icon class="add-icon"><Plus /></el-icon>作物</div>
-                    </div>
-                </div>
-                <div class="service-item">
-                    <div class="sub-title">服务类型</div>
-                    <div class="tag-group" v-if="!isEdit">
-                        <div class="tag-item" v-for="(item, idx) in serviceTypes" :key="'t-'+idx">{{ item.name }}</div>
-                    </div>
-                    <div class="tag-group add-tag-group" v-else>
-                        <div class="tag-item" :class="{ self: item.isSelf === 1 }" v-for="(item, idx) in serviceTypes" :key="'te-'+idx">
-                            <span class="text">{{ item.name }}<el-icon @click.stop="handleEdit(item.name)" v-if="item.isSelf===1" class="edit-icon"><Edit /></el-icon></span>
-                            <el-icon v-if="item.isSelf===1" class="del-icon" @click.stop="handleDelete('serviceTypes', idx)"><Close /></el-icon>
-                        </div>
-                        <div class="tag-item last-add" @click="handleAdd('类型')"><el-icon class="add-icon"><Plus /></el-icon>类型</div>
-                    </div>
-                </div>
-                <div class="service-item">
-                    <div class="sub-title">农机设备</div>
-                    <div class="tag-group" v-if="!isEdit">
-                        <div class="tag-item" v-for="(item, idx) in machines" :key="'m-'+idx">{{ item.name }}</div>
-                    </div>
-                    <div class="tag-group add-tag-group" v-else>
-                        <div class="tag-item" :class="{ self: item.isSelf === 1 }" v-for="(item, idx) in machines" :key="'me-'+idx">
-                            <span class="text">{{ item.name }}<el-icon @click.stop="handleEdit(item.name)" v-if="item.isSelf===1" class="edit-icon"><Edit /></el-icon></span>
-                            <el-icon v-if="item.isSelf===1" class="del-icon" @click.stop="handleDelete('machines', idx)"><Close /></el-icon>
-                        </div>
-                        <div class="tag-item last-add" @click="handleAdd('设备')"><el-icon class="add-icon"><Plus /></el-icon>设备</div>
-                    </div>
-                </div>
-            </div>
-        </div>
+        <ServiceInfo 
+            v-model:crops="crops"
+            v-model:serviceTypes="serviceTypes"
+            v-model:machines="machines"
+            v-model:isEdit="isEdit"
+        />
         
         <div class="page-action" v-if="isEdit">
             <div class="btn-item cancel" @click="isEdit = false">取消</div>
@@ -59,36 +18,14 @@
             <div class="btn-item primary center-btn" @click="isEdit = true">编辑服务类型</div>
         </div>
     </div>
-
-    <popup class="add-tag-popup" round v-model:show="showAddPopup">
-        <div class="popup-title" v-if="isEditPopup">编辑标签</div>
-        <div class="popup-title" v-else>添加{{addTypeName}}<span class="ml-2">标签</span></div>
-        <el-input class="popup-input" v-model="input" placeholder="标签" size="large" />
-        <div class="popup-button">
-            <div class="cancel" @click="showAddPopup = false">取消</div>
-            <div>{{isEditPopup ? '确定' : '添加'}}</div>
-        </div>
-    </popup>
 </template>
 
 <script setup>
 import { ref } from "vue";
 import customHeader from "@/components/customHeader.vue";
-import { Popup} from "vant";
-import { Edit, Close, Plus } from '@element-plus/icons-vue'
+import ServiceInfo from "@/components/pageComponents/ServiceInfo.vue";
 
 const isEdit = ref(false);
-const showAddPopup = ref(false);
-
-const input = ref("");
-
-const addTypeName = ref("");
-function handleAdd(type) {
-    isEditPopup.value = false
-    addTypeName.value = type;
-    input.value = "";
-    showAddPopup.value = true;
-}
 
 // 三类数据:数组对象形式,随意赋值 isSelf=0/1
 const crops = ref([
@@ -106,19 +43,6 @@ const machines = ref([
     { name: "收割机", isSelf: 1 },
     { name: "M3E", isSelf: 0 }
 ]);
-
-function handleDelete(category, index) {
-    if (category === 'crops') crops.value.splice(index, 1);
-    if (category === 'serviceTypes') serviceTypes.value.splice(index, 1);
-    if (category === 'machines') machines.value.splice(index, 1);
-}
-
-const isEditPopup = ref(false);
-function handleEdit(val) {
-    isEditPopup.value = true;
-    input.value = val;
-    showAddPopup.value = true;
-}
 </script>
 
 <style lang="scss" scoped>
@@ -126,97 +50,6 @@ function handleEdit(val) {
     width: 100%;
     height: 100vh;
     background: #F5F7FB;
-    .main-content {
-        max-height: calc(100% - 40px);
-        overflow: auto;
-        padding: 15px 12px;
-        margin: 14px 12px;
-        border-radius: 12px;
-        background: #fff;
-        .service-title {
-            font-size: 18px;
-            color: #222222;
-            font-weight: 500;
-            margin-bottom: 10px;
-            .label-icon {
-                width: 14px;
-                padding-right: 5px;
-            }
-        }
-        .service-content {
-            margin-top: 12px;
-            padding-top: 12px;
-            border-top: 1px solid #F5F5F5;
-            .service-item {
-                .sub-title {
-                    font-size: 16px;
-                    font-weight: 500;
-                    color: rgba(0, 0, 0, 0.9);
-                }
-                .tag-group {
-                    display: flex;
-                    align-items: center;
-                    flex-wrap: wrap;
-                    gap: 0 12px;
-                    font-size: 16px;
-                    .tag-item {
-                        margin-top: 10px;
-                        position: relative;
-                        background: #E8F5FF;
-                        border-radius: 8px;
-                        color: #2199f8;
-                        padding: 0 12px;
-                        box-sizing: border-box;
-                        min-width: 26vw;
-                        height: 48px;
-                        text-align: center;
-                        line-height: 48px;
-                        .text { display: inline-flex; align-items: center; }
-                        .edit-icon { margin-left: 8px; }
-                        .del-icon {
-                            position: absolute;
-                            right: -8px;
-                            top: -8px;
-                            background: #2199F8;
-                            border-radius: 50%;
-                            width: 16px; height: 16px;
-                            font-size: 10px;
-                            display: flex; align-items: center; justify-content: center;
-                            color: #fff;
-                        }
-                    }
-                    &.add-tag-group {
-                        .tag-item {
-                            color: #000000;
-                            background: none;
-                            border: 1px solid #999999;
-                            &.self {
-                                border: 1px solid #2199F8;
-                                background: #E8F5FF;
-                                color: #2199F8;
-                            }
-                            &.last-add {
-                                background: #F7F7F7;
-                                color: #343434;
-                                border: none;
-                                display: flex;
-                                align-items: center;
-                                justify-content: center;
-                                .add-icon {
-                                    font-size: 14px;
-                                    font-weight: bold;
-                                    margin-right: 3px;
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            .service-item + .service-item {
-                margin-top: 20px;
-            }
-        }
-    }
     
     .page-action {
         position: fixed;
@@ -258,42 +91,4 @@ function handleEdit(val) {
         }
     }
 }
-
-
-.add-tag-popup{
-    width: 90%;
-    padding: 20px 16px;
-    .popup-title{
-        font-size: 18px;
-        font-weight: 500;
-        text-align: center;
-        margin-bottom: 12px;
-    }
-    .ml-2 {
-        margin-left: 3px;
-    }
-    .popup-input{
-        margin-bottom: 30px;
-    }
-    .popup-button{
-        display: flex;
-        padding-top: 20px;
-        border-top: 1px solid rgba(0, 0, 0, 0.1);
-        div{
-            flex: 1;
-            font-size: 16px;
-            padding: 9px;
-            border-radius: 20px;
-            background: #2199F8;
-            color: #fff;
-            text-align: center;
-        }
-        .cancel{
-            margin-right: 20px;
-            color: #000;
-            background: #fff;
-            border: 1px solid #999999;
-        }
-    }
-}
 </style>

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

@@ -27,20 +27,18 @@
                         :key="ele.agriculturalStoreId"
                         class="list-item"
                         :data="{
+                            ...ele,
                             farmName: ele.name,
                             area: ele.mianji + '亩',
                             variety: ele.speciesName,
                             address: ele.address,
                             mapImage: ele.mapImage || '/map.png',
                             maxWidth: '90px',
-                            // day: 15,
-                            // farmInfo: '梢期杀虫',
-                            // estimatedIncome: ele.estimatedIncome || 2585
                         }"
                         @click="handleItemClick(ele)"
                     >
                         <template #right>
-                            <div @click.stop="handleChat(ele)">{{ ele.receiveUserId ? '在线沟通' : '分享农场' }}</div>
+                            <div @click.stop="handleChat(ele)">{{ ele.receiveUserId ? '在线沟通' : '分享认领' }}</div>
                         </template>
                     </farm-info-card>
                 </collapse-item>
@@ -91,9 +89,31 @@ const getUserList = async () => {
         // 清空现有的子项
         dataList.value[0].children = [];
         dataList.value[1].children = data || [];
+        getLatestBroadcast();
     }
 };
 
+const getLatestBroadcast = () => {
+    VE_API.user.getLatestBroadcast({sourceTypes:[0,1]}).then(({ data }) => {
+        if (data && typeof data === 'object') {
+            // 遍历广播数据,key 是 farmId(字符串格式)
+            Object.keys(data).forEach(farmIdStr => {
+                const farmId = Number(farmIdStr);
+                const broadcasts = data[farmIdStr] || [];
+                
+                // 在农场列表中找到对应的农场
+                const farmItem = dataList.value[1].children.find(item => item.id === farmId || item.farmId === farmId);
+                
+                if (farmItem && broadcasts.length > 0) {
+                    // 将广播数据合并到农场项中
+                    farmItem.broadcasts = broadcasts;
+                }
+            });
+            console.log("dataList.value", dataList.value);
+        }
+    });
+};
+
 const input = ref("");
 //新建分组
 const showGroupPopup = ref(false);