Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
wangjian963
2026-06-15 15:28:05 +08:00
3 changed files with 141 additions and 4 deletions

View File

@@ -449,10 +449,17 @@ function checkSelectable(row, index) {
*/
function clickRow(params) {
const row = params.row || params;
patientInfo.value = row;
const encId = row.encounterId ?? row.id;
if (encId === undefined || encId === null || encId === '') {
proxy.$modal.msgError('患者记录缺少就诊ID无法加载收费详情');
chargeList.value = [];
patientInfo.value = row;
return;
}
patientInfo.value = { ...row, encounterId: encId };
chargeLoading.value = true;
encounterId.value = row.encounterId;
getChargeList(row.encounterId).then((res) => {
encounterId.value = encId;
getChargeList(encId).then((res) => {
chargeList.value = res.data;
setTimeout(() => {
chargeLoading.value = false;

View File

@@ -34,7 +34,7 @@
label="临床医嘱"
name="prescription"
>
<Advice ref="adviceRef" />
<Advice ref="adviceRef" :patient-info="currentPatientInfo" />
</el-tab-pane>
<!-- <el-tab-pane label="医技报告" name="fourth">Task</el-tab-pane> -->
<el-tab-pane

View File

@@ -0,0 +1,130 @@
import { test, expect } from '@playwright/test';
/**
* Bug #681 — 精确验证 clickRow 兜底逻辑
*
* 策略:
* 1. 进入任意可加载的页面
* 2. 通过 page.addScriptTag 直接模拟调用 clickRow 的输入
* 3. 监听所有请求,断言没有 encounterId=undefined/null/NaN 被发出
*
* 由于 cliniccharge 路由需要动态菜单,这里直接用 page.evaluate 注入调用
* 模拟前端实际发出的请求参数构造逻辑。
*/
test.describe('🐛 Bug#681 精确验证:请求 URL 不携带 undefined encounterId', () => {
let undefinedRequests: string[] = [];
let jsErrors: string[] = [];
test.beforeEach(async ({ page }) => {
undefinedRequests = [];
jsErrors = [];
page.on('pageerror', (err) => jsErrors.push(err.message));
page.on('request', (req) => {
const url = req.url();
if (url.includes('encounterId=undefined') ||
url.includes('encounterId=null') ||
url.includes('encounterId=NaN') ||
/encounterId=$/.test(url)) {
undefinedRequests.push(url);
}
});
});
test('#681 模拟 clickRow 三种场景有encounterId / 仅id / 全无', async ({ page }) => {
await page.goto('about:blank');
// 注入测试脚本:模拟前端 clickRow 中请求构造的关键逻辑
// 这正是我修复后的代码(从 index.vue 提取):
const result = await page.evaluate(() => {
const calls: string[] = [];
const errors: string[] = [];
const mockProxy = { $modal: { msgError: (m: string) => errors.push(m) } };
// 模拟修复后的 clickRow 核心逻辑
function clickRowFixed(row: any): { called: string | null; errorMsg: string | null } {
const encId = row.encounterId ?? row.id;
if (encId === undefined || encId === null || encId === '') {
mockProxy.$modal.msgError('患者记录缺少就诊ID无法加载收费详情');
return { called: null, errorMsg: '患者记录缺少就诊ID无法加载收费详情' };
}
const url = '/charge-manage/charge/patient-prescription?encounterId=' + encId;
calls.push(url);
return { called: url, errorMsg: null };
}
// 场景 1有 encounterId
const r1 = clickRowFixed({ encounterId: 1001, patientName: '张三' });
// 场景 2无 encounterId 但有 id兜底
const r2 = clickRowFixed({ id: 2002, patientName: '李四' });
// 场景 3encounterId 和 id 都缺(错误提示)
const r3 = clickRowFixed({ patientName: '王五' });
// 场景 4encounterId 是 undefined
const r4 = clickRowFixed({ encounterId: undefined, patientName: '赵六' });
// 场景 5encounterId 是 null
const r5 = clickRowFixed({ encounterId: null, patientName: '孙七' });
// 场景 6encounterId 是空字符串
const r6 = clickRowFixed({ encounterId: '', patientName: '周八' });
return {
calls,
errors,
scenarios: [r1, r2, r3, r4, r5, r6],
};
});
console.log('calls:', result.calls);
console.log('errors:', result.errors);
console.log('scenarios:', JSON.stringify(result.scenarios, null, 2));
// 断言 1只有场景 1 和 2 发出请求,且 URL 中不含 undefined
expect(result.calls.length).toBe(2);
expect(result.calls[0]).toContain('encounterId=1001');
expect(result.calls[1]).toContain('encounterId=2002');
result.calls.forEach((url) => {
expect(url).not.toContain('undefined');
expect(url).not.toContain('null');
expect(url).not.toContain('NaN');
});
// 断言 2场景 3-6 都触发了 msgError且没发请求
expect(result.errors.length).toBe(4);
result.errors.forEach((msg) => {
expect(msg).toContain('患者记录缺少就诊ID');
});
// 断言 3场景 1 没报错、场景 3-6 报错了
expect(result.scenarios[0].errorMsg).toBeNull();
expect(result.scenarios[1].errorMsg).toBeNull();
expect(result.scenarios[2].errorMsg).not.toBeNull();
expect(result.scenarios[3].errorMsg).not.toBeNull();
expect(result.scenarios[4].errorMsg).not.toBeNull();
expect(result.scenarios[5].errorMsg).not.toBeNull();
});
test('#681 对比修复前:无兜底时会发出 encounterId=undefined 请求', async ({ page }) => {
await page.goto('about:blank');
// 模拟修复前的 clickRow 行为(旧代码)
const result = await page.evaluate(() => {
const calls: string[] = [];
// 旧代码:直接 row.encounterId 拼接
function clickRowOld(row: any): string {
const url = '/charge-manage/charge/patient-prescription?encounterId=' + row.encounterId;
calls.push(url);
return url;
}
// 场景encounterId 缺失(这正是 bug 的触发条件)
const url = clickRowOld({ patientName: '王五' });
return { calls, lastUrl: url };
});
console.log('OLD calls:', result.calls);
// 修复前的代码会发出 encounterId=undefined 请求
expect(result.lastUrl).toContain('encounterId=undefined');
// 这正是 bug 的表现 → 我修复后不会发生
});
});