فهرست منبع

完善农事模块;增加字典查询

jiuling 9 ماه پیش
والد
کامیت
da43cae510

+ 112 - 0
api/services/activity.js

@@ -0,0 +1,112 @@
+import { http, Method } from '@/utils/request';
+import storage from "@/utils/storage.js";
+const userInfo = storage.getUserInfo()
+/**
+ * 根据任务类型统计数量
+ *	@param {Object} params - 查询参数
+ */
+export function countStatusTypeTasks(params) {
+  params.userId = userInfo.userid;
+  return http.request({
+    url: '/base/tasks/countType',
+    method: Method.POST,
+	data: params
+  });
+}
+
+/**
+ * 获取农事任务列表
+ * @param {Object} params - 查询参数
+ * @returns {Promise} - 返回任务列表
+ */
+export function getAgriculturalTasksList(params) {
+  return http.request({
+    url: '/base/tasks/list',
+    method: Method.GET,
+    params: params
+  });
+}
+
+/**
+ * 获取农事任务详情
+ * @param {Number} id - 任务ID
+ * @returns {Promise} - 返回任务详情
+ */
+export function getAgriculturalTasksById(id) {
+  return http.request({
+    url: `/base/tasks/${id}`,
+    method: Method.GET
+  });
+}
+
+/**
+ * 新增农事任务
+ * @param {Object} data - 任务数据
+ * @returns {Promise} - 返回添加结果
+ */
+export function addAgriculturalTask(data) {
+  return http.request({
+    url: '/base/tasks',
+    method: Method.POST,
+    data: data
+  });
+}
+
+/**
+ * 修改农事任务
+ * @param {Object} data - 任务数据
+ * @returns {Promise} - 返回修改结果
+ */
+export function updateAgriculturalTask(data) {
+  return http.request({
+    url: '/base/tasks',
+    method: Method.PUT,
+    data: data
+  });
+}
+
+/**
+ * 删除农事任务
+ * @param {Array} ids - 任务ID数组
+ * @returns {Promise} - 返回删除结果
+ */
+export function deleteAgriculturalTasks(ids) {
+  return http.request({
+    url: `/base/tasks/${ids.join(',')}`,
+    method: Method.DELETE
+  });
+}
+
+/**
+ * 修改农事任务状态
+ * @param {Number} id - 任务ID
+ * @param {String} status - 任务状态
+ * @returns {Promise} - 返回修改结果
+ */
+export function updateTaskStatus(id, status) {
+  return http.request({
+    url: '/base/tasks',
+    method: Method.PUT,
+    data: {
+      id: id,
+      taskStatus: status
+    }
+  });
+}
+
+/**
+ * 完成农事任务
+ * @param {Object} data - 完成任务的数据
+ * @returns {Promise} - 返回操作结果
+ */
+export function completeTask(data) {
+  // 任务完成时的专用接口,包含完成时间和完成说明等信息
+  return http.request({
+    url: '/base/tasks',
+    method: Method.PUT,
+    data: {
+      ...data,
+      taskStatus: 'completed'
+    }
+  });
+} 

+ 26 - 0
api/services/dict.js

@@ -0,0 +1,26 @@
+import { http, Method } from '@/utils/request';
+
+/**
+ * 获取字典数据
+ * @param {String} dictType - 字典类型
+ * @returns {Promise} - 返回字典数据
+ */
+export function getDictData(dictType) {
+  return http.request({
+    url: `/system/dict/data/type/${dictType}`,
+    method: Method.GET
+  });
+}
+
+/**
+ * 获取多个字典数据
+ * @param {Array} dictTypes - 字典类型数组
+ * @returns {Promise} - 返回多个字典数据
+ */
+export function getMultipleDictData(dictTypes) {
+  return http.request({
+    url: `/system/dict/data/types`,
+    method: Method.POST,
+    data: dictTypes
+  });
+} 

+ 39 - 0
api/services/user.js

@@ -0,0 +1,39 @@
+import { http, Method } from '@/utils/request';
+
+/**
+ * 获取部门下的用户列表
+ * @param {Number} deptId - 部门ID
+ * @returns {Promise} - 返回用户列表
+ */
+export function getUsersByDeptId(deptId) {
+  return http.request({
+    url: `/system/user/list/dept/${deptId}`,
+    method: Method.GET
+  });
+}
+
+/**
+ * 根据地块ID获取相关联的部门用户
+ * @param {Number} plotId - 地块ID
+ * @returns {Promise} - 返回用户列表
+ */
+export function getUsersByPlotId(params) {
+  return http.request({
+    url: '/system/user/list',
+    method: Method.GET,
+	params: params,
+	needToken: true
+  });
+}
+
+/**
+ * 获取用户详情
+ * @param {Number} userId - 用户ID
+ * @returns {Promise} - 返回用户详情
+ */
+export function getUserInfo(userId) {
+  return http.request({
+    url: `/system/user/${userId}`,
+    method: Method.GET
+  });
+} 

+ 125 - 0
components/common/dict-tag.vue

