# 畜牧科技资源管理 — 测试用例

> 依据：`畜牧科技资源管理功能需求.md`、`畜牧科技资源管理技术方案.md`  
> **接口 Base Path**：`/techServices/techResource`；鉴权与若依一致（Cookie / Token）。

**通用前置（无特殊说明）**：具备本模块全套权限的账号已登录（`techService:techResource:list|query|add|edit|remove|publish|offline|assignAccount`）。`biz_tech_resource` 宜预置（`del_flag=0`）：

| 样本 | 类型 | 名称 | 发布态要点 |
| --- | --- | --- | --- |
| **Z1** | `004005` 专家 | 张专家 | 未发布；未分配账号 |
| **Z2** | `004005` 专家 | 李专家 | 已发布 |
| **C1** | `004006` 技术成果 | 育种新技术 | 未发布 |
| **Y1** | `004007` 共享仪器 | 显微镜01 | 已发布 |
| **Y2** | `004007` 共享仪器 | 离心机02 | 已下架（`offline_time` 非空） |
| **K1** | `004008` 视频课程 | 基础养殖入门 | 未发布 |

**专家合法 Body 片段**：`resourceType=004005`，`resourceName=测试专家`，`introduction=专家简介`，`contactPhone=13800138000`，`affiliatedUnit=县畜牧局`，`detailAddress=科技路1号`，`serviceArea=全县`，`feeStandard=100`，`serviceStartTime=08:00`，`serviceEndTime=18:00`，`serviceWeekdays=[1,2,3,4,5]`，`photoFileUrl`/`photoFilePath` 来自上传。

**技术成果 Body 片段**：`resourceType=004006`，`resourceName=测试成果`，`researchDirection=繁育`，`achievementSummary=摘要`，`keyTechPrinciple=原理`，`techAdvantage=优势`，`completionUnit=县农科院`。

**共享仪器 Body 片段**：`resourceType=004007`，`resourceName=测试仪`，`instrumentModel=A1`，`introduction=介绍`，`affiliatedUnit=县实验室`，`storageLocation=3号楼`，`reservationProcess=提前预约`，`personInCharge=王工`，`contactPhone=13800138001`，`borrowFee=50`，`serviceStartTime=09:00`，`serviceEndTime=17:00`，`serviceWeekdays=[1,2,3,4,5]`，`photoFileUrl`/`photoFilePath` 已上传。

**视频课程 Body 片段**：`resourceType=004008`，`resourceName=测试课程`，`introduction=课程简介`，`courseTopic=005001`，`videoFileUrl`/`videoFilePath` 已上传（mp4）。

**界面（UI）测试**：**Playwright** + **Chromium**（`channel: 'chrome'` 使用本机 **Google Chrome**）。

---

## 一、单元测试用例

