feat: 健康体检体检年份筛选控件统一及PRD文档与截图补充

- 管理端健康体检各页体检年份筛选由原生select替换为自定义下拉控件
- 导航标签精简(体检预约/已选项目/已检员工等)
- 单位报表未检人数弹窗移除未检原因列
- 补充健康体检管理端与员工端PRD文档、截图脚本及页面截图
This commit is contained in:
liuyunqin
2026-09-14 19:20:51 +08:00
parent 39547a8bb6
commit dcacbe289b
160 changed files with 4869 additions and 398 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,155 @@
/**
* 健康体检(员工端)PRD 截图脚本
* 规则(同 health-monitor/doc/screenshot-final.mjs):
* - 标准 phone-shell 尺寸 390×844
* - 短页面(实测内容 < 844):保持 844 高度,外壳完整
* - 长页面(实测内容 > 844):phone-shell 解除高度限制,按真实内容展开
* - 结果页(booking/gastro/cta-date-selected)通过导航栏演示下拉切换成功/失败两态
*/
import { chromium } from 'playwright';
import { fileURLToPath } from 'url';
import path from 'path';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const docDir = __dirname;
const root = path.resolve(__dirname, '..');
// mode: auto(短页面最低 844 / 长页面真实高度)
const tasks = [
// ========== 模块主页 ==========
{ html: 'index.html', out: 'index' },
{ html: 'index-inactive.html', out: 'index-inactive' },
// ========== 体检预约(通用 + 常规体检流程) ==========
{ html: 'booking-type.html', out: 'booking-type' },
{ html: 'booking-hospital.html', out: 'booking-hospital' },
{ html: 'booking-hospital.html', out: 'booking-hospital-dialog', query: '?from=booking-type' },
{ html: 'booking-project.html', out: 'booking-project' },
{ html: 'booking-project.html', out: 'booking-project-required', clickText: '必检项目' },
{ html: 'booking-project-selected.html', out: 'booking-project-selected' },
{ html: 'booking-date.html', out: 'booking-date' },
{ html: 'booking-date-selected.html', out: 'booking-date-selected' },
{ html: 'booking-date-selected.html', out: 'booking-date-selected-fail', demo: 'fail' },
{ html: 'project-detail.html', out: 'project-detail', query: '?id=general' },
// ========== 胃肠镜体检流程 ==========
{ html: 'gastro-hospital.html', out: 'gastro-hospital' },
{ html: 'gastro-questionnaire.html', out: 'gastro-questionnaire' },
{ html: 'gastro-questionnaire.html', out: 'gastro-questionnaire-tangdu', query: '?hospital=tangdu' },
{ html: 'gastro-date.html', out: 'gastro-date' },
{ html: 'gastro-date-selected.html', out: 'gastro-date-selected' },
{ html: 'gastro-date-selected.html', out: 'gastro-date-selected-fail', demo: 'fail' },
{ html: 'gastro-preselect.html', out: 'gastro-preselect' },
{ html: 'gastro-preselect-done.html', out: 'gastro-preselect-done' },
// ========== 冠脉CTA体检流程 ==========
{ html: 'cta-hospital.html', out: 'cta-hospital' },
{ html: 'cta-date.html', out: 'cta-date' },
{ html: 'cta-date-selected.html', out: 'cta-date-selected' },
{ html: 'cta-date-selected.html', out: 'cta-date-selected-fail', demo: 'fail' },
// ========== 现场体检 ==========
{ html: 'my-appointments-all.html', out: 'my-appointments-all' },
{ html: 'my-appointments-all.html', out: 'my-appointments-all-gastro', query: '?type=gastro&status=pending' },
{ html: 'my-appointments-all.html', out: 'my-appointments-all-cta', query: '?type=cta&status=pending' },
{ html: 'hospital-checkin.html', out: 'hospital-checkin' },
// ========== 体检报告 ==========
{ html: 'reports.html', out: 'reports' },
{ html: 'report-query.html', out: 'report-query' },
{ html: 'report-cta.html', out: 'report-cta' },
{ html: 'report-gastro.html', out: 'report-gastro' },
{ html: 'indicator-compare.html', out: 'indicator-compare' },
{ html: 'indicator-compare-detail.html', out: 'indicator-compare-detail', query: '?item=bmi' },
// ========== 消息 / 咨询 / 操作指引 ==========
{ html: 'messages.html', out: 'messages' },
{ html: 'message-detail.html', out: 'message-detail', query: '?id=report-2026' },
{ html: 'message-detail.html', out: 'message-detail-ai', query: '?id=warn-indicator' },
{ html: 'consult.html', out: 'consult' },
{ html: 'process-guide.html', out: 'process-guide' },
{ html: 'process-guide-detail.html', out: 'process-guide-detail', query: '?type=image&id=booking' },
{ html: 'process-guide-detail.html', out: 'process-guide-detail-video', query: '?type=video&id=gastro' },
];
(async () => {
const browser = await chromium.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });
const context = await browser.newContext({ viewport: { width: 390, height: 4000 } });
for (const t of tasks) {
const page = await context.newPage();
const filePath = path.join(root, t.html);
const url = `file:///${filePath.replace(/\\/g, '/')}${t.query || ''}`;
await page.goto(url, { waitUntil: 'networkidle' });
await page.waitForTimeout(300);
// 演示下拉切换(预约结果页成功/失败两态)
if (t.demo) {
await page.evaluate((v) => {
const sel = document.querySelector('#demoSelect, .demo-select');
if (sel) {
sel.value = v;
sel.dispatchEvent(new Event('change', { bubbles: true }));
if (typeof setResult === 'function') setResult(v);
}
}, t.demo);
await page.waitForTimeout(250);
}
// 按文本点击(如「必检项目」Tab)
if (t.clickText) {
await page.evaluate((text) => {
const els = Array.from(document.querySelectorAll('div,span,button,li'));
const target = els.filter(el => el.textContent.trim() === text && el.offsetParent).pop();
if (target) target.click();
}, t.clickText);
await page.waitForTimeout(250);
}
// 解除 phone-shell 高度限制:短页面保底 844,长页面按内容展开
await page.evaluate(() => {
const shell = document.querySelector('.phone-shell');
if (shell) {
shell.style.height = 'auto';
shell.style.minHeight = '844px';
shell.style.maxHeight = 'none';
shell.style.borderRadius = '0';
shell.style.boxShadow = 'none';
shell.style.overflow = 'visible';
shell.style.display = 'block';
}
document.querySelectorAll('.scroll-content, .page-content, .main-content, .list-wrap, .content').forEach(c => {
c.style.overflow = 'visible';
c.style.maxHeight = 'none';
c.style.height = 'auto';
c.style.flex = 'none';
});
document.body.style.padding = '0';
document.body.style.minHeight = 'auto';
document.body.style.background = '#fff';
});
await page.waitForTimeout(300);
const measured = await page.evaluate(() => {
const shell = document.querySelector('.phone-shell');
if (!shell) return document.body.scrollHeight;
return Math.ceil(shell.getBoundingClientRect().height);
});
const h = Math.max(measured, 844);
await page.setViewportSize({ width: 390, height: h });
await page.waitForTimeout(150);
const shell = await page.$('.phone-shell');
const target = shell || page;
await target.screenshot({
path: path.join(docDir, 'screenshots', `${t.out}.jpg`),
type: 'jpeg',
quality: 85,
});
console.log(`${t.out}.jpg`);
await page.close();
}
await browser.close();
console.log(`\n完成!共截取 ${tasks.length}`);
})();
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

