Skip to content

【SRM数据看板】基础数据管理 — 详细设计文档

版本:V3.3
日期:2025-07-11
状态:修订稿
涉及系统:SRM 租户管理系统、SRM 品牌方管理系统
前置依赖:商品主表 goods_base 已有


1. 文档概述

1.1 目的

本文档基于《【SRM数据看板】基础数据管理需求规格说明书 V2.0》,对商品类目管理、属性库管理、商品档案管理等功能模块进行详细设计。

渠道表和部门表已存在,不在本次设计范围内。

1.2 设计范围

模块 功能点 备注
商品类目管理 类目列表、新建/编辑类目、类目属性模板 新建表
属性库管理 属性列表、新增/编辑/删除属性 新建表
商品档案管理 新建商品(优化) 基于已有 goods_base
历史商品数据割接 预制默认类目 + 类目变更机制 通过 catalog_id 判断

1.3 不在本迭代范围

  • 渠道/部门表变更(已存在)
  • 变更日志功能(含变更日志表,本迭代不建表;仅类目和属性需要,后续迭代补充)
  • 商品批量导入(已移除)
  • catalog_id 自动填充(由割接方案处理)

2. 核心设计决策

2.1 商品数据存储方案(方案 B)

goods_base 固定字段不动
    ↓
通用属性 → 类目模板控制显示顺序/可见性 → 存储到 goods_base 固定列
类目属性 → 类目模板定义可用属性 → 存储到动态属性表

2.2 编码唯一性规则

业务对象 唯一性范围
渠道编码 租户内唯一
部门编码 租户内唯一
类目编码 全局唯一(数据按租户隔离)
商品编码 全局唯一

2.3 价格处理规则

场景 处理方式
页面输入 用户输入小数,如 99.00
页面显示 保留 2 位小数
数据库存储 金额 × 10000 存为整数
读取展示 数据库值 ÷ 10000 还原

2.4 权限控制

  • 仅菜单按钮级权限

2.5 重量字段

  • 数字类型,单位 g(克)

2.6 历史商品割接策略

  • 建立预制默认类目 CAT_DEFAULT,仅含 14 项通用属性,无类目属性
  • 历史商品 catalog_id 统一指向 CAT_DEFAULT
  • 通过 catalog_id = 'cat_default' 判断是否允许类目变更,不需要额外字段
  • 类目属性允许先保存后补填

3. 数据模型设计

3.1 公共字段规范

所有新建表必须包含以下标准字段:

字段名 类型 默认值 说明
id VARCHAR(64) 主键
create_by VARCHAR(64) NULL 创建者
create_date DATETIME CURRENT_TIMESTAMP 创建时间
update_by VARCHAR(64) NULL 更新者
update_date DATETIME CURRENT_TIMESTAMP 更新时间
remarks VARCHAR(256) NULL 备注
del_flag VARCHAR(2) '0' 删除标记 1=已删除, 0=未删除

3.2 商品类目表 (t_goods_catalog)

字段名 数据类型 必填 说明
id VARCHAR(64) PK 主键
catalog_code VARCHAR(64) 类目编码,全局唯一
catalog_name VARCHAR(64) 类目名称
parent_id VARCHAR(64) 父类目 ID,NULL 为一级
parent_ids VARCHAR(256) 物化路径:所有上级+自己ID,逗号分隔,如 "1,5,12"
level TINYINT 层级:1/2/3,最多三级
status VARCHAR(16) 状态:1-启用,0-停用
description VARCHAR(512) 类目说明
has_product TINYINT 是否已关联商品:0-否,1-是(默认0,商品创建时置1)
category_type VARCHAR(20) 类目类型:DEFAULT=预制默认类目,NORMAL=正常业务类目(默认 NORMAL)
+ 公共字段 见 3.1

业务规则: - category_type=DEFAULT 的预制类目:不可删除、不可停用、不可修改模板 - 预制类目 has_product 始终为 1 - 新建商品时类目选择器过滤掉 DEFAULT 类目

索引

索引名 字段 类型
uk_catalog_code catalog_code UNIQUE(全局)
idx_parent_ids parent_ids NORMAL(支持 LIKE 查询子孙)
idx_parent_id parent_id NORMAL
idx_category_type category_type NORMAL

