Procházet zdrojové kódy

feat(product): 新增商品审核流程和商品池功能优化

- 在 base API 中新增 reviewBase、shelfReview、getProductStatusCount 和 changeProductType 方法
- 在 category API 中新增 setCategoryReviewer 方法并修改 listCategory 类型定义
- 在 poolLink API 中新增 batchReview、reSubmit、editPrice 和 editStock 方法
- 更新路由配置,添加商品池管理缓存和入池清单审核页面
- 优化 base 页面的商品上下架状态选项和统计信息展示
- 实现商品审核、上下架审核和商品类型变更功能
- 重构 category 页面实现懒加载树形结构和设置审核员功能
- 优化 pool 页面的产品池类型管理和统计信息展示
- 在 poolLink 页面添加价格维护和库存修改对话框功能
肖路 před 3 měsíci
rodič
revize
beead1f48d

+ 45 - 1
src/api/product/base/index.ts

@@ -1,6 +1,6 @@
 import request from '@/utils/request';
 import request from '@/utils/request';
 import { AxiosPromise } from 'axios';
 import { AxiosPromise } from 'axios';
-import { BaseVO, BaseForm, BaseQuery } from '@/api/product/base/types';
+import { BaseVO, BaseForm, BaseQuery, StatusCountVo } from '@/api/product/base/types';
 import { CategoryQuery, categoryTreeVO, CategoryVO } from '../category/types';
 import { CategoryQuery, categoryTreeVO, CategoryVO } from '../category/types';
 import { BrandQuery, BrandVO } from '../brand/types';
 import { BrandQuery, BrandVO } from '../brand/types';
 import { AttributesVO } from '../attributes/types';
 import { AttributesVO } from '../attributes/types';
@@ -155,3 +155,47 @@ export const getUnitList = (query?: UnitQuery): AxiosPromise<UnitVO[]> => {
   });
   });
 };
 };
 
 
