浏览代码

完善农事模块的图片显示以及农资商城

jiuling 9 月之前
父节点
当前提交
e7c5239ccc
共有 4 个文件被更改,包括 640 次插入414 次删除
  1. 11 4
      pages/activity/activity-detail.vue
  2. 19 16
      pages/service/mall-detail.vue
  3. 96 33
      pages/service/mall.vue
  4. 514 361
      utils/mixins/dictMixin.js

+ 11 - 4
pages/activity/activity-detail.vue

@@ -190,7 +190,8 @@
                 :key="index"
                 @click="previewImage(item, index)"
               >
-                <image :src="getImageUrl(item)" mode="aspectFill"/>
+                <!-- <image :src="getImageUrl(item)" mode="aspectFill"/> -->
+                <image :src="item.url" mode="aspectFill"/>
                 <view class="delete-btn" @click.stop="deletePic(index)">
                   <text>×</text>
                 </view>
@@ -216,7 +217,8 @@
                 :key="index"
                 @click="previewImage(item, index)"
               >
-                <image :src="getImageUrl(item)" mode="aspectFill"/>
+                <!-- <image :src="getImageUrl(item)" mode="aspectFill"/> -->
+                <image :src="item.url" mode="aspectFill"/>
               </view>
             </view>
           </view>