3.3 属性库表 (goods_attribute)

字段名 数据类型 必填 说明
id VARCHAR(64) PK 主键
attr_type TINYINT 属性类型:1-通用属性(平台),2-类目属性
attr_name VARCHAR(128) 属性名称
data_type TINYINT 数据类型:1-文本,2-单选,3-多选,4-数字,5-数值区间,6-图片上传
options TEXT 选项值 JSON(单选/多选时使用)
regex_pattern VARCHAR(256) 正则表达式
description VARCHAR(512) 属性说明(≤200字)
is_builtin TINYINT 是否内置:1-是(不可删除),0-否
+ 公共字段 见 3.1

业务规则: - 属性库由总后台统一维护(无 tenant_id) - 属性没有启用/停用状态 - 内置属性(is_builtin=1)不可删除 - 数值区间类型的单位通过 goods_attribute_option(option_type=2)管理

索引

索引名 字段 类型
idx_attr_type attr_type NORMAL

3.4 属性选项值表 (goods_attribute_option)

字段名 数据类型 必填 说明
id VARCHAR(64) PK 主键
attribute_id VARCHAR(64) 属性 ID(FK → goods_attribute.id)
option_value VARCHAR(128) 选项值文本
option_type TINYINT 选项类型:1-属性选项值,2-单位选项值(数值区间用)
sort_order INT 排序号
+ 公共字段 见 3.1

3.5 类目属性模板组表 (goods_catalog_template_group)

字段名 数据类型 必填 说明
id VARCHAR(64) PK 主键
catalog_id VARCHAR(64) 类目 ID(FK → t_goods_catalog.id)
group_name VARCHAR(32) 属性组名称(≤12字符)
group_desc VARCHAR(512) 属性组说明
group_sort INT 属性组排序
+ 公共字段 见 3.1

3.6 类目属性模板明细表 (goods_catalog_template_item)

字段名 数据类型 必填 说明
id VARCHAR(64) PK 主键
group_id VARCHAR(64) 模板属性组 ID(FK → goods_catalog_template_group.id)
attribute_id VARCHAR(64) 属性 ID(FK → goods_attribute.id)
is_required TINYINT 是否必填:1-是,0-否
is_visible TINYINT 是否显示:1-显示,0-隐藏(通用属性用)
sort_order INT 排序号
+ 公共字段 见 3.1

3.7 商品动态属性值表 (goods_product_attr_value)

字段名 数据类型 必填 说明
id VARCHAR(64) PK 主键
product_id VARCHAR(64) 商品 ID(FK → goods_base.id)
attribute_id VARCHAR(64) 属性 ID(FK → goods_attribute.id)
attr_value TEXT 属性值(文本/单选/数值)
attr_values TEXT 多选值 JSON(如 ["红色","蓝色"])
attr_value_min DECIMAL(18,4) 数值区间最小值
attr_value_max DECIMAL(18,4) 数值区间最大值
+ 公共字段 见 3.1

索引

索引名 字段 类型
uk_product_attr product_id + attribute_id UNIQUE
idx_attribute_id attribute_id NORMAL

3.8 变更日志表 (goods_change_log)

⚠️ 本迭代不建表。仅类目和属性需要变更日志,后续迭代补充。

预留表结构(点击展开) | 字段名 | 数据类型 | 必填 | 说明 | |--------|----------|------|------| | id | VARCHAR(64) | PK | 主键 | | biz_type | VARCHAR(32) | ✅ | 业务类型:CATALOG / ATTRIBUTE | | biz_id | VARCHAR(64) | ✅ | 业务对象 ID | | action | VARCHAR(16) | ✅ | 操作类型:CREATE / UPDATE / DELETE | | before_data | TEXT | ❌ | 变更前数据 JSON | | after_data | TEXT | ❌ | 变更后数据 JSON | | tenant_id | VARCHAR(64) | ✅ | 租户 ID | | + 公共字段 | — | — | 见 3.1(create_by 为操作人) | **索引**: | 索引名 | 字段 | 类型 | |--------|------|------| | idx_biz | biz_type, biz_id | NORMAL | | idx_create_date | create_date | NORMAL |

