Browse Source

fix: 分配果树,下载模板,上传订单

lxf 1 week ago
parent
commit
1d43df32b6

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

@@ -101,4 +101,12 @@ module.exports = {
         url: config.base_url + "lz_sample/legendList",
         type: "get",
     },
+    fetchFarmWorkList: {
+        url: config.base_url + "z_farm_work_lib/page/{page}/{limit}",
+        type: "get",
+    },
+    saveFarmWork:{
+        url:  config.base_url + "z_farm_work_lib/save",
+        type: "post",
+    }
 }

+ 9 - 1
src/api/modules/manage_interface.js

@@ -37,5 +37,13 @@ module.exports = {
         url: config.base_url + "adm/images/{organId}/{areaId}",
         type: "get",
     },
-
+    fetchGroupList: {
+        url: config.base_url + "z_sample_lighten_card_offline_take/groupList",
+        type: "get",
+    },
+    saveTreeUser: {
+        url: config.base_url + "z_sample_lighten_card_offline_take/batchSave",
+        type: "post",
+    },
+    
 }

+ 12 - 0
src/api/modules/manage_user.js

@@ -0,0 +1,12 @@
+const config = require("../config")
+
+module.exports = {
+    downloadTemplate: {
+        url: config.base_url + "adm/download_lighten_card_offline_template",
+        type: "blob",
+    },
+    uploadUser: {
+        url: config.base_url + "adm/import_lighten_card_offline",
+        type: "post",
+    },
+}

+ 5 - 1
src/api/modules/system.js

@@ -53,5 +53,9 @@ module.exports = {
     findGuangzhouDistrict:{
         url: config.base_url + "district/findGuangzhouDistrict",
         type:"get"
-    }
+    },
+    organList: {
+        url: config.base_url + "farm/list",
+        type: "post",
+    },
 };

+ 111 - 0
src/components/common/UploadMedia.vue

@@ -0,0 +1,111 @@
+<template>
+  <el-upload
+             :file-list="fileList"
+             :on-remove="handleRemove"
+             :http-request="uploading"
+             :limit="1"
+             :headers="headers"
+             :data="data"
+             list-type="picture-card"
+             :show-file-list="true"
+             :auto-upload="true">
+    <el-icon><Plus /></el-icon>
+
+  </el-upload>
+</template>
+
+<script setup>
+import { base_img_url3 } from '@/api/config'
+import OSS from "ali-oss"
+import {ref, toRefs} from "vue";
+import {useStore} from "vuex";
+import {getFileExt} from "@/utils/util"
+
+const store = useStore()
+const disabled = ref(false)
+const imageUrl = ref("")
+const headers = {token:store.getters.token};
+const data = {uploadType:"banner",durable:1};
+const fileList = ref([])
+let credentials = null; // STS凭证
+let ossClient = null; // oss客户端实例
+const bucket = 'birdseye'; // bucket名称
+const region = 'oss-cn-guangzhou'; // oss服务区域名称
+
+const props = defineProps({
+  limit:{
+    type: Number,
+    default: 1,
+  },
+  fullPath:{
+    type: Boolean,
+    default: false,
+  },
+  url: {
+    type: String,
+    default: null,
+  },
+  name: {
+    type: String,
+    default: new Date().getTime(),
+  },
+  filename: {
+    type: String,
+    default: new Date().getTime(),
+  }
+});
+if(props.url){
+  fileList.value.push({name:props.name,url:props.url})
+}
+
+
+function getFileName(url) {
+  return  new Date().getTime() + url.substring(url.lastIndexOf("."))
+}
+
+const emit = defineEmits(["uploadSuccess","handleRemove"]);
+
+const handleRemove = (file) => {
+  emit("handleRemove", props.name);
+}
+
+async function uploading(option){
+  if (!ossClient) {
+    await initOSSClient();
+  }
+  let file = option.file
+  let ext = getFileExt(file.name)
+  let fileName = props.filename+"."+ext;
+
+  return ossClient.put(fileName, file).then(result => {
+    emit("uploadSuccess", props.fullPath? `${base_img_url3}/${result.name}` : result.name, props.name);
+  }).catch(err => {
+    console.log(`Common upload ${file.name} failed === `, err);
+  });
+}
+
+function getCredential() {
+  return VE_API.ali.credential()
+      .then( ({data})=> {
+        credentials = data;
+        initOSSClient()
+      })
+}
+getCredential()
+
+async function initOSSClient() {
+  const { accessKeyId, accessKeySecret, securityToken } = credentials;
+  ossClient = new OSS({
+    accessKeyId: accessKeyId,
+    accessKeySecret: accessKeySecret,
+    stsToken: securityToken,
+    bucket,
+    region
+  });
+}
+
+</script>
+
+<style scoped>
+
+</style>

+ 2 - 0
src/plugins/axios.js

@@ -188,6 +188,8 @@ const install = (app, { router, store, opt }) => {
         delete: (url, p, config) =>{
             return _axios.delete(url, config)
         },
+        // 新增 blob 请求(用于文件下载)
+        blob: (url, p, config) => _axios.get(url, Object.assign(config, { params: p, responseType: "blob",})),
     };
 
     let api = {};

+ 3 - 1
src/views/home/components/adoptList.vue

@@ -223,7 +223,8 @@
             <div class="pagination-wrap">
                 <el-pagination
                     background
-                    :page-size="20"
+                    v-model:page-size="pageSize"
+                    :page-size="[20]"
                     :pagerCount="5"
                     v-model:current-page="currentPage"
                     @current-change="getSamplePage"
@@ -309,6 +310,7 @@ onMounted(() => {
 });
 
 const currentPage = ref(1);
