Pārlūkot izejas kodu

feat(product): 添加商品审核详情页面并完善数据绑定

- 新增商品审核详情查看页面(/product/baseAudit/view/:id)
- 修复促销标题字段绑定错误,从packagingSpec改为promotionTitle
- 将售后服务字段类型从string统一为number类型处理
- 添加定制说明相关字段的回显逻辑
- 更新商品审核列表页面添加预览和查看链接
- 在路由配置中注册新的审核详情查看页面
- 移除API类型定义中冗余的游标分页参数
- 优化售后服务数据类型支持字符串或数字类型
肖路 1 dienu atpakaļ
vecāks
revīzija
ca11146d64

+ 7 - 32
src/api/product/base/types.ts

@@ -385,6 +385,11 @@ export interface BaseForm extends BaseEntity {
    */
   sectionNo?: string;
 
+  /**
+   * 促销标题
+   */
+  promotionTitle?: string;
+
   /**
    * 包装规格
    */
@@ -437,7 +442,7 @@ export interface BaseForm extends BaseEntity {
   /**
    * 售后服务
    */
-  afterSalesService?: string;
+  afterSalesService?: string | number;
 
   /**
    * 服务保障 支持多选,分隔 (存储服务保障ID列表,如: "1,2,3")
@@ -590,7 +595,7 @@ export interface BaseForm extends BaseEntity {
   supplyValidityPeriod?: string;
 
   /**
-   * 是否包邮 0 不包邮,1包邮
+   * 是否包邮 0=不包邮,1=包邮
    */
   supplyPostStatus?: number;
 }
@@ -735,36 +740,6 @@ export interface BaseQuery extends PageQuery {
    * 商品ID列表(按指定ID集合查询)
    */
   ids?: Array<string | number>;
-
-  /**
-   * 游标分页 - 最后一条记录ID
-   */
-  lastSeenId?: string | number;
-
-  /**
-   * 游标分页 - 第一条记录ID
-   */
-  firstSeenId?: string | number;
-
-  /**
-   * 翻页方向:0=上一页,1=下一页
-   */
-  way?: number;
-
-  /**
-   * 查询类型
-   */
-  queryType?: string | number;
-
-  /**
-   * 业务类型
-   */
-  type?: number;
-
-  /**
-   * 审核状态
-   */
-  auditStatus?: number;
 }
 /**
  * 状态数量统计视图对象

+ 6 - 0
src/router/index.ts

@@ -163,6 +163,12 @@ export const constantRoutes: RouteRecordRaw[] = [
         name: 'BaseAuditEdit',
         meta: { title: '商品审核', activeMenu: '/product/baseAudit' }
       },
+      {
+        path: 'baseAudit/view/:id',
+        component: () => import('@/views/product/baseAudit/view.vue'),
+        name: 'BaseAuditView',
+        meta: { title: '查看商品', activeMenu: '/product/baseAudit' }
+      },
       {
         path: 'base/detail/:id',
         component: () => import('@/views/product/base/add.vue'),

+ 1 - 1
src/views/product/base/add.vue

@@ -308,7 +308,7 @@
 
             <!-- 促销标题 -->
             <el-form-item label="促销标题:">
-              <el-input v-model="productForm.packagingSpec" type="textarea" :rows="3" placeholder="请输入促销标题" maxlength="300" show-word-limit />
+              <el-input v-model="productForm.promotionTitle" type="textarea" :rows="3" placeholder="请输入促销标题" maxlength="300" show-word-limit />
             </el-form-item>
 
             <!-- 商品简介 -->

+ 39 - 2
src/views/product/baseAudit/add.vue

@@ -294,7 +294,7 @@
 
             <!-- 促销标题 -->
             <el-form-item label="促销标题:">
-              <el-input v-model="productForm.packagingSpec" type="textarea" :rows="3" placeholder="请输入促销标题" maxlength="300" show-word-limit />
+              <el-input v-model="productForm.promotionTitle" type="textarea" :rows="3" placeholder="请输入促销标题" maxlength="300" show-word-limit />
             </el-form-item>
 
             <!-- 商品简介 -->
@@ -1629,7 +1629,7 @@ const loadProductDetail = async () => {
 
       // 回显售后服务 - 确保类型与下拉选项的id一致(数字类型)
       if (res.data.productBaseVo.afterSalesService !== undefined && res.data.productBaseVo.afterSalesService !== null) {
-        productForm.afterSalesService = String(res.data.productBaseVo.afterSalesService);
+        productForm.afterSalesService = Number(res.data.productBaseVo.afterSalesService);
       }
 
       // 回显轮播图
@@ -1681,6 +1681,43 @@ const loadProductDetail = async () => {
       } else {
         diyAttributesList.value = [];
       }
+
+      // 回显定制说明相关字段
+      const baseVo = res.data.productBaseVo as any;
+      // 可定制开关
+      customForm.isCustomize = Number(baseVo.isCustomize) === 1;
+      // 定制方式(逗号分隔字符串 → 数组)
+      if (baseVo.customizedStyle) {
+        customForm.selectedMethods = String(baseVo.customizedStyle)
+          .split(',')
+          .map((s: string) => s.trim())
+          .filter((s: string) => s);
+      } else {
+        customForm.selectedMethods = [];
+      }
+      // 定制工艺(逗号分隔字符串 → 数组)
+      if (baseVo.customizedCraft) {
+        customForm.selectedCrafts = String(baseVo.customizedCraft)
+          .split(',')
+          .map((s: string) => s.trim())
+          .filter((s: string) => s);
+      } else {
+        customForm.selectedCrafts = [];
+      }
+      // 定制说明
+      customForm.customDescription = baseVo.customDescription || '';
+      // 定制详情表格(JSON 字符串 → 数组),必须在 selectedMethods/selectedCrafts 赋值后覆盖,避免 watch 重建覆盖填写值
+      await nextTick();
+      if (baseVo.customDetailsJson) {
+        try {
+          const parsedDetails = JSON.parse(baseVo.customDetailsJson);
+          if (Array.isArray(parsedDetails)) {
+            customForm.customDetails = parsedDetails;
+          }
+        } catch (e) {
+          console.error('解析定制详情失败:', e);
+        }
+      }
     } catch (error) {
       console.error('加载商品详情失败:', error);
       ElMessage.error('加载商品详情失败');

+ 8 - 1
src/views/product/baseAudit/index.vue

@@ -201,6 +201,8 @@
           <template #default="scope">
             <div class="flex flex-wrap gap-1 justify-center">
               <!-- 待提交状态:编辑 + 提交审核 -->
+                <el-link type="primary" :underline="false" @click="handleView(scope.row)">预览</el-link>
+                <el-link type="info" :underline="false" @click="handleViewDetail(scope.row)">查看</el-link>
                 <el-link v-if="scope.row.auditStatus === 0" type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
                 <el-link v-if="scope.row.auditStatus === 0" type="success" :underline="false" @click="handleCommitAudit(scope.row)">提交审核</el-link>
 <!--              &lt;!&ndash; 待审核状态:审核 &ndash;&gt;-->
@@ -611,10 +613,15 @@ const handleExport = async () => {
 
 /** 查看商品详情 */
 const handleView = (row: BaseVO) => {
-  const url = `https://item.xiaoluwebsite.xyz/item?id=${row.id}`;
+  const url = `https://item.xiaoluwebsite.xyz/itemPreview?id=${row.id}`;
   window.open(url, '_blank');
 };
 
+/** 查看审核详情页 */
+const handleViewDetail = (row: BaseAuditVO) => {
+  router.push(`/product/baseAudit/view/${row.id}`);
+};
+
 /** 上下架操作 */
 const handleShelf = async (row: BaseVO) => {
   const isOnShelf = row.productStatus === 1;

+ 1781 - 0
src/views/product/baseAudit/view.vue

@@ -0,0 +1,1781 @@
+<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">查看商品</span>
+        </div>
+      </div>
+    </el-card>
+
+    <div class="product-wizard-page">
+      <!-- 步骤内容 -->
+      <div class="step-content" v-loading="loading">
+        <!-- 步骤2: 填写商品信息 -->
+        <el-card 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" disabled>
+            <!-- 商品分类显示 -->
+            <el-form-item label="商品分类:">
+              <div class="category-display">
+                <span class="category-text">{{ getCategoryPath() }}</span>
+              </div>
+            </el-form-item>
+
+            <!-- 商品名称 -->
+            <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.brandNo},${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.unitNo},${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"
+                  />
+                </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.taxrateNo},${option.taxrateName}`" :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 弹窗(查看模式下不启用) -->
+
+            <!-- 销量人气 -->
+            <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.promotionTitle" type="textarea" :rows="3" placeholder="请输入促销标题" maxlength="300" show-word-limit />
+            </el-form-item>
+
+            <!-- 商品简介 -->
+            <el-form-item label="商品简介:">
+              <el-input v-model="productForm.productDescription" type="textarea" :rows="3" placeholder="请输入商品简介" maxlength="500" 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="售后服务:">
+              <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 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" disabled>
+            <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-row>
+            <el-row :gutter="20">
+              <el-col :span="8">
+                <el-form-item label="最低起订量:" prop="minOrderQuantity" required>
+                  <el-input v-model="productForm.minOrderQuantity" min="1" 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 shadow="never" class="step-card mt-3">
+          <template #header>
+            <span class="text-lg font-bold">供应价格</span>
+          </template>
+
+          <el-form label-width="120px" class="product-info-form" disabled>
+            <el-row :gutter="20">
+              <el-col :span="8">
+                <el-form-item label="供应价:">
+                  <el-input
+                    v-model="productForm.supplyPrice"
+                    type="number"
+                    placeholder="请输入供应价"
+                    :min="0"
+                    @blur="formatPrice('supplyPrice')"
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item label="供应有效时间:">
+                  <el-date-picker
+                    v-model="productForm.supplyValidityPeriod"
+                    type="date"
+                    placeholder="请选择供应有效时间"
+                    value-format="YYYY-MM-DD"
+                    class="w-full"
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item label="是否包邮:">
+                  <el-radio-group v-model="productForm.supplyPostStatus">
+                    <el-radio :value="0">不包邮</el-radio>
+                    <el-radio :value="1">包邮</el-radio>
+                  </el-radio-group>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+        <!-- 自定义属性 -->
+        <el-card shadow="never" class="step-card mt-3">
+          <template #header>
+            <div class="flex items-center justify-between">
+              <span class="text-lg font-bold">自定义属性</span>
+            </div>
+          </template>
+
+          <el-form label-width="0px" class="product-info-form" disabled>
+            <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="12">
+                <el-input v-model="item.attributeKey" placeholder="属性名称" />
+              </el-col>
+              <el-col :span="12">
+                <el-input v-model="item.attributeValue" placeholder="属性值" />
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+
+        <!-- 商品属性 -->
+        <el-card 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" disabled>
+            <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].isOptional === '0'"
+                        v-model="productAttributesValues[attributesList[rowIndex * 2 + colIndex - 1].productAttributesName]"
+                        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].isOptional === '2'"
+                        v-model="productAttributesValues[attributesList[rowIndex * 2 + colIndex - 1].productAttributesName]"
+                        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].productAttributesName]"
+                        placeholder="请输入"
+                        clearable
+                      />
+                    </el-form-item>
+                  </template>
+                </el-col>
+              </el-row>
+            </template>
+          </el-form>
+        </el-card>
+
+        <!-- 商品详情 -->
+        <el-card 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" disabled>
+            <!-- 商品主图 -->
+            <el-form-item label="商品主图:" required>
+              <div class="view-disabled-wrapper">
+                <upload-image v-model="productForm.productImage" :limit="1" width="178px" height="178px" imageText="选择图片" />
+              </div>
+            </el-form-item>
+
+            <!-- 商品轮播图 -->
+            <el-form-item label="商品轮播图:" required>
+              <div class="view-disabled-wrapper">
+                <upload-image v-model="carouselImages" :limit="20" width="120px" height="120px" imageText="添加图片" />
+              </div>
+            </el-form-item>
+
+            <!-- 商品详情 -->
+            <el-form-item label="商品详情:" required>
+              <el-tabs v-model="activeDetailTab" type="border-card">
+                <el-tab-pane label="电脑端详情" name="pc">
+                  <div class="view-disabled-wrapper">
+                    <Editor v-model="productForm.pcDetail" :height="400" :readOnly="true" />
+                  </div>
+                </el-tab-pane>
+                <el-tab-pane label="移动端详情" name="mobile">
+                  <div class="view-disabled-wrapper">
+                    <Editor v-model="productForm.mobileDetail" :height="400" :readOnly="true" />
+                  </div>
+                </el-tab-pane>
+              </el-tabs>
+            </el-form-item>
+          </el-form>
+        </el-card>
+
+        <!-- 定制说明 -->
+        <el-card 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" disabled>
+            <!-- 可定制开关 -->
+            <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'"
+                    disabled
+                  >
+                    {{ 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'"
+                    disabled
+                  >
+                    {{ 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>
+              </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>
+      </div>
+    </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(1);
+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.taxationNo},${taxRes.data.name}`;
+    } else {
+      taxCodeNo.value = row.taxationNo ? `${row.taxationNo},${row.name}` : (row.name || '');
+    }
+  } catch (e) {
+    console.error('获取税率编码详情失败:', e);
+    taxCodeNo.value = row.taxationNo ? `${row.taxationNo},${row.name}` : (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',
+  productDescription: undefined,
+  mainLibraryIntro: undefined,
+  afterSalesService: undefined,
+  serviceGuarantee: undefined, // 服务保障ID列表,逗号分隔
+  freeInstallation: '0',
+  marketPrice: undefined,
+  memberPrice: undefined,
+  minSellingPrice: undefined,
+  purchasingPrice: undefined,
+  maxPurchasePrice: undefined,
+  supplyPrice: undefined,
+  supplyValidityPeriod: undefined,
+  supplyPostStatus: 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;
+
+    // 校验商品主图、轮播图、详情必填
+    if (!productForm.productImage) {
+      ElMessage.warning('请上传商品主图');
+      submitLoading.value = false;
+      return;
+    }
+    if (!carouselImages.value || carouselImages.value.length === 0) {
+      ElMessage.warning('请上传商品轮播图');
+      submitLoading.value = false;
+      return;
+    }
+    if (!productForm.pcDetail) {
+      ElMessage.warning('请填写电脑端商品详情');
+      submitLoading.value = false;
+      return;
+    }
+
+    // 校验价格关系:市场价 > 官网价 > 最低售价
+    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: route.params.id as string,
+      productData: JSON.stringify(submitProductData),
+      type: 0,
+      auditStatus: 0
+    };
+
+    if (auditData.id) {
+      await updateBaseAudit(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 getBaseAudit(id as string);
+      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);
+      }
+
+      // 回显采购人员 - 确保转换为字符串类型以匹配下拉框的value
+      if (res.data.productBaseVo.purchasingPersonnel !== undefined && res.data.productBaseVo.purchasingPersonnel !== null) {
+        productForm.purchasingPersonnel = String(res.data.productBaseVo.purchasingPersonnel);
+      }
+
+      // 回显税率编码显示值
+      const rawData = res.data.productBaseVo as any;
+      // 通过 taxationId 调接口获取中文名称回显
+      if (rawData.taxationId) {
+        try {
+          const taxRes = await getTaxCode(rawData.taxationId);
+          if (taxRes.data) {
+            taxCodeNo.value = `${taxRes.data.taxationNo},${taxRes.data.name}`;
+          }
+        } catch (e) {
+          console.error('获取税率编码失败:', e);
+        }
+      }
+
+      // 回显税率 - 在税率选项中查找匹配的值(处理浮点数精度问题)
+      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;
+        }
+      }
+
+      // 回显单位 - 确保类型与下拉选项的id一致(数字类型)
+      if (res.data.productBaseVo.unitId !== undefined && res.data.productBaseVo.unitId !== null) {
+        productForm.unitId = Number(res.data.productBaseVo.unitId);
+      }
+
+      // 回显品牌 - 先加载对应的品牌信息到选项列表中
+      if (res.data.productBaseVo.brandId) {
+        productForm.brandId = Number(res.data.productBaseVo.brandId);
+        try {
+          const brandRes = await getBrand(res.data.productBaseVo.brandId);
+          if (brandRes.data) {
+            // 检查品牌是否已在选项列表中
+            const existBrand = brandOptions.value.find((item) => Number(item.id) === Number(res.data.productBaseVo.brandId));
+            if (!existBrand) {
+              brandOptions.value.unshift(brandRes.data);
+            }
+          }
+        } catch (e) {
+          console.error('加载品牌信息失败:', e);
+        }
+      }
+
+      // 回显售后服务 - 确保类型与下拉选项的id一致(数字类型)
+      if (res.data.productBaseVo.afterSalesService !== undefined && res.data.productBaseVo.afterSalesService !== null) {
+        productForm.afterSalesService = Number(res.data.productBaseVo.afterSalesService);
+      }
+
+      // 回显轮播图
+      if (res.data.productBaseVo.imageUrl) {
+        carouselImages.value = res.data.productBaseVo.imageUrl.split(',').filter((url: string) => url.trim());
+      } else {
+        carouselImages.value = [];
+      }
+
+      // 回显分类选择
+      categoryForm.topCategoryId = res.data.productBaseVo.topCategoryId;
+      categoryForm.mediumCategoryId = res.data.productBaseVo.mediumCategoryId;
+      categoryForm.bottomCategoryId = res.data.productBaseVo.bottomCategoryId;
+
+      // 回显服务保障复选框 - 将逗号分隔的ID字符串转换为数组
+      if (res.data.productBaseVo.serviceGuarantee) {
+        serviceGuarantees.value = res.data.productBaseVo.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.productBaseVo.freeInstallation === '1') services.push('freeInstallation');
+      installationServices.value = services;
+
+      // 回显分类名称 - 使用nextTick确保DOM更新后再查找子分类
+      await restoreCategorySelection();
+
+      // 回显商品属性值(必须在restoreCategorySelection之后,避免loadCategoryAttributes清空属性值)
+      if (res.data.productBaseVo.attributesList) {
+        try {
+          const parsedAttributes = JSON.parse(res.data.productBaseVo.attributesList);
+          productAttributesValues.value = parsedAttributes;
+        } catch (e) {
+          console.error('解析商品属性失败:', e);
+          productAttributesValues.value = {};
+        }
+      }
+
+      // 回显自定义属性列表
+      const rawResData = res.data as any;
+      if (Array.isArray(rawResData.productBaseVo.diyAttributesList) && rawResData.productBaseVo.diyAttributesList.length > 0) {
+        diyAttributesList.value = rawResData.productBaseVo.diyAttributesList;
+      } else {
+        diyAttributesList.value = [];
+      }
+
+      // 回显定制说明相关字段
+      const baseVo = res.data.productBaseVo as any;
+      // 可定制开关
+      customForm.isCustomize = Number(baseVo.isCustomize) === 1;
+      // 定制方式(逗号分隔字符串 → 数组)
+      if (baseVo.customizedStyle) {
+        customForm.selectedMethods = String(baseVo.customizedStyle)
+          .split(',')
+          .map((s: string) => s.trim())
+          .filter((s: string) => s);
+      } else {
+        customForm.selectedMethods = [];
+      }
+      // 定制工艺(逗号分隔字符串 → 数组)
+      if (baseVo.customizedCraft) {
+        customForm.selectedCrafts = String(baseVo.customizedCraft)
+          .split(',')
+          .map((s: string) => s.trim())
+          .filter((s: string) => s);
+      } else {
+        customForm.selectedCrafts = [];
+      }
+      // 定制说明
+      customForm.customDescription = baseVo.customDescription || '';
+      // 定制详情表格(JSON 字符串 → 数组),必须在 selectedMethods/selectedCrafts 赋值后覆盖,避免 watch 重建覆盖填写值
+      await nextTick();
+      if (baseVo.customDetailsJson) {
+        try {
+          const parsedDetails = JSON.parse(baseVo.customDetailsJson);
+          if (Array.isArray(parsedDetails)) {
+            customForm.customDetails = parsedDetails;
+          }
+        } catch (e) {
+          console.error('解析定制详情失败:', e);
+        }
+      }
+    } 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;
+  }
+
+  .view-disabled-wrapper {
+    pointer-events: none;
+    opacity: 0.9;
+    width: 100%;
+  }
+}
+</style>