~~3.9 导入任务表 (goods_import_task)~~

已删除:本迭代不需要导入任务表。


3.10 goods_base 已有表

goods_base 为已有表,不新增任何字段。类目变更判断仅通过 catalog_id 判断: - catalog_id = 'cat_default' → 允许切换类目 - catalog_id ≠ 'cat_default' → 不允许切换类目

不需要 is_catalog_confirmed 字段。


3.11 ER 关系图

goods_attribute ──1:N──→ goods_attribute_option
     │
     │ (模板引用)
     ↓
goods_catalog_template_group ──1:N──→ goods_catalog_template_item
     │                                      │
     │ (所属类目)                       (引用属性)
     ↓                                      │
t_goods_catalog ←───────────────────────────┘
  ├── category_type = NORMAL (业务类目)
  └── category_type = DEFAULT (预制默认类目)
     │
     │ (商品选择类目 → goods_base.catalog_id)
     ↓
goods_base (已有,不新增字段)
  └── catalog_id = 'cat_default' → 允许变更类目
  └── catalog_id ≠ 'cat_default' → 不允许变更类目
     │
     └──1:N──→ goods_product_attr_value
                    │
                    └──→ goods_attribute

4. 接口设计

4.1 商品类目管理接口

4.1.1 查询类目列表

GET /api/v1/goods-catalog/list

请求参数

参数 类型 必填 说明
keyword String 类目编码/名称模糊搜索
status String 状态
startDate String 创建日期起
endDate String 创建日期止

4.1.2 获取类目树

GET /api/v1/goods-catalog/tree

业务规则: - 新建商品调用时,过滤掉 category_type='DEFAULT',仅返回 NORMAL 类目 - 类目管理页面调用时,返回全部类目(含 DEFAULT)

响应体

{
  "code": 200,
  "data": [
    {
      "id": "1",
      "catalogCode": "CAT001",
      "catalogName": "婴童服饰鞋配",
      "categoryType": "NORMAL",
      "level": 1,
      "children": [
        {
          "id": "2",
          "catalogCode": "CAT001-01",
          "catalogName": "婴童内着家居服",
          "categoryType": "NORMAL",
          "level": 2,
          "children": []
        }
      ]
    }
  ]
}

4.1.3 新建类目

POST /api/v1/goods-catalog

业务逻辑

  1. 校验类目编码全局唯一
  2. 校验层级不超过 3 级
  3. 若有 parentId,从父类目继承模板(深拷贝)
  4. category_type 强制为 NORMAL(不允许通过 API 创建 DEFAULT 类目)

请求体

{
  "catalogCode": "CAT001",
  "catalogName": "婴童服饰鞋配",
  "parentId": null,
  "level": 1,
  "description": "",
  "status": "1",
  "templateGroups": [
    {
      "groupName": "基础信息",
      "groupDesc": "商品基础属性",
      "groupSort": 1,
      "items": [
        {
          "attributeId": "attr_001",
          "isRequired": 1,
          "isVisible": 1,
          "sortOrder": 1
        }
      ]
    }
  ]
}

4.1.4 编辑类目

PUT /api/v1/goods-catalog/{id}

业务逻辑

  1. category_type=DEFAULT 的类目禁止编辑
  2. 若类目已关联商品:只允许新增属性到模板,不允许删除或修改已有属性
  3. 若类目未关联商品:允许完整 CRUD
  4. 修改模板后级联影响子类目:
  5. 子级属性 = 子级自有属性 + 上级属性(去重)
  6. 上级新增属性同步到子级和已有商品

4.1.5 删除类目

DELETE /api/v1/goods-catalog/{id}

业务校验: - category_type=DEFAULT 的类目禁止删除 - 类目下存在商品或有子类目时禁止删除

4.1.6 预览类目商品模板

GET /api/v1/goods-catalog/{id}/template-preview

返回该类目完整属性模板(含继承的所有层级属性,去重后),用于新建/编辑商品时展示

响应体