| 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| ZCZX-KJZYGL-UT-001 | 参数校验 | 服务时段 | 单元测试 | JUnit5 | §5.4、§5.6 | 无 | 结束早于开始；合法 `08:00`～`18:00` | 非法失败；合法通过 |
| ZCZX-KJZYGL-UT-002 | 参数校验 | 手机号 | 单元测试 | JUnit5 | §5.2 | 无 | `123`；`13800138000` | 非法失败；合法通过 |
| ZCZX-KJZYGL-UT-003 | 参数校验 | 名称长度 | 单元测试 | JUnit5 | §5.4～5.7 | 无 | 专家名 11 字；成果名 21 字；仪器名 10 字 | 超限失败；合法通过 |
| ZCZX-KJZYGL-UT-004 | 参数校验 | 收费标准/借用金额 | 单元测试 | JUnit5 | §5.4、§5.6 | 无 | `feeStandard`/`borrowFee` 为 0、负数、正数 | 非正数失败；正数通过 |
| ZCZX-KJZYGL-UT-005 | 参数校验 | 服务周日 | 单元测试 | JUnit5 | §5.4 | 无 | `required=true` 时空数组失败；`required=false` 时通过 | 与必填开关一致 |
| ZCZX-KJZYGL-UT-006 | 参数校验 | 技术成果三项长文本 | 单元测试 | JUnit5 | §5.5 | 无 | 摘要/原理/优势 501 字；合法 500 字 | 超长失败；通过 |
| ZCZX-KJZYGL-UT-006a | 参数校验 | 成果缺研究方向 | 单元测试 | JUnit5 | §5.5 | 无 | 仅成果名称 | 失败 |
| ZCZX-KJZYGL-UT-006a2 | 参数校验 | 成果名称与方向 | 单元测试 | JUnit5 | §5.5 | 无 | 成果名称+研究方向 | 通过 |
| ZCZX-KJZYGL-UT-006b | 参数校验 | 专家资料选填 | 单元测试 | JUnit5 | §5.4 | 无 | 仅专家姓名 | 通过 |
| ZCZX-KJZYGL-UT-006c | 参数校验 | 仪器资料选填 | 单元测试 | JUnit5 | §5.6 | 无 | 仅仪器名称 | 通过 |
| ZCZX-KJZYGL-UT-006d | 参数校验 | 课程简介选填 | 单元测试 | JUnit5 | §5.7 | 无 | 标题+主题+视频；无简介 | 通过 |
| ZCZX-KJZYGL-UT-007 | 参数校验 | 类型字段矩阵 | 单元测试 | JUnit5 | §5.3、§2.1 | 无 | 成果带 `contactPhone`；专家缺 `feeStandard`；课程缺 `videoFilePath` | 专家/成果通过；课程缺视频失败 |
| ZCZX-KJZYGL-UT-008 | 参数校验 | 图片/视频路径 | 单元测试 | JUnit5 | §5.2 | 无 | 非 `/profile`；jpg 图；mp4 视频 | 非法失败；合法通过 |
| ZCZX-KJZYGL-UT-009 | 发布态 | 已发布不可改 | 单元测试 | JUnit5 | §5.8、§6 | `publish_status=1` | `validateForUpdate` | 失败 |
| ZCZX-KJZYGL-UT-010 | 发布态 | 仅已发布可下架 | 单元测试 | JUnit5 | §5.11 | 未发布/已发布 | `validateOffline` | 仅已发布通过 |
| ZCZX-KJZYGL-UT-011 | 发布态 | 三态解析 | 单元测试 | JUnit5 | §2.1 | 三组记录 | 解析展示状态 | 未发布/已发布/已下架与 `offline_time` 一致 |
| ZCZX-KJZYGL-UT-012 | 分配账号 | 类型与次数 | 单元测试 | JUnit5 | §5.12 | 成果 `004006`；仪器 `004007`；已分配专家 | `validateAssignAccount` | 非专家失败；已分配失败 |
| ZCZX-KJZYGL-UT-012a | 资源类型 | 资讯类别校验 | 单元测试 | JUnit5+Mockito | §2.2 | Mock children | `TechResourceTypeValidator.assertAllowed` | 合法 `004006` 通过；非法编码失败 |
| ZCZX-KJZYGL-UT-013 | Service | 新增落库 | 单元测试 | JUnit5+Mockito | §5.2 | Mock Mapper | `insert` 合法专家 | `publish_status=0`；`offline_time` 空；`account_assigned=0` |
| ZCZX-KJZYGL-UT-014 | Service | 发布清空下架时间 | 单元测试 | JUnit5+Mockito | §5.11 | 已下架样本 | `publish(id)` | `publish_status=1`；`offline_time` 空 |
| ZCZX-KJZYGL-UT-015 | Service | 下架保留发布时间 | 单元测试 | JUnit5+Mockito | §5.11 | 已发布 Z2 | `offline(id)` | `publish_status=0`；`offline_time` 有值；`publish_time` 保留 |
| ZCZX-KJZYGL-UT-016 | Service | 逻辑删除 | 单元测试 | JUnit5+Mockito | §5.10 | 未发布 | `remove(id)` | `del_flag=2` |
| ZCZX-KJZYGL-UT-017 | Service | 删除有关联 | 单元测试 | JUnit5+Mockito | §2.5 | `hasReference=true` | `remove` | 抛 `ServiceException` |
| ZCZX-KJZYGL-UT-018 | Service | 删除联动删账号 | 单元测试 | JUnit5+Mockito | §5.10、草稿 §10 | 未发布已分配专家；`sys_user_id` 非空 | `deleteByIds` | 调用 `deleteLinkedAccount`；`del_flag=2` |
| ZCZX-KJZYGL-UT-019 | Service | 专家分配账号 | 单元测试 | JUnit5+Mockito | §5.12、草稿 §11 | 未发布 Z1；Mock 用户服务 | `assignAccount(id)` | `account_assigned=1`；绑定 `role_key=**exp**` |
| ZCZX-KJZYGL-UT-019a | 登录名 | 拼音首字母+id | 单元测试 | JUnit5 | §2.6 | 无 | `generate("张专家",12L)` | `zzj12` |
| ZCZX-KJZYGL-UT-020 | 分配账号 | 专家角色权限字符 | 单元测试 | JUnit5 | §5.12 | 无 | `ROLE_KEY_EXPERT` | 值为 **exp** |
| ZCZX-KJZYGL-UT-021 | Mapper | 列表筛选 SQL | 单元测试 | JUnit5 | §3.1 | 无 | 检查 XML | `del_flag=0`；`resource_type=`；`resource_name LIKE`；`create_time DESC` |
| ZCZX-KJZYGL-UT-022 | Mapper | 发布态筛选 | 单元测试 | JUnit5 | §2.1 | 无 | `publishStatus=2` | 含 `offline_time IS NOT NULL` |