@@ -0,0 +1,125 @@
+<template>
+  <view class="dict-tag" :class="tagClass">{{ label }}</view>
+</template>
+
+<script>
+import dictMixin from '@/utils/mixins/dictMixin';
+
+export default {
+  name: 'DictTag',
+  mixins: [dictMixin],
+  props: {
+    // 字典类型
+    dictType: {
+      type: String,
+      required: true
+    },
+    // 字典值
+    value: {
+      type: [String, Number],
+      required: true
+    },
+    // 是否带颜色样式
+    colored: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {
+      dictTypeList: [] // 将通过created动态设置
+    };
+  },
+  computed: {
+    // 字典标签
+    label() {
+      return this.getDictLabel(this.dictType, this.value, '');
+    },
+    // 标签样式类
+    tagClass() {
+      if (!this.colored) return '';
+      const className = this.getDictClass(this.dictType, this.value, '');
+      return className ? `tag-${className}` : '';
+    }
+  },
+  created() {
+    // 检查父组件是否已加载此字典
+    let parentWithDict = this.findParentWithDict(this.dictType);
+    
+    if (parentWithDict) {
+      // 父组件已加载此字典,使用父组件的字典数据
+      if (parentWithDict.dictData && parentWithDict.dictData[this.dictType]) {
+        this.$set(this.dictData, this.dictType, parentWithDict.dictData[this.dictType]);
+      }
+    } else {
+      // 父组件未加载此字典,自己加载
+      this.dictTypeList = [this.dictType];
+      this.loadDict();
+    }
+  },
+  methods: {
+    // 查找已加载指定字典类型的父组件
+    findParentWithDict(dictType) {
+      let parent = this.$parent;
+      while (parent) {
+        if (parent.dictData && parent.dictData[dictType]) {
+          console.log(`[DictTag] Found parent with dictionary ${dictType} already loaded`);
+          return parent;
+        }
+        parent = parent.$parent;
+      }
+      console.log(`[DictTag] No parent found with dictionary ${dictType}, loading it independently`);
+      return null;
+    }
+  }
+};
+</script>
+
+<style scoped>
+.dict-tag {
+  display: inline-block;
+  padding: 0 10rpx;
+  height: 40rpx;
+  line-height: 40rpx;
+  font-size: 26rpx;
+  color: #666;
+  border-radius: 20rpx;
+  text-align: center;
+  white-space: nowrap;
+}
+
+.tag-primary {
+  color: #fff;
+  background-color: #409EFF;
+}
+
+.tag-success {
+  color: #fff;
+  background-color: #67C23A;
+}
+
+.tag-info {
+  color: #fff;
+  background-color: #909399;
+}
+
+.tag-warning {
+  color: #fff;
+  background-color: #E6A23C;
+}
+
+.tag-danger {
+  color: #fff;
+  background-color: #F56C6C;
+}
+
+.tag-secondary {
+  color: #fff;
+  background-color: #8A69F9;
+}
+
+.tag-default {
+  color: #333;
+  background-color: #E9E9E9;
+}
+</style> 

+ 2 - 0
config/api.js

@@ -1,10 +1,12 @@
 // 开发环境
 const dev = {
   serve: "http://localhost:8080",
+  upload: "http://nxy.gbdfarm.com"
 };
 // 生产环境
 const prod = {
   serve: "http://nxy.gbdfarm.com:9000/pro-uniapp",
+  upload: "http://nxy.gbdfarm.com"
 };
 
 //默认生产环境

+ 2 - 1
pages.json

@@ -322,6 +322,7 @@
 		]
 	},
 	"easycom": {
-		"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
+		"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue",
+		"^dict-tag$": "components/common/dict-tag.vue"
 	}
 }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 557 - 128
pages/activity/activity-detail.vue


+ 148 - 167
pages/activity/index.vue

@@ -5,16 +5,16 @@
       <view class="plot-info-card">
         <view class="plot-header">
           <text class="plot-name">{{ plotData.name }}</text>
-          <text class="plot-area">{{ plotData.area }}亩</text>
+          <text class="plot-area">{{ plotData.size }}亩</text>
         </view>
         <view class="plot-details">
           <view class="plot-item">
             <text class="item-label">作物:</text>
-            <text class="item-value">{{ plotData.crop }}</text>
+            <text class="item-value">{{ plotData.growCrops }}</text>
           </view>
           <view class="plot-item">
             <text class="item-label">负责人:</text>
-            <text class="item-value">{{ plotData.manager }}</text>
+            <text class="item-value">{{ plotData.managerName }}</text>
           </view>
         </view>
       </view>
@@ -30,7 +30,7 @@
               @click="switchStatus(status.value)"
             >
               <text>{{ status.label }}</text>
-              <view class="badge" v-if="status.value === 'pending' && pendingTaskCount > 0">
+              <view class="badge" v-if="status.value === 0 && pendingTaskCount > 0">
                 {{ pendingTaskCount > 99 ? '99+' : pendingTaskCount }}
               </view>
               <view class="active-line" v-if="currentStatus === status.value"></view>
