Просмотр исходного кода

feat(product): 重构商品管理功能并优化供应商信息处理

- 添加商品审核、自定义属性、产品池审核等相关API接口
- 新增CategoryCascadeSelect组件实现商品分类级联选择功能
- 重构商品基础页面的商品品牌搜索和分类筛选功能
- 优化供应商信息详情页的数据保存逻辑和临时信息处理
- 添加多个产品相关模块的API接口包括分类审核、产品池关联审核等功能
- 新增通用工具函数包括URL判断、图片处理和深度克隆功能
- 调整客户信息页面的字段验证和数据绑定逻辑
- 优化商品列表的搜索条件和数据显示统计功能
肖路 2 дней назад
Родитель
Сommit
54ecd2eac4
38 измененных файлов с 3489 добавлено и 284 удалено
  1. 1 0
      package.json
  2. 7 2
      src/api/product/attributes/types.ts
  3. 32 0
      src/api/product/base/index.ts
  4. 45 49
      src/api/product/base/types.ts
  5. 87 0
      src/api/product/baseAudit/index.ts
  6. 173 0
      src/api/product/baseAudit/types.ts
  7. 10 11
      src/api/product/category/index.ts
  8. 63 0
      src/api/product/classificationDiy/index.ts
  9. 86 0
      src/api/product/classificationDiy/types.ts
  10. 0 61
      src/api/product/contracproduct/types.ts
  11. 3 3
      src/api/product/pool/types.ts
  12. 145 0
      src/api/product/poolAudit/index.ts
  13. 555 0
      src/api/product/poolAudit/types.ts
  14. 11 0
      src/api/product/poolLink/index.ts
  15. 19 4
      src/api/product/poolLink/types.ts
  16. 83 0
      src/api/product/poolLinkAudit/index.ts
  17. 205 0
      src/api/product/poolLinkAudit/types.ts
  18. 75 0
      src/api/product/pptScheme/index.ts
  19. 406 0
      src/api/product/pptScheme/types.ts
  20. 63 0
      src/api/product/pptTemplate/index.ts
  21. 251 0
      src/api/product/pptTemplate/types.ts
  22. 3 3
      src/api/product/priceInventory/types.ts
  23. 63 0
      src/api/product/productExquisite/index.ts
  24. 71 0
      src/api/product/productExquisite/types.ts
  25. 63 0
      src/api/product/productSelf/index.ts
  26. 71 0
      src/api/product/productSelf/types.ts
  27. 13 1
      src/api/product/products/index.ts
  28. 8 0
      src/api/product/products/types.ts
  29. 183 0
      src/components/CategoryCascadeSelect/index.vue
  30. 51 0
      src/utils/common.ts
  31. 54 0
      src/utils/mockData.js
  32. 246 0
      src/utils/pptPlugin.js
  33. 19 0
      src/views/customer/info/components/BasicInfoTab.vue
  34. 6 4
      src/views/customer/info/detail.vue
  35. 2 2
      src/views/customer/info/index.vue
  36. 2 6
      src/views/product/base/add.vue
  37. 298 128
      src/views/product/base/index.vue
  38. 16 10
      src/views/supplier/approve/index.vue

+ 1 - 0
package.json

@@ -38,6 +38,7 @@
     "jsencrypt": "3.3.2",
     "nprogress": "0.2.0",
     "pinia": "3.0.2",
+    "pptxgenjs": "^4.0.1",
     "screenfull": "6.0.2",
     "vue": "3.5.13",
     "vue-cropper": "1.1.1",

+ 7 - 2
src/api/product/attributes/types.ts

