ext.liuqiwen3 1 napja
szülő
commit
1d7a3c1d16

+ 7 - 0
api/merchant.js

@@ -103,4 +103,11 @@ export function templatesList(data) {
  */
 export function productSave(data) {
   return request.post(`product/save`,data);
+}
+/**
+ * 获取运费模板
+ * @param
+ */
+export function productInfo(id) {
+  return request.get(`product/info/${id}`);
 }

+ 182 - 93
components/CategorySelector/index.vue

@@ -6,20 +6,18 @@
           v-for="item in categoryList"
           :key="item.id"
           class="first-item"
-          :class="{ active: selectedFirstLevel.includes(item.id) }"
-          @click="toggleFirstLevel(item)"
+          :class="{ active: currentFirstLevel === item.id }"
+          @click="selectFirstLevel(item)"
       >
         <view class="item-content">
-<!--          <image-->
-<!--              v-if="item.extra"-->
-<!--              :src="item.extra"-->
-<!--              class="category-icon"-->
-<!--              mode="aspectFit"-->
-<!--          />-->
           <text class="category-name">{{ item.name }}</text>
+          <text v-if="getSelectedChildCount(item) > 0" class="selected-count">
+            ({{ getSelectedChildCount(item) }})
+          </text>
         </view>
         <view class="checkbox">
-          <text v-if="selectedFirstLevel.includes(item.id)" class="checked">✓</text>
+          <text v-if="isFirstLevelAllSelected(item)" class="checked">✓</text>
+          <text v-else-if="getSelectedChildCount(item) > 0" class="partial">-</text>
           <text v-else class="unchecked">○</text>
         </view>
       </view>
@@ -45,7 +43,7 @@
 </template>
 
 <script setup>
-import { ref, computed, watch } from 'vue'
+import {ref, computed, watch} from 'vue'
 
 const props = defineProps({
   categoryList: {
@@ -61,13 +59,11 @@ const props = defineProps({
 
 const emit = defineEmits(['change'])
 
-// 选中的一级分类ID
-const selectedFirstLevel = ref([])
+// 当前显示的一级分类ID(用于右侧显示)
+const currentFirstLevel = ref(null)
 // 选中的二级分类ID
 const selectedSecondLevel = ref([])
 
-// 当前显示二级分类的一级分类
-const currentFirstLevel = ref(null)
 // 当前显示的二级分类列表
 const currentSecondLevel = computed(() => {
   if (!currentFirstLevel.value) return []
@@ -78,63 +74,35 @@ const currentSecondLevel = computed(() => {
 // 是否有二级分类显示
 const hasSecondLevel = computed(() => currentSecondLevel.value.length > 0)
 
-// 初始化选中状态
-const initSelected = () => {
-  selectedFirstLevel.value = []
-  selectedSecondLevel.value = []
-
-  props.selectedIds.forEach(id => {
-    // 检查是否是一级分类
-    const firstLevel = props.categoryList.find(item => item.id === id)
-    if (firstLevel) {
-      selectedFirstLevel.value.push(id)
-    }
-
-    // 检查是否是二级分类
-    for (const parent of props.categoryList) {
-      if (parent.child) {
-        const secondLevel = parent.child.find(child => child.id === id)
-        if (secondLevel) {
-          selectedSecondLevel.value.push(id)
-          // 如果选中了二级分类,自动选中对应的一级分类
-          if (!selectedFirstLevel.value.includes(parent.id)) {
-            selectedFirstLevel.value.push(parent.id)
-          }
-        }
-      }
-    }
-  })
+// 获取一级分类下选中的子分类数量
+const getSelectedChildCount = (firstLevelItem) => {
+  if (!firstLevelItem.child) return 0
+  return firstLevelItem.child.filter(child =>
+      selectedSecondLevel.value.includes(child.id)
+  ).length
 }
 
-// 切换一级分类选中状态
-const toggleFirstLevel = (item) => {
-  const index = selectedFirstLevel.value.indexOf(item.id)
-
-  if (index > -1) {
-    // 取消选中
-    selectedFirstLevel.value.splice(index, 1)
-    // 如果取消选中一级分类,同时取消选中其下的所有二级分类
-    if (item.child) {
-      item.child.forEach(child => {
-        const childIndex = selectedSecondLevel.value.indexOf(child.id)
-        if (childIndex > -1) {
-          selectedSecondLevel.value.splice(childIndex, 1)
-        }
-      })
-    }
-  } else {
-    // 选中
-    selectedFirstLevel.value.push(item.id)
+// 检查一级分类是否全部选中
+const isFirstLevelAllSelected = (firstLevelItem) => {
+  if (!firstLevelItem.child || firstLevelItem.child.length === 0) {
+    // 如果一级分类没有子分类,直接检查是否选中
+    return selectedSecondLevel.value.includes(firstLevelItem.id)
   }
 
-  // 设置当前显示的一级分类
+  const childCount = firstLevelItem.child.length
+  const selectedCount = getSelectedChildCount(firstLevelItem)
+  return childCount > 0 && selectedCount === childCount
+}
+
+// 选择一级分类(仅用于显示右侧内容)
+const selectFirstLevel = (item) => {
   if (item.child && item.child.length > 0) {
     currentFirstLevel.value = item.id
   } else {
     currentFirstLevel.value = null
+    // 如果没有子分类,点击一级分类相当于选择/取消选择
+    toggleSecondLevel(item)
   }
-
-  emitSelectionChange()
 }
 
 // 切换二级分类选中状态
@@ -142,69 +110,184 @@ const toggleSecondLevel = (child) => {
   const index = selectedSecondLevel.value.indexOf(child.id)
 
   if (index > -1) {
+    // 取消选中
     selectedSecondLevel.value.splice(index, 1)
   } else {
+    // 选中
     selectedSecondLevel.value.push(child.id)
-    // 如果选中二级分类,确保对应的一级分类也被选中
-    const parentId = getParentId(child.id)
-    if (parentId && !selectedFirstLevel.value.includes(parentId)) {
-      selectedFirstLevel.value.push(parentId)
-    }
   }
 
   emitSelectionChange()
 }
 
-// 根据二级分类ID获取一级分类ID
-const getParentId = (childId) => {
-  for (const parent of props.categoryList) {
-    if (parent.child) {
-      const child = parent.child.find(item => item.id === childId)
-      if (child) return parent.id
+// 获取所有选中的分类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)
+          }
+        })
+      }
     }
-  }
-  return null
+  })
+
+  return selectedIds
 }
 
 // 发射选择变化事件
 const emitSelectionChange = () => {
-  const selectedIds = [...selectedFirstLevel.value, ...selectedSecondLevel.value]
+  const selectedIds = getSelectedIds()
   emit('change', {
     selectedIds,
-    firstLevel: selectedFirstLevel.value,
     secondLevel: selectedSecondLevel.value
   })
 }
 
-// 获取所有选中的分类ID
-const getSelectedIds = () => {
-  return [...selectedFirstLevel.value, ...selectedSecondLevel.value]
+// 初始化选中状态
+const initSelected = () => {
+  selectedSecondLevel.value = [];
+  currentFirstLevel.value = null;
+
+  console.log('初始化选中IDs:', props.selectedIds);
+  console.log('分类数据:', props.categoryList);
+
+  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;
+    }
+    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);
+        }
+      });
+    } else {
+      // 如果是二级分类或没有子分类的一级分类,直接选中
+      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(String(child.id)));
+    }
+    return selectedSecondLevel.value.includes(String(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;
+    }
+  }
 }
 
 // 清空所有选择
 const clearSelection = () => {
-  selectedFirstLevel.value = []
   selectedSecondLevel.value = []
   currentFirstLevel.value = null
   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();
+};
 
 // 监听props变化
 watch(() => props.selectedIds, (newVal) => {
   initSelected()
-})
+}, {immediate: true})
 
 watch(() => props.categoryList, (newVal) => {
-  initSelected()
+  if (newVal && newVal.length > 0) {
+    initSelected()
+  }
 })
 