+1 -1
View File
@@ -675,7 +675,7 @@ stateDiagram-v2
- 周历(含月历弹窗):日期用彩色圆环标记来源(自记/蓝牙称/体重秤/体脂仪),圆环下方显示来源文字标签(自记/蓝牙称/体重秤/体脂仪)
- 当日最新记录区:体重(大字)+ 较上次变化 + BMI(含偏瘦/正常/超重/肥胖标签)+ 体脂率/腰围 + 时间 + 来源标签
- 数据来源卡片:四张来源小卡(体重秤/蓝牙称/体脂仪/自记,各显示该来源最近一次体重值,无记录显示"尚未记录"),点击体重秤/蓝牙称/体脂仪卡片查看当日该来源体重记录,点击自记卡片打开记录体重弹窗
- 变化趋势卡片:时间范围(周/月/季/年/活动期间)+ 三 Tab(体重变化/体脂变化/腰围变化),各含统计行(平均/最大/最小/变化)+ 折线图(初始线/目标线/推荐范围/实际趋势 + 数据点悬浮提示)
- 变化趋势卡片:时间范围(周/月/季/年/活动期间)+ 三 T························································································································································································································································································································ ab(体重变化/体脂变化/腰围变化),各含统计行(平均/最大/最小/变化)+ 折线图(初始线/目标线/推荐范围/实际趋势 + 数据点悬浮提示)
- 记录明细列表:日期 + 时间 + 体重 + 体脂/腰围 + 来源标签;非自记来源带箭头可点击
- 记录体重弹窗:记录体重(必填)+ 记录体脂率(开关)+ 记录腰围(开关),滑动尺子调整数值 + 保存