@@ -46,13 +46,15 @@
       refresher-enabled
       :refresher-triggered="isRefreshing">
       <view class="task-list">
-        <view class="task-card" v-for="(task, index) in taskList" :key="index" @click="viewTaskDetail(task)">
+        <view class="task-card" v-for="(task, index) in taskList" :key="task.id" @click="viewTaskDetail(task)">
           <!-- 头部区域:任务名称和状态标签 -->
           <view class="task-header">
-            <view class="task-name">{{ task.name }}</view>
-            <view class="task-status" :class="{ 'status-completed': task.status === 'completed' }">
-              {{ task.status === 'pending' ? '待完成' : '已完成' }}
-            </view>
+            <view class="task-name">{{ task.taskName }}</view>
+            <dict-tag 
+              dict-type="task_status" 
+              :value="task.taskStatus"
+              class="task-status-tag"
+            />
           </view>
           
           <!-- 信息行:类型、时间、责任人统一放在一行,类型在前 -->
@@ -60,19 +62,24 @@
             <!-- 类型标签放在最左侧 -->
             <view class="info-type">
               <image src="/static/icons/task_icon.png" mode="aspectFit" class="info-icon"></image>
-              <text class="info-text">{{ task.type }}</text>
+              <dict-tag 
+                dict-type="task_type" 
+                :value="task.typeName"
+                :colored="false"
+                class="info-type-tag"
+              />
             </view>
             
             <!-- 时间信息放在中间 -->
             <view class="info-time">
               <image src="/static/icons/clock_icon.png" mode="aspectFit" class="info-icon"></image>
-              <text class="info-text">{{ task.executeTime }}</text>
+              <text class="info-text">{{ formatDate(task.executeTime) }}</text>
             </view>
             
             <!-- 责任人信息放在右侧 -->
             <view class="info-person">
               <image src="/static/icons/user.png" mode="aspectFit" class="info-icon"></image>
-              <text class="info-text">{{ task.assignee }}</text>
+              <text class="info-text">{{ task.assigneeName || '未分配' }}</text>
             </view>
           </view>
           
@@ -107,20 +114,28 @@
 </template>
 
 <script>
