Ver código fonte

feat(product): 添加产品模块相关API接口

- 新增售后服务项管理API (afterSales)
- 新增产品关联管理API (associate)
- 新增产品属性定义API (attributes)
- 新增产品基础信息及关联查询API (base)
- 新增产品黑名单管理API (blacklist)
- 新增产品品牌管理API (brand)
- 新增产品分类管理API (category)
- 新增产品属性关联API (classification)
- 新增产品定制信息API (customization)
- 新增产品保障项管理API (ensure)
- 新增产品扩展属性API (extend)
- 新增产品标签管理API (lable)
- 新增产品池管理API (pool)
- 新增产品池关联管理API (poolLink)
- 新增产品价格库存管理API (priceInventory)
- 新增产品解决方案管理API (program)
- 新增项目方案关联管理API (programLink)
- 新增产品推荐位配置API (recommend)
- 新增产品推荐关联管理API (recommendLink)
- 新增产品规格关联管理API (specs)
- 新增产品税率配置管理API (taxrate)
- 新增产品计量单位管理API (unit)
- 新增产品体积单位管理API (volumeUnit)
肖路 5 meses atrás
pai
commit
12b49fbbab
75 arquivos alterados com 13086 adições e 3 exclusões
  1. 63 0
      src/api/product/afterSales/index.ts
  2. 71 0
      src/api/product/afterSales/types.ts
  3. 63 0
      src/api/product/associate/index.ts
  4. 101 0
      src/api/product/associate/types.ts
  5. 63 0
      src/api/product/attributes/index.ts
  6. 161 0
      src/api/product/attributes/types.ts
  7. 157 0
      src/api/product/base/index.ts
  8. 670 0
      src/api/product/base/types.ts
  9. 63 0
      src/api/product/blacklist/index.ts
  10. 86 0
      src/api/product/blacklist/types.ts
  11. 63 0
      src/api/product/brand/index.ts
  12. 315 0
      src/api/product/brand/types.ts
  13. 63 0
      src/api/product/category/index.ts
  14. 383 0
      src/api/product/category/types.ts
  15. 63 0
      src/api/product/classification/index.ts
  16. 86 0
      src/api/product/classification/types.ts
  17. 63 0
      src/api/product/customization/index.ts
  18. 161 0
      src/api/product/customization/types.ts
  19. 63 0
      src/api/product/ensure/index.ts
  20. 71 0
      src/api/product/ensure/types.ts
  21. 63 0
      src/api/product/extend/index.ts
  22. 626 0
      src/api/product/extend/types.ts
  23. 63 0
      src/api/product/lable/index.ts
  24. 86 0
      src/api/product/lable/types.ts
  25. 63 0
      src/api/product/pool/index.ts
  26. 116 0
      src/api/product/pool/types.ts
  27. 63 0
      src/api/product/poolLink/index.ts
  28. 146 0
      src/api/product/poolLink/types.ts
  29. 63 0
      src/api/product/priceInventory/index.ts
  30. 206 0
      src/api/product/priceInventory/types.ts
  31. 63 0
      src/api/product/program/index.ts
  32. 210 0
      src/api/product/program/types.ts
  33. 63 0
      src/api/product/programLink/index.ts
  34. 71 0
      src/api/product/programLink/types.ts
  35. 63 0
      src/api/product/recommend/index.ts
  36. 116 0
      src/api/product/recommend/types.ts
  37. 63 0
      src/api/product/recommendLink/index.ts
  38. 71 0
      src/api/product/recommendLink/types.ts
  39. 63 0
      src/api/product/specs/index.ts
  40. 86 0
      src/api/product/specs/types.ts
  41. 63 0
      src/api/product/taxrate/index.ts
  42. 116 0
      src/api/product/taxrate/types.ts
  43. 63 0
      src/api/product/unit/index.ts
  44. 101 0
      src/api/product/unit/types.ts
  45. 63 0
      src/api/product/volumeUnit/index.ts
  46. 71 0
      src/api/product/volumeUnit/types.ts
  47. 63 0
      src/api/product/weightUnit/index.ts
  48. 71 0
      src/api/product/weightUnit/types.ts
  49. 1 1
      src/layout/components/Sidebar/Logo.vue
  50. 20 0
      src/router/index.ts
  51. 2 2
      src/views/login.vue
  52. 235 0
      src/views/product/afterSales/index.vue
  53. 256 0
      src/views/product/associate/index.vue
  54. 298 0
      src/views/product/attributes/index.vue
  55. 471 0
      src/views/product/base/index.vue
  56. 244 0
      src/views/product/blacklist/index.vue
  57. 433 0
      src/views/product/brand/index.vue
  58. 469 0
      src/views/product/category/index.vue
  59. 247 0
      src/views/product/classification/index.vue
  60. 307 0
      src/views/product/customization/index.vue
  61. 235 0
      src/views/product/ensure/index.vue
  62. 675 0
      src/views/product/extend/index.vue
  63. 244 0
      src/views/product/lable/index.vue
  64. 253 0
      src/views/product/pool/index.vue
  65. 274 0
      src/views/product/poolLink/index.vue
  66. 331 0
      src/views/product/priceInventory/index.vue
  67. 317 0
      src/views/product/program/index.vue
  68. 235 0
      src/views/product/programLink/index.vue
  69. 256 0
      src/views/product/recommend/index.vue
  70. 235 0
      src/views/product/recommendLink/index.vue
  71. 244 0
      src/views/product/specs/index.vue
  72. 271 0
      src/views/product/taxrate/index.vue
  73. 259 0
      src/views/product/unit/index.vue
  74. 235 0
      src/views/product/volumeUnit/index.vue
  75. 235 0
      src/views/product/weightUnit/index.vue

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { AfterSalesVO, AfterSalesForm, AfterSalesQuery } from '@/api/product/afterSales/types';
+
+/**
+ * 查询产品售后服务项列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listAfterSales = (query?: AfterSalesQuery): AxiosPromise<AfterSalesVO[]> => {
+  return request({
+    url: '/product/afterSales/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品售后服务项详细
+ * @param id
+ */
+export const getAfterSales = (id: string | number): AxiosPromise<AfterSalesVO> => {
+  return request({
+    url: '/product/afterSales/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品售后服务项
+ * @param data
+ */
+export const addAfterSales = (data: AfterSalesForm) => {
+  return request({
+    url: '/product/afterSales',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品售后服务项
+ * @param data
+ */
+export const updateAfterSales = (data: AfterSalesForm) => {
+  return request({
+    url: '/product/afterSales',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品售后服务项
+ * @param id
+ */
+export const delAfterSales = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/afterSales/' + id,
+    method: 'delete'
+  });
+};

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

@@ -0,0 +1,71 @@
+export interface AfterSalesVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 售后服务项目(如:保修、退换货、技术支持等)
+   */
+  afterSalesItems: string;
+
+  /**
+   * 数据来源(如:系统录入、接口同步等)
+   */
+  dataSource: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface AfterSalesForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 售后服务项目(如:保修、退换货、技术支持等)
+   */
+  afterSalesItems?: string;
+
+  /**
+   * 数据来源(如:系统录入、接口同步等)
+   */
+  dataSource?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface AfterSalesQuery extends PageQuery {
+
+  /**
+   * 售后服务项目(如:保修、退换货、技术支持等)
+   */
+  afterSalesItems?: string;
+
+  /**
+   * 数据来源(如:系统录入、接口同步等)
+   */
+  dataSource?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { AssociateVO, AssociateForm, AssociateQuery } from '@/api/product/associate/types';
+
+/**
+ * 查询产品关联列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listAssociate = (query?: AssociateQuery): AxiosPromise<AssociateVO[]> => {
+  return request({
+    url: '/product/associate/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品关联详细
+ * @param id
+ */
+export const getAssociate = (id: string | number): AxiosPromise<AssociateVO> => {
+  return request({
+    url: '/product/associate/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品关联
+ * @param data
+ */
+export const addAssociate = (data: AssociateForm) => {
+  return request({
+    url: '/product/associate',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品关联
+ * @param data
+ */
+export const updateAssociate = (data: AssociateForm) => {
+  return request({
+    url: '/product/associate',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品关联
+ * @param id
+ */
+export const delAssociate = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/associate/' + id,
+    method: 'delete'
+  });
+};

+ 101 - 0
src/api/product/associate/types.ts

@@ -0,0 +1,101 @@
+export interface AssociateVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 主产品id
+   */
+  productId: string | number;
+
+  /**
+   * 关联产品编号列表(如:用逗号分隔的产品编号)
+   */
+  productIds: string | number;
+
+  /**
+   * 是否单向关联:0=双向,1=单向
+   */
+  isUnidirectional: string | number;
+
+  /**
+   * 关联标题/展示名称
+   */
+  relatedTitle: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface AssociateForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 主产品id
+   */
+  productId?: string | number;
+
+  /**
+   * 关联产品编号列表(如:用逗号分隔的产品编号)
+   */
+  productIds?: string | number;
+
+  /**
+   * 是否单向关联:0=双向,1=单向
+   */
+  isUnidirectional?: string | number;
+
+  /**
+   * 关联标题/展示名称
+   */
+  relatedTitle?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface AssociateQuery extends PageQuery {
+
+  /**
+   * 主产品id
+   */
+  productId?: string | number;
+
+  /**
+   * 关联产品编号列表(如:用逗号分隔的产品编号)
+   */
+  productIds?: string | number;
+
+  /**
+   * 是否单向关联:0=双向,1=单向
+   */
+  isUnidirectional?: string | number;
+
+  /**
+   * 关联标题/展示名称
+   */
+  relatedTitle?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { AttributesVO, AttributesForm, AttributesQuery } from '@/api/product/attributes/types';
+
+/**
+ * 查询产品属性定义(用于动态属性配置)列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listAttributes = (query?: AttributesQuery): AxiosPromise<AttributesVO[]> => {
+  return request({
+    url: '/product/attributes/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品属性定义(用于动态属性配置)详细
+ * @param id
+ */
+export const getAttributes = (id: string | number): AxiosPromise<AttributesVO> => {
+  return request({
+    url: '/product/attributes/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品属性定义(用于动态属性配置)
+ * @param data
+ */
+export const addAttributes = (data: AttributesForm) => {
+  return request({
+    url: '/product/attributes',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品属性定义(用于动态属性配置)
+ * @param data
+ */
+export const updateAttributes = (data: AttributesForm) => {
+  return request({
+    url: '/product/attributes',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品属性定义(用于动态属性配置)
+ * @param id
+ */
+export const delAttributes = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/attributes/' + id,
+    method: 'delete'
+  });
+};

+ 161 - 0
src/api/product/attributes/types.ts

@@ -0,0 +1,161 @@
+export interface AttributesVO {
+  /**
+   * 主键,自增ID
+   */
+  id: string | number;
+
+  /**
+   * 关联的产品分类id
+   */
+  categoryId: string | number;
+
+  /**
+   * 属性编码(用于系统识别)
+   */
+  productAttributesCode: string;
+
+  /**
+   * 属性显示名称
+   */
+  productAttributesName: string;
+
+  /**
+   * 是否可选:1=是,0=否
+   */
+  isOptional: string;
+
+  /**
+   * 属性录入方式(1=下拉,2=文本输入,3=多选等)
+   */
+  entryMethod: string;
+
+  /**
+   * 是否用于商品筛选:1=是,0=否
+   */
+  isFilter: string;
+
+  /**
+   * 预定义属性值列表(逗号分隔或JSON)
+   */
+  attributesList: string;
+
+  /**
+   * 是否必填: 1=是, 0=否
+   */
+  required: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface AttributesForm extends BaseEntity {
+  /**
+   * 主键,自增ID
+   */
+  id?: string | number;
+
+  /**
+   * 关联的产品分类id
+   */
+  categoryId?: string | number;
+
+  /**
+   * 属性编码(用于系统识别)
+   */
+  productAttributesCode?: string;
+
+  /**
+   * 属性显示名称
+   */
+  productAttributesName?: string;
+
+  /**
+   * 是否可选:1=是,0=否
+   */
+  isOptional?: string;
+
+  /**
+   * 属性录入方式(1=下拉,2=文本输入,3=多选等)
+   */
+  entryMethod?: string;
+
+  /**
+   * 是否用于商品筛选:1=是,0=否
+   */
+  isFilter?: string;
+
+  /**
+   * 预定义属性值列表(逗号分隔或JSON)
+   */
+  attributesList?: string;
+
+  /**
+   * 是否必填: 1=是, 0=否
+   */
+  required?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface AttributesQuery extends PageQuery {
+
+  /**
+   * 关联的产品分类id
+   */
+  categoryId?: string | number;
+
+  /**
+   * 属性编码(用于系统识别)
+   */
+  productAttributesCode?: string;
+
+  /**
+   * 属性显示名称
+   */
+  productAttributesName?: string;
+
+  /**
+   * 是否可选:1=是,0=否
+   */
+  isOptional?: string;
+
+  /**
+   * 属性录入方式(1=下拉,2=文本输入,3=多选等)
+   */
+  entryMethod?: string;
+
+  /**
+   * 是否用于商品筛选:1=是,0=否
+   */
+  isFilter?: string;
+
+  /**
+   * 预定义属性值列表(逗号分隔或JSON)
+   */
+  attributesList?: string;
+
+  /**
+   * 是否必填: 1=是, 0=否
+   */
+  required?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,157 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { BaseVO, BaseForm, BaseQuery } from '@/api/product/base/types';
+import { CategoryQuery, categoryTreeVO, CategoryVO } from '../category/types';
+import { BrandQuery, BrandVO } from '../brand/types';
+import { AttributesVO } from '../attributes/types';
+import { EnsureQuery, EnsureVO } from '../ensure/types';
+import { AfterSalesQuery, AfterSalesVO } from '../afterSales/types';
+import { UnitQuery, UnitVO } from '../unit/types';
+
+/**
+ * 查询产品基础信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listBase = (query?: BaseQuery): AxiosPromise<BaseVO[]> => {
+  return request({
+    url: '/product/base/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品基础信息详细
+ * @param id
+ */
+export const getBase = (id: string | number): AxiosPromise<BaseVO> => {
+  return request({
+    url: '/product/base/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品基础信息
+ * @param data
+ */
+export const addBase = (data: BaseForm) => {
+  return request({
+    url: '/product/base',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品基础信息
+ * @param data
+ */
+export const updateBase = (data: BaseForm) => {
+  return request({
+    url: '/product/base',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品基础信息
+ * @param id
+ */
+export const delBase = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/base/' + id,
+    method: 'delete'
+  });
+};
+
+/**
+ * 获取产品分类树
+ * @param query
+ * @returns {*}
+ */
+export const categoryTree = (query?: CategoryQuery): AxiosPromise<categoryTreeVO[]> => {
+  return request({
+    url: '/product/base/categoryTree',
+    method: 'get',
+    params: query
+  });
+};
+/**
+ * 查询产品分类信息列表
+ * @param query
+ * @returns {*}
+ */
+export const categoryList = (query?: CategoryQuery): AxiosPromise<CategoryVO[]> => {
+  return request({
+    url: '/product/base/categoryList',
+    method: 'get',
+    params: query
+  });
+};
+/**
+ * 查询产品品牌信息列表
+ * @param query
+ * @returns {*}
+ */
+export const brandList = (query?: BrandQuery): AxiosPromise<BrandVO[]> => {
+  return request({
+    url: '/product/base/brandList',
+    method: 'get',
+    params: query
+  });
+};
+/**
+ * 查询产品分类下的属性列表
+ * @param id
+ * @returns {*}
+ */
+export const categoryAttributeList = (id: string | number): AxiosPromise<AttributesVO[]> => {
+  return request({
+    url: '/product/base/getProductAttributeList/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 查询产品服务保障列表
+ * @param query
+ * @returns {*}
+ */
+export const getServiceList = (query?: EnsureQuery): AxiosPromise<EnsureVO[]> => {
+  return request({
+    url: '/product/base/getServiceList',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 获取售后服务信息列表
+ * @param query
+ * @returns {*}
+ */
+export const getAfterSaleList = (query?: AfterSalesQuery): AxiosPromise<AfterSalesVO[]> => {
+  return request({
+    url: '/product/base/getAfterSalesList',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 获取单位信息列表
+ * @param query
+ * @returns {*}
+ */
+export const getUnitList = (query?: UnitQuery): AxiosPromise<UnitVO[]> => {
+  return request({
+    url: '/product/base/getUnitList',
+    method: 'get',
+    params: query
+  });
+};
+

+ 670 - 0
src/api/product/base/types.ts

@@ -0,0 +1,670 @@
+export interface BaseVO {
+  /**
+   * 主键,自增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;
+
+  /**
+   * 产品审核状态 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=下架等
+   */
+  productStatus: string;
+
+  /**
+   * 数据来源
+   */
+  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;
+
+}
+
+export interface BaseForm extends BaseEntity {
+  /**
+   * 主键,自增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;
+
+  /**
+   * 是否自营(1=是,0=否)
+   */
+  isSelf?: string;
+
+  /**
+   * 产品审核状态 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=下架等
+   */
+  productStatus?: string;
+
+  /**
+   * 数据来源
+   */
+  dataSource?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+  /**
+   * 款号
+   */
+  styleNo?: string;
+
+  /**
+   * A10产品名称
+   */
+  a10ProductName?: string;
+
+  /**
+   * 规格型号
+   */
+  specification?: string;
+
+  /**
+   * UPC(S)条码
+   */
+  upcBarcode?: string;
+
+  /**
+   * 发票名称
+   */
+  invoiceName?: string;
+
+  /**
+   * 发票规格
+   */
+  invoiceSpec?: string;
+
+  /**
+   * 产品品牌
+   */
+  productBrand?: string;
+
+  /**
+   * 段号
+   */
+  sectionNo?: string;
+
+  /**
+   * 包装规格
+   */
+  packagingSpec?: string;
+
+  /**
+   * 采用基准
+   */
+  adoptionStandard?: string;
+
+  /**
+   * 采品性质
+   */
+  purchaseNature?: string;
+
+  /**
+   * 参考链接
+   */
+  referenceLink?: string;
+
+  /**
+   * 商品重量
+   */
+  weight?: string;
+
+  /**
+   * 重量单位
+   */
+  weightUnit?: string;
+
+  /**
+   * 商品体积
+   */
+  volume?: string;
+
+  /**
+   * 体积单位
+   */
+  volumeUnit?: 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;
+
+  /**
+   * 是否可定制
+   */
+  customizable?: boolean;
+
+  /**
+   * 定制方式(逗号分隔)
+   */
+  customizedStyle?: string;
+
+  /**
+   * 定制工艺(逗号分隔)
+   */
+  customizedCraft?: string;
+
+  /**
+   * 定制说明
+   */
+  customDescription?: string;
+
+  /**
+   * 定制详情列表(JSON字符串)
+   */
+  customDetailsJson?: string;
+
+  /**
+   * 销售量/销量人气
+   */
+  salesVolume?: number;
+
+}
+
+export interface BaseQuery extends PageQuery {
+
+  /**
+   * 产品编号
+   */
+  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;
+
+  /**
+   * 是否自营(1=是,0=否)
+   */
+  isSelf?: string;
+
+  /**
+   * 产品审核状态 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=下架等
+   */
+  productStatus?: string | number;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+  /**
+   * 商品标签
+   */
+  productTag?: string;
+
+  /**
+   * 采购性质
+   */
+  purchaseNature?: string;
+
+  /**
+   * 供应商类型
+   */
+  supplierType?: string;
+
+  /**
+   * 供应商性质
+   */
+  supplierNature?: string;
+
+  /**
+   * 项目组织
+   */
+  projectOrg?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { BlacklistVO, BlacklistForm, BlacklistQuery } from '@/api/product/blacklist/types';
+
+/**
+ * 查询产品黑名单列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listBlacklist = (query?: BlacklistQuery): AxiosPromise<BlacklistVO[]> => {
+  return request({
+    url: '/product/blacklist/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品黑名单详细
+ * @param id
+ */
+export const getBlacklist = (id: string | number): AxiosPromise<BlacklistVO> => {
+  return request({
+    url: '/product/blacklist/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品黑名单
+ * @param data
+ */
+export const addBlacklist = (data: BlacklistForm) => {
+  return request({
+    url: '/product/blacklist',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品黑名单
+ * @param data
+ */
+export const updateBlacklist = (data: BlacklistForm) => {
+  return request({
+    url: '/product/blacklist',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品黑名单
+ * @param id
+ */
+export const delBlacklist = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/blacklist/' + id,
+    method: 'delete'
+  });
+};

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

@@ -0,0 +1,86 @@
+export interface BlacklistVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 客户id(可为空,表示全局黑名单)
+   */
+  customerId: string | number;
+
+  /**
+   * 产品id(可为空,表示该客户对整个分类禁用)
+   */
+  productId: string | number;
+
+  /**
+   * 产品分类id(必填)
+   */
+  productCategoryId: string | number;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface BlacklistForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 客户id(可为空,表示全局黑名单)
+   */
+  customerId?: string | number;
+
+  /**
+   * 产品id(可为空,表示该客户对整个分类禁用)
+   */
+  productId?: string | number;
+
+  /**
+   * 产品分类id(必填)
+   */
+  productCategoryId?: string | number;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface BlacklistQuery extends PageQuery {
+
+  /**
+   * 客户id(可为空,表示全局黑名单)
+   */
+  customerId?: string | number;
+
+  /**
+   * 产品id(可为空,表示该客户对整个分类禁用)
+   */
+  productId?: string | number;
+
+  /**
+   * 产品分类id(必填)
+   */
+  productCategoryId?: string | number;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { BrandVO, BrandForm, BrandQuery } from '@/api/product/brand/types';
+
+/**
+ * 查询产品品牌信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listBrand = (query?: BrandQuery): AxiosPromise<BrandVO[]> => {
+  return request({
+    url: '/product/brand/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品品牌信息详细
+ * @param id
+ */
+export const getBrand = (id: string | number): AxiosPromise<BrandVO> => {
+  return request({
+    url: '/product/brand/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品品牌信息
+ * @param data
+ */
+export const addBrand = (data: BrandForm) => {
+  return request({
+    url: '/product/brand',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品品牌信息
+ * @param data
+ */
+export const updateBrand = (data: BrandForm) => {
+  return request({
+    url: '/product/brand',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品品牌信息
+ * @param id
+ */
+export const delBrand = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/brand/' + id,
+    method: 'delete'
+  });
+};

+ 315 - 0
src/api/product/brand/types.ts

@@ -0,0 +1,315 @@
+export interface BrandVO {
+  /**
+   * 主键
+   */
+  id: string | number;
+
+  /**
+   * 品牌编号(唯一标识)
+   */
+  brandNo: string;
+
+  /**
+   * 品牌中文名称
+   */
+  brandName: string;
+
+  /**
+   * 品牌首字母缩写(如拼音首字母)
+   */
+  brandInitials: string;
+
+  /**
+   * 品牌英文名称
+   */
+  brandEnglishName: string;
+
+  /**
+   * 推荐值(数值越大越靠前)
+   */
+  recommendValue: number;
+
+  /**
+   * 品牌Logo图片路径或URL
+   */
+  brandLogo: string;
+
+  /**
+   * 品牌标题(用于展示)
+   */
+  brandTitle: string;
+
+  /**
+   * 品牌大图(横幅/封面图)
+   */
+  brandBigImage: string;
+
+  /**
+   * 品牌大图(横幅/封面图)Url
+   */
+  brandBigImageUrl: string;
+  /**
+   * 品牌故事(简介文本)
+   */
+  brandStory: string;
+
+  /**
+   * 是否显示(1=显示,0=隐藏)
+   */
+  isShow: number;
+
+  /**
+   * 品牌注册人
+   */
+  brandRegistrant: string;
+
+  /**
+   * 许可证编号
+   */
+  license: string;
+
+  /**
+   * 注册证书编号
+   */
+  registrationCertificate: string;
+
+  /**
+   * 证书/许可过期时间
+   */
+  expireTime: string;
+
+  /**
+   * 品牌描述(较长文本)
+   */
+  brandDescribe: string;
+
+  /**
+   * 展示位置(如首页、分类页等)
+   */
+  position: string;
+
+  /**
+   * 关注度/收藏数(默认为0)
+   */
+  care: number;
+
+  /**
+   * 数据来源
+   */
+  dataSource: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface BrandForm extends BaseEntity {
+  /**
+   * 主键
+   */
+  id?: string | number;
+
+  /**
+   * 品牌编号(唯一标识)
+   */
+  brandNo?: string;
+
+  /**
+   * 品牌中文名称
+   */
+  brandName?: string;
+
+  /**
+   * 品牌首字母缩写(如拼音首字母)
+   */
+  brandInitials?: string;
+
+  /**
+   * 品牌英文名称
+   */
+  brandEnglishName?: string;
+
+  /**
+   * 推荐值(数值越大越靠前)
+   */
+  recommendValue?: number;
+
+  /**
+   * 品牌Logo图片路径或URL
+   */
+  brandLogo?: string;
+
+  /**
+   * 品牌标题(用于展示)
+   */
+  brandTitle?: string;
+
+  /**
+   * 品牌大图(横幅/封面图)
+   */
+  brandBigImage?: string;
+
+  /**
+   * 品牌故事(简介文本)
+   */
+  brandStory?: string;
+
+  /**
+   * 是否显示(1=显示,0=隐藏)
+   */
+  isShow?: number;
+
+  /**
+   * 品牌注册人
+   */
+  brandRegistrant?: string;
+
+  /**
+   * 许可证编号
+   */
+  license?: string;
+
+  /**
+   * 注册证书编号
+   */
+  registrationCertificate?: string;
+
+  /**
+   * 证书/许可过期时间
+   */
+  expireTime?: string;
+
+  /**
+   * 品牌描述(较长文本)
+   */
+  brandDescribe?: string;
+
+  /**
+   * 展示位置(如首页、分类页等)
+   */
+  position?: string;
+
+  /**
+   * 关注度/收藏数(默认为0)
+   */
+  care?: number;
+
+  /**
+   * 数据来源
+   */
+  dataSource?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface BrandQuery extends PageQuery {
+
+  /**
+   * 品牌编号(唯一标识)
+   */
+  brandNo?: string;
+
+  /**
+   * 品牌中文名称
+   */
+  brandName?: string;
+
+  /**
+   * 品牌首字母缩写(如拼音首字母)
+   */
+  brandInitials?: string;
+
+  /**
+   * 品牌英文名称
+   */
+  brandEnglishName?: string;
+
+  /**
+   * 推荐值(数值越大越靠前)
+   */
+  recommendValue?: number;
+
+  /**
+   * 品牌Logo图片路径或URL
+   */
+  brandLogo?: string;
+
+  /**
+   * 品牌标题(用于展示)
+   */
+  brandTitle?: string;
+
+  /**
+   * 品牌大图(横幅/封面图)
+   */
+  brandBigImage?: string;
+
+  /**
+   * 品牌故事(简介文本)
+   */
+  brandStory?: string;
+
+  /**
+   * 是否显示(1=显示,0=隐藏)
+   */
+  isShow?: number;
+
+  /**
+   * 品牌注册人
+   */
+  brandRegistrant?: string;
+
+  /**
+   * 许可证编号
+   */
+  license?: string;
+
+  /**
+   * 注册证书编号
+   */
+  registrationCertificate?: string;
+
+  /**
+   * 证书/许可过期时间
+   */
+  expireTime?: string;
+
+  /**
+   * 品牌描述(较长文本)
+   */
+  brandDescribe?: string;
+
+  /**
+   * 展示位置(如首页、分类页等)
+   */
+  position?: string;
+
+  /**
+   * 关注度/收藏数(默认为0)
+   */
+  care?: number;
+
+  /**
+   * 数据来源
+   */
+  dataSource?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { CategoryVO, CategoryForm, CategoryQuery } from '@/api/product/category/types';
+
+/**
+ * 查询产品分类列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listCategory = (query?: CategoryQuery): AxiosPromise<CategoryVO[]> => {
+  return request({
+    url: '/product/category/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品分类详细
+ * @param id
+ */
+export const getCategory = (id: string | number): AxiosPromise<CategoryVO> => {
+  return request({
+    url: '/product/category/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品分类
+ * @param data
+ */
+export const addCategory = (data: CategoryForm) => {
+  return request({
+    url: '/product/category',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品分类
+ * @param data
+ */
+export const updateCategory = (data: CategoryForm) => {
+  return request({
+    url: '/product/category',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品分类
+ * @param id
+ */
+export const delCategory = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/category/' + id,
+    method: 'delete'
+  });
+};

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

@@ -0,0 +1,383 @@
+export interface CategoryVO {
+  /**
+   * 主键
+   */
+  id: string | number;
+
+  /**
+   * 分类编号
+   */
+  categoryNo: string;
+
+  /**
+   * 分类名称
+   */
+  categoryName: string;
+
+  /**
+   * 父级分类ID
+   */
+  parentId: string | number;
+
+  /**
+   * 祖籍列表
+   */
+  ancestors: string;
+
+  /**
+   * 分类层级(1=一级,2=二级, 3三级)
+   */
+  classLevel: number;
+
+  /**
+   * 是否显示(1=显示,0=隐藏)
+   */
+  isShow: number;
+
+  /**
+   * 是否在GPS中显示
+   */
+  isShowGps: number;
+
+  /**
+   * 折扣率(可能为JSON或文本)
+   */
+  discountRate: number;
+
+  /**
+   * 拼音码(用于快速检索)
+   */
+  pyCode: string;
+
+  /**
+   * 分类描述
+   */
+  classDescription: string;
+
+  /**
+   * 数据来源
+   */
+  dataSource: string;
+
+  /**
+   * 自定义标签1
+   */
+  oneLable1: string;
+
+  /**
+   * 自定义标签2
+   */
+  oneLable2: string;
+
+  /**
+   * 自定义链接1
+   */
+  oneLink1: string;
+
+  /**
+   * 自定义链接2
+   */
+  oneLink2: string;
+
+  /**
+   * 排序值,默认为0
+   */
+  sort: number;
+
+  /**
+   * 颜色(如CSS颜色值)
+   */
+  color: string;
+
+  /**
+   * 采购编号
+   */
+  purchaseNo: string;
+
+  /**
+   * 采购名称
+   */
+  purchaseName: string;
+
+  /**
+   * 采购负责人编号
+   */
+  purchaseManagerNo: string;
+
+  /**
+   * 采购负责人姓名
+   */
+  purchaseManagerName: string;
+
+  /**
+   * 所属平台(0=Web, 1=小程序)
+   */
+  platform: number;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface CategoryForm extends BaseEntity {
+  /**
+   * 主键
+   */
+  id?: string | number;
+
+  /**
+   * 分类编号
+   */
+  categoryNo?: string;
+
+  /**
+   * 分类名称
+   */
+  categoryName?: string;
+
+  /**
+   * 父级分类ID
+   */
+  parentId?: string | number;
+
+  /**
+   * 祖籍列表
+   */
+  ancestors?: string;
+
+  /**
+   * 分类层级(1=一级,2=二级, 3三级)
+   */
+  classLevel?: number;
+
+  /**
+   * 是否显示(1=显示,0=隐藏)
+   */
+  isShow?: number;
+
+  /**
+   * 是否在GPS中显示
+   */
+  isShowGps?: number;
+
+  /**
+   * 折扣率(可能为JSON或文本)
+   */
+  discountRate?: number;
+
+  /**
+   * 拼音码(用于快速检索)
+   */
+  pyCode?: string;
+
+  /**
+   * 分类描述
+   */
+  classDescription?: string;
+
+  /**
+   * 数据来源
+   */
+  dataSource?: string;
+
+  /**
+   * 自定义标签1
+   */
+  oneLable1?: string;
+
+  /**
+   * 自定义标签2
+   */
+  oneLable2?: string;
+
+  /**
+   * 自定义链接1
+   */
+  oneLink1?: string;
+
+  /**
+   * 自定义链接2
+   */
+  oneLink2?: string;
+
+  /**
+   * 排序值,默认为0
+   */
+  sort?: number;
+
+  /**
+   * 颜色(如CSS颜色值)
+   */
+  color?: string;
+
+  /**
+   * 采购编号
+   */
+  purchaseNo?: string;
+
+  /**
+   * 采购名称
+   */
+  purchaseName?: string;
+
+  /**
+   * 采购负责人编号
+   */
+  purchaseManagerNo?: string;
+
+  /**
+   * 采购负责人姓名
+   */
+  purchaseManagerName?: string;
+
+  /**
+   * 所属平台(0=Web, 1=小程序)
+   */
+  platform?: number;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface CategoryQuery extends PageQuery {
+
+  /**
+   * 分类编号
+   */
+  categoryNo?: string;
+
+  /**
+   * 分类名称
+   */
+  categoryName?: string;
+
+  /**
+   * 父级分类ID
+   */
+  parentId?: string | number;
+
+  /**
+   * 祖籍列表
+   */
+  ancestors?: string;
+
+  /**
+   * 分类层级(1=一级,2=二级, 3三级)
+   */
+  classLevel?: number;
+
+  /**
+   * 是否显示(1=显示,0=隐藏)
+   */
+  isShow?: number;
+
+  /**
+   * 是否在GPS中显示
+   */
+  isShowGps?: number;
+
+  /**
+   * 折扣率(可能为JSON或文本)
+   */
+  discountRate?: number;
+
+  /**
+   * 拼音码(用于快速检索)
+   */
+  pyCode?: string;
+
+  /**
+   * 分类描述
+   */
+  classDescription?: string;
+
+  /**
+   * 数据来源
+   */
+  dataSource?: string;
+
+  /**
+   * 自定义标签1
+   */
+  oneLable1?: string;
+
+  /**
+   * 自定义标签2
+   */
+  oneLable2?: string;
+
+  /**
+   * 自定义链接1
+   */
+  oneLink1?: string;
+
+  /**
+   * 自定义链接2
+   */
+  oneLink2?: string;
+
+  /**
+   * 排序值,默认为0
+   */
+  sort?: number;
+
+  /**
+   * 颜色(如CSS颜色值)
+   */
+  color?: string;
+
+  /**
+   * 采购编号
+   */
+  purchaseNo?: string;
+
+  /**
+   * 采购名称
+   */
+  purchaseName?: string;
+
+  /**
+   * 采购负责人编号
+   */
+  purchaseManagerNo?: string;
+
+  /**
+   * 采购负责人姓名
+   */
+  purchaseManagerName?: string;
+
+  /**
+   * 所属平台(0=Web, 1=小程序)
+   */
+  platform?: number;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+/**
+ * 部门类型
+ */
+export interface categoryTreeVO extends BaseEntity {
+  id: number | string;
+  label: string;
+  parentId: number | string;
+  weight: number;
+  children: categoryTreeVO[];
+  isShow: '';
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ClassificationVO, ClassificationForm, ClassificationQuery } from '@/api/product/classification/types';
+
+/**
+ * 查询产品属性关联列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listClassification = (query?: ClassificationQuery): AxiosPromise<ClassificationVO[]> => {
+  return request({
+    url: '/product/classification/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品属性关联详细
+ * @param id
+ */
+export const getClassification = (id: string | number): AxiosPromise<ClassificationVO> => {
+  return request({
+    url: '/product/classification/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品属性关联
+ * @param data
+ */
+export const addClassification = (data: ClassificationForm) => {
+  return request({
+    url: '/product/classification',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品属性关联
+ * @param data
+ */
+export const updateClassification = (data: ClassificationForm) => {
+  return request({
+    url: '/product/classification',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品属性关联
+ * @param id
+ */
+export const delClassification = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/classification/' + id,
+    method: 'delete'
+  });
+};

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

@@ -0,0 +1,86 @@
+export interface ClassificationVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 产品id
+   */
+  productId: string | number;
+
+  /**
+   * 分类编号
+   */
+  categoryId: string | number;
+
+  /**
+   * 属性列表(JSON或分号分隔等格式)
+   */
+  attributesList: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface ClassificationForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 产品id
+   */
+  productId?: string | number;
+
+  /**
+   * 分类编号
+   */
+  categoryId?: string | number;
+
+  /**
+   * 属性列表(JSON或分号分隔等格式)
+   */
+  attributesList?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface ClassificationQuery extends PageQuery {
+
+  /**
+   * 产品id
+   */
+  productId?: string | number;
+
+  /**
+   * 分类编号
+   */
+  categoryId?: string | number;
+
+  /**
+   * 属性列表(JSON或分号分隔等格式)
+   */
+  attributesList?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { CustomizationVO, CustomizationForm, CustomizationQuery } from '@/api/product/customization/types';
+
+/**
+ * 查询产品定制信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listCustomization = (query?: CustomizationQuery): AxiosPromise<CustomizationVO[]> => {
+  return request({
+    url: '/product/customization/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品定制信息详细
+ * @param id
+ */
+export const getCustomization = (id: string | number): AxiosPromise<CustomizationVO> => {
+  return request({
+    url: '/product/customization/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品定制信息
+ * @param data
+ */
+export const addCustomization = (data: CustomizationForm) => {
+  return request({
+    url: '/product/customization',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品定制信息
+ * @param data
+ */
+export const updateCustomization = (data: CustomizationForm) => {
+  return request({
+    url: '/product/customization',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品定制信息
+ * @param id
+ */
+export const delCustomization = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/customization/' + id,
+    method: 'delete'
+  });
+};

+ 161 - 0
src/api/product/customization/types.ts

@@ -0,0 +1,161 @@
+export interface CustomizationVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 定制编号
+   */
+  customizationNo: string;
+
+  /**
+   * 产品id
+   */
+  productId: string | number;
+
+  /**
+   * 定制方式  支持多选,分隔  (0=包装定制,1=商品定制,2=开模定制)
+   */
+  customizedStyle: string;
+
+  /**
+   * 定制工艺  支持多选,分隔  (0=丝印,1=热转印,2=激光,烤花,压印)
+   */
+  customizedCraft: string;
+
+  /**
+   * 打样周期(天)
+   */
+  proofingPeriod: number;
+
+  /**
+   * 生产周期(天)
+   */
+  productionCycle: number;
+
+  /**
+   * 最小起订量(MOQ)
+   */
+  moq: number;
+
+  /**
+   * MOQ对应价格
+   */
+  moqPrice: number;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface CustomizationForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 定制编号
+   */
+  customizationNo?: string;
+
+  /**
+   * 产品id
+   */
+  productId?: string | number;
+
+  /**
+   * 定制方式  支持多选,分隔  (0=包装定制,1=商品定制,2=开模定制)
+   */
+  customizedStyle?: string;
+
+  /**
+   * 定制工艺  支持多选,分隔  (0=丝印,1=热转印,2=激光,烤花,压印)
+   */
+  customizedCraft?: string;
+
+  /**
+   * 打样周期(天)
+   */
+  proofingPeriod?: number;
+
+  /**
+   * 生产周期(天)
+   */
+  productionCycle?: number;
+
+  /**
+   * 最小起订量(MOQ)
+   */
+  moq?: number;
+
+  /**
+   * MOQ对应价格
+   */
+  moqPrice?: number;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface CustomizationQuery extends PageQuery {
+
+  /**
+   * 定制编号
+   */
+  customizationNo?: string;
+
+  /**
+   * 产品id
+   */
+  productId?: string | number;
+
+  /**
+   * 定制方式  支持多选,分隔  (0=包装定制,1=商品定制,2=开模定制)
+   */
+  customizedStyle?: string;
+
+  /**
+   * 定制工艺  支持多选,分隔  (0=丝印,1=热转印,2=激光,烤花,压印)
+   */
+  customizedCraft?: string;
+
+  /**
+   * 打样周期(天)
+   */
+  proofingPeriod?: number;
+
+  /**
+   * 生产周期(天)
+   */
+  productionCycle?: number;
+
+  /**
+   * 最小起订量(MOQ)
+   */
+  moq?: number;
+
+  /**
+   * MOQ对应价格
+   */
+  moqPrice?: number;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { EnsureVO, EnsureForm, EnsureQuery } from '@/api/product/ensure/types';
+
+/**
+ * 查询产品保障项列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listEnsure = (query?: EnsureQuery): AxiosPromise<EnsureVO[]> => {
+  return request({
+    url: '/product/ensure/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品保障项详细
+ * @param id
+ */
+export const getEnsure = (id: string | number): AxiosPromise<EnsureVO> => {
+  return request({
+    url: '/product/ensure/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品保障项
+ * @param data
+ */
+export const addEnsure = (data: EnsureForm) => {
+  return request({
+    url: '/product/ensure',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品保障项
+ * @param data
+ */
+export const updateEnsure = (data: EnsureForm) => {
+  return request({
+    url: '/product/ensure',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品保障项
+ * @param id
+ */
+export const delEnsure = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/ensure/' + id,
+    method: 'delete'
+  });
+};

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

@@ -0,0 +1,71 @@
+export interface EnsureVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 保障名称(如:正品保证、售后保障等)
+   */
+  ensureName: string;
+
+  /**
+   * 数据来源(如:系统配置、接口同步等)
+   */
+  dataSource: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface EnsureForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 保障名称(如:正品保证、售后保障等)
+   */
+  ensureName?: string;
+
+  /**
+   * 数据来源(如:系统配置、接口同步等)
+   */
+  dataSource?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface EnsureQuery extends PageQuery {
+
+  /**
+   * 保障名称(如:正品保证、售后保障等)
+   */
+  ensureName?: string;
+
+  /**
+   * 数据来源(如:系统配置、接口同步等)
+   */
+  dataSource?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ExtendVO, ExtendForm, ExtendQuery } from '@/api/product/extend/types';
+
+/**
+ * 查询产品扩展属性(低频访问字段)列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listExtend = (query?: ExtendQuery): AxiosPromise<ExtendVO[]> => {
+  return request({
+    url: '/product/extend/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品扩展属性(低频访问字段)详细
+ * @param productId
+ */
+export const getExtend = (productId: string | number): AxiosPromise<ExtendVO> => {
+  return request({
+    url: '/product/extend/' + productId,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品扩展属性(低频访问字段)
+ * @param data
+ */
+export const addExtend = (data: ExtendForm) => {
+  return request({
+    url: '/product/extend',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品扩展属性(低频访问字段)
+ * @param data
+ */
+export const updateExtend = (data: ExtendForm) => {
+  return request({
+    url: '/product/extend',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品扩展属性(低频访问字段)
+ * @param productId
+ */
+export const delExtend = (productId: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/extend/' + productId,
+    method: 'delete'
+  });
+};

+ 626 - 0
src/api/product/extend/types.ts

@@ -0,0 +1,626 @@
+export interface ExtendVO {
+  /**
+   * 关联 product_base.id
+   */
+  productId: string | number;
+
+  /**
+   * 促销标题
+   */
+  promotionTitle: string;
+
+  /**
+   * 发票名称
+   */
+  invoiceName: string;
+
+  /**
+   * 发票类型
+   */
+  invoiceType: string;
+
+  /**
+   * 规格代码
+   */
+  specificationsCode: string;
+
+  /**
+   * 条形码
+   */
+  barCoding: string;
+
+  /**
+   * 产品描述
+   */
+  productDescription: string;
+
+  /**
+   * 产品重量
+   */
+  productWeight: string;
+
+  /**
+   * 重量单位
+   */
+  weightUnit: string;
+
+  /**
+   * 产品体积
+   */
+  productVolume: string;
+
+  /**
+   * 体积单位
+   */
+  volumeUnit: string;
+
+  /**
+   * 售后服务
+   */
+  afterSalesService: string;
+
+  /**
+   * 服务保障  支持多选,分隔 (0=无忧退货,1=快速退款,2=免费包邮,3正品保障)
+   */
+  serviceGuarantee: string;
+
+  /**
+   * 是否安装服务:1=是,0=否
+   */
+  isInstallService: string;
+
+  /**
+   * 安装费用
+   */
+  installAmount: string;
+
+  /**
+   * 分销价格
+   */
+  distributionPrice: string;
+
+  /**
+   * 标准尺寸
+   */
+  standardSizes: string;
+
+  /**
+   * 克重
+   */
+  gramWeight: string;
+
+  /**
+   * 透明度
+   */
+  opacity: string;
+
+  /**
+   * 是否可定制:1=是,0=否
+   */
+  isCustomize: string;
+
+  /**
+   * 定制描述
+   */
+  customDescription: string;
+
+  /**
+   * 产品利润
+   */
+  productProfit: string;
+
+  /**
+   * 报告需求
+   */
+  reportRequire: string;
+
+  /**
+   * 审核评论
+   */
+  reviewComments: string;
+
+  /**
+   * 供应商编号
+   */
+  supplierNo: string;
+
+  /**
+   * 推送状态
+   */
+  pushStatus: string;
+
+  /**
+   * 数据来源
+   */
+  dataSource: string;
+
+  /**
+   * 发票规格
+   */
+  invoiceSpecs: string;
+
+  /**
+   * 增量
+   */
+  increment: number;
+
+  /**
+   * 采购编号
+   */
+  purchaseNo: string;
+
+  /**
+   * 采购名称
+   */
+  purchaseName: string;
+
+  /**
+   * 供应商名称
+   */
+  supplierName: string;
+
+  /**
+   * 采购经理编号
+   */
+  purchaseManagerNo: string;
+
+  /**
+   * 采购经理姓名
+   */
+  purchaseManagerName: string;
+
+  /**
+   * 参考链接
+   */
+  referenceLink: string;
+
+  /**
+   * 销售量
+   */
+  salesVolume: number;
+
+  /**
+   * 发货时效
+   */
+  deliveryTime: string;
+
+  /**
+   * PIT时间
+   */
+  pitTime: string;
+
+  /**
+   * 创建时的供应商标识
+   */
+  createSupplier: string;
+
+  /**
+   * 其他补充信息
+   */
+  otherInfo: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface ExtendForm extends BaseEntity {
+  /**
+   * 关联 product_base.id
+   */
+  productId?: string | number;
+
+  /**
+   * 促销标题
+   */
+  promotionTitle?: string;
+
+  /**
+   * 发票名称
+   */
+  invoiceName?: string;
+
+  /**
+   * 发票类型
+   */
+  invoiceType?: string;
+
+  /**
+   * 规格代码
+   */
+  specificationsCode?: string;
+
+  /**
+   * 条形码
+   */
+  barCoding?: string;
+
+  /**
+   * 产品描述
+   */
+  productDescription?: string;
+
+  /**
+   * 产品重量
+   */
+  productWeight?: string;
+
+  /**
+   * 重量单位
+   */
+  weightUnit?: string;
+
+  /**
+   * 产品体积
+   */
+  productVolume?: string;
+
+  /**
+   * 体积单位
+   */
+  volumeUnit?: string;
+
+  /**
+   * 售后服务
+   */
+  afterSalesService?: string;
+
+  /**
+   * 服务保障  支持多选,分隔 (0=无忧退货,1=快速退款,2=免费包邮,3正品保障)
+   */
+  serviceGuarantee?: string;
+
+  /**
+   * 是否安装服务:1=是,0=否
+   */
+  isInstallService?: string;
+
+  /**
+   * 安装费用
+   */
+  installAmount?: string;
+
+  /**
+   * 分销价格
+   */
+  distributionPrice?: string;
+
+  /**
+   * 标准尺寸
+   */
+  standardSizes?: string;
+
+  /**
+   * 克重
+   */
+  gramWeight?: string;
+
+  /**
+   * 透明度
+   */
+  opacity?: string;
+
+  /**
+   * 是否可定制:1=是,0=否
+   */
+  isCustomize?: string;
+
+  /**
+   * 定制描述
+   */
+  customDescription?: string;
+
+  /**
+   * 产品利润
+   */
+  productProfit?: string;
+
+  /**
+   * 报告需求
+   */
+  reportRequire?: string;
+
+  /**
+   * 审核评论
+   */
+  reviewComments?: string;
+
+  /**
+   * 供应商编号
+   */
+  supplierNo?: string;
+
+  /**
+   * 推送状态
+   */
+  pushStatus?: string;
+
+  /**
+   * 数据来源
+   */
+  dataSource?: string;
+
+  /**
+   * 发票规格
+   */
+  invoiceSpecs?: string;
+
+  /**
+   * 增量
+   */
+  increment?: number;
+
+  /**
+   * 采购编号
+   */
+  purchaseNo?: string;
+
+  /**
+   * 采购名称
+   */
+  purchaseName?: string;
+
+  /**
+   * 供应商名称
+   */
+  supplierName?: string;
+
+  /**
+   * 采购经理编号
+   */
+  purchaseManagerNo?: string;
+
+  /**
+   * 采购经理姓名
+   */
+  purchaseManagerName?: string;
+
+  /**
+   * 参考链接
+   */
+  referenceLink?: string;
+
+  /**
+   * 销售量
+   */
+  salesVolume?: number;
+
+  /**
+   * 发货时效
+   */
+  deliveryTime?: string;
+
+  /**
+   * PIT时间
+   */
+  pitTime?: string;
+
+  /**
+   * 创建时的供应商标识
+   */
+  createSupplier?: string;
+
+  /**
+   * 其他补充信息
+   */
+  otherInfo?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface ExtendQuery extends PageQuery {
+
+  /**
+   * 促销标题
+   */
+  promotionTitle?: string;
+
+  /**
+   * 发票名称
+   */
+  invoiceName?: string;
+
+  /**
+   * 发票类型
+   */
+  invoiceType?: string;
+
+  /**
+   * 规格代码
+   */
+  specificationsCode?: string;
+
+  /**
+   * 条形码
+   */
+  barCoding?: string;
+
+  /**
+   * 产品描述
+   */
+  productDescription?: string;
+
+  /**
+   * 产品重量
+   */
+  productWeight?: string;
+
+  /**
+   * 重量单位
+   */
+  weightUnit?: string;
+
+  /**
+   * 产品体积
+   */
+  productVolume?: string;
+
+  /**
+   * 体积单位
+   */
+  volumeUnit?: string;
+
+  /**
+   * 售后服务
+   */
+  afterSalesService?: string;
+
+  /**
+   * 服务保障  支持多选,分隔 (0=无忧退货,1=快速退款,2=免费包邮,3正品保障)
+   */
+  serviceGuarantee?: string;
+
+  /**
+   * 是否安装服务:1=是,0=否
+   */
+  isInstallService?: string;
+
+  /**
+   * 安装费用
+   */
+  installAmount?: string;
+
+  /**
+   * 分销价格
+   */
+  distributionPrice?: string;
+
+  /**
+   * 标准尺寸
+   */
+  standardSizes?: string;
+
+  /**
+   * 克重
+   */
+  gramWeight?: string;
+
+  /**
+   * 透明度
+   */
+  opacity?: string;
+
+  /**
+   * 是否可定制:1=是,0=否
+   */
+  isCustomize?: string;
+
+  /**
+   * 定制描述
+   */
+  customDescription?: string;
+
+  /**
+   * 产品利润
+   */
+  productProfit?: string;
+
+  /**
+   * 报告需求
+   */
+  reportRequire?: string;
+
+  /**
+   * 审核评论
+   */
+  reviewComments?: string;
+
+  /**
+   * 供应商编号
+   */
+  supplierNo?: string;
+
+  /**
+   * 推送状态
+   */
+  pushStatus?: string;
+
+  /**
+   * 数据来源
+   */
+  dataSource?: string;
+
+  /**
+   * 发票规格
+   */
+  invoiceSpecs?: string;
+
+  /**
+   * 增量
+   */
+  increment?: number;
+
+  /**
+   * 采购编号
+   */
+  purchaseNo?: string;
+
+  /**
+   * 采购名称
+   */
+  purchaseName?: string;
+
+  /**
+   * 供应商名称
+   */
+  supplierName?: string;
+
+  /**
+   * 采购经理编号
+   */
+  purchaseManagerNo?: string;
+
+  /**
+   * 采购经理姓名
+   */
+  purchaseManagerName?: string;
+
+  /**
+   * 参考链接
+   */
+  referenceLink?: string;
+
+  /**
+   * 销售量
+   */
+  salesVolume?: number;
+
+  /**
+   * 发货时效
+   */
+  deliveryTime?: string;
+
+  /**
+   * PIT时间
+   */
+  pitTime?: string;
+
+  /**
+   * 创建时的供应商标识
+   */
+  createSupplier?: string;
+
+  /**
+   * 其他补充信息
+   */
+  otherInfo?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { LableVO, LableForm, LableQuery } from '@/api/product/lable/types';
+
+/**
+ * 查询产品标签信息(注意:名疑似拼写错误,应为 product_label)列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listLable = (query?: LableQuery): AxiosPromise<LableVO[]> => {
+  return request({
+    url: '/product/lable/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品标签信息(注意:名疑似拼写错误,应为 product_label)详细
+ * @param id
+ */
+export const getLable = (id: string | number): AxiosPromise<LableVO> => {
+  return request({
+    url: '/product/lable/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品标签信息(注意:名疑似拼写错误,应为 product_label)
+ * @param data
+ */
+export const addLable = (data: LableForm) => {
+  return request({
+    url: '/product/lable',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品标签信息(注意:名疑似拼写错误,应为 product_label)
+ * @param data
+ */
+export const updateLable = (data: LableForm) => {
+  return request({
+    url: '/product/lable',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品标签信息(注意:名疑似拼写错误,应为 product_label)
+ * @param id
+ */
+export const delLable = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/lable/' + id,
+    method: 'delete'
+  });
+};

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

@@ -0,0 +1,86 @@
+export interface LableVO {
+  /**
+   * 主键,自增ID
+   */
+  id: string | number;
+
+  /**
+   * 产品标签编号(如:NEW2025、HOT、VIP_ONLY 等)
+   */
+  productLabelNo: string;
+
+  /**
+   * 标签显示名称(如:新品、热销、限时优惠)
+   */
+  productLabelName: string;
+
+  /**
+   * 使用该标签的产品数量(可用于统计或缓存)
+   */
+  productQuantity: number;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface LableForm extends BaseEntity {
+  /**
+   * 主键,自增ID
+   */
+  id?: string | number;
+
+  /**
+   * 产品标签编号(如:NEW2025、HOT、VIP_ONLY 等)
+   */
+  productLabelNo?: string;
+
+  /**
+   * 标签显示名称(如:新品、热销、限时优惠)
+   */
+  productLabelName?: string;
+
+  /**
+   * 使用该标签的产品数量(可用于统计或缓存)
+   */
+  productQuantity?: number;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface LableQuery extends PageQuery {
+
+  /**
+   * 产品标签编号(如:NEW2025、HOT、VIP_ONLY 等)
+   */
+  productLabelNo?: string;
+
+  /**
+   * 标签显示名称(如:新品、热销、限时优惠)
+   */
+  productLabelName?: string;
+
+  /**
+   * 使用该标签的产品数量(可用于统计或缓存)
+   */
+  productQuantity?: number;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { PoolVO, PoolForm, PoolQuery } from '@/api/product/pool/types';
+
+/**
+ * 查询产品池列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listPool = (query?: PoolQuery): AxiosPromise<PoolVO[]> => {
+  return request({
+    url: '/product/pool/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品池详细
+ * @param id
+ */
+export const getPool = (id: string | number): AxiosPromise<PoolVO> => {
+  return request({
+    url: '/product/pool/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品池
+ * @param data
+ */
+export const addPool = (data: PoolForm) => {
+  return request({
+    url: '/product/pool',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品池
+ * @param data
+ */
+export const updatePool = (data: PoolForm) => {
+  return request({
+    url: '/product/pool',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品池
+ * @param id
+ */
+export const delPool = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/pool/' + id,
+    method: 'delete'
+  });
+};

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

@@ -0,0 +1,116 @@
+export interface PoolVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 池编码
+   */
+  poolNo: string;
+
+  /**
+   * 池名称
+   */
+  name: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow: string;
+
+  /**
+   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  productReviewStatus: string;
+
+  /**
+   * 审核原因
+   */
+  reviewReason: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface PoolForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 池编码
+   */
+  poolNo?: string;
+
+  /**
+   * 池名称
+   */
+  name?: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow?: string;
+
+  /**
+   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  productReviewStatus?: string;
+
+  /**
+   * 审核原因
+   */
+  reviewReason?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface PoolQuery extends PageQuery {
+
+  /**
+   * 池编码
+   */
+  poolNo?: string;
+
+  /**
+   * 池名称
+   */
+  name?: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow?: string;
+
+  /**
+   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  productReviewStatus?: string;
+
+  /**
+   * 审核原因
+   */
+  reviewReason?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { PoolLinkVO, PoolLinkForm, PoolLinkQuery } from '@/api/product/poolLink/types';
+
+/**
+ * 查询产品池和产品关联列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listPoolLink = (query?: PoolLinkQuery): AxiosPromise<PoolLinkVO[]> => {
+  return request({
+    url: '/product/poolLink/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品池和产品关联详细
+ * @param id
+ */
+export const getPoolLink = (id: string | number): AxiosPromise<PoolLinkVO> => {
+  return request({
+    url: '/product/poolLink/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品池和产品关联
+ * @param data
+ */
+export const addPoolLink = (data: PoolLinkForm) => {
+  return request({
+    url: '/product/poolLink',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品池和产品关联
+ * @param data
+ */
+export const updatePoolLink = (data: PoolLinkForm) => {
+  return request({
+    url: '/product/poolLink',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品池和产品关联
+ * @param id
+ */
+export const delPoolLink = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/poolLink/' + id,
+    method: 'delete'
+  });
+};

+ 146 - 0
src/api/product/poolLink/types.ts

@@ -0,0 +1,146 @@
+export interface PoolLinkVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 所属池ID
+   */
+  poolId: string | number;
+
+  /**
+   * 产品id
+   */
+  productId: string | number;
+
+  /**
+   * 产品价格
+   */
+  productPrice: number;
+
+  /**
+   * 是否在池中:1-是,0-否
+   */
+  isPoolStatus: string;
+
+  /**
+   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  productReviewStatus: string;
+
+  /**
+   * 审核原因
+   */
+  reviewReason: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface PoolLinkForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 所属池ID
+   */
+  poolId?: string | number;
+
+  /**
+   * 产品id
+   */
+  productId?: string | number;
+
+  /**
+   * 产品价格
+   */
+  productPrice?: number;
+
+  /**
+   * 是否在池中:1-是,0-否
+   */
+  isPoolStatus?: string;
+
+  /**
+   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  productReviewStatus?: string;
+
+  /**
+   * 审核原因
+   */
+  reviewReason?: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface PoolLinkQuery extends PageQuery {
+
+  /**
+   * 所属池ID
+   */
+  poolId?: string | number;
+
+  /**
+   * 产品id
+   */
+  productId?: string | number;
+
+  /**
+   * 产品价格
+   */
+  productPrice?: number;
+
+  /**
+   * 是否在池中:1-是,0-否
+   */
+  isPoolStatus?: string;
+
+  /**
+   * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
+   */
+  productReviewStatus?: string;
+
+  /**
+   * 审核原因
+   */
+  reviewReason?: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { PriceInventoryVO, PriceInventoryForm, PriceInventoryQuery } from '@/api/product/priceInventory/types';
+
+/**
+ * 查询产品价格与库存信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listPriceInventory = (query?: PriceInventoryQuery): AxiosPromise<PriceInventoryVO[]> => {
+  return request({
+    url: '/product/priceInventory/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品价格与库存信息详细
+ * @param productId
+ */
+export const getPriceInventory = (productId: string | number): AxiosPromise<PriceInventoryVO> => {
+  return request({
+    url: '/product/priceInventory/' + productId,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品价格与库存信息
+ * @param data
+ */
+export const addPriceInventory = (data: PriceInventoryForm) => {
+  return request({
+    url: '/product/priceInventory',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品价格与库存信息
+ * @param data
+ */
+export const updatePriceInventory = (data: PriceInventoryForm) => {
+  return request({
+    url: '/product/priceInventory',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品价格与库存信息
+ * @param productId
+ */
+export const delPriceInventory = (productId: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/priceInventory/' + productId,
+    method: 'delete'
+  });
+};

+ 206 - 0
src/api/product/priceInventory/types.ts

@@ -0,0 +1,206 @@
+export interface PriceInventoryVO {
+  /**
+   * 关联 product_base.id
+   */
+  productId: string | number;
+
+  /**
+   * 市场价格
+   */
+  marketPrice: number;
+
+  /**
+   * 会员价格
+   */
+  memberPrice: number;
+
+  /**
+   * 最低销售价格
+   */
+  minSellingPrice: number;
+
+  /**
+   * 采购价格
+   */
+  purchasingPrice: number;
+
+  /**
+   * 最高采购价格
+   */
+  maxPurchasePrice: number;
+
+  /**
+   * 总库存量
+   */
+  totalInventory: number;
+
+  /**
+   * 当前可用库存
+   */
+  nowInventory: number;
+
+  /**
+   * 虚拟库存
+   */
+  virtualInventory: number;
+
+  /**
+   * 最小起订数量
+   */
+  minOrderQuantity: number;
+
+  /**
+   * 税率
+   */
+  taxRate: number;
+
+  /**
+   * 货币类型
+   */
+  currency: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface PriceInventoryForm extends BaseEntity {
+  /**
+   * 关联 product_base.id
+   */
+  productId?: string | number;
+
+  /**
+   * 市场价格
+   */
+  marketPrice?: number;
+
+  /**
+   * 会员价格
+   */
+  memberPrice?: number;
+
+  /**
+   * 最低销售价格
+   */
+  minSellingPrice?: number;
+
+  /**
+   * 采购价格
+   */
+  purchasingPrice?: number;
+
+  /**
+   * 最高采购价格
+   */
+  maxPurchasePrice?: number;
+
+  /**
+   * 总库存量
+   */
+  totalInventory?: number;
+
+  /**
+   * 当前可用库存
+   */
+  nowInventory?: number;
+
+  /**
+   * 虚拟库存
+   */
+  virtualInventory?: number;
+
+  /**
+   * 最小起订数量
+   */
+  minOrderQuantity?: number;
+
+  /**
+   * 税率
+   */
+  taxRate?: number;
+
+  /**
+   * 货币类型
+   */
+  currency?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface PriceInventoryQuery extends PageQuery {
+
+  /**
+   * 市场价格
+   */
+  marketPrice?: number;
+
+  /**
+   * 会员价格
+   */
+  memberPrice?: number;
+
+  /**
+   * 最低销售价格
+   */
+  minSellingPrice?: number;
+
+  /**
+   * 采购价格
+   */
+  purchasingPrice?: number;
+
+  /**
+   * 最高采购价格
+   */
+  maxPurchasePrice?: number;
+
+  /**
+   * 总库存量
+   */
+  totalInventory?: number;
+
+  /**
+   * 当前可用库存
+   */
+  nowInventory?: number;
+
+  /**
+   * 虚拟库存
+   */
+  virtualInventory?: number;
+
+  /**
+   * 最小起订数量
+   */
+  minOrderQuantity?: number;
+
+  /**
+   * 税率
+   */
+  taxRate?: number;
+
+  /**
+   * 货币类型
+   */
+  currency?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ProgramVO, ProgramForm, ProgramQuery } from '@/api/product/program/types';
+
+/**
+ * 查询产品解决方案/项目方案列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listProgram = (query?: ProgramQuery): AxiosPromise<ProgramVO[]> => {
+  return request({
+    url: '/product/program/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品解决方案/项目方案详细
+ * @param id
+ */
+export const getProgram = (id: string | number): AxiosPromise<ProgramVO> => {
+  return request({
+    url: '/product/program/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品解决方案/项目方案
+ * @param data
+ */
+export const addProgram = (data: ProgramForm) => {
+  return request({
+    url: '/product/program',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品解决方案/项目方案
+ * @param data
+ */
+export const updateProgram = (data: ProgramForm) => {
+  return request({
+    url: '/product/program',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品解决方案/项目方案
+ * @param id
+ */
+export const delProgram = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/program/' + id,
+    method: 'delete'
+  });
+};

+ 210 - 0
src/api/product/program/types.ts

@@ -0,0 +1,210 @@
+export interface ProgramVO {
+  /**
+   * 主键,自增ID
+   */
+  id: string | number;
+
+  /**
+   * 方案编号(唯一标识)
+   */
+  programNo: string;
+
+  /**
+   * 方案标题
+   */
+  title: string;
+
+  /**
+   * 方案描述(注意:字段名为 SQL 关键字,建议未来重命名为 description)
+   */
+  describe: string;
+
+  /**
+   * 所属分类编号或名称
+   */
+  category: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow: string;
+
+  /**
+   * 封面图片URL(可存储较长路径)
+   */
+  coverImage: string;
+
+  /**
+   * 封面图片URL(可存储较长路径)Url
+   */
+  coverImageUrl: string;
+  /**
+   * 方案内容(如简介、详情等)
+   */
+  content: string;
+
+  /**
+   * 所属行业编号或名称
+   */
+  industry: string;
+
+  /**
+   * 适配产品/设备编号
+   */
+  adaptNo: string;
+
+  /**
+   * 标签
+   */
+  label: string;
+
+  /**
+   * 内部广告内容(如 Banner 文案或链接)
+   */
+  innerAdvert: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface ProgramForm extends BaseEntity {
+  /**
+   * 主键,自增ID
+   */
+  id?: string | number;
+
+  /**
+   * 方案编号(唯一标识)
+   */
+  programNo?: string;
+
+  /**
+   * 方案标题
+   */
+  title?: string;
+
+  /**
+   * 方案描述(注意:字段名为 SQL 关键字,建议未来重命名为 description)
+   */
+  describe?: string;
+
+  /**
+   * 所属分类编号或名称
+   */
+  category?: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow?: string;
+
+  /**
+   * 封面图片URL(可存储较长路径)
+   */
+  coverImage?: string;
+
+  /**
+   * 方案内容(如简介、详情等)
+   */
+  content?: string;
+
+  /**
+   * 所属行业编号或名称
+   */
+  industry?: string;
+
+  /**
+   * 适配产品/设备编号
+   */
+  adaptNo?: string;
+
+  /**
+   * 标签
+   */
+  label?: string;
+
+  /**
+   * 内部广告内容(如 Banner 文案或链接)
+   */
+  innerAdvert?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface ProgramQuery extends PageQuery {
+
+  /**
+   * 方案编号(唯一标识)
+   */
+  programNo?: string;
+
+  /**
+   * 方案标题
+   */
+  title?: string;
+
+  /**
+   * 方案描述(注意:字段名为 SQL 关键字,建议未来重命名为 description)
+   */
+  describe?: string;
+
+  /**
+   * 所属分类编号或名称
+   */
+  category?: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow?: string;
+
+  /**
+   * 封面图片URL(可存储较长路径)
+   */
+  coverImage?: string;
+
+  /**
+   * 方案内容(如简介、详情等)
+   */
+  content?: string;
+
+  /**
+   * 所属行业编号或名称
+   */
+  industry?: string;
+
+  /**
+   * 适配产品/设备编号
+   */
+  adaptNo?: string;
+
+  /**
+   * 标签
+   */
+  label?: string;
+
+  /**
+   * 内部广告内容(如 Banner 文案或链接)
+   */
+  innerAdvert?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ProgramLinkVO, ProgramLinkForm, ProgramLinkQuery } from '@/api/product/programLink/types';
+
+/**
+ * 查询项目方案关联列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listProgramLink = (query?: ProgramLinkQuery): AxiosPromise<ProgramLinkVO[]> => {
+  return request({
+    url: '/product/programLink/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询项目方案关联详细
+ * @param id
+ */
+export const getProgramLink = (id: string | number): AxiosPromise<ProgramLinkVO> => {
+  return request({
+    url: '/product/programLink/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增项目方案关联
+ * @param data
+ */
+export const addProgramLink = (data: ProgramLinkForm) => {
+  return request({
+    url: '/product/programLink',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改项目方案关联
+ * @param data
+ */
+export const updateProgramLink = (data: ProgramLinkForm) => {
+  return request({
+    url: '/product/programLink',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除项目方案关联
+ * @param id
+ */
+export const delProgramLink = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/programLink/' + id,
+    method: 'delete'
+  });
+};

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

@@ -0,0 +1,71 @@
+export interface ProgramLinkVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 项目编号
+   */
+  programId: string | number;
+
+  /**
+   * 产品编号
+   */
+  productId: string | number;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface ProgramLinkForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 项目编号
+   */
+  programId?: string | number;
+
+  /**
+   * 产品编号
+   */
+  productId?: string | number;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface ProgramLinkQuery extends PageQuery {
+
+  /**
+   * 项目编号
+   */
+  programId?: string | number;
+
+  /**
+   * 产品编号
+   */
+  productId?: string | number;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { RecommendVO, RecommendForm, RecommendQuery } from '@/api/product/recommend/types';
+
+/**
+ * 查询产品推荐位配置列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listRecommend = (query?: RecommendQuery): AxiosPromise<RecommendVO[]> => {
+  return request({
+    url: '/product/recommend/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品推荐位配置详细
+ * @param id
+ */
+export const getRecommend = (id: string | number): AxiosPromise<RecommendVO> => {
+  return request({
+    url: '/product/recommend/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品推荐位配置
+ * @param data
+ */
+export const addRecommend = (data: RecommendForm) => {
+  return request({
+    url: '/product/recommend',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品推荐位配置
+ * @param data
+ */
+export const updateRecommend = (data: RecommendForm) => {
+  return request({
+    url: '/product/recommend',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品推荐位配置
+ * @param id
+ */
+export const delRecommend = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/recommend/' + id,
+    method: 'delete'
+  });
+};

+ 116 - 0
src/api/product/recommend/types.ts

@@ -0,0 +1,116 @@
+export interface RecommendVO {
+  /**
+   * 主键,自增ID
+   */
+  id: string | number;
+
+  /**
+   * 推荐编号(唯一标识)
+   */
+  recommendNo: string;
+
+  /**
+   * 推荐名称(如:首页爆款、新品专区等)
+   */
+  recommendName: string;
+
+  /**
+   * 推荐位描述(用于后台说明或前端提示)
+   */
+  recommendDescribe: string;
+
+  /**
+   * 是否显示:1=显示,0=隐藏
+   */
+  isShow: string;
+
+  /**
+   * 推荐封面图片路径或URL
+   */
+  recommendCoverphoto: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface RecommendForm extends BaseEntity {
+  /**
+   * 主键,自增ID
+   */
+  id?: string | number;
+
+  /**
+   * 推荐编号(唯一标识)
+   */
+  recommendNo?: string;
+
+  /**
+   * 推荐名称(如:首页爆款、新品专区等)
+   */
+  recommendName?: string;
+
+  /**
+   * 推荐位描述(用于后台说明或前端提示)
+   */
+  recommendDescribe?: string;
+
+  /**
+   * 是否显示:1=显示,0=隐藏
+   */
+  isShow?: string;
+
+  /**
+   * 推荐封面图片路径或URL
+   */
+  recommendCoverphoto?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface RecommendQuery extends PageQuery {
+
+  /**
+   * 推荐编号(唯一标识)
+   */
+  recommendNo?: string;
+
+  /**
+   * 推荐名称(如:首页爆款、新品专区等)
+   */
+  recommendName?: string;
+
+  /**
+   * 推荐位描述(用于后台说明或前端提示)
+   */
+  recommendDescribe?: string;
+
+  /**
+   * 是否显示:1=显示,0=隐藏
+   */
+  isShow?: string;
+
+  /**
+   * 推荐封面图片路径或URL
+   */
+  recommendCoverphoto?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { RecommendLinkVO, RecommendLinkForm, RecommendLinkQuery } from '@/api/product/recommendLink/types';
+
+/**
+ * 查询产品推荐关联列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listRecommendLink = (query?: RecommendLinkQuery): AxiosPromise<RecommendLinkVO[]> => {
+  return request({
+    url: '/product/recommendLink/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品推荐关联详细
+ * @param id
+ */
+export const getRecommendLink = (id: string | number): AxiosPromise<RecommendLinkVO> => {
+  return request({
+    url: '/product/recommendLink/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品推荐关联
+ * @param data
+ */
+export const addRecommendLink = (data: RecommendLinkForm) => {
+  return request({
+    url: '/product/recommendLink',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品推荐关联
+ * @param data
+ */
+export const updateRecommendLink = (data: RecommendLinkForm) => {
+  return request({
+    url: '/product/recommendLink',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品推荐关联
+ * @param id
+ */
+export const delRecommendLink = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/recommendLink/' + id,
+    method: 'delete'
+  });
+};

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

@@ -0,0 +1,71 @@
+export interface RecommendLinkVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 项目编号
+   */
+  recommendId: string | number;
+
+  /**
+   * 产品编号
+   */
+  productId: string | number;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface RecommendLinkForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 项目编号
+   */
+  recommendId?: string | number;
+
+  /**
+   * 产品编号
+   */
+  productId?: string | number;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface RecommendLinkQuery extends PageQuery {
+
+  /**
+   * 项目编号
+   */
+  recommendId?: string | number;
+
+  /**
+   * 产品编号
+   */
+  productId?: string | number;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { SpecsVO, SpecsForm, SpecsQuery } from '@/api/product/specs/types';
+
+/**
+ * 查询产品规格关联列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listSpecs = (query?: SpecsQuery): AxiosPromise<SpecsVO[]> => {
+  return request({
+    url: '/product/specs/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品规格关联详细
+ * @param id
+ */
+export const getSpecs = (id: string | number): AxiosPromise<SpecsVO> => {
+  return request({
+    url: '/product/specs/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品规格关联
+ * @param data
+ */
+export const addSpecs = (data: SpecsForm) => {
+  return request({
+    url: '/product/specs',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品规格关联
+ * @param data
+ */
+export const updateSpecs = (data: SpecsForm) => {
+  return request({
+    url: '/product/specs',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品规格关联
+ * @param id
+ */
+export const delSpecs = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/specs/' + id,
+    method: 'delete'
+  });
+};

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

@@ -0,0 +1,86 @@
+export interface SpecsVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 主产品编号
+   */
+  productId: string | number;
+
+  /**
+   * 关联的规格产品id列表(如:逗号分隔的产品id)
+   */
+  specsProductIds: string | number;
+
+  /**
+   * 是否单向关联:0=双向,1=单向
+   */
+  isUnidirectional: string | number;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface SpecsForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 主产品编号
+   */
+  productId?: string | number;
+
+  /**
+   * 关联的规格产品id列表(如:逗号分隔的产品id)
+   */
+  specsProductIds?: string | number;
+
+  /**
+   * 是否单向关联:0=双向,1=单向
+   */
+  isUnidirectional?: string | number;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface SpecsQuery extends PageQuery {
+
+  /**
+   * 主产品编号
+   */
+  productId?: string | number;
+
+  /**
+   * 关联的规格产品id列表(如:逗号分隔的产品id)
+   */
+  specsProductIds?: string | number;
+
+  /**
+   * 是否单向关联:0=双向,1=单向
+   */
+  isUnidirectional?: string | number;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { TaxrateVO, TaxrateForm, TaxrateQuery } from '@/api/product/taxrate/types';
+
+/**
+ * 查询产品税率配置列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listTaxrate = (query?: TaxrateQuery): AxiosPromise<TaxrateVO[]> => {
+  return request({
+    url: '/product/taxrate/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品税率配置详细
+ * @param id
+ */
+export const getTaxrate = (id: string | number): AxiosPromise<TaxrateVO> => {
+  return request({
+    url: '/product/taxrate/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品税率配置
+ * @param data
+ */
+export const addTaxrate = (data: TaxrateForm) => {
+  return request({
+    url: '/product/taxrate',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品税率配置
+ * @param data
+ */
+export const updateTaxrate = (data: TaxrateForm) => {
+  return request({
+    url: '/product/taxrate',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品税率配置
+ * @param id
+ */
+export const delTaxrate = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/taxrate/' + id,
+    method: 'delete'
+  });
+};

+ 116 - 0
src/api/product/taxrate/types.ts

@@ -0,0 +1,116 @@
+export interface TaxrateVO {
+  /**
+   * 主键,自增ID
+   */
+  id: string | number;
+
+  /**
+   * 税率编号
+   */
+  taxrateNo: string;
+
+  /**
+   * 税率名称
+   */
+  taxrateName: string;
+
+  /**
+   * 税率值)
+   */
+  taxrate: number;
+
+  /**
+   * 数据来源
+   */
+  dataSource: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface TaxrateForm extends BaseEntity {
+  /**
+   * 主键,自增ID
+   */
+  id?: string | number;
+
+  /**
+   * 税率编号
+   */
+  taxrateNo?: string;
+
+  /**
+   * 税率名称
+   */
+  taxrateName?: string;
+
+  /**
+   * 税率值)
+   */
+  taxrate?: number;
+
+  /**
+   * 数据来源
+   */
+  dataSource?: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface TaxrateQuery extends PageQuery {
+
+  /**
+   * 税率编号
+   */
+  taxrateNo?: string;
+
+  /**
+   * 税率名称
+   */
+  taxrateName?: string;
+
+  /**
+   * 税率值)
+   */
+  taxrate?: number;
+
+  /**
+   * 数据来源
+   */
+  dataSource?: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { UnitVO, UnitForm, UnitQuery } from '@/api/product/unit/types';
+
+/**
+ * 查询产品计量单位列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listUnit = (query?: UnitQuery): AxiosPromise<UnitVO[]> => {
+  return request({
+    url: '/product/unit/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品计量单位详细
+ * @param id
+ */
+export const getUnit = (id: string | number): AxiosPromise<UnitVO> => {
+  return request({
+    url: '/product/unit/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品计量单位
+ * @param data
+ */
+export const addUnit = (data: UnitForm) => {
+  return request({
+    url: '/product/unit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品计量单位
+ * @param data
+ */
+export const updateUnit = (data: UnitForm) => {
+  return request({
+    url: '/product/unit',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品计量单位
+ * @param id
+ */
+export const delUnit = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/unit/' + id,
+    method: 'delete'
+  });
+};

+ 101 - 0
src/api/product/unit/types.ts

@@ -0,0 +1,101 @@
+export interface UnitVO {
+  /**
+   * 主键,自增ID
+   */
+  id: string | number;
+
+  /**
+   * 单位编号
+   */
+  unitNo: string;
+
+  /**
+   * 单位名称(如:件、箱、千克等)
+   */
+  unitName: string;
+
+  /**
+   * 数据来源
+   */
+  dataSource: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface UnitForm extends BaseEntity {
+  /**
+   * 主键,自增ID
+   */
+  id?: string | number;
+
+  /**
+   * 单位编号
+   */
+  unitNo?: string;
+
+  /**
+   * 单位名称(如:件、箱、千克等)
+   */
+  unitName?: string;
+
+  /**
+   * 数据来源
+   */
+  dataSource?: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface UnitQuery extends PageQuery {
+
+  /**
+   * 单位编号
+   */
+  unitNo?: string;
+
+  /**
+   * 单位名称(如:件、箱、千克等)
+   */
+  unitName?: string;
+
+  /**
+   * 数据来源
+   */
+  dataSource?: string;
+
+  /**
+   * 是否显示:1=是,0=否
+   */
+  isShow?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { VolumeUnitVO, VolumeUnitForm, VolumeUnitQuery } from '@/api/product/volumeUnit/types';
+
+/**
+ * 查询产品体积单位列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listVolumeUnit = (query?: VolumeUnitQuery): AxiosPromise<VolumeUnitVO[]> => {
+  return request({
+    url: '/product/volumeUnit/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品体积单位详细
+ * @param id
+ */
+export const getVolumeUnit = (id: string | number): AxiosPromise<VolumeUnitVO> => {
+  return request({
+    url: '/product/volumeUnit/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品体积单位
+ * @param data
+ */
+export const addVolumeUnit = (data: VolumeUnitForm) => {
+  return request({
+    url: '/product/volumeUnit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品体积单位
+ * @param data
+ */
+export const updateVolumeUnit = (data: VolumeUnitForm) => {
+  return request({
+    url: '/product/volumeUnit',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品体积单位
+ * @param id
+ */
+export const delVolumeUnit = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/volumeUnit/' + id,
+    method: 'delete'
+  });
+};

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

@@ -0,0 +1,71 @@
+export interface VolumeUnitVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 体积单位名称(如:立方米、升、立方厘米等)
+   */
+  unitName: string;
+
+  /**
+   * 数据来源(如:系统配置、接口同步等)
+   */
+  dataSource: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface VolumeUnitForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 体积单位名称(如:立方米、升、立方厘米等)
+   */
+  unitName?: string;
+
+  /**
+   * 数据来源(如:系统配置、接口同步等)
+   */
+  dataSource?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface VolumeUnitQuery extends PageQuery {
+
+  /**
+   * 体积单位名称(如:立方米、升、立方厘米等)
+   */
+  unitName?: string;
+
+  /**
+   * 数据来源(如:系统配置、接口同步等)
+   */
+  dataSource?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { WeightUnitVO, WeightUnitForm, WeightUnitQuery } from '@/api/product/weightUnit/types';
+
+/**
+ * 查询产品重量单位列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listWeightUnit = (query?: WeightUnitQuery): AxiosPromise<WeightUnitVO[]> => {
+  return request({
+    url: '/product/weightUnit/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品重量单位详细
+ * @param id
+ */
+export const getWeightUnit = (id: string | number): AxiosPromise<WeightUnitVO> => {
+  return request({
+    url: '/product/weightUnit/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品重量单位
+ * @param data
+ */
+export const addWeightUnit = (data: WeightUnitForm) => {
+  return request({
+    url: '/product/weightUnit',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品重量单位
+ * @param data
+ */
+export const updateWeightUnit = (data: WeightUnitForm) => {
+  return request({
+    url: '/product/weightUnit',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品重量单位
+ * @param id
+ */
+export const delWeightUnit = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/product/weightUnit/' + id,
+    method: 'delete'
+  });
+};

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

@@ -0,0 +1,71 @@
+export interface WeightUnitVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 重量单位名称(如:千克、克、吨、磅等)
+   */
+  unitName: string;
+
+  /**
+   * 数据来源(如:系统配置、接口同步等)
+   */
+  dataSource: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+
+}
+
+export interface WeightUnitForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 重量单位名称(如:千克、克、吨、磅等)
+   */
+  unitName?: string;
+
+  /**
+   * 数据来源(如:系统配置、接口同步等)
+   */
+  dataSource?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+
+}
+
+export interface WeightUnitQuery extends PageQuery {
+
+  /**
+   * 重量单位名称(如:千克、克、吨、磅等)
+   */
+  unitName?: string;
+
+  /**
+   * 数据来源(如:系统配置、接口同步等)
+   */
+  dataSource?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 1 - 1
src/layout/components/Sidebar/Logo.vue

@@ -20,7 +20,7 @@
       <router-link key="collapse" class="sidebar-logo-link" to="/">
         <!-- <img v-if="logo" :src="logo" class="sidebar-logo" /> -->
         <h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">
-          优易达-OMS订单管理系统
+          优易达-PMS产品管理系统
         </h1>
       </router-link>
     </transition>

+ 20 - 0
src/router/index.ts

@@ -88,6 +88,26 @@ export const constantRoutes: RouteRecordRaw[] = [
         meta: { title: '个人中心', icon: 'user' }
       }
     ]
+  },
+  {
+    path: '/product',
+    component: Layout,
+    hidden: true,
+    redirect: 'noredirect',
+    children: [
+      {
+        path: 'base/add',
+        component: () => import('@/views/product/base/add.vue'),
+        name: 'ProductAdd',
+        meta: { title: '新增商品', activeMenu: '/product/base' }
+      },
+      {
+        path: 'base/edit/:id',
+        component: () => import('@/views/product/base/add.vue'),
+        name: 'ProductEdit',
+        meta: { title: '编辑商品', activeMenu: '/product/base' }
+      }
+    ]
   }
 ];
 

+ 2 - 2
src/views/login.vue

@@ -96,8 +96,8 @@ const { t } = useI18n();
 
 const loginForm = ref<LoginData>({
   tenantId: '000000',
-  username: 'admin',
-  password: 'admin123',
+  username: 'pmsadmin',
+  password: '123456',
   rememberMe: false,
   code: '',
   uuid: ''

+ 235 - 0
src/views/product/afterSales/index.vue

@@ -0,0 +1,235 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="售后服务项目" prop="afterSalesItems">
+              <el-input v-model="queryParams.afterSalesItems" placeholder="请输入售后服务项目" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="数据来源" prop="dataSource">
+              <el-input v-model="queryParams.dataSource" placeholder="请输入数据来源" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:afterSales:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:afterSales:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:afterSales:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:afterSales:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="afterSalesList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="售后服务项目" align="center" prop="afterSalesItems" />
+        <el-table-column label="数据来源" align="center" prop="dataSource" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:afterSales:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:afterSales:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品售后服务项对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="afterSalesFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="售后服务项目" prop="afterSalesItems">
+          <el-input v-model="form.afterSalesItems" placeholder="请输入售后服务项目" />
+        </el-form-item>
+        <el-form-item label="数据来源" prop="dataSource">
+          <el-input v-model="form.dataSource" placeholder="请输入数据来源" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="AfterSales" lang="ts">
+import { listAfterSales, getAfterSales, delAfterSales, addAfterSales, updateAfterSales } from '@/api/product/afterSales';
+import { AfterSalesVO, AfterSalesQuery, AfterSalesForm } from '@/api/product/afterSales/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const afterSalesList = ref<AfterSalesVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const afterSalesFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: AfterSalesForm = {
+  id: undefined,
+  afterSalesItems: undefined,
+  dataSource: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<AfterSalesForm, AfterSalesQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    afterSalesItems: undefined,
+    dataSource: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    afterSalesItems: [
+      { required: true, message: "售后服务项目不能为空", trigger: "blur" }
+    ],
+    dataSource: [
+      { required: true, message: "数据来源不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品售后服务项列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listAfterSales(queryParams.value);
+  afterSalesList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  afterSalesFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: AfterSalesVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品售后服务项";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: AfterSalesVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getAfterSales(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品售后服务项";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  afterSalesFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateAfterSales(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addAfterSales(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: AfterSalesVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品售后服务项编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delAfterSales(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/afterSales/export', {
+    ...queryParams.value
+  }, `afterSales_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 256 - 0
src/views/product/associate/index.vue

@@ -0,0 +1,256 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="主产品id" prop="productId">
+              <el-input v-model="queryParams.productId" placeholder="请输入主产品id" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="关联产品编号列表" prop="productIds">
+              <el-input v-model="queryParams.productIds" placeholder="请输入关联产品编号列表" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否单向关联:0=双向,1=单向" prop="isUnidirectional">
+              <el-input v-model="queryParams.isUnidirectional" placeholder="请输入是否单向关联:0=双向,1=单向" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="关联标题/展示名称" prop="relatedTitle">
+              <el-input v-model="queryParams.relatedTitle" placeholder="请输入关联标题/展示名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:associate:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:associate:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:associate:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:associate:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="associateList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="主产品id" align="center" prop="productId" />
+        <el-table-column label="关联产品编号列表" align="center" prop="productIds" />
+        <el-table-column label="是否单向关联:0=双向,1=单向" align="center" prop="isUnidirectional" />
+        <el-table-column label="关联标题/展示名称" align="center" prop="relatedTitle" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:associate:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:associate:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品关联对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="associateFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="主产品id" prop="productId">
+          <el-input v-model="form.productId" placeholder="请输入主产品id" />
+        </el-form-item>
+        <el-form-item label="关联产品编号列表" prop="productIds">
+            <el-input v-model="form.productIds" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="是否单向关联:0=双向,1=单向" prop="isUnidirectional">
+          <el-input v-model="form.isUnidirectional" placeholder="请输入是否单向关联:0=双向,1=单向" />
+        </el-form-item>
+        <el-form-item label="关联标题/展示名称" prop="relatedTitle">
+          <el-input v-model="form.relatedTitle" placeholder="请输入关联标题/展示名称" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Associate" lang="ts">
+import { listAssociate, getAssociate, delAssociate, addAssociate, updateAssociate } from '@/api/product/associate';
+import { AssociateVO, AssociateQuery, AssociateForm } from '@/api/product/associate/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const associateList = ref<AssociateVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const associateFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: AssociateForm = {
+  id: undefined,
+  productId: undefined,
+  productIds: undefined,
+  isUnidirectional: undefined,
+  relatedTitle: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<AssociateForm, AssociateQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    productId: undefined,
+    productIds: undefined,
+    isUnidirectional: undefined,
+    relatedTitle: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    productId: [
+      { required: true, message: "主产品id不能为空", trigger: "blur" }
+    ],
+    productIds: [
+      { required: true, message: "关联产品编号列表不能为空", trigger: "blur" }
+    ],
+    relatedTitle: [
+      { required: true, message: "关联标题/展示名称不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品关联列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listAssociate(queryParams.value);
+  associateList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  associateFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: AssociateVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品关联";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: AssociateVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getAssociate(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品关联";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  associateFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateAssociate(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addAssociate(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: AssociateVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品关联编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delAssociate(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/associate/export', {
+    ...queryParams.value
+  }, `associate_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 298 - 0
src/views/product/attributes/index.vue

@@ -0,0 +1,298 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="关联的产品分类id" prop="categoryId">
+              <el-input v-model="queryParams.categoryId" placeholder="请输入关联的产品分类id" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="属性编码" prop="productAttributesCode">
+              <el-input v-model="queryParams.productAttributesCode" placeholder="请输入属性编码" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="属性显示名称" prop="productAttributesName">
+              <el-input v-model="queryParams.productAttributesName" placeholder="请输入属性显示名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否可选:1=是,0=否" prop="isOptional">
+              <el-input v-model="queryParams.isOptional" placeholder="请输入是否可选:1=是,0=否" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="属性录入方式" prop="entryMethod">
+              <el-input v-model="queryParams.entryMethod" placeholder="请输入属性录入方式" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否用于商品筛选:1=是,0=否" prop="isFilter">
+              <el-input v-model="queryParams.isFilter" placeholder="请输入是否用于商品筛选:1=是,0=否" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="预定义属性值列表" prop="attributesList">
+              <el-input v-model="queryParams.attributesList" placeholder="请输入预定义属性值列表" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否必填: 1=是, 0=否" prop="required">
+              <el-input v-model="queryParams.required" placeholder="请输入是否必填: 1=是, 0=否" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:attributes:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:attributes:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:attributes:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:attributes:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="attributesList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键,自增ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="关联的产品分类id" align="center" prop="categoryId" />
+        <el-table-column label="属性编码" align="center" prop="productAttributesCode" />
+        <el-table-column label="属性显示名称" align="center" prop="productAttributesName" />
+        <el-table-column label="是否可选:1=是,0=否" align="center" prop="isOptional" />
+        <el-table-column label="属性录入方式" align="center" prop="entryMethod" />
+        <el-table-column label="是否用于商品筛选:1=是,0=否" align="center" prop="isFilter" />
+        <el-table-column label="预定义属性值列表" align="center" prop="attributesList" />
+        <el-table-column label="是否必填: 1=是, 0=否" align="center" prop="required" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:attributes:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:attributes:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品属性定义(用于动态属性配置)对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="attributesFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="关联的产品分类id" prop="categoryId">
+          <el-input v-model="form.categoryId" placeholder="请输入关联的产品分类id" />
+        </el-form-item>
+        <el-form-item label="属性编码" prop="productAttributesCode">
+          <el-input v-model="form.productAttributesCode" placeholder="请输入属性编码" />
+        </el-form-item>
+        <el-form-item label="属性显示名称" prop="productAttributesName">
+          <el-input v-model="form.productAttributesName" placeholder="请输入属性显示名称" />
+        </el-form-item>
+        <el-form-item label="是否可选:1=是,0=否" prop="isOptional">
+          <el-input v-model="form.isOptional" placeholder="请输入是否可选:1=是,0=否" />
+        </el-form-item>
+        <el-form-item label="属性录入方式" prop="entryMethod">
+          <el-input v-model="form.entryMethod" placeholder="请输入属性录入方式" />
+        </el-form-item>
+        <el-form-item label="是否用于商品筛选:1=是,0=否" prop="isFilter">
+          <el-input v-model="form.isFilter" placeholder="请输入是否用于商品筛选:1=是,0=否" />
+        </el-form-item>
+        <el-form-item label="预定义属性值列表" prop="attributesList">
+          <el-input v-model="form.attributesList" placeholder="请输入预定义属性值列表" />
+        </el-form-item>
+        <el-form-item label="是否必填: 1=是, 0=否" prop="required">
+          <el-input v-model="form.required" placeholder="请输入是否必填: 1=是, 0=否" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Attributes" lang="ts">
+import { listAttributes, getAttributes, delAttributes, addAttributes, updateAttributes } from '@/api/product/attributes';
+import { AttributesVO, AttributesQuery, AttributesForm } from '@/api/product/attributes/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const attributesList = ref<AttributesVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const attributesFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: AttributesForm = {
+  id: undefined,
+  categoryId: undefined,
+  productAttributesCode: undefined,
+  productAttributesName: undefined,
+  isOptional: undefined,
+  entryMethod: undefined,
+  isFilter: undefined,
+  attributesList: undefined,
+  required: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<AttributesForm, AttributesQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    categoryId: undefined,
+    productAttributesCode: undefined,
+    productAttributesName: undefined,
+    isOptional: undefined,
+    entryMethod: undefined,
+    isFilter: undefined,
+    attributesList: undefined,
+    required: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    categoryId: [
+      { required: true, message: "关联的产品分类id不能为空", trigger: "blur" }
+    ],
+    productAttributesCode: [
+      { required: true, message: "属性编码不能为空", trigger: "blur" }
+    ],
+    productAttributesName: [
+      { required: true, message: "属性显示名称不能为空", trigger: "blur" }
+    ],
+    attributesList: [
+      { required: true, message: "预定义属性值列表不能为空", trigger: "blur" }
+    ],
+    required: [
+      { required: true, message: "是否必填: 1=是, 0=否不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品属性定义(用于动态属性配置)列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listAttributes(queryParams.value);
+  attributesList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  attributesFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: AttributesVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品属性定义(用于动态属性配置)";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: AttributesVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getAttributes(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品属性定义(用于动态属性配置)";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  attributesFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateAttributes(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addAttributes(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: AttributesVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品属性定义(用于动态属性配置)编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delAttributes(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/attributes/export', {
+    ...queryParams.value
+  }, `attributes_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 471 - 0
src/views/product/base/index.vue

@@ -0,0 +1,471 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" label-width="90px">
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品编号" prop="productNo">
+                  <el-input v-model="queryParams.productNo" placeholder="请输入商品编号" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品名称" prop="itemName">
+                   <el-input v-model="queryParams.itemName" placeholder="请输入商品名称" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品品牌" prop="brandId">
+                  <el-select v-model="queryParams.brandId" placeholder="请选择商品品牌" clearable>
+                    <el-option 
+                      v-for="brand in brandOptions" 
+                      :key="brand.id" 
+                      :label="brand.brandName" 
+                      :value="brand.id" 
+                    />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品来源" prop="purchaseNature">
+                   <el-input v-model="queryParams.itemName" placeholder="请输入商品来源" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20">
+              <el-col :span="6">
+                <el-form-item label="商品分类" prop="bottomCategoryId">
+                  <el-tree-select
+                    v-model="queryParams.bottomCategoryId"
+                    :data="categoryOptions"
+                    :props="{ value: 'id', label: 'label', children: 'children' } as any"
+                    value-key="id"
+                    placeholder="请选择商品分类"
+                    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-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="1" />
+                    <el-option label="审核通过" :value="2" />
+                    <el-option label="审核拒绝" :value="3" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="上下架状态" prop="productStatus">
+                  <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
+                    <el-option label="上架" :value="1" />
+                    <el-option label="下架" :value="0" />
+                  </el-select>
+                </el-form-item>
+              </el-col>
+            </el-row>
+            <el-row>
+              <el-col :span="24" class="text-left">
+                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <!-- 统计信息区域 -->
+    <el-card shadow="never" class="mb-[10px]">
+      <div class="flex items-center text-sm text-gray-600">
+        <span>商品总/已配置数量: </span>
+        <span class="text-blue-600 mx-1">总=<span class="text-red-600">{{ statistics.total }}</span>条,</span>
+        <span>外/已配置数量<span class="text-red-600">{{ statistics.configured }}</span>条,</span>
+        <span>【上架/总数({{ statistics.onShelf }}/{{ statistics.total }})】</span>
+        <span class="mx-2">,审核状态({{ statistics.reviewStatus }}),上架状态({{ statistics.shelfStatus }})</span>
+        <div class="ml-auto flex gap-2">
+          <el-button type="primary" icon="Plus" @click="handleAdd">商品新增</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>
+      </div>
+    </el-card>
+
+    <el-card shadow="never">
+
+      <el-table v-loading="loading" border :data="baseList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="商品编号" align="center" prop="productNo" width="120" fixed="left">
+          <template #default="scope">
+            <el-link type="primary" @click="handleView(scope.row)">{{ scope.row.productNo }}</el-link>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品图片" align="center" prop="productImageUrl" width="100">
+          <template #default="scope">
+            <image-preview :src="scope.row.productImageUrl" :width="60" :height="60"/>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品信息" align="center" width="250" show-overflow-tooltip>
+          <template #default="scope">
+            <div class="text-left">
+              <div>{{ scope.row.itemName }}</div>
+              <div class="text-gray-500" style="font-size: 12px;">品牌: {{ scope.row.brandName || '-' }}</div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品分类" align="center" prop="categoryName" width="120" />
+        <el-table-column label="单位" align="center" prop="unitName" width="80" />
+        <el-table-column label="SKU价格" align="center" width="180">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px;">
+              <div>
+                <span class="text-gray-500">市场价:</span>
+                <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">会员价:</span>
+                <span class="text-red-500">¥{{ scope.row.memberPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">最低价:</span>
+                <span class="text-red-500">¥{{ scope.row.minSellingPrice || '0.00' }}</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="成本情况" align="center" width="150">
+          <template #default="scope">
+            <div class="text-left" style="font-size: 12px;">
+              <div>
+                <span class="text-gray-500">采购价:</span>
+                <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
+              </div>
+              <div>
+                <span class="text-gray-500">暂估毛利率:</span>
+                <span>{{ scope.row.tempGrossMargin || '0.0000' }}%</span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="数据来源" align="center" prop="dataSource" width="100">
+          <template #default="scope">
+            <span>{{ scope.row.dataSource || '-' }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="是否自营" align="center" width="100">
+          <template #default="scope">
+            <el-tag v-if="scope.row.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="100">
+          <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="120">
+          <template #default="scope">
+            <el-tag v-if="scope.row.productStatus === '1'" type="success">上架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === '0'" type="warning">下架</el-tag>
+            <el-tag v-else type="info">未知</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" align="center" width="200" fixed="right">
+          <template #default="scope">
+            <div class="flex flex-col gap-1">
+              <div class="flex gap-1 justify-center">
+                <el-link 
+                  :type="scope.row.productStatus === '1' ? 'warning' : 'success'" 
+                  :underline="false" 
+                  @click="handleShelf(scope.row)">
+                  {{ scope.row.isSelf === '1' ? '取消自营' : '加入自营池' }}
+                </el-link>
+                <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
+                <el-link 
+                  :type="scope.row.productStatus === '1' ? 'warning' : 'success'" 
+                  :underline="false" 
+                  @click="handleShelf(scope.row)">
+                  {{ scope.row.productStatus === '1' ? '下架' : '上架' }}
+                </el-link>
+                <el-link type="primary" :underline="false" @click="handlePrice(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>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+  </div>
+</template>
+
+<script setup name="Base" lang="ts">
+import { listBase, getBase, delBase, brandList, categoryTree } from '@/api/product/base';
+import { BaseVO, BaseQuery, BaseForm } from '@/api/product/base/types';
+import { BrandVO } from '@/api/product/brand/types';
+import { categoryTreeVO } from '@/api/product/category/types';
+import { useRouter } from 'vue-router';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const router = useRouter();
+
+const baseList = ref<BaseVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const brandOptions = ref<BrandVO[]>([]);
+const categoryOptions = ref<categoryTreeVO[]>([]);
+
+// 统计信息
+const statistics = ref({
+  total: 0,
+  configured: 0,
+  onShelf: 0,
+  reviewStatus: '待审核0条',
+  shelfStatus: '上架0条'
+});
+
+const queryFormRef = ref<ElFormInstance>();
+const baseFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: BaseForm = {
+  id: undefined,
+  productNo: undefined,
+  itemName: undefined,
+  brandId: undefined,
+  topCategoryId: undefined,
+  mediumCategoryId: undefined,
+  bottomCategoryId: undefined,
+  unitId: undefined,
+  productImage: undefined,
+  isSelf: undefined,
+  productReviewStatus: undefined,
+  homeRecommended: undefined,
+  categoryRecommendation: undefined,
+  cartRecommendation: undefined,
+  recommendedProductOrder: undefined,
+  isPopular: undefined,
+  isNew: undefined,
+  productStatus: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<BaseForm, BaseQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    productNo: undefined,
+    itemName: undefined,
+    brandId: undefined,
+    productTag: undefined,
+    purchaseNature: undefined,
+    supplierType: undefined,
+    supplierNature: undefined,
+    projectOrg: undefined,
+    topCategoryId: undefined,
+    mediumCategoryId: undefined,
+    bottomCategoryId: undefined,
+    productStatus: undefined,
+    params: {
+    }
+  },
+  rules: {
+    productNo: [
+      { required: true, message: "产品编号不能为空", trigger: "blur" }
+    ],
+    itemName: [
+      { required: true, message: "项目名称不能为空", trigger: "blur" }
+    ],
+    brandId: [
+      { required: true, message: "品牌id不能为空", trigger: "blur" }
+    ],
+    topCategoryId: [
+      { required: true, message: "顶级分类id不能为空", trigger: "blur" }
+    ],
+    mediumCategoryId: [
+      { required: true, message: "中级分类id不能为空", trigger: "blur" }
+    ],
+    bottomCategoryId: [
+      { required: true, message: "底层分类id不能为空", trigger: "blur" }
+    ],
+    unitId: [
+      { required: true, message: "单位id不能为空", trigger: "blur" }
+    ],
+    productImage: [
+      { required: true, message: "产品图片URL不能为空", trigger: "blur" }
+    ],
+    productReviewStatus: [
+      { required: true, message: "产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回不能为空", trigger: "change" }
+    ],
+    homeRecommended: [
+      { required: true, message: "首页推荐:1=推荐,0=不推荐不能为空", trigger: "blur" }
+    ],
+    categoryRecommendation: [
+      { required: true, message: "分类推荐:1=推荐,0=不推荐不能为空", trigger: "blur" }
+    ],
+    cartRecommendation: [
+      { required: true, message: "购物车推荐:1=推荐,0=不推荐不能为空", trigger: "blur" }
+    ],
+    recommendedProductOrder: [
+      { required: true, message: "推荐产品顺序不能为空", trigger: "blur" }
+    ],
+    isPopular: [
+      { required: true, message: "是否热门:1=是,0=否不能为空", trigger: "blur" }
+    ],
+    isNew: [
+      { required: true, message: "是否新品:1=是,0=否不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品基础信息列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listBase(queryParams.value);
+  baseList.value = res.rows;
+  total.value = res.total;
+  
+  // 更新统计信息
+  statistics.value.total = res.total || 0;
+  statistics.value.configured = res.rows?.filter((item: any) => item.isConfigured)?.length || 0;
+  statistics.value.onShelf = res.rows?.filter((item: any) => item.productStatus === '1')?.length || 0;
+  
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  baseFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: BaseVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  router.push('/product/base/add');
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: BaseVO) => {
+  const _id = row?.id || ids.value[0];
+  router.push(`/product/base/edit/${_id}`);
+}
+
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: BaseVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品基础信息编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delBase(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/base/export', {
+    ...queryParams.value
+  }, `base_${new Date().getTime()}.xlsx`)
+}
+
+/** 查看商品详情 */
+const handleView = (row: BaseVO) => {
+  console.log('查看商品', row);
+  // TODO: 实现查看详情逻辑
+}
+
+/** 上下架操作 */
+const handleShelf = async (row: BaseVO) => {
+  const action = row.productStatus === '1' ? '下架' : '上架';
+  await proxy?.$modal.confirm(`确认${action}该商品吗?`);
+  // TODO: 调用上下架API
+  proxy?.$modal.msgSuccess(`${action}成功`);
+  await getList();
+}
+
+/** 价格设置 */
+const handlePrice = (row: BaseVO) => {
+  console.log('设置价格', row);
+  // TODO: 打开价格设置对话框
+}
+
+/** 供货存管理 */
+const handleSupply = (row: BaseVO) => {
+  console.log('供货存管理', row);
+  // TODO: 打开供货存管理对话框
+}
+
+/** 查询品牌列表 */
+const getBrandList = async () => {
+  const res = await brandList();
+  brandOptions.value = res.data || [];
+}
+
+/** 查询分类树 */
+const getCategoryTree = async () => {
+  const res = await categoryTree();
+  categoryOptions.value = res.data || [];
+}
+
+onMounted(() => {
+  getList();
+  getBrandList();
+  getCategoryTree();
+});
+</script>

+ 244 - 0
src/views/product/blacklist/index.vue

@@ -0,0 +1,244 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="客户id" prop="customerId">
+              <el-input v-model="queryParams.customerId" placeholder="请输入客户id" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="产品id" prop="productId">
+              <el-input v-model="queryParams.productId" placeholder="请输入产品id" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="产品分类id" prop="productCategoryId">
+              <el-input v-model="queryParams.productCategoryId" placeholder="请输入产品分类id" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:blacklist:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:blacklist:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:blacklist:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:blacklist:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="blacklistList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="客户id" align="center" prop="customerId" />
+        <el-table-column label="产品id" align="center" prop="productId" />
+        <el-table-column label="产品分类id" align="center" prop="productCategoryId" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:blacklist:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:blacklist:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品黑名单对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="blacklistFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="客户id" prop="customerId">
+          <el-input v-model="form.customerId" placeholder="请输入客户id" />
+        </el-form-item>
+        <el-form-item label="产品id" prop="productId">
+          <el-input v-model="form.productId" placeholder="请输入产品id" />
+        </el-form-item>
+        <el-form-item label="产品分类id" prop="productCategoryId">
+          <el-input v-model="form.productCategoryId" placeholder="请输入产品分类id" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Blacklist" lang="ts">
+import { listBlacklist, getBlacklist, delBlacklist, addBlacklist, updateBlacklist } from '@/api/product/blacklist';
+import { BlacklistVO, BlacklistQuery, BlacklistForm } from '@/api/product/blacklist/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const blacklistList = ref<BlacklistVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const blacklistFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: BlacklistForm = {
+  id: undefined,
+  customerId: undefined,
+  productId: undefined,
+  productCategoryId: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<BlacklistForm, BlacklistQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    customerId: undefined,
+    productId: undefined,
+    productCategoryId: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    customerId: [
+      { required: true, message: "客户id不能为空", trigger: "blur" }
+    ],
+    productId: [
+      { required: true, message: "产品id不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品黑名单列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listBlacklist(queryParams.value);
+  blacklistList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  blacklistFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: BlacklistVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品黑名单";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: BlacklistVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getBlacklist(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品黑名单";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  blacklistFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateBlacklist(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addBlacklist(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: BlacklistVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品黑名单编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delBlacklist(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/blacklist/export', {
+    ...queryParams.value
+  }, `blacklist_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 433 - 0
src/views/product/brand/index.vue

@@ -0,0 +1,433 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="品牌编号" prop="brandNo">
+              <el-input v-model="queryParams.brandNo" placeholder="请输入品牌编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="品牌中文名称" prop="brandName">
+              <el-input v-model="queryParams.brandName" placeholder="请输入品牌中文名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="品牌首字母缩写" prop="brandInitials">
+              <el-input v-model="queryParams.brandInitials" placeholder="请输入品牌首字母缩写" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="品牌英文名称" prop="brandEnglishName">
+              <el-input v-model="queryParams.brandEnglishName" placeholder="请输入品牌英文名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="推荐值" prop="recommendValue">
+              <el-input v-model="queryParams.recommendValue" placeholder="请输入推荐值" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="品牌Logo图片路径或URL" prop="brandLogo">
+              <el-input v-model="queryParams.brandLogo" placeholder="请输入品牌Logo图片路径或URL" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="品牌标题" prop="brandTitle">
+              <el-input v-model="queryParams.brandTitle" placeholder="请输入品牌标题" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="品牌故事" prop="brandStory">
+              <el-input v-model="queryParams.brandStory" placeholder="请输入品牌故事" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否显示" prop="isShow">
+              <el-input v-model="queryParams.isShow" placeholder="请输入是否显示" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="品牌注册人" prop="brandRegistrant">
+              <el-input v-model="queryParams.brandRegistrant" placeholder="请输入品牌注册人" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="许可证编号" prop="license">
+              <el-input v-model="queryParams.license" placeholder="请输入许可证编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="注册证书编号" prop="registrationCertificate">
+              <el-input v-model="queryParams.registrationCertificate" placeholder="请输入注册证书编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="证书/许可过期时间" prop="expireTime">
+              <el-date-picker clearable
+                v-model="queryParams.expireTime"
+                type="date"
+                value-format="YYYY-MM-DD"
+                placeholder="请选择证书/许可过期时间"
+              />
+            </el-form-item>
+            <el-form-item label="品牌描述" prop="brandDescribe">
+              <el-input v-model="queryParams.brandDescribe" placeholder="请输入品牌描述" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="展示位置" prop="position">
+              <el-input v-model="queryParams.position" placeholder="请输入展示位置" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="关注度/收藏数" prop="care">
+              <el-input v-model="queryParams.care" placeholder="请输入关注度/收藏数" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="数据来源" prop="dataSource">
+              <el-input v-model="queryParams.dataSource" placeholder="请输入数据来源" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:brand:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:brand:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:brand:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:brand:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="brandList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键" align="center" prop="id" v-if="true" />
+        <el-table-column label="品牌编号" align="center" prop="brandNo" />
+        <el-table-column label="品牌中文名称" align="center" prop="brandName" />
+        <el-table-column label="品牌首字母缩写" align="center" prop="brandInitials" />
+        <el-table-column label="品牌英文名称" align="center" prop="brandEnglishName" />
+        <el-table-column label="推荐值" align="center" prop="recommendValue" />
+        <el-table-column label="品牌Logo图片路径或URL" align="center" prop="brandLogo" />
+        <el-table-column label="品牌标题" align="center" prop="brandTitle" />
+        <el-table-column label="品牌大图" align="center" prop="brandBigImageUrl" width="100">
+          <template #default="scope">
+            <image-preview :src="scope.row.brandBigImageUrl" :width="50" :height="50"/>
+          </template>
+        </el-table-column>
+        <el-table-column label="品牌故事" align="center" prop="brandStory" />
+        <el-table-column label="是否显示" align="center" prop="isShow" />
+        <el-table-column label="品牌注册人" align="center" prop="brandRegistrant" />
+        <el-table-column label="许可证编号" align="center" prop="license" />
+        <el-table-column label="注册证书编号" align="center" prop="registrationCertificate" />
+        <el-table-column label="证书/许可过期时间" align="center" prop="expireTime" width="180">
+          <template #default="scope">
+            <span>{{ parseTime(scope.row.expireTime, '{y}-{m}-{d}') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="品牌描述" align="center" prop="brandDescribe" />
+        <el-table-column label="展示位置" align="center" prop="position" />
+        <el-table-column label="关注度/收藏数" align="center" prop="care" />
+        <el-table-column label="数据来源" align="center" prop="dataSource" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:brand:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:brand:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品品牌信息对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="brandFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="品牌编号" prop="brandNo">
+          <el-input v-model="form.brandNo" placeholder="请输入品牌编号" />
+        </el-form-item>
+        <el-form-item label="品牌中文名称" prop="brandName">
+          <el-input v-model="form.brandName" placeholder="请输入品牌中文名称" />
+        </el-form-item>
+        <el-form-item label="品牌首字母缩写" prop="brandInitials">
+          <el-input v-model="form.brandInitials" placeholder="请输入品牌首字母缩写" />
+        </el-form-item>
+        <el-form-item label="品牌英文名称" prop="brandEnglishName">
+          <el-input v-model="form.brandEnglishName" placeholder="请输入品牌英文名称" />
+        </el-form-item>
+        <el-form-item label="推荐值" prop="recommendValue">
+          <el-input v-model="form.recommendValue" placeholder="请输入推荐值" />
+        </el-form-item>
+        <el-form-item label="品牌Logo图片路径或URL" prop="brandLogo">
+          <el-input v-model="form.brandLogo" placeholder="请输入品牌Logo图片路径或URL" />
+        </el-form-item>
+        <el-form-item label="品牌标题" prop="brandTitle">
+          <el-input v-model="form.brandTitle" placeholder="请输入品牌标题" />
+        </el-form-item>
+        <el-form-item label="品牌大图" prop="brandBigImage">
+          <image-upload v-model="form.brandBigImage"/>
+        </el-form-item>
+        <el-form-item label="品牌故事" prop="brandStory">
+            <el-input v-model="form.brandStory" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="是否显示" prop="isShow">
+          <el-input v-model="form.isShow" placeholder="请输入是否显示" />
+        </el-form-item>
+        <el-form-item label="品牌注册人" prop="brandRegistrant">
+          <el-input v-model="form.brandRegistrant" placeholder="请输入品牌注册人" />
+        </el-form-item>
+        <el-form-item label="许可证编号" prop="license">
+          <el-input v-model="form.license" placeholder="请输入许可证编号" />
+        </el-form-item>
+        <el-form-item label="注册证书编号" prop="registrationCertificate">
+          <el-input v-model="form.registrationCertificate" placeholder="请输入注册证书编号" />
+        </el-form-item>
+        <el-form-item label="证书/许可过期时间" prop="expireTime">
+          <el-date-picker clearable
+            v-model="form.expireTime"
+            type="datetime"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            placeholder="请选择证书/许可过期时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="品牌描述" prop="brandDescribe">
+            <el-input v-model="form.brandDescribe" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="展示位置" prop="position">
+          <el-input v-model="form.position" placeholder="请输入展示位置" />
+        </el-form-item>
+        <el-form-item label="关注度/收藏数" prop="care">
+          <el-input v-model="form.care" placeholder="请输入关注度/收藏数" />
+        </el-form-item>
+        <el-form-item label="数据来源" prop="dataSource">
+          <el-input v-model="form.dataSource" placeholder="请输入数据来源" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Brand" lang="ts">
+import { listBrand, getBrand, delBrand, addBrand, updateBrand } from '@/api/product/brand';
+import { BrandVO, BrandQuery, BrandForm } from '@/api/product/brand/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const brandList = ref<BrandVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const brandFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: BrandForm = {
+  id: undefined,
+  brandNo: undefined,
+  brandName: undefined,
+  brandInitials: undefined,
+  brandEnglishName: undefined,
+  recommendValue: undefined,
+  brandLogo: undefined,
+  brandTitle: undefined,
+  brandBigImage: undefined,
+  brandStory: undefined,
+  isShow: undefined,
+  brandRegistrant: undefined,
+  license: undefined,
+  registrationCertificate: undefined,
+  expireTime: undefined,
+  brandDescribe: undefined,
+  position: undefined,
+  care: undefined,
+  dataSource: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<BrandForm, BrandQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    brandNo: undefined,
+    brandName: undefined,
+    brandInitials: undefined,
+    brandEnglishName: undefined,
+    recommendValue: undefined,
+    brandLogo: undefined,
+    brandTitle: undefined,
+    brandBigImage: undefined,
+    brandStory: undefined,
+    isShow: undefined,
+    brandRegistrant: undefined,
+    license: undefined,
+    registrationCertificate: undefined,
+    expireTime: undefined,
+    brandDescribe: undefined,
+    position: undefined,
+    care: undefined,
+    dataSource: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    brandInitials: [
+      { required: true, message: "品牌首字母缩写不能为空", trigger: "blur" }
+    ],
+    brandEnglishName: [
+      { required: true, message: "品牌英文名称不能为空", trigger: "blur" }
+    ],
+    recommendValue: [
+      { required: true, message: "推荐值不能为空", trigger: "blur" }
+    ],
+    brandLogo: [
+      { required: true, message: "品牌Logo图片路径或URL不能为空", trigger: "blur" }
+    ],
+    brandTitle: [
+      { required: true, message: "品牌标题不能为空", trigger: "blur" }
+    ],
+    brandBigImage: [
+      { required: true, message: "品牌大图不能为空", trigger: "blur" }
+    ],
+    brandStory: [
+      { required: true, message: "品牌故事不能为空", trigger: "blur" }
+    ],
+    isShow: [
+      { required: true, message: "是否显示不能为空", trigger: "blur" }
+    ],
+    brandRegistrant: [
+      { required: true, message: "品牌注册人不能为空", trigger: "blur" }
+    ],
+    license: [
+      { required: true, message: "许可证编号不能为空", trigger: "blur" }
+    ],
+    registrationCertificate: [
+      { required: true, message: "注册证书编号不能为空", trigger: "blur" }
+    ],
+    expireTime: [
+      { required: true, message: "证书/许可过期时间不能为空", trigger: "blur" }
+    ],
+    brandDescribe: [
+      { required: true, message: "品牌描述不能为空", trigger: "blur" }
+    ],
+    position: [
+      { required: true, message: "展示位置不能为空", trigger: "blur" }
+    ],
+    dataSource: [
+      { required: true, message: "数据来源不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品品牌信息列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listBrand(queryParams.value);
+  brandList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  brandFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: BrandVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品品牌信息";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: BrandVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getBrand(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品品牌信息";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  brandFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateBrand(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addBrand(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: BrandVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品品牌信息编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delBrand(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/brand/export', {
+    ...queryParams.value
+  }, `brand_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 469 - 0
src/views/product/category/index.vue

@@ -0,0 +1,469 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="分类编号" prop="categoryNo">
+              <el-input v-model="queryParams.categoryNo" placeholder="请输入分类编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="分类名称" prop="categoryName">
+              <el-input v-model="queryParams.categoryName" placeholder="请输入分类名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="父级分类ID" prop="parentId">
+              <el-input v-model="queryParams.parentId" placeholder="请输入父级分类ID" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="祖籍列表" prop="ancestors">
+              <el-input v-model="queryParams.ancestors" placeholder="请输入祖籍列表" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="分类层级" prop="classLevel">
+              <el-input v-model="queryParams.classLevel" placeholder="请输入分类层级" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否显示" prop="isShow">
+              <el-input v-model="queryParams.isShow" placeholder="请输入是否显示" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否在GPS中显示" prop="isShowGps">
+              <el-input v-model="queryParams.isShowGps" placeholder="请输入是否在GPS中显示" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="折扣率" prop="discountRate">
+              <el-input v-model="queryParams.discountRate" placeholder="请输入折扣率" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="拼音码" prop="pyCode">
+              <el-input v-model="queryParams.pyCode" placeholder="请输入拼音码" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="分类描述" prop="classDescription">
+              <el-input v-model="queryParams.classDescription" placeholder="请输入分类描述" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="数据来源" prop="dataSource">
+              <el-input v-model="queryParams.dataSource" placeholder="请输入数据来源" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="自定义标签1" prop="oneLable1">
+              <el-input v-model="queryParams.oneLable1" placeholder="请输入自定义标签1" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="自定义标签2" prop="oneLable2">
+              <el-input v-model="queryParams.oneLable2" placeholder="请输入自定义标签2" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="自定义链接1" prop="oneLink1">
+              <el-input v-model="queryParams.oneLink1" placeholder="请输入自定义链接1" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="自定义链接2" prop="oneLink2">
+              <el-input v-model="queryParams.oneLink2" placeholder="请输入自定义链接2" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="排序值,默认为0" prop="sort">
+              <el-input v-model="queryParams.sort" placeholder="请输入排序值,默认为0" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="颜色" prop="color">
+              <el-input v-model="queryParams.color" placeholder="请输入颜色" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="采购编号" prop="purchaseNo">
+              <el-input v-model="queryParams.purchaseNo" placeholder="请输入采购编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="采购名称" prop="purchaseName">
+              <el-input v-model="queryParams.purchaseName" placeholder="请输入采购名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="采购负责人编号" prop="purchaseManagerNo">
+              <el-input v-model="queryParams.purchaseManagerNo" placeholder="请输入采购负责人编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="采购负责人姓名" prop="purchaseManagerName">
+              <el-input v-model="queryParams.purchaseManagerName" placeholder="请输入采购负责人姓名" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="所属平台" prop="platform">
+              <el-input v-model="queryParams.platform" placeholder="请输入所属平台" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:category:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:category:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:category:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:category:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="categoryList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键" align="center" prop="id" v-if="true" />
+        <el-table-column label="分类编号" align="center" prop="categoryNo" />
+        <el-table-column label="分类名称" align="center" prop="categoryName" />
+        <el-table-column label="父级分类ID" align="center" prop="parentId" />
+        <el-table-column label="祖籍列表" align="center" prop="ancestors" />
+        <el-table-column label="分类层级" align="center" prop="classLevel" />
+        <el-table-column label="是否显示" align="center" prop="isShow" />
+        <el-table-column label="是否在GPS中显示" align="center" prop="isShowGps" />
+        <el-table-column label="折扣率" align="center" prop="discountRate" />
+        <el-table-column label="拼音码" align="center" prop="pyCode" />
+        <el-table-column label="分类描述" align="center" prop="classDescription" />
+        <el-table-column label="数据来源" align="center" prop="dataSource" />
+        <el-table-column label="自定义标签1" align="center" prop="oneLable1" />
+        <el-table-column label="自定义标签2" align="center" prop="oneLable2" />
+        <el-table-column label="自定义链接1" align="center" prop="oneLink1" />
+        <el-table-column label="自定义链接2" align="center" prop="oneLink2" />
+        <el-table-column label="排序值,默认为0" align="center" prop="sort" />
+        <el-table-column label="颜色" align="center" prop="color" />
+        <el-table-column label="采购编号" align="center" prop="purchaseNo" />
+        <el-table-column label="采购名称" align="center" prop="purchaseName" />
+        <el-table-column label="采购负责人编号" align="center" prop="purchaseManagerNo" />
+        <el-table-column label="采购负责人姓名" align="center" prop="purchaseManagerName" />
+        <el-table-column label="所属平台" align="center" prop="platform" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:category:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:category:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品分类对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="categoryFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="分类编号" prop="categoryNo">
+          <el-input v-model="form.categoryNo" placeholder="请输入分类编号" />
+        </el-form-item>
+        <el-form-item label="分类名称" prop="categoryName">
+          <el-input v-model="form.categoryName" placeholder="请输入分类名称" />
+        </el-form-item>
+        <el-form-item label="父级分类ID" prop="parentId">
+          <el-input v-model="form.parentId" placeholder="请输入父级分类ID" />
+        </el-form-item>
+        <el-form-item label="祖籍列表" prop="ancestors">
+            <el-input v-model="form.ancestors" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="分类层级" prop="classLevel">
+          <el-input v-model="form.classLevel" placeholder="请输入分类层级" />
+        </el-form-item>
+        <el-form-item label="是否显示" prop="isShow">
+          <el-input v-model="form.isShow" placeholder="请输入是否显示" />
+        </el-form-item>
+        <el-form-item label="是否在GPS中显示" prop="isShowGps">
+          <el-input v-model="form.isShowGps" placeholder="请输入是否在GPS中显示" />
+        </el-form-item>
+        <el-form-item label="折扣率" prop="discountRate">
+          <el-input v-model="form.discountRate" placeholder="请输入折扣率" />
+        </el-form-item>
+        <el-form-item label="拼音码" prop="pyCode">
+            <el-input v-model="form.pyCode" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="分类描述" prop="classDescription">
+            <el-input v-model="form.classDescription" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="数据来源" prop="dataSource">
+          <el-input v-model="form.dataSource" placeholder="请输入数据来源" />
+        </el-form-item>
+        <el-form-item label="自定义标签1" prop="oneLable1">
+          <el-input v-model="form.oneLable1" placeholder="请输入自定义标签1" />
+        </el-form-item>
+        <el-form-item label="自定义标签2" prop="oneLable2">
+          <el-input v-model="form.oneLable2" placeholder="请输入自定义标签2" />
+        </el-form-item>
+        <el-form-item label="自定义链接1" prop="oneLink1">
+          <el-input v-model="form.oneLink1" placeholder="请输入自定义链接1" />
+        </el-form-item>
+        <el-form-item label="自定义链接2" prop="oneLink2">
+          <el-input v-model="form.oneLink2" placeholder="请输入自定义链接2" />
+        </el-form-item>
+        <el-form-item label="排序值,默认为0" prop="sort">
+          <el-input v-model="form.sort" placeholder="请输入排序值,默认为0" />
+        </el-form-item>
+        <el-form-item label="颜色" prop="color">
+          <el-input v-model="form.color" placeholder="请输入颜色" />
+        </el-form-item>
+        <el-form-item label="采购编号" prop="purchaseNo">
+          <el-input v-model="form.purchaseNo" placeholder="请输入采购编号" />
+        </el-form-item>
+        <el-form-item label="采购名称" prop="purchaseName">
+          <el-input v-model="form.purchaseName" placeholder="请输入采购名称" />
+        </el-form-item>
+        <el-form-item label="采购负责人编号" prop="purchaseManagerNo">
+          <el-input v-model="form.purchaseManagerNo" placeholder="请输入采购负责人编号" />
+        </el-form-item>
+        <el-form-item label="采购负责人姓名" prop="purchaseManagerName">
+          <el-input v-model="form.purchaseManagerName" placeholder="请输入采购负责人姓名" />
+        </el-form-item>
+        <el-form-item label="所属平台" prop="platform">
+          <el-input v-model="form.platform" placeholder="请输入所属平台" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Category" lang="ts">
+import { listCategory, getCategory, delCategory, addCategory, updateCategory } from '@/api/product/category';
+import { CategoryVO, CategoryQuery, CategoryForm } from '@/api/product/category/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const categoryList = ref<CategoryVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const categoryFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: CategoryForm = {
+  id: undefined,
+  categoryNo: undefined,
+  categoryName: undefined,
+  parentId: undefined,
+  ancestors: undefined,
+  classLevel: undefined,
+  isShow: undefined,
+  isShowGps: undefined,
+  discountRate: undefined,
+  pyCode: undefined,
+  classDescription: undefined,
+  dataSource: undefined,
+  oneLable1: undefined,
+  oneLable2: undefined,
+  oneLink1: undefined,
+  oneLink2: undefined,
+  sort: undefined,
+  color: undefined,
+  purchaseNo: undefined,
+  purchaseName: undefined,
+  purchaseManagerNo: undefined,
+  purchaseManagerName: undefined,
+  platform: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<CategoryForm, CategoryQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    categoryNo: undefined,
+    categoryName: undefined,
+    parentId: undefined,
+    ancestors: undefined,
+    classLevel: undefined,
+    isShow: undefined,
+    isShowGps: undefined,
+    discountRate: undefined,
+    pyCode: undefined,
+    classDescription: undefined,
+    dataSource: undefined,
+    oneLable1: undefined,
+    oneLable2: undefined,
+    oneLink1: undefined,
+    oneLink2: undefined,
+    sort: undefined,
+    color: undefined,
+    purchaseNo: undefined,
+    purchaseName: undefined,
+    purchaseManagerNo: undefined,
+    purchaseManagerName: undefined,
+    platform: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    categoryNo: [
+      { required: true, message: "分类编号不能为空", trigger: "blur" }
+    ],
+    categoryName: [
+      { required: true, message: "分类名称不能为空", trigger: "blur" }
+    ],
+    parentId: [
+      { required: true, message: "父级分类ID不能为空", trigger: "blur" }
+    ],
+    ancestors: [
+      { required: true, message: "祖籍列表不能为空", trigger: "blur" }
+    ],
+    isShow: [
+      { required: true, message: "是否显示不能为空", trigger: "blur" }
+    ],
+    discountRate: [
+      { required: true, message: "折扣率不能为空", trigger: "blur" }
+    ],
+    pyCode: [
+      { required: true, message: "拼音码不能为空", trigger: "blur" }
+    ],
+    classDescription: [
+      { required: true, message: "分类描述不能为空", trigger: "blur" }
+    ],
+    dataSource: [
+      { required: true, message: "数据来源不能为空", trigger: "blur" }
+    ],
+    oneLable1: [
+      { required: true, message: "自定义标签1不能为空", trigger: "blur" }
+    ],
+    oneLable2: [
+      { required: true, message: "自定义标签2不能为空", trigger: "blur" }
+    ],
+    oneLink1: [
+      { required: true, message: "自定义链接1不能为空", trigger: "blur" }
+    ],
+    oneLink2: [
+      { required: true, message: "自定义链接2不能为空", trigger: "blur" }
+    ],
+    sort: [
+      { required: true, message: "排序值,默认为0不能为空", trigger: "blur" }
+    ],
+    color: [
+      { required: true, message: "颜色不能为空", trigger: "blur" }
+    ],
+    purchaseNo: [
+      { required: true, message: "采购编号不能为空", trigger: "blur" }
+    ],
+    purchaseName: [
+      { required: true, message: "采购名称不能为空", trigger: "blur" }
+    ],
+    purchaseManagerNo: [
+      { required: true, message: "采购负责人编号不能为空", trigger: "blur" }
+    ],
+    purchaseManagerName: [
+      { required: true, message: "采购负责人姓名不能为空", trigger: "blur" }
+    ],
+    platform: [
+      { required: true, message: "所属平台不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品分类列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listCategory(queryParams.value);
+  categoryList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  categoryFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: CategoryVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品分类";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: CategoryVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getCategory(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品分类";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  categoryFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateCategory(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addCategory(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: CategoryVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品分类编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delCategory(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/category/export', {
+    ...queryParams.value
+  }, `category_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 247 - 0
src/views/product/classification/index.vue

@@ -0,0 +1,247 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="产品id" prop="productId">
+              <el-input v-model="queryParams.productId" placeholder="请输入产品id" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="分类编号" prop="categoryId">
+              <el-input v-model="queryParams.categoryId" placeholder="请输入分类编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="属性列表" prop="attributesList">
+              <el-input v-model="queryParams.attributesList" placeholder="请输入属性列表" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:classification:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:classification:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:classification:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:classification:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="classificationList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="产品id" align="center" prop="productId" />
+        <el-table-column label="分类编号" align="center" prop="categoryId" />
+        <el-table-column label="属性列表" align="center" prop="attributesList" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:classification:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:classification:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品属性关联对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="classificationFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="产品id" prop="productId">
+          <el-input v-model="form.productId" placeholder="请输入产品id" />
+        </el-form-item>
+        <el-form-item label="分类编号" prop="categoryId">
+          <el-input v-model="form.categoryId" placeholder="请输入分类编号" />
+        </el-form-item>
+        <el-form-item label="属性列表" prop="attributesList">
+            <el-input v-model="form.attributesList" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Classification" lang="ts">
+import { listClassification, getClassification, delClassification, addClassification, updateClassification } from '@/api/product/classification';
+import { ClassificationVO, ClassificationQuery, ClassificationForm } from '@/api/product/classification/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const classificationList = ref<ClassificationVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const classificationFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: ClassificationForm = {
+  id: undefined,
+  productId: undefined,
+  categoryId: undefined,
+  attributesList: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<ClassificationForm, ClassificationQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    productId: undefined,
+    categoryId: undefined,
+    attributesList: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    productId: [
+      { required: true, message: "产品id不能为空", trigger: "blur" }
+    ],
+    categoryId: [
+      { required: true, message: "分类编号不能为空", trigger: "blur" }
+    ],
+    attributesList: [
+      { required: true, message: "属性列表不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品属性关联列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listClassification(queryParams.value);
+  classificationList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  classificationFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: ClassificationVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品属性关联";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: ClassificationVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getClassification(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品属性关联";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  classificationFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateClassification(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addClassification(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: ClassificationVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品属性关联编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delClassification(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/classification/export', {
+    ...queryParams.value
+  }, `classification_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 307 - 0
src/views/product/customization/index.vue

@@ -0,0 +1,307 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="定制编号" prop="customizationNo">
+              <el-input v-model="queryParams.customizationNo" placeholder="请输入定制编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="产品id" prop="productId">
+              <el-input v-model="queryParams.productId" placeholder="请输入产品id" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="定制方式  支持多选,分隔  (0=包装定制,1=商品定制,2=开模定制)" prop="customizedStyle">
+              <el-input v-model="queryParams.customizedStyle" placeholder="请输入定制方式  支持多选,分隔  (0=包装定制,1=商品定制,2=开模定制)" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="定制工艺  支持多选,分隔  (0=丝印,1=热转印,2=激光,烤花,压印)" prop="customizedCraft">
+              <el-input v-model="queryParams.customizedCraft" placeholder="请输入定制工艺  支持多选,分隔  (0=丝印,1=热转印,2=激光,烤花,压印)" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="打样周期" prop="proofingPeriod">
+              <el-input v-model="queryParams.proofingPeriod" placeholder="请输入打样周期" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="生产周期" prop="productionCycle">
+              <el-input v-model="queryParams.productionCycle" placeholder="请输入生产周期" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="最小起订量" prop="moq">
+              <el-input v-model="queryParams.moq" placeholder="请输入最小起订量" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="MOQ对应价格" prop="moqPrice">
+              <el-input v-model="queryParams.moqPrice" placeholder="请输入MOQ对应价格" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:customization:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:customization:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:customization:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:customization:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="customizationList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="定制编号" align="center" prop="customizationNo" />
+        <el-table-column label="产品id" align="center" prop="productId" />
+        <el-table-column label="定制方式  支持多选,分隔  (0=包装定制,1=商品定制,2=开模定制)" align="center" prop="customizedStyle" />
+        <el-table-column label="定制工艺  支持多选,分隔  (0=丝印,1=热转印,2=激光,烤花,压印)" align="center" prop="customizedCraft" />
+        <el-table-column label="打样周期" align="center" prop="proofingPeriod" />
+        <el-table-column label="生产周期" align="center" prop="productionCycle" />
+        <el-table-column label="最小起订量" align="center" prop="moq" />
+        <el-table-column label="MOQ对应价格" align="center" prop="moqPrice" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:customization:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:customization:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品定制信息对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="customizationFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="定制编号" prop="customizationNo">
+          <el-input v-model="form.customizationNo" placeholder="请输入定制编号" />
+        </el-form-item>
+        <el-form-item label="产品id" prop="productId">
+          <el-input v-model="form.productId" placeholder="请输入产品id" />
+        </el-form-item>
+        <el-form-item label="定制方式  支持多选,分隔  (0=包装定制,1=商品定制,2=开模定制)" prop="customizedStyle">
+          <el-input v-model="form.customizedStyle" placeholder="请输入定制方式  支持多选,分隔  (0=包装定制,1=商品定制,2=开模定制)" />
+        </el-form-item>
+        <el-form-item label="定制工艺  支持多选,分隔  (0=丝印,1=热转印,2=激光,烤花,压印)" prop="customizedCraft">
+          <el-input v-model="form.customizedCraft" placeholder="请输入定制工艺  支持多选,分隔  (0=丝印,1=热转印,2=激光,烤花,压印)" />
+        </el-form-item>
+        <el-form-item label="打样周期" prop="proofingPeriod">
+          <el-input v-model="form.proofingPeriod" placeholder="请输入打样周期" />
+        </el-form-item>
+        <el-form-item label="生产周期" prop="productionCycle">
+          <el-input v-model="form.productionCycle" placeholder="请输入生产周期" />
+        </el-form-item>
+        <el-form-item label="最小起订量" prop="moq">
+          <el-input v-model="form.moq" placeholder="请输入最小起订量" />
+        </el-form-item>
+        <el-form-item label="MOQ对应价格" prop="moqPrice">
+          <el-input v-model="form.moqPrice" placeholder="请输入MOQ对应价格" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Customization" lang="ts">
+import { listCustomization, getCustomization, delCustomization, addCustomization, updateCustomization } from '@/api/product/customization';
+import { CustomizationVO, CustomizationQuery, CustomizationForm } from '@/api/product/customization/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const customizationList = ref<CustomizationVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const customizationFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: CustomizationForm = {
+  id: undefined,
+  customizationNo: undefined,
+  productId: undefined,
+  customizedStyle: undefined,
+  customizedCraft: undefined,
+  proofingPeriod: undefined,
+  productionCycle: undefined,
+  moq: undefined,
+  moqPrice: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<CustomizationForm, CustomizationQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    customizationNo: undefined,
+    productId: undefined,
+    customizedStyle: undefined,
+    customizedCraft: undefined,
+    proofingPeriod: undefined,
+    productionCycle: undefined,
+    moq: undefined,
+    moqPrice: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    customizationNo: [
+      { required: true, message: "定制编号不能为空", trigger: "blur" }
+    ],
+    productId: [
+      { required: true, message: "产品id不能为空", trigger: "blur" }
+    ],
+    customizedStyle: [
+      { required: true, message: "定制方式  支持多选,分隔  (0=包装定制,1=商品定制,2=开模定制)不能为空", trigger: "blur" }
+    ],
+    customizedCraft: [
+      { required: true, message: "定制工艺  支持多选,分隔  (0=丝印,1=热转印,2=激光,烤花,压印)不能为空", trigger: "blur" }
+    ],
+    proofingPeriod: [
+      { required: true, message: "打样周期不能为空", trigger: "blur" }
+    ],
+    productionCycle: [
+      { required: true, message: "生产周期不能为空", trigger: "blur" }
+    ],
+    moq: [
+      { required: true, message: "最小起订量不能为空", trigger: "blur" }
+    ],
+    moqPrice: [
+      { required: true, message: "MOQ对应价格不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品定制信息列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listCustomization(queryParams.value);
+  customizationList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  customizationFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: CustomizationVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品定制信息";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: CustomizationVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getCustomization(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品定制信息";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  customizationFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateCustomization(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addCustomization(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: CustomizationVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品定制信息编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delCustomization(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/customization/export', {
+    ...queryParams.value
+  }, `customization_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 235 - 0
src/views/product/ensure/index.vue

@@ -0,0 +1,235 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="保障名称" prop="ensureName">
+              <el-input v-model="queryParams.ensureName" placeholder="请输入保障名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="数据来源" prop="dataSource">
+              <el-input v-model="queryParams.dataSource" placeholder="请输入数据来源" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:ensure:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:ensure:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:ensure:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:ensure:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="ensureList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="保障名称" align="center" prop="ensureName" />
+        <el-table-column label="数据来源" align="center" prop="dataSource" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:ensure:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:ensure:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品保障项对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="ensureFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="保障名称" prop="ensureName">
+          <el-input v-model="form.ensureName" placeholder="请输入保障名称" />
+        </el-form-item>
+        <el-form-item label="数据来源" prop="dataSource">
+          <el-input v-model="form.dataSource" placeholder="请输入数据来源" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Ensure" lang="ts">
+import { listEnsure, getEnsure, delEnsure, addEnsure, updateEnsure } from '@/api/product/ensure';
+import { EnsureVO, EnsureQuery, EnsureForm } from '@/api/product/ensure/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const ensureList = ref<EnsureVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const ensureFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: EnsureForm = {
+  id: undefined,
+  ensureName: undefined,
+  dataSource: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<EnsureForm, EnsureQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    ensureName: undefined,
+    dataSource: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    ensureName: [
+      { required: true, message: "保障名称不能为空", trigger: "blur" }
+    ],
+    dataSource: [
+      { required: true, message: "数据来源不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品保障项列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listEnsure(queryParams.value);
+  ensureList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  ensureFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: EnsureVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品保障项";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: EnsureVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getEnsure(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品保障项";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  ensureFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateEnsure(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addEnsure(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: EnsureVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品保障项编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delEnsure(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/ensure/export', {
+    ...queryParams.value
+  }, `ensure_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 675 - 0
src/views/product/extend/index.vue

@@ -0,0 +1,675 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="促销标题" prop="promotionTitle">
+              <el-input v-model="queryParams.promotionTitle" placeholder="请输入促销标题" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="发票名称" prop="invoiceName">
+              <el-input v-model="queryParams.invoiceName" placeholder="请输入发票名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="规格代码" prop="specificationsCode">
+              <el-input v-model="queryParams.specificationsCode" placeholder="请输入规格代码" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="条形码" prop="barCoding">
+              <el-input v-model="queryParams.barCoding" placeholder="请输入条形码" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="产品描述" prop="productDescription">
+              <el-input v-model="queryParams.productDescription" placeholder="请输入产品描述" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="产品重量" prop="productWeight">
+              <el-input v-model="queryParams.productWeight" placeholder="请输入产品重量" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="重量单位" prop="weightUnit">
+              <el-input v-model="queryParams.weightUnit" placeholder="请输入重量单位" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="产品体积" prop="productVolume">
+              <el-input v-model="queryParams.productVolume" placeholder="请输入产品体积" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="体积单位" prop="volumeUnit">
+              <el-input v-model="queryParams.volumeUnit" placeholder="请输入体积单位" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="售后服务" prop="afterSalesService">
+              <el-input v-model="queryParams.afterSalesService" placeholder="请输入售后服务" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="服务保障  支持多选,分隔 (0=无忧退货,1=快速退款,2=免费包邮,3正品保障)" prop="serviceGuarantee">
+              <el-input v-model="queryParams.serviceGuarantee" placeholder="请输入服务保障  支持多选,分隔 (0=无忧退货,1=快速退款,2=免费包邮,3正品保障)" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否安装服务:1=是,0=否" prop="isInstallService">
+              <el-input v-model="queryParams.isInstallService" placeholder="请输入是否安装服务:1=是,0=否" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="安装费用" prop="installAmount">
+              <el-input v-model="queryParams.installAmount" placeholder="请输入安装费用" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="分销价格" prop="distributionPrice">
+              <el-input v-model="queryParams.distributionPrice" placeholder="请输入分销价格" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="标准尺寸" prop="standardSizes">
+              <el-input v-model="queryParams.standardSizes" placeholder="请输入标准尺寸" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="克重" prop="gramWeight">
+              <el-input v-model="queryParams.gramWeight" placeholder="请输入克重" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="透明度" prop="opacity">
+              <el-input v-model="queryParams.opacity" placeholder="请输入透明度" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否可定制:1=是,0=否" prop="isCustomize">
+              <el-input v-model="queryParams.isCustomize" placeholder="请输入是否可定制:1=是,0=否" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="定制描述" prop="customDescription">
+              <el-input v-model="queryParams.customDescription" placeholder="请输入定制描述" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="产品利润" prop="productProfit">
+              <el-input v-model="queryParams.productProfit" placeholder="请输入产品利润" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="报告需求" prop="reportRequire">
+              <el-input v-model="queryParams.reportRequire" placeholder="请输入报告需求" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="审核评论" prop="reviewComments">
+              <el-input v-model="queryParams.reviewComments" placeholder="请输入审核评论" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="供应商编号" prop="supplierNo">
+              <el-input v-model="queryParams.supplierNo" placeholder="请输入供应商编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="数据来源" prop="dataSource">
+              <el-input v-model="queryParams.dataSource" placeholder="请输入数据来源" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="发票规格" prop="invoiceSpecs">
+              <el-input v-model="queryParams.invoiceSpecs" placeholder="请输入发票规格" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="增量" prop="increment">
+              <el-input v-model="queryParams.increment" placeholder="请输入增量" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="采购编号" prop="purchaseNo">
+              <el-input v-model="queryParams.purchaseNo" placeholder="请输入采购编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="采购名称" prop="purchaseName">
+              <el-input v-model="queryParams.purchaseName" placeholder="请输入采购名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="供应商名称" prop="supplierName">
+              <el-input v-model="queryParams.supplierName" placeholder="请输入供应商名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="采购经理编号" prop="purchaseManagerNo">
+              <el-input v-model="queryParams.purchaseManagerNo" placeholder="请输入采购经理编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="采购经理姓名" prop="purchaseManagerName">
+              <el-input v-model="queryParams.purchaseManagerName" placeholder="请输入采购经理姓名" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="参考链接" prop="referenceLink">
+              <el-input v-model="queryParams.referenceLink" placeholder="请输入参考链接" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="销售量" prop="salesVolume">
+              <el-input v-model="queryParams.salesVolume" placeholder="请输入销售量" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="发货时效" prop="deliveryTime">
+              <el-input v-model="queryParams.deliveryTime" placeholder="请输入发货时效" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="PIT时间" prop="pitTime">
+              <el-date-picker clearable
+                v-model="queryParams.pitTime"
+                type="date"
+                value-format="YYYY-MM-DD"
+                placeholder="请选择PIT时间"
+              />
+            </el-form-item>
+            <el-form-item label="创建时的供应商标识" prop="createSupplier">
+              <el-input v-model="queryParams.createSupplier" placeholder="请输入创建时的供应商标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="其他补充信息" prop="otherInfo">
+              <el-input v-model="queryParams.otherInfo" placeholder="请输入其他补充信息" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:extend:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:extend:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:extend:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:extend:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="extendList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="关联 product_base.id" align="center" prop="productId" v-if="true" />
+        <el-table-column label="促销标题" align="center" prop="promotionTitle" />
+        <el-table-column label="发票名称" align="center" prop="invoiceName" />
+        <el-table-column label="发票类型" align="center" prop="invoiceType" />
+        <el-table-column label="规格代码" align="center" prop="specificationsCode" />
+        <el-table-column label="条形码" align="center" prop="barCoding" />
+        <el-table-column label="产品描述" align="center" prop="productDescription" />
+        <el-table-column label="产品重量" align="center" prop="productWeight" />
+        <el-table-column label="重量单位" align="center" prop="weightUnit" />
+        <el-table-column label="产品体积" align="center" prop="productVolume" />
+        <el-table-column label="体积单位" align="center" prop="volumeUnit" />
+        <el-table-column label="售后服务" align="center" prop="afterSalesService" />
+        <el-table-column label="服务保障  支持多选,分隔 (0=无忧退货,1=快速退款,2=免费包邮,3正品保障)" align="center" prop="serviceGuarantee" />
+        <el-table-column label="是否安装服务:1=是,0=否" align="center" prop="isInstallService" />
+        <el-table-column label="安装费用" align="center" prop="installAmount" />
+        <el-table-column label="分销价格" align="center" prop="distributionPrice" />
+        <el-table-column label="标准尺寸" align="center" prop="standardSizes" />
+        <el-table-column label="克重" align="center" prop="gramWeight" />
+        <el-table-column label="透明度" align="center" prop="opacity" />
+        <el-table-column label="是否可定制:1=是,0=否" align="center" prop="isCustomize" />
+        <el-table-column label="定制描述" align="center" prop="customDescription" />
+        <el-table-column label="产品利润" align="center" prop="productProfit" />
+        <el-table-column label="报告需求" align="center" prop="reportRequire" />
+        <el-table-column label="审核评论" align="center" prop="reviewComments" />
+        <el-table-column label="供应商编号" align="center" prop="supplierNo" />
+        <el-table-column label="推送状态" align="center" prop="pushStatus" />
+        <el-table-column label="数据来源" align="center" prop="dataSource" />
+        <el-table-column label="发票规格" align="center" prop="invoiceSpecs" />
+        <el-table-column label="增量" align="center" prop="increment" />
+        <el-table-column label="采购编号" align="center" prop="purchaseNo" />
+        <el-table-column label="采购名称" align="center" prop="purchaseName" />
+        <el-table-column label="供应商名称" align="center" prop="supplierName" />
+        <el-table-column label="采购经理编号" align="center" prop="purchaseManagerNo" />
+        <el-table-column label="采购经理姓名" align="center" prop="purchaseManagerName" />
+        <el-table-column label="参考链接" align="center" prop="referenceLink" />
+        <el-table-column label="销售量" align="center" prop="salesVolume" />
+        <el-table-column label="发货时效" align="center" prop="deliveryTime" />
+        <el-table-column label="PIT时间" align="center" prop="pitTime" width="180">
+          <template #default="scope">
+            <span>{{ parseTime(scope.row.pitTime, '{y}-{m}-{d}') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="创建时的供应商标识" align="center" prop="createSupplier" />
+        <el-table-column label="其他补充信息" align="center" prop="otherInfo" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:extend:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:extend:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品扩展属性(低频访问字段)对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="extendFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="促销标题" prop="promotionTitle">
+          <el-input v-model="form.promotionTitle" placeholder="请输入促销标题" />
+        </el-form-item>
+        <el-form-item label="发票名称" prop="invoiceName">
+            <el-input v-model="form.invoiceName" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="规格代码" prop="specificationsCode">
+            <el-input v-model="form.specificationsCode" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="条形码" prop="barCoding">
+          <el-input v-model="form.barCoding" placeholder="请输入条形码" />
+        </el-form-item>
+        <el-form-item label="产品描述" prop="productDescription">
+            <el-input v-model="form.productDescription" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="产品重量" prop="productWeight">
+          <el-input v-model="form.productWeight" placeholder="请输入产品重量" />
+        </el-form-item>
+        <el-form-item label="重量单位" prop="weightUnit">
+          <el-input v-model="form.weightUnit" placeholder="请输入重量单位" />
+        </el-form-item>
+        <el-form-item label="产品体积" prop="productVolume">
+          <el-input v-model="form.productVolume" placeholder="请输入产品体积" />
+        </el-form-item>
+        <el-form-item label="体积单位" prop="volumeUnit">
+          <el-input v-model="form.volumeUnit" placeholder="请输入体积单位" />
+        </el-form-item>
+        <el-form-item label="售后服务" prop="afterSalesService">
+          <el-input v-model="form.afterSalesService" placeholder="请输入售后服务" />
+        </el-form-item>
+        <el-form-item label="服务保障  支持多选,分隔 (0=无忧退货,1=快速退款,2=免费包邮,3正品保障)" prop="serviceGuarantee">
+          <el-input v-model="form.serviceGuarantee" placeholder="请输入服务保障  支持多选,分隔 (0=无忧退货,1=快速退款,2=免费包邮,3正品保障)" />
+        </el-form-item>
+        <el-form-item label="是否安装服务:1=是,0=否" prop="isInstallService">
+          <el-input v-model="form.isInstallService" placeholder="请输入是否安装服务:1=是,0=否" />
+        </el-form-item>
+        <el-form-item label="安装费用" prop="installAmount">
+          <el-input v-model="form.installAmount" placeholder="请输入安装费用" />
+        </el-form-item>
+        <el-form-item label="分销价格" prop="distributionPrice">
+          <el-input v-model="form.distributionPrice" placeholder="请输入分销价格" />
+        </el-form-item>
+        <el-form-item label="标准尺寸" prop="standardSizes">
+          <el-input v-model="form.standardSizes" placeholder="请输入标准尺寸" />
+        </el-form-item>
+        <el-form-item label="克重" prop="gramWeight">
+          <el-input v-model="form.gramWeight" placeholder="请输入克重" />
+        </el-form-item>
+        <el-form-item label="透明度" prop="opacity">
+          <el-input v-model="form.opacity" placeholder="请输入透明度" />
+        </el-form-item>
+        <el-form-item label="是否可定制:1=是,0=否" prop="isCustomize">
+          <el-input v-model="form.isCustomize" placeholder="请输入是否可定制:1=是,0=否" />
+        </el-form-item>
+        <el-form-item label="定制描述" prop="customDescription">
+          <el-input v-model="form.customDescription" placeholder="请输入定制描述" />
+        </el-form-item>
+        <el-form-item label="产品利润" prop="productProfit">
+          <el-input v-model="form.productProfit" placeholder="请输入产品利润" />
+        </el-form-item>
+        <el-form-item label="报告需求" prop="reportRequire">
+          <el-input v-model="form.reportRequire" placeholder="请输入报告需求" />
+        </el-form-item>
+        <el-form-item label="审核评论" prop="reviewComments">
+          <el-input v-model="form.reviewComments" placeholder="请输入审核评论" />
+        </el-form-item>
+        <el-form-item label="供应商编号" prop="supplierNo">
+          <el-input v-model="form.supplierNo" placeholder="请输入供应商编号" />
+        </el-form-item>
+        <el-form-item label="数据来源" prop="dataSource">
+          <el-input v-model="form.dataSource" placeholder="请输入数据来源" />
+        </el-form-item>
+        <el-form-item label="发票规格" prop="invoiceSpecs">
+            <el-input v-model="form.invoiceSpecs" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="增量" prop="increment">
+          <el-input v-model="form.increment" placeholder="请输入增量" />
+        </el-form-item>
+        <el-form-item label="采购编号" prop="purchaseNo">
+          <el-input v-model="form.purchaseNo" placeholder="请输入采购编号" />
+        </el-form-item>
+        <el-form-item label="采购名称" prop="purchaseName">
+          <el-input v-model="form.purchaseName" placeholder="请输入采购名称" />
+        </el-form-item>
+        <el-form-item label="供应商名称" prop="supplierName">
+            <el-input v-model="form.supplierName" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="采购经理编号" prop="purchaseManagerNo">
+          <el-input v-model="form.purchaseManagerNo" placeholder="请输入采购经理编号" />
+        </el-form-item>
+        <el-form-item label="采购经理姓名" prop="purchaseManagerName">
+          <el-input v-model="form.purchaseManagerName" placeholder="请输入采购经理姓名" />
+        </el-form-item>
+        <el-form-item label="参考链接" prop="referenceLink">
+            <el-input v-model="form.referenceLink" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="销售量" prop="salesVolume">
+          <el-input v-model="form.salesVolume" placeholder="请输入销售量" />
+        </el-form-item>
+        <el-form-item label="发货时效" prop="deliveryTime">
+          <el-input v-model="form.deliveryTime" placeholder="请输入发货时效" />
+        </el-form-item>
+        <el-form-item label="PIT时间" prop="pitTime">
+          <el-date-picker clearable
+            v-model="form.pitTime"
+            type="datetime"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            placeholder="请选择PIT时间">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="创建时的供应商标识" prop="createSupplier">
+          <el-input v-model="form.createSupplier" placeholder="请输入创建时的供应商标识" />
+        </el-form-item>
+        <el-form-item label="其他补充信息" prop="otherInfo">
+          <el-input v-model="form.otherInfo" placeholder="请输入其他补充信息" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Extend" lang="ts">
+import { listExtend, getExtend, delExtend, addExtend, updateExtend } from '@/api/product/extend';
+import { ExtendVO, ExtendQuery, ExtendForm } from '@/api/product/extend/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const extendList = ref<ExtendVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const extendFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: ExtendForm = {
+  productId: undefined,
+  promotionTitle: undefined,
+  invoiceName: undefined,
+  invoiceType: undefined,
+  specificationsCode: undefined,
+  barCoding: undefined,
+  productDescription: undefined,
+  productWeight: undefined,
+  weightUnit: undefined,
+  productVolume: undefined,
+  volumeUnit: undefined,
+  afterSalesService: undefined,
+  serviceGuarantee: undefined,
+  isInstallService: undefined,
+  installAmount: undefined,
+  distributionPrice: undefined,
+  standardSizes: undefined,
+  gramWeight: undefined,
+  opacity: undefined,
+  isCustomize: undefined,
+  customDescription: undefined,
+  productProfit: undefined,
+  reportRequire: undefined,
+  reviewComments: undefined,
+  supplierNo: undefined,
+  pushStatus: undefined,
+  dataSource: undefined,
+  invoiceSpecs: undefined,
+  increment: undefined,
+  purchaseNo: undefined,
+  purchaseName: undefined,
+  supplierName: undefined,
+  purchaseManagerNo: undefined,
+  purchaseManagerName: undefined,
+  referenceLink: undefined,
+  salesVolume: undefined,
+  deliveryTime: undefined,
+  pitTime: undefined,
+  createSupplier: undefined,
+  otherInfo: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<ExtendForm, ExtendQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    promotionTitle: undefined,
+    invoiceName: undefined,
+    invoiceType: undefined,
+    specificationsCode: undefined,
+    barCoding: undefined,
+    productDescription: undefined,
+    productWeight: undefined,
+    weightUnit: undefined,
+    productVolume: undefined,
+    volumeUnit: undefined,
+    afterSalesService: undefined,
+    serviceGuarantee: undefined,
+    isInstallService: undefined,
+    installAmount: undefined,
+    distributionPrice: undefined,
+    standardSizes: undefined,
+    gramWeight: undefined,
+    opacity: undefined,
+    isCustomize: undefined,
+    customDescription: undefined,
+    productProfit: undefined,
+    reportRequire: undefined,
+    reviewComments: undefined,
+    supplierNo: undefined,
+    pushStatus: undefined,
+    dataSource: undefined,
+    invoiceSpecs: undefined,
+    increment: undefined,
+    purchaseNo: undefined,
+    purchaseName: undefined,
+    supplierName: undefined,
+    purchaseManagerNo: undefined,
+    purchaseManagerName: undefined,
+    referenceLink: undefined,
+    salesVolume: undefined,
+    deliveryTime: undefined,
+    pitTime: undefined,
+    createSupplier: undefined,
+    otherInfo: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    promotionTitle: [
+      { required: true, message: "促销标题不能为空", trigger: "blur" }
+    ],
+    invoiceName: [
+      { required: true, message: "发票名称不能为空", trigger: "blur" }
+    ],
+    invoiceType: [
+      { required: true, message: "发票类型不能为空", trigger: "change" }
+    ],
+    specificationsCode: [
+      { required: true, message: "规格代码不能为空", trigger: "blur" }
+    ],
+    barCoding: [
+      { required: true, message: "条形码不能为空", trigger: "blur" }
+    ],
+    productDescription: [
+      { required: true, message: "产品描述不能为空", trigger: "blur" }
+    ],
+    productWeight: [
+      { required: true, message: "产品重量不能为空", trigger: "blur" }
+    ],
+    weightUnit: [
+      { required: true, message: "重量单位不能为空", trigger: "blur" }
+    ],
+    productVolume: [
+      { required: true, message: "产品体积不能为空", trigger: "blur" }
+    ],
+    volumeUnit: [
+      { required: true, message: "体积单位不能为空", trigger: "blur" }
+    ],
+    afterSalesService: [
+      { required: true, message: "售后服务不能为空", trigger: "blur" }
+    ],
+    serviceGuarantee: [
+      { required: true, message: "服务保障  支持多选,分隔 (0=无忧退货,1=快速退款,2=免费包邮,3正品保障)不能为空", trigger: "blur" }
+    ],
+    installAmount: [
+      { required: true, message: "安装费用不能为空", trigger: "blur" }
+    ],
+    distributionPrice: [
+      { required: true, message: "分销价格不能为空", trigger: "blur" }
+    ],
+    standardSizes: [
+      { required: true, message: "标准尺寸不能为空", trigger: "blur" }
+    ],
+    gramWeight: [
+      { required: true, message: "克重不能为空", trigger: "blur" }
+    ],
+    opacity: [
+      { required: true, message: "透明度不能为空", trigger: "blur" }
+    ],
+    customDescription: [
+      { required: true, message: "定制描述不能为空", trigger: "blur" }
+    ],
+    productProfit: [
+      { required: true, message: "产品利润不能为空", trigger: "blur" }
+    ],
+    reportRequire: [
+      { required: true, message: "报告需求不能为空", trigger: "blur" }
+    ],
+    reviewComments: [
+      { required: true, message: "审核评论不能为空", trigger: "blur" }
+    ],
+    supplierNo: [
+      { required: true, message: "供应商编号不能为空", trigger: "blur" }
+    ],
+    pushStatus: [
+      { required: true, message: "推送状态不能为空", trigger: "change" }
+    ],
+    dataSource: [
+      { required: true, message: "数据来源不能为空", trigger: "blur" }
+    ],
+    invoiceSpecs: [
+      { required: true, message: "发票规格不能为空", trigger: "blur" }
+    ],
+    increment: [
+      { required: true, message: "增量不能为空", trigger: "blur" }
+    ],
+    purchaseNo: [
+      { required: true, message: "采购编号不能为空", trigger: "blur" }
+    ],
+    purchaseName: [
+      { required: true, message: "采购名称不能为空", trigger: "blur" }
+    ],
+    supplierName: [
+      { required: true, message: "供应商名称不能为空", trigger: "blur" }
+    ],
+    purchaseManagerNo: [
+      { required: true, message: "采购经理编号不能为空", trigger: "blur" }
+    ],
+    purchaseManagerName: [
+      { required: true, message: "采购经理姓名不能为空", trigger: "blur" }
+    ],
+    referenceLink: [
+      { required: true, message: "参考链接不能为空", trigger: "blur" }
+    ],
+    salesVolume: [
+      { required: true, message: "销售量不能为空", trigger: "blur" }
+    ],
+    deliveryTime: [
+      { required: true, message: "发货时效不能为空", trigger: "blur" }
+    ],
+    pitTime: [
+      { required: true, message: "PIT时间不能为空", trigger: "blur" }
+    ],
+    createSupplier: [
+      { required: true, message: "创建时的供应商标识不能为空", trigger: "blur" }
+    ],
+    otherInfo: [
+      { required: true, message: "其他补充信息不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品扩展属性(低频访问字段)列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listExtend(queryParams.value);
+  extendList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  extendFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: ExtendVO[]) => {
+  ids.value = selection.map(item => item.productId);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品扩展属性(低频访问字段)";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: ExtendVO) => {
+  reset();
+  const _productId = row?.productId || ids.value[0]
+  const res = await getExtend(_productId);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品扩展属性(低频访问字段)";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  extendFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.productId) {
+        await updateExtend(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addExtend(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: ExtendVO) => {
+  const _productIds = row?.productId || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品扩展属性(低频访问字段)编号为"' + _productIds + '"的数据项?').finally(() => loading.value = false);
+  await delExtend(_productIds);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/extend/export', {
+    ...queryParams.value
+  }, `extend_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 244 - 0
src/views/product/lable/index.vue

@@ -0,0 +1,244 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="产品标签编号" prop="productLabelNo">
+              <el-input v-model="queryParams.productLabelNo" placeholder="请输入产品标签编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="标签显示名称" prop="productLabelName">
+              <el-input v-model="queryParams.productLabelName" placeholder="请输入标签显示名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="使用该标签的产品数量" prop="productQuantity">
+              <el-input v-model="queryParams.productQuantity" placeholder="请输入使用该标签的产品数量" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:lable:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:lable:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:lable:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:lable:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="lableList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键,自增ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="产品标签编号" align="center" prop="productLabelNo" />
+        <el-table-column label="标签显示名称" align="center" prop="productLabelName" />
+        <el-table-column label="使用该标签的产品数量" align="center" prop="productQuantity" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:lable:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:lable:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品标签信息(注意:名疑似拼写错误,应为 product_label)对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="lableFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="产品标签编号" prop="productLabelNo">
+          <el-input v-model="form.productLabelNo" placeholder="请输入产品标签编号" />
+        </el-form-item>
+        <el-form-item label="标签显示名称" prop="productLabelName">
+          <el-input v-model="form.productLabelName" placeholder="请输入标签显示名称" />
+        </el-form-item>
+        <el-form-item label="使用该标签的产品数量" prop="productQuantity">
+          <el-input v-model="form.productQuantity" placeholder="请输入使用该标签的产品数量" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Lable" lang="ts">
+import { listLable, getLable, delLable, addLable, updateLable } from '@/api/product/lable';
+import { LableVO, LableQuery, LableForm } from '@/api/product/lable/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const lableList = ref<LableVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const lableFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: LableForm = {
+  id: undefined,
+  productLabelNo: undefined,
+  productLabelName: undefined,
+  productQuantity: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<LableForm, LableQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    productLabelNo: undefined,
+    productLabelName: undefined,
+    productQuantity: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    productLabelNo: [
+      { required: true, message: "产品标签编号不能为空", trigger: "blur" }
+    ],
+    productLabelName: [
+      { required: true, message: "标签显示名称不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品标签信息(注意:名疑似拼写错误,应为 product_label)列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listLable(queryParams.value);
+  lableList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  lableFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: LableVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品标签信息(注意:名疑似拼写错误,应为 product_label)";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: LableVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getLable(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品标签信息(注意:名疑似拼写错误,应为 product_label)";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  lableFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateLable(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addLable(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: LableVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品标签信息(注意:名疑似拼写错误,应为 product_label)编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delLable(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/lable/export', {
+    ...queryParams.value
+  }, `lable_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 253 - 0
src/views/product/pool/index.vue

@@ -0,0 +1,253 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="池编码" prop="poolNo">
+              <el-input v-model="queryParams.poolNo" placeholder="请输入池编码" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="池名称" prop="name">
+              <el-input v-model="queryParams.name" placeholder="请输入池名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否显示:1=是,0=否" prop="isShow">
+              <el-input v-model="queryParams.isShow" placeholder="请输入是否显示:1=是,0=否" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="审核原因" prop="reviewReason">
+              <el-input v-model="queryParams.reviewReason" placeholder="请输入审核原因" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:pool:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:pool:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:pool:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:pool:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="poolList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="池编码" align="center" prop="poolNo" />
+        <el-table-column label="池名称" align="center" prop="name" />
+        <el-table-column label="是否显示:1=是,0=否" align="center" prop="isShow" />
+        <el-table-column label="产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回" align="center" prop="productReviewStatus" />
+        <el-table-column label="审核原因" align="center" prop="reviewReason" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:pool:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:pool:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品池对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="poolFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="池编码" prop="poolNo">
+          <el-input v-model="form.poolNo" placeholder="请输入池编码" />
+        </el-form-item>
+        <el-form-item label="池名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入池名称" />
+        </el-form-item>
+        <el-form-item label="是否显示:1=是,0=否" prop="isShow">
+          <el-input v-model="form.isShow" placeholder="请输入是否显示:1=是,0=否" />
+        </el-form-item>
+        <el-form-item label="审核原因" prop="reviewReason">
+          <el-input v-model="form.reviewReason" placeholder="请输入审核原因" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Pool" lang="ts">
+import { listPool, getPool, delPool, addPool, updatePool } from '@/api/product/pool';
+import { PoolVO, PoolQuery, PoolForm } from '@/api/product/pool/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const poolList = ref<PoolVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const poolFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: PoolForm = {
+  id: undefined,
+  poolNo: undefined,
+  name: undefined,
+  isShow: undefined,
+  productReviewStatus: undefined,
+  reviewReason: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<PoolForm, PoolQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    poolNo: undefined,
+    name: undefined,
+    isShow: undefined,
+    productReviewStatus: undefined,
+    reviewReason: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    reviewReason: [
+      { required: true, message: "审核原因不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品池列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listPool(queryParams.value);
+  poolList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  poolFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: PoolVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品池";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: PoolVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getPool(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品池";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  poolFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updatePool(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addPool(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: PoolVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品池编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delPool(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/pool/export', {
+    ...queryParams.value
+  }, `pool_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 274 - 0
src/views/product/poolLink/index.vue

@@ -0,0 +1,274 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="所属池ID" prop="poolId">
+              <el-input v-model="queryParams.poolId" placeholder="请输入所属池ID" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="产品id" prop="productId">
+              <el-input v-model="queryParams.productId" placeholder="请输入产品id" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="产品价格" prop="productPrice">
+              <el-input v-model="queryParams.productPrice" placeholder="请输入产品价格" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="审核原因" prop="reviewReason">
+              <el-input v-model="queryParams.reviewReason" placeholder="请输入审核原因" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否显示:1=是,0=否" prop="isShow">
+              <el-input v-model="queryParams.isShow" placeholder="请输入是否显示:1=是,0=否" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:poolLink:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:poolLink:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:poolLink:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:poolLink:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="poolLinkList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="所属池ID" align="center" prop="poolId" />
+        <el-table-column label="产品id" align="center" prop="productId" />
+        <el-table-column label="产品价格" align="center" prop="productPrice" />
+        <el-table-column label="是否在池中:1-是,0-否" align="center" prop="isPoolStatus" />
+        <el-table-column label="产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回" align="center" prop="productReviewStatus" />
+        <el-table-column label="审核原因" align="center" prop="reviewReason" />
+        <el-table-column label="是否显示:1=是,0=否" align="center" prop="isShow" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:poolLink:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:poolLink:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品池和产品关联对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="poolLinkFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="所属池ID" prop="poolId">
+          <el-input v-model="form.poolId" placeholder="请输入所属池ID" />
+        </el-form-item>
+        <el-form-item label="产品id" prop="productId">
+          <el-input v-model="form.productId" placeholder="请输入产品id" />
+        </el-form-item>
+        <el-form-item label="产品价格" prop="productPrice">
+          <el-input v-model="form.productPrice" placeholder="请输入产品价格" />
+        </el-form-item>
+        <el-form-item label="审核原因" prop="reviewReason">
+          <el-input v-model="form.reviewReason" placeholder="请输入审核原因" />
+        </el-form-item>
+        <el-form-item label="是否显示:1=是,0=否" prop="isShow">
+          <el-input v-model="form.isShow" placeholder="请输入是否显示:1=是,0=否" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="PoolLink" lang="ts">
+import { listPoolLink, getPoolLink, delPoolLink, addPoolLink, updatePoolLink } from '@/api/product/poolLink';
+import { PoolLinkVO, PoolLinkQuery, PoolLinkForm } from '@/api/product/poolLink/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const poolLinkList = ref<PoolLinkVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const poolLinkFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: PoolLinkForm = {
+  id: undefined,
+  poolId: undefined,
+  productId: undefined,
+  productPrice: undefined,
+  isPoolStatus: undefined,
+  productReviewStatus: undefined,
+  reviewReason: undefined,
+  isShow: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<PoolLinkForm, PoolLinkQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    poolId: undefined,
+    productId: undefined,
+    productPrice: undefined,
+    isPoolStatus: undefined,
+    productReviewStatus: undefined,
+    reviewReason: undefined,
+    isShow: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    productPrice: [
+      { required: true, message: "产品价格不能为空", trigger: "blur" }
+    ],
+    productReviewStatus: [
+      { required: true, message: "产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回不能为空", trigger: "change" }
+    ],
+    reviewReason: [
+      { required: true, message: "审核原因不能为空", trigger: "blur" }
+    ],
+    isShow: [
+      { required: true, message: "是否显示:1=是,0=否不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品池和产品关联列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listPoolLink(queryParams.value);
+  poolLinkList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  poolLinkFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: PoolLinkVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品池和产品关联";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: PoolLinkVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getPoolLink(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品池和产品关联";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  poolLinkFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updatePoolLink(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addPoolLink(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: PoolLinkVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品池和产品关联编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delPoolLink(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/poolLink/export', {
+    ...queryParams.value
+  }, `poolLink_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 331 - 0
src/views/product/priceInventory/index.vue

@@ -0,0 +1,331 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="市场价格" prop="marketPrice">
+              <el-input v-model="queryParams.marketPrice" placeholder="请输入市场价格" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="会员价格" prop="memberPrice">
+              <el-input v-model="queryParams.memberPrice" placeholder="请输入会员价格" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="最低销售价格" prop="minSellingPrice">
+              <el-input v-model="queryParams.minSellingPrice" placeholder="请输入最低销售价格" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="采购价格" prop="purchasingPrice">
+              <el-input v-model="queryParams.purchasingPrice" placeholder="请输入采购价格" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="最高采购价格" prop="maxPurchasePrice">
+              <el-input v-model="queryParams.maxPurchasePrice" placeholder="请输入最高采购价格" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="总库存量" prop="totalInventory">
+              <el-input v-model="queryParams.totalInventory" placeholder="请输入总库存量" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="当前可用库存" prop="nowInventory">
+              <el-input v-model="queryParams.nowInventory" placeholder="请输入当前可用库存" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="虚拟库存" prop="virtualInventory">
+              <el-input v-model="queryParams.virtualInventory" placeholder="请输入虚拟库存" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="最小起订数量" prop="minOrderQuantity">
+              <el-input v-model="queryParams.minOrderQuantity" placeholder="请输入最小起订数量" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="税率" prop="taxRate">
+              <el-input v-model="queryParams.taxRate" placeholder="请输入税率" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="货币类型" prop="currency">
+              <el-input v-model="queryParams.currency" placeholder="请输入货币类型" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:priceInventory:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:priceInventory:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:priceInventory:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:priceInventory:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="priceInventoryList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="关联 product_base.id" align="center" prop="productId" v-if="true" />
+        <el-table-column label="市场价格" align="center" prop="marketPrice" />
+        <el-table-column label="会员价格" align="center" prop="memberPrice" />
+        <el-table-column label="最低销售价格" align="center" prop="minSellingPrice" />
+        <el-table-column label="采购价格" align="center" prop="purchasingPrice" />
+        <el-table-column label="最高采购价格" align="center" prop="maxPurchasePrice" />
+        <el-table-column label="总库存量" align="center" prop="totalInventory" />
+        <el-table-column label="当前可用库存" align="center" prop="nowInventory" />
+        <el-table-column label="虚拟库存" align="center" prop="virtualInventory" />
+        <el-table-column label="最小起订数量" align="center" prop="minOrderQuantity" />
+        <el-table-column label="税率" align="center" prop="taxRate" />
+        <el-table-column label="货币类型" align="center" prop="currency" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:priceInventory:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:priceInventory:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品价格与库存信息对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="priceInventoryFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="市场价格" prop="marketPrice">
+          <el-input v-model="form.marketPrice" placeholder="请输入市场价格" />
+        </el-form-item>
+        <el-form-item label="会员价格" prop="memberPrice">
+          <el-input v-model="form.memberPrice" placeholder="请输入会员价格" />
+        </el-form-item>
+        <el-form-item label="最低销售价格" prop="minSellingPrice">
+          <el-input v-model="form.minSellingPrice" placeholder="请输入最低销售价格" />
+        </el-form-item>
+        <el-form-item label="采购价格" prop="purchasingPrice">
+          <el-input v-model="form.purchasingPrice" placeholder="请输入采购价格" />
+        </el-form-item>
+        <el-form-item label="最高采购价格" prop="maxPurchasePrice">
+          <el-input v-model="form.maxPurchasePrice" placeholder="请输入最高采购价格" />
+        </el-form-item>
+        <el-form-item label="总库存量" prop="totalInventory">
+          <el-input v-model="form.totalInventory" placeholder="请输入总库存量" />
+        </el-form-item>
+        <el-form-item label="当前可用库存" prop="nowInventory">
+          <el-input v-model="form.nowInventory" placeholder="请输入当前可用库存" />
+        </el-form-item>
+        <el-form-item label="虚拟库存" prop="virtualInventory">
+          <el-input v-model="form.virtualInventory" placeholder="请输入虚拟库存" />
+        </el-form-item>
+        <el-form-item label="最小起订数量" prop="minOrderQuantity">
+          <el-input v-model="form.minOrderQuantity" placeholder="请输入最小起订数量" />
+        </el-form-item>
+        <el-form-item label="税率" prop="taxRate">
+          <el-input v-model="form.taxRate" placeholder="请输入税率" />
+        </el-form-item>
+        <el-form-item label="货币类型" prop="currency">
+          <el-input v-model="form.currency" placeholder="请输入货币类型" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="PriceInventory" lang="ts">
+import { listPriceInventory, getPriceInventory, delPriceInventory, addPriceInventory, updatePriceInventory } from '@/api/product/priceInventory';
+import { PriceInventoryVO, PriceInventoryQuery, PriceInventoryForm } from '@/api/product/priceInventory/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const priceInventoryList = ref<PriceInventoryVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const priceInventoryFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: PriceInventoryForm = {
+  productId: undefined,
+  marketPrice: undefined,
+  memberPrice: undefined,
+  minSellingPrice: undefined,
+  purchasingPrice: undefined,
+  maxPurchasePrice: undefined,
+  totalInventory: undefined,
+  nowInventory: undefined,
+  virtualInventory: undefined,
+  minOrderQuantity: undefined,
+  taxRate: undefined,
+  currency: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<PriceInventoryForm, PriceInventoryQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    marketPrice: undefined,
+    memberPrice: undefined,
+    minSellingPrice: undefined,
+    purchasingPrice: undefined,
+    maxPurchasePrice: undefined,
+    totalInventory: undefined,
+    nowInventory: undefined,
+    virtualInventory: undefined,
+    minOrderQuantity: undefined,
+    taxRate: undefined,
+    currency: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    marketPrice: [
+      { required: true, message: "市场价格不能为空", trigger: "blur" }
+    ],
+    memberPrice: [
+      { required: true, message: "会员价格不能为空", trigger: "blur" }
+    ],
+    minSellingPrice: [
+      { required: true, message: "最低销售价格不能为空", trigger: "blur" }
+    ],
+    purchasingPrice: [
+      { required: true, message: "采购价格不能为空", trigger: "blur" }
+    ],
+    maxPurchasePrice: [
+      { required: true, message: "最高采购价格不能为空", trigger: "blur" }
+    ],
+    taxRate: [
+      { required: true, message: "税率不能为空", trigger: "blur" }
+    ],
+    currency: [
+      { required: true, message: "货币类型不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品价格与库存信息列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listPriceInventory(queryParams.value);
+  priceInventoryList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  priceInventoryFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: PriceInventoryVO[]) => {
+  ids.value = selection.map(item => item.productId);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品价格与库存信息";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: PriceInventoryVO) => {
+  reset();
+  const _productId = row?.productId || ids.value[0]
+  const res = await getPriceInventory(_productId);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品价格与库存信息";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  priceInventoryFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.productId) {
+        await updatePriceInventory(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addPriceInventory(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: PriceInventoryVO) => {
+  const _productIds = row?.productId || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品价格与库存信息编号为"' + _productIds + '"的数据项?').finally(() => loading.value = false);
+  await delPriceInventory(_productIds);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/priceInventory/export', {
+    ...queryParams.value
+  }, `priceInventory_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 317 - 0
src/views/product/program/index.vue

@@ -0,0 +1,317 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="方案编号" prop="programNo">
+              <el-input v-model="queryParams.programNo" placeholder="请输入方案编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="方案标题" prop="title">
+              <el-input v-model="queryParams.title" placeholder="请输入方案标题" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="方案描述" prop="describe">
+              <el-input v-model="queryParams.describe" placeholder="请输入方案描述" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="所属分类编号或名称" prop="category">
+              <el-input v-model="queryParams.category" placeholder="请输入所属分类编号或名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否显示:1=是,0=否" prop="isShow">
+              <el-input v-model="queryParams.isShow" placeholder="请输入是否显示:1=是,0=否" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="所属行业编号或名称" prop="industry">
+              <el-input v-model="queryParams.industry" placeholder="请输入所属行业编号或名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="适配产品/设备编号" prop="adaptNo">
+              <el-input v-model="queryParams.adaptNo" placeholder="请输入适配产品/设备编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="标签" prop="label">
+              <el-input v-model="queryParams.label" placeholder="请输入标签" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="内部广告内容" prop="innerAdvert">
+              <el-input v-model="queryParams.innerAdvert" placeholder="请输入内部广告内容" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:program:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:program:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:program:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:program:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="programList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键,自增ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="方案编号" align="center" prop="programNo" />
+        <el-table-column label="方案标题" align="center" prop="title" />
+        <el-table-column label="方案描述" align="center" prop="describe" />
+        <el-table-column label="所属分类编号或名称" align="center" prop="category" />
+        <el-table-column label="是否显示:1=是,0=否" align="center" prop="isShow" />
+        <el-table-column label="封面图片URL" align="center" prop="coverImageUrl" width="100">
+          <template #default="scope">
+            <image-preview :src="scope.row.coverImageUrl" :width="50" :height="50"/>
+          </template>
+        </el-table-column>
+        <el-table-column label="方案内容" align="center" prop="content" />
+        <el-table-column label="所属行业编号或名称" align="center" prop="industry" />
+        <el-table-column label="适配产品/设备编号" align="center" prop="adaptNo" />
+        <el-table-column label="标签" align="center" prop="label" />
+        <el-table-column label="内部广告内容" align="center" prop="innerAdvert" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:program:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:program:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品解决方案/项目方案对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="programFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="方案编号" prop="programNo">
+          <el-input v-model="form.programNo" placeholder="请输入方案编号" />
+        </el-form-item>
+        <el-form-item label="方案标题" prop="title">
+          <el-input v-model="form.title" placeholder="请输入方案标题" />
+        </el-form-item>
+        <el-form-item label="方案描述" prop="describe">
+            <el-input v-model="form.describe" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="所属分类编号或名称" prop="category">
+          <el-input v-model="form.category" placeholder="请输入所属分类编号或名称" />
+        </el-form-item>
+        <el-form-item label="是否显示:1=是,0=否" prop="isShow">
+          <el-input v-model="form.isShow" placeholder="请输入是否显示:1=是,0=否" />
+        </el-form-item>
+        <el-form-item label="封面图片URL" prop="coverImage">
+          <image-upload v-model="form.coverImage"/>
+        </el-form-item>
+        <el-form-item label="方案内容">
+          <editor v-model="form.content" :min-height="192"/>
+        </el-form-item>
+        <el-form-item label="所属行业编号或名称" prop="industry">
+          <el-input v-model="form.industry" placeholder="请输入所属行业编号或名称" />
+        </el-form-item>
+        <el-form-item label="适配产品/设备编号" prop="adaptNo">
+          <el-input v-model="form.adaptNo" placeholder="请输入适配产品/设备编号" />
+        </el-form-item>
+        <el-form-item label="标签" prop="label">
+          <el-input v-model="form.label" placeholder="请输入标签" />
+        </el-form-item>
+        <el-form-item label="内部广告内容" prop="innerAdvert">
+          <el-input v-model="form.innerAdvert" placeholder="请输入内部广告内容" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Program" lang="ts">
+import { listProgram, getProgram, delProgram, addProgram, updateProgram } from '@/api/product/program';
+import { ProgramVO, ProgramQuery, ProgramForm } from '@/api/product/program/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const programList = ref<ProgramVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const programFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: ProgramForm = {
+  id: undefined,
+  programNo: undefined,
+  title: undefined,
+  describe: undefined,
+  category: undefined,
+  isShow: undefined,
+  coverImage: undefined,
+  content: undefined,
+  industry: undefined,
+  adaptNo: undefined,
+  label: undefined,
+  innerAdvert: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<ProgramForm, ProgramQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    programNo: undefined,
+    title: undefined,
+    describe: undefined,
+    category: undefined,
+    isShow: undefined,
+    coverImage: undefined,
+    content: undefined,
+    industry: undefined,
+    adaptNo: undefined,
+    label: undefined,
+    innerAdvert: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    content: [
+      { required: true, message: "方案内容不能为空", trigger: "blur" }
+    ],
+    label: [
+      { required: true, message: "标签不能为空", trigger: "blur" }
+    ],
+    innerAdvert: [
+      { required: true, message: "内部广告内容不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品解决方案/项目方案列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listProgram(queryParams.value);
+  programList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  programFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: ProgramVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品解决方案/项目方案";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: ProgramVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getProgram(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品解决方案/项目方案";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  programFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateProgram(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addProgram(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: ProgramVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品解决方案/项目方案编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delProgram(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/program/export', {
+    ...queryParams.value
+  }, `program_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 235 - 0
src/views/product/programLink/index.vue

@@ -0,0 +1,235 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="项目编号" prop="programId">
+              <el-input v-model="queryParams.programId" placeholder="请输入项目编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="产品编号" prop="productId">
+              <el-input v-model="queryParams.productId" placeholder="请输入产品编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:programLink:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:programLink:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:programLink:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:programLink:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="programLinkList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="项目编号" align="center" prop="programId" />
+        <el-table-column label="产品编号" align="center" prop="productId" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:programLink:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:programLink:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改项目方案关联对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="programLinkFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="项目编号" prop="programId">
+          <el-input v-model="form.programId" placeholder="请输入项目编号" />
+        </el-form-item>
+        <el-form-item label="产品编号" prop="productId">
+          <el-input v-model="form.productId" placeholder="请输入产品编号" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="ProgramLink" lang="ts">
+import { listProgramLink, getProgramLink, delProgramLink, addProgramLink, updateProgramLink } from '@/api/product/programLink';
+import { ProgramLinkVO, ProgramLinkQuery, ProgramLinkForm } from '@/api/product/programLink/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const programLinkList = ref<ProgramLinkVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const programLinkFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: ProgramLinkForm = {
+  id: undefined,
+  programId: undefined,
+  productId: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<ProgramLinkForm, ProgramLinkQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    programId: undefined,
+    productId: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    programId: [
+      { required: true, message: "项目编号不能为空", trigger: "blur" }
+    ],
+    productId: [
+      { required: true, message: "产品编号不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询项目方案关联列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listProgramLink(queryParams.value);
+  programLinkList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  programLinkFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: ProgramLinkVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加项目方案关联";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: ProgramLinkVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getProgramLink(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改项目方案关联";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  programLinkFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateProgramLink(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addProgramLink(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: ProgramLinkVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除项目方案关联编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delProgramLink(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/programLink/export', {
+    ...queryParams.value
+  }, `programLink_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 256 - 0
src/views/product/recommend/index.vue

@@ -0,0 +1,256 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="推荐编号" prop="recommendNo">
+              <el-input v-model="queryParams.recommendNo" placeholder="请输入推荐编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="推荐名称" prop="recommendName">
+              <el-input v-model="queryParams.recommendName" placeholder="请输入推荐名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="推荐位描述" prop="recommendDescribe">
+              <el-input v-model="queryParams.recommendDescribe" placeholder="请输入推荐位描述" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否显示:1=显示,0=隐藏" prop="isShow">
+              <el-input v-model="queryParams.isShow" placeholder="请输入是否显示:1=显示,0=隐藏" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="推荐封面图片路径或URL" prop="recommendCoverphoto">
+              <el-input v-model="queryParams.recommendCoverphoto" placeholder="请输入推荐封面图片路径或URL" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:recommend:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:recommend:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:recommend:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:recommend:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="recommendList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键,自增ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="推荐编号" align="center" prop="recommendNo" />
+        <el-table-column label="推荐名称" align="center" prop="recommendName" />
+        <el-table-column label="推荐位描述" align="center" prop="recommendDescribe" />
+        <el-table-column label="是否显示:1=显示,0=隐藏" align="center" prop="isShow" />
+        <el-table-column label="推荐封面图片路径或URL" align="center" prop="recommendCoverphoto" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:recommend:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:recommend:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品推荐位配置对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="recommendFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="推荐编号" prop="recommendNo">
+          <el-input v-model="form.recommendNo" placeholder="请输入推荐编号" />
+        </el-form-item>
+        <el-form-item label="推荐名称" prop="recommendName">
+          <el-input v-model="form.recommendName" placeholder="请输入推荐名称" />
+        </el-form-item>
+        <el-form-item label="推荐位描述" prop="recommendDescribe">
+          <el-input v-model="form.recommendDescribe" placeholder="请输入推荐位描述" />
+        </el-form-item>
+        <el-form-item label="是否显示:1=显示,0=隐藏" prop="isShow">
+          <el-input v-model="form.isShow" placeholder="请输入是否显示:1=显示,0=隐藏" />
+        </el-form-item>
+        <el-form-item label="推荐封面图片路径或URL" prop="recommendCoverphoto">
+          <el-input v-model="form.recommendCoverphoto" placeholder="请输入推荐封面图片路径或URL" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Recommend" lang="ts">
+import { listRecommend, getRecommend, delRecommend, addRecommend, updateRecommend } from '@/api/product/recommend';
+import { RecommendVO, RecommendQuery, RecommendForm } from '@/api/product/recommend/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const recommendList = ref<RecommendVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const recommendFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: RecommendForm = {
+  id: undefined,
+  recommendNo: undefined,
+  recommendName: undefined,
+  recommendDescribe: undefined,
+  isShow: undefined,
+  recommendCoverphoto: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<RecommendForm, RecommendQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    recommendNo: undefined,
+    recommendName: undefined,
+    recommendDescribe: undefined,
+    isShow: undefined,
+    recommendCoverphoto: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品推荐位配置列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listRecommend(queryParams.value);
+  recommendList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  recommendFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: RecommendVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品推荐位配置";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: RecommendVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getRecommend(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品推荐位配置";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  recommendFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateRecommend(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addRecommend(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: RecommendVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品推荐位配置编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delRecommend(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/recommend/export', {
+    ...queryParams.value
+  }, `recommend_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 235 - 0
src/views/product/recommendLink/index.vue

@@ -0,0 +1,235 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="项目编号" prop="recommendId">
+              <el-input v-model="queryParams.recommendId" placeholder="请输入项目编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="产品编号" prop="productId">
+              <el-input v-model="queryParams.productId" placeholder="请输入产品编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:recommendLink:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:recommendLink:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:recommendLink:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:recommendLink:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="recommendLinkList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="项目编号" align="center" prop="recommendId" />
+        <el-table-column label="产品编号" align="center" prop="productId" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:recommendLink:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:recommendLink:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品推荐关联对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="recommendLinkFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="项目编号" prop="recommendId">
+          <el-input v-model="form.recommendId" placeholder="请输入项目编号" />
+        </el-form-item>
+        <el-form-item label="产品编号" prop="productId">
+          <el-input v-model="form.productId" placeholder="请输入产品编号" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="RecommendLink" lang="ts">
+import { listRecommendLink, getRecommendLink, delRecommendLink, addRecommendLink, updateRecommendLink } from '@/api/product/recommendLink';
+import { RecommendLinkVO, RecommendLinkQuery, RecommendLinkForm } from '@/api/product/recommendLink/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const recommendLinkList = ref<RecommendLinkVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const recommendLinkFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: RecommendLinkForm = {
+  id: undefined,
+  recommendId: undefined,
+  productId: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<RecommendLinkForm, RecommendLinkQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    recommendId: undefined,
+    productId: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    recommendId: [
+      { required: true, message: "项目编号不能为空", trigger: "blur" }
+    ],
+    productId: [
+      { required: true, message: "产品编号不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品推荐关联列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listRecommendLink(queryParams.value);
+  recommendLinkList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  recommendLinkFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: RecommendLinkVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品推荐关联";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: RecommendLinkVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getRecommendLink(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品推荐关联";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  recommendLinkFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateRecommendLink(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addRecommendLink(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: RecommendLinkVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品推荐关联编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delRecommendLink(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/recommendLink/export', {
+    ...queryParams.value
+  }, `recommendLink_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 244 - 0
src/views/product/specs/index.vue

@@ -0,0 +1,244 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="主产品编号" prop="productId">
+              <el-input v-model="queryParams.productId" placeholder="请输入主产品编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="关联的规格产品id列表" prop="specsProductIds">
+              <el-input v-model="queryParams.specsProductIds" placeholder="请输入关联的规格产品id列表" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否单向关联:0=双向,1=单向" prop="isUnidirectional">
+              <el-input v-model="queryParams.isUnidirectional" placeholder="请输入是否单向关联:0=双向,1=单向" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:specs:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:specs:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:specs:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:specs:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="specsList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="主产品编号" align="center" prop="productId" />
+        <el-table-column label="关联的规格产品id列表" align="center" prop="specsProductIds" />
+        <el-table-column label="是否单向关联:0=双向,1=单向" align="center" prop="isUnidirectional" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:specs:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:specs:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品规格关联对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="specsFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="主产品编号" prop="productId">
+          <el-input v-model="form.productId" placeholder="请输入主产品编号" />
+        </el-form-item>
+        <el-form-item label="关联的规格产品id列表" prop="specsProductIds">
+            <el-input v-model="form.specsProductIds" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="是否单向关联:0=双向,1=单向" prop="isUnidirectional">
+          <el-input v-model="form.isUnidirectional" placeholder="请输入是否单向关联:0=双向,1=单向" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Specs" lang="ts">
+import { listSpecs, getSpecs, delSpecs, addSpecs, updateSpecs } from '@/api/product/specs';
+import { SpecsVO, SpecsQuery, SpecsForm } from '@/api/product/specs/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const specsList = ref<SpecsVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const specsFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: SpecsForm = {
+  id: undefined,
+  productId: undefined,
+  specsProductIds: undefined,
+  isUnidirectional: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<SpecsForm, SpecsQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    productId: undefined,
+    specsProductIds: undefined,
+    isUnidirectional: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    productId: [
+      { required: true, message: "主产品编号不能为空", trigger: "blur" }
+    ],
+    specsProductIds: [
+      { required: true, message: "关联的规格产品id列表不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品规格关联列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listSpecs(queryParams.value);
+  specsList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  specsFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: SpecsVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品规格关联";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: SpecsVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getSpecs(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品规格关联";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  specsFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateSpecs(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addSpecs(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: SpecsVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品规格关联编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delSpecs(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/specs/export', {
+    ...queryParams.value
+  }, `specs_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 271 - 0
src/views/product/taxrate/index.vue

@@ -0,0 +1,271 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="税率编号" prop="taxrateNo">
+              <el-input v-model="queryParams.taxrateNo" placeholder="请输入税率编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="税率名称" prop="taxrateName">
+              <el-input v-model="queryParams.taxrateName" placeholder="请输入税率名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="税率值)" prop="taxrate">
+              <el-input v-model="queryParams.taxrate" placeholder="请输入税率值)" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="数据来源" prop="dataSource">
+              <el-input v-model="queryParams.dataSource" placeholder="请输入数据来源" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否显示:1=是,0=否" prop="isShow">
+              <el-input v-model="queryParams.isShow" placeholder="请输入是否显示:1=是,0=否" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:taxrate:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:taxrate:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:taxrate:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:taxrate:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="taxrateList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键,自增ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="税率编号" align="center" prop="taxrateNo" />
+        <el-table-column label="税率名称" align="center" prop="taxrateName" />
+        <el-table-column label="税率值)" align="center" prop="taxrate" />
+        <el-table-column label="数据来源" align="center" prop="dataSource" />
+        <el-table-column label="是否显示:1=是,0=否" align="center" prop="isShow" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:taxrate:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:taxrate:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品税率配置对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="taxrateFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="税率编号" prop="taxrateNo">
+          <el-input v-model="form.taxrateNo" placeholder="请输入税率编号" />
+        </el-form-item>
+        <el-form-item label="税率名称" prop="taxrateName">
+          <el-input v-model="form.taxrateName" placeholder="请输入税率名称" />
+        </el-form-item>
+        <el-form-item label="税率值)" prop="taxrate">
+          <el-input v-model="form.taxrate" placeholder="请输入税率值)" />
+        </el-form-item>
+        <el-form-item label="数据来源" prop="dataSource">
+          <el-input v-model="form.dataSource" placeholder="请输入数据来源" />
+        </el-form-item>
+        <el-form-item label="是否显示:1=是,0=否" prop="isShow">
+          <el-input v-model="form.isShow" placeholder="请输入是否显示:1=是,0=否" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Taxrate" lang="ts">
+import { listTaxrate, getTaxrate, delTaxrate, addTaxrate, updateTaxrate } from '@/api/product/taxrate';
+import { TaxrateVO, TaxrateQuery, TaxrateForm } from '@/api/product/taxrate/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const taxrateList = ref<TaxrateVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const taxrateFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: TaxrateForm = {
+  id: undefined,
+  taxrateNo: undefined,
+  taxrateName: undefined,
+  taxrate: undefined,
+  dataSource: undefined,
+  isShow: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<TaxrateForm, TaxrateQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    taxrateNo: undefined,
+    taxrateName: undefined,
+    taxrate: undefined,
+    dataSource: undefined,
+    isShow: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    taxrateNo: [
+      { required: true, message: "税率编号不能为空", trigger: "blur" }
+    ],
+    taxrateName: [
+      { required: true, message: "税率名称不能为空", trigger: "blur" }
+    ],
+    taxrate: [
+      { required: true, message: "税率值)不能为空", trigger: "blur" }
+    ],
+    dataSource: [
+      { required: true, message: "数据来源不能为空", trigger: "blur" }
+    ],
+    isShow: [
+      { required: true, message: "是否显示:1=是,0=否不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品税率配置列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listTaxrate(queryParams.value);
+  taxrateList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  taxrateFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: TaxrateVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品税率配置";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: TaxrateVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getTaxrate(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品税率配置";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  taxrateFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateTaxrate(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addTaxrate(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: TaxrateVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品税率配置编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delTaxrate(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/taxrate/export', {
+    ...queryParams.value
+  }, `taxrate_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 259 - 0
src/views/product/unit/index.vue

@@ -0,0 +1,259 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="单位编号" prop="unitNo">
+              <el-input v-model="queryParams.unitNo" placeholder="请输入单位编号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="单位名称" prop="unitName">
+              <el-input v-model="queryParams.unitName" placeholder="请输入单位名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="数据来源" prop="dataSource">
+              <el-input v-model="queryParams.dataSource" placeholder="请输入数据来源" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="是否显示:1=是,0=否" prop="isShow">
+              <el-input v-model="queryParams.isShow" placeholder="请输入是否显示:1=是,0=否" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:unit:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:unit:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:unit:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:unit:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="unitList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键,自增ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="单位编号" align="center" prop="unitNo" />
+        <el-table-column label="单位名称" align="center" prop="unitName" />
+        <el-table-column label="数据来源" align="center" prop="dataSource" />
+        <el-table-column label="是否显示:1=是,0=否" align="center" prop="isShow" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:unit:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:unit:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品计量单位对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="unitFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="单位编号" prop="unitNo">
+          <el-input v-model="form.unitNo" placeholder="请输入单位编号" />
+        </el-form-item>
+        <el-form-item label="单位名称" prop="unitName">
+          <el-input v-model="form.unitName" placeholder="请输入单位名称" />
+        </el-form-item>
+        <el-form-item label="数据来源" prop="dataSource">
+          <el-input v-model="form.dataSource" placeholder="请输入数据来源" />
+        </el-form-item>
+        <el-form-item label="是否显示:1=是,0=否" prop="isShow">
+          <el-input v-model="form.isShow" placeholder="请输入是否显示:1=是,0=否" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Unit" lang="ts">
+import { listUnit, getUnit, delUnit, addUnit, updateUnit } from '@/api/product/unit';
+import { UnitVO, UnitQuery, UnitForm } from '@/api/product/unit/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const unitList = ref<UnitVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const unitFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: UnitForm = {
+  id: undefined,
+  unitNo: undefined,
+  unitName: undefined,
+  dataSource: undefined,
+  isShow: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<UnitForm, UnitQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    unitNo: undefined,
+    unitName: undefined,
+    dataSource: undefined,
+    isShow: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    unitNo: [
+      { required: true, message: "单位编号不能为空", trigger: "blur" }
+    ],
+    unitName: [
+      { required: true, message: "单位名称不能为空", trigger: "blur" }
+    ],
+    dataSource: [
+      { required: true, message: "数据来源不能为空", trigger: "blur" }
+    ],
+    isShow: [
+      { required: true, message: "是否显示:1=是,0=否不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品计量单位列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listUnit(queryParams.value);
+  unitList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  unitFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: UnitVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品计量单位";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: UnitVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getUnit(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品计量单位";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  unitFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateUnit(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addUnit(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: UnitVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品计量单位编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delUnit(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/unit/export', {
+    ...queryParams.value
+  }, `unit_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 235 - 0
src/views/product/volumeUnit/index.vue

@@ -0,0 +1,235 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="体积单位名称" prop="unitName">
+              <el-input v-model="queryParams.unitName" placeholder="请输入体积单位名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="数据来源" prop="dataSource">
+              <el-input v-model="queryParams.dataSource" placeholder="请输入数据来源" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:volumeUnit:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:volumeUnit:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:volumeUnit:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:volumeUnit:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="volumeUnitList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="体积单位名称" align="center" prop="unitName" />
+        <el-table-column label="数据来源" align="center" prop="dataSource" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:volumeUnit:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:volumeUnit:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品体积单位对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="volumeUnitFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="体积单位名称" prop="unitName">
+          <el-input v-model="form.unitName" placeholder="请输入体积单位名称" />
+        </el-form-item>
+        <el-form-item label="数据来源" prop="dataSource">
+          <el-input v-model="form.dataSource" placeholder="请输入数据来源" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="VolumeUnit" lang="ts">
+import { listVolumeUnit, getVolumeUnit, delVolumeUnit, addVolumeUnit, updateVolumeUnit } from '@/api/product/volumeUnit';
+import { VolumeUnitVO, VolumeUnitQuery, VolumeUnitForm } from '@/api/product/volumeUnit/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const volumeUnitList = ref<VolumeUnitVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const volumeUnitFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: VolumeUnitForm = {
+  id: undefined,
+  unitName: undefined,
+  dataSource: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<VolumeUnitForm, VolumeUnitQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    unitName: undefined,
+    dataSource: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    unitName: [
+      { required: true, message: "体积单位名称不能为空", trigger: "blur" }
+    ],
+    dataSource: [
+      { required: true, message: "数据来源不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品体积单位列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listVolumeUnit(queryParams.value);
+  volumeUnitList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  volumeUnitFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: VolumeUnitVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品体积单位";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: VolumeUnitVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getVolumeUnit(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品体积单位";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  volumeUnitFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateVolumeUnit(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addVolumeUnit(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: VolumeUnitVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品体积单位编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delVolumeUnit(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/volumeUnit/export', {
+    ...queryParams.value
+  }, `volumeUnit_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 235 - 0
src/views/product/weightUnit/index.vue

@@ -0,0 +1,235 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="重量单位名称" prop="unitName">
+              <el-input v-model="queryParams.unitName" placeholder="请输入重量单位名称" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="数据来源" prop="dataSource">
+              <el-input v-model="queryParams.dataSource" placeholder="请输入数据来源" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="平台标识" prop="platformCode">
+              <el-input v-model="queryParams.platformCode" placeholder="请输入平台标识" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['product:weightUnit:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['product:weightUnit:edit']">修改</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['product:weightUnit:remove']">删除</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['product:weightUnit:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="weightUnitList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键ID" align="center" prop="id" v-if="true" />
+        <el-table-column label="重量单位名称" align="center" prop="unitName" />
+        <el-table-column label="数据来源" align="center" prop="dataSource" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['product:weightUnit:edit']"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['product:weightUnit:remove']"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改产品重量单位对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+      <el-form ref="weightUnitFormRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="重量单位名称" prop="unitName">
+          <el-input v-model="form.unitName" placeholder="请输入重量单位名称" />
+        </el-form-item>
+        <el-form-item label="数据来源" prop="dataSource">
+          <el-input v-model="form.dataSource" placeholder="请输入数据来源" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="WeightUnit" lang="ts">
+import { listWeightUnit, getWeightUnit, delWeightUnit, addWeightUnit, updateWeightUnit } from '@/api/product/weightUnit';
+import { WeightUnitVO, WeightUnitQuery, WeightUnitForm } from '@/api/product/weightUnit/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const weightUnitList = ref<WeightUnitVO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+const weightUnitFormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+  visible: false,
+  title: ''
+});
+
+const initFormData: WeightUnitForm = {
+  id: undefined,
+  unitName: undefined,
+  dataSource: undefined,
+  remark: undefined,
+}
+const data = reactive<PageData<WeightUnitForm, WeightUnitQuery>>({
+  form: {...initFormData},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    unitName: undefined,
+    dataSource: undefined,
+    platformCode: undefined,
+    params: {
+    }
+  },
+  rules: {
+    unitName: [
+      { required: true, message: "重量单位名称不能为空", trigger: "blur" }
+    ],
+    dataSource: [
+      { required: true, message: "数据来源不能为空", trigger: "blur" }
+    ],
+    remark: [
+      { required: true, message: "备注不能为空", trigger: "blur" }
+    ],
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询产品重量单位列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listWeightUnit(queryParams.value);
+  weightUnitList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+}
+
+/** 取消按钮 */
+const cancel = () => {
+  reset();
+  dialog.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+  form.value = {...initFormData};
+  weightUnitFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+}
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: WeightUnitVO[]) => {
+  ids.value = selection.map(item => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  reset();
+  dialog.visible = true;
+  dialog.title = "添加产品重量单位";
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: WeightUnitVO) => {
+  reset();
+  const _id = row?.id || ids.value[0]
+  const res = await getWeightUnit(_id);
+  Object.assign(form.value, res.data);
+  dialog.visible = true;
+  dialog.title = "修改产品重量单位";
+}
+
+/** 提交按钮 */
+const submitForm = () => {
+  weightUnitFormRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      if (form.value.id) {
+        await updateWeightUnit(form.value).finally(() =>  buttonLoading.value = false);
+      } else {
+        await addWeightUnit(form.value).finally(() =>  buttonLoading.value = false);
+      }
+      proxy?.$modal.msgSuccess("操作成功");
+      dialog.visible = false;
+      await getList();
+    }
+  });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: WeightUnitVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除产品重量单位编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await delWeightUnit(_ids);
+  proxy?.$modal.msgSuccess("删除成功");
+  await getList();
+}
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download('product/weightUnit/export', {
+    ...queryParams.value
+  }, `weightUnit_${new Date().getTime()}.xlsx`)
+}
+
+onMounted(() => {
+  getList();
+});
+</script>