Преглед изворни кода

refactor(product): 重构商品基础信息页面结构和字段映射

- 整合代码格式化调整,统一标签换行和属性排列
- 更新字段映射关系,将specification映射为specificationsCode,upcBarcode映射为barCoding
- 修改价格相关字段映射,midRangePrice改为marketPrice,standardPrice改为memberPrice
- 添加自定义属性功能模块,支持动态添加删除属性键值对
- 优化表单提交逻辑,区分新增和编辑模式的数据提交方式
- 调整分类选择组件的样式和交互细节
- 修复定制功能相关的字段映射和状态管理问题
- 优化分类回显逻辑,增强查找和容错处理机制
肖路 пре 1 месец
родитељ
комит
7d76ec98df
36 измењених фајлова са 9520 додато и 1062 уклоњено
  1. 21 45
      src/api/product/base/types.ts
  2. 1 1
      src/api/product/category/index.ts
  3. 26 1
      src/api/product/poolAudit/index.ts
  4. 290 0
      src/api/product/poolAudit/types.ts
  5. 29 0
      src/api/product/poolLinkAudit/types.ts
  6. 10 4
      src/router/index.ts
  7. 2 2
      src/views/external/item/index.vue
  8. 74 21
      src/views/external/item/productManage.vue
  9. 1 1
      src/views/external/item/review.vue
  10. 235 266
      src/views/product/base/add.vue
  11. 66 53
      src/views/product/base/index.vue
  12. 142 41
      src/views/product/base/review.vue
  13. 543 186
      src/views/product/base/selected.vue
  14. 446 220
      src/views/product/base/self.vue
  15. 19 13
      src/views/product/base/shelfReview.vue
  16. 1971 0
      src/views/product/baseAudit/add.vue
  17. 855 0
      src/views/product/baseAudit/index.vue
  18. 2 2
      src/views/product/category/index.vue
  19. 12 12
      src/views/product/pool/index.vue
  20. 2 2
      src/views/product/pool/review1.vue
  21. 2 2
      src/views/product/pool/reviewDetail.vue
  22. 1 1
      src/views/product/pool/selectedAudit.vue
  23. 1 1
      src/views/product/pool/selfAudit.vue
  24. 3 2
      src/views/product/poolAudit/index.vue
  25. 860 0
      src/views/product/poolAudit/itemAudit.vue
  26. 845 0
      src/views/product/poolAudit/marketingAudit.vue
  27. 859 0
      src/views/product/poolAudit/protocolAudit.vue
  28. 845 0
      src/views/product/poolAudit/selectedAudit.vue
  29. 845 0
      src/views/product/poolAudit/selfAudit.vue
  30. 1 1
      src/views/product/poolAuditReview/index.vue
  31. 14 24
      src/views/product/poolLink/index.vue
  32. 2 2
      src/views/product/poolLink/index1.vue
  33. 406 92
      src/views/product/poolLinkAudit/index.vue
  34. 20 19
      src/views/product/protocolInfo/index.vue
  35. 66 45
      src/views/product/protocolInfo/productManage.vue
  36. 3 3
      src/views/product/protocolInfo/review.vue

+ 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;
 }
-
-
-

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

@@ -68,7 +68,7 @@ export const delCategory = (id: string | number | Array<string | number>) => {
   */
 export const listCategoryExcludeChild = (id: string | number): AxiosPromise<CategoryVO[]> => {
   return request({
-    url: '/product/category/list/exclude/' + id,
+    url: '/product/category/tree/exclude/' + id,
     method: 'get'
   });
 };

+ 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;
 }
 
 

+ 10 - 4
src/router/index.ts

@@ -126,10 +126,16 @@ export const constantRoutes: RouteRecordRaw[] = [
         meta: { title: '商品池管理', activeMenu: '/product/pool', noCache: true }
       },
       {
-        path: 'base/review',
-        component: () => import('@/views/product/base/review.vue'),
-        name: 'BaseReview',
-        meta: { title: '商品审核', activeMenu: '/product/base' }
+        path: 'baseAudit/add',
+        component: () => import('@/views/product/baseAudit/add.vue'),
+        name: 'BaseAuditAdd',
+        meta: { title: '商品审核', activeMenu: '/product/baseAudit' }
+      },
+      {
+        path: 'baseAudit/edit/:id',
+        component: () => import('@/views/product/baseAudit/add.vue'),
+        name: 'BaseAuditEdit',
+        meta: { title: '商品审核', activeMenu: '/product/baseAudit' }
       },
       {
         path: 'base/detail/:id',

+ 2 - 2
src/views/external/item/index.vue

@@ -37,13 +37,13 @@
       </template>
 
       <el-table v-loading="loading" border :data="itemList" @selection-change="handleSelectionChange">
-        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column type="selection" width="100" align="center" />
+        <el-table-column label="项目编号" align="center" prop="itemNo" />
         <el-table-column label="负责人" align="center" prop="purchaseId">
           <template #default="scope">
             {{ getStaffLabel(scope.row.purchaseId) }}
           </template>
         </el-table-column>
-        <el-table-column label="项目logo" align="center" prop="logo" />
         <el-table-column label="项目名" align="center" prop="itemName" />
         <el-table-column label="项目标识" align="center" prop="itemKey" />
         <el-table-column label="项目url" align="center" prop="url" />

+ 74 - 21
src/views/external/item/productManage.vue

@@ -52,28 +52,63 @@
       </template>
 
       <el-table v-loading="loading" border :data="productsList">
-        <el-table-column label="产品编号" align="center" prop="productNo" width="120" />
-        <el-table-column label="商品图片" align="center" width="100">
+        <el-table-column label="商品编号" align="center" prop="productNo" width="120" fixed="left">
           <template #default="scope">
-            <image-preview :src="scope.row.productImage" :width="60" :height="60"/>
+            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
           </template>
         </el-table-column>
-        <el-table-column label="商品名称" align="center" min-width="180">
+        <el-table-column label="商品图片" align="center" prop="productImage" width="100">
           <template #default="scope">
-            <div>
-              <div class="text-primary">{{ scope.row.itemName }}</div>
-              <div class="text-gray-400 text-sm">{{ scope.row.brandName }}</div>
+            <image-preview :src="scope.row.productImage" :width="60" :height="60" />
+          </template>
+        </el-table-column>
+        <el-table-column label="商品信息" align="center" min-width="250">
+          <template #default="scope">
+            <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.topCategoryName+'-'+scope.row.mediumCategoryName+'-'+ scope.row.bottomCategoryName}}</div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="产品类别" align="center" prop="categoryName" width="100" />
-        <el-table-column label="单位" align="center" prop="unitName" width="80" />
-        <el-table-column label="Sku价格" align="center" width="140">
+        <el-table-column label="单位" align="center" width="100">
           <template #default="scope">
             <div class="text-left">
