ext.liuqiwen3 3 órája%!(EXTRA string=)
szülő
commit
cac84f8384

+ 48 - 0
api/customerService.js

@@ -0,0 +1,48 @@
+import request from "@/utils/request.js";
+/**
+ * armg-2025/8/15-获取团队客服列表
+ * @param page 页码
+ * @param limit 每页数量
+ */
+export function getCustomerServiceList() {
+  return request.get('im/team/list');
+}
+
+/**
+ * armg-2025/8/18-创建群聊
+ * @param imGroupChat 
+ * @param chatName 群聊名称
+ * @param chatIntroduction 群聊简介
+ */
+export function createGroupChat(imGroupChat) {
+  return request.post('im/groupchat/create',imGroupChat);
+}
+
+/**
+ * armg-2025/8/19-群聊加人
+ * @param imRelationship 
+ * @param chatCode 群组id
+ * @param type 类型(1团队、2群聊) 
+ * @param userId 需要入群的人的id
+ */
+export function createGroupAdd(imRelationship) {
+  return request.post('im/groupchat/add',imRelationship);
+}
+
+/**
+ * armg-2025/8/20-根据用户id查询群聊id
+ * @param userId 
+ */
+export function getGroupchatList(data) {
+  return request.get('im/groupchat/selectlist',data);
+}
+
+/**
+ * armg-2025/8/21-查询是否禁言
+ * @param  userId
+ * 0=不禁言
+ * 1=禁言
+ */
+export function interdictionChatApi(uid) {
+  return request.get(`interdiction/${uid}`);
+}

+ 14 - 0
api/merchant.js