+const pageSize = ref(20);
 const totalVal = ref(0);
 
 function getSamplePage() {

+ 276 - 28
src/views/home/components/clientList.vue

@@ -1,8 +1,66 @@
 <template>
     <div class="list-wrap">
         <div class="list-content">
-            <div class="list-item" v-for="(ele, idx) in defalutList" :key="idx">
-                <div class="item-flex">
+            <el-collapse v-model="activeNames" expand-icon-position="left">
+                <el-collapse-item
+                    title="Consistency"
+                    v-for="(group, groupIndex) in groupList"
+                    :key="groupIndex"
+                    :name="groupIndex"
+                >
+                    <template #title="{ isActive }">
+                        <div :class="['title-wrapper', { 'is-active': isActive }]">
+                            <div class="title-l">
+                                <el-icon class="arrow-icon"><CaretBottom /></el-icon>
+                                {{ group.name }}
+                                <span class="group-length">({{ group.list.length }})</span>
+                            </div>
+                            <div class="title-r" @click.stop="handleRightClick">
+                                <span class="title-manage">管理</span>
+                                <el-checkbox
+                                    v-show="toSelectClient"
+                                    v-model="groupCheckStates[groupIndex].checkAll"
+                                    :indeterminate="groupCheckStates[groupIndex].isIndeterminate"
+                                    @change="(val) => handleCheckAllChange(val, groupIndex)"
+                                >
+                                    全选
+                                </el-checkbox>
+                            </div>
+                        </div>
+                    </template>
+                    <template #icon> </template>
+                    <!-- 遍历当前分组中的每一项 -->
+                    <el-checkbox-group v-model="checkedCities" @change="handleCheckedCitiesChange">
+                        <div v-for="(ele, index) in group.list" :key="index" class="list-item">
+                            <el-checkbox v-show="toSelectClient" label="" :value="ele.tel"> </el-checkbox>
+                            <div class="item-flex">
+                                <img
+                                    class="photo"
+                                    :src="
+                                        ele.icon || 'https://birdseye-img.sysuimars.com/dinggou-mini/defalut-icon.png'
+                                    "
+                                    alt=""
+                                />
+                                <div class="item-text">
+                                    <div class="name">
+                                        <span>{{ ele.name }}</span>
+                                        <el-icon
+                                            class="icon"
+                                            @click.stop="handlePerson('edit', ele)"
+                                            color="#2199F8"
+                                            size="16"
+                                            ><Edit
+                                        /></el-icon>
+                                    </div>
+                                    <div><span class="item-title">电话:</span>{{ ele.tel }}</div>
+                                    <div><span class="item-title">地址:</span>{{ ele.address || "--" }}</div>
+                                </div>
+                                <!-- <div class="blue-btn" @click="toCustomOneTree(ele)">去分配</div> -->
+                            </div>
+                        </div>
+                    </el-checkbox-group>
+                </el-collapse-item>
+                <!-- <div class="item-flex">
                     <img class="photo" :src="ele.icon || 'https://birdseye-img.sysuimars.com/dinggou-mini/defalut-icon.png'" alt="" />
                     <div class="item-text">
                         <div class="name">
@@ -14,51 +72,173 @@
                         <div><span class="item-title">地址:</span>{{ ele.address || "--" }}</div>
                     </div>
                     <div class="blue-btn" @click="toCustomOneTree(ele)">去分配</div>
-                </div>
-            </div>
+                </div> -->
+            </el-collapse>
         </div>
-        
+
         <!-- 渐变主色按钮 -->
-        <div class="center-btn" @click="toCustomPage">一键分配</div>
+        <div class="center-btn" v-show="!toSelectClient" @click="toCustomPage">一键分配</div>
+        <div class="global-wrap" v-show="toSelectClient">
+            <div class="global-btn" @click="handleGlobalCheckAllChange">全选</div>
+        </div>
     </div>
     <!-- 新增客户、编辑客户 -->
     <edit-client-popup ref="editClientRef"></edit-client-popup>
 </template>
 
 <script setup>
-import { ref, reactive, onMounted } from "vue";
+import { ref, reactive, onMounted, watch } from "vue";
 import { Collapse, CollapseItem, Checkbox, Popup } from "vant";
-import { deepClone } from "@/common/commonFun";
 import EditClientPopup from "@/components/editClientPopup.vue";
 import { useRouter } from "vue-router";
 const router = useRouter();
+const props = defineProps({
+    // 是否显示选择客户
+    checkDistributeShow: {
+        type: Boolean,
+        default: false,
+    },
+    // 是否开始重新加载列表
+    startReloadList: {
+        type: Boolean,
+        default: false,
+    },
+});
 
 // const curIndex = ref(0)
 const handlePerson = (type, data) => {
-    editClientRef.value.openClientPopup(type, data)
+    editClientRef.value.openClientPopup(type, data);
 };
 
 const editClientRef = ref(null);
 
-const defalutList = ref([]);
+const activeNames = ref([0]);
+const groupList = ref([]);
 
+const toSelectClient = ref(false);
 function toCustomPage() {
-    router.push("/layout/customTree");
+    toSelectClient.value = true;
+    // toSelectClient.value = !toSelectClient.value;
+    // eventBus.emit("startBoxSelect", toSelectClient.value);
+    emit("update:checkDistributeShow", toSelectClient.value);
+    // router.push("/layout/customTree");
 }
 
+const handleGlobalCheckAllChange = (val) => {
+    if (val) {
+        // 全选所有项目
+        checkedCities.value = groupList.value.flatMap((group) => group.list.map((item) => item.tel));
+    } else {
+        // 清空所有选择
+        checkedCities.value = [];
+    }
+
+    // 更新所有分组的状态
+    groupList.value.forEach((_, index) => {
+        updateGroupCheckStatus(index);
+    });
+};
+
 function toCustomOneTree(data) {
     router.push("/layout/customTree?type=single&data=" + JSON.stringify(data));
 }
 
 onMounted(() => {
-    getUserList()
-})
+    getUserList();
+});
 
 function getUserList() {
-    VE_API.manage_interface.offlineTakeList({farmId: 766}).then(({data}) => {
-        defalutList.value = data
-    })
+    VE_API.manage_interface.fetchGroupList({ farmId: 766 }).then(({ data }) => {
+        // defalutList.value = data
+        groupList.value = Object.keys(data).map((key) => {
+            return {
+                name: key,
+                list: data[key],
+            };
+        });
+        initGroupCheckStates(); // 初始化分组选择状态
+    });
 }
+
+const checkedCities = ref([]);
+
+// 使用一个对象来存储每个分组的全选状态
+const groupCheckStates = ref({});
+
+// 初始化分组选择状态
+const initGroupCheckStates = () => {
+    groupList.value.forEach((group, index) => {
+        groupCheckStates.value[index] = {
+            checkAll: false,
+            isIndeterminate: false,
+        };
+    });
+};
+
+// 修改后的全选处理方法
+const handleCheckAllChange = (val, groupIndex) => {
+    const currentGroup = groupList.value[groupIndex];
+    if (val) {
+        // 添加当前分组的所有项到选中列表
+        currentGroup.list.forEach((item) => {
+            if (!checkedCities.value.includes(item.tel)) {
+                checkedCities.value.push(item.tel);
+            }
+        });
+    } else {
+        // 移除当前分组的所有项
+        checkedCities.value = checkedCities.value.filter(
+            (name) => !currentGroup.list.some((item) => item.tel === name)
+        );
+    }
+    updateGroupCheckStatus(groupIndex);
+};
+// 更新分组的选择状态
+const updateGroupCheckStatus = (groupIndex) => {
+    const currentGroup = groupList.value[groupIndex];
+    const checkedCount = currentGroup.list.filter((item) => checkedCities.value.includes(item.tel)).length;
+
+    groupCheckStates.value[groupIndex].checkAll = checkedCount === currentGroup.list.length;
+    groupCheckStates.value[groupIndex].isIndeterminate = checkedCount > 0 && checkedCount < currentGroup.list.length;
+    console.log('groupList.value', checkedCities.value);
+
+    emit("update:checkData", checkedCities.value);
+};
+
+// 修改 handleCheckedCitiesChange 方法
+const handleCheckedCitiesChange = (value) => {
+    // 遍历所有分组,更新每个分组的选中状态
+    groupList.value.forEach((group, groupIndex) => {
+        updateGroupCheckStatus(groupIndex);
+    });
+};
+
+function handleRightClick() {
+    // 点击事件处理
+}
+
+watch(
+    () => props.checkDistributeShow,
+    (newVal) => {
+        if (newVal === false) {
+            toSelectClient.value = false; // 如果显示选择客户,则切换到选择客户模式
+            // 清空所有选择
+            checkedCities.value = [];
+            initGroupCheckStates(); // 初始化分组选择状态
+        }
+    }
+);
+
+watch(
+    () => props.startReloadList,
+    (newVal) => {
+        if (newVal) {
+            getUserList(); // 重新加载用户列表
+        }
+    }
+);
+
+const emit = defineEmits(["update:checkDistributeShow", "update:checkData"]);
 </script>
 
 <style lang="scss" scoped>