-              <div>市场价: ¥{{ scope.row.marketPrice || 0 }}</div>
-              <div class="text-red-500">官网价: ¥{{ scope.row.memberPrice || 0 }}</div>
-              <div>标准成本: ¥{{ scope.row.purchasingPrice || 0 }}</div>
+              <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="120">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px">
+              <div>
+                <span class="text-gray-500">市场价:</span>
+                <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">官网价:</span>
+                <span class="text-red-500">¥{{ scope.row.memberPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">最低价:</span>
+                <span class="text-red-500">¥{{ scope.row.minSellingPrice || '0.00' }}</span>
+              </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>
+                <span class="text-gray-500">采购价:</span>
+                <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">暂估毛利率:</span>
+                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
+              </div>
             </div>
           </template>
         </el-table-column>
@@ -89,17 +124,35 @@
             />
           </template>
         </el-table-column>
-        <el-table-column label="推送状态" align="center" width="100">
+<!--        <el-table-column label="计价规则" align="center" width="90">-->
+<!--          <template #default="scope">-->
+<!--            {{-->
+<!--              scope.row.pricingRule === '0'-->
+<!--                ? '一品一率'-->
+<!--                : scope.row.pricingRule === '1'-->
+<!--                  ? '折扣率'-->
+<!--                  : '-'-->
+<!--            }}-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+<!--        <el-table-column  label="第三方分类" align="center" width="160">-->
+<!--          <template #default="scope">-->
+<!--            {{ tempProjectProductInfo[scope.row.id]?.categoryName || '-' }}-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+        <el-table-column label="上下架状态" align="center" prop="productStatus" width="100">
           <template #default="scope">
-            <el-tag v-if="scope.row.pushStatus === 1" type="success">已推送</el-tag>
-            <el-tag v-else type="info">未推送</el-tag>
+            <el-tag v-if="scope.row.productStatus === 1" type="success">已上架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 0" type="warning">下架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 2" type="info">上架中</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
           </template>
         </el-table-column>
-        <el-table-column label="状态" align="center" width="80">
+
+        <el-table-column label="推送状态" align="center" width="100">
           <template #default="scope">
-            <span :class="scope.row.productStatus === '1' ? 'text-green-500' : 'text-red-500'">
-              {{ scope.row.productStatus === '1' ? '上架' : '下架' }}
-            </span>
+            <el-tag v-if="scope.row.pushStatus === 1" type="success">已推送</el-tag>
+            <el-tag v-else type="info">未推送</el-tag>
           </template>
         </el-table-column>
         <!-- <el-table-column label="审核状态" align="center" width="100">
@@ -185,7 +238,7 @@
               </div>
             </template>
           </el-table-column>
-          <el-table-column label="SKU价格" align="center" width="150">
+          <el-table-column label="价格信息" align="center" width="150">
             <template #default="scope">
               <div class="text-left" style="font-size: 12px;">
                 <div>

+ 1 - 1
src/views/external/item/review.vue

@@ -76,7 +76,7 @@
         </el-table-column>
         <el-table-column label="产品类别" align="center" prop="categoryName" width="100" />
         <el-table-column label="单位" align="center" prop="unitName" width="80" />
-        <el-table-column label="Sku价格" align="center" width="140">
+        <el-table-column label="价格信息" align="center" width="140">
           <template #default="scope">
             <div class="text-left">
               <div>市场价: ¥{{ scope.row.marketPrice || 0 }}</div>

Разлика између датотеке није приказан због своје велике величине
+ 235 - 266
src/views/product/base/add.vue


+ 66 - 53
src/views/product/base/index.vue

@@ -39,19 +39,6 @@
               </el-col>
             </el-row>
             <el-row :gutter="20">
-              <el-col :span="6">
-                <el-form-item label="商品分类" prop="bottomCategoryId">
-                  <el-tree-select
-                    v-model="queryParams.bottomCategoryId"
-                    :data="categoryOptions"
-                    :props="{ value: 'id', label: 'label', children: 'children' } as any"
-                    value-key="id"
-                    placeholder="请选择商品分类"
-                    clearable
-                    check-strictly
-                  />
-                </el-form-item>
-              </el-col>
               <el-col :span="6">
                 <el-form-item label="是否自营" prop="isSelf">
                   <el-select v-model="queryParams.isSelf" placeholder="请选择" clearable>
@@ -76,13 +63,31 @@
                     <el-option label="已上架" :value="1" />
                     <el-option label="下架" :value="0" />
                     <el-option label="上架中" :value="2" />
-                    <el-option label="驳回上架" :value="3" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品类型" prop="productStatus">
+                  <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
+                    <el-option label="已上架" :value="1" />
+                    <el-option label="下架" :value="0" />
+                    <el-option label="上架中" :value="2" />
                   </el-select>
                 </el-form-item>
               </el-col>
             </el-row>
-            <el-row>
-              <el-col :span="24" class="text-left">
+            <el-row :gutter="20">
+              <el-col :span="18">
+                <el-form-item label="商品分类">
+                  <category-cascade-select
+                    ref="categoryCascadeRef"
+                    v-model:top-category-id="queryParams.topCategoryId"
+                    v-model:medium-category-id="queryParams.mediumCategoryId"
+                    v-model:bottom-category-id="queryParams.bottomCategoryId"
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6" class="text-left" style="display: flex; align-items: center; padding-bottom: 18px">
                 <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                 <el-button icon="Refresh" @click="resetQuery">重置</el-button>
               </el-col>
@@ -140,12 +145,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="120">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px">
               <div>
@@ -163,47 +175,48 @@
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="库存情况" align="center" width="140">
+
+        <el-table-column label="采购信息" align="center" width="150">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px">
               <div>
-                <span class="text-gray-500">总库存:</span>
-                <span>{{ scope.row.totalInventory ?? '-' }}</span>
-              </div>
-              <div>
-                <span class="text-gray-500">可用库存:</span>
-                <span>{{ scope.row.nowInventory ?? '-' }}</span>
+                <span class="text-gray-500">采购价:</span>
+                <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
               </div>
               <div>
-                <span class="text-gray-500">虚拟库存:</span>
-                <span>{{ scope.row.virtualInventory ?? '-' }}</span>
+                <span class="text-gray-500">暂估毛利率:</span>
+                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
               </div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="成本情况" align="center" width="150">
+        <el-table-column label="库存情况" align="center" width="140">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px">
               <div>
-                <span class="text-gray-500">采购价:</span>
-                <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
+                <span class="text-gray-500">总库存:</span>
+                <span>{{ scope.row.totalInventory ?? '-' }}</span>
               </div>
               <div>
-                <span class="text-gray-500">毛利率:</span>
-                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
+                <span class="text-gray-500">可用库存:</span>
+                <span>{{ scope.row.nowInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">虚拟库存:</span>
+                <span>{{ scope.row.virtualInventory ?? '-' }}</span>
               </div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="数据来源" align="center" prop="dataSource" width="80">
-          <template #default="scope">
-            <span>{{ scope.row.dataSource || '-' }}</span>
-          </template>
-        </el-table-column>
+<!--        <el-table-column label="数据来源" align="center" prop="dataSource" width="80">-->
+<!--          <template #default="scope">-->
+<!--            <span>{{ scope.row.dataSource || '-' }}</span>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
         <el-table-column label="是否自营" align="center" width="80">
           <template #default="scope">
-            <el-tag v-if="scope.row.isSelf === 1" type="success">是</el-tag>
-            <el-tag v-else-if="scope.row.isSelf === 0" type="info">否</el-tag>
+            <span v-if="scope.row.isSelf === 1">是</span>
+            <span v-else-if="scope.row.isSelf === 0">否</span>
             <span v-else>-</span>
           </template>
         </el-table-column>
@@ -308,7 +321,6 @@ import {
   delBase,
   brandList,
   updateBase,
-  categoryTree,
   shelfReview,
   changeProductType,
   getProductStatusCount
@@ -320,7 +332,6 @@ import { PriceInventoryForm } from '@/api/product/priceInventory/types';
 import { BaseVO, BaseQuery, BaseForm, StatusCountVo } from '@/api/product/base/types';
 import { BrandVO } from '@/api/product/brand/types';
 import { listBrand } from '@/api/product/brand';
-import { categoryTreeVO } from '@/api/product/category/types';
 import { useRoute, useRouter } from 'vue-router';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -335,14 +346,16 @@ const ids = ref<Array<string | number>>([]);
 const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
-const categoryOptions = ref<categoryTreeVO[]>([]);
 const brandOptions = ref<BrandVO[]>([]);
 const brandLoading = ref(false);
-let brandSearchTimer: ReturnType<typeof setTimeout> | null = null;
+const brandSearchTimer = ref<ReturnType<typeof setTimeout> | null>(null);
 const hasMore = ref(true); // 是否还有更多数据
-// 页面历史记录,存储每页的第一个id和最后一个id,用于支持双向翻页
+// 页面历史记录,存储每页的第一个 id 和最后一个 id,用于支持双向翻页
 const pageHistory = ref([]);
 
+// 三级分类选择组件引用
+const categoryCascadeRef = ref();
+
 // 统计信息
 const statistics = ref<StatusCountVo>({
   total: 0,
@@ -540,6 +553,11 @@ const handleQuery = () => {
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
+  // 手动重置分类字段
+  queryParams.value.topCategoryId = undefined;
+  queryParams.value.mediumCategoryId = undefined;
+  queryParams.value.bottomCategoryId = undefined;
+  categoryCascadeRef.value?.reset();
   queryParams.value.lastSeenId = undefined;
   pageHistory.value = []; // 重置页面历史
   handleQuery();
@@ -770,11 +788,7 @@ const handleGoReview = () => {
   });
 };
 
-/** 查询分类树 */
-const getCategoryTree = async () => {
-  const res = await categoryTree();
-  categoryOptions.value = res.data || [];
-};
+
 
 /** 加载品牌选项(默认100条) */
 const loadBrandOptions = async (keyword?: string) => {
@@ -791,8 +805,8 @@ const loadBrandOptions = async (keyword?: string) => {
 
 /** 品牌远程搜索(防抖) */
 const handleBrandSearch = (query: string) => {
-  if (brandSearchTimer) clearTimeout(brandSearchTimer);
-  brandSearchTimer = setTimeout(() => {
+  if (brandSearchTimer.value) clearTimeout(brandSearchTimer.value);
+  brandSearchTimer.value = setTimeout(() => {
     loadBrandOptions(query || undefined);
   }, 300);
 };
@@ -811,7 +825,6 @@ const getStatistics = async () => {
 
 onMounted(() => {
   getList();
-  getCategoryTree();
   getStatistics();
   loadBrandOptions();
 });

+ 142 - 41
src/views/product/base/review.vue

@@ -1,10 +1,21 @@
 <template>
   <div class="app-container">
+    <!-- 状态 Tab 筛选栏 -->
+    <div class="status-tab-bar mb-[10px]">
+      <el-radio-group v-model="activeTab" @change="handleTabChange">
+        <el-radio-button value="all">全部 (0)</el-radio-button>
+        <el-radio-button value="0">待审核(0)</el-radio-button>
+        <el-radio-button value="1">审核通过(0)</el-radio-button>
+        <el-radio-button value="2">审核驳回(0)</el-radio-button>
+        <el-radio-button value="3">其它(0)</el-radio-button>
+      </el-radio-group>
+    </div>
+
     <!-- 搜索区域 -->
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
       <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form ref="queryFormRef" :model="queryParams" label-width="100px">
+          <el-form ref="queryFormRef" :model="queryParams" label-width="90px">
             <el-row :gutter="20">
               <el-col :span="6">
                 <el-form-item label="商品编号" prop="productNo">
@@ -17,52 +28,100 @@
                 </el-form-item>
               </el-col>
               <el-col :span="6">
-                <el-form-item label="商品类别" prop="bottomCategoryId">
+                <el-form-item label="商品品牌" prop="brandId">
+                  <el-select
+                    v-model="queryParams.brandId"
+                    placeholder="请输入品牌名称搜索"
+                    filterable
+                    remote
+                    clearable
+                    :remote-method="handleBrandSearch"
+                    :loading="brandLoading"
+                    style="width: 100%"
+                    @keyup.enter="handleQuery"
+                  >
+                    <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="6">
+                <el-form-item label="商品来源" prop="purchaseNature">
+                  <el-input v-model="queryParams.itemName" placeholder="请输入商品来源" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品类型" prop="bottomCategoryId">
                   <el-tree-select
                     v-model="queryParams.bottomCategoryId"
                     :data="categoryOptions"
                     :props="{ value: 'id', label: 'label', children: 'children' } as any"
                     value-key="id"
-                    placeholder="请选择商品类别"
+                    placeholder="请选择商品类"
                     clearable
                     check-strictly
                   />
                 </el-form-item>
               </el-col>
               <el-col :span="6">
-                <el-form-item label="商品品牌" prop="brandName">
-                  <el-select-v2
-                    v-model="queryParams.brandName"
-                    :options="brandOptionsFormatted"
-                    placeholder="请选择商品品牌"
-                    clearable
+                <el-form-item label="商品类别" prop="bottomCategoryId">
+                  <el-select
+                    v-model="queryParams.brandId"
+                    placeholder="一级类目"
                     filterable
+                    remote
+                    clearable
+                    :remote-method="handleBrandSearch"
                     :loading="brandLoading"
-                    @visible-change="handleBrandVisibleChange"
-                  />
+                    style="width: 100%"
+                    @keyup.enter="handleQuery"
+                  >
+                    <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="6">
-                <el-form-item label="审核状态" prop="productReviewStatus">
+                <el-form-item label="商品类别" prop="bottomCategoryId">
                   <el-select
-                    v-model="queryParams.productReviewStatus"
-                    placeholder="请选择审核状态"
+                    v-model="queryParams.brandId"
+                    placeholder="二级类目"
+                    filterable
+                    remote
                     clearable
+                    :remote-method="handleBrandSearch"
+                    :loading="brandLoading"
+                    style="width: 100%"
+                    @keyup.enter="handleQuery"
                   >
-                    <el-option label="待采购审核" :value="0" />
-                    <el-option label="审核通过" :value="1" />
-                    <el-option label="驳回" :value="2" />
-                    <el-option label="待营销审核" :value="3" />
+                    <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="6">
-                <el-form-item>
-                  <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-                  <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+                <el-form-item label="商品类别" prop="bottomCategoryId">
+                  <el-select
+                    v-model="queryParams.brandId"
+                    placeholder="三级类目"
+                    filterable
+                    remote
+                    clearable
+                    :remote-method="handleBrandSearch"
+                    :loading="brandLoading"
+                    style="width: 100%"
+                    @keyup.enter="handleQuery"
+                  >
+                    <el-option v-for="item in brandOptions" :key="item.id" :label="item.brandName" :value="item.id" />
+                  </el-select>
                 </el-form-item>
               </el-col>
             </el-row>
+            <el-row>
+              <el-col :span="24" class="text-left">
+                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+              </el-col>
+            </el-row>
           </el-form>
         </el-card>
       </div>
@@ -83,39 +142,40 @@
 
       <el-table v-loading="loading" border :data="baseList" :height="tableHeight" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="商品图片" align="center" prop="productImage" width="100" >
+        <el-table-column label="商品编号" align="center" prop="productNo" width="120" >
           <template #default="scope">
-            <image-preview :src="scope.row.productImage" :width="60" :height="60"/>
+            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
           </template>
         </el-table-column>
-        <el-table-column label="商品编号" align="center" prop="productNo" width="120" >
+        <el-table-column label="商品图片" align="center" prop="productImage" width="100" >
           <template #default="scope">
-            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
+            <image-preview :src="scope.row.productImage" :width="60" :height="60"/>
           </template>
         </el-table-column>
         <el-table-column label="商品信息" align="center" min-width="250" show-overflow-tooltip>
           <template #default="scope">
             <div class="text-left">
               <div>{{ 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.brandName || '-' }}</div>
+              <div class="text-gray-500" style="font-size: 12px">
+                分类: {{ scope.row.topCategoryName + '-' + scope.row.topCategoryName + '-' + scope.row.bottomCategoryName }}
+              </div>
             </div>
+
           </template>
         </el-table-column>
         <el-table-column label="基本情况" align="center" width="180">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px;">
-              <div>
-                <span class="text-gray-500">商品分类:</span>
-                <span>{{ scope.row.categoryName || '-' }}</span>
-              </div>
               <div>
                 <span class="text-gray-500">单位:</span>
                 <span>{{ scope.row.unitName || '-' }}</span>
               </div>
+              <div class="text-gray-500" style="font-size: 12px">起订量: {{ scope.row.minOrderQuantity || '-' }}</div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="SKU价格" align="center" width="180">
+        <el-table-column label="价格信息" align="center" width="180">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px">
               <div>
@@ -142,17 +202,22 @@
               </div>
               <div>
                 <span class="text-gray-500">暂估毛利率:</span>
-                <span>{{ scope.row.tempGrossMargin || '0.00' }}%</span>
+                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
               </div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="商品来源" align="center" width="100">
+        <el-table-column label="商品类型" align="center" width="100">
           <template #default="scope">
             <span>{{ scope.row.dataSource || '-' }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="商品状态" align="center" width="100">
+        <el-table-column label="供应商" align="center" width="100">
+          <template #default="scope">
+            <span>{{ scope.row.dataSource || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="审核状态" align="center" width="100">
           <template #default="scope">
             <el-tag v-if="scope.row.productReviewStatus === 0" type="info">待采购审核</el-tag>
             <el-tag v-else-if="scope.row.productReviewStatus === 1" type="success">审核通过</el-tag>
@@ -161,10 +226,10 @@
             <span v-else>-</span>
           </template>
         </el-table-column>
-        <el-table-column label="审核意见" align="center" width="180" show-overflow-tooltip>
-          <template #default="scope">
+        <el-table-column label="提交时间" align="center" width="180" show-overflow-tooltip>
+          <!-- <template #default="scope">
             <span>{{ scope.row.reviewComments || '-' }}</span>
-          </template>
+          </template> -->
         </el-table-column>
         <el-table-column label="操作" align="center" width="200" fixed="right" class-name="border-left">
           <template #default="scope">
@@ -173,25 +238,33 @@
               <template v-if="scope.row.productReviewStatus === 0">
                 <!-- 待采购审核 -->
                 <div class="flex gap-1 justify-center">
+                  <el-link type="primary" :underline="false" @click="handleEdit(scope.row)">查看</el-link>
                   <el-link type="primary" :underline="false" @click="handleEdit(scope.row)">编辑</el-link>
-                  <el-link type="success" :underline="false" @click="handlePurchaseReview(scope.row)">采购审核</el-link>
+<!--                  <el-link type="success" :underline="false" @click="handlePurchaseReview(scope.row)">采购审核</el-link>-->
+                  <el-link type="primary" :underline="false" @click="handlePurchaseReview(scope.row)">审核</el-link>
+                  <el-link type="primary" :underline="false" @click="handlePurchaseReview(scope.row)">驳回</el-link>
                 </div>
               </template>
               <template v-else-if="scope.row.productReviewStatus === 1">
+                <el-link type="primary" :underline="false" @click="handleEdit(scope.row)">查看</el-link>
                 <!-- 审核通过:不显示任何按钮 -->
               </template>
               <template v-else-if="scope.row.productReviewStatus === 2">
                 <!-- 驳回 -->
                 <div class="flex gap-1 justify-center">
+                  <el-link type="primary" :underline="false" @click="handleEdit(scope.row)">查看</el-link>
                   <el-link type="primary" :underline="false" @click="handleEdit(scope.row)">编辑</el-link>
-                  <el-link type="success" :underline="false" @click="handleReSubmit(scope.row)">重新提交</el-link>
+                  <el-link type="primary" :underline="false" @click="handleReSubmit(scope.row)">重新提交</el-link>
                 </div>
               </template>
               <template v-else-if="scope.row.productReviewStatus === 3">
                 <!-- 待营销审核 -->
                 <div class="flex gap-1 justify-center">
+                  <el-link type="primary" :underline="false" @click="handleEdit(scope.row)">查看</el-link>
                   <el-link type="primary" :underline="false" @click="handleEdit(scope.row)">编辑</el-link>
-                  <el-link type="warning" :underline="false" @click="handleMarketingReview(scope.row)">营销审核</el-link>
+<!--                  <el-link type="warning" :underline="false" @click="handleMarketingReview(scope.row)">营销审核</el-link>-->
+                  <el-link type="primary" :underline="false" @click="handleMarketingReview(scope.row)">审核</el-link>
+                  <el-link type="primary" :underline="false" @click="handleMarketingReview(scope.row)">驳回</el-link>
                 </div>
               </template>
             </div>
@@ -271,6 +344,18 @@ const categoryOptions = ref<categoryTreeVO[]>([]);
 const hasMore = ref(true); // 是否还有更多数据
 const pageHistory = ref([]);
 
+// Tab 状态筛选
+const activeTab = ref<string>('all');
+
+const handleTabChange = (val: string) => {
+  if (val === 'all') {
+    queryParams.value.productReviewStatus = undefined;
+  } else {
+    queryParams.value.productReviewStatus = Number(val);
+  }
+  handleQuery();
+};
+
 // 动态计算表格高度
 const tableHeight = computed(() => {
   // 基础高度 = 视口高度 - 顶部导航(84) - 容器padding(16) - 搜索区域 - 卡片header(60) - 分页器(60)
@@ -382,7 +467,9 @@ const getList = async () => {
 const initRouteParams = () => {
   // 从路由参数中获取筛选条件
   if (route.query.productReviewStatus) {
-    queryParams.value.productReviewStatus = Number(route.query.productReviewStatus);
+    const status = Number(route.query.productReviewStatus);
+    queryParams.value.productReviewStatus = status;
+    activeTab.value = String(status);
   }
   if (route.query.brandName) {
     queryParams.value.brandName = route.query.brandName as string;
@@ -404,6 +491,8 @@ const handleQuery = () => {
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   queryParams.value.lastSeenId = undefined;
+  queryParams.value.productReviewStatus = undefined;
+  activeTab.value = 'all';
   pageHistory.value = [0]; // 重置页面历史
   handleQuery();
 };
@@ -532,6 +621,18 @@ onMounted(() => {
   overflow: hidden;
 }
 
+.status-tab-bar {
+  background: #fff;
+  border-radius: 4px;
+  padding: 12px 16px;
+  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
+
+  :deep(.el-radio-button__inner) {
+    padding: 8px 20px;
+    font-size: 14px;
+  }
+}
+
 .table-card {
   flex: 1;
   display: flex;

+ 543 - 186
src/views/product/base/selected.vue

@@ -1,10 +1,9 @@
 <template>
-  <div class="app-container">
-    <!-- 搜索区域 -->
+  <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
       <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form ref="queryFormRef" :model="queryParams" label-width="100px">
+          <el-form ref="queryFormRef" :model="queryParams" label-width="90px">
             <el-row :gutter="20">
               <el-col :span="6">
                 <el-form-item label="商品编号" prop="productNo">
@@ -17,49 +16,62 @@
                 </el-form-item>
               </el-col>
               <el-col :span="6">
-                <el-form-item label="商品类别" prop="bottomCategoryId">
+                <el-form-item label="商品品牌" prop="brandId">
+                  <el-select
+                    v-model="queryParams.brandId"
+                    placeholder="请输入品牌名称搜索"
+                    filterable
+                    remote
+                    clearable
+                    :remote-method="handleBrandSearch"
+                    :loading="brandLoading"
+                    style="width: 100%"
+                    @keyup.enter="handleQuery"
+                  >
+                    <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="6">
+                <el-form-item label="上下架状态" prop="productStatus">
+                  <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
+                    <el-option label="已上架" :value="1" />
+                    <el-option label="下架" :value="0" />
+                    <el-option label="上架中" :value="2" />
+                    <el-option label="驳回上架" :value="3" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品类型" prop="bottomCategoryId">
                   <el-tree-select
                     v-model="queryParams.bottomCategoryId"
                     :data="categoryOptions"
                     :props="{ value: 'id', label: 'label', children: 'children' } as any"
                     value-key="id"
-                    placeholder="请选择商品类别"
+                    placeholder="请选择商品类"
                     clearable
                     check-strictly
                   />
                 </el-form-item>
               </el-col>
-              <el-col :span="6">
-                <el-form-item label="商品品牌" prop="brandName">
-                  <el-select-v2
-                    v-model="queryParams.brandName"
-                    :options="brandOptionsFormatted"
-                    placeholder="请选择商品品牌"
-                    clearable
-                    filterable
-                    :loading="brandLoading"
-                    @visible-change="handleBrandVisibleChange"
+              <el-col :span="18">
+                <el-form-item label="商品分类">
+                  <category-cascade-select
+                    ref="categoryCascadeRef"
+                    v-model:top-category-id="queryParams.topCategoryId"
+                    v-model:medium-category-id="queryParams.mediumCategoryId"
+                    v-model:bottom-category-id="queryParams.bottomCategoryId"
                   />
                 </el-form-item>
               </el-col>
-              <el-col :span="6">
-                <el-form-item label="审核状态" prop="auditStatus">
-                  <el-select
-                    v-model="queryParams.auditStatus"
-                    placeholder="请选择审核状态"
-                    clearable
-                  >
-                    <el-option label="待审核" :value="1" />
-                    <el-option label="审核通过" :value="2" />
-                    <el-option label="审核驳回" :value="3" />
-                  </el-select>
-                </el-form-item>
-              </el-col>
-              <el-col :span="6">
-                <el-form-item>
-                  <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-                  <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-                </el-form-item>
+            </el-row>
+            <el-row>
+              <el-col :span="24" class="text-left">
+                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
               </el-col>
             </el-row>
           </el-form>
@@ -67,52 +79,67 @@
       </div>
     </transition>
 
-    <!-- 审核商品信息列表 -->
-    <el-card shadow="never" class="table-card">
-      <template #header>
-        <div class="flex items-center justify-between">
-          <span class="font-semibold">审核商品信息列表</span>
-          <div class="flex gap-2">
-            <el-button circle icon="Refresh" @click="getList"></el-button>
-          </div>
+    <!-- 统计信息区域 -->
+    <el-card shadow="never" class="mb-[10px]">
+      <div class="flex items-center text-sm text-gray-600">
+        <span>商品总数: </span>
+        <span class="text-blue-600 mx-1"
+        >总=<span class="text-red-600">{{ statistics.total || 0 }}</span
+        >条</span
+        >
+        <span class="mx-2">【上架/总数({{ statistics.onSale || 0 }}/{{ statistics.total || 0 }})】</span>
+        <span class="mx-2"
+        >审核状态: 待审核<span class="text-red-600">{{ statistics.waitAudit || 0 }}</span
+        >条,通过<span class="text-green-600">{{ statistics.auditPass || 0 }}</span
+        >条,驳回<span class="text-orange-600">{{ statistics.auditReject || 0 }}</span
+        >条</span
+        >
+        <span class="mx-2"
+        >上下架状态: 已上架<span class="text-green-600">{{ statistics.onSale || 0 }}</span
+        >条,下架<span class="text-gray-600">{{ statistics.offSale || 0 }}</span
+        >条</span
+        >
+        <div class="ml-auto flex gap-2">
+          <el-button type="primary" icon="Plus" @click="handleAdd">商品新增</el-button>
+          <!-- <el-button type="warning" icon="Check" @click="handleGoReview">商品审核</el-button> -->
+          <!--          <el-button plain>批量操作</el-button>-->
+          <el-button plain icon="Download" @click="handleExport">导出</el-button>
+          <el-button circle icon="Refresh" @click="getList"></el-button>
         </div>
-      </template>
+      </div>
+    </el-card>
 
-      <el-table v-loading="loading" border :data="baseList" :height="tableHeight" @selection-change="handleSelectionChange">
+    <el-card shadow="never">
+      <el-table v-loading="loading" border :data="baseList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="商品图片" align="center" prop="productImage" width="100" >
+        <el-table-column label="商品编号" align="center" prop="productNo" width="120" fixed="left">
           <template #default="scope">
-            <image-preview :src="scope.row.productImage" :width="60" :height="60"/>
+            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
           </template>
         </el-table-column>
-        <el-table-column label="商品编号" align="center" prop="productNo" width="120" >
+        <el-table-column label="商品图片" align="center" prop="productImage" width="100">
           <template #default="scope">
-            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
+            <image-preview :src="scope.row.productImage" :width="60" :height="60" />
           </template>
         </el-table-column>
-        <el-table-column label="商品信息" align="center" min-width="250" show-overflow-tooltip>
+        <el-table-column label="商品信息" align="center" min-width="250">
           <template #default="scope">
             <div class="text-left">
-              <div>{{ scope.row.itemName }}</div>
-              <div class="text-gray-500" style="font-size: 12px;">品牌: {{ scope.row.brandName || '-' }}</div>
+              <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.topCategoryName+'-'+scope.row.mediumCategoryName+'-'+ scope.row.bottomCategoryName}}</div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="基本情况" align="center" width="180">
+        <el-table-column label="单位" align="center" width="100">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px;">
-              <div>
-                <span class="text-gray-500">商品分类:</span>
-                <span>{{ scope.row.categoryName || '-' }}</span>
-              </div>
-              <div>
-                <span class="text-gray-500">单位:</span>
-                <span>{{ scope.row.unitName || '-' }}</span>
-              </div>
+            <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="SKU价格" align="center" width="180">
+        <el-table-column label="价格信息" align="center" width="120">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px">
               <div>
@@ -130,44 +157,98 @@
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="成本预算" align="center" width="150">
+
+        <el-table-column label="采购信息" align="center" width="150">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px;">
+            <div class="text-left" style="font-size: 12px">
               <div>
                 <span class="text-gray-500">采购价:</span>
                 <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
               </div>
               <div>
                 <span class="text-gray-500">暂估毛利率:</span>
-                <span>{{ scope.row.tempGrossMargin || '0.00' }}%</span>
+                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
               </div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="商品来源" align="center" width="100">
+        <el-table-column label="库存情况" align="center" width="140">
           <template #default="scope">
-            <span>{{ scope.row.dataSource || '-' }}</span>
+            <div class="text-left" style="font-size: 12px">
+              <div>
+                <span class="text-gray-500">总库存:</span>
+                <span>{{ scope.row.totalInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">可用库存:</span>
+                <span>{{ scope.row.nowInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">虚拟库存:</span>
+                <span>{{ scope.row.virtualInventory ?? '-' }}</span>
+              </div>
+            </div>
           </template>
         </el-table-column>
-        <el-table-column label="商品状态" align="center" width="100">
+        <!--        <el-table-column label="数据来源" align="center" prop="dataSource" width="80">-->
+        <!--          <template #default="scope">-->
+        <!--            <span>{{ scope.row.dataSource || '-' }}</span>-->
+        <!--          </template>-->
+        <!--        </el-table-column>-->
+        <el-table-column label="是否自营" align="center" width="80">
           <template #default="scope">
-            <el-tag v-if="scope.row.auditStatus === 1" type="warning">待审核</el-tag>
-            <el-tag v-else-if="scope.row.auditStatus === 2" type="success">审核通过</el-tag>
-            <el-tag v-else-if="scope.row.auditStatus === 3" type="danger">审核驳回</el-tag>
+            <span v-if="scope.row.isSelf === 1">是</span>
+            <span v-else-if="scope.row.isSelf === 0">否</span>
             <span v-else>-</span>
           </template>
         </el-table-column>
-        <el-table-column label="审核意见" align="center" width="180" show-overflow-tooltip>
+        <el-table-column label="审核状态" align="center" prop="productReviewStatus" width="90">
           <template #default="scope">
-            <span>{{ scope.row.auditReason || '-' }}</span>
+            <span v-if="scope.row.productReviewStatus === 0">待采购审核</span>
+            <span v-else-if="scope.row.productReviewStatus === 1">审核通过</span>
+            <span v-else-if="scope.row.productReviewStatus === 2">驳回</span>
+            <span v-else-if="scope.row.productReviewStatus === 3">待营销审核</span>
+            <span v-else>-</span>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center" width="150" fixed="right" class-name="border-left">
+        <el-table-column label="上下架状态" align="center" prop="productStatus" width="100">
           <template #default="scope">
-            <div class="flex gap-1 justify-center">
-              <el-link type="primary" :underline="false" @click="handleView(scope.row)">详情</el-link>
+            <el-tag v-if="scope.row.productStatus === 1" type="success">已上架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 0" type="warning">下架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 2" type="info">上架中</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" width="150" fixed="right">
+          <template #default="scope">
+            <!-- 待审核状态:只显示编辑 -->
+            <div v-if="scope.row.productReviewStatus !== 1" class="flex gap-1 justify-center">
+              <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
+            </div>
+
+            <!-- 审核通过 -->
+            <div v-else-if="scope.row.productReviewStatus === 1" class="flex flex-col gap-1">
+              <!-- 下架状态:编辑、上架、停售、修改库存 -->
+              <div v-if="scope.row.productStatus === 0" class="flex gap-1 justify-center">
+                <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
+                <el-link type="success" :underline="false" @click="handleShelf(scope.row)">上架</el-link>
+                <el-link type="danger" :underline="false" @click="handleDiscontinue(scope.row)">停售</el-link>
+              </div>
+
+              <!-- 上架状态:编辑、下架、停售、修改库存 -->
+              <div v-else-if="scope.row.productStatus === 1" class="flex gap-1 justify-center">
+                <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
+                <el-link type="warning" :underline="false" @click="handleShelf(scope.row)">下架</el-link>
+                <el-link type="danger" :underline="false" @click="handleDiscontinue(scope.row)">停售</el-link>
+              </div>
+            </div>
+
+            <!-- 其他状态(待提交、审核驳回等):显示编辑 -->
+            <div v-else class="flex gap-1 justify-center">
               <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
-              <el-link v-if="scope.row.auditStatus === 2" type="warning" :underline="false" @click="handleOffShelf(scope.row)">下架</el-link>
+            </div>
+            <div class="flex gap-1 justify-center">
+              <el-link type="primary" :underline="false" @click="handleSupply(scope.row)">修改库存</el-link>
             </div>
           </template>
         </el-table-column>
@@ -184,74 +265,165 @@
         @pagination="getList"
       />
     </el-card>
-
-
+    <!-- 库存修改弹框 -->
+    <el-dialog v-model="inventoryDialog.visible" title="修改库存" width="500px" :close-on-click-modal="false">
+      <div v-loading="inventoryDialog.loading">
+        <el-form ref="inventoryFormRef" :model="inventoryForm" :rules="inventoryRules" label-width="110px">
+          <el-form-item label="虚拟库存" prop="virtualInventory">
+            <el-input-number
+              v-model="inventoryForm.virtualInventory"
+              :min="0"
+              :precision="0"
+              controls-position="right"
+              style="width: 100%"
+              placeholder="请输入虚拟库存"
+            />
+          </el-form-item>
+        </el-form>
+      </div>
+      <template #footer>
+        <el-button @click="inventoryDialog.visible = false">取消</el-button>
+        <el-button type="primary" :loading="inventoryDialog.submitLoading" @click="submitInventory">确定</el-button>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
-<script setup name="BaseReview" lang="ts">
-import { getGoodProductPage, brandList, categoryTree } from '@/api/product/base';
-import { BaseVO, BaseQuery } from '@/api/product/base/types';
-import { updateProductExquisite } from '@/api/product/productExquisite';
+<script setup name="Base" lang="ts">
+import {
+  listBase,
+  getBase,
+  delBase,
+  brandList,
+  updateBase,
+  categoryTree,
+  shelfReview,
+  changeProductType,
+  getProductStatusCount
+} from '@/api/product/base';
+import { generatePPT } from '@/utils/pptPlugin';
+import { addProductSelf } from '@/api/product/productSelf';
+import { addProductExquisite } from '@/api/product/productExquisite';
+import { PriceInventoryForm } from '@/api/product/priceInventory/types';
+import { BaseVO, BaseQuery, BaseForm, StatusCountVo } from '@/api/product/base/types';
 import { BrandVO } from '@/api/product/brand/types';
+import { listBrand } from '@/api/product/brand';
 import { categoryTreeVO } from '@/api/product/category/types';
-import { useRouter, useRoute } from 'vue-router';
+import { useRoute, useRouter } from 'vue-router';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const router = useRouter();
 const route = useRoute();
 
 const baseList = ref<BaseVO[]>([]);
+const buttonLoading = ref(false);
 const loading = ref(true);
 const showSearch = ref(true);
 const ids = ref<Array<string | number>>([]);
 const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
+const categoryOptions = ref<categoryTreeVO[]>([]);
 const brandOptions = ref<BrandVO[]>([]);
 const brandLoading = ref(false);
-const brandOptionsFormatted = computed(() => {
-  return brandOptions.value.slice(0, 500).map((item) => ({
-    label: item.brandName,
-    value: item.brandName // review.vue使用brandName作为value
-  }));
-});
-const categoryOptions = ref<categoryTreeVO[]>([]);
+let brandSearchTimer: ReturnType<typeof setTimeout> | null = null;
 const hasMore = ref(true); // 是否还有更多数据
+// 页面历史记录,存储每页的第一个id和最后一个id,用于支持双向翻页
 const pageHistory = ref([]);
 
-// 动态计算表格高度
-const tableHeight = computed(() => {
-  // 基础高度 = 视口高度 - 顶部导航(84) - 容器padding(16) - 搜索区域 - 卡片header(60) - 分页器(60)
-  const baseHeight = window.innerHeight - 84 - 16;
-  const searchHeight = showSearch.value ? 150 : 10; // 搜索区域高度
-  const cardHeaderHeight = 60; // 卡片header高度
-  const paginationHeight = 60; // 分页器高度
-  return baseHeight - searchHeight - cardHeaderHeight - paginationHeight;
+// 分类相关
+const categoryCascadeRef = ref();
+
+// 统计信息
+const statistics = ref<StatusCountVo>({
+  total: 0,
+  onSale: 0,
+  offSale: 0,
+  waitAudit: 0,
+  auditPass: 0,
+  auditReject: 0
 });
 
 const queryFormRef = ref<ElFormInstance>();
+const baseFormRef = ref<ElFormInstance>();
 
-const queryParams = ref<BaseQuery & { auditStatus?: number }>({
-  pageNum: 1,
-  pageSize: 10,
-  way: undefined,
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: BaseForm = {
+  id: undefined,
   productNo: undefined,
   itemName: undefined,
-  brandName: undefined,
-  purchaseNature: undefined,
+  brandId: undefined,
+  topCategoryId: undefined,
+  mediumCategoryId: undefined,
   bottomCategoryId: undefined,
+  unitId: undefined,
+  productImage: undefined,
   isSelf: undefined,
-  auditStatus: undefined,
+  productReviewStatus: undefined,
+  homeRecommended: undefined,
+  categoryRecommendation: undefined,
+  cartRecommendation: undefined,
+  recommendedProductOrder: undefined,
+  isPopular: undefined,
+  isNew: undefined,
   productStatus: undefined,
-  lastSeenId: undefined // 游标分页的lastSeenId
+  remark: undefined
+};
+const data = reactive<PageData<BaseForm, BaseQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    productNo: undefined,
+    itemName: undefined,
+    brandId: undefined,
+    productTag: undefined,
+    purchaseNature: undefined,
+    supplierType: undefined,
+    supplierNature: undefined,
+    projectOrg: undefined,
+    topCategoryId: undefined,
+    mediumCategoryId: undefined,
+    bottomCategoryId: undefined,
+    isSelf: 1,
+    productCategory: 2,
+    productReviewStatus: undefined,
+    productStatus: undefined,
+    lastSeenId: undefined, // 游标分页的lastSeenId
+    way: undefined,
+    params: {}
+  },
+  rules: {
+    productNo: [{ required: true, message: '产品编号不能为空', trigger: 'blur' }],
+    itemName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
+    brandId: [{ required: true, message: '品牌id不能为空', trigger: 'blur' }],
+    topCategoryId: [{ required: true, message: '顶级分类id不能为空', trigger: 'blur' }],
+    mediumCategoryId: [{ required: true, message: '中级分类id不能为空', trigger: 'blur' }],
+    bottomCategoryId: [{ required: true, message: '底层分类id不能为空', trigger: 'blur' }],
+    unitId: [{ required: true, message: '单位id不能为空', trigger: 'blur' }],
+    productImage: [{ required: true, message: '产品图片URL不能为空', trigger: 'blur' }],
+    productReviewStatus: [{ required: true, message: '产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核不能为空', trigger: 'change' }],
+    homeRecommended: [{ required: true, message: '首页推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    categoryRecommendation: [{ required: true, message: '分类推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    cartRecommendation: [{ required: true, message: '购物车推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    recommendedProductOrder: [{ required: true, message: '推荐产品顺序不能为空', trigger: 'blur' }],
+    isPopular: [{ required: true, message: '是否热门:1=是,0=否不能为空', trigger: 'blur' }],
+    isNew: [{ required: true, message: '是否新品:1=是,0=否不能为空', trigger: 'blur' }],
+    remark: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
+  }
 });
 
+const { queryParams, form, rules } = toRefs(data);
 
-/** 查询商品列表 */
+/** 查询产品基础信息列表 */
 const getList = async () => {
   loading.value = true;
   try {
+    initRouteParams();
     const params = { ...queryParams.value };
     const currentPageNum = queryParams.value.pageNum;
 
@@ -278,7 +450,7 @@ const getList = async () => {
       }
     }
 
-    const res = await getGoodProductPage(params);
+    const res = await listBase(params);
     baseList.value = res.rows || [];
 
     // 判断是否还有更多数据
@@ -297,6 +469,7 @@ const getList = async () => {
         };
       }
     }
+
     total.value = res.total || 0;
   } catch (error) {
     console.error('获取列表失败:', error);
@@ -305,11 +478,17 @@ const getList = async () => {
   }
 };
 
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
 /** 初始化路由参数 */
 const initRouteParams = () => {
   // 从路由参数中获取筛选条件
-  if (route.query.auditStatus) {
-    queryParams.value.auditStatus = Number(route.query.auditStatus);
+  if (route.query.productReviewStatus) {
+    queryParams.value.productReviewStatus = Number(route.query.productReviewStatus);
   }
   if (route.query.brandName) {
     queryParams.value.brandName = route.query.brandName as string;
@@ -317,21 +496,49 @@ const initRouteParams = () => {
   if (route.query.bottomCategoryId) {
     queryParams.value.bottomCategoryId = route.query.bottomCategoryId as string;
   }
+  if (route.query.isSelf) {
+    queryParams.value.isSelf = Number(route.query.isSelf);
+  }
+  if (route.query.productCategory) {
+    queryParams.value.productCategory = Number(route.query.productCategory);
+  }
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  baseFormRef.value?.resetFields();
 };
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
-  queryParams.value.pageNum = 1;
-  queryParams.value.lastSeenId = undefined;
-  pageHistory.value = [0]; // 重置页面历史
+  // 同步查询参数到游标分页参数
+  queryParams.value = {
+    ...queryParams.value,
+    pageNum: 1,
+    productNo: queryParams.value.productNo,
+    itemName: queryParams.value.itemName,
+    brandName: queryParams.value.brandName,
+    bottomCategoryId: queryParams.value.bottomCategoryId,
+    isSelf: queryParams.value.isSelf,
+    productReviewStatus: queryParams.value.productReviewStatus,
+    productStatus: queryParams.value.productStatus,
+    lastSeenId: undefined
+  };
+  pageHistory.value = []; // 重置页面历史
   getList();
 };
 
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
+  // 手动重置分类字段
+  queryParams.value.topCategoryId = undefined;
+  queryParams.value.mediumCategoryId = undefined;
+  queryParams.value.bottomCategoryId = undefined;
+  categoryCascadeRef.value?.reset();
   queryParams.value.lastSeenId = undefined;
-  pageHistory.value = [0]; // 重置页面历史
+  pageHistory.value = []; // 重置页面历史
   handleQuery();
 };
 
@@ -342,15 +549,71 @@ const handleSelectionChange = (selection: BaseVO[]) => {
   multiple.value = !selection.length;
 };
 
+/** 新增按钮操作 */
+const handleAdd = () => {
+  router.push('/product/base/add');
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: BaseVO) => {
+  const _id = row?.id || ids.value[0];
+  router.push(`/product/base/edit/${_id}`);
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: BaseVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品基础信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delBase(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
 /** 导出按钮操作 */
-const handleExport = () => {
-  proxy?.download(
-    'product/base/export',
-    {
-      ...queryParams.value
-    },
-    `base_review_${new Date().getTime()}.xlsx`
-  );
+const handleExport = async () => {
+  // 检查是否有选中的商品
+  if (ids.value.length === 0) {
+    proxy?.$modal.msgWarning('请先选择要导出的商品');
+    return;
+  }
+
+  // 获取选中商品的完整信息
+  const selectedProducts = baseList.value.filter(item => ids.value.includes(item.id));
+
+  if (selectedProducts.length === 0) {
+    proxy?.$modal.msgWarning('未找到选中的商品信息');
+    return;
+  }
+
+  // 转换为 generatePPT 需要的格式
+  const products = selectedProducts.map(item => ({
+    image: item.productImage || item.productImageUrl || '',
+    name: item.itemName || '',
+    code: item.productNo || '',
+    spec: item.specification || item.packagingSpec || '-',
+    price: item.minSellingPrice || item.memberPrice || 0
+  }));
+
+  // 默认模板配置
+  const template = {
+    name: '商品展示方案',
+    title: '商品展示方案',
+    themeColor: '#C00000',
+    itemsPerPage: 1, // 每页1个商品,展示更详细
+    cover: '',
+    logo: ''
+  };
+
+  try {
+    proxy?.$modal.loading('正在生成PPT...');
+    await generatePPT(template, products);
+    proxy?.$modal.closeLoading();
+    proxy?.$modal.msgSuccess('PPT导出成功');
+  } catch (error) {
+    proxy?.$modal.closeLoading();
+    console.error('PPT导出失败:', error);
+    proxy?.$modal.msgError('PPT导出失败');
+  }
 };
 
 /** 查看商品详情 */
@@ -359,95 +622,189 @@ const handleView = (row: BaseVO) => {
   window.open(url, '_blank');
 };
 
-/** 编辑商品 */
-const handleUpdate = (row: BaseVO) => {
-  router.push(`/product/base/edit/${row.id}`);
-};
+/** 上下架操作 */
+const handleShelf = async (row: BaseVO) => {
+  const isOnShelf = row.productStatus === 1;
+  const action = isOnShelf ? '下架' : '上架';
+  await proxy?.$modal.confirm(`确认${action}该商品吗?`);
 
-/** 下架操作 */
-const handleOffShelf = async (row: BaseVO) => {
-  await proxy?.$modal.confirm('确认下架该精选商品吗?');
   try {
-    await updateProductExquisite({
-      id: row.exquisiteId,
-      auditStatus: 3,
-      auditReason: '下架操作'
+    // 上架:状态改为2(上架中),下架:状态改为0(下架)
+    const productStatus = isOnShelf ? 0 : 2;
+    await shelfReview({
+      id: row.id,
+      productStatus: productStatus,
+      shelfComments: `${action}操作`
     });
-    proxy?.$modal.msgSuccess('下架成功');
+    proxy?.$modal.msgSuccess(`${action}成功`);
     await getList();
   } catch (error) {
-    console.error('下架失败:', error);
-    proxy?.$modal.msgError('下架失败');
+    console.error(`${action}失败:`, error);
+    proxy?.$modal.msgError(`${action}失败`);
   }
 };
 
-/** 查询品牌列表(实时请求,每次只加载500条) */
-const getBrandList = async () => {
+
+/** 库存修改弹框 */
+const inventoryDialog = reactive({
+  visible: false,
+  loading: false,
+  submitLoading: false
+});
+
+const inventoryFormRef = ref<ElFormInstance>();
+
+const inventoryForm = reactive<PriceInventoryForm>({
+  productId: undefined,
+  totalInventory: undefined,
+  nowInventory: undefined,
+  virtualInventory: undefined
+});
+
+const inventoryRules = {
+  totalInventory: [{ required: true, message: '总库存不能为空', trigger: 'blur' }],
+  nowInventory: [{ required: true, message: '当前可用库存不能为空', trigger: 'blur' }],
+  virtualInventory: [{ required: true, message: '虚拟库存不能为空', trigger: 'blur' }]
+};
+
+/** 打开库存修改弹框 */
+const handleSupply = async (row: BaseVO) => {
+  inventoryForm.id = row.id;
+  inventoryForm.totalInventory = undefined;
+  inventoryForm.nowInventory = undefined;
+  inventoryForm.virtualInventory = undefined;
+  inventoryDialog.loading = true;
+  inventoryDialog.visible = true;
   try {
-    brandLoading.value = true;
-    const res = await brandList({ pageNum: 1, pageSize: 500 });
-    brandOptions.value = res.data || [];
+    const res = await getBase(row.id);
+    if (res.data) {
+      inventoryForm.totalInventory = res.data.totalInventory;
+      inventoryForm.nowInventory = res.data.nowInventory;
+      inventoryForm.virtualInventory = res.data.virtualInventory;
+    }
   } catch (error) {
-    console.error('获取品牌列表失败:', error);
+    console.error('获取库存信息失败:', error);
   } finally {
-    brandLoading.value = false;
+    inventoryDialog.loading = false;
   }
 };
 
-/** 处理品牌下拉框显示/隐藏 */
-const handleBrandVisibleChange = (visible: boolean) => {
-  if (visible && brandOptions.value.length === 0) {
-    getBrandList();
+/** 提交库存修改 */
+const submitInventory = async () => {
+  await inventoryFormRef.value?.validate();
+  inventoryDialog.submitLoading = true;
+  try {
+    await updateBase({ ...inventoryForm });
+    proxy?.$modal.msgSuccess('库存修改成功');
+    inventoryDialog.visible = false;
+    await getList();
+  } catch (error) {
+    console.error('库存修改失败:', error);
+    proxy?.$modal.msgError('库存修改失败');
+  } finally {
+    inventoryDialog.submitLoading = false;
   }
 };
 
+/** 停售操作 */
+const handleDiscontinue = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认停售该商品吗?停售后商品将无法正常售卖。');
+
+  try {
+    // 调用停售API,将商品类型改为3(停售商品)
+    await changeProductType({
+      id: row.id,
+      productCategory: 3
+    });
+    proxy?.$modal.msgSuccess('停售成功');
+    await getList();
+  } catch (error) {
+    console.error('停售失败:', error);
+    proxy?.$modal.msgError('停售失败');
+  }
+};
+
+/** 加入自营池操作 */
+const handleAddToSelfPool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入自营池吗?');
+
+  try {
+    await addProductSelf({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入自营池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入自营池失败:', error);
+    proxy?.$modal.msgError('加入自营池失败');
+  }
+};
+
+/** 加入精品池操作 */
+const handleAddToExquisitePool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入精品池吗?');
+
+  try {
+    await addProductExquisite({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入精品池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入精品池失败:', error);
+    proxy?.$modal.msgError('加入精品池失败');
+  }
+};
+
+/** 跳转到商品审核页面 */
+const handleGoReview = () => {
+  router.push({
+    path: '/product/base/review',
+    query: {
+      productReviewStatus: 1 // 默认显示待审核的商品
+    }
+  });
+};
+
 /** 查询分类树 */
 const getCategoryTree = async () => {
   const res = await categoryTree();
   categoryOptions.value = res.data || [];
 };
 
-onMounted(() => {
-  getCategoryTree();
-  initRouteParams();
-  getList();
-});
-</script>
-
-<style scoped lang="scss">
-.app-container {
-  padding: 8px;
-  height: calc(100vh - 84px);
-  display: flex;
-  flex-direction: column;
-  overflow: hidden;
-}
-
-.table-card {
-  flex: 1;
-  display: flex;
-  flex-direction: column;
-  overflow: hidden;
-
-  :deep(.el-card__body) {
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-    overflow: hidden;
+/** 加载品牌选项(默认100条) */
+const loadBrandOptions = async (keyword?: string) => {
+  brandLoading.value = true;
+  try {
+    const res = await listBrand({ pageNum: 1, pageSize: 100, brandName: keyword });
+    brandOptions.value = res.rows || [];
+  } catch (error) {
+    console.error('加载品牌列表失败:', error);
+  } finally {
+    brandLoading.value = false;
   }
+};
 
-  :deep(.el-table) {
-    flex: 1;
-  }
+/** 品牌远程搜索(防抖) */
+const handleBrandSearch = (query: string) => {
+  if (brandSearchTimer) clearTimeout(brandSearchTimer);
+  brandSearchTimer = setTimeout(() => {
+    loadBrandOptions(query || undefined);
+  }, 300);
+};
 
-  // 确保固定列左侧有边框
-  :deep(.el-table__fixed-right) {
-    box-shadow: -1px 0 0 var(--el-table-border-color) !important;
+/** 获取统计信息 */
+const getStatistics = async () => {
+  try {
+    const res = await getProductStatusCount();
+    if (res.data) {
+      statistics.value = res.data;
+    }
+  } catch (error) {
+    console.error('获取统计信息失败:', error);
   }
+};
 
-  // 固定列的单元格左边框
-  :deep(.el-table__fixed-right .el-table__cell) {
-    border-left: 1px solid var(--el-table-border-color) !important;
-  }
-}
-</style>
+
+onMounted(() => {
+  getList();
+  getStatistics();
+  loadBrandOptions();
+});
+</script>

+ 446 - 220
src/views/product/base/self.vue

@@ -1,10 +1,9 @@
 <template>
-  <div class="app-container">
-    <!-- 搜索区域 -->
+  <div class="p-2">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
       <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form ref="queryFormRef" :model="queryParams" label-width="100px">
+          <el-form ref="queryFormRef" :model="queryParams" label-width="90px">
             <el-row :gutter="20">
               <el-col :span="6">
                 <el-form-item label="商品编号" prop="productNo">
@@ -17,49 +16,62 @@
                 </el-form-item>
               </el-col>
               <el-col :span="6">
-                <el-form-item label="商品类别" prop="bottomCategoryId">
+                <el-form-item label="商品品牌" prop="brandId">
+                  <el-select
+                    v-model="queryParams.brandId"
+                    placeholder="请输入品牌名称搜索"
+                    filterable
+                    remote
+                    clearable
+                    :remote-method="handleBrandSearch"
+                    :loading="brandLoading"
+                    style="width: 100%"
+                    @keyup.enter="handleQuery"
+                  >
+                    <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="6">
+                <el-form-item label="上下架状态" prop="productStatus">
+                  <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
+                    <el-option label="已上架" :value="1" />
+                    <el-option label="下架" :value="0" />
+                    <el-option label="上架中" :value="2" />
+                    <el-option label="驳回上架" :value="3" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品类型" prop="bottomCategoryId">
                   <el-tree-select
                     v-model="queryParams.bottomCategoryId"
                     :data="categoryOptions"
                     :props="{ value: 'id', label: 'label', children: 'children' } as any"
                     value-key="id"
-                    placeholder="请选择商品类别"
+                    placeholder="请选择商品类"
                     clearable
                     check-strictly
                   />
                 </el-form-item>
               </el-col>
-              <el-col :span="6">
-                <el-form-item label="商品品牌" prop="brandName">
-                  <el-select-v2
-                    v-model="queryParams.brandName"
-                    :options="brandOptionsFormatted"
-                    placeholder="请选择商品品牌"
-                    clearable
-                    filterable
-                    :loading="brandLoading"
-                    @visible-change="handleBrandVisibleChange"
+              <el-col :span="18">
+                <el-form-item label="商品分类">
+                  <category-cascade-select
+                    ref="categoryCascadeRef"
+                    v-model:top-category-id="queryParams.topCategoryId"
+                    v-model:medium-category-id="queryParams.mediumCategoryId"
+                    v-model:bottom-category-id="queryParams.bottomCategoryId"
                   />
                 </el-form-item>
               </el-col>
-              <el-col :span="6">
-                <el-form-item label="审核状态" prop="auditStatus">
-                  <el-select
-                    v-model="queryParams.auditStatus"
-                    placeholder="请选择审核状态"
-                    clearable
-                  >
-                    <el-option label="待审核" :value="1" />
-                    <el-option label="审核通过" :value="2" />
-                    <el-option label="审核驳回" :value="3" />
-                  </el-select>
-                </el-form-item>
-              </el-col>
-              <el-col :span="6">
-                <el-form-item>
-                  <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-                  <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-                </el-form-item>
+            </el-row>
+            <el-row>
+              <el-col :span="24" class="text-left">
+                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
               </el-col>
             </el-row>
           </el-form>
@@ -67,53 +79,67 @@
       </div>
     </transition>
 
-    <!-- 审核商品信息列表 -->
-    <el-card shadow="never" class="table-card">
-      <template #header>
-        <div class="flex items-center justify-between">
-          <span class="font-semibold">审核商品信息列表</span>
-          <div class="flex gap-2">
-
-            <el-button circle icon="Refresh" @click="getList"></el-button>
-          </div>
+    <!-- 统计信息区域 -->
+    <el-card shadow="never" class="mb-[10px]">
+      <div class="flex items-center text-sm text-gray-600">
+        <span>商品总数: </span>
+        <span class="text-blue-600 mx-1"
+        >总=<span class="text-red-600">{{ statistics.total || 0 }}</span
+        >条</span
+        >
+        <span class="mx-2">【上架/总数({{ statistics.onSale || 0 }}/{{ statistics.total || 0 }})】</span>
+        <span class="mx-2"
+        >审核状态: 待审核<span class="text-red-600">{{ statistics.waitAudit || 0 }}</span
+        >条,通过<span class="text-green-600">{{ statistics.auditPass || 0 }}</span
+        >条,驳回<span class="text-orange-600">{{ statistics.auditReject || 0 }}</span
+        >条</span
+        >
+        <span class="mx-2"
+        >上下架状态: 已上架<span class="text-green-600">{{ statistics.onSale || 0 }}</span
+        >条,下架<span class="text-gray-600">{{ statistics.offSale || 0 }}</span
+        >条</span
+        >
+        <div class="ml-auto flex gap-2">
+          <el-button type="primary" icon="Plus" @click="handleAdd">商品新增</el-button>
+          <!-- <el-button type="warning" icon="Check" @click="handleGoReview">商品审核</el-button> -->
+          <!--          <el-button plain>批量操作</el-button>-->
+          <el-button plain icon="Download" @click="handleExport">导出</el-button>
+          <el-button circle icon="Refresh" @click="getList"></el-button>
         </div>
-      </template>
+      </div>
+    </el-card>
 
-      <el-table v-loading="loading" border :data="baseList" :height="tableHeight" @selection-change="handleSelectionChange">
+    <el-card shadow="never">
+      <el-table v-loading="loading" border :data="baseList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="商品图片" align="center" prop="productImage" width="100" >
+        <el-table-column label="商品编号" align="center" prop="productNo" width="120" fixed="left">
           <template #default="scope">
-            <image-preview :src="scope.row.productImage" :width="60" :height="60"/>
+            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
           </template>
         </el-table-column>
-        <el-table-column label="商品编号" align="center" prop="productNo" width="120" >
+        <el-table-column label="商品图片" align="center" prop="productImage" width="100">
           <template #default="scope">
-            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
+            <image-preview :src="scope.row.productImage" :width="60" :height="60" />
           </template>
         </el-table-column>
-        <el-table-column label="商品信息" align="center" min-width="250" show-overflow-tooltip>
+        <el-table-column label="商品信息" align="center" min-width="250">
           <template #default="scope">
             <div class="text-left">
-              <div>{{ scope.row.itemName }}</div>
-              <div class="text-gray-500" style="font-size: 12px;">品牌: {{ scope.row.brandName || '-' }}</div>
+              <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.topCategoryName+'-'+scope.row.mediumCategoryName+'-'+ scope.row.bottomCategoryName}}</div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="基本情况" align="center" width="180">
+        <el-table-column label="单位" align="center" width="100">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px;">
-              <div>
-                <span class="text-gray-500">商品分类:</span>
-                <span>{{ scope.row.categoryName || '-' }}</span>
-              </div>
-              <div>
-                <span class="text-gray-500">单位:</span>
-                <span>{{ scope.row.unitName || '-' }}</span>
-              </div>
+            <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="SKU价格" align="center" width="180">
+        <el-table-column label="价格信息" align="center" width="120">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px">
               <div>
@@ -131,55 +157,85 @@
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="成本预算" align="center" width="150">
+
+        <el-table-column label="采购信息" align="center" width="150">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px;">
+            <div class="text-left" style="font-size: 12px">
               <div>
                 <span class="text-gray-500">采购价:</span>
                 <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
               </div>
               <div>
                 <span class="text-gray-500">暂估毛利率:</span>
-                <span>{{ scope.row.tempGrossMargin || '0.00' }}%</span>
+                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="库存情况" align="center" width="140">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px">
+              <div>
+                <span class="text-gray-500">总库存:</span>
+                <span>{{ scope.row.totalInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">可用库存:</span>
+                <span>{{ scope.row.nowInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">虚拟库存:</span>
+                <span>{{ scope.row.virtualInventory ?? '-' }}</span>
               </div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="商品来源" align="center" width="100">
+        <!--        <el-table-column label="数据来源" align="center" prop="dataSource" width="80">-->
+        <!--          <template #default="scope">-->
+        <!--            <span>{{ scope.row.dataSource || '-' }}</span>-->
+        <!--          </template>-->
+        <!--        </el-table-column>-->
+        <el-table-column label="是否自营" align="center" width="80">
           <template #default="scope">
-            <span>{{ scope.row.dataSource || '-' }}</span>
+            <span v-if="scope.row.isSelf === 1">是</span>
+            <span v-else-if="scope.row.isSelf === 0">否</span>
+            <span v-else>-</span>
           </template>
         </el-table-column>
-        <el-table-column label="商品状态" align="center" width="100">
+        <el-table-column label="审核状态" align="center" prop="productReviewStatus" width="90">
           <template #default="scope">
-            <el-tag v-if="scope.row.auditStatus === 1" type="warning">待审核</el-tag>
-            <el-tag v-else-if="scope.row.auditStatus === 2" type="success">审核通过</el-tag>
-            <el-tag v-else-if="scope.row.auditStatus === 3" type="danger">审核驳回</el-tag>
+            <span v-if="scope.row.productReviewStatus === 0">待采购审核</span>
+            <span v-else-if="scope.row.productReviewStatus === 1">审核通过</span>
+            <span v-else-if="scope.row.productReviewStatus === 2">驳回</span>
+            <span v-else-if="scope.row.productReviewStatus === 3">待营销审核</span>
             <span v-else>-</span>
           </template>
         </el-table-column>
-        <el-table-column label="审核意见" align="center" width="180" show-overflow-tooltip>
+        <el-table-column label="上下架状态" align="center" prop="productStatus" width="100">
           <template #default="scope">
-            <span>{{ scope.row.auditReason || '-' }}</span>
+            <el-tag v-if="scope.row.productStatus === 1" type="success">已上架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 0" type="warning">下架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 2" type="info">上架中</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center" width="150" fixed="right" class-name="border-left">
+        <el-table-column label="操作" align="center" width="150" fixed="right">
           <template #default="scope">
             <!-- 待审核状态:只显示编辑 -->
-            <div v-if="scope.row.auditStatus === 1" class="flex gap-1 justify-center">
+            <div v-if="scope.row.productReviewStatus !== 1" class="flex gap-1 justify-center">
               <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
             </div>
 
             <!-- 审核通过 -->
-            <div v-else-if="scope.row.auditStatus === 2" class="flex flex-col gap-1">
-              <!-- 下架状态:编辑、上架、停售 -->
+            <div v-else-if="scope.row.productReviewStatus === 1" class="flex flex-col gap-1">
+              <!-- 下架状态:编辑、上架、停售、修改库存 -->
               <div v-if="scope.row.productStatus === 0" class="flex gap-1 justify-center">
                 <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
                 <el-link type="success" :underline="false" @click="handleShelf(scope.row)">上架</el-link>
                 <el-link type="danger" :underline="false" @click="handleDiscontinue(scope.row)">停售</el-link>
               </div>
 
-              <!-- 上架状态:编辑、下架、停售 -->
+              <!-- 上架状态:编辑、下架、停售、修改库存 -->
               <div v-else-if="scope.row.productStatus === 1" class="flex gap-1 justify-center">
                 <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
                 <el-link type="warning" :underline="false" @click="handleShelf(scope.row)">下架</el-link>
@@ -187,12 +243,7 @@
               </div>
             </div>
 
-            <!-- 审核驳回:显示编辑 -->
-            <div v-else-if="scope.row.auditStatus === 3" class="flex gap-1 justify-center">
-              <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
-            </div>
-
-            <!-- 其他状态:显示编辑 -->
+            <!-- 其他状态(待提交、审核驳回等):显示编辑 -->
             <div v-else class="flex gap-1 justify-center">
               <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
             </div>
@@ -214,7 +265,6 @@
         @pagination="getList"
       />
     </el-card>
-
     <!-- 库存修改弹框 -->
     <el-dialog v-model="inventoryDialog.visible" title="修改库存" width="500px" :close-on-click-modal="false">
       <div v-loading="inventoryDialog.loading">
@@ -239,89 +289,140 @@
   </div>
 </template>
 
-<script setup name="BaseReview" lang="ts">
-import { getSelfProductPage, brandList, categoryTree, getBase, updateBase, shelfReview, changeProductType } from '@/api/product/base';
-import { BaseVO, BaseQuery, BaseForm } from '@/api/product/base/types';
+<script setup name="Base" lang="ts">
+import {
+  listBase,
+  getBase,
+  delBase,
+  brandList,
+  updateBase,
+  categoryTree,
+  shelfReview,
+  changeProductType,
+  getProductStatusCount
+} from '@/api/product/base';
+import { generatePPT } from '@/utils/pptPlugin';
+import { addProductSelf } from '@/api/product/productSelf';
+import { addProductExquisite } from '@/api/product/productExquisite';
+import { PriceInventoryForm } from '@/api/product/priceInventory/types';
+import { BaseVO, BaseQuery, BaseForm, StatusCountVo } from '@/api/product/base/types';
 import { BrandVO } from '@/api/product/brand/types';
+import { listBrand } from '@/api/product/brand';
 import { categoryTreeVO } from '@/api/product/category/types';
-import { useRouter, useRoute } from 'vue-router';
+import { useRoute, useRouter } from 'vue-router';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const router = useRouter();
 const route = useRoute();
 
 const baseList = ref<BaseVO[]>([]);
+const buttonLoading = ref(false);
 const loading = ref(true);
 const showSearch = ref(true);
 const ids = ref<Array<string | number>>([]);
 const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
+const categoryOptions = ref<categoryTreeVO[]>([]);
 const brandOptions = ref<BrandVO[]>([]);
 const brandLoading = ref(false);
-const brandOptionsFormatted = computed(() => {
-  return brandOptions.value.slice(0, 500).map((item) => ({
-    label: item.brandName,
-    value: item.brandName // review.vue使用brandName作为value
-  }));
-});
-const categoryOptions = ref<categoryTreeVO[]>([]);
+let brandSearchTimer: ReturnType<typeof setTimeout> | null = null;
 const hasMore = ref(true); // 是否还有更多数据
+// 页面历史记录,存储每页的第一个id和最后一个id,用于支持双向翻页
 const pageHistory = ref([]);
 
-// 动态计算表格高度
-const tableHeight = computed(() => {
-  // 基础高度 = 视口高度 - 顶部导航(84) - 容器padding(16) - 搜索区域 - 卡片header(60) - 分页器(60)
-  const baseHeight = window.innerHeight - 84 - 16;
-  const searchHeight = showSearch.value ? 150 : 10; // 搜索区域高度
-  const cardHeaderHeight = 60; // 卡片header高度
-  const paginationHeight = 60; // 分页器高度
-  return baseHeight - searchHeight - cardHeaderHeight - paginationHeight;
+// 分类相关
+const categoryCascadeRef = ref();
+
+// 统计信息
+const statistics = ref<StatusCountVo>({
+  total: 0,
+  onSale: 0,
+  offSale: 0,
+  waitAudit: 0,
+  auditPass: 0,
+  auditReject: 0
 });
 
 const queryFormRef = ref<ElFormInstance>();
-const inventoryFormRef = ref<ElFormInstance>();
+const baseFormRef = ref<ElFormInstance>();
 
-// 库存修改弹框
-const inventoryDialog = reactive({
+const dialog = reactive<DialogOption>({
   visible: false,
-  loading: false,
-  submitLoading: false
+  title: ''
 });
 
-const inventoryForm = reactive<any>({
+const initFormData: BaseForm = {
   id: undefined,
-  totalInventory: undefined,
-  nowInventory: undefined,
-  virtualInventory: undefined
-});
-
-const inventoryRules = {
-  totalInventory: [{ required: true, message: '总库存不能为空', trigger: 'blur' }],
-  nowInventory: [{ required: true, message: '当前可用库存不能为空', trigger: 'blur' }],
-  virtualInventory: [{ required: true, message: '虚拟库存不能为空', trigger: 'blur' }]
-};
-
-const queryParams = ref<BaseQuery & { auditStatus?: number }>({
-  pageNum: 1,
-  pageSize: 10,
-  way: undefined,
   productNo: undefined,
   itemName: undefined,
-  brandName: undefined,
-  purchaseNature: undefined,
+  brandId: undefined,
+  topCategoryId: undefined,
+  mediumCategoryId: undefined,
   bottomCategoryId: undefined,
+  unitId: undefined,
+  productImage: undefined,
   isSelf: undefined,
-  auditStatus: undefined,
+  productReviewStatus: undefined,
+  homeRecommended: undefined,
+  categoryRecommendation: undefined,
+  cartRecommendation: undefined,
+  recommendedProductOrder: undefined,
+  isPopular: undefined,
+  isNew: undefined,
   productStatus: undefined,
-  lastSeenId: undefined // 游标分页的lastSeenId
+  remark: undefined
+};
+const data = reactive<PageData<BaseForm, BaseQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    productNo: undefined,
+    itemName: undefined,
+    brandId: undefined,
+    productTag: undefined,
+    purchaseNature: undefined,
+    supplierType: undefined,
+    supplierNature: undefined,
+    projectOrg: undefined,
+    topCategoryId: undefined,
+    mediumCategoryId: undefined,
+    bottomCategoryId: undefined,
+    isSelf: 1,
+    productReviewStatus: undefined,
+    productStatus: undefined,
+    lastSeenId: undefined, // 游标分页的lastSeenId
+    way: undefined,
+    params: {}
+  },
+  rules: {
+    productNo: [{ required: true, message: '产品编号不能为空', trigger: 'blur' }],
+    itemName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
+    brandId: [{ required: true, message: '品牌id不能为空', trigger: 'blur' }],
+    topCategoryId: [{ required: true, message: '顶级分类id不能为空', trigger: 'blur' }],
+    mediumCategoryId: [{ required: true, message: '中级分类id不能为空', trigger: 'blur' }],
+    bottomCategoryId: [{ required: true, message: '底层分类id不能为空', trigger: 'blur' }],
+    unitId: [{ required: true, message: '单位id不能为空', trigger: 'blur' }],
+    productImage: [{ required: true, message: '产品图片URL不能为空', trigger: 'blur' }],
+    productReviewStatus: [{ required: true, message: '产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核不能为空', trigger: 'change' }],
+    homeRecommended: [{ required: true, message: '首页推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    categoryRecommendation: [{ required: true, message: '分类推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    cartRecommendation: [{ required: true, message: '购物车推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    recommendedProductOrder: [{ required: true, message: '推荐产品顺序不能为空', trigger: 'blur' }],
+    isPopular: [{ required: true, message: '是否热门:1=是,0=否不能为空', trigger: 'blur' }],
+    isNew: [{ required: true, message: '是否新品:1=是,0=否不能为空', trigger: 'blur' }],
+    remark: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
+  }
 });
 
+const { queryParams, form, rules } = toRefs(data);
 
-/** 查询商品列表 */
+/** 查询产品基础信息列表 */
 const getList = async () => {
   loading.value = true;
   try {
+    initRouteParams();
     const params = { ...queryParams.value };
     const currentPageNum = queryParams.value.pageNum;
 
@@ -348,7 +449,7 @@ const getList = async () => {
       }
     }
 
-    const res = await getSelfProductPage(params);
+    const res = await listBase(params);
     baseList.value = res.rows || [];
 
     // 判断是否还有更多数据
@@ -367,6 +468,7 @@ const getList = async () => {
         };
       }
     }
+
     total.value = res.total || 0;
   } catch (error) {
     console.error('获取列表失败:', error);
@@ -375,11 +477,17 @@ const getList = async () => {
   }
 };
 
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
 /** 初始化路由参数 */
 const initRouteParams = () => {
   // 从路由参数中获取筛选条件
-  if (route.query.auditStatus) {
-    queryParams.value.auditStatus = Number(route.query.auditStatus);
+  if (route.query.productReviewStatus) {
+    queryParams.value.productReviewStatus = Number(route.query.productReviewStatus);
   }
   if (route.query.brandName) {
     queryParams.value.brandName = route.query.brandName as string;
@@ -387,21 +495,49 @@ const initRouteParams = () => {
   if (route.query.bottomCategoryId) {
     queryParams.value.bottomCategoryId = route.query.bottomCategoryId as string;
   }
+  if (route.query.isSelf) {
+    queryParams.value.isSelf = Number(route.query.isSelf);
+  }
+  if (route.query.productCategory) {
+    queryParams.value.productCategory = Number(route.query.productCategory);
+  }
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  baseFormRef.value?.resetFields();
 };
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
-  queryParams.value.pageNum = 1;
-  queryParams.value.lastSeenId = undefined;
-  pageHistory.value = [0]; // 重置页面历史
+  // 同步查询参数到游标分页参数
+  queryParams.value = {
+    ...queryParams.value,
+    pageNum: 1,
+    productNo: queryParams.value.productNo,
+    itemName: queryParams.value.itemName,
+    brandName: queryParams.value.brandName,
+    bottomCategoryId: queryParams.value.bottomCategoryId,
+    isSelf: queryParams.value.isSelf,
+    productReviewStatus: queryParams.value.productReviewStatus,
+    productStatus: queryParams.value.productStatus,
+    lastSeenId: undefined
+  };
+  pageHistory.value = []; // 重置页面历史
   getList();
 };
 
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
+  // 手动重置分类字段
+  queryParams.value.topCategoryId = undefined;
+  queryParams.value.mediumCategoryId = undefined;
+  queryParams.value.bottomCategoryId = undefined;
+  categoryCascadeRef.value?.reset();
   queryParams.value.lastSeenId = undefined;
-  pageHistory.value = [0]; // 重置页面历史
+  pageHistory.value = []; // 重置页面历史
   handleQuery();
 };
 
@@ -412,25 +548,77 @@ const handleSelectionChange = (selection: BaseVO[]) => {
   multiple.value = !selection.length;
 };
 
+/** 新增按钮操作 */
+const handleAdd = () => {
+  router.push('/product/base/add');
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: BaseVO) => {
+  const _id = row?.id || ids.value[0];
+  router.push(`/product/base/edit/${_id}`);
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: BaseVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品基础信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delBase(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
 /** 导出按钮操作 */
-const handleExport = () => {
-  proxy?.download(
-    'product/base/export',
-    {
-      ...queryParams.value
-    },
-    `base_review_${new Date().getTime()}.xlsx`
-  );
+const handleExport = async () => {
+  // 检查是否有选中的商品
+  if (ids.value.length === 0) {
+    proxy?.$modal.msgWarning('请先选择要导出的商品');
+    return;
+  }
+
+  // 获取选中商品的完整信息
+  const selectedProducts = baseList.value.filter(item => ids.value.includes(item.id));
+
+  if (selectedProducts.length === 0) {
+    proxy?.$modal.msgWarning('未找到选中的商品信息');
+    return;
+  }
+
+  // 转换为 generatePPT 需要的格式
+  const products = selectedProducts.map(item => ({
+    image: item.productImage || item.productImageUrl || '',
+    name: item.itemName || '',
+    code: item.productNo || '',
+    spec: item.specification || item.packagingSpec || '-',
+    price: item.minSellingPrice || item.memberPrice || 0
+  }));
+
+  // 默认模板配置
+  const template = {
+    name: '商品展示方案',
+    title: '商品展示方案',
+    themeColor: '#C00000',
+    itemsPerPage: 1, // 每页1个商品,展示更详细
+    cover: '',
+    logo: ''
+  };
+
+  try {
+    proxy?.$modal.loading('正在生成PPT...');
+    await generatePPT(template, products);
+    proxy?.$modal.closeLoading();
+    proxy?.$modal.msgSuccess('PPT导出成功');
+  } catch (error) {
+    proxy?.$modal.closeLoading();
+    console.error('PPT导出失败:', error);
+    proxy?.$modal.msgError('PPT导出失败');
+  }
 };
 
 /** 查看商品详情 */
 const handleView = (row: BaseVO) => {
-  router.push(`/product/base/detail/${row.id}`);
-};
-
-/** 编辑商品 */
-const handleUpdate = (row: BaseVO) => {
-  router.push(`/product/base/edit/${row.id}`);
+  const url = `https://item.xiaoluwebsite.xyz/item?id=${row.id}`;
+  window.open(url, '_blank');
 };
 
 /** 上下架操作 */
@@ -440,6 +628,7 @@ const handleShelf = async (row: BaseVO) => {
   await proxy?.$modal.confirm(`确认${action}该商品吗?`);
 
   try {
+    // 上架:状态改为2(上架中),下架:状态改为0(下架)
     const productStatus = isOnShelf ? 0 : 2;
     await shelfReview({
       id: row.id,
@@ -454,21 +643,27 @@ const handleShelf = async (row: BaseVO) => {
   }
 };
 
-/** 停售操作 */
-const handleDiscontinue = async (row: BaseVO) => {
-  await proxy?.$modal.confirm('确认停售该商品吗?停售后商品将无法正常售卖。');
 
-  try {
-    await changeProductType({
-      id: row.id,
-      productCategory: 3
-    });
-    proxy?.$modal.msgSuccess('停售成功');
-    await getList();
-  } catch (error) {
-    console.error('停售失败:', error);
-    proxy?.$modal.msgError('停售失败');
-  }
+/** 库存修改弹框 */
+const inventoryDialog = reactive({
+  visible: false,
+  loading: false,
+  submitLoading: false
+});
+
+const inventoryFormRef = ref<ElFormInstance>();
+
+const inventoryForm = reactive<PriceInventoryForm>({
+  productId: undefined,
+  totalInventory: undefined,
+  nowInventory: undefined,
+  virtualInventory: undefined
+});
+
+const inventoryRules = {
+  totalInventory: [{ required: true, message: '总库存不能为空', trigger: 'blur' }],
+  nowInventory: [{ required: true, message: '当前可用库存不能为空', trigger: 'blur' }],
+  virtualInventory: [{ required: true, message: '虚拟库存不能为空', trigger: 'blur' }]
 };
 
 /** 打开库存修改弹框 */
@@ -482,10 +677,9 @@ const handleSupply = async (row: BaseVO) => {
   try {
     const res = await getBase(row.id);
     if (res.data) {
-      const data = res.data as any;
-      inventoryForm.totalInventory = data.totalInventory;
-      inventoryForm.nowInventory = data.nowInventory;
-      inventoryForm.virtualInventory = data.virtualInventory;
+      inventoryForm.totalInventory = res.data.totalInventory;
+      inventoryForm.nowInventory = res.data.nowInventory;
+      inventoryForm.virtualInventory = res.data.virtualInventory;
     }
   } catch (error) {
     console.error('获取库存信息失败:', error);
@@ -511,73 +705,105 @@ const submitInventory = async () => {
   }
 };
 
-/** 查询品牌列表(实时请求,每次只加载500条) */
-const getBrandList = async () => {
+/** 停售操作 */
+const handleDiscontinue = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认停售该商品吗?停售后商品将无法正常售卖。');
+
+  try {
+    // 调用停售API,将商品类型改为3(停售商品)
+    await changeProductType({
+      id: row.id,
+      productCategory: 3
+    });
+    proxy?.$modal.msgSuccess('停售成功');
+    await getList();
+  } catch (error) {
+    console.error('停售失败:', error);
+    proxy?.$modal.msgError('停售失败');
+  }
+};
+
+/** 加入自营池操作 */
+const handleAddToSelfPool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入自营池吗?');
+
   try {
-    brandLoading.value = true;
-    const res = await brandList({ pageNum: 1, pageSize: 500 });
-    brandOptions.value = res.data || [];
+    await addProductSelf({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入自营池成功');
+    await getList();
   } catch (error) {
-    console.error('获取品牌列表失败:', error);
-  } finally {
-    brandLoading.value = false;
+    console.error('加入自营池失败:', error);
+    proxy?.$modal.msgError('加入自营池失败');
   }
 };
 
-/** 处理品牌下拉框显示/隐藏 */
-const handleBrandVisibleChange = (visible: boolean) => {
-  if (visible && brandOptions.value.length === 0) {
-    getBrandList();
+/** 加入精品池操作 */
+const handleAddToExquisitePool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入精品池吗?');
+
+  try {
+    await addProductExquisite({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入精品池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入精品池失败:', error);
+    proxy?.$modal.msgError('加入精品池失败');
   }
 };
 
+/** 跳转到商品审核页面 */
+const handleGoReview = () => {
+  router.push({
+    path: '/product/base/review',
+    query: {
+      productReviewStatus: 1 // 默认显示待审核的商品
+    }
+  });
+};
+
 /** 查询分类树 */
 const getCategoryTree = async () => {
   const res = await categoryTree();
   categoryOptions.value = res.data || [];
 };
 
-onMounted(() => {
-  getCategoryTree();
-  initRouteParams();
-  getList();
-});
-</script>
-
-<style scoped lang="scss">
-.app-container {
-  padding: 8px;
-  height: calc(100vh - 84px);
-  display: flex;
-  flex-direction: column;
-  overflow: hidden;
-}
-
-.table-card {
-  flex: 1;
-  display: flex;
-  flex-direction: column;
-  overflow: hidden;
-
-  :deep(.el-card__body) {
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-    overflow: hidden;
+/** 加载品牌选项(默认100条) */
+const loadBrandOptions = async (keyword?: string) => {
+  brandLoading.value = true;
+  try {
+    const res = await listBrand({ pageNum: 1, pageSize: 100, brandName: keyword });
+    brandOptions.value = res.rows || [];
+  } catch (error) {
+    console.error('加载品牌列表失败:', error);
+  } finally {
+    brandLoading.value = false;
   }
+};
 
-  :deep(.el-table) {
-    flex: 1;
-  }
+/** 品牌远程搜索(防抖) */
+const handleBrandSearch = (query: string) => {
+  if (brandSearchTimer) clearTimeout(brandSearchTimer);
+  brandSearchTimer = setTimeout(() => {
+    loadBrandOptions(query || undefined);
+  }, 300);
+};
 
-  // 确保固定列左侧有边框
-  :deep(.el-table__fixed-right) {
-    box-shadow: -1px 0 0 var(--el-table-border-color) !important;
+/** 获取统计信息 */
+const getStatistics = async () => {
+  try {
+    const res = await getProductStatusCount();
+    if (res.data) {
+      statistics.value = res.data;
+    }
+  } catch (error) {
+    console.error('获取统计信息失败:', error);
   }
+};
 
-  // 固定列的单元格左边框
-  :deep(.el-table__fixed-right .el-table__cell) {
-    border-left: 1px solid var(--el-table-border-color) !important;
-  }
-}
-</style>
+
+onMounted(() => {
+  getList();
+  getStatistics();
+  loadBrandOptions();
+});
+</script>

+ 19 - 13
src/views/product/base/shelfReview.vue

@@ -89,41 +89,42 @@
 
       <el-table v-loading="loading" border :data="baseList" :height="tableHeight" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="商品图片" align="center" prop="productImage" width="100" >
+        <el-table-column label="商品编号" align="center" prop="productNo" width="120" >
           <template #default="scope">
-            <image-preview :src="scope.row.productImage" :width="60" :height="60"/>
+            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
           </template>
         </el-table-column>
-        <el-table-column label="商品编号" align="center" prop="productNo" width="120" >
+        <el-table-column label="商品图片" align="center" prop="productImage" width="100" >
           <template #default="scope">
-            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
+            <image-preview :src="scope.row.productImage" :width="60" :height="60"/>
           </template>
         </el-table-column>
         <el-table-column label="商品信息" align="center" min-width="250" show-overflow-tooltip>
           <template #default="scope">
             <div class="text-left">
               <div>{{ 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.brandName || '-' }}</div>
+              <div class="text-gray-500" style="font-size: 12px">
+                分类: {{ scope.row.topCategoryName + '-' + scope.row.topCategoryName + '-' + scope.row.bottomCategoryName }}
+              </div>
             </div>
+
           </template>
         </el-table-column>
         <el-table-column label="基本情况" align="center" width="180">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px;">
-              <div>
-                <span class="text-gray-500">商品分类:</span>
-                <span>{{ scope.row.categoryName || '-' }}</span>
-              </div>
               <div>
                 <span class="text-gray-500">单位:</span>
                 <span>{{ scope.row.unitName || '-' }}</span>
               </div>
+              <div class="text-gray-500" style="font-size: 12px">起订量: {{ scope.row.minOrderQuantity || '-' }}</div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="SKU价格" align="center" width="180">
+        <el-table-column label="价格信息" align="center" width="180">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px;">
+            <div class="text-left" style="font-size: 12px">
               <div>
                 <span class="text-gray-500">市场价:</span>
                 <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
@@ -148,12 +149,17 @@
               </div>
               <div>
                 <span class="text-gray-500">暂估毛利率:</span>
-                <span>{{ scope.row.tempGrossMargin || '0.00' }}%</span>
+                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
               </div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="商品来源" align="center" width="100">
+        <el-table-column label="商品类型" align="center" width="100">
+          <template #default="scope">
+            <span>{{ scope.row.dataSource || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="供应商" align="center" width="100">
           <template #default="scope">
             <span>{{ scope.row.dataSource || '-' }}</span>
           </template>

+ 1971 - 0
src/views/product/baseAudit/add.vue

@@ -0,0 +1,1971 @@
+<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" >
+              <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: 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.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 = String(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 = [];
+      }
+    } 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>

+ 855 - 0
src/views/product/baseAudit/index.vue

@@ -0,0 +1,855 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" label-width="90px">
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品编号" prop="productNo">
+                  <el-input v-model="queryParams.productNo" placeholder="请输入商品编号" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品名称" prop="itemName">
+                  <el-input v-model="queryParams.itemName" placeholder="请输入商品名称" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品品牌" prop="brandId">
+                  <el-select
+                    v-model="queryParams.brandId"
+                    placeholder="请输入品牌名称搜索"
+                    filterable
+                    remote
+                    clearable
+                    :remote-method="handleBrandSearch"
+                    :loading="brandLoading"
+                    style="width: 100%"
+                    @keyup.enter="handleQuery"
+                  >
+                    <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="6">
+                <el-form-item label="商品来源" prop="purchaseNature">
+                  <el-input v-model="queryParams.itemName" placeholder="请输入商品来源" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="是否自营" prop="isSelf">
+                  <el-select v-model="queryParams.isSelf" placeholder="请选择" clearable>
+                    <el-option label="是" :value="1" />
+                    <el-option label="否" :value="0" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="审核状态" prop="productReviewStatus">
+                  <el-select v-model="queryParams.productReviewStatus" placeholder="请选择" clearable>
+                    <el-option label="待采购审核" value="0" />
+                    <el-option label="审核通过" value="1" />
+                    <el-option label="驳回" value="2" />
+                    <el-option label="待营销审核" value="3" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="上下架状态" prop="productStatus">
+                  <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
+                    <el-option label="已上架" :value="1" />
+                    <el-option label="下架" :value="0" />
+                    <el-option label="上架中" :value="2" />
+                    <el-option label="驳回上架" :value="3" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品类型" prop="productStatus">
+                  <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
+                    <el-option label="已上架" :value="1" />
+                    <el-option label="下架" :value="0" />
+                    <el-option label="上架中" :value="2" />
+                    <el-option label="驳回上架" :value="3" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="18">
+                <el-form-item label="商品分类">
+                  <category-cascade-select
+                    ref="categoryCascadeRef"
+                    v-model:top-category-id="queryParams.topCategoryId"
+                    v-model:medium-category-id="queryParams.mediumCategoryId"
+                    v-model:bottom-category-id="queryParams.bottomCategoryId"
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6" class="text-left" style="display: flex; align-items: center; padding-bottom: 18px">
+                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <!-- 统计信息区域 -->
+    <el-card shadow="never" class="mb-[10px]">
+      <div class="flex items-center text-sm text-gray-600">
+        <span>商品总数: </span>
+        <span class="text-blue-600 mx-1"
+          >总=<span class="text-red-600">{{ statistics.total || 0 }}</span
+          >条</span
+        >
+        <span class="mx-2">【上架/总数({{ statistics.onSale || 0 }}/{{ statistics.total || 0 }})】</span>
+        <span class="mx-2"
+          >审核状态: 待审核<span class="text-red-600">{{ statistics.waitAudit || 0 }}</span
+          >条,通过<span class="text-green-600">{{ statistics.auditPass || 0 }}</span
+          >条,驳回<span class="text-orange-600">{{ statistics.auditReject || 0 }}</span
+          >条</span
+        >
+        <span class="mx-2"
+          >上下架状态: 已上架<span class="text-green-600">{{ statistics.onSale || 0 }}</span
+          >条,下架<span class="text-gray-600">{{ statistics.offSale || 0 }}</span
+          >条</span
+        >
+        <div class="ml-auto flex gap-2">
+          <el-button v-if="queryParams.auditStatus === 0" type="primary" icon="Plus" @click="handleAdd">商品新增</el-button>
+          <el-button plain icon="Download" @click="handleExport">导出</el-button>
+          <el-button circle icon="Refresh" @click="getList"></el-button>
+        </div>
+      </div>
+    </el-card>
+
+    <el-card shadow="never">
+      <el-table v-loading="loading" border :data="baseList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="商品编号" align="center" prop="productNo" width="120" fixed="left">
+          <template #default="scope">
+            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productBaseVo.productNo }}</el-link>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品图片" align="center" prop="productImage" width="100">
+          <template #default="scope">
+            <image-preview :src="scope.row.productBaseVo.productImage" :width="60" :height="60" />
+          </template>
+        </el-table-column>
+        <el-table-column label="商品信息" align="center" min-width="250">
+          <template #default="scope">
+            <div class="text-left">
+              <div style="white-space: normal; word-break: break-all; line-height: 1.4">{{ scope.row.productBaseVo.itemName }}</div>
+              <div class="text-gray-500" style="font-size: 12px">品牌: {{ scope.row.productBaseVo.brandName || '-' }}</div>
+              <div class="text-gray-500" style="font-size: 12px">分类: {{ scope.row.productBaseVo.topCategoryName+'-'+scope.row.productBaseVo.mediumCategoryName+'-'+ scope.row.productBaseVo.bottomCategoryName}}</div>
+            </div>
+          </template>
+        </el-table-column>
+        <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.productBaseVo.unitName || '-' }}</div>
+              <div class="text-gray-500" style="font-size: 12px">起订量: {{ scope.row.productBaseVo.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>
+                <span class="text-gray-500">市场价:</span>
+                <span class="text-red-500">¥{{ scope.row.productBaseVo.marketPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">官网价:</span>
+                <span class="text-red-500">¥{{ scope.row.productBaseVo.memberPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">最低价:</span>
+                <span class="text-red-500">¥{{ scope.row.productBaseVo.minSellingPrice || '0.00' }}</span>
+              </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>
+                <span class="text-gray-500">采购价:</span>
+                <span>¥{{ scope.row.productBaseVo.purchasingPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">暂估毛利率:</span>
+                <span>{{ scope.row.productBaseVo.memberPrice ? (((scope.row.productBaseVo.memberPrice - (scope.row.productBaseVo.purchasingPrice || 0)) / scope.row.productBaseVo.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+<!--        <el-table-column label="数据来源" align="center" prop="dataSource" width="80">-->
+<!--          <template #default="scope">-->
+<!--            <span>{{ scope.row.productBaseVo.dataSource || '-' }}</span>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+        <el-table-column label="审核状态" align="center" prop="productReviewStatus" width="90">
+          <template #default="scope">
+            <span v-if="scope.row.auditStatus === 0">待提交</span>
+            <span v-else-if="scope.row.auditStatus === 1">待审核</span>
+            <span v-else-if="scope.row.auditStatus === 2">审核通过</span>
+            <span v-else-if="scope.row.auditStatus === 3">审核驳回</span>
+            <span v-else-if="scope.row.auditStatus === 4">待审核</span>
+            <span v-else-if="scope.row.auditStatus === 5">待审核</span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="审核原因" align="center" prop="auditReason" width="150" fixed="right">
+          <template #default="scope">
+            <span>{{ scope.row.auditReason || '-' }}</span>
+          </template>
+        </el-table-column>
+<!--        <el-table-column label="审核人" align="center" prop="auditUserId" width="80">-->
+<!--          <template #default="scope">-->
+<!--            <span>{{ scope.row.auditUserId || '-' }}</span>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+<!--        <el-table-column label="审核时间" align="center" prop="auditTime" width="120">-->
+<!--          <template #default="scope">-->
+<!--            <span>{{ scope.row.auditTime || '-' }}</span>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+        <el-table-column label="操作" align="center" width="180" fixed="right">
+          <template #default="scope">
+            <div class="flex flex-wrap gap-1 justify-center">
+              <!-- 待提交状态:编辑 + 提交审核 -->
+              <template v-if="scope.row.auditStatus === 0">
+                <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
+                <el-link type="success" :underline="false" @click="handleCommitAudit(scope.row)">提交审核</el-link>
+              </template>
+              <!-- 待审核状态:审核 -->
+              <el-link v-if="scope.row.auditStatus === 1 || scope.row.auditStatus ===4 || scope.row.auditStatus ===5" type="warning" :underline="false" @click="handleAudit(scope.row)">审核</el-link>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 游标分页控制 -->
+      <pagination
+        v-show="baseList.length > 0"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        v-model:way="queryParams.way"
+        :cursor-mode="true"
+        :has-more="hasMore"
+        @pagination="getList"
+      />
+    </el-card>
+    <!-- 审核弹框 -->
+    <el-dialog v-model="auditDialog.visible" title="商品审核" width="480px" :close-on-click-modal="false">
+      <el-form ref="auditFormRef" :model="auditForm" :rules="auditRules" label-width="90px">
+        <el-form-item label="审核结果" prop="auditStatus">
+          <el-radio-group v-model="auditForm.auditStatus">
+            <el-radio value="2">审核通过</el-radio>
+            <el-radio value="3">驳回</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item v-if="auditForm.auditStatus === '3'" label="驳回原因" prop="auditReason">
+          <el-input
+            v-model="auditForm.auditReason"
+            type="textarea"
+            :rows="3"
+            placeholder="请输入驳回原因"
+            maxlength="200"
+            show-word-limit
+          />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="auditDialog.visible = false">取消</el-button>
+        <el-button type="primary" :loading="auditDialog.submitLoading" @click="submitAudit">确定</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 库存修改弹框 -->
+    <el-dialog v-model="inventoryDialog.visible" title="修改库存" width="500px" :close-on-click-modal="false">
+      <div v-loading="inventoryDialog.loading">
+        <el-form ref="inventoryFormRef" :model="inventoryForm" :rules="inventoryRules" label-width="110px">
+          <el-form-item label="虚拟库存" prop="virtualInventory">
+            <el-input-number
+              v-model="inventoryForm.virtualInventory"
+              :min="0"
+              :precision="0"
+              controls-position="right"
+              style="width: 100%"
+              placeholder="请输入虚拟库存"
+            />
+          </el-form-item>
+        </el-form>
+      </div>
+      <template #footer>
+        <el-button @click="inventoryDialog.visible = false">取消</el-button>
+        <el-button type="primary" :loading="inventoryDialog.submitLoading" @click="submitInventory">确定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Base" lang="ts">
+import {
+  listBase,
+  getBase,
+  delBase,
+  brandList,
+  updateBase,
+  shelfReview,
+  changeProductType,
+  getProductStatusCount
+} from '@/api/product/base';
+import { listBaseAudit, auditBaseAudit, commitBaseAudit } from '@/api/product/baseAudit';
+import { ProductAuditForm } from '@/api/product/baseAudit/types';
+import { generatePPT } from '@/utils/pptPlugin';
+import { addProductSelf } from '@/api/product/productSelf';
+import { addProductExquisite } from '@/api/product/productExquisite';
+import { PriceInventoryForm } from '@/api/product/priceInventory/types';
+import { BaseVO, BaseQuery, BaseForm, StatusCountVo } from '@/api/product/base/types';
+import { BaseAuditVO, BaseAuditQuery, BaseAuditForm } from '@/api/product/baseAudit/types';
+import { BrandVO } from '@/api/product/brand/types';
+import { listBrand } from '@/api/product/brand';
+import { useRoute, useRouter } from 'vue-router';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const router = useRouter();
+const route = useRoute();
+
+const baseList = ref<BaseVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const brandOptions = ref<BrandVO[]>([]);
+const brandLoading = ref(false);
+const brandSearchTimer = ref<ReturnType<typeof setTimeout> | null>(null);
+const hasMore = ref(true); // 是否还有更多数据
+// 页面历史记录,存储每页的第一个 id 和最后一个 id,用于支持双向翻页
+const pageHistory = ref([]);
+
+// 三级分类选择组件引用
+const categoryCascadeRef = ref();
+
+// 统计信息
+const statistics = ref<StatusCountVo>({
+  total: 0,
+  onSale: 0,
+  offSale: 0,
+  waitAudit: 0,
+  auditPass: 0,
+  auditReject: 0
+});
+
+const queryFormRef = ref<ElFormInstance>();
+const baseFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: BaseForm = {
+  id: undefined,
+  productNo: undefined,
+  itemName: undefined,
+  brandId: undefined,
+  topCategoryId: undefined,
+  mediumCategoryId: undefined,
+  bottomCategoryId: undefined,
+  unitId: undefined,
+  productImage: undefined,
+  isSelf: undefined,
+  productReviewStatus: undefined,
+  homeRecommended: undefined,
+  categoryRecommendation: undefined,
+  cartRecommendation: undefined,
+  recommendedProductOrder: undefined,
+  isPopular: undefined,
+  isNew: undefined,
+  productStatus: undefined,
+  remark: undefined
+};
+const data = reactive<PageData<BaseForm, BaseQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    productNo: undefined,
+    itemName: undefined,
+    brandId: undefined,
+    productTag: undefined,
+    purchaseNature: undefined,
+    supplierType: undefined,
+    supplierNature: undefined,
+    projectOrg: undefined,
+    topCategoryId: undefined,
+    mediumCategoryId: undefined,
+    bottomCategoryId: undefined,
+    isSelf: undefined,
+    productReviewStatus: undefined,
+    productStatus: undefined,
+    lastSeenId: undefined, // 游标分页的lastSeenId
+    way: undefined,
+    type: undefined,
+    auditStatus: undefined,
+    params: {}
+  },
+  rules: {
+    productNo: [{ required: true, message: '产品编号不能为空', trigger: 'blur' }],
+    itemName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
+    brandId: [{ required: true, message: '品牌id不能为空', trigger: 'blur' }],
+    topCategoryId: [{ required: true, message: '顶级分类id不能为空', trigger: 'blur' }],
+    mediumCategoryId: [{ required: true, message: '中级分类id不能为空', trigger: 'blur' }],
+    bottomCategoryId: [{ required: true, message: '底层分类id不能为空', trigger: 'blur' }],
+    unitId: [{ required: true, message: '单位id不能为空', trigger: 'blur' }],
+    productImage: [{ required: true, message: '产品图片URL不能为空', trigger: 'blur' }],
+    productReviewStatus: [{ required: true, message: '产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核不能为空', trigger: 'change' }],
+    homeRecommended: [{ required: true, message: '首页推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    categoryRecommendation: [{ required: true, message: '分类推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    cartRecommendation: [{ required: true, message: '购物车推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    recommendedProductOrder: [{ required: true, message: '推荐产品顺序不能为空', trigger: 'blur' }],
+    isPopular: [{ required: true, message: '是否热门:1=是,0=否不能为空', trigger: 'blur' }],
+    isNew: [{ required: true, message: '是否新品:1=是,0=否不能为空', trigger: 'blur' }],
+    remark: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品基础信息列表 */
+const getList = async () => {
+  loading.value = true;
+  try {
+    initRouteParams();
+    const params = { ...queryParams.value };
+    const currentPageNum = queryParams.value.pageNum;
+
+    // 第一页不需要游标参数
+    if (currentPageNum === 1) {
+      delete params.lastSeenId;
+      delete params.way;
+    } else {
+      // way参数:0=上一页,1=下一页
+      if (queryParams.value.way === 0) {
+        // 上一页:使用目标页(即当前显示页)的firstId
+        const nextPageHistory = pageHistory.value[currentPageNum];
+        if (nextPageHistory) {
+          params.firstSeenId = nextPageHistory.firstId;
+          params.way = 0;
+        }
+      } else {
+        // 下一页:使用前一页的lastId作为lastSeenId
+        const prevPageHistory = pageHistory.value[currentPageNum - 1];
+        if (prevPageHistory) {
+          params.lastSeenId = prevPageHistory.lastId;
+          params.way = 1;
+        }
+      }
+    }
+
+    const res = await listBaseAudit(params);
+    baseList.value = res.rows || [];
+
+    // 判断是否还有更多数据
+    hasMore.value = baseList.value.length === queryParams.value.pageSize;
+
+    // 记录当前页的第一个id和最后一个id
+    if (baseList.value.length > 0) {
+      const firstItem = baseList.value[0];
+      const lastItem = baseList.value[baseList.value.length - 1];
+      //如果长度小于currentPageNum则创建
+
+      if (pageHistory.value.length <= currentPageNum) {
+        pageHistory.value[currentPageNum] = {
+          firstId: firstItem.id,
+          lastId: lastItem.id
+        };
+      }
+    }
+
+    total.value = res.total || 0;
+  } catch (error) {
+    console.error('获取列表失败:', error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 初始化路由参数 */
+const initRouteParams = () => {
+  // 从路由参数中获取筛选条件
+  if (route.query.productReviewStatus) {
+    queryParams.value.productReviewStatus = Number(route.query.productReviewStatus);
+  }
+  if (route.query.brandName) {
+    queryParams.value.brandName = route.query.brandName as string;
+  }
+  if (route.query.bottomCategoryId) {
+    queryParams.value.bottomCategoryId = route.query.bottomCategoryId as string;
+  }
+  if (route.query.isSelf) {
+    queryParams.value.isSelf = Number(route.query.isSelf);
+  }
+  if (route.query.productCategory) {
+    queryParams.value.productCategory = Number(route.query.productCategory);
+  }
+  if (route.query.type !== undefined && route.query.type !== '') {
+    queryParams.value.type = Number(route.query.type);
+  }
+  if (route.query.auditStatus !== undefined && route.query.auditStatus !== '') {
+    queryParams.value.auditStatus = Number(route.query.auditStatus);
+  }
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  baseFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  // 同步查询参数到游标分页参数
+  queryParams.value = {
+    ...queryParams.value,
+    pageNum: 1,
+    productNo: queryParams.value.productNo,
+    itemName: queryParams.value.itemName,
+    brandName: queryParams.value.brandName,
+    bottomCategoryId: queryParams.value.bottomCategoryId,
+    isSelf: queryParams.value.isSelf,
+    productReviewStatus: queryParams.value.productReviewStatus,
+    productStatus: queryParams.value.productStatus,
+    lastSeenId: undefined
+  };
+  pageHistory.value = []; // 重置页面历史
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  // 手动重置分类字段
+  queryParams.value.topCategoryId = undefined;
+  queryParams.value.mediumCategoryId = undefined;
+  queryParams.value.bottomCategoryId = undefined;
+  categoryCascadeRef.value?.reset();
+  queryParams.value.lastSeenId = undefined;
+  pageHistory.value = []; // 重置页面历史
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: BaseVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  router.push('/product/baseAudit/add');
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: BaseVO) => {
+  const _id = row?.id || ids.value[0];
+  router.push(`/product/baseAudit/edit/${_id}`);
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: BaseVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品基础信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delBase(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  // 检查是否有选中的商品
+  if (ids.value.length === 0) {
+    proxy?.$modal.msgWarning('请先选择要导出的商品');
+    return;
+  }
+
+  // 获取选中商品的完整信息
+  const selectedProducts = baseList.value.filter(item => ids.value.includes(item.id));
+
+  if (selectedProducts.length === 0) {
+    proxy?.$modal.msgWarning('未找到选中的商品信息');
+    return;
+  }
+
+  // 转换为 generatePPT 需要的格式
+  const products = selectedProducts.map(item => ({
+    image: item.productImage || item.productImageUrl || '',
+    name: item.itemName || '',
+    code: item.productNo || '',
+    spec: item.specification || item.packagingSpec || '-',
+    price: item.minSellingPrice || item.memberPrice || 0
+  }));
+
+  // 默认模板配置
+  const template = {
+    name: '商品展示方案',
+    title: '商品展示方案',
+    themeColor: '#C00000',
+    itemsPerPage: 1, // 每页1个商品,展示更详细
+    cover: '',
+    logo: ''
+  };
+
+  try {
+    proxy?.$modal.loading('正在生成PPT...');
+    await generatePPT(template, products);
+    proxy?.$modal.closeLoading();
+    proxy?.$modal.msgSuccess('PPT导出成功');
+  } catch (error) {
+    proxy?.$modal.closeLoading();
+    console.error('PPT导出失败:', error);
+    proxy?.$modal.msgError('PPT导出失败');
+  }
+};
+
+/** 查看商品详情 */
+const handleView = (row: BaseVO) => {
+  const url = `https://item.xiaoluwebsite.xyz/item?id=${row.id}`;
+  window.open(url, '_blank');
+};
+
+/** 上下架操作 */
+const handleShelf = async (row: BaseVO) => {
+  const isOnShelf = row.productStatus === 1;
+  const action = isOnShelf ? '下架' : '上架';
+  await proxy?.$modal.confirm(`确认${action}该商品吗?`);
+
+  try {
+    // 上架:状态改为2(上架中),下架:状态改为0(下架)
+    const productStatus = isOnShelf ? 0 : 2;
+    await shelfReview({
+      id: row.id,
+      productStatus: productStatus,
+      shelfComments: `${action}操作`
+    });
+    proxy?.$modal.msgSuccess(`${action}成功`);
+    await getList();
+  } catch (error) {
+    console.error(`${action}失败:`, error);
+    proxy?.$modal.msgError(`${action}失败`);
+  }
+};
+
+/** 价格设置 */
+const handlePrice = (row: BaseVO) => {
+  console.log('设置价格', row);
+  // TODO: 打开价格设置对话框
+};
+
+/** 库存修改弹框 */
+const inventoryDialog = reactive({
+  visible: false,
+  loading: false,
+  submitLoading: false
+});
+
+const inventoryFormRef = ref<ElFormInstance>();
+
+const inventoryForm = reactive<PriceInventoryForm>({
+  productId: undefined,
+  totalInventory: undefined,
+  nowInventory: undefined,
+  virtualInventory: undefined
+});
+
+const inventoryRules = {
+  virtualInventory: [{ required: true, message: '请输入虚拟库存', trigger: 'blur' }]
+};
+
+
+
+/** 提交库存修改 */
+const submitInventory = async () => {
+  await inventoryFormRef.value?.validate();
+  inventoryDialog.submitLoading = true;
+  try {
+    await updateBase({ ...inventoryForm });
+    proxy?.$modal.msgSuccess('库存修改成功');
+    inventoryDialog.visible = false;
+    await getList();
+  } catch (error) {
+    console.error('库存修改失败:', error);
+    proxy?.$modal.msgError('库存修改失败');
+  } finally {
+    inventoryDialog.submitLoading = false;
+  }
+};
+
+/** 停售操作 */
+const handleDiscontinue = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认停售该商品吗?停售后商品将无法正常售卖。');
+
+  try {
+    // 调用停售API,将商品类型改为3(停售商品)
+    await changeProductType({
+      id: row.id,
+      productCategory: 3
+    });
+    proxy?.$modal.msgSuccess('停售成功');
+    await getList();
+  } catch (error) {
+    console.error('停售失败:', error);
+    proxy?.$modal.msgError('停售失败');
+  }
+};
+
+/** 加入自营池操作 */
+const handleAddToSelfPool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入自营池吗?');
+
+  try {
+    await addProductSelf({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入自营池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入自营池失败:', error);
+    proxy?.$modal.msgError('加入自营池失败');
+  }
+};
+
+/** 加入精品池操作 */
+const handleAddToExquisitePool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入精品池吗?');
+
+  try {
+    await addProductExquisite({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入精品池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入精品池失败:', error);
+    proxy?.$modal.msgError('加入精品池失败');
+  }
+};
+
+
+/** 审核弹框 */
+const auditDialog = reactive({
+  visible: false,
+  submitLoading: false
+});
+
+const auditFormRef = ref<ElFormInstance>();
+
+const auditForm = reactive<ProductAuditForm>({
+  ids: [],
+  auditStatus: undefined,
+  auditReason: undefined
+});
+
+const auditRules = {
+  auditStatus: [{ required: true, message: '请选择审核结果', trigger: 'change' }],
+  auditReason: [{ required: true, message: '请输入驳回原因', trigger: 'blur' }]
+};
+
+/** 提交审核 */
+const handleCommitAudit = async (row: BaseAuditVO) => {
+  await proxy?.$modal.confirm('确认提交该商品进行审核吗?');
+  try {
+    await commitBaseAudit({ id: row.id, productId: row.productId });
+    proxy?.$modal.msgSuccess('提交审核成功');
+    await getList();
+  } catch (error) {
+    console.error('提交审核失败:', error);
+  }
+};
+
+/** 打开审核弹框 */
+const handleAudit = (row: BaseAuditVO) => {
+  auditForm.ids = [row.id];
+  auditForm.auditStatus = undefined;
+  auditForm.auditReason = undefined;
+  auditFormRef.value?.resetFields();
+  auditDialog.visible = true;
+};
+
+/** 提交审核结果 */
+const submitAudit = async () => {
+  await auditFormRef.value?.validate();
+  auditDialog.submitLoading = true;
+  try {
+    await auditBaseAudit({ ...auditForm });
+    proxy?.$modal.msgSuccess('审核操作成功');
+    auditDialog.visible = false;
+    await getList();
+  } catch (error) {
+    console.error('审核操作失败:', error);
+  } finally {
+    auditDialog.submitLoading = false;
+  }
+};
+
+/** 修改库存(占位,避免TS报错) */
+const handleSupply = (row: BaseAuditVO) => {
+  console.log('修改库存', row);
+};
+
+
+
+/** 加载品牌选项(默认100条) */
+const loadBrandOptions = async (keyword?: string) => {
+  brandLoading.value = true;
+  try {
+    const res = await listBrand({ pageNum: 1, pageSize: 100, brandName: keyword });
+    brandOptions.value = res.rows || [];
+  } catch (error) {
+    console.error('加载品牌列表失败:', error);
+  } finally {
+    brandLoading.value = false;
+  }
+};
+
+/** 品牌远程搜索(防抖) */
+const handleBrandSearch = (query: string) => {
+  if (brandSearchTimer.value) clearTimeout(brandSearchTimer.value);
+  brandSearchTimer.value = setTimeout(() => {
+    loadBrandOptions(query || undefined);
+  }, 300);
+};
+
+/** 获取统计信息 */
+const getStatistics = async () => {
+  try {
+    const res = await getProductStatusCount();
+    if (res.data) {
+      statistics.value = res.data;
+    }
+  } catch (error) {
+    console.error('获取统计信息失败:', error);
+  }
+};
+
+onMounted(() => {
+  getList();
+  getStatistics();
+  loadBrandOptions();
+});
+</script>

+ 2 - 2
src/views/product/category/index.vue

@@ -81,7 +81,7 @@
               <el-tree-select
                 v-model="form.parentId"
                 :data="categoryOptions"
-                :props="{ value: 'id', label: 'categoryName', children: 'children' } as any"
+                :props="{ value: 'id', label: 'label', children: 'children' } as any"
                 value-key="id"
                 placeholder="选择上级分类"
                 check-strictly
@@ -365,7 +365,7 @@ const handleSetReviewer = (row: CategoryVO) => {
 /** 审核员选择回调 */
 const handleReviewerSelected = async (users: UserVO[]) => {
   if (!currentReviewerCategory.value || users.length === 0) return;
-  
+
   const user = users[0];
   try {
     await setCategoryReviewer(currentReviewerCategory.value.id, user.userId);

+ 12 - 12
src/views/product/pool/index.vue

@@ -31,20 +31,20 @@
 
 
       <el-table v-loading="loading" border :data="poolList">
-
+        <el-table-column label="编号" align="center" prop="poolNo" />
         <el-table-column label="营销商品池名称" align="center" prop="name" />
-        <!-- <el-table-column label="产品池类型" align="center" prop="type">
+<!--        <el-table-column label="商品数量" align="center" prop="approvedCount" />-->
+        <el-table-column label="创建时间" align="center" prop="createTime" width="180" />
+        <el-table-column label="状态" align="center" prop="isShow">
           <template #default="scope">
-            {{ getPoolTypeLabel(scope.row.type) }}
+            <el-switch
+              v-model="scope.row.isShow"
+              active-value="1"
+              inactive-value="0"
+              @change="handleStatusChange(scope.row)"
+            />
           </template>
-        </el-table-column> -->
-<!--        <el-table-column label="商品数量" align="center" prop="productCount" />-->
-        <el-table-column label="创建时间" align="center" prop="createTime" width="180" />
-        <el-table-column label="备注" align="center" prop="remark" width="180" />
-        <!-- <el-table-column label="待申请" align="center" prop="waitApplyCount" /> -->
-        <!-- <el-table-column label="待审核" align="center" prop="waitReviewCount" /> -->
-        <el-table-column label="商品数量" align="center" prop="approvedCount" />
-        <!-- <el-table-column label="已驳回" align="center" prop="rejectedCount" /> -->
+        </el-table-column>
         <el-table-column label="操作" align="center" width="260">
           <template #default="scope">
             <el-link type="primary" @click="handleModifyPool(scope.row)" v-hasPermi="['product:pool:edit']">修改营销商品池售卖</el-link>
@@ -57,7 +57,7 @@
       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
     </el-card>
     <!-- 添加或修改产品池对话框 -->
-    <el-dialog title="项目/平台商品信息" v-model="dialog.visible" width="500px" append-to-body>
+    <el-dialog title="营销商品池信息" v-model="dialog.visible" width="500px" append-to-body>
       <el-form ref="poolFormRef" :model="form" :rules="rules" label-width="110px">
         <el-form-item label="商品池名称:" prop="name">
           <el-input v-model="form.name" placeholder="办公设备精选池" />

+ 2 - 2
src/views/product/pool/review1.vue

@@ -29,7 +29,7 @@
               </template>
             </el-table-column>
             <el-table-column label="单位" align="center" prop="unitName" width="80" />
-            <el-table-column label="SKU价格" align="center" width="150">
+            <el-table-column label="价格信息" align="center" width="150">
               <template #default="scope">
                 <div class="text-left" style="font-size: 12px;">
                   <div>
@@ -103,7 +103,7 @@
               </template>
             </el-table-column>
             <el-table-column label="单位" align="center" prop="unitName" width="80" />
-            <el-table-column label="SKU价格" align="center" width="150">
+            <el-table-column label="价格信息" align="center" width="150">
               <template #default="scope">
                 <div class="text-left" style="font-size: 12px;">
                   <div>

+ 2 - 2
src/views/product/pool/reviewDetail.vue

@@ -135,7 +135,7 @@
           </template>
         </el-table-column>
         <el-table-column label="单位" align="center" prop="unitName" width="80" />
-        <el-table-column label="SKU价格" align="center" width="150">
+        <el-table-column label="价格信息" align="center" width="150">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px;">
               <div>
@@ -321,7 +321,7 @@
               </div>
             </template>
           </el-table-column>
-          <el-table-column label="SKU价格" align="center" width="150">
+          <el-table-column label="价格信息" align="center" width="150">
             <template #default="scope">
               <div class="text-left" style="font-size: 12px;">
                 <div>

+ 1 - 1
src/views/product/pool/selectedAudit.vue

@@ -112,7 +112,7 @@
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="SKU价格" align="center" width="180">
+        <el-table-column label="价格信息" align="center" width="180">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px">
               <div>

+ 1 - 1
src/views/product/pool/selfAudit.vue

@@ -113,7 +113,7 @@
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="SKU价格" align="center" width="180">
+        <el-table-column label="价格信息" align="center" width="180">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px">
               <div>

+ 3 - 2
src/views/product/poolAudit/index.vue

@@ -361,7 +361,7 @@ const handleSelectionChange = (selection: PoolAuditVO[]) => {
 
 /** 新增按钮操作 */
 const handleAdd = () => {
-  router.push({ path: '/product/poolLinkAudit' });
+  router.push({ path: '/product/poolLinkAudit', query: { type: String(poolType.value) } });
 }
 
 /** 查看按钮操作 */
@@ -378,7 +378,8 @@ const handleView = async (row: PoolAuditVO) => {
 /** 修改按钮操作 */
 const handleUpdate = (row?: PoolAuditVO) => {
   const _id = row?.id || ids.value[0];
-  router.push({ path: '/product/poolLinkAudit', query: { id: _id } });
+  const _type = row?.type !== undefined ? String(row.type) : String(poolType.value);
+  router.push({ path: '/product/poolLinkAudit', query: { id: _id, type: _type } });
 }
 
 /** 去审核 */

+ 860 - 0
src/views/product/poolAudit/itemAudit.vue

@@ -0,0 +1,860 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" label-width="90px">
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品编号" prop="productNo">
+                  <el-input v-model="queryParams.productNo" placeholder="请输入商品编号" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品名称" prop="itemName">
+                  <el-input v-model="queryParams.itemName" placeholder="请输入商品名称" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品品牌" prop="brandId">
+                  <el-select
+                    v-model="queryParams.brandId"
+                    placeholder="请输入品牌名称搜索"
+                    filterable
+                    remote
+                    clearable
+                    :remote-method="handleBrandSearch"
+                    :loading="brandLoading"
+                    style="width: 100%"
+                    @keyup.enter="handleQuery"
+                  >
+                    <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="6">
+                <el-form-item label="上下架状态" prop="productStatus">
+                  <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
+                    <el-option label="已上架" :value="1" />
+                    <el-option label="下架" :value="0" />
+                    <el-option label="上架中" :value="2" />
+                    <el-option label="驳回上架" :value="3" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="项目名称" prop="bottomCategoryId">
+                  <el-tree-select
+                    v-model="queryParams.bottomCategoryId"
+                    :data="categoryOptions"
+                    :props="{ value: 'id', label: 'label', children: 'children' } as any"
+                    value-key="id"
+                    placeholder="请选择商品类型"
+                    clearable
+                    check-strictly
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="18">
+                <el-form-item label="商品分类">
+                  <category-cascade-select
+                    ref="categoryCascadeRef"
+                    v-model:top-category-id="queryParams.topCategoryId"
+                    v-model:medium-category-id="queryParams.mediumCategoryId"
+                    v-model:bottom-category-id="queryParams.bottomCategoryId"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品类型" prop="bottomCategoryId">
+                  <el-tree-select
+                    v-model="queryParams.bottomCategoryId"
+                    :data="categoryOptions"
+                    :props="{ value: 'id', label: 'label', children: 'children' } as any"
+                    value-key="id"
+                    placeholder="请选择商品类型"
+                    clearable
+                    check-strictly
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6" class="text-left">
+                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <!-- 统计信息区域 -->
+    <el-card shadow="never" class="mb-[10px]">
+      <div class="flex items-center text-sm text-gray-600">
+        <span>商品总数: </span>
+        <span class="text-blue-600 mx-1"
+        >总=<span class="text-red-600">{{ statistics.total || 0 }}</span
+        >条</span
+        >
+        <span class="mx-2">【上架/总数({{ statistics.onSale || 0 }}/{{ statistics.total || 0 }})】</span>
+        <span class="mx-2"
+        >审核状态: 待审核<span class="text-red-600">{{ statistics.waitAudit || 0 }}</span
+        >条,通过<span class="text-green-600">{{ statistics.auditPass || 0 }}</span
+        >条,驳回<span class="text-orange-600">{{ statistics.auditReject || 0 }}</span
+        >条</span
+        >
+        <span class="mx-2"
+        >上下架状态: 已上架<span class="text-green-600">{{ statistics.onSale || 0 }}</span
+        >条,下架<span class="text-gray-600">{{ statistics.offSale || 0 }}</span
+        >条</span
+        >
+        <div class="ml-auto flex gap-2">
+          <el-button plain icon="Download" @click="handleExport">导出</el-button>
+          <el-button circle icon="Refresh" @click="getList"></el-button>
+        </div>
+      </div>
+    </el-card>
+
+    <el-card shadow="never">
+      <el-table v-loading="loading" border :data="baseList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="项目名称" align="center" prop="name" width="100" fixed="left"/>
+        <el-table-column label="商品编号" align="center" prop="productNo" width="120" >
+          <template #default="scope">
+            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品图片" align="center" prop="productImage" width="100">
+          <template #default="scope">
+            <image-preview :src="scope.row.productImage" :width="60" :height="60" />
+          </template>
+        </el-table-column>
+        <el-table-column label="商品信息" align="center" min-width="250">
+          <template #default="scope">
+            <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.topCategoryName+'-'+scope.row.mediumCategoryName+'-'+ scope.row.bottomCategoryName}}</div>
+            </div>
+          </template>
+        </el-table-column>
+        <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="120">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px">
+              <div>
+                <span class="text-gray-500">市场价:</span>
+                <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">官网价:</span>
+                <span class="text-red-500">¥{{ scope.row.memberPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">最低价:</span>
+                <span class="text-red-500">¥{{ scope.row.minSellingPrice || '0.00' }}</span>
+              </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>
+                <span class="text-gray-500">采购价:</span>
+                <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">暂估毛利率:</span>
+                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
+              </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>
+                <span class="text-gray-500">协议价:</span>
+                <span>¥{{ scope.row.agreementPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">暂估毛利率:</span>
+                <span>{{ scope.row.agreementPrice ? (((scope.row.agreementPrice - (scope.row.purchasingPrice || 0)) / scope.row.agreementPrice) * 100).toFixed(2) : '0.00' }}%</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品类型" align="center" width="140">
+          <template #default="scope">
+
+          </template>
+        </el-table-column>
+        <el-table-column label="是否自营" align="center" width="80">
+          <template #default="scope">
+            <span v-if="scope.row.isSelf === 1">是</span>
+            <span v-else-if="scope.row.isSelf === 0">否</span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column label="上下架状态" align="center" prop="productStatus" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.productStatus === 1" type="success">已上架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 0" type="warning">下架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 2" type="info">上架中</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="申请类型" align="center" prop="type" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.type === 0" type="success">新增</el-tag>
+            <el-tag v-else-if="scope.row.type === 1" type="warning">移出</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" width="150" fixed="right">
+          <template #default="scope">
+            <div class="flex gap-1 justify-center">
+              <el-link type="primary" :underline="false" @click="handleViewDetail(scope.row)">查看</el-link>
+              <el-link type="success" :underline="false" @click="handleAudit(scope.row)">审核</el-link>
+              <el-link type="danger" :underline="false" @click="handleReject(scope.row)">驳回</el-link>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 游标分页控制 -->
+      <pagination
+        v-show="baseList.length > 0"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        v-model:way="queryParams.way"
+        :cursor-mode="true"
+        :has-more="hasMore"
+        @pagination="getList"
+      />
+    </el-card>
+    <!-- 产品详情抽屉 -->
+    <product-detail-drawer
+      v-model="detailDrawer.visible"
+      :id="detailDrawer.id"
+    />
+
+    <!-- 库存修改弹框 -->
+    <el-dialog v-model="inventoryDialog.visible" title="修改库存" width="500px" :close-on-click-modal="false">
+      <div v-loading="inventoryDialog.loading">
+        <el-form ref="inventoryFormRef" :model="inventoryForm" :rules="inventoryRules" label-width="110px">
+          <el-form-item label="虚拟库存" prop="virtualInventory">
+            <el-input-number
+              v-model="inventoryForm.virtualInventory"
+              :min="0"
+              :precision="0"
+              controls-position="right"
+              style="width: 100%"
+              placeholder="请输入虚拟库存"
+            />
+          </el-form-item>
+        </el-form>
+      </div>
+      <template #footer>
+        <el-button @click="inventoryDialog.visible = false">取消</el-button>
+        <el-button type="primary" :loading="inventoryDialog.submitLoading" @click="submitInventory">确定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Base" lang="ts">
+import ProductDetailDrawer from './ProductDetailDrawer.vue';
+import {
+  getBase,
+  delBase,
+  brandList,
+  updateBase,
+  categoryTree,
+  shelfReview,
+  changeProductType,
+  getProductStatusCount
+} from '@/api/product/base';
+import { selectPoolAuditProductPage, audit } from '@/api/product/poolAudit';
+import { ProductListVO } from '@/api/product/poolAudit/types';
+import { generatePPT } from '@/utils/pptPlugin';
+import { addProductSelf } from '@/api/product/productSelf';
+import { addProductExquisite } from '@/api/product/productExquisite';
+import { PriceInventoryForm } from '@/api/product/priceInventory/types';
+import { BaseVO, BaseQuery, BaseForm, StatusCountVo } from '@/api/product/base/types';
+import { BrandVO } from '@/api/product/brand/types';
+import { listBrand } from '@/api/product/brand';
+import { categoryTreeVO } from '@/api/product/category/types';
+import { useRoute, useRouter } from 'vue-router';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const router = useRouter();
+const route = useRoute();
+
+const baseList = ref<ProductListVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const categoryOptions = ref<categoryTreeVO[]>([]);
+const brandOptions = ref<BrandVO[]>([]);
+const brandLoading = ref(false);
+let brandSearchTimer: ReturnType<typeof setTimeout> | null = null;
+const hasMore = ref(true); // 是否还有更多数据
+// 页面历史记录,存储每页的第一个id和最后一个id,用于支持双向翻页
+const pageHistory = ref([]);
+
+// 分类相关
+const categoryCascadeRef = ref();
+
+// 统计信息
+const statistics = ref<StatusCountVo>({
+  total: 0,
+  onSale: 0,
+  offSale: 0,
+  waitAudit: 0,
+  auditPass: 0,
+  auditReject: 0
+});
+
+const queryFormRef = ref<ElFormInstance>();
+const baseFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: BaseForm = {
+  id: undefined,
+  productNo: undefined,
+  itemName: undefined,
+  brandId: undefined,
+  topCategoryId: undefined,
+  mediumCategoryId: undefined,
+  bottomCategoryId: undefined,
+  unitId: undefined,
+  productImage: undefined,
+  isSelf: undefined,
+  productReviewStatus: undefined,
+  homeRecommended: undefined,
+  categoryRecommendation: undefined,
+  cartRecommendation: undefined,
+  recommendedProductOrder: undefined,
+  isPopular: undefined,
+  isNew: undefined,
+  productStatus: undefined,
+  remark: undefined
+};
+const data = reactive<PageData<BaseForm, BaseQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    productNo: undefined,
+    itemName: undefined,
+    brandId: undefined,
+    productTag: undefined,
+    purchaseNature: undefined,
+    supplierType: undefined,
+    supplierNature: undefined,
+    projectOrg: undefined,
+    topCategoryId: undefined,
+    mediumCategoryId: undefined,
+    bottomCategoryId: undefined,
+    isSelf: 1,
+    productReviewStatus: undefined,
+    productStatus: undefined,
+    lastSeenId: undefined, // 游标分页的lastSeenId
+    way: undefined,
+    params: {}
+  },
+  rules: {
+    productNo: [{ required: true, message: '产品编号不能为空', trigger: 'blur' }],
+    itemName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
+    brandId: [{ required: true, message: '品牌id不能为空', trigger: 'blur' }],
+    topCategoryId: [{ required: true, message: '顶级分类id不能为空', trigger: 'blur' }],
+    mediumCategoryId: [{ required: true, message: '中级分类id不能为空', trigger: 'blur' }],
+    bottomCategoryId: [{ required: true, message: '底层分类id不能为空', trigger: 'blur' }],
+    unitId: [{ required: true, message: '单位id不能为空', trigger: 'blur' }],
+    productImage: [{ required: true, message: '产品图片URL不能为空', trigger: 'blur' }],
+    productReviewStatus: [{ required: true, message: '产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核不能为空', trigger: 'change' }],
+    homeRecommended: [{ required: true, message: '首页推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    categoryRecommendation: [{ required: true, message: '分类推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    cartRecommendation: [{ required: true, message: '购物车推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    recommendedProductOrder: [{ required: true, message: '推荐产品顺序不能为空', trigger: 'blur' }],
+    isPopular: [{ required: true, message: '是否热门:1=是,0=否不能为空', trigger: 'blur' }],
+    isNew: [{ required: true, message: '是否新品:1=是,0=否不能为空', trigger: 'blur' }],
+    remark: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品基础信息列表 */
+const getList = async () => {
+  loading.value = true;
+  try {
+    initRouteParams();
+    const params = { ...queryParams.value };
+    const currentPageNum = queryParams.value.pageNum;
+
+    // 第一页不需要游标参数
+    if (currentPageNum === 1) {
+      delete params.lastSeenId;
+      delete params.way;
+    } else {
+      // way参数:0=上一页,1=下一页
+      if (queryParams.value.way === 0) {
+        // 上一页:使用目标页(即当前显示页)的firstId
+        const nextPageHistory = pageHistory.value[currentPageNum];
+        if (nextPageHistory) {
+          params.firstSeenId = nextPageHistory.firstId;
+          params.way = 0;
+        }
+      } else {
+        // 下一页:使用前一页的lastId作为lastSeenId
+        const prevPageHistory = pageHistory.value[currentPageNum - 1];
+        if (prevPageHistory) {
+          params.lastSeenId = prevPageHistory.lastId;
+          params.way = 1;
+        }
+      }
+    }
+
+    const res = await selectPoolAuditProductPage({ ...params, poolType: 3 }); // 项目产品池
+    baseList.value = res.rows || [];
+
+    // 判断是否还有更多数据
+    hasMore.value = baseList.value.length === queryParams.value.pageSize;
+
+    // 记录当前页的第一个id和最后一个id
+    if (baseList.value.length > 0) {
+      const firstItem = baseList.value[0];
+      const lastItem = baseList.value[baseList.value.length - 1];
+      //如果长度小于currentPageNum则创建
+
+      if (pageHistory.value.length <= currentPageNum) {
+        pageHistory.value[currentPageNum] = {
+          firstId: firstItem.id,
+          lastId: lastItem.id
+        };
+      }
+    }
+
+    total.value = res.total || 0;
+  } catch (error) {
+    console.error('获取列表失败:', error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 初始化路由参数 */
+const initRouteParams = () => {
+  // 从路由参数中获取筛选条件
+  if (route.query.productReviewStatus) {
+    queryParams.value.productReviewStatus = Number(route.query.productReviewStatus);
+  }
+  if (route.query.brandName) {
+    queryParams.value.brandName = route.query.brandName as string;
+  }
+  if (route.query.bottomCategoryId) {
+    queryParams.value.bottomCategoryId = route.query.bottomCategoryId as string;
+  }
+  if (route.query.isSelf) {
+    queryParams.value.isSelf = Number(route.query.isSelf);
+  }
+  if (route.query.productCategory) {
+    queryParams.value.productCategory = Number(route.query.productCategory);
+  }
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  baseFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  // 同步查询参数到游标分页参数
+  queryParams.value = {
+    ...queryParams.value,
+    pageNum: 1,
+    productNo: queryParams.value.productNo,
+    itemName: queryParams.value.itemName,
+    brandName: queryParams.value.brandName,
+    bottomCategoryId: queryParams.value.bottomCategoryId,
+    isSelf: queryParams.value.isSelf,
+    productReviewStatus: queryParams.value.productReviewStatus,
+    productStatus: queryParams.value.productStatus,
+    lastSeenId: undefined
+  };
+  pageHistory.value = []; // 重置页面历史
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  // 手动重置分类字段
+  queryParams.value.topCategoryId = undefined;
+  queryParams.value.mediumCategoryId = undefined;
+  queryParams.value.bottomCategoryId = undefined;
+  categoryCascadeRef.value?.reset();
+  queryParams.value.lastSeenId = undefined;
+  pageHistory.value = []; // 重置页面历史
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: BaseVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  router.push('/product/base/add');
+};
+
+/** 产品详情抽屉 */
+const detailDrawer = reactive({
+  visible: false,
+  id: undefined as string | number | undefined
+});
+
+/** 查看产品详情 */
+const handleViewDetail = (row: ProductListVO) => {
+  detailDrawer.id = row.id;
+  detailDrawer.visible = true;
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: BaseVO) => {
+  const _id = row?.id || ids.value[0];
+  router.push(`/product/base/edit/${_id}`);
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: BaseVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品基础信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delBase(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  // 检查是否有选中的商品
+  if (ids.value.length === 0) {
+    proxy?.$modal.msgWarning('请先选择要导出的商品');
+    return;
+  }
+
+  // 获取选中商品的完整信息
+  const selectedProducts = baseList.value.filter(item => ids.value.includes(item.id));
+
+  if (selectedProducts.length === 0) {
+    proxy?.$modal.msgWarning('未找到选中的商品信息');
+    return;
+  }
+
+  // 转换为 generatePPT 需要的格式
+  const products = selectedProducts.map(item => ({
+    image: item.productImage || item.productImageUrl || '',
+    name: item.itemName || '',
+    code: item.productNo || '',
+    spec: item.specification || item.packagingSpec || '-',
+    price: item.minSellingPrice || item.memberPrice || 0
+  }));
+
+  // 默认模板配置
+  const template = {
+    name: '商品展示方案',
+    title: '商品展示方案',
+    themeColor: '#C00000',
+    itemsPerPage: 1, // 每页1个商品,展示更详细
+    cover: '',
+    logo: ''
+  };
+
+  try {
+    proxy?.$modal.loading('正在生成PPT...');
+    await generatePPT(template, products);
+    proxy?.$modal.closeLoading();
+    proxy?.$modal.msgSuccess('PPT导出成功');
+  } catch (error) {
+    proxy?.$modal.closeLoading();
+    console.error('PPT导出失败:', error);
+    proxy?.$modal.msgError('PPT导出失败');
+  }
+};
+
+/** 查看商品详情 */
+const handleView = (row: BaseVO) => {
+  const url = `https://item.xiaoluwebsite.xyz/item?id=${row.id}`;
+  window.open(url, '_blank');
+};
+
+/** 上下架操作 */
+const handleShelf = async (row: BaseVO) => {
+  const isOnShelf = row.productStatus === 1;
+  const action = isOnShelf ? '下架' : '上架';
+  await proxy?.$modal.confirm(`确认${action}该商品吗?`);
+
+  try {
+    // 上架:状态改为2(上架中),下架:状态改为0(下架)
+    const productStatus = isOnShelf ? 0 : 2;
+    await shelfReview({
+      id: row.id,
+      productStatus: productStatus,
+      shelfComments: `${action}操作`
+    });
+    proxy?.$modal.msgSuccess(`${action}成功`);
+    await getList();
+  } catch (error) {
+    console.error(`${action}失败:`, error);
+    proxy?.$modal.msgError(`${action}失败`);
+  }
+};
+
+
+/** 库存修改弹框 */
+const inventoryDialog = reactive({
+  visible: false,
+  loading: false,
+  submitLoading: false
+});
+
+const inventoryFormRef = ref<ElFormInstance>();
+
+const inventoryForm = reactive<PriceInventoryForm>({
+  productId: undefined,
+  totalInventory: undefined,
+  nowInventory: undefined,
+  virtualInventory: undefined
+});
+
+const inventoryRules = {
+  totalInventory: [{ required: true, message: '总库存不能为空', trigger: 'blur' }],
+  nowInventory: [{ required: true, message: '当前可用库存不能为空', trigger: 'blur' }],
+  virtualInventory: [{ required: true, message: '虚拟库存不能为空', trigger: 'blur' }]
+};
+
+/** 打开库存修改弹框 */
+const handleSupply = async (row: BaseVO) => {
+  inventoryForm.id = row.id;
+  inventoryForm.totalInventory = undefined;
+  inventoryForm.nowInventory = undefined;
+  inventoryForm.virtualInventory = undefined;
+  inventoryDialog.loading = true;
+  inventoryDialog.visible = true;
+  try {
+    const res = await getBase(row.id);
+    if (res.data) {
+      inventoryForm.totalInventory = res.data.totalInventory;
+      inventoryForm.nowInventory = res.data.nowInventory;
+      inventoryForm.virtualInventory = res.data.virtualInventory;
+    }
+  } catch (error) {
+    console.error('获取库存信息失败:', error);
+  } finally {
+    inventoryDialog.loading = false;
+  }
+};
+
+/** 提交库存修改 */
+const submitInventory = async () => {
+  await inventoryFormRef.value?.validate();
+  inventoryDialog.submitLoading = true;
+  try {
+    await updateBase({ ...inventoryForm });
+    proxy?.$modal.msgSuccess('库存修改成功');
+    inventoryDialog.visible = false;
+    await getList();
+  } catch (error) {
+    console.error('库存修改失败:', error);
+    proxy?.$modal.msgError('库存修改失败');
+  } finally {
+    inventoryDialog.submitLoading = false;
+  }
+};
+
+/** 停售操作 */
+const handleDiscontinue = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认停售该商品吗?停售后商品将无法正常售卖。');
+
+  try {
+    // 调用停售API,将商品类型改为3(停售商品)
+    await changeProductType({
+      id: row.id,
+      productCategory: 3
+    });
+    proxy?.$modal.msgSuccess('停售成功');
+    await getList();
+  } catch (error) {
+    console.error('停售失败:', error);
+    proxy?.$modal.msgError('停售失败');
+  }
+};
+
+/** 加入自营池操作 */
+const handleAddToSelfPool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入自营池吗?');
+
+  try {
+    await addProductSelf({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入自营池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入自营池失败:', error);
+    proxy?.$modal.msgError('加入自营池失败');
+  }
+};
+
+/** 加入精品池操作 */
+const handleAddToExquisitePool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入精品池吗?');
+
+  try {
+    await addProductExquisite({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入精品池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入精品池失败:', error);
+    proxy?.$modal.msgError('加入精品池失败');
+  }
+};
+
+/** 审核通过 */
+const handleAudit = async (row: ProductListVO) => {
+  if (!row.poolAuditId) {
+    proxy?.$modal.msgWarning('该商品未关联入池单,无法审核');
+    return;
+  }
+  await proxy?.$modal.confirm(`确认审核通过商品"${row.itemName}"吗?`);
+  try {
+    await audit({
+      poolAuditId: row.poolAuditId,
+      productIds: [row.productId],
+      auditStatus: 2
+    });
+    proxy?.$modal.msgSuccess('审核通过成功');
+    await getList();
+  } catch (error) {
+    console.error('审核失败:', error);
+  }
+};
+
+/** 驳回 */
+const handleReject = async (row: ProductListVO) => {
+  if (!row.poolAuditId) {
+    proxy?.$modal.msgWarning('该商品未关联入池单,无法驳回');
+    return;
+  }
+  try {
+    const { value: reason } = await ElMessageBox.prompt('请输入驳回原因', '驳回', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      inputPlaceholder: '请输入驳回原因',
+      inputValidator: (val) => (val && val.trim() ? true : '驳回原因不能为空')
+    });
+    await audit({
+      poolAuditId: row.poolAuditId,
+      productIds: [row.productId],
+      auditStatus: 3,
+      reason: reason.trim()
+    });
+    proxy?.$modal.msgSuccess('驳回成功');
+    await getList();
+  } catch (error: any) {
+    if (error !== 'cancel') {
+      console.error('驳回失败:', error);
+    }
+  }
+};
+
+/** 跳转到商品审核页面 */
+const handleGoReview = () => {
+  router.push({
+    path: '/product/base/review',
+    query: {
+      productReviewStatus: 1 // 默认显示待审核的商品
+    }
+  });
+};
+
+/** 查询分类树 */
+const getCategoryTree = async () => {
+  const res = await categoryTree();
+  categoryOptions.value = res.data || [];
+};
+
+/** 加载品牌选项(默认100条) */
+const loadBrandOptions = async (keyword?: string) => {
+  brandLoading.value = true;
+  try {
+    const res = await listBrand({ pageNum: 1, pageSize: 100, brandName: keyword });
+    brandOptions.value = res.rows || [];
+  } catch (error) {
+    console.error('加载品牌列表失败:', error);
+  } finally {
+    brandLoading.value = false;
+  }
+};
+
+/** 品牌远程搜索(防抖) */
+const handleBrandSearch = (query: string) => {
+  if (brandSearchTimer) clearTimeout(brandSearchTimer);
+  brandSearchTimer = setTimeout(() => {
+    loadBrandOptions(query || undefined);
+  }, 300);
+};
+
+/** 获取统计信息 */
+const getStatistics = async () => {
+  try {
+    const res = await getProductStatusCount();
+    if (res.data) {
+      statistics.value = res.data;
+    }
+  } catch (error) {
+    console.error('获取统计信息失败:', error);
+  }
+};
+
+
+onMounted(() => {
+  getList();
+  getStatistics();
+  loadBrandOptions();
+});
+</script>

+ 845 - 0
src/views/product/poolAudit/marketingAudit.vue

@@ -0,0 +1,845 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" label-width="90px">
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品编号" prop="productNo">
+                  <el-input v-model="queryParams.productNo" placeholder="请输入商品编号" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品名称" prop="itemName">
+                  <el-input v-model="queryParams.itemName" placeholder="请输入商品名称" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品品牌" prop="brandId">
+                  <el-select
+                    v-model="queryParams.brandId"
+                    placeholder="请输入品牌名称搜索"
+                    filterable
+                    remote
+                    clearable
+                    :remote-method="handleBrandSearch"
+                    :loading="brandLoading"
+                    style="width: 100%"
+                    @keyup.enter="handleQuery"
+                  >
+                    <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="6">
+                <el-form-item label="上下架状态" prop="productStatus">
+                  <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
+                    <el-option label="已上架" :value="1" />
+                    <el-option label="下架" :value="0" />
+                    <el-option label="上架中" :value="2" />
+                    <el-option label="驳回上架" :value="3" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品类型" prop="bottomCategoryId">
+                  <el-tree-select
+                    v-model="queryParams.bottomCategoryId"
+                    :data="categoryOptions"
+                    :props="{ value: 'id', label: 'label', children: 'children' } as any"
+                    value-key="id"
+                    placeholder="请选择商品类型"
+                    clearable
+                    check-strictly
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="18">
+                <el-form-item label="商品分类">
+                  <category-cascade-select
+                    ref="categoryCascadeRef"
+                    v-model:top-category-id="queryParams.topCategoryId"
+                    v-model:medium-category-id="queryParams.mediumCategoryId"
+                    v-model:bottom-category-id="queryParams.bottomCategoryId"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row>
+              <el-col :span="24" class="text-left">
+                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <!-- 统计信息区域 -->
+    <el-card shadow="never" class="mb-[10px]">
+      <div class="flex items-center text-sm text-gray-600">
+        <span>商品总数: </span>
+        <span class="text-blue-600 mx-1"
+        >总=<span class="text-red-600">{{ statistics.total || 0 }}</span
+        >条</span
+        >
+        <span class="mx-2">【上架/总数({{ statistics.onSale || 0 }}/{{ statistics.total || 0 }})】</span>
+        <span class="mx-2"
+        >审核状态: 待审核<span class="text-red-600">{{ statistics.waitAudit || 0 }}</span
+        >条,通过<span class="text-green-600">{{ statistics.auditPass || 0 }}</span
+        >条,驳回<span class="text-orange-600">{{ statistics.auditReject || 0 }}</span
+        >条</span
+        >
+        <span class="mx-2"
+        >上下架状态: 已上架<span class="text-green-600">{{ statistics.onSale || 0 }}</span
+        >条,下架<span class="text-gray-600">{{ statistics.offSale || 0 }}</span
+        >条</span
+        >
+        <div class="ml-auto flex gap-2">
+          <el-button plain icon="Download" @click="handleExport">导出</el-button>
+          <el-button circle icon="Refresh" @click="getList"></el-button>
+        </div>
+      </div>
+    </el-card>
+
+    <el-card shadow="never">
+      <el-table v-loading="loading" border :data="baseList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="入池名称" align="center" prop="name" width="100" fixed="left" />
+        <el-table-column label="商品编号" align="center" prop="productNo" width="120" >
+          <template #default="scope">
+            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品图片" align="center" prop="productImage" width="100">
+          <template #default="scope">
+            <image-preview :src="scope.row.productImage" :width="60" :height="60" />
+          </template>
+        </el-table-column>
+        <el-table-column label="商品信息" align="center" min-width="250">
+          <template #default="scope">
+            <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.topCategoryName+'-'+scope.row.mediumCategoryName+'-'+ scope.row.bottomCategoryName}}</div>
+            </div>
+          </template>
+        </el-table-column>
+        <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="120">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px">
+              <div>
+                <span class="text-gray-500">市场价:</span>
+                <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">官网价:</span>
+                <span class="text-red-500">¥{{ scope.row.memberPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">最低价:</span>
+                <span class="text-red-500">¥{{ scope.row.minSellingPrice || '0.00' }}</span>
+              </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>
+                <span class="text-gray-500">采购价:</span>
+                <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">暂估毛利率:</span>
+                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品类型" align="center" width="140">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px">
+              <div>
+                <span class="text-gray-500">总库存:</span>
+                <span>{{ scope.row.totalInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">可用库存:</span>
+                <span>{{ scope.row.nowInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">虚拟库存:</span>
+                <span>{{ scope.row.virtualInventory ?? '-' }}</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="是否自营" align="center" width="80">
+          <template #default="scope">
+            <span v-if="scope.row.isSelf === 1">是</span>
+            <span v-else-if="scope.row.isSelf === 0">否</span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column label="上下架状态" align="center" prop="productStatus" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.productStatus === 1" type="success">已上架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 0" type="warning">下架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 2" type="info">上架中</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="申请类型" align="center" prop="type" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.type === 0" type="success">新增</el-tag>
+            <el-tag v-else-if="scope.row.type === 1" type="warning">移出</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" width="150" fixed="right">
+          <template #default="scope">
+            <div class="flex gap-1 justify-center">
+              <el-link type="primary" :underline="false" @click="handleViewDetail(scope.row)">查看</el-link>
+              <el-link type="success" :underline="false" @click="handleAudit(scope.row)">审核</el-link>
+              <el-link type="danger" :underline="false" @click="handleReject(scope.row)">驳回</el-link>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 游标分页控制 -->
+      <pagination
+        v-show="baseList.length > 0"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        v-model:way="queryParams.way"
+        :cursor-mode="true"
+        :has-more="hasMore"
+        @pagination="getList"
+      />
+    </el-card>
+    <!-- 产品详情抽屉 -->
+    <product-detail-drawer
+      v-model="detailDrawer.visible"
+      :id="detailDrawer.id"
+    />
+
+    <!-- 库存修改弹框 -->
+    <el-dialog v-model="inventoryDialog.visible" title="修改库存" width="500px" :close-on-click-modal="false">
+      <div v-loading="inventoryDialog.loading">
+        <el-form ref="inventoryFormRef" :model="inventoryForm" :rules="inventoryRules" label-width="110px">
+          <el-form-item label="虚拟库存" prop="virtualInventory">
+            <el-input-number
+              v-model="inventoryForm.virtualInventory"
+              :min="0"
+              :precision="0"
+              controls-position="right"
+              style="width: 100%"
+              placeholder="请输入虚拟库存"
+            />
+          </el-form-item>
+        </el-form>
+      </div>
+      <template #footer>
+        <el-button @click="inventoryDialog.visible = false">取消</el-button>
+        <el-button type="primary" :loading="inventoryDialog.submitLoading" @click="submitInventory">确定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Base" lang="ts">
+import ProductDetailDrawer from './ProductDetailDrawer.vue';
+import {
+  getBase,
+  delBase,
+  brandList,
+  updateBase,
+  categoryTree,
+  shelfReview,
+  changeProductType,
+  getProductStatusCount
+} from '@/api/product/base';
+import { selectPoolAuditProductPage, audit } from '@/api/product/poolAudit';
+import { ProductListVO } from '@/api/product/poolAudit/types';
+import { generatePPT } from '@/utils/pptPlugin';
+import { addProductSelf } from '@/api/product/productSelf';
+import { addProductExquisite } from '@/api/product/productExquisite';
+import { PriceInventoryForm } from '@/api/product/priceInventory/types';
+import { BaseVO, BaseQuery, BaseForm, StatusCountVo } from '@/api/product/base/types';
+import { BrandVO } from '@/api/product/brand/types';
+import { listBrand } from '@/api/product/brand';
+import { categoryTreeVO } from '@/api/product/category/types';
+import { useRoute, useRouter } from 'vue-router';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const router = useRouter();
+const route = useRoute();
+
+const baseList = ref<ProductListVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const categoryOptions = ref<categoryTreeVO[]>([]);
+const brandOptions = ref<BrandVO[]>([]);
+const brandLoading = ref(false);
+let brandSearchTimer: ReturnType<typeof setTimeout> | null = null;
+const hasMore = ref(true); // 是否还有更多数据
+// 页面历史记录,存储每页的第一个id和最后一个id,用于支持双向翻页
+const pageHistory = ref([]);
+
+// 分类相关
+const categoryCascadeRef = ref();
+
+// 统计信息
+const statistics = ref<StatusCountVo>({
+  total: 0,
+  onSale: 0,
+  offSale: 0,
+  waitAudit: 0,
+  auditPass: 0,
+  auditReject: 0
+});
+
+const queryFormRef = ref<ElFormInstance>();
+const baseFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: BaseForm = {
+  id: undefined,
+  productNo: undefined,
+  itemName: undefined,
+  brandId: undefined,
+  topCategoryId: undefined,
+  mediumCategoryId: undefined,
+  bottomCategoryId: undefined,
+  unitId: undefined,
+  productImage: undefined,
+  isSelf: undefined,
+  productReviewStatus: undefined,
+  homeRecommended: undefined,
+  categoryRecommendation: undefined,
+  cartRecommendation: undefined,
+  recommendedProductOrder: undefined,
+  isPopular: undefined,
+  isNew: undefined,
+  productStatus: undefined,
+  remark: undefined
+};
+const data = reactive<PageData<BaseForm, BaseQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    productNo: undefined,
+    itemName: undefined,
+    brandId: undefined,
+    productTag: undefined,
+    purchaseNature: undefined,
+    supplierType: undefined,
+    supplierNature: undefined,
+    projectOrg: undefined,
+    topCategoryId: undefined,
+    mediumCategoryId: undefined,
+    bottomCategoryId: undefined,
+    isSelf: 1,
+    productReviewStatus: undefined,
+    productStatus: undefined,
+    lastSeenId: undefined, // 游标分页的lastSeenId
+    way: undefined,
+    params: {}
+  },
+  rules: {
+    productNo: [{ required: true, message: '产品编号不能为空', trigger: 'blur' }],
+    itemName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
+    brandId: [{ required: true, message: '品牌id不能为空', trigger: 'blur' }],
+    topCategoryId: [{ required: true, message: '顶级分类id不能为空', trigger: 'blur' }],
+    mediumCategoryId: [{ required: true, message: '中级分类id不能为空', trigger: 'blur' }],
+    bottomCategoryId: [{ required: true, message: '底层分类id不能为空', trigger: 'blur' }],
+    unitId: [{ required: true, message: '单位id不能为空', trigger: 'blur' }],
+    productImage: [{ required: true, message: '产品图片URL不能为空', trigger: 'blur' }],
+    productReviewStatus: [{ required: true, message: '产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核不能为空', trigger: 'change' }],
+    homeRecommended: [{ required: true, message: '首页推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    categoryRecommendation: [{ required: true, message: '分类推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    cartRecommendation: [{ required: true, message: '购物车推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    recommendedProductOrder: [{ required: true, message: '推荐产品顺序不能为空', trigger: 'blur' }],
+    isPopular: [{ required: true, message: '是否热门:1=是,0=否不能为空', trigger: 'blur' }],
+    isNew: [{ required: true, message: '是否新品:1=是,0=否不能为空', trigger: 'blur' }],
+    remark: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品基础信息列表 */
+const getList = async () => {
+  loading.value = true;
+  try {
+    initRouteParams();
+    const params = { ...queryParams.value };
+    const currentPageNum = queryParams.value.pageNum;
+
+    // 第一页不需要游标参数
+    if (currentPageNum === 1) {
+      delete params.lastSeenId;
+      delete params.way;
+    } else {
+      // way参数:0=上一页,1=下一页
+      if (queryParams.value.way === 0) {
+        // 上一页:使用目标页(即当前显示页)的firstId
+        const nextPageHistory = pageHistory.value[currentPageNum];
+        if (nextPageHistory) {
+          params.firstSeenId = nextPageHistory.firstId;
+          params.way = 0;
+        }
+      } else {
+        // 下一页:使用前一页的lastId作为lastSeenId
+        const prevPageHistory = pageHistory.value[currentPageNum - 1];
+        if (prevPageHistory) {
+          params.lastSeenId = prevPageHistory.lastId;
+          params.way = 1;
+        }
+      }
+    }
+
+    const res = await selectPoolAuditProductPage({ ...params, poolType: 4 }); // 营销产品池
+    baseList.value = res.rows || [];
+
+    // 判断是否还有更多数据
+    hasMore.value = baseList.value.length === queryParams.value.pageSize;
+
+    // 记录当前页的第一个id和最后一个id
+    if (baseList.value.length > 0) {
+      const firstItem = baseList.value[0];
+      const lastItem = baseList.value[baseList.value.length - 1];
+      //如果长度小于currentPageNum则创建
+
+      if (pageHistory.value.length <= currentPageNum) {
+        pageHistory.value[currentPageNum] = {
+          firstId: firstItem.id,
+          lastId: lastItem.id
+        };
+      }
+    }
+
+    total.value = res.total || 0;
+  } catch (error) {
+    console.error('获取列表失败:', error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 初始化路由参数 */
+const initRouteParams = () => {
+  // 从路由参数中获取筛选条件
+  if (route.query.productReviewStatus) {
+    queryParams.value.productReviewStatus = Number(route.query.productReviewStatus);
+  }
+  if (route.query.brandName) {
+    queryParams.value.brandName = route.query.brandName as string;
+  }
+  if (route.query.bottomCategoryId) {
+    queryParams.value.bottomCategoryId = route.query.bottomCategoryId as string;
+  }
+  if (route.query.isSelf) {
+    queryParams.value.isSelf = Number(route.query.isSelf);
+  }
+  if (route.query.productCategory) {
+    queryParams.value.productCategory = Number(route.query.productCategory);
+  }
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  baseFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  // 同步查询参数到游标分页参数
+  queryParams.value = {
+    ...queryParams.value,
+    pageNum: 1,
+    productNo: queryParams.value.productNo,
+    itemName: queryParams.value.itemName,
+    brandName: queryParams.value.brandName,
+    bottomCategoryId: queryParams.value.bottomCategoryId,
+    isSelf: queryParams.value.isSelf,
+    productReviewStatus: queryParams.value.productReviewStatus,
+    productStatus: queryParams.value.productStatus,
+    lastSeenId: undefined
+  };
+  pageHistory.value = []; // 重置页面历史
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  // 手动重置分类字段
+  queryParams.value.topCategoryId = undefined;
+  queryParams.value.mediumCategoryId = undefined;
+  queryParams.value.bottomCategoryId = undefined;
+  categoryCascadeRef.value?.reset();
+  queryParams.value.lastSeenId = undefined;
+  pageHistory.value = []; // 重置页面历史
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: BaseVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  router.push('/product/base/add');
+};
+
+/** 产品详情抽屉 */
+const detailDrawer = reactive({
+  visible: false,
+  id: undefined as string | number | undefined
+});
+
+/** 查看产品详情 */
+const handleViewDetail = (row: ProductListVO) => {
+  detailDrawer.id = row.id;
+  detailDrawer.visible = true;
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: BaseVO) => {
+  const _id = row?.id || ids.value[0];
+  router.push(`/product/base/edit/${_id}`);
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: BaseVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品基础信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delBase(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  // 检查是否有选中的商品
+  if (ids.value.length === 0) {
+    proxy?.$modal.msgWarning('请先选择要导出的商品');
+    return;
+  }
+
+  // 获取选中商品的完整信息
+  const selectedProducts = baseList.value.filter(item => ids.value.includes(item.id));
+
+  if (selectedProducts.length === 0) {
+    proxy?.$modal.msgWarning('未找到选中的商品信息');
+    return;
+  }
+
+  // 转换为 generatePPT 需要的格式
+  const products = selectedProducts.map(item => ({
+    image: item.productImage || item.productImageUrl || '',
+    name: item.itemName || '',
+    code: item.productNo || '',
+    spec: item.specification || item.packagingSpec || '-',
+    price: item.minSellingPrice || item.memberPrice || 0
+  }));
+
+  // 默认模板配置
+  const template = {
+    name: '商品展示方案',
+    title: '商品展示方案',
+    themeColor: '#C00000',
+    itemsPerPage: 1, // 每页1个商品,展示更详细
+    cover: '',
+    logo: ''
+  };
+
+  try {
+    proxy?.$modal.loading('正在生成PPT...');
+    await generatePPT(template, products);
+    proxy?.$modal.closeLoading();
+    proxy?.$modal.msgSuccess('PPT导出成功');
+  } catch (error) {
+    proxy?.$modal.closeLoading();
+    console.error('PPT导出失败:', error);
+    proxy?.$modal.msgError('PPT导出失败');
+  }
+};
+
+/** 查看商品详情 */
+const handleView = (row: BaseVO) => {
+  const url = `https://item.xiaoluwebsite.xyz/item?id=${row.id}`;
+  window.open(url, '_blank');
+};
+
+/** 上下架操作 */
+const handleShelf = async (row: BaseVO) => {
+  const isOnShelf = row.productStatus === 1;
+  const action = isOnShelf ? '下架' : '上架';
+  await proxy?.$modal.confirm(`确认${action}该商品吗?`);
+
+  try {
+    // 上架:状态改为2(上架中),下架:状态改为0(下架)
+    const productStatus = isOnShelf ? 0 : 2;
+    await shelfReview({
+      id: row.id,
+      productStatus: productStatus,
+      shelfComments: `${action}操作`
+    });
+    proxy?.$modal.msgSuccess(`${action}成功`);
+    await getList();
+  } catch (error) {
+    console.error(`${action}失败:`, error);
+    proxy?.$modal.msgError(`${action}失败`);
+  }
+};
+
+
+/** 库存修改弹框 */
+const inventoryDialog = reactive({
+  visible: false,
+  loading: false,
+  submitLoading: false
+});
+
+const inventoryFormRef = ref<ElFormInstance>();
+
+const inventoryForm = reactive<PriceInventoryForm>({
+  productId: undefined,
+  totalInventory: undefined,
+  nowInventory: undefined,
+  virtualInventory: undefined
+});
+
+const inventoryRules = {
+  totalInventory: [{ required: true, message: '总库存不能为空', trigger: 'blur' }],
+  nowInventory: [{ required: true, message: '当前可用库存不能为空', trigger: 'blur' }],
+  virtualInventory: [{ required: true, message: '虚拟库存不能为空', trigger: 'blur' }]
+};
+
+/** 打开库存修改弹框 */
+const handleSupply = async (row: BaseVO) => {
+  inventoryForm.id = row.id;
+  inventoryForm.totalInventory = undefined;
+  inventoryForm.nowInventory = undefined;
+  inventoryForm.virtualInventory = undefined;
+  inventoryDialog.loading = true;
+  inventoryDialog.visible = true;
+  try {
+    const res = await getBase(row.id);
+    if (res.data) {
+      inventoryForm.totalInventory = res.data.totalInventory;
+      inventoryForm.nowInventory = res.data.nowInventory;
+      inventoryForm.virtualInventory = res.data.virtualInventory;
+    }
+  } catch (error) {
+    console.error('获取库存信息失败:', error);
+  } finally {
+    inventoryDialog.loading = false;
+  }
+};
+
+/** 提交库存修改 */
+const submitInventory = async () => {
+  await inventoryFormRef.value?.validate();
+  inventoryDialog.submitLoading = true;
+  try {
+    await updateBase({ ...inventoryForm });
+    proxy?.$modal.msgSuccess('库存修改成功');
+    inventoryDialog.visible = false;
+    await getList();
+  } catch (error) {
+    console.error('库存修改失败:', error);
+    proxy?.$modal.msgError('库存修改失败');
+  } finally {
+    inventoryDialog.submitLoading = false;
+  }
+};
+
+/** 停售操作 */
+const handleDiscontinue = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认停售该商品吗?停售后商品将无法正常售卖。');
+
+  try {
+    // 调用停售API,将商品类型改为3(停售商品)
+    await changeProductType({
+      id: row.id,
+      productCategory: 3
+    });
+    proxy?.$modal.msgSuccess('停售成功');
+    await getList();
+  } catch (error) {
+    console.error('停售失败:', error);
+    proxy?.$modal.msgError('停售失败');
+  }
+};
+
+/** 加入自营池操作 */
+const handleAddToSelfPool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入自营池吗?');
+
+  try {
+    await addProductSelf({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入自营池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入自营池失败:', error);
+    proxy?.$modal.msgError('加入自营池失败');
+  }
+};
+
+/** 加入精品池操作 */
+const handleAddToExquisitePool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入精品池吗?');
+
+  try {
+    await addProductExquisite({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入精品池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入精品池失败:', error);
+    proxy?.$modal.msgError('加入精品池失败');
+  }
+};
+
+/** 审核通过 */
+const handleAudit = async (row: ProductListVO) => {
+  if (!row.poolAuditId) {
+    proxy?.$modal.msgWarning('该商品未关联入池单,无法审核');
+    return;
+  }
+  await proxy?.$modal.confirm(`确认审核通过商品"${row.itemName}"吗?`);
+  try {
+    await audit({
+      poolAuditId: row.poolAuditId,
+      productIds: [row.productId],
+      auditStatus: 2
+    });
+    proxy?.$modal.msgSuccess('审核通过成功');
+    await getList();
+  } catch (error) {
+    console.error('审核失败:', error);
+  }
+};
+
+/** 驳回 */
+const handleReject = async (row: ProductListVO) => {
+  if (!row.poolAuditId) {
+    proxy?.$modal.msgWarning('该商品未关联入池单,无法驳回');
+    return;
+  }
+  try {
+    const { value: reason } = await ElMessageBox.prompt('请输入驳回原因', '驳回', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      inputPlaceholder: '请输入驳回原因',
+      inputValidator: (val) => (val && val.trim() ? true : '驳回原因不能为空')
+    });
+    await audit({
+      poolAuditId: row.poolAuditId,
+      productIds: [row.productId],
+      auditStatus: 3,
+      reason: reason.trim()
+    });
+    proxy?.$modal.msgSuccess('驳回成功');
+    await getList();
+  } catch (error: any) {
+    if (error !== 'cancel') {
+      console.error('驳回失败:', error);
+    }
+  }
+};
+
+/** 跳转到商品审核页面 */
+const handleGoReview = () => {
+  router.push({
+    path: '/product/base/review',
+    query: {
+      productReviewStatus: 1 // 默认显示待审核的商品
+    }
+  });
+};
+
+/** 查询分类树 */
+const getCategoryTree = async () => {
+  const res = await categoryTree();
+  categoryOptions.value = res.data || [];
+};
+
+/** 加载品牌选项(默认100条) */
+const loadBrandOptions = async (keyword?: string) => {
+  brandLoading.value = true;
+  try {
+    const res = await listBrand({ pageNum: 1, pageSize: 100, brandName: keyword });
+    brandOptions.value = res.rows || [];
+  } catch (error) {
+    console.error('加载品牌列表失败:', error);
+  } finally {
+    brandLoading.value = false;
+  }
+};
+
+/** 品牌远程搜索(防抖) */
+const handleBrandSearch = (query: string) => {
+  if (brandSearchTimer) clearTimeout(brandSearchTimer);
+  brandSearchTimer = setTimeout(() => {
+    loadBrandOptions(query || undefined);
+  }, 300);
+};
+
+/** 获取统计信息 */
+const getStatistics = async () => {
+  try {
+    const res = await getProductStatusCount();
+    if (res.data) {
+      statistics.value = res.data;
+    }
+  } catch (error) {
+    console.error('获取统计信息失败:', error);
+  }
+};
+
+
+onMounted(() => {
+  getList();
+  getStatistics();
+  loadBrandOptions();
+});
+</script>

+ 859 - 0
src/views/product/poolAudit/protocolAudit.vue

@@ -0,0 +1,859 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" label-width="90px">
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品编号" prop="productNo">
+                  <el-input v-model="queryParams.productNo" placeholder="请输入商品编号" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品名称" prop="itemName">
+                  <el-input v-model="queryParams.itemName" placeholder="请输入商品名称" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品品牌" prop="brandId">
+                  <el-select
+                    v-model="queryParams.brandId"
+                    placeholder="请输入品牌名称搜索"
+                    filterable
+                    remote
+                    clearable
+                    :remote-method="handleBrandSearch"
+                    :loading="brandLoading"
+                    style="width: 100%"
+                    @keyup.enter="handleQuery"
+                  >
+                    <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="6">
+                <el-form-item label="上下架状态" prop="productStatus">
+                  <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
+                    <el-option label="已上架" :value="1" />
+                    <el-option label="下架" :value="0" />
+                    <el-option label="上架中" :value="2" />
+                    <el-option label="驳回上架" :value="3" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品类型" prop="bottomCategoryId">
+                  <el-tree-select
+                    v-model="queryParams.bottomCategoryId"
+                    :data="categoryOptions"
+                    :props="{ value: 'id', label: 'label', children: 'children' } as any"
+                    value-key="id"
+                    placeholder="请选择商品类型"
+                    clearable
+                    check-strictly
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="18">
+                <el-form-item label="商品分类">
+                  <category-cascade-select
+                    ref="categoryCascadeRef"
+                    v-model:top-category-id="queryParams.topCategoryId"
+                    v-model:medium-category-id="queryParams.mediumCategoryId"
+                    v-model:bottom-category-id="queryParams.bottomCategoryId"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row>
+              <el-col :span="24" class="text-left">
+                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <!-- 统计信息区域 -->
+    <el-card shadow="never" class="mb-[10px]">
+      <div class="flex items-center text-sm text-gray-600">
+        <span>商品总数: </span>
+        <span class="text-blue-600 mx-1"
+        >总=<span class="text-red-600">{{ statistics.total || 0 }}</span
+        >条</span
+        >
+        <span class="mx-2">【上架/总数({{ statistics.onSale || 0 }}/{{ statistics.total || 0 }})】</span>
+        <span class="mx-2"
+        >审核状态: 待审核<span class="text-red-600">{{ statistics.waitAudit || 0 }}</span
+        >条,通过<span class="text-green-600">{{ statistics.auditPass || 0 }}</span
+        >条,驳回<span class="text-orange-600">{{ statistics.auditReject || 0 }}</span
+        >条</span
+        >
+        <span class="mx-2"
+        >上下架状态: 已上架<span class="text-green-600">{{ statistics.onSale || 0 }}</span
+        >条,下架<span class="text-gray-600">{{ statistics.offSale || 0 }}</span
+        >条</span
+        >
+        <div class="ml-auto flex gap-2">
+          <el-button plain icon="Download" @click="handleExport">导出</el-button>
+          <el-button circle icon="Refresh" @click="getList"></el-button>
+        </div>
+      </div>
+    </el-card>
+
+    <el-card shadow="never">
+      <el-table v-loading="loading" border :data="baseList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="客户名称" align="center" prop="name" width="100" fixed="left"/>
+        <el-table-column label="商品编号" align="center" prop="productNo" width="120" >
+          <template #default="scope">
+            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品图片" align="center" prop="productImage" width="100">
+          <template #default="scope">
+            <image-preview :src="scope.row.productImage" :width="60" :height="60" />
+          </template>
+        </el-table-column>
+        <el-table-column label="商品信息" align="center" min-width="250">
+          <template #default="scope">
+            <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.topCategoryName+'-'+scope.row.mediumCategoryName+'-'+ scope.row.bottomCategoryName}}</div>
+            </div>
+          </template>
+        </el-table-column>
+        <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="120">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px">
+              <div>
+                <span class="text-gray-500">市场价:</span>
+                <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">官网价:</span>
+                <span class="text-red-500">¥{{ scope.row.memberPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">最低价:</span>
+                <span class="text-red-500">¥{{ scope.row.minSellingPrice || '0.00' }}</span>
+              </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>
+                <span class="text-gray-500">采购价:</span>
+                <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">暂估毛利率:</span>
+                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
+              </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>
+                <span class="text-gray-500">协议价:</span>
+                <span>¥{{ scope.row.agreementPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">暂估毛利率:</span>
+                <span>{{ scope.row.agreementPrice ? (((scope.row.agreementPrice - (scope.row.purchasingPrice || 0)) / scope.row.agreementPrice) * 100).toFixed(2) : '0.00' }}%</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品类型" align="center" width="140">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px">
+              <div>
+                <span class="text-gray-500">总库存:</span>
+                <span>{{ scope.row.totalInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">可用库存:</span>
+                <span>{{ scope.row.nowInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">虚拟库存:</span>
+                <span>{{ scope.row.virtualInventory ?? '-' }}</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="是否自营" align="center" width="80">
+          <template #default="scope">
+            <span v-if="scope.row.isSelf === 1">是</span>
+            <span v-else-if="scope.row.isSelf === 0">否</span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column label="上下架状态" align="center" prop="productStatus" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.productStatus === 1" type="success">已上架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 0" type="warning">下架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 2" type="info">上架中</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="申请类型" align="center" prop="type" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.type === 0" type="success">新增</el-tag>
+            <el-tag v-else-if="scope.row.type === 1" type="warning">移出</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" width="150" fixed="right">
+          <template #default="scope">
+            <div class="flex gap-1 justify-center">
+              <el-link type="primary" :underline="false" @click="handleViewDetail(scope.row)">查看</el-link>
+              <el-link type="success" :underline="false" @click="handleAudit(scope.row)">审核</el-link>
+              <el-link type="danger" :underline="false" @click="handleReject(scope.row)">驳回</el-link>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 游标分页控制 -->
+      <pagination
+        v-show="baseList.length > 0"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        v-model:way="queryParams.way"
+        :cursor-mode="true"
+        :has-more="hasMore"
+        @pagination="getList"
+      />
+    </el-card>
+    <!-- 产品详情抽屉 -->
+    <product-detail-drawer
+      v-model="detailDrawer.visible"
+      :id="detailDrawer.id"
+    />
+
+    <!-- 库存修改弹框 -->
+    <el-dialog v-model="inventoryDialog.visible" title="修改库存" width="500px" :close-on-click-modal="false">
+      <div v-loading="inventoryDialog.loading">
+        <el-form ref="inventoryFormRef" :model="inventoryForm" :rules="inventoryRules" label-width="110px">
+          <el-form-item label="虚拟库存" prop="virtualInventory">
+            <el-input-number
+              v-model="inventoryForm.virtualInventory"
+              :min="0"
+              :precision="0"
+              controls-position="right"
+              style="width: 100%"
+              placeholder="请输入虚拟库存"
+            />
+          </el-form-item>
+        </el-form>
+      </div>
+      <template #footer>
+        <el-button @click="inventoryDialog.visible = false">取消</el-button>
+        <el-button type="primary" :loading="inventoryDialog.submitLoading" @click="submitInventory">确定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Base" lang="ts">
+import ProductDetailDrawer from './ProductDetailDrawer.vue';
+import {
+  getBase,
+  delBase,
+  brandList,
+  updateBase,
+  categoryTree,
+  shelfReview,
+  changeProductType,
+  getProductStatusCount
+} from '@/api/product/base';
+import { selectPoolAuditProductPage, audit } from '@/api/product/poolAudit';
+import { ProductListVO } from '@/api/product/poolAudit/types';
+import { generatePPT } from '@/utils/pptPlugin';
+import { addProductSelf } from '@/api/product/productSelf';
+import { addProductExquisite } from '@/api/product/productExquisite';
+import { PriceInventoryForm } from '@/api/product/priceInventory/types';
+import { BaseVO, BaseQuery, BaseForm, StatusCountVo } from '@/api/product/base/types';
+import { BrandVO } from '@/api/product/brand/types';
+import { listBrand } from '@/api/product/brand';
+import { categoryTreeVO } from '@/api/product/category/types';
+import { useRoute, useRouter } from 'vue-router';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const router = useRouter();
+const route = useRoute();
+
+const baseList = ref<ProductListVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const categoryOptions = ref<categoryTreeVO[]>([]);
+const brandOptions = ref<BrandVO[]>([]);
+const brandLoading = ref(false);
+let brandSearchTimer: ReturnType<typeof setTimeout> | null = null;
+const hasMore = ref(true); // 是否还有更多数据
+// 页面历史记录,存储每页的第一个id和最后一个id,用于支持双向翻页
+const pageHistory = ref([]);
+
+// 分类相关
+const categoryCascadeRef = ref();
+
+// 统计信息
+const statistics = ref<StatusCountVo>({
+  total: 0,
+  onSale: 0,
+  offSale: 0,
+  waitAudit: 0,
+  auditPass: 0,
+  auditReject: 0
+});
+
+const queryFormRef = ref<ElFormInstance>();
+const baseFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: BaseForm = {
+  id: undefined,
+  productNo: undefined,
+  itemName: undefined,
+  brandId: undefined,
+  topCategoryId: undefined,
+  mediumCategoryId: undefined,
+  bottomCategoryId: undefined,
+  unitId: undefined,
+  productImage: undefined,
+  isSelf: undefined,
+  productReviewStatus: undefined,
+  homeRecommended: undefined,
+  categoryRecommendation: undefined,
+  cartRecommendation: undefined,
+  recommendedProductOrder: undefined,
+  isPopular: undefined,
+  isNew: undefined,
+  productStatus: undefined,
+  remark: undefined
+};
+const data = reactive<PageData<BaseForm, BaseQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    productNo: undefined,
+    itemName: undefined,
+    brandId: undefined,
+    productTag: undefined,
+    purchaseNature: undefined,
+    supplierType: undefined,
+    supplierNature: undefined,
+    projectOrg: undefined,
+    topCategoryId: undefined,
+    mediumCategoryId: undefined,
+    bottomCategoryId: undefined,
+    isSelf: 1,
+    productReviewStatus: undefined,
+    productStatus: undefined,
+    lastSeenId: undefined, // 游标分页的lastSeenId
+    way: undefined,
+    params: {}
+  },
+  rules: {
+    productNo: [{ required: true, message: '产品编号不能为空', trigger: 'blur' }],
+    itemName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
+    brandId: [{ required: true, message: '品牌id不能为空', trigger: 'blur' }],
+    topCategoryId: [{ required: true, message: '顶级分类id不能为空', trigger: 'blur' }],
+    mediumCategoryId: [{ required: true, message: '中级分类id不能为空', trigger: 'blur' }],
+    bottomCategoryId: [{ required: true, message: '底层分类id不能为空', trigger: 'blur' }],
+    unitId: [{ required: true, message: '单位id不能为空', trigger: 'blur' }],
+    productImage: [{ required: true, message: '产品图片URL不能为空', trigger: 'blur' }],
+    productReviewStatus: [{ required: true, message: '产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核不能为空', trigger: 'change' }],
+    homeRecommended: [{ required: true, message: '首页推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    categoryRecommendation: [{ required: true, message: '分类推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    cartRecommendation: [{ required: true, message: '购物车推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    recommendedProductOrder: [{ required: true, message: '推荐产品顺序不能为空', trigger: 'blur' }],
+    isPopular: [{ required: true, message: '是否热门:1=是,0=否不能为空', trigger: 'blur' }],
+    isNew: [{ required: true, message: '是否新品:1=是,0=否不能为空', trigger: 'blur' }],
+    remark: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品基础信息列表 */
+const getList = async () => {
+  loading.value = true;
+  try {
+    initRouteParams();
+    const params = { ...queryParams.value };
+    const currentPageNum = queryParams.value.pageNum;
+
+    // 第一页不需要游标参数
+    if (currentPageNum === 1) {
+      delete params.lastSeenId;
+      delete params.way;
+    } else {
+      // way参数:0=上一页,1=下一页
+      if (queryParams.value.way === 0) {
+        // 上一页:使用目标页(即当前显示页)的firstId
+        const nextPageHistory = pageHistory.value[currentPageNum];
+        if (nextPageHistory) {
+          params.firstSeenId = nextPageHistory.firstId;
+          params.way = 0;
+        }
+      } else {
+        // 下一页:使用前一页的lastId作为lastSeenId
+        const prevPageHistory = pageHistory.value[currentPageNum - 1];
+        if (prevPageHistory) {
+          params.lastSeenId = prevPageHistory.lastId;
+          params.way = 1;
+        }
+      }
+    }
+
+    const res = await selectPoolAuditProductPage({ ...params, poolType: 2 }); // 协议产品池
+    baseList.value = res.rows || [];
+
+    // 判断是否还有更多数据
+    hasMore.value = baseList.value.length === queryParams.value.pageSize;
+
+    // 记录当前页的第一个id和最后一个id
+    if (baseList.value.length > 0) {
+      const firstItem = baseList.value[0];
+      const lastItem = baseList.value[baseList.value.length - 1];
+      //如果长度小于currentPageNum则创建
+
+      if (pageHistory.value.length <= currentPageNum) {
+        pageHistory.value[currentPageNum] = {
+          firstId: firstItem.id,
+          lastId: lastItem.id
+        };
+      }
+    }
+
+    total.value = res.total || 0;
+  } catch (error) {
+    console.error('获取列表失败:', error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 初始化路由参数 */
+const initRouteParams = () => {
+  // 从路由参数中获取筛选条件
+  if (route.query.productReviewStatus) {
+    queryParams.value.productReviewStatus = Number(route.query.productReviewStatus);
+  }
+  if (route.query.brandName) {
+    queryParams.value.brandName = route.query.brandName as string;
+  }
+  if (route.query.bottomCategoryId) {
+    queryParams.value.bottomCategoryId = route.query.bottomCategoryId as string;
+  }
+  if (route.query.isSelf) {
+    queryParams.value.isSelf = Number(route.query.isSelf);
+  }
+  if (route.query.productCategory) {
+    queryParams.value.productCategory = Number(route.query.productCategory);
+  }
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  baseFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  // 同步查询参数到游标分页参数
+  queryParams.value = {
+    ...queryParams.value,
+    pageNum: 1,
+    productNo: queryParams.value.productNo,
+    itemName: queryParams.value.itemName,
+    brandName: queryParams.value.brandName,
+    bottomCategoryId: queryParams.value.bottomCategoryId,
+    isSelf: queryParams.value.isSelf,
+    productReviewStatus: queryParams.value.productReviewStatus,
+    productStatus: queryParams.value.productStatus,
+    lastSeenId: undefined
+  };
+  pageHistory.value = []; // 重置页面历史
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  // 手动重置分类字段
+  queryParams.value.topCategoryId = undefined;
+  queryParams.value.mediumCategoryId = undefined;
+  queryParams.value.bottomCategoryId = undefined;
+  categoryCascadeRef.value?.reset();
+  queryParams.value.lastSeenId = undefined;
+  pageHistory.value = []; // 重置页面历史
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: BaseVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  router.push('/product/base/add');
+};
+
+/** 产品详情抽屉 */
+const detailDrawer = reactive({
+  visible: false,
+  id: undefined as string | number | undefined
+});
+
+/** 查看产品详情 */
+const handleViewDetail = (row: ProductListVO) => {
+  detailDrawer.id = row.id;
+  detailDrawer.visible = true;
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: BaseVO) => {
+  const _id = row?.id || ids.value[0];
+  router.push(`/product/base/edit/${_id}`);
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: BaseVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品基础信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delBase(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  // 检查是否有选中的商品
+  if (ids.value.length === 0) {
+    proxy?.$modal.msgWarning('请先选择要导出的商品');
+    return;
+  }
+
+  // 获取选中商品的完整信息
+  const selectedProducts = baseList.value.filter(item => ids.value.includes(item.id));
+
+  if (selectedProducts.length === 0) {
+    proxy?.$modal.msgWarning('未找到选中的商品信息');
+    return;
+  }
+
+  // 转换为 generatePPT 需要的格式
+  const products = selectedProducts.map(item => ({
+    image: item.productImage || item.productImageUrl || '',
+    name: item.itemName || '',
+    code: item.productNo || '',
+    spec: item.specification || item.packagingSpec || '-',
+    price: item.minSellingPrice || item.memberPrice || 0
+  }));
+
+  // 默认模板配置
+  const template = {
+    name: '商品展示方案',
+    title: '商品展示方案',
+    themeColor: '#C00000',
+    itemsPerPage: 1, // 每页1个商品,展示更详细
+    cover: '',
+    logo: ''
+  };
+
+  try {
+    proxy?.$modal.loading('正在生成PPT...');
+    await generatePPT(template, products);
+    proxy?.$modal.closeLoading();
+    proxy?.$modal.msgSuccess('PPT导出成功');
+  } catch (error) {
+    proxy?.$modal.closeLoading();
+    console.error('PPT导出失败:', error);
+    proxy?.$modal.msgError('PPT导出失败');
+  }
+};
+
+/** 查看商品详情 */
+const handleView = (row: BaseVO) => {
+  const url = `https://item.xiaoluwebsite.xyz/item?id=${row.id}`;
+  window.open(url, '_blank');
+};
+
+/** 上下架操作 */
+const handleShelf = async (row: BaseVO) => {
+  const isOnShelf = row.productStatus === 1;
+  const action = isOnShelf ? '下架' : '上架';
+  await proxy?.$modal.confirm(`确认${action}该商品吗?`);
+
+  try {
+    // 上架:状态改为2(上架中),下架:状态改为0(下架)
+    const productStatus = isOnShelf ? 0 : 2;
+    await shelfReview({
+      id: row.id,
+      productStatus: productStatus,
+      shelfComments: `${action}操作`
+    });
+    proxy?.$modal.msgSuccess(`${action}成功`);
+    await getList();
+  } catch (error) {
+    console.error(`${action}失败:`, error);
+    proxy?.$modal.msgError(`${action}失败`);
+  }
+};
+
+
+/** 库存修改弹框 */
+const inventoryDialog = reactive({
+  visible: false,
+  loading: false,
+  submitLoading: false
+});
+
+const inventoryFormRef = ref<ElFormInstance>();
+
+const inventoryForm = reactive<PriceInventoryForm>({
+  productId: undefined,
+  totalInventory: undefined,
+  nowInventory: undefined,
+  virtualInventory: undefined
+});
+
+const inventoryRules = {
+  totalInventory: [{ required: true, message: '总库存不能为空', trigger: 'blur' }],
+  nowInventory: [{ required: true, message: '当前可用库存不能为空', trigger: 'blur' }],
+  virtualInventory: [{ required: true, message: '虚拟库存不能为空', trigger: 'blur' }]
+};
+
+/** 打开库存修改弹框 */
+const handleSupply = async (row: BaseVO) => {
+  inventoryForm.id = row.id;
+  inventoryForm.totalInventory = undefined;
+  inventoryForm.nowInventory = undefined;
+  inventoryForm.virtualInventory = undefined;
+  inventoryDialog.loading = true;
+  inventoryDialog.visible = true;
+  try {
+    const res = await getBase(row.id);
+    if (res.data) {
+      inventoryForm.totalInventory = res.data.totalInventory;
+      inventoryForm.nowInventory = res.data.nowInventory;
+      inventoryForm.virtualInventory = res.data.virtualInventory;
+    }
+  } catch (error) {
+    console.error('获取库存信息失败:', error);
+  } finally {
+    inventoryDialog.loading = false;
+  }
+};
+
+/** 提交库存修改 */
+const submitInventory = async () => {
+  await inventoryFormRef.value?.validate();
+  inventoryDialog.submitLoading = true;
+  try {
+    await updateBase({ ...inventoryForm });
+    proxy?.$modal.msgSuccess('库存修改成功');
+    inventoryDialog.visible = false;
+    await getList();
+  } catch (error) {
+    console.error('库存修改失败:', error);
+    proxy?.$modal.msgError('库存修改失败');
+  } finally {
+    inventoryDialog.submitLoading = false;
+  }
+};
+
+/** 停售操作 */
+const handleDiscontinue = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认停售该商品吗?停售后商品将无法正常售卖。');
+
+  try {
+    // 调用停售API,将商品类型改为3(停售商品)
+    await changeProductType({
+      id: row.id,
+      productCategory: 3
+    });
+    proxy?.$modal.msgSuccess('停售成功');
+    await getList();
+  } catch (error) {
+    console.error('停售失败:', error);
+    proxy?.$modal.msgError('停售失败');
+  }
+};
+
+/** 加入自营池操作 */
+const handleAddToSelfPool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入自营池吗?');
+
+  try {
+    await addProductSelf({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入自营池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入自营池失败:', error);
+    proxy?.$modal.msgError('加入自营池失败');
+  }
+};
+
+/** 加入精品池操作 */
+const handleAddToExquisitePool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入精品池吗?');
+
+  try {
+    await addProductExquisite({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入精品池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入精品池失败:', error);
+    proxy?.$modal.msgError('加入精品池失败');
+  }
+};
+
+/** 审核通过 */
+const handleAudit = async (row: ProductListVO) => {
+  if (!row.poolAuditId) {
+    proxy?.$modal.msgWarning('该商品未关联入池单,无法审核');
+    return;
+  }
+  await proxy?.$modal.confirm(`确认审核通过商品"${row.itemName}"吗?`);
+  try {
+    await audit({
+      poolAuditId: row.poolAuditId,
+      productIds: [row.productId],
+      auditStatus: 2
+    });
+    proxy?.$modal.msgSuccess('审核通过成功');
+    await getList();
+  } catch (error) {
+    console.error('审核失败:', error);
+  }
+};
+
+/** 驳回 */
+const handleReject = async (row: ProductListVO) => {
+  if (!row.poolAuditId) {
+    proxy?.$modal.msgWarning('该商品未关联入池单,无法驳回');
+    return;
+  }
+  try {
+    const { value: reason } = await ElMessageBox.prompt('请输入驳回原因', '驳回', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      inputPlaceholder: '请输入驳回原因',
+      inputValidator: (val) => (val && val.trim() ? true : '驳回原因不能为空')
+    });
+    await audit({
+      poolAuditId: row.poolAuditId,
+      productIds: [row.productId],
+      auditStatus: 3,
+      reason: reason.trim()
+    });
+    proxy?.$modal.msgSuccess('驳回成功');
+    await getList();
+  } catch (error: any) {
+    if (error !== 'cancel') {
+      console.error('驳回失败:', error);
+    }
+  }
+};
+
+/** 跳转到商品审核页面 */
+const handleGoReview = () => {
+  router.push({
+    path: '/product/base/review',
+    query: {
+      productReviewStatus: 1 // 默认显示待审核的商品
+    }
+  });
+};
+
+/** 查询分类树 */
+const getCategoryTree = async () => {
+  const res = await categoryTree();
+  categoryOptions.value = res.data || [];
+};
+
+/** 加载品牌选项(默认100条) */
+const loadBrandOptions = async (keyword?: string) => {
+  brandLoading.value = true;
+  try {
+    const res = await listBrand({ pageNum: 1, pageSize: 100, brandName: keyword });
+    brandOptions.value = res.rows || [];
+  } catch (error) {
+    console.error('加载品牌列表失败:', error);
+  } finally {
+    brandLoading.value = false;
+  }
+};
+
+/** 品牌远程搜索(防抖) */
+const handleBrandSearch = (query: string) => {
+  if (brandSearchTimer) clearTimeout(brandSearchTimer);
+  brandSearchTimer = setTimeout(() => {
+    loadBrandOptions(query || undefined);
+  }, 300);
+};
+
+/** 获取统计信息 */
+const getStatistics = async () => {
+  try {
+    const res = await getProductStatusCount();
+    if (res.data) {
+      statistics.value = res.data;
+    }
+  } catch (error) {
+    console.error('获取统计信息失败:', error);
+  }
+};
+
+
+onMounted(() => {
+  getList();
+  getStatistics();
+  loadBrandOptions();
+});
+</script>

+ 845 - 0
src/views/product/poolAudit/selectedAudit.vue

@@ -0,0 +1,845 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" label-width="90px">
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品编号" prop="productNo">
+                  <el-input v-model="queryParams.productNo" placeholder="请输入商品编号" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品名称" prop="itemName">
+                  <el-input v-model="queryParams.itemName" placeholder="请输入商品名称" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品品牌" prop="brandId">
+                  <el-select
+                    v-model="queryParams.brandId"
+                    placeholder="请输入品牌名称搜索"
+                    filterable
+                    remote
+                    clearable
+                    :remote-method="handleBrandSearch"
+                    :loading="brandLoading"
+                    style="width: 100%"
+                    @keyup.enter="handleQuery"
+                  >
+                    <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="6">
+                <el-form-item label="上下架状态" prop="productStatus">
+                  <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
+                    <el-option label="已上架" :value="1" />
+                    <el-option label="下架" :value="0" />
+                    <el-option label="上架中" :value="2" />
+                    <el-option label="驳回上架" :value="3" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品类型" prop="bottomCategoryId">
+                  <el-tree-select
+                    v-model="queryParams.bottomCategoryId"
+                    :data="categoryOptions"
+                    :props="{ value: 'id', label: 'label', children: 'children' } as any"
+                    value-key="id"
+                    placeholder="请选择商品类型"
+                    clearable
+                    check-strictly
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="18">
+                <el-form-item label="商品分类">
+                  <category-cascade-select
+                    ref="categoryCascadeRef"
+                    v-model:top-category-id="queryParams.topCategoryId"
+                    v-model:medium-category-id="queryParams.mediumCategoryId"
+                    v-model:bottom-category-id="queryParams.bottomCategoryId"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row>
+              <el-col :span="24" class="text-left">
+                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <!-- 统计信息区域 -->
+    <el-card shadow="never" class="mb-[10px]">
+      <div class="flex items-center text-sm text-gray-600">
+        <span>商品总数: </span>
+        <span class="text-blue-600 mx-1"
+        >总=<span class="text-red-600">{{ statistics.total || 0 }}</span
+        >条</span
+        >
+        <span class="mx-2">【上架/总数({{ statistics.onSale || 0 }}/{{ statistics.total || 0 }})】</span>
+        <span class="mx-2"
+        >审核状态: 待审核<span class="text-red-600">{{ statistics.waitAudit || 0 }}</span
+        >条,通过<span class="text-green-600">{{ statistics.auditPass || 0 }}</span
+        >条,驳回<span class="text-orange-600">{{ statistics.auditReject || 0 }}</span
+        >条</span
+        >
+        <span class="mx-2"
+        >上下架状态: 已上架<span class="text-green-600">{{ statistics.onSale || 0 }}</span
+        >条,下架<span class="text-gray-600">{{ statistics.offSale || 0 }}</span
+        >条</span
+        >
+        <div class="ml-auto flex gap-2">
+          <el-button plain icon="Download" @click="handleExport">导出</el-button>
+          <el-button circle icon="Refresh" @click="getList"></el-button>
+        </div>
+      </div>
+    </el-card>
+
+    <el-card shadow="never">
+      <el-table v-loading="loading" border :data="baseList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="入池名称" align="center" prop="name" width="100" fixed="left" />
+        <el-table-column label="商品编号" align="center" prop="productNo" width="120" >
+          <template #default="scope">
+            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品图片" align="center" prop="productImage" width="100">
+          <template #default="scope">
+            <image-preview :src="scope.row.productImage" :width="60" :height="60" />
+          </template>
+        </el-table-column>
+        <el-table-column label="商品信息" align="center" min-width="250">
+          <template #default="scope">
+            <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.topCategoryName+'-'+scope.row.mediumCategoryName+'-'+ scope.row.bottomCategoryName}}</div>
+            </div>
+          </template>
+        </el-table-column>
+        <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="120">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px">
+              <div>
+                <span class="text-gray-500">市场价:</span>
+                <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">官网价:</span>
+                <span class="text-red-500">¥{{ scope.row.memberPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">最低价:</span>
+                <span class="text-red-500">¥{{ scope.row.minSellingPrice || '0.00' }}</span>
+              </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>
+                <span class="text-gray-500">采购价:</span>
+                <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">暂估毛利率:</span>
+                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品类型" align="center" width="140">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px">
+              <div>
+                <span class="text-gray-500">总库存:</span>
+                <span>{{ scope.row.totalInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">可用库存:</span>
+                <span>{{ scope.row.nowInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">虚拟库存:</span>
+                <span>{{ scope.row.virtualInventory ?? '-' }}</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="是否自营" align="center" width="80">
+          <template #default="scope">
+            <span v-if="scope.row.isSelf === 1">是</span>
+            <span v-else-if="scope.row.isSelf === 0">否</span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column label="上下架状态" align="center" prop="productStatus" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.productStatus === 1" type="success">已上架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 0" type="warning">下架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 2" type="info">上架中</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="申请类型" align="center" prop="type" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.type === 0" type="success">新增</el-tag>
+            <el-tag v-else-if="scope.row.type === 1" type="warning">移出</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" width="150" fixed="right">
+          <template #default="scope">
+            <div class="flex gap-1 justify-center">
+              <el-link type="primary" :underline="false" @click="handleViewDetail(scope.row)">查看</el-link>
+              <el-link type="success" :underline="false" @click="handleAudit(scope.row)">审核</el-link>
+              <el-link type="danger" :underline="false" @click="handleReject(scope.row)">驳回</el-link>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 游标分页控制 -->
+      <pagination
+        v-show="baseList.length > 0"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        v-model:way="queryParams.way"
+        :cursor-mode="true"
+        :has-more="hasMore"
+        @pagination="getList"
+      />
+    </el-card>
+    <!-- 产品详情抽屉 -->
+    <product-detail-drawer
+      v-model="detailDrawer.visible"
+      :id="detailDrawer.id"
+    />
+
+    <!-- 库存修改弹框 -->
+    <el-dialog v-model="inventoryDialog.visible" title="修改库存" width="500px" :close-on-click-modal="false">
+      <div v-loading="inventoryDialog.loading">
+        <el-form ref="inventoryFormRef" :model="inventoryForm" :rules="inventoryRules" label-width="110px">
+          <el-form-item label="虚拟库存" prop="virtualInventory">
+            <el-input-number
+              v-model="inventoryForm.virtualInventory"
+              :min="0"
+              :precision="0"
+              controls-position="right"
+              style="width: 100%"
+              placeholder="请输入虚拟库存"
+            />
+          </el-form-item>
+        </el-form>
+      </div>
+      <template #footer>
+        <el-button @click="inventoryDialog.visible = false">取消</el-button>
+        <el-button type="primary" :loading="inventoryDialog.submitLoading" @click="submitInventory">确定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Base" lang="ts">
+import ProductDetailDrawer from './ProductDetailDrawer.vue';
+import {
+  getBase,
+  delBase,
+  brandList,
+  updateBase,
+  categoryTree,
+  shelfReview,
+  changeProductType,
+  getProductStatusCount
+} from '@/api/product/base';
+import { selectPoolAuditProductPage, audit } from '@/api/product/poolAudit';
+import { ProductListVO } from '@/api/product/poolAudit/types';
+import { generatePPT } from '@/utils/pptPlugin';
+import { addProductSelf } from '@/api/product/productSelf';
+import { addProductExquisite } from '@/api/product/productExquisite';
+import { PriceInventoryForm } from '@/api/product/priceInventory/types';
+import { BaseVO, BaseQuery, BaseForm, StatusCountVo } from '@/api/product/base/types';
+import { BrandVO } from '@/api/product/brand/types';
+import { listBrand } from '@/api/product/brand';
+import { categoryTreeVO } from '@/api/product/category/types';
+import { useRoute, useRouter } from 'vue-router';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const router = useRouter();
+const route = useRoute();
+
+const baseList = ref<ProductListVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const categoryOptions = ref<categoryTreeVO[]>([]);
+const brandOptions = ref<BrandVO[]>([]);
+const brandLoading = ref(false);
+let brandSearchTimer: ReturnType<typeof setTimeout> | null = null;
+const hasMore = ref(true); // 是否还有更多数据
+// 页面历史记录,存储每页的第一个id和最后一个id,用于支持双向翻页
+const pageHistory = ref([]);
+
+// 分类相关
+const categoryCascadeRef = ref();
+
+// 统计信息
+const statistics = ref<StatusCountVo>({
+  total: 0,
+  onSale: 0,
+  offSale: 0,
+  waitAudit: 0,
+  auditPass: 0,
+  auditReject: 0
+});
+
+const queryFormRef = ref<ElFormInstance>();
+const baseFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: BaseForm = {
+  id: undefined,
+  productNo: undefined,
+  itemName: undefined,
+  brandId: undefined,
+  topCategoryId: undefined,
+  mediumCategoryId: undefined,
+  bottomCategoryId: undefined,
+  unitId: undefined,
+  productImage: undefined,
+  isSelf: undefined,
+  productReviewStatus: undefined,
+  homeRecommended: undefined,
+  categoryRecommendation: undefined,
+  cartRecommendation: undefined,
+  recommendedProductOrder: undefined,
+  isPopular: undefined,
+  isNew: undefined,
+  productStatus: undefined,
+  remark: undefined
+};
+const data = reactive<PageData<BaseForm, BaseQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    productNo: undefined,
+    itemName: undefined,
+    brandId: undefined,
+    productTag: undefined,
+    purchaseNature: undefined,
+    supplierType: undefined,
+    supplierNature: undefined,
+    projectOrg: undefined,
+    topCategoryId: undefined,
+    mediumCategoryId: undefined,
+    bottomCategoryId: undefined,
+    isSelf: 1,
+    productReviewStatus: undefined,
+    productStatus: undefined,
+    lastSeenId: undefined, // 游标分页的lastSeenId
+    way: undefined,
+    params: {}
+  },
+  rules: {
+    productNo: [{ required: true, message: '产品编号不能为空', trigger: 'blur' }],
+    itemName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
+    brandId: [{ required: true, message: '品牌id不能为空', trigger: 'blur' }],
+    topCategoryId: [{ required: true, message: '顶级分类id不能为空', trigger: 'blur' }],
+    mediumCategoryId: [{ required: true, message: '中级分类id不能为空', trigger: 'blur' }],
+    bottomCategoryId: [{ required: true, message: '底层分类id不能为空', trigger: 'blur' }],
+    unitId: [{ required: true, message: '单位id不能为空', trigger: 'blur' }],
+    productImage: [{ required: true, message: '产品图片URL不能为空', trigger: 'blur' }],
+    productReviewStatus: [{ required: true, message: '产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核不能为空', trigger: 'change' }],
+    homeRecommended: [{ required: true, message: '首页推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    categoryRecommendation: [{ required: true, message: '分类推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    cartRecommendation: [{ required: true, message: '购物车推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    recommendedProductOrder: [{ required: true, message: '推荐产品顺序不能为空', trigger: 'blur' }],
+    isPopular: [{ required: true, message: '是否热门:1=是,0=否不能为空', trigger: 'blur' }],
+    isNew: [{ required: true, message: '是否新品:1=是,0=否不能为空', trigger: 'blur' }],
+    remark: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品基础信息列表 */
+const getList = async () => {
+  loading.value = true;
+  try {
+    initRouteParams();
+    const params = { ...queryParams.value };
+    const currentPageNum = queryParams.value.pageNum;
+
+    // 第一页不需要游标参数
+    if (currentPageNum === 1) {
+      delete params.lastSeenId;
+      delete params.way;
+    } else {
+      // way参数:0=上一页,1=下一页
+      if (queryParams.value.way === 0) {
+        // 上一页:使用目标页(即当前显示页)的firstId
+        const nextPageHistory = pageHistory.value[currentPageNum];
+        if (nextPageHistory) {
+          params.firstSeenId = nextPageHistory.firstId;
+          params.way = 0;
+        }
+      } else {
+        // 下一页:使用前一页的lastId作为lastSeenId
+        const prevPageHistory = pageHistory.value[currentPageNum - 1];
+        if (prevPageHistory) {
+          params.lastSeenId = prevPageHistory.lastId;
+          params.way = 1;
+        }
+      }
+    }
+
+    const res = await selectPoolAuditProductPage({ ...params, poolType: 1 }); // 自营产品池
+    baseList.value = res.rows || [];
+
+    // 判断是否还有更多数据
+    hasMore.value = baseList.value.length === queryParams.value.pageSize;
+
+    // 记录当前页的第一个id和最后一个id
+    if (baseList.value.length > 0) {
+      const firstItem = baseList.value[0];
+      const lastItem = baseList.value[baseList.value.length - 1];
+      //如果长度小于currentPageNum则创建
+
+      if (pageHistory.value.length <= currentPageNum) {
+        pageHistory.value[currentPageNum] = {
+          firstId: firstItem.id,
+          lastId: lastItem.id
+        };
+      }
+    }
+
+    total.value = res.total || 0;
+  } catch (error) {
+    console.error('获取列表失败:', error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 初始化路由参数 */
+const initRouteParams = () => {
+  // 从路由参数中获取筛选条件
+  if (route.query.productReviewStatus) {
+    queryParams.value.productReviewStatus = Number(route.query.productReviewStatus);
+  }
+  if (route.query.brandName) {
+    queryParams.value.brandName = route.query.brandName as string;
+  }
+  if (route.query.bottomCategoryId) {
+    queryParams.value.bottomCategoryId = route.query.bottomCategoryId as string;
+  }
+  if (route.query.isSelf) {
+    queryParams.value.isSelf = Number(route.query.isSelf);
+  }
+  if (route.query.productCategory) {
+    queryParams.value.productCategory = Number(route.query.productCategory);
+  }
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  baseFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  // 同步查询参数到游标分页参数
+  queryParams.value = {
+    ...queryParams.value,
+    pageNum: 1,
+    productNo: queryParams.value.productNo,
+    itemName: queryParams.value.itemName,
+    brandName: queryParams.value.brandName,
+    bottomCategoryId: queryParams.value.bottomCategoryId,
+    isSelf: queryParams.value.isSelf,
+    productReviewStatus: queryParams.value.productReviewStatus,
+    productStatus: queryParams.value.productStatus,
+    lastSeenId: undefined
+  };
+  pageHistory.value = []; // 重置页面历史
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  // 手动重置分类字段
+  queryParams.value.topCategoryId = undefined;
+  queryParams.value.mediumCategoryId = undefined;
+  queryParams.value.bottomCategoryId = undefined;
+  categoryCascadeRef.value?.reset();
+  queryParams.value.lastSeenId = undefined;
+  pageHistory.value = []; // 重置页面历史
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: BaseVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  router.push('/product/base/add');
+};
+
+/** 产品详情抽屉 */
+const detailDrawer = reactive({
+  visible: false,
+  id: undefined as string | number | undefined
+});
+
+/** 查看产品详情 */
+const handleViewDetail = (row: ProductListVO) => {
+  detailDrawer.id = row.id;
+  detailDrawer.visible = true;
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: BaseVO) => {
+  const _id = row?.id || ids.value[0];
+  router.push(`/product/base/edit/${_id}`);
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: BaseVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品基础信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delBase(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  // 检查是否有选中的商品
+  if (ids.value.length === 0) {
+    proxy?.$modal.msgWarning('请先选择要导出的商品');
+    return;
+  }
+
+  // 获取选中商品的完整信息
+  const selectedProducts = baseList.value.filter(item => ids.value.includes(item.id));
+
+  if (selectedProducts.length === 0) {
+    proxy?.$modal.msgWarning('未找到选中的商品信息');
+    return;
+  }
+
+  // 转换为 generatePPT 需要的格式
+  const products = selectedProducts.map(item => ({
+    image: item.productImage || item.productImageUrl || '',
+    name: item.itemName || '',
+    code: item.productNo || '',
+    spec: item.specification || item.packagingSpec || '-',
+    price: item.minSellingPrice || item.memberPrice || 0
+  }));
+
+  // 默认模板配置
+  const template = {
+    name: '商品展示方案',
+    title: '商品展示方案',
+    themeColor: '#C00000',
+    itemsPerPage: 1, // 每页1个商品,展示更详细
+    cover: '',
+    logo: ''
+  };
+
+  try {
+    proxy?.$modal.loading('正在生成PPT...');
+    await generatePPT(template, products);
+    proxy?.$modal.closeLoading();
+    proxy?.$modal.msgSuccess('PPT导出成功');
+  } catch (error) {
+    proxy?.$modal.closeLoading();
+    console.error('PPT导出失败:', error);
+    proxy?.$modal.msgError('PPT导出失败');
+  }
+};
+
+/** 查看商品详情 */
+const handleView = (row: BaseVO) => {
+  const url = `https://item.xiaoluwebsite.xyz/item?id=${row.id}`;
+  window.open(url, '_blank');
+};
+
+/** 上下架操作 */
+const handleShelf = async (row: BaseVO) => {
+  const isOnShelf = row.productStatus === 1;
+  const action = isOnShelf ? '下架' : '上架';
+  await proxy?.$modal.confirm(`确认${action}该商品吗?`);
+
+  try {
+    // 上架:状态改为2(上架中),下架:状态改为0(下架)
+    const productStatus = isOnShelf ? 0 : 2;
+    await shelfReview({
+      id: row.id,
+      productStatus: productStatus,
+      shelfComments: `${action}操作`
+    });
+    proxy?.$modal.msgSuccess(`${action}成功`);
+    await getList();
+  } catch (error) {
+    console.error(`${action}失败:`, error);
+    proxy?.$modal.msgError(`${action}失败`);
+  }
+};
+
+
+/** 库存修改弹框 */
+const inventoryDialog = reactive({
+  visible: false,
+  loading: false,
+  submitLoading: false
+});
+
+const inventoryFormRef = ref<ElFormInstance>();
+
+const inventoryForm = reactive<PriceInventoryForm>({
+  productId: undefined,
+  totalInventory: undefined,
+  nowInventory: undefined,
+  virtualInventory: undefined
+});
+
+const inventoryRules = {
+  totalInventory: [{ required: true, message: '总库存不能为空', trigger: 'blur' }],
+  nowInventory: [{ required: true, message: '当前可用库存不能为空', trigger: 'blur' }],
+  virtualInventory: [{ required: true, message: '虚拟库存不能为空', trigger: 'blur' }]
+};
+
+/** 打开库存修改弹框 */
+const handleSupply = async (row: BaseVO) => {
+  inventoryForm.id = row.id;
+  inventoryForm.totalInventory = undefined;
+  inventoryForm.nowInventory = undefined;
+  inventoryForm.virtualInventory = undefined;
+  inventoryDialog.loading = true;
+  inventoryDialog.visible = true;
+  try {
+    const res = await getBase(row.id);
+    if (res.data) {
+      inventoryForm.totalInventory = res.data.totalInventory;
+      inventoryForm.nowInventory = res.data.nowInventory;
+      inventoryForm.virtualInventory = res.data.virtualInventory;
+    }
+  } catch (error) {
+    console.error('获取库存信息失败:', error);
+  } finally {
+    inventoryDialog.loading = false;
+  }
+};
+
+/** 提交库存修改 */
+const submitInventory = async () => {
+  await inventoryFormRef.value?.validate();
+  inventoryDialog.submitLoading = true;
+  try {
+    await updateBase({ ...inventoryForm });
+    proxy?.$modal.msgSuccess('库存修改成功');
+    inventoryDialog.visible = false;
+    await getList();
+  } catch (error) {
+    console.error('库存修改失败:', error);
+    proxy?.$modal.msgError('库存修改失败');
+  } finally {
+    inventoryDialog.submitLoading = false;
+  }
+};
+
+/** 停售操作 */
+const handleDiscontinue = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认停售该商品吗?停售后商品将无法正常售卖。');
+
+  try {
+    // 调用停售API,将商品类型改为3(停售商品)
+    await changeProductType({
+      id: row.id,
+      productCategory: 3
+    });
+    proxy?.$modal.msgSuccess('停售成功');
+    await getList();
+  } catch (error) {
+    console.error('停售失败:', error);
+    proxy?.$modal.msgError('停售失败');
+  }
+};
+
+/** 加入自营池操作 */
+const handleAddToSelfPool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入自营池吗?');
+
+  try {
+    await addProductSelf({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入自营池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入自营池失败:', error);
+    proxy?.$modal.msgError('加入自营池失败');
+  }
+};
+
+/** 加入精品池操作 */
+const handleAddToExquisitePool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入精品池吗?');
+
+  try {
+    await addProductExquisite({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入精品池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入精品池失败:', error);
+    proxy?.$modal.msgError('加入精品池失败');
+  }
+};
+
+/** 审核通过 */
+const handleAudit = async (row: ProductListVO) => {
+  if (!row.poolAuditId) {
+    proxy?.$modal.msgWarning('该商品未关联入池单,无法审核');
+    return;
+  }
+  await proxy?.$modal.confirm(`确认审核通过商品"${row.itemName}"吗?`);
+  try {
+    await audit({
+      poolAuditId: row.poolAuditId,
+      productIds: [row.productId],
+      auditStatus: 2
+    });
+    proxy?.$modal.msgSuccess('审核通过成功');
+    await getList();
+  } catch (error) {
+    console.error('审核失败:', error);
+  }
+};
+
+/** 驳回 */
+const handleReject = async (row: ProductListVO) => {
+  if (!row.poolAuditId) {
+    proxy?.$modal.msgWarning('该商品未关联入池单,无法驳回');
+    return;
+  }
+  try {
+    const { value: reason } = await ElMessageBox.prompt('请输入驳回原因', '驳回', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      inputPlaceholder: '请输入驳回原因',
+      inputValidator: (val) => (val && val.trim() ? true : '驳回原因不能为空')
+    });
+    await audit({
+      poolAuditId: row.poolAuditId,
+      productIds: [row.productId],
+      auditStatus: 3,
+      reason: reason.trim()
+    });
+    proxy?.$modal.msgSuccess('驳回成功');
+    await getList();
+  } catch (error: any) {
+    if (error !== 'cancel') {
+      console.error('驳回失败:', error);
+    }
+  }
+};
+
+/** 跳转到商品审核页面 */
+const handleGoReview = () => {
+  router.push({
+    path: '/product/base/review',
+    query: {
+      productReviewStatus: 1 // 默认显示待审核的商品
+    }
+  });
+};
+
+/** 查询分类树 */
+const getCategoryTree = async () => {
+  const res = await categoryTree();
+  categoryOptions.value = res.data || [];
+};
+
+/** 加载品牌选项(默认100条) */
+const loadBrandOptions = async (keyword?: string) => {
+  brandLoading.value = true;
+  try {
+    const res = await listBrand({ pageNum: 1, pageSize: 100, brandName: keyword });
+    brandOptions.value = res.rows || [];
+  } catch (error) {
+    console.error('加载品牌列表失败:', error);
+  } finally {
+    brandLoading.value = false;
+  }
+};
+
+/** 品牌远程搜索(防抖) */
+const handleBrandSearch = (query: string) => {
+  if (brandSearchTimer) clearTimeout(brandSearchTimer);
+  brandSearchTimer = setTimeout(() => {
+    loadBrandOptions(query || undefined);
+  }, 300);
+};
+
+/** 获取统计信息 */
+const getStatistics = async () => {
+  try {
+    const res = await getProductStatusCount();
+    if (res.data) {
+      statistics.value = res.data;
+    }
+  } catch (error) {
+    console.error('获取统计信息失败:', error);
+  }
+};
+
+
+onMounted(() => {
+  getList();
+  getStatistics();
+  loadBrandOptions();
+});
+</script>

+ 845 - 0
src/views/product/poolAudit/selfAudit.vue

@@ -0,0 +1,845 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" label-width="90px">
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品编号" prop="productNo">
+                  <el-input v-model="queryParams.productNo" placeholder="请输入商品编号" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品名称" prop="itemName">
+                  <el-input v-model="queryParams.itemName" placeholder="请输入商品名称" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品品牌" prop="brandId">
+                  <el-select
+                    v-model="queryParams.brandId"
+                    placeholder="请输入品牌名称搜索"
+                    filterable
+                    remote
+                    clearable
+                    :remote-method="handleBrandSearch"
+                    :loading="brandLoading"
+                    style="width: 100%"
+                    @keyup.enter="handleQuery"
+                  >
+                    <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="6">
+                <el-form-item label="上下架状态" prop="productStatus">
+                  <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
+                    <el-option label="已上架" :value="1" />
+                    <el-option label="下架" :value="0" />
+                    <el-option label="上架中" :value="2" />
+                    <el-option label="驳回上架" :value="3" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品类型" prop="bottomCategoryId">
+                  <el-tree-select
+                    v-model="queryParams.bottomCategoryId"
+                    :data="categoryOptions"
+                    :props="{ value: 'id', label: 'label', children: 'children' } as any"
+                    value-key="id"
+                    placeholder="请选择商品类型"
+                    clearable
+                    check-strictly
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="18">
+                <el-form-item label="商品分类">
+                  <category-cascade-select
+                    ref="categoryCascadeRef"
+                    v-model:top-category-id="queryParams.topCategoryId"
+                    v-model:medium-category-id="queryParams.mediumCategoryId"
+                    v-model:bottom-category-id="queryParams.bottomCategoryId"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row>
+              <el-col :span="24" class="text-left">
+                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <!-- 统计信息区域 -->
+    <el-card shadow="never" class="mb-[10px]">
+      <div class="flex items-center text-sm text-gray-600">
+        <span>商品总数: </span>
+        <span class="text-blue-600 mx-1"
+        >总=<span class="text-red-600">{{ statistics.total || 0 }}</span
+        >条</span
+        >
+        <span class="mx-2">【上架/总数({{ statistics.onSale || 0 }}/{{ statistics.total || 0 }})】</span>
+        <span class="mx-2"
+        >审核状态: 待审核<span class="text-red-600">{{ statistics.waitAudit || 0 }}</span
+        >条,通过<span class="text-green-600">{{ statistics.auditPass || 0 }}</span
+        >条,驳回<span class="text-orange-600">{{ statistics.auditReject || 0 }}</span
+        >条</span
+        >
+        <span class="mx-2"
+        >上下架状态: 已上架<span class="text-green-600">{{ statistics.onSale || 0 }}</span
+        >条,下架<span class="text-gray-600">{{ statistics.offSale || 0 }}</span
+        >条</span
+        >
+        <div class="ml-auto flex gap-2">
+          <el-button plain icon="Download" @click="handleExport">导出</el-button>
+          <el-button circle icon="Refresh" @click="getList"></el-button>
+        </div>
+      </div>
+    </el-card>
+
+    <el-card shadow="never">
+      <el-table v-loading="loading" border :data="baseList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="入池名称" align="center" prop="name" width="100" fixed="left"/>
+        <el-table-column label="商品编号" align="center" prop="productNo" width="120" >
+          <template #default="scope">
+            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品图片" align="center" prop="productImage" width="100">
+          <template #default="scope">
+            <image-preview :src="scope.row.productImage" :width="60" :height="60" />
+          </template>
+        </el-table-column>
+        <el-table-column label="商品信息" align="center" min-width="250">
+          <template #default="scope">
+            <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.topCategoryName+'-'+scope.row.mediumCategoryName+'-'+ scope.row.bottomCategoryName}}</div>
+            </div>
+          </template>
+        </el-table-column>
+        <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="120">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px">
+              <div>
+                <span class="text-gray-500">市场价:</span>
+                <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">官网价:</span>
+                <span class="text-red-500">¥{{ scope.row.memberPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">最低价:</span>
+                <span class="text-red-500">¥{{ scope.row.minSellingPrice || '0.00' }}</span>
+              </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>
+                <span class="text-gray-500">采购价:</span>
+                <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">暂估毛利率:</span>
+                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品类型" align="center" width="140">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px">
+              <div>
+                <span class="text-gray-500">总库存:</span>
+                <span>{{ scope.row.totalInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">可用库存:</span>
+                <span>{{ scope.row.nowInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">虚拟库存:</span>
+                <span>{{ scope.row.virtualInventory ?? '-' }}</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="是否自营" align="center" width="80">
+          <template #default="scope">
+            <span v-if="scope.row.isSelf === 1">是</span>
+            <span v-else-if="scope.row.isSelf === 0">否</span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+
+        <el-table-column label="上下架状态" align="center" prop="productStatus" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.productStatus === 1" type="success">已上架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 0" type="warning">下架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 2" type="info">上架中</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="申请类型" align="center" prop="type" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.type === 0" type="success">新增</el-tag>
+            <el-tag v-else-if="scope.row.type === 1" type="warning">移出</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" width="150" fixed="right">
+          <template #default="scope">
+            <div class="flex gap-1 justify-center">
+              <el-link type="primary" :underline="false" @click="handleViewDetail(scope.row)">查看</el-link>
+              <el-link type="success" :underline="false" @click="handleAudit(scope.row)">审核</el-link>
+              <el-link type="danger" :underline="false" @click="handleReject(scope.row)">驳回</el-link>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- 游标分页控制 -->
+      <pagination
+        v-show="baseList.length > 0"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        v-model:way="queryParams.way"
+        :cursor-mode="true"
+        :has-more="hasMore"
+        @pagination="getList"
+      />
+    </el-card>
+    <!-- 产品详情抽屉 -->
+    <product-detail-drawer
+      v-model="detailDrawer.visible"
+      :id="detailDrawer.id"
+    />
+
+    <!-- 库存修改弹框 -->
+    <el-dialog v-model="inventoryDialog.visible" title="修改库存" width="500px" :close-on-click-modal="false">
+      <div v-loading="inventoryDialog.loading">
+        <el-form ref="inventoryFormRef" :model="inventoryForm" :rules="inventoryRules" label-width="110px">
+          <el-form-item label="虚拟库存" prop="virtualInventory">
+            <el-input-number
+              v-model="inventoryForm.virtualInventory"
+              :min="0"
+              :precision="0"
+              controls-position="right"
+              style="width: 100%"
+              placeholder="请输入虚拟库存"
+            />
+          </el-form-item>
+        </el-form>
+      </div>
+      <template #footer>
+        <el-button @click="inventoryDialog.visible = false">取消</el-button>
+        <el-button type="primary" :loading="inventoryDialog.submitLoading" @click="submitInventory">确定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Base" lang="ts">
+import ProductDetailDrawer from './ProductDetailDrawer.vue';
+import {
+  getBase,
+  delBase,
+  brandList,
+  updateBase,
+  categoryTree,
+  shelfReview,
+  changeProductType,
+  getProductStatusCount
+} from '@/api/product/base';
+import { selectPoolAuditProductPage, audit } from '@/api/product/poolAudit';
+import { ProductListVO } from '@/api/product/poolAudit/types';
+import { generatePPT } from '@/utils/pptPlugin';
+import { addProductSelf } from '@/api/product/productSelf';
+import { addProductExquisite } from '@/api/product/productExquisite';
+import { PriceInventoryForm } from '@/api/product/priceInventory/types';
+import { BaseVO, BaseQuery, BaseForm, StatusCountVo } from '@/api/product/base/types';
+import { BrandVO } from '@/api/product/brand/types';
+import { listBrand } from '@/api/product/brand';
+import { categoryTreeVO } from '@/api/product/category/types';
+import { useRoute, useRouter } from 'vue-router';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const router = useRouter();
+const route = useRoute();
+
+const baseList = ref<ProductListVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const categoryOptions = ref<categoryTreeVO[]>([]);
+const brandOptions = ref<BrandVO[]>([]);
+const brandLoading = ref(false);
+let brandSearchTimer: ReturnType<typeof setTimeout> | null = null;
+const hasMore = ref(true); // 是否还有更多数据
+// 页面历史记录,存储每页的第一个id和最后一个id,用于支持双向翻页
+const pageHistory = ref([]);
+
+// 分类相关
+const categoryCascadeRef = ref();
+
+// 统计信息
+const statistics = ref<StatusCountVo>({
+  total: 0,
+  onSale: 0,
+  offSale: 0,
+  waitAudit: 0,
+  auditPass: 0,
+  auditReject: 0
+});
+
+const queryFormRef = ref<ElFormInstance>();
+const baseFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: BaseForm = {
+  id: undefined,
+  productNo: undefined,
+  itemName: undefined,
+  brandId: undefined,
+  topCategoryId: undefined,
+  mediumCategoryId: undefined,
+  bottomCategoryId: undefined,
+  unitId: undefined,
+  productImage: undefined,
+  isSelf: undefined,
+  productReviewStatus: undefined,
+  homeRecommended: undefined,
+  categoryRecommendation: undefined,
+  cartRecommendation: undefined,
+  recommendedProductOrder: undefined,
+  isPopular: undefined,
+  isNew: undefined,
+  productStatus: undefined,
+  remark: undefined
+};
+const data = reactive<PageData<BaseForm, BaseQuery>>({
+  form: { ...initFormData },
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    productNo: undefined,
+    itemName: undefined,
+    brandId: undefined,
+    productTag: undefined,
+    purchaseNature: undefined,
+    supplierType: undefined,
+    supplierNature: undefined,
+    projectOrg: undefined,
+    topCategoryId: undefined,
+    mediumCategoryId: undefined,
+    bottomCategoryId: undefined,
+    isSelf: 1,
+    productReviewStatus: undefined,
+    productStatus: undefined,
+    lastSeenId: undefined, // 游标分页的lastSeenId
+    way: undefined,
+    params: {}
+  },
+  rules: {
+    productNo: [{ required: true, message: '产品编号不能为空', trigger: 'blur' }],
+    itemName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
+    brandId: [{ required: true, message: '品牌id不能为空', trigger: 'blur' }],
+    topCategoryId: [{ required: true, message: '顶级分类id不能为空', trigger: 'blur' }],
+    mediumCategoryId: [{ required: true, message: '中级分类id不能为空', trigger: 'blur' }],
+    bottomCategoryId: [{ required: true, message: '底层分类id不能为空', trigger: 'blur' }],
+    unitId: [{ required: true, message: '单位id不能为空', trigger: 'blur' }],
+    productImage: [{ required: true, message: '产品图片URL不能为空', trigger: 'blur' }],
+    productReviewStatus: [{ required: true, message: '产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核不能为空', trigger: 'change' }],
+    homeRecommended: [{ required: true, message: '首页推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    categoryRecommendation: [{ required: true, message: '分类推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    cartRecommendation: [{ required: true, message: '购物车推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    recommendedProductOrder: [{ required: true, message: '推荐产品顺序不能为空', trigger: 'blur' }],
+    isPopular: [{ required: true, message: '是否热门:1=是,0=否不能为空', trigger: 'blur' }],
+    isNew: [{ required: true, message: '是否新品:1=是,0=否不能为空', trigger: 'blur' }],
+    remark: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品基础信息列表 */
+const getList = async () => {
+  loading.value = true;
+  try {
+    initRouteParams();
+    const params = { ...queryParams.value };
+    const currentPageNum = queryParams.value.pageNum;
+
+    // 第一页不需要游标参数
+    if (currentPageNum === 1) {
+      delete params.lastSeenId;
+      delete params.way;
+    } else {
+      // way参数:0=上一页,1=下一页
+      if (queryParams.value.way === 0) {
+        // 上一页:使用目标页(即当前显示页)的firstId
+        const nextPageHistory = pageHistory.value[currentPageNum];
+        if (nextPageHistory) {
+          params.firstSeenId = nextPageHistory.firstId;
+          params.way = 0;
+        }
+      } else {
+        // 下一页:使用前一页的lastId作为lastSeenId
+        const prevPageHistory = pageHistory.value[currentPageNum - 1];
+        if (prevPageHistory) {
+          params.lastSeenId = prevPageHistory.lastId;
+          params.way = 1;
+        }
+      }
+    }
+
+    const res = await selectPoolAuditProductPage({ ...params, poolType: 0 }); // 自营产品池
+    baseList.value = res.rows || [];
+
+    // 判断是否还有更多数据
+    hasMore.value = baseList.value.length === queryParams.value.pageSize;
+
+    // 记录当前页的第一个id和最后一个id
+    if (baseList.value.length > 0) {
+      const firstItem = baseList.value[0];
+      const lastItem = baseList.value[baseList.value.length - 1];
+      //如果长度小于currentPageNum则创建
+
+      if (pageHistory.value.length <= currentPageNum) {
+        pageHistory.value[currentPageNum] = {
+          firstId: firstItem.id,
+          lastId: lastItem.id
+        };
+      }
+    }
+
+    total.value = res.total || 0;
+  } catch (error) {
+    console.error('获取列表失败:', error);
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+};
+
+/** 初始化路由参数 */
+const initRouteParams = () => {
+  // 从路由参数中获取筛选条件
+  if (route.query.productReviewStatus) {
+    queryParams.value.productReviewStatus = Number(route.query.productReviewStatus);
+  }
+  if (route.query.brandName) {
+    queryParams.value.brandName = route.query.brandName as string;
+  }
+  if (route.query.bottomCategoryId) {
+    queryParams.value.bottomCategoryId = route.query.bottomCategoryId as string;
+  }
+  if (route.query.isSelf) {
+    queryParams.value.isSelf = Number(route.query.isSelf);
+  }
+  if (route.query.productCategory) {
+    queryParams.value.productCategory = Number(route.query.productCategory);
+  }
+};
+
+/** 表单重置 */
+const reset = () => {
+  form.value = { ...initFormData };
+  baseFormRef.value?.resetFields();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  // 同步查询参数到游标分页参数
+  queryParams.value = {
+    ...queryParams.value,
+    pageNum: 1,
+    productNo: queryParams.value.productNo,
+    itemName: queryParams.value.itemName,
+    brandName: queryParams.value.brandName,
+    bottomCategoryId: queryParams.value.bottomCategoryId,
+    isSelf: queryParams.value.isSelf,
+    productReviewStatus: queryParams.value.productReviewStatus,
+    productStatus: queryParams.value.productStatus,
+    lastSeenId: undefined
+  };
+  pageHistory.value = []; // 重置页面历史
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  // 手动重置分类字段
+  queryParams.value.topCategoryId = undefined;
+  queryParams.value.mediumCategoryId = undefined;
+  queryParams.value.bottomCategoryId = undefined;
+  categoryCascadeRef.value?.reset();
+  queryParams.value.lastSeenId = undefined;
+  pageHistory.value = []; // 重置页面历史
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: BaseVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  router.push('/product/base/add');
+};
+
+/** 产品详情抽屉 */
+const detailDrawer = reactive({
+  visible: false,
+  id: undefined as string | number | undefined
+});
+
+/** 查看产品详情 */
+const handleViewDetail = (row: ProductListVO) => {
+  detailDrawer.id = row.id;
+  detailDrawer.visible = true;
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: BaseVO) => {
+  const _id = row?.id || ids.value[0];
+  router.push(`/product/base/edit/${_id}`);
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: BaseVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品基础信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delBase(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  // 检查是否有选中的商品
+  if (ids.value.length === 0) {
+    proxy?.$modal.msgWarning('请先选择要导出的商品');
+    return;
+  }
+
+  // 获取选中商品的完整信息
+  const selectedProducts = baseList.value.filter(item => ids.value.includes(item.id));
+
+  if (selectedProducts.length === 0) {
+    proxy?.$modal.msgWarning('未找到选中的商品信息');
+    return;
+  }
+
+  // 转换为 generatePPT 需要的格式
+  const products = selectedProducts.map(item => ({
+    image: item.productImage || item.productImageUrl || '',
+    name: item.itemName || '',
+    code: item.productNo || '',
+    spec: item.specification || item.packagingSpec || '-',
+    price: item.minSellingPrice || item.memberPrice || 0
+  }));
+
+  // 默认模板配置
+  const template = {
+    name: '商品展示方案',
+    title: '商品展示方案',
+    themeColor: '#C00000',
+    itemsPerPage: 1, // 每页1个商品,展示更详细
+    cover: '',
+    logo: ''
+  };
+
+  try {
+    proxy?.$modal.loading('正在生成PPT...');
+    await generatePPT(template, products);
+    proxy?.$modal.closeLoading();
+    proxy?.$modal.msgSuccess('PPT导出成功');
+  } catch (error) {
+    proxy?.$modal.closeLoading();
+    console.error('PPT导出失败:', error);
+    proxy?.$modal.msgError('PPT导出失败');
+  }
+};
+
+/** 查看商品详情 */
+const handleView = (row: BaseVO) => {
+  const url = `https://item.xiaoluwebsite.xyz/item?id=${row.id}`;
+  window.open(url, '_blank');
+};
+
+/** 上下架操作 */
+const handleShelf = async (row: BaseVO) => {
+  const isOnShelf = row.productStatus === 1;
+  const action = isOnShelf ? '下架' : '上架';
+  await proxy?.$modal.confirm(`确认${action}该商品吗?`);
+
+  try {
+    // 上架:状态改为2(上架中),下架:状态改为0(下架)
+    const productStatus = isOnShelf ? 0 : 2;
+    await shelfReview({
+      id: row.id,
+      productStatus: productStatus,
+      shelfComments: `${action}操作`
+    });
+    proxy?.$modal.msgSuccess(`${action}成功`);
+    await getList();
+  } catch (error) {
+    console.error(`${action}失败:`, error);
+    proxy?.$modal.msgError(`${action}失败`);
+  }
+};
+
+
+/** 库存修改弹框 */
+const inventoryDialog = reactive({
+  visible: false,
+  loading: false,
+  submitLoading: false
+});
+
+const inventoryFormRef = ref<ElFormInstance>();
+
+const inventoryForm = reactive<PriceInventoryForm>({
+  productId: undefined,
+  totalInventory: undefined,
+  nowInventory: undefined,
+  virtualInventory: undefined
+});
+
+const inventoryRules = {
+  totalInventory: [{ required: true, message: '总库存不能为空', trigger: 'blur' }],
+  nowInventory: [{ required: true, message: '当前可用库存不能为空', trigger: 'blur' }],
+  virtualInventory: [{ required: true, message: '虚拟库存不能为空', trigger: 'blur' }]
+};
+
+/** 打开库存修改弹框 */
+const handleSupply = async (row: BaseVO) => {
+  inventoryForm.id = row.id;
+  inventoryForm.totalInventory = undefined;
+  inventoryForm.nowInventory = undefined;
+  inventoryForm.virtualInventory = undefined;
+  inventoryDialog.loading = true;
+  inventoryDialog.visible = true;
+  try {
+    const res = await getBase(row.id);
+    if (res.data) {
+      inventoryForm.totalInventory = res.data.totalInventory;
+      inventoryForm.nowInventory = res.data.nowInventory;
+      inventoryForm.virtualInventory = res.data.virtualInventory;
+    }
+  } catch (error) {
+    console.error('获取库存信息失败:', error);
+  } finally {
+    inventoryDialog.loading = false;
+  }
+};
+
+/** 提交库存修改 */
+const submitInventory = async () => {
+  await inventoryFormRef.value?.validate();
+  inventoryDialog.submitLoading = true;
+  try {
+    await updateBase({ ...inventoryForm });
+    proxy?.$modal.msgSuccess('库存修改成功');
+    inventoryDialog.visible = false;
+    await getList();
+  } catch (error) {
+    console.error('库存修改失败:', error);
+    proxy?.$modal.msgError('库存修改失败');
+  } finally {
+    inventoryDialog.submitLoading = false;
+  }
+};
+
+/** 停售操作 */
+const handleDiscontinue = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认停售该商品吗?停售后商品将无法正常售卖。');
+
+  try {
+    // 调用停售API,将商品类型改为3(停售商品)
+    await changeProductType({
+      id: row.id,
+      productCategory: 3
+    });
+    proxy?.$modal.msgSuccess('停售成功');
+    await getList();
+  } catch (error) {
+    console.error('停售失败:', error);
+    proxy?.$modal.msgError('停售失败');
+  }
+};
+
+/** 加入自营池操作 */
+const handleAddToSelfPool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入自营池吗?');
+
+  try {
+    await addProductSelf({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入自营池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入自营池失败:', error);
+    proxy?.$modal.msgError('加入自营池失败');
+  }
+};
+
+/** 加入精品池操作 */
+const handleAddToExquisitePool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入精品池吗?');
+
+  try {
+    await addProductExquisite({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入精品池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入精品池失败:', error);
+    proxy?.$modal.msgError('加入精品池失败');
+  }
+};
+
+/** 审核通过 */
+const handleAudit = async (row: ProductListVO) => {
+  if (!row.poolAuditId) {
+    proxy?.$modal.msgWarning('该商品未关联入池单,无法审核');
+    return;
+  }
+  await proxy?.$modal.confirm(`确认审核通过商品"${row.itemName}"吗?`);
+  try {
+    await audit({
+      poolAuditId: row.poolAuditId,
+      productIds: [row.productId],
+      auditStatus: 2
+    });
+    proxy?.$modal.msgSuccess('审核通过成功');
+    await getList();
+  } catch (error) {
+    console.error('审核失败:', error);
+  }
+};
+
+/** 驳回 */
+const handleReject = async (row: ProductListVO) => {
+  if (!row.poolAuditId) {
+    proxy?.$modal.msgWarning('该商品未关联入池单,无法驳回');
+    return;
+  }
+  try {
+    const { value: reason } = await ElMessageBox.prompt('请输入驳回原因', '驳回', {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      inputPlaceholder: '请输入驳回原因',
+      inputValidator: (val) => (val && val.trim() ? true : '驳回原因不能为空')
+    });
+    await audit({
+      poolAuditId: row.poolAuditId,
+      productIds: [row.productId],
+      auditStatus: 3,
+      reason: reason.trim()
+    });
+    proxy?.$modal.msgSuccess('驳回成功');
+    await getList();
+  } catch (error: any) {
+    if (error !== 'cancel') {
+      console.error('驳回失败:', error);
+    }
+  }
+};
+
+/** 跳转到商品审核页面 */
+const handleGoReview = () => {
+  router.push({
+    path: '/product/base/review',
+    query: {
+      productReviewStatus: 1 // 默认显示待审核的商品
+    }
+  });
+};
+
+/** 查询分类树 */
+const getCategoryTree = async () => {
+  const res = await categoryTree();
+  categoryOptions.value = res.data || [];
+};
+
+/** 加载品牌选项(默认100条) */
+const loadBrandOptions = async (keyword?: string) => {
+  brandLoading.value = true;
+  try {
+    const res = await listBrand({ pageNum: 1, pageSize: 100, brandName: keyword });
+    brandOptions.value = res.rows || [];
+  } catch (error) {
+    console.error('加载品牌列表失败:', error);
+  } finally {
+    brandLoading.value = false;
+  }
+};
+
+/** 品牌远程搜索(防抖) */
+const handleBrandSearch = (query: string) => {
+  if (brandSearchTimer) clearTimeout(brandSearchTimer);
+  brandSearchTimer = setTimeout(() => {
+    loadBrandOptions(query || undefined);
+  }, 300);
+};
+
+/** 获取统计信息 */
+const getStatistics = async () => {
+  try {
+    const res = await getProductStatusCount();
+    if (res.data) {
+      statistics.value = res.data;
+    }
+  } catch (error) {
+    console.error('获取统计信息失败:', error);
+  }
+};
+
+
+onMounted(() => {
+  getList();
+  getStatistics();
+  loadBrandOptions();
+});
+</script>

+ 1 - 1
src/views/product/poolAuditReview/index.vue

@@ -51,7 +51,7 @@
           </template>
         </el-table-column>
         <el-table-column label="单位" align="center" prop="unitName" width="80" />
-        <el-table-column label="SKU价格" align="center" width="150">
+        <el-table-column label="价格信息" align="center" width="150">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px">
               <div>

+ 14 - 24
src/views/product/poolLink/index.vue

@@ -68,8 +68,8 @@
                 </el-form-item>
               </el-col>
               <el-col :span="6">
-                <el-form-item label="创建供应商" prop="supplier">
-                  <el-select v-model="queryParams.supplier" placeholder="请选择创建供应商" clearable filterable>
+                <el-form-item label="供应商" prop="supplier">
+                  <el-select v-model="queryParams.supplier" placeholder="请选择供应商" clearable filterable>
                     <el-option
                       v-for="item in supplierOptions"
                       :key="item.id"
@@ -125,19 +125,19 @@
             <div class="text-left" style="font-size: 12px;">
               <div>{{ scope.row.itemName }}</div>
               <div class="text-gray-500">品牌:{{ scope.row.brandName || '-' }}</div>
-              <div class="text-gray-500">库存:{{ scope.row.stock || '999' }}</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" width="150">
+        <el-table-column label="单位" align="center" width="100">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px;">
-              <div>{{ scope.row.categoryName || '办公设备+扫描设备+平板式扫描仪' }}</div>
+            <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" prop="unitName" width="80" />
-        <el-table-column label="SKU价格" align="center" width="150">
+        <el-table-column label="价格信息" align="center" width="150">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px;">
               <div>
@@ -146,11 +146,11 @@
               </div>
               <div>
                 <span class="text-gray-500">官网价:</span>
-                <span class="text-red-500">¥{{ scope.row.platformPrice || '0.00' }}</span>
+                <span class="text-red-500">¥{{ scope.row.memberPrice || '0.00' }}</span>
               </div>
               <div>
                 <span class="text-gray-500">最低售价:</span>
-                <span class="text-red-500">¥{{ scope.row.minPrice || '0.00' }}</span>
+                <span class="text-red-500">¥{{ scope.row.minSellingPrice || '0.00' }}</span>
               </div>
             </div>
           </template>
@@ -160,11 +160,11 @@
             <div class="text-left" style="font-size: 12px;">
               <div>
                 <span class="text-gray-500">采购价:</span>
-                <span>¥{{ scope.row.purchasePrice || '0.00' }}</span>
+                <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
               </div>
               <div>
                 <span class="text-gray-500">暂估毛利率:</span>
-                <span>{{ scope.row.grossMargin || '0.00' }}%</span>
+                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
               </div>
             </div>
           </template>
@@ -177,21 +177,11 @@
           </template>
         </el-table-column>
         <el-table-column label="入池时间" align="center" prop="createTime" width="120" />
-        <el-table-column label="创建供应商" align="center" width="100">
+        <el-table-column label="供应商" align="center" width="100">
           <template #default="scope">
             <span>{{ getSupplierName(scope.row.supplier) }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="产品审核状态" align="center" width="100">
-          <template #default="scope">
-            <el-tag v-if="scope.row.productReviewStatus === '0'" type="info">待提交</el-tag>
-            <el-tag v-else-if="scope.row.productReviewStatus === '1'" type="warning">待审核</el-tag>
-            <el-tag v-else-if="scope.row.productReviewStatus === '2'" type="success">审核通过</el-tag>
-            <el-tag v-else-if="scope.row.productReviewStatus === '3'" type="danger">审核驳回</el-tag>
-            <el-tag v-else type="info">未知</el-tag>
-          </template>
-        </el-table-column>
-        <el-table-column label="审核原因" align="center" prop="reviewReason" width="150" show-overflow-tooltip />
         <el-table-column label="操作" align="center" width="120" fixed="right">
           <template #default="scope">
             <div class="flex flex-col gap-1">
@@ -309,7 +299,7 @@
               </div>
             </template>
           </el-table-column>
-          <el-table-column label="SKU价格" align="center" width="150">
+          <el-table-column label="价格信息" align="center" width="150">
             <template #default="scope">
               <div class="text-left" style="font-size: 12px;">
                 <div>

+ 2 - 2
src/views/product/poolLink/index1.vue

@@ -122,7 +122,7 @@
           </template>
         </el-table-column>
         <el-table-column label="单位" align="center" prop="unitName" width="80" />
-        <el-table-column label="SKU价格" align="center" width="150">
+        <el-table-column label="价格信息" align="center" width="150">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px;">
               <div>
@@ -308,7 +308,7 @@
               </div>
             </template>
           </el-table-column>
-          <el-table-column label="SKU价格" align="center" width="150">
+          <el-table-column label="价格信息" align="center" width="150">
             <template #default="scope">
               <div class="text-left" style="font-size: 12px;">
                 <div>

+ 406 - 92
src/views/product/poolLinkAudit/index.vue

@@ -8,11 +8,11 @@
     <!-- 申请入池表单头部 -->
     <el-card shadow="hover" class="mb-[10px]">
       <el-form :model="auditForm" label-width="100px">
-        <!-- 第一行:产品池类型 + 产品册选择 -->
+        <!-- 第一行:产品池类型 + 产品册选择 + 申请类型 -->
         <el-row :gutter="20">
           <el-col :span="8">
             <el-form-item label="产品池类型" prop="type">
-              <el-select v-model="auditForm.type" placeholder="请选择产品池类型" style="width: 100%">
+              <el-select v-model="auditForm.type" placeholder="请选择产品池类型" style="width: 100%" :disabled="typeDisabled">
                 <el-option label="自营产品池" value="0" />
                 <el-option label="标准产品池" value="1" />
                 <el-option label="协议产品池" value="2" />
@@ -52,6 +52,14 @@
         </el-row>
         <!-- 第三行:附件 -->
         <el-row>
+          <el-col :span="8">
+            <el-form-item label="申请类型" prop="applyType">
+              <el-radio-group v-model="auditForm.applyType">
+                <el-radio :value="0">更新</el-radio>
+                <el-radio :value="1">移出</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
           <el-col :span="24">
             <el-form-item label="附件" prop="attachment">
               <file-upload v-model="auditForm.attachment" :file-size="20" :limit="5" />
@@ -74,31 +82,36 @@
       </template>
 
       <el-table v-loading="loading" border :data="productList">
-        <el-table-column type="index" label="序号" width="60" align="center" />
-        <el-table-column label="商品编号" align="center" prop="productNo" width="120" />
+        <el-table-column label="商品编号" align="center" prop="productNo" width="120" fixed="left">
+          <template #default="scope">
+            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
+          </template>
+        </el-table-column>
         <el-table-column label="商品图片" align="center" prop="productImage" width="100">
           <template #default="scope">
             <image-preview :src="scope.row.productImage" :width="60" :height="60" />
           </template>
         </el-table-column>
-        <el-table-column label="商品信息" align="center" min-width="200">
+        <el-table-column label="商品信息" align="center" min-width="250">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px">
-              <div>{{ scope.row.itemName }}</div>
-              <div class="text-gray-500">品牌:{{ scope.row.brandName || '-' }}</div>
-              <div class="text-gray-500">库存:{{ scope.row.stock || '999' }}</div>
+            <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.topCategoryName + '-' + scope.row.mediumCategoryName + '-' + scope.row.bottomCategoryName }}
+              </div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="商品类别" align="center" width="150">
+        <el-table-column label="单位" align="center" width="100">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px">
-              <div>{{ scope.row.categoryName || getCategoryFullPath(scope.row.bottomCategoryId) || '-' }}</div>
+            <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" prop="unitName" width="80" />
-        <el-table-column label="SKU价格" align="center" width="150">
+        <el-table-column label="价格信息" align="center" width="120">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px">
               <div>
@@ -110,49 +123,69 @@
                 <span class="text-red-500">¥{{ scope.row.memberPrice || '0.00' }}</span>
               </div>
               <div>
-                <span class="text-gray-500">最低价:</span>
+                <span class="text-gray-500">最低价:</span>
                 <span class="text-red-500">¥{{ scope.row.minSellingPrice || '0.00' }}</span>
               </div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column v-if="auditForm.type === '2'" label="协议价" align="center" width="140">
-          <template #default="scope">
-            <el-input-number
-              v-model="tempAgreementPrices[scope.row.id]"
-              :min="0"
-              :precision="2"
-              :controls="false"
-              size="small"
-              style="width: 120px"
-              placeholder="请输入协议价"
-            />
-          </template>
-        </el-table-column>
-        <el-table-column label="成本数据" align="center" width="150">
+
+        <el-table-column label="采购信息" align="center" width="150">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px">
               <div>
                 <span class="text-gray-500">采购价:</span>
-                <span>¥{{ scope.row.purchasePrice || '0.00' }}</span>
+                <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
               </div>
               <div>
                 <span class="text-gray-500">暂估毛利率:</span>
-                <span>{{ scope.row.grossMargin ?? scope.row.tempGrossMargin ?? '0.00' }}%</span>
+                <span
+                  >{{
+                    scope.row.memberPrice
+                      ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2)
+                      : '0.00'
+                  }}%</span
+                >
               </div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="商品状态" align="center" width="80">
+        <el-table-column v-if="auditForm.type === '3'" label="第三方售价" align="center" width="100">
+          <template #default="scope">
+            <span class="text-red-500">¥{{ tempProjectProductInfo[scope.row.id]?.negotiatedPrice?.toFixed(2) || '0.00' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column v-if="auditForm.type === '3'" label="计价规则" align="center" width="90">
           <template #default="scope">
-            <el-tag v-if="String(scope.row.productStatus) === '1'" type="success">上架</el-tag>
-            <el-tag v-else type="warning">下架</el-tag>
+            {{
+              tempProjectProductInfo[scope.row.id]?.pricingRule === '0'
+                ? '一品一率'
+                : tempProjectProductInfo[scope.row.id]?.pricingRule === '1'
+                  ? '折扣率'
+                  : '-'
+            }}
           </template>
         </el-table-column>
-        <el-table-column label="入池时间" align="center" prop="createTime" width="120" />
-        <el-table-column label="创建供应商" align="center" width="100">
+        <el-table-column v-if="auditForm.type === '3'" label="第三方分类" align="center" width="160">
           <template #default="scope">
-            <span>{{ getSupplierName(scope.row.supplier) }}</span>
+            {{ tempProjectProductInfo[scope.row.id]?.categoryName || '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column label="商品类型" align="center" prop="productReviewStatus" width="90">
+          <template #default="scope">
+            <span v-if="scope.row.productReviewStatus === 0">待采购审核</span>
+            <span v-else-if="scope.row.productReviewStatus === 1">审核通过</span>
+            <span v-else-if="scope.row.productReviewStatus === 2">驳回</span>
+            <span v-else-if="scope.row.productReviewStatus === 3">待营销审核</span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="上下架状态" align="center" prop="productStatus" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.productStatus === 1" type="success">已上架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 0" type="warning">下架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 2" type="info">上架中</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
           </template>
         </el-table-column>
         <el-table-column label="操作" align="center" width="120" fixed="right">
@@ -207,9 +240,6 @@
       <div class="add-product-dialog">
         <!-- 搜索区域 -->
         <el-form :model="addProductQuery" :inline="true" class="mb-4">
-          <el-form-item>
-            <el-button type="primary" icon="Plus" @click="handleBatchAdd">加入清单</el-button>
-          </el-form-item>
           <el-form-item label="商品名称:" label-width="80px">
             <el-input v-model="addProductQuery.itemName" placeholder="商品名称" clearable style="width: 200px" />
           </el-form-item>
@@ -219,6 +249,9 @@
           <el-form-item>
             <el-button type="primary" icon="Search" @click="handleSearchProducts">搜索</el-button>
           </el-form-item>
+          <el-form-item v-if="auditForm.type !== '2' && auditForm.type !== '3'">
+            <el-button type="primary" icon="Plus" @click="handleBatchAdd">加入清单</el-button>
+          </el-form-item>
         </el-form>
 
         <!-- 商品列表 -->
@@ -237,70 +270,97 @@
               <image-preview :src="scope.row.productImage" :width="60" :height="60" />
             </template>
           </el-table-column>
-          <el-table-column label="商品信息" align="center" min-width="200">
+          <el-table-column label="商品信息" align="center" min-width="250">
             <template #default="scope">
-              <div class="text-left" style="font-size: 12px">
-                <div>{{ scope.row.itemName }}</div>
-                <div class="text-gray-500">品牌:{{ scope.row.brandName || '雅唐' }}</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>{{ getCategoryName(scope.row) }}</div>
+              <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.topCategoryName + '-' + scope.row.mediumCategoryName + '-' + scope.row.bottomCategoryName }}
+                </div>
               </div>
             </template>
           </el-table-column>
           <el-table-column label="单位" align="center" width="100">
             <template #default="scope">
-              <div class="text-left" style="font-size: 12px">
-                <div>单位:{{ scope.row.unitName || '件' }}</div>
-                <div>起订量:{{ scope.row.minOrderQuantity || 1 }}</div>
+              <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="SKU价格" align="center" width="150">
+          <el-table-column label="价格信息" align="center" width="120">
             <template #default="scope">
               <div class="text-left" style="font-size: 12px">
                 <div>
                   <span class="text-gray-500">市场价:</span>
-                  <span>¥{{ scope.row.midRangePrice || '0.00' }}</span>
+                  <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
                 </div>
                 <div>
                   <span class="text-gray-500">官网价:</span>
-                  <span class="text-red-500">¥{{ scope.row.standardPrice || '0.00' }}</span>
+                  <span class="text-red-500">¥{{ scope.row.memberPrice || '0.00' }}</span>
                 </div>
                 <div>
                   <span class="text-gray-500">最低价:</span>
-                  <span>¥{{ scope.row.certificatePrice || '0.00' }}</span>
+                  <span class="text-red-500">¥{{ scope.row.minSellingPrice || '0.00' }}</span>
                 </div>
               </div>
             </template>
           </el-table-column>
-          <el-table-column v-if="auditForm.type === '2'" label="协议价" align="center" width="140">
+
+          <el-table-column label="采购信息" align="center" width="150">
             <template #default="scope">
-              <el-input-number
-                v-model="priceInputMap[scope.row.id]"
-                :min="0"
-                :precision="2"
-                :controls="false"
-                size="small"
-                style="width: 120px"
-                placeholder="请输入协议价"
-              />
+              <div class="text-left" style="font-size: 12px">
+                <div>
+                  <span class="text-gray-500">采购价:</span>
+                  <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
+                </div>
+                <div>
+                  <span class="text-gray-500">暂估毛利率:</span>
+                  <span
+                    >{{
+                      scope.row.memberPrice
+                        ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2)
+                        : '0.00'
+                    }}%</span
+                  >
+                </div>
+              </div>
             </template>
           </el-table-column>
-          <el-table-column label="库存情况" align="center" width="150">
+          <el-table-column label="库存情况" align="center" width="140">
             <template #default="scope">
               <div class="text-left" style="font-size: 12px">
-                <div class="text-red-500">库存总数:{{ scope.row.stock || 0 }}</div>
-                <div>现有库存:{{ scope.row.availableStock || 0 }}</div>
-                <div>虚拟库存:{{ scope.row.virtualStock || 0 }}</div>
-                <div class="text-orange-500">[现有库存不足时]</div>
+                <div>
+                  <span class="text-gray-500">总库存:</span>
+                  <span>{{ scope.row.totalInventory ?? '-' }}</span>
+                </div>
+                <div>
+                  <span class="text-gray-500">可用库存:</span>
+                  <span>{{ scope.row.nowInventory ?? '-' }}</span>
+                </div>
+                <div>
+                  <span class="text-gray-500">虚拟库存:</span>
+                  <span>{{ scope.row.virtualInventory ?? '-' }}</span>
+                </div>
               </div>
             </template>
           </el-table-column>
+          <el-table-column label="是否自营" align="center" width="80">
+            <template #default="scope">
+              <span v-if="scope.row.isSelf === 1">是</span>
+              <span v-else-if="scope.row.isSelf === 0">否</span>
+              <span v-else>-</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="上下架状态" align="center" prop="productStatus" width="100">
+            <template #default="scope">
+              <el-tag v-if="scope.row.productStatus === 1" type="success">已上架</el-tag>
+              <el-tag v-else-if="scope.row.productStatus === 0" type="warning">下架</el-tag>
+              <el-tag v-else-if="scope.row.productStatus === 2" type="info">上架中</el-tag>
+              <el-tag v-else type="info">未知</el-tag>
+            </template>
+          </el-table-column>
           <el-table-column label="供应情况" align="center" width="150">
             <template #default="scope">
               <div class="text-left" style="font-size: 12px">
@@ -329,6 +389,62 @@
         />
       </div>
     </el-dialog>
+
+    <!-- 选择第三方产品分类弹框(项目产品池) -->
+    <el-dialog title="选择第三方产品分类" v-model="thirdPartyDialog.visible" width="520px" append-to-body :destroy-on-close="true">
+      <el-form label-width="130px">
+        <el-form-item label="价格模式:">
+          <el-radio-group v-model="thirdPartyDialog.pricingRule">
+            <el-radio label="0">一品一率</el-radio>
+            <el-radio label="1">折扣率</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="* 第三方产品分类:">
+          <el-cascader
+            ref="categoryRef"
+            v-model="thirdPartyDialog.categoryValue"
+            :props="categoryLazyProps"
+            style="width: 100%"
+            placeholder="请选择"
+            clearable
+            @change="handleCategoryChange"
+          />
+        </el-form-item>
+        <el-form-item v-if="thirdPartyDialog.pricingRule === '1'" label="折扣率:">
+          <span>{{ thirdPartyDialog.discountRate !== undefined ? thirdPartyDialog.discountRate : '-' }}</span>
+        </el-form-item>
+        <el-form-item label="* 第三方平台售价:">
+          <el-input-number
+            v-model="thirdPartyDialog.negotiatedPrice"
+            :disabled="thirdPartyDialog.pricingRule === '1'"
+            :precision="2"
+            :min="0"
+            controls-position="right"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item label="市场价:">
+          <span>{{ thirdPartyDialog.row?.marketPrice || 0 }}</span>
+        </el-form-item>
+        <el-form-item label="官网价:">
+          <span>{{ thirdPartyDialog.row?.memberPrice || 0 }}</span>
+        </el-form-item>
+        <el-form-item label="起订量:">
+          <el-input-number v-model="thirdPartyDialog.minOrderQuantity" :min="1" controls-position="right" style="width: 100%" />
+        </el-form-item>
+        <el-form-item label="最低售价:">
+          <span class="text-red-500">¥{{ thirdPartyDialog.row?.minSellingPrice || 0 }}</span>
+        </el-form-item>
+      </el-form>
+      <div class="mx-1 mb-3 px-3 py-2 rounded flex items-center gap-1 text-sm" style="background: #fff9f0; border: 1px solid #ffd591; color: #d48806">
+        <el-icon><i-ep-warning /></el-icon>
+        <span>(当选价不能低于最低售价,不低于官网价)</span>
+      </div>
+      <template #footer>
+        <el-button @click="thirdPartyDialog.visible = false">返回</el-button>
+        <el-button type="primary" @click="handleConfirmThirdParty">确认</el-button>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
@@ -337,7 +453,6 @@ import { useRouter, useRoute } from 'vue-router';
 import { categoryTree, listBase } from '@/api/product/base';
 import { BaseVO, BaseQuery } from '@/api/product/base/types';
 import { getPoolAudit, updatePoolAudit, addPoolAudit } from '@/api/product/poolAudit';
-import { getPoolLinkAudit } from '@/api/product/poolLinkAudit';
 import { listInfo } from '@/api/customer/supplierInfo';
 import { InfoVO } from '@/api/customer/supplierInfo/types';
 import { listBrand } from '@/api/product/brand';
@@ -350,6 +465,8 @@ import { InfoVO as ProtocolInfoVO } from '@/api/product/protocolInfo/types';
 import { getPool, listPool } from '@/api/product/pool';
 import { PoolVO } from '@/api/product/pool/types';
 import * as XLSX from 'xlsx';
+import { listProductCategory } from '@/api/external/productCategory';
+import { ProductCategoryVO } from '@/api/external/productCategory/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const router = useRouter();
@@ -367,6 +484,7 @@ const poolInfo = ref<PoolVO | undefined>();
 
 // 申请入池表单数据
 const auditForm = reactive<PoolAuditForm>({
+  id: undefined,
   type: undefined,
   name: undefined,
   poolId: undefined,
@@ -374,7 +492,8 @@ const auditForm = reactive<PoolAuditForm>({
   itemId: undefined,
   remark: undefined,
   attachment: undefined,
-  productIds: []
+  productIds: [],
+  applyType: 0
 });
 
 /** 下拉选项数据 */
@@ -400,7 +519,7 @@ const loadSelectOptions = async (type?: string | number) => {
 // 回显时屏蔽 watch 副作用
 const isInitializing = ref(false);
 
-/** 切换产品池类型时,清空关联选择并重新加载选项 */
+/** 切换产品池类型时,清空关联选择并重新加载选项,同时清空商品列表 */
 watch(
   () => auditForm.type,
   (newType) => {
@@ -409,12 +528,32 @@ watch(
     auditForm.protocolId = undefined;
     auditForm.itemId = undefined;
     auditForm.name = undefined;
+    // 切换类型时清空商品列表
+    tempProductIds.value = '';
+    Object.keys(tempAgreementPrices).forEach((key) => delete tempAgreementPrices[key]);
+    productList.value = [];
+    total.value = 0;
     if (newType !== undefined && newType !== null) {
       loadSelectOptions(newType);
     }
   }
 );
 
+/** 切换具体产品池/协议/项目时,清空商品列表 */
+watch(
+  () => [auditForm.poolId, auditForm.protocolId, auditForm.itemId] as const,
+  (newVal, oldVal) => {
+    if (isInitializing.value) return;
+    const changed = newVal.some((v, i) => v !== oldVal[i]);
+    if (changed) {
+      tempProductIds.value = '';
+      Object.keys(tempAgreementPrices).forEach((key) => delete tempAgreementPrices[key]);
+      productList.value = [];
+      total.value = 0;
+    }
+  }
+);
+
 const queryParams = ref({
   pageNum: 1,
   pageSize: 10,
@@ -428,6 +567,10 @@ const queryParams = ref({
   dateRange: undefined
 });
 
+/** 路由传入的产品池类型(存在时禁用类型下拉) */
+const routeType = computed(() => route.query.type as string | undefined);
+const typeDisabled = computed(() => !!routeType.value && routeType.value !== 'undefined' && routeType.value !== '-1');
+
 const categoryOptions = ref<any[]>([]);
 const categoryMap = ref<Map<string | number, any>>(new Map());
 const supplierOptions = ref<InfoVO[]>([]);
@@ -476,6 +619,61 @@ const tempProductIds = ref<string>('');
 // 临时展示用:本地暂存的协议价(type=2)
 const tempAgreementPrices = reactive<Record<string | number, number | undefined>>({});
 
+// 第三方产品分类弹框状态(type=3 项目产品池时使用)
+const thirdPartyDialog = reactive({
+  visible: false,
+  row: null as BaseVO | null,
+  pricingRule: '0' as '0' | '1',
+  categoryValue: [] as (string | number)[],
+  discountRate: undefined as number | undefined,
+  negotiatedPrice: 0 as number,
+  minOrderQuantity: 1 as number
+});
+
+// 分类折扣率缓存(categoryId -> discountRate)
+const categoryDiscountMap = ref<Record<string | number, number | undefined>>({});
+
+// 项目产品池商品额外信息(type=3 时存储第三方售价、计价规则、分类)
+const tempProjectProductInfo = reactive<
+  Record<
+    string | number,
+    {
+      negotiatedPrice: number;
+      pricingRule: '0';
+      categoryId: string | number | null;
+      categoryName: string;
+      minOrderQuantity: number;
+    }
+  >
+>({});
+
+// 第三方分类级联选择器 ref
+const categoryRef = ref<any>();
+
+// 分类懒加载配置(最多3级,itemId 来自 auditForm.itemId)
+const categoryLazyProps = {
+  lazy: true,
+  lazyLoad: (node: any, resolve: (data: any[]) => void) => {
+    const { level, value } = node;
+    const parentId = level === 0 ? 0 : value;
+    listProductCategory({ itemId: auditForm.itemId as any, parentId } as any)
+      .then((res) => {
+        const data = (res.rows || []) as ProductCategoryVO[];
+        data.forEach((item) => {
+          categoryDiscountMap.value[item.id] = item.discountRate;
+        });
+        resolve(
+          data.map((item) => ({
+            value: item.id,
+            label: item.categoryName,
+            leaf: (item.classLevel !== undefined && item.classLevel >= 3) || !item.hasChildren
+          }))
+        );
+      })
+      .catch(() => resolve([]));
+  }
+};
+
 /** 获取审核状态标签文字 */
 const getStatusLabel = (status?: string): string => {
   const map: Record<string, string> = { '0': '待提交', '1': '待审核', '2': '审核通过', '3': '审核驳回' };
@@ -499,12 +697,14 @@ const loadAuditInfo = async () => {
   if (!id) return;
   auditInfoLoading.value = true;
   try {
-    const res = await getPoolLinkAudit(id as string | number);
-    const data = res.data as any;
-    auditInfo.value = data;
+    // 调用 getPoolAudit 获取审核信息
+    const res = await getPoolAudit(id as string | number);
+    const data = res.data as PoolAuditVO;
+    auditInfo.value = data as any;
 
     // 回显表单,先设标志位防止 watch 清空字段
     isInitializing.value = true;
+    auditForm.id = data.id;
     auditForm.type = data.type !== undefined && data.type !== null ? String(data.type) : undefined;
     auditForm.name = data.name;
     auditForm.poolId = data.poolId;
@@ -512,6 +712,7 @@ const loadAuditInfo = async () => {
     auditForm.itemId = data.itemId;
     auditForm.remark = data.remark;
     auditForm.attachment = data.attachment;
+    auditForm.applyType = data.applyType;
     isInitializing.value = false;
 
     // 加载对应下拉选项
@@ -520,7 +721,7 @@ const loadAuditInfo = async () => {
     }
 
     // 从 products 初始化商品 ID 列表和协议价
-    const products: Array<{ productId: string | number; agreementPrice?: number }> = data.products || [];
+    const products: Array<{ productId: string | number; agreementPrice?: number }> = (data as any).products || [];
     tempProductIds.value = products.map((p: any) => p.productId).join(',');
     products.forEach((p: any) => {
       if (p.agreementPrice !== undefined && p.agreementPrice !== null) {
@@ -659,7 +860,7 @@ const handleApplyPool = async () => {
   await proxy?.$modal.confirm('确认要申请入池吗?提交后状态将变为待审核。');
   const id = auditInfo.value?.id;
   if (!id) return;
-  await updatePoolAudit({ id, productReviewStatus: '1' });
+  await updatePoolAudit({ id, productReviewStatus: '0' });
   proxy?.$modal.msgSuccess('申请成功,状态已变为待审核');
   await loadAuditInfo();
 };
@@ -682,10 +883,6 @@ const handleSubmitAudit = async () => {
     proxy?.$modal.msgWarning('请选择项目');
     return;
   }
-  if (auditForm.type === '1' && !auditForm.name) {
-    proxy?.$modal.msgWarning('请输入产品池名称');
-    return;
-  }
   if (!tempProductIds.value) {
     proxy?.$modal.msgWarning('请先添加商品到入池清单');
     return;
@@ -702,12 +899,24 @@ const handleSubmitAudit = async () => {
         .filter((id) => id)
         .map((id) => ({
           productId: id,
-          negotiatedPrice: tempAgreementPrices[id]
+          negotiatedPrice: tempAgreementPrices[id],
+          ...(auditForm.type === '3' && tempProjectProductInfo[id]
+            ? {
+                negotiatedPrice: tempProjectProductInfo[id].negotiatedPrice,
+                pricingRule: tempProjectProductInfo[id].pricingRule,
+                categoryId: tempProjectProductInfo[id].categoryId,
+                categoryName: tempProjectProductInfo[id].categoryName
+              }
+            : {})
         })),
-      productReviewStatus: '1' // 提交后状态为待审核
+      productReviewStatus: '0' // 提交后状态为待申请
     };
+    if (!auditForm.id) {
+      await addPoolAudit(submitData);
+    } else {
+      await updatePoolAudit(submitData);
+    }
 
-    await addPoolAudit(submitData);
     proxy?.$modal.msgSuccess('提交成功');
     goBack();
   } catch (error) {
@@ -727,6 +936,7 @@ const handleClearPool = async () => {
 
 /** 导入商品按钮 */
 const handleImport = () => {
+  if (!checkPoolSelected()) return;
   importDialog.open = true;
   importDialog.isUploading = false;
   importDialog.selectedFile = null;
@@ -849,8 +1059,26 @@ const submitFileForm = async () => {
   }
 };
 
+/** 检查营销/协议/项目产品池是否已选择对应池 */
+const checkPoolSelected = (): boolean => {
+  if (auditForm.type === '4' && !auditForm.poolId) {
+    proxy?.$modal.msgWarning('请先选择产品池');
+    return false;
+  }
+  if (auditForm.type === '2' && !auditForm.protocolId) {
+    proxy?.$modal.msgWarning('请先选择协议');
+    return false;
+  }
+  if (auditForm.type === '3' && !auditForm.itemId) {
+    proxy?.$modal.msgWarning('请先选择项目');
+    return false;
+  }
+  return true;
+};
+
 /** 添加商品 */
 const handleAddProduct = () => {
+  if (!checkPoolSelected()) return;
   addProductDialog.visible = true;
   addProductQuery.value = {
     pageNum: 1,
@@ -873,9 +1101,10 @@ const getProductList = async () => {
   addProductDialog.loading = true;
   try {
     const params = { ...addProductQuery.value };
-    //如果选择的是自营商品isSelf=1
-    params.isSelf = auditForm.type == 0 ? 0 : undefined;
-    params.isSelf = auditForm.type == 2 ? 1 : undefined;
+    // 标准产品池(type=1)或协议产品池(type=2)时查询自营产品
+    if (auditForm.type === '1' || auditForm.type === '2') {
+      params.isSelf = 1;
+    }
     const currentPageNum = addProductQuery.value.pageNum;
 
     if (currentPageNum === 1) {
@@ -995,6 +1224,18 @@ const handleAddSingleProduct = async (row: BaseVO) => {
     return;
   }
 
+  // 项目产品池:弹出第三方产品分类弹框
+  if (auditForm.type === '3') {
+    thirdPartyDialog.row = row;
+    thirdPartyDialog.pricingRule = '0';
+    thirdPartyDialog.categoryValue = [];
+    thirdPartyDialog.discountRate = undefined;
+    thirdPartyDialog.negotiatedPrice = 0;
+    thirdPartyDialog.minOrderQuantity = Number(row.minOrderQuantity) || 1;
+    thirdPartyDialog.visible = true;
+    return;
+  }
+
   const isProtocol = auditForm.type === '2';
   tempProductIds.value = tempProductIds.value ? `${tempProductIds.value},${idStr}` : idStr;
   tempAgreementPrices[row.id] = isProtocol ? (priceInputMap[row.id] ?? row.standardPrice ?? row.midRangePrice) : undefined;
@@ -1003,6 +1244,71 @@ const handleAddSingleProduct = async (row: BaseVO) => {
   await getList();
 };
 
+/** 处理第三方产品分类选择变化 */
+const handleCategoryChange = (value: (string | number)[]) => {
+  if (!value || value.length === 0) {
+    thirdPartyDialog.discountRate = undefined;
+    return;
+  }
+  const lastId = value[value.length - 1];
+  thirdPartyDialog.discountRate = categoryDiscountMap.value[lastId];
+  if (thirdPartyDialog.pricingRule === '1') {
+    const memberPrice = Number(thirdPartyDialog.row?.memberPrice) || 0;
+    const rate = thirdPartyDialog.discountRate || 0;
+    thirdPartyDialog.negotiatedPrice = parseFloat((memberPrice * rate).toFixed(2));
+  }
+};
+
+/** 切换价格模式时重新计算售价 */
+watch(
+  () => thirdPartyDialog.pricingRule,
+  (mode) => {
+    if (mode === 'discount') {
+      const memberPrice = Number(thirdPartyDialog.row?.memberPrice) || 0;
+      const rate = thirdPartyDialog.discountRate || 0;
+      thirdPartyDialog.negotiatedPrice = parseFloat((memberPrice * rate).toFixed(2));
+    }
+  }
+);
+
+/** 确认选择第三方产品分类,加入入池清单 */
+const handleConfirmThirdParty = async () => {
+  if (!thirdPartyDialog.categoryValue || thirdPartyDialog.categoryValue.length === 0) {
+    proxy?.$modal.msgWarning('请选择第三方产品分类');
+    return;
+  }
+  if (thirdPartyDialog.negotiatedPrice <= 0) {
+    proxy?.$modal.msgWarning('请输入有效的第三方平台售价');
+    return;
+  }
+  const row = thirdPartyDialog.row!;
+  const idStr = String(row.id);
+  const categoryId = thirdPartyDialog.categoryValue[thirdPartyDialog.categoryValue.length - 1] ?? null;
+
+  // 从级联选择器获取路径标签
+  let categoryName = '';
+  const checkedNodes = categoryRef.value?.getCheckedNodes(true);
+  if (checkedNodes && checkedNodes.length > 0) {
+    categoryName = (checkedNodes[0].pathLabels || []).join(' / ');
+  }
+
+  // 加入临时 ID 列表
+  tempProductIds.value = tempProductIds.value ? `${tempProductIds.value},${idStr}` : idStr;
+
+  // 存储项目商品额外信息
+  tempProjectProductInfo[row.id] = {
+    negotiatedPrice: thirdPartyDialog.negotiatedPrice,
+    pricingRule: thirdPartyDialog.pricingRule,
+    categoryId,
+    categoryName,
+    minOrderQuantity: thirdPartyDialog.minOrderQuantity
+  };
+
+  thirdPartyDialog.visible = false;
+  proxy?.$modal.msgSuccess('添加成功');
+  await getList();
+};
+
 /** 获取分类名称 */
 const getCategoryName = (row: BaseVO): string => {
   if (row.bottomCategoryId) {
@@ -1026,7 +1332,15 @@ const handleRemoveProduct = async (row: BaseVO) => {
   await getList();
 };
 
-onMounted(() => {
+onMounted(async () => {
+  // 新增场景:有路由 type 但无 id,自动填充并加载选项
+  const hasId = route.params.id || route.query.id;
+  if (!hasId && typeDisabled.value && routeType.value) {
+    isInitializing.value = true;
+    auditForm.type = routeType.value;
+    isInitializing.value = false;
+    await loadSelectOptions(routeType.value);
+  }
   loadAuditInfo();
   getCategoryTree();
   getSupplierList();

+ 20 - 19
src/views/product/protocolInfo/index.vue

@@ -41,14 +41,14 @@
       </template>
 
       <el-table v-loading="loading" border :data="infoList" @selection-change="handleSelectionChange">
-        <el-table-column label="创建时间" align="center" prop="createTime" width="120">
-          <template #default="scope">
-            <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
-          </template>
-        </el-table-column>
+<!--        <el-table-column label="创建时间" align="center" prop="createTime" width="120">-->
+<!--          <template #default="scope">-->
+<!--            <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
         <el-table-column label="客户编号" align="center" prop="customerNo" width="100" />
         <el-table-column label="客户名称" align="center" prop="customerName" min-width="180" />
-        <el-table-column label="业务员" align="center" prop="salesmanName" width="100" />
+        <el-table-column label="负责人" align="center" prop="salesmanName" width="100" />
         <el-table-column label="客服" align="center" prop="serviceName" width="100" />
         <el-table-column label="截止时间" align="center" prop="endTime" width="120">
           <template #default="scope">
@@ -56,11 +56,11 @@
           </template>
         </el-table-column>
         <el-table-column label="商品数量" align="center" prop="productNum" width="100" />
-        <!-- <el-table-column label="状态" align="center" prop="approvalStatus" width="80">
+        <el-table-column label="状态" align="center" prop="approvalStatus" width="80">
           <template #default="scope">
             <span>{{ getStatusLabel(scope.row.protocolStatus) }}</span>
           </template>
-        </el-table-column> -->
+        </el-table-column>
         <el-table-column label="操作" align="center" fixed="right" width="300" class-name="small-padding fixed-width">
           <template #default="scope">
             <el-button link type="primary" @click="handleDetail(scope.row)" >基本信息</el-button>
@@ -78,19 +78,19 @@
     <el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
       <el-form ref="infoFormRef" :model="form" :rules="rules" label-width="100px">
         <el-form-item label="客户名称" prop="customerId">
-          <el-select 
-            v-model="form.customerId" 
-            placeholder="请选择" 
-            clearable 
+          <el-select
+            v-model="form.customerId"
+            placeholder="请选择"
+            clearable
             filterable
             :disabled="dialog.isView"
             @change="handleCustomerChange"
             style="width: 100%"
           >
-            <el-option 
-              v-for="item in customerList" 
-              :key="item.id" 
-              :label="item.customerName" 
+            <el-option
+              v-for="item in customerList"
+              :key="item.id"
+              :label="item.customerName"
               :value="item.id"
             />
           </el-select>
@@ -113,7 +113,7 @@
         <el-row :gutter="20">
           <el-col :span="12">
             <el-form-item label="起始时间" prop="startTime">
-              <el-date-picker 
+              <el-date-picker
                 v-model="form.startTime"
                 type="date"
                 placeholder="请选择"
@@ -125,7 +125,7 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="截止时间" prop="endTime">
-              <el-date-picker 
+              <el-date-picker
                 v-model="form.endTime"
                 type="date"
                 placeholder="请选择"
@@ -176,6 +176,7 @@ import { listInfo, getInfo, delInfo, addInfo, updateInfo } from '@/api/product/p
 import { InfoVO, InfoQuery, InfoForm } from '@/api/product/protocolInfo/types';
 import { listCustomerInfo } from '@/api/customer/customerInfo';
 import { CustomerInfoVO } from '@/api/customer/customerInfo/types';
+import { parseTime } from '../../../utils/ruoyi';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const router = useRouter();
@@ -312,7 +313,7 @@ const handleCustomerChange = (customerId: string | number) => {
     // 公司名称显示客户名称
     form.value.companyId = customer.belongCompanyId;
     form.value.companyName = customer.customerName;
-    
+
     // 从客户信息中获取业务员和客服信息
     if (customer.customerSalesInfoVo) {
       form.value.salesmanId = customer.customerSalesInfoVo.salesPersonId;

+ 66 - 45
src/views/product/protocolInfo/productManage.vue

@@ -66,75 +66,87 @@
       </template>
 
       <el-table v-loading="loading" border :data="productsList">
-        <el-table-column label="品编号" align="center" prop="productNo" width="120" />
-        <el-table-column label="商品图片" align="center" width="100">
+        <el-table-column label="品编号" align="center" prop="productNo" width="120" />
+        <el-table-column label="商品图片" align="center" prop="productImage" width="100">
           <template #default="scope">
             <image-preview :src="scope.row.productImage" :width="60" :height="60"/>
           </template>
         </el-table-column>
-        <el-table-column label="商品名称" align="center" min-width="180">
+        <el-table-column label="商品信息" align="center" min-width="200">
           <template #default="scope">
-            <div>
-              <div class="text-primary">{{ scope.row.itemName }}</div>
-              <div class="text-gray-400 text-sm">{{ scope.row.brandName }}</div>
+            <div class="text-left" style="font-size: 12px;">
+              <div>{{ scope.row.itemName }}</div>
+              <div class="text-gray-500">品牌:{{ scope.row.brandName || '-' }}</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="categoryName" width="100" />
-        <el-table-column label="单位" align="center" prop="unitName" width="80" />
-        <el-table-column label="Sku价格" align="center" width="170">
+        <el-table-column label="单位" align="center" width="100">
           <template #default="scope">
             <div class="text-left">
-              <div>市场价: ¥{{ scope.row.marketPrice || 0 }}</div>
-              <div class="text-red-500">官网价: ¥{{ scope.row.memberPrice || 0 }}</div>
-              <div>标准成本: ¥{{ scope.row.purchasingPrice || 0 }}</div>
-              <div>最低售价: ¥{{ scope.row.minSellingPrice || 0 }}</div>
+              <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" prop="dataSource" width="100" />
-        <el-table-column label="状态" align="center" width="80">
+        <el-table-column label="价格信息" align="center" width="150">
           <template #default="scope">
-            <span :class="scope.row.productStatus === '1' ? 'text-green-500' : 'text-red-500'">
-              {{ scope.row.productStatus === '1' ? '上架' : '下架' }}
-            </span>
-          </template>
-        </el-table-column>
-        <!-- <el-table-column label="审核状态" align="center" width="100">
-          <template #default="scope">
-            <el-tag v-if="scope.row.auditStatus === 1" type="warning">待审核</el-tag>
-            <el-tag v-else-if="scope.row.auditStatus === 2" type="success">审核通过</el-tag>
-            <el-tag v-else-if="scope.row.auditStatus === 3" type="danger">审核驳回</el-tag>
-            <span v-else>-</span>
+            <div class="text-left" style="font-size: 12px;">
+              <div>
+                <span class="text-gray-500">市场价:</span>
+                <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">官网价:</span>
+                <span class="text-red-500">¥{{ scope.row.memberPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">最低售价:</span>
+                <span class="text-red-500">¥{{ scope.row.minSellingPrice || '0.00' }}</span>
+              </div>
+            </div>
           </template>
         </el-table-column>
-        <el-table-column label="审核意见" align="center" width="150" show-overflow-tooltip>
-          <template #default="scope">
-            <span>{{ scope.row.auditReason || '-' }}</span>
-          </template>
-        </el-table-column> -->
-        <el-table-column label="协议供货价" align="center" width="140">
+        <el-table-column label="成本数据" align="center" width="150">
           <template #default="scope">
-            <el-input-number
-              v-model="scope.row.agreementPrice"
-              :min="0"
-              :precision="2"
-              size="small"
-              controls-position="right"
-              @change="handlePriceChange(scope.row)"
-            />
+            <div class="text-left" style="font-size: 12px;">
+              <div>
+                <span class="text-gray-500">采购价:</span>
+                <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">暂估毛利率:</span>
+                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
+              </div>
+            </div>
           </template>
         </el-table-column>
-        <el-table-column label="供货价毛利率" align="center" width="120">
+        <!-- <el-table-column label="项目官网价" align="center" prop="platformPrice" width="100" /> -->
+        <el-table-column label="商品状态" align="center" width="80">
           <template #default="scope">
-            {{ calculateMargin(scope.row) }}
+            <el-tag v-if="scope.row.productStatus === '1'" type="success">上架</el-tag>
+            <el-tag v-else type="warning">下架</el-tag>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center" fixed="right" width="80">
+        <el-table-column label="协议价/毛利率" align="center" width="200">
           <template #default="scope">
-            <el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
+            <div class="text-left" style="font-size: 12px;">
+              <div>
+                <span class="text-gray-500">协议价:</span>
+                <span class="text-red-500">¥{{ scope.row.agreementPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">毛利率:</span>
+                <span :class="calculateMarginClass(scope.row)">{{ calculateMargin(scope.row) }}</span>
+              </div>
+            </div>
           </template>
         </el-table-column>
+<!--        <el-table-column label="操作" align="center" fixed="right" width="80">-->
+<!--          <template #default="scope">-->
+<!--            <el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
       </el-table>
 
       <pagination
@@ -204,7 +216,7 @@
               </div>
             </template>
           </el-table-column>
-          <el-table-column label="SKU价格" align="center" width="150">
+          <el-table-column label="价格信息" align="center" width="150">
             <template #default="scope">
               <div class="text-left" style="font-size: 12px;">
                 <div>
@@ -645,6 +657,15 @@ const calculateMargin = (row: any) => {
   return margin;
 };
 
+/** 计算毛利率样式类 */
+const calculateMarginClass = (row: any) => {
+  const margin = parseFloat(calculateMargin(row));
+  if (isNaN(margin)) return '';
+  if (margin > 0) return 'text-green-500 font-semibold';
+  if (margin < 0) return 'text-red-500 font-semibold';
+  return '';
+};
+
 onMounted(() => {
   // 从路由参数获取协议ID
   protocolId.value = route.query.protocolId as string || route.params.id as string || '';

+ 3 - 3
src/views/product/protocolInfo/review.vue

@@ -88,7 +88,7 @@
         </el-table-column>
         <el-table-column label="产品类别" align="center" prop="categoryName" width="100" />
         <el-table-column label="单位" align="center" prop="unitName" width="80" />
-        <el-table-column label="Sku价格" align="center" width="140">
+        <el-table-column label="价格信息" align="center" width="140">
           <template #default="scope">
             <div class="text-left">
               <div>市场价: ¥{{ scope.row.marketPrice || 0 }}</div>
@@ -119,7 +119,7 @@
             <span>{{ scope.row.auditReason || '-' }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="协议供货价" align="center" width="140">
+        <el-table-column label="协议价" align="center" width="140">
           <template #default="scope">
             <el-input-number
               v-model="scope.row.agreementPrice"
@@ -231,7 +231,7 @@
               </div>
             </template>
           </el-table-column>
-          <el-table-column label="SKU价格" align="center" width="150">
+          <el-table-column label="价格信息" align="center" width="150">
             <template #default="scope">
               <div class="text-left" style="font-size: 12px;">
                 <div>

Неке датотеке нису приказане због велике количине промена