---

## 二、接口测试用例

| 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| ZCZX-KJZYGL-API-001 | 列表 | 默认分页 | 接口测试 | Postman | §5.1 | 有多条样本 | `GET /list?resourceType=004005` | `code=200`；≤20 条；创建时间倒序 |
| ZCZX-KJZYGL-API-002 | 列表 | 名称模糊 | 接口测试 | Postman | §2.6 | 有 Z1「张专家」 | `resourceName=张` | 含 Z1 |
| ZCZX-KJZYGL-API-003 | 列表 | 发布状态筛选 | 接口测试 | Postman | §2.6 | 有 Z2 | `publishStatus=1` | 仅已发布 |
| ZCZX-KJZYGL-API-004 | 列表 | 已下架筛选 | 接口测试 | Postman | §2.4 | 有 Y2 | `publishStatus=2` | 含 Y2 |
| ZCZX-KJZYGL-API-005 | 列表 | 不含已删除 | 接口测试 | Postman | §2.5 | 某 id 已删 | `GET /list` | 无该 id |
| ZCZX-KJZYGL-API-006 | 列表 | 缺 resourceType | 接口测试 | Postman | §3.1 | 已登录 | 不传 `resourceType` | 参数错误或空列表 |
| ZCZX-KJZYGL-API-007 | 新增 | 专家 | 接口测试 | Postman | §5.4 | 已登录 | `POST` 专家 Body；仅专家姓名 | `code=200`；资料字段可省略 |
| ZCZX-KJZYGL-API-008 | 新增 | 技术成果 | 接口测试 | Postman | §5.5 | 已登录 | `POST` `resourceType=004006`；成果名称+研究方向 | 成功；摘要/原理/优势/完成单位可省略 |
| ZCZX-KJZYGL-API-009 | 新增 | 共享仪器 | 接口测试 | Postman | §5.6 | 已登录 | `POST` `resourceType=004007`；仅仪器名称 | 成功；照片/型号/服务时段等可省略 |
| ZCZX-KJZYGL-API-010 | 新增 | 视频课程 | 接口测试 | Postman | §5.7 | 已上传 mp4 | `POST` `resourceType=004008`；无简介 | 成功；含 `videoFileUrl`、课程主题 |
| ZCZX-KJZYGL-API-011 | 新增 | 专家服务时段非法 | 接口测试 | Postman | §5.4 | 已登录 | `serviceEndTime` 早于 `serviceStartTime` | 失败 |
| ZCZX-KJZYGL-API-012 | 新增 | 课程缺视频 | 接口测试 | Postman | §5.7 | 已登录 | 缺 `videoFilePath` | 失败 |
| ZCZX-KJZYGL-API-013 | 新增 | 手机号非法 | 接口测试 | Postman | §5.2 | 专家/仪器 | `contactPhone=123` | `msg` 含联系方式 |
| ZCZX-KJZYGL-API-014 | 详情 | 有效 id | 接口测试 | Postman | §5.9 | 有 Z1 | `GET /{id}` | 全字段；`serviceWeekdays` 为数组 |
| ZCZX-KJZYGL-API-015 | 详情 | 无效/已删 id | 接口测试 | Postman | 异常 | 已登录 | 不存在或已删 id | 失败或 `data` 空 |
| ZCZX-KJZYGL-API-016 | 修改 | 未发布修改 | 接口测试 | Postman | §5.8 | 有 Z1 | `PUT` 改 `introduction` | 成功；`resourceType` 不变 |
| ZCZX-KJZYGL-API-017 | 修改 | 已发布禁止 | 接口测试 | Postman | §5.8 | 有 Z2 | `PUT` | 失败 |
| ZCZX-KJZYGL-API-018 | 修改 | 改类型无效 | 接口测试 | Postman | §5.2 | 有 Z1 | `PUT` `resourceType=004008` | 失败或忽略；库仍为 `004005` |
| ZCZX-KJZYGL-API-019 | 发布 | 未发布发布 | 接口测试 | Postman | §5.11 | 有 Z1 | `POST /publish/{id}` | `publish_status=1`；`publishTime` 有值 |
| ZCZX-KJZYGL-API-020 | 发布 | 重复发布 | 接口测试 | Postman | §5.11 | Z2 已发布 | 再次 `publish` | 「该资源已发布」 |
| ZCZX-KJZYGL-API-021 | 下架 | 已发布下架 | 接口测试 | Postman | §5.11 | 有 Z2 | `POST /offline/{id}` | `publish_status=0`；`offline_time` 有值 |
| ZCZX-KJZYGL-API-022 | 下架 | 未发布不可下架 | 接口测试 | Postman | §5.11 | 有 Z1 | `POST /offline/{id}` | 失败 |
| ZCZX-KJZYGL-API-023 | 删除 | 未发布逻辑删 | 接口测试 | Postman | §5.10 | 无关联新行 | `DELETE /{id}` | 成功；列表不可见 |
| ZCZX-KJZYGL-API-023a | 删除 | 已分配联动删账号 | 接口测试 | Postman | §5.10、草稿 §10 | 未发布专家已 `assignAccount` | `DELETE /{id}` | 资源不可见；`sys_user` 对应用户已删 |
| ZCZX-KJZYGL-API-024 | 删除 | 已发布禁止 | 接口测试 | Postman | §5.10 | 有 Z2 | `DELETE` | 失败 |
| ZCZX-KJZYGL-API-025 | 分配账号 | 专家成功 | 接口测试 | Postman | §5.12、草稿 §11 | Z1 未分配 | `POST /assignAccount/{id}` | `accountAssigned=1`；登录名拼音首字母+id（如 `zzj{id}`）；角色 **exp** |
| ZCZX-KJZYGL-API-026 | 分配账号 | 重复分配 | 接口测试 | Postman | §5.12 | 已分配 | 再次调用 | 失败 |
| ZCZX-KJZYGL-API-027 | 分配账号 | 成果禁止 | 接口测试 | Postman | §5.12 | 有 C1 | `assignAccount` | 失败 |
| ZCZX-KJZYGL-API-028 | 分配账号 | 已发布禁止 | 接口测试 | Postman | §5.12 | 有 Z2 | `assignAccount` | 失败 |
| ZCZX-KJZYGL-API-029 | 端到端 | 下架后编辑再发布 | 接口测试 | Postman | §4.2 | 有 Y2 | `offline` 后 `PUT`→`publish`（或 Y2 已下架直接改发） | 最终已发布 |
| ZCZX-KJZYGL-API-030 | 端到端 | 专家全流程 | 接口测试 | Postman | §4.2 | 已登录 | `POST`专家→`assignAccount`→`publish`→`offline`→`DELETE` | 关键步成功 |
| ZCZX-KJZYGL-API-031 | 鉴权 | 未登录 | 接口测试 | curl | 安全 | 无 Token | `GET /list?resourceType=004005` | 401 或未登录 |
| ZCZX-KJZYGL-API-032 | 权限 | 无发布权限 | 接口测试 | Postman | §6 | 无 publish | `POST /publish/1` | 无权限失败 |
| ZCZX-KJZYGL-API-033 | 权限 | 无分配账号权限 | 接口测试 | Postman | §6 | 无 assignAccount | `POST /assignAccount/1` | 无权限失败 |
| ZCZX-KJZYGL-API-034 | 响应 | 失败可读 | 接口测试 | Postman | §8 | 已登录 | 已发布修改、课程缺视频、重复分配 | `msg` 可区分 |

