# 表 → 栏目 / 字段映射 **DMS 环境**:`http://121.43.55.7:10081/dms`(`DMS_HOST` 可覆盖) **建栏时间**:2026-09-16(session 004) > 📍 **本文引用的 tools / artifacts 不在本仓库**,属于另一个项目 > `F:\yysk\AI_zhaoshang\DMS_Data_Migration\`(本文从它的 `harness/docs/` 复制而来)。 > 链接已改为**绝对路径**指向那边。 **执行工具**:[`create_dms_columns.py`](F:/yysk/AI_zhaoshang/DMS_Data_Migration/harness/tools/create_dms_columns.py) **原始记录**:[`created_columns.json`](F:/yysk/AI_zhaoshang/DMS_Data_Migration/harness/artifacts/created_columns.json) > 这份文件是**机器可读契约**,不是散文。迁移脚本会直接消费它。 > 改动这里 = 改动迁移行为,请同步更新对应 feature 的证据。 --- ## 1. 目标栏目结构(已建成) 父栏目 **营商助手**:`columnId=1883` · `type=0`(分级)· `tag=yszs` ``` 营商助手 (1883, 分级, yszs) ├── 助手页面浏览 (1885) yszs_page_view ← assistant_page_view 39,723 行 ├── 企业荣誉信息 (1886) yszs_qcc_honor ← qcc_honor 7,118 行 ├── 助手会话 (1887) yszs_chat_session ← chat_session 3,133 行 ├── 企业基础信息 (1888) yszs_qcc_enterprise ← qcc_enterprise 81,980 行 └── 助手问答记录 (1889) yszs_chat_record ← chat_record 15,542 行 ``` 合计 **147,496 行**待迁移。 --- ## 2. 完整映射表 | 源表 | 行数 | 栏目名 | columnId | tag | 基础模型 id | 栏目模型 id | 栏目模型名 | 字段数 | |------|------|--------|----------|-----|------------|------------|-----------|--------| | `assistant_page_view` | 39,723 | 助手页面浏览 | **1885** | `yszs_page_view` | 2029 | 2030 | `yszs_page_view_yszs_page_view_model` | 4 | | `qcc_honor` | 7,118 | 企业荣誉信息 | **1886** | `yszs_qcc_honor` | 2031 | 2032 | `yszs_qcc_honor_yszs_qcc_honor_model` | 11 | | `chat_session` | 3,133 | 助手会话 | **1887** | `yszs_chat_session` | 2033 | 2034 | `yszs_chat_session_yszs_chat_session_model` | 7 | | `qcc_enterprise` | 81,980 | 企业基础信息 | **1888** | `yszs_qcc_enterprise` | 2035 | 2036 | `yszs_qcc_enterprise_yszs_qcc_enterprise_model` | 41 | | `chat_record` | 15,542 | 助手问答记录 | **1889** | `yszs_chat_record` | 2037 | 2038 | `yszs_chat_record_yszs_chat_record_model` | 13 | **写入时用 `columnId` + `modelId`(栏目模型 id,即上表「栏目模型 id」列)。** > DMS 在 `addColumn` 时把基础模型(type=1)克隆为栏目模型(type=2), > 克隆时给每个字段加 `c_` 前缀。物理表名是 `column_{栏目模型名}`。 --- ## 3. 字段级映射 字段名规则:`源字段` → `c_{源字段}`(前缀由 DMS 克隆时自动加)。 中文别名与类型映射在 [`create_dms_columns.py`](F:/yysk/AI_zhaoshang/DMS_Data_Migration/harness/tools/create_dms_columns.py) 里定义。 ### 3.1 `assistant_page_view` → 助手页面浏览 (1885) | 源字段 | PG 类型 | 目标字段 | DMS type | frontType | 别名 | |--------|---------|----------|----------|-----------|------| | `id` | bigint | `c_id` | integer | int_num | ID | | `business_code` | varchar(64) | `c_business_code` | text | varchar | 业务编码 | | `visitor_id` | varchar(64) | `c_visitor_id` | text | varchar | 访客ID | | `created_at` | bigint | `c_created_at` | timestamp | date_time | 创建时间 | ### 3.2 `qcc_honor` → 企业荣誉信息 (1886) | 源字段 | 目标字段 | DMS type | 别名 | |--------|----------|----------|------| | `id` | `c_id` | integer | ID | | `credit_code` | `c_credit_code` | text | 统一社会信用代码 | | `name` | `c_name` | text | 企业名称 | | `level` | `c_level` | text | 级别 | | `source` | `c_source` | text | 来源 | | `publish_office` | `c_publish_office` | text | 发布机构 | | `publish_date` | `c_publish_date` | text | 发布日期 | | `beging_date` | `c_beging_date` | text | 起始日期 | | `dead_line` | `c_dead_line` | text | 截止日期 | | `certificate_code` | `c_certificate_code` | text | 证书编号 | | `created_at` | `c_created_at` | timestamp | 创建时间 | ### 3.3 `chat_session` → 助手会话 (1887) | 源字段 | 目标字段 | DMS type | 别名 | |--------|----------|----------|------| | `id` | `c_id` | integer | ID | | `credit_code` | `c_credit_code` | text | 统一社会信用代码 | | `session_id` | `c_session_id` | text | 会话ID | | `title` | `c_title` | text | 标题 | | `created_at` | `c_created_at` | timestamp | 创建时间 | | `updated_at` | `c_updated_at` | timestamp | 更新时间 | | `source` | `c_source` | text | 来源 | ### 3.4 `qcc_enterprise` → 企业基础信息 (1888) 41 字段(源表口径;**2026-09-18 起 DMS 模型已扩到 47**——前端分类同步新增了 6 个 `c_tag_*`, 见 [`DMS_COLUMNS.md`](DMS_COLUMNS.md) §2.4)。**主键 `credit_code`**(无 `id` 列)。完整字段表由 [`create_dms_columns.py`](F:/yysk/AI_zhaoshang/DMS_Data_Migration/harness/tools/create_dms_columns.py) 的 `ALIAS` 字典定义,摘要: - 主体:`credit_code` → `c_credit_code`、`name` → `c_name` - jsonb 列(`designated_representative_list`/`original_name`/`revoke_info`/`area`/`industry`) → `c_*`,**类型在模型里定义为 `text`** - `created_at` → `c_created_at`(timestamp) ### 3.5 `chat_record` → 助手问答记录 (1889) 13 字段。完整定义同上工具文件。 --- ## 4. ⚠️ 迁移时必须注意 ### 4.1 `created_at` 是 **epoch 秒**,不是毫秒 实测(session 003/004): ``` chat_record.created_at = 1789450583 → 2026-09-15 13:36 ✅ 秒 当作毫秒 → 1970-01-22 ❌ ``` 模型里定义为 `timestamp`,**写入前需 `datetime.fromtimestamp(v)` 换算**。 涉及字段:`created_at`、`updated_at`、`feedback_at`(按表不同)。 ### 4.2 `credit_code` 是主键但不是 NOT NULL `qcc_enterprise.credit_code` 是主键;`qcc_honor.credit_code`、`chat_*` 的 `credit_code` 可空。做幂等键时要处理空值情况。 ### 4.3 幂等键 | 表 | 幂等键 | 说明 | |----|--------|------| | `qcc_enterprise` | `credit_code` | 主键,天然唯一 | | `qcc_honor` | `id` | 主键 | | `chat_session` | `id` | 主键 | | `chat_record` | `id` | 主键 | | `assistant_page_view` | `id` | 主键 | > 写入前按幂等键查 DMS 是否已存在:不存在 `addContent`,已存在 `updateContent`。 > 详见 feature `F4-02`。 ### 4.4 jsonb 字段存成 text 后不可检索 `qcc_enterprise` 的 5 个 jsonb 列在 DMS 里是 `text`,**DMS 的 search 无法检索其内部字段**。 若将来需要按法定代表人/行业检索,需另建展开栏目(见 `F3-02` 后续)。 --- ## 5. 建栏目时踩过的坑(DMS API 真实契约) 这些是**实测得出**的,文档(`SKILL.md`/Apifox)里没有。写在这里避免重复踩。 | # | 坑 | 正确做法 | |---|-----|----------| | 1 | `addModel`/`addColumn` 必须带 `authorId` + `authorName` | 否则 `code=-1 参数错误`。可从 JWT payload 解出(见 `dms.py` 的 `identity()`) | | 2 | `fieldList` 里字段的 `frontType` 不是 `"content"` | 必须是基础字段库(`/param/selectAll`)里的 **param 名**:`varchar`/`text`/`int_num`/`float_num`/`date_time`/`boolean`/`files`。用错得到 `code=214 数据错误` | | 3 | 字段要有 `index`,`sequence` 从 **0** 起 | 缺 `index` 或 1 起会 `code=214` | | 4 | 基础模型字段名**不加** `c_` 前缀 | 前缀由 `addColumn` 克隆时自动加。自己加会导致 `c_c_xxx` | | 5 | `searchField`/`sortField` 是空数组字面量 `"[]"` | 填字段名会 `code=214` | | 6 | 参数放 **query string** 会有长度限制 | 41 字段的 fieldList 触发 **HTTP 400**。用 **form body**(PUT + `application/x-www-form-urlencoded`) | | 7 | `addColumn` 要求模型**已存在** | 否则 `code=205 模型不存在`。必须先 `addModel` 再 `addColumn` | | 8 | 服务端有 OpenAPI 规范 | `GET /dms/v3/api-docs`(只读,118KB)。比 Apifox 新,**优先查它** | | 9 | 更新模型**不能用** `updateFields` / `updateFieldList` | 用 **`POST /model/updateProperty`**。实测:`updateProperty`→200,`updateFields`→HTTP 400,`updateFieldList`→HTTP 500。**名字最贴切的反而不能用** | | 10 | 字段别名漏配不会报错,只会静默显示英文名 | 建栏目后应逐字段核对 alias。检查法:alias 是否等于字段名去掉 `c_` 前缀 | > 完整 OpenAPI 已存档:[`dms_openapi.json`](F:/yysk/AI_zhaoshang/DMS_Data_Migration/harness/artifacts/dms_openapi.json) --- ## 6. 重跑 建栏目是**幂等**的(模型已存在则跳过): ```bash export DMS_TOKEN='...' python harness/tools/create_dms_columns.py # dry-run 看计划 python harness/tools/create_dms_columns.py --apply # 执行 ``` ---