@@ -67,6 +67,11 @@ export interface AttributesForm extends BaseEntity {
    */
   categoryId?: string | number;
 
+  /**
+   * 产品分类名称
+   */
+  categoryName?: string;
+
   /**
    * 属性编码(用于系统识别)
    */
@@ -83,7 +88,7 @@ export interface AttributesForm extends BaseEntity {
   isOptional?: string | number;
 
   /**
-   * 属性录入方式(manual=手工录入,select=从列表中选择)
+   * 属性录入方式(1=手工录入,2=从列表中选择)
    */
   entryMethod?: string;
 
@@ -100,7 +105,7 @@ export interface AttributesForm extends BaseEntity {
   /**
    * 是否必填: 1=是, 0=否
    */
-  required?: string;
+  required?: string | number;
 
   /**
    * 备注

+ 32 - 0
src/api/product/base/index.ts

@@ -209,3 +209,35 @@ export const getTaxRateList = () => {
   });
 };
 
+/**
+ * 获取自营商品列表
+ * */
+export const getSelfProductPage = (query?: BaseQuery): AxiosPromise<BaseVO[]> => {
+  return request({
+    url: '/product/base/getSelfProductPage',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 获取精品商品列表
+ * */
+export const getGoodProductPage = (query?: BaseQuery): AxiosPromise<BaseVO[]> => {
+  return request({
+    url: '/product/base/getGoodProductPage',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 获取项目商品列表
+ * */
+export const getProjectProductPage = (query?: BaseQuery): AxiosPromise<BaseVO[]> => {
+  return request({
+    url: '/product/base/getItemProductPage',
+    method: 'get',
+    params: query
+  });
+};

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

@@ -96,7 +96,7 @@ export interface BaseVO {
   /**
    * 商品状态:1=已上架,0=下架,2=上架中
    */
-  productStatus: string;
+  productStatus: number;
 
   /**
    * 数据来源
@@ -109,7 +109,7 @@ export interface BaseVO {
   marketPrice: number;
 
   /**
-   * 会员价格
+   * 官网价
    */
   memberPrice: number;
 
@@ -153,35 +153,15 @@ export interface BaseVO {
    */
   freeInstallation?: string;
 
-  /**
-   * 市场价
-   */
-  midRangePrice?: number;
-
-  /**
-   * 平档价
-   */
-  standardPrice?: number;
-
-  /**
-   * 最低售价
-   */
-  certificatePrice?: number;
-
   /**
    * 售价验证量
    */
   priceVerificationQuantity?: string;
 
   /**
-   * 采购价
+   *最高采购价
    */
-  purchasePrice?: number;
-
-  /**
-   * 暂估采购价
-   */
-  estimatedPurchasePrice?: number;
+  maxPurchasePrice?: number;
 
   /**
    * 产品性质
@@ -248,6 +228,15 @@ export interface BaseVO {
    */
   imageUrl?: string;
 
+  /**
+   * 审核状态 1=待审核,2=审核通过,3=审核驳回
+   */
+  auditStatus?: number;
+
+  /**
+   * 审核意见
+   */
+  auditReason?: string;
 }
 
 export interface BaseForm extends BaseEntity {
@@ -344,7 +333,7 @@ export interface BaseForm extends BaseEntity {
   /**
    * 商品状态:1=已上架,0=下架,2=上架中
    */
-  productStatus?: string;
+  productStatus?: string | number;
 
   /**
    * 数据来源
@@ -369,12 +358,12 @@ export interface BaseForm extends BaseEntity {
   /**
    * 规格型号
    */
-  specification?: string;
+  specificationsCode?: string;
 
   /**
    * UPC(S)条码
    */
-  upcBarcode?: string;
+  barCoding?: string;
 
   /**
    * 发票名称
@@ -384,7 +373,7 @@ export interface BaseForm extends BaseEntity {
   /**
    * 发票规格
    */
-  invoiceSpec?: string;
+  invoiceSpecs?: string;
 
   /**
    * 产品品牌
@@ -396,6 +385,11 @@ export interface BaseForm extends BaseEntity {
    */
   sectionNo?: string;
 
+  /**
+   * 促销标题
+   */
+  promotionTitle?: string;
+
   /**
    * 包装规格
    */
@@ -416,10 +410,14 @@ export interface BaseForm extends BaseEntity {
    */
   referenceLink?: string;
 
+  /**
+   * 商品描述
+   * */
+  productDescription?: string;
   /**
    * 商品重量
    */
-  weight?: string;
+  productWeight?: string;
 
   /**
    * 重量单位
@@ -429,7 +427,7 @@ export interface BaseForm extends BaseEntity {
   /**
    * 商品体积
    */
-  volume?: string;
+  productVolume?: string;
 
   /**
    * 体积单位
@@ -444,7 +442,7 @@ export interface BaseForm extends BaseEntity {
   /**
    * 售后服务
    */
-  afterSalesService?: string;
+  afterSalesService?: string | number;
 
   /**
    * 服务保障 支持多选,分隔 (存储服务保障ID列表,如: "1,2,3")
@@ -459,17 +457,17 @@ export interface BaseForm extends BaseEntity {
   /**
    * 市场价
    */
-  midRangePrice?: number;
+  marketPrice?: number;
 
   /**
    * 平档价
    */
-  standardPrice?: number;
+  memberPrice?: number;
 
   /**
    * 最低售价
    */
-  certificatePrice?: number;
+  minSellingPrice?: number;
 
   /**
    * 售价验证量
@@ -479,12 +477,12 @@ export interface BaseForm extends BaseEntity {
   /**
    * 采购价
    */
-  purchasePrice?: number;
+  purchasingPrice?: number;
 
   /**
-   * 暂估采购价
+   *最高采购价
    */
-  estimatedPurchasePrice?: number;
+  maxPurchasePrice?: number;
 
   /**
    * 产品性质
@@ -537,9 +535,9 @@ export interface BaseForm extends BaseEntity {
   minOrderQuantity?: number;
 
   /**
-   * 是否可定制
+   * 是否可定制:1=是,0=否
    */
-  customizable?: boolean;
+  isCustomize?: number | string;
 
   /**
    * 定制方式(逗号分隔)
@@ -585,11 +583,9 @@ export interface BaseForm extends BaseEntity {
    * 商品轮播图URL(逗号分隔)
    */
   imageUrl?: string;
-
 }
 
 export interface BaseQuery extends PageQuery {
-
   /**
    * 搜索文本(商品名称/商品编号)
    */
@@ -720,12 +716,15 @@ export interface BaseQuery extends PageQuery {
    */
   projectOrg?: string;
 
+  /**
+   * 日期范围参数
+   */
+  params?: any;
 
-
-    /**
-     * 日期范围参数
-     */
-    params?: any;
+  /**
+   * 商品ID列表(按指定ID集合查询)
+   */
+  ids?: Array<string | number>;
 }
 /**
  * 状态数量统计视图对象
@@ -761,6 +760,3 @@ export class StatusCountVo {
    */
   auditReject: number | null = null;
 }
-
-
-

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

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

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

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

+ 10 - 11
src/api/product/category/index.ts

@@ -65,22 +65,24 @@ export const delCategory = (id: string | number | Array<string | number>) => {
 /**
  * 查询产品分类列表(排除节点)
  * @param id
- */
+  */
 export const listCategoryExcludeChild = (id: string | number): AxiosPromise<CategoryVO[]> => {
   return request({
-    url: '/product/category/list/exclude/' + id,
+    url: '/product/category/tree/exclude/' + id,
     method: 'get'
   });
 };
 
-export const setCategoryReviewer = (categoryId: string | number, reviewerUserId: string | number) => {
+/**
+ * 设置分类审核员
+ * @param id 分类ID
+ * @param reviewerId 审核员用户ID
+ */
+export const setCategoryReviewer = (id: string | number, reviewerId: string | number) => {
   return request({
     url: '/product/category/setReviewer',
-    method: 'post',
-    data: {
-      categoryId,
-      reviewerUserId
-    }
+    method: 'put',
+    data: { id, reviewerId }
   });
 };
 
@@ -93,6 +95,3 @@ export const getProductCategoryList = () => {
     method: 'get'
   });
 };
-
-
-

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

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

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

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

+ 0 - 61
src/api/product/contracproduct/types.ts

@@ -9,11 +9,6 @@ export interface ContracproductVO {
    */
   contractSupplyNo: string;
 
-  /**
-   * 合同供货Id
-   */
-  contractSupplyId?: string | number;
-
   /**
    * 产品编号
    */
@@ -49,34 +44,6 @@ export interface ContracproductVO {
    */
   status: string;
 
-  productName?: string;
-  productImage?: string;
-  unitName?: string;
-  minOrderQuantity?: number;
-  bottomCategoryName?: string;
-  marketPrice?: number;
-  memberPrice?: number;
-  minSellingPrice?: number;
-  totalInventory?: number;
-  nowInventory?: number;
-  virtualInventory?: number;
-  brandId?: string | number;
-  brandName?: string;
-  enterpriseName?: string;
-  provinceName?: string;
-  cityName?: string;
-
-  province?: string;
-  city?: string;
-
-  remark?: string;
-
-  offerEndTime?: string;
-  grossMarginRate?: number;
-
-  endTime?: string;
-  grossProfitRate?: number;
-
 }
 
 export interface ContracproductForm extends BaseEntity {
@@ -90,11 +57,6 @@ export interface ContracproductForm extends BaseEntity {
    */
   contractSupplyNo?: string;
 
-  /**
-   * 合同供货Id
-   */
-  contractSupplyId?: string | number;
-
   /**
    * 产品编号
    */
@@ -130,15 +92,6 @@ export interface ContracproductForm extends BaseEntity {
    */
   status?: string;
 
-  remark?: string;
-
-  productName?: string;
-  enterpriseName?: string;
-  provinceName?: string;
-  cityName?: string;
-  province?: string;
-  city?: string;
-
 }
 
 export interface ContracproductQuery extends PageQuery {
@@ -148,11 +101,6 @@ export interface ContracproductQuery extends PageQuery {
    */
   contractSupplyNo?: string;
 
-  /**
-   * 合同供货Id
-   */
-  contractSupplyId?: string | number;
-
   /**
    * 产品编号
    */
@@ -188,15 +136,6 @@ export interface ContracproductQuery extends PageQuery {
    */
   status?: string;
 
-  productName?: string;
-  enterpriseName?: string;
-  provinceName?: string;
-  cityName?: string;
-  province?: string;
-  city?: string;
-
-  remark?: string;
-
     /**
      * 日期范围参数
      */

+ 3 - 3
src/api/product/pool/types.ts

@@ -20,7 +20,7 @@ export interface PoolVO {
   categoryId: string | number;
 
   /**
-   * 产品池类型 0普通产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
+   * 产品池类型 0自营产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
    */
   type: number;
 
@@ -113,7 +113,7 @@ export interface PoolForm extends BaseEntity {
   categoryId: string | number;
 
   /**
-   * 产品池类型 0普通产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
+   * 产品池类型 0自营产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
    */
   type: number;
 
@@ -162,7 +162,7 @@ export interface PoolQuery extends PageQuery {
   categoryId: string | number;
 
   /**
-   * 产品池类型 0普通产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
+   * 产品池类型 0自营产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
    */
   type: number;
 

+ 145 - 0
src/api/product/poolAudit/index.ts

@@ -0,0 +1,145 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { PoolAuditVO, PoolAuditForm, PoolAuditQuery, ProductListVO } from '@/api/product/poolAudit/types';
+import { BaseVO, BaseQuery } from '@/api/product/base/types';
+
+/**
+ * 查询产品池审核列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listPoolAudit = (query?: PoolAuditQuery): AxiosPromise<PoolAuditVO[]> => {
+  return request({
+    url: '/product/poolAudit/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品池审核详细
+ * @param id
+ */
+export const getPoolAudit = (id: string | number): AxiosPromise<PoolAuditVO> => {
+  return request({
+    url: '/product/poolAudit/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品池审核
+ * @param data
+ */
+export const addPoolAudit = (data: PoolAuditForm) => {
+  return request({
+    url: '/product/poolAudit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品池审核
+ * @param data
+ */
+export const updatePoolAudit = (data: PoolAuditForm) => {
+  return request({
+    url: '/product/poolAudit',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品池审核
+ * @param id
+ */
+export const delPoolAudit = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/poolAudit/' + id,
+    method: 'delete'
+  });
+};
+
+/**
+ * 获取审核池里的商品列表
+ * @param query
+ * @returns {*}
+ * */
+export const getPoolAuditProductPage = (query?: BaseQuery & PageQuery): AxiosPromise<BaseVO[]> => {
+  return request({
+    url: '/product/poolAudit/getPoolAuditProductPage',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 获取审核池里的商品列表
+ * @param query
+ * @returns {*}
+ * */
+export const selectPoolAuditProductPage = (query?: (BaseQuery & PageQuery) & { type?: number }): AxiosPromise<ProductListVO[]> => {
+  return request({
+    url: '/product/poolAudit/selectPoolAuditProductPage',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 批量审核产品池商品
+ * @param data
+ */
+export interface PoolAuditBatchData {
+  poolAuditId: string | number;
+  productIds: Array<string | number>;
+  auditStatus: string | number;
+  reason?: string;
+}
+
+export const batchAudit = (data: PoolAuditBatchData) => {
+  return request({
+    url: '/product/poolAudit/batchAudit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 申请入池单(待提交 -> 待审核)
+ * @param id
+ */
+export const applyPoolAudit = (id: string | number) => {
+  return request({
+    url: '/product/poolAudit/apply/' + id,
+    method: 'put'
+  });
+};
+
+/**
+ * 清空审核池
+ * @param id
+ */
+export const clearPool = (id: string | number) => {
+  return request({
+    url: '/product/poolAudit/clearPool/' + id,
+    method: 'delete'
+  });
+};
+
+/**
+ * 单条商品审核池
+ * @param id
+ */
+export const audit = (data: PoolAuditBatchData) => {
+  return request({
+    url: '/product/poolAudit/audit',
+    method: 'post',
+    data: data
+  });
+};
+
+

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

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

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

@@ -130,3 +130,14 @@ export const editStock = (data: PoolLinkForm) => {
     data: data
   });
 };
+
+/**
+ * 清空产品池
+ * @param poolId 产品池ID
+ */
+export const clearPool = (poolId: string | number) => {
+  return request({
+    url: '/product/poolLink/clear/' + poolId,
+    method: 'delete'
+  });
+};

+ 19 - 4
src/api/product/poolLink/types.ts

@@ -15,7 +15,7 @@ export interface PoolLinkVO {
   poolName?: string;
 
   /**
-   * 产品池类型 0普通产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
+   * 产品池类型 0自营产品池,1精选产品池,2协议产品池,3项目产品池,4分类产品池
    */
   type?: number;
 
@@ -100,7 +100,7 @@ export interface PoolLinkVO {
   marketPrice?: number;
 
   /**
-   * 平台售
+   * 官网
    */
   platformPrice?: number;
 
@@ -128,6 +128,16 @@ export interface PoolLinkVO {
    * 供应商
    */
   supplier?: string;
+
+  /**
+   * 协议价格
+   */
+  negotiatedPrice?: number;
+
+  /**
+   * 审核池商品关联ID(用于移除)
+   */
+  poolAuditProductId?: string | number;
 }
 
 export interface PoolLinkForm extends BaseEntity {
@@ -243,9 +253,14 @@ export interface PoolLinkQuery extends PageQuery {
   brandId?: string | number;
 
   /**
-   * 分类ID
+   * 品牌名称
+   */
+  brandName?: string;
+
+  /**
+   * 底部分类ID
    */
-  categoryId?: string | number;
+  bottomCategoryId?: string | number;
 
   /**
    * 商品状态:1=已上架,0=下架,2=上架中

+ 83 - 0
src/api/product/poolLinkAudit/index.ts

@@ -0,0 +1,83 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { PoolLinkAuditVO, PoolLinkAuditForm, PoolLinkAuditQuery } from '@/api/product/poolLinkAudit/types';
+
+/**
+ * 查询产品池和产品关联审核列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listPoolLinkAudit = (query?: PoolLinkAuditQuery): AxiosPromise<PoolLinkAuditVO[]> => {
+  return request({
+    url: '/product/poolLinkAudit/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品池和产品关联审核详细
+ * @param id
+ */
+export const getPoolLinkAudit = (id: string | number): AxiosPromise<PoolLinkAuditVO> => {
+  return request({
+    url: '/product/poolLinkAudit/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品池和产品关联审核
+ * @param data
+ */
+export const addPoolLinkAudit = (data: PoolLinkAuditForm) => {
+  return request({
+    url: '/product/poolLinkAudit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品池和产品关联审核
+ * @param data
+ */
+export const updatePoolLinkAudit = (data: PoolLinkAuditForm) => {
+  return request({
+    url: '/product/poolLinkAudit',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品池和产品关联审核
+ * @param id
+ */
+export const delPoolLinkAudit = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/poolLinkAudit/' + id,
+    method: 'delete'
+  });
+};
+
+/**
+ * 批量添加商品到商品池
+ * @param data 批量添加参数
+ */
+export interface BatchAddProductData {
+  poolId: string | number;
+  products: Array<{
+    productId: string | number;
+    agreementPrice?: number;
+  }>;
+}
+
+export const batchAddProducts = (data: BatchAddProductData) => {
+  return request({
+    url: '/product/poolLinkAudit/batchAdd',
+    method: 'post',
+    data: data
+  });
+};

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

@@ -0,0 +1,205 @@
+export interface PoolLinkAuditVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 所属池ID
+   */
+  poolId: string | number;
+
+  /**
+   * 审核池id
+   */
+  poolAuditId: string | number;
+
+  /**
+   * 产品id
+   */
+  productId: string | number;
+
+  /**
+   * 产品价格
+   */
+  productPrice: number;
+
+  /**
+   * 协议价格
+   */
+  negotiatedPrice: number;
+
+  /**
+   * 分类id
+   */
+  categoryId: string | number;
+
+  /**
+   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  productReviewStatus: string;
+
+  /**
+   * 审核原因
+   */
+  reviewReason: string;
+
+  /**
+   * 审核人
+   */
+  reviewer: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+  /**
+   * 计价规则(0 一品一价,1 按类目折扣率报价)
+   */
+  pricingRule: string;
+
+  /**
+   * 起订量
+   */
+  minOrderQuantity: number;
+}
+
+export interface PoolLinkAuditForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 所属池ID
+   */
+  poolId?: string | number;
+
+  /**
+   * 审核池id
+   */
+  poolAuditId?: string | number;
+
+  /**
+   * 产品id
+   */
+  productId?: string | number;
+
+  /**
+   * 产品价格
+   */
+  productPrice?: number;
+
+  /**
+   * 协议价格
+   */
+  negotiatedPrice?: number;
+
+  /**
+   * 分类id
+   */
+  categoryId?: string | number;
+
+  /**
+   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  productReviewStatus?: string;
+
+  /**
+   * 审核原因
+   */
+  reviewReason?: string;
+
+  /**
+   * 审核人
+   */
+  reviewer?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+  /**
+   * 计价规则(0 一品一价,1 按类目折扣率报价)
+   */
+  pricingRule: string;
+
+  /**
+   * 起订量
+   */
+  minOrderQuantity: number;
+
+}
+
+export interface PoolLinkAuditQuery extends PageQuery {
+
+  /**
+   * 所属池ID
+   */
+  poolId?: string | number;
+
+  /**
+   * 审核池id
+   */
+  poolAuditId?: string | number;
+
+  /**
+   * 产品id
+   */
+  productId?: string | number;
+
+  /**
+   * 产品价格
+   */
+  productPrice?: number;
+
+  /**
+   * 协议价格
+   */
+  negotiatedPrice?: number;
+
+  /**
+   * 分类id
+   */
+  categoryId?: string | number;
+
+  /**
+   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  productReviewStatus?: string;
+
+  /**
+   * 审核原因
+   */
+  reviewReason?: string;
+
+  /**
+   * 审核人
+   */
+  reviewer?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+
+  /**
+   * 计价规则(0 一品一价,1 按类目折扣率报价)
+   */
+  pricingRule: string;
+
+  /**
+   * 起订量
+   */
+  minOrderQuantity: number;
+}
+
+
+

+ 75 - 0
src/api/product/pptScheme/index.ts

@@ -0,0 +1,75 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { PptSchemeVO, PptSchemeForm, PptSchemeQuery } from '@/api/product/pptScheme/types';
+
+/**
+ * 查询PPT 方案主列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listPptScheme = (query?: PptSchemeQuery): AxiosPromise<PptSchemeVO[]> => {
+  return request({
+    url: '/product/pptScheme/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询PPT 方案主详细
+ * @param id
+ */
+export const getPptScheme = (id: string | number): AxiosPromise<PptSchemeVO> => {
+  return request({
+    url: '/product/pptScheme/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增PPT 方案主
+ * @param data
+ */
+export const addPptScheme = (data: PptSchemeForm) => {
+  return request({
+    url: '/product/pptScheme',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改PPT 方案主
+ * @param data
+ */
+export const updatePptScheme = (data: PptSchemeForm) => {
+  return request({
+    url: '/product/pptScheme',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除PPT 方案主
+ * @param id
+ */
+export const delPptScheme = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/pptScheme/' + id,
+    method: 'delete'
+  });
+};
+
+/**
+ * 分享方案
+ * @param query
+ */
+export const sharePptScheme = (id: string | number, userIds: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/pptScheme/share',
+    method: 'post',
+    data: { id, userIds }
+  });
+};

+ 406 - 0
src/api/product/pptScheme/types.ts

@@ -0,0 +1,406 @@
+export interface PptSchemeVO {
+  /**
+   * 方案主键
+   */
+  id: string | number;
+
+  /**
+   * 方案名称(用户自定义)
+   */
+  name: string;
+
+  /**
+   * 选用的原始模板 ID(ppt_template.id),仅用于溯源
+   */
+  templateId: string | number;
+
+  /**
+   * (快照)模板名称
+   */
+  tplName: string;
+
+  /**
+   * (快照)封面底图
+   */
+  tplCover: string;
+
+  /**
+   * (快照)封面 Logo
+   */
+  tplCoverLogo: string;
+
+  /**
+   * (快照)内容页 Logo
+   */
+  tplContentLogo: string;
+
+  /**
+   * (快照)主题色
+   */
+  tplThemeColor: string;
+
+  /**
+   * (快照)商品排版模式
+   */
+  tplItemsPerPage: number;
+
+  /**
+   * (快照)封面主标题
+   */
+  tplCoverTitle: string;
+
+  /**
+   * (快照)封面副标题
+   */
+  tplCoverSubTitle: string;
+
+  /**
+   * (快照)方案截止日期,如:方案有效期:2026年12月31日
+   */
+  tplValidity: string | number;
+
+  /**
+   * (快照)品牌名称
+   */
+  tplBrandName: string;
+
+  /**
+   * (快照)品牌口号
+   */
+  tplBrandSlogan: string;
+
+  /**
+   * (快照)官网
+   */
+  tplWebsite: string;
+
+  /**
+   * (快照)电话
+   */
+  tplPhone: string;
+
+  /**
+   * (快照)内容页标题
+   */
+  tplContentTitle: string;
+
+  /**
+   * 方案归属者 user_id(可以是分享接收者)
+   */
+  ownerId: string | number;
+
+  /**
+   * 是否公开:0私有 1公开(支撑"其他人创建"Tab)
+   */
+  isPublic: string;
+
+  /**
+   * 是否由他人分享而来:0否 1是(支撑"分享给我的"Tab)
+   */
+  isShared: string;
+
+  /**
+   * 来源方案 ID(从哪个原始方案分享过来的)
+   */
+  sourceSchemeId: string | number;
+
+  /**
+   * 分享人 user_id
+   */
+  sharerId: string | number;
+
+  /**
+   * 分享人姓名
+   */
+  sharerName: string;
+
+  /**
+   * 分享时间
+   */
+  shareTime: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface PptSchemeForm extends BaseEntity {
+  /**
+   * 方案主键
+   */
+  id?: string | number;
+
+  /**
+   * 方案名称(用户自定义)
+   */
+  name?: string;
+
+  /**
+   * 选用的原始模板 ID(ppt_template.id),仅用于溯源
+   */
+  templateId?: string | number;
+
+  /**
+   * (快照)模板名称
+   */
+  tplName?: string;
+
+  /**
+   * (快照)封面底图
+   */
+  tplCover?: string;
+
+  /**
+   * (快照)封面 Logo
+   */
+  tplCoverLogo?: string;
+
+  /**
+   * (快照)内容页 Logo
+   */
+  tplContentLogo?: string;
+
+  /**
+   * (快照)主题色
+   */
+  tplThemeColor?: string;
+
+  /**
+   * (快照)商品排版模式
+   */
+  tplItemsPerPage?: number;
+
+  /**
+   * (快照)封面主标题
+   */
+  tplCoverTitle?: string;
+
+  /**
+   * (快照)封面副标题
+   */
+  tplCoverSubTitle?: string;
+
+  /**
+   * (快照)方案截止日期,如:方案有效期:2026年12月31日
+   */
+  tplValidity?: string | number;
+
+  /**
+   * (快照)品牌名称
+   */
+  tplBrandName?: string;
+
+  /**
+   * (快照)品牌口号
+   */
+  tplBrandSlogan?: string;
+
+  /**
+   * (快照)官网
+   */
+  tplWebsite?: string;
+
+  /**
+   * (快照)电话
+   */
+  tplPhone?: string;
+
+  /**
+   * (快照)内容页标题
+   */
+  tplContentTitle?: string;
+
+  /**
+   * 方案归属者 user_id(可以是分享接收者)
+   */
+  ownerId?: string | number;
+
+  /**
+   * 是否公开:0私有 1公开(支撑"其他人创建"Tab)
+   */
+  isPublic?: string;
+
+  /**
+   * 是否由他人分享而来:0否 1是(支撑"分享给我的"Tab)
+   */
+  isShared?: string;
+
+  /**
+   * 来源方案 ID(从哪个原始方案分享过来的)
+   */
+  sourceSchemeId?: string | number;
+
+  /**
+   * 分享人 user_id
+   */
+  sharerId?: string | number;
+
+  /**
+   * 分享人姓名
+   */
+  sharerName?: string;
+
+  /**
+   * 分享时间
+   */
+  shareTime?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface PptSchemeQuery extends PageQuery {
+
+  /**
+   * 方案名称(用户自定义)
+   */
+  name?: string;
+
+  /**
+   * 选用的原始模板 ID(ppt_template.id),仅用于溯源
+   */
+  templateId?: string | number;
+
+  /**
+   * (快照)模板名称
+   */
+  tplName?: string;
+
+  /**
+   * (快照)封面底图
+   */
+  tplCover?: string;
+
+  /**
+   * (快照)封面 Logo
+   */
+  tplCoverLogo?: string;
+
+  /**
+   * (快照)内容页 Logo
+   */
+  tplContentLogo?: string;
+
+  /**
+   * (快照)主题色
+   */
+  tplThemeColor?: string;
+
+  /**
+   * (快照)商品排版模式
+   */
+  tplItemsPerPage?: number;
+
+  /**
+   * (快照)封面主标题
+   */
+  tplCoverTitle?: string;
+
+  /**
+   * (快照)封面副标题
+   */
+  tplCoverSubTitle?: string;
+
+  /**
+   * (快照)方案截止日期,如:方案有效期:2026年12月31日
+   */
+  tplValidity?: string | number;
+
+  /**
+   * (快照)品牌名称
+   */
+  tplBrandName?: string;
+
+  /**
+   * (快照)品牌口号
+   */
+  tplBrandSlogan?: string;
+
+  /**
+   * (快照)官网
+   */
+  tplWebsite?: string;
+
+  /**
+   * (快照)电话
+   */
+  tplPhone?: string;
+
+  /**
+   * (快照)内容页标题
+   */
+  tplContentTitle?: string;
+
+  /**
+   * 方案归属者 user_id(可以是分享接收者)
+   */
+  ownerId?: string | number;
+
+  /**
+   * 是否公开:0私有 1公开(支撑"其他人创建"Tab)
+   */
+  isPublic?: string;
+
+  /**
+   * 是否由他人分享而来:0否 1是(支撑"分享给我的"Tab)
+   */
+  isShared?: string;
+
+  /**
+   * 来源方案 ID(从哪个原始方案分享过来的)
+   */
+  sourceSchemeId?: string | number;
+
+  /**
+   * 分享人 user_id
+   */
+  sharerId?: string | number;
+
+  /**
+   * 分享人姓名
+   */
+  sharerName?: string;
+
+  /**
+   * 分享时间
+   */
+  shareTime?: string;
+
+  /**
+   * 创建人 user_id(支撑"我创建的"Tab)
+   */
+  createBy?: string | number;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { PptTemplateVO, PptTemplateForm, PptTemplateQuery } from '@/api/product/pptTemplate/types';
+
+/**
+ * 查询PPT 模板库(公共底版)列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listPptTemplate = (query?: PptTemplateQuery): AxiosPromise<PptTemplateVO[]> => {
+  return request({
+    url: '/product/pptTemplate/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询PPT 模板库(公共底版)详细
+ * @param id
+ */
+export const getPptTemplate = (id: string | number): AxiosPromise<PptTemplateVO> => {
+  return request({
+    url: '/product/pptTemplate/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增PPT 模板库(公共底版)
+ * @param data
+ */
+export const addPptTemplate = (data: PptTemplateForm) => {
+  return request({
+    url: '/product/pptTemplate',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改PPT 模板库(公共底版)
+ * @param data
+ */
+export const updatePptTemplate = (data: PptTemplateForm) => {
+  return request({
+    url: '/product/pptTemplate',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除PPT 模板库(公共底版)
+ * @param id
+ */
+export const delPptTemplate = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/pptTemplate/' + id,
+    method: 'delete'
+  });
+};

+ 251 - 0
src/api/product/pptTemplate/types.ts

@@ -0,0 +1,251 @@
+export interface PptTemplateVO {
+  /**
+   * 模板主键
+   */
+  id: string | number;
+
+  /**
+   * 模板名称(显示在列表)
+   */
+  name: string;
+
+  /**
+   * 封面底图(Base64 或 CDN URL)
+   */
+  cover: string;
+
+  /**
+   * 整篇主题色(Hex)
+   */
+  themeColor: string;
+
+  /**
+   * 商品排版模式:1简约 2交错 3明细
+   */
+  itemsPerPage: number;
+
+  /**
+   * 品牌名称
+   */
+  brandName: string;
+
+  /**
+   * 品牌口号 Slogan
+   */
+  brandSlogan: string;
+
+  /**
+   * 官网地址
+   */
+  website: string;
+
+  /**
+   * 联系电话
+   */
+  phone: string;
+
+  /**
+   * 封面底部 Logo(Base64 或 URL)
+   */
+  coverLogo: string;
+
+  /**
+   * 内容页页眉 Logo(Base64 或 URL)
+   */
+  contentLogo: string;
+
+  /**
+   * 封面主标题(如:诞生珍礼,非你莫属)
+   */
+  coverTitle: string;
+
+  /**
+   * 封面副标题(如:卓越品质,专属定制)
+   */
+  coverSubTitle: string;
+
+  /**
+   * 内容页统一分类标题
+   */
+  contentTitle: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface PptTemplateForm extends BaseEntity {
+  /**
+   * 模板主键
+   */
+  id?: string | number;
+
+  /**
+   * 模板名称(显示在列表)
+   */
+  name?: string;
+
+  /**
+   * 封面底图(Base64 或 CDN URL)
+   */
+  cover?: string;
+
+  /**
+   * 整篇主题色(Hex)
+   */
+  themeColor?: string;
+
+  /**
+   * 商品排版模式:1简约 2交错 3明细
+   */
+  itemsPerPage?: number;
+
+  /**
+   * 品牌名称
+   */
+  brandName?: string;
+
+  /**
+   * 品牌口号 Slogan
+   */
+  brandSlogan?: string;
+
+  /**
+   * 官网地址
+   */
+  website?: string;
+
+  /**
+   * 联系电话
+   */
+  phone?: string;
+
+  /**
+   * 封面底部 Logo(Base64 或 URL)
+   */
+  coverLogo?: string;
+
+  /**
+   * 内容页页眉 Logo(Base64 或 URL)
+   */
+  contentLogo?: string;
+
+  /**
+   * 封面主标题(如:诞生珍礼,非你莫属)
+   */
+  coverTitle?: string;
+
+  /**
+   * 封面副标题(如:卓越品质,专属定制)
+   */
+  coverSubTitle?: string;
+
+  /**
+   * 内容页统一分类标题
+   */
+  contentTitle?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface PptTemplateQuery extends PageQuery {
+
+  /**
+   * 模板名称(显示在列表)
+   */
+  name?: string;
+
+  /**
+   * 封面底图(Base64 或 CDN URL)
+   */
+  cover?: string;
+
+  /**
+   * 整篇主题色(Hex)
+   */
+  themeColor?: string;
+
+  /**
+   * 商品排版模式:1简约 2交错 3明细
+   */
+  itemsPerPage?: number;
+
+  /**
+   * 品牌名称
+   */
+  brandName?: string;
+
+  /**
+   * 品牌口号 Slogan
+   */
+  brandSlogan?: string;
+
+  /**
+   * 官网地址
+   */
+  website?: string;
+
+  /**
+   * 联系电话
+   */
+  phone?: string;
+
+  /**
+   * 封面底部 Logo(Base64 或 URL)
+   */
+  coverLogo?: string;
+
+  /**
+   * 内容页页眉 Logo(Base64 或 URL)
+   */
+  contentLogo?: string;
+
+  /**
+   * 封面主标题(如:诞生珍礼,非你莫属)
+   */
+  coverTitle?: string;
+
+  /**
+   * 封面副标题(如:卓越品质,专属定制)
+   */
+  coverSubTitle?: string;
+
+  /**
+   * 内容页统一分类标题
+   */
+  contentTitle?: string;
+
+  /**
+   * 状态(0正常 1停用)
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 3 - 3
src/api/product/priceInventory/types.ts

@@ -10,7 +10,7 @@ export interface PriceInventoryVO {
   marketPrice: number;
 
   /**
-   * 会员价格
+   * 官网价
    */
   memberPrice: number;
 
@@ -78,7 +78,7 @@ export interface PriceInventoryForm extends BaseEntity {
   marketPrice?: number;
 
   /**
-   * 会员价格
+   * 官网价
    */
   memberPrice?: number;
 
@@ -142,7 +142,7 @@ export interface PriceInventoryQuery extends PageQuery {
   marketPrice?: number;
 
   /**
-   * 会员价格
+   * 官网价
    */
   memberPrice?: number;
 

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ProductExquisiteVO, ProductExquisiteForm, ProductExquisiteQuery } from '@/api/product/productExquisite/types';
+
+/**
+ * 查询精品商品池列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listProductExquisite = (query?: ProductExquisiteQuery): AxiosPromise<ProductExquisiteVO[]> => {
+  return request({
+    url: '/product/productExquisite/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询精品商品池详细
+ * @param productId
+ */
+export const getProductExquisite = (productId: string | number): AxiosPromise<ProductExquisiteVO> => {
+  return request({
+    url: '/product/productExquisite/' + productId,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增精品商品池
+ * @param data
+ */
+export const addProductExquisite = (data: ProductExquisiteForm) => {
+  return request({
+    url: '/product/productExquisite',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改精品商品池
+ * @param data
+ */
+export const updateProductExquisite = (data: ProductExquisiteForm) => {
+  return request({
+    url: '/product/productExquisite',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除精品商品池
+ * @param productId
+ */
+export const delProductExquisite = (productId: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/productExquisite/' + productId,
+    method: 'delete'
+  });
+};

+ 71 - 0
src/api/product/productExquisite/types.ts

@@ -0,0 +1,71 @@
+export interface ProductExquisiteVO {
+  /**
+   * 
+   */
+  productId: string | number;
+
+  /**
+   * 产品审核状态:0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  auditStatus: number;
+
+  /**
+   * 审核意见
+   */
+  auditReason: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface ProductExquisiteForm extends BaseEntity {
+  /**
+   * 
+   */
+  productId?: string | number;
+
+  /**
+   * 产品审核状态:0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  auditStatus?: number;
+
+  /**
+   * 审核意见
+   */
+  auditReason?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface ProductExquisiteQuery extends PageQuery {
+
+  /**
+   * 产品审核状态:0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  auditStatus?: number;
+
+  /**
+   * 审核意见
+   */
+  auditReason?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ProductSelfVO, ProductSelfForm, ProductSelfQuery } from '@/api/product/productSelf/types';
+
+/**
+ * 查询自营商品池列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listProductSelf = (query?: ProductSelfQuery): AxiosPromise<ProductSelfVO[]> => {
+  return request({
+    url: '/product/productSelf/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询自营商品池详细
+ * @param productId
+ */
+export const getProductSelf = (productId: string | number): AxiosPromise<ProductSelfVO> => {
+  return request({
+    url: '/product/productSelf/' + productId,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增自营商品池
+ * @param data
+ */
+export const addProductSelf = (data: ProductSelfForm) => {
+  return request({
+    url: '/product/productSelf',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改自营商品池
+ * @param data
+ */
+export const updateProductSelf = (data: ProductSelfForm) => {
+  return request({
+    url: '/product/productSelf',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除自营商品池
+ * @param productId
+ */
+export const delProductSelf = (productId: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/productSelf/' + productId,
+    method: 'delete'
+  });
+};

+ 71 - 0
src/api/product/productSelf/types.ts

@@ -0,0 +1,71 @@
+export interface ProductSelfVO {
+  /**
+   * 
+   */
+  productId: string | number;
+
+  /**
+   * 产品审核状态:0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  auditStatus: number;
+
+  /**
+   * 审核意见
+   */
+  auditReason: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface ProductSelfForm extends BaseEntity {
+  /**
+   * 
+   */
+  productId?: string | number;
+
+  /**
+   * 产品审核状态:0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  auditStatus?: number;
+
+  /**
+   * 审核意见
+   */
+  auditReason?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface ProductSelfQuery extends PageQuery {
+
+  /**
+   * 产品审核状态:0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  auditStatus?: number;
+
+  /**
+   * 审核意见
+   */
+  auditReason?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 13 - 1
src/api/product/products/index.ts

@@ -1,6 +1,6 @@
 import request from '@/utils/request';
 import { AxiosPromise } from 'axios';
-import { ProductsVO, ProductsForm, ProductsQuery } from '@/api/product/protocolProducts/types';
+import { ProductsVO, ProductsForm, ProductsQuery } from '@/api/product/products/types';
 import { BaseQuery, BaseVO } from '@/api/product/base/types';
 
 /**
@@ -88,3 +88,15 @@ export const updateProductsPrice = (data: ProductsForm) => {
     data: data
   })
 }
+
+/**
+ * 批量审核协议商品
+ * @param data 审核参数列表
+ */
+export const updateProductsAudit = (data: { id: string | number; auditStatus: number; auditReason: string }[]) => {
+  return request({
+    url: '/product/protocolProducts/batchAudit',
+    method: 'post',
+    data: data
+  })
+}

+ 8 - 0
src/api/product/products/types.ts

@@ -170,6 +170,10 @@ export interface ProductsQuery extends PageQuery {
    * 商品品牌id
    */
   brandId?: string | number;
+  /**
+   * 商品品牌名称
+   */
+  brandName?: string;
   /**
    * 商品状态 0-下架 1-上架
    */
@@ -178,6 +182,10 @@ export interface ProductsQuery extends PageQuery {
    * 商品id
    */
   productId?: string | number;
+  /**
+   * 审核状态 1=待审核,2=审核通过,3=审核驳回
+   */
+  auditStatus?: number;
 
     /**
    * 日期范围参数

+ 183 - 0
src/components/CategoryCascadeSelect/index.vue

@@ -0,0 +1,183 @@
+<template>
+  <div style="display: flex; gap: 8px; align-items: center; width: 100%">
+    <div style="flex: 1">
+      <el-select
+        :model-value="topCategoryId"
+        placeholder="一级类目"
+        filterable
+        remote
+        clearable
+        :remote-method="handleFirstLevelSearch"
+        :loading="loading"
+        style="width: 100%"
+        @update:model-value="handleFirstLevelChange"
+      >
+        <el-option v-for="item in firstOptions" :key="item.id" :label="item.categoryName" :value="item.id" />
+      </el-select>
+    </div>
+    <div style="flex: 1">
+      <el-select
+        :model-value="mediumCategoryId"
+        placeholder="二级类目"
+        filterable
+        remote
+        clearable
+        :remote-method="handleSecondLevelSearch"
+        :loading="loading"
+        style="width: 100%"
+        :disabled="!topCategoryId"
+        @update:model-value="handleSecondLevelChange"
+      >
+        <el-option v-for="item in secondOptions" :key="item.id" :label="item.categoryName" :value="item.id" />
+      </el-select>
+    </div>
+    <div style="flex: 1">
+      <el-select
+        :model-value="bottomCategoryId"
+        placeholder="三级类目"
+        filterable
+        remote
+        clearable
+        :remote-method="handleThirdLevelSearch"
+        :loading="loading"
+        style="width: 100%"
+        :disabled="!mediumCategoryId"
+        @update:model-value="(val) => emit('update:bottomCategoryId', val)"
+      >
+        <el-option v-for="item in thirdOptions" :key="item.id" :label="item.categoryName" :value="item.id" />
+      </el-select>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { listCategory } from '@/api/product/category';
+import { CategoryVO } from '@/api/product/category/types';
+
+const props = defineProps<{
+  topCategoryId?: string | number;
+  mediumCategoryId?: string | number;
+  bottomCategoryId?: string | number;
+}>();
+
+const emit = defineEmits<{
+  (e: 'update:topCategoryId', val: string | number | undefined): void;
+  (e: 'update:mediumCategoryId', val: string | number | undefined): void;
+  (e: 'update:bottomCategoryId', val: string | number | undefined): void;
+}>();
+
+const loading = ref(false);
+const firstOptions = ref<CategoryVO[]>([]);
+const secondOptions = ref<CategoryVO[]>([]);
+const thirdOptions = ref<CategoryVO[]>([]);
+
+const firstSearchTimer = ref<ReturnType<typeof setTimeout> | null>(null);
+const secondSearchTimer = ref<ReturnType<typeof setTimeout> | null>(null);
+const thirdSearchTimer = ref<ReturnType<typeof setTimeout> | null>(null);
+
+/** 加载一级分类 */
+const loadFirst = async (keyword?: string) => {
+  loading.value = true;
+  try {
+    const res = await listCategory({ classLevel: 1, categoryName: keyword });
+    firstOptions.value = res.data || (res as any).rows || [];
+  } catch (e) {
+    console.error('加载一级分类失败', e);
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 加载二级分类 */
+const loadSecond = async (parentId?: string | number, keyword?: string) => {
+  if (!parentId) {
+    secondOptions.value = [];
+    return;
+  }
+  loading.value = true;
+  try {
+    const res = await listCategory({ parentId, classLevel: 2, categoryName: keyword });
+    secondOptions.value = res.data || (res as any).rows || [];
+  } catch (e) {
+    console.error('加载二级分类失败', e);
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 加载三级分类 */
+const loadThird = async (parentId?: string | number, keyword?: string) => {
+  if (!parentId) {
+    thirdOptions.value = [];
+    return;
+  }
+  loading.value = true;
+  try {
+    const res = await listCategory({ parentId, classLevel: 3, categoryName: keyword });
+    thirdOptions.value = res.data || (res as any).rows || [];
+  } catch (e) {
+    console.error('加载三级分类失败', e);
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 一级分类远程搜索(防抖) */
+const handleFirstLevelSearch = (query: string) => {
+  if (firstSearchTimer.value) clearTimeout(firstSearchTimer.value);
+  firstSearchTimer.value = setTimeout(() => loadFirst(query || undefined), 300);
+};
+
+/** 二级分类远程搜索(防抖) */
+const handleSecondLevelSearch = (query: string) => {
+  if (secondSearchTimer.value) clearTimeout(secondSearchTimer.value);
+  secondSearchTimer.value = setTimeout(() => loadSecond(props.topCategoryId, query || undefined), 300);
+};
+
+/** 三级分类远程搜索(防抖) */
+const handleThirdLevelSearch = (query: string) => {
+  if (thirdSearchTimer.value) clearTimeout(thirdSearchTimer.value);
+  thirdSearchTimer.value = setTimeout(() => loadThird(props.mediumCategoryId, query || undefined), 300);
+};
+
+/** 一级分类改变 */
+const handleFirstLevelChange = (val: string | number | undefined) => {
+  emit('update:topCategoryId', val);
+  emit('update:mediumCategoryId', undefined);
+  emit('update:bottomCategoryId', undefined);
+  secondOptions.value = [];
+  thirdOptions.value = [];
+  if (val) {
+    loadSecond(val);
+  }
+};
+
+/** 二级分类改变 */
+const handleSecondLevelChange = (val: string | number | undefined) => {
+  emit('update:mediumCategoryId', val);
+  emit('update:bottomCategoryId', undefined);
+  thirdOptions.value = [];
+  if (val) {
+    loadThird(val);
+  }
+};
+
+/** 重置组件状态(外部可调用) */
+const reset = () => {
+  secondOptions.value = [];
+  thirdOptions.value = [];
+};
+
+/** 初始化:加载一级分类;若已有值则加载对应下级 */
+onMounted(async () => {
+  await loadFirst();
+  if (props.topCategoryId) {
+    await loadSecond(props.topCategoryId);
+  }
+  if (props.mediumCategoryId) {
+    await loadThird(props.mediumCategoryId);
+  }
+});
+
+defineExpose({ reset });
+</script>

+ 51 - 0
src/utils/common.ts

@@ -0,0 +1,51 @@
+/**
+ * 判断是否是url
+ * @param str
+ * @returns
+ */
+export function isUrl(str: string): boolean {
+  return str.indexOf('http://') != -1 || str.indexOf('https://') != -1;
+}
+
+const isArray = (value: any) => {
+  if (typeof Array.isArray === 'function') {
+    return Array.isArray(value);
+  }
+  return Object.prototype.toString.call(value) === '[object Array]';
+};
+
+/**
+ * 图片输出
+ * @param path
+ * @returns
+ */
+export function img(path: string): string {
+  let imgDomain = import.meta.env.VITE_IMG_DOMAIN || location.origin;
+
+  if (typeof path == 'string' && path.startsWith('/')) path = path.replace(/^\//, '');
+  if (typeof imgDomain == 'string' && imgDomain.endsWith('/')) imgDomain = imgDomain.slice(0, -1);
+  if (path) {
+    return isUrl(path) ? path : `${imgDomain}/${path}`;
+  }
+}
+
+/**
+ * @description 深度克隆
+ * @param {object} obj 需要深度克隆的对象
+ * @returns {*} 克隆后的对象或者原值(不是对象)
+ */
+export function deepClone(obj: any) {
+  // 对常见的“非”值,直接返回原来值
+  if ([null, undefined, NaN, false].includes(obj)) return obj;
+  if (typeof obj !== 'object' && typeof obj !== 'function') {
+    // 原始类型直接返回
+    return obj;
+  }
+  const o = isArray(obj) ? [] : {};
+  for (const i in obj) {
+    if (obj.hasOwnProperty(i)) {
+      o[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i];
+    }
+  }
+  return o;
+}

+ 54 - 0
src/utils/mockData.js

@@ -0,0 +1,54 @@
+// 采用生成的高清精美本地照片资产,纯同源请求绝不跨域!
+const realImgs = [
+  '/images/nuts.png',
+  '/images/juice.png',
+  '/images/toast.png',
+  '/images/snack.png',
+  '/images/tuna.png',
+  '/images/coffee.png'
+]
+
+const mockNames = [
+  '精选有机特级混合坚果', '100%纯手工鲜榨橙汁', '厚切多层肉松拉丝吐司', 
+  '香辣诱惑脆皮休闲零食', '大颗粒深海金枪鱼罐头', '手冲特调浓香丝滑咖啡'
+]
+
+const attrPool = [
+  ['原产地: 特选优质农场', '工艺: 低温慢烘更健康', '净含量: 综合特调装', '保质期: 180天', '储藏: 阴凉干燥避光'],
+  ['鲜榨工艺: 纯物理冷压', '配料: 100%新鲜甜橙', '规格: 300ml标准瓶', '保质期: 21天', '储藏: 2-8℃冷藏保存'],
+  ['烘焙度: 日式轻柔工艺', '风味: 咸香肉松搭配拉丝', '包装: 独立防潮微压包', '保质期: 30天', '是否含防腐剂: 否'],
+  ['工艺: 高温快速脱水', '风味: 香辣诱惑系列款', '配料: 优质土豆及香辛料', '保质期: 9个月', '净含量: 120g'],
+  ['部位: 深海大目金枪鱼', '形态: 大块原肉段封存', '加工法: 初榨植物油浸泡', '保质期: 3年', '开罐方式: 易拉快开'],
+  ['咖啡豆: 阿拉比卡精选', '处理法: 水洗与日晒拼接', '风味: 浓郁黑巧及焦糖', '保质期: 1年', '适用: 滤挂手冲即时享用']
+];
+
+const featPool = [
+  ['1、五种以上精选坚果黄金搭配', '2、科学配比满足均衡每日营养', '3、无多余添加剂还原自然坚果香', '4、严格人工挑选颗颗饱满大果仁', '5、充氮锁鲜处理开袋即食脆爽'],
+  ['1、原产地新鲜采摘甜橙直取果汁', '2、无任何加水或糖浆注入保持纯正', '3、全程冷链护航锁死珍贵维他命C', '4、保留细小果肉口感真实且顺滑', '5、早餐好伴侣清甜解腻提升活力'],
+  ['1、秘制大颗粒肉松紧密包裹吐司', '2、微波加热15秒爆浆拉丝惊艳视觉', '3、特别精选新西兰进口高品质黄油', '4、入口松软绵密不干噎层次分明', '5、独立单只包装携带方便不易碎'],
+  ['1、嘎嘣脆响声声解压的零食爆款', '2、独家香辣配方辣而不辛回味无穷', '3、超薄切片工艺让每一片片片入味', '4、非传统高温油炸保留更多清爽', '5、下午茶及剧集陪伴的最佳黄金搭档'],
+  ['1、远洋深海捕捞新鲜直达杀菌车间', '2、超大肉片块纹理清晰毫不细碎', '3、高蛋白低脂肪特别适合健康轻食', '4、即食沙拉或搭配三明治绝佳风味', '5、纯净海域捕捞从源头严把安全品质'],
+  ['1、专业评委级寻豆师定制烘焙曲线', '2、高阻隔滤挂包完美还原手冲醇厚感', '3、快速萃取释放是忙里偷闲提神佳品', '4、独有黑巧克力深邃回甘余韵绵长', '5、小巧轻奢挂耳无论是自用还是礼赠']
+];
+
+export const getMockProducts = () => {
+  const allData = []
+  for (let i = 0; i < 22; i++) {
+    const rIdx = i % 6;
+    allData.push({
+      id: i + 1,
+      itemName: `${mockNames[rIdx]} - 批次${i+1}`,
+      productImage: realImgs[rIdx], // 直接使用已加载的本地高清单反效果原生图
+      barCoding: `6989912340${i.toString().padStart(3,'0')}`,
+      specificationsCode: `${Math.floor(Math.random() * 400 + 100)}g/包`,
+      supplyPrice: (Math.random() * 80 + 9).toFixed(1),
+      brandName: '优易甄选',
+      productNo: `000037${300 + i}`,
+      minOrderQuantity: '1箱',
+      marketPrice: (Math.random() * 120 + 39).toFixed(1),
+      attributesList: attrPool[rIdx],
+      mainLibraryIntro: featPool[rIdx]
+    })
+  }
+  return allData
+};

+ 246 - 0
src/utils/pptPlugin.js

@@ -0,0 +1,246 @@
+import pptxgen from "pptxgenjs";
+
+/**
+ * 将任意图片 URL(含相对路径)转为 base64 data URL
+ * pptxgenjs 在浏览器端必须使用 base64 或完整 http 地址才能嵌入图片
+ */
+const toBase64 = (src) => {
+  return new Promise((resolve) => {
+    if (!src) { resolve(null); return; }
+    if (src.startsWith('data:')) { resolve(src); return; }
+
+    // 优先用 fetch 获取 Blob → base64(支持同源相对路径 & 允许CORS的外链)
+    const fullUrl = src.startsWith('http') ? src : (window.location.origin + (src.startsWith('/') ? src : '/' + src));
+    fetch(fullUrl)
+      .then(r => r.blob())
+      .then(blob => {
+        const reader = new FileReader();
+        reader.onload = () => resolve(reader.result);
+        reader.onerror = () => resolve(null);
+        reader.readAsDataURL(blob);
+      })
+      .catch(() => {
+        // fetch 失败时降级用 canvas(跨域图片会被 taint,可能失败)
+        const img = new Image();
+        img.crossOrigin = 'anonymous';
+        img.onload = () => {
+          try {
+            const c = document.createElement('canvas');
+            c.width = img.width; c.height = img.height;
+            c.getContext('2d').drawImage(img, 0, 0);
+            resolve(c.toDataURL('image/png'));
+          } catch { resolve(null); }
+        };
+        img.onerror = () => resolve(null);
+        img.src = fullUrl;
+      });
+  });
+};
+
+/** 1×1 灰色像素,作为图片加载失败时的占位符 */
+const PLACEHOLDER_B64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQI12NgYGBgAAAABQABpfZFQAAAAABJRU5ErkJggg==';
+
+export const generatePPT = async (template, products) => {
+  if (!products || products.length === 0) return;
+
+  const pres    = new pptxgen();
+  const MC      = (template.themeColor || '#C00000').replace('#', '');
+  const WHITE   = 'FFFFFF';
+
+  // ── 把所有涉及到的资产图片提前并行转 base64 ──────────────────────────────────────
+  const [coverB64, coverLogoB64, contentLogoB64, ...productImgB64s] = await Promise.all([
+    toBase64(template.cover),
+    toBase64(template.coverLogo),
+    toBase64(template.contentLogo),
+    ...products.map(p => toBase64(p.productImage))
+  ]);
+
+  // ── 0. 定义全局母版 (MASTER) ────────────────────────────────────────────────
+  pres.defineSlideMaster({
+    title: 'MASTER',
+    background: { color: 'F5F7FA' }, // 浅灰背景,更有高级感
+    objects: [
+      // 底部装饰条
+      { shape: pres.ShapeType.rect, options: { x: 0, y: 5.4, w: '100%', h: 0.2, fill: { color: MC } } }
+    ]
+  });
+
+  // ══════════════════════════ 1. 封面页 ══════════════════════════════
+  const coverSlide = pres.addSlide();
+  // 背景图 (占据上方 75%)
+  if (coverB64) coverSlide.addImage({ data: coverB64, x: 0, y: 0, w: '100%', h: 4.2, sizing: { type: 'cover' } });
+  coverSlide.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: '100%', h: 4.2, fill: { color: '000000', transparency: 50 } });
+
+  // 封面文字
+  coverSlide.addText(template.title || 'VIP客户生日礼方案', { x: 0.4, y: 2.2, w: 6.0, h: 0.8, fontSize: 32, color: WHITE, bold: true });
+  coverSlide.addText(template.subTitle || '卓越品质,专属定制', { x: 0.4, y: 2.9, w: 6.0, h: 0.5, fontSize: 22, color: WHITE, opacity: 0.9 });
+  coverSlide.addText(template.validity || '方案有效期:2026年12月31日', { x: 0.4, y: 3.4, w: 6.0, h: 0.3, fontSize: 11, color: 'EEEEEE' });
+
+  // 底部白条 (Logo/品牌信息)
+  coverSlide.addShape(pres.ShapeType.rect, { x: 0, y: 4.2, w: '100%', h: 1.4, fill: { color: WHITE } });
+  if (coverLogoB64) coverSlide.addImage({ data: coverLogoB64, x: 0.4, y: 4.4, w: 1.0, h: 1.0, sizing: { type: 'contain' } });
+  coverSlide.addShape(pres.ShapeType.line, { x: 1.5, y: 4.5, w: 0, h: 0.8, line: { color: 'DDDDDD', width: 1 } });
+  
+  coverSlide.addText(template.brandName || '优易365', { x: 1.6, y: 4.5, w: 3.0, h: 0.4, fontSize: 20, color: '000000', bold: true });
+  coverSlide.addText(template.brandSlogan || '领先的企业级数字化采购及服务品牌', { x: 1.6, y: 4.9, w: 4.0, h: 0.3, fontSize: 10, color: '666666' });
+  
+  coverSlide.addText(template.website || 'www.yoe365.com', { x: 7.0, y: 4.5, w: 2.6, h: 0.3, fontSize: 12, color: '000000', align: 'right', bold: true });
+  coverSlide.addText(template.phone || '400-000-0000', { x: 7.0, y: 4.8, w: 2.6, h: 0.3, fontSize: 12, color: '000000', align: 'right', bold: true });
+
+  // ══════════════════════════ 2. 商品内页 ══════════════════════════════
+  const layoutId = template.itemsPerPage || 1;
+  // 特殊逻辑:itemsPerPage === 3 是“单品明细版”的标识符,逻辑上强制为 每页1个商品
+  const itemsPerPage = layoutId === 3 ? 1 : layoutId;
+  const totalPages   = Math.ceil(products.length / itemsPerPage);
+
+  for (let i = 0; i < totalPages; i++) {
+    const slide        = pres.addSlide({ masterName: 'MASTER' });
+    const pageProducts = products.slice(i * itemsPerPage, (i + 1) * itemsPerPage);
+
+    // 渲染定制化顶栏及背景覆盖
+    const curTopTitle = template.contentTitle || '商品展示方案';
+
+    if (layoutId !== 3) {
+      if (contentLogoB64) slide.addImage({ data: contentLogoB64, x: 0.2, y: 0.08, w: 1.1, h: 0.44, sizing: { type: 'contain' } });
+      slide.addText(curTopTitle, { x: contentLogoB64 ? 1.45 : 0.2, y: 0.1, w: 6.5, h: 0.42, fontSize: 16, color: MC, bold: true });
+      slide.addText(`Page ${i + 1}`, { x: 8.5, y: 0.12, w: 1, h: 0.3, fontSize: 11, color: '999999', align: 'right' });
+      slide.addShape(pres.ShapeType.rect, { x: 0, y: 0.64, w: 0.12, h: 4.8, fill: { color: MC } });
+    } else {
+      slide.addShape(pres.ShapeType.rect, { x: 0, y: 0, w: '100%', h: 0.6, fill: { color: 'FFFFFF' } }); // 标题背景区
+      slide.addShape(pres.ShapeType.rect, { x: 0.4, y: 0.18, w: 0.05, h: 0.24, fill: { color: 'E3132D' } }); // 红色装饰条
+      slide.addText(curTopTitle, { x: 0.55, y: 0.18, w: 6.0, h: 0.24, fontSize: 16, color: '1A1A1A', bold: true, valign: 'middle' });
+      if (contentLogoB64) slide.addImage({ data: contentLogoB64, x: 8.4, y: 0.1, w: 1.2, h: 0.4, sizing: { type: 'contain' } });
+      // 分割线:满宽,且正好在背景块底部 (y=0.6)
+      slide.addShape(pres.ShapeType.line, { x: 0, y: 0.6, w: '100%', h: 0, line: { color: 'BDBDBD', width: 0.5, dashType: 'sysDash' } });
+    }
+
+    if (layoutId === 3) {
+      // ──── [A] 1 商品 / 页图文详细版式 (明细版) ────────────────────────
+      const p    = pageProducts[0];
+      const imgB = productImgB64s[i] || PLACEHOLDER_B64;
+      
+      slide.addShape(pres.ShapeType.rect, { x: 0.5, y: 1.15, w: 3.8, h: 4.0, fill: { color: 'FFFFFF' } });
+      if (imgB) slide.addImage({ data: imgB, x: 0.55, y: 1.2, w: 3.7, h: 3.9, sizing: { type: 'contain' } });
+
+      const tx = 4.6;
+      const rw = 5.0;
+      slide.addText(p.itemName, { x: tx, y: 0.95, w: rw, h: 0.45, fontSize: 13, color: '1A1A1A', wrap: true });
+      slide.addShape(pres.ShapeType.line, { x: tx, y: 1.45, w: rw, h: 0, line: { color: 'E3132D', width: 0.75 } });
+      
+      let cy = 1.6;
+      slide.addText(`规格型号:${p.specificationsCode}`, { x: tx, y: cy, w: rw, h: 0.25, fontSize: 11, color: '111111', bold: true }); cy += 0.28;
+      slide.addText(`产品编号:${p.productNo || p.barCoding}`, { x: tx, y: cy, w: rw, h: 0.25, fontSize: 11, color: '111111', bold: true }); cy += 0.28;
+      slide.addText(`品牌名称:${p.brandName || '未知'}`, { x: tx, y: cy, w: rw, h: 0.25, fontSize: 11, color: '111111', bold: true }); cy += 0.28;
+      slide.addText(`最低起订量:${p.minOrderQuantity || '1'}`, { x: tx, y: cy, w: rw, h: 0.25, fontSize: 11, color: '111111', bold: true }); cy += 0.28;
+      
+      cy += 0.05;
+      slide.addText(`市场价:${p.marketPrice || p.marketPrice} 元`, { x: tx, y: cy, w: rw, h: 0.25, fontSize: 11, color: '666666', bold: true, strike: true }); cy += 0.28;
+      slide.addText(`供应价:${p.marketPrice}元`, { x: tx, y: cy, w: rw, h: 0.3, fontSize: 13, color: 'E3132D', bold: true }); cy += 0.45;
+
+      slide.addText(`产品属性`, { x: tx, y: cy, w: 2.3, h: 0.25, fontSize: 12, color: '111111', bold: true });
+      slide.addText(`产品简介`, { x: tx+2.4, y: cy, w: 2.3, h: 0.25, fontSize: 12, color: '111111', bold: true });
+      cy += 0.25;
+      
+      if (p.attributesList) {
+        let attrText = '';
+        if (Array.isArray(p.attributesList)) {
+          // mock 数据:字符串数组
+          attrText = p.attributesList.join('\n');
+        } else if (typeof p.attributesList === 'string') {
+          try {
+            // 真实 API:JSON 字符串,格式如 {"1":["3kg","4kg"],"2":["红色"]}
+            const attrObj = JSON.parse(p.attributesList);
+            attrText = Object.entries(attrObj)
+              .map(([key, vals]) => `${key}:${Array.isArray(vals) ? vals.join('、') : String(vals)}`)
+              .join('\n');
+          } catch (e) {
+            attrText = p.attributesList;
+          }
+        }
+        if (attrText) {
+          slide.addText(attrText, { x: tx, y: cy, w: 2.3, h: 1.0, fontSize: 10, color: '666666', valign: 'top', lineSpacing: 14 });
+        }
+      }
+      if (p.productDescription) {
+        slide.addText(p.productDescription.join('\n'), { x: tx+2.4, y: cy, w: 2.4, h: 1.0, fontSize: 10, color: '666666', valign: 'top', lineSpacing: 14 });
+      }
+
+    } else if (itemsPerPage === 1) {
+      // ──── [B] 基础 1 商品 / 页版式 ────────────────────────────────────────
+      const p    = pageProducts[0];
+      const imgB = productImgB64s[i] || PLACEHOLDER_B64;
+
+      if (imgB) {
+        slide.addImage({ data: imgB, x: 0.5, y: 0.9, w: 4.7, h: 3.8, sizing: { type: 'cover', w: 4.7, h: 3.8 } });
+        slide.addShape(pres.ShapeType.rect, { x: 0.5, y: 0.9, w: 4.7, h: 3.8, fill: { type: 'none' }, line: { color: 'E0E0E0', width: 1 } });
+      } else {
+        slide.addShape(pres.ShapeType.rect, { x: 0.5, y: 0.9, w: 4.7, h: 3.8, fill: { type: 'solid', color: 'F0F0F0' }, line: { color: 'E0E0E0', width: 1 } });
+      }
+
+      const sx = 5.5;
+      slide.addText(p.itemName, { x: sx, y: 0.9, w: 3.9, h: 1.4, fontSize: 20, bold: true, color: '222222', wrap: true, valign: 'top' });
+      slide.addText(`产品编号:${p.productNo || p.barCoding}`, { x: sx, y: 2.3, w: 3.9, h: 0.35, fontSize: 13, color: '666666' });
+      slide.addText(`规格型号:${p.specificationsCode}`,  { x: sx, y: 2.7, w: 3.9, h: 0.35, fontSize: 13, color: '666666' });
+
+      slide.addShape(pres.ShapeType.roundRect, { x: sx, y: 3.5, w: 2.8, h: 0.75, fill: { color: MC }, rectRadius: 0.12 });
+      slide.addText(`供应价: ¥${p.marketPrice}`, { x: sx, y: 3.5, w: 2.8, h: 0.75, fontSize: 22, color: WHITE, align: 'center', bold: true });
+
+    } else if (itemsPerPage === 2) {
+      // ──── [C] 2 商品 / 页交错版式 ─────────────────────────────────────────
+      if (pageProducts.length === 2) {
+        slide.addShape(pres.ShapeType.line, { x: 0.4, y: 3.0, w: 9.1, h: 0, line: { color: 'DDDDDD', width: 1, dashType: 'dash' } });
+      }
+
+      for (let j = 0; j < pageProducts.length; j++) {
+        const p       = pageProducts[j];
+        const imgIdx  = i * itemsPerPage + j;
+        const imgB    = productImgB64s[imgIdx] || PLACEHOLDER_B64;
+        const isUpper = j === 0;
+        const yBase   = isUpper ? 0.75 : 3.1;
+        const imgX  = isUpper ? 0.4  : 6.6;
+        const txtX  = isUpper ? 3.4  : 0.4;
+        const txtAl = isUpper ? 'left' : 'right';
+
+        if (imgB) {
+          slide.addImage({ data: imgB, x: imgX, y: yBase, w: 2.7, h: 2.05, sizing: { type: 'cover', w: 2.7, h: 2.05 } });
+          slide.addShape(pres.ShapeType.rect, { x: imgX, y: yBase, w: 2.7, h: 2.05, fill: { type: 'none' }, line: { color: 'E0E0E0', width: 1 } });
+        } else {
+          slide.addShape(pres.ShapeType.rect, { x: imgX, y: yBase, w: 2.7, h: 2.05, fill: { type: 'solid', color: 'F5F5F5' }, line: { color: 'EEEEEE', width: 1 } });
+        }
+
+        slide.addText(p.itemName, { x: txtX, y: yBase + 0.05, w: 3.1, h: 0.95, fontSize: 15, bold: true, color: '222222', align: txtAl, wrap: true, valign: 'top' });
+        slide.addText(`编号: ${p.productNo || p.barCoding} | 规格: ${p.specificationsCode}`, { x: txtX, y: yBase + 1.05, w: 3.1, h: 0.4, fontSize: 11, color: '888888', align: txtAl });
+
+        const priceX = isUpper ? txtX : txtX + 1.1;
+        slide.addShape(pres.ShapeType.roundRect, { x: priceX, y: yBase + 1.55, w: 2.0, h: 0.44, fill: { color: 'F5F5F5' }, rectRadius: 0.08, line: { color: MC, width: 1 } });
+        slide.addText(`¥ ${p.marketPrice}`, { x: priceX, y: yBase + 1.55, w: 2.0, h: 0.44, fontSize: 16, bold: true, color: MC, align: 'center' });
+      }
+    }
+  }
+
+  // ══════════════════════════ 3. 尾页 (复刻预览设计的致谢页) ══════════════════════
+  const end = pres.addSlide();
+  end.background = { color: WHITE };
+
+  // 主标题 THANKS
+  end.addText('THANKS', {
+    x: 3.0, y: 1.4, w: 6.6, h: 1.4,
+    fontSize: 90, bold: true, color: MC, align: 'right'
+  });
+
+  // 品牌名称 - 宣传口号 (增加宽度 w: 7 避免长文案换行)
+  const brandGroup = `${template.brandName || '优易365'} - ${template.brandSlogan || '领先的企业级数字化采购及服务品牌'}`;
+  end.addText(brandGroup, {
+    x: 2.6, y: 3.0, w: 7.0, h: 0.5,
+    fontSize: 18, bold: true, color: '333333', align: 'right'
+  });
+
+  // 网址
+  end.addText(template.website || 'www.yoe365.com', {
+    x: 3.0, y: 3.5, w: 6.6, h: 0.3,
+    fontSize: 14, bold: true, color: MC, align: 'right'
+  });
+
+  // 导出
+  await pres.writeFile({ fileName: `${template.title || '商品展示方案'}_${Date.now()}.pptx` });
+};

+ 19 - 0
src/views/customer/info/components/BasicInfoTab.vue

@@ -507,6 +507,10 @@ const loadTaxrateList = async () => {
       pageSize: 1000
     });
     taxrateList.value = res.rows || [];
+    // 默认选择第一个
+    if (!erpSupplierInfoForm.rateId && taxrateList.value.length > 0) {
+      erpSupplierInfoForm.rateId = taxrateList.value[0].id;
+    }
   } catch (error) {}
 };
 
@@ -519,6 +523,10 @@ const loadCurrencyList = async () => {
       pageSize: 1000
     });
     currencyList.value = res.rows || [];
+    // 默认选择第一个
+    if (!erpSupplierInfoForm.dealCurrencyId && currencyList.value.length > 0) {
+      erpSupplierInfoForm.dealCurrencyId = currencyList.value[0].id;
+    }
   } catch (error) {
     console.error('加载币种列表失败:', error);
     currencyList.value = [];
@@ -620,6 +628,17 @@ watch(
   { immediate: true }
 );
 
+// 监听付款条件字典加载完成后默认选择第一个
+watch(
+  () => payment_clause.value,
+  (val) => {
+    if (!erpSupplierInfoForm.settlementMethod && val && val.length > 0) {
+      erpSupplierInfoForm.settlementMethod = val[0].value;
+    }
+  },
+  { immediate: true }
+);
+
 onMounted(() => {
   loadErpStaffList();
   loadTaxrateList();

+ 6 - 4
src/views/customer/info/detail.vue

@@ -577,7 +577,7 @@ import { listInvoiceType } from '@/api/system/invoiceType';
 import { InvoiceTypeVO } from '@/api/system/invoiceType/types';
 import { listBank as listSystemBank } from '@/api/system/bank';
 import { BankVO as SystemBankVO } from '@/api/system/bank/types';
-import { getInfoTemporary } from '@/api/supplier/infoTemporary';
+import { getInfoTemporary, addInfoTemporary } from '@/api/supplier/infoTemporary';
 import { getChinaArea } from '@/api/system/addressarea/index';
 import download from '@/plugins/download';
 import { listQualification } from '@/api/supplier/qualification';
@@ -1125,10 +1125,12 @@ const handleSave = async () => {
     let res;
     if (isAddMode.value && !isBasicInfoSaved.value) {
       // 新增模式,调用新增接口
-      res = await addInfo(submitData);
+      submitData.supplyStatus = 0; 
+      res = await addInfoTemporary(submitData);
     } else {
-      // 编辑模式,调用SCM更新接口(不走审核)
-      res = await scmEditInfo(submitData);
+      // 编辑模式,调用供应商临时信息更新接口
+      submitData.supplyStatus = 0; // 编辑模式下,将 supplyStatus 设置为 0
+      res = await addInfoTemporary(submitData);
     }
     ElMessage.success('保存成功');
 

+ 2 - 2
src/views/customer/info/index.vue

@@ -39,11 +39,11 @@
                 <el-option v-for="item in comStaffList" :key="item.staffId" :label="item.staffName" :value="item.staffId" />
               </el-select>
             </el-form-item>
-            <el-form-item label="状态" prop="supplyStatus">
+            <!-- <el-form-item label="状态" prop="supplyStatus">
               <el-select v-model="queryParams.supplyStatus" placeholder="请选择供应商状态" clearable>
                 <el-option v-for="option in supplierStatusOptions" :key="option.value" :label="option.label" :value="option.value" />
               </el-select>
-            </el-form-item>
+            </el-form-item> -->
             <el-form-item>
               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
               <el-button icon="Refresh" @click="resetQuery">重置</el-button>

+ 2 - 6
src/views/product/base/add.vue

@@ -1210,7 +1210,7 @@ const nextStep = async () => {
     productForm.topCategoryId = categoryForm.topCategoryId;
     productForm.mediumCategoryId = categoryForm.mediumCategoryId;
     productForm.bottomCategoryId = categoryForm.bottomCategoryId;
-    
+
     currentStep.value++;
   } else if (currentStep.value === 1) {
     // 验证商品信息表单并提交
@@ -1406,10 +1406,6 @@ const getUnitOptions = async () => {
   try {
     const res = await getUnitList();
     unitOptions.value = res.data || [];
-    // 如果是新增模式且有选项,设置第一个为默认值
-    if (!route.params.id && unitOptions.value.length > 0 && !productForm.unitId) {
-      productForm.unitId = unitOptions.value[0].id;
-    }
   } catch (error) {
     console.error('获取单位列表失败:', error);
   }
@@ -1691,7 +1687,7 @@ onMounted(async () => {
 
     .image-preview {
       position: relative;
-      
+
       .preview-image {
         width: 178px;
         height: 178px;

+ 298 - 128
src/views/product/base/index.vue

@@ -16,25 +16,19 @@
                 </el-form-item>
               </el-col>
               <el-col :span="6">
-                <el-form-item label="商品品牌" prop="brandName">
+                <el-form-item label="商品品牌" prop="brandId">
                   <el-select
-                    v-model="queryParams.brandName"
+                    v-model="queryParams.brandId"
                     placeholder="请输入品牌名称搜索"
                     filterable
                     remote
                     clearable
                     :remote-method="handleBrandSearch"
                     :loading="brandLoading"
-                    value-key="brandName"
                     style="width: 100%"
                     @keyup.enter="handleQuery"
                   >
-                    <el-option
-                      v-for="item in brandOptions"
-                      :key="item.id"
-                      :label="item.brandName"
-                      :value="item.brandName"
-                    />
+                    <el-option v-for="item in brandOptions" :key="item.id" :label="item.brandName" :value="item.id" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -45,39 +39,35 @@
               </el-col>
             </el-row>
             <el-row :gutter="20">
-              <el-col :span="6">
-                <el-form-item label="商品分类" prop="bottomCategoryId">
-                  <el-tree-select
-                    v-model="queryParams.bottomCategoryId"
-                    :data="categoryOptions"
-                    :props="{ value: 'id', label: 'label', children: 'children' } as any"
-                    value-key="id"
-                    placeholder="请选择商品分类"
-                    clearable
-                    check-strictly
-                  />
-                </el-form-item>
-              </el-col>
               <el-col :span="6">
                 <el-form-item label="是否自营" prop="isSelf">
                   <el-select v-model="queryParams.isSelf" placeholder="请选择" clearable>
-                    <el-option label="是" value="1" />
-                    <el-option label="否" value="0" />
+                    <el-option label="是" :value="1" />
+                    <el-option label="否" :value="0" />
                   </el-select>
                 </el-form-item>
               </el-col>
+<!--              <el-col :span="6">-->
+<!--                <el-form-item label="审核状态" prop="productReviewStatus">-->
+<!--                  <el-select v-model="queryParams.productReviewStatus" placeholder="请选择" clearable>-->
+<!--                    <el-option label="待采购审核" value="0" />-->
+<!--                    <el-option label="审核通过" value="1" />-->
+<!--                    <el-option label="驳回" value="2" />-->
+<!--                    <el-option label="待营销审核" value="3" />-->
+<!--                  </el-select>-->
+<!--                </el-form-item>-->
+<!--              </el-col>-->
               <el-col :span="6">
-                <el-form-item label="审核状态" prop="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-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-col :span="6">
-                <el-form-item label="上下架状态" prop="productStatus">
+                <el-form-item label="商品类型" prop="productStatus">
                   <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
                     <el-option label="已上架" :value="1" />
                     <el-option label="下架" :value="0" />
@@ -86,8 +76,18 @@
                 </el-form-item>
               </el-col>
             </el-row>
-            <el-row>
-              <el-col :span="24" class="text-left">
+            <el-row :gutter="20">
+              <el-col :span="18">
+                <el-form-item label="商品分类">
+                  <category-cascade-select
+                    ref="categoryCascadeRef"
+                    v-model:top-category-id="queryParams.topCategoryId"
+                    v-model:medium-category-id="queryParams.mediumCategoryId"
+                    v-model:bottom-category-id="queryParams.bottomCategoryId"
+                  />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6" class="text-left" style="display: flex; align-items: center; padding-bottom: 18px">
                 <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                 <el-button icon="Refresh" @click="resetQuery">重置</el-button>
               </el-col>
@@ -106,12 +106,21 @@
           >条</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>
+        <span class="mx-2"
+          >审核状态: 待审核<span class="text-red-600">{{ statistics.waitAudit || 0 }}</span
+          >条,通过<span class="text-green-600">{{ statistics.auditPass || 0 }}</span
+          >条,驳回<span class="text-orange-600">{{ statistics.auditReject || 0 }}</span
+          >条</span
+        >
+        <span class="mx-2"
+          >上下架状态: 已上架<span class="text-green-600">{{ statistics.onSale || 0 }}</span
+          >条,下架<span class="text-gray-600">{{ statistics.offSale || 0 }}</span
+          >条</span
+        >
         <div class="ml-auto flex gap-2">
-          <el-button type="primary" icon="Plus" @click="handleAdd">商品新增</el-button>
-          <el-button type="warning" icon="Check" @click="handleGoReview">商品审核</el-button>
-          <el-button plain>批量操作</el-button>
+<!--          <el-button type="primary" icon="Plus" @click="handleAdd">商品新增</el-button>-->
+          <!-- <el-button type="warning" icon="Check" @click="handleGoReview">商品审核</el-button> -->
+          <!--          <el-button plain>批量操作</el-button>-->
           <el-button plain icon="Download" @click="handleExport">导出</el-button>
           <el-button circle icon="Refresh" @click="getList"></el-button>
         </div>
@@ -136,12 +145,19 @@
             <div class="text-left">
               <div style="white-space: normal; word-break: break-all; line-height: 1.4">{{ scope.row.itemName }}</div>
               <div class="text-gray-500" style="font-size: 12px">品牌: {{ scope.row.brandName || '-' }}</div>
+              <div class="text-gray-500" style="font-size: 12px">分类: {{ scope.row.topCategoryName+'-'+scope.row.mediumCategoryName+'-'+ scope.row.bottomCategoryName}}</div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="商品分类" align="center" prop="categoryName" width="120" />
-        <el-table-column label="单位" align="center" prop="unitName" width="60" />
-        <el-table-column label="SKU价格" align="center" width="120">
+        <el-table-column label="单位" align="center" width="100">
+          <template #default="scope">
+            <div class="text-left">
+              <div class="text-gray-500" style="font-size: 12px">单位: {{ scope.row.unitName || '-' }}</div>
+              <div class="text-gray-500" style="font-size: 12px">起订量: {{ scope.row.minOrderQuantity || '-' }}</div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="价格信息" align="center" width="120">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px">
               <div>
@@ -149,7 +165,7 @@
                 <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
               </div>
               <div>
-                <span class="text-gray-500">会员价:</span>
+                <span class="text-gray-500">官网价:</span>
                 <span class="text-red-500">¥{{ scope.row.memberPrice || '0.00' }}</span>
               </div>
               <div>
@@ -159,7 +175,8 @@
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="成本情况" align="center" width="150">
+
+        <el-table-column label="采购信息" align="center" width="150">
           <template #default="scope">
             <div class="text-left" style="font-size: 12px">
               <div>
@@ -168,32 +185,50 @@
               </div>
               <div>
                 <span class="text-gray-500">暂估毛利率:</span>
-                <span>{{ scope.row.tempGrossMargin || '0.0000' }}%</span>
+                <span>{{ scope.row.memberPrice ? (((scope.row.memberPrice - (scope.row.purchasingPrice || 0)) / scope.row.memberPrice) * 100).toFixed(2) : '0.00' }}%</span>
               </div>
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="数据来源" align="center" prop="dataSource" width="80">
+        <el-table-column label="库存情况" align="center" width="140">
           <template #default="scope">
-            <span>{{ scope.row.dataSource || '-' }}</span>
+            <div class="text-left" style="font-size: 12px">
+              <div>
+                <span class="text-gray-500">总库存:</span>
+                <span>{{ scope.row.totalInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">可用库存:</span>
+                <span>{{ scope.row.nowInventory ?? '-' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">虚拟库存:</span>
+                <span>{{ scope.row.virtualInventory ?? '-' }}</span>
+              </div>
+            </div>
           </template>
         </el-table-column>
+<!--        <el-table-column label="数据来源" align="center" prop="dataSource" width="80">-->
+<!--          <template #default="scope">-->
+<!--            <span>{{ scope.row.dataSource || '-' }}</span>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
         <el-table-column label="是否自营" align="center" width="80">
           <template #default="scope">
-            <el-tag v-if="scope.row.isSelf === 1" type="success">是</el-tag>
-            <el-tag v-else-if="scope.row.isSelf === 0" type="info">否</el-tag>
-            <span v-else>-</span>
-          </template>
-        </el-table-column>
-        <el-table-column label="审核状态" align="center" prop="productReviewStatus" width="90">
-          <template #default="scope">
-            <span v-if="scope.row.productReviewStatus === 0">待采购审核</span>
-            <span v-else-if="scope.row.productReviewStatus === 1">审核通过</span>
-            <span v-else-if="scope.row.productReviewStatus === 2">驳回</span>
-            <span v-else-if="scope.row.productReviewStatus === 3">待营销审核</span>
+            <span v-if="scope.row.isSelf === 1">是</span>
+            <span v-else-if="scope.row.isSelf === 0">否</span>
             <span v-else>-</span>
           </template>
         </el-table-column>
+<!--        <el-table-column label="审核状态" align="center" prop="productReviewStatus" width="90">-->
+<!--          <template #default="scope">-->
+<!--            <span v-if="scope.row.productReviewStatus === 0">待采购审核</span>-->
+<!--            <span v-else-if="scope.row.productReviewStatus === 1">审核通过</span>-->
+<!--            <span v-else-if="scope.row.productReviewStatus === 2">驳回</span>-->
+<!--            <span v-else-if="scope.row.productReviewStatus === 3">待营销审核</span>-->
+<!--            <span v-else>-</span>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
         <el-table-column label="上下架状态" align="center" prop="productStatus" width="100">
           <template #default="scope">
             <el-tag v-if="scope.row.productStatus === 1" type="success">已上架</el-tag>
@@ -202,42 +237,25 @@
             <el-tag v-else type="info">未知</el-tag>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center" width="150" fixed="right">
-          <template #default="scope">
-            <!-- 待审核状态:只显示编辑 -->
-            <div v-if="scope.row.productReviewStatus !== 1" class="flex gap-1 justify-center">
-              <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
-            </div>
-
-            <!-- 审核通过 -->
-            <div v-else-if="scope.row.productReviewStatus === 1" class="flex flex-col gap-1">
-              <!-- 下架状态:编辑、上架、停售、修改库存 -->
-              <div v-if="scope.row.productStatus === 0" class="flex gap-1 justify-center">
-                <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
-                <el-link type="success" :underline="false" @click="handleShelf(scope.row)">上架</el-link>
-                <el-link type="danger" :underline="false" @click="handleDiscontinue(scope.row)">停售</el-link>
-              </div>
-              <div v-if="scope.row.productStatus === 0" class="flex gap-1 justify-center">
-                <el-link type="primary" :underline="false" @click="handleSupply(scope.row)">修改库存</el-link>
-              </div>
-
-              <!-- 上架状态:编辑、下架、停售、修改库存 -->
-              <div v-else-if="scope.row.productStatus === 1" class="flex gap-1 justify-center">
-                <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
-                <el-link type="warning" :underline="false" @click="handleShelf(scope.row)">下架</el-link>
-                <el-link type="danger" :underline="false" @click="handleDiscontinue(scope.row)">停售</el-link>
-              </div>
-              <div v-else-if="scope.row.productStatus === 1" class="flex gap-1 justify-center">
-                <el-link type="primary" :underline="false" @click="handleSupply(scope.row)">修改库存</el-link>
-              </div>
-            </div>
-
-            <!-- 其他状态(待提交、审核驳回等):显示编辑 -->
-            <div v-else class="flex gap-1 justify-center">
-              <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
-            </div>
-          </template>
-        </el-table-column>
+<!--        <el-table-column label="操作" align="center" width="150" fixed="right">-->
+<!--          <template #default="scope">-->
+<!--            &lt;!&ndash; 其他状态(待提交、审核驳回等):显示编辑 &ndash;&gt;-->
+<!--            <div class="flex gap-1 justify-center">-->
+<!--              <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>-->
+<!--            </div>-->
+<!--            <div class="flex gap-1 justify-center">-->
+<!--              <el-link type="primary" :underline="false" @click="handleSupply(scope.row)">修改库存</el-link>-->
+<!--            </div>-->
+<!--            <div v-if="scope.row.productStatus === 0" class="flex gap-1 justify-center">-->
+<!--              <el-link type="success" :underline="false" @click="handleShelf(scope.row)">上架</el-link>-->
+<!--              <el-link type="danger" :underline="false" @click="handleDiscontinue(scope.row)">停售</el-link>-->
+<!--            </div>-->
+<!--            <div v-if="scope.row.productStatus === 1" class="flex gap-1 justify-center">-->
+<!--              <el-link type="warning" :underline="false" @click="handleShelf(scope.row)">下架</el-link>-->
+<!--              <el-link type="danger" :underline="false" @click="handleDiscontinue(scope.row)">停售</el-link>-->
+<!--            </div>-->
+<!--          </template>-->
+<!--        </el-table-column>-->
       </el-table>
 
       <!-- 游标分页控制 -->
@@ -251,15 +269,48 @@
         @pagination="getList"
       />
     </el-card>
+    <!-- 库存修改弹框 -->
+    <el-dialog v-model="inventoryDialog.visible" title="修改库存" width="500px" :close-on-click-modal="false">
+      <div v-loading="inventoryDialog.loading">
+        <el-form ref="inventoryFormRef" :model="inventoryForm" :rules="inventoryRules" label-width="110px">
+          <el-form-item label="虚拟库存" prop="virtualInventory">
+            <el-input-number
+              v-model="inventoryForm.virtualInventory"
+              :min="0"
+              :precision="0"
+              controls-position="right"
+              style="width: 100%"
+              placeholder="请输入虚拟库存"
+            />
+          </el-form-item>
+        </el-form>
+      </div>
+      <template #footer>
+        <el-button @click="inventoryDialog.visible = false">取消</el-button>
+        <el-button type="primary" :loading="inventoryDialog.submitLoading" @click="submitInventory">确定</el-button>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
 <script setup name="Base" lang="ts">
-import { listBase, getBase, delBase, brandList, categoryTree, shelfReview, changeProductType, getProductStatusCount } from '@/api/product/base';
+import {
+  listBase,
+  getBase,
+  delBase,
+  brandList,
+  updateBase,
+  shelfReview,
+  changeProductType,
+  getProductStatusCount
+} from '@/api/product/base';
+import { generatePPT } from '@/utils/pptPlugin';
+import { addProductSelf } from '@/api/product/productSelf';
+import { addProductExquisite } from '@/api/product/productExquisite';
+import { PriceInventoryForm } from '@/api/product/priceInventory/types';
 import { BaseVO, BaseQuery, BaseForm, StatusCountVo } from '@/api/product/base/types';
 import { BrandVO } from '@/api/product/brand/types';
 import { listBrand } from '@/api/product/brand';
-import { categoryTreeVO } from '@/api/product/category/types';
 import { useRoute, useRouter } from 'vue-router';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -274,14 +325,16 @@ const ids = ref<Array<string | number>>([]);
 const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
-const categoryOptions = ref<categoryTreeVO[]>([]);
 const brandOptions = ref<BrandVO[]>([]);
 const brandLoading = ref(false);
-let brandSearchTimer: ReturnType<typeof setTimeout> | null = null;
+const brandSearchTimer = ref<ReturnType<typeof setTimeout> | null>(null);
 const hasMore = ref(true); // 是否还有更多数据
-// 页面历史记录,存储每页的第一个id和最后一个id,用于支持双向翻页
+// 页面历史记录,存储每页的第一个 id 和最后一个 id,用于支持双向翻页
 const pageHistory = ref([]);
 
+// 三级分类选择组件引用
+const categoryCascadeRef = ref();
+
 // 统计信息
 const statistics = ref<StatusCountVo>({
   total: 0,
@@ -328,7 +381,7 @@ const data = reactive<PageData<BaseForm, BaseQuery>>({
     pageSize: 10,
     productNo: undefined,
     itemName: undefined,
-    brandName: undefined,
+    brandId: undefined,
     productTag: undefined,
     purchaseNature: undefined,
     supplierType: undefined,
@@ -353,7 +406,6 @@ const data = reactive<PageData<BaseForm, BaseQuery>>({
     bottomCategoryId: [{ required: true, message: '底层分类id不能为空', trigger: 'blur' }],
     unitId: [{ required: true, message: '单位id不能为空', trigger: 'blur' }],
     productImage: [{ required: true, message: '产品图片URL不能为空', trigger: 'blur' }],
-    productReviewStatus: [{ required: true, message: '产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核不能为空', trigger: 'change' }],
     homeRecommended: [{ required: true, message: '首页推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
     categoryRecommendation: [{ required: true, message: '分类推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
     cartRecommendation: [{ required: true, message: '购物车推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
@@ -366,11 +418,11 @@ const data = reactive<PageData<BaseForm, BaseQuery>>({
 
 const { queryParams, form, rules } = toRefs(data);
 
-
 /** 查询产品基础信息列表 */
 const getList = async () => {
   loading.value = true;
   try {
+    initRouteParams();
     const params = { ...queryParams.value };
     const currentPageNum = queryParams.value.pageNum;
 
@@ -479,6 +531,11 @@ const handleQuery = () => {
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
+  // 手动重置分类字段
+  queryParams.value.topCategoryId = undefined;
+  queryParams.value.mediumCategoryId = undefined;
+  queryParams.value.bottomCategoryId = undefined;
+  categoryCascadeRef.value?.reset();
   queryParams.value.lastSeenId = undefined;
   pageHistory.value = []; // 重置页面历史
   handleQuery();
@@ -512,32 +569,67 @@ const handleDelete = async (row?: BaseVO) => {
 };
 
 /** 导出按钮操作 */
-const handleExport = () => {
-  proxy?.download(
-    'product/base/export',
-    {
-      ...queryParams.value
-    },
-    `base_${new Date().getTime()}.xlsx`
-  );
+const handleExport = async () => {
+  // 检查是否有选中的商品
+  if (ids.value.length === 0) {
+    proxy?.$modal.msgWarning('请先选择要导出的商品');
+    return;
+  }
+
+  // 获取选中商品的完整信息
+  const selectedProducts = baseList.value.filter(item => ids.value.includes(item.id));
+
+  if (selectedProducts.length === 0) {
+    proxy?.$modal.msgWarning('未找到选中的商品信息');
+    return;
+  }
+
+  // 转换为 generatePPT 需要的格式
+  const products = selectedProducts.map(item => ({
+    image: item.productImage || item.productImageUrl || '',
+    name: item.itemName || '',
+    code: item.productNo || '',
+    spec: item.specification || item.packagingSpec || '-',
+    price: item.minSellingPrice || item.memberPrice || 0
+  }));
+
+  // 默认模板配置
+  const template = {
+    name: '商品展示方案',
+    title: '商品展示方案',
+    themeColor: '#C00000',
+    itemsPerPage: 1, // 每页1个商品,展示更详细
+    cover: '',
+    logo: ''
+  };
+
+  try {
+    proxy?.$modal.loading('正在生成PPT...');
+    await generatePPT(template, products);
+    proxy?.$modal.closeLoading();
+    proxy?.$modal.msgSuccess('PPT导出成功');
+  } catch (error) {
+    proxy?.$modal.closeLoading();
+    console.error('PPT导出失败:', error);
+    proxy?.$modal.msgError('PPT导出失败');
+  }
 };
 
 /** 查看商品详情 */
 const handleView = (row: BaseVO) => {
-  console.log('查看商品', row);
-  // TODO: 实现查看详情逻辑
+  const url = `https://item.xiaoluwebsite.xyz/item?productNo=${row.productNo}`;
+  window.open(url, '_blank');
 };
 
 /** 上下架操作 */
 const handleShelf = async (row: BaseVO) => {
-  // productStatus字段定义为string类型:1=已上架,0=下架,2=上架中
-  const isOnShelf = row.productStatus === '1';
+  const isOnShelf = row.productStatus === 1;
   const action = isOnShelf ? '下架' : '上架';
   await proxy?.$modal.confirm(`确认${action}该商品吗?`);
 
   try {
     // 上架:状态改为2(上架中),下架:状态改为0(下架)
-    const productStatus = isOnShelf ? '0' : '2';
+    const productStatus = isOnShelf ? 0 : 2;
     await shelfReview({
       id: row.id,
       productStatus: productStatus,
@@ -557,16 +649,71 @@ const handlePrice = (row: BaseVO) => {
   // TODO: 打开价格设置对话框
 };
 
-/** 供货存管理 */
-const handleSupply = (row: BaseVO) => {
-  console.log('供货存管理', row);
-  // TODO: 打开供货存管理对话框
+/** 库存修改弹框 */
+const inventoryDialog = reactive({
+  visible: false,
+  loading: false,
+  submitLoading: false
+});
+
+const inventoryFormRef = ref<ElFormInstance>();
+
+const inventoryForm = reactive<PriceInventoryForm>({
+  productId: undefined,
+  totalInventory: undefined,
+  nowInventory: undefined,
+  virtualInventory: undefined
+});
+
+const inventoryRules = {
+  totalInventory: [{ required: true, message: '总库存不能为空', trigger: 'blur' }],
+  nowInventory: [{ required: true, message: '当前可用库存不能为空', trigger: 'blur' }],
+  virtualInventory: [{ required: true, message: '虚拟库存不能为空', trigger: 'blur' }]
+};
+
+/** 打开库存修改弹框 */
+const handleSupply = async (row: BaseVO) => {
+  inventoryForm.id = row.id;
+  inventoryForm.totalInventory = undefined;
+  inventoryForm.nowInventory = undefined;
+  inventoryForm.virtualInventory = undefined;
+  inventoryDialog.loading = true;
+  inventoryDialog.visible = true;
+  try {
+    const res = await getBase(row.id);
+    if (res.data) {
+      inventoryForm.totalInventory = res.data.totalInventory;
+      inventoryForm.nowInventory = res.data.nowInventory;
+      inventoryForm.virtualInventory = res.data.virtualInventory;
+    }
+  } catch (error) {
+    console.error('获取库存信息失败:', error);
+  } finally {
+    inventoryDialog.loading = false;
+  }
+};
+
+/** 提交库存修改 */
+const submitInventory = async () => {
+  await inventoryFormRef.value?.validate();
+  inventoryDialog.submitLoading = true;
+  try {
+    await updateBase({ ...inventoryForm });
+    proxy?.$modal.msgSuccess('库存修改成功');
+    inventoryDialog.visible = false;
+    await getList();
+  } catch (error) {
+    console.error('库存修改失败:', error);
+    proxy?.$modal.msgError('库存修改失败');
+  } finally {
+    inventoryDialog.submitLoading = false;
+  }
 };
 
 /** 停售操作 */
 const handleDiscontinue = async (row: BaseVO) => {
   await proxy?.$modal.confirm('确认停售该商品吗?停售后商品将无法正常售卖。');
-  
+
   try {
     // 调用停售API,将商品类型改为3(停售商品)
     await changeProductType({
@@ -581,6 +728,34 @@ const handleDiscontinue = async (row: BaseVO) => {
   }
 };
 
+/** 加入自营池操作 */
+const handleAddToSelfPool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入自营池吗?');
+
+  try {
+    await addProductSelf({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入自营池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入自营池失败:', error);
+    proxy?.$modal.msgError('加入自营池失败');
+  }
+};
+
+/** 加入精品池操作 */
+const handleAddToExquisitePool = async (row: BaseVO) => {
+  await proxy?.$modal.confirm('确认将该商品加入精品池吗?');
+
+  try {
+    await addProductExquisite({ productId: row.id, auditStatus: 1 });
+    proxy?.$modal.msgSuccess('加入精品池成功');
+    await getList();
+  } catch (error) {
+    console.error('加入精品池失败:', error);
+    proxy?.$modal.msgError('加入精品池失败');
+  }
+};
+
 /** 跳转到商品审核页面 */
 const handleGoReview = () => {
   router.push({
@@ -591,18 +766,14 @@ const handleGoReview = () => {
   });
 };
 
-/** 查询分类树 */
-const getCategoryTree = async () => {
-  const res = await categoryTree();
-  categoryOptions.value = res.data || [];
-};
+
 
 /** 加载品牌选项(默认100条) */
 const loadBrandOptions = async (keyword?: string) => {
   brandLoading.value = true;
   try {
     const res = await listBrand({ pageNum: 1, pageSize: 100, brandName: keyword });
-    brandOptions.value =  res.rows || [];
+    brandOptions.value = res.rows || [];
   } catch (error) {
     console.error('加载品牌列表失败:', error);
   } finally {
@@ -612,8 +783,8 @@ const loadBrandOptions = async (keyword?: string) => {
 
 /** 品牌远程搜索(防抖) */
 const handleBrandSearch = (query: string) => {
-  if (brandSearchTimer) clearTimeout(brandSearchTimer);
-  brandSearchTimer = setTimeout(() => {
+  if (brandSearchTimer.value) clearTimeout(brandSearchTimer.value);
+  brandSearchTimer.value = setTimeout(() => {
     loadBrandOptions(query || undefined);
   }, 300);
 };
@@ -632,7 +803,6 @@ const getStatistics = async () => {
 
 onMounted(() => {
   getList();
-  getCategoryTree();
   getStatistics();
   loadBrandOptions();
 });

+ 16 - 10
src/views/supplier/approve/index.vue

@@ -104,12 +104,12 @@
           <template #default="scope">
             <span>{{ getCooperationStatusDisplayName(scope.row.cooperative) }}</span>
           </template>
-        </el-table-column>
+        </el-table-column> -->
         <el-table-column label="审核状态" align="center" prop="supplyStatus" width="180">
           <template #default="scope">
             <span>{{ getStatusDisplayName(scope.row.supplyStatus) }}</span>
           </template>
-        </el-table-column> -->
+        </el-table-column>
         <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="250" fixed="right">
           <template #default="scope">
             <!-- 状态 0、3、4:待审核、审核未通过、待修改审核 -->
@@ -117,8 +117,6 @@
               v-if="
                 scope.row.supplyStatus === '0' ||
                 scope.row.supplyStatus === 0 ||
-                scope.row.supplyStatus === '3' ||
-                scope.row.supplyStatus === 3 ||
                 scope.row.supplyStatus === '4' ||
                 scope.row.supplyStatus === 4
               "
@@ -140,6 +138,11 @@
               <el-button link type="primary" @click="handleUpdate(scope.row)" v-hasPermi="['customer:info:edit']">编辑</el-button>
               <el-button link type="primary" @click="handleResumeCooperation(scope.row)" v-hasPermi="['customer:info:edit']">恢复合作</el-button>
             </template>
+            <!-- 状态 未通过 -->
+            <template v-else-if="scope.row.supplyStatus === '3' || scope.row.supplyStatus === 3">
+              <el-button link type="primary" @click="handleView(scope.row)" v-hasPermi="['customer:info:query']">查看</el-button>
+              <el-button link type="primary" @click="handleUpdate(scope.row)" v-hasPermi="['customer:info:edit']">编辑</el-button>
+            </template>
           </template>
         </el-table-column>
       </el-table>
@@ -649,13 +652,16 @@ const handleAdd = () => {
 
 /** 修改按钮操作 */
 const handleUpdate = async (row?: InfoVO) => {
-  reset();
+  // 跳转到详情页(编辑模式)
+  const router = proxy?.$router;
   const _id = row?.id || ids.value[0];
-  const res = await getInfo(_id);
-  Object.assign(form.value, res.data);
-  dialog.visible = true;
-  dialog.title = '修改供应商信息';
-  dialog.readonly = false;
+  router?.push({
+    path: '/customer/info/detail',
+    query: {
+      id: _id,
+      mode: 'edit'
+    }
+  });
 };
 
 /** 提交按钮 */