@@ -106,8 +286,10 @@ function getUserList() {
     }
     .list-content {
         width: 100%;
-        height: 100%;
+        height: calc(100% - 56px);
         overflow: auto;
+        padding: 0 8px;
+        box-sizing: border-box;
         &.max-height {
             height: calc(100% - 50px - 55px);
         }
@@ -116,6 +298,17 @@ function getUserList() {
             cursor: pointer;
         }
         ::v-deep {
+            .el-collapse-item__arrow {
+                display: none;
+            }
+            .el-collapse-item__header .is-active {
+                .arrow-icon {
+                    transform: rotate(90deg);
+                }
+            }
+            .el-collapse {
+                border-color: transparent;
+            }
             .van-cell:after,
             .van-collapse-item--border:after,
             .van-hairline--top-bottom:after {
@@ -164,6 +357,38 @@ function getUserList() {
                 color: #000;
             }
         }
+        .title-wrapper {
+            width: 100%;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            .arrow-icon {
+                transition: transform 0.3s ease;
+            }
+            &.is-active {
+                .arrow-icon {
+                    transform: rotate(90deg);
+                }
+            }
+            .title-r {
+                color: #2199f8;
+                font-size: 14px;
+                display: flex;
+                align-items: center;
+                .title-manage {
+                    margin-right: 10px;
+                }
+                ::v-deep {
+                    .el-checkbox {
+                        color: #2199f8;
+                    }
+                }
+            }
+        }
+        .group-length {
+            color: rgba(0, 0, 0, 0.4);
+            font-size: 12px;
+        }
         .list-item {
             border-radius: 6px;
             position: relative;
@@ -185,12 +410,12 @@ function getUserList() {
                 justify-content: space-between;
                 width: 100%;
                 .blue-btn {
-                  cursor: pointer;
-                  color: #FFFFFF;
-                  font-size: 12px;
-                  padding: 5px 15px;
-                  border-radius: 20px;
-                  background: #2199F8;
+                    cursor: pointer;
+                    color: #ffffff;
+                    font-size: 12px;
+                    padding: 5px 15px;
+                    border-radius: 20px;
+                    background: #2199f8;
                 }
             }
             .photo {
@@ -218,7 +443,7 @@ function getUserList() {
                     }
                 }
                 .item-title {
-                  color: #666666;
+                    color: #666666;
                 }
             }
         }
@@ -226,23 +451,46 @@ function getUserList() {
             margin-top: 12px;
         }
     }