@@ -1050,7 +1052,8 @@ export default {
       tempFilePaths.forEach((path, index) => {
         // 调用上传API
         uni.uploadFile({
-          url: api.serve + '/base/tasks/uploadTaskImage', // 
+          // url: api.serve + '/base/tasks/uploadTaskImage', 
+          url: api.serve + '/file/upload', 
           filePath: path,
           name: 'file', // 文件参数名称,需要与后端接口匹配
           formData: {
@@ -1165,7 +1168,8 @@ export default {
     // 预览图片
     previewImage(item, index) {
       // 获取所有图片的完整URL
-      const urls = this.formData.images.map(file => this.getImageUrl(file));
+      // const urls = this.formData.images.map(file => this.getImageUrl(file));
+	  const urls = this.formData.images.map(item => item.url);
       uni.previewImage({
         urls: urls,
         current: index
@@ -1242,7 +1246,10 @@ export default {
       const submitData = {
         // 如果是编辑模式,需要提供ID
         ...(this.formData.id ? { id: this.formData.id } : {}),
+		farmId: this.formData.farmId,
         plotId: this.formData.plotId,
+        fieldName: this.formData.plotName,
+        growCrops: this.formData.crop,
         taskName: this.formData.taskName,
         taskImages: this.formData.taskImages,
         typeName: this.formData.typeNameId,

+ 19 - 16
pages/service/mall-detail.vue

@@ -4,7 +4,7 @@
     <view class="swiper-container">
       <swiper class="goods-swiper" :indicator-dots="true" :autoplay="true" :circular="true">
         <swiper-item v-for="(image, index) in goodsImages" :key="index">
-          <image class="swiper-image" :src="getImageUrl(image)" mode="aspectFill"></image>
+          <image class="swiper-image" :src=image.url mode="aspectFill"></image>
         </swiper-item>
       </swiper>
     </view>
@@ -15,7 +15,7 @@
       <view class="goods-subtitle">{{ goodsDetail.description }}</view>
       <view class="price-container">
         <text class="current-price">¥{{ goodsDetail.price }}</text>
-        <!-- <text class="price-unit">/{{ goodsDetail.unit }}</text> -->
+        <text class="price-unit">{{ goodsDetail.unit }}</text>
         <text class="original-price" v-if="goodsDetail.originalPrice">¥{{ goodsDetail.originalPrice }}</text>
       </view>
       <view class="specs-info">
@@ -59,7 +59,7 @@
             class="detail-image" 
             v-for="(item, index) in goodsDetail.detailImages" 
             :key="index"
-            :src="getImageUrl(item)" 
+            :src="item.url" 
             mode="widthFix"
             @click="previewImage(item, index)"
           ></image>
@@ -121,11 +121,14 @@ export default {
   },
   
   methods: {
-	getImageUrl(item) {
-		// 默认返回url或path
-		console.log("api.upload + item.url",api.upload + item.url);
-	    return  api.upload + item.url;
-	  },
+	// getImageUrl(item) {
+	//   	// 默认返回url或path
+	// 	console.log("imageUrls",item);
+	// 	if(item == null) return
+	// 	// const imageUrls = item.split(',');
+		
+	//     return  imageUrls;
+	// },
     // 加载商品详情
     loadGoodsDetail(goodsId) {
 		uni.showLoading({
@@ -135,6 +138,7 @@ export default {
 			if (res.data.code === 200) {
 			  const { data } = res.data;
 			  this.goodsDetail = data
+			  console.log("this.goodsDetail", this.goodsDetail);
 			  // 处理图片数据
 			  if (this.goodsDetail.detailImages && this.goodsDetail.swiperImages) {
 			    try {
@@ -150,7 +154,7 @@ export default {
 			        url: url.trim(), // 保存原始URL,显示时会通过getImageUrl方法处理
 			        status: 'success'
 			      }));
-			      // console.log('解析后的图片数据:', this.goodsDetail.detailImages);
+			      console.log('解析后的图片数据:', this.goodsDetail.detailImages);
 			    } catch (e) {
 			      console.error('解析图片数据失败:', e);
 			      this.goodsDetail.detailImages = [];
@@ -237,13 +241,12 @@ export default {
     
     // 预览图片
     previewImage(image, index) {
-	// 获取所有图片的完整URL
-	 const urls = this.goodsDetail.detailImages.map(file => this.getImageUrl(file));
-	 console.log("urls",urls);
-      uni.previewImage({
-        current: index,
-        urls: urls
-      });
+		const urls = this.formData.images.map(item => item.url);
+		uni.previewImage({
+		  urls: urls,
+		  current: index
+		});
+		  
     },
     
     // 立即咨询

+ 96 - 33
pages/service/mall.vue

@@ -43,9 +43,10 @@
 
     <!-- 商品展示区 -->
 	
-    <view class="goods-container">
+<!--    <view class="goods-container">
 		<scroll-view
 			scroll-y 
+			v-if="goodsList.length > 0"
 		    style="height: 100vh;" 
 		    @scrolltolower="loadMore">
 			<view class="goods-grid">
@@ -56,14 +57,14 @@
 			    @click="navigateToDetail(item)"
 			  >
 			    <view class="goods-image">
-			      <image :src="getImageUrl(item.detailImages)" mode="aspectFill"></image>
+			      <image :src="getImageUrl(item.swiperImages)" mode="aspectFill"></image>
 			    </view>
 			    <view class="goods-info">
 			      <text class="goods-title">{{ item.title }}</text>
 			      <text class="goods-desc">{{ item.description }}</text>
 			      <view class="goods-price">
 			        <text class="price">¥{{ item.price }}</text>
-			        <!-- <text class="unit">/{{ item.unit }}</text> -->
+			        <!-- <text class="unit">/{{ item.unit }}</text> 
 			      </view>
 			      <view class="action-btn">了解更多</view>
 			    </view>
@@ -73,7 +74,49 @@
         <view class="no-more-data" v-if="noMoreData && goodsList.length > 0">
           <text>没有更多数据了</text>
         </view>
-    </view>
+    </view> -->
+	<view class="container">
+	  <!-- 有数据 -->
+	  <scroll-view
+	    v-if="goodsList.length > 0"
+	    scroll-y
+	    style="height: 100vh;"
+	    @scrolltolower="loadMore"
+	  >
+	    <view class="goods-grid">
+	      <view
+	        class="goods-card"
+	        v-for="item in filteredGoods"
+	        :key="item.id"
+	        @click="navigateToDetail(item)"
+	      >
+	        <view class="goods-image">
+	          <image :src="getImageUrl(item.swiperImages)" mode="aspectFill"></image>
+	        </view>
+	        <view class="goods-info">
+	          <text class="goods-title">{{ item.title }}</text>
+	          <text class="goods-desc">{{ item.description }}</text>
+	          <view class="goods-price">
+	            <text class="price">¥{{ item.price }}</text>
+				<text class="unit">{{ item.unit }}</text>
+	          </view>
+	          <view class="action-btn">了解更多</view>
+	        </view>
+	      </view>
+	    </view>
+	
+	    
+	  </scroll-view>
+	<!-- 没有更多数据提示 -->
+	<view class="no-more-data" v-if="noMoreData">
+	  <text>没有更多数据了</text>
+	</view>
+	  <!-- 无数据 -->
+	 <!-- <view v-else class="empty">
+	    暂无数据
+	  </view> -->
+	</view>
+
   </view>
 </template>
 
@@ -87,7 +130,7 @@ export default {
     return {
 	  dictTypeList: ['mall_product_category'],
       searchKeyword: '',
-      activeCategory: 0,
+      activeCategory: -1,
       scrollLeft: 0,
       
       // 商品列表
@@ -105,18 +148,20 @@ export default {
       let goods = this.goodsList;
       
       // 按分类筛选
-      if (this.activeCategory !== 0) {
+      if (this.activeCategory != -1) {
         goods = goods.filter(item => item.productCategory == this.activeCategory);
-      }
+      }else{
+		  goods = goods.filter(item => item.isRecommended == 1);
+	  }
       
-      // 按搜索关键词筛选
-      if (this.searchKeyword.trim()) {
-        const keyword = this.searchKeyword.trim().toLowerCase();
-        goods = goods.filter(item => 
-          item.title.toLowerCase().includes(keyword) || 
-          item.description.toLowerCase().includes(keyword)
-        );
-      }
+      // // 按搜索关键词筛选
+      // if (this.searchKeyword.trim()) {
+      //   const keyword = this.searchKeyword.trim().toLowerCase();
+      //   goods = goods.filter(item => 
+      //     item.title.toLowerCase().includes(keyword) || 
+      //     item.description.toLowerCase().includes(keyword)
+      //   );
+      // }
       return goods;
     }
   },
@@ -126,9 +171,10 @@ export default {
 	  	// 默认返回url或path
 		if(item == null) return
 		const imageUrls = item.split(',');
-	    return  api.upload + imageUrls[0];
+		console.log("imageUrls",imageUrls);
+	    return  imageUrls[0];
 	},
-	loadMallData(){
+	loadMallData(keyword){
 		this.isLoading = true;
 		uni.showLoading({
 			title: '加载中'
@@ -137,24 +183,33 @@ export default {
 		const params = {
 		  pageNum: this.pageNum,
 		  pageSize: this.pageSize,
-		  productCategory: this.activeCategory
+		  // productCategory: this.activeCategory,
+		  // recommend:1 // 查询推荐商品
 		};
-		
-		// 如果不是查询全部,添加状态过滤条件
-		if (this.activeCategory !== 0) {
-		  params.productCategory = this.activeCategory;
+		if(keyword != null && keyword != ''){
+			params.searchKeyword = keyword
 		}
 		
+		// 分类逻辑
+		  if (this.activeCategory == -1) {
+			  // 默认场景:推荐查询
+			  params.isRecommended = 1;
+		    
+		  } else {
+		    // 分类查询:只带 productCategory
+		    params.productCategory = this.activeCategory;
+		  }
+		
 		getMallList(params).then(res => {
 		  if (res.data.code === 200) {
 		    const { rows, total } = res.data;
-		    rows.detailImages
 		    if (this.pageNum === 1) {
 		      this.goodsList = rows;
 		    } else {
 		      this.goodsList = [...this.goodsList, ...rows];
 		    }
-		    
+		    console.log("this.goodsList.length >= total",this.goodsList.length);
+		    console.log("this.goodsList.length >= total",this.goodsList.length >= total);
 		    // 判断是否还有更多数据
 		    this.noMoreData = this.goodsList.length >= total;
 		    uni.hideLoading();
@@ -188,8 +243,9 @@ export default {
     switchCategory(categoryId) {
 		console.log("dfdssdf",categoryId);
       this.activeCategory = categoryId;
+	  this.goodsList = [] // 切换时置空数据数组
       // 滚动到当前分类位置
-	  this.loadMallData()
+	  this.loadMallData(this.searchKeyword.trim())
       this.$nextTick(() => {
         this.scrollToActiveCategory(categoryId);
       });
@@ -198,6 +254,7 @@ export default {
     // 滚动到激活的分类  
     scrollToActiveCategory(categoryId) {
       const index = this.dictData.mall_product_category.findIndex(item => item.id == categoryId);
+	  console.log("index",index);
       if (index > -1) {
         // 计算滚动位置,让当前分类居中显示
         const itemWidth = 120; // 每个分类项大约120rpx宽度
@@ -211,14 +268,15 @@ export default {
     
     // 搜索处理
     handleSearch() {
-      if (!this.searchKeyword.trim()) {
-        uni.showToast({
-          title: '请输入搜索关键词',
-          icon: 'none'
-        });
-        return;
-      }
-      // 搜索逻辑已在computed中处理
+      // if (!this.searchKeyword.trim()) {
+      //   uni.showToast({
+      //     title: '请输入搜索关键词',
+      //     icon: 'none'
+      //   });
+      //   return;
+      // }
+	  const keyword = this.searchKeyword.trim().toLowerCase();
+	  this.loadMallData(keyword)
     },
     
     // 导航到商品详情
@@ -339,6 +397,11 @@ export default {
 .goods-container {
   padding: 20rpx;
 }
+.container {
+  height: 100vh;
+  display: flex;
+  flex-direction: column;
+}
 
 .goods-grid {
   display: grid;

+ 514 - 361
utils/mixins/dictMixin.js

@@ -1,17 +1,20 @@
-import { getDictData, getMultipleDictData } from '@/api/services/dict';
+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: {}
+	// 缓存的字典数据,格式为 { dictType: [{label, value, ...}, ...] }
+	data: {},
+	// 缓存过期时间,单位为毫秒
+	expireTime: 1000 * 60 * 60, // 1小时
+	// 缓存最后更新时间
+	lastUpdateTime: {},
+	// 正在加载的字典类型,用于防止重复请求
+	loading: {}
 };
 
 /**
@@ -24,355 +27,505 @@ const dictCache = {
  * 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;
-    }
-  }
-}; 
+	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;
+				console.log("this.dictData", this.dictData);
+				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<Object|Array>} 
+		 *          - 单个字典时返回 dictList 数组
+		 *          - 多个字典时返回 { dictType: dictList } 的 Map
+		 */
+		fetchDictData(dictTypes) {
+			// 标记这些字典类型正在加载
+			dictTypes.forEach(type => {
+				dictCache.loading[type] = true;
+			});
+
+			// --- 单个字典类型 ---
+			if (dictTypes.length === 1) {
+				const dictType = dictTypes[0];
+				console.log(`[DictMixin] Fetching single dictionary: ${dictType}`);
+				return getDictData(dictType).then(res => {
+					if (res.data.code === 200) {
+						let dictList = [];
+						if (dictType === 'mall_product_category') {
+							dictList.push({
+								dictLabel: '推荐',
+								dictValue: '-1'
+							});
+							dictList.push(...res.data.data);
+						} else {
+							dictList = res.data.data;
+						}
+
+						// 更新组件数据和缓存
+						this.$set(this.dictData, dictType, dictList);
+						this.updateDictCache(dictType, dictList);
+						delete dictCache.loading[dictType];
+
+						return dictList;
+					} else {
+						console.error(`获取字典[${dictType}]数据失败:`, res.data.msg);
+						delete dictCache.loading[dictType];
+						return Promise.reject(res.data.msg);
+					}
+				}).catch(err => {
+					delete dictCache.loading[dictType];
+					throw err;
+				});
+			}
+
+			// --- 多个字典类型,并发请求 ---
+			console.log(`[DictMixin] Concurrently fetching ${dictTypes.length} dictionaries: ${dictTypes.join(', ')}`);
+
+			const requests = dictTypes.map(dictType => {
+				return getDictData(dictType).then(res => {
+					if (res.data.code === 200) {
+						let dictList = [];
+						if (dictType === 'mall_product_category') {
+							dictList.push({
+								dictLabel: '推荐',
+								dictValue: '-1'
+							});
+							dictList.push(...res.data.data);
+						} else {
+							dictList = res.data.data;
+						}
+
+						this.$set(this.dictData, dictType, dictList);
+						this.updateDictCache(dictType, dictList);
+						delete dictCache.loading[dictType];
+
+						return {
+							dictType,
+							dictList,
+							success: true
+						};
+					} else {
+						console.error(`获取字典[${dictType}]数据失败:`, res.data.msg);
+						delete dictCache.loading[dictType];
+						return {
+							dictType,
+							dictList: [],
+							success: false,
+							msg: res.data.msg
+						};
+					}
+				}).catch(err => {
+					console.error(`获取字典[${dictType}]异常:`, err);
+					delete dictCache.loading[dictType];
+					return {
+						dictType,
+						dictList: [],
+						success: false,
+						msg: err
+					};
+				});
+			});
+
+			// 等所有请求完成
+			return Promise.allSettled(requests).then(results => {
+				const dictMap = {};
+				const failed = [];
+
+				results.forEach(r => {
+					if (r.status === 'fulfilled') {
+						const {
+							dictType,
+							dictList,
+							success,
+							msg
+						} = r.value;
+						if (success) {
+							dictMap[dictType] = dictList;
+						} else {
+							failed.push({
+								dictType,
+								msg
+							});
+						}
+					} else {
+						// 理论上不会走这里,因为 catch 已经返回对象了
+						console.error(`字典请求失败:`, r.reason);
+					}
+				});
+
+				console.log(
+					`[DictMixin] Loaded ${Object.keys(dictMap).length} dictionaries, failed ${failed.length}`
+					);
+
+				if (failed.length > 0) {
+					console.warn('以下字典加载失败:', failed);
+				}
+
+				return dictMap;
+			});
+		},
+
+		/**
+		 * 从服务器获取字典数据
+		 * @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];
+		// var dictList = []
+		// if(dictType === 'mall_product_category'){
+		// 	dictList.push({
+		// 		dictLabel:'推荐',
+		// 		dictValue:'-1'
+		// 	})
+		// 	// 展开数组追加
+		// 	 dictList.push(...res.data.data);
+		// }else{
+		// 	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;
+		}
+	}
+};