docs(broadcast): plan multi-role file insights
This commit is contained in:
@@ -0,0 +1,522 @@
|
||||
# 大喇叭公司文件多岗位解读 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 在现有“大喇叭消息 + 单个公司文件”链路中生成有原文依据的多岗位解读,并让员工默认看到自己岗位视角、可切换查看全部相关视角。
|
||||
|
||||
**Architecture:** 复用现有附件解析、摘要、鉴权下载和消息追问链路。新增一个职责单一的 `AihrBroadcastInsightService`,使用现有模型调用边界按自然段分块生成结构化岗位解读,服务端只保留引用能在原文块中精确命中的内容;附件文件状态与解读状态分离,解读失败不阻塞文件发布和阅读。
|
||||
|
||||
**Tech Stack:** Java 17、Spring Boot、JdbcTemplate、Jackson、MySQL 8、Vue 3、uni-app、TypeScript、Node test、JUnit 5/Mockito。
|
||||
|
||||
---
|
||||
|
||||
## 文件职责
|
||||
|
||||
- Create `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/broadcast/AihrBroadcastInsightService.java`
|
||||
- 固定岗位目录、岗位映射、自然段分块、模型调用、JSON 清洗、原文引用校验、跨块合并和响应反序列化。
|
||||
- Modify `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/broadcast/AihrBroadcastAttachmentService.java`
|
||||
- 文件提取完成后先保存 `READY`,再独立领取和处理岗位解读任务;恢复卡死任务。
|
||||
- Modify `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/broadcast/AihrBroadcastService.java`
|
||||
- 员工详情查询解读字段,基于认证手机号对应的在职组织岗位计算默认视角,不返回 `extracted_text`。
|
||||
- Modify `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/broadcast/AihrBroadcastDto.java`
|
||||
- 增加岗位解读、来源依据和解读状态字段。
|
||||
- Create `backend/script/sql/update/aihr_20260725_broadcast_multi_role_insight_mysql8.sql`
|
||||
- 为附件表增加 `insight_status`、`insights_json`、`insight_version` 及解读队列索引。
|
||||
- Create `backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/broadcast/AihrBroadcastInsightServiceTest.java`
|
||||
- 覆盖岗位映射、自然段分块、伪造引用剔除、跨块合并和部分成功状态。
|
||||
- Modify existing broadcast backend tests
|
||||
- 覆盖文件与解读状态解耦、DTO 不泄漏全文、租户/撤回/在职身份约束不回退。
|
||||
- Modify `mobile-uni/src/services/broadcast.ts`
|
||||
- 声明岗位解读响应类型。
|
||||
- Modify `mobile-uni/src/pages/user/broadcast/detail.vue`
|
||||
- 在文件摘要之后展示默认岗位、岗位切换、五类要点和折叠的原文依据。
|
||||
- Modify `mobile-uni/src/pages/user/broadcast/index.vue`
|
||||
- 将通知命中标签“与我有关”改为“定向提醒”。
|
||||
- Create `mobile-uni/tests/broadcast-multi-role-insight.test.mjs`
|
||||
- 覆盖类型契约、默认视角、切换、依据折叠、降级状态及术语改名。
|
||||
- Modify `scripts/reset-dev-db.sh`, `scripts/tests/aihr-schema-migrations.test.sh`, `scripts/release-preflight.sh`, `scripts/demo-check.sh`
|
||||
- 纳入正式迁移与远端只读 schema 合同。
|
||||
- Modify `docs/API_INTEGRATION.md`, `docs/BRD_IMPLEMENTATION_AUDIT.md`
|
||||
- 记录接口字段、生成状态、失败降级和验收边界。
|
||||
|
||||
### Task 1: 数据库合同与 DTO
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/script/sql/update/aihr_20260725_broadcast_multi_role_insight_mysql8.sql`
|
||||
- Modify: `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/broadcast/AihrBroadcastDto.java`
|
||||
- Modify: `scripts/tests/aihr-schema-migrations.test.sh`
|
||||
- Test: `backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/broadcast/AihrBroadcastAttachmentContractTest.java`
|
||||
|
||||
- [ ] **Step 1: 写失败的 schema 与 DTO 合同测试**
|
||||
|
||||
在迁移测试中要求以下三列存在:
|
||||
|
||||
```bash
|
||||
SELECT COUNT(*)
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema='$DB'
|
||||
AND table_name='aihr_broadcast_attachment'
|
||||
AND column_name IN ('insight_status','insights_json','insight_version');
|
||||
```
|
||||
|
||||
在 `AihrBroadcastAttachmentContractTest` 中断言响应包含 `insightStatus`、`defaultPerspectiveCode`、`perspectives`,同时不包含 `extractedText` 和 `insightsJson`。
|
||||
|
||||
- [ ] **Step 2: 运行测试并确认失败**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
bash scripts/tests/aihr-schema-migrations.test.sh
|
||||
mvn -f backend/pom.xml -pl ruoyi-modules/ruoyi-aihr -am \
|
||||
-Dtest=AihrBroadcastAttachmentContractTest \
|
||||
-Dsurefire.failIfNoSpecifiedTests=false test
|
||||
```
|
||||
|
||||
Expected: schema 测试缺少 3 列,Java 测试缺少新的 record component。
|
||||
|
||||
- [ ] **Step 3: 写幂等迁移和最小 DTO**
|
||||
|
||||
迁移增加:
|
||||
|
||||
```sql
|
||||
ALTER TABLE aihr_broadcast_attachment
|
||||
ADD COLUMN insight_status varchar(20) NOT NULL DEFAULT 'NOT_PROCESSED' AFTER summary,
|
||||
ADD COLUMN insights_json longtext NULL AFTER insight_status,
|
||||
ADD COLUMN insight_version varchar(30) NULL AFTER insights_json;
|
||||
```
|
||||
|
||||
迁移必须通过 `information_schema` + prepared statement 分列幂等执行,并增加:
|
||||
|
||||
```sql
|
||||
KEY idx_aihr_broadcast_attachment_insight_queue
|
||||
(insight_status, status, update_time)
|
||||
```
|
||||
|
||||
DTO 增加:
|
||||
|
||||
```java
|
||||
public record BroadcastEvidence(int paragraphIndex, String quote) {}
|
||||
|
||||
public record BroadcastPerspective(
|
||||
String code,
|
||||
String label,
|
||||
String summary,
|
||||
List<String> concerns,
|
||||
List<String> impacts,
|
||||
List<String> actions,
|
||||
List<String> risks,
|
||||
List<BroadcastEvidence> evidence
|
||||
) {}
|
||||
```
|
||||
|
||||
附件响应追加:
|
||||
|
||||
```java
|
||||
String insightStatus,
|
||||
String defaultPerspectiveCode,
|
||||
List<String> perspectiveLabels,
|
||||
List<BroadcastPerspective> perspectives
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 运行测试并确认通过**
|
||||
|
||||
Run the two Task 1 commands.
|
||||
|
||||
Expected: PASS,迁移可重复执行,DTO 没有原文和 JSON 存储字段。
|
||||
|
||||
- [ ] **Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add backend/script/sql/update/aihr_20260725_broadcast_multi_role_insight_mysql8.sql \
|
||||
backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/broadcast/AihrBroadcastDto.java \
|
||||
backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/broadcast/AihrBroadcastAttachmentContractTest.java \
|
||||
scripts/tests/aihr-schema-migrations.test.sh
|
||||
git commit -m "feat(broadcast): add multi-role insight contract"
|
||||
```
|
||||
|
||||
### Task 2: 岗位解读生成器
|
||||
|
||||
**Files:**
|
||||
- Create: `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/broadcast/AihrBroadcastInsightService.java`
|
||||
- Create: `backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/broadcast/AihrBroadcastInsightServiceTest.java`
|
||||
|
||||
- [ ] **Step 1: 写失败的核心逻辑测试**
|
||||
|
||||
使用 Mockito 模拟 `AihrModelSeedService.chat` 返回 OpenAI-compatible JSON,覆盖:
|
||||
|
||||
```java
|
||||
assertEquals("finance", AihrBroadcastInsightService.defaultPerspectiveCode(List.of("财务经理")));
|
||||
assertEquals("living_advisor", AihrBroadcastInsightService.defaultPerspectiveCode(List.of("物业管家")));
|
||||
assertNull(AihrBroadcastInsightService.defaultPerspectiveCode(List.of("未知岗位")));
|
||||
assertTrue(AihrBroadcastInsightService.chunks(longParagraphText).size() > 1);
|
||||
assertTrue(result.perspectives().getFirst().evidence().stream()
|
||||
.allMatch(item -> source.contains(item.quote())));
|
||||
assertFalse(resultJson.contains("模型编造但原文不存在"));
|
||||
```
|
||||
|
||||
另测第二块模型失败时保留第一块结果并返回 `PARTIAL`,所有块失败时返回 `FAILED`。
|
||||
|
||||
- [ ] **Step 2: 运行测试并确认失败**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -f backend/pom.xml -pl ruoyi-modules/ruoyi-aihr -am \
|
||||
-Dtest=AihrBroadcastInsightServiceTest \
|
||||
-Dsurefire.failIfNoSpecifiedTests=false test
|
||||
```
|
||||
|
||||
Expected: FAIL because the service does not exist.
|
||||
|
||||
- [ ] **Step 3: 实现最小生成器**
|
||||
|
||||
固定九个角色:
|
||||
|
||||
```java
|
||||
private static final Map<String, String> ROLE_LABELS = Map.ofEntries(
|
||||
entry("living_advisor", "生活顾问/客服"),
|
||||
entry("cleaning", "保洁"),
|
||||
entry("security", "保安"),
|
||||
entry("engineering", "保修/工程"),
|
||||
entry("finance", "财务"),
|
||||
entry("hr", "人力"),
|
||||
entry("operations", "业务运营"),
|
||||
entry("audit_risk", "审计风控"),
|
||||
entry("management", "管理层")
|
||||
);
|
||||
```
|
||||
|
||||
自然段块目标 4,000 字、相邻重叠 300 字,最多 80 块。每块调用:
|
||||
|
||||
```java
|
||||
modelService.chat(new ChatRequest(
|
||||
prompt(fileName, chunk, paragraphOffset),
|
||||
null,
|
||||
"只根据给定原文返回 JSON;未提及的岗位不要输出;evidence.quote 必须逐字复制原文。"
|
||||
));
|
||||
```
|
||||
|
||||
只接受 `mode == "openai-compatible"` 且 `error` 为空的响应。解析后执行:
|
||||
|
||||
```java
|
||||
if (!chunk.text().contains(evidence.quote())) {
|
||||
continue;
|
||||
}
|
||||
```
|
||||
|
||||
每岗位最多 5 条 concerns/impacts/actions/risks、3 条 evidence;文本去空白、去重、限制长度;仅保留固定角色代码。成功块少于总块数或正文超过 80 块时为 `PARTIAL`,全部失败为 `FAILED`。
|
||||
|
||||
- [ ] **Step 4: 运行测试并确认通过**
|
||||
|
||||
Run the Task 2 Maven command.
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/broadcast/AihrBroadcastInsightService.java \
|
||||
backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/broadcast/AihrBroadcastInsightServiceTest.java
|
||||
git commit -m "feat(broadcast): generate grounded role insights"
|
||||
```
|
||||
|
||||
### Task 3: 附件异步链路与员工详情
|
||||
|
||||
**Files:**
|
||||
- Modify: `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/broadcast/AihrBroadcastAttachmentService.java`
|
||||
- Modify: `backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/broadcast/AihrBroadcastService.java`
|
||||
- Modify: `backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/broadcast/AihrBroadcastServiceTest.java`
|
||||
- Modify: `backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/broadcast/AihrBroadcastAttachmentContractTest.java`
|
||||
|
||||
- [ ] **Step 1: 写失败的链路测试**
|
||||
|
||||
测试源代码和 JDBC 参数,要求:
|
||||
|
||||
```java
|
||||
assertTrue(attachmentSource.contains("set status = 'READY', extracted_text = ?, summary = ?"));
|
||||
assertTrue(attachmentSource.contains("insight_status = 'PENDING'"));
|
||||
assertTrue(attachmentSource.contains("insight_status = 'FAILED'"));
|
||||
assertTrue(detailSql.contains("a.insights_json as attachment_insights_json"));
|
||||
assertTrue(detailSql.contains("m.status = 'PUBLISHED'"));
|
||||
assertFalse(responseFields.contains("extractedText"));
|
||||
```
|
||||
|
||||
新增详情测试:岗位 `财务主管` 默认代码为 `finance`;同一响应仍返回其他全部岗位;撤回、跨租户、非在职员工继续在查询前失败关闭。
|
||||
|
||||
- [ ] **Step 2: 运行测试并确认失败**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -f backend/pom.xml -pl ruoyi-modules/ruoyi-aihr -am \
|
||||
-Dtest=AihrBroadcastServiceTest,AihrBroadcastAttachmentContractTest \
|
||||
-Dsurefire.failIfNoSpecifiedTests=false test
|
||||
```
|
||||
|
||||
Expected: FAIL on missing insight queue and response mapping.
|
||||
|
||||
- [ ] **Step 3: 分离文件状态和解读状态**
|
||||
|
||||
附件解析成功后立即写:
|
||||
|
||||
```sql
|
||||
status = 'READY',
|
||||
extracted_text = ?,
|
||||
summary = ?,
|
||||
insight_status = 'PENDING',
|
||||
insights_json = NULL,
|
||||
insight_version = NULL
|
||||
```
|
||||
|
||||
解读任务领取时把 `PENDING` 原子更新为内部 `PROCESSING`;API 将内部 `PROCESSING` 映射为 `PENDING`。成功保存 `READY/PARTIAL` 与 JSON、版本;异常只写 `insight_status='FAILED'`,不得把附件 `status` 改回 `FAILED`。启动恢复将超过 30 分钟的内部 `PROCESSING` 重置为 `PENDING`。
|
||||
|
||||
- [ ] **Step 4: 安全映射员工详情**
|
||||
|
||||
详情 SQL 只在既有租户、`PUBLISHED`、在职员工门禁通过后读取存储 JSON。服务端用当前 APP 用户手机号和 `aihr_org_snapshot` 的精确在职匹配读取 `position_name`,再计算 `defaultPerspectiveCode`;客户端不得提交岗位。返回全部已生成岗位,但绝不返回 `extracted_text` 或 `insights_json`。
|
||||
|
||||
- [ ] **Step 5: 运行测试并确认通过**
|
||||
|
||||
Run the Task 3 Maven command.
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 6: 提交**
|
||||
|
||||
```bash
|
||||
git add backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/broadcast/AihrBroadcastAttachmentService.java \
|
||||
backend/ruoyi-modules/ruoyi-aihr/src/main/java/org/dromara/aihr/broadcast/AihrBroadcastService.java \
|
||||
backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/broadcast/AihrBroadcastServiceTest.java \
|
||||
backend/ruoyi-modules/ruoyi-aihr/src/test/java/org/dromara/aihr/broadcast/AihrBroadcastAttachmentContractTest.java
|
||||
git commit -m "feat(broadcast): expose employee role insights"
|
||||
```
|
||||
|
||||
### Task 4: 员工端多岗位阅读
|
||||
|
||||
**Files:**
|
||||
- Modify: `mobile-uni/src/services/broadcast.ts`
|
||||
- Modify: `mobile-uni/src/pages/user/broadcast/detail.vue`
|
||||
- Modify: `mobile-uni/src/pages/user/broadcast/index.vue`
|
||||
- Create: `mobile-uni/tests/broadcast-multi-role-insight.test.mjs`
|
||||
- Modify: `mobile-uni/tests/broadcast-attachment.test.mjs`
|
||||
|
||||
- [ ] **Step 1: 写失败的移动端合同测试**
|
||||
|
||||
断言源码包含:
|
||||
|
||||
```js
|
||||
assert.match(service, /interface BroadcastPerspective/);
|
||||
assert.match(detail, /多岗位解读/);
|
||||
assert.match(detail, /defaultPerspectiveCode/);
|
||||
assert.match(detail, /原文依据/);
|
||||
assert.match(detail, /insightStatus === 'FAILED'/);
|
||||
assert.doesNotMatch(detail, /与我有关/);
|
||||
assert.match(index, /定向提醒/);
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行测试并确认失败**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
npm --prefix mobile-uni run test:unit
|
||||
```
|
||||
|
||||
Expected: new multi-role test FAIL.
|
||||
|
||||
- [ ] **Step 3: 增加类型和默认选择**
|
||||
|
||||
类型与后端一致。详情加载后:
|
||||
|
||||
```ts
|
||||
const perspectives = computed(() => item.value?.attachment?.perspectives || []);
|
||||
const selectedCode = ref('');
|
||||
|
||||
const selectInitialPerspective = (attachment?: BroadcastAttachment) => {
|
||||
selectedCode.value = attachment?.perspectives.some(
|
||||
perspective => perspective.code === attachment.defaultPerspectiveCode
|
||||
)
|
||||
? attachment.defaultPerspectiveCode || ''
|
||||
: attachment?.perspectives[0]?.code || '';
|
||||
};
|
||||
```
|
||||
|
||||
显示“我的岗位视角”仅当默认代码实际命中;否则显示“多岗位解读”。
|
||||
|
||||
- [ ] **Step 4: 实现移动端布局和降级状态**
|
||||
|
||||
摘要保持在前。其后依次展示:
|
||||
|
||||
```text
|
||||
多岗位解读 / 我的岗位视角
|
||||
[生活顾问] [财务] [人力] [业务运营] …
|
||||
本岗位摘要
|
||||
关注点 / 影响 / 建议行动 / 风险
|
||||
原文依据(默认折叠)
|
||||
```
|
||||
|
||||
`PENDING` 显示“AI 正在从不同岗位解读”;`PARTIAL` 显示“已生成部分岗位解读”;`FAILED` 或 `NOT_PROCESSED` 只显示轻量说明,不隐藏摘要、原文件和“问这条消息”。岗位 chips 允许横向滚动,按钮具备可识别选中态和可读文本。
|
||||
|
||||
- [ ] **Step 5: 运行移动端测试、类型检查和构建**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
npm --prefix mobile-uni run test:unit
|
||||
npm --prefix mobile-uni run typecheck
|
||||
npm --prefix mobile-uni run build:h5
|
||||
```
|
||||
|
||||
Expected: all PASS.
|
||||
|
||||
- [ ] **Step 6: 提交**
|
||||
|
||||
```bash
|
||||
git add mobile-uni/src/services/broadcast.ts \
|
||||
mobile-uni/src/pages/user/broadcast/detail.vue \
|
||||
mobile-uni/src/pages/user/broadcast/index.vue \
|
||||
mobile-uni/tests/broadcast-multi-role-insight.test.mjs \
|
||||
mobile-uni/tests/broadcast-attachment.test.mjs
|
||||
git commit -m "feat(mobile): show broadcast role perspectives"
|
||||
```
|
||||
|
||||
### Task 5: 开发重置、发布预检与文档
|
||||
|
||||
**Files:**
|
||||
- Modify: `scripts/reset-dev-db.sh`
|
||||
- Modify: `scripts/release-preflight.sh`
|
||||
- Modify: `scripts/demo-check.sh`
|
||||
- Modify: `docs/API_INTEGRATION.md`
|
||||
- Modify: `docs/BRD_IMPLEMENTATION_AUDIT.md`
|
||||
|
||||
- [ ] **Step 1: 写失败的发布合同**
|
||||
|
||||
将远端附件合同从 11 个业务列扩展为 14 个,并明确要求:
|
||||
|
||||
```text
|
||||
insight_status
|
||||
insights_json
|
||||
insight_version
|
||||
```
|
||||
|
||||
`demo-check.sh` 要求新迁移、解读服务、移动端“多岗位解读”和“定向提醒”存在。
|
||||
|
||||
- [ ] **Step 2: 运行静态预检并确认失败**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
bash scripts/demo-check.sh
|
||||
```
|
||||
|
||||
Expected: FAIL on missing preflight/docs markers before implementation.
|
||||
|
||||
- [ ] **Step 3: 接入迁移与更新文档**
|
||||
|
||||
`reset-dev-db.sh` 在附件基础迁移后执行新迁移。API 文档记录:
|
||||
|
||||
```text
|
||||
insightStatus: NOT_PROCESSED | PENDING | READY | PARTIAL | FAILED
|
||||
defaultPerspectiveCode: 服务端按认证手机号对应在职岗位计算
|
||||
perspectives[]: code/label/summary/concerns/impacts/actions/risks/evidence
|
||||
```
|
||||
|
||||
同时记录:所有有原消息阅读权限的员工可切换全部生成岗位;引用必须逐字命中原文;失败不影响摘要、下载和追问;旧“与我有关”改名“定向提醒”且语义仍为通知定向。
|
||||
|
||||
- [ ] **Step 4: 运行静态预检**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
bash scripts/demo-check.sh
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add scripts/reset-dev-db.sh scripts/release-preflight.sh scripts/demo-check.sh \
|
||||
docs/API_INTEGRATION.md docs/BRD_IMPLEMENTATION_AUDIT.md
|
||||
git commit -m "docs(broadcast): define role insight release contract"
|
||||
```
|
||||
|
||||
### Task 6: 集成、视觉和真实交互验收
|
||||
|
||||
**Files:**
|
||||
- Verify all modified files
|
||||
- Evidence: local browser screenshots at 390 × 844 and desktop responsive view
|
||||
|
||||
- [ ] **Step 1: 运行后端与移动端全量相关检查**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -f backend/pom.xml -pl ruoyi-modules/ruoyi-aihr -am \
|
||||
-DskipITs -Dsurefire.failIfNoSpecifiedTests=false test
|
||||
npm --prefix mobile-uni run test:unit
|
||||
npm --prefix mobile-uni run typecheck
|
||||
npm --prefix mobile-uni run build:h5
|
||||
bash scripts/demo-check.sh
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
- [ ] **Step 2: 启动本地服务并造两份可识别测试文件**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.dev.yml up -d
|
||||
portless run --name wygj-api ./scripts/dev-backend.sh
|
||||
portless run --name wygj-mobile-uni npm --prefix mobile-uni run dev:h5
|
||||
```
|
||||
|
||||
通过现有管理端上传并发布:
|
||||
|
||||
1. 同时涉及财务、人力、业务运营的短文件;
|
||||
2. 超过 4,000 字且关键内容在尾部的长文件。
|
||||
|
||||
使用数据库中实际在职手机号和开发固定验证码登录,不在日志、截图或报告中保留手机号。
|
||||
|
||||
- [ ] **Step 3: 在 390 × 844 浏览器真实验证**
|
||||
|
||||
逐项操作:
|
||||
|
||||
1. 打开大喇叭详情,确认摘要位于多岗位解读之前;
|
||||
2. 确认默认选中当前员工岗位对应视角;
|
||||
3. 横向切换财务、人力、业务运营等全部返回岗位;
|
||||
4. 展开原文依据并核对引文存在于文件;
|
||||
5. 打开原文件;
|
||||
6. 点击“问这条消息”;
|
||||
7. 验证 `PENDING/PARTIAL/FAILED` 时主链路仍可用;
|
||||
8. 检查文字换行、chip 溢出、底部按钮、滚动与点击区域。
|
||||
|
||||
保存并检查截图,不以页面可加载替代视觉验收。
|
||||
|
||||
- [ ] **Step 4: 安全回归**
|
||||
|
||||
用自动化或直接 HTTP 证据确认:
|
||||
|
||||
```text
|
||||
撤回消息 -> 404
|
||||
跨租户消息 -> 404
|
||||
非在职 APP 身份 -> 403
|
||||
员工详情 JSON -> 不含 extracted_text / insights_json
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 代码审查与修复**
|
||||
|
||||
分别进行 Java、TypeScript 和整体代码审查;修复所有高/中优先级问题后重跑 Task 6 Step 1。
|
||||
|
||||
- [ ] **Step 6: 提交最终修复**
|
||||
|
||||
```bash
|
||||
git add -u
|
||||
git commit -m "fix(broadcast): close multi-role insight review findings"
|
||||
```
|
||||
|
||||
- [ ] **Step 7: 交付分支**
|
||||
|
||||
确认工作区干净,报告 `implemented / locally verified / visually verified`;生产部署与 `production-verified` 只有在执行正式迁移、静态发布、后端发布、完整 `release-preflight` 和线上真实账号验证后才能声明。
|
||||
Reference in New Issue
Block a user