+/**
+ * 商品审核
+ * @param data 审核信息(包含id、productReviewStatus、reviewComments)
+ */
+export const reviewBase = (data: BaseForm) => {
+  return request({
+    url: '/product/base/review',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 商品上下架审核
+ * @param data 审核信息(包含id、productStatus、shelfComments)
+ */
+export const shelfReview = (data: BaseForm) => {
+  return request({
+    url: '/product/base/shelfReview',
+    method: 'post',
+    data: data
+  });
+};
+/**
+ * 获取所有商品各个状态数量
+ */
+export const getProductStatusCount = (): AxiosPromise<StatusCountVo> => {
+  return request({
+    url: '/product/base/getProductStatusCount',
+    method: 'get'
+  });
+};
+/**
+ * 商品类型改变  1=默认类型,2精选商品,3=停售商品
+ * @param data 停售信息(包含id、productStatus、shelfComments)
+ */
+export const changeProductType = (data: BaseForm) => {
+  return request({
+    url: '/product/base/changeProductType',
+    method: 'post',
+    data: data
+  });
+};
+

+ 71 - 6
src/api/product/base/types.ts

@@ -54,7 +54,12 @@ export interface BaseVO {
   isSelf: string;
   isSelf: string;
 
 
   /**
   /**
-   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   * 商品类型 1=默认类型,2精选商品,3=停售商品
+   * */
+  productCategory?: number;
+
+  /**
+   * 产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核
    */
    */
   productReviewStatus: string;
   productReviewStatus: string;
 
 
@@ -89,7 +94,7 @@ export interface BaseVO {
   isNew: string;
   isNew: string;
 
 
   /**
   /**
-   * 商品状态:1=上架,0=下架等
+   * 商品状态:1=已上架,0=下架,2=上架中
    */
    */
   productStatus: string;
   productStatus: string;
 
 
@@ -228,6 +233,11 @@ export interface BaseVO {
    */
    */
   minOrderQuantity?: number;
   minOrderQuantity?: number;
 
 
+  /**
+   * 审核意见
+   */
+  reviewComments?: string;
+
   /**
   /**
    * 商品属性值(JSON字符串)
    * 商品属性值(JSON字符串)
    */
    */
@@ -287,7 +297,12 @@ export interface BaseForm extends BaseEntity {
   isSelf?: number;
   isSelf?: number;
 
 
   /**
   /**
-   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   * 商品类型 1=默认类型,2精选商品,3=停售商品
+   * */
+  productCategory?: number;
+
+  /**
+   * 产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核
    */
    */
   productReviewStatus?: number;
   productReviewStatus?: number;
 
 
@@ -322,7 +337,7 @@ export interface BaseForm extends BaseEntity {
   isNew?: number;
   isNew?: number;
 
 
   /**
   /**
-   * 商品状态:1=上架,0=下架等
+   * 商品状态:1=已上架,0=下架,2=上架中
    */
    */
   productStatus?: string;
   productStatus?: string;
 
 
@@ -551,6 +566,16 @@ export interface BaseForm extends BaseEntity {
    */
    */
   attributesList?: string;
   attributesList?: string;
 
 
+  /**
+   * 审核意见
+   */
+  reviewComments?: string;
+
+  /**
+   * 上下架审核意见
+   */
+  shelfComments?: string;
+
 }
 }
 
 
 export interface BaseQuery extends PageQuery {
 export interface BaseQuery extends PageQuery {
@@ -611,7 +636,12 @@ export interface BaseQuery extends PageQuery {
   isSelf?: number;
   isSelf?: number;
 
 
   /**
   /**
-   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   * 商品类型 1=默认类型,2精选商品,3=停售商品
+   * */
+  productCategory?: number;
+
+  /**
+   * 产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核
    */
    */
   productReviewStatus?: number;
   productReviewStatus?: number;
 
 
@@ -646,7 +676,7 @@ export interface BaseQuery extends PageQuery {
   isNew?: number;
   isNew?: number;
 
 
   /**
   /**
-   * 商品状态:1=上架,0=下架等
+   * 商品状态:1=已上架,0=下架,2=上架中
    */
    */
   productStatus?: number;
   productStatus?: number;
 
 
@@ -681,11 +711,46 @@ export interface BaseQuery extends PageQuery {
   projectOrg?: string;
   projectOrg?: string;
 
 
 
 
+
     /**
     /**
      * 日期范围参数
      * 日期范围参数
      */
      */
     params?: any;
     params?: any;
 }
 }
+/**
+ * 状态数量统计视图对象
+ */
+export class StatusCountVo {
+  /**
+   * 总数
+   */
+  total: number | null = null;
+
+  /**
+   * 上架数
+   */
+  onSale: number | null = null;
+
+  /**
+   * 下架数
+   */
+  offSale: number | null = null;
+
+  /**
+   * 待审核数量
+   */
+  waitAudit: number | null = null;
+
+  /**
+   * 通过数量
+   */
+  auditPass: number | null = null;
+
+  /**
+   * 驳回数量
+   */
+  auditReject: number | null = null;
+}
 
 
 
 
 
 

+ 15 - 2
src/api/product/category/index.ts

@@ -8,7 +8,7 @@ import { CategoryVO, CategoryForm, CategoryQuery } from '@/api/product/category/
  * @returns {*}
  * @returns {*}
  */
  */
 
 
-export const listCategory = (query?: CategoryQuery): AxiosPromise<CategoryVO[]> => {
+export const listCategory = (query?: Partial<CategoryQuery>): AxiosPromise<CategoryVO[]> => {
   return request({
   return request({
     url: '/product/category/list',
     url: '/product/category/list',
     method: 'get',
     method: 'get',
@@ -65,10 +65,23 @@ export const delCategory = (id: string | number | Array<string | number>) => {
 /**
 /**
  * 查询产品分类列表(排除节点)
  * 查询产品分类列表(排除节点)
  * @param id
  * @param id
- */
+  */
 export const listCategoryExcludeChild = (id: string | number): AxiosPromise<CategoryVO[]> => {
 export const listCategoryExcludeChild = (id: string | number): AxiosPromise<CategoryVO[]> => {
   return request({
   return request({
     url: '/product/category/list/exclude/' + id,
     url: '/product/category/list/exclude/' + id,
     method: 'get'
     method: 'get'
   });
   });
 };
 };
+
+/**
+ * 设置分类审核员
+ * @param id 分类ID
+ * @param reviewerId 审核员用户ID
+ */
+export const setCategoryReviewer = (id: string | number, reviewerId: string | number) => {
+  return request({
+    url: '/product/category/setReviewer',
+    method: 'put',
+    data: { id, reviewerId }
+  });
+};

+ 4 - 0
src/api/product/category/types.ts

@@ -129,6 +129,10 @@ export interface CategoryVO {
    */
    */
   children?: CategoryVO[];
   children?: CategoryVO[];
 
 
+  /**
+   * 是否有子节点(用于懒加载)
+   */
+  hasChildren?: boolean;
 }
 }
 
 
 export interface CategoryForm extends BaseEntity {
 export interface CategoryForm extends BaseEntity {

+ 65 - 0
src/api/product/pool/types.ts

@@ -9,6 +9,21 @@ export interface PoolVO {
    */
    */
   poolNo: string;
   poolNo: string;
 
 
+  /**
+   * 项目id
+   */
+  itemId: string | number;
+
+  /**
+   * 分类id
+   */
+  categoryId: string | number;
+
+  /**
+   * 产品池类型 0普通产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
+   */
+  type: number;
+
   /**
   /**
    * 池名称
    * 池名称
    */
    */
@@ -39,6 +54,26 @@ export interface PoolVO {
    */
    */
   productCount?: number;
   productCount?: number;
 
 
+  /**
+   * 待审核的产品数量
+   */
+  waitReviewCount?: number;
+
+  /**
+   * 已驳回的产品数量
+   */
+  rejectedCount?: number;
+
+  /**
+   * 已通过审核的产品数量
+   */
+  approvedCount?: number;
+
+  /**
+   * 待申请的产品数量
+   */
+  waitApplyCount?: number;
+
   /**
   /**
    * 创建时间
    * 创建时间
    */
    */
@@ -67,6 +102,21 @@ export interface PoolForm extends BaseEntity {
    */
    */
   poolNo?: string;
   poolNo?: string;
 
 
+  /**
+   * 项目id
+   */
+  itemId: string | number;
+
+  /**
+   * 分类id
+   */
+  categoryId: string | number;
+
+  /**
+   * 产品池类型 0普通产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
+   */
+  type: number;
+
   /**
   /**
    * 池名称
    * 池名称
    */
    */
@@ -101,6 +151,21 @@ export interface PoolQuery extends PageQuery {
    */
    */
   poolNo?: string;
   poolNo?: string;
 
 
+  /**
+   * 项目id
+   */
+  itemId: string | number;
+
+  /**
+   * 分类id
+   */
+  categoryId: string | number;
+
+  /**
+   * 产品池类型 0普通产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
+   */
+  type: number;
+
   /**
   /**
    * 池名称
    * 池名称
    */
    */

+ 49 - 0
src/api/product/poolLink/index.ts

@@ -1,6 +1,7 @@
 import request from '@/utils/request';
 import request from '@/utils/request';
 import { AxiosPromise } from 'axios';
 import { AxiosPromise } from 'axios';
 import { PoolLinkVO, PoolLinkForm, PoolLinkQuery } from '@/api/product/poolLink/types';
 import { PoolLinkVO, PoolLinkForm, PoolLinkQuery } from '@/api/product/poolLink/types';
+export type { PoolLinkForm };
 
 
 /**
 /**
  * 查询产品池和产品关联列表
  * 查询产品池和产品关联列表
@@ -81,3 +82,51 @@ export const batchAddProducts = (data: BatchAddProductData) => {
     data: data
     data: data
   });
   });
 };
 };
+
+/**
+ * 批量审核商品进入商品池
+ * @param data 审核参数列表
+ */
+export const batchReview = (data: PoolLinkForm[]) => {
+  return request({
+    url: '/product/poolLink/batchReview',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 提交审核商品到商品池
+ * @param data 提交审核参数列表
+ */
+export const reSubmit = (data: PoolLinkForm[]) => {
+  return request({
+    url: '/product/poolLink/reSubmit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 编辑商品价格
+ * @param data 价格参数
+ */
+export const editPrice = (data: PoolLinkForm) => {
+  return request({
+    url: '/product/poolLink/editPrice',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 编辑商品库存
+ * @param data 库存参数
+ */
+export const editStock = (data: PoolLinkForm) => {
+  return request({
+    url: '/product/poolLink/editStock',
+    method: 'post',
+    data: data
+  });
+};

+ 17 - 2
src/api/product/poolLink/types.ts

@@ -9,6 +9,16 @@ export interface PoolLinkVO {
    */
    */
   poolId: string | number;
   poolId: string | number;
 
 
+  /**
+   * 产品池名称
+   */
+  poolName?: string;
+
+  /**
+   * 产品池类型 0普通产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
+   */
+  type?: number;
+
   /**
   /**
    * 产品id
    * 产品id
    */
    */
@@ -110,7 +120,7 @@ export interface PoolLinkVO {
   grossMargin?: number;
   grossMargin?: number;
 
 
   /**
   /**
-   * 商品状态 1=上架,0=下架
+   * 商品状态:1=已上架,0=下架,2=上架中
    */
    */
   productStatus?: string;
   productStatus?: string;
 
 
@@ -161,6 +171,11 @@ export interface PoolLinkForm extends BaseEntity {
    */
    */
   isShow?: string;
   isShow?: string;
 
 
+  /**
+   * 库存
+   */
+  stock?: number;
+
   /**
   /**
    * 备注
    * 备注
    */
    */
@@ -233,7 +248,7 @@ export interface PoolLinkQuery extends PageQuery {
   categoryId?: string | number;
   categoryId?: string | number;
 
 
   /**
   /**
-   * 商品状态 1=上架,0=下架
+   * 商品状态:1=已上架,0=下架,2=上架中
    */
    */
   productStatus?: string;
   productStatus?: string;
 
 

+ 7 - 1
src/router/index.ts

@@ -123,7 +123,7 @@ export const constantRoutes: RouteRecordRaw[] = [
         path: 'poolLink',
         path: 'poolLink',
         component: () => import('@/views/product/poolLink/index.vue'),
         component: () => import('@/views/product/poolLink/index.vue'),
         name: 'PoolLink',
         name: 'PoolLink',
-        meta: { title: '商品池管理', activeMenu: '/product/pool' }
+        meta: { title: '商品池管理', activeMenu: '/product/pool', noCache: true }
       },
       },
       {
       {
         path: 'base/review',
         path: 'base/review',
@@ -136,6 +136,12 @@ export const constantRoutes: RouteRecordRaw[] = [
         component: () => import('@/views/product/base/add.vue'),
         component: () => import('@/views/product/base/add.vue'),
         name: 'BaseDetail',
         name: 'BaseDetail',
         meta: { title: '商品详情', activeMenu: '/product/base' }
         meta: { title: '商品详情', activeMenu: '/product/base' }
+      },
+      {
+        path: 'pool/reviewDetail',
+        component: () => import('@/views/product/pool/reviewDetail.vue'),
+        name: 'PoolReviewDetail',
+        meta: { title: '入池清单审核', activeMenu: '/product/pool', noCache: true }
       }
       }
     ]
     ]
   }
   }

+ 99 - 59
src/views/product/base/index.vue

@@ -61,8 +61,9 @@
               <el-col :span="6">
               <el-col :span="6">
                 <el-form-item label="上下架状态" prop="productStatus">
                 <el-form-item label="上下架状态" prop="productStatus">
                   <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
                   <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
-                    <el-option label="上架" value="1" />
-                    <el-option label="下架" value="0" />
+                    <el-option label="已上架" :value="1" />
+                    <el-option label="下架" :value="0" />
+                    <el-option label="上架中" :value="2" />
                   </el-select>
                   </el-select>
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </el-col>
@@ -81,17 +82,14 @@
     <!-- 统计信息区域 -->
     <!-- 统计信息区域 -->
     <el-card shadow="never" class="mb-[10px]">
     <el-card shadow="never" class="mb-[10px]">
       <div class="flex items-center text-sm text-gray-600">
       <div class="flex items-center text-sm text-gray-600">
-        <span>商品总/已配置: </span>
+        <span>商品总数: </span>
         <span class="text-blue-600 mx-1"
         <span class="text-blue-600 mx-1"
-          >总=<span class="text-red-600">{{ statistics.total }}</span
-          >条</span
+          >总=<span class="text-red-600">{{ statistics.total || 0 }}</span
+          >条</span
         >
         >
-        <span
-          >外/已配置数量<span class="text-red-600">{{ statistics.configured }}</span
-          >条,</span
-        >
-        <span>【上架/总数({{ statistics.onShelf }}/{{ statistics.total }})】</span>
-        <span class="mx-2">,审核状态({{ statistics.reviewStatus }}),上架状态({{ statistics.shelfStatus }})</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">
         <div class="ml-auto flex gap-2">
           <el-button type="primary" icon="Plus" @click="handleAdd">商品新增</el-button>
           <el-button type="primary" icon="Plus" @click="handleAdd">商品新增</el-button>
           <el-button type="warning" icon="Check" @click="handleGoReview">商品审核</el-button>
           <el-button type="warning" icon="Check" @click="handleGoReview">商品审核</el-button>
@@ -180,12 +178,13 @@
         </el-table-column>
         </el-table-column>
         <el-table-column label="上下架状态" align="center" prop="productStatus" width="120">
         <el-table-column label="上下架状态" align="center" prop="productStatus" width="120">
           <template #default="scope">
           <template #default="scope">
-            <el-tag v-if="scope.row.productStatus === 1" type="success">上架</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 === 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>
             <el-tag v-else type="info">未知</el-tag>
           </template>
           </template>
         </el-table-column>
         </el-table-column>
-        <el-table-column label="操作" align="center" width="200" fixed="right">
+        <el-table-column label="操作" align="center" width="280" fixed="right">
           <template #default="scope">
           <template #default="scope">
             <!-- 待审核状态:只显示编辑 -->
             <!-- 待审核状态:只显示编辑 -->
             <div v-if="scope.row.productReviewStatus !== 2" class="flex gap-1 justify-center">
             <div v-if="scope.row.productReviewStatus !== 2" class="flex gap-1 justify-center">
@@ -226,9 +225,9 @@
       <!-- 游标分页控制 -->
       <!-- 游标分页控制 -->
       <pagination
       <pagination
         v-show="baseList.length > 0"
         v-show="baseList.length > 0"
-        v-model:page="cursorQueryParams.pageNum"
-        v-model:limit="cursorQueryParams.pageSize"
-        v-model:way="cursorQueryParams.way"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        v-model:way="queryParams.way"
         :cursor-mode="true"
         :cursor-mode="true"
         :has-more="hasMore"
         :has-more="hasMore"
         @pagination="getList"
         @pagination="getList"
@@ -238,14 +237,15 @@
 </template>
 </template>
 
 
 <script setup name="Base" lang="ts">
 <script setup name="Base" lang="ts">
-import { listBase, getBase, delBase, brandList, categoryTree } from '@/api/product/base';
-import { BaseVO, BaseQuery, BaseForm } from '@/api/product/base/types';
+import { listBase, getBase, delBase, brandList, categoryTree, shelfReview, changeProductType, getProductStatusCount } from '@/api/product/base';
+import { BaseVO, BaseQuery, BaseForm, StatusCountVo } from '@/api/product/base/types';
 import { BrandVO } from '@/api/product/brand/types';
 import { BrandVO } from '@/api/product/brand/types';
 import { categoryTreeVO } from '@/api/product/category/types';
 import { categoryTreeVO } from '@/api/product/category/types';
-import { useRouter } from 'vue-router';
+import { useRoute, useRouter } from 'vue-router';
 
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const router = useRouter();
 const router = useRouter();
+const route = useRoute();
 
 
 const baseList = ref<BaseVO[]>([]);
 const baseList = ref<BaseVO[]>([]);
 const buttonLoading = ref(false);
 const buttonLoading = ref(false);
@@ -261,12 +261,13 @@ const hasMore = ref(true); // 是否还有更多数据
 const pageHistory = ref([]);
 const pageHistory = ref([]);
 
 
 // 统计信息
 // 统计信息
-const statistics = ref({
+const statistics = ref<StatusCountVo>({
   total: 0,
   total: 0,
-  configured: 0,
-  onShelf: 0,
-  reviewStatus: '待审核0条',
-  shelfStatus: '上架0条'
+  onSale: 0,
+  offSale: 0,
+  waitAudit: 0,
+  auditPass: 0,
+  auditReject: 0
 });
 });
 
 
 const queryFormRef = ref<ElFormInstance>();
 const queryFormRef = ref<ElFormInstance>();
@@ -317,6 +318,8 @@ const data = reactive<PageData<BaseForm, BaseQuery>>({
     isSelf: undefined,
     isSelf: undefined,
     productReviewStatus: undefined,
     productReviewStatus: undefined,
     productStatus: undefined,
     productStatus: undefined,
+    lastSeenId: undefined, // 游标分页的lastSeenId
+    way: undefined,
     params: {}
     params: {}
   },
   },
   rules: {
   rules: {
@@ -341,28 +344,13 @@ const data = reactive<PageData<BaseForm, BaseQuery>>({
 
 
 const { queryParams, form, rules } = toRefs(data);
 const { queryParams, form, rules } = toRefs(data);
 
 
-// 游标分页查询参数
-const cursorQueryParams = ref<BaseQuery>({
-  pageNum: 1,
-  pageSize: 10,
-  way: undefined,
-  productNo: undefined,
-  itemName: undefined,
-  brandName: undefined,
-  purchaseNature: undefined,
-  bottomCategoryId: undefined,
-  isSelf: undefined,
-  productReviewStatus: undefined,
-  productStatus: undefined,
-  lastSeenId: undefined // 游标分页的lastSeenId
-});
 
 
 /** 查询产品基础信息列表 */
 /** 查询产品基础信息列表 */
 const getList = async () => {
 const getList = async () => {
   loading.value = true;
   loading.value = true;
   try {
   try {
-    const params = { ...cursorQueryParams.value };
-    const currentPageNum = cursorQueryParams.value.pageNum;
+    const params = { ...queryParams.value };
+    const currentPageNum = queryParams.value.pageNum;
 
 
     // 第一页不需要游标参数
     // 第一页不需要游标参数
     if (currentPageNum === 1) {
     if (currentPageNum === 1) {
@@ -370,7 +358,7 @@ const getList = async () => {
       delete params.way;
       delete params.way;
     } else {
     } else {
       // way参数:0=上一页,1=下一页
       // way参数:0=上一页,1=下一页
-      if (cursorQueryParams.value.way === 0) {
+      if (queryParams.value.way === 0) {
         // 上一页:使用目标页(即当前显示页)的firstId
         // 上一页:使用目标页(即当前显示页)的firstId
         const nextPageHistory = pageHistory.value[currentPageNum];
         const nextPageHistory = pageHistory.value[currentPageNum];
         if (nextPageHistory) {
         if (nextPageHistory) {
@@ -391,7 +379,7 @@ const getList = async () => {
     baseList.value = res.rows || [];
     baseList.value = res.rows || [];
 
 
     // 判断是否还有更多数据
     // 判断是否还有更多数据
-    hasMore.value = baseList.value.length === cursorQueryParams.value.pageSize;
+    hasMore.value = baseList.value.length === queryParams.value.pageSize;
 
 
     // 记录当前页的第一个id和最后一个id
     // 记录当前页的第一个id和最后一个id
     if (baseList.value.length > 0) {
     if (baseList.value.length > 0) {
@@ -408,11 +396,6 @@ const getList = async () => {
     }
     }
 
 
     total.value = res.total || 0;
     total.value = res.total || 0;
-
-    // 更新统计信息
-    statistics.value.total = res.total || 0;
-    statistics.value.configured = res.rows?.filter((item: any) => item.isConfigured)?.length || 0;
-    statistics.value.onShelf = res.rows?.filter((item: any) => item.productStatus === '1')?.length || 0;
   } catch (error) {
   } catch (error) {
     console.error('获取列表失败:', error);
     console.error('获取列表失败:', error);
   } finally {
   } finally {
@@ -426,6 +409,26 @@ const cancel = () => {
   dialog.visible = false;
   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 = () => {
 const reset = () => {
   form.value = { ...initFormData };
   form.value = { ...initFormData };
@@ -435,8 +438,8 @@ const reset = () => {
 /** 搜索按钮操作 */
 /** 搜索按钮操作 */
 const handleQuery = () => {
 const handleQuery = () => {
   // 同步查询参数到游标分页参数
   // 同步查询参数到游标分页参数
-  cursorQueryParams.value = {
-    ...cursorQueryParams.value,
+  queryParams.value = {
+    ...queryParams.value,
     pageNum: 1,
     pageNum: 1,
     productNo: queryParams.value.productNo,
     productNo: queryParams.value.productNo,
     itemName: queryParams.value.itemName,
     itemName: queryParams.value.itemName,
@@ -454,7 +457,7 @@ const handleQuery = () => {
 /** 重置按钮操作 */
 /** 重置按钮操作 */
 const resetQuery = () => {
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   queryFormRef.value?.resetFields();
-  cursorQueryParams.value.lastSeenId = undefined;
+  queryParams.value.lastSeenId = undefined;
   pageHistory.value = []; // 重置页面历史
   pageHistory.value = []; // 重置页面历史
   handleQuery();
   handleQuery();
 };
 };
@@ -505,11 +508,25 @@ const handleView = (row: BaseVO) => {
 
 
 /** 上下架操作 */
 /** 上下架操作 */
 const handleShelf = async (row: BaseVO) => {
 const handleShelf = async (row: BaseVO) => {
-  const action = row.productStatus === '1' ? '下架' : '上架';
+  // productStatus字段定义为string类型:1=已上架,0=下架,2=上架中
+  const isOnShelf = row.productStatus === '1';
+  const action = isOnShelf ? '下架' : '上架';
   await proxy?.$modal.confirm(`确认${action}该商品吗?`);
   await proxy?.$modal.confirm(`确认${action}该商品吗?`);
-  // TODO: 调用上下架API
-  proxy?.$modal.msgSuccess(`${action}成功`);
-  await getList();
+
+  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}失败`);
+  }
 };
 };
 
 
 /** 价格设置 */
 /** 价格设置 */
@@ -526,10 +543,20 @@ const handleSupply = (row: BaseVO) => {
 
 
 /** 停售操作 */
 /** 停售操作 */
 const handleDiscontinue = async (row: BaseVO) => {
 const handleDiscontinue = async (row: BaseVO) => {
-  await proxy?.$modal.confirm('确认停售该商品吗?');
-  // TODO: 调用停售API
-  proxy?.$modal.msgSuccess('停售成功');
-  await getList();
+  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('停售失败');
+  }
 };
 };
 
 
 /** 跳转到商品审核页面 */
 /** 跳转到商品审核页面 */
@@ -548,8 +575,21 @@ const getCategoryTree = async () => {
   categoryOptions.value = res.data || [];
   categoryOptions.value = res.data || [];
 };
 };
 
 
+/** 获取统计信息 */
+const getStatistics = async () => {
+  try {
+    const res = await getProductStatusCount();
+    if (res.data) {
+      statistics.value = res.data;
+    }
+  } catch (error) {
+    console.error('获取统计信息失败:', error);
+  }
+};
+
 onMounted(() => {
 onMounted(() => {
   getList();
   getList();
   getCategoryTree();
   getCategoryTree();
+  getStatistics();
 });
 });
 </script>
 </script>

+ 109 - 45
src/views/product/base/review.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-  <div class="p-2">
+  <div class="app-container">
     <!-- 搜索区域 -->
     <!-- 搜索区域 -->
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
       <div v-show="showSearch" class="mb-[10px]">
       <div v-show="showSearch" class="mb-[10px]">
@@ -42,6 +42,20 @@
                   />
                   />
                 </el-form-item>
                 </el-form-item>
               </el-col>
               </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-col :span="6">
                 <el-form-item>
                 <el-form-item>
                   <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                   <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
@@ -54,11 +68,11 @@
       </div>
       </div>
     </transition>
     </transition>
 
 
-    <!-- 审核商品信息列表 -->
-    <el-card shadow="never" class="mb-[10px]">
+    <!-- 审核商品信息列表 -->
+    <el-card shadow="never" class="table-card">
       <template #header>
       <template #header>
         <div class="flex items-center justify-between">
         <div class="flex items-center justify-between">
-          <span class="font-semibold">审核商品信息列表</span>
+          <span class="font-semibold">审核商品信息列表</span>
           <div class="flex gap-2">
           <div class="flex gap-2">
             <el-button type="primary" icon="Download" @click="handleExport">导出商品</el-button>
             <el-button type="primary" icon="Download" @click="handleExport">导出商品</el-button>
             <el-button type="success" icon="Upload">导入商品</el-button>
             <el-button type="success" icon="Upload">导入商品</el-button>
@@ -67,29 +81,29 @@
         </div>
         </div>
       </template>
       </template>
 
 
-      <el-table v-loading="loading" border :data="baseList" @selection-change="handleSelectionChange">
+      <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 type="selection" width="55" align="center" />
-        <el-table-column label="商品图片" align="center" prop="productImage" width="100" fixed="left">
+        <el-table-column label="商品图片" align="center" prop="productImage" width="100" >
           <template #default="scope">
           <template #default="scope">
-            <image-preview :src="scope.row.productImage" :width="60" :height="60" />
+            <image-preview :src="scope.row.productImage" :width="60" :height="60"/>
           </template>
           </template>
         </el-table-column>
         </el-table-column>
-        <el-table-column label="商品编号" align="center" prop="productNo" width="120" fixed="left">
+        <el-table-column label="商品编号" align="center" prop="productNo" width="120" >
           <template #default="scope">
           <template #default="scope">
             <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
             <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
           </template>
           </template>
         </el-table-column>
         </el-table-column>
-        <el-table-column label="商品信息" align="center" width="250" show-overflow-tooltip>
+        <el-table-column label="商品信息" align="center" min-width="250" show-overflow-tooltip>
           <template #default="scope">
           <template #default="scope">
             <div class="text-left">
             <div class="text-left">
               <div>{{ scope.row.itemName }}</div>
               <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>
             </div>
           </template>
           </template>
         </el-table-column>
         </el-table-column>
         <el-table-column label="基本情况" align="center" width="180">
         <el-table-column label="基本情况" align="center" width="180">
           <template #default="scope">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px">
+            <div class="text-left" style="font-size: 12px;">
               <div>
               <div>
                 <span class="text-gray-500">商品分类:</span>
                 <span class="text-gray-500">商品分类:</span>
                 <span>{{ scope.row.categoryName || '-' }}</span>
                 <span>{{ scope.row.categoryName || '-' }}</span>
@@ -103,7 +117,7 @@
         </el-table-column>
         </el-table-column>
         <el-table-column label="SKU价格" align="center" width="180">
         <el-table-column label="SKU价格" align="center" width="180">
           <template #default="scope">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px">
+            <div class="text-left" style="font-size: 12px;">
               <div>
               <div>
                 <span class="text-gray-500">市场价:</span>
                 <span class="text-gray-500">市场价:</span>
                 <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
                 <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
@@ -121,7 +135,7 @@
         </el-table-column>
         </el-table-column>
         <el-table-column label="成本预算" align="center" width="150">
         <el-table-column label="成本预算" align="center" width="150">
           <template #default="scope">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px">
+            <div class="text-left" style="font-size: 12px;">
               <div>
               <div>
                 <span class="text-gray-500">采购价:</span>
                 <span class="text-gray-500">采购价:</span>
                 <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
                 <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
@@ -147,29 +161,37 @@
             <span v-else>-</span>
             <span v-else>-</span>
           </template>
           </template>
         </el-table-column>
         </el-table-column>
-        <el-table-column label="操作" align="center" width="200" fixed="right">
+        <el-table-column label="审核意见" align="center" width="180" show-overflow-tooltip>
+          <template #default="scope">
+            <span>{{ scope.row.reviewComments || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" width="200" fixed="right" class-name="border-left">
           <template #default="scope">
           <template #default="scope">
             <div class="flex flex-col gap-1">
             <div class="flex flex-col gap-1">
               <!-- 根据审核状态显示不同按钮 -->
               <!-- 根据审核状态显示不同按钮 -->
-              <template v-if="scope.row.productReviewStatus === 1">
-                <!-- 待审核 -->
+              <template v-if="scope.row.productReviewStatus === 0">
+                <!-- 待采购审核 -->
                 <div class="flex gap-1 justify-center">
                 <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="handleReview(scope.row)">审核</el-link>
-                  <el-link type="danger" :underline="false" @click="handleReject(scope.row)">驳回</el-link>
+                  <el-link type="success" :underline="false" @click="handlePurchaseReview(scope.row)">采购审核</el-link>
                 </div>
                 </div>
               </template>
               </template>
-              <template v-else-if="scope.row.productReviewStatus === 3">
-                <!-- 审核驳回 -->
+              <template v-else-if="scope.row.productReviewStatus === 1">
+                <!-- 审核通过:不显示任何按钮 -->
+              </template>
+              <template v-else-if="scope.row.productReviewStatus === 2">
+                <!-- 驳回 -->
                 <div class="flex gap-1 justify-center">
                 <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="success" :underline="false" @click="handleReSubmit(scope.row)">重新提交</el-link>
                 </div>
                 </div>
               </template>
               </template>
-              <template v-else>
-                <!-- 其他状态 -->
+              <template v-else-if="scope.row.productReviewStatus === 3">
+                <!-- 待营销审核 -->
                 <div class="flex gap-1 justify-center">
                 <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>
                 </div>
                 </div>
               </template>
               </template>
             </div>
             </div>
@@ -204,8 +226,8 @@
             <el-radio :label="3">审核驳回</el-radio>
             <el-radio :label="3">审核驳回</el-radio>
           </el-radio-group>
           </el-radio-group>
         </el-form-item>
         </el-form-item>
-        <el-form-item label="审核意见" prop="reviewRemark">
-          <el-input v-model="reviewForm.reviewRemark" type="textarea" :rows="4" placeholder="请输入审核意见" />
+        <el-form-item label="审核意见" prop="reviewComments">
+          <el-input v-model="reviewForm.reviewComments" type="textarea" :rows="4" placeholder="请输入审核意见" />
         </el-form-item>
         </el-form-item>
       </el-form>
       </el-form>
       <template #footer>
       <template #footer>
@@ -219,7 +241,7 @@
 </template>
 </template>
 
 
 <script setup name="BaseReview" lang="ts">
 <script setup name="BaseReview" lang="ts">
-import { listBase, getBase, updateBase, brandList, categoryTree } from '@/api/product/base';
+import { listBase, getBase, reviewBase, brandList, categoryTree } from '@/api/product/base';
 import { BaseVO, BaseQuery, BaseForm } from '@/api/product/base/types';
 import { BaseVO, BaseQuery, BaseForm } from '@/api/product/base/types';
 import { BrandVO } from '@/api/product/brand/types';
 import { BrandVO } from '@/api/product/brand/types';
 import { categoryTreeVO } from '@/api/product/category/types';
 import { categoryTreeVO } from '@/api/product/category/types';
@@ -248,6 +270,16 @@ const categoryOptions = ref<categoryTreeVO[]>([]);
 const hasMore = ref(true); // 是否还有更多数据
 const hasMore = ref(true); // 是否还有更多数据
 const pageHistory = ref([]);
 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 queryFormRef = ref<ElFormInstance>();
 const queryFormRef = ref<ElFormInstance>();
 const reviewFormRef = ref<ElFormInstance>();
 const reviewFormRef = ref<ElFormInstance>();
 
 
@@ -263,13 +295,13 @@ const reviewForm = ref<any>({
   productNo: '',
   productNo: '',
   itemName: '',
   itemName: '',
   reviewStatus: 2,
   reviewStatus: 2,
-  reviewRemark: ''
+  reviewComments: ''
 });
 });
 
 
 // 审核表单验证规则
 // 审核表单验证规则
 const reviewRules = ref({
 const reviewRules = ref({
   reviewStatus: [{ required: true, message: '请选择审核结果', trigger: 'change' }],
   reviewStatus: [{ required: true, message: '请选择审核结果', trigger: 'change' }],
-  reviewRemark: [{ required: true, message: '请输入审核意见', trigger: 'blur' }]
+  reviewComments: [{ required: true, message: '请输入审核意见', trigger: 'blur' }]
 });
 });
 
 
 const queryParams = ref<BaseQuery>({
 const queryParams = ref<BaseQuery>({
@@ -370,8 +402,6 @@ const handleQuery = () => {
 /** 重置按钮操作 */
 /** 重置按钮操作 */
 const resetQuery = () => {
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   queryFormRef.value?.resetFields();
-  // 重置后仍然保持待审核状态
-  queryParams.value.productReviewStatus = 1;
   queryParams.value.lastSeenId = undefined;
   queryParams.value.lastSeenId = undefined;
   pageHistory.value = [0]; // 重置页面历史
   pageHistory.value = [0]; // 重置页面历史
   handleQuery();
   handleQuery();
@@ -405,29 +435,29 @@ const handleEdit = (row: BaseVO) => {
   router.push(`/product/base/edit/${row.id}`);
   router.push(`/product/base/edit/${row.id}`);
 };
 };
 
 
-/** 审核商品 */
-const handleReview = (row: BaseVO) => {
+/** 采购审核 */
+const handlePurchaseReview = (row: BaseVO) => {
   reviewDialog.visible = true;
   reviewDialog.visible = true;
-  reviewDialog.title = '商品审核';
+  reviewDialog.title = '采购审核';
   reviewForm.value = {
   reviewForm.value = {
     id: row.id,
     id: row.id,
     productNo: row.productNo,
     productNo: row.productNo,
     itemName: row.itemName,
     itemName: row.itemName,
-    reviewStatus: 2,
-    reviewRemark: ''
+    reviewStatus: 3,
+    reviewComments: ''
   };
   };
-};
+}
 
 
-/** 驳回商品 */
-const handleReject = (row: BaseVO) => {
+/** 营销审核 */
+const handleMarketingReview = (row: BaseVO) => {
   reviewDialog.visible = true;
   reviewDialog.visible = true;
-  reviewDialog.title = '商品驳回';
+  reviewDialog.title = '营销审核';
   reviewForm.value = {
   reviewForm.value = {
     id: row.id,
     id: row.id,
     productNo: row.productNo,
     productNo: row.productNo,
     itemName: row.itemName,
     itemName: row.itemName,
-    reviewStatus: 3,
-    reviewRemark: ''
+    reviewStatus: 1,
+    reviewComments: ''
   };
   };
 };
 };
 
 
@@ -436,9 +466,9 @@ const handleReSubmit = async (row: BaseVO) => {
   await proxy?.$modal.confirm('确认重新提交该商品进行审核吗?');
   await proxy?.$modal.confirm('确认重新提交该商品进行审核吗?');
   const data: BaseForm = {
   const data: BaseForm = {
     id: row.id,
     id: row.id,
-    productReviewStatus: 1 // 设置为待审核状态
+    productReviewStatus: 0 // 设置为待审核状态
   };
   };
-  await updateBase(data);
+  await reviewBase(data);
   proxy?.$modal.msgSuccess('重新提交成功');
   proxy?.$modal.msgSuccess('重新提交成功');
   await getList();
   await getList();
 };
 };
@@ -449,9 +479,9 @@ const submitReview = async () => {
   const data: BaseForm = {
   const data: BaseForm = {
     id: reviewForm.value.id,
     id: reviewForm.value.id,
     productReviewStatus: Number(reviewForm.value.reviewStatus),
     productReviewStatus: Number(reviewForm.value.reviewStatus),
-    remark: reviewForm.value.reviewRemark
+    reviewComments: reviewForm.value.reviewComments
   };
   };
-  await updateBase(data);
+  await reviewBase(data);
   proxy?.$modal.msgSuccess(reviewForm.value.reviewStatus === 2 ? '审核通过' : '审核驳回');
   proxy?.$modal.msgSuccess(reviewForm.value.reviewStatus === 2 ? '审核通过' : '审核驳回');
   reviewDialog.visible = false;
   reviewDialog.visible = false;
   await getList();
   await getList();
@@ -491,5 +521,39 @@ onMounted(() => {
 </script>
 </script>
 
 
 <style scoped lang="scss">
 <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;
+  }
+
+  :deep(.el-table) {
+    flex: 1;
+  }
+
+  // 确保固定列左侧有边框
+  :deep(.el-table__fixed-right) {
+    box-shadow: -1px 0 0 var(--el-table-border-color) !important;
+  }
+
+  // 固定列的单元格左边框
+  :deep(.el-table__fixed-right .el-table__cell) {
+    border-left: 1px solid var(--el-table-border-color) !important;
+  }
+}
 </style>
 </style>

+ 78 - 34
src/views/product/category/index.vue

@@ -22,12 +22,7 @@
           <el-col :span="1.5">
           <el-col :span="1.5">
             <el-button v-hasPermi="['product:category:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增分类</el-button>
             <el-button v-hasPermi="['product:category:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增分类</el-button>
           </el-col>
           </el-col>
-          <el-col :span="1.5">
-            <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">全部展开</el-button>
-          </el-col>
-          <el-col :span="1.5">
-            <el-button type="info" plain icon="Sort" @click="handleToggleCollapseAll">全部收起</el-button>
-          </el-col>
+
           <right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
           <right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
         </el-row>
       </template>
       </template>
@@ -38,8 +33,9 @@
         :data="categoryList"
         :data="categoryList"
         row-key="id"
         row-key="id"
         border
         border
+        lazy
+        :load="loadChildren"
         :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
         :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
-        :default-expand-all="isExpandAll"
       >
       >
         <el-table-column prop="categoryName" label="分类名称" width="260"></el-table-column>
         <el-table-column prop="categoryName" label="分类名称" width="260"></el-table-column>
         <el-table-column prop="classLevel" align="center" label="分类级别" width="150">
         <el-table-column prop="classLevel" align="center" label="分类级别" width="150">
@@ -69,6 +65,9 @@
             <el-tooltip content="删除" placement="top">
             <el-tooltip content="删除" placement="top">
               <el-button v-hasPermi="['product:category:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" />
               <el-button v-hasPermi="['product:category:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" />
             </el-tooltip>
             </el-tooltip>
+            <el-tooltip v-if="scope.row.classLevel === 3" content="设置审核员" placement="top">
+              <el-button v-hasPermi="['product:category:edit']" link type="primary" icon="User" @click="handleSetReviewer(scope.row)" />
+            </el-tooltip>
           </template>
           </template>
         </el-table-column>
         </el-table-column>
       </el-table>
       </el-table>
@@ -156,11 +155,16 @@
         </div>
         </div>
       </template>
       </template>
     </el-dialog>
     </el-dialog>
+
+    <!-- 用户选择组件 -->
+    <UserSelect ref="userSelectRef" :multiple="false" @confirmCallBack="handleReviewerSelected" />
   </div>
   </div>
 </template>
 </template>
 
 
 <script setup name="Category" lang="ts">
 <script setup name="Category" lang="ts">
-import { listCategory, getCategory, delCategory, addCategory, updateCategory, listCategoryExcludeChild } from '@/api/product/category';
+import { listCategory, getCategory, delCategory, addCategory, updateCategory, listCategoryExcludeChild, setCategoryReviewer } from '@/api/product/category';
+import UserSelect from '@/components/UserSelect/index.vue';
+import { UserVO } from '@/api/system/user/types';
 import { CategoryVO, CategoryQuery, CategoryForm } from '@/api/product/category/types';
 import { CategoryVO, CategoryQuery, CategoryForm } from '@/api/product/category/types';
 
 
 interface CategoryOptionsType {
 interface CategoryOptionsType {
@@ -175,7 +179,8 @@ const categoryList = ref<CategoryVO[]>([]);
 const loading = ref(true);
 const loading = ref(true);
 const showSearch = ref(true);
 const showSearch = ref(true);
 const categoryOptions = ref<CategoryOptionsType[]>([]);
 const categoryOptions = ref<CategoryOptionsType[]>([]);
-const isExpandAll = ref(false);
+// 存储懒加载的子节点加载状态和 resolve 函数
+const lazyTreeNodeMap = ref<Map<string | number, { tree: any; treeNode: any; resolve: (data: CategoryVO[]) => void }>>(new Map());
 
 
 const dialog = reactive<DialogOption>({
 const dialog = reactive<DialogOption>({
   visible: false,
   visible: false,
@@ -185,6 +190,10 @@ const dialog = reactive<DialogOption>({
 const categoryTableRef = ref<ElTableInstance>();
 const categoryTableRef = ref<ElTableInstance>();
 const queryFormRef = ref<ElFormInstance>();
 const queryFormRef = ref<ElFormInstance>();
 const categoryFormRef = ref<ElFormInstance>();
 const categoryFormRef = ref<ElFormInstance>();
+const userSelectRef = ref<InstanceType<typeof UserSelect>>();
+
+// 当前设置审核员的分类
+const currentReviewerCategory = ref<CategoryVO | null>(null);
 
 
 const initFormData: CategoryForm = {
 const initFormData: CategoryForm = {
   id: undefined,
   id: undefined,
@@ -201,7 +210,7 @@ const initFormData: CategoryForm = {
   oneLink2: undefined,
   oneLink2: undefined,
   classDescription: undefined
   classDescription: undefined
 }
 }
-const data = reactive<PageData<CategoryForm, CategoryQuery>>({
+const data = reactive<PageData<CategoryForm, Partial<CategoryQuery>>>({
   form: {...initFormData},
   form: {...initFormData},
   queryParams: {
   queryParams: {
     categoryName: undefined
     categoryName: undefined
@@ -218,17 +227,40 @@ const data = reactive<PageData<CategoryForm, CategoryQuery>>({
 
 
 const { queryParams, form, rules } = toRefs(data);
 const { queryParams, form, rules } = toRefs(data);
 
 
-/** 查询产品分类列表 */
+/** 查询产品分类列表(只加载顶级分类) */
 const getList = async () => {
 const getList = async () => {
   loading.value = true;
   loading.value = true;
-  const res = await listCategory(queryParams.value);
-  const data = proxy?.handleTree<CategoryVO>(res.rows, 'id');
-  if (data) {
-    categoryList.value = data;
-  }
+  // 清空懒加载缓存
+  lazyTreeNodeMap.value.clear();
+  // 只加载顶级分类(parentId = 0)
+  const res = await listCategory({ ...queryParams.value, parentId: 0 });
+  const data = (res as any).rows || res.data || [];
+  // 根据 hasChildren 字段标记是否有子节点
+  categoryList.value = data.map((item: CategoryVO) => ({
+    ...item,
+    hasChildren: item.hasChildren ?? (item.classLevel < 3) // 如果后端没返回 hasChildren,根据 classLevel 判断
+  }));
   loading.value = false;
   loading.value = false;
 }
 }
 
 
+/** 懒加载子节点 */
+const loadChildren = async (row: CategoryVO, treeNode: any, resolve: (data: CategoryVO[]) => void) => {
+  // 存储加载状态,便于刷新时重新加载
+  lazyTreeNodeMap.value.set(row.id, { tree: row, treeNode, resolve });
+  try {
+    const res = await listCategory({ parentId: row.id });
+    const data = (res as any).rows || res.data || [];
+    // 标记子节点是否还有子级
+    const children = data.map((item: CategoryVO) => ({
+      ...item,
+      hasChildren: item.hasChildren ?? (item.classLevel < 3)
+    }));
+    resolve(children);
+  } catch (error) {
+    resolve([]);
+  }
+}
+
 /** 取消按钮 */
 /** 取消按钮 */
 const cancel = () => {
 const cancel = () => {
   reset();
   reset();
@@ -252,23 +284,15 @@ const resetQuery = () => {
   handleQuery();
   handleQuery();
 }
 }
 
 
-/** 展开/折叠操作 */
-const handleToggleExpandAll = () => {
-  isExpandAll.value = true;
-  toggleExpandAll(categoryList.value, true);
-};
-
-/** 全部收起操作 */
-const handleToggleCollapseAll = () => {
-  isExpandAll.value = false;
-  toggleExpandAll(categoryList.value, false);
-};
-
-/** 展开/折叠所有 */
-const toggleExpandAll = (data: CategoryVO[], status: boolean) => {
-  data.forEach((item) => {
-    categoryTableRef.value?.toggleRowExpansion(item, status);
-    if (item.children && item.children.length > 0) toggleExpandAll(item.children, status);
+/** 刷新已展开的懒加载节点 */
+const refreshLazyNodes = () => {
+  lazyTreeNodeMap.value.forEach(async ({ tree, treeNode, resolve }, key) => {
+    // 重置已加载状态
+    if (treeNode.loaded) {
+      treeNode.loaded = false;
+    }
+    // 重新加载
+    await loadChildren(tree, treeNode, resolve);
   });
   });
 };
 };
 
 
@@ -276,7 +300,8 @@ const toggleExpandAll = (data: CategoryVO[], status: boolean) => {
 const handleAdd = async (row?: CategoryVO) => {
 const handleAdd = async (row?: CategoryVO) => {
   reset();
   reset();
   const res = await listCategory();
   const res = await listCategory();
-  const data = proxy?.handleTree<CategoryOptionsType>(res.rows, 'id');
+  const responseData = (res as any).rows || res.data || [];
+  const data = proxy?.handleTree<CategoryOptionsType>(responseData, 'id');
   if (data) {
   if (data) {
     categoryOptions.value = data;
     categoryOptions.value = data;
     if (row && row.id) {
     if (row && row.id) {
@@ -331,6 +356,25 @@ const handleDelete = async (row: CategoryVO) => {
   proxy?.$modal.msgSuccess('删除成功');
   proxy?.$modal.msgSuccess('删除成功');
 }
 }
 
 
+/** 设置审核员按钮操作 */
+const handleSetReviewer = (row: CategoryVO) => {
+  currentReviewerCategory.value = row;
+  userSelectRef.value?.open();
+};
+
+/** 审核员选择回调 */
+const handleReviewerSelected = async (users: UserVO[]) => {
+  if (!currentReviewerCategory.value || users.length === 0) return;
+  
+  const user = users[0];
+  try {
+    await setCategoryReviewer(currentReviewerCategory.value.id, user.userId);
+    proxy?.$modal.msgSuccess(`已将 ${user.nickName} 设置为 ${currentReviewerCategory.value.categoryName} 的审核员`);
+  } catch (error) {
+    console.error('设置审核员失败:', error);
+  }
+};
+
 onMounted(() => {
 onMounted(() => {
   getList();
   getList();
 });
 });

+ 44 - 13
src/views/product/pool/index.vue

@@ -21,23 +21,20 @@
 
 
 
 
       <el-table v-loading="loading" border :data="poolList">
       <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="name" />
-        <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="isShow">
+        <el-table-column label="产品池类型" align="center" prop="type">
           <template #default="scope">
           <template #default="scope">
-            <el-switch 
-              v-model="scope.row.isShow" 
-              active-value="1" 
-              inactive-value="0"
-              
-              
-              @change="handleStatusChange(scope.row)"
-            />
+            {{ getPoolTypeLabel(scope.row.type) }}
           </template>
           </template>
         </el-table-column>
         </el-table-column>
-        <el-table-column label="操作" align="center" width="300">
+        <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="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 label="操作" align="center" width="260">
           <template #default="scope">
           <template #default="scope">
             <el-link type="primary" @click="handleModifyPool(scope.row)" v-hasPermi="['product:pool:edit']">修改分类商品池售卖</el-link>
             <el-link type="primary" @click="handleModifyPool(scope.row)" v-hasPermi="['product:pool:edit']">修改分类商品池售卖</el-link>
             <el-divider direction="vertical" />
             <el-divider direction="vertical" />
@@ -54,6 +51,16 @@
         <el-form-item label="项目/平台名称:" prop="name">
         <el-form-item label="项目/平台名称:" prop="name">
           <el-input v-model="form.name" placeholder="办公设备精选池" />
           <el-input v-model="form.name" placeholder="办公设备精选池" />
         </el-form-item>
         </el-form-item>
+        <el-form-item label="产品池类型:" prop="type">
+          <el-select v-model="form.type" placeholder="请选择产品池类型" style="width: 100%">
+            <el-option
+              v-for="item in poolTypeOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
         <el-form-item label="状态:" prop="isShow">
         <el-form-item label="状态:" prop="isShow">
           <el-switch 
           <el-switch 
             v-model="form.isShow" 
             v-model="form.isShow" 
@@ -89,6 +96,21 @@ import { PoolVO, PoolQuery, PoolForm } from '@/api/product/pool/types';
 
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
 
+/** 产品池类型选项 */
+const poolTypeOptions = [
+  { label: '普通产品池', value: 0 },
+  { label: '精选产品池', value: 1 },
+  { label: '协议产品池', value: 2 },
+  { label: '项目产品池', value: 3 },
+  { label: '分类产品池', value: 4 }
+];
+
+/** 获取产品池类型标签 */
+const getPoolTypeLabel = (type: number) => {
+  const option = poolTypeOptions.find(item => item.value === type);
+  return option ? option.label : '未知类型';
+};
+
 const poolList = ref<PoolVO[]>([]);
 const poolList = ref<PoolVO[]>([]);
 const buttonLoading = ref(false);
 const buttonLoading = ref(false);
 const loading = ref(true);
 const loading = ref(true);
@@ -109,6 +131,9 @@ const dialog = reactive<DialogOption>({
 const initFormData: PoolForm = {
 const initFormData: PoolForm = {
   id: undefined,
   id: undefined,
   poolNo: undefined,
   poolNo: undefined,
+  itemId: undefined,
+  categoryId: undefined,
+  type: 0,
   name: undefined,
   name: undefined,
   isShow: '1',
   isShow: '1',
   productReviewStatus: undefined,
   productReviewStatus: undefined,
@@ -121,6 +146,9 @@ const data = reactive<PageData<PoolForm, PoolQuery>>({
     pageNum: 1,
     pageNum: 1,
     pageSize: 10,
     pageSize: 10,
     poolNo: undefined,
     poolNo: undefined,
+    itemId: undefined,
+    categoryId: undefined,
+    type: undefined,
     name: undefined,
     name: undefined,
     isShow: undefined,
     isShow: undefined,
     productReviewStatus: undefined,
     productReviewStatus: undefined,
@@ -133,6 +161,9 @@ const data = reactive<PageData<PoolForm, PoolQuery>>({
     name: [
     name: [
       { required: true, message: "项目/平台名称不能为空", trigger: "blur" }
       { required: true, message: "项目/平台名称不能为空", trigger: "blur" }
     ],
     ],
+    type: [
+      { required: true, message: "产品池类型不能为空", trigger: "change" }
+    ],
     isShow: [
     isShow: [
       { required: true, message: "状态不能为空", trigger: "change" }
       { required: true, message: "状态不能为空", trigger: "change" }
     ],
     ],

+ 59 - 27
src/views/product/pool/review.vue

@@ -54,36 +54,40 @@
 
 
       <el-table v-loading="loading" border :data="poolList">
       <el-table v-loading="loading" border :data="poolList">
         <el-table-column label="产品池名称" align="center" prop="name" min-width="200" />
         <el-table-column label="产品池名称" align="center" prop="name" min-width="200" />
-        <el-table-column label="创建人" align="center" prop="createBy" />
-        <el-table-column label="审核人" align="center" prop="reviewBy" />
-        <el-table-column label="状态" align="center" prop="productReviewStatus">
+        <el-table-column label="产品池类型" align="center" prop="type">
           <template #default="scope">
           <template #default="scope">
-            <dict-tag :options="product_review_status" :value="scope.row.productReviewStatus" />
+            {{ getPoolTypeLabel(scope.row.type) }}
           </template>
           </template>
         </el-table-column>
         </el-table-column>
+        <!-- <el-table-column label="创建人" align="center" prop="createBy" />
+        <el-table-column label="审核人" align="center" prop="reviewBy" /> -->
+        <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 label="操作" align="center" width="300" fixed="right">
         <el-table-column label="操作" align="center" width="300" fixed="right">
           <template #default="scope">
           <template #default="scope">
             <!-- 待审核:查看、去审核 -->
             <!-- 待审核:查看、去审核 -->
-            <template v-if="scope.row.productReviewStatus === '1'">
-              <el-link type="primary" @click="handleView(scope.row)" v-hasPermi="['product:pool:query']">查看</el-link>
+            <template v-if="queryParams.productReviewStatus === '1'">
+              <el-link type="primary" @click="handleView(scope.row)">查看</el-link>
               <el-divider direction="vertical" />
               <el-divider direction="vertical" />
-              <el-link type="primary" @click="handleReview(scope.row)" v-hasPermi="['product:pool:review']">去审核</el-link>
+              <el-link type="primary" @click="handleReview(scope.row)">去审核</el-link>
             </template>
             </template>
             <!-- 已驳回:查看 -->
             <!-- 已驳回:查看 -->
-            <template v-else-if="scope.row.productReviewStatus === '3'">
-              <el-link type="primary" @click="handleView(scope.row)" v-hasPermi="['product:pool:query']">查看</el-link>
+            <template v-else-if="queryParams.productReviewStatus === '3'">
+              <el-link type="primary" @click="handleView(scope.row)">查看</el-link>
             </template>
             </template>
             <!-- 已通过:查看 -->
             <!-- 已通过:查看 -->
-            <template v-else-if="scope.row.productReviewStatus === '2'">
-              <el-link type="primary" @click="handleView(scope.row)" v-hasPermi="['product:pool:query']">查看</el-link>
+            <template v-else-if="queryParams.productReviewStatus === '2'">
+              <el-link type="primary" @click="handleView(scope.row)">查看</el-link>
             </template>
             </template>
             <!-- 待申请:查看、申请入池单、修改入池 -->
             <!-- 待申请:查看、申请入池单、修改入池 -->
-            <template v-else-if="scope.row.productReviewStatus === '0'">
-              <el-link type="primary" @click="handleView(scope.row)" v-hasPermi="['product:pool:query']">查看</el-link>
+            <template v-else-if="queryParams.productReviewStatus === '0'">
+              <el-link type="primary" @click="handleView(scope.row)">查看</el-link>
               <el-divider direction="vertical" />
               <el-divider direction="vertical" />
-              <el-link type="primary" @click="handleApply(scope.row)" v-hasPermi="['product:pool:apply']">申请入池单</el-link>
+              <el-link type="primary" @click="handleApply(scope.row)">申请入池单</el-link>
               <el-divider direction="vertical" />
               <el-divider direction="vertical" />
-              <el-link type="primary" @click="handleModify(scope.row)" v-hasPermi="['product:pool:edit']">修改入池</el-link>
+              <el-link type="primary" @click="handleModify(scope.row)">修改入池</el-link>
             </template>
             </template>
           </template>
           </template>
         </el-table-column>
         </el-table-column>
@@ -131,6 +135,24 @@ import { listPool, getPool, updatePool } from '@/api/product/pool';
 import { PoolVO, PoolQuery, PoolReviewForm } from '@/api/product/pool/types';
 import { PoolVO, PoolQuery, PoolReviewForm } from '@/api/product/pool/types';
 
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+// 字典数据
+const { product_review_status } = toRefs<any>(proxy?.useDict('product_review_status'));
+
+/** 产品池类型选项 */
+const poolTypeOptions = [
+  { label: '普通产品池', value: 0 },
+  { label: '精选产品池', value: 1 },
+  { label: '协议产品池', value: 2 },
+  { label: '项目产品池', value: 3 },
+  { label: '分类产品池', value: 4 }
+];
+
+/** 获取产品池类型标签 */
+const getPoolTypeLabel = (type: number) => {
+  const option = poolTypeOptions.find(item => item.value === type);
+  return option ? option.label : '未知类型';
+};
 const route = useRoute();
 const route = useRoute();
 
 
 const poolList = ref<PoolVO[]>([]);
 const poolList = ref<PoolVO[]>([]);
@@ -152,12 +174,13 @@ const viewDialog = reactive<DialogOption>({
   title: ''
   title: ''
 });
 });
 
 
-// 字典数据
-const { product_review_status } = toRefs<any>(proxy?.useDict('product_review_status'));
 
 
 const initFormData: PoolQuery = {
 const initFormData: PoolQuery = {
   pageNum: 1,
   pageNum: 1,
   pageSize: 10,
   pageSize: 10,
+  itemId: undefined,
+  categoryId: undefined,
+  type: undefined,
   name: undefined,
   name: undefined,
   productReviewStatus: undefined,
   productReviewStatus: undefined,
   createBy: undefined,
   createBy: undefined,
@@ -177,6 +200,9 @@ const { queryParams } = toRefs(data);
 const viewForm = ref<PoolVO>({
 const viewForm = ref<PoolVO>({
   id: '',
   id: '',
   poolNo: '',
   poolNo: '',
+  itemId: '',
+  categoryId: '',
+  type: 0,
   name: '',
   name: '',
   isShow: '',
   isShow: '',
   productReviewStatus: '',
   productReviewStatus: '',
@@ -253,24 +279,27 @@ const handleView = async (row: PoolVO) => {
 /** 去审核 */
 /** 去审核 */
 const handleReview = (row: PoolVO) => {
 const handleReview = (row: PoolVO) => {
   proxy?.$router.push({
   proxy?.$router.push({
-    path: '/product/pool/reviewDetail',
-    query: { poolId: row.id }
+    name: 'PoolReviewDetail',
+    query: { poolId: row.id, poolName: row.name, type: 'edit', productReviewStatus: route.query.productReviewStatus as string }
   });
   });
 }
 }
 
 
 /** 提交审核 */
 /** 提交审核 */
 const submitReview = () => {
 const submitReview = () => {
-  reviewFormRef.value?.validate(async (valid: boolean) => {
+  viewFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
     if (valid) {
       buttonLoading.value = true;
       buttonLoading.value = true;
       try {
       try {
         await updatePool({
         await updatePool({
-          id: reviewForm.value.id,
-          productReviewStatus: reviewForm.value.productReviewStatus,
-          reviewReason: reviewForm.value.reviewReason
-        });
+          id: viewForm.value.id,
+          itemId: viewForm.value.itemId,
+          categoryId: viewForm.value.categoryId,
+          type: viewForm.value.type,
+          productReviewStatus: viewForm.value.productReviewStatus,
+          reviewReason: viewForm.value.reviewReason
+        } as any);
         proxy?.$modal.msgSuccess("审核成功");
         proxy?.$modal.msgSuccess("审核成功");
-        reviewDialog.visible = false;
+        viewDialog.visible = false;
         await getList();
         await getList();
       } finally {
       } finally {
         buttonLoading.value = false;
         buttonLoading.value = false;
@@ -285,8 +314,11 @@ const handleApply = async (row: PoolVO) => {
     await proxy?.$modal.confirm('确认要申请该产品池入池吗?');
     await proxy?.$modal.confirm('确认要申请该产品池入池吗?');
     await updatePool({
     await updatePool({
       id: row.id,
       id: row.id,
+      itemId: row.itemId,
+      categoryId: row.categoryId,
+      type: row.type,
       productReviewStatus: '1' // 更新为待审核
       productReviewStatus: '1' // 更新为待审核
-    });
+    } as any);
     proxy?.$modal.msgSuccess("申请成功");
     proxy?.$modal.msgSuccess("申请成功");
     await getList();
     await getList();
   } catch {
   } catch {
@@ -298,7 +330,7 @@ const handleApply = async (row: PoolVO) => {
 const handleModify = (row: PoolVO) => {
 const handleModify = (row: PoolVO) => {
   proxy?.$router.push({
   proxy?.$router.push({
     path: '/product/poolLink',
     path: '/product/poolLink',
-    query: { poolId: row.id, poolName: row.name, type: 'edit' }
+    query: { poolId: row.id, poolName: row.name, type: 'edit', productReviewStatus: route.query.productReviewStatus as string }
   });
   });
 }
 }
 
 

+ 769 - 330
src/views/product/pool/reviewDetail.vue

@@ -3,406 +3,845 @@
     <!-- 返回按钮 -->
     <!-- 返回按钮 -->
     <div class="mb-4 flex items-center">
     <div class="mb-4 flex items-center">
       <el-button link icon="ArrowLeft" @click="goBack">返回</el-button>
       <el-button link icon="ArrowLeft" @click="goBack">返回</el-button>
-      <span class="ml-2 text-lg font-bold">入池清单信息</span>
+      <span class="ml-2 text-lg font-bold">商品配置</span>
     </div>
     </div>
 
 
-    <!-- 入池清单信息卡片 -->
-    <el-card shadow="hover" class="mb-4">
-      <el-descriptions :column="4" border>
-        <el-descriptions-item label="订单编号">{{ poolInfo.poolNo }}</el-descriptions-item>
-        <el-descriptions-item label="产品池名称">{{ poolInfo.name }}</el-descriptions-item>
-        <el-descriptions-item label="申请时间">{{ poolInfo.createTime }}</el-descriptions-item>
-        <el-descriptions-item label="审核时间">{{ poolInfo.reviewTime || '-' }}</el-descriptions-item>
-        <el-descriptions-item label="状态">
-          <dict-tag :options="product_review_status" :value="poolInfo.productReviewStatus" />
-        </el-descriptions-item>
-        <el-descriptions-item label="创建人">{{ poolInfo.createBy }}</el-descriptions-item>
-        <el-descriptions-item label="11" label-class-name="custom-label">11</el-descriptions-item>
-        <el-descriptions-item label="审核人">{{ poolInfo.reviewBy || '-' }}</el-descriptions-item>
-        <el-descriptions-item label="驳回意见" :span="4">
-          <span v-if="poolInfo.reviewReason">{{ poolInfo.reviewReason }}</span>
-          <span v-else class="text-gray-400">-</span>
-        </el-descriptions-item>
-      </el-descriptions>
-    </el-card>
+    <!-- 搜索区域 -->
+    <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-input v-model="queryParams.brandId" placeholder="请选择" clearable />
+                </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 :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品类别" prop="categoryId">
+                  <el-tree-select
+                    v-model="queryParams.categoryId"
+                    :data="categoryOptions"
+                    :props="{ value: 'id', label: 'label', children: 'children' }"
+                    check-strictly
+                    :render-after-expand="false"
+                    clearable
+                    placeholder="请选择商品类别"
+                  >
+                    <template #default="{ data }">
+                      <span>{{ getCategoryFullPath(data.id) }}</span>
+                    </template>
+                  </el-tree-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="创建供应商" prop="supplier">
+                  <el-input v-model="queryParams.supplier" placeholder="请选择创建供应商" clearable />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="入池时间" prop="dateRange">
+                  <el-date-picker
+                    v-model="queryParams.dateRange"
+                    type="daterange"
+                    range-separator="至"
+                    start-placeholder="开始时间"
+                    end-placeholder="结束时间"
+                    style="width: 100%"
+                  />
+                </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">
     <el-card shadow="never">
-      <el-tabs v-model="activeTab" @tab-click="handleTabClick">
-        <el-tab-pane label="待入池产品" name="pending">
-          <!-- 待入池产品按钮 -->
-          <div class="mb-4">
-            <el-button type="primary" icon="Plus">加入入池清单</el-button>
+      <template #header>
+        <div class="flex justify-between items-center">
+          <span class="font-bold">商品列表信息列表</span>
+          <div class="flex gap-2">
+            <el-button type="primary" icon="Plus" @click="handleAddProduct">添加商品</el-button>
+            <el-button type="warning" plain :disabled="!hasReviewableItems" @click="handleBatchReview">批量审核</el-button>
+            <el-button type="danger" plain :disabled="selectedPoolLinks.length === 0" @click="handleBatchRemove">批量移出</el-button>
+            <el-button type="primary" plain :disabled="!hasSubmittableItems" @click="handleSubmitReview">提交审核</el-button>
           </div>
           </div>
+        </div>
+      </template>
 
 
-          <!-- 待入池产品表格 -->
-          <el-table v-loading="pendingLoading" border :data="pendingProductList">
-            <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="productImageUrl" width="100">
-              <template #default="scope">
-                <image-preview :src="scope.row.productImageUrl" :width="60" :height="60"/>
-              </template>
-            </el-table-column>
-            <el-table-column label="商品信息" align="center" min-width="200">
-              <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 || '-' }}</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">
-              <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.platformPrice || '0.00' }}</span>
-                  </div>
-                  <div>
-                    <span class="text-gray-500">最低售价:</span>
-                    <span class="text-red-500">¥{{ scope.row.minPrice || '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.purchasePrice || '0.00' }}</span>
-                  </div>
-                  <div>
-                    <span class="text-gray-500">暂估毛利率:</span>
-                    <span>{{ scope.row.grossMargin || '0.00' }}%</span>
-                  </div>
-                </div>
-              </template>
-            </el-table-column>
-            <el-table-column label="项目/平台价" align="center" prop="productPrice" width="120">
-              <template #default="scope">
-                ¥{{ scope.row.productPrice || '0.00' }}
-              </template>
-            </el-table-column>
-            <el-table-column label="商品状态" align="center" width="100">
-              <template #default="scope">
-                <dict-tag :options="product_review_status" :value="scope.row.productReviewStatus" />
-              </template>
-            </el-table-column>
-            <el-table-column label="创建供应商" align="center" prop="supplier" width="120" />
-          </el-table>
-
-          <pagination v-show="pendingTotal > 0" :total="pendingTotal" v-model:page="pendingQuery.pageNum" v-model:limit="pendingQuery.pageSize" @pagination="getPendingList" />
-        </el-tab-pane>
-
-        <el-tab-pane label="入池清单" name="approved">
-          <!-- 入池清单表格 -->
-          <el-table v-loading="approvedLoading" border :data="approvedProductList">
-            <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="productImageUrl" width="100">
-              <template #default="scope">
-                <image-preview :src="scope.row.productImageUrl" :width="60" :height="60"/>
-              </template>
-            </el-table-column>
-            <el-table-column label="商品信息" align="center" min-width="200">
-              <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 || '-' }}</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">
-              <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.platformPrice || '0.00' }}</span>
-                  </div>
-                  <div>
-                    <span class="text-gray-500">最低售价:</span>
-                    <span class="text-red-500">¥{{ scope.row.minPrice || '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.purchasePrice || '0.00' }}</span>
-                  </div>
-                  <div>
-                    <span class="text-gray-500">暂估毛利率:</span>
-                    <span>{{ scope.row.grossMargin || '0.00' }}%</span>
-                  </div>
-                </div>
-              </template>
-            </el-table-column>
-            <el-table-column label="项目/平台价" align="center" prop="productPrice" width="120">
-              <template #default="scope">
-                ¥{{ scope.row.productPrice || '0.00' }}
-              </template>
-            </el-table-column>
-            <el-table-column label="商品状态" align="center" width="100">
-              <template #default="scope">
-                <dict-tag :options="product_review_status" :value="scope.row.productReviewStatus" />
-              </template>
-            </el-table-column>
-            <el-table-column label="创建供应商" align="center" prop="supplier" width="120" />
-          </el-table>
-
-          <pagination v-show="approvedTotal > 0" :total="approvedTotal" v-model:page="approvedQuery.pageNum" v-model:limit="approvedQuery.pageSize" @pagination="getApprovedList" />
-        </el-tab-pane>
-      </el-tabs>
+      <el-table v-loading="loading" border :data="productList" @selection-change="handlePoolLinkSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <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="productImageUrl" width="100">
+          <template #default="scope">
+            <image-preview :src="scope.row.productImageUrl" :width="60" :height="60"/>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品信息" align="center" width="200">
+          <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>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品类别" align="center" width="150">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px;">
+              <div>{{ scope.row.categoryName || '办公设备+扫描设备+平板式扫描仪' }}</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">
+          <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.platformPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">最低售价:</span>
+                <span class="text-red-500">¥{{ scope.row.minPrice || '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.purchasePrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">暂估毛利率:</span>
+                <span>{{ scope.row.grossMargin || '0.00' }}%</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="项目平台价" align="center" prop="platformPrice" width="100" />
+        <el-table-column label="商品状态" align="center" width="80">
+          <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="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="createTime" width="120" />
+        <el-table-column label="创建供应商" align="center" prop="supplier" width="100" />
+        <el-table-column label="操作" align="center" width="120" fixed="right">
+          <template #default="scope">
+            <div class="flex flex-col gap-1">
+              <el-link type="primary" :underline="false" @click="handlePriceMaintain(scope.row)">价格维护</el-link>
+              <el-link type="primary" :underline="false" @click="handleStockMaintain(scope.row)">修改库存</el-link>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
     </el-card>
     </el-card>
 
 
-    <!-- 底部审核按钮 -->
-    <div class="fixed bottom-0 left-0 right-0 bg-white border-t p-4 flex justify-center gap-4" style="z-index: 100;">
-      <el-button @click="handleReject" size="large">驳回</el-button>
-      <el-button type="primary" @click="handleApprove" size="large">通过</el-button>
-    </div>
+    <!-- 价格维护对话框 -->
+    <el-dialog title="价格维护" v-model="priceDialog.visible" width="500px" append-to-body>
+      <el-form ref="priceFormRef" :model="priceDialog.form" :rules="priceRules" label-width="100px">
+        <el-form-item label="商品名称">
+          <span>{{ priceDialog.row?.itemName }}</span>
+        </el-form-item>
+        <el-form-item label="市场价" prop="marketPrice">
+          <el-input-number v-model="priceDialog.form.marketPrice" :precision="2" :min="0" controls-position="right" style="width: 100%" />
+        </el-form-item>
+        <el-form-item label="平台售价" prop="platformPrice">
+          <el-input-number v-model="priceDialog.form.platformPrice" :precision="2" :min="0" controls-position="right" style="width: 100%" />
+        </el-form-item>
+        <el-form-item label="最低售价" prop="minPrice">
+          <el-input-number v-model="priceDialog.form.minPrice" :precision="2" :min="0" controls-position="right" style="width: 100%" />
+        </el-form-item>
+        <el-form-item label="产品价格" prop="productPrice">
+          <el-input-number v-model="priceDialog.form.productPrice" :precision="2" :min="0" controls-position="right" style="width: 100%" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="priceDialog.visible = false">取 消</el-button>
+        <el-button type="primary" @click="submitPriceForm">确 定</el-button>
+      </template>
+    </el-dialog>
 
 
-    <!-- 驳回对话框 -->
-    <el-dialog title="驳回原因" v-model="rejectDialog.visible" width="500px" append-to-body>
-      <el-form ref="rejectFormRef" :model="rejectForm" :rules="rejectRules" label-width="100px">
-        <el-form-item label="驳回原因:" prop="reviewReason">
-          <el-input 
-            v-model="rejectForm.reviewReason" 
-            type="textarea" 
-            placeholder="请输入驳回原因" 
-            maxlength="200"
-            show-word-limit
-            :rows="4"
-          />
+    <!-- 修改库存对话框 -->
+    <el-dialog title="修改库存" v-model="stockDialog.visible" width="500px" append-to-body>
+      <el-form ref="stockFormRef" :model="stockDialog.form" :rules="stockRules" label-width="100px">
+        <el-form-item label="商品名称">
+          <span>{{ stockDialog.row?.itemName }}</span>
+        </el-form-item>
+        <el-form-item label="当前库存">
+          <span>{{ stockDialog.row?.stock || 0 }}</span>
+        </el-form-item>
+        <el-form-item label="库存数量" prop="stock">
+          <el-input-number v-model="stockDialog.form.stock" :min="0" :precision="0" controls-position="right" style="width: 100%" />
         </el-form-item>
         </el-form-item>
       </el-form>
       </el-form>
       <template #footer>
       <template #footer>
-        <div class="dialog-footer">
-          <el-button :loading="buttonLoading" type="primary" @click="submitReject">确 认</el-button>
-          <el-button @click="rejectDialog.visible = false">取 消</el-button>
-        </div>
+        <el-button @click="stockDialog.visible = false">取 消</el-button>
+        <el-button type="primary" @click="submitStockForm">确 定</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 批量审核对话框 -->
+    <el-dialog title="批量审核" v-model="reviewDialog.visible" width="500px" append-to-body>
+      <el-form ref="reviewFormRef" :model="reviewDialog.form" :rules="reviewRules" label-width="100px">
+        <el-form-item label="审核结果" prop="productReviewStatus">
+          <el-radio-group v-model="reviewDialog.form.productReviewStatus">
+            <el-radio label="2">通过</el-radio>
+            <el-radio label="3">驳回</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item v-if="reviewDialog.form.productReviewStatus === '3'" label="驳回原因" prop="reviewReason">
+          <el-input v-model="reviewDialog.form.reviewReason" type="textarea" :rows="3" placeholder="请输入驳回原因" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="reviewDialog.visible = false">取 消</el-button>
+        <el-button type="primary" @click="submitReviewForm">确 定</el-button>
       </template>
       </template>
     </el-dialog>
     </el-dialog>
+
+    <!-- 添加商品对话框 -->
+    <el-dialog title="添加商品" v-model="addProductDialog.visible" width="1400px" append-to-body top="5vh">
+      <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="商品名称:">
+            <el-input v-model="addProductQuery.itemName" placeholder="商品名称" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item label="商品编号:">
+            <el-input v-model="addProductQuery.productNo" placeholder="商品编号" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="Search" @click="handleSearchProducts">搜索</el-button>
+          </el-form-item>
+        </el-form>
+
+        <!-- 商品列表 -->
+        <el-table
+          ref="addProductTableRef"
+          v-loading="addProductDialog.loading"
+          :data="addProductDialog.productList"
+          border
+          @selection-change="handleSelectionChange"
+          max-height="500"
+        >
+          <el-table-column type="selection" width="55" align="center" />
+          <el-table-column label="商品编号" align="center" prop="productNo" width="120" />
+          <el-table-column label="商品图片" align="center" prop="productImageUrl" width="100">
+            <template #default="scope">
+              <image-preview :src="scope.row.productImageUrl" :width="60" :height="60"/>
+            </template>
+          </el-table-column>
+          <el-table-column label="商品信息" align="center" min-width="200">
+            <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>
+            </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>
+            </template>
+          </el-table-column>
+          <el-table-column label="SKU价格" 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.midRangePrice || '0.00' }}</span>
+                </div>
+                <div>
+                  <span class="text-gray-500">平台价:</span>
+                  <span class="text-red-500">¥{{ scope.row.standardPrice || '0.00' }}</span>
+                </div>
+                <div>
+                  <span class="text-gray-500">最低价:</span>
+                  <span>¥{{ scope.row.certificatePrice || '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 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>
+            </template>
+          </el-table-column>
+          <el-table-column label="供应情况" align="center" width="150">
+            <template #default="scope">
+              <div class="text-left" style="font-size: 12px;">
+                <div>供应商数量:{{ scope.row.supplierCount || 0 }}</div>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column label="协议价" align="center" prop="agreementPrice" width="100" />
+          <el-table-column label="操作" align="center" width="100" fixed="right">
+            <template #default="scope">
+              <el-link type="primary" :underline="false" @click="handleAddSingleProduct(scope.row)">加入清单</el-link>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <!-- 游标分页控制 -->
+        <pagination
+          v-show="addProductDialog.productList.length > 0"
+          v-model:page="addProductQuery.pageNum"
+          v-model:limit="addProductQuery.pageSize"
+          v-model:way="addProductQuery.way"
+          :cursor-mode="true"
+          :has-more="addProductHasMore"
+          @pagination="getProductList"
+        />
+      </div>
+    </el-dialog>
   </div>
   </div>
 </template>
 </template>
 
 
-<script setup name="PoolReviewDetail" lang="ts">
+<script setup name="PoolLink" lang="ts">
 import { useRouter, useRoute } from 'vue-router';
 import { useRouter, useRoute } from 'vue-router';
-import { getPool, updatePool } from '@/api/product/pool';
-import { PoolVO } from '@/api/product/pool/types';
-import { listPoolLink } from '@/api/product/poolLink';
-import { PoolLinkVO, PoolLinkQuery } from '@/api/product/poolLink/types';
+import { categoryTree, listBase } from '@/api/product/base';
+import { BaseVO, BaseQuery } from '@/api/product/base/types';
+import { listPoolLink, batchAddProducts, BatchAddProductData, batchReview, reSubmit, editPrice, editStock, PoolLinkForm } from '@/api/product/poolLink';
+import { PoolLinkQuery, PoolLinkVO } from '@/api/product/poolLink/types';
 
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const router = useRouter();
 const router = useRouter();
 const route = useRoute();
 const route = useRoute();
 
 
-// 产品池信息
-const poolInfo = ref<PoolVO>({
-  id: '',
-  poolNo: '',
-  name: '',
-  isShow: '',
-  productReviewStatus: '',
-  reviewReason: '',
-  remark: '',
-  createTime: '',
-  createBy: '',
-  reviewBy: ''
-});
+const productList = ref<PoolLinkVO[]>([]);
+const selectedPoolLinks = ref<PoolLinkVO[]>([]); // 主列表选中的商品
+const loading = ref(false);
+const showSearch = ref(true);
+const total = ref(0);
 
 
-// 当前标签页
-const activeTab = ref('pending');
+// 添加商品弹框游标分页相关
+const addProductHasMore = ref(true); // 是否还有更多数据
+// 页面历史记录,存储每页的第一个id和最后一个id,用于支持双向翻页
+const addProductPageHistory = ref<Array<{ firstId: any; lastId: any }>>([]);
 
 
-// 待入池产品列表
-const pendingProductList = ref<PoolLinkVO[]>([]);
-const pendingLoading = ref(false);
-const pendingTotal = ref(0);
-const pendingQuery = ref<PoolLinkQuery>({
-  pageNum: 1,
-  pageSize: 10,
-  poolId: undefined,
-  productReviewStatus: '1' // 待审核
-});
+const queryFormRef = ref<ElFormInstance>();
 
 
-// 入池清单列表
-const approvedProductList = ref<PoolLinkVO[]>([]);
-const approvedLoading = ref(false);
-const approvedTotal = ref(0);
-const approvedQuery = ref<PoolLinkQuery>({
+const queryParams = ref({
   pageNum: 1,
   pageNum: 1,
   pageSize: 10,
   pageSize: 10,
-  poolId: undefined,
-  productReviewStatus: '2' // 审核通过
+  poolId: (route.params.id || route.query.poolId) as string | number,
+  productReviewStatus: route.query.productReviewStatus as string | undefined,
+  productNo: undefined,
+  itemName: undefined,
+  brandId: undefined,
+  productStatus: undefined,
+  categoryId: undefined,
+  supplier: undefined,
+  dateRange: undefined,
 });
 });
 
 
-// 驳回对话框
-const rejectDialog = reactive({
-  visible: false
+const categoryOptions = ref<any[]>([]);
+const categoryMap = ref<Map<string | number, any>>(new Map());
+
+// 添加商品对话框
+const addProductDialog = reactive({
+  visible: false,
+  loading: false,
+  productList: [] as BaseVO[],
+  total: 0,
 });
 });
 
 
-const rejectFormRef = ref<ElFormInstance>();
-const rejectForm = ref({
-  reviewReason: ''
+// 添加商品查询参数
+const addProductQuery = ref({
+  pageNum: 1,
+  pageSize: 10,
+  productNo: undefined as string | undefined,
+  itemName: undefined as string | undefined,
+  lastSeenId: undefined as string | number | undefined, // 游标分页的lastSeenId
+  way: undefined as number | undefined // 翻页方向: 0=上一页, 1=下一页
 });
 });
 
 
-const rejectRules = {
-  reviewReason: [
-    { required: true, message: "请输入驳回原因", trigger: "blur" }
-  ]
+// 选中的商品
+const selectedProducts = ref<BaseVO[]>([]);
+const addProductTableRef = ref<any>();
+
+/** 获取分类树 */
+const getCategoryTree = async () => {
+  try {
+    const res = await categoryTree();
+    categoryOptions.value = res.data || [];
+    // 构建分类映射
+    buildCategoryMap(categoryOptions.value);
+  } catch (error) {
+    console.error('获取分类树失败:', error);
+  }
 };
 };
 
 
-const buttonLoading = ref(false);
+/** 构建分类映射 */
+const buildCategoryMap = (categories: any[], parentPath = '') => {
+  categories.forEach(category => {
+    const fullPath = parentPath ? `${parentPath} > ${category.label}` : category.label;
+    categoryMap.value.set(category.id, { ...category, fullPath });
+    if (category.children && category.children.length > 0) {
+      buildCategoryMap(category.children, fullPath);
+    }
+  });
+};
 
 
-// 字典数据
-const { product_review_status } = toRefs<any>(proxy?.$dict.getDict('product_review_status'));
+/** 获取分类完整路径 */
+const getCategoryFullPath = (categoryId: string | number): string => {
+  const category = categoryMap.value.get(categoryId);
+  return category?.fullPath || '';
+};
 
 
-/** 获取产品池信息 */
-const getPoolInfo = async () => {
+/** 查询商品列表 */
+const getList = async () => {
+  loading.value = true;
   try {
   try {
-    const poolId = route.params.id || route.query.poolId;
-    if (!poolId) {
-      proxy?.$modal.msgError('缺少产品池ID');
-      goBack();
-      return;
+    const query: PoolLinkQuery = {
+      pageNum: queryParams.value.pageNum,
+      pageSize: queryParams.value.pageSize,
+      poolId: queryParams.value.poolId,
+      productReviewStatus: queryParams.value.productReviewStatus,
+      productNo: queryParams.value.productNo,
+      itemName: queryParams.value.itemName,
+      brandId: queryParams.value.brandId,
+      categoryId: queryParams.value.categoryId,
+      productStatus: queryParams.value.productStatus,
+      supplier: queryParams.value.supplier
+    };
+
+    // 处理日期范围
+    if (queryParams.value.dateRange && queryParams.value.dateRange.length === 2) {
+      query.params = {
+        beginCreateTime: queryParams.value.dateRange[0],
+        endCreateTime: queryParams.value.dateRange[1]
+      };
     }
     }
-    
-    const res = await getPool(poolId);
-    poolInfo.value = res.data;
-    
-    // 设置查询参数的poolId
-    pendingQuery.value.poolId = poolId;
-    approvedQuery.value.poolId = poolId;
+
+    const res = await listPoolLink(query);
+    productList.value = res.rows || [];
+    total.value = res.total || 0;
   } catch (error) {
   } catch (error) {
-    console.error('获取产品池信息失败:', error);
-    proxy?.$modal.msgError('获取产品池信息失败');
+    console.error('获取商品列表失败:', error);
+    productList.value = [];
+    total.value = 0;
+  } finally {
+    loading.value = false;
   }
   }
+}
+
+/** 返回 */
+const goBack = () => {
+  router.back();
+}
+
+/** 搜索 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 添加商品 */
+const handleAddProduct = () => {
+  addProductDialog.visible = true;
+  // 重置查询条件
+  addProductQuery.value = {
+    pageNum: 1,
+    pageSize: 10,
+    productNo: undefined,
+    itemName: undefined,
+    lastSeenId: undefined,
+    way: undefined,
+  };
+  addProductPageHistory.value = []; // 重置页面历史
+  selectedProducts.value = [];
+  getProductList();
 };
 };
 
 
-/** 获取待入池产品列表 */
-const getPendingList = async () => {
-  pendingLoading.value = true;
+/** 获取商品列表(游标分页) */
+const getProductList = async () => {
+  addProductDialog.loading = true;
   try {
   try {
-    const res = await listPoolLink(pendingQuery.value);
-    pendingProductList.value = res.rows || [];
-    pendingTotal.value = res.total || 0;
+    const currentPageNum = addProductQuery.value.pageNum;
+    const params: any = { ...addProductQuery.value };
+
+    // 第一页不需要游标参数
+    if (currentPageNum === 1) {
+      delete params.lastSeenId;
+      delete params.firstSeenId;
+      delete params.way;
+    } else {
+      // way参数:0=上一页,1=下一页
+      if (addProductQuery.value.way === 0) {
+        // 上一页:使用目标页的firstId
+        const nextPageHistory = addProductPageHistory.value[currentPageNum];
+        if (nextPageHistory) {
+          params.firstSeenId = nextPageHistory.firstId;
+          params.way = 0;
+        }
+      } else {
+        // 下一页:使用前一页的lastId作为lastSeenId
+        const prevPageHistory = addProductPageHistory.value[currentPageNum - 1];
+        if (prevPageHistory) {
+          params.lastSeenId = prevPageHistory.lastId;
+          params.way = 1;
+        }
+      }
+    }
+
+    const res = await listBase(params);
+    // 兼容两种返回结构
+    if (res.rows) {
+      addProductDialog.productList = res.rows;
+      addProductDialog.total = res.total || 0;
+    } else if (res.data) {
+      addProductDialog.productList = Array.isArray(res.data) ? res.data : [];
+      addProductDialog.total = addProductDialog.productList.length;
+    } else {
+      addProductDialog.productList = [];
+      addProductDialog.total = 0;
+    }
+
+    // 判断是否还有更多数据
+    addProductHasMore.value = addProductDialog.productList.length === addProductQuery.value.pageSize;
+
+    // 记录当前页的第一个id和最后一个id
+    if (addProductDialog.productList.length > 0) {
+      const firstItem = addProductDialog.productList[0];
+      const lastItem = addProductDialog.productList[addProductDialog.productList.length - 1];
+      // 如果长度小于currentPageNum则创建
+      if (addProductPageHistory.value.length <= currentPageNum) {
+        addProductPageHistory.value[currentPageNum] = {
+          firstId: firstItem.id,
+          lastId: lastItem.id
+        };
+      }
+    }
   } catch (error) {
   } catch (error) {
-    console.error('获取待入池产品列表失败:', error);
-    pendingProductList.value = [];
-    pendingTotal.value = 0;
+    console.error('获取品列表失败:', error);
+    addProductDialog.productList = [];
+    addProductDialog.total = 0;
   } finally {
   } finally {
-    pendingLoading.value = false;
+    addProductDialog.loading = false;
   }
   }
 };
 };
 
 
-/** 获取入池清单列表 */
-const getApprovedList = async () => {
-  approvedLoading.value = true;
+/** 搜索商品 */
+const handleSearchProducts = () => {
+  addProductQuery.value.pageNum = 1;
+  addProductQuery.value.lastSeenId = undefined;
+  addProductQuery.value.way = undefined;
+  addProductPageHistory.value = []; // 重置页面历史
+  getProductList();
+};
+
+/** 选择变化 */
+const handleSelectionChange = (selection: BaseVO[]) => {
+  selectedProducts.value = selection;
+};
+
+/** 批量加入清单 */
+const handleBatchAdd = async () => {
+  if (selectedProducts.value.length === 0) {
+    proxy?.$modal.msgWarning('请先选择要添加的商品');
+    return;
+  }
+
   try {
   try {
-    const res = await listPoolLink(approvedQuery.value);
-    approvedProductList.value = res.rows || [];
-    approvedTotal.value = res.total || 0;
+    // 构造批量添加的数据
+    const batchData: BatchAddProductData = {
+      poolId: queryParams.value.poolId ,
+      products: selectedProducts.value.map(product => ({
+        productId: product.id ,
+        agreementPrice: product.standardPrice || product.midRangePrice // 使用平台价或市场价作为协议价
+      }))
+    };
+
+    await batchAddProducts(batchData);
+    proxy?.$modal.msgSuccess(`成功添加 ${selectedProducts.value.length} 个商品到商品池`);
+    addProductDialog.visible = false;
+    // 清空选中项
+    selectedProducts.value = [];
+    if (addProductTableRef.value) {
+      addProductTableRef.value.clearSelection();
+    }
+    await getList();
   } catch (error) {
   } catch (error) {
-    console.error('获取入池清单列表失败:', error);
-    approvedProductList.value = [];
-    approvedTotal.value = 0;
-  } finally {
-    approvedLoading.value = false;
+    console.error('添加商品失败:', error);
   }
   }
 };
 };
 
 
-/** 标签页切换 */
-const handleTabClick = () => {
-  if (activeTab.value === 'pending') {
-    getPendingList();
-  } else {
-    getApprovedList();
+/** 添加单个商品 */
+const handleAddSingleProduct = async (row: BaseVO) => {
+  try {
+    // 构造单个商品添加的数据
+    const batchData: BatchAddProductData = {
+      poolId: queryParams.value.poolId ,
+      products: [{
+        productId: row.id ,
+        agreementPrice: row.standardPrice || row.midRangePrice // 使用平台价或市场价作为协议价
+      }]
+    };
+
+    await batchAddProducts(batchData);
+    proxy?.$modal.msgSuccess('添加成功');
+    // 不关闭对话框,允许继续添加
+    await getList();
+  } catch (error) {
+    console.error('添加商品失败:', error);
   }
   }
 };
 };
 
 
-/** 返回 */
-const goBack = () => {
-  router.back();
+/** 获取分类名称 */
+const getCategoryName = (row: BaseVO): string => {
+  // 优先使用完整路径
+  if (row.bottomCategoryId) {
+    return getCategoryFullPath(row.bottomCategoryId);
+  }
+  return '-';
 };
 };
 
 
-/** 驳回 */
-const handleReject = () => {
-  rejectForm.value.reviewReason = '';
-  rejectDialog.visible = true;
+/** 主列表选择变化 */
+const handlePoolLinkSelectionChange = (selection: PoolLinkVO[]) => {
+  selectedPoolLinks.value = selection;
 };
 };
 
 
-/** 提交驳回 */
-const submitReject = () => {
-  rejectFormRef.value?.validate(async (valid: boolean) => {
-    if (valid) {
-      buttonLoading.value = true;
-      try {
-        await updatePool({
-          id: poolInfo.value.id,
-          productReviewStatus: '3', // 驳回
-          reviewReason: rejectForm.value.reviewReason
-        });
-        proxy?.$modal.msgSuccess("驳回成功");
-        rejectDialog.visible = false;
-        goBack();
-      } finally {
-        buttonLoading.value = false;
-      }
-    }
-  });
+/** 是否有可审核的项(待审核状态) */
+const hasReviewableItems = computed(() => {
+  return selectedPoolLinks.value.some(item => item.productReviewStatus === '1');
+});
+
+/** 是否有可提交审核的项(待提交或驳回状态) */
+const hasSubmittableItems = computed(() => {
+  return selectedPoolLinks.value.some(item => item.productReviewStatus === '0' || item.productReviewStatus === '3');
+});
+
+// ========== 批量审核相关 ==========
+const reviewDialog = reactive({
+  visible: false,
+  form: {
+    productReviewStatus: '2' as string,
+    reviewReason: '' as string
+  }
+});
+const reviewFormRef = ref<ElFormInstance>();
+const reviewRules = reactive({
+  productReviewStatus: [{ required: true, message: '请选择审核结果', trigger: 'change' }],
+  reviewReason: [{ required: true, message: '请输入驳回原因', trigger: 'blur' }]
+});
+
+/** 批量审核 */
+const handleBatchReview = () => {
+  const reviewableItems = selectedPoolLinks.value.filter(item => item.productReviewStatus === '1');
+  if (reviewableItems.length === 0) {
+    proxy?.$modal.msgWarning('请选择待审核的商品');
+    return;
+  }
+  reviewDialog.form = { productReviewStatus: '2', reviewReason: '' };
+  reviewDialog.visible = true;
 };
 };
 
 
-/** 通过 */
-const handleApprove = async () => {
-  try {
-    await proxy?.$modal.confirm('确认通过该产品池审核吗?');
-    buttonLoading.value = true;
-    try {
-      await updatePool({
-        id: poolInfo.value.id,
-        productReviewStatus: '2', // 通过
-        reviewReason: ''
-      });
-      proxy?.$modal.msgSuccess("审核通过");
-      goBack();
-    } finally {
-      buttonLoading.value = false;
-    }
-  } catch {
-    // 取消操作
+/** 提交审核表单 */
+const submitReviewForm = async () => {
+  await reviewFormRef.value?.validate();
+  const reviewableItems = selectedPoolLinks.value.filter(item => item.productReviewStatus === '1');
+  const data: PoolLinkForm[] = reviewableItems.map(item => ({
+    id: item.id,
+    productReviewStatus: reviewDialog.form.productReviewStatus,
+    reviewReason: reviewDialog.form.productReviewStatus === '3' ? reviewDialog.form.reviewReason : undefined
+  }));
+  await batchReview(data);
+  proxy?.$modal.msgSuccess('审核成功');
+  reviewDialog.visible = false;
+  await getList();
+};
+
+/** 提交审核(待提交和驳回的商品) */
+const handleSubmitReview = async () => {
+  const submittableItems = selectedPoolLinks.value.filter(item => item.productReviewStatus === '0' || item.productReviewStatus === '3');
+  if (submittableItems.length === 0) {
+    proxy?.$modal.msgWarning('请选择待提交或已驳回的商品');
+    return;
+  }
+  await proxy?.$modal.confirm(`确认提交 ${submittableItems.length} 个商品进行审核吗?`);
+  const data: PoolLinkForm[] = submittableItems.map(item => ({ id: item.id, productReviewStatus: '1' }));
+  await reSubmit(data);
+  proxy?.$modal.msgSuccess('提交成功');
+  await getList();
+};
+
+/** 批量移出 */
+const handleBatchRemove = async () => {
+  if (selectedPoolLinks.value.length === 0) {
+    proxy?.$modal.msgWarning('请先选择要移出的商品');
+    return;
+  }
+  await proxy?.$modal.confirm(`确认要移出选中的 ${selectedPoolLinks.value.length} 个商品吗?`);
+  const ids = selectedPoolLinks.value.map(item => item.id);
+  // 调用删除接口
+  const { delPoolLink } = await import('@/api/product/poolLink');
+  await delPoolLink(ids);
+  proxy?.$modal.msgSuccess('移出成功');
+  await getList();
+};
+
+// ========== 价格维护相关 ==========
+const priceDialog = reactive({
+  visible: false,
+  row: null as PoolLinkVO | null,
+  form: {
+    marketPrice: 0,
+    platformPrice: 0,
+    minPrice: 0,
+    productPrice: 0
   }
   }
+});
+const priceFormRef = ref<ElFormInstance>();
+const priceRules = reactive({
+  productPrice: [{ required: true, message: '请输入产品价格', trigger: 'blur' }]
+});
+
+/** 价格维护 */
+const handlePriceMaintain = (row: PoolLinkVO) => {
+  priceDialog.row = row;
+  priceDialog.form = {
+    marketPrice: row.marketPrice || 0,
+    platformPrice: row.platformPrice || 0,
+    minPrice: row.minPrice || 0,
+    productPrice: row.productPrice || 0
+  };
+  priceDialog.visible = true;
+};
+
+/** 提交价格表单 */
+const submitPriceForm = async () => {
+  await priceFormRef.value?.validate();
+  const data: PoolLinkForm = {
+    id: priceDialog.row?.id,
+    productPrice: priceDialog.form.productPrice
+  };
+  await editPrice(data);
+  proxy?.$modal.msgSuccess('价格修改成功');
+  priceDialog.visible = false;
+  await getList();
+};
+
+// ========== 库存维护相关 ==========
+const stockDialog = reactive({
+  visible: false,
+  row: null as PoolLinkVO | null,
+  form: {
+    stock: 0
+  }
+});
+const stockFormRef = ref<ElFormInstance>();
+const stockRules = reactive({
+  stock: [{ required: true, message: '请输入库存数量', trigger: 'blur' }]
+});
+
+/** 修改库存 */
+const handleStockMaintain = (row: PoolLinkVO) => {
+  stockDialog.row = row;
+  stockDialog.form = {
+    stock: row.stock || 0
+  };
+  stockDialog.visible = true;
+};
+
+/** 提交库存表单 */
+const submitStockForm = async () => {
+  await stockFormRef.value?.validate();
+  const data: PoolLinkForm = {
+    id: stockDialog.row?.id,
+    stock: stockDialog.form.stock
+  };
+  await editStock(data);
+  proxy?.$modal.msgSuccess('库存修改成功');
+  stockDialog.visible = false;
+  await getList();
 };
 };
 
 
-onMounted(async () => {
-  await getPoolInfo();
-  // 默认加载待入池产品
-  await getPendingList();
+onMounted(() => {
+  getCategoryTree();
+  getList();
 });
 });
 </script>
 </script>
 
 
 <style scoped lang="scss">
 <style scoped lang="scss">
-// 为底部固定按钮留出空间
-:deep(.el-card__body) {
-  padding-bottom: 80px;
-}
-
-.custom-label {
-  font-weight: normal;
+.add-product-dialog {
+  :deep(.el-form--inline .el-form-item) {
+    margin-right: 10px;
+  }
 }
 }
 </style>
 </style>

+ 198 - 33
src/views/product/poolLink/index.vue

@@ -74,7 +74,6 @@
               <el-col :span="6" class="text-left">
               <el-col :span="6" class="text-left">
                 <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                 <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                 <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                 <el-button icon="Refresh" @click="resetQuery">重置</el-button>
-                <el-button type="danger" plain @click="handleClearPool">清空产品池</el-button>
               </el-col>
               </el-col>
             </el-row>
             </el-row>
           </el-form>
           </el-form>
@@ -88,8 +87,6 @@
           <span class="font-bold">商品列表信息列表</span>
           <span class="font-bold">商品列表信息列表</span>
           <div class="flex gap-2">
           <div class="flex gap-2">
             <el-button type="primary" icon="Plus" @click="handleAddProduct">添加商品</el-button>
             <el-button type="primary" icon="Plus" @click="handleAddProduct">添加商品</el-button>
-            <el-button type="success" icon="Download" @click="handleExportProduct">导出商品</el-button>
-            <el-button type="warning" icon="Upload" @click="handleImportProduct">导入商品</el-button>
           </div>
           </div>
         </div>
         </div>
       </template>
       </template>
@@ -102,7 +99,7 @@
             <image-preview :src="scope.row.productImageUrl" :width="60" :height="60"/>
             <image-preview :src="scope.row.productImageUrl" :width="60" :height="60"/>
           </template>
           </template>
         </el-table-column>
         </el-table-column>
-        <el-table-column label="商品信息" align="center" width="200">
+        <el-table-column label="商品信息" align="center" min-width="200">
           <template #default="scope">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px;">
             <div class="text-left" style="font-size: 12px;">
               <div>{{ scope.row.itemName }}</div>
               <div>{{ scope.row.itemName }}</div>
@@ -174,6 +171,50 @@
       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
     </el-card>
     </el-card>
 
 
+    <!-- 价格维护对话框 -->
+    <el-dialog title="价格维护" v-model="priceDialog.visible" width="500px" append-to-body>
+      <el-form ref="priceFormRef" :model="priceDialog.form" :rules="priceRules" label-width="100px">
+        <el-form-item label="商品名称">
+          <span>{{ priceDialog.row?.itemName }}</span>
+        </el-form-item>
+        <el-form-item label="市场价" prop="marketPrice">
+          <el-input-number v-model="priceDialog.form.marketPrice" :precision="2" :min="0" controls-position="right" style="width: 100%" />
+        </el-form-item>
+        <el-form-item label="平台售价" prop="platformPrice">
+          <el-input-number v-model="priceDialog.form.platformPrice" :precision="2" :min="0" controls-position="right" style="width: 100%" />
+        </el-form-item>
+        <el-form-item label="最低售价" prop="minPrice">
+          <el-input-number v-model="priceDialog.form.minPrice" :precision="2" :min="0" controls-position="right" style="width: 100%" />
+        </el-form-item>
+        <el-form-item label="产品价格" prop="productPrice">
+          <el-input-number v-model="priceDialog.form.productPrice" :precision="2" :min="0" controls-position="right" style="width: 100%" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="priceDialog.visible = false">取 消</el-button>
+        <el-button type="primary" @click="submitPriceForm">确 定</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 修改库存对话框 -->
+    <el-dialog title="修改库存" v-model="stockDialog.visible" width="500px" append-to-body>
+      <el-form ref="stockFormRef" :model="stockDialog.form" :rules="stockRules" label-width="100px">
+        <el-form-item label="商品名称">
+          <span>{{ stockDialog.row?.itemName }}</span>
+        </el-form-item>
+        <el-form-item label="当前库存">
+          <span>{{ stockDialog.row?.stock || 0 }}</span>
+        </el-form-item>
+        <el-form-item label="库存数量" prop="stock">
+          <el-input-number v-model="stockDialog.form.stock" :min="0" :precision="0" controls-position="right" style="width: 100%" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="stockDialog.visible = false">取 消</el-button>
+        <el-button type="primary" @click="submitStockForm">确 定</el-button>
+      </template>
+    </el-dialog>
+
     <!-- 添加商品对话框 -->
     <!-- 添加商品对话框 -->
     <el-dialog title="添加商品" v-model="addProductDialog.visible" width="1400px" append-to-body top="5vh">
     <el-dialog title="添加商品" v-model="addProductDialog.visible" width="1400px" append-to-body top="5vh">
       <div class="add-product-dialog">
       <div class="add-product-dialog">
@@ -275,11 +316,14 @@
           </el-table-column>
           </el-table-column>
         </el-table>
         </el-table>
 
 
+        <!-- 游标分页控制 -->
         <pagination
         <pagination
-          v-show="addProductDialog.total > 0"
-          :total="addProductDialog.total"
+          v-show="addProductDialog.productList.length > 0"
           v-model:page="addProductQuery.pageNum"
           v-model:page="addProductQuery.pageNum"
           v-model:limit="addProductQuery.pageSize"
           v-model:limit="addProductQuery.pageSize"
+          v-model:way="addProductQuery.way"
+          :cursor-mode="true"
+          :has-more="addProductHasMore"
           @pagination="getProductList"
           @pagination="getProductList"
         />
         />
       </div>
       </div>
@@ -291,14 +335,14 @@
 import { useRouter, useRoute } from 'vue-router';
 import { useRouter, useRoute } from 'vue-router';
 import { categoryTree, listBase } from '@/api/product/base';
 import { categoryTree, listBase } from '@/api/product/base';
 import { BaseVO, BaseQuery } from '@/api/product/base/types';
 import { BaseVO, BaseQuery } from '@/api/product/base/types';
-import { listPoolLink, batchAddProducts, BatchAddProductData } from '@/api/product/poolLink';
-import { PoolLinkQuery } from '@/api/product/poolLink/types';
+import { listPoolLink, batchAddProducts, BatchAddProductData, editPrice, editStock, delPoolLink, PoolLinkForm } from '@/api/product/poolLink';
+import { PoolLinkQuery, PoolLinkVO } from '@/api/product/poolLink/types';
 
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const router = useRouter();
 const router = useRouter();
 const route = useRoute();
 const route = useRoute();
 
 
-const productList = ref<any[]>([]);
+const productList = ref<PoolLinkVO[]>([]);
 const loading = ref(false);
 const loading = ref(false);
 const showSearch = ref(true);
 const showSearch = ref(true);
 const total = ref(0);
 const total = ref(0);
@@ -308,7 +352,7 @@ const queryFormRef = ref<ElFormInstance>();
 const queryParams = ref({
 const queryParams = ref({
   pageNum: 1,
   pageNum: 1,
   pageSize: 10,
   pageSize: 10,
-  poolId: route.params.id || route.query.poolId,
+  poolId: (route.params.id || route.query.poolId) as string | number,
   productNo: undefined,
   productNo: undefined,
   itemName: undefined,
   itemName: undefined,
   brandId: undefined,
   brandId: undefined,
@@ -329,12 +373,18 @@ const addProductDialog = reactive({
   total: 0,
   total: 0,
 });
 });
 
 
+// 游标分页相关变量
+const addProductHasMore = ref(true); // 是否还有更多数据
+const addProductPageHistory = ref<Array<{ firstId: string | number; lastId: string | number }>>([]);
+
 // 添加商品查询参数
 // 添加商品查询参数
 const addProductQuery = ref<BaseQuery>({
 const addProductQuery = ref<BaseQuery>({
   pageNum: 1,
   pageNum: 1,
   pageSize: 10,
   pageSize: 10,
+  way: undefined,
   productNo: undefined,
   productNo: undefined,
   itemName: undefined,
   itemName: undefined,
+  lastSeenId: undefined, // 游标分页的lastSeenId
 });
 });
 
 
 // 选中的商品
 // 选中的商品
@@ -377,7 +427,7 @@ const getList = async () => {
     const query: PoolLinkQuery = {
     const query: PoolLinkQuery = {
       pageNum: queryParams.value.pageNum,
       pageNum: queryParams.value.pageNum,
       pageSize: queryParams.value.pageSize,
       pageSize: queryParams.value.pageSize,
-      poolId: queryParams.value.poolId,
+      poolId: queryParams.value.poolId as string | number,
       productNo: queryParams.value.productNo,
       productNo: queryParams.value.productNo,
       itemName: queryParams.value.itemName,
       itemName: queryParams.value.itemName,
       brandId: queryParams.value.brandId,
       brandId: queryParams.value.brandId,
@@ -385,7 +435,7 @@ const getList = async () => {
       productStatus: queryParams.value.productStatus,
       productStatus: queryParams.value.productStatus,
       supplier: queryParams.value.supplier
       supplier: queryParams.value.supplier
     };
     };
-    
+
     // 处理日期范围
     // 处理日期范围
     if (queryParams.value.dateRange && queryParams.value.dateRange.length === 2) {
     if (queryParams.value.dateRange && queryParams.value.dateRange.length === 2) {
       query.params = {
       query.params = {
@@ -393,7 +443,7 @@ const getList = async () => {
         endCreateTime: queryParams.value.dateRange[1]
         endCreateTime: queryParams.value.dateRange[1]
       };
       };
     }
     }
-    
+
     const res = await listPoolLink(query);
     const res = await listPoolLink(query);
     productList.value = res.rows || [];
     productList.value = res.rows || [];
     total.value = res.total || 0;
     total.value = res.total || 0;
@@ -438,9 +488,14 @@ const handleAddProduct = () => {
   addProductQuery.value = {
   addProductQuery.value = {
     pageNum: 1,
     pageNum: 1,
     pageSize: 10,
     pageSize: 10,
+    way: undefined,
     productNo: undefined,
     productNo: undefined,
     itemName: undefined,
     itemName: undefined,
+    lastSeenId: undefined,
   };
   };
+  // 重置游标分页状态
+  addProductPageHistory.value = [];
+  addProductHasMore.value = true;
   selectedProducts.value = [];
   selectedProducts.value = [];
   getProductList();
   getProductList();
 };
 };
@@ -449,7 +504,34 @@ const handleAddProduct = () => {
 const getProductList = async () => {
 const getProductList = async () => {
   addProductDialog.loading = true;
   addProductDialog.loading = true;
   try {
   try {
-    const res = await listBase(addProductQuery.value);
+    const params = { ...addProductQuery.value };
+    const currentPageNum = addProductQuery.value.pageNum;
+
+    // 第一页不需要游标参数
+    if (currentPageNum === 1) {
+      delete params.lastSeenId;
+      delete params.firstSeenId;
+      delete params.way;
+    } else {
+      // way参数:0=上一页,1=下一页
+      if (addProductQuery.value.way === 0) {
+        // 上一页:使用目标页的firstId
+        const nextPageHistory = addProductPageHistory.value[currentPageNum];
+        if (nextPageHistory) {
+          params.firstSeenId = nextPageHistory.firstId;
+          params.way = 0;
+        }
+      } else {
+        // 下一页:使用前一页的lastId作为lastSeenId
+        const prevPageHistory = addProductPageHistory.value[currentPageNum - 1];
+        if (prevPageHistory) {
+          params.lastSeenId = prevPageHistory.lastId;
+          params.way = 1;
+        }
+      }
+    }
+
+    const res = await listBase(params);
     // 兼容两种返回结构
     // 兼容两种返回结构
     if (res.rows) {
     if (res.rows) {
       addProductDialog.productList = res.rows;
       addProductDialog.productList = res.rows;
@@ -461,6 +543,22 @@ const getProductList = async () => {
       addProductDialog.productList = [];
       addProductDialog.productList = [];
       addProductDialog.total = 0;
       addProductDialog.total = 0;
     }
     }
+
+    // 判断是否还有更多数据
+    addProductHasMore.value = addProductDialog.productList.length === addProductQuery.value.pageSize;
+
+    // 记录当前页的第一个id和最后一个id
+    if (addProductDialog.productList.length > 0) {
+      const firstItem = addProductDialog.productList[0];
+      const lastItem = addProductDialog.productList[addProductDialog.productList.length - 1];
+      // 如果长度小于currentPageNum则创建
+      if (addProductPageHistory.value.length <= currentPageNum) {
+        addProductPageHistory.value[currentPageNum] = {
+          firstId: firstItem.id,
+          lastId: lastItem.id
+        };
+      }
+    }
   } catch (error) {
   } catch (error) {
     console.error('获取商品列表失败:', error);
     console.error('获取商品列表失败:', error);
     addProductDialog.productList = [];
     addProductDialog.productList = [];
@@ -473,6 +571,9 @@ const getProductList = async () => {
 /** 搜索商品 */
 /** 搜索商品 */
 const handleSearchProducts = () => {
 const handleSearchProducts = () => {
   addProductQuery.value.pageNum = 1;
   addProductQuery.value.pageNum = 1;
+  addProductQuery.value.lastSeenId = undefined;
+  addProductPageHistory.value = []; // 重置页面历史
+  addProductHasMore.value = true;
   getProductList();
   getProductList();
 };
 };
 
 
@@ -487,17 +588,17 @@ const handleBatchAdd = async () => {
     proxy?.$modal.msgWarning('请先选择要添加的商品');
     proxy?.$modal.msgWarning('请先选择要添加的商品');
     return;
     return;
   }
   }
-  
+
   try {
   try {
     // 构造批量添加的数据
     // 构造批量添加的数据
     const batchData: BatchAddProductData = {
     const batchData: BatchAddProductData = {
-      poolId: queryParams.value.poolId as number,
+      poolId: queryParams.value.poolId,
       products: selectedProducts.value.map(product => ({
       products: selectedProducts.value.map(product => ({
-        productId: product.id as number,
+        productId: product.id,
         agreementPrice: product.standardPrice || product.midRangePrice // 使用平台价或市场价作为协议价
         agreementPrice: product.standardPrice || product.midRangePrice // 使用平台价或市场价作为协议价
       }))
       }))
     };
     };
-    
+
     await batchAddProducts(batchData);
     await batchAddProducts(batchData);
     proxy?.$modal.msgSuccess(`成功添加 ${selectedProducts.value.length} 个商品到商品池`);
     proxy?.$modal.msgSuccess(`成功添加 ${selectedProducts.value.length} 个商品到商品池`);
     addProductDialog.visible = false;
     addProductDialog.visible = false;
@@ -517,13 +618,13 @@ const handleAddSingleProduct = async (row: BaseVO) => {
   try {
   try {
     // 构造单个商品添加的数据
     // 构造单个商品添加的数据
     const batchData: BatchAddProductData = {
     const batchData: BatchAddProductData = {
-      poolId: queryParams.value.poolId as number,
+      poolId: queryParams.value.poolId,
       products: [{
       products: [{
-        productId: row.id as number,
+        productId: row.id,
         agreementPrice: row.standardPrice || row.midRangePrice // 使用平台价或市场价作为协议价
         agreementPrice: row.standardPrice || row.midRangePrice // 使用平台价或市场价作为协议价
       }]
       }]
     };
     };
-    
+
     await batchAddProducts(batchData);
     await batchAddProducts(batchData);
     proxy?.$modal.msgSuccess('添加成功');
     proxy?.$modal.msgSuccess('添加成功');
     // 不关闭对话框,允许继续添加
     // 不关闭对话框,允许继续添加
@@ -545,31 +646,95 @@ const getCategoryName = (row: BaseVO): string => {
 /** 导出商品 */
 /** 导出商品 */
 const handleExportProduct = () => {
 const handleExportProduct = () => {
   // TODO: 导出功能
   // TODO: 导出功能
-  proxy?.$modal.msgInfo('导出商品功能');
+  proxy?.$modal.msg('导出商品功能');
 }
 }
 
 
 /** 导入商品 */
 /** 导入商品 */
 const handleImportProduct = () => {
 const handleImportProduct = () => {
   // TODO: 导入功能
   // TODO: 导入功能
-  proxy?.$modal.msgInfo('导入商品功能');
+  proxy?.$modal.msg('导入商品功能');
 }
 }
 
 
+// ========== 价格维护相关 ==========
+const priceDialog = reactive({
+  visible: false,
+  row: null as PoolLinkVO | null,
+  form: {
+    marketPrice: 0,
+    platformPrice: 0,
+    minPrice: 0,
+    productPrice: 0
+  }
+});
+const priceFormRef = ref<ElFormInstance>();
+const priceRules = reactive({
+  productPrice: [{ required: true, message: '请输入产品价格', trigger: 'blur' }]
+});
+
 /** 价格维护 */
 /** 价格维护 */
-const handlePriceMaintain = (row: any) => {
-  // TODO: 打开价格维护对话框
-  proxy?.$modal.msgInfo('价格维护功能');
-}
+const handlePriceMaintain = (row: PoolLinkVO) => {
+  priceDialog.row = row;
+  priceDialog.form = {
+    marketPrice: row.marketPrice || 0,
+    platformPrice: row.platformPrice || 0,
+    minPrice: row.minPrice || 0,
+    productPrice: row.productPrice || 0
+  };
+  priceDialog.visible = true;
+};
+
+/** 提交价格表单 */
+const submitPriceForm = async () => {
+  await priceFormRef.value?.validate();
+  const data: PoolLinkForm = {
+    id: priceDialog.row?.id,
+    productPrice: priceDialog.form.productPrice
+  };
+  await editPrice(data);
+  proxy?.$modal.msgSuccess('价格修改成功');
+  priceDialog.visible = false;
+  await getList();
+};
+
+// ========== 库存维护相关 ==========
+const stockDialog = reactive({
+  visible: false,
+  row: null as PoolLinkVO | null,
+  form: {
+    stock: 0
+  }
+});
+const stockFormRef = ref<ElFormInstance>();
+const stockRules = reactive({
+  stock: [{ required: true, message: '请输入库存数量', trigger: 'blur' }]
+});
 
 
 /** 修改库存 */
 /** 修改库存 */
-const handleInventoryMaintain = (row: any) => {
-  // TODO: 打开修改库存对话框
-  proxy?.$modal.msgInfo('修改库存功能');
-}
+const handleInventoryMaintain = (row: PoolLinkVO) => {
+  stockDialog.row = row;
+  stockDialog.form = {
+    stock: row.stock || 0
+  };
+  stockDialog.visible = true;
+};
+
+/** 提交库存表单 */
+const submitStockForm = async () => {
+  await stockFormRef.value?.validate();
+  const data: PoolLinkForm = {
+    id: stockDialog.row?.id,
+    stock: stockDialog.form.stock
+  };
+  await editStock(data);
+  proxy?.$modal.msgSuccess('库存修改成功');
+  stockDialog.visible = false;
+  await getList();
+};
 
 
 /** 移除商品池 */
 /** 移除商品池 */
-const handleRemoveProduct = async (row: any) => {
+const handleRemoveProduct = async (row: PoolLinkVO) => {
   await proxy?.$modal.confirm('确认要移除该商品吗?');
   await proxy?.$modal.confirm('确认要移除该商品吗?');
-  // TODO: 调用移除API
+  await delPoolLink(row.id);
   proxy?.$modal.msgSuccess('移除成功');
   proxy?.$modal.msgSuccess('移除成功');
   await getList();
   await getList();
 }
 }

+ 847 - 0
src/views/product/poolLink/index1.vue

@@ -0,0 +1,847 @@
+<template>
+  <div class="p-2">
+    <!-- 返回按钮 -->
+    <div class="mb-4 flex items-center">
+      <el-button link icon="ArrowLeft" @click="goBack">返回</el-button>
+      <span class="ml-2 text-lg font-bold">商品配置</span>
+    </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="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-input v-model="queryParams.brandId" placeholder="请选择" clearable />
+                </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 :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品类别" prop="categoryId">
+                  <el-tree-select
+                    v-model="queryParams.categoryId"
+                    :data="categoryOptions"
+                    :props="{ value: 'id', label: 'label', children: 'children' }"
+                    check-strictly
+                    :render-after-expand="false"
+                    clearable
+                    placeholder="请选择商品类别"
+                  >
+                    <template #default="{ data }">
+                      <span>{{ getCategoryFullPath(data.id) }}</span>
+                    </template>
+                  </el-tree-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="创建供应商" prop="supplier">
+                  <el-input v-model="queryParams.supplier" placeholder="请选择创建供应商" clearable />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="入池时间" prop="dateRange">
+                  <el-date-picker
+                    v-model="queryParams.dateRange"
+                    type="daterange"
+                    range-separator="至"
+                    start-placeholder="开始时间"
+                    end-placeholder="结束时间"
+                    style="width: 100%"
+                  />
+                </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">
+      <template #header>
+        <div class="flex justify-between items-center">
+          <span class="font-bold">商品列表信息列表</span>
+          <div class="flex gap-2">
+            <el-button type="primary" icon="Plus" @click="handleAddProduct">添加商品</el-button>
+            <el-button type="warning" plain :disabled="!hasReviewableItems" @click="handleBatchReview">批量审核</el-button>
+            <el-button type="danger" plain :disabled="selectedPoolLinks.length === 0" @click="handleBatchRemove">批量移出</el-button>
+            <el-button type="primary" plain :disabled="!hasSubmittableItems" @click="handleSubmitReview">提交审核</el-button>
+          </div>
+        </div>
+      </template>
+
+      <el-table v-loading="loading" border :data="productList" @selection-change="handlePoolLinkSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <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="productImageUrl" width="100">
+          <template #default="scope">
+            <image-preview :src="scope.row.productImageUrl" :width="60" :height="60"/>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品信息" align="center" width="200">
+          <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>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品类别" align="center" width="150">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px;">
+              <div>{{ scope.row.categoryName || '办公设备+扫描设备+平板式扫描仪' }}</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">
+          <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.platformPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">最低售价:</span>
+                <span class="text-red-500">¥{{ scope.row.minPrice || '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.purchasePrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">暂估毛利率:</span>
+                <span>{{ scope.row.grossMargin || '0.00' }}%</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="项目平台价" align="center" prop="platformPrice" width="100" />
+        <el-table-column label="商品状态" align="center" width="80">
+          <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="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="createTime" width="120" />
+        <el-table-column label="创建供应商" align="center" prop="supplier" width="100" />
+        <el-table-column label="操作" align="center" width="120" fixed="right">
+          <template #default="scope">
+            <div class="flex flex-col gap-1">
+              <el-link type="primary" :underline="false" @click="handlePriceMaintain(scope.row)">价格维护</el-link>
+              <el-link type="primary" :underline="false" @click="handleStockMaintain(scope.row)">修改库存</el-link>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <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="priceDialog.visible" width="500px" append-to-body>
+      <el-form ref="priceFormRef" :model="priceDialog.form" :rules="priceRules" label-width="100px">
+        <el-form-item label="商品名称">
+          <span>{{ priceDialog.row?.itemName }}</span>
+        </el-form-item>
+        <el-form-item label="市场价" prop="marketPrice">
+          <el-input-number v-model="priceDialog.form.marketPrice" :precision="2" :min="0" controls-position="right" style="width: 100%" />
+        </el-form-item>
+        <el-form-item label="平台售价" prop="platformPrice">
+          <el-input-number v-model="priceDialog.form.platformPrice" :precision="2" :min="0" controls-position="right" style="width: 100%" />
+        </el-form-item>
+        <el-form-item label="最低售价" prop="minPrice">
+          <el-input-number v-model="priceDialog.form.minPrice" :precision="2" :min="0" controls-position="right" style="width: 100%" />
+        </el-form-item>
+        <el-form-item label="产品价格" prop="productPrice">
+          <el-input-number v-model="priceDialog.form.productPrice" :precision="2" :min="0" controls-position="right" style="width: 100%" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="priceDialog.visible = false">取 消</el-button>
+        <el-button type="primary" @click="submitPriceForm">确 定</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 修改库存对话框 -->
+    <el-dialog title="修改库存" v-model="stockDialog.visible" width="500px" append-to-body>
+      <el-form ref="stockFormRef" :model="stockDialog.form" :rules="stockRules" label-width="100px">
+        <el-form-item label="商品名称">
+          <span>{{ stockDialog.row?.itemName }}</span>
+        </el-form-item>
+        <el-form-item label="当前库存">
+          <span>{{ stockDialog.row?.stock || 0 }}</span>
+        </el-form-item>
+        <el-form-item label="库存数量" prop="stock">
+          <el-input-number v-model="stockDialog.form.stock" :min="0" :precision="0" controls-position="right" style="width: 100%" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="stockDialog.visible = false">取 消</el-button>
+        <el-button type="primary" @click="submitStockForm">确 定</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 批量审核对话框 -->
+    <el-dialog title="批量审核" v-model="reviewDialog.visible" width="500px" append-to-body>
+      <el-form ref="reviewFormRef" :model="reviewDialog.form" :rules="reviewRules" label-width="100px">
+        <el-form-item label="审核结果" prop="productReviewStatus">
+          <el-radio-group v-model="reviewDialog.form.productReviewStatus">
+            <el-radio label="2">通过</el-radio>
+            <el-radio label="3">驳回</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item v-if="reviewDialog.form.productReviewStatus === '3'" label="驳回原因" prop="reviewReason">
+          <el-input v-model="reviewDialog.form.reviewReason" type="textarea" :rows="3" placeholder="请输入驳回原因" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="reviewDialog.visible = false">取 消</el-button>
+        <el-button type="primary" @click="submitReviewForm">确 定</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 添加商品对话框 -->
+    <el-dialog title="添加商品" v-model="addProductDialog.visible" width="1400px" append-to-body top="5vh">
+      <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="商品名称:">
+            <el-input v-model="addProductQuery.itemName" placeholder="商品名称" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item label="商品编号:">
+            <el-input v-model="addProductQuery.productNo" placeholder="商品编号" clearable style="width: 200px" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="Search" @click="handleSearchProducts">搜索</el-button>
+          </el-form-item>
+        </el-form>
+
+        <!-- 商品列表 -->
+        <el-table
+          ref="addProductTableRef"
+          v-loading="addProductDialog.loading"
+          :data="addProductDialog.productList"
+          border
+          @selection-change="handleSelectionChange"
+          max-height="500"
+        >
+          <el-table-column type="selection" width="55" align="center" />
+          <el-table-column label="商品编号" align="center" prop="productNo" width="120" />
+          <el-table-column label="商品图片" align="center" prop="productImageUrl" width="100">
+            <template #default="scope">
+              <image-preview :src="scope.row.productImageUrl" :width="60" :height="60"/>
+            </template>
+          </el-table-column>
+          <el-table-column label="商品信息" align="center" min-width="200">
+            <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>
+            </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>
+            </template>
+          </el-table-column>
+          <el-table-column label="SKU价格" 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.midRangePrice || '0.00' }}</span>
+                </div>
+                <div>
+                  <span class="text-gray-500">平台价:</span>
+                  <span class="text-red-500">¥{{ scope.row.standardPrice || '0.00' }}</span>
+                </div>
+                <div>
+                  <span class="text-gray-500">最低价:</span>
+                  <span>¥{{ scope.row.certificatePrice || '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 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>
+            </template>
+          </el-table-column>
+          <el-table-column label="供应情况" align="center" width="150">
+            <template #default="scope">
+              <div class="text-left" style="font-size: 12px;">
+                <div>供应商数量:{{ scope.row.supplierCount || 0 }}</div>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column label="协议价" align="center" prop="agreementPrice" width="100" />
+          <el-table-column label="操作" align="center" width="100" fixed="right">
+            <template #default="scope">
+              <el-link type="primary" :underline="false" @click="handleAddSingleProduct(scope.row)">加入清单</el-link>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <!-- 游标分页控制 -->
+        <pagination
+          v-show="addProductDialog.productList.length > 0"
+          v-model:page="addProductQuery.pageNum"
+          v-model:limit="addProductQuery.pageSize"
+          v-model:way="addProductQuery.way"
+          :cursor-mode="true"
+          :has-more="addProductHasMore"
+          @pagination="getProductList"
+        />
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="PoolLink" lang="ts">
+import { useRouter, useRoute } from 'vue-router';
+import { categoryTree, listBase } from '@/api/product/base';
+import { BaseVO, BaseQuery } from '@/api/product/base/types';
+import { listPoolLink, batchAddProducts, BatchAddProductData, batchReview, reSubmit, editPrice, editStock, PoolLinkForm } from '@/api/product/poolLink';
+import { PoolLinkQuery, PoolLinkVO } from '@/api/product/poolLink/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const router = useRouter();
+const route = useRoute();
+
+const productList = ref<PoolLinkVO[]>([]);
+const selectedPoolLinks = ref<PoolLinkVO[]>([]); // 主列表选中的商品
+const loading = ref(false);
+const showSearch = ref(true);
+const total = ref(0);
+
+// 添加商品弹框游标分页相关
+const addProductHasMore = ref(true); // 是否还有更多数据
+// 页面历史记录,存储每页的第一个id和最后一个id,用于支持双向翻页
+const addProductPageHistory = ref<Array<{ firstId: any; lastId: any }>>([]);
+
+const queryFormRef = ref<ElFormInstance>();
+
+const queryParams = ref({
+  pageNum: 1,
+  pageSize: 10,
+  poolId: (route.params.id || route.query.poolId) as string | number,
+  productReviewStatus: route.query.productReviewStatus as string | undefined,
+  productNo: undefined,
+  itemName: undefined,
+  brandId: undefined,
+  productStatus: undefined,
+  categoryId: undefined,
+  supplier: undefined,
+  dateRange: undefined,
+});
+
+const categoryOptions = ref<any[]>([]);
+const categoryMap = ref<Map<string | number, any>>(new Map());
+
+// 添加商品对话框
+const addProductDialog = reactive({
+  visible: false,
+  loading: false,
+  productList: [] as BaseVO[],
+  total: 0,
+});
+
+// 添加商品查询参数
+const addProductQuery = ref({
+  pageNum: 1,
+  pageSize: 10,
+  productNo: undefined as string | undefined,
+  itemName: undefined as string | undefined,
+  lastSeenId: undefined as string | number | undefined, // 游标分页的lastSeenId
+  way: undefined as number | undefined // 翻页方向: 0=上一页, 1=下一页
+});
+
+// 选中的商品
+const selectedProducts = ref<BaseVO[]>([]);
+const addProductTableRef = ref<any>();
+
+/** 获取分类树 */
+const getCategoryTree = async () => {
+  try {
+    const res = await categoryTree();
+    categoryOptions.value = res.data || [];
+    // 构建分类映射
+    buildCategoryMap(categoryOptions.value);
+  } catch (error) {
+    console.error('获取分类树失败:', error);
+  }
+};
+
+/** 构建分类映射 */
+const buildCategoryMap = (categories: any[], parentPath = '') => {
+  categories.forEach(category => {
+    const fullPath = parentPath ? `${parentPath} > ${category.label}` : category.label;
+    categoryMap.value.set(category.id, { ...category, fullPath });
+    if (category.children && category.children.length > 0) {
+      buildCategoryMap(category.children, fullPath);
+    }
+  });
+};
+
+/** 获取分类完整路径 */
+const getCategoryFullPath = (categoryId: string | number): string => {
+  const category = categoryMap.value.get(categoryId);
+  return category?.fullPath || '';
+};
+
+/** 查询商品列表 */
+const getList = async () => {
+  loading.value = true;
+  try {
+    const query: PoolLinkQuery = {
+      pageNum: queryParams.value.pageNum,
+      pageSize: queryParams.value.pageSize,
+      poolId: queryParams.value.poolId,
+      productReviewStatus: queryParams.value.productReviewStatus,
+      productNo: queryParams.value.productNo,
+      itemName: queryParams.value.itemName,
+      brandId: queryParams.value.brandId,
+      categoryId: queryParams.value.categoryId,
+      productStatus: queryParams.value.productStatus,
+      supplier: queryParams.value.supplier
+    };
+
+    // 处理日期范围
+    if (queryParams.value.dateRange && queryParams.value.dateRange.length === 2) {
+      query.params = {
+        beginCreateTime: queryParams.value.dateRange[0],
+        endCreateTime: queryParams.value.dateRange[1]
+      };
+    }
+
+    const res = await listPoolLink(query);
+    productList.value = res.rows || [];
+    total.value = res.total || 0;
+  } catch (error) {
+    console.error('获取商品列表失败:', error);
+    productList.value = [];
+    total.value = 0;
+  } finally {
+    loading.value = false;
+  }
+}
+
+/** 返回 */
+const goBack = () => {
+  router.back();
+}
+
+/** 搜索 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 添加商品 */
+const handleAddProduct = () => {
+  addProductDialog.visible = true;
+  // 重置查询条件
+  addProductQuery.value = {
+    pageNum: 1,
+    pageSize: 10,
+    productNo: undefined,
+    itemName: undefined,
+    lastSeenId: undefined,
+    way: undefined,
+  };
+  addProductPageHistory.value = []; // 重置页面历史
+  selectedProducts.value = [];
+  getProductList();
+};
+
+/** 获取商品列表(游标分页) */
+const getProductList = async () => {
+  addProductDialog.loading = true;
+  try {
+    const currentPageNum = addProductQuery.value.pageNum;
+    const params: any = { ...addProductQuery.value };
+
+    // 第一页不需要游标参数
+    if (currentPageNum === 1) {
+      delete params.lastSeenId;
+      delete params.firstSeenId;
+      delete params.way;
+    } else {
+      // way参数:0=上一页,1=下一页
+      if (addProductQuery.value.way === 0) {
+        // 上一页:使用目标页的firstId
+        const nextPageHistory = addProductPageHistory.value[currentPageNum];
+        if (nextPageHistory) {
+          params.firstSeenId = nextPageHistory.firstId;
+          params.way = 0;
+        }
+      } else {
+        // 下一页:使用前一页的lastId作为lastSeenId
+        const prevPageHistory = addProductPageHistory.value[currentPageNum - 1];
+        if (prevPageHistory) {
+          params.lastSeenId = prevPageHistory.lastId;
+          params.way = 1;
+        }
+      }
+    }
+
+    const res = await listBase(params);
+    // 兼容两种返回结构
+    if (res.rows) {
+      addProductDialog.productList = res.rows;
+      addProductDialog.total = res.total || 0;
+    } else if (res.data) {
+      addProductDialog.productList = Array.isArray(res.data) ? res.data : [];
+      addProductDialog.total = addProductDialog.productList.length;
+    } else {
+      addProductDialog.productList = [];
+      addProductDialog.total = 0;
+    }
+
+    // 判断是否还有更多数据
+    addProductHasMore.value = addProductDialog.productList.length === addProductQuery.value.pageSize;
+
+    // 记录当前页的第一个id和最后一个id
+    if (addProductDialog.productList.length > 0) {
+      const firstItem = addProductDialog.productList[0];
+      const lastItem = addProductDialog.productList[addProductDialog.productList.length - 1];
+      // 如果长度小于currentPageNum则创建
+      if (addProductPageHistory.value.length <= currentPageNum) {
+        addProductPageHistory.value[currentPageNum] = {
+          firstId: firstItem.id,
+          lastId: lastItem.id
+        };
+      }
+    }
+  } catch (error) {
+    console.error('获取商品列表失败:', error);
+    addProductDialog.productList = [];
+    addProductDialog.total = 0;
+  } finally {
+    addProductDialog.loading = false;
+  }
+};
+
+/** 搜索商品 */
+const handleSearchProducts = () => {
+  addProductQuery.value.pageNum = 1;
+  addProductQuery.value.lastSeenId = undefined;
+  addProductQuery.value.way = undefined;
+  addProductPageHistory.value = []; // 重置页面历史
+  getProductList();
+};
+
+/** 选择变化 */
+const handleSelectionChange = (selection: BaseVO[]) => {
+  selectedProducts.value = selection;
+};
+
+/** 批量加入清单 */
+const handleBatchAdd = async () => {
+  if (selectedProducts.value.length === 0) {
+    proxy?.$modal.msgWarning('请先选择要添加的商品');
+    return;
+  }
+
+  try {
+    // 构造批量添加的数据
+    const batchData: BatchAddProductData = {
+      poolId: queryParams.value.poolId ,
+      products: selectedProducts.value.map(product => ({
+        productId: product.id ,
+        agreementPrice: product.standardPrice || product.midRangePrice // 使用平台价或市场价作为协议价
+      }))
+    };
+
+    await batchAddProducts(batchData);
+    proxy?.$modal.msgSuccess(`成功添加 ${selectedProducts.value.length} 个商品到商品池`);
+    addProductDialog.visible = false;
+    // 清空选中项
+    selectedProducts.value = [];
+    if (addProductTableRef.value) {
+      addProductTableRef.value.clearSelection();
+    }
+    await getList();
+  } catch (error) {
+    console.error('添加商品失败:', error);
+  }
+};
+
+/** 添加单个商品 */
+const handleAddSingleProduct = async (row: BaseVO) => {
+  try {
+    // 构造单个商品添加的数据
+    const batchData: BatchAddProductData = {
+      poolId: queryParams.value.poolId ,
+      products: [{
+        productId: row.id ,
+        agreementPrice: row.standardPrice || row.midRangePrice // 使用平台价或市场价作为协议价
+      }]
+    };
+
+    await batchAddProducts(batchData);
+    proxy?.$modal.msgSuccess('添加成功');
+    // 不关闭对话框,允许继续添加
+    await getList();
+  } catch (error) {
+    console.error('添加商品失败:', error);
+  }
+};
+
+/** 获取分类名称 */
+const getCategoryName = (row: BaseVO): string => {
+  // 优先使用完整路径
+  if (row.bottomCategoryId) {
+    return getCategoryFullPath(row.bottomCategoryId);
+  }
+  return '-';
+};
+
+/** 主列表选择变化 */
+const handlePoolLinkSelectionChange = (selection: PoolLinkVO[]) => {
+  selectedPoolLinks.value = selection;
+};
+
+/** 是否有可审核的项(待审核状态) */
+const hasReviewableItems = computed(() => {
+  return selectedPoolLinks.value.some(item => item.productReviewStatus === '1');
+});
+
+/** 是否有可提交审核的项(待提交或驳回状态) */
+const hasSubmittableItems = computed(() => {
+  return selectedPoolLinks.value.some(item => item.productReviewStatus === '0' || item.productReviewStatus === '3');
+});
+
+// ========== 批量审核相关 ==========
+const reviewDialog = reactive({
+  visible: false,
+  form: {
+    productReviewStatus: '2' as string,
+    reviewReason: '' as string
+  }
+});
+const reviewFormRef = ref<ElFormInstance>();
+const reviewRules = reactive({
+  productReviewStatus: [{ required: true, message: '请选择审核结果', trigger: 'change' }],
+  reviewReason: [{ required: true, message: '请输入驳回原因', trigger: 'blur' }]
+});
+
+/** 批量审核 */
+const handleBatchReview = () => {
+  const reviewableItems = selectedPoolLinks.value.filter(item => item.productReviewStatus === '1');
+  if (reviewableItems.length === 0) {
+    proxy?.$modal.msgWarning('请选择待审核的商品');
+    return;
+  }
+  reviewDialog.form = { productReviewStatus: '2', reviewReason: '' };
+  reviewDialog.visible = true;
+};
+
+/** 提交审核表单 */
+const submitReviewForm = async () => {
+  await reviewFormRef.value?.validate();
+  const reviewableItems = selectedPoolLinks.value.filter(item => item.productReviewStatus === '1');
+  const data: PoolLinkForm[] = reviewableItems.map(item => ({
+    id: item.id,
+    productReviewStatus: reviewDialog.form.productReviewStatus,
+    reviewReason: reviewDialog.form.productReviewStatus === '3' ? reviewDialog.form.reviewReason : undefined
+  }));
+  await batchReview(data);
+  proxy?.$modal.msgSuccess('审核成功');
+  reviewDialog.visible = false;
+  await getList();
+};
+
+/** 提交审核(待提交和驳回的商品) */
+const handleSubmitReview = async () => {
+  const submittableItems = selectedPoolLinks.value.filter(item => item.productReviewStatus === '0' || item.productReviewStatus === '3');
+  if (submittableItems.length === 0) {
+    proxy?.$modal.msgWarning('请选择待提交或已驳回的商品');
+    return;
+  }
+  await proxy?.$modal.confirm(`确认提交 ${submittableItems.length} 个商品进行审核吗?`);
+  const data: PoolLinkForm[] = submittableItems.map(item => ({ id: item.id, productReviewStatus: '1' }));
+  await reSubmit(data);
+  proxy?.$modal.msgSuccess('提交成功');
+  await getList();
+};
+
+/** 批量移出 */
+const handleBatchRemove = async () => {
+  if (selectedPoolLinks.value.length === 0) {
+    proxy?.$modal.msgWarning('请先选择要移出的商品');
+    return;
+  }
+  await proxy?.$modal.confirm(`确认要移出选中的 ${selectedPoolLinks.value.length} 个商品吗?`);
+  const ids = selectedPoolLinks.value.map(item => item.id);
+  // 调用删除接口
+  const { delPoolLink } = await import('@/api/product/poolLink');
+  await delPoolLink(ids);
+  proxy?.$modal.msgSuccess('移出成功');
+  await getList();
+};
+
+// ========== 价格维护相关 ==========
+const priceDialog = reactive({
+  visible: false,
+  row: null as PoolLinkVO | null,
+  form: {
+    marketPrice: 0,
+    platformPrice: 0,
+    minPrice: 0,
+    productPrice: 0
+  }
+});
+const priceFormRef = ref<ElFormInstance>();
+const priceRules = reactive({
+  productPrice: [{ required: true, message: '请输入产品价格', trigger: 'blur' }]
+});
+
+/** 价格维护 */
+const handlePriceMaintain = (row: PoolLinkVO) => {
+  priceDialog.row = row;
+  priceDialog.form = {
+    marketPrice: row.marketPrice || 0,
+    platformPrice: row.platformPrice || 0,
+    minPrice: row.minPrice || 0,
+    productPrice: row.productPrice || 0
+  };
+  priceDialog.visible = true;
+};
+
+/** 提交价格表单 */
+const submitPriceForm = async () => {
+  await priceFormRef.value?.validate();
+  const data: PoolLinkForm = {
+    id: priceDialog.row?.id,
+    productPrice: priceDialog.form.productPrice
+  };
+  await editPrice(data);
+  proxy?.$modal.msgSuccess('价格修改成功');
+  priceDialog.visible = false;
+  await getList();
+};
+
+// ========== 库存维护相关 ==========
+const stockDialog = reactive({
+  visible: false,
+  row: null as PoolLinkVO | null,
+  form: {
+    stock: 0
+  }
+});
+const stockFormRef = ref<ElFormInstance>();
+const stockRules = reactive({
+  stock: [{ required: true, message: '请输入库存数量', trigger: 'blur' }]
+});
+
+/** 修改库存 */
+const handleStockMaintain = (row: PoolLinkVO) => {
+  stockDialog.row = row;
+  stockDialog.form = {
+    stock: row.stock || 0
+  };
+  stockDialog.visible = true;
+};
+
+/** 提交库存表单 */
+const submitStockForm = async () => {
+  await stockFormRef.value?.validate();
+  const data: PoolLinkForm = {
+    id: stockDialog.row?.id,
+    stock: stockDialog.form.stock
+  };
+  await editStock(data);
+  proxy?.$modal.msgSuccess('库存修改成功');
+  stockDialog.visible = false;
+  await getList();
+};
+
+onMounted(() => {
+  getCategoryTree();
+  getList();
+});
+</script>
+
+<style scoped lang="scss">
+.add-product-dialog {
+  :deep(.el-form--inline .el-form-item) {
+    margin-right: 10px;
+  }
+}
+</style>