Переглянути джерело

refactor(product): 重构商品基础信息页面代码结构

- 添加useRoute导入并优化路由相关功能
- 移除多余换行和空格,统一代码格式化样式
- 重命名字段specification为specificationsCode,upcBarcode为barCoding
- 重命名字段invoiceSpec为invoiceSpecs,weight为productWeight,volume为productVolume
- 重命名价格字段midRangePrice为marketPrice,standardPrice为memberPrice,purchasePrice为purchasingPrice
- 添加最低售价字段minSellingPrice和最大采购价字段maxPurchasePrice
- 重构价格验证逻辑,增加官网价必须大于最低售价的校验
- 添加自定义属性管理功能和相关操作方法
- 更新表单提交逻辑,改为审核流程模式
- 重命名定制开关customizable为isCustomize
- 优化组件布局结构和模板语法
- 添加主供应商和采购人员选择功能
- 优化代码注释和变量命名规范
肖路 2 тижнів тому
батько
коміт
bf3925f6ba

+ 21 - 45
src/api/product/base/types.ts

@@ -153,35 +153,15 @@ export interface BaseVO {
    */
   freeInstallation?: string;
 
-  /**
-   * 市场价
-   */
-  midRangePrice?: number;
-
-  /**
-   * 平档价
-   */
-  standardPrice?: number;
-
-  /**
-   * 最低售价
-   */
-  certificatePrice?: number;
-
   /**
    * 售价验证量
    */
   priceVerificationQuantity?: string;
 
-  /**
-   * 采购价
-   */
-  purchasePrice?: number;
-
   /**
    *最高采购价
    */
-  estimatedPurchasePrice?: number;
+  maxPurchasePrice?: number;
 
   /**
    * 产品性质
@@ -257,7 +237,6 @@ export interface BaseVO {
    * 审核意见
    */
   auditReason?: string;
-
 }
 
 export interface BaseForm extends BaseEntity {
@@ -379,12 +358,12 @@ export interface BaseForm extends BaseEntity {
   /**
    * 规格型号
    */
-  specification?: string;
+  specificationsCode?: string;
 
   /**
    * UPC(S)条码
    */
-  upcBarcode?: string;
+  barCoding?: string;
 
   /**
    * 发票名称
@@ -394,7 +373,7 @@ export interface BaseForm extends BaseEntity {
   /**
    * 发票规格
    */
-  invoiceSpec?: string;
+  invoiceSpecs?: string;
 
   /**
    * 产品品牌
@@ -426,10 +405,14 @@ export interface BaseForm extends BaseEntity {
    */
   referenceLink?: string;
 
+  /**
+   * 商品描述
+   * */
+  productDescription?: string;
   /**
    * 商品重量
    */
-  weight?: string;
+  productWeight?: string;
 
   /**
    * 重量单位
@@ -439,7 +422,7 @@ export interface BaseForm extends BaseEntity {
   /**
    * 商品体积
    */
-  volume?: string;
+  productVolume?: string;
 
   /**
    * 体积单位
@@ -469,17 +452,17 @@ export interface BaseForm extends BaseEntity {
   /**
    * 市场价
    */
-  midRangePrice?: number;
+  marketPrice?: number;
 
   /**
    * 平档价
    */
-  standardPrice?: number;
+  memberPrice?: number;
 
   /**
    * 最低售价
    */
-  certificatePrice?: number;
+  minSellingPrice?: number;
 
   /**
    * 售价验证量
@@ -489,12 +472,12 @@ export interface BaseForm extends BaseEntity {
   /**
    * 采购价
    */
-  purchasePrice?: number;
+  purchasingPrice?: number;
 
   /**
    *最高采购价
    */
-  estimatedPurchasePrice?: number;
+  maxPurchasePrice?: number;
 
   /**
    * 产品性质
@@ -547,9 +530,9 @@ export interface BaseForm extends BaseEntity {
   minOrderQuantity?: number;
 
   /**
-   * 是否可定制
+   * 是否可定制:1=是,0=否
    */
-  customizable?: boolean;
+  isCustomize?: number | string;
 
   /**
    * 定制方式(逗号分隔)
@@ -595,11 +578,9 @@ export interface BaseForm extends BaseEntity {
    * 商品轮播图URL(逗号分隔)
    */
   imageUrl?: string;
-
 }
 
 export interface BaseQuery extends PageQuery {
-
   /**
    * 搜索文本(商品名称/商品编号)
    */
@@ -730,12 +711,10 @@ export interface BaseQuery extends PageQuery {
    */
   projectOrg?: string;
 
-
-
-    /**
-     * 日期范围参数
-     */
-    params?: any;
+  /**
+   * 日期范围参数
+   */
+  params?: any;
 
   /**
    * 商品ID列表(按指定ID集合查询)
@@ -776,6 +755,3 @@ export class StatusCountVo {
    */
   auditReject: number | null = null;
 }
-
-
-

+ 87 - 0
src/api/product/baseAudit/index.ts

@@ -0,0 +1,87 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { BaseAuditVO, BaseAuditForm, BaseAuditQuery, ProductAuditForm } from '@/api/product/baseAudit/types';
+
+/**
+ * 查询商品审核列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listBaseAudit = (query?: BaseAuditQuery): AxiosPromise<BaseAuditVO[]> => {
+  return request({
+    url: '/product/baseAudit/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询商品审核详细
+ * @param id
+ */
+export const getBaseAudit = (id: string | number): AxiosPromise<BaseAuditVO> => {
+  return request({
+    url: '/product/baseAudit/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增商品审核
+ * @param data
+ */
+export const addBaseAudit = (data: BaseAuditForm) => {
+  return request({
+    url: '/product/baseAudit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改商品审核
+ * @param data
+ */
+export const updateBaseAudit = (data: BaseAuditForm) => {
+  return request({
+    url: '/product/baseAudit',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除商品审核
+ * @param id
+ */
+export const delBaseAudit = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/baseAudit/' + id,
+    method: 'delete'
+  });
+};
+
+/**
+ * 审核商品
+ * @param data
+ */
+export const auditBaseAudit = (data: ProductAuditForm) => {
+  return request({
+    url: '/product/baseAudit/audit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 提交审核
+ * @param data
+ */
+export const commitBaseAudit = (data: BaseAuditForm) => {
+  return request({
+    url: '/product/baseAudit/commit',
+    method: 'post',
+    data: data
+  });
+};

+ 173 - 0
src/api/product/baseAudit/types.ts

@@ -0,0 +1,173 @@
+import { BaseVO } from '@/api/product/base/types';
+
+export interface BaseAuditVO {
+  /**
+   *
+   */
+  id: string | number;
+
+  /**
+   * 商品id
+   */
+  productId: string | number;
+
+  /**
+   * 审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回,4=营销审核,5运营审核
+   */
+  auditStatus: number;
+
+  /**
+   * 审核原因
+   */
+  auditReason: string;
+
+  /**
+   * 审核人
+   */
+  auditUserId: string | number;
+
+  /**
+   * 审核时间
+   */
+  auditTime: string;
+
+  /**
+   * 商品审核数据
+   */
+  productData: string;
+
+  /**
+   * 类型 0=提交审核,1上下架审核
+   */
+  type: number;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+  /**
+  * 商品对象
+  * */
+  productBaseVo?: BaseVO;
+
+}
+
+export interface BaseAuditForm extends BaseEntity {
+  /**
+   *
+   */
+  id?: string | number;
+
+  /**
+   * 商品id
+   */
+  productId?: string | number;
+
+  /**
+   * 审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回,4=营销审核,5运营审核
+   */
+  auditStatus?: number;
+
+  /**
+   * 审核原因
+   */
+  auditReason?: string;
+
+  /**
+   * 审核人
+   */
+  auditUserId?: string | number;
+
+  /**
+   * 审核时间
+   */
+  auditTime?: string;
+
+  /**
+   * 商品审核数据
+   */
+  productData?: string;
+
+  /**
+   * 类型 0=提交审核,1上下架审核
+   */
+  type?: number;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface BaseAuditQuery extends PageQuery {
+
+  /**
+   * 商品id
+   */
+  productId?: string | number;
+
+  /**
+   * 审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回,4=营销审核,5运营审核
+   */
+  auditStatus?: number;
+
+  /**
+   * 审核原因
+   */
+  auditReason?: string;
+
+  /**
+   * 审核人
+   */
+  auditUserId?: string | number;
+
+  /**
+   * 审核时间
+   */
+  auditTime?: string;
+
+  /**
+   * 商品审核数据
+   */
+  productData?: string;
+
+  /**
+   * 类型 0=提交审核,1上下架审核
+   */
+  type?: number;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+/**
+ * 商品审核BO(用于审核操作)
+ */
+export interface ProductAuditForm {
+  /**
+   * ID列表
+   */
+  ids?: Array<string | number>;
+
+  /**
+   * 审核状态 2=通过,3=驳回
+   */
+  auditStatus?: string;
+
+  /**
+   * 驳回原因
+   */
+  auditReason?: string;
+}
+
+
+

+ 12 - 12
src/api/product/category/index.ts

@@ -65,20 +65,10 @@ export const delCategory = (id: string | number | Array<string | number>) => {
 /**
  * 查询产品分类列表(排除节点)
  * @param id
- */
+  */
 export const listCategoryExcludeChild = (id: string | number): AxiosPromise<CategoryVO[]> => {
   return request({
-    url: '/product/category/list/exclude/' + id,
-    method: 'get'
-  });
-};
-
-/**
- * 获取产品分类列表
- */
-export const getProductCategoryList = () => {
-  return request({
-    url: '/product/category/getProductCategoryList',
+    url: '/product/category/tree/exclude/' + id,
     method: 'get'
   });
 };
@@ -95,3 +85,13 @@ export const setCategoryReviewer = (id: string | number, reviewerId: string | nu
     data: { id, reviewerId }
   });
 };
+
+/**
+ * 获取产品分类列表
+ */
+export const getProductCategoryList = () => {
+  return request({
+    url: '/product/category/getProductCategoryList',
+    method: 'get'
+  });
+};

+ 63 - 0
src/api/product/classificationDiy/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ClassificationDiyVO, ClassificationDiyForm, ClassificationDiyQuery } from '@/api/product/classificationDiy/types';
+
+/**
+ * 查询商品自定义属性列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listClassificationDiy = (query?: ClassificationDiyQuery): AxiosPromise<ClassificationDiyVO[]> => {
+  return request({
+    url: '/product/classificationDiy/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询商品自定义属性详细
+ * @param id
+ */
+export const getClassificationDiy = (id: string | number): AxiosPromise<ClassificationDiyVO> => {
+  return request({
+    url: '/product/classificationDiy/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增商品自定义属性
+ * @param data
+ */
+export const addClassificationDiy = (data: ClassificationDiyForm) => {
+  return request({
+    url: '/product/classificationDiy',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改商品自定义属性
+ * @param data
+ */
+export const updateClassificationDiy = (data: ClassificationDiyForm) => {
+  return request({
+    url: '/product/classificationDiy',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除商品自定义属性
+ * @param id
+ */
+export const delClassificationDiy = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/classificationDiy/' + id,
+    method: 'delete'
+  });
+};

+ 86 - 0
src/api/product/classificationDiy/types.ts

@@ -0,0 +1,86 @@
+export interface ClassificationDiyVO {
+  /**
+   * 
+   */
+  id: string | number;
+
+  /**
+   * 商品id
+   */
+  productId: string | number;
+
+  /**
+   * 属性key
+   */
+  attributeKey: string;
+
+  /**
+   * 属性value
+   */
+  attributeValue: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface ClassificationDiyForm extends BaseEntity {
+  /**
+   * 
+   */
+  id?: string | number;
+
+  /**
+   * 商品id
+   */
+  productId?: string | number;
+
+  /**
+   * 属性key
+   */
+  attributeKey?: string;
+
+  /**
+   * 属性value
+   */
+  attributeValue?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface ClassificationDiyQuery extends PageQuery {
+
+  /**
+   * 商品id
+   */
+  productId?: string | number;
+
+  /**
+   * 属性key
+   */
+  attributeKey?: string;
+
+  /**
+   * 属性value
+   */
+  attributeValue?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 26 - 1
src/api/product/poolAudit/index.ts

@@ -1,6 +1,6 @@
 import request from '@/utils/request';
 import { AxiosPromise } from 'axios';
-import { PoolAuditVO, PoolAuditForm, PoolAuditQuery } from '@/api/product/poolAudit/types';
+import { PoolAuditVO, PoolAuditForm, PoolAuditQuery, ProductListVO } from '@/api/product/poolAudit/types';
 import { BaseVO, BaseQuery } from '@/api/product/base/types';
 
 /**
@@ -76,6 +76,19 @@ export const getPoolAuditProductPage = (query?: BaseQuery & PageQuery): AxiosPro
   });
 };
 
+/**
+ * 获取审核池里的商品列表
+ * @param query
+ * @returns {*}
+ * */
+export const selectPoolAuditProductPage = (query?: (BaseQuery & PageQuery) & { type?: number }): AxiosPromise<ProductListVO[]> => {
+  return request({
+    url: '/product/poolAudit/selectPoolAuditProductPage',
+    method: 'get',
+    params: query
+  });
+};
+
 /**
  * 批量审核产品池商品
  * @param data
@@ -117,4 +130,16 @@ export const clearPool = (id: string | number) => {
   });
 };
 
+/**
+ * 单条商品审核池
+ * @param id
+ */
+export const audit = (data: PoolAuditBatchData) => {
+  return request({
+    url: '/product/poolAudit/audit',
+    method: 'post',
+    data: data
+  });
+};
+
 

+ 290 - 0
src/api/product/poolAudit/types.ts

@@ -75,6 +75,11 @@ export interface PoolAuditVO {
    */
   remark: string;
 
+  /**
+   * 申请类型 0更新,1移出
+   */
+  applyType?: number;
+
 }
 
 export interface PoolAuditForm extends BaseEntity {
@@ -164,6 +169,11 @@ export interface PoolAuditForm extends BaseEntity {
    */
   attachment?: string;
 
+    /**
+   * 申请类型 0更新,1移出
+   */
+  applyType?: number;
+
   /**
    * 商品ID列表
    */
@@ -259,6 +269,286 @@ export interface PoolAuditQuery extends PageQuery {
    * 日期范围参数
    */
   params?: any;
+
+  /**
+   * 申请类型 0更新,1移出
+   */
+  applyType?: number;
+}
+
+/**
+ * 审核池商品列表 VO
+ */
+export interface ProductListVO {
+  /**
+   * 主键,自增 ID
+   */
+  id: string | number;
+
+  /**
+   * 产品编号
+   */
+  productNo: string;
+
+  /**
+   * 商品名称
+   */
+  itemName: string;
+
+  /**
+   * 品牌 id
+   */
+  brandId: string | number;
+
+  /**
+   * 顶级分类 id
+   */
+  topCategoryId: string | number;
+
+  /**
+   * 中级分类 id
+   */
+  mediumCategoryId: string | number;
+
+  /**
+   * 底层分类 id
+   */
+  bottomCategoryId: string | number;
+
+  /**
+   * 单位 id
+   */
+  unitId: string | number;
+
+  /**
+   * 产品图片 URL
+   */
+  productImage: string;
+
+  /**
+   * 产品图片 URLUrl
+   */
+  productImageUrl: string;
+
+  /**
+   * 是否自营(1=是,0=否)
+   */
+  isSelf: string;
+
+  /**
+   * 商品类型 1=默认类型,2 精选商品,3=停售商品
+   * */
+  productCategory?: number;
+
+  /**
+   * 产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核
+   */
+  productReviewStatus: string;
+
+  /**
+   * 首页推荐:1=推荐,0=不推荐
+   */
+  homeRecommended: string;
+
+  /**
+   * 分类推荐:1=推荐,0=不推荐
+   */
+  categoryRecommendation: string;
+
+  /**
+   * 购物车推荐:1=推荐,0=不推荐
+   */
+  cartRecommendation: string;
+
+  /**
+   * 推荐产品顺序
+   */
+  recommendedProductOrder: number;
+
+  /**
+   * 是否热门:1=是,0=否
+   */
+  isPopular: string;
+
+  /**
+   * 是否新品:1=是,0=否
+   */
+  isNew: string;
+
+  /**
+   * 商品状态:1=已上架,0=下架,2=上架中
+   */
+  productStatus: number;
+
+  /**
+   * 数据来源
+   */
+  dataSource: string;
+
+  /**
+   * 市场价
+   */
+  marketPrice: number;
+
+  /**
+   * 官网价
+   */
+  memberPrice: number;
+
+  /**
+   * 最低销售价格
+   */
+  minSellingPrice: number;
+
+  /**
+   * 采购价格
+   */
+  purchasingPrice: number;
+
+  /**
+   * 暂估毛利率
+   */
+  tempGrossMargin: number;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+  /**
+   * 主库简介
+   */
+  mainLibraryIntro?: string;
+
+  /**
+   * 售后服务
+   */
+  afterSalesService?: string;
+
+  /**
+   * 服务保障 支持多选,分隔 (存储服务保障 ID 列表,如:"1,2,3")
+   */
+  serviceGuarantee?: string;
+
+  /**
+   * 安装服务 - 免费安装
+   */
+  freeInstallation?: string;
+
+  /**
+   * 市场价
+   */
+  midRangePrice?: number;
+
+  /**
+   * 平档价
+   */
+  standardPrice?: number;
+
+  /**
+   * 最低售价
+   */
+  certificatePrice?: number;
+
+  /**
+   * 售价验证量
+   */
+  priceVerificationQuantity?: string;
+
+  /**
+   * 采购价
+   */
+  purchasePrice?: number;
+
+  /**
+   * 最高采购价
+   */
+  estimatedPurchasePrice?: number;
+
+  /**
+   * 产品性质
+   */
+  productNature?: string;
+
+  /**
+   * 采购人员
+   */
+  purchasingPersonnel?: string;
+
+  /**
+   * 旧属性类型
+   */
+  oldAttributeType?: string;
+
+  /**
+   * 录入套数
+   */
+  entrySetCount?: string;
+
+  /**
+   * 商品主图
+   */
+  mainImage?: string;
+
+  /**
+   * 商品详情 - 电脑端
+   */
+  pcDetail?: string;
+
+  /**
+   * 商品详情 - 移动端
+   */
+  mobileDetail?: string;
+
+  /**
+   * 税率
+   */
+  taxRate?: number;
+
+  /**
+   * 币种
+   */
+  currency?: string;
+
+  /**
+   * 最低起订量
+   */
+  minOrderQuantity?: number;
+
+  /**
+   * 审核意见
+   */
+  reviewComments?: string;
+
+  /**
+   * 商品属性值(JSON 字符串)
+   */
+  attributesList?: string;
+
+  /**
+   * 商品轮播图 URL(逗号分隔)
+   */
+  imageUrl?: string;
+
+  /**
+   * 审核状态 1=待审核,2=审核通过,3=审核驳回
+   */
+  auditStatus?: number;
+
+  /**
+   * 审核意见
+   */
+  auditReason?: string;
+
+  /**
+   * 关联的入池单 ID
+   */
+  poolAuditId?: string | number;
+
+  /**
+   * 协议价格
+   */
+  agreementPrice?: number;
 }
 
 

+ 29 - 0
src/api/product/poolLinkAudit/types.ts

@@ -54,6 +54,15 @@ export interface PoolLinkAuditVO {
    */
   remark: string;
 
+  /**
+   * 计价规则(0 一品一价,1 按类目折扣率报价)
+   */
+  pricingRule: string;
+
+  /**
+   * 起订量
+   */
+  minOrderQuantity: number;
 }
 
 export interface PoolLinkAuditForm extends BaseEntity {
@@ -112,6 +121,16 @@ export interface PoolLinkAuditForm extends BaseEntity {
    */
   remark?: string;
 
+  /**
+   * 计价规则(0 一品一价,1 按类目折扣率报价)
+   */
+  pricingRule: string;
+
+  /**
+   * 起订量
+   */
+  minOrderQuantity: number;
+
 }
 
 export interface PoolLinkAuditQuery extends PageQuery {
@@ -170,6 +189,16 @@ export interface PoolLinkAuditQuery extends PageQuery {
      * 日期范围参数
      */
     params?: any;
+
+  /**
+   * 计价规则(0 一品一价,1 按类目折扣率报价)
+   */
+  pricingRule: string;
+
+  /**
+   * 起订量
+   */
+  minOrderQuantity: number;
 }
 
 

+ 1 - 1
src/views/order/revenueHeader/add.vue

@@ -205,7 +205,7 @@
   </div>
 </template>
 <script setup lang="ts">
-import { useRouter } from 'vue-router';
+import { useRouter, useRoute } from 'vue-router';
 import { listRevenueHeader, getRevenueHeader, addRevenueHeader, updateRevenueHeader } from '@/api/order/revenueHeader';
 import { RevenueHeaderVO, RevenueHeaderQuery, RevenueHeaderForm } from '@/api/order/revenueHeader/types';
 import { listCustomerInfo, getCustomerInfo } from '@/api/customer/customerFile/customerInfo';

Різницю між файлами не показано, бо вона завелика
+ 265 - 266
src/views/product/base/add.vue


+ 1970 - 0
src/views/product/base/add1.vue

@@ -0,0 +1,1970 @@
+<template>
+  <div class="app-container">
+    <el-card shadow="never" class="mb-3">
+      <div class="flex items-center justify-between">
+        <div class="flex items-center">
+          <el-button icon="ArrowLeft" @click="handleBack">返回</el-button>
+          <span class="ml-4 text-xl font-bold">{{ pageTitle }}</span>
+        </div>
+      </div>
+    </el-card>
+
+    <div class="product-wizard-page">
+      <!-- 步骤条 -->
+      <el-card shadow="never" class="mb-3">
+        <el-steps :active="currentStep" finish-status="success" align-center>
+          <el-step title="选择分类" description="选择商品分类" />
+          <el-step title="填写商品信息" description="填写商品基本信息" />
+          <el-step title="完成" description="确认提交" />
+        </el-steps>
+      </el-card>
+
+      <!-- 步骤内容 -->
+      <div class="step-content" v-loading="loading">
+        <!-- 步骤1: 选择分类 -->
+        <el-card v-show="currentStep === 0" shadow="never" class="step-card">
+          <template #header>
+            <div class="flex items-center justify-between">
+              <span class="text-lg font-bold">选择分类</span>
+              <span v-if="selectedLevel3Name" class="text-sm ml-4" style="color: #409eff"> 已选:{{ getCategoryPath() }} </span>
+            </div>
+          </template>
+
+          <div class="category-selection">
+            <el-row :gutter="20">
+              <!-- 一级分类 -->
+              <el-col :span="8">
+                <div class="category-box">
+                  <div class="category-header">选择一级分类</div>
+                  <div class="category-search">
+                    <el-input v-model="searchLevel1" placeholder="搜索一级分类" clearable prefix-icon="Search" size="small" />
+                  </div>
+                  <div class="category-list">
+                    <div
+                      v-for="item in filteredLevel1Categories"
+                      :key="item.id"
+                      :class="[
+                        'category-item',
+                        { 'active': categoryForm.topCategoryId === item.id, 'disabled': !item.children || item.children.length === 0 }
+                      ]"
+                      @click="selectLevel1(item)"
+                    >
+                      <span>{{ item.label }}</span>
+                      <el-icon v-if="categoryForm.topCategoryId === item.id"><ArrowRight /></el-icon>
+                    </div>
+                    <el-empty v-if="filteredLevel1Categories.length === 0" description="暂无数据" :image-size="60" />
+                  </div>
+                </div>
+              </el-col>
+
+              <!-- 二级分类 -->
+              <el-col :span="8">
+                <div class="category-box">
+                  <div class="category-header">选择二级分类</div>
+                  <div class="category-search">
+                    <el-input v-model="searchLevel2" placeholder="搜索二级分类" clearable prefix-icon="Search" size="small" />
+                  </div>
+                  <div class="category-list">
+                    <div
+                      v-for="item in filteredLevel2Categories"
+                      :key="item.id"
+                      :class="[
+                        'category-item',
+                        { 'active': categoryForm.mediumCategoryId === item.id, 'disabled': !item.children || item.children.length === 0 }
+                      ]"
+                      @click="selectLevel2(item)"
+                    >
+                      <span>{{ item.label }}</span>
+                      <el-icon v-if="categoryForm.mediumCategoryId === item.id"><ArrowRight /></el-icon>
+                    </div>
+                    <el-empty
+                      v-if="filteredLevel2Categories.length === 0"
+                      :description="categoryForm.topCategoryId ? '当前分类无子分类,请选择其他一级分类' : '请先选择一级分类'"
+                      :image-size="60"
+                    />
+                  </div>
+                </div>
+              </el-col>
+
+              <!-- 三级分类 -->
+              <el-col :span="8">
+                <div class="category-box">
+                  <div class="category-header">选择三级分类</div>
+                  <div class="category-search">
+                    <el-select
+                      v-model="level3SearchValue"
+                      placeholder="搜索全部三级分类"
+                      filterable
+                      remote
+                      clearable
+                      :remote-method="handleLevel3Search"
+                      :loading="level3SearchLoading"
+                      size="small"
+                      class="w-full"
+                      @change="handleLevel3SearchSelect"
+                    >
+                      <el-option v-for="item in level3SearchOptions" :key="item.id" :label="item.categoryName" :value="item.id" />
+                    </el-select>
+                  </div>
+                  <div class="category-list">
+                    <div
+                      v-for="item in filteredLevel3Categories"
+                      :key="item.id"
+                      :class="['category-item', { 'active': categoryForm.bottomCategoryId === item.id }]"
+                      @click="selectLevel3(item)"
+                    >
+                      <span>{{ item.label }}</span>
+                      <el-icon v-if="categoryForm.bottomCategoryId === item.id"><Check /></el-icon>
+                    </div>
+                    <el-empty
+                      v-if="filteredLevel3Categories.length === 0"
+                      :description="categoryForm.mediumCategoryId ? '当前分类无子分类,请选择其他二级分类' : '请先选择二级分类'"
+                      :image-size="60"
+                    />
+                  </div>
+                </div>
+              </el-col>
+            </el-row>
+          </div>
+
+          <!-- 已选分类提示 -->
+          <!-- <div class="mt-4">
+            <el-checkbox v-model="autoCreateCategory" label="如果选择的分类不存在,自动创建分类" />
+          </div>
+          <div class="mt-2">
+            <el-input
+              v-model="manualCategoryInput"
+              placeholder="请输入入口类名称"
+              clearable
+              style="width: 400px;"
+            />
+          </div> -->
+        </el-card>
+
+        <!-- 步骤2: 填写商品信息 -->
+        <el-card v-show="currentStep === 1" shadow="never" class="step-card">
+          <template #header>
+            <span class="text-lg font-bold">基本信息</span>
+          </template>
+
+          <el-form ref="productFormRef" :model="productForm" :rules="productRules" label-width="120px" class="product-info-form">
+            <!-- 商品分类显示 -->
+            <el-form-item label="商品分类:">
+              <div class="category-display">
+                <span class="category-text">{{ getCategoryPath() }}</span>
+                <el-link type="primary" :underline="false" @click="currentStep = 0" class="ml-2">修改</el-link>
+                <el-link type="danger" :underline="false" @click="clearCategory" class="ml-2">删除</el-link>
+              </div>
+            </el-form-item>
+
+            <!-- 商品编号 -->
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="商品编号:" prop="productNo">
+                  <el-input v-model="productForm.productNo" placeholder="002169745" maxlength="20" show-word-limit disabled />
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="状态:">
+                  <span class="category-text">上架在售</span>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <!-- 商品名称 -->
+            <el-form-item label="商品名称:" prop="itemName" required>
+              <el-input v-model="productForm.itemName" type="textarea" :rows="2" placeholder="请输入商品名称" maxlength="200" show-word-limit />
+            </el-form-item>
+
+            <!-- A10产品名称 -->
+            <el-form-item label="A10产品名称:">
+              <el-input
+                :value="a10ProductNameComputed"
+                type="textarea"
+                :rows="2"
+                disabled
+                placeholder="自动拼接:品牌名 + 规格型号 + 产品分类 + 发票规格"
+              />
+              <div class="form-item-tip">A10产品名称由系统自动拼接:品牌名 + 规格型号 + 产品分类(三级分类)+ 发票规格,无需手动填写</div>
+            </el-form-item>
+
+            <!-- 规格型号 和 UPC(69)条码 -->
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="规格型号:">
+                  <el-input v-model="productForm.specificationsCode" placeholder="请输入规格型号" maxlength="20" show-word-limit />
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="UPC(69)条码:">
+                  <el-input v-model="productForm.barCoding" placeholder="请输入UPC(69)条码" maxlength="20" show-word-limit @input="handleUpcInput" />
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <!-- 发票名称 和 发票规格 -->
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="发票名称:">
+                  <el-input v-model="productForm.invoiceName" placeholder="请输入发票名称" maxlength="20" show-word-limit />
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="发票规格:">
+                  <el-input v-model="productForm.invoiceSpecs" placeholder="请输入发票规格" maxlength="20" show-word-limit />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <!-- 商品品牌 -->
+              <el-col :span="12">
+                <el-form-item label="商品品牌:" prop="brandId" required>
+                  <el-select
+                    v-model="productForm.brandId"
+                    placeholder="请输入品牌名称搜索"
+                    filterable
+                    remote
+                    clearable
+                    :remote-method="handleBrandSearch"
+                    :loading="brandLoading"
+                    class="w-full"
+                  >
+                    <el-option v-for="item in brandOptions" :key="item.id" :label="item.brandName" :value="item.id" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+
+              <el-col :span="12">
+                <el-form-item label="单位:">
+                  <el-select
+                    v-model="productForm.unitId"
+                    placeholder="请选择"
+                    clearable
+                    class="w-full"
+                    :disabled="productForm.productReviewStatus === 1"
+                  >
+                    <el-option v-for="option in unitOptions" :key="option.id" :label="option.unitName" :value="option.id" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <!-- 税率编码 、税率 和 币种 -->
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="税率编码:">
+                  <el-input
+                    v-model="taxCodeNo"
+                    placeholder="点击选择税率编码"
+                    readonly
+                    class="w-full"
+                    style="cursor: pointer"
+                    @click="taxCodeSelectRef?.open()"
+                  >
+                    <template #suffix>
+                      <el-icon style="cursor: pointer" @click.stop="taxCodeSelectRef?.open()"><Search /></el-icon>
+                    </template>
+                  </el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="税率:" required>
+                  <el-select v-model="productForm.taxRate" placeholder="请选择税率" clearable class="w-full">
+                    <el-option v-for="option in taxRateOptions" :key="option.id" :label="option.taxrate" :value="option.taxrate" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="币种:">
+                  <el-select v-model="productForm.currency" placeholder="请选择" class="w-full">
+                    <el-option label="人民币(RMB)" value="RMB" />
+                    <el-option label="美元(USD)" value="USD" />
+                    <el-option label="欧元(EUR)" value="EUR" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <!-- TaxCodeSelect 弹窗 -->
+            <TaxCodeSelect ref="taxCodeSelectRef" @select="handleTaxCodeSelect" />
+
+            <!-- 销量人气 -->
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="销量人气:">
+                  <el-input
+                    v-model="productForm.salesVolume"
+                    type="number"
+                    placeholder="请输入销量人气"
+                    :min="0"
+                    step="1"
+                    @input="handleSalesVolumeInput"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <!-- 促销标题 -->
+            <el-form-item label="促销标题:">
+              <el-input v-model="productForm.packagingSpec" type="textarea" :rows="3" placeholder="请输入促销标题" maxlength="300" show-word-limit />
+            </el-form-item>
+
+            <!-- 重量 和 体积 -->
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="商品重量:">
+                  <el-input v-model="productForm.productWeight" placeholder="0" maxlength="10" show-word-limit>
+                    <template #append>
+                      <el-select v-model="productForm.weightUnit" placeholder="请选择" style="width: 100px">
+                        <el-option label="kg" value="kg" />
+                        <el-option label="g" value="g" />
+                        <el-option label="t" value="t" />
+                      </el-select>
+                    </template>
+                  </el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="商品体积:">
+                  <el-input v-model="productForm.productVolume" placeholder="0" maxlength="10" show-word-limit>
+                    <template #append>
+                      <el-select v-model="productForm.volumeUnit" placeholder="请选择" style="width: 80px">
+                        <el-option label="m³" value="m3" />
+                        <el-option label="cm³" value="cm3" />
+                        <el-option label="L" value="L" />
+                      </el-select>
+                    </template>
+                  </el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+
+            <!-- 参考链接 -->
+            <el-form-item label="参考链接">
+              <el-input v-model="productForm.referenceLink" type="textarea" :rows="3" placeholder="请输入参考链接" />
+            </el-form-item>
+
+
+            <!-- 主供应商 -->
+            <el-form-item label="主供应商:" prop="mainLibraryIntro" required>
+              <el-select v-model="productForm.mainLibraryIntro" placeholder="请选择" clearable class="w-full" value-key="id">
+                <el-option
+                  v-for="option in supplierOptions"
+                  :key="option.id"
+                  :label="`${option.supplierNo},${option.enterpriseName}`"
+                  :value="String(option.id)"
+                />
+              </el-select>
+            </el-form-item>
+
+            <!-- 售后服务 -->
+            <el-form-item label="售后服务:">
+              <el-select v-model="productForm.afterSalesService" placeholder="请选择" clearable class="w-full">
+                <el-option v-for="option in afterSalesOptions" :key="option.id" :label="option.afterSalesItems" :value="option.id" />
+              </el-select>
+            </el-form-item>
+
+            <!-- 服务保障 -->
+            <el-form-item label="服务保障:">
+              <el-checkbox-group v-model="serviceGuarantees">
+                <el-checkbox v-for="option in serviceGuaranteeOptions" :key="option.id" :label="option.ensureName" :value="option.id" />
+              </el-checkbox-group>
+            </el-form-item>
+
+            <!-- 安装服务 -->
+            <el-form-item label="安装服务:">
+              <el-checkbox-group v-model="installationServices">
+                <el-checkbox label="免费安装" value="freeInstallation" />
+              </el-checkbox-group>
+            </el-form-item>
+          </el-form>
+        </el-card>
+
+        <!-- 销售价格 -->
+        <el-card v-show="currentStep === 1" shadow="never" class="step-card mt-3">
+          <template #header>
+            <span class="text-lg font-bold">销售价格</span>
+          </template>
+
+          <el-form ref="priceFormRef" :model="productForm" :rules="productRules" label-width="120px" class="product-info-form">
+            <el-row :gutter="20">
+              <el-col :span="8">
+                <el-form-item label="市场价:" prop="marketPrice" required>
+                  <el-input
+                    v-model="productForm.marketPrice"
+                    type="number"
+                    placeholder="请输入市场价"
+                    :min="0"
+                    @blur="formatPrice('marketPrice')"
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item label="官网价:" prop="memberPrice" required>
+                  <el-input
+                    v-model="productForm.memberPrice"
+                    type="number"
+                    placeholder="请输入平台售价"
+                    :min="0"
+                    @blur="formatPrice('memberPrice')"
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item label="最低售价:" prop="minSellingPrice" required>
+                  <el-input
+                    v-model="productForm.minSellingPrice"
+                    type="number"
+                    placeholder="请输入最低售价"
+                    :min="0"
+                    @blur="formatPrice('minSellingPrice')"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="8">
+                <el-form-item label="最低起订量:" prop="minOrderQuantity" required>
+                  <el-input v-model="productForm.minOrderQuantity" type="number" placeholder="请输入最低起订量" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item label="备注:">
+                  <span class="currency-text">市场价>官网价>最低售价</span>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+
+        <!-- 采购价格 -->
+        <el-card v-show="currentStep === 1" shadow="never" class="step-card mt-3">
+          <template #header>
+            <span class="text-lg font-bold">采购价格</span>
+          </template>
+
+          <el-form ref="purchasePriceFormRef" :model="productForm" :rules="productRules" label-width="120px" class="product-info-form">
+            <el-row :gutter="20">
+              <el-col :span="12">
+                <el-form-item label="采购价:" prop="purchasingPrice" required>
+                  <el-input
+                    v-model="productForm.purchasingPrice"
+                    type="number"
+                    placeholder="请输入采购价"
+                    :min="0"
+                    @blur="formatPrice('purchasingPrice')"
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="最高采购价:">
+                  <el-input
+                    v-model="productForm.maxPurchasePrice"
+                    type="number"
+                    placeholder="请输入最高采购价"
+                    :min="0"
+                    @blur="formatPrice('maxPurchasePrice')"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+
+        <!-- 采购信息 -->
+        <el-card v-show="currentStep === 1" shadow="never" class="step-card mt-3">
+          <template #header>
+            <span class="text-lg font-bold">采购信息</span>
+          </template>
+
+          <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-option
+                      v-for="option in staffOptions"
+                      :key="option.staffId"
+                      :label="`${option.staffCode},${option.staffName}`"
+                      :value="String(option.staffId)"
+                    />
+                  </el-select>
+                </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-option
+                      v-for="option in staffOptions"
+                      :key="option.staffId"
+                      :label="`${option.staffCode},${option.staffName}`"
+                      :value="String(option.staffId)"
+                    />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+        <!-- 自定义属性 -->
+        <el-card v-show="currentStep === 1" shadow="never" class="step-card mt-3">
+          <template #header>
+            <div class="flex items-center justify-between">
+              <span class="text-lg font-bold">自定义属性</span>
+              <el-button type="primary" icon="Plus" size="small" @click="addDiyAttribute">添加属性</el-button>
+            </div>
+          </template>
+
+          <el-form label-width="0px" class="product-info-form">
+            <div v-if="diyAttributesList.length === 0" class="text-center text-gray-400 py-4 text-sm">
+              暂无自定义属性,点击右上角"添加属性"按钮添加
+            </div>
+            <el-row v-for="(item, index) in diyAttributesList" :key="index" :gutter="20" class="mb-2">
+              <el-col :span="11">
+                <el-input v-model="item.attributeKey" placeholder="请输入属性名称" clearable />
+              </el-col>
+              <el-col :span="11">
+                <el-input v-model="item.attributeValue" placeholder="请输入属性值" clearable />
+              </el-col>
+              <el-col :span="2" class="flex items-center">
+                <el-button type="danger" icon="Delete" circle size="small" @click="removeDiyAttribute(index)" />
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+
+        <!-- 商品属性 -->
+        <el-card v-show="currentStep === 1" shadow="never" class="step-card mt-3">
+          <template #header>
+            <span class="text-lg font-bold">商品属性</span>
+          </template>
+
+          <el-form ref="attributeFormRef" :model="productForm" label-width="120px" class="product-info-form">
+            <div v-if="attributesList.length === 0" class="text-center text-gray-500 py-8">该分类暂无属性配置</div>
+            <template v-else>
+              <el-row :gutter="20" v-for="(row, rowIndex) in Math.ceil(attributesList.length / 2)" :key="rowIndex">
+                <el-col :span="12" v-for="colIndex in 2" :key="colIndex">
+                  <template v-if="attributesList[rowIndex * 2 + colIndex - 1]">
+                    <el-form-item
+                      :label="attributesList[rowIndex * 2 + colIndex - 1].productAttributesName + ':'"
+                      :required="attributesList[rowIndex * 2 + colIndex - 1].required === '1'"
+                    >
+                      <!-- 下拉选择 -->
+                      <el-select
+                        v-if="attributesList[rowIndex * 2 + colIndex - 1].entryMethod === '1'"
+                        v-model="productAttributesValues[attributesList[rowIndex * 2 + colIndex - 1].id]"
+                        placeholder="请选择"
+                        clearable
+                        class="w-full"
+                      >
+                        <el-option
+                          v-for="option in parseAttributesList(attributesList[rowIndex * 2 + colIndex - 1].attributesList)"
+                          :key="option"
+                          :label="option"
+                          :value="option"
+                        />
+                      </el-select>
+                      <!-- 多选 -->
+                      <el-select
+                        v-else-if="attributesList[rowIndex * 2 + colIndex - 1].entryMethod === '3'"
+                        v-model="productAttributesValues[attributesList[rowIndex * 2 + colIndex - 1].id]"
+                        placeholder="请选择"
+                        multiple
+                        clearable
+                        class="w-full"
+                      >
+                        <el-option
+                          v-for="option in parseAttributesList(attributesList[rowIndex * 2 + colIndex - 1].attributesList)"
+                          :key="option"
+                          :label="option"
+                          :value="option"
+                        />
+                      </el-select>
+                      <!-- 文本输入 -->
+                      <el-input
+                        v-else
+                        v-model="productAttributesValues[attributesList[rowIndex * 2 + colIndex - 1].id]"
+                        placeholder="请输入"
+                        clearable
+                      />
+                    </el-form-item>
+                  </template>
+                </el-col>
+              </el-row>
+            </template>
+          </el-form>
+        </el-card>
+
+        <!-- 商品详情 -->
+        <el-card v-show="currentStep === 1" shadow="never" class="step-card mt-3">
+          <template #header>
+            <span class="text-lg font-bold">商品详情</span>
+          </template>
+
+          <el-form ref="detailFormRef" :model="productForm" label-width="120px" class="product-info-form">
+            <!-- 商品主图 -->
+            <el-form-item label="商品主图:">
+              <upload-image 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="商品轮播图:">
+              <upload-image v-model="carouselImages" :limit="20" width="120px" height="120px" imageText="添加图片" />
+              <div class="form-item-tip">从图片库选择,支持多选,建议尺寸300*300px</div>
+            </el-form-item>
+
+            <!-- 商品详情 -->
+            <el-form-item label="商品详情:">
+              <el-tabs v-model="activeDetailTab" type="border-card">
+                <el-tab-pane label="电脑端详情" name="pc">
+                  <Editor v-model="productForm.pcDetail" :height="400" />
+                </el-tab-pane>
+                <el-tab-pane label="移动端详情" name="mobile">
+                  <Editor v-model="productForm.mobileDetail" :height="400" />
+                </el-tab-pane>
+              </el-tabs>
+            </el-form-item>
+          </el-form>
+        </el-card>
+
+        <!-- 定制说明 -->
+        <el-card v-show="currentStep === 1" shadow="never" class="step-card mt-3">
+          <template #header>
+            <span class="text-lg font-bold">定制说明</span>
+          </template>
+
+          <el-form ref="customFormRef" :model="customForm" label-width="120px" class="product-info-form">
+            <!-- 可定制开关 -->
+            <el-form-item label="可定制:">
+              <el-switch v-model="customForm.isCustomize" />
+            </el-form-item>
+
+            <!-- 定制内容 -->
+            <template v-if="customForm.isCustomize">
+              <!-- 定制方式 -->
+              <el-form-item label="定制方式:">
+                <div class="custom-options">
+                  <el-button
+                    v-for="option in customMethodOptions"
+                    :key="option.value"
+                    :type="customForm.selectedMethods.includes(option.value) ? 'primary' : 'default'"
+                    @click="toggleMethod(option.value)"
+                  >
+                    {{ option.label }}
+                  </el-button>
+                </div>
+              </el-form-item>
+
+              <!-- 定制工艺 -->
+              <el-form-item label="定制工艺:">
+                <div class="custom-options">
+                  <el-button
+                    v-for="craft in customCraftOptions"
+                    :key="craft.value"
+                    :type="customForm.selectedCrafts.includes(craft.value) ? 'primary' : 'default'"
+                    @click="toggleCraft(craft.value)"
+                  >
+                    {{ craft.label }}
+                  </el-button>
+                </div>
+              </el-form-item>
+
+              <!-- 定制方式表格 -->
+              <el-form-item label="" label-width="120">
+                <el-table :data="customForm.customDetails" border class="custom-table">
+                  <el-table-column label="装饰方法" width="120">
+                    <template #default="{ row }">
+                      <span>{{ row.decorationMethod }}</span>
+                    </template>
+                  </el-table-column>
+                  <el-table-column label="定制工艺" width="120">
+                    <template #default="{ row }">
+                      <span>{{ row.craft }}</span>
+                    </template>
+                  </el-table-column>
+                  <el-table-column label="起订数量" width="150">
+                    <template #default="{ row }">
+                      <el-input v-model="row.minOrderQty" placeholder="请输入" />
+                    </template>
+                  </el-table-column>
+                  <el-table-column label="起订价格" width="150">
+                    <template #default="{ row }">
+                      <el-input
+                        v-model="row.minOrderPrice"
+                        type="number"
+                        :min="0"
+                        placeholder="请输入"
+                        @blur="formatRowPrice(row, 'minOrderPrice')"
+                      />
+                    </template>
+                  </el-table-column>
+                  <el-table-column label="打样工期[天]" width="150">
+                    <template #default="{ row }">
+                      <el-input v-model="row.samplePeriod" placeholder="请输入" />
+                    </template>
+                  </el-table-column>
+                  <el-table-column label="生产周期[天]" width="150">
+                    <template #default="{ row }">
+                      <el-input v-model="row.productionPeriod" placeholder="请输入" />
+                    </template>
+                  </el-table-column>
+                  <el-table-column label="操作" width="100" fixed="right">
+                    <template #default="{ $index }">
+                      <el-link type="danger" :underline="false" @click="removeCustomDetail($index)"> 删除 </el-link>
+                    </template>
+                  </el-table-column>
+                </el-table>
+              </el-form-item>
+
+              <!-- 定制说明 -->
+              <el-form-item label="定制说明:">
+                <el-input v-model="customForm.customDescription" type="textarea" :rows="5" placeholder="请输入定制说明" />
+              </el-form-item>
+            </template>
+          </el-form>
+        </el-card>
+
+        <!-- 步骤3: 完成 -->
+        <el-card v-show="currentStep === 2" shadow="never" class="step-card completion-card">
+          <div class="completion-content">
+            <div class="success-icon">
+              <el-icon :size="80" color="#67c23a">
+                <CircleCheck />
+              </el-icon>
+            </div>
+            <div class="completion-text">商品编辑完成,请点击返回,继续其他操作</div>
+            <div class="completion-action">
+              <el-button type="primary" @click="handleBackToList">返回</el-button>
+            </div>
+          </div>
+        </el-card>
+      </div>
+
+      <!-- 底部操作按钮 -->
+      <el-card v-if="currentStep < 2" shadow="never" class="mt-3">
+        <div class="flex justify-center gap-4">
+          <el-button v-if="currentStep > 0" @click="prevStep">上一步</el-button>
+          <el-button v-if="currentStep < 2" type="primary" @click="nextStep">下一步</el-button>
+          <el-button @click="handleBack">取消</el-button>
+        </div>
+      </el-card>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, computed, onMounted, watch, nextTick } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+import { ElMessage } from 'element-plus';
+import { Warning, ArrowRight, Check, Plus, CircleCheck, Search } from '@element-plus/icons-vue';
+import Editor from '@/components/Editor/index.vue';
+import UploadImage from '@/components/upload-image/index.vue';
+import TaxCodeSelect from '@/components/TaxCodeSelect/index.vue';
+import { categoryTreeVO, CategoryVO } from '@/api/product/category/types';
+import { BrandVO } from '@/api/product/brand/types';
+import { BaseForm } from '@/api/product/base/types';
+import { ClassificationDiyForm } from '@/api/product/classificationDiy/types';
+import { AttributesVO } from '@/api/product/attributes/types';
+import {
+  addBase,
+  updateBase,
+  getBase,
+  categoryTree,
+  categoryList,
+  categoryAttributeList,
+  getAfterSaleList,
+  getServiceList,
+  getUnitList,
+  getTaxRateList
+} from '@/api/product/base';
+import {
+  addBaseAudit,
+  updateBaseAudit,
+  getBaseAudit,
+} from '@/api/product/baseAudit';
+import { BaseAuditVO, BaseAuditQuery, BaseAuditForm } from '@/api/product/baseAudit/types';
+import { getTaxCode } from '@/api/system/taxCode';
+import { listBrand, getBrand } from '@/api/product/brand';
+import { listInfo } from '@/api/customer/supplierInfo';
+import { InfoVO } from '@/api/customer/supplierInfo/types';
+import { listComStaff } from '@/api/system/comStaff';
+import { ComStaffVO } from '@/api/system/comStaff/types';
+
+const route = useRoute();
+const router = useRouter();
+
+const currentStep = ref(0);
+const loading = ref(false);
+const submitLoading = ref(false);
+const productFormRef = ref();
+
+// 服务保障和安装服务的多选框
+const serviceGuarantees = ref<(string | number)[]>([]);
+const installationServices = ref<string[]>([]);
+
+// 商品详情选项卡
+const activeDetailTab = ref('pc');
+
+// 轮播图URL数组(UI管理用)
+const carouselImages = ref<string[]>([]);
+
+// 税率选项
+const taxRateOptions = ref<any[]>([]);
+
+// 税率编码选择组件
+const taxCodeSelectRef = ref();
+// 已选的税率编码(显示用)
+const taxCodeNo = ref('');
+
+// 处理税率编码选择
+const handleTaxCodeSelect = async (row: any) => {
+  (productForm as any).taxationId = row.id;
+  try {
+    const taxRes = await getTaxCode(row.id);
+    if (taxRes.data) {
+      taxCodeNo.value = taxRes.data.name || row.name || '';
+    } else {
+      taxCodeNo.value = row.name || '';
+    }
+  } catch (e) {
+    console.error('获取税率编码详情失败:', e);
+    taxCodeNo.value = row.name || '';
+  }
+  // 同时将显示值存入 form,方便编辑回显时直接读取
+  (productForm as any).taxationNo = taxCodeNo.value;
+};
+
+// 定制说明表单
+const customForm = reactive({
+  isCustomize: false,
+  selectedMethods: [] as string[],
+  selectedCrafts: [] as string[],
+  customDetails: [] as Array<{
+    decorationMethod: string;
+    craft: string;
+    minOrderQty: string;
+    minOrderPrice: string;
+    samplePeriod: string;
+    productionPeriod: string;
+  }>,
+  customDescription: ''
+});
+
+// 定制方式选项
+const customMethodOptions = [
+  { label: '包装定制', value: 'package' },
+  { label: '商品定制', value: 'product' },
+  { label: '开模定制', value: 'mold' }
+];
+
+// 定制工艺选项
+const customCraftOptions = [
+  { label: '丝印', value: 'silkScreen' },
+  { label: '热转印', value: 'thermalTransfer' },
+  { label: '激光', value: 'laser' },
+  { label: '烤花', value: 'baking' },
+  { label: '压印', value: 'embossing' }
+];
+
+// 定制方式映射
+const customMethodMap: Record<string, string> = {
+  'package': '包装定制',
+  'product': '商品定制',
+  'mold': '开模定制'
+};
+
+// 定制工艺映射
+const customCraftMap: Record<string, string> = {
+  'silkScreen': '丝印',
+  'thermalTransfer': '热转印',
+  'laser': '激光',
+  'baking': '烤花',
+  'embossing': '压印'
+};
+
+// 服务保障选择不需要watch,在提交时直接转换为逗号分隔字符串
+
+// 监听安装服务复选框变化,同步到表单
+watch(
+  installationServices,
+  (newVal) => {
+    productForm.freeInstallation = newVal.includes('freeInstallation') ? '1' : '0';
+  },
+  { deep: true }
+);
+
+// 监听定制方式和工艺选择变化,更新表格数据
+watch(
+  [() => customForm.selectedMethods, () => customForm.selectedCrafts],
+  ([newMethods, newCrafts]) => {
+    const newDetails: typeof customForm.customDetails = [];
+
+    // 遍历所有选中的定制方式和工艺组合
+    newMethods.forEach((method) => {
+      const decorationMethod = customMethodMap[method];
+
+      newCrafts.forEach((craft) => {
+        const craftName = customCraftMap[craft];
+
+        // 查找是否已存在该组合的数据
+        const existing = customForm.customDetails.find((item) => item.decorationMethod === decorationMethod && item.craft === craftName);
+
+        newDetails.push(
+          existing || {
+            decorationMethod,
+            craft: craftName,
+            minOrderQty: '',
+            minOrderPrice: '',
+            samplePeriod: '',
+            productionPeriod: ''
+          }
+        );
+      });
+    });
+
+    customForm.customDetails = newDetails;
+  },
+  { deep: true }
+);
+
+// 切换定制方式选择
+const toggleMethod = (method: string) => {
+  const index = customForm.selectedMethods.indexOf(method);
+  if (index > -1) {
+    customForm.selectedMethods.splice(index, 1);
+  } else {
+    customForm.selectedMethods.push(method);
+  }
+};
+
+// 切换定制工艺选择
+const toggleCraft = (craft: string) => {
+  const index = customForm.selectedCrafts.indexOf(craft);
+  if (index > -1) {
+    customForm.selectedCrafts.splice(index, 1);
+  } else {
+    customForm.selectedCrafts.push(craft);
+  }
+};
+
+// 删除定制详情行
+const removeCustomDetail = (index: number) => {
+  customForm.customDetails.splice(index, 1);
+};
+
+const pageTitle = computed(() => {
+  return route.params.id ? '编辑商品' : '新增商品';
+});
+
+// 分类选择表单
+const categoryForm = reactive({
+  topCategoryId: undefined as string | number | undefined,
+  mediumCategoryId: undefined as string | number | undefined,
+  bottomCategoryId: undefined as string | number | undefined
+});
+
+const autoCreateCategory = ref(false);
+const manualCategoryInput = ref('');
+
+// 商品信息表单
+const productForm = reactive<BaseForm>({
+  id: undefined,
+  productNo: undefined,
+  itemName: undefined,
+  brandId: undefined,
+  topCategoryId: undefined,
+  mediumCategoryId: undefined,
+  bottomCategoryId: undefined,
+  unitId: undefined,
+  productImage: undefined,
+  imageUrl: undefined,
+  isSelf: 0,
+  productReviewStatus: 0,
+  homeRecommended: 0,
+  categoryRecommendation: 0,
+  cartRecommendation: 0,
+  recommendedProductOrder: 0,
+  isPopular: 0,
+  isNew: 0,
+  productStatus: '0',
+  remark: undefined,
+  a10ProductName: undefined,
+  specificationsCode: undefined,
+  barCoding: undefined,
+  invoiceName: undefined,
+  invoiceSpecs: undefined,
+  packagingSpec: undefined,
+  referenceLink: undefined,
+  productWeight: undefined,
+  weightUnit: 'kg',
+  productVolume: undefined,
+  volumeUnit: 'm3',
+  mainLibraryIntro: undefined,
+  afterSalesService: undefined,
+  serviceGuarantee: undefined, // 服务保障ID列表,逗号分隔
+  freeInstallation: '0',
+  marketPrice: undefined,
+  memberPrice: undefined,
+  minSellingPrice: undefined,
+  purchasingPrice: undefined,
+  maxPurchasePrice: undefined,
+  productNature: '1',
+  purchasingPersonnel: '1',
+  pcDetail: undefined,
+  mobileDetail: undefined,
+  taxRate: undefined,
+  currency: 'RMB',
+  minOrderQuantity: undefined,
+  salesVolume: undefined
+});
+
+// 表单验证规则
+const productRules = {
+  // productNo: [{ required: true, message: '商品编号不能为空', trigger: 'blur' }],
+  itemName: [{ required: true, message: '商品名称不能为空', trigger: 'blur' }],
+  brandId: [{ required: true, message: '商品品牌不能为空', trigger: 'change' }],
+  mainLibraryIntro: [{ required: true, message: '主供应商不能为空', trigger: 'change' }],
+  marketPrice: [{ required: true, message: '市场价不能为空', trigger: 'blur' }],
+  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' }],
+  taxRate: [{ required: true, message: '税率不能为空', trigger: 'change' }],
+  minOrderQuantity: [{ required: true, message: '最低起订量不能为空', trigger: 'blur' }]
+};
+
+// 分类和品牌选项
+const categoryOptions = ref<categoryTreeVO[]>([]);
+const brandOptions = ref<BrandVO[]>([]);
+const brandLoading = ref(false);
+let brandSearchTimer: ReturnType<typeof setTimeout> | null = null;
+
+// 商品属性列表
+const attributesList = ref<AttributesVO[]>([]);
+const productAttributesValues = ref<Record<string | number, any>>({});
+
+// 售后服务和服务保障选项
+const afterSalesOptions = ref<any[]>([]);
+const serviceGuaranteeOptions = ref<any[]>([]);
+
+// 单位选项
+const unitOptions = ref<any[]>([]);
+
+// 主供应商选项
+const supplierOptions = ref<InfoVO[]>([]);
+
+// 自定义属性列表
+const diyAttributesList = ref<ClassificationDiyForm[]>([]);
+
+// 添加自定义属性行
+const addDiyAttribute = () => {
+  diyAttributesList.value.push({ attributeKey: '', attributeValue: '' });
+};
+
+// 删除自定义属性行
+const removeDiyAttribute = (index: number) => {
+  diyAttributesList.value.splice(index, 1);
+};
+
+// 采购人员选项
+const staffOptions = ref<ComStaffVO[]>([]);
+
+// 搜索关键词
+const searchLevel1 = ref('');
+const searchLevel2 = ref('');
+const searchLevel3 = ref('');
+
+// 三级分类下拉搜索
+const level3SearchValue = ref<string | number | null>(null);
+const level3SearchOptions = ref<CategoryVO[]>([]);
+const level3SearchLoading = ref(false);
+
+// 一级分类列表
+const level1Categories = computed(() => {
+  return categoryOptions.value || [];
+});
+
+// 二级分类列表
+const level2Categories = ref<categoryTreeVO[]>([]);
+
+// 三级分类列表
+const level3Categories = ref<categoryTreeVO[]>([]);
+
+// 过滤后的一级分类列表
+const filteredLevel1Categories = computed(() => {
+  if (!searchLevel1.value) {
+    return level1Categories.value;
+  }
+  return level1Categories.value.filter((item) => item.label.toLowerCase().includes(searchLevel1.value.toLowerCase()));
+});
+
+// 过滤后的二级分类列表
+const filteredLevel2Categories = computed(() => {
+  if (!searchLevel2.value) {
+    return level2Categories.value;
+  }
+  return level2Categories.value.filter((item) => item.label.toLowerCase().includes(searchLevel2.value.toLowerCase()));
+});
+
+// 过滤后的三级分类列表
+const filteredLevel3Categories = computed(() => {
+  if (!searchLevel3.value) {
+    return level3Categories.value;
+  }
+  return level3Categories.value.filter((item) => item.label.toLowerCase().includes(searchLevel3.value.toLowerCase()));
+});
+
+// 搜索三级分类(调用接口)
+const handleLevel3Search = async (keyword: string) => {
+  if (!keyword) {
+    level3SearchOptions.value = [];
+    return;
+  }
+  level3SearchLoading.value = true;
+  try {
+    const res = await categoryList({ classLevel: 3, categoryName: keyword, pageNum: 1, pageSize: 50 });
+    level3SearchOptions.value = (res as any).data || (res as any).rows || [];
+  } catch (error) {
+    console.error('搜索三级分类失败:', error);
+  } finally {
+    level3SearchLoading.value = false;
+  }
+};
+
+// 选择三级分类搜索结果后,自动在树中定位
+const handleLevel3SearchSelect = async (categoryId: string | number) => {
+  if (!categoryId) return;
+  const selectedCategory = level3SearchOptions.value.find((item) => String(item.id) === String(categoryId));
+  if (!selectedCategory) return;
+
+  // 在分类树中查找对应的二级节点(三级的父节点)
+  const level2Node = findCategoryById(categoryOptions.value, selectedCategory.parentId);
+  if (!level2Node) return;
+
+  // 在一级列表中查找(二级的父节点)
+  const level1Node = level1Categories.value.find((item) => String(item.id) === String(level2Node.parentId));
+  if (!level1Node) return;
+
+  // 依次选中一级、二级、三级
+  categoryForm.topCategoryId = level1Node.id;
+  selectedLevel1Name.value = level1Node.label;
+  level2Categories.value = level1Node.children || [];
+
+  await nextTick();
+
+  categoryForm.mediumCategoryId = level2Node.id;
+  selectedLevel2Name.value = level2Node.label;
+  level3Categories.value = level2Node.children || [];
+
+  await nextTick();
+
+  // 精确查找三级节点
+  const level3Node = level3Categories.value.find((item) => String(item.id) === String(selectedCategory.id));
+  if (level3Node) {
+    categoryForm.bottomCategoryId = level3Node.id;
+    selectedLevel3Name.value = level3Node.label;
+    await loadCategoryAttributes(level3Node.id);
+  } else {
+    categoryForm.bottomCategoryId = selectedCategory.id;
+    selectedLevel3Name.value = selectedCategory.categoryName;
+    await loadCategoryAttributes(selectedCategory.id);
+  }
+
+  // 清空搜索框
+  level3SearchValue.value = null;
+  level3SearchOptions.value = [];
+};
+
+// 选中的分类名称
+const selectedLevel1Name = ref('');
+const selectedLevel2Name = ref('');
+const selectedLevel3Name = ref('');
+
+// 选择一级分类
+const selectLevel1 = (item: categoryTreeVO) => {
+  if (!item.children || item.children.length === 0) {
+    ElMessage.warning('该分类无子分类,请选择含三级分类的类别');
+    return;
+  }
+  categoryForm.topCategoryId = item.id;
+  categoryForm.mediumCategoryId = undefined;
+  categoryForm.bottomCategoryId = undefined;
+  selectedLevel1Name.value = item.label;
+  selectedLevel2Name.value = '';
+  selectedLevel3Name.value = '';
+
+  level2Categories.value = item.children || [];
+  level3Categories.value = [];
+};
+
+// 选择二级分类
+const selectLevel2 = (item: categoryTreeVO) => {
+  if (!item.children || item.children.length === 0) {
+    ElMessage.warning('该分类无子分类,请选择含三级分类的类别');
+    return;
+  }
+  categoryForm.mediumCategoryId = item.id;
+  categoryForm.bottomCategoryId = undefined;
+  selectedLevel2Name.value = item.label;
+  selectedLevel3Name.value = '';
+
+  level3Categories.value = item.children || [];
+};
+
+// 选择三级分类
+const selectLevel3 = async (item: categoryTreeVO) => {
+  categoryForm.bottomCategoryId = item.id;
+  selectedLevel3Name.value = item.label;
+
+  // 加载该分类下的属性列表
+  await loadCategoryAttributes(item.id);
+};
+
+// 获取分类路径
+const getCategoryPath = () => {
+  const parts = [];
+  if (selectedLevel1Name.value) parts.push(selectedLevel1Name.value);
+  if (selectedLevel2Name.value) parts.push(selectedLevel2Name.value);
+  if (selectedLevel3Name.value) parts.push(selectedLevel3Name.value);
+  return parts.join(' > ') || '请选择分类';
+};
+
+// 清除分类
+const clearCategory = () => {
+  categoryForm.topCategoryId = undefined;
+  categoryForm.mediumCategoryId = undefined;
+  categoryForm.bottomCategoryId = undefined;
+  selectedLevel1Name.value = '';
+  selectedLevel2Name.value = '';
+  selectedLevel3Name.value = '';
+  level2Categories.value = [];
+  level3Categories.value = [];
+  attributesList.value = [];
+  productAttributesValues.value = {};
+};
+
+// 下一步
+const nextStep = async () => {
+  if (currentStep.value === 0) {
+    // 验证分类选择
+    if (!categoryForm.topCategoryId) {
+      ElMessage.warning('请选择一级分类');
+      return;
+    }
+    if (!categoryForm.mediumCategoryId) {
+      ElMessage.warning('请选择二级分类');
+      return;
+    }
+    if (!categoryForm.bottomCategoryId) {
+      ElMessage.warning('请选择三级分类');
+      return;
+    }
+
+    // 将分类信息同步到商品表单
+    productForm.topCategoryId = categoryForm.topCategoryId;
+    productForm.mediumCategoryId = categoryForm.mediumCategoryId;
+    productForm.bottomCategoryId = categoryForm.bottomCategoryId;
+
+    currentStep.value++;
+  } else if (currentStep.value === 1) {
+    // 验证商品信息表单并提交
+    try {
+      await productFormRef.value?.validate();
+      // 调用提交函数
+      await handleSubmit();
+    } catch (error) {
+      ElMessage.warning('请完善商品信息');
+      return;
+    }
+  }
+};
+
+// 上一步
+const prevStep = () => {
+  if (currentStep.value > 0) {
+    currentStep.value--;
+  }
+};
+
+// 提交
+const handleSubmit = async () => {
+  try {
+    submitLoading.value = true;
+
+    // 校验价格关系:市场价 > 官网价 > 最低售价
+    const midRange = parseFloat(String(productForm.marketPrice));
+    const standard = parseFloat(String(productForm.memberPrice));
+    const certificate = parseFloat(String(productForm.minSellingPrice));
+    if (!isNaN(midRange) && !isNaN(standard) && !isNaN(certificate)) {
+      if (!(midRange > standard)) {
+        ElMessage.warning('市场价必须大于官网价');
+        submitLoading.value = false;
+        return;
+      }
+      if (!(standard > certificate)) {
+        ElMessage.warning('官网价必须大于最低售价');
+        submitLoading.value = false;
+        return;
+      }
+    }
+
+    // 准备提交数据,包含定制信息(A10产品名称由前端自动拼接,不传后端)
+    const submitProductData: any = {
+      ...productForm,
+      // 将服务保障ID数组转换为逗号分隔字符串
+      serviceGuarantee: serviceGuarantees.value.map((id) => String(id)).join(','),
+      // 轮播图URL逗号分隔
+      imageUrl: carouselImages.value.join(','),
+      // 将商品属性值转换为JSON字符串
+      attributesList: JSON.stringify(productAttributesValues.value),
+      isCustomize: customForm.isCustomize ? 1 : 0,
+      customizedStyle: customForm.selectedMethods.join(','),
+      customizedCraft: customForm.selectedCrafts.join(','),
+      customDescription: customForm.customDescription,
+      customDetailsJson: JSON.stringify(customForm.customDetails),
+      diyAttributesList: diyAttributesList.value.filter((item) => item.attributeKey || item.attributeValue)
+    };
+    // A10产品名称不传后端
+    delete submitProductData.a10ProductName;
+
+    const auditData: BaseAuditForm = {
+      id: productForm.id,
+      productData: JSON.stringify(submitProductData),
+      type: 0,
+      auditStatus: 0
+    };
+    if (productForm.id) {
+      await updateBase(auditData);
+      ElMessage.success('修改成功');
+    } else {
+      await addBaseAudit(auditData);
+      ElMessage.success('新增成功');
+    }
+    // 跳转到完成页面(步骤3)
+    currentStep.value = 2;
+  } catch (error) {
+    console.error('提交失败:', error);
+  } finally {
+    submitLoading.value = false;
+  }
+};
+
+// 返回
+const handleBack = () => {
+  router.back();
+};
+
+// 返回列表
+const handleBackToList = () => {
+  router.push('/product/base');
+};
+
+// UPC(69)条码只允许输入数字
+const handleUpcInput = () => {
+  if (productForm.barCoding) {
+    productForm.barCoding = productForm.barCoding.replace(/\D/g, '');
+  }
+};
+
+// 销量人气只允许输入整数
+const handleSalesVolumeInput = (val: string) => {
+  if (val !== undefined && val !== null && val !== '') {
+    const intVal = parseInt(String(val).replace(/[^\d]/g, ''), 10);
+    productForm.salesVolume = !isNaN(intVal) ? intVal : undefined;
+  } else {
+    productForm.salesVolume = undefined;
+  }
+};
+
+// A10产品名称自动拼接(品牌名 + 规格型号 + 产品分类 + 发票规格)
+const a10ProductNameComputed = computed(() => {
+  const brand = brandOptions.value.find((b) => Number(b.id) === Number(productForm.brandId));
+  const brandName = brand?.brandName || '';
+  const specificationsCode = productForm.specificationsCode || '';
+  const categoryName = selectedLevel3Name.value || '';
+  const invoiceSpecs = productForm.invoiceSpecs || '';
+  return [brandName, specificationsCode, categoryName, invoiceSpecs].filter((s) => s.trim()).join(' ');
+});
+
+// 格式化价格为两位小数(不允许负数)
+const formatPrice = (field: string) => {
+  const val = (productForm as any)[field];
+  if (val !== undefined && val !== null && val !== '') {
+    let num = parseFloat(String(val));
+    if (!isNaN(num)) {
+      // 不允许负数
+      if (num < 0) num = 0;
+      (productForm as any)[field] = num.toFixed(2);
+    }
+  }
+};
+
+// 格式化表格行中的价格为两位小数(不允许负数)
+const formatRowPrice = (row: any, field: string) => {
+  const val = row[field];
+  if (val !== undefined && val !== null && val !== '') {
+    let num = parseFloat(String(val));
+    if (!isNaN(num)) {
+      // 不允许负数
+      if (num < 0) num = 0;
+      row[field] = num.toFixed(2);
+    }
+  }
+};
+
+// 获取分类树
+const getCategoryTree = async () => {
+  try {
+    const res = await categoryTree();
+    categoryOptions.value = res.data || [];
+  } catch (error) {
+    console.error('获取分类树失败:', error);
+  }
+};
+
+// 加载品牌选项(默认100条)
+const loadBrandOptions = async (keyword?: string) => {
+  brandLoading.value = true;
+  try {
+    const res = await listBrand({ pageNum: 1, pageSize: 100, brandName: keyword });
+    const newList = res.rows || [];
+    // 编辑模式下保留当前选中的品牌,避免被新列表覆盖后 A10产品名称 computed 失效
+    if (productForm.brandId) {
+      const exists = newList.find((item) => Number(item.id) === Number(productForm.brandId));
+      if (!exists) {
+        const currentBrand = brandOptions.value.find((item) => Number(item.id) === Number(productForm.brandId));
+        if (currentBrand) {
+          newList.unshift(currentBrand);
+        }
+      }
+    }
+    brandOptions.value = newList;
+  } catch (error) {
+    console.error('加载品牌列表失败:', error);
+  } finally {
+    brandLoading.value = false;
+  }
+};
+
+// 品牌远程搜索(防抖)
+const handleBrandSearch = (query: string) => {
+  if (brandSearchTimer) clearTimeout(brandSearchTimer);
+  brandSearchTimer = setTimeout(() => {
+    loadBrandOptions(query || undefined);
+  }, 300);
+};
+
+// 处理品牌下拉框显示/隐藏
+const handleBrandVisibleChange = (visible: boolean) => {
+  if (visible && brandOptions.value.length === 0) {
+    loadBrandOptions();
+  }
+};
+
+// 获取售后服务列表
+const getAfterSalesOptions = async () => {
+  try {
+    const res = await getAfterSaleList();
+    afterSalesOptions.value = res.data || [];
+    // 如果是新增模式且有选项,设置第一个为默认值
+    if (!route.params.id && afterSalesOptions.value.length > 0 && !productForm.afterSalesService) {
+      productForm.afterSalesService = afterSalesOptions.value[0].id;
+    }
+  } catch (error) {
+    console.error('获取售后服务列表失败:', error);
+  }
+};
+
+// 获取服务保障列表
+const getServiceGuaranteeOptions = async () => {
+  try {
+    const res = await getServiceList();
+    serviceGuaranteeOptions.value = res.data || [];
+    // 如果是新增模式且有选项,设置第一个为默认选中
+    if (!route.params.id && serviceGuaranteeOptions.value.length > 0 && serviceGuarantees.value.length === 0) {
+      serviceGuarantees.value = [serviceGuaranteeOptions.value[0].id];
+    }
+  } catch (error) {
+    console.error('获取服务保障列表失败:', error);
+  }
+};
+
+// 获取单位列表
+const getUnitOptions = async () => {
+  try {
+    const res = await getUnitList();
+    unitOptions.value = res.data || [];
+    // 如果是新增模式且有选项,设置第一个为默认值
+    if (!route.params.id && unitOptions.value.length > 0 && !productForm.unitId) {
+      productForm.unitId = unitOptions.value[0].id;
+    }
+  } catch (error) {
+    console.error('获取单位列表失败:', error);
+  }
+};
+
+// 获取主供应商列表
+const getSupplierOptions = async () => {
+  try {
+    const res = await listInfo();
+    console.log('供应商接口返回:', res);
+    // 处理可能的数据结构: res.data 或 res.rows
+    const dataList = res.data || res.rows || [];
+    supplierOptions.value = dataList;
+    console.log('供应商列表:', supplierOptions.value);
+    // 如果有选项且当前没有选中值,设置第一个为默认值
+    if (supplierOptions.value.length > 0 && !productForm.mainLibraryIntro) {
+      productForm.mainLibraryIntro = String(supplierOptions.value[0].id);
+    }
+  } catch (error) {
+    console.error('获取主供应商列表失败:', error);
+  }
+};
+
+// 获取采购人员列表
+const getStaffOptions = async () => {
+  try {
+    const res = await listComStaff();
+    console.log('采购人员接口返回:', res);
+    // 处理可能的数据结构: res.data 或 res.rows
+    const dataList = res.data || res.rows || [];
+    staffOptions.value = dataList;
+    console.log('采购人员列表:', staffOptions.value);
+    // 如果有选项且当前没有选中值,设置第一个为默认值
+    if (staffOptions.value.length > 0 && !productForm.purchasingPersonnel) {
+      productForm.purchasingPersonnel = String(staffOptions.value[0].staffId);
+    }
+  } catch (error) {
+    console.error('获取采购人员列表失败:', error);
+  }
+};
+
+// 获取税率列表
+const getTaxRateOptions = async () => {
+  try {
+    const res = await getTaxRateList();
+    taxRateOptions.value = res.rows || [];
+  } catch (error) {
+    console.error('获取税率列表失败:', error);
+  }
+};
+
+// 加载分类属性列表
+const loadCategoryAttributes = async (categoryId: string | number) => {
+  try {
+    const res = await categoryAttributeList(categoryId);
+    attributesList.value = res.data || [];
+    // 清空之前的属性值
+    productAttributesValues.value = {};
+
+    // 如果是新增模式,为有选项的属性设置默认值
+    if (!route.params.id) {
+      attributesList.value.forEach((attr) => {
+        if (attr.entryMethod === '1' && attr.attributesList) {
+          // 下拉选择
+          const options = parseAttributesList(attr.attributesList);
+          if (options.length > 0) {
+            productAttributesValues.value[attr.id] = options[0];
+          }
+        } else if (attr.entryMethod === '3' && attr.attributesList) {
+          // 多选
+          const options = parseAttributesList(attr.attributesList);
+          if (options.length > 0) {
+            productAttributesValues.value[attr.id] = [options[0]];
+          }
+        }
+      });
+    }
+  } catch (error) {
+    console.error('加载分类属性失败:', error);
+    attributesList.value = [];
+  }
+};
+
+// 解析属性值列表(JSON数组或逗号分隔字符串)
+const parseAttributesList = (attributesListStr: string): string[] => {
+  if (!attributesListStr) return [];
+
+  try {
+    // 尝试解析为JSON数组
+    const parsed = JSON.parse(attributesListStr);
+    if (Array.isArray(parsed)) {
+      return parsed;
+    }
+  } catch (e) {
+    // 如果不是JSON,按逗号分隔
+    return attributesListStr
+      .split(',')
+      .map((item) => item.trim())
+      .filter((item) => item);
+  }
+
+  return [];
+};
+
+// 加载商品详情(编辑模式)
+const loadProductDetail = async () => {
+  const id = route.params.id;
+  if (id) {
+    try {
+      loading.value = true;
+      const res = await getBase(id as string);
+      Object.assign(productForm, res.data);
+
+      // 回显产品经理 - 确保转换为字符串类型以匹配下拉框的value
+      if (res.data.productNature !== undefined && res.data.productNature !== null) {
+        productForm.productNature = String(res.data.productNature);
+      }
+
+      // 回显采购人员 - 确保转换为字符串类型以匹配下拉框的value
+      if (res.data.purchasingPersonnel !== undefined && res.data.purchasingPersonnel !== null) {
+        productForm.purchasingPersonnel = String(res.data.purchasingPersonnel);
+      }
+
+      // 回显税率编码显示值
+      const rawData = res.data as any;
+      // 通过 taxationId 调接口获取中文名称回显
+      if (rawData.taxationId) {
+        try {
+          const taxRes = await getTaxCode(rawData.taxationId);
+          if (taxRes.data) {
+            taxCodeNo.value = taxRes.data.name || '';
+          }
+        } catch (e) {
+          console.error('获取税率编码失败:', e);
+        }
+      }
+
+      // 回显税率 - 在税率选项中查找匹配的值(处理浮点数精度问题)
+      if (res.data.taxRate !== undefined && res.data.taxRate !== null) {
+        const apiTaxRate = Number(res.data.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;
+        }
+      }
+
+      // 回显单位 - 确保类型与下拉选项的id一致(数字类型)
+      if (res.data.unitId !== undefined && res.data.unitId !== null) {
+        productForm.unitId = Number(res.data.unitId);
+      }
+
+      // 回显品牌 - 先加载对应的品牌信息到选项列表中
+      if (res.data.brandId) {
+        productForm.brandId = Number(res.data.brandId);
+        try {
+          const brandRes = await getBrand(res.data.brandId);
+          if (brandRes.data) {
+            // 检查品牌是否已在选项列表中
+            const existBrand = brandOptions.value.find((item) => Number(item.id) === Number(res.data.brandId));
+            if (!existBrand) {
+              brandOptions.value.unshift(brandRes.data);
+            }
+          }
+        } catch (e) {
+          console.error('加载品牌信息失败:', e);
+        }
+      }
+
+      // 回显售后服务 - 确保类型与下拉选项的id一致(数字类型)
+      if (res.data.afterSalesService !== undefined && res.data.afterSalesService !== null) {
+        productForm.afterSalesService = String(res.data.afterSalesService);
+      }
+
+      // 回显轮播图
+      if (res.data.imageUrl) {
+        carouselImages.value = res.data.imageUrl.split(',').filter((url: string) => url.trim());
+      } else {
+        carouselImages.value = [];
+      }
+
+      // 回显分类选择
+      categoryForm.topCategoryId = res.data.topCategoryId;
+      categoryForm.mediumCategoryId = res.data.mediumCategoryId;
+      categoryForm.bottomCategoryId = res.data.bottomCategoryId;
+
+      // 回显服务保障复选框 - 将逗号分隔的ID字符串转换为数组
+      if (res.data.serviceGuarantee) {
+        serviceGuarantees.value = res.data.serviceGuarantee.split(',').map((id: string) => {
+          // 尝试转换为数字,如果失败则保持字符串
+          const numId = Number(id.trim());
+          return isNaN(numId) ? id.trim() : numId;
+        });
+      } else {
+        serviceGuarantees.value = [];
+      }
+
+      // 回显安装服务复选框
+      const services: string[] = [];
+      if (res.data.freeInstallation === '1') services.push('freeInstallation');
+      installationServices.value = services;
+
+      // 回显分类名称 - 使用nextTick确保DOM更新后再查找子分类
+      await restoreCategorySelection();
+
+      // 回显商品属性值(必须在restoreCategorySelection之后,避免loadCategoryAttributes清空属性值)
+      if (res.data.attributesList) {
+        try {
+          const parsedAttributes = JSON.parse(res.data.attributesList);
+          productAttributesValues.value = parsedAttributes;
+        } catch (e) {
+          console.error('解析商品属性失败:', e);
+          productAttributesValues.value = {};
+        }
+      }
+
+      // 回显自定义属性列表
+      const rawResData = res.data as any;
+      if (Array.isArray(rawResData.diyAttributesList) && rawResData.diyAttributesList.length > 0) {
+        diyAttributesList.value = rawResData.diyAttributesList;
+      } else {
+        diyAttributesList.value = [];
+      }
+    } catch (error) {
+      console.error('加载商品详情失败:', error);
+      ElMessage.error('加载商品详情失败');
+    } finally {
+      loading.value = false;
+    }
+  }
+};
+
+// 递归查找分类节点
+const findCategoryById = (categories: categoryTreeVO[], id: string | number): categoryTreeVO | null => {
+  for (const category of categories) {
+    if (String(category.id) === String(id)) {
+      return category;
+    }
+    if (category.children && category.children.length > 0) {
+      const found = findCategoryById(category.children, id);
+      if (found) return found;
+    }
+  }
+  return null;
+};
+
+// 恢复分类选择状态
+const restoreCategorySelection = async () => {
+  // 先保存原始的分类ID值
+  const originalTopCategoryId = categoryForm.topCategoryId;
+  const originalMediumCategoryId = categoryForm.mediumCategoryId;
+  const originalBottomCategoryId = categoryForm.bottomCategoryId;
+
+  console.log('回显分类 - 原始ID:', {
+    top: originalTopCategoryId,
+    medium: originalMediumCategoryId,
+    bottom: originalBottomCategoryId
+  });
+
+  if (!originalTopCategoryId) return;
+
+  // 查找一级分类
+  const level1 = level1Categories.value.find((item) => String(item.id) === String(originalTopCategoryId));
+  console.log('查找一级分类:', level1);
+  if (!level1) return;
+
+  // 设置一级分类选中状态
+  categoryForm.topCategoryId = level1.id;
+  selectedLevel1Name.value = level1.label;
+  level2Categories.value = level1.children || [];
+
+  await nextTick();
+
+  // 查找二级分类
+  if (originalMediumCategoryId) {
+    // 先在当前一级分类的children中查找
+    let level2 = level2Categories.value.find((item) => String(item.id) === String(originalMediumCategoryId));
+
+    // 如果找不到,尝试在整个分类树中查找(容错处理)
+    if (!level2) {
+      console.log('二级分类在当前一级下未找到,尝试全局查找...');
+      level2 = findCategoryById(categoryOptions.value, originalMediumCategoryId);
+    }
+
+    console.log('查找二级分类:', level2);
+    if (level2) {
+      categoryForm.mediumCategoryId = level2.id;
+      selectedLevel2Name.value = level2.label;
+      level3Categories.value = level2.children || [];
+
+      await nextTick();
+
+      // 查找三级分类
+      if (originalBottomCategoryId) {
+        // 先在当前二级分类的children中查找
+        let level3 = level3Categories.value.find((item) => String(item.id) === String(originalBottomCategoryId));
+
+        // 如果找不到,尝试在整个分类树中查找(容错处理)
+        if (!level3) {
+          console.log('三级分类在当前二级下未找到,尝试全局查找...');
+          level3 = findCategoryById(categoryOptions.value, originalBottomCategoryId);
+        }
+
+        console.log('查找三级分类:', level3, '原始ID:', originalBottomCategoryId);
+        if (level3) {
+          categoryForm.bottomCategoryId = level3.id;
+          selectedLevel3Name.value = level3.label;
+          console.log('设置三级分类名称:', selectedLevel3Name.value);
+          await loadCategoryAttributes(level3.id);
+        }
+      }
+    }
+  }
+};
+
+onMounted(async () => {
+  // 编辑模式下先直接跳到第二步,再加载数据,避免闪烁步骤一
+  if (route.params.id) {
+    currentStep.value = 1;
+  }
+  await getCategoryTree();
+  await getUnitOptions();
+  await getAfterSalesOptions();
+  await getServiceGuaranteeOptions();
+  await getTaxRateOptions();
+  // 先加载商品详情(如果是编辑模式)
+  await loadProductDetail();
+  // 再加载下拉选项,这样如果详情中没有值,会自动设置第一个
+  await getSupplierOptions();
+  await getStaffOptions();
+  loadBrandOptions();
+});
+</script>
+
+<style scoped lang="scss">
+.product-wizard-page {
+  .category-selection {
+    margin-top: 12px;
+  }
+
+  .category-box {
+    border: 1px solid #e4e7ed;
+    border-radius: 4px;
+    overflow: hidden;
+
+    .category-header {
+      background-color: #f5f7fa;
+      padding: 10px 12px;
+      font-weight: 600;
+      border-bottom: 1px solid #e4e7ed;
+      text-align: center;
+      font-size: 14px;
+    }
+
+    .category-search {
+      padding: 10px;
+      border-bottom: 1px solid #e4e7ed;
+      background-color: #fff;
+    }
+
+    .category-list {
+      height: 280px;
+      overflow-y: auto;
+
+      .category-item {
+        padding: 10px 12px;
+        cursor: pointer;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        border-bottom: 1px solid #f0f0f0;
+        transition: all 0.3s;
+
+        &:hover {
+          background-color: #f5f7fa;
+        }
+
+        &.active {
+          background-color: #ecf5ff;
+          color: #409eff;
+          font-weight: 600;
+        }
+
+        &:last-child {
+          border-bottom: none;
+        }
+
+        &.disabled {
+          cursor: not-allowed;
+          opacity: 0.45;
+          pointer-events: none;
+        }
+      }
+    }
+  }
+
+  .confirm-info {
+    margin-top: 12px;
+    text-align: left;
+  }
+
+  .product-info-form {
+    .category-display {
+      display: flex;
+      align-items: center;
+
+      .category-text {
+        color: #606266;
+      }
+    }
+
+    .form-item-tip {
+      font-size: 12px;
+      color: #909399;
+      line-height: 1.5;
+      margin-top: 4px;
+    }
+
+    .currency-text {
+      color: #303133;
+      font-size: 14px;
+    }
+  }
+
+  .custom-options {
+    display: flex;
+    gap: 10px;
+    flex-wrap: wrap;
+  }
+
+  .custom-table {
+    width: 100%;
+    margin-top: 10px;
+  }
+
+  .completion-card {
+    min-height: 400px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+    .completion-content {
+      text-align: center;
+      padding: 40px 0;
+
+      .success-icon {
+        margin-bottom: 24px;
+      }
+
+      .completion-text {
+        font-size: 16px;
+        color: #606266;
+        margin-bottom: 32px;
+        line-height: 1.6;
+      }
+
+      .completion-action {
+        display: flex;
+        justify-content: center;
+      }
+    }
+  }
+}
+</style>

+ 10 - 3
src/views/product/base/index.vue

@@ -140,12 +140,19 @@
             <div class="text-left">
               <div style="white-space: normal; word-break: break-all; line-height: 1.4">{{ scope.row.itemName }}</div>
               <div class="text-gray-500" style="font-size: 12px">品牌: {{ scope.row.brandName || '-' }}</div>
-              <div class="text-gray-500" style="font-size: 12px">分类: {{ scope.row.categoryName || '-' }}</div>
+              <div class="text-gray-500" style="font-size: 12px">分类: {{ scope.row.topCategoryName+'-'+scope.row.mediumCategoryName+'-'+ scope.row.bottomCategoryName}}</div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="单位" align="center" prop="unitName" width="60" />
-        <el-table-column label="SKU价格" align="center" width="120">
+        <el-table-column label="单位" align="center" width="100">
+          <template #default="scope">
+            <div class="text-left">
+              <div class="text-gray-500" style="font-size: 12px">单位: {{ scope.row.unitName || '-' }}</div>
+              <div class="text-gray-500" style="font-size: 12px">起订量: {{ scope.row.minOrderQuantity || '-' }}</div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="价格信息" align="center" width="150">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px">
               <div>

Деякі файли не було показано, через те що забагато файлів було змінено