{
  "code": 200,
  "data": {
    "catalogId": "1",
    "catalogName": "婴童服饰鞋配",
    "groups": [
      {
        "groupId": "g1",
        "groupName": "基础信息",
        "groupSort": 1,
        "items": [
          {
            "attributeId": "attr_001",
            "attrName": "商品编码",
            "attrType": 1,
            "dataType": 1,
            "isRequired": 1,
            "isVisible": 1,
            "sortOrder": 1,
            "isBuiltin": 1,
            "mappedField": "code"
          }
        ]
      }
    ]
  }
}

4.2 属性库管理接口

4.2.1 查询属性列表

GET /api/v1/attribute/list

请求参数

参数 类型 必填 说明
attrType Integer 属性类型筛选
keyword String 属性名称搜索

4.2.2 新增属性

POST /api/v1/attribute

请求体

{
  "attrType": 2,
  "attrName": "适合年龄",
  "dataType": 5,
  "options": null,
  "regexPattern": null,
  "description": "适合年龄区间",
  "unit": "月"
}

4.2.3 编辑属性

PUT /api/v1/attribute/{id}

校验逻辑

检查属性是否已被商品引用
    ├── 未引用 → 允许完整编辑
    └── 已引用 → 仅允许 attr_name/description,选项值已用不可删

4.2.4 删除属性

DELETE /api/v1/attribute/{id}
  • is_builtin=1 → 拒绝:"内置属性不可删除"
  • 已被商品引用 → 拒绝:"该属性已存在商品档案信息,无法删除"
  • 其他 → 逻辑删除(del_flag='1')

4.3 商品档案管理接口

4.3.1 新建商品

POST /api/v1/goods

请求体

{
  "catalogId": "2",
  "commonAttrs": {
    "code": "SPU001",
    "name": "婴童纯棉连体衣",
    "barCode": "6901234567890",
    "exField2": "ART001",
    "brandId": "brand_001",
    "kindId": "kind_001",
    "typeId": "9",
    "producer": "浙江杭州",
    "weight": "200",
    "salesPrice": 990000,
    "status": "1",
    "remarks": "",
    "imageUrl": "/images/product001.jpg"
  },
  "customAttrs": [
    {
      "attributeId": "attr_020",
      "attrValues": ["红色", "蓝色"]
    },
    {
      "attributeId": "attr_025",
      "attrValueMin": 1,
      "attrValueMax": 5
    }
  ]
}

业务逻辑

  1. 校验 catalogId 对应的类目 category_type='NORMAL'(拒绝 DEFAULT 类目)
  2. 根据 catalogId 加载模板,校验必填属性
  3. 通用属性写入 goods_base 固定列
  4. 类目属性写入 goods_product_attr_value
  5. 商品编码全局唯一校验
  6. 不需要 is_catalog_confirmed 字段,新建商品 catalog_id 直接指向真实类目

4.3.2 编辑商品

PUT /api/v1/goods/{id}

业务逻辑

  1. 加载商品所属类目的最新模板
  2. 模板中新增的属性(已有商品没有的):展示该字段,值为空
  3. 通用属性更新 goods_base
  4. 类目属性更新 goods_product_attr_value

4.3.3 变更商品类目(历史商品专用)

POST /api/v1/goods/{id}/change-catalog

请求体

{
  "newCatalogId": "cat_001"
}

业务逻辑

  1. 校验 catalog_id = 'cat_default',否则拒绝:"该商品类目已确认,不可变更"
  2. 校验 newCatalogId 对应的类目 category_type='NORMAL'
  3. 事务内执行
  4. UPDATE goods_base SET catalog_id = 新值 WHERE id = 商品ID
  5. DELETE FROM goods_product_attr_value WHERE product_id = 商品ID(清空旧类目属性值)
  6. 通用属性保留不变,类目属性为空待用户填写

后端事务伪代码

BEGIN TRANSACTION;

-- 校验前置条件(FOR UPDATE 防并发)
SELECT catalog_id INTO @cat_id
FROM goods_base WHERE id = @goods_id FOR UPDATE;

IF @cat_id != 'cat_default' THEN
  ROLLBACK; RETURN 'NOT_ALLOWED';
