doc_id: DEV-202607-002 feature_id: FEAT-202606-001-unified-entry-client type: dev-progress title: 患者服务台血常规闭环原型实施计划 status: draft owner: 医梦研发团队 created_at: 2026-07-05 updated_at: 2026-07-05 reviewers:
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: 在现有 patient-service-desk-v3 中加入患者端血常规深闭环,同时保留
独立的挂号、签到和候诊演示链。
Architecture: 继续使用纯前端事件投影原型。状态模型保存报告来源快照、 患者事项、授权、解释结果、反馈和失效状态;视图根据投影渲染报告中心、详情、 授权、处理中、结果和降级页面。报告解读不创建挂号命令,检查报告只增加统一入口 和扩展框架。
Tech Stack: HTML5、CSS3、原生JavaScript ES Modules、Node.js内置
node:test、esbuild经典浏览器包、Lucide图标、Open Design HTML Artifact。
| 文件 | 职责 |
|---|---|
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.state.mjs |
报告来源、状态迁移、反馈和场景fixture |
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.js |
报告中心、详情、结果、降级和控制器渲染 |
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.css |
报告组件、状态提示和双视口布局 |
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs |
状态、渲染、交互和安全边界测试 |
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.bundle.js |
从JS入口重新生成的经典浏览器包 |
docs/prototypes/patient-service-desk-v3/使用说明.md |
场景、操作和验证方式 |
docs/initiatives/FEAT-202606-001-unified-entry-client/测试计划.md |
报告闭环验收项 |
docs/initiatives/FEAT-202606-001-unified-entry-client/测试结果.md |
最终执行记录 |
在初始状态中增加报告源投影和反馈集合:
{
reportSourceProjections: {},
reportFeedback: [],
reportFilters: {
family: "ALL",
status: "ALL"
}
}
血常规报告源fixture使用以下稳定结构:
{
reportId: "report-blood-20260702",
family: "LAB",
reportType: "BLOOD_ROUTINE",
title: "血常规",
hospitalName: "空海医院",
departmentName: "检验科",
issuedAt: "2026-07-03 09:30",
sourceStatus: "FINAL",
interpretationStatus: "NOT_REQUESTED",
sourceVersion: 1,
sourceHash: "sha256:blood-v1",
metrics: [
{
metricId: "metric-wbc",
code: "WBC",
name: "白细胞计数",
value: "11.2",
unit: "10^9/L",
referenceRange: "3.5–9.5",
sourceFlag: "HIGH"
}
]
}
原型允许的患者端解释状态:
NOT_REQUESTED
CONSENT_REQUIRED
GENERATING
READY
NEED_REVIEW
CRITICAL_NOTICE
AI_UNAVAILABLE
INVALIDATED
Files:
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.state.mjsdocs/prototypes/patient-service-desk-v3/patient-service-desk-v3.jsTest: docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
[ ] Step 1:写失败测试
新增测试,要求控制器存在两个场景组,并锁定报告组八个场景:
assert.deepEqual(demoScenarioGroups.REPORT_CLOSURE, [
"REPORT_ARRIVED",
"REPORT_DETAIL",
"REPORT_CONSENT",
"REPORT_GENERATING",
"REPORT_READY",
"REPORT_NEED_REVIEW",
"REPORT_CRITICAL",
"REPORT_INVALIDATED",
]);
assert.ok(demoScenarioGroups.CARE_CLOSURE.includes("REGISTRATION_QUERY"));
[ ] Step 2:运行测试确认失败
node --test --test-name-pattern="scenario groups" \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:FAIL,提示demoScenarioGroups尚未导出。
在patient-service-desk-v3.js导出冻结分组,并让demoScenarios由分组扁平化生成:
export const demoScenarioGroups = Object.freeze({
REPORT_CLOSURE: Object.freeze([
"REPORT_ARRIVED",
"REPORT_DETAIL",
"REPORT_CONSENT",
"REPORT_GENERATING",
"REPORT_READY",
"REPORT_NEED_REVIEW",
"REPORT_CRITICAL",
"REPORT_INVALIDATED",
]),
CARE_CLOSURE: Object.freeze([
"EMPTY_HOME",
"REGISTRATION_QUERY",
"COMMAND_PREPARED",
"APPOINTMENT_CREATED",
"CHECKIN_AVAILABLE",
"QUEUE_UPDATED",
]),
});
export const demoScenarios = Object.freeze(
Object.values(demoScenarioGroups).flat(),
);
[ ] Step 4:运行测试确认通过
node --test --test-name-pattern="scenario groups" \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:PASS。
[ ] Step 5:提交
git add docs/prototypes/patient-service-desk-v3
git commit -m "test: define patient report closure scenarios"
Files:
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.state.mjsTest: docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
[ ] Step 1:写失败测试
覆盖报告出具、详情读取和筛选:
const bloodRoutineReportFixture = {
reportId: "report-blood-20260702",
family: "LAB",
reportType: "BLOOD_ROUTINE",
title: "血常规",
hospitalName: "空海医院",
departmentName: "检验科",
issuedAt: "2026-07-03 09:30",
sourceStatus: "FINAL",
interpretationStatus: "NOT_REQUESTED",
verificationStatus: "VERIFIED",
sourceVersion: 1,
sourceHash: "sha256:blood-v1",
readStatus: "UNREAD",
metrics: [],
};
const arrived = applyServerProjectionFixture(createInitialState(), {
id: "report-issued-blood-v1",
type: "REPORT_ISSUED",
occurredAt: "2026-07-03T09:30:00+08:00",
payload: bloodRoutineReportFixture,
});
assert.equal(
arrived.reportSourceProjections["report-blood-20260702"].sourceStatus,
"FINAL",
);
assert.equal(arrived.patientWorkItems.length, 1);
assert.equal(arrived.activeAgentTaskProjection, null);
assert.deepEqual(
selectReports(arrived, { family: "LAB", status: "UNREAD" })
.map((report) => report.reportId),
["report-blood-20260702"],
);
[ ] Step 2:运行测试确认失败
node --test --test-name-pattern="report source|report filters" \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:FAIL,报告源集合或selectReports不存在。
在createInitialState增加:
reportSourceProjections: {},
reportFeedback: [],
reportFilters: { family: "ALL", status: "ALL" },
REPORT_ISSUED只新增或版本化更新报告源、患者事项和消息,不创建活动Agent任务。
导出纯函数:
export function selectReports(
state,
{ family = "ALL", status = "ALL" } = {},
) {
return Object.values(state?.reportSourceProjections ?? {})
.filter((report) => family === "ALL" || report.family === family)
.filter((report) => status === "ALL" || report.readStatus === status)
.sort((a, b) => b.issuedAt.localeCompare(a.issuedAt));
}
[ ] Step 4:运行报告状态测试
node --test --test-name-pattern="report source|report filters" \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:PASS。
[ ] Step 5:提交
git add docs/prototypes/patient-service-desk-v3
git commit -m "feat: add patient report source projections"
Files:
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.jsdocs/prototypes/patient-service-desk-v3/patient-service-desk-v3.cssTest: docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
[ ] Step 1:写失败测试
const reportState = loadScenario(createInitialState(), "REPORT_ARRIVED");
const centerHtml = renderReportCenter(reportState);
assert.match(centerHtml, /全部/);
assert.match(centerHtml, /检验报告/);
assert.match(centerHtml, /检查报告/);
assert.match(centerHtml, /血常规/);
const detailHtml = renderReportDetail(
reportState.reportSourceProjections["report-blood-20260702"],
);
assert.match(detailHtml, /医院原始报告/);
assert.match(detailHtml, /白细胞计数/);
assert.match(detailHtml, /11\\.2/);
assert.match(detailHtml, /10\\^9\\/L/);
assert.match(detailHtml, /3\\.5–9\\.5/);
assert.doesNotMatch(detailHtml, /建议挂.*科|建议服用|确诊/);
[ ] Step 2:运行测试确认失败
node --test --test-name-pattern="report center|blood routine detail" \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:FAIL,渲染接口或完整内容不存在。
新增并导出:
export const renderReportCenter = (state) => {
const reports = selectReports(state, state?.reportFilters);
return `
<section class="report-center" aria-labelledby="reportCenterTitle">
<h1 id="reportCenterTitle">检验检查报告</h1>
<div class="report-filters" aria-label="报告类型筛选">
<button data-action="set-report-family-filter" data-filter="ALL">全部</button>
<button data-action="set-report-family-filter" data-filter="LAB">检验报告</button>
<button data-action="set-report-family-filter" data-filter="EXAM">检查报告</button>
</div>
<div class="report-list">
${reports.map((report) => `
<button
class="report-list-item"
data-action="view-report"
data-report-id="${escapeHtml(report.reportId)}"
>
<strong>${escapeHtml(report.title)}</strong>
<span>${escapeHtml(report.hospitalName)} · ${escapeHtml(report.issuedAt)}</span>
</button>
`).join("")}
</div>
</section>
`;
};
export const renderReportDetail = (report, expanded = false) => {
const metrics = expanded ? report.metrics : report.metrics.slice(0, 3);
return `
<section class="report-detail" aria-labelledby="reportDetailTitle">
<h1 id="reportDetailTitle">${escapeHtml(report.title)}</h1>
<p>${escapeHtml(report.hospitalName)} · ${escapeHtml(report.departmentName)}</p>
<h2>医院原始报告</h2>
<dl>
${metrics.map((metric) => `
<div>
<dt>${escapeHtml(metric.name)}</dt>
<dd>
${escapeHtml(metric.value)} ${escapeHtml(metric.unit)}
· 参考 ${escapeHtml(metric.referenceRange)}
</dd>
</div>
`).join("")}
</dl>
<button data-action="interpret-report"
data-report-id="${escapeHtml(report.reportId)}">AI辅助解读</button>
</section>
`;
};
增加操作:
open-report-center
set-report-family-filter
set-report-status-filter
view-report
toggle-report-metrics
报告详情中的主按钮为“AI辅助解读”,不能出现“推荐复诊”或“预约相关科室”。
[ ] Step 4:运行对应测试
node --test --test-name-pattern="report center|blood routine detail" \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:PASS。
[ ] Step 5:提交
git add docs/prototypes/patient-service-desk-v3
git commit -m "feat: add blood routine report center and detail"
Files:
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.state.mjsdocs/prototypes/patient-service-desk-v3/patient-service-desk-v3.jsTest: docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
[ ] Step 1:写失败测试
测试授权绑定和可信门禁:
const reportId = "report-blood-20260702";
const reportState = loadScenario(createInitialState(), "REPORT_ARRIVED");
const requested = requestReportInterpretation(reportState, reportId);
assert.equal(requested.overlays.consentId, `consent-ai-${reportId}`);
const granted = grantConsent(requested, `consent-ai-${reportId}`);
assert.equal(granted.reportSourceProjections[reportId].interpretationStatus,
"GENERATING");
for (const reason of [
"SOURCE_NOT_FINAL",
"OCR_REVIEW_REQUIRED",
"REFERENCE_CONFLICT",
]) {
const blockedState = {
...reportState,
reportSourceProjections: {
...reportState.reportSourceProjections,
[reportId]: {
...reportState.reportSourceProjections[reportId],
verificationStatus: "NEED_REVIEW",
verificationReason: reason,
},
},
};
const blocked = evaluateReportInterpretationGate(
blockedState,
reportId,
);
assert.equal(blocked.allowed, false);
}
[ ] Step 2:运行测试确认失败
node --test --test-name-pattern="report consent boundary|interpretation gate" \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:FAIL,门禁函数或绑定结构不存在。
导出:
export function evaluateReportInterpretationGate(state, reportId) {
const report = state?.reportSourceProjections?.[reportId];
if (!report) return { allowed: false, reason: "REPORT_NOT_FOUND" };
if (report.sourceStatus !== "FINAL") {
return { allowed: false, reason: "SOURCE_NOT_FINAL" };
}
if (report.verificationStatus !== "VERIFIED") {
return { allowed: false, reason: report.verificationReason };
}
if (report.criticalNotice === true) {
return { allowed: false, reason: "CRITICAL_NOTICE" };
}
return { allowed: true, reason: null };
}
授权只绑定当前患者和当前报告。门禁失败时不创建结果,不启动解释计时器。
同时将现有grantConsent改为接受动态consent-ai-${reportId},并从当前overlay校验
患者和报告绑定;不新增第二套授权函数。
[ ] Step 4:运行授权与门禁测试
node --test --test-name-pattern="report consent boundary|interpretation gate" \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:PASS。
[ ] Step 5:提交
git add docs/prototypes/patient-service-desk-v3
git commit -m "feat: enforce patient report interpretation gate"
Files:
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.state.mjsdocs/prototypes/patient-service-desk-v3/patient-service-desk-v3.jsdocs/prototypes/patient-service-desk-v3/patient-service-desk-v3.cssTest: docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
[ ] Step 1:写失败测试
const reportId = "report-blood-20260702";
const generating = loadScenario(createInitialState(), "REPORT_GENERATING");
const ready = applyReportInterpretationProjectionFixture(generating, reportId);
const html = renderReportInterpretationResult(
ready.resultSnapshotProjections["result-report-interpretation-001"],
);
for (const text of [
"结果概括",
"需要关注",
"指标解释",
"常见相关因素",
"可以怎么做",
"内容依据",
]) {
assert.match(html, new RegExp(text));
}
assert.doesNotMatch(html, /推荐科室|复查周期|治疗方案|建议服用/);
const feedback = submitReportFeedback(ready, {
reportId,
category: "HARD_TO_UNDERSTAND",
});
assert.equal(feedback.reportFeedback.at(-1).category, "HARD_TO_UNDERSTAND");
[ ] Step 2:运行测试确认失败
node --test --test-name-pattern="safe report result|report feedback" \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:FAIL,六层结果或反馈接口不存在。
结果只提供以下操作:
查看原始报告
咨询开单医生
在线咨询
联系人工服务
提交反馈
撤回授权
导出纯函数:
export function submitReportFeedback(state, { reportId, category }) {
const allowed = new Set([
"HELPFUL",
"METRIC_INACCURATE",
"HARD_TO_UNDERSTAND",
"DIFFERS_FROM_DOCTOR",
"OTHER",
]);
if (!allowed.has(category)) return state;
return {
...state,
reportFeedback: [
...(state.reportFeedback ?? []),
{ id: `feedback-${reportId}-${category}`, reportId, category },
],
};
}
[ ] Step 4:运行结果与反馈测试
node --test --test-name-pattern="safe report result|report feedback" \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:PASS。
[ ] Step 5:提交
git add docs/prototypes/patient-service-desk-v3
git commit -m "feat: add safe blood report result and feedback"
Files:
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.state.mjsdocs/prototypes/patient-service-desk-v3/patient-service-desk-v3.jsdocs/prototypes/patient-service-desk-v3/patient-service-desk-v3.cssTest: docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
[ ] Step 1:写失败测试
const reportId = "report-blood-20260702";
const readyState = loadScenario(createInitialState(), "REPORT_READY");
const needsReview = loadScenario(createInitialState(), "REPORT_NEED_REVIEW");
assert.match(renderReportUnavailable({
reason: "OCR_REVIEW_REQUIRED",
}), /暂不适合自动解读/);
assert.doesNotMatch(renderReportUnavailable({
reason: "OCR_REVIEW_REQUIRED",
}), /继续生成/);
const critical = loadScenario(createInitialState(), "REPORT_CRITICAL");
assert.match(renderReportUnavailable({
reason: "CRITICAL_NOTICE",
}), /请按医院提示及时联系/);
assert.doesNotMatch(renderReportUnavailable({
reason: "CRITICAL_NOTICE",
}), /AI解读|推荐科室/);
const invalidated = applyServerProjectionFixture(readyState, {
id: "report-corrected-blood-v2",
type: "REPORT_CORRECTED",
occurredAt: "2026-07-03T11:00:00+08:00",
payload: {
reportId,
sourceVersion: 2,
sourceHash: "sha256:blood-v2",
},
});
assert.equal(
invalidated.reportSourceProjections[reportId].interpretationStatus,
"INVALIDATED",
);
assert.equal(
invalidated.resultSnapshotProjections[
"result-report-interpretation-001"
].valid,
false,
);
[ ] Step 2:运行测试确认失败
node --test --test-name-pattern="report degradation|critical notice|report invalidation" \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:FAIL,降级页面或更正事件未实现。
统一降级组件接收原因码:
const REPORT_UNAVAILABLE_PRESENTATION = Object.freeze({
OCR_REVIEW_REQUIRED: {
title: "当前报告暂不适合自动解读",
description: "报告内容需要人工核对,您仍可查看医院原始报告。",
},
CRITICAL_NOTICE: {
title: "请按医院提示及时联系",
description: "当前报告需要按医院既有流程处理。",
},
AI_UNAVAILABLE: {
title: "AI辅助解读暂不可用",
description: "医院原始报告仍可正常查看,请稍后重试。",
},
UNSUPPORTED: {
title: "暂不支持自动解读",
description: "您可以查看原始报告或联系人工服务。",
},
});
export const renderReportUnavailable = ({ reason }) => {
const presentation = REPORT_UNAVAILABLE_PRESENTATION[reason]
?? REPORT_UNAVAILABLE_PRESENTATION.UNSUPPORTED;
return `
<section class="report-unavailable" role="status">
<h1>${escapeHtml(presentation.title)}</h1>
<p>${escapeHtml(presentation.description)}</p>
<button data-action="open-original-report">查看原始报告</button>
<button data-action="contact-human-service">联系人工服务</button>
</section>
`;
};
REPORT_CORRECTED和REPORT_WITHDRAWN必须使旧结果失效;旧结果可保留在状态中用于
演示审计,但不能由当前页面读取为有效结果。
[ ] Step 4:运行降级和失效测试
node --test --test-name-pattern="report degradation|critical notice|report invalidation" \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:PASS。
[ ] Step 5:提交
git add docs/prototypes/patient-service-desk-v3
git commit -m "feat: add patient report safety degradation states"
Files:
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.state.mjsdocs/prototypes/patient-service-desk-v3/patient-service-desk-v3.jsTest: docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
[ ] Step 1:写失败测试
const reportState = loadScenario(createInitialState(), "REPORT_ARRIVED");
const imaging = {
reportId: "report-ct-20260702",
family: "EXAM",
reportType: "IMAGING",
title: "胸部CT",
bodyPart: "胸部",
findings: "双肺纹理清晰。",
conclusion: "本次检查未见明确异常。",
sourceStatus: "FINAL",
};
const html = renderExaminationReportDetail(imaging);
assert.match(html, /检查所见/);
assert.match(html, /报告结论/);
assert.doesNotMatch(html, /参考范围|异常指标列表/);
assert.match(html, /该类型暂未开放AI辅助解读/);
assert.match(renderHome(reportState), /血常规报告已出/);
assert.match(renderMessages(reportState), /血常规报告/);
assert.match(renderRecords({
...reportState,
activeTab: "records",
}), /检验报告/);
assert.match(renderAssistant({
...reportState,
activeTab: "assistant",
}), /帮我看报告/);
[ ] Step 2:运行测试确认失败
node --test --test-name-pattern="examination report framework|report entry points" \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:FAIL,检查报告详情或入口联动不足。
检查报告只渲染:
检查名称和部位
检查所见
报告结论
报告医生与审核状态
图像或PDF入口
暂未开放AI辅助解读
不得复用检验报告的指标、单位和参考区间组件。
[ ] Step 4:运行测试
node --test --test-name-pattern="examination report framework|report entry points" \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:PASS。
[ ] Step 5:提交
git add docs/prototypes/patient-service-desk-v3
git commit -m "feat: add examination report extension shell"
Files:
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.jsdocs/prototypes/patient-service-desk-v3/patient-service-desk-v3.cssdocs/prototypes/patient-service-desk-v3/patient-service-desk-v3.bundle.jsdocs/prototypes/patient-service-desk-v3/使用说明.mddocs/initiatives/FEAT-202606-001-unified-entry-client/测试计划.mddocs/initiatives/FEAT-202606-001-unified-entry-client/测试结果.mdTest: docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
[ ] Step 1:写完整故事线失败测试
for (const scenario of demoScenarioGroups.REPORT_CLOSURE) {
const state = loadScenario(createInitialState(), scenario);
assert.equal(state.demoScenario, scenario);
assert.equal(state.activeAgentTaskProjection, null);
}
const reportStory = [
"REPORT_ARRIVED",
"REPORT_DETAIL",
"REPORT_CONSENT",
"REPORT_GENERATING",
"REPORT_READY",
"REPORT_INVALIDATED",
];
assert.deepEqual(
reportStory.map((scenario) => (
loadScenario(createInitialState(), scenario).demoScenario
)),
reportStory,
);
同时断言:
HTML继续通过经典bundle支持file://直接打开。
[ ] Step 2:运行全部测试确认尚有失败
node --test \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
预期:新增完整故事线测试FAIL,既有测试不得出现无关失败。
遥控器分组显示“报告闭环”和“就医闭环”,保持:
上一步
下一步
重置
390×844
430×932
隐藏控制器
所有报告弹窗挂载在.phone-shell内部,不得覆盖外部页面。
[ ] Step 4:重新生成经典bundle
/Users/destiny/node_modules/.bin/esbuild \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.js \
--bundle \
--format=iife \
--platform=browser \
--target=es2022 \
--banner:js='/* Generated from patient-service-desk-v3.js for direct file:// opening. */' \
--outfile=docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.bundle.js
预期:生成成功,无未解析import。
[ ] Step 5:运行完整验证
node --test \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.test.mjs
node --check \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.state.mjs
node --check \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.js
node --check \
docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.bundle.js
git diff --check
预期:全部测试通过、语法检查通过、差异检查无输出。
[ ] Step 6:同步Open Design发布副本
OPEN_DESIGN="/Users/destiny/Library/Application Support/Open Design/namespaces/release-stable/data/projects/b7a08855-87bd-493c-92a4-31655a384570/web"
cp docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.html \
"$OPEN_DESIGN/patient-service-desk-v3.html"
cp docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.css \
"$OPEN_DESIGN/patient-service-desk-v3.css"
cp docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.js \
"$OPEN_DESIGN/patient-service-desk-v3.js"
cp docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.state.mjs \
"$OPEN_DESIGN/patient-service-desk-v3.state.mjs"
cp docs/prototypes/patient-service-desk-v3/patient-service-desk-v3.bundle.js \
"$OPEN_DESIGN/patient-service-desk-v3.bundle.js"
逐个使用cmp确认发布副本与仓库源码一致。
更新测试计划、测试结果和使用说明,记录:
不包含真实LIS、FastGPT和医护审核台。
[ ] Step 8:提交
git add \
docs/prototypes/patient-service-desk-v3 \
docs/initiatives/FEAT-202606-001-unified-entry-client/测试计划.md \
docs/initiatives/FEAT-202606-001-unified-entry-client/测试结果.md
git commit -m "docs: complete patient blood report prototype delivery"
完成后必须满足:
REPORT_ISSUED只创建患者事项,不自动启动AI解读;| 日期 | 进展 | 风险 | 下一步 |
|---|---|---|---|
| 2026-07-05 | 完成功能策略、边界和逐页设计评审 | 原型仍是fixture,不代表生产接口 | 按Task 1开始TDD实现 |
file://地址;自动测试和静态契约不能替代
产品负责人在可访问环境中的真实双视口视觉复核。cmp验证。