@@ -104,10 +104,24 @@ export function templatesList(data) {
 export function productSave(data) {
   return request.post(`product/save`,data);
 }
+/**
+ * 修改商品
+ * @param
+ */
+export function productUpdate(data) {
+  return request.post(`product/update`,data);
+}
 /**
  * 获取运费模板
  * @param
  */
 export function productInfo(id) {
   return request.get(`product/info/${id}`);
+}
+/**
+ * 商品删除
+ * @param
+ */
+export function productDelete(id) {
+  return request.get(`product/delete/${id}`);
 }

+ 145 - 0
components/Authorize.vue

@@ -0,0 +1,145 @@
+<template>
+	<view>
+		<view class='Popup' v-if='isShowAuth'>
+		   <image :src='logoUrl'></image>
+		   <view class='title'>授权提醒</view>
+		   <view class='tip'>请授权头像等信息,以便为您提供更好的服务</view>
+		   <view class='bottom flex'>
+		      <view class='item' @click='close'>随便逛逛</view>
+			  <!-- #ifdef APP-PLUS -->
+			  <button class='item grant' @click="setUserInfo">去授权</button>
+			  <!-- #endif -->
+			  <!-- #ifdef MP -->
+			  <button class='item grant'  type="primary" open-type="getUserInfo" lang="zh_CN" @getuserinfo="setUserInfo">去授权</button>
+			  <!-- #endif -->
+		   </view>
+		</view>
+		<view class='mask' v-if='isShowAuth' @click='close'></view>
+	</view>
+</template>
+
+<script>
+	const app = getApp();
+	import Cache from '../utils/cache';
+	import { getLogo } from '../api/public';
+	import { LOGO_URL } from '../config/cache';
+	import { mapGetters } from 'vuex';
+	import Routine from '../libs/routine';
+	
+	export default {
+		name:'Authorize',
+		props:{
+			isAuto:{
+				type:Boolean,
+				default:true
+			},
+			isGoIndex:{
+				type:Boolean,
+				default:true
+			},
+			isShowAuth:{
+				type:Boolean,
+				default:false
+			}
+		},
+		data(){
+			return {
+				logoUrl:''
+			}
+		},
+		computed:mapGetters(['isLogin','userInfo']),
+		watch:{
+			isLogin(n){
+				n === true && this.$emit('onLoadFun',this.userInfo);
+			}
+		},
+		created() {
+			this.getLogoUrl();
+			this.setAuthStatus();
+		},
+		methods:{
+			setAuthStatus(){
+				Routine.authorize().then(res=>{
+					if(res.islogin === false)
+						this.setUserInfo();
+					else
+						this.$emit('onLoadFun',this.userInfo);
+				}).catch(res=>{
+					if (this.isAuto) 
+						this.$emit('authColse',true);
+				})
+			},
+			getUserInfo(code){
+				Routine.getUserInfo().then(res=>{
+					let userInfo = res.userInfo
+					userInfo.code = code;
+					userInfo.spread_spid = app.globalData.spid;//获取推广人ID
+					userInfo.spread_code = app.globalData.code;//获取推广人分享二维码ID
+					userInfo.avatar  = userInfo.userInfo.avatarUrl;
+					userInfo.city  = userInfo.userInfo.city;
+					userInfo.country  = userInfo.userInfo.country;
+					userInfo.nickName  = userInfo.userInfo.nickName;
+					userInfo.province  = userInfo.userInfo.province;
+					userInfo.sex  = userInfo.userInfo.gender;
+					Routine.authUserInfo(code,userInfo).then(res=>{
+						uni.hideLoading();
+						this.$emit('authColse',false);
+						this.$emit('onLoadFun',this.userInfo);
+					}).catch(res=>{
+						uni.hideLoading();
+						uni.showToast({
+							title:res.message,
+							icon:'none',
+							duration:2000
+						});
+					})
+				}).catch(res =>{
+					uni.hideLoading();
+				})
+			},
+			setUserInfo(){
+				uni.showLoading({title:'正在登录中'});
+				Routine.getCode().then(code=>{
+					this.getUserInfo(code);
+				}).catch(res=>{
+					uni.hideLoading();
+				})
+			},
+			getLogoUrl(){
+				let that = this;
+				if (Cache.has(LOGO_URL)) {
+					this.logoUrl = Cache.get(LOGO_URL);
+					return;
+				}
+				getLogo().then(res=>{
+					that.logoUrl = res.data.logoUrl
+					Cache.set(LOGO_URL,that.logoUrl);
+				})
+			},
+			close(){
+				let pages = getCurrentPages(), currPage  = pages[pages.length - 1];
+				if(this.isGoIndex){
+					uni.switchTab({url:'/pages/index/index'});
+				} else {
+					this.$emit('authColse',false);
+				}
+				// if (currPage && currPage.isShowAuth != undefined){
+				// 	currPage.isShowAuth = true;
+				// }
+			},
+		}
+	}
+</script>
+
+<style scoped lang='scss'>
+	.Popup{width:500rpx;background-color:#fff;position:fixed;top:50%;left:50%;margin-left:-250rpx;transform:translateY(-50%);z-index:320;}
+	.Popup image{width:150rpx;height:150rpx;margin:-67rpx auto 0 auto;display:block;border: 8rpx solid #fff;border-radius: 50%}
+	.Popup .title{font-size:28rpx;color:#000;text-align:center;margin-top: 30rpx}
+	.Popup .tip{font-size:22rpx;color:#555;padding:0 24rpx;margin-top:25rpx;}
+	.Popup .bottom .item{width:50%;height:80rpx;background-color:#eeeeee;text-align:center;line-height:80rpx;font-size:24rpx;color:#666;margin-top:54rpx;}
+	.Popup .bottom .item.on{width: 100%}
+	.flex{display:flex;}
+	.Popup .bottom .item.grant{font-size:28rpx;color:#fff;font-weight:bold;background-color:$theme-color;border-radius:0;padding:0;}
+	.mask{position:fixed;top:0;right:0;left:0;bottom:0;background-color:rgba(0,0,0,0.65);z-index:310;}
+	
+</style>

+ 125 - 116
components/CategorySelector/index.vue

@@ -6,7 +6,7 @@
           v-for="item in categoryList"
           :key="item.id"
           class="first-item"
-          :class="{ active: currentFirstLevel === item.id }"
+          :class="{ active: currentFirstLevel === item.id || isFirstLevelAllSelected(item) }"
           @click="selectFirstLevel(item)"
       >
         <view class="item-content">
@@ -29,7 +29,7 @@
           v-for="child in currentSecondLevel"
           :key="child.id"
           class="second-item"
-          :class="{ active: selectedSecondLevel.includes(child.id) }"
+          :class="{ active: selectedSecondLevel.includes(String(child.id)) }"
           @click="toggleSecondLevel(child)"
       >
         <text class="category-name">{{ child.name }}</text>
@@ -78,7 +78,7 @@ const hasSecondLevel = computed(() => currentSecondLevel.value.length > 0)
 const getSelectedChildCount = (firstLevelItem) => {
   if (!firstLevelItem.child) return 0
   return firstLevelItem.child.filter(child =>
-      selectedSecondLevel.value.includes(child.id)
+      selectedSecondLevel.value.includes(String(child.id))  // 转为字符串
   ).length
 }
 
@@ -86,7 +86,7 @@ const getSelectedChildCount = (firstLevelItem) => {
 const isFirstLevelAllSelected = (firstLevelItem) => {
   if (!firstLevelItem.child || firstLevelItem.child.length === 0) {
     // 如果一级分类没有子分类,直接检查是否选中
-    return selectedSecondLevel.value.includes(firstLevelItem.id)
+    return selectedSecondLevel.value.includes(String(firstLevelItem.id))  // 转为字符串
   }
 
   const childCount = firstLevelItem.child.length
@@ -107,14 +107,15 @@ const selectFirstLevel = (item) => {
 
 // 切换二级分类选中状态
 const toggleSecondLevel = (child) => {
-  const index = selectedSecondLevel.value.indexOf(child.id)
+  const childId = String(child.id)
+  const index = selectedSecondLevel.value.indexOf(childId)
 
   if (index > -1) {
     // 取消选中
     selectedSecondLevel.value.splice(index, 1)
   } else {
     // 选中
-    selectedSecondLevel.value.push(child.id)
+    selectedSecondLevel.value.push(childId)
   }
 
   emitSelectionChange()
@@ -122,26 +123,45 @@ const toggleSecondLevel = (child) => {
 
 // 获取所有选中的分类ID(根据规则:全选父类才包含父类ID,否则只包含子类ID)
 const getSelectedIds = () => {
-  const selectedIds = [...selectedSecondLevel.value]
-
-  // 遍历所有一级分类,检查是否需要添加一级分类ID
-  props.categoryList.forEach(firstLevel => {
-    if (isFirstLevelAllSelected(firstLevel)) {
-      // 如果全部子类选中,添加一级分类ID,并移除所有子分类ID
-      selectedIds.push(firstLevel.id)
-      // 移除该一级分类下的所有子分类ID
-      if (firstLevel.child) {
-        firstLevel.child.forEach(child => {
-          const childIndex = selectedIds.indexOf(child.id)
-          if (childIndex > -1) {
-            selectedIds.splice(childIndex, 1)
+  console.log('当前选中状态:', {
+    allCategories: props.categoryList,
+    selectedChildren: selectedSecondLevel.value
+  })
+
+  const result = []
+
+  // 遍历一级分类
+  for (const category of props.categoryList) {
+    const parentId = String(category.id)
+
+    if (category.child && category.child.length > 0) {
+      // 有子分类的情况
+      const allChildIds = category.child.map(child => String(child.id))
+      const isAllSelected = allChildIds.every(id =>
+          selectedSecondLevel.value.includes(id)
+      )
+
+      if (isAllSelected) {
+        // 全选子类,只添加父类ID
+        result.push(parentId)
+      } else {
+        // 非全选,添加选中的子类
+        allChildIds.forEach(id => {
+          if (selectedSecondLevel.value.includes(id)) {
+            result.push(id)
           }
         })
       }
+    } else {
+      // 没有子分类,直接检查是否选中
+      if (selectedSecondLevel.value.includes(parentId)) {
+        result.push(parentId)
+      }
     }
-  })
+  }
 
-  return selectedIds
+  console.log('计算出的选中IDs:', result)
+  return result
 }
 
 // 发射选择变化事件
@@ -152,63 +172,96 @@ const emitSelectionChange = () => {
     secondLevel: selectedSecondLevel.value
   })
 }
+// 统一设置选中状态的方法
+const setSelectedState = (ids) => {
+  selectedSecondLevel.value = []
+  currentFirstLevel.value = null
+
+  console.log('设置选中IDs:', ids)
+  console.log('可用分类数据:', props.categoryList)
 
-// 初始化选中状态
-const initSelected = () => {
-  selectedSecondLevel.value = [];
-  currentFirstLevel.value = null;
+  if (!ids || !Array.isArray(ids) || ids.length === 0) {
+    initDefaultView()
+    return
+  }
+
+  // 将传入的ID统一转换为字符串
+  const stringIds = ids.map(id => String(id))
 
-  console.log('初始化选中IDs:', props.selectedIds);
-  console.log('分类数据:', props.categoryList);
+  // 首先处理所有选中的分类
+  stringIds.forEach(id => {
+    let found = false
 
-  if (!props.selectedIds || !Array.isArray(props.selectedIds) || props.selectedIds.length === 0) {
-    // 设置默认显示
-    const firstWithChildren = props.categoryList.find(item => item.child && item.child.length > 0);
-    if (firstWithChildren) {
-      currentFirstLevel.value = firstWithChildren.id;
+    // 先查找二级分类
+    for (const parent of props.categoryList) {
+      if (parent.child) {
+        const child = parent.child.find(c => String(c.id) === id)
+        if (child) {
+          if (!selectedSecondLevel.value.includes(id)) {
+            selectedSecondLevel.value.push(id)
+          }
+          found = true
+          break
+        }
+      }
     }
-    return;
-  }
 
-  props.selectedIds.forEach(id => {
-    // 确保id是字符串类型进行比较
-    const idStr = String(id);
-
-    // 检查是否是一级分类(表示该分类下的所有子分类都被选中)
-    const firstLevel = props.categoryList.find(item => String(item.id) === idStr);
-    if (firstLevel && firstLevel.child) {
-      // 如果是一级分类且全选,选中所有子分类
-      firstLevel.child.forEach(child => {
-        const childIdStr = String(child.id);
-        if (!selectedSecondLevel.value.includes(childIdStr)) {
-          selectedSecondLevel.value.push(childIdStr);
+    // 如果没有找到对应的二级分类,检查是否是一级分类
+    if (!found) {
+      const firstLevel = props.categoryList.find(item => String(item.id) === id)
+      if (firstLevel) {
+        // 如果是一级分类,检查是否有子分类
+        if (firstLevel.child && firstLevel.child.length > 0) {
+          // 有子分类的一级分类:选中所有子分类
+          firstLevel.child.forEach(child => {
+            const childId = String(child.id)
+            if (!selectedSecondLevel.value.includes(childId)) {
+              selectedSecondLevel.value.push(childId)
+            }
+          })
+        } else {
+          // 没有子分类的一级分类:直接选中
+          if (!selectedSecondLevel.value.includes(id)) {
+            selectedSecondLevel.value.push(id)
+          }
         }
-      });
-    } else {
-      // 如果是二级分类或没有子分类的一级分类,直接选中
-      if (!selectedSecondLevel.value.includes(idStr)) {
-        selectedSecondLevel.value.push(idStr);
       }
     }
-  });
+  })
 
-  console.log('初始化后的选中子分类:', selectedSecondLevel.value);
+  console.log('设置后的选中子分类:', selectedSecondLevel.value)
+
+  // 设置当前显示的选中项
+  setCurrentView()
+
+  // 触发选择变化事件
+  emitSelectionChange()
+}
 
-  // 设置默认显示的第一个有选中项的一级分类
+// 设置当前显示视图
+const setCurrentView = () => {
+  // 查找第一个有选中项的一级分类
   const firstWithSelected = props.categoryList.find(item => {
     if (item.child) {
-      return item.child.some(child => selectedSecondLevel.value.includes(String(child.id)));
+      return item.child.some(child =>
+          selectedSecondLevel.value.includes(String(child.id))  // 转为字符串
+      )
     }
-    return selectedSecondLevel.value.includes(String(item.id));
-  });
+    return selectedSecondLevel.value.includes(String(item.id))  // 转为字符串
+  })
 
   if (firstWithSelected) {
-    currentFirstLevel.value = firstWithSelected.id;
+    currentFirstLevel.value = firstWithSelected.id
   } else {
-    const firstWithChildren = props.categoryList.find(item => item.child && item.child.length > 0);
-    if (firstWithChildren) {
-      currentFirstLevel.value = firstWithChildren.id;
-    }
+    initDefaultView()
+  }
+}
+
+// 初始化默认视图
+const initDefaultView = () => {
+  const firstWithChildren = props.categoryList.find(item => item.child && item.child.length > 0)
+  if (firstWithChildren) {
+    currentFirstLevel.value = firstWithChildren.id
   }
 }
 
@@ -216,70 +269,26 @@ const initSelected = () => {
 const clearSelection = () => {
   selectedSecondLevel.value = []
   currentFirstLevel.value = null
+  initDefaultView()
   emitSelectionChange()
 }
-// 设置选中状态的方法
-const setSelectedIds = (ids) => {
-  selectedSecondLevel.value = [];
-  currentFirstLevel.value = null;
-
-  console.log('设置选中IDs:', ids);
-  console.log('可用分类列表:', props.categoryList);
-
-  if (!ids || !Array.isArray(ids) || ids.length === 0) return;
-
-  ids.forEach(id => {
-    // 检查是否是一级分类(表示该分类下的所有子分类都被选中)
-    const firstLevel = props.categoryList.find(item => item.id == id);
-    if (firstLevel && firstLevel.child) {
-      // 如果是一级分类且全选,选中所有子分类
-      firstLevel.child.forEach(child => {
-        if (!selectedSecondLevel.value.includes(child.id)) {
-          selectedSecondLevel.value.push(child.id);
-        }
-      });
-    } else {
-      // 如果是二级分类或没有子分类的一级分类,直接选中
-      // 确保id是字符串类型(因为分类ID可能是字符串或数字)
-      const idStr = String(id);
-      if (!selectedSecondLevel.value.includes(idStr)) {
-        selectedSecondLevel.value.push(idStr);
-      }
-    }
-  });
-
-  console.log('设置后的选中子分类:', selectedSecondLevel.value);
 
-  // 设置默认显示的第一个有选中项的一级分类
-  const firstWithSelected = props.categoryList.find(item => {
-    if (item.child) {
-      return item.child.some(child => selectedSecondLevel.value.includes(child.id));
-    }
-    return selectedSecondLevel.value.includes(item.id);
-  });
-
-  if (firstWithSelected) {
-    currentFirstLevel.value = firstWithSelected.id;
-  } else {
-    // 如果没有选中项,显示第一个有子分类的一级分类
-    const firstWithChildren = props.categoryList.find(item => item.child && item.child.length > 0);
-    if (firstWithChildren) {
-      currentFirstLevel.value = firstWithChildren.id;
-    }
-  }
-
-  // 触发选择变化事件
-  emitSelectionChange();
-};
+// 设置选中状态的方法(暴露给父组件)
+const setSelectedIds = (ids) => {
+  setSelectedState(ids)
+}
 
 // 监听props变化
 watch(() => props.selectedIds, (newVal) => {
-  initSelected()
+  console.log('props.selectedIds 变化:', newVal)
+  setSelectedState(newVal)
 }, {immediate: true})
 
 watch(() => props.categoryList, (newVal) => {
+  console.log('分类数据变化:', newVal)
   if (newVal && newVal.length > 0) {
-    initSelected()
+    // 重新应用选中状态
+    setSelectedState(props.selectedIds)
   }
 })
 

+ 130 - 0
components/home/index.vue

@@ -0,0 +1,130 @@
+<template>
+  <view style="touch-action: none">
+    <view
+      class="home"
+      style="position: fixed"
+      :style="{ top: top + 'px' }"
+      id="right-nav"
+      @touchmove.stop.prevent="setTouchMove"
+    >
+      <view
+        class="homeCon bg-color-red"
+        :class="appStore.homeActiveComputed === true ? 'on' : ''"
+        v-if="appStore.homeActiveComputed"
+      >
+        <navigator
+          hover-class="none"
+          url="/pages/index/index"
+          open-type="switchTab"
+          class="iconfont icon-shouye-xianxing"
+        ></navigator>
+        <navigator
+          hover-class="none"
+          url="/pages/order_addcart/order_addcart"
+          open-type="switchTab"
+          class="iconfont icon-caigou-xianxing"
+        ></navigator>
+        <navigator
+          hover-class="none"
+          url="/pages/user/index"
+          open-type="switchTab"
+          class="iconfont icon-yonghu1"
+        ></navigator>
+      </view>
+      <view @click="open" class="pictrueBox">
+        <view class="pictrue">
+          <image
+            :src="
+              appStore.homeActiveComputed === true
+                ? '/static/images/close.gif'
+                : '/static/images/open.gif'
+            "
+            class="image"
+          />
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref } from 'vue';
+import { useAppStore } from "@/stores/app.js";
+const appStore = useAppStore();
+const top = ref(500);
+const setTouchMove = (e) => {
+  if (e.touches[0].clientY < 545 && e.touches[0].clientY > 66) {
+    top.value = e.touches[0].clientY;
+    // that.setData({
+    // 	top: e.touches[0].clientY
+    // })
+  }
+};
+const open = () => {
+	appStore.homeActiveComputed
+		? appStore.CLOSE_HOME()
+		: appStore.OPEN_HOME();
+};
+</script>
+
+<style scoped>
+.pictrueBox {
+  width: 130rpx;
+  height: 120rpx;
+}
+
+/*返回主页按钮*/
+.home {
+  position: fixed;
+  color: white;
+  text-align: center;
+  z-index: 9999;
+  right: 15rpx;
+  display: flex;
+}
+
+.home .homeCon {
+  border-radius: 50rpx;
+  opacity: 0;
+  height: 0;
+  color: $theme-color;
+  width: 0;
+}
+
+.home .homeCon.on {
+  opacity: 1;
+  animation: bounceInRight 0.5s cubic-bezier(0.215, 0.61, 0.355, 1);
+  width: 300rpx;
+  height: 86rpx;
+  margin-bottom: 20rpx;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background: #f44939 !important;
+}
+
+.home .homeCon .iconfont {
+  font-size: 48rpx;
+  color: #fff;
+  display: inline-block;
+  margin: 0 auto;
+}
+
+.home .pictrue {
+  width: 86rpx;
+  height: 86rpx;
+  border-radius: 50%;
+  margin: 0 auto;
+}
+
+.home .pictrue .image {
+  width: 100%;
+  height: 100%;
+  border-radius: 50%;
+  transform: rotate(90deg);
+  ms-transform: rotate(90deg);
+  moz-transform: rotate(90deg);
+  webkit-transform: rotate(90deg);
+  o-transform: rotate(90deg);
+}
+</style>

+ 57 - 0
components/shareRedPackets/index.vue

@@ -0,0 +1,57 @@
+<template>
+	<view class='sharing-packets' :class='sharePacket.isState==true?"on":""'>
+	   <view class='iconfont icon-guanbi' @click="closeShare"></view>
+	   <view class='line'></view>
+	   <view class='sharing-con' @click='goShare'>
+	      <image src='../../static/images/red-packets.png'></image>
+	      <view class='text font-color'>
+	        <view>会员分享返</view>
+	        <view class='money'><text class='label'>¥</text>{{sharePacket.priceName}}</view>
+	        <view class='tip'>下单即返佣金</view>
+	        <view class='shareBut'>立即分享</view>
+	      </view>
+	   </view>  
+	</view>
+</template>
+
+<script>
+	export default {
+		
+		props: {
+			    sharePacket: {
+					type: Object,
+					default: function(){
+						return {isState: true,priceName:''}
+					}
+			    }
+		},
+		data() {
+			return {
+
+			};
+		},
+		
+		methods: {
+			closeShare:function(){
+				  this.$emit('closeChange');
+			    },
+				goShare:function(){
+				      this.$emit('listenerActionSheet');
+				    }
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.sharing-packets{position:fixed;left:30rpx;bottom:200rpx;z-index:5;transition:all 0.3s ease-in-out 0s;opacity:1;transform: scale(1);}
+	.sharing-packets.on{transform: scale(0);opacity:0;}
+	.sharing-packets .iconfont{width:44rpx;height:44rpx;border-radius:50%;text-align:center;line-height:44rpx;background-color:#999;font-size:20rpx;color:#fff;margin:0 auto;box-sizing:border-box;padding-left:1px;}
+	.sharing-packets .line{width:2rpx;height:40rpx;background-color:#999;margin:0 auto;}
+	.sharing-packets .sharing-con{width:187rpx;height:210rpx;position:relative;}
+	.sharing-packets .sharing-con image{width:100%;height:100%;}
+	.sharing-packets .sharing-con .text{position:absolute;top:30rpx;font-size:20rpx;width:100%;text-align:center;}
+	.sharing-packets .sharing-con .text .money{font-size:32rpx;font-weight:bold;margin-top:5rpx;}
+	.sharing-packets .sharing-con .text .money .label{font-size:20rpx;}
+	.sharing-packets .sharing-con .text .tip{font-size:18rpx;color:#999;margin-top:5rpx;}
+	.sharing-packets .sharing-con .text .shareBut{font-size:22rpx;color:#fff;margin-top:18rpx;height:50rpx;line-height:50rpx;}
+</style>

+ 23 - 0
pages.json

@@ -506,6 +506,29 @@
 						"navigationBarBackgroundColor": "#ffe079",
 						"navigationBarTextStyle": "black"
 					}
+				},
+				{
+					"path": "customer_service_message/index",
+					"style": {
+						"navigationBarTitleText": "客服消息",
+						"navigationBarBackgroundColor": "#ffe079",
+						"navigationBarTextStyle": "black",
+						"app-plus": {
+							// #ifdef APP-PLUS
+							"titleNView": {
+								"type": "default"
+							}
+							// #endif
+						}
+					}
+				},
+				{
+					"path": "user_goods_collection/index",
+					"style": {
+						"navigationBarTitleText": "收藏商品",
+						"navigationBarBackgroundColor": "#ffe079",
+						"navigationBarTextStyle": "black"
+					}
 				}
 			]
 		}

+ 152 - 33
pages/goods_details/index.vue

@@ -30,9 +30,9 @@
       <template #center> </template>
       <template #right>
         <!-- 分享 -->
-        <view @click="handleShare" class="share share-top">
-          <uni-icons size="24" type="redo"></uni-icons>
-        </view>
+<!--        <view @click="handleShare" class="share share-top">-->
+<!--          <uni-icons size="24" type="redo"></uni-icons>-->
+<!--        </view>-->
       </template>
     </up-navbar>
     <!-- 	<view class='iconfont icon-xiangzuo' :style="'top:'+navH/2+'rpx'" @tap='returns'></view> -->
@@ -54,11 +54,14 @@
           <view class="pad30 container">
             <view class="wrapper mb30 borRadius14" style="margin-top: 0;">
               <view class="product-info">
-                <view style="width: 80%;">
+                <view style="width:100%;">
                   <view class="share acea-row row-between row-bottom">
                     <view class="money font-color">
                       <text class="num">¥{{ attr.productSelect.storePrice }}</text>
                     </view>
+                    <view @click="listenerActionSheet" class="share share-top">
+                      <uni-icons size="24" type="redo"></uni-icons>
+                    </view>
                   </view>
                   <view class="label acea-row row-between-wrapper">
                     <view>工费:{{ attr.productSelect.price || 0 }}元/g</view>
@@ -66,15 +69,20 @@
                     <view>
                       附加费:{{ attr.productSelect.additionalAmount || "" }}
                     </view>
+                    <view >
+                      销量:{{
+                        Number(productInfo?.sales || 0) + productInfo.ficti || "0"
+                      }}件
+                    </view>
                   </view>
                 </view>
-                <view class="sales-container">
-                  <text class="sales-text">
-                    销量:{{
-                      Number(productInfo?.sales || 0) + productInfo.ficti || "0"
-                    }}件
-                  </text>
-                </view>
+<!--                <view class="sales-container">-->
+<!--                  <text class="sales-text">-->
+<!--                    销量:{{-->
+<!--                      Number(productInfo?.sales || 0) + productInfo.ficti || "0"-->
+<!--                    }}件-->
+<!--                  </text>-->
+<!--                </view>-->
               </view>
 
               <view class="introduce" style="margin-bottom: 0;">{{ productInfo.storeName }}</view>
@@ -216,21 +224,22 @@
       </scroll-view>
     </view>
     <view class="footer acea-row row-between-wrapper">
-      <navigator
-        open-type="switchTab"
-        class="animated item"
-        :class="animated == true ? 'bounceIn' : ''"
-        url="/pages/mall/index"
-        hover-class="none"
-      >
-        <uni-icons
-          size="22"
-          color="#666"
-          customPrefix="iconfont"
-          type="icon-shouye"
-        ></uni-icons>
-        <view>首页</view>
-      </navigator>
+<!--      <navigator-->
+<!--        open-type="switchTab"-->
+<!--        class="animated item"-->
+<!--        :class="animated == true ? 'bounceIn' : ''"-->
+<!--        url="/pages/mall/index"-->
+<!--        hover-class="none"-->
+<!--      >-->
+<!--        <uni-icons-->
+<!--          size="22"-->
+<!--          color="#666"-->
+<!--          customPrefix="iconfont"-->
+<!--          type="icon-shouye"-->
+<!--        ></uni-icons>-->
+<!--        <view>首页</view>-->
+<!--      </navigator>-->
+
       <button
         @click="toMessagePage"
         open-type="contact"
@@ -245,6 +254,27 @@
         ></uni-icons>
         <view>客服</view>
       </button>
+      <button
+          @click="setCollect"
+          hover-class="none"
+          class="item"
+      >
+        <uni-icons
+            size="22"
+            color="#F8C008"
+            customPrefix="iconfont"
+            type="icon-shoucangxuanzhong"
+            v-if="userCollect"
+        ></uni-icons>
+        <uni-icons
+            size="22"
+            color="#666"
+            customPrefix="iconfont"
+            type="icon-shoucang"
+            v-else
+        ></uni-icons>
+      <view>收藏</view>
+      </button>
       <block v-if="type === 'normal'">
         <view
           class="animated item"
@@ -335,6 +365,34 @@
       @tabCouponType="tabCouponType"
     >
     </couponListWindow>
+    <!-- 分享按钮 -->
+    <view class="generate-posters acea-row row-middle" :class="posters ? 'on' : ''">
+      <!-- #ifndef MP -->
+      <view class="item" hover-class='none' v-if="weixinStatus === true" @click="H5ShareBox = true">
+        <view>
+          <image class="shareImg" src="@/static/images/wexin.png" mode="widthFix"></image>
+        </view>
+        <view class="">发送给朋友</view>
+      </view>
+      <!-- #endif -->
+      <!-- #ifdef MP -->
+      <view class="item" open-type="share" hover-class='none' @click="goFriend">
+        <view class="">
+          <image class="shareImg" src="@/static/images/wexin.png" mode="widthFix"></image>
+        </view>
+        <view class="">发送给朋友</view>
+      </view>
+      <!-- #endif -->
+      <view class="item" hover-class='none' @click="goPoster">
+        <view style="display: flex;justify-content: center;align-items: center;">
+          <view class="shareImg1">
+            <image class="img" src="@/static/images/picture.png" mode="widthFix"></image>
+          </view>
+        </view>
+        <view class="">生成海报</view>
+      </view>
+    </view>
+    <view class="mask" v-if="posters" @click="closePosters"></view>
   </view>
 </template>
 
@@ -345,7 +403,7 @@ import { useToast } from "@/hooks/useToast";
 import { useAppStore } from "@/stores/app.js";
 // import uQRCode from '@/js_sdk/Sansnn-uQRCode/uqrcode.js';
 import UQRCode from "uqrcodejs";
-import { getProductDetail, postCartAdd } from "@/api/store.js";
+import { getProductDetail, postCartAdd,collectDel,collectAdd } from "@/api/store.js";
 import { spread } from "@/api/user";
 import { getCoupons, getQrcode } from "@/api/api.js";
 import { getCartCounts } from "@/api/order.js";
@@ -357,6 +415,7 @@ import productConSwiper from "@/components/productConSwiper";
 import couponListWindow from "@/components/couponListWindow";
 import productWindow from "@/components/productWindow";
 import { isTabBarPage } from "@/utils/util.js";
+import $util from "@/utils/util.js";
 import { HTTP_REQUEST_URL_SHARE } from "@/config/app.js";
 import UniIcons from "../../uni_modules/uni-icons/components/uni-icons/uni-icons.vue";
 const { Toast } = useToast();
@@ -637,10 +696,10 @@ const getGoodsDetails = async () => {
       // #ifdef H5
       // make(uid.value);
       // ShareInfo();
-      // getImageBase64(productInfo.value.image);
+      getImageBase64(productInfo.value.image);
       // #endif
       // #ifdef MP
-      // getQrcodeFn();
+      getQrcodeFn();
       // #endif
     }
     // nextTick(() => {
@@ -889,10 +948,6 @@ const getPreOrderFn = () => {
   getPreOrder(params);
 };
 
-const closePosters = () => {
-  posters.value = false;
-};
-
 const posterImageClose = () => {
   canvasStatus.value = false;
 };
@@ -976,6 +1031,8 @@ const goPoster = async () => {
     mask: true,
   });
   posters.value = false;
+  console.log('PromotionCode.value',PromotionCode.value)
+  console.log('imgTop.value',imgTop.value)
   if (!PromotionCode.value) {
     uni.hideLoading();
     Toast({
@@ -1133,6 +1190,29 @@ const handleShare = () => {
     });
   }
 };
+
+/**
+ * 分享打开
+ *
+ */
+function listenerActionSheet () {
+  if (isLogin === false) {
+    toLogin();
+  } else {
+    // #ifdef H5
+    if (wechat.isWeixin() === true) {
+      weixinStatus = true;
+    }
+    // #endif
+    posters.value = true;
+
+  }
+}
+function closePosters() {
+  posters.value = false;
+}
+
+
 const goBack = () => {
   if (isTabBarPage()) {
     uni.switchTab({
@@ -1205,6 +1285,26 @@ const metalTypeFormatter = (val)=> {
 const toStore = () => {
   uni.navigateTo({ url: "/pages/merchant/index?merchantId="+sbMerchantInfo.value.id });
 }
+/**
+ *
+ *
+ * 收藏商品
+ */
+function setCollect () {
+  if (isLogin.value === false) {
+    toLogin();
+  } else {
+    if (userCollect.value) {
+      collectDel(productInfo.value.id).then(res => {
+        userCollect.value = !userCollect.value;
+      })
+    } else {
+      collectAdd(productInfo.value.id).then(res => {
+        userCollect.value = !userCollect.value;
+      })
+    }
+  }
+}
 </script>
 
 <style scoped lang="scss">
@@ -1963,6 +2063,23 @@ action-sheet-item {
   padding: 20rpx;
   margin-top: 30rpx;
 }
+.shareImg{
+  width: 70rpx;
+  height: 70rpx;
+  border-radius: 50%;
+}
+.shareImg1{
+  width: 70rpx;
+  height: 70rpx;
+  border-radius: 50%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background-color: #5590EB;
+  .img{
+    width: 40rpx;
+  }
+}
 </style>
 <style>
 .goods-nav-bar {
@@ -1977,4 +2094,6 @@ action-sheet-item {
   align-items: center;
   background-color: rgba(255, 255, 255, 0.8);
 }
+
+
 </style>

+ 9 - 2
pages/index/index.vue

@@ -136,7 +136,7 @@
                   <!-- <view class="txt">券</view> -->
                 </view>
                 <template v-if="item?.merchant?.id && (appStore.userInfo && !appStore.userInfo.merchant)">
-                  <view class="merchantInfo" @click="toMerchant(item.merchant.id)">
+                  <view class="merchantInfo" @click.stop="toMerchant(item.merchant.id)">
                     <image class="merchantLogo" :src="item.merchant.merchantLogo" mode="scaleToFill"></image>
                     <text class="merchantName">{{item.merchant.merchantName}}</text>
                     <uni-icons style="margin-left: 10rpx;" type="right" size="16" color="#999999"></uni-icons>
@@ -261,7 +261,14 @@ onShow(() => {
   }
 
   uni.setNavigationBarTitle({ title: site_name.value });
-  merchantId.value = appStore.merchantId || '';
+  if(appStore.merchantId && appStore.merchantId!=''){
+    merchantId.value = appStore.merchantId;
+  }else if(appStore?.userInfo?.merchant && appStore?.userInfo?.merchant.id){
+    merchantId.value = appStore.userInfo.merchant.id
+  }else{
+    merchantId.value = '';
+  }
+
 
   if(merchantId.value && merchantId.value!=''){
     getSbmerchantInfoFn();

+ 5 - 5
pages/merchantCenter/index.vue

@@ -136,11 +136,11 @@ const orderStatus = ref([
 const commonFunctions = ref([
   { src: '/static/images/setting/fabu.png', name: '发布商品',pageUrl:'/pages/merchantCenter/postInformation',show:true },
   { src: '/static/images/setting/shangpin.png', name: '商品管理',pageUrl:'/pages/merchantCenter/productManagement',show:true },
-  { src: '/static/images/setting/kucun.png', name: '库存管理',pageUrl:'/pages/users/user_address_list/index' ,show:true},
-  { src: '/static/images/setting/jinqian.png', name: '我的收益',pageUrl: '/pages/users/my_merchant/index' ,show:appStore.merchantId?true:false},
-  { src: '/static/images/setting/kabao.png', name: '卡包管理' ,show:true},
-  { src: '/static/images/setting/mendian.png', name: '门店推广',show:true },
-  { src: '/static/images/setting/dianpu.png', name: '我的商城' ,show:true},
+  { src: '/static/images/setting/kucun.png', name: '库存管理',pageUrl:'/pages/users/user_asset/asset_info/asset_info' ,show:true},
+  { src: '/static/images/setting/jinqian.png', name: '我的收益',pageUrl: '' ,show:true},
+  { src: '/static/images/setting/kabao.png', name: '卡包管理' ,pageUrl: '/pages/users/bank_card_manage/index' ,show:true},
+  { src: '/static/images/setting/mendian.png', name: '门店推广',pageUrl: '/pages/users/my_merchant/index' ,show:true },
+  { src: '/static/images/setting/dianpu.png', name: '我的商城' ,pageUrl: '/pages/users/bank_card_manage/index' ,show:true},
 ])
 const params = ref({
   page: 1,

+ 1 - 1
pages/merchantCenter/productCenter.vue

@@ -140,7 +140,7 @@ const getGroomList = async () => {
 };
 function addProduct (obj){
   uni.navigateTo({
-    url:`pages/merchantCenter/releaseProduct?id=${obj.id}`
+    url:`/pages/merchantCenter/releaseProduct?id=${obj.id}&isProductCenter=1`
   })
 }
 onReachBottom(() => {

+ 14 - 3
pages/merchantCenter/productManagement.vue

@@ -71,9 +71,10 @@
         </view>
 
         <view class="action-buttons">
+          <button class="btn btn-delete" @click="deleteFn(item,index)">删除</button>
           <button class="btn btn-offline" v-show="params.isShow==1" @click="OffShellFn(item,index)">下架</button>
           <button class="btn btn-offline" v-show="params.isShow==0" @click="PutOnShellFn(item,index)">上架</button>
-          <button class="btn btn-edit" @click="toEditProduct(item)">编辑</button>
+          <button class="btn btn-edit" v-show="params.isShow==0" @click="toEditProduct(item)">编辑</button>
         </view>
       </view>
       <view class="loadingicon acea-row row-center-wrapper" v-if="goodScroll">
@@ -97,7 +98,7 @@
 <script setup>
 import {computed, ref} from 'vue'
 import { onLoad, onShow, onReachBottom } from "@dcloudio/uni-app";
-import { productsList,productPutOnShell,productOffShell } from "@/api/merchant.js";
+import { productsList,productPutOnShell,productOffShell,productDelete } from "@/api/merchant.js";
 import { useAppStore } from "@/stores/app";
 
 const appStore = useAppStore();
@@ -190,6 +191,13 @@ function toEditProduct (obj){
     url:`/pages/merchantCenter/releaseProduct?id=${obj.id}`
   })
 }
+async function deleteFn(obj,index){
+  const {code} = await productDelete(obj.id);
+  if(code == 200){
+    uni.showToast({ title: "操作成功", icon: "none" });
+    goodsList.value.splice(index,1);
+  }
+}
 onReachBottom(() => {
   getGroomList();
 });
@@ -328,7 +336,10 @@ onReachBottom(() => {
   border: none;
 }
 
-
+.btn-delete {
+  background: #FEEAEA;
+  color: #F52929;
+}
 .btn-offline {
   background: #F5F7FA;
   color: #333;

+ 241 - 100
pages/merchantCenter/releaseProduct.vue

@@ -9,7 +9,7 @@
           :labelWidth="100"
       >
         <!-- 商品分类 -->
-        <view class="card-title">商品分类</view>
+        <view class="card-title" v-if="!isProductCenter">商品分类</view>
         <up-form-item
             class="form-item"
             label="商品分类"
@@ -17,6 +17,7 @@
             :borderBottom="false"
             @click="showCategory = true"
             :required="true"
+            v-if="!isProductCenter"
         >
           <up-input
               v-model="formData.categoryDisplayName"
@@ -51,6 +52,7 @@
             prop="keyword"
             :borderBottom="false"
             :required="true"
+            v-if="!isProductCenter"
         >
           <up-input
               v-model="formData.keyword"
@@ -64,6 +66,7 @@
             prop="storeInfo"
             :borderBottom="false"
             :required="true"
+            v-if="!isProductCenter"
         >
           <up-textarea
               v-model="formData.storeInfo"
@@ -77,6 +80,7 @@
             prop="unitName"
             :borderBottom="false"
             :required="true"
+            v-if="!isProductCenter"
         >
           <up-input
               v-model="formData.unitName"
@@ -87,7 +91,7 @@
         </up-form-item>
 
         <!-- 图片上传 -->
-        <view class="upload-section">
+        <view class="upload-section" v-if="!isProductCenter">
           <view class="upload-item">
             <view class="upload-label"><text class="required">*</text>商品封面图</view>
             <up-upload
@@ -111,7 +115,7 @@
           </view>
         </view>
 
-        <view class="upload-section">
+        <view class="upload-section" v-if="!isProductCenter">
           <view class="upload-item">
             <view class="upload-label"><text class="required">*</text>商品图片</view>
             <up-upload
@@ -143,6 +147,7 @@
             prop="metalType"
             :borderBottom="false"
             :required="true"
+            v-if="!isProductCenter"
         >
           <up-radio-group
               v-model="formData.metalType"
@@ -154,6 +159,7 @@
                 :key="index"
                 :label="item.name"
                 :name="item.code"
+                activeColor="#F8C008"
             >
             </up-radio>
           </up-radio-group>
@@ -178,10 +184,10 @@
         </up-form-item>
 
         <!-- 商品描述 -->
-        <view class="card-title">商品描述</view>
-        <view class="editor-section">
+        <view class="card-title" v-if="!isProductCenter">商品描述</view>
+        <view class="editor-section" v-if="!isProductCenter">
           <view class="editor-header">
-            <text class="editor-label"><text class="required">*</text>商品描述</text>
+            <text class="editor-label">商品描述</text>
             <text class="word-count">{{ descriptionText.length }}/500</text>
           </view>
           <sp-editor
@@ -358,9 +364,9 @@
 </template>
 
 <script setup>
-import { ref, computed, watch } from 'vue';
+import { ref, computed, watch,nextTick } from 'vue';
 import { onShow,onLoad } from "@dcloudio/uni-app";
-import { productCategory,productSave,templatesList,productInfo } from "@/api/merchant";
+import { productCategory,productSave,productUpdate,templatesList,productInfo } from "@/api/merchant";
 import CategorySelector from '@/components/CategorySelector';
 import { useAppStore } from "@/stores/app";
 import { useImageUpload } from "@/hooks/useImageUpload";
@@ -373,6 +379,9 @@ const { imageList, afterRead, deletePic, uploadLoading } = useImageUpload({
 const appStore = useAppStore();
 const merchantInfo = appStore.userInfo.merchant
 
+// 表单验证和提交
+const formRef = ref(null);
+
 // 表单数据
 const formData = ref({
   categoryIds: [], // 选中的分类ID数组
@@ -415,6 +424,9 @@ const previewImages = ref([]);
 const productImages = ref([]);
 const productImagesGg = ref([]);
 
+const productId = ref(null);
+const isProductCenter = ref(null);
+
 // 材质列表
 const materialList = ref([
   { name: '黄金',code:'au' },
@@ -428,7 +440,7 @@ const rules = ref({
     type: 'array',
     required: true,
     message: '请选择商品分类',
-    trigger: ['change']
+    trigger: ['blur','change']
   },
   storeName: {
     type: 'string',
@@ -464,7 +476,7 @@ const rules = ref({
     type: 'string',
     required: true,
     message: '请选择材质',
-    trigger: ['change']
+    trigger: ['blur','change']
   },
   weight: {
     type: 'string',
@@ -491,21 +503,34 @@ const rules = ref({
     type: 'string',
     pattern: /^\d*$/,
     message: '排序号必须是整数',
-    trigger: ['blur', 'change']
+    trigger: ['blur', 'change'],
+    validator: (rule, value) => {
+      if (!value || value.trim().length === 0) return true; // 可选字段,为空时通过
+      return /^\d+$/.test(value);
+    }
   },
   stock: {
     type: 'string',
     required: true,
     pattern: /^\d*$/,
     message: '库存必须是整数',
-    trigger: ['blur', 'change']
+    trigger: ['blur', 'change'],
+    validator: (rule, value) => {
+      if (!value || value.trim().length === 0) return false;
+      return /^\d+$/.test(value);
+    }
   },
   barCode: {
     type: 'string',
     required: true,
     pattern: /^\d*$/,
     message: '商品编号必须是整数',
-    trigger: ['blur', 'change']
+    trigger: ['blur', 'change'],
+    validator: (rule, value) => {
+      if (!value || value.trim().length === 0) return false;
+      return /^\d+$/.test(value);
+    }
+
   },
 });
 
@@ -516,9 +541,13 @@ onShow(() => {
 onLoad(async (options)=>{
   await getProductCategory();
   await getTempData();
-  console.log(options);
+  console.log(options)
   if(options.id){
+    productId.value = options.id;
+    isProductCenter.value = options.isProductCenter || null;
     await getProductDetail(options.id);
+  }else {
+    resetForm();
   }
 })
 
@@ -562,42 +591,112 @@ async function getTempData(){
     uni.showToast({ title: '获取分类失败', icon: 'none' });
   }
 }
+const initFormValidation = async () => {
+  await nextTick();
+
+  if (!formRef.value) {
+    console.error('表单引用不存在');
+    return;
+  }
+
+  try {
+    // 方法1:清除所有验证状态,然后重新验证
+    formRef.value.clearValidate();
+
+    // 方法2:延迟触发字段验证
+    setTimeout(async () => {
+      // 逐个触发必填字段的验证
+      const requiredFields = ['categoryIds', 'storeName', 'keyword', 'storeInfo', 'unitName',
+        'tempIds', 'metalType', 'weight', 'laborCost', 'additionalFee',
+        'stock', 'barCode'];
+
+      for (const field of requiredFields) {
+        try {
+          await formRef.value.validateField(field);
+        } catch (error) {
+          console.log(`⚠️ 字段 ${field} 验证状态:`, error);
+        }
+      }
+    }, 300);
+
+  } catch (error) {
+    console.error('初始化表单验证状态失败:', error);
+  }
+};
 // 获取商品详情
 async function getProductDetail(id){
   try {
     const { data } = await productInfo(id)
     console.log('获取商品详情:',data);
-    formData.value = data;
+
+    // 使用Object.assign确保响应式更新
+    Object.assign(formData.value, {
+      ...data,
+      // 确保categoryIds是数组格式
+      categoryIds: data.cateId ? (Array.isArray(data.cateId) ? data.cateId : data.cateId.split(',')) : [],
+      // 确保tempIds是数组格式
+      tempIds: data.tempId ? [data.tempId] : []
+    });
+
     productImages.value = [];
-    formData.value.categoryIds =data.cateId.split(',') ;
+
+    console.log('分类IDs:', formData.value.categoryIds);
+    console.log('运费模板IDs:', formData.value.tempIds);
+
+    // 等待DOM更新
+    await nextTick();
+
+    // 更新显示名称
     formData.value.categoryDisplayName = getCategoryDisplayName(formData.value.categoryIds);
-    console.log(formData.value.categoryDisplayName)
-    formData.value.tempName =formatterTemp(data.tempId);
-    previewImages.value[0] = {};
-    previewImages.value[0].url = data.image;
-    const urlArr = JSON.parse(data.sliderImage);
-    if(urlArr.length > 0){
-      urlArr.forEach((item)=>{
-        productImages.value.push({
-          url:item
-        })
-      })
+    formData.value.tempName = formatterTemp(data.tempId);
+    console.log('分类显示名称:', formData.value.categoryDisplayName);
+
+    // 图片处理
+    previewImages.value = data.image ? [{ url: data.image }] : [];
+
+    // 商品轮播图
+    if(data.sliderImage){
+      try {
+        const urlArr = typeof data.sliderImage === 'string' ? JSON.parse(data.sliderImage) : data.sliderImage;
+        if(urlArr && urlArr.length > 0){
+          productImages.value = urlArr.map(url => ({ url }));
+        }
+      } catch (error) {
+        console.error('解析轮播图失败:', error);
+        productImages.value = [];
+      }
     }
-    console.log(productImages.value)
-    formData.value.additionalFee = data.attrValue[0].additionalAmount;
-    formData.value.laborCost = data.attrValue[0].price;
-    formData.value.barCode = data.attrValue[0].barCode;
-    productImagesGg.value[0] = {};
-    productImagesGg.value[0].url = data.attrValue[0].image;
-    formData.value.stock = data.attrValue[0].stock;
-    formData.value.weight = data.attrValue[0].weight;
 
+    // 商品属性
+    if (data.attrValue && data.attrValue.length > 0) {
+      formData.value.additionalFee = data.attrValue[0].additionalAmount;
+      formData.value.laborCost = data.attrValue[0].price;
+      formData.value.barCode = data.attrValue[0].barCode;
+      formData.value.stock = data.attrValue[0].stock;
+      formData.value.weight = data.attrValue[0].weight;
+
+      // 规格图片
+      productImagesGg.value = data.attrValue[0].image ? [{ url: data.attrValue[0].image }] : [];
+    }
+
+    // 商品描述
+    descriptionText.value = data.content ? data.content.replace(/<[^>]*>/g, '').substring(0, 500) : '';
+    formData.value.content = data.content || '';
+
+    // 设置分类选择器
     if (categoryRef.value && formData.value.categoryIds.length > 0) {
-      // 给组件一点时间初始化
-      setTimeout(() => {
+
+      // 使用nextTick确保组件已渲染
+      await nextTick();
+
+      if (categoryRef.value.setSelectedIds) {
         categoryRef.value.setSelectedIds(formData.value.categoryIds);
-      }, 100);
+      }
     }
+
+    // 重要:手动初始化表单验证状态
+    await initFormValidation();
+
   } catch (error) {
     console.error('获取商品详情失败:', error);
     uni.showToast({ title: '获取商品详情失败', icon: 'none' });
@@ -613,7 +712,11 @@ function tempConfirm(obj){
   formData.value.tempId = obj.value[0].id;
   formData.value.tempName = obj.value[0].name;
   showTemp.value = false;
-
+  setTimeout(() => {
+    if (formRef.value) {
+      formRef.value.validateField('tempIds');
+    }
+  }, 100);
 }
 // 分类选择变化
 const onCategoryChange = (result) => {
@@ -637,6 +740,12 @@ const confirmCategory = () => {
 
     showCategory.value = false
     console.log('最终选中的分类ID:', selectedIds)
+    // 触发校验
+    setTimeout(() => {
+      if (formRef.value) {
+        formRef.value.validateField('categoryIds');
+      }
+    }, 100);
   }
 }
 
@@ -690,7 +799,6 @@ async function getImage() {
   imageList.value = [];
 }
 async function getImageProduct() {
-  console.log(imageList.value)
   if (imageList.value.length > 0) {
     if (imageList.value[0].status == "success") {
       productImages.value = [...productImages.value,...imageList.value];
@@ -702,7 +810,6 @@ async function getImageProduct() {
   imageList.value = [];
 }
 async function getImageProductGg() {
-  console.log(imageList.value)
   if (imageList.value.length > 0) {
     if (imageList.value[0].status == "success") {
       productImagesGg.value = imageList.value;
@@ -749,74 +856,69 @@ const onUpinImage = (tempFiles, editorCtx) => {
   });
 };
 
-// 表单验证和提交
-const formRef = ref(null);
 
-const validateForm = async () => {
+
+const validateForm = () => {
   try {
-    const valid = await formRef.value.validate();
-    return valid;
-  } catch (error) {
-    console.error('表单验证失败:', error);
-    return false;
-  }
-};
+    if(!isProductCenter.value){
+      // 检查图片上传
+      if (previewImages.value.length === 0) {
+        uni.showToast({ title: '请上传商品预览图', icon: 'none' });
+        return;
+      }
 
-const submitForm = async () => {
-  console.log(formData.value)
-  // 检查商品描述
-  if (!descriptionText.value.trim()) {
-    uni.showToast({ title: '请输入商品描述', icon: 'none' });
-    return;
-  }
+      if (productImages.value.length === 0) {
+        uni.showToast({ title: '请上传商品图片', icon: 'none' });
+        return;
+      }
 
-  // 检查图片上传
-  if (previewImages.value.length === 0) {
-    uni.showToast({ title: '请上传商品预览图', icon: 'none' });
-    return;
-  }
+      if (formData.value.sort && !/^\d+$/.test(formData.value.sort)) {
+        uni.showToast({ title: '排序号必须是整数', icon: 'none' });
+        return;
+      }
+    }
 
-  if (productImages.value.length === 0) {
-    uni.showToast({ title: '请上传商品图片', icon: 'none' });
-    return;
-  }
 
-  if (productImagesGg.value.length === 0) {
-    uni.showToast({ title: '请上传商品规格图片', icon: 'none' });
-    return;
-  }
+    if (productImagesGg.value.length === 0) {
+      uni.showToast({ title: '请上传商品规格图片', icon: 'none' });
+      return;
+    }
 
-  // 验证数字字段
-  if (!/^\d+(\.\d+)?$/.test(formData.value.weight)) {
-    uni.showToast({ title: '重量格式不正确', icon: 'none' });
-    return;
-  }
+    // 验证数字字段
+    if (!/^\d+(\.\d+)?$/.test(formData.value.weight)) {
+      uni.showToast({ title: '重量格式不正确', icon: 'none' });
+      return;
+    }
 
-  if (!/^\d+(\.\d+)?$/.test(formData.value.laborCost)) {
-    uni.showToast({ title: '工费格式不正确', icon: 'none' });
-    return;
-  }
+    if (!/^\d+(\.\d+)?$/.test(formData.value.laborCost)) {
+      uni.showToast({ title: '工费格式不正确', icon: 'none' });
+      return;
+    }
 
-  if (!/^\d+(\.\d+)?$/.test(formData.value.additionalFee)) {
-    uni.showToast({ title: '附加费格式不正确', icon: 'none' });
-    return;
-  }
+    if (!/^\d+(\.\d+)?$/.test(formData.value.additionalFee)) {
+      uni.showToast({ title: '附加费格式不正确', icon: 'none' });
+      return;
+    }
 
-  if (!/^\d+$/.test(formData.value.stock)) {
-    uni.showToast({ title: '库存必须是整数', icon: 'none' });
-    return;
-  }
-  if (!/^\d+$/.test(formData.value.barCode)) {
-    uni.showToast({ title: '商品编号必须是整数', icon: 'none' });
-    return;
-  }
+    if (!/^\d+$/.test(formData.value.stock)) {
+      uni.showToast({ title: '库存必须是整数', icon: 'none' });
+      return;
+    }
+    if (!/^\d+$/.test(formData.value.barCode)) {
+      uni.showToast({ title: '商品编号必须是整数', icon: 'none' });
+      return;
+    }
 
-  if (formData.value.sort && !/^\d+$/.test(formData.value.sort)) {
-    uni.showToast({ title: '排序号必须是整数', icon: 'none' });
-    return;
+    const valid = formRef.value.validate();
+    return valid;
+  } catch (error) {
+    console.error('表单验证失败:', error);
+    return false;
   }
+};
+const submitForm = async () => {
+  const valid = validateForm();
 
-  const valid = await validateForm();
   if (valid) {
     const submitData = {
       ...formData.value
@@ -847,13 +949,51 @@ const submitForm = async () => {
       }
     ];
     console.log('提交数据:', submitData);
-    const {data} = await productSave(submitData);
-    uni.showToast({ title: '发布成功', icon: 'success' });
+
+    if(productId.value && !isProductCenter.value){
+      const {data} = await productUpdate(submitData);
+      uni.showToast({ title: '修改成功', icon: 'success' });
+    }else{
+      const {data} = await productSave(submitData);
+      uni.showToast({ title: '发布成功', icon: 'success' });
+    }
+
     uni.navigateTo({
-      url: '/pages/merchantCenter/productCenter'
+      url: '/pages/merchantCenter/productManagement'
     })
   }
-};
+}
+// 重置表单(用于新建场景)
+const resetForm = () => {
+  formData.value = {
+    categoryIds: [],
+    categoryDisplayName: '',
+    tempName: '',
+    tempIds: [],
+    storeName: '',
+    keyword: '',
+    storeInfo: '',
+    unitName: '',
+    metalType: '',
+    weight: '',
+    laborCost: '',
+    additionalFee: '',
+    sort: '',
+    content: '',
+    stock: '',
+    barCode: ''
+  };
+
+  previewImages.value = [];
+  productImages.value = [];
+  productImagesGg.value = [];
+  descriptionText.value = '';
+
+  // 清除校验状态
+  if (formRef.value) {
+    formRef.value.clearValidate();
+  }
+}
 </script>
 
 <style scoped lang="scss">
@@ -957,6 +1097,7 @@ const submitForm = async () => {
   background-color: #FFF;
   padding: 20rpx 30rpx;
   box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.1);
+  z-index: 5;
 }
 
 .submit {

+ 3 - 2
pages/user/index.vue

@@ -199,13 +199,14 @@ const orderStatus = ref([
 // 常用功能
 const commonFunctions = ref([
   { src: '/static/images/setting/zuji.png', name: '浏览足迹',pageUrl:'/pages/users/browsing_history/index',show:true },
-  { src: '/static/images/setting/shoucang.png', name: '我的收藏' },
+  { src: '/static/images/setting/shoucang.png', name: '我的收藏',pageUrl:'/pages/users/user_goods_collection/index' ,show:true},
   { src: '/static/images/setting/dingwei.png', name: '收货地址',pageUrl:'/pages/users/user_address_list/index' ,show:true},
   { src: '/static/images/setting/dianpu.png', name: '联系商家',pageUrl: '/pages/users/my_merchant/index' ,show:appStore.merchantId?true:false},
+  { src: '/static/images/setting/dianpu.png', name: '门店主页',pageUrl: '/pages/merchantCenter/index' ,show:appStore.userInfo?.merchant?.id?true:false},
   { src: '/static/images/setting/yijianjianyi.png', name: '意见建议' ,show:true},
   { src: '/static/images/setting/xiazaiapp.png', name: '下载APP',show:true },
   { src: '/static/images/setting/lianxikefu.png', name: '平台客服' ,show:true},
-  { src: '/static/images/setting/lianxikefu.png', name: '资产明细' ,pageUrl:'/pages/users/user_asset/asset_info/asset_info',show:true}
+  // { src: '/static/images/setting/lianxikefu.png', name: '资产明细' ,pageUrl:'/pages/users/user_asset/asset_info/asset_info',show:true}
 ])
 const params = ref({
   page: 1,

+ 2 - 1
pages/users/bank_card_manage/create.vue

@@ -106,7 +106,8 @@
         <u-button
           type="primary"
           :customStyle="{
-            background: 'linear-gradient(135deg, #e9c279 0%, #d4a853 100%)',
+            background: '#F8C008',
+            color:'#333',
             border: 'none',
             borderRadius: '16rpx',
             height: '88rpx',

+ 19 - 10
pages/users/bank_card_manage/index.vue

@@ -171,7 +171,7 @@ const addNewCard = () => {
 <style lang="scss" scoped>
 .bank-manage-container {
   min-height: 100vh;
-  background: #fff;
+  background: #F9F7F0;
 
   .card-list {
     padding: 30rpx 30rpx 0;
@@ -295,22 +295,31 @@ const addNewCard = () => {
   }
 
   .add-card-section {
-    padding: 30rpx 30rpx 60rpx;
-
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    background-color: #FFF;
+    padding: 20rpx 30rpx;
+    box-shadow: 0 -2rpx 10rpx rgba(0,0,0,0.1);
+    z-index: 5;
     .add-card-btn {
       width: 100%;
-      background: linear-gradient(135deg, #e9c279 0%, #d4a853 100%);
-      color: #fff;
-      font-size: 30rpx;
-      font-weight: 600;
-      padding: 32rpx 0;
+      //background: linear-gradient(135deg, #e9c279 0%, #d4a853 100%);
+      background: #F8C008;
+      color: #333;
+      font-size: 32rpx;
+      //font-weight: 600;
+      //padding: 32rpx 0;
+      height: 88rpx;
+      line-height: 88rpx;
       border-radius: 16rpx;
       border: none;
       display: flex;
       align-items: center;
       justify-content: center;
-      box-shadow: 0 6rpx 20rpx rgba(233, 194, 121, 0.3);
-      transition: all 0.3s ease;
+      //box-shadow: 0 6rpx 20rpx rgba(233, 194, 121, 0.3);
+      //transition: all 0.3s ease;
 
       &:active {
         transform: translateY(2rpx);

+ 182 - 0
pages/users/customer_service_message/index.vue

@@ -0,0 +1,182 @@
+<template>
+  <view>
+    <view class="message-list" v-if="customerList.length > 0">
+      <!-- 客服消息 -->
+      <view
+        class="message-item"
+        v-for="(item, index) in customerList"
+        :key="index"
+        @click="handleCustomerClick(item)"
+      >
+        <view class="message-avatar service-avatar">
+          <uni-icons
+            size="30"
+            color="#ffffff"
+            customPrefix="iconfont"
+            type="icon-kefu2"
+          />
+        </view>
+        <view class="message-content">
+          <view class="message-header">
+            <text class="message-title">{{ item.imTeamName }}</text>
+            <!-- <text class="badge" >{{ item.count }}</text> -->
+          </view>
+          <!-- <text class="message-desc" v-show="item.newMsg">{{ item.newMsg }}</text> -->
+        </view>
+      </view>
+    </view>
+    <!-- 数据为空 -->
+    <view class="not-data-wrapper" v-if="notDataFlag">
+      <uni-icons type="info" size="70" color="#999999"></uni-icons>
+      <p>暂无数据</p>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted } from "vue";
+import { onPullDownRefresh } from "@dcloudio/uni-app";
+import { getCustomerServiceList } from "@/api/customerService";
+import { useAppStore } from "@/stores/app";
+let customerList = ref([]); //客服列表
+let notDataFlag = ref(false); //数据为空
+const appStore = useAppStore();
+onMounted(() => {
+  getList();
+});
+onPullDownRefresh(() => {
+  getList();
+});
+// 获取客服列表
+function getList() {
+  try {
+    getCustomerServiceList()
+      .then((res) => {
+        if (res.data && res.data.list && res.data.list.length > 0) {
+          customerList.value = res.data.list;
+        } else {
+          notDataFlag.value = true;
+        }
+      })
+      .catch((err) => {
+        notDataFlag.value = true;
+      });
+  } catch (error) {
+    notDataFlag.value = true;
+  }
+}
+// 点击客服
+const handleCustomerClick = (item) => {
+  // uni.navigateTo({ url: `/pages/message_customer/message_customer?code=${item.imTeamCode}` });
+  let chatParam = ref({
+    avatar: "",
+    where: "teamServes",
+  });
+  chatParam.value.to = item.imTeamCode;
+  chatParam.value.nickName = item.imTeamName || "客服";
+  appStore.updata_userSelecChat(chatParam);
+  uni.navigateTo({ url: `/pages/private_chat/index` });
+};
+</script>
+
+<style lang="scss" scoped>
+.message-list {
+  .message-item {
+    display: flex;
+    align-items: center;
+    background-color: #fff;
+    padding: 20rpx 40rpx;
+    margin-bottom: 8px;
+    position: relative;
+    &:active {
+      background-color: #dedede;
+    }
+
+    .message-avatar {
+      width: 48px;
+      height: 48px;
+      border-radius: 50%;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-right: 12px;
+      font-size: 20px;
+
+      &.activity-avatar {
+        background-color: #2196f3;
+        color: white;
+      }
+
+      &.service-avatar {
+        background-color: #fc9145;
+        color: white;
+      }
+    }
+
+    .message-content {
+      flex: 1;
+
+      .message-header {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        /* margin-bottom: 4px; */
+        position: relative;
+        height: 20px;
+
+        .message-title {
+          font-size: 16px;
+          /* font-weight: 500; */
+          color: #333;
+        }
+      }
+
+      .message-desc {
+        font-size: 14px;
+        color: #999;
+      }
+    }
+
+    .message-right {
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      align-items: flex-end;
+    }
+
+    .message-time {
+      font-size: 14px;
+      color: #999;
+      margin-bottom: 10rpx;
+    }
+
+    .badge {
+      background-color: #ff4757;
+      color: white;
+      border-radius: 50%;
+      width: 38rpx;
+      height: 38rpx;
+      line-height: 38rpx;
+      text-align: center;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 18rpx;
+      font-weight: 500;
+      padding: 0 4px;
+      border: 2px solid #fff;
+    }
+
+    .unread-dot {
+      position: absolute;
+      top: 50%;
+      right: 16px;
+      transform: translateY(-50%);
+      width: 8px;
+      height: 8px;
+      background-color: #ff4757;
+      border-radius: 50%;
+    }
+  }
+}
+</style>

+ 4 - 2
pages/users/login/index.vue

@@ -333,6 +333,7 @@ const getUserInfoFn = async (data) => {
       }
       await footprintScanFn(obj)
     }else{
+      appStore.UPDATE_MERCHANT_ID('')
       Toast({ title: "登录成功" });
       backHome();
     }
@@ -344,7 +345,8 @@ const getUserInfoFn = async (data) => {
 };
 
 onLoad((options) => {
-  getSceneInfo(options)
+  const params = getSceneInfo(options);
+  merchantId.value = params.merchantId || '';
   getLogoImage();
 });
 
@@ -372,7 +374,7 @@ onMounted(() => {
 });
 
 const backHome = () => {
-  if(userInfo.value.merchant){
+  if(userInfo.value.merchant && userInfo.value.merchant.id){
     uni.navigateTo({
       url:"/pages/merchantCenter/index"
     })

+ 458 - 0
pages/users/user_goods_collection/index.vue

@@ -0,0 +1,458 @@
+<template>
+	<view>
+		<view class="hdbj"></view>
+		<view class='collectionGoods' v-if="collectProductList.length">
+			<!-- #ifdef  H5 || MP-->
+			<view class='nav acea-row row-between-wrapper'>
+				<view>当前共 <text class='num font-color'>{{ totals }}</text>件商品</view>
+				<view class='administrate acea-row row-center-wrapper' @click='manage'>{{ footerswitch ? '管理' : '取消'}}
+				</view>
+			</view>
+			<!-- #endif -->
+			<view class="list">
+				<checkbox-group @change="checkboxChange" class="centent">
+					<view v-for="(item,index) in collectProductList" :key="index" class='item acea-row row-middle'>
+						<checkbox :value="item.id.toString()" :checked="item.checked" v-if="!footerswitch"
+							style="margin-right: 10rpx;" />
+						<navigator :url='"/pages/goods_details/index?id="+item.productId' hover-class='none'
+							class="acea-row">
+							<view class='pictrue'>
+								<image :src="item.image" mode="aspectFill"></image>
+							</view>
+							<view>
+								<view class='name line1'>{{item.storeName}}</view>
+								<view class='money font-color'>¥{{item.price}}</view>
+							</view>
+						</navigator>
+					</view>
+				</checkbox-group>
+			</view>
+			<view class='loadingicon acea-row row-center-wrapper'>
+				<text class='loading iconfont icon-jiazai' :hidden='loading==false'></text>{{loadTitle}}
+			</view>
+			<view v-if="!footerswitch" class='footer acea-row row-between-wrapper'>
+				<view>
+					<checkbox-group @change="checkboxAllChange">
+						<checkbox value="all" :checked="!!isAllSelect" />
+						<text class='checkAll'>全选</text>
+					</checkbox-group>
+				</view>
+				<view class='button acea-row row-middle'>
+					<form @submit="delCollectionAll" report-submit='true'>
+						<button class='bnt cart-color' formType="submit">取消收藏</button>
+					</form>
+				</view>
+			</view>
+		</view>
+		<view class='noCommodity' v-else-if="!collectProductList.length && page > 1">
+			<view class='pictrue'>
+				<image src='@/static/images/noCollection.png'></image>
+			</view>
+			<recommend :hostProduct="hostProduct"></recommend>
+		</view>
+		<!-- #ifdef MP -->
+		<!-- <authorize @onLoadFun="onLoadFun" :isAuto="isAuto" :isShowAuth="isShowAuth" @authColse="authColse"></authorize> -->
+		<!-- #endif -->
+		<home></home>
+	</view>
+</template>
+
+<script>
+	import {
+		getCollectUserList,
+		getProductHot,
+		collectDelete
+	} from '@/api/store.js';
+	import {
+		mapGetters
+	} from "vuex";
+	import {
+		toLogin
+	} from '@/libs/login.js';
+	import recommend from '@/components/recommend';
+	// #ifdef MP
+	import authorize from '@/components/Authorize';
+	// #endif
+	import home from '@/components/home';
+	export default {
+		components: {
+			recommend,
+			// #ifdef MP
+			authorize,
+			// #endif
+			home
+		},
+		data() {
+			return {
+				footerswitch: true,
+				hostProduct: [],
+				loadTitle: '加载更多',
+				loading: false,
+				loadend: false,
+				collectProductList: [],
+				limit: 8,
+				page: 1,
+				isAuto: false, //没有授权的不会自动授权
+				isShowAuth: false, //是否隐藏授权
+				hotScroll: false,
+				hotPage: 1,
+				hotLimit: 10,
+				isAllSelect: false, //全选
+				selectValue: [], //选中的数据
+				delBtnWidth: 80, //左滑默认宽度
+				totals: 0
+			};
+		},
+		computed: mapGetters(['isLogin']),
+		onLoad() {
+			if (this.isLogin) {
+				this.loadend = false;
+				this.page = 1;
+				this.collectProductList = [];
+				this.get_user_collect_product();
+			} else {
+				toLogin();
+			}
+		},
+		onShow() {
+			this.loadend = false;
+			this.page = 1;
+			this.collectProductList = [];
+			this.get_user_collect_product();
+		},
+		methods: {
+			// #ifdef MP
+			drawStart(e) {
+				var touch = e.touches[0];
+				this.startX = touch.clientX;
+			},
+			//触摸滑动
+			drawMove(e) {
+				var touch = e.touches[0];
+				var item = this.collectProductList[e.currentTarget.dataset.index];
+				var disX = this.startX - touch.clientX;
+				if (disX >= 20) {
+					if (disX > this.delBtnWidth) {
+						disX = this.delBtnWidth;
+					}
+					this.$set(this.collectProductList[e.currentTarget.dataset.index], 'right', disX);
+				} else {
+					this.$set(this.collectProductList[e.currentTarget.dataset.index], 'right', 0);
+				}
+			},
+			//触摸滑动结束
+			drawEnd(e) {
+				var item = this.collectProductList[e.currentTarget.dataset.index];
+				if (item.right >= this.delBtnWidth / 2) {
+					this.$set(this.collectProductList[e.currentTarget.dataset.index], 'right', this.delBtnWidth);
+				} else {
+					this.$set(this.collectProductList[e.currentTarget.dataset.index], 'right', 0);
+				}
+			},
+			// #endif
+			manage: function() {
+				this.footerswitch = !this.footerswitch;
+			},
+
+			checkboxChange: function(event) {
+				var items = this.collectProductList,
+					values = event.detail.value;
+				for (var i = 0, lenI = items.length; i < lenI; ++i) {
+					const item = items[i]
+					if (values.includes(item.id.toString())) {
+						this.$set(item, 'checked', true)
+					} else {
+						this.$set(item, 'checked', false)
+					}
+				}
+				this.selectValue = values.toString();
+				this.isAllSelect = items.length === values.length;
+			},
+			checkboxAllChange: function(event) {
+				let value = event.detail.value;
+				if (value.length > 0) {
+					this.setAllSelectValue(1)
+				} else {
+					this.setAllSelectValue(0)
+				}
+			},
+			setAllSelectValue: function(status) {
+				let selectValue = [];
+				if (this.collectProductList.length > 0) {
+					this.collectProductList.map(item => {
+						if (status) {
+							this.$set(item, 'checked', true)
+							selectValue.push(item.id);
+							this.isAllSelect = true;
+						} else {
+							this.$set(item, 'checked', false)
+							this.isAllSelect = false;
+						}
+					});
+					this.selectValue = selectValue.toString();
+				}
+			},
+			/**
+			 * 授权回调
+			 */
+			onLoadFun: function() {
+				this.get_user_collect_product();
+				this.get_host_product();
+			},
+			// 授权关闭
+			authColse: function(e) {
+				this.isShowAuth = e
+			},
+			/**
+			 * 获取收藏产品
+			 */
+			get_user_collect_product: function() {
+				let that = this;
+				if (this.loading) return;
+				if (this.loadend) return;
+				that.loading = true;
+				that.loadTitle = "";
+				getCollectUserList({
+					page: that.page,
+					limit: that.limit
+				}).then(res => {
+					res.data.list.map(item => {
+						that.$set(item, 'right', 0);
+					});
+					that.totals = res.data.total;
+					let collectProductList = res.data.list;
+					let loadend = collectProductList.length < that.limit;
+					that.collectProductList = that.$util.SplitArray(collectProductList, that
+						.collectProductList);
+					that.$set(that, 'collectProductList', that.collectProductList);
+					if (that.collectProductList.length === 0) that.get_host_product();
+					that.loadend = loadend;
+					that.loadTitle = loadend ? '已全部加载' : '加载更多';
+					that.page = that.page + 1;
+					that.loading = false;
+				}).catch(err => {
+					that.loading = false;
+					that.loadTitle = "加载更多";
+				});
+			},
+			/**
+			 * 取消收藏
+			 */
+			delCollection: function(id, index) {
+				this.selectValue = id;
+				this.del({
+					ids: this.selectValue.toString()
+				});
+			},
+			delCollectionAll: function() {
+				if (!this.selectValue || this.selectValue.length == 0) return this.$util.Tips({
+					title: '请选择商品'
+				});
+				this.del({
+					ids: this.selectValue
+				});
+			},
+			del: function(data) {
+				collectDelete(data).then(res => {
+					this.$util.Tips({
+						title: '取消收藏成功',
+						icon: 'success'
+					});
+					// this.collectProductList = this.collectProductList.filter(item=>item!==this.selectValue)
+					this.collectProductList = [];
+					this.loadend = false;
+					this.page = 1;
+					this.get_user_collect_product();
+				}).catch(err => {
+					return this.$util.Tips({
+						title: err
+					})
+				});
+			},
+			/**
+			 * 获取我的推荐
+			 */
+			get_host_product: function() {
+				let that = this;
+				if (that.hotScroll) return
+				getProductHot(
+					that.hotPage,
+					that.hotLimit,
+				).then(res => {
+					that.hotPage++
+					that.hotScroll = res.data.list.length < that.hotLimit
+					that.hostProduct = that.hostProduct.concat(res.data.list)
+				});
+			}
+		},
+		/**
+		 * 页面上拉触底事件的处理函数
+		 */
+		onReachBottom() {
+			this.get_user_collect_product();
+			this.get_host_product();
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+
+	.hdbj {
+		width: 100%;
+		height: 30rpx;
+		background-color: #f5f5f5;
+		z-index: 999999;
+		position: fixed;
+		top: 0;
+	}
+
+	.order-item {
+		width: 100%;
+		display: flex;
+		position: relative;
+		align-items: right;
+		flex-direction: row;
+	}
+
+	.remove {
+		width: 120rpx;
+		height: 100%;
+		background-color: $theme-color;
+		color: white;
+		position: absolute;
+		top: 0;
+		right: -160rpx;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		font-size: 24rpx;
+	}
+
+	.collectionGoods {
+
+		.nav {
+			width: 92%;
+			height: 90rpx;
+			background-color: #fff;
+			padding: 0 24rpx;
+			-webkit-box-sizing: border-box;
+			box-sizing: border-box;
+			font-size: 28rpx;
+			color: #282828;
+			position: fixed;
+			left: 30rpx;
+			z-index: 5;
+			top: 30rpx;
+			border-bottom: 1px solid #EEEEEE;
+			border-top-left-radius: 14rpx;
+			border-top-right-radius: 14rpx;
+		}
+
+		.list {
+			padding: 30rpx;
+			margin-top: 90rpx;
+
+			.name {
+				width: 434rpx;
+				margin-bottom: 56rpx;
+			}
+		}
+
+		.centent {
+			/* #ifdef H5 || MP */
+			background-color: #fff;
+			/* #endif */
+			border-bottom-left-radius: 14rpx;
+			border-bottom-right-radius: 14rpx;
+		}
+	}
+
+	.collectionGoods .item {
+		background-color: #fff;
+		padding-left: 24rpx;
+		height: 180rpx;
+		margin-bottom: 15rpx;
+		border-radius: 14rpx;
+
+	}
+
+	.collectionGoods .item .pictrue {
+		width: 130rpx;
+		height: 130rpx;
+		margin-right: 20rpx;
+	}
+
+	.collectionGoods .item .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 14rpx;
+	}
+
+	.collectionGoods .item .text {
+		width: 535rpx;
+		height: 130rpx;
+		font-size: 28rpx;
+		color: #282828;
+	}
+
+	.collectionGoods .item .text .name {
+		width: 100%;
+	}
+
+	.collectionGoods .item .text .money {
+		font-size: 26rpx;
+	}
+
+	.collectionGoods .item .text .delete {
+		font-size: 26rpx;
+		color: #282828;
+		width: 144rpx;
+		height: 46rpx;
+		border: 1px solid #bbb;
+		border-radius: 4rpx;
+		text-align: center;
+		line-height: 46rpx;
+	}
+
+	.noCommodity {
+		background-color: #fff;
+		padding-top: 1rpx;
+		border-top: 0;
+	}
+
+	.footer {
+		z-index: 9;
+		width: 100%;
+		height: 96rpx;
+		background-color: #fff;
+		position: fixed;
+		padding: 0 30rpx;
+		box-sizing: border-box;
+		border-top: 1rpx solid #eee;
+		border-bottom: 1px solid #EEEEEE;
+		/* #ifdef H5 || MP */
+		bottom: 0rpx;
+		/* #endif */
+		/* #ifndef MP */
+		// bottom: 98rpx;
+		// bottom: calc(98rpx+ constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+		// bottom: calc(98rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+		/* #endif */
+		.checkAll {
+			font-size: 28rpx;
+			color: #282828;
+			margin-left: 16rpx;
+		}
+
+		.button .bnt {
+			font-size: 28rpx;
+			color: #999;
+			border-radius: 30rpx;
+			border: 1px solid #999;
+			width: 160rpx;
+			height: 60rpx;
+			text-align: center;
+			line-height: 60rpx;
+		}
+	}
+</style>

BIN
static/images/noCollection.png


BIN
static/images/picture.png


BIN
static/images/red-packets.png


BIN
static/images/wexin.png