END IF;

-- 变更类目
UPDATE goods_base
SET    catalog_id = @new_catalog_id
WHERE  id = @goods_id;

-- 清空旧类目属性值(通用属性不动)
DELETE FROM goods_product_attr_value
WHERE  product_id = @goods_id;

COMMIT;

失败处理

失败场景 处理 用户提示
catalog_id ≠ 'cat_default' 拒绝 "该商品类目已确认,不可变更"
newCatalogId 无效或为 DEFAULT 前端拦截 "请选择有效类目"
并发冲突(两人同时变更) FOR UPDATE 拒绝后者 "该商品类目已被其他人员更新"
数据库异常 事务回滚,保持原状 "操作失败,请重试"

~~4.4 导入任务接口~~

已删除:本迭代不需要导入任务表和接口。


5. 详细功能逻辑

5.1 类目属性模板继承机制

继承规则

子级属性 = 子级自有属性 ∪ 上级属性(去重)

示例

一级类目属性:A, B, C
    ↓ 继承
二级类目属性:A, B, C + D, E, F
    ↓ 继承
三级类目属性:A, B, C, D, E, F + H, J

关键规则

  • 同一级内属性不能重复,跨级可以重复
  • 子级不影响上级
  • 上级会影响子级:上级新增属性自动同步到子级
  • 上级新增属性同步回填到已有商品(编辑时展示,值为空)

模板变更级联流程

上级类目新增属性 X
        │
        ↓
查找所有子级类目(通过 parent_ids 物化路径)
        │
        ↓
去重检查 → 没有则添加到子级模板
        │
        ↓
查找该类目下所有已有商品
        │
        ↓
在 goods_product_attr_value 中添加空记录
(编辑商品时展示该字段,值为空)

类目 CRUD 权限矩阵

类目状态 新增属性 删除属性 修改属性 调整排序
DEFAULT 类目
未关联商品
已关联商品

5.2 属性库 CRUD 权限矩阵

属性状态 新增 编辑 删除 新增选项值
未关联商品
已关联商品 仅 name/desc ✅(已用的不能删)

5.3 新建商品流程

用户点击"新建商品"
        │
        ↓
【第一步】选择商品类目
        │
        ├── 加载类目树 GET /goods-catalog/tree(过滤 category_type=DEFAULT)
        ├── 用户选择叶子类目
        └── 点击"下一步"(未选时按钮置灰)
        │
        ↓
【第二步】填写商品信息
        │
        ├── 加载模板 GET /goods-catalog/{id}/template-preview
        ├── 通用属性组 → 固定字段表单(按模板排序/可见性)
        ├── 类目属性组 → 动态字段表单
        ├── 必填字段显示 *
        └── 提交保存
            ├── 通用属性 → goods_base
            └── 类目属性 → goods_product_attr_value

5.4 编辑商品流程

加载商品数据 + 最新类目模板
        │
        ↓
判断 catalog_id
  ├── = 'cat_default'(历史商品)→ 展示"变更类目"按钮 + 提示
  └── ≠ 'cat_default'(正常商品)→ 正常编辑
        │
        ↓
合并展示
  ├── goods_base 固定字段值 + 模板控制显示
  ├── goods_product_attr_value 已有值
  └── 模板中新增的属性(值为空) → 展示空字段
        │
        ↓
用户修改 → 提交保存

5.5 页面展示方案

通用属性不存 goods_product_attr_value 表,前端通过类目模板控制展示顺序和可见性。

前端渲染逻辑

1. 获取类目模板 GET /goods-catalog/{id}/template-preview
   → 返回:属性组列表 + 每组下的属性列表(含排序、可见性)

2. 遍历模板属性:
   ├── 通用属性(attrType=1)→ 从 goods_base 取值渲染
   └── 类目属性(attrType=2)→ 从 goods_product_attr_value 取值渲染

3. 前端按 group_sort 分块,按 sort_order 排列

历史商品编辑页展示(catalog_id = 'cat_default')

