Răsfoiți Sursa

refactor(product): 重构产品基础信息管理模块

- 将产品经理和采购人员字段映射从 productNature/purchasingPersonnel 更改为 purchaseManagerNo/purchaseNo
- 更新表单验证规则适配新的字段名称
- 优化图片上传组件 ImageUpload,支持直接 URL 字符串回显并修正 ID 转换逻辑
- 添加价格链校验功能,确保市场价 > 官网价 ≥ 最低售价 ≥ 最高采购价 ≥ 采购价的业务规则
- 统一分类查询接口调用,添加 platform 参数过滤
- 修正产品审核页面的字段绑定和初始值设置
- 调整产品类别页面字段标签和表单布局
- 为产品池审核页面添加编号列显示
肖路 3 zile în urmă
părinte
comite
c0075b3c46

+ 12 - 2
src/components/ImageUpload/index.vue

@@ -99,6 +99,15 @@ watch(
       let list: OssVO[] = [];
       if (Array.isArray(val)) {
         list = val as OssVO[];
+      } else if (typeof val === 'string' && (val.startsWith('http://') || val.startsWith('https://'))) {
+        // 值已经是URL(后端直接返回了URL),跳过listByIds,直接按逗号分隔构造回显数据
+        const urls = val.split(',').filter((u) => u.trim());
+        fileList.value = urls.map((url, index) => ({
+          name: url,
+          url: url,
+          ossId: url
+        }));
+        return;
       } else {
         const res = await listByIds(val);
         list = res.data;
@@ -108,7 +117,8 @@ watch(
         // 字符串回显处理 如果此处存的是url可直接回显 如果存的是id需要调用接口查出来
         let itemData;
         if (typeof item === 'string') {
-          itemData = { name: item, url: item };
+          // URL字符串也设置ossId,与上方URL绕过分支保持一致,确保listToString能正确追踪
+          itemData = { name: item, url: item, ossId: item };
         } else {
           // 此处name使用ossId 防止删除出现重名
           itemData = { name: item.ossId, url: item.url, ossId: item.ossId };
@@ -227,7 +237,7 @@ const listToString = (list: any[], separator?: string) => {
   separator = separator || ',';
   for (const i in list) {
     if (undefined !== list[i].ossId && list[i].url.indexOf('blob:') !== 0) {
-      strs += list[i].ossId + separator;
+      strs += list[i].url + separator;
     }
   }
   return strs != '' ? strs.substring(0, strs.length - 1) : '';

+ 85 - 27
src/views/product/base/add.vue

@@ -254,7 +254,7 @@
                     placeholder="请选择"
                     clearable
                     class="w-full"
-                    :disabled="productForm.productReviewStatus === 1"
+                    :disabled=" !!route.params.id"
 
                   >
                     <el-option v-for="option in unitOptions" :key="option.id" :label="`${option.unitNo},${option.unitName}`" :value="option.id" />
@@ -530,8 +530,8 @@
           <el-form ref="purchaseInfoFormRef" :model="productForm" :rules="productRules" label-width="120px" class="product-info-form">
             <el-row :gutter="20">
               <el-col :span="12">
-                <el-form-item label="产品经理:" prop="productNature" required>
-                  <el-select v-model="productForm.productNature" placeholder="请选择" clearable class="w-full" value-key="staffId">
+                <el-form-item label="产品经理:" prop="purchaseManagerNo" required>
+                  <el-select v-model="productForm.purchaseManagerNo" placeholder="请选择" clearable class="w-full" value-key="staffId">
                     <el-option
                       v-for="option in staffOptions"
                       :key="option.staffId"
@@ -542,8 +542,8 @@
                 </el-form-item>
               </el-col>
               <el-col :span="12">
-                <el-form-item label="采购人员:" prop="purchasingPersonnel" required>
-                  <el-select v-model="productForm.purchasingPersonnel" placeholder="请选择" clearable class="w-full" value-key="staffId">
+                <el-form-item label="采购人员:" prop="purchaseNo" required>
+                  <el-select v-model="productForm.purchaseNo" placeholder="请选择" clearable class="w-full" value-key="staffId">
                     <el-option
                       v-for="option in staffOptions"
                       :key="option.staffId"
@@ -825,6 +825,7 @@ import {
   getUnitList
 } from '@/api/product/base';
 import { addBaseAudit, updateBaseAudit, getBaseAudit } from '@/api/product/baseAudit';
+import { listByIds } from '@/api/system/oss';
 import { BaseAuditVO, BaseAuditQuery, BaseAuditForm } from '@/api/product/baseAudit/types';
 import { getTaxCode } from '@/api/system/taxCode';
 import { listBrand, getBrand } from '@/api/product/brand';
@@ -1072,8 +1073,6 @@ const productForm = reactive<BaseForm>({
   minSellingPrice: undefined,
   purchasingPrice: undefined,
   maxPurchasePrice: undefined,
-  productNature: '',
-  purchasingPersonnel: '',
   purchaseNo: undefined,
   purchaseName: undefined,
   purchaseManagerNo: undefined,
@@ -1110,8 +1109,8 @@ const productRules = {
       trigger: 'blur'
     }
   ],
-  productNature: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
-  purchasingPersonnel: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
+  purchaseNo: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
+  purchaseManagerNo: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
   taxRate: [{ required: true, message: '税率不能为空', trigger: 'change' }],
   minOrderQuantity: [{ required: true, message: '最低起订量不能为空', trigger: 'blur' }]
 };
@@ -1205,7 +1204,7 @@ const handleLevel3Search = async (keyword: string) => {
   }
   level3SearchLoading.value = true;
   try {
-    const res = await categoryList({ classLevel: 3, categoryName: keyword, pageNum: 1, pageSize: 50 });
+    const res = await categoryList({ classLevel: 3, categoryName: keyword, platform: 0, pageNum: 1, pageSize: 50 });
     level3SearchOptions.value = (res as any).data || (res as any).rows || [];
   } catch (error) {
     console.error('搜索三级分类失败:', error);
@@ -1322,20 +1321,7 @@ const fillPurchaseFromCategory = async (categoryId: string | number, category?:
     productForm.purchaseManagerNo = detail.purchaseManagerNo || undefined;
     productForm.purchaseManagerName = detail.purchaseManagerName || undefined;
 
-    // 联动产品经理下拉:通过 purchaseManagerNo 匹配 staffCode
-    if (detail.purchaseManagerNo) {
-      const matchedManager = staffOptions.value.find((s) => s.staffCode === detail!.purchaseManagerNo);
-      if (matchedManager) {
-        productForm.productNature = String(matchedManager.staffId);
-      }
-    }
-    // 联动采购人员下拉:通过 purchaseNo 匹配 staffCode
-    if (detail.purchaseNo) {
-      const matchedPurchase = staffOptions.value.find((s) => s.staffCode === detail!.purchaseNo);
-      if (matchedPurchase) {
-        productForm.purchasingPersonnel = String(matchedPurchase.staffId);
-      }
-    }
+  
   } catch (e) {
     console.error('获取三级分类采购信息失败:', e);
   }
@@ -1513,13 +1499,40 @@ const handleSubmit = async () => {
       return;
     }
 
+    // 将主图ossId转为url(如果已是URL则直接使用)
+    let productImageUrl = '';
+    if (productForm.productImage) {
+      if (typeof productForm.productImage === 'string' && (productForm.productImage.startsWith('http://') || productForm.productImage.startsWith('https://'))) {
+        productImageUrl = productForm.productImage;
+      } else {
+        const mainRes = await listByIds(productForm.productImage);
+        if (mainRes.data && mainRes.data.length > 0) {
+          productImageUrl = mainRes.data[0].url;
+        }
+      }
+    }
+    // 将轮播图ossId转为url(如果已是URL则直接使用)
+    let imageUrlStr = '';
+    if (carouselImages.value) {
+      if (typeof carouselImages.value === 'string' && (carouselImages.value.startsWith('http://') || carouselImages.value.startsWith('https://'))) {
+        imageUrlStr = carouselImages.value;
+      } else {
+        const carouselRes = await listByIds(carouselImages.value);
+        if (carouselRes.data && carouselRes.data.length > 0) {
+          imageUrlStr = carouselRes.data.map((item) => item.url).join(',');
+        }
+      }
+    }
+
     // 准备提交数据,包含定制信息(A10产品名称由前端自动拼接,不传后端)
     const submitProductData: any = {
       ...productForm,
+      // 主图存url
+      productImage: productImageUrl,
       // 将服务保障ID数组转换为逗号分隔字符串
       serviceGuarantee: serviceGuarantees.value.map((id) => String(id)).join(','),
-      // 轮播图(ImageUpload 已是逗号分隔字符串)
-      imageUrl: carouselImages.value,
+      // 轮播图存url
+      imageUrl: imageUrlStr,
       // 将商品属性值转换为JSON字符串
       attributesList: JSON.stringify(productAttributesValues.value),
       isCustomize: customForm.isCustomize ? 1 : 0,
@@ -1637,6 +1650,51 @@ const formatPrice = (field: string) => {
       (productForm as any)[field] = num.toFixed(2);
     }
   }
+  // 失焦时校验价格链:市场价 > 官网价 ≥ 最低售价 ≥ 最高采购价 ≥ 采购价
+  validatePriceChain(field);
+};
+
+// 价格链失焦校验
+const validatePriceChain = (field: string) => {
+  const market = parseFloat(String(productForm.marketPrice));
+  const member = parseFloat(String(productForm.memberPrice));
+  const minSell = parseFloat(String(productForm.minSellingPrice));
+  const maxPurch = parseFloat(String(productForm.maxPurchasePrice));
+  const purch = parseFloat(String(productForm.purchasingPrice));
+
+  switch (field) {
+    case 'marketPrice':
+      if (!isNaN(market) && !isNaN(member) && !(market > member)) {
+        ElMessage.warning('市场价必须大于官网价');
+      }
+      break;
+    case 'memberPrice':
+      if (!isNaN(market) && !isNaN(member) && !(market > member)) {
+        ElMessage.warning('官网价必须小于市场价');
+      } else if (!isNaN(member) && !isNaN(minSell) && !(member >= minSell)) {
+        ElMessage.warning('官网价必须大于等于最低售价');
+      }
+      break;
+    case 'minSellingPrice':
+      if (!isNaN(member) && !isNaN(minSell) && !(member >= minSell)) {
+        ElMessage.warning('最低售价必须小于等于官网价');
+      } else if (!isNaN(minSell) && !isNaN(maxPurch) && !(minSell >= maxPurch)) {
+        ElMessage.warning('最低售价必须大于等于最高采购价');
+      }
+      break;
+    case 'maxPurchasePrice':
+      if (!isNaN(minSell) && !isNaN(maxPurch) && !(minSell >= maxPurch)) {
+        ElMessage.warning('最高采购价必须小于等于最低售价');
+      } else if (!isNaN(maxPurch) && !isNaN(purch) && !(maxPurch >= purch)) {
+        ElMessage.warning('最高采购价必须大于等于采购价');
+      }
+      break;
+    case 'purchasingPrice':
+      if (!isNaN(maxPurch) && !isNaN(purch) && !(maxPurch >= purch)) {
+        ElMessage.warning('采购价必须小于等于最高采购价');
+      }
+      break;
+  }
 };
 
 // 格式化表格行中的价格为两位小数(不允许负数)
@@ -1655,7 +1713,7 @@ const formatRowPrice = (row: any, field: string) => {
 // 获取分类树
 const getCategoryTree = async () => {
   try {
-    const res = await categoryTree();
+    const res = await categoryTree({ platform: 0 });
     categoryOptions.value = res.data || [];
   } catch (error) {
     console.error('获取分类树失败:', error);

+ 121 - 30
src/views/product/baseAudit/add.vue

@@ -247,7 +247,7 @@
               </el-col>
 
               <el-col :span="12">
-                <el-form-item label="单位:">
+                <el-form-item label="单位:" disabled>
                   <el-select
                     v-model="productForm.unitId"
                     placeholder="请选择"
@@ -535,8 +535,8 @@
           <el-form ref="purchaseInfoFormRef" :model="productForm" :rules="productRules" label-width="120px" class="product-info-form">
             <el-row :gutter="20">
               <el-col :span="12">
-                <el-form-item label="产品经理:" prop="productNature" required>
-                  <el-select v-model="productForm.productNature" placeholder="请选择" clearable class="w-full" value-key="staffId">
+                <el-form-item label="产品经理:" prop="purchaseManagerNo" required>
+                  <el-select v-model="productForm.purchaseManagerNo" placeholder="请选择" clearable class="w-full" value-key="staffId">
                     <el-option
                       v-for="option in staffOptions"
                       :key="option.staffId"
@@ -547,8 +547,8 @@
                 </el-form-item>
               </el-col>
               <el-col :span="12">
-                <el-form-item label="采购人员:" prop="purchasingPersonnel" required>
-                  <el-select v-model="productForm.purchasingPersonnel" placeholder="请选择" clearable class="w-full" value-key="staffId">
+                <el-form-item label="采购人员:" prop="purchaseNo" required>
+                  <el-select v-model="productForm.purchaseNo" placeholder="请选择" clearable class="w-full" value-key="staffId">
                     <el-option
                       v-for="option in staffOptions"
                       :key="option.staffId"
@@ -659,13 +659,13 @@
           <el-form ref="detailFormRef" :model="productForm" label-width="120px" class="product-info-form">
             <!-- 商品主图 -->
             <el-form-item label="商品主图:" required>
-              <upload-image v-model="productForm.productImage" :limit="1" width="178px" height="178px" imageText="选择图片" />
+              <image-upload v-model="productForm.productImage" :limit="1" width="178px" height="178px" imageText="选择图片" />
               <div class="form-item-tip">从图片库选择,建议尺寸300*300px</div>
             </el-form-item>
 
             <!-- 商品轮播图 -->
             <el-form-item label="商品轮播图:" required>
-              <upload-image v-model="carouselImages" :limit="20" width="120px" height="120px" imageText="添加图片" />
+              <image-upload v-model="carouselImages" :limit="20" width="120px" height="120px" imageText="添加图片" />
               <div class="form-item-tip">从图片库选择,支持多选,建议尺寸300*300px</div>
             </el-form-item>
 
@@ -834,6 +834,7 @@ import {
   updateBaseAudit,
   getBaseAudit,
 } from '@/api/product/baseAudit';
+import { listByIds } from '@/api/system/oss';
 import { BaseAuditVO, BaseAuditQuery, BaseAuditForm } from '@/api/product/baseAudit/types';
 import { getTaxCode } from '@/api/system/taxCode';
 import { listBrand, getBrand } from '@/api/product/brand';
@@ -1076,8 +1077,8 @@ const productForm = reactive<BaseForm>({
   minSellingPrice: undefined,
   purchasingPrice: undefined,
   maxPurchasePrice: undefined,
-  productNature: '1',
-  purchasingPersonnel: '1',
+  purchaseManagerNo: undefined,
+  purchaseNo: undefined,
   pcDetail: undefined,
   mobileDetail: undefined,
   taxRate: undefined,
@@ -1110,8 +1111,8 @@ const productRules = {
   minSellingPrice: [{ required: true, message: '最低售价不能为空', trigger: 'blur' }],
   purchasingPrice: [{ required: true, message: '采购价不能为空', trigger: 'blur' }],
   maxPurchasePrice: [{ required: true, message: '最高采购价不能为空', trigger: 'blur' }],
-  productNature: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
-  purchasingPersonnel: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
+  purchaseManagerNo: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
+  purchaseNo: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
   taxRate: [{ required: true, message: '税率不能为空', trigger: 'change' }],
   minOrderQuantity: [{ required: true, message: '最低起订量不能为空', trigger: 'blur' }]
 };
@@ -1205,7 +1206,7 @@ const handleLevel3Search = async (keyword: string) => {
   }
   level3SearchLoading.value = true;
   try {
-    const res = await categoryList({ classLevel: 3, categoryName: keyword, pageNum: 1, pageSize: 50 });
+    const res = await categoryList({ classLevel: 3, categoryName: keyword, platform: 0, pageNum: 1, pageSize: 50 });
     level3SearchOptions.value = (res as any).data || (res as any).rows || [];
   } catch (error) {
     console.error('搜索三级分类失败:', error);
@@ -1481,13 +1482,60 @@ const handleSubmit = async () => {
       return;
     }
 
+    
+    // 将主图ossId转为url
+    let productImageUrl = '';
+    if (productForm.productImage) {
+      if (Array.isArray(productForm.productImage)) {
+        // 未重新上传,保留原URL
+        productImageUrl = productForm.productImage[0];
+      } else if (typeof productForm.productImage === 'string' && (productForm.productImage.startsWith('http://') || productForm.productImage.startsWith('https://'))) {
+        // ImageUpload emit后可能是URL字符串,直接使用
+        productImageUrl = productForm.productImage;
+      } else {
+        const mainRes = await listByIds(productForm.productImage);
+        if (mainRes.data && mainRes.data.length > 0) {
+          productImageUrl = mainRes.data[0].url;
+        }
+      }
+    }
+    // 将轮播图ossId转为url
+    let imageUrlStr = '';
+    const carouselVal = carouselImages.value as any;
+    if (carouselVal && carouselVal.length > 0) {
+      if (typeof carouselVal === 'string' && (carouselVal.startsWith('http://') || carouselVal.startsWith('https://'))) {
+        // ImageUpload emit后可能是逗号分隔的URL字符串,直接使用
+        imageUrlStr = carouselVal;
+      } else if (Array.isArray(carouselVal)) {
+        const firstItem = carouselVal[0];
+        if (firstItem && (typeof firstItem === 'string' && (firstItem.startsWith('http://') || firstItem.startsWith('https://')))) {
+          // 未重新上传,保留原URL
+          imageUrlStr = carouselVal.join(',');
+        } else {
+          // ossId数组
+          const carouselRes = await listByIds(carouselVal.join(','));
+          if (carouselRes.data && carouselRes.data.length > 0) {
+            imageUrlStr = carouselRes.data.map((item) => item.url).join(',');
+          }
+        }
+      } else {
+        // 用户重新上传了,carouselVal是ossId字符串
+        const carouselRes = await listByIds(carouselVal);
+        if (carouselRes.data && carouselRes.data.length > 0) {
+          imageUrlStr = carouselRes.data.map((item) => item.url).join(',');
+        }
+      }
+    }
+
     // 准备提交数据,包含定制信息(A10产品名称由前端自动拼接,不传后端)
     const submitProductData: any = {
       ...productForm,
+      // 主图存url
+      productImage: productImageUrl,
       // 将服务保障ID数组转换为逗号分隔字符串
       serviceGuarantee: serviceGuarantees.value.map((id) => String(id)).join(','),
-      // 轮播图URL逗号分隔
-      imageUrl: carouselImages.value.join(','),
+      // 轮播图存url
+      imageUrl: imageUrlStr,
       // 将商品属性值转换为JSON字符串
       attributesList: JSON.stringify(productAttributesValues.value),
       isCustomize: customForm.isCustomize ? 1 : 0,
@@ -1592,6 +1640,51 @@ const formatPrice = (field: string) => {
       (productForm as any)[field] = num.toFixed(2);
     }
   }
+    // 失焦时校验价格链:市场价 > 官网价 ≥ 最低售价 ≥ 最高采购价 ≥ 采购价
+  validatePriceChain(field);
+};
+
+// 价格链失焦校验
+const 成 = (field: string) => {
+  const market = parseFloat(String(productForm.marketPrice));
+  const member = parseFloat(String(productForm.memberPrice));
+  const minSell = parseFloat(String(productForm.minSellingPrice));
+  const maxPurch = parseFloat(String(productForm.maxPurchasePrice));
+  const purch = parseFloat(String(productForm.purchasingPrice));
+
+  switch (field) {
+    case 'marketPrice':
+      if (!isNaN(market) && !isNaN(member) && !(market > member)) {
+        ElMessage.warning('市场价必须大于官网价');
+      }
+      break;
+    case 'memberPrice':
+      if (!isNaN(market) && !isNaN(member) && !(market > member)) {
+        ElMessage.warning('官网价必须小于市场价');
+      } else if (!isNaN(member) && !isNaN(minSell) && !(member >= minSell)) {
+        ElMessage.warning('官网价必须大于等于最低售价');
+      }
+      break;
+    case 'minSellingPrice':
+      if (!isNaN(member) && !isNaN(minSell) && !(member >= minSell)) {
+        ElMessage.warning('最低售价必须小于等于官网价');
+      } else if (!isNaN(minSell) && !isNaN(maxPurch) && !(minSell >= maxPurch)) {
+        ElMessage.warning('最低售价必须大于等于最高采购价');
+      }
+      break;
+    case 'maxPurchasePrice':
+      if (!isNaN(minSell) && !isNaN(maxPurch) && !(minSell >= maxPurch)) {
+        ElMessage.warning('最高采购价必须小于等于最低售价');
+      } else if (!isNaN(maxPurch) && !isNaN(purch) && !(maxPurch >= purch)) {
+        ElMessage.warning('最高采购价必须大于等于采购价');
+      }
+      break;
+    case 'purchasingPrice':
+      if (!isNaN(maxPurch) && !isNaN(purch) && !(maxPurch >= purch)) {
+        ElMessage.warning('采购价必须小于等于最高采购价');
+      }
+      break;
+  }
 };
 
 // 格式化表格行中的价格为两位小数(不允许负数)
@@ -1610,7 +1703,7 @@ const formatRowPrice = (row: any, field: string) => {
 // 获取分类树
 const getCategoryTree = async () => {
   try {
-    const res = await categoryTree();
+    const res = await categoryTree({ platform: 0 });
     categoryOptions.value = res.data || [];
   } catch (error) {
     console.error('获取分类树失败:', error);
@@ -1726,8 +1819,8 @@ const getStaffOptions = async () => {
     staffOptions.value = dataList;
     console.log('采购人员列表:', staffOptions.value);
     // 如果有选项且当前没有选中值,设置第一个为默认值
-    if (staffOptions.value.length > 0 && !productForm.purchasingPersonnel) {
-      productForm.purchasingPersonnel = String(staffOptions.value[0].staffId);
+    if (staffOptions.value.length > 0 && !productForm.purchaseNo) {
+      productForm.purchaseNo = String(staffOptions.value[0].staffId);
     }
   } catch (error) {
     console.error('获取采购人员列表失败:', error);
@@ -1799,13 +1892,13 @@ const loadProductDetail = async () => {
       Object.assign(productForm, res.data.productBaseVo);
 
       // 回显产品经理 - 确保转换为字符串类型以匹配下拉框的value
-      if (res.data.productBaseVo.productNature !== undefined && res.data.productBaseVo.productNature !== null) {
-        productForm.productNature = String(res.data.productBaseVo.productNature);
+      if (res.data.productBaseVo.purchaseManagerNo !== undefined && res.data.productBaseVo.purchaseManagerNo !== null) {
+        productForm.purchaseManagerNo = String(res.data.productBaseVo.purchaseManagerNo);
       }
 
       // 回显采购人员 - 确保转换为字符串类型以匹配下拉框的value
-      if (res.data.productBaseVo.purchasingPersonnel !== undefined && res.data.productBaseVo.purchasingPersonnel !== null) {
-        productForm.purchasingPersonnel = String(res.data.productBaseVo.purchasingPersonnel);
+      if (res.data.productBaseVo.purchaseNo !== undefined && res.data.productBaseVo.purchaseNo !== null) {
+        productForm.purchaseNo = String(res.data.productBaseVo.purchaseNo);
       }
 
       // 回显税率编码显示值
@@ -1822,16 +1915,9 @@ const loadProductDetail = async () => {
         }
       }
 
-      // 回显税率 - 在税率选项中查找匹配的值(处理浮点数精度问题)
+      // 回显税率 - 税率由税率编码自动带出(只读),直接赋值
       if (res.data.productBaseVo.taxRate !== undefined && res.data.productBaseVo.taxRate !== null) {
-        const apiTaxRate = Number(res.data.productBaseVo.taxRate);
-        // 使用精度容差比较浮点数
-        const matchedOption = taxRateOptions.value.find((opt) => Math.abs(Number(opt.taxrate) - apiTaxRate) < 0.0001);
-        if (matchedOption) {
-          productForm.taxRate = matchedOption.taxrate;
-        } else {
-          productForm.taxRate = apiTaxRate;
-        }
+        productForm.taxRate = Number(res.data.productBaseVo.taxRate);
       }
 
       // 回显单位 - 确保类型与下拉选项的id一致(数字类型)
@@ -1861,6 +1947,11 @@ const loadProductDetail = async () => {
         productForm.afterSalesService = Number(res.data.productBaseVo.afterSalesService);
       }
 
+      // 回显主图 - 包装为数组让ImageUpload走数组分支直接用URL回显
+      if (res.data.productBaseVo.productImage) {
+        productForm.productImage = [res.data.productBaseVo.productImage] as any;
+      }
+
       // 回显轮播图
       if (res.data.productBaseVo.imageUrl) {
         carouselImages.value = res.data.productBaseVo.imageUrl.split(',').filter((url: string) => url.trim());

+ 14 - 14
src/views/product/baseAudit/view.vue

@@ -391,8 +391,8 @@
           <el-form ref="purchaseInfoFormRef" :model="productForm" :rules="productRules" label-width="120px" class="product-info-form" disabled>
             <el-row :gutter="20">
               <el-col :span="12">
-                <el-form-item label="产品经理:" prop="productNature" required>
-                  <el-select v-model="productForm.productNature" placeholder="请选择" clearable class="w-full" value-key="staffId">
+                <el-form-item label="产品经理:" prop="purchaseManagerNo" required>
+                  <el-select v-model="productForm.purchaseManagerNo" placeholder="请选择" clearable class="w-full" value-key="staffId">
                     <el-option
                       v-for="option in staffOptions"
                       :key="option.staffId"
@@ -403,8 +403,8 @@
                 </el-form-item>
               </el-col>
               <el-col :span="12">
-                <el-form-item label="采购人员:" prop="purchasingPersonnel" required>
-                  <el-select v-model="productForm.purchasingPersonnel" placeholder="请选择" clearable class="w-full" value-key="staffId">
+                <el-form-item label="采购人员:" prop="purchaseNo" required>
+                  <el-select v-model="productForm.purchaseNo" placeholder="请选择" clearable class="w-full" value-key="staffId">
                     <el-option
                       v-for="option in staffOptions"
                       :key="option.staffId"
@@ -894,8 +894,8 @@ const productForm = reactive<BaseForm>({
   minSellingPrice: undefined,
   purchasingPrice: undefined,
   maxPurchasePrice: undefined,
-  productNature: '1',
-  purchasingPersonnel: '1',
+  purchaseManagerNo: undefined,
+  purchaseNo: undefined,
   pcDetail: undefined,
   mobileDetail: undefined,
   taxRate: undefined,
@@ -914,8 +914,8 @@ const productRules = {
   memberPrice: [{ required: true, message: '平台售价不能为空', trigger: 'blur' }],
   minSellingPrice: [{ required: true, message: '最低售价不能为空', trigger: 'blur' }],
   purchasingPrice: [{ required: true, message: '采购价不能为空', trigger: 'blur' }],
-  productNature: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
-  purchasingPersonnel: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
+  purchaseManagerNo: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
+  purchaseNo: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
   taxRate: [{ required: true, message: '税率不能为空', trigger: 'change' }],
   minOrderQuantity: [{ required: true, message: '最低起订量不能为空', trigger: 'blur' }]
 };
@@ -1436,8 +1436,8 @@ const getStaffOptions = async () => {
     staffOptions.value = dataList;
     console.log('采购人员列表:', staffOptions.value);
     // 如果有选项且当前没有选中值,设置第一个为默认值
-    if (staffOptions.value.length > 0 && !productForm.purchasingPersonnel) {
-      productForm.purchasingPersonnel = String(staffOptions.value[0].staffId);
+    if (staffOptions.value.length > 0 && !productForm.purchaseNo) {
+      productForm.purchaseNo = String(staffOptions.value[0].staffId);
     }
   } catch (error) {
     console.error('获取采购人员列表失败:', error);
@@ -1517,13 +1517,13 @@ const loadProductDetail = async () => {
       Object.assign(productForm, res.data.productBaseVo);
 
       // 回显产品经理 - 确保转换为字符串类型以匹配下拉框的value
-      if (res.data.productBaseVo.productNature !== undefined && res.data.productBaseVo.productNature !== null) {
-        productForm.productNature = String(res.data.productBaseVo.productNature);
+      if (res.data.productBaseVo.purchaseManagerNo !== undefined && res.data.productBaseVo.purchaseManagerNo !== null) {
+        productForm.purchaseManagerNo = String(res.data.productBaseVo.purchaseManagerNo);
       }
 
       // 回显采购人员 - 确保转换为字符串类型以匹配下拉框的value
-      if (res.data.productBaseVo.purchasingPersonnel !== undefined && res.data.productBaseVo.purchasingPersonnel !== null) {
-        productForm.purchasingPersonnel = String(res.data.productBaseVo.purchasingPersonnel);
+      if (res.data.productBaseVo.purchaseNo !== undefined && res.data.productBaseVo.purchaseNo !== null) {
+        productForm.purchaseNo = String(res.data.productBaseVo.purchaseNo);
       }
 
       // 回显税率编码显示值

+ 7 - 19
src/views/product/category/index.vue

@@ -44,7 +44,7 @@
           </template>
         </el-table-column>
         <el-table-column prop="sort" align="center" label="排序" width="150"></el-table-column>
-        <el-table-column prop="isShow" align="center" label="是否示" width="150">
+        <el-table-column prop="isShow" align="center" label="是否示" width="150">
           <template #default="scope">
             <span>{{ scope.row.isShow === 1 ? '是' : '否' }}</span>
           </template>
@@ -76,7 +76,7 @@
               <el-tree-select
                 v-model="form.parentId"
                 :data="categoryOptions"
-                :props="{ value: 'id', label: 'label', children: 'children' } as any"
+                :props="{ value: 'id', label: 'categoryName', children: 'children' } as any"
                 value-key="id"
                 placeholder="选择上级分类"
                 check-strictly
@@ -88,11 +88,6 @@
               <el-input v-model="form.categoryName" placeholder="请输入分类名称" />
             </el-form-item>
           </el-col>
-          <el-col :span="12">
-            <el-form-item label="分类编号" prop="categoryNo">
-              <el-input v-model="form.categoryNo" placeholder="请输入分类编号" />
-            </el-form-item>
-          </el-col>
           <el-col :span="12">
             <el-form-item label="标签1" prop="oneLable1">
               <el-input v-model="form.oneLable1" placeholder="请输入标签1" />
@@ -119,15 +114,7 @@
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="平台" prop="platform">
-              <el-select v-model="form.platform" placeholder="请选择所属平台" style="width: 100%">
-                <el-option label="PC端" :value="0" />
-                <el-option label="工业品" :value="1" />
-              </el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="是否提示" prop="isShow">
+            <el-form-item label="是否显示" prop="isShow">
               <el-switch v-model="form.isShow" :active-value="1" :inactive-value="0" />
             </el-form-item>
           </el-col>
@@ -196,7 +183,7 @@ const initFormData: CategoryForm = {
   categoryNo: undefined,
   parentId: undefined,
   sort: 0,
-  platform: undefined,
+  platform: 0,
   isShow: 1,
   isShowGps: 0,
   oneLable1: undefined,
@@ -208,7 +195,8 @@ const initFormData: CategoryForm = {
 const data = reactive<PageData<CategoryForm, Partial<CategoryQuery>>>({
   form: {...initFormData},
   queryParams: {
-    categoryName: undefined
+    categoryName: undefined,
+    platform: 0
   },
   rules: {
     categoryName: [
@@ -294,7 +282,7 @@ const refreshLazyNodes = () => {
 /** 新增按钮操作 */
 const handleAdd = async (row?: CategoryVO) => {
   reset();
-  const res = await listCategory();
+  const res = await listCategory({ platform: 0 });
   const responseData = (res as any).rows || res.data || [];
   const data = proxy?.handleTree<CategoryOptionsType>(responseData, 'id');
   if (data) {

+ 1 - 0
src/views/product/poolAudit/index.vue

@@ -50,6 +50,7 @@
       </template>
 
       <el-table v-loading="loading" border :data="poolAuditList">
+        <el-table-column label="编号" align="center" prop="poolAuditNo" />
         <el-table-column label="产品池类型" align="center" prop="type">
           <template #default="scope">
             <el-tag>