---

## 三、界面测试用例（UI）

**测试工具**：**Playwright** + **Chromium**（`channel: 'chrome'` 使用本机 **Google Chrome**）。

| 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| ZCZX-KJZYGL-UI-001 | 列表 | 四 Tab 展示 | UI 测试 | Playwright+Chrome | §5.1、§2.3 | 已登录；有各类型数据 | 进入「畜牧科技资源管理」；切换四个 Tab | 每 Tab 仅本类型；列含名称、发布状态、操作 |
| ZCZX-KJZYGL-UI-002 | 列表 | Tab 与下拉联动 | UI 测试 | Playwright+Chrome | §2.3 | 已登录 | 切换 Tab；改资源类型下拉 | Tab 与下拉一致 |
| ZCZX-KJZYGL-UI-003 | 列表 | 名称模糊筛选 | UI 测试 | Playwright+Chrome | §2.6 | 有「张专家」 | 填「张」→搜索 | 含匹配行 |
| ZCZX-KJZYGL-UI-004 | 列表 | 发布状态筛选 | UI 测试 | Playwright+Chrome | §2.6 | 有已发布样本 | 选「已发布」→搜索 | 仅已发布行 |
| ZCZX-KJZYGL-UI-005 | 列表 | 重置 | UI 测试 | Playwright+Chrome | §5.1 | 已筛选 | 搜索→重置 | 条件清空；列表恢复 |
| ZCZX-KJZYGL-UI-006 | 新增 | 动态表单-专家 | UI 测试 | Playwright+Chrome | §5.4 | 有 add 权限 | 新增→选专家→填必填→上传照片→确定 | 成功；未发布；含服务区域、收费标准 |
| ZCZX-KJZYGL-UI-007 | 新增 | 动态表单-技术成果 | UI 测试 | Playwright+Chrome | §5.5 | 已登录 | 新增→选技术成果→填摘要/原理/优势→确定 | 无专家字段；成功 |
| ZCZX-KJZYGL-UI-008 | 新增 | 动态表单-共享仪器 | UI 测试 | Playwright+Chrome | §5.6 | 已登录 | 新增→选共享仪器→填预约流程、借用金额→确定 | 成功 |
| ZCZX-KJZYGL-UI-009 | 新增 | 动态表单-视频课程 | UI 测试 | Playwright+Chrome | §5.7 | 已登录 | 新增→选视频课程→上传 mp4→确定 | 成功；含课程主题 |
| ZCZX-KJZYGL-UI-010 | 新增 | 类型切换字段变化 | UI 测试 | Playwright+Chrome | §4.3 | 打开新增 | 选专家→改选视频课程 | 字段集切换；无仪器字段残留 |
| ZCZX-KJZYGL-UI-011 | 新增 | 必填校验 | UI 测试 | Playwright+Chrome | §5.2 | 新增弹窗 | 留空成果名称→确定 | 校验失败 |
| ZCZX-KJZYGL-UI-012 | 新增 | 附件格式提示 | UI 测试 | Playwright+Chrome | §5.2 | 视频课程新增 | 上传非 mp4 或超大文件（若可测） | 失败提示 |
| ZCZX-KJZYGL-UI-013 | 查看 | 只读详情 | UI 测试 | Playwright+Chrome | §5.9 | 任意行 | 点击查看 | 只读；含发布状态 |
| ZCZX-KJZYGL-UI-014 | 操作列 | 未发布按钮集 | UI 测试 | Playwright+Chrome | §6 | 未发布专家行 | 查看操作列 | 有编辑、删除、发布、分配账号 |
| ZCZX-KJZYGL-UI-015 | 操作列 | 已发布按钮集 | UI 测试 | Playwright+Chrome | §6 | 已发布行 | 查看操作列 | 有查看、下架；无编辑、删除、分配账号 |
| ZCZX-KJZYGL-UI-016 | 操作列 | 成果无分配账号 | UI 测试 | Playwright+Chrome | §5.12 | 技术成果 Tab | 查看操作列 | 无分配账号 |
| ZCZX-KJZYGL-UI-017 | 编辑 | 未发布修改 | UI 测试 | Playwright+Chrome | §5.8 | 未发布行 | 编辑→改介绍→确定 | 列表已更新 |
| ZCZX-KJZYGL-UI-018 | 编辑 | 已发布不可进 | UI 测试 | Playwright+Chrome | §5.8 | 已发布行 | 尝试编辑 | 无入口或提示先下架 |
| ZCZX-KJZYGL-UI-019 | 发布下架 | 发布确认 | UI 测试 | Playwright+Chrome | §5.11 | 未发布行 | 发布→确认 | 状态变已发布 |
| ZCZX-KJZYGL-UI-020 | 发布下架 | 下架确认 | UI 测试 | Playwright+Chrome | §5.11 | 已发布行 | 下架→确认 | 状态变已下架 |
| ZCZX-KJZYGL-UI-021 | 删除 | 确认删除 | UI 测试 | Playwright+Chrome | §5.10 | 未发布行 | 删除→确认 | 行消失 |
| ZCZX-KJZYGL-UI-021a | 删除 | 已分配联动删账号 | UI 测试 | Playwright+Chrome | §5.10、草稿 §10 | 未发布已分配专家 | 删除→确认 | 列表无该行；该登录名不可再登录 |
| ZCZX-KJZYGL-UI-022 | 分配账号 | 专家分配 | UI 测试 | Playwright+Chrome | §5.12 | 未发布未分配专家 | 分配账号→确认 | 显示已分配 |
| ZCZX-KJZYGL-UI-023 | 地图标点 | 本期不展示 | UI 测试 | Playwright+Chrome | §5.13 | 共享仪器 Tab | 查看操作列 | 无地图标点或置灰说明 |
| ZCZX-KJZYGL-UI-024 | 权限 | 只读角色 | UI 测试 | Playwright+Chrome | §6 | 仅 list/query | 进入模块 | 无新增/编辑/发布等 |
| ZCZX-KJZYGL-UI-025 | 端到端 | 运营全流程 | UI 集成 | Playwright+Chrome | §4.2 | 权限齐备 | 新增专家→分配→发布→下架→编辑→再发布→删除 | 状态与按钮符合矩阵 |