┌─────────────────────────────────────────────────────────┐
│  编辑商品 — 婴童纯棉连体衣                                │
│  当前类目:未分类商品(预制默认类目)                        │
│  ⚠️ 此商品尚未归属具体类目                                │
│                                    [ 🔄 变更类目 ]       │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  ▎ 商品基础信息                                          │
│  ┌──────────────────────────────────────────────┐       │
│  │  商品编码 *    [ SP001               ]  只读   │       │
│  │  商品名称 *    [ 婴童纯棉连体衣       ]         │       │
│  │  商品条码      [ 6901234567890       ]         │       │
│  │  ... (通用属性正常展示)                       │       │
│  └──────────────────────────────────────────────┘       │
│                                                         │
│  ℹ️ 变更类目后可补充类目属性(颜色、尺码等)                │
│                                                         │
│                              [ 取消 ]  [ 保存 ]         │
└─────────────────────────────────────────────────────────┘

正常商品编辑页(catalog_id ≠ 'cat_default')

┌─────────────────────────────────────────────────────────┐
│  编辑商品 — 婴童纯棉连体衣                                │
│  类目:婴童内着家居服                                     │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  ▎ 基础信息(属性组1)                                    │
│  ┌──────────────────────────────────────────────┐       │
│  │  商品编码 *    [ SP001               ]        │       │
│  │  商品名称 *    [ 婴童纯棉连体衣      ]         │       │
│  │  ... (通用属性正常展示)                       │       │
│  └──────────────────────────────────────────────┘       │
│                                                         │
│  ▎ 服饰属性(属性组2)                                    │
│  ┌──────────────────────────────────────────────┐       │
│  │  颜色          [ + 添加标签 ]                  │       │
│  │  尺码          [ + 添加标签 ]                  │       │
│  │  ... (类目属性为空,可补填)                    │       │
│  └──────────────────────────────────────────────┘       │
│                                                         │
│                              [ 取消 ]  [ 保存 ]         │
└─────────────────────────────────────────────────────────┘

变更类目后展示

┌─────────────────────────────────────────────────────────┐
│  编辑商品 — 婴童纯棉连体衣                                │
│  类目:婴童内着家居服 ✓ 已确认                            │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  ▎ 基础信息                                             │
│  ┌──────────────────────────────────────────────┐       │
│  │  (通用属性保留原值)                            │       │
│  └──────────────────────────────────────────────┘       │
│                                                         │
│  ▎ 服饰属性                                             │
│  ┌──────────────────────────────────────────────┐       │
│  │  适用性别      [              ]               │       │
│  │  颜色          [              ]               │       │
│  │  尺码          [              ]               │       │
│  │  ... (类目属性为空,待用户补填)                 │       │
│  └──────────────────────────────────────────────┘       │
│                                                         │
│  ℹ️ 请补充类目属性后保存                                  │
│                                                         │
│                              [ 取消 ]  [ 保存 ]         │
└─────────────────────────────────────────────────────────┘

数据来源对照

问题 方案
通用属性按类目顺序展示 前端从模板 API 获取排序,按排序渲染 goods_base 字段
通用属性是否显示 模板中 is_visible 控制
编辑商品时回填 通用属性从 goods_base 回填,类目属性从 goods_product_attr_value 回填
数据来源 前端一次请求拿到模板定义 + 商品数据,本地合并渲染

6. 内置通用属性与 goods_base 映射表

# 属性名称 数据类型 必填 goods_base 字段 字段类型 备注
1 商品编码 文本 code VARCHAR(64)
2 商品名称 文本 name VARCHAR(80)
3 商品条码 文本 bar_code VARCHAR(64) 文本类型
4 货号 文本 ex_field2 VARCHAR(64) 扩展字段
5 品牌 单选 brand_id VARCHAR(64) 关联 goods_brand
6 品类 单选 kind_id VARCHAR(64) 关联 goods_kind
7 商品类型 单选 type_id VARCHAR(64) 新品/老品/引流品/主推品
8 产地 文本 producer VARCHAR(64)
9 重量(g) 数字 weight VARCHAR(100) 单位 g
10 效期 文本 validity_period INT 不用管
11 建议零售价 数字 sales_price DECIMAL(18) ×10000 存储
12 状态 开关 status VARCHAR(16) 两边状态值不同
13 备注 文本 remarks VARCHAR(256)
14 图片 图片 image_url VARCHAR(500) 存 URL/路径