-// 初始化
-initSelected()
-
 // 暴露方法给父组件
 defineExpose({
   getSelectedIds,
-  clearSelection
+  clearSelection,
+  setSelectedIds
 })
 </script>
 
@@ -232,6 +315,7 @@ defineExpose({
   justify-content: space-between;
   padding: 20rpx;
   border-bottom: 1rpx solid #eee;
+  cursor: pointer;
 }
 
 .first-item.active {
@@ -251,16 +335,16 @@ defineExpose({
   flex: 1;
 }
 
-.category-icon {
-  width: 40rpx;
-  height: 40rpx;
-  margin-right: 15rpx;
-}
-
 .category-name {
   font-size: 28rpx;
 }
 
+.selected-count {
+  font-size: 24rpx;
+  color: #F8C008;
+  margin-left: 10rpx;
+}
+
 .checkbox {
   width: 40rpx;
   height: 40rpx;
@@ -275,6 +359,11 @@ defineExpose({
   font-weight: bold;
 }
 
+.partial {
+  color: #FFA500; /* 橙色表示部分选中 */
+  font-weight: bold;
+}
+
 .unchecked {
   color: #ccc;
 }

+ 3 - 3
pages/merchantCenter/postInformation.vue

@@ -56,9 +56,9 @@ const handleManualPublish = () => {
 }
 
 const handleTemplatePublish = () => {
-  // uni.navigateTo({
-  //   url: '/pages/goods/publish-from-template'
-  // })
+  uni.navigateTo({
+    url: '/pages/merchantCenter/productCenter'
+  })
 }
 </script>
 

+ 2 - 44
pages/merchantCenter/productCenter.vue

@@ -2,10 +2,6 @@
   <view class="container">
     <!-- 搜索栏 -->
     <view class="search-bar">
-<!--      <up-search placeholder="搜索商品名称" shape="square" :clearabled="true"-->
-<!--                 height="36" bgColor="#F9F7F0" :showAction="false" v-model="searchVal"-->
-<!--                 @clear="onClear" @search="onSearch"-->
-<!--                 :focus="isFocus" @focus="onFocus" @blur="onBlur" ></up-search>-->
       <view class="search-bar-con">
         <view class="search-input-wrapper">
           <uni-icons class="search-icon" type="search" size="18" color="#999"></uni-icons>
@@ -54,9 +50,7 @@
         </view>
 
         <view class="action-buttons">
-          <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" @click="addProduct(item)">添加商品</button>
         </view>
       </view>
       <view class="loadingicon acea-row row-center-wrapper" v-if="goodScroll">
@@ -114,27 +108,6 @@ onShow(() => {
   getGroomList()
 })
 
-const onFocus = () => {
-  console.log('获取焦点')
-  isFocus.value = true
-}
-
-const onBlur = () => {
-  console.log('失去焦点')
-  // 不要立即设置为false,避免焦点闪烁
-  setTimeout(() => {
-    isFocus.value = false
-  }, 200)
-}
-const tabChange = (item) => {
-  console.log('item',item)
-  goodsList.value = [];
-  loading.value = false;
-  goodScroll.value = true;
-  params.value.isShow = item.code;
-  params.value.page = 1;
-  getGroomList();
-}
 const onSearch = () => {
   goodsList.value = [];
   loading.value = false;
@@ -165,22 +138,7 @@ const getGroomList = async () => {
     loading.value = false;
   }
 };
-async function OffShellFn(obj,index) {
-  const {code} = await productOffShell(obj.id);
-  if(code == 200){
-    uni.showToast({ title: "操作成功", icon: "none" });
-    goodsList.value.splice(index,1);
-  }
-}
-async function PutOnShellFn(obj,index) {
-  const {code} = await productPutOnShell(obj.id);
-  if(code == 200){
-    uni.showToast({ title: "操作成功", icon: "none" });
-    goodsList.value.splice(index,1);
-  }
-
-}
-function toEditProduct (obj){
+function addProduct (obj){
   uni.navigateTo({
     url:`pages/merchantCenter/releaseProduct?id=${obj.id}`
   })

+ 1 - 17
pages/merchantCenter/productManagement.vue

@@ -2,10 +2,6 @@
   <view class="container">
     <!-- 搜索栏 -->
     <view class="search-bar">
-<!--      <up-search placeholder="搜索商品名称" shape="square" :clearabled="true"-->
-<!--                 height="36" bgColor="#F9F7F0" :showAction="false" v-model="searchVal"-->
-<!--                 @clear="onClear" @search="onSearch"-->
-<!--                 :focus="isFocus" @focus="onFocus" @blur="onBlur" ></up-search>-->
       <view class="search-bar-con">
         <view class="search-input-wrapper">
           <uni-icons class="search-icon" type="search" size="18" color="#999"></uni-icons>
@@ -135,18 +131,6 @@ onShow(() => {
   getGroomList()
 })
 
-const onFocus = () => {
-  console.log('获取焦点')
-  isFocus.value = true
-}
-
-const onBlur = () => {
-  console.log('失去焦点')
-  // 不要立即设置为false,避免焦点闪烁
-  setTimeout(() => {
-    isFocus.value = false
-  }, 200)
-}
 const tabChange = (item) => {
   console.log('item',item)
   goodsList.value = [];
@@ -203,7 +187,7 @@ async function PutOnShellFn(obj,index) {
 }
 function toEditProduct (obj){
   uni.navigateTo({
-    url:`pages/merchantCenter/releaseProduct?id=${obj.id}`
+    url:`/pages/merchantCenter/releaseProduct?id=${obj.id}`
   })
 }
 onReachBottom(() => {

+ 80 - 16
pages/merchantCenter/releaseProduct.vue

@@ -359,8 +359,8 @@
 
 <script setup>
 import { ref, computed, watch } from 'vue';
-import { onShow } from "@dcloudio/uni-app";
-import { productCategory,productSave,templatesList } from "@/api/merchant";
+import { onShow,onLoad } from "@dcloudio/uni-app";
+import { productCategory,productSave,templatesList,productInfo } from "@/api/merchant";
 import CategorySelector from '@/components/CategorySelector';
 import { useAppStore } from "@/stores/app";
 import { useImageUpload } from "@/hooks/useImageUpload";
@@ -511,8 +511,15 @@ const rules = ref({
 
 // 页面加载
 onShow(() => {
-  getProductCategory();
-  getTempData();
+
+})
+onLoad(async (options)=>{
+  await getProductCategory();
+  await getTempData();
+  console.log(options);
+  if(options.id){
+    await getProductDetail(options.id);
+  }
 })
 
 // 获取商品分类
@@ -540,6 +547,7 @@ async function getProductCategory(){
   }
 }
 
+// 获取运费模板
 async function getTempData(){
   let obj = {
     page:1,
@@ -554,15 +562,58 @@ async function getTempData(){
     uni.showToast({ title: '获取分类失败', icon: 'none' });
   }
 }
+// 获取商品详情
+async function getProductDetail(id){
+  try {
+    const { data } = await productInfo(id)
+    console.log('获取商品详情:',data);
+    formData.value = data;
+    productImages.value = [];
+    formData.value.categoryIds =data.cateId.split(',') ;
+    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
+        })
+      })
+    }
+    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 (categoryRef.value && formData.value.categoryIds.length > 0) {
+      // 给组件一点时间初始化
+      setTimeout(() => {
+        categoryRef.value.setSelectedIds(formData.value.categoryIds);
+      }, 100);
+    }
+  } catch (error) {
+    console.error('获取商品详情失败:', error);
+    uni.showToast({ title: '获取商品详情失败', icon: 'none' });
+  }
+}
+// 运费模板id获取中文名
+function formatterTemp(id) {
+  // 假设 tempColumns 是一个数组
+  const foundItem = tempColumns.value[0].find(item => item.id == id);
+  return foundItem ? foundItem.name : '';
+}
 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('tempId').catch(() => {});
-  //   }
-  // }, 100);
+
 }
 // 分类选择变化
 const onCategoryChange = (result) => {
@@ -591,24 +642,35 @@ const confirmCategory = () => {
 
 // 根据选中的ID生成显示名称
 const getCategoryDisplayName = (selectedIds) => {
-  if (selectedIds.length === 0) return ''
+  if (!selectedIds || selectedIds.length === 0) return ''
 
   const names = []
+
   selectedIds.forEach(id => {
-    // 查找一级分类
-    const firstLevel = categoryData.value.find(item => item.id === id)
+    // 检查是否是一级分类(表示全选)
+    const firstLevel = categoryData.value.find(item => item.id == id)
     if (firstLevel) {
-      names.push(firstLevel.name)
+      // 如果是一级分类,显示"分类名称(全部)"
+      names.push(`${firstLevel.name}`)
     } else {
       // 查找二级分类
       for (const parent of categoryData.value) {
         if (parent.child) {
-          const secondLevel = parent.child.find(child => child.id === id)
+          const secondLevel = parent.child.find(child => child.id == id)
           if (secondLevel) {
             names.push(`${parent.name}-${secondLevel.name}`)
+            break
           }
         }
       }
+
+      // 如果没有子分类的一级分类
+      const singleLevel = categoryData.value.find(item =>
+          !item.child && item.id == id
+      )
+      if (singleLevel) {
+        names.push(singleLevel.name)
+      }
     }
   })
 
@@ -761,7 +823,7 @@ const submitForm = async () => {
     };
     submitData.cateId =formData.value.categoryIds.join(',');
     submitData.image =previewImages.value[0].url;
-    const urlString = productImages.value.map(item => item.url).join(',');
+    const urlString = JSON.stringify(productImages.value.map(item => item.url));
     submitData.sliderImage =urlString;
     submitData.merchantId =parseInt(merchantInfo.id);
     submitData.specType = 0;
@@ -787,7 +849,9 @@ const submitForm = async () => {
     console.log('提交数据:', submitData);
     const {data} = await productSave(submitData);
     uni.showToast({ title: '发布成功', icon: 'success' });
-
+    uni.navigateTo({
+      url: '/pages/merchantCenter/productCenter'
+    })
   }
 };
 </script>