-    
+
     .center-btn {
         position: absolute;
-        bottom: 64px;
+        bottom: 9px;
         left: 50%;
         transform: translateX(-50%);
-        color: #FFFFFF;
+        color: #ffffff;
         border-radius: 20px;
         font-size: 14px;
         padding: 7px 10px;
         cursor: pointer;
         border: 1px solid #fff;
-        background: linear-gradient(180deg, #84C9FF, #2199F8);
+        background: linear-gradient(180deg, #84c9ff, #2199f8);
         width: 194px;
         box-sizing: border-box;
         text-align: center;
     }
+    .global-wrap {
+        width: 100%;
+        padding-top: 17px;
+        box-shadow: 4px 0 4px rgba(0, 0, 0, 0.2);
+        padding-top: 12px;
+        box-shadow: 4px 0 4px rgba(0, 0, 0, 0.2);
+        text-align: center;
+        margin: 0 auto;
+        padding-bottom: 11px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        .global-btn {
+            height: 38px;
+            width: 168px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            background: #2199f8;
+            color: #fff;
+            border-radius: 4px;
+        }
+    }
     .list-footer {
         position: absolute;
         bottom: 0;

+ 339 - 0
src/views/home/components/leftTabs/editRecord.vue

@@ -0,0 +1,339 @@
+<!--
+ * @Author: your name
+ * @Date: 2021-02-09 15:24:23
+ * @LastEditTime: 2022-04-28 19:04:23
+ * @LastEditors: Please set LastEditors
+ * @Description: In User Settings Edit
+ * @FilePath: \vue3-element-admin\src\views\layoutpages\system\components\usersEdit.vue
+-->
+<template>
+    <el-dialog
+            width="50%"
+            :title="title"
+            append-to-body
+            destroy-on-close
+            :model-value="showDialog"
+            @close="closeDialog()"
+    >
+        <el-form
+                :model="form"
+                ref="formRef"
+                :rules="rules"
+                label-width="200px"
+                :inline="false"
+        >
+                <el-form-item label="农场id" prop="farmId">
+                    <el-select
+                        filterable
+                        style="width: 100%"
+                        v-model="farmId"
+                        placeholder=""
+                        clearable
+                    >
+                      <el-option
+                          v-for="item in organList"
+                          :key="item.id"
+                          :label="item.name"
+                          :value="item.id"
+                      ></el-option>
+                    </el-select>
+                </el-form-item>
+                <el-form-item label="农事卡片id" prop="farmWorkLibId">
+                    <el-select
+                        filterable
+                        style="width: 100%"
+                        v-model="farmWorkLibId"
+                        placeholder=""
+                        clearable
+                    >
+                      <el-option
+                          v-for="item in farmWorkLibList"
+                          :key="item.id"
+                          :label="item.name + '(' +item.periodName+ ')'"
+                          :value="item.id"
+                      ></el-option>
+                    </el-select>
+                </el-form-item>
+<!--                <el-form-item label="分数" prop="score">-->
+<!--                    <el-input v-model="score" placeholder="请输入分数" clearable></el-input>-->
+<!--                </el-form-item>-->
+                <el-form-item label="处方缩写" prop="shortName">
+                  <el-input v-model="shortName" placeholder="请输入缩写" clearable></el-input>
+                </el-form-item>
+                <el-form-item label="药品安全性标准" prop="standard">
+                    <el-select v-model="standard" placeholder="请选择药品安全性标准">
+                        <el-option value="常规防治">常规防治</el-option>
+                        <el-option value="常规调控">常规调控</el-option>
+                        <el-option value="生态防治">生态防治</el-option>
+                        <el-option value="生态调控">生态调控</el-option>
+                        <el-option value="有机肥营养">有机肥营养</el-option>
+                        <el-option value="复合肥营养">复合肥营养</el-option>
+                        <el-option value="叶面肥营养">叶面肥营养</el-option>
+                    </el-select>
+                </el-form-item>
+                <el-form-item label="执行日期" prop="executeDate">
+                    <el-date-picker v-model="executeDate"                 format="YYYY-MM-DD"
+                                    value-format="YYYY-MM-DD" type="date" placeholder="选择日期" clearable></el-date-picker>
+                </el-form-item>
+          <el-form-item label="生态理念" prop="shortName">
+            <el-input v-model="stln" placeholder="生态理念" clearable></el-input>
+          </el-form-item>
+          <el-form-item label="物候进程" prop="whjc">
+            <el-input v-model="whjc" placeholder="物候进程" clearable></el-input>
+          </el-form-item>
+          <el-form-item label="农事目标" prop="targetText">
+            <el-input v-model="targetText" placeholder="农事目标" clearable></el-input>
+          </el-form-item>
+                <el-form-item label="农事图片" >
+                  <el-button class="el-button el-button--primary" @click="addImg">添加图片</el-button>
+                  <template v-for="(item,index) in images" :key="index">
+                    <el-input v-model="images[index]" placeholder="农事图片" clearable></el-input>
+                    <UploadMedia :fullPath="true"   @uploadSuccess="onSuccess" @handleRemove="onRemove"
+                                 :filename="'images_'+index+'/'+new Date().getTime()"
+                                 :name="'images_'+index" :url="item"></UploadMedia>
+                    <el-button type="danger" @click="images.splice(index, 1)">删除</el-button>
+                  </template>
+                </el-form-item>
+<!--                <el-form-item label="审核状态" prop="status">-->
+<!--                    <el-select v-model="status" placeholder="请选择审核状态">-->
+<!--                        <el-option label="通过" :value="1"></el-option>-->
+<!--                        <el-option label="未通过" :value="2"></el-option>-->
+<!--                    </el-select>-->
+<!--                </el-form-item>-->
+<!--                <el-form-item label="处方信息json" prop="prescription">-->
+<!--                  <json-editor-vue language="zh-CN" currentMode="tree"  style="width: 100%;height: 300px" v-model="rowData.prescriptionObj"  />-->
+<!--                </el-form-item>-->
+        </el-form>
+
+        <template v-slot:footer>
+            <span>
+                <el-button @click="closeDialog()">取消</el-button>
+                <el-button type="primary" @click="onSubmit()">确定</el-button>
+            </span>
+        </template>
+    </el-dialog>
+</template>
+
+<script setup>
+    import { onMounted, reactive, ref, toRefs } from "vue";
+    import UploadMedia from "@/components/common/UploadMedia";
+    const props = defineProps({
+        showDialog: {
+            type: Boolean,
+            default: true,
+        },
+        title: {
+            type: String,
+            default: "添加",
+        },
+        rowData: {
+            type: Object,
+            default: null,
+        },
+    });
+    const emit = defineEmits(["closeDialog"]);
+    const periodList = ref(null)
+
+    const { title, rowData, showDialog } = toRefs(props);
+    const closeDialog = () => {
+        emit("closeDialog", false);
+    };
+
+    let form = reactive({
+        farmId:"",
+        farmWorkLibId:"",
+        shortName:"",
+        score:"",
+        standard:"",
+        evidenceImgs:"",
+        status:"",
+        executeDate:"",
+        stln:"",
+        whjc:"",
+        targetText:"",
+        images:[]
+    });
+    let { farmId,farmWorkLibId,shortName,score,standard,evidenceImgs,status,executeDate,stln,whjc,targetText,images} = toRefs(form);
+
+    /**
+     * @description:初始化赋值
+     * @param {*}
+     * @return {*}
+     */
+    if(rowData.value && rowData.value.authId){
+        farmId.value = rowData.value.farmId
+        farmWorkLibId.value = rowData.value.farmWorkLibId
+        score.value = rowData.value.score
+        shortName.value = rowData.value.shortName
+        standard.value = rowData.value.standard
+        evidenceImgs.value = rowData.value.evidenceImgs
+        status.value = rowData.value.status
+        executeDate.value = rowData.value.executeDate
+        images.value = rowData.value.images
+        stln.value = rowData.value.stln
+        whjc.value = rowData.value.whjc
+        targetText.value = rowData.value.targetText
+
+    }else{
+        farmId.value = rowData.value.farmId
+    }
+
+    const formRef = ref(null);
+
+
+
+    const rules = {
+        farmId: [
+            {
+                required: true,
+                message: "请输入",
+                trigger: "blur",
+            },
+        ],
+        farmWorkLibId: [
+            {
+                required: true,
+                message: "请输入",
+                trigger: "blur",
+            },
+        ],
+        score: [
+            {
+                required: true,
+                message: "请输入",
+                trigger: "blur",
+            },
+        ],
+        shortName: [
+            {
+                required: true,
+                message: "请输入",
+                trigger: "blur",
+            },
+        ],
+        standard: [
+            {
+                required: true,
+                message: "请输入",
+                trigger: "blur",
+            },
+        ],
+        status: [
+            {
+                required: true,
+                message: "请输入",
+                trigger: "blur",
+            },
+        ],
+        evidenceImgs: [
+            {
+                required: true,
+                message: "请输入",
+                trigger: "blur",
+            },
+        ],
+        executeDate: [
+            {
+                required: true,
+                message: "请输入",
+                trigger: "blur",
+            },
+        ],
+    };
+
+    /**
+     * @description:提交
+     * @param {*}
+     * @return {*}
+     */
+    const onSubmit = () => {
+        formRef.value.validate(async (valid) => {
+            if (valid) {
+                if (title.value != "添加") {
+                    form.id = rowData.value.authId
+                }
+                if(form.images && form.images.length > 0){
+                  form.imgs = JSON.stringify(images.value)
+                }
+                let res = await VE_API.farm.saveFarmWork(form);
+                if(res.code == 0){
+                    closeDialog();
+                }
+            } else {
+                console.log("error submit!!");
+                return false;
+            }
+        });
+    };
+    const organList = ref(null);
+    const farmWorkLibList = ref(null);
+    /**
+     * 获取果园列表
+     * @returns {Promise<void>}
+     */
+    const getOrganList = async () => {
+      const {code, data} = await VE_API.system.organList();
+      if (code === 0) {
+        organList.value = data;
+      }
+    };
+    getOrganList();
+
+    /**
+     * 获取农事卡片
+     * @returns {Promise<void>}
+     */
+    const getFarmWorkLibList = async () => {
+      const {code, data} = await VE_API.farm.fetchFarmWorkList({page: 1, limit: 100,userId:81881,speciesId:1});
+      if (code === 0) {
+        farmWorkLibList.value = data;
+      }
+    };
+    getFarmWorkLibList();
+
+
+    function onSuccess(urls, name) {
+      if (name == "images_0") {
+        images.value[0] = urls; // 设置到第一位
+      } else if (name == "images_1") {
+        images.value[1] = urls; // 设置到第二位
+      } else if (name == "images_2") {
+        images.value[2] = urls; // 设置到第三位
+      }
+    }
+    function onRemove(name) {
+      if(name == "images_0") {
+        images.value.splice(0, 1); // 删除第一位
+      }
+      if(name == "images_1") {
+        images.value.splice(1, 1); // 删除第二位
+      }
+      if(name == "images_2") {
+        images.value.splice(2, 1); // 删除第三位
+      }
+      if(images.value.length == 0){
+        images.value.push("")
+      }
+    }
+    function addImg(){
+      images.value.push("")
+    }
+
+
+</script>
+
+<style lang="scss">
+    body {
+    .ve_role_item {
+    .el-form-item__content {
+        display: block !important;
+    }
+    }
+    }
+    .fl {
+        float: left;
+    }
+    .p0 {
+        padding: 0 !important;
+    }
+</style>

+ 52 - 30
src/views/home/components/leftTabs/imgManage.vue

@@ -11,8 +11,8 @@
                 value-format="YYYY-MM-DD"
                 :style="{ width: '100%' }"
             />
-            <el-select class="select" v-model="value" size="large">
-                <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
+            <el-select class="select" @change="changeArea" v-model="areaValue" size="large">
+                <el-option v-for="(item, index) in areaOptions" :key="index" :label="item.name" :value="item.id" />
             </el-select>
         </div>
         <!-- <div class="fly-box">
@@ -26,7 +26,7 @@
             </div>
         </div> -->
         <div class="photo-list">
-            <div class="photo-item" v-for="(item, index) in imageList" :key="index">
+            <div class="photo-item" v-for="(item, index) in imageList" :class="{'m-l-10': index % 2 !== 0}" :key="index">
                 <album-carousel-item
                     lbum-carousel-item
                     :key="index"
@@ -36,6 +36,18 @@
                     :lock="false"
                 ></album-carousel-item>
             </div>
+            <div class="no-photo" v-show="!imageList.length">暂无数据</div>
+        </div>
+        <div class="pagination-wrap">
+            <el-pagination
+                background
+                :page-size="pageSize"
+                :pagerCount="5"
+                v-model:current-page="currentPage"
+                @current-change="geImgaeList"
+                layout="prev, pager, next"
+                :total="totalVal"
+            />
         </div>
     </div>
 </template>
@@ -56,42 +68,37 @@ const dateTime = ref(getCurrentMonth());
 const changeDate = () => {
     geImgaeList();
 };
-const value = ref("Option1");
+const areaValue = ref(2); // 默认区域ID
 
-const options = [
-    {
-        value: "Option1",
-        label: "全部区",
-    },
-    {
-        value: "Option2",
-        label: "Option2",
-    },
-    {
-        value: "Option3",
-        label: "Option3",
-    },
-    {
-        value: "Option4",
-        label: "Option4",
-    },
-    {
-        value: "Option5",
-        label: "Option5",
-    },
-];
+const areaOptions = ref([]);
+const currentPage = ref(1);
+const pageSize = ref(20); // 每页显示20条数据
+const totalVal = ref(0);
 
 const imageList = ref([]);
 const geImgaeList = () => {
-    VE_API.manage_interface.fetchGardenImgs({ organId: 766, areaId: 2, limit: 10, page: 10 }).then((res) => {
+    VE_API.manage_interface.fetchGardenImgs({ date: dateTime.value, organId: 766, areaId: areaValue.value, limit: pageSize.value, page: currentPage.value }).then((res) => {
         imageList.value = res.data;
+        totalVal.value = res.count;
     });
 };
 
+function changeArea() {
+    currentPage.value = 1; // 重置页码
+    geImgaeList();
+}
+
 onMounted(() => {
     geImgaeList();
+    getBlueRegionList()
 });
 
+function getBlueRegionList() {
+    VE_API.manage_interface.fetchRegionList({ farmId: 766 }).then(({ data }) => {
+        areaOptions.value = data;
+    });
+}
+
 // 提取前6位并转换为日期格式
 function formatDatePart(originalStr) {
     // 提取前6位数字
@@ -183,9 +190,10 @@ function formatDatePart(originalStr) {
         flex-wrap: wrap;
         overflow: auto;
         width: 100%;
-        height: calc(100% - 60px);
+        height: calc(100% - 60px - 42px);
         .photo-item {
             width: calc(50% - 5px);
+            margin-bottom: 10px;
             .img {
                 width: 100%;
                 height: 100%;
@@ -201,9 +209,23 @@ function formatDatePart(originalStr) {
                 }
             }
         }
-        .photo-item:nth-last-child(2n+1) {
+        .m-l-10 {
             margin-left: 10px;
-            margin-bottom: 10px;
+        }
+        .no-photo {
+            color: #000;
+            width: 100%;
+            text-align: center;
+            padding-top: 20px;
+        }
+    }
+
+    .pagination-wrap {
+        padding-top: 10px;
+        ::v-deep {
+            .el-pagination {
+                justify-content: center;
+            }
         }
     }
 }

+ 36 - 6
src/views/home/components/leftTabs/recordsManage.vue

@@ -35,7 +35,7 @@
                                 <div class="card-title serve-title">
                                     <div class="title-name">
                                         <span>{{ card.farmWorkLibName }}</span>
-                                        <div class="edit-btn" @click="handleEdit">
+                                        <div class="edit-btn" @click="handleEdit('编辑农事', card)">
                                             <el-icon><Edit /></el-icon>
                                             <span>编辑</span>
                                         </div>
@@ -78,8 +78,16 @@
             </div>
         </div>
     </div>
+    
+    <editRecord
+        v-if="showDialog"
+        :rowData="rowData"
+        :title="dialogTitle"
+        :showDialog="showDialog"
+        @closeDialog="handelDialog($event)"
+></editRecord>
     <!-- 编辑弹窗 -->
-    <el-dialog v-model="dialogVisible" title="编辑农事" align-center width="50%" :before-close="handleClose">
+    <!-- <el-dialog v-model="dialogVisible" title="编辑农事" align-center width="50%" :before-close="handleClose">
         <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="90px">
             <el-form-item label="农场名称" prop="name">
                 <el-input v-model="ruleForm.name" disabled />
@@ -111,7 +119,7 @@
                 <el-button type="primary" @click="submitForm(ruleFormRef)"> 确认修改 </el-button>
             </div>
         </template>
-    </el-dialog>
+    </el-dialog> -->
 </template>
 
 <script setup>
@@ -120,6 +128,7 @@ import imgSwipe from "./imgSwipe.vue";
 import { useRoute } from "vue-router";
 import upload from "@/components/common/upload.vue";
 import eventBus from "@/api/eventBus";
+import editRecord from "./editRecord.vue";
 
 const disabledDate = (time) => {
     return time.getTime() > Date.now();
@@ -161,9 +170,30 @@ const rules = reactive({
 });
 
 const dialogVisible = ref(false);
-const handleEdit = () => {
-    dialogVisible.value = true;
-};
+
+    const showDialog = ref(false);
+    const rowData = ref(null);
+    const dialogTitle = ref("");
+
+    /**
+     * @description:添加or编辑事件
+     * @param {*}
+     * @return {*}
+     */
+    const handleEdit = (title, row = null) => {
+        console.log('row', row);
+        showDialog.value = true;
+        dialogTitle.value = title;
+        rowData.value = row;
+        if (!row) {
+          rowData.value = {farmId:row.farmId};
+        }
+    };
+    
+    const handelDialog = (e) => {
+        showDialog.value = false
+        getData();
+    };
 const handleClose = () => {
     resetForm(ruleFormRef.value);
 };

+ 56 - 4
src/views/home/homeMap.vue

@@ -133,6 +133,23 @@ const enableBoxSelect = () => {
     dragBox.on("boxend", handleBoxEnd);
 };
 
+// 启用框选--分配果树
+const enableDistributeBoxSelect = () => {
+    const data = mapPoint.value.filter(item => item.isRenyang === 1 && !item.miniUserId);
+    updateClusterData(data, 1);
+    isDrawing.value = true;
+    
+    dragBox = new DragBox({
+        condition: platformModifierKeyOnly,
+    });
+
+    window.addEventListener("keydown", handleKeyDown);
+    window.addEventListener("keyup", handleKeyUp);
+
+    kmap.map.addInteraction(dragBox);
+    dragBox.on("boxend", handleBoxEnd);
+};
+
 const handleKeyDown = (e) => {
     if (e.ctrlKey) {
         areaRef.value.style.cursor = "crosshair";
@@ -151,9 +168,9 @@ const handleBoxEnd = () => {
         // 只对当前框选范围内且未被认养的树进行操作
         if (feature.getGeometry().intersectsExtent(extent)) {
             // 累加选中状态(不会取消之前选中的)
-            if (!feature.get("isRenyang")) {
-                feature.set("highlight", true);
-            }
+            feature.set("highlight", true);
+            // if (!feature.get("isRenyang")) {
+            // }
         }
     });
     refreshClusterStyle();
@@ -188,6 +205,26 @@ const saveSelect = (callback) => {
     });
 };
 
+// 保存选择--分配果树
+const saveDistributeSelect = (callback) => {
+    const sampleIds = [];
+    treeClusterLayer.layer.getSource().getSource().getFeatures().forEach(feature => {
+        if (feature.get("highlight")) {
+            sampleIds.push(feature.get("sampleId"));
+        }
+    });
+    
+    const params = {
+        sampleIds,
+        isRenyang: 1,
+        farmId: Number(sessionStorage.getItem("currentFarmId"))
+    };
+    
+    // VE_API.manage_interface.batchOpenOrCloseSample(params).then(() => {// 保存成功后刷新数据
+    //     callback?.();
+    // });
+};
+
 // 更新集群数据而不重新渲染整个图层
 const updateClusterData = (treeListData, distanceVal = 20) => {
     if (!treeListData || !Array.isArray(treeListData)) {
@@ -320,6 +357,17 @@ const refreshClusterStyle = () => {
     if (treeClusterLayer) {
         treeClusterLayer.layer.getSource().refresh();
     }
+    console.log('geteget');
+    if (isDrawing.value) {
+        const sampleIds = [];
+        treeClusterLayer.layer.getSource().getSource().getFeatures().forEach(feature => {
+            if (feature.get("highlight")) {
+                sampleIds.push(feature.get("sampleId"));
+            }
+        });
+        // 数据处理
+        emit("update:selectedTree", sampleIds);
+    }
 };
 
 // 设置地图点击处理
@@ -404,13 +452,17 @@ const initAreaMap = (arr) => {
 
 defineExpose({ 
     addCluster: updateClusterData, 
-    enableBoxSelect, 
+    enableBoxSelect,
+    enableDistributeBoxSelect,
     stopBoxSelect, 
     initAreaMap, 
     resetCurrentTree, 
     saveSelect,
+    saveDistributeSelect,
     refreshClusterStyle // 暴露刷新方法
 });
+
+const emit = defineEmits(["update:selectedTree"]);
 </script>
 
 <style lang="less" scoped>

+ 82 - 21
src/views/home/index.vue

@@ -14,7 +14,12 @@
                                 <adopt-list></adopt-list>
                             </el-tab-pane>
                             <el-tab-pane label="待分配" name="待分配">
-                                <client-list></client-list>
+                                <client-list
+                                    :checkDistributeShow="checkDistributeShow"
+                                    :startReloadList="startReloadList"
+                                    @update:checkDistributeShow="hanldeDistributeCheck"
+                                    @update:checkData="handlCheckChange"
+                                    ></client-list>
                             </el-tab-pane>
                             <el-tab-pane label="已分配" name="已分配">
                                 <apply-list></apply-list>
@@ -35,14 +40,10 @@
                 </div>
             </div>
             <div v-else class="map-bg map-legend yes-events">
-                <div class="item" v-if="ROLE == 1">
+                <div class="item" v-show="!checkDistributeShow">
                     <img src="@/assets/images/map/status/wry.png" alt="" />
                     未开放
                 </div>
-                <div class="item" v-if="ROLE == 2">
-                    <img src="@/assets/images/map/status/other.png" alt="" />
-                    其他树
-                </div>
                 <div class="item" v-show="!checkShow">
                     <img src="@/assets/images/map/status/dry.png" alt="" />
                     待守护
@@ -51,7 +52,7 @@
                     <img src="@/assets/images/map/status/yry.png" alt="" />
                     已守护
                 </div> -->
-                <div class="item selected-item" v-show="checkShow">
+                <div class="item selected-item" v-show="checkShow || checkDistributeShow">
                     <img src="@/assets/images/map/status/selected.png" alt="" />
                     已选择
                 </div>
@@ -59,20 +60,33 @@
 
             <div class="tips" v-show="checkShow">
                 <div class="text">
-                    <span>提示:</span>请在底图上点选 <span>可守护的果树</span>,或按住 Ctrl 框选 <span>守护的区域</span>
+                    <span>提示:</span>请在底图上点选 <span>未开放的果树</span>,或按住 Ctrl 框选
+                    <span>开放守护的区域</span>
+                </div>
+            </div>
+            <div class="tips" v-show="checkDistributeShow">
+                <div class="text">
+                    <span>提示:</span>请在底图上点选 <span>待守护的果树</span>,或按住 Ctrl 框选
+                    <span>分配的区域</span>
                 </div>
             </div>
 
-            <div v-show="!checkShow && ROLE == 1" class="right-button yes-events" @click="hanldeCheck">
+            <div v-show="!checkShow && !checkDistributeShow" class="right-button yes-events" @click="hanldeCheck">
                 新增守护区域
             </div>
             <div v-show="checkShow" class="center-button">
                 <div class="cancel yes-events" @click="handleCancel">取消</div>
                 <div class="yes-events" @click="saveEdit">确认开放守护权限</div>
             </div>
+            <div v-show="checkDistributeShow" class="center-button">
+                <div class="cancel yes-events" @click="handleCancel">取消分配</div>
+                <div class="yes-events" @click="saveDistributeEdit" :class="{'disabled': !selectedTree.length || !selectedTels.length}">
+                    确认分配<span class="select-text">(已选{{selectedTree.length}}/<span class="select-total">{{ selectedTels.length }}</span>)</span>
+                </div>
+            </div>
         </div>
     </div>
-    <custom-map class="bottom-map" ref="mapRef"></custom-map>
+    <custom-map class="bottom-map" ref="mapRef" @update:selectedTree="handleSelectedTree"></custom-map>
 
     <!-- 图片弹窗 -->
     <PicturePreview :imageUrl="urls" :curIndex="urlsIndex"></PicturePreview>
@@ -98,6 +112,7 @@ import { useRouter } from "vue-router";
 import { useStore } from "vuex";
 import eventBus from "@/api/eventBus";
 import PdfDialog from "../../components/PdfDialog";
+import { ElMessage } from "element-plus";
 let store = useStore();
 const components = {
     leftTabs,
@@ -108,17 +123,11 @@ const router = useRouter();
 const mapRef = ref(null);
 
 const activeName = ref("果树列表");
-// 用户角色
-store.commit("home/SET_USER_ROLE", 1);
 
-let ROLE = ref(null);
 onMounted(() => {
-    
     //区域切换监听事件
     eventBus.on("area:id", areaId);
-    ROLE.value = store.state.home.userRole;
-    // 柏桥村
-    sessionStorage.setItem("currentFarmId", 766)
+    sessionStorage.setItem("currentFarmId", 766);
     areaId({ areaId: 0, farmId: 766 });
 
     // 修改单棵树信息后刷新地图数据
@@ -135,7 +144,6 @@ onUnmounted(() => {
     eventBus.off("clickMapPoint", toggleLeftComponet);
 });
 
-
 const getPointList = () => {
     VE_API.manage_interface.fetchSampleList({ farmId: organId.value }).then(({ data }) => {
         if (mapRef.value) {
@@ -162,18 +170,60 @@ const hanldeCheck = () => {
     mapRef.value.enableBoxSelect();
 };
 
+// 分配果树
+const checkDistributeShow = ref(false); 
+const startReloadList = ref(false); 
+const hanldeDistributeCheck = () => {
+    checkDistributeShow.value = true;
+    mapRef.value.enableDistributeBoxSelect();
+};
+
+// 分配果树勾选值变化事件
+const selectedTels = ref([]);
+const handlCheckChange = (val) => {
+    selectedTels.value = val;
+};
+
+// 地图--选树时抛出的事件
+const selectedTree = ref([]);
+const handleSelectedTree = (data) => {
+    selectedTree.value = data;
+}
+
 const handleCancel = () => {
     checkShow.value = false;
+    checkDistributeShow.value = false;
     // mapRef.value.clearSelection()
     mapRef.value.stopBoxSelect();
 };
 
 const saveEdit = () => {
     mapRef.value.saveSelect(() => {
-        getPointList()
+        getPointList();
     });
     checkShow.value = false;
-}
+    checkDistributeShow.value = false;
+};
+
+const saveDistributeEdit = () => {
+    // mapRef.value.saveDistributeSelect(() => {
+    //     getPointList();
+    // });
+    const params = {
+        farmId: 766,
+        sampleIds: selectedTree.value,
+        tels: selectedTels.value,
+    };
+    console.log('params', params);
+    VE_API.manage_interface.saveTreeUser(params).then(({code}) => {
+        if (code === 0) {
+            ElMessage.success("分配成功");
+            startReloadList.value = true; // 触发重新加载列表
+            handleCancel()
+            return;
+        }
+    })
+};
 
 // 图例
 const legendArr = ref([]);
@@ -234,7 +284,7 @@ function backHome() {
     position: absolute;
     box-sizing: border-box;
     z-index: 1;
-    color: #FFFFFF;
+    color: #ffffff;
 
     .content {
         width: 100%;
@@ -436,6 +486,17 @@ function backHome() {
                 margin-right: 20px;
                 background: #eeeeee;
             }
+            .disabled {
+                opacity: 0.6;
+                cursor: not-allowed;
+            }
+        }
+        .select-text {
+            padding-left: 4px;
+            font-size: 16px;
+            .select-total {
+                color: rgba(29, 29, 29, 0.5);
+            }
         }
         .map-btn {
             top: 19px;

+ 108 - 74
src/views/user/index.vue

@@ -15,8 +15,22 @@
                     placeholder="搜索用户/手机号"
                     :prefix-icon="Search"
                     />
-                <el-button class="ml-10" size="large" type="primary">上传订单</el-button>
-                <el-button size="large" type="primary" plain>新建分组</el-button>
+                <el-button class="ml-10" size="large" type="primary" plain @click="downloadTemplate">下载模板</el-button>
+                <!-- <el-button size="large" type="primary" @click="uploadData">上传订单</el-button> -->
+                <el-upload
+                    v-model:file-list="fileList"
+                    class="upload-demo"
+                    :action="config.base_url + 'adm/import_lighten_card_offline'"
+                    multiple
+                    :data="{farmId: 766}"
+                    :headers="uploadHeaders"
+                    :on-success="handleUploadMsg"
+                    :on-error="handleUploadMsg"
+                    :limit="1"
+                    >
+                    <el-button class="ml-10" size="large" type="primary">上传订单</el-button>
+                </el-upload>
+                <el-button class="ml-10" size="large" type="primary" plain>新建分组</el-button>
                 <el-button size="large" type="primary" plain>批量发送</el-button>
             </div>
         </div>
@@ -72,10 +86,10 @@
             </div>
         </div>
         <div class="table-wrap">
-            <el-table :data="tableData" style="width: 100%" @selection-change="handleTableSelect" height="600px">
+            <el-table :data="tableData" style="width: 100%" @selection-change="handleTableSelect" height="100%">
                 <el-table-column type="selection" width="55" />
-                <el-table-column property="code" label="用户编码" width="120" />
-                <el-table-column property="name" label="用户昵称" width="120">
+                <el-table-column property="miniUserId" label="用户编码" width="120" />
+                <el-table-column property="name" label="用户昵称">
                     <template #default="scope">
                         <div class="user-info">
                             <!-- <el-avatar :size="24" src="https://birdseye-img-ali-cdn.sysuimars.com/birdseye-look-mini/91754/1750583672619.png" /> -->
@@ -91,31 +105,43 @@
                     width="240"
                     show-overflow-tooltip
                 />
-                <el-table-column property="count" label="订单量" />
                 <el-table-column label="守护等级">
                     <template #default="scope">
-                        <span :class="['level-tag', 'level-'+scope.row.level]">{{ levelObj[scope.row.level] }}</span>
+                        <span :class="['level-tag', 'level-'+scope.row.level?.id]">{{ levelObj[scope.row.level?.id] }}</span>
                     </template>
                 </el-table-column>
                 <el-table-column property="fosterCode" label="守护树编号" />
                 <el-table-column label="状态">
                     <template #default="scope">
-                        <span :class="['status-text', 'status-'+scope.row.status]">{{ statusObj[scope.row.status] }}</span>
+                        <span :class="['status-text']">{{ scope.row.fosterStatus }}</span>
                     </template>
                 </el-table-column>
                 <el-table-column label="日期" sortable>
                     <template #default="scope">{{ scope.row.fosterDate }}</template>
                 </el-table-column>
-                <el-table-column label="操作" width="260">
+                <el-table-column label="操作" width="310">
                     <template #default="scope">
                         <div class="action-btn">
                             <el-button type="primary" @click="handleMsg(scope.row)"><el-icon class="el-icon--right"><Comment /></el-icon>发消息</el-button>
                             <el-button type="primary" @click="handleMsg(scope.row)"><el-icon><Briefcase /></el-icon>发礼物</el-button>
+                            <el-button type="danger" @click="deleteUser(scope.row)"><el-icon><Delete /></el-icon>删除</el-button>
                         </div>
                     </template>
                 </el-table-column>
             </el-table>
         </div>
+        
+        <div class="pagination-wrap">
+            <el-pagination
+                v-model:current-page="currentPage"
+                v-model:page-size="pageSize"
+                :page-sizes="[10, 20, 50, 100]"
+                layout="total, sizes, prev, pager, next"
+                :total="totalVal"
+                @size-change="handleSizeChange"
+                @current-change="getTableData"
+                />
+        </div>
         <div class="put-btn" v-if="selectedRows.length">
             <div class="btn-l">推送消息</div>
             <div class="btn-r">推送优惠券</div>
@@ -126,6 +152,10 @@
 <script setup>
 import { onMounted, ref } from 'vue';
 import { Search } from '@element-plus/icons-vue'
+import config from "@/api/config.js";
+import { useStore } from "vuex";
+import { ElMessage, ElMessageBox } from 'element-plus';
+let store = useStore();
 
 const searchVal = ref(null)
 
@@ -143,63 +173,7 @@ const statusObj = {
     2: "待激活",
 }
 
-const tableData = ref([
-    {
-        code: "c2547475411",
-        name: "张三三",
-        tel: "13969685874",
-        address: "湖北省武汉市智慧谷A3座1104",
-        count: "3",
-        treeCode: "tree857874574",
-        level: 1,
-        status: 1,
-        date: "2025-07-04",
-    },
-    {
-        code: "c388547411",
-        name: "李四四",
-        tel: "159856874",
-        address: "湖北省武汉市江夏区山川街道光束庆南城12栋1258室",
-        count: "3",
-        treeCode: "tree857874574",
-        level: 0,
-        status: 0,
-        date: "2025-07-04",
-    },
-    {
-        code: "c2547475411",
-        name: "张三三",
-        tel: "13969685874",
-        address: "湖北省武汉市智慧谷A3座1104",
-        count: "3",
-        treeCode: "tree857874574",
-        level: 2,
-        status: 2,
-        date: "2025-07-04",
-    },
-    {
-        code: "c2547475411",
-        name: "张三三",
-        tel: "13969685874",
-        address: "湖北省武汉市智慧谷A3座1104",
-        count: "1",
-        treeCode: "tree857874574",
-        level: 3,
-        status: 1,
-        date: "2025-07-04",
-    },
-    {
-        code: "c2547475411",
-        name: "张三三",
-        tel: "13969685874",
-        address: "湖北省武汉市智慧谷A3座1104",
-        count: "3",
-        treeCode: "tree857874574",
-        level: 4,
-        status: 2,
-        date: "2025-07-04",
-    },
-]);
+const tableData = ref([]);
 
 const selectedRows = ref([])
 function handleTableSelect(selection) {
@@ -228,16 +202,64 @@ const levelOptions = ref([
     {label: "白银守护", value: "白银守护"},
 ])
 
+const currentPage = ref(1);
+const pageSize = ref(20); // 每页显示20条数据
+const totalVal = ref(0);
+
 onMounted(() => {
     getTableData()
 })
 
+function handleSizeChange(newSize) {
+    pageSize.value = newSize;
+    currentPage.value = 1; // 重置页码
+    getTableData();
+}
+
 function getTableData() {
     // 模拟获取数据
-    VE_API.manage_interface.fetchUserList({farmId: 766, page: 1, limit: 10}).then(({data}) => {
+    VE_API.manage_interface.fetchUserList({farmId: 766, page: currentPage.value, limit: pageSize.value}).then(({data, count}) => {
         tableData.value = data;
+        totalVal.value = count
+    });
+}
+
+// 下载模板
+function downloadTemplate() {
+    VE_API.manage_user.downloadTemplate().then((response) => {
+        const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+        const link = document.createElement('a');
+        link.href = window.URL.createObjectURL(blob);
+        link.download = '用户数据模板.xlsx';
+        link.click();
+    }).catch(error => {
+        console.error('下载模板失败:', error);
     });
 }
+
+const fileList = ref([]);
+const uploadHeaders = {
+    'token': store.getters.token,
+};
+// 上传数据
+function handleUploadMsg(res) {
+    ElMessage.success(res.msg);
+}
+
+// 删除数据
+function deleteUser(item) {
+    ElMessageBox.confirm(`确认删除 ${item.name} 的守护权限吗?`, '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+    }).then(() => {
+        // 这里可以添加取消守护的逻辑
+        ElMessage({
+            type: 'success',
+            message: `已删除 ${item.name}`,
+        });
+    }).catch(() => {});
+}
 </script>
 
 <style lang="scss" scoped>
@@ -276,6 +298,11 @@ function getTableData() {
         .title-r {
             display: flex;
             align-items: center;
+            ::v-deep {
+                .el-upload-list {
+                    display: none;
+                }
+            }
         }
     }
     .ml-10 {
@@ -289,6 +316,7 @@ function getTableData() {
     }
     .table-wrap {
         flex: 1;
+        height: calc(100% - 44px - 88px - 70px);
         .action-btn {
             display: flex;
             align-items: center;
@@ -304,8 +332,8 @@ function getTableData() {
             border-radius: 4px;
         }
         .level-0 {
-            color: #7D7D7D;
-            background: rgba(125, 125, 125, 0.2);
+            color: #03b2d5;
+            background: rgba(3, 178, 213, 0.2);
         }
         .level-1 {
             color: #D88C4A;
@@ -324,7 +352,6 @@ function getTableData() {
             background: rgba(236, 125, 255, 0.2);
         }
         .status-text {
-            font-size: 16px;
             color: #7D7D7D;
         }
         .status-1 {
@@ -334,14 +361,21 @@ function getTableData() {
             color: #2199F8;
         }
     }
+    .pagination-wrap {
+        padding: 16px 0;
+        display: flex;
+        justify-content: end;
+    }
     .put-btn {
-        padding: 20px 0 26px 0;
-        border-top: 1px solid rgba(0, 0, 0, 0.2);
         display: flex;
         align-items: center;
         justify-content: center;
+        position: absolute;
+        left: 50%;
+        transform: translateX(-50%);
+        bottom: 10px;
         .btn-l {
-            padding: 18px 44px;
+            padding: 12px 44px;
             background: #F0AC37;
             border-radius: 4px;
             font-size: 16px;
@@ -349,7 +383,7 @@ function getTableData() {
         }
         .btn-r {
             margin-left: 30px;
-            padding: 18px 36px;
+            padding: 12px 36px;
             background: #2199F8;
             border-radius: 4px;
             font-size: 16px;