注意:goods_base.status 与属性模板中的"状态"是不同的状态体系,各自独立维护。


7. 预制类目初始化数据

7.1 预制默认类目(割接用)

字段
catalog_code DEFAULT
catalog_name 未分类商品
category_type DEFAULT
level 1
status 1(启用)
has_product 1(始终为 true)

模板配置: - 仅含一个「商品基础信息」属性组 - 14 项通用属性映射到 goods_base 固定列 - 无类目属性

保护规则:不可删除、不可停用、不可修改模板

7.2 一级类目 + 类目属性

一级类目:婴童服饰鞋配

通用属性:14 项(同第 6 节映射表)

类目属性(9 项):

# 属性名称 数据类型 必填 说明
1 适用性别 单选(下拉)
2 颜色 多选(标签)
3 尺码 多选(标签)
4 季节 单选(下拉)
5 年份 单选(下拉)
6 系列 文本
7 面料 多选
8 风格 文本
9 适合年龄 数值区间 单位:岁/月/日

7.3 二级类目

类目名称 继承属性
婴童内着家居服 继承一级全部属性
婴童外出服饰 继承一级全部属性
婴童鞋靴 继承一级全部属性
婴童配饰 继承一级全部属性

7.4 类目属性与 goods_base 映射(类目属性部分)

类目属性 goods_base 字段 映射方式
颜色 color_id 关联字段
尺码 size 直接映射
面料 ex_field3 扩展字段
其他 goods_product_attr_value 动态存储

~~8. 批量导入通用设计~~

已删除:导入任务表已移除,批量导入使用已有框架能力。


9. 历史商品数据割接

9.1 割接背景

新体系引入类目属性模板后,历史商品数据需要关联类目(catalog_id),以便前端按模板正确展示。由于无法自动推断历史商品应归属哪个类目,采用「预制默认类目 + 人工一次性变更」方案。

9.2 割接范围

项目 说明
割接对象 goods_base 中 catalog_id 为 NULL 的历史商品
割接动作 填充 catalog_id = 预制默认类目
不涉及 通用属性(已在 goods_base 固定列,无需迁移)
不涉及 类目属性(历史商品此类为空,不做割接)
goods_product_attr_value 不写入任何数据

9.3 DDL 变更

-- 1. t_goods_catalog 新增 category_type 字段
ALTER TABLE t_goods_catalog
ADD COLUMN category_type VARCHAR(20) NOT NULL DEFAULT 'NORMAL'
COMMENT '类目类型: DEFAULT=预制 NORMAL=正常';

-- ⚠️ 不需要新增 is_catalog_confirmed 字段
-- 判断逻辑仅通过 catalog_id: 'cat_default'=允许切换, 其他=不允许

9.4 创建预制默认类目

-- 创建类目
INSERT INTO t_goods_catalog
  (catalog_code, catalog_name, parent_id, level, status, category_type, has_product)
VALUES
  ('DEFAULT', '未分类商品', NULL, 1, '1', 'DEFAULT', 1);

-- 获取预制类目 ID
SET @CAT_DEFAULT = (SELECT id FROM t_goods_catalog
  WHERE category_type = 'DEFAULT' AND del_flag = '0' LIMIT 1);

-- 创建模板组(仅商品基础信息)
INSERT INTO goods_catalog_template_group
  (catalog_id, group_name, group_desc, group_sort)
VALUES
  (@CAT_DEFAULT, '商品基础信息', '通用属性模板', 1);

-- 创建模板明细(14 项通用属性映射)
-- 按第 6 节映射表,逐一插入 goods_catalog_template_item

9.5 割接迁移 SQL

-- 统计待迁移数量
SELECT COUNT(*) FROM goods_base WHERE catalog_id IS NULL AND del_flag = '0';

-- 执行迁移:填充 catalog_id
UPDATE goods_base
SET    catalog_id = @CAT_DEFAULT
WHERE  catalog_id IS NULL
  AND  del_flag = '0';

分批执行(大数据量)