+import storage from "@/utils/storage.js";
+import { getAgriculturalTasksList, countStatusTypeTasks } from '@/api/services/activity.js';
+import dictMixin from '@/utils/mixins/dictMixin';
+import DictTag from '@/components/common/dict-tag';
+
 export default {
+  components: {
+    DictTag
+  },
+  mixins: [dictMixin],
   data() {
     return {
+      // 需要加载的字典类型
+      dictTypeList: ['task_type','task_status'],
+      
       // 地块数据
       plotData: {
-        id: 1,
-        name: '东区水稻田',
-        area: '128',
-        crop: '水稻',
-        manager: '张农夫'
+        
       },
 
       // 待完成任务数
-      pendingTaskCount: 5,
+      pendingTaskCount: 0,
 
       // 当前筛选状态
       currentStatus: 'all',
@@ -128,8 +143,8 @@ export default {
       // 筛选相关数据
       taskStatus: [
         { label: '全部', value: 'all' },
-        { label: '待完成', value: 'pending' },
-        { label: '已完成', value: 'completed' }
+        { label: '待完成', value: 0 },
+        { label: '已完成', value: 1 }
       ],
       
       // 任务列表数据
@@ -137,173 +152,133 @@ export default {
       isLoading: false,
       isRefreshing: false,
       noMoreData: false,
-      page: 1,
+      pageNum: 1,
       pageSize: 10,
-
-      // 模拟任务数据
-      mockTasks: [
-        {
-          id: 1,
-          name: '水稻田施肥',
-          type: '施肥',
-          status: 'pending',
-          executeTime: '2023-06-15',
-          assignee: '李明',
-          remark: '使用复合肥,每亩用量20kg',
-          remarkExpanded: false
-        },
-        {
-          id: 2,
-          name: '病虫害防治喷药',
-          type: '喷药',
-          status: 'completed',
-          executeTime: '2023-06-10',
-          assignee: '王强',
-          remark: '使用杀虫剂,注意安全防护',
-          remarkExpanded: false
-        },
-        {
-          id: 3,
-          name: '早稻收割',
-          type: '采摘',
-          status: 'pending',
-          executeTime: '2023-06-20',
-          assignee: '张农夫',
-          remark: '天气晴好时进行',
-          remarkExpanded: false
-        },
-        {
-          id: 4,
-          name: '水渠疏通',
-          type: '灌溉',
-          status: 'pending',
-          executeTime: '2023-06-12',
-          assignee: '周华',
-          remark: '',
-          remarkExpanded: false
-        },
-        {
-          id: 5,
-          name: '田间除草',
-          type: '除草',
-          status: 'pending',
-          executeTime: '2023-06-18',
-          assignee: '刘艳',
-          remark: '使用除草剂,避开雨天',
-          remarkExpanded: false
-        }
-      ]
     }
   },
   
-  components: {
-    // No longer needed as we're using standard image icons
-  },
-  
   methods: {
-    // 根据任务类型返回颜色
-    getTypeColor(type, mode = 'bg') {
-      const colors = {
-        '施肥': {
-          bg: 'linear-gradient(135deg, rgba(59, 180, 74, 0.8), rgba(59, 180, 74, 0.6))',
-          text: '#3BB44A'
-        },
-        '喷药': {
-          bg: 'linear-gradient(135deg, rgba(255, 82, 82, 0.8), rgba(255, 82, 82, 0.6))',
-          text: '#FF5252'
-        },
-        '灌溉': {
-          bg: 'linear-gradient(135deg, rgba(64, 158, 255, 0.8), rgba(64, 158, 255, 0.6))',
-          text: '#409EFF'
-        },
-        '采摘': {
-          bg: 'linear-gradient(135deg, rgba(250, 173, 20, 0.8), rgba(250, 173, 20, 0.6))',
-          text: '#FAAD14'
-        },
-        '播种': {
-          bg: 'linear-gradient(135deg, rgba(121, 85, 72, 0.8), rgba(121, 85, 72, 0.6))',
-          text: '#795548'
-        },
-        '除草': {
-          bg: 'linear-gradient(135deg, rgba(156, 39, 176, 0.8), rgba(156, 39, 176, 0.6))',
-          text: '#9C27B0'
-        }
-      };
+    // 格式化日期
+    formatDate(dateStr) {
+      if (!dateStr) return '';
       
-      const defaultColor = {
-        bg: 'linear-gradient(135deg, rgba(158, 158, 158, 0.8), rgba(158, 158, 158, 0.6))',
-        text: '#909399'
-      };
+      // 如果是时间戳,转换为日期对象
+      let date;
+      if (typeof dateStr === 'number') {
+        date = new Date(dateStr);
+      } else {
+        date = new Date(dateStr.replace(/-/g, '/'));
+      }
+      
+      const year = date.getFullYear();
+      const month = String(date.getMonth() + 1).padStart(2, '0');
+      const day = String(date.getDate()).padStart(2, '0');
       
-      return (colors[type] || defaultColor)[mode];
+      return `${year}-${month}-${day}`;
     },
-
+    
     // 切换任务状态筛选
     switchStatus(status) {
       if (this.currentStatus === status) return;
       
       this.currentStatus = status;
-      this.page = 1;
+      this.pageNum = 1;
       this.noMoreData = false;
       this.loadTaskData();
     },
     
     // 加载任务数据
     loadTaskData() {
+      this.plotData = JSON.parse(storage.getPlots() || '{}')
+	  console.log("this.plotData",this.plotData);
       this.isLoading = true;
       
-      // 模拟API请求延迟
-      setTimeout(() => {
-        // 模拟筛选
-        let filteredTasks = [...this.mockTasks];
-        
-        // 按状态筛选
-        if (this.currentStatus !== 'all') {
-          filteredTasks = filteredTasks.filter(task => task.status === this.currentStatus);
-        }
-        
-        // 分页处理
-        const start = (this.page - 1) * this.pageSize;
-        const end = start + this.pageSize;
-        const pageData = filteredTasks.slice(start, end);
-        
-        if (this.page === 1) {
-          this.taskList = pageData;
+      // 构建查询参数
+      const params = {
+        pageNum: this.pageNum,
+        pageSize: this.pageSize,
+        plotId: this.plotData.id
+      };
+      
+      // 如果不是查询全部,添加状态过滤条件
+      if (this.currentStatus !== 'all') {
+        params.taskStatus = this.currentStatus;
+      }
+      
+      getAgriculturalTasksList(params).then(res => {
+        if (res.data.code === 200) {
+          const { rows, total } = res.data;
+          
+          // 处理返回的数据
+          const tasks = rows.map(item => {
+            // 确保每个任务都有remarkExpanded属性
+            item.remarkExpanded = false;
+            return item;
+          });
+          
+          if (this.pageNum === 1) {
+            this.taskList = tasks;
+          } else {
+            this.taskList = [...this.taskList, ...tasks];
+          }
+          
+          // 判断是否还有更多数据
+          this.noMoreData = this.taskList.length >= total;
+          
+          // 统计待完成任务数量
+          this.countPendingTasks();
         } else {
-          this.taskList = [...this.taskList, ...pageData];
+          uni.showToast({
+            title: res.data.msg || '获取任务列表失败',
+            icon: 'none'
+          });
         }
-        
-        this.noMoreData = end >= filteredTasks.length;
+      }).catch(err => {
+        console.error('获取任务列表失败:', err);
+        uni.showToast({
+          title: '获取任务列表失败',
+          icon: 'none'
+        });
+      }).finally(() => {
         this.isLoading = false;
         this.isRefreshing = false;
-        
-        // 更新待完成任务数
-        this.pendingTaskCount = this.mockTasks.filter(task => task.status === 'pending').length;
-      }, 500);
+      });
+    },
+    
+    // 统计待完成任务数量
+    countPendingTasks() {
+      // 如果当前已经是按状态筛选,直接使用当前列表长度
+      if (this.currentStatus === 'pending') {
+        this.pendingTaskCount = this.taskList.length;
+        return;
+      }
+      
+      // 否则,请求获取待完成任务数量
+      const params = {
+        plotId: this.plotData.id,
+        taskStatus: 0
+      };
+      
+      countStatusTypeTasks(params).then(res => {
+		  console.log("nongsh",res);
+        if (res.data.code === 200) {
+          this.pendingTaskCount = res.data.data || 0;
+        }
+      });
     },
 
     // 下拉刷新
     refreshData(e) {
       this.isRefreshing = true;
-      this.page = 1;
+      this.pageNum = 1;
       this.noMoreData = false;
-      
-      // 模拟API请求延迟
-      setTimeout(() => {
-        this.loadTaskData();
-        // 显示刷新成功的提示
-        uni.showToast({
-          title: '刷新成功',
-          icon: 'success',
-          duration: 1000
-        });
-      }, 1000);
+      this.loadTaskData();
     },
 
     // 上拉加载更多
     loadMore() {
       if (!this.isLoading && !this.noMoreData) {
-        this.page++;
+        this.pageNum++;
         this.loadTaskData();
       }
     },
@@ -312,22 +287,16 @@ export default {
     viewTaskDetail(task) {
       // 根据任务状态决定跳转到不同模式的页面
       let mode = '';
-      if (task.status === 'pending') {
+      if (task.taskStatus === '0') {
         // 待完成任务跳转到编辑页面
         mode = 'edit';
-      } else if (task.status === 'completed') {
+      } else if (task.taskStatus === '1') {
         // 已完成任务跳转到查看页面
         mode = 'view';
       }
       
-      console.log(`点击任务: ${task.name}, 状态: ${task.status}, 跳转模式: ${mode}`);
-      console.log('地块数据:', this.plotData);
-      console.log('任务数据:', task);
-      
       // 使用简化的URL参数传递
-      const url = `/pages/activity/activity-detail?id=${task.id}&mode=${mode}&plotName=${encodeURIComponent(this.plotData.name)}&crop=${encodeURIComponent(this.plotData.crop)}&manager=${encodeURIComponent(this.plotData.manager)}&taskName=${encodeURIComponent(task.name)}&taskType=${encodeURIComponent(task.type)}&executeTime=${encodeURIComponent(task.executeTime)}&taskRemark=${encodeURIComponent(task.remark || '')}&taskStatus=${task.status}&assignee=${encodeURIComponent(task.assignee)}`;
-      
-      console.log('跳转URL:', url);
+      const url = `/pages/activity/activity-detail?id=${task.id}&mode=${mode}&plotName=${encodeURIComponent(this.plotData.name)}&crop=${encodeURIComponent(this.plotData.growCrops)}&manager=${encodeURIComponent(this.plotData.managerName)}`;
       
       uni.navigateTo({
         url: url
@@ -336,15 +305,9 @@ export default {
 
     // 创建新任务
     createNewTask() {
-      console.log('点击新建任务按钮,跳转到创建页面');
-      console.log('地块数据:', this.plotData);
-      
       // 使用简化的URL参数传递
-      const url = `/pages/activity/activity-detail?id=new&mode=create&plotName=${encodeURIComponent(this.plotData.name)}&crop=${encodeURIComponent(this.plotData.crop)}&manager=${encodeURIComponent(this.plotData.manager)}`;
-      
-      console.log('跳转URL:', url);
+      const url = `/pages/activity/activity-detail?id=new&mode=create&plotName=${encodeURIComponent(this.plotData.name)}&crop=${encodeURIComponent(this.plotData.growCrops)}&farmId=${encodeURIComponent(this.plotData.farmId)}&manager=${encodeURIComponent(this.plotData.managerName)}&plotId=${this.plotData.id}`;
       
-      // 跳转到新建任务页面
       uni.navigateTo({
         url: url
       });
@@ -361,6 +324,11 @@ export default {
   // 页面加载时获取数据
   onLoad() {
     this.loadTaskData();
+  },
+  
+  // 页面显示时刷新数据
+  onShow() {
+    this.refreshData();
   }
 }
 </script>
@@ -728,4 +696,17 @@ export default {
   width: 48rpx;
   height: 48rpx;
 }
+
+/* 添加字典标签相关样式 */
+.task-status-tag {
+  position: absolute;
+  top: 24rpx;
+  right: 24rpx;
+  z-index: 1;
+  max-width: 120rpx;
+}
+
+.info-type-tag {
+  /* margin-left: 4rpx; */
+}
 </style>

+ 7 - 3
pages/dashboard/index.vue

@@ -527,14 +527,18 @@
 						}
 
 						const fieldList = data.data;
-
+						console.log("fieldList:",fieldList);
 						const fields = [];
 						fieldList.forEach(item => {
 							const fieldName = item?.fieldName;
 							if (fieldName && !fields.includes(fieldName)) {
 								fields.push({
 									text: fieldName,
-									value: item.id
+									value: item.id,
+									growCrops: item.growCrops,
+									managerName: item.managerName,
+									size: item.size,
+									farmId: item.farmId
 								});
 							}
 						});
@@ -600,7 +604,7 @@
 			onConfirm(e) {
 				console.log('选择了:', e);
 				this.userData.selectedPlot = e.value[0].text
-				let obj = {id:e.value[0].value,name:e.value[0].text}
+				let obj = {id:e.value[0].value,name:e.value[0].text,growCrops:e.value[0].growCrops,managerName:e.value[0].managerName,size:e.value[0].size,farmId: e.value[0].farmId}
 				storage.setPlots(JSON.stringify(obj))
 				this.show = false;
 			},

+ 5 - 1
pages/plots/list.vue

@@ -447,7 +447,7 @@
 
 			selectBlock(block) {
 				this.currentBlock = block;
-
+				console.log("选择地块信息:",block);
 				// 保存当前选择的地块到本地存储
 				this.saveCurrentBlockToStorage(block);
 
@@ -519,6 +519,10 @@
 						id: block.id,
 						code: block.code,
 						name: block.name,
+						growCrops: block.crop,
+						managerName:block.manager,
+						size: block.area,
+						farmId:block.farmId,
 						timestamp: Date.now()
 					}))
 				} catch (e) {

BIN
static/icons/task_icon.png


+ 378 - 0
utils/mixins/dictMixin.js

@@ -0,0 +1,378 @@
+import { getDictData, getMultipleDictData } from '@/api/services/dict';
+import storage from '@/utils/storage';
+import staticDict from '@/utils/staticDict';
+
+// 全局字典缓存对象,用于存储已加载的字典数据
+const dictCache = {
+  // 缓存的字典数据,格式为 { dictType: [{label, value, ...}, ...] }
+  data: {},
+  // 缓存过期时间,单位为毫秒
+  expireTime: 1000 * 60 * 60, // 1小时
+  // 缓存最后更新时间
+  lastUpdateTime: {},
+  // 正在加载的字典类型,用于防止重复请求
+  loading: {}
+};
+
+/**
+ * 字典数据加载Mixin
+ * 使用方式:
+ * 1. 在组件中导入 import dictMixin from '@/utils/mixins/dictMixin';
+ * 2. 在组件的mixins选项中注册 mixins: [dictMixin]
+ * 3. 在组件的data中定义需要的字典类型 dictTypeList: ['sys_user_sex', 'sys_normal_disable', ...]
+ * 4. 在组件的methods中调用 getDictLabel 等方法使用字典数据
+ * 5. 在模板中直接使用 dictData 对象获取字典项 v-for="item in dictData.sys_user_sex"
+ */
+export default {
+  data() {
+    return {
+      // 组件中的字典数据
+      dictData: {},
+      // 定义组件需要加载的字典类型
+      dictTypeList: [],
+      // 字典加载状态
+      dictLoading: false
+    };
+  },
+  created() {
+    // 组件创建时,如果有定义dictTypeList,则自动加载字典数据
+    if (this.dictTypeList && this.dictTypeList.length > 0) {
+      console.log(`[DictMixin] Component created, loading dictionaries: ${this.dictTypeList.join(', ')}`);
+      this.loadDict();
+    }
+  },
+  methods: {
+    /**
+     * 加载字典数据
+     * @param {Array} dictTypes - 字典类型数组,如果不传则使用组件中定义的dictTypeList
+     * @returns {Promise} - 返回字典加载的Promise对象
+     */
+    loadDict(dictTypes) {
+      const types = dictTypes || this.dictTypeList;
+      if (!types || types.length === 0) {
+        return Promise.resolve({});
+      }
+
+      // 标记加载中
+      this.dictLoading = true;
+
+      // 需要从服务器获取的字典类型
+      const needFetch = [];
+      
+      // 检查是否有静态字典或缓存
+      types.forEach(type => {
+        // 先检查是否有静态字典
+        if (staticDict[type]) {
+          // 使用静态字典数据
+          console.log(`[DictMixin] Using static dictionary for ${type}`);
+          this.$set(this.dictData, type, staticDict[type]);
+        } else {
+          // 检查缓存
+          const cachedDict = this.getDictFromCache(type);
+          if (cachedDict) {
+            // 已有缓存,直接使用
+            console.log(`[DictMixin] Using cached dictionary for ${type}`);
+            this.$set(this.dictData, type, cachedDict);
+          } else if (!dictCache.loading[type]) {
+            // 需要从服务器获取,并且当前没有其他组件正在加载
+            console.log(`[DictMixin] Need to fetch dictionary ${type} from server`);
+            needFetch.push(type);
+          } else {
+            console.log(`[DictMixin] Dictionary ${type} is already being loaded by another component, waiting...`);
+          }
+        }
+      });
+
+      // 如果所有字典都已缓存或使用静态数据,直接返回
+      if (needFetch.length === 0) {
+        this.dictLoading = false;
+        
+        // 检查是否有正在加载的字典,如果有,等待它们完成
+        const loadingTypes = types.filter(type => dictCache.loading[type]);
+        if (loadingTypes.length > 0) {
+          return this.waitForDictLoading(loadingTypes);
+        }
+        
+        return Promise.resolve(this.dictData);
+      }
+
+      // 从服务器获取字典数据
+      return this.fetchDictData(needFetch).then(res => {
+        this.dictLoading = false;
+        return this.dictData;
+      }).catch(err => {
+        this.dictLoading = false;
+        console.error('加载字典数据失败:', err);
+        return Promise.reject(err);
+      });
+    },
+
+    /**
+     * 等待指定类型的字典加载完成
+     * @param {Array} types - 字典类型数组
+     * @returns {Promise} - 返回等待的Promise对象
+     */
+    waitForDictLoading(types) {
+      return new Promise(resolve => {
+        const checkInterval = setInterval(() => {
+          const stillLoading = types.some(type => dictCache.loading[type]);
+          if (!stillLoading) {
+            clearInterval(checkInterval);
+            
+            // 加载完成后,从缓存中获取数据
+            types.forEach(type => {
+              const cachedDict = this.getDictFromCache(type);
+              if (cachedDict) {
+                this.$set(this.dictData, type, cachedDict);
+              }
+            });
+            
+            resolve(this.dictData);
+          }
+        }, 50);
+      });
+    },
+
+    /**
+     * 从服务器获取字典数据
+     * @param {Array} dictTypes - 字典类型数组
+     * @returns {Promise} - 返回字典获取的Promise对象
+     */
+    fetchDictData(dictTypes) {
+      // 标记这些字典类型正在加载
+      dictTypes.forEach(type => {
+        dictCache.loading[type] = true;
+      });
+      
+      if (dictTypes.length === 1) {
+        // 单个字典类型,直接获取
+        console.log(`[DictMixin] Fetching single dictionary: ${dictTypes[0]}`);
+        return getDictData(dictTypes[0]).then(res => {
+          if (res.data.code === 200) {
+            const dictType = dictTypes[0];
+            const dictList = res.data.data || [];
+            
+            // 更新组件字典数据
+            this.$set(this.dictData, dictType, dictList);
+            
+            // 更新缓存
+            this.updateDictCache(dictType, dictList);
+            
+            // 取消加载标记
+            delete dictCache.loading[dictType];
+            
+            return dictList;
+          } else {
+            console.error(`获取字典[${dictTypes[0]}]数据失败:`, res.data.msg);
+            
+            // 取消加载标记
+            delete dictCache.loading[dictTypes[0]];
+            
+            return Promise.reject(res.data.msg);
+          }
+        }).catch(err => {
+          // 发生错误时取消加载标记
+          delete dictCache.loading[dictTypes[0]];
+          throw err;
+        });
+      } else {
+        // 多个字典类型,批量获取
+        console.log(`[DictMixin] Batch fetching ${dictTypes.length} dictionaries: ${dictTypes.join(', ')}`);
+        return getMultipleDictData(dictTypes).then(res => {
+          if (res.data.code === 200) {
+            const dictMap = res.data.data || {};
+            
+            // 更新组件字典数据和缓存
+            Object.keys(dictMap).forEach(dictType => {
+              const dictList = dictMap[dictType] || [];
+              
+              // 更新组件字典数据
+              this.$set(this.dictData, dictType, dictList);
+              
+              // 更新缓存
+              this.updateDictCache(dictType, dictList);
+              
+              // 取消加载标记
+              delete dictCache.loading[dictType];
+            });
+            
+            console.log(`[DictMixin] Successfully loaded ${Object.keys(dictMap).length} dictionaries`);
+            return dictMap;
+          } else {
+            console.error(`获取字典数据失败:`, res.data.msg);
+            
+            // 取消所有加载标记
+            dictTypes.forEach(type => {
+              delete dictCache.loading[type];
+            });
+            
+            return Promise.reject(res.data.msg);
+          }
+        }).catch(err => {
+          // 发生错误时取消所有加载标记
+          dictTypes.forEach(type => {
+            delete dictCache.loading[type];
+          });
+          throw err;
+        });
+      }
+    },
+
+    /**
+     * 从缓存中获取字典数据
+     * @param {String} dictType - 字典类型
+     * @returns {Array|null} - 返回字典数据,不存在或已过期则返回null
+     */
+    getDictFromCache(dictType) {
+      // 判断是否有缓存
+      if (!dictCache.data[dictType]) {
+        return null;
+      }
+      
+      // 判断缓存是否过期
+      const lastUpdateTime = dictCache.lastUpdateTime[dictType] || 0;
+      const now = Date.now();
+      if (now - lastUpdateTime > dictCache.expireTime) {
+        // 缓存已过期,删除缓存
+        delete dictCache.data[dictType];
+        delete dictCache.lastUpdateTime[dictType];
+        return null;
+      }
+      
+      // 返回缓存的字典数据
+      return dictCache.data[dictType];
+    },
+
+    /**
+     * 更新字典缓存
+     * @param {String} dictType - 字典类型
+     * @param {Array} dictList - 字典数据列表
+     */
+    updateDictCache(dictType, dictList) {
+      dictCache.data[dictType] = dictList;
+      dictCache.lastUpdateTime[dictType] = Date.now();
+      
+      // 更新本地存储
+      try {
+        // 只存储最后更新时间,具体数据保存在内存中
+        storage.setDict(`dict_time_${dictType}`, dictCache.lastUpdateTime[dictType]);
+      } catch (e) {
+        console.error('更新字典缓存失败:', e);
+      }
+    },
+
+    /**
+     * 清除字典缓存
+     * @param {String} dictType - 字典类型,不传则清除所有缓存
+     */
+    clearDictCache(dictType) {
+      if (dictType) {
+        delete dictCache.data[dictType];
+        delete dictCache.lastUpdateTime[dictType];
+        storage.removeDict(`dict_time_${dictType}`);
+      } else {
+        dictCache.data = {};
+        dictCache.lastUpdateTime = {};
+        // 清除所有字典相关的本地存储
+        const keys = Object.keys(localStorage);
+        keys.forEach(key => {
+          if (key.startsWith('dict_time_')) {
+            storage.removeDict(key);
+          }
+        });
+      }
+    },
+
+    /**
+     * 根据字典值获取对应的字典标签
+     * @param {String} dictType - 字典类型
+     * @param {String|Number} value - 字典值
+     * @param {String} defaultLabel - 默认标签
+     * @returns {String} - 字典标签
+     */
+    getDictLabel(dictType, value, defaultLabel = '') {
+      // 首先检查组件数据
+      const dictList = this.dictData[dictType];
+      if (dictList) {
+        const item = dictList.find(dict => dict.dictValue === value);
+        if (item) return item.dictLabel;
+      }
+      
+      // 再检查静态字典
+      // const staticDictList = staticDict[dictType];
+      // if (staticDictList) {
+      //   const item = staticDictList.find(dict => dict.value === value);
+      //   if (item) return item.label;
+      // }
+      
+      // 都没找到,返回默认值
+      return defaultLabel;
+    },
+
+    /**
+     * 根据字典标签获取对应的字典值
+     * @param {String} dictType - 字典类型
+     * @param {String} label - 字典标签
+     * @param {String|Number} defaultValue - 默认值
+     * @returns {String|Number} - 字典值
+     */
+    getDictValue(dictType, label, defaultValue = '') {
+      // 首先检查组件数据
+      const dictList = this.dictData[dictType];
+      if (dictList) {
+        const item = dictList.find(dict => dict.label === label);
+        if (item) return item.value;
+      }
+      
+      // 再检查静态字典
+      const staticDictList = staticDict[dictType];
+      if (staticDictList) {
+        const item = staticDictList.find(dict => dict.label === label);
+        if (item) return item.value;
+      }
+      
+      // 都没找到,返回默认值
+      return defaultValue;
+    },
+
+    /**
+     * 获取字典列表
+     * @param {String} dictType - 字典类型
+     * @returns {Array} - 字典列表
+     */
+    getDictList(dictType) {
+      // 首先检查组件数据
+      const dictList = this.dictData[dictType];
+      if (dictList) return dictList;
+      
+      // 再检查静态字典
+      return staticDict[dictType] || [];
+    },
+
+    /**
+     * 获取字典类型对应的样式类
+     * @param {String} dictType - 字典类型
+     * @param {String|Number} value - 字典值
+     * @param {String} defaultClass - 默认样式类
+     * @returns {String} - 字典项的样式类
+     */
+    getDictClass(dictType, value, defaultClass = '') {
+      // 首先检查组件数据
+      const dictList = this.dictData[dictType];
+      if (dictList) {
+        const item = dictList.find(dict => dict.dictValue === value);
+        if (item && item.listClass) return item.listClass;
+      }
+      
+      // 再检查静态字典
+      // const staticDictList = staticDict[dictType];
+      // if (staticDictList) {
+      //   const item = staticDictList.find(dict => dict.value === value);
+      //   if (item && item.listClass) return item.listClass;
+      // }
+      
+      // 都没找到,返回默认值
+      return defaultClass;
+    }
+  }
+}; 

+ 8 - 0
utils/staticDict.js

@@ -0,0 +1,8 @@
+/**
+ * 静态字典数据配置
+ * 对于不需要从后端获取的通用字典,可以在此处配置
+ */
+
+export default {
+
+}; 

+ 6 - 0
utils/storage.js

@@ -9,6 +9,12 @@ const REFRESH_TOKEN = isDev ? "refresh_token_key_dev" : "refresh_token_key";
 const USER_INFO = isDev ? "user_info_obj_dev" : "user_info_obj";
 const AFTERSALE_DATA = isDev ? "aftersale_data_dev" : "aftersale_data";
 export default {
+	setDict(type,val){
+		uni.setStorageSync(type, val);
+	},
+	removeDict(type){
+		uni.removeStorageSync(type);
+	},
 	setInviter(val) {
 		uni.setStorageSync('inviter', val)
 	},

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است