---

## 四、覆盖对照

| 类别 | 单元 UT | 接口 API | 界面 UI |
| --- | --- | --- | --- |
| 正常流程 | UT-013～018 | API-007～010、016、019、023、029～030 | UI-006～013、017、019～022、025 |
| 异常/校验 | UT-001～008 | API-011～013、017～018 | UI-011～012 |
| 发布状态机 | UT-009～011、014～015 | API-003～004、019～022、029 | UI-004、014～015、019～020 |
| 分配账号 | UT-012、019、019a、020 | API-025～028 | UI-016、022 |
| 四类资源 | UT-007 | API-007～012 | UI-006～010 |
| 逻辑删除/引用 | UT-016～018 | API-005、023～024、023a | UI-021、021a |
| 权限/鉴权 | — | API-031～033 | UI-024 |
| 地图标点（不做） | — | — | UI-023 |

---

## 五、功能需求追溯

| 需求章节 | 要点 | 主要用例 |
| --- | --- | --- |
| §5.1 列表 | Tab、模糊、发布筛选 | API-001～006；UI-001～005 |
| §5.2～5.7 新增/字段 | 四类表单、附件 | UT-001～008；API-007～013；UI-006～012 |
| §5.8 修改 | 仅未发布/已下架 | API-016～018；UI-017～018 |
| §5.9 查看 | 只读 | API-014～015；UI-013 |
| §5.10 删除 | 逻辑删；已分配删账号 | UT-016～018；API-023～024、023a；UI-021、021a |
| §5.11 发布下架 | 状态迁移 | UT-009～015；API-019～022；UI-019～020 |
| §5.12 分配账号 | 仅专家、`exp`、拼音首字母+id | UT-012、019、019a、020；API-025～028；UI-022 |
| §5.13 地图标点 | 不做 | UI-023 |
| §6 权限 | 按钮级 | API-031～033；UI-024 |

---

## 六、Playwright 实施提示

- 安装：`npm i -D @playwright/test`；`npx playwright install chrome`。  
- 配置：`use: { channel: 'chrome', locale: 'zh-CN', baseURL: 'http://localhost:80' }`；`storageState` 复用登录态。  
- 路由：`page.goto('/techService/techResource')`（以菜单 `component` 为准）。  
- 定位示例：`page.getByRole('tab', { name: '专家库' })`；`page.getByRole('button', { name: '新增' })`；`page.getByLabel('专家姓名')`；`page.getByLabel('成果名称')`。

---

## 七、修订记录

| 版本 | 说明 |
| --- | --- |
| 1.0 | 初版：单元 20、接口 34、UI 25；覆盖四类资源、发布下架、专家分配账号；Playwright+Chrome |
| 1.1 | 对齐草稿 §10/§11：删除联动删账号；专家角色 101 用例；UT/API/UI 编号顺延 |
| 1.2 | 分配账号：拼音首字母+id；`ROLE_KEY_EXPERT=exp`；UT-019a |