-- batch size 5000,每批间隔 2~3 秒
UPDATE goods_base
SET    catalog_id = @CAT_DEFAULT
WHERE  catalog_id IS NULL AND del_flag = '0'
LIMIT  5000;
-- 重复直到影响行数 = 0

9.6 割接后验证

-- 1. 确认无残留
SELECT COUNT(*) FROM goods_base
WHERE catalog_id IS NULL AND del_flag = '0';
-- 期望: 0

-- 2. 确认历史商品状态
SELECT catalog_id, COUNT(*)
FROM goods_base
WHERE catalog_id = @CAT_DEFAULT AND del_flag = '0'
GROUP BY catalog_id;
-- 期望: catalog_id = 'cat_default' 的行数 = 历史商品总数

-- 3. 确认预制类目已创建
SELECT id, catalog_code, catalog_name, category_type
FROM t_goods_catalog
WHERE category_type = 'DEFAULT';

9.7 一次性变更类目流程

历史商品编辑页
        │
        ↓
检测 catalog_id = 'cat_default'
        │
        ↓
展示"变更类目"按钮 + 提示"建议切换到具体类目"
        │
        ↓
用户点击 → 打开类目选择器(过滤 category_type='NORMAL')
        │
        ↓
用户选择新类目 → 确认
        │
        ↓
后端事务内执行:
  ├── UPDATE goods_base SET catalog_id=新值
  └── DELETE goods_product_attr_value(清空旧类目属性值)
        │
        ↓
前端跳转编辑页
  ├── 通用属性保留原值
  ├── 类目属性为空(可先保存后补填)
  └── "变更类目"按钮消失(不可逆)

9.8 回滚手册

严格按逆序执行:

-- Step 1:清空历史商品的 catalog_id
UPDATE goods_base
SET    catalog_id = NULL
WHERE  catalog_id = @CAT_DEFAULT AND del_flag = '0';

-- Step 2:删除预制类目模板明细
DELETE FROM goods_catalog_template_item
WHERE group_id IN (SELECT id FROM goods_catalog_template_group WHERE catalog_id = @CAT_DEFAULT);

-- Step 3:删除预制类目模板组
DELETE FROM goods_catalog_template_group WHERE catalog_id = @CAT_DEFAULT;

-- Step 4:删除预制类目
DELETE FROM t_goods_catalog WHERE category_type = 'DEFAULT';

-- Step 5(可选):回滚 DDL
ALTER TABLE t_goods_catalog DROP COLUMN category_type;

9.9 执行计划

Step 内容 负责人 依赖
1 执行 DDL(t_goods_catalog 新增 category_type) 后端/DBA
2 类目预置数据 + 属性库初始化 后端
3 创建预制默认类目 + 模板 + 14 项映射 后端 Step 1, 2
4 执行历史商品迁移 SQL DBA Step 3
5 前端:变更类目按钮 + catalog_id 判断逻辑 前端 Step 1
6 前端:新建商品过滤 DEFAULT 类目 前端 Step 3
7 测试环境全流程验证 QA Step 4~6
8 生产执行 DBA + 后端 Step 7

附录:变更记录

版本 日期 变更内容
V2.0 2025-07-11 初始详细设计
V2.1 2025-07-11 同步完整交付文档:t_goods_catalog 增加 parent_ids/has_product、移除 tenant_id;goods_attribute 移除 tenant_id/unit;goods_attribute_option 增加 option_type;变更日志表改为本迭代不建表;补充编辑商品流程和页面展示方案
V3.0 2025-07-11 新增历史商品数据割接方案:t_goods_catalog 增加 category_type 字段;预制默认类目机制;新增变更类目接口(4.3.3);补充割接流程、前端交互、回滚手册和执行计划(第 9 章)
V3.1 2026-05-12 移除导入任务表(goods_import_task);移除 is_catalog_confirmed 字段,改用 catalog_id 判断类目变更;移除导入任务接口
V3.2 2026-05-14 确认割接决策:去掉 is_catalog_confirmed,一次性不可逆,不允许真实→真实切换,使用 category_type,无报表模块
V3.3 2026-05-14 所有新建表统一以 goods_ 开头