feat: 健康体检员工端取消预约二次确认、胃肠镜预选可重填及报告筛选调整
- 预约日期页取消预约改为二次确认 - 胃肠镜医院预选支持重新填写调整(至少2家/最多3家) - 现场体检状态口径改为已预约/无预约 - 报告列表新增年份/类型筛选 - 同步更新 PRD 与演示截图
@@ -136,23 +136,6 @@
|
||||
background: #f7f9fb; border-radius: 12px; padding: 10px 14px; margin-bottom: 16px;
|
||||
font-size: 13px; font-weight: 600; color: var(--text-secondary); text-align: center;
|
||||
}
|
||||
.cancel-modal__label { font-size: 13px; font-weight: 600; margin-bottom: 10px; }
|
||||
.cancel-modal__label em { color: var(--danger); font-style: normal; }
|
||||
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
|
||||
.chip {
|
||||
padding: 7px 14px; border-radius: 16px; border: 1px solid #e8e8e8; background: #fafafa;
|
||||
font-size: 13px; color: var(--text-secondary); cursor: pointer; transition: all 0.2s; user-select: none;
|
||||
}
|
||||
.chip.selected { background: var(--primary-light); border-color: var(--primary); color: var(--primary-dark); font-weight: 600; }
|
||||
.other-input {
|
||||
display: none; width: 100%; border: 1px solid #e8e8e8; border-radius: 12px;
|
||||
padding: 10px 12px; font-size: 13px; font-family: inherit; line-height: 1.6;
|
||||
resize: none; outline: none; margin-bottom: 6px; color: var(--text-primary);
|
||||
}
|
||||
.other-input.show { display: block; }
|
||||
.other-input:focus { border-color: var(--primary); }
|
||||
.cancel-modal__err { display: none; font-size: 12px; color: var(--danger); margin-bottom: 6px; }
|
||||
.cancel-modal__err.show { display: block; }
|
||||
.cancel-modal__actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 10px; }
|
||||
.cancel-modal__btn { height: 44px; border-radius: 22px; font-size: 15px; font-weight: 600; border: none; cursor: pointer; }
|
||||
.cancel-modal__btn--ghost { background: #f5f5f5; color: var(--text-secondary); }
|
||||
@@ -250,7 +233,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<div class="result-banner__title" id="resultTitle">预约成功</div>
|
||||
<div class="result-banner__sub" id="resultSub">已为您锁定体检名额,请按预约日期准时到检</div>
|
||||
<div class="result-banner__sub" id="resultSub">请按预约日期准时到检</div>
|
||||
<div class="result-banner__reason">
|
||||
<span>失败原因:所选日期号源已约满</span>
|
||||
<span class="reason-help" onclick="openReasonModal()">?</span>
|
||||
@@ -296,10 +279,10 @@
|
||||
|
||||
<!-- [交互] 预约成功态底部按钮 -->
|
||||
<div class="bottom-actions" id="actionsSuccess">
|
||||
<!-- [交互] 取消预约改为二次确认弹窗,需选择或填写取消原因 -->
|
||||
<!-- [交互] 取消预约改为二次确认弹窗 -->
|
||||
<button class="bottom-actions__btn bottom-actions__btn--ghost" onclick="openCancelModal()">取消预约</button>
|
||||
<!-- [交互] 查看预约详情,跳转至 my-appointments-all.html(常规·待体检) -->
|
||||
<button class="bottom-actions__btn bottom-actions__btn--primary" onclick="window.location.href='my-appointments-all.html?type=routine&status=pending'">查看预约详情</button>
|
||||
<!-- [交互] 现场体检,跳转至 my-appointments-all.html(常规·待体检,含签到码) -->
|
||||
<button class="bottom-actions__btn bottom-actions__btn--primary" onclick="window.location.href='my-appointments-all.html?type=routine&status=pending'">现场体检</button>
|
||||
</div>
|
||||
<!-- [交互] 预约失败态底部按钮:重新预约,跳回预约日期页 -->
|
||||
<div class="bottom-actions" id="actionsFail" style="display: none;">
|
||||
@@ -319,30 +302,16 @@
|
||||
<div class="reason-modal__label">发生时间</div>
|
||||
<div class="reason-modal__text">2026-03-16 12:00:35</div>
|
||||
</div>
|
||||
<div class="reason-modal__item">
|
||||
<div class="reason-modal__label">处理建议</div>
|
||||
<div class="reason-modal__text">请点击「重新预约」选择其他可约日期;若长期无可用号源,可联系健康管理专员协调加号。</div>
|
||||
</div>
|
||||
<button class="reason-modal__btn" onclick="closeReasonModal()">知道了</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- [交互] 取消预约二次确认:单选原因chips,选「其他」时填写具体原因 -->
|
||||
<!-- [交互] 取消预约二次确认弹窗 -->
|
||||
<div class="modal-overlay hidden" id="cancelModal">
|
||||
<div class="cancel-modal">
|
||||
<div class="cancel-modal__title">确认取消预约</div>
|
||||
<div class="cancel-modal__desc">取消后名额将释放,如仍需体检请重新预约</div>
|
||||
<div class="cancel-modal__order">宁夏宝石花医院 · 2026年3月23日</div>
|
||||
<div class="cancel-modal__label">请选择取消原因 <em>*</em></div>
|
||||
<div class="chips" id="cancelChips">
|
||||
<span class="chip" data-reason="时间冲突" onclick="selectChip(this)">时间冲突</span>
|
||||
<span class="chip" data-reason="医院选择不当" onclick="selectChip(this)">医院选择不当</span>
|
||||
<span class="chip" data-reason="日期选择不当" onclick="selectChip(this)">日期选择不当</span>
|
||||
<span class="chip" data-reason="个人健康原因" onclick="selectChip(this)">个人健康原因</span>
|
||||
<span class="chip" data-reason="other" onclick="selectChip(this)">其他</span>
|
||||
</div>
|
||||
<textarea class="other-input" id="otherInput" rows="2" maxlength="100" placeholder="请填写取消原因(必填)"></textarea>
|
||||
<div class="cancel-modal__err" id="cancelErr">请选择或填写取消原因</div>
|
||||
<div class="cancel-modal__actions">
|
||||
<button class="cancel-modal__btn cancel-modal__btn--ghost" onclick="closeCancelModal()">再想想</button>
|
||||
<button class="cancel-modal__btn cancel-modal__btn--danger" onclick="confirmCancel()">确认取消</button>
|
||||
@@ -383,36 +352,14 @@
|
||||
document.getElementById('reasonModal').classList.add('hidden');
|
||||
}
|
||||
|
||||
// [交互] 取消预约二次确认:原因单选 + 其他原因填写 + 校验 + 确认后跳转重新预约
|
||||
let cancelReason = null;
|
||||
function selectChip(el) {
|
||||
document.querySelectorAll('#cancelChips .chip').forEach(c => c.classList.remove('selected'));
|
||||
el.classList.add('selected');
|
||||
cancelReason = el.dataset.reason;
|
||||
document.getElementById('otherInput').classList.toggle('show', cancelReason === 'other');
|
||||
hideCancelErr();
|
||||
}
|
||||
function hideCancelErr() {
|
||||
document.getElementById('cancelErr').classList.remove('show');
|
||||
}
|
||||
// [交互] 取消预约二次确认:确认后提示已取消,稍后跳回预约日期页
|
||||
function openCancelModal() {
|
||||
cancelReason = null;
|
||||
document.querySelectorAll('#cancelChips .chip').forEach(c => c.classList.remove('selected'));
|
||||
const input = document.getElementById('otherInput');
|
||||
input.value = '';
|
||||
input.classList.remove('show');
|
||||
hideCancelErr();
|
||||
document.getElementById('cancelModal').classList.remove('hidden');
|
||||
}
|
||||
function closeCancelModal() {
|
||||
document.getElementById('cancelModal').classList.add('hidden');
|
||||
}
|
||||
function confirmCancel() {
|
||||
const input = document.getElementById('otherInput');
|
||||
if (!cancelReason || (cancelReason === 'other' && !input.value.trim())) {
|
||||
document.getElementById('cancelErr').classList.add('show');
|
||||
return;
|
||||
}
|
||||
closeCancelModal();
|
||||
const toast = document.getElementById('stepToast');
|
||||
toast.textContent = '预约已取消';
|
||||
|
||||
@@ -384,7 +384,7 @@
|
||||
</div>
|
||||
<div class="modal-field">
|
||||
<span class="modal-field__label">身份证号</span>
|
||||
<span class="modal-field__value">6101021994********</span>
|
||||
<span class="modal-field__value">610102199403154729</span>
|
||||
</div>
|
||||
<div class="modal-field">
|
||||
<span class="modal-field__label">性别</span>
|
||||
|
||||
@@ -130,6 +130,7 @@
|
||||
.project-list-panel::-webkit-scrollbar { display: none; }
|
||||
.project-grid { display: flex; flex-direction: column; gap: 10px; }
|
||||
.project-card {
|
||||
position: relative;
|
||||
background: #fff; border-radius: 14px; padding: 14px 16px; border: 2px solid #eef5f5;
|
||||
cursor: pointer; transition: all 0.2s; display: flex; align-items: center; gap: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.03);
|
||||
@@ -140,6 +141,9 @@
|
||||
cursor: default; background: #fff; border-color: #eef5f5;
|
||||
}
|
||||
.project-card.project-card--readonly:hover { border-color: #eef5f5; }
|
||||
/* 额度已满后剩余项目置灰,不可再选 */
|
||||
.project-card--disabled { opacity: 0.45; cursor: not-allowed; }
|
||||
.project-card--disabled:hover { border-color: #eef5f5; background: #fff; }
|
||||
.project-card__check {
|
||||
width: 22px; height: 22px; border-radius: 6px; border: 2px solid #d9d9d9;
|
||||
display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: all 0.2s;
|
||||
@@ -151,16 +155,22 @@
|
||||
.project-card.selected .project-card__check { background: var(--primary); border-color: var(--primary); }
|
||||
.project-card.selected .project-card__check::after { opacity: 1; }
|
||||
.project-card__info { flex: 1; min-width: 0; }
|
||||
.project-card__name { font-size: 14px; font-weight: 600; margin-bottom: 2px; }
|
||||
.project-card__desc { font-size: 12px; color: var(--text-muted); }
|
||||
.project-card__name { font-size: 15px; font-weight: 600; margin-bottom: 6px; }
|
||||
/* 项目示意图标块:沿用医院卡渐变底 + emoji 占位风格 */
|
||||
.project-card__img {
|
||||
width: 52px; height: 52px; border-radius: 14px;
|
||||
background: linear-gradient(135deg, #e6fffb 0%, #b5f5ec 100%);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 24px; flex-shrink: 0;
|
||||
}
|
||||
.project-card.selected .project-card__img {
|
||||
background: linear-gradient(135deg, #b5f5ec 0%, #87e8de 100%);
|
||||
}
|
||||
.project-card__side {
|
||||
flex-shrink: 0; display: flex; align-items: center; gap: 10px;
|
||||
margin-left: auto; padding-left: 8px;
|
||||
}
|
||||
.project-card__tags {
|
||||
display: flex; flex-direction: column; align-items: flex-end; gap: 6px;
|
||||
}
|
||||
.project-card__price { font-size: 13px; color: var(--primary-dark); font-weight: 700; }
|
||||
.project-card__price { font-size: 14px; color: var(--primary-dark); font-weight: 700; }
|
||||
.project-card__badge {
|
||||
display: inline-flex; align-items: center; justify-content: center; height: 22px;
|
||||
padding: 0 10px; border-radius: 11px; background: #f5f5f5;
|
||||
@@ -170,7 +180,7 @@
|
||||
background: #fff1f0; color: #ff4d4f;
|
||||
}
|
||||
.project-card__meta {
|
||||
display: flex; align-items: center; gap: 6px;
|
||||
display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
|
||||
}
|
||||
/* AI 推荐标签分三档,字号阶梯放大 + 深色实底强化等级对比:
|
||||
强烈推荐 12px 红橙实底 > 建议加做 11px 紫蓝实底 > 可选参考 10px 浅蓝描边 */
|
||||
@@ -191,6 +201,10 @@
|
||||
height: 20px; padding: 0 8px; border-radius: 10px; font-size: 10px; font-weight: 600;
|
||||
background: #f0f5ff; color: #597ef7; border: 1px solid #d6e4ff;
|
||||
}
|
||||
/* 列表卡片上的 AI 推荐标签固定在卡片右上角(弹窗内的同名标签不受影响) */
|
||||
.project-card__badge--ai-corner {
|
||||
position: absolute; top: 6px; right: 16px;
|
||||
}
|
||||
.project-card__arrow {
|
||||
flex-shrink: 0; color: #d0d0d0; font-size: 16px; cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
@@ -247,6 +261,26 @@
|
||||
.confirm-modal__btn--primary {
|
||||
background: linear-gradient(135deg, #13c2c2 0%, #36cfc9 100%); color: #fff;
|
||||
}
|
||||
/* 互斥项目弹窗:二选一选项行 */
|
||||
.mutex-options { margin-bottom: 18px; }
|
||||
.mutex-option {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
padding: 12px 14px; border: 2px solid #eef5f5; border-radius: 14px;
|
||||
background: #fff; cursor: pointer; transition: all 0.2s;
|
||||
}
|
||||
.mutex-option + .mutex-option { margin-top: 10px; }
|
||||
.mutex-option.active { border-color: var(--primary); background: var(--primary-light); }
|
||||
.mutex-option__radio {
|
||||
width: 18px; height: 18px; border-radius: 50%; border: 2px solid #d9d9d9;
|
||||
flex-shrink: 0; position: relative; transition: all 0.2s;
|
||||
}
|
||||
.mutex-option.active .mutex-option__radio { border-color: var(--primary); }
|
||||
.mutex-option.active .mutex-option__radio::after {
|
||||
content: ''; position: absolute; left: 3px; top: 3px; width: 8px; height: 8px;
|
||||
border-radius: 50%; background: var(--primary);
|
||||
}
|
||||
.mutex-option__name { flex: 1; min-width: 0; font-size: 14px; font-weight: 600; }
|
||||
.mutex-option__price { font-size: 13px; font-weight: 700; color: var(--primary-dark); }
|
||||
/* AI 推荐理由弹窗 */
|
||||
.ai-modal { padding: 24px 20px 18px; }
|
||||
.ai-modal__project {
|
||||
@@ -383,6 +417,43 @@
|
||||
<button class="confirm-modal__btn confirm-modal__btn--primary ai-modal__close" onclick="closeAiReason()">知道了</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- [交互] 关联项目提醒:同步选中 / 取消选择 -->
|
||||
<div class="modal-overlay hidden" id="linkModal">
|
||||
<div class="confirm-modal">
|
||||
<div class="confirm-modal__title">🔗 关联项目提醒</div>
|
||||
<div class="confirm-modal__desc" id="linkModalDesc"></div>
|
||||
<div class="confirm-modal__info" id="linkModalInfo"></div>
|
||||
<div class="confirm-modal__actions">
|
||||
<button class="confirm-modal__btn confirm-modal__btn--ghost" onclick="closeLinkModal()">取消选择</button>
|
||||
<button class="confirm-modal__btn confirm-modal__btn--primary" onclick="confirmLinkSelect()">同步选中</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- [交互] 互斥项目提醒:两项展示出来二选一,确定后替换已选项 -->
|
||||
<div class="modal-overlay hidden" id="mutexModal">
|
||||
<div class="confirm-modal">
|
||||
<div class="confirm-modal__title">⚠️ 互斥项目提醒</div>
|
||||
<div class="confirm-modal__desc" id="mutexModalDesc"></div>
|
||||
<div class="mutex-options" id="mutexOptions"></div>
|
||||
<div class="confirm-modal__actions">
|
||||
<button class="confirm-modal__btn confirm-modal__btn--ghost" onclick="closeMutexModal()">取消</button>
|
||||
<button class="confirm-modal__btn confirm-modal__btn--primary" onclick="confirmMutexSelect()">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- [交互] 额度不足提醒 -->
|
||||
<div class="modal-overlay hidden" id="exceedModal">
|
||||
<div class="confirm-modal">
|
||||
<div class="confirm-modal__title">💰 额度不足提醒</div>
|
||||
<div class="confirm-modal__desc" id="exceedModalDesc"></div>
|
||||
<div class="confirm-modal__actions">
|
||||
<button class="confirm-modal__btn confirm-modal__btn--primary" onclick="closeExceedModal()">知道了</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// 年度体检总额度(可用额度 = 总额度 − 已选项目费用,原型模拟数据)
|
||||
@@ -394,20 +465,20 @@
|
||||
1: { label: '可选参考', cls: 'low', icon: '✨', desc: '按年龄段与常见风险的一般性补充筛查,可结合剩余额度自行选择。' }
|
||||
};
|
||||
const projects = [
|
||||
{ id: 'general', name: '一般检查', desc: '身高、体重、血压、视力', price: 120, type: 'required', level: 'normal' },
|
||||
{ id: 'blood', name: '血常规', desc: '血红蛋白、白细胞、血小板等', price: 80, type: 'required', level: 'normal' },
|
||||
{ id: 'urine', name: '尿常规', desc: '尿蛋白、尿糖、尿潜血等', price: 45, type: 'required', level: 'normal' },
|
||||
{ id: 'liver', name: '肝功能', desc: 'ALT、AST、总胆红素等', price: 160, type: 'required', level: 'key' },
|
||||
{ id: 'kidney', name: '肾功能', desc: '肌酐、尿素氮、尿酸等', price: 110, type: 'required', level: 'key' },
|
||||
{ id: 'lipid', name: '血脂四项', desc: '总胆固醇、甘油三酯、HDL、LDL', price: 90, type: 'required', level: 'normal' },
|
||||
{ id: 'glucose', name: '空腹血糖', desc: '空腹静脉血糖检测', price: 40, type: 'required', level: 'normal' },
|
||||
{ id: 'ecg', name: '心电图', desc: '十二导联心电图检查', price: 75, type: 'required', level: 'key' },
|
||||
{ id: 'xray', name: '胸部X光', desc: '胸部正位X线摄影', price: 140, type: 'optional', level: 'normal' },
|
||||
{ id: 'ultrasound', name: '腹部B超', desc: '肝胆脾胰肾超声检查', price: 180, type: 'optional', level: 'key', aiLevel: 3, aiReason: '健康画像显示 BMI 26.8(超重),且近年血脂持续偏高,属于脂肪肝与胆囊病变的高风险人群,建议本年度务必完成腹部超声重点筛查。预计费用 ¥180,在本年度体检额度内。' },
|
||||
{ id: 'thyroid', name: '甲状腺彩超', desc: '甲状腺结构与结节筛查', price: 160, type: 'optional', level: 'key', aiLevel: 2, aiReason: '既往史显示 2024 年体检发现甲状腺结节(TI-RADS 2 类),建议每年做一次超声随访复查,观察结节变化。预计费用 ¥160,在本年度体检额度内。' },
|
||||
{ id: 'tumor', name: '肿瘤标志物', desc: '基础肿瘤风险筛查', price: 220, type: 'optional', level: 'key', aiLevel: 2, aiReason: '家族史提示直系亲属有肿瘤病史,结合您所处年龄段(45 岁以上),建议今年纳入基础肿瘤标志物筛查,做到早发现早干预。预计费用 ¥220,在本年度体检额度内。' },
|
||||
{ id: 'echo', name: '心脏彩超', desc: '心脏结构与瓣膜功能超声', price: 360, type: 'optional', level: 'key', aiLevel: 1, aiReason: '近两次体检血压处于正常高值,可完成一次心脏彩超,建立心脏结构与瓣膜功能的基线资料,便于日后对比随访。预计费用 ¥360,请注意控制项目总额。' },
|
||||
{ id: 'gastro', name: '胃幽门螺杆菌检测', desc: 'C13 呼气试验,筛查胃部风险', price: 480, type: 'optional', level: 'normal', aiLevel: 1, aiReason: '幽门螺杆菌是胃癌明确的危险因素,国内感染率较高。如从未检测过,建议先做一次 C13 呼气试验筛查,阳性可规范四联根除治疗。预计费用 ¥480,可结合剩余额度自行选择。' }
|
||||
{ id: 'general', name: '一般检查', icon: '📏', price: 120, type: 'required', level: 'normal' },
|
||||
{ id: 'blood', name: '血常规', icon: '🩸', price: 80, type: 'required', level: 'normal' },
|
||||
{ id: 'urine', name: '尿常规', icon: '🧪', price: 45, type: 'required', level: 'normal' },
|
||||
{ id: 'liver', name: '肝功能', icon: '⚗️', price: 160, type: 'required', level: 'key' },
|
||||
{ id: 'kidney', name: '肾功能', icon: '🧫', price: 110, type: 'required', level: 'key' },
|
||||
{ id: 'lipid', name: '血脂四项', icon: '🧬', price: 90, type: 'required', level: 'normal' },
|
||||
{ id: 'glucose', name: '空腹血糖', icon: '🍬', price: 40, type: 'required', level: 'normal' },
|
||||
{ id: 'ecg', name: '心电图', icon: '📈', price: 75, type: 'required', level: 'key' },
|
||||
{ id: 'xray', name: '胸部X光', icon: '🦴', price: 140, type: 'optional', level: 'normal' },
|
||||
{ id: 'ultrasound', name: '腹部B超', icon: '🔬', price: 180, type: 'optional', level: 'key', aiLevel: 3, linkId: 'thyroid', aiReason: '健康画像显示 BMI 26.8(超重),且近年血脂持续偏高,属于脂肪肝与胆囊病变的高风险人群,建议本年度务必完成腹部超声重点筛查。预计费用 ¥180,在本年度体检额度内。' },
|
||||
{ id: 'thyroid', name: '甲状腺彩超', icon: '🦋', price: 160, type: 'optional', level: 'key', aiLevel: 2, linkId: 'ultrasound', aiReason: '既往史显示 2024 年体检发现甲状腺结节(TI-RADS 2 类),建议每年做一次超声随访复查,观察结节变化。预计费用 ¥160,在本年度体检额度内。' },
|
||||
{ id: 'tumor', name: '肿瘤标志物', icon: '🎗️', price: 220, type: 'optional', level: 'key', aiLevel: 2, mutexId: 'echo', aiReason: '家族史提示直系亲属有肿瘤病史,结合您所处年龄段(45 岁以上),建议今年纳入基础肿瘤标志物筛查,做到早发现早干预。预计费用 ¥220,在本年度体检额度内。' },
|
||||
{ id: 'echo', name: '心脏彩超', icon: '🫀', price: 360, type: 'optional', level: 'key', aiLevel: 1, mutexId: 'tumor', aiReason: '近两次体检血压处于正常高值,可完成一次心脏彩超,建立心脏结构与瓣膜功能的基线资料,便于日后对比随访。预计费用 ¥360,请注意控制项目总额。' },
|
||||
{ id: 'gastro', name: '胃幽门螺杆菌检测', icon: '🦠', price: 480, type: 'optional', level: 'normal', aiLevel: 1, aiReason: '幽门螺杆菌是胃癌明确的危险因素,国内感染率较高。如从未检测过,建议先做一次 C13 呼气试验筛查,阳性可规范四联根除治疗。预计费用 ¥480,可结合剩余额度自行选择。' }
|
||||
];
|
||||
|
||||
let activeTab = 'optional';
|
||||
@@ -478,25 +549,25 @@
|
||||
const card = document.createElement('div');
|
||||
const isReadonly = project.type === 'required';
|
||||
const isSelected = selectedOptionalIds.has(project.id);
|
||||
// 额度已满时,未选中的可选项目置灰不可再选
|
||||
const isDisabled = !isReadonly && !isSelected && getAvailableFee() <= 0;
|
||||
const projectLevelText = project.level === 'key' ? '重点项目' : '一般项目';
|
||||
const aiLevel = AI_LEVELS[project.aiLevel];
|
||||
card.className = `project-card${isReadonly ? ' project-card--readonly' : ''}${isSelected ? ' selected' : ''}`;
|
||||
card.className = `project-card${isReadonly ? ' project-card--readonly' : ''}${isSelected ? ' selected' : ''}${isDisabled ? ' project-card--disabled' : ''}`;
|
||||
card.innerHTML = `
|
||||
<div class="project-card__check${isReadonly ? ' project-card__check--hidden' : ''}"></div>
|
||||
<div class="project-card__img">${project.icon}</div>
|
||||
<div class="project-card__info">
|
||||
<div class="project-card__name">${project.name}</div>
|
||||
<div class="project-card__desc">${project.desc}</div>
|
||||
<div class="project-card__meta">
|
||||
<span class="project-card__badge${project.level === 'key' ? ' project-card__badge--key' : ''}">${projectLevelText}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-card__side">
|
||||
<div class="project-card__tags">
|
||||
<span class="project-card__price">${formatPrice(project.price)}</span>
|
||||
<div class="project-card__meta">
|
||||
<span class="project-card__badge${project.level === 'key' ? ' project-card__badge--key' : ''}">${projectLevelText}</span>
|
||||
${aiLevel ? `<span class="project-card__badge project-card__badge--ai project-card__badge--ai-${aiLevel.cls}">${aiLevel.icon} ${aiLevel.label}</span>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
<span class="project-card__price">${formatPrice(project.price)}</span>
|
||||
<span class="project-card__arrow" data-detail="${project.id}">›</span>
|
||||
</div>
|
||||
${aiLevel ? `<span class="project-card__badge project-card__badge--ai project-card__badge--ai-${aiLevel.cls} project-card__badge--ai-corner">${aiLevel.icon} ${aiLevel.label}</span>` : ''}
|
||||
`;
|
||||
|
||||
// [交互] 箭头点击跳转项目详情
|
||||
@@ -515,21 +586,133 @@
|
||||
}
|
||||
|
||||
if (!isReadonly) {
|
||||
card.addEventListener('click', () => {
|
||||
if (selectedOptionalIds.has(project.id)) {
|
||||
selectedOptionalIds.delete(project.id);
|
||||
} else {
|
||||
selectedOptionalIds.add(project.id);
|
||||
}
|
||||
renderProjects();
|
||||
updateSummary();
|
||||
});
|
||||
card.addEventListener('click', () => trySelectProject(project));
|
||||
}
|
||||
|
||||
grid.appendChild(card);
|
||||
});
|
||||
}
|
||||
|
||||
// ===== 选择流程:关联项目同步选中 / 互斥项目二选一 / 额度校验 =====
|
||||
// 关联:ultrasound ↔ thyroid;互斥:tumor ↔ echo
|
||||
let pendingLinkProject = null;
|
||||
let pendingMutex = null;
|
||||
|
||||
function trySelectProject(project) {
|
||||
// 已选中 → 取消勾选,关联项目同步取消
|
||||
if (selectedOptionalIds.has(project.id)) {
|
||||
selectedOptionalIds.delete(project.id);
|
||||
const linked = project.linkId && projects.find(p => p.id === project.linkId);
|
||||
if (linked && selectedOptionalIds.has(linked.id)) selectedOptionalIds.delete(linked.id);
|
||||
renderProjects();
|
||||
updateSummary();
|
||||
return;
|
||||
}
|
||||
// 额度已满:剩余项目置灰,点击不响应
|
||||
if (getAvailableFee() <= 0) return;
|
||||
// 关联项目:对方未选中 → 弹窗提醒同步选中
|
||||
const linked = project.linkId && projects.find(p => p.id === project.linkId);
|
||||
if (linked && !selectedOptionalIds.has(linked.id)) {
|
||||
openLinkModal(project, linked);
|
||||
return;
|
||||
}
|
||||
// 互斥项目:对方已选中 → 弹窗二选一
|
||||
const mutex = project.mutexId && projects.find(p => p.id === project.mutexId);
|
||||
if (mutex && selectedOptionalIds.has(mutex.id)) {
|
||||
openMutexModal(project, mutex);
|
||||
return;
|
||||
}
|
||||
// 单选超额 → 弹窗提示,不生效
|
||||
if (getAvailableFee() < project.price) {
|
||||
openExceedModal(`「${project.name}」预计费用 ${formatPrice(project.price)},选择后项目总额将超出年度体检额度,请调整已选项目后再试`);
|
||||
return;
|
||||
}
|
||||
selectedOptionalIds.add(project.id);
|
||||
renderProjects();
|
||||
updateSummary();
|
||||
}
|
||||
|
||||
// 关联项目弹窗
|
||||
function openLinkModal(project, linked) {
|
||||
pendingLinkProject = project;
|
||||
document.getElementById('linkModalDesc').innerHTML =
|
||||
`「${project.name}」与「${linked.name}」为关联项目,<br>选中其中一项将同步选中另一项`;
|
||||
document.getElementById('linkModalInfo').innerHTML = [project, linked].map(p =>
|
||||
`<div class="confirm-modal__row"><span>${p.name}</span><span class="confirm-modal__value">${formatPrice(p.price)}</span></div>`
|
||||
).join('');
|
||||
document.getElementById('linkModal').classList.remove('hidden');
|
||||
}
|
||||
function closeLinkModal() {
|
||||
document.getElementById('linkModal').classList.add('hidden');
|
||||
}
|
||||
function confirmLinkSelect() {
|
||||
const project = pendingLinkProject;
|
||||
const linked = projects.find(p => p.id === project.linkId);
|
||||
const cost = project.price + linked.price;
|
||||
// 两项合计超出剩余额度 → 转额度不足提醒
|
||||
if (getAvailableFee() < cost) {
|
||||
closeLinkModal();
|
||||
openExceedModal(`「${project.name}」与「${linked.name}」需同步选中,合计 ${formatPrice(cost)},选择后项目总额将超出年度体检额度,请调整已选项目后再试`);
|
||||
return;
|
||||
}
|
||||
selectedOptionalIds.add(project.id);
|
||||
selectedOptionalIds.add(linked.id);
|
||||
closeLinkModal();
|
||||
renderProjects();
|
||||
updateSummary();
|
||||
}
|
||||
|
||||
// 互斥项目弹窗:展示两项做单选,确定后替换已选项
|
||||
function openMutexModal(clicked, other) {
|
||||
pendingMutex = { clicked, other, chosenId: clicked.id };
|
||||
document.getElementById('mutexModalDesc').innerHTML =
|
||||
`「${clicked.name}」与「${other.name}」互斥,只能同时体检其中一个项目,请选择本次要做的项目`;
|
||||
renderMutexOptions();
|
||||
document.getElementById('mutexModal').classList.remove('hidden');
|
||||
}
|
||||
function renderMutexOptions() {
|
||||
document.getElementById('mutexOptions').innerHTML = [pendingMutex.clicked, pendingMutex.other].map(p => `
|
||||
<div class="mutex-option${pendingMutex.chosenId === p.id ? ' active' : ''}" onclick="chooseMutexOption('${p.id}')">
|
||||
<span class="mutex-option__radio"></span>
|
||||
<span class="mutex-option__name">${p.name}</span>
|
||||
<span class="mutex-option__price">${formatPrice(p.price)}</span>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
function chooseMutexOption(id) {
|
||||
pendingMutex.chosenId = id;
|
||||
renderMutexOptions();
|
||||
}
|
||||
function closeMutexModal() {
|
||||
document.getElementById('mutexModal').classList.add('hidden');
|
||||
}
|
||||
function confirmMutexSelect() {
|
||||
const { clicked, other, chosenId } = pendingMutex;
|
||||
const chosen = chosenId === clicked.id ? clicked : other;
|
||||
const dropped = chosenId === clicked.id ? other : clicked;
|
||||
// 替换后的可用额度 = 当前可用 + 被替换项目释放额度 - 新选项目费用
|
||||
if (getAvailableFee() + dropped.price - chosen.price < 0) {
|
||||
closeMutexModal();
|
||||
openExceedModal(`选择「${chosen.name}」后项目总额将超出年度体检额度,请调整已选项目后再试`);
|
||||
return;
|
||||
}
|
||||
selectedOptionalIds.delete(clicked.id);
|
||||
selectedOptionalIds.delete(other.id);
|
||||
selectedOptionalIds.add(chosen.id);
|
||||
closeMutexModal();
|
||||
renderProjects();
|
||||
updateSummary();
|
||||
}
|
||||
|
||||
// 额度不足提醒弹窗
|
||||
function openExceedModal(desc) {
|
||||
document.getElementById('exceedModalDesc').innerHTML = desc;
|
||||
document.getElementById('exceedModal').classList.remove('hidden');
|
||||
}
|
||||
function closeExceedModal() {
|
||||
document.getElementById('exceedModal').classList.add('hidden');
|
||||
}
|
||||
|
||||
tabButtons.forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
activeTab = button.dataset.tab;
|
||||
|
||||
@@ -166,6 +166,18 @@
|
||||
.consult-table--gastro thead th:nth-child(2) { width: 70%; }
|
||||
.is-abnormal { color: var(--danger); font-weight: 600; }
|
||||
.consult-table tbody td:nth-child(2) { color: var(--danger); font-weight: 600; }
|
||||
|
||||
/* 顶部体检信息:年份 + 类型 */
|
||||
.info-bar {
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 13px 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
.info-bar__item { display: flex; align-items: center; gap: 8px; font-size: 13px; }
|
||||
.info-bar__label { color: var(--text-muted); flex-shrink: 0; }
|
||||
.info-bar__value { color: var(--text-primary); font-weight: 600; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -185,6 +197,10 @@
|
||||
|
||||
<div class="scroll-content">
|
||||
<div class="page-body">
|
||||
<!-- 顶部体检信息:当前咨询报告的年份 -->
|
||||
<div class="info-bar">
|
||||
<div class="info-bar__item"><span class="info-bar__label">体检年份</span><span class="info-bar__value">2025年</span></div>
|
||||
</div>
|
||||
<!-- 化学检查 -->
|
||||
<div class="category">
|
||||
<div class="category__title">化学检查</div>
|
||||
|
||||
@@ -16,19 +16,19 @@
|
||||
│ │ ├── 选择项目(年度额度 · 必检/选检 · AI 智能推荐)→ 项目详情
|
||||
│ │ ├── 已选项目确认
|
||||
│ │ ├── 预约日期(月历号源 · 近30天可约)
|
||||
│ │ └── 预约结果(成功/失败 · 取消预约需填原因)
|
||||
│ │ └── 预约结果(成功/失败 · 取消预约二次确认)
|
||||
│ ├── 胃肠镜流程(步骤条:1 选择医院 → 2 填问卷 → 3 预约日期)
|
||||
│ │ ├── 选择医院(唐都医院需就诊卡号)
|
||||
│ │ ├── 病史问卷(是/否单选 · 就诊卡条件题)
|
||||
│ │ ├── 预约日期(7~30 天可约窗口)
|
||||
│ │ └── 预约结果(成功/失败 · 取消预约)
|
||||
│ └── 冠脉CTA流程(免问卷,两步:选择医院 → 预约日期 → 预约结果)
|
||||
├── 胃肠镜医院预选(征集期一次性活动,与正式预约解耦)
|
||||
│ ├── 医院预选填写(多选意向医院 · 仅可提交一次)
|
||||
│ └── 预选提交完成(只读回显,不可修改)
|
||||
├── 现场体检(Tab:常规/胃肠镜/冠脉CTA × 状态:待体检/已完成/无预约)
|
||||
├── 胃肠镜医院预选(征集期活动,与正式预约解耦)
|
||||
│ ├── 医院预选填写(多选意向医院 · 至少2家/最多3家 · 可重新填写调整)
|
||||
│ └── 预选提交完成(回显当前提交的意向医院 · 可重新填写)
|
||||
├── 现场体检(Tab:常规/胃肠镜/冠脉CTA × 状态:已预约/无预约)
|
||||
├── 体检报告
|
||||
│ ├── 报告列表(累计年份统计 · 历年体检趋势入口 · 历年报告)
|
||||
│ ├── 报告列表(累计年份统计 · 历年体检趋势入口 · 年份/类型筛选 · 历年报告)
|
||||
│ ├── 常规体检报告(AI 解读/结论/建议 · 14 科室明细)
|
||||
│ ├── 冠脉CTA报告(钙化积分 · 冠脉分段 · 影像诊断)
|
||||
│ ├── 胃肠镜报告(胃镜/肠镜/病理诊断)
|
||||
@@ -38,7 +38,7 @@
|
||||
└── 操作说明(标题搜索过滤)→ 讲解详情(图文教程 / 视频播放)
|
||||
```
|
||||
|
||||
> 胃肠镜医院预选为独立的一次性问卷收集活动:征集期内「未提交 → 已提交」,提交后不可修改;征集期结束通知条隐藏。
|
||||
> 胃肠镜医院预选为独立于正式预约的意向征集活动:征集期内员工多选意向医院(至少 2 家、最多 3 家),提交后可在完成页「重新填写」再次调整提交;征集期结束通知条隐藏。
|
||||
|
||||
---
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
| 31 | 操作说明 | process-guide.html | 页面 |
|
||||
| 32 | 讲解详情(图文/视频) | process-guide-detail.html | 页面 |
|
||||
|
||||
> 预约结果页(10/16/21)、现场体检(22)的「成功/失败/待体检/已完成/无预约」等状态由原型内演示控件切换,实际由数据驱动,逐页说明中一并描述。
|
||||
> 预约结果页(9/15/20)、现场体检(21)的「成功/失败/已预约/无预约」等状态由原型内演示控件切换,实际由数据驱动,逐页说明中一并描述。
|
||||
|
||||
---
|
||||
|
||||
@@ -140,17 +140,17 @@
|
||||
**主要UI元素:**
|
||||
- 导航栏:返回箭头(回 APP 首页)、标题「健康体检」、消息铃铛(红色角标显示未读消息数)
|
||||
- 年度体检计划 Banner 轮播(4 张滑动切换,圆点指示器随内容变色):
|
||||
- 常规体检:计划标题、体检日期范围、体检费用额度胶囊、右下角状态(未预约、已预约、已参检)
|
||||
- 胃肠镜体检:计划标题、体检日期范围、右下角状态(未预约、已预约、已参检)
|
||||
- 冠脉CTA体检:计划标题、体检日期范围、右下角状态(未预约、已预约、已参检)
|
||||
- 常规体检:计划标题、起止日期、体检费用额度胶囊、右下角状态(未预约、已预约、已参检)
|
||||
- 胃肠镜体检:计划标题、起止日期、右下角状态(未预约、已预约、已参检)
|
||||
- 冠脉CTA体检:计划标题、起止日期、右下角状态(未预约、已预约、已参检)
|
||||
- 未开启计划占位:🌱 图标 + 占位文案
|
||||
- 胃肠镜医院预选通知条(橙色,仅征集期展示):📢 图标、标题、截止日期与「每人仅可填写一次」说明、「去选择」按钮
|
||||
- 胃肠镜医院预选通知条(橙色,仅征集期展示):📢 图标、标题、截止日期与「去选择」按钮
|
||||
- 体检服务入口卡片:体检预约(选医院和项目,预约日期)、现场体检(到院扫码/体检进度查询)、体检报告(查看报告/解读结果)
|
||||
- 其他服务宫格:操作说明、一键咨询
|
||||
|
||||
**业务规则:**
|
||||
- Banner 按员工实际计划状态渲染:有计划显示对应类型卡片并按进度跳转,无计划的类型不出现;单位未开启任何计划时仅显示占位图
|
||||
- 预选通知条三态:征集期未提交(「去选择」,进入预选填写)、已提交(标题改「预选已完成」、绿色对勾、「查看结果」,进入完成页)
|
||||
- 预选通知条三态:征集期未提交(「去选择」,进入预选填写)、已提交(标题改「预选已完成」、绿色对勾、「查看结果」,进入完成页),仅预选日期范围内展示
|
||||
|
||||
**交互说明:**
|
||||
- 左右滑动切换 Banner,点击圆点跳转到对应banner
|
||||
@@ -213,13 +213,13 @@
|
||||
|
||||

|
||||
|
||||
**确认个人信息弹窗:** 标题「确认个人信息」+ 副标题;字段:姓名、单位、身份证号(脱敏显示)、性别、年龄、体检类型(「已婚体检 / 未婚体检」胶囊切换,默认已婚);「确认」按钮关闭弹窗。
|
||||
**确认个人信息弹窗:** 标题「确认个人信息」+ 副标题;字段:姓名、单位、身份证号、性别、年龄、体检类型(「已婚体检 / 未婚体检」胶囊切换,默认已婚);「确认」按钮关闭弹窗。
|
||||
|
||||
**业务规则:**
|
||||
- 从选择体检类型页进入时自动弹出个人信息确认弹窗;也可从导航栏「个人信息」手动打开
|
||||
- 已婚/未婚体检切换仅影响本次预约的检查套餐
|
||||
- 可选择的医院范围:后台开展计划选择的医院&职业体检支持的医院(如需参加职业体检)&指定员工的医院(如被指定医院体检)
|
||||
|
||||
- 提交选择医院时需要判断当前员工选择的医院是否符合最终条件,例如已被纳入指定医院体检/已被纳入职业体检,医院需开启职业体检
|
||||
**交互说明:**
|
||||
- 点击医院卡片单选选中
|
||||
- 点击「个人信息」打开确认个人信息弹窗,点击「确认」关闭
|
||||
@@ -237,11 +237,15 @@
|
||||
**主要UI元素:**
|
||||
- 体检额度卡片:「年度体检总额度」、「已选项目费用」(随勾选联动)、额度进度条(超支变红)、三格统计:必检项目 / 选检项目 / 可用额度(超支标红)
|
||||
- 项目 Tab:「选检项目」(默认)/「必检项目」
|
||||
- 项目卡片:示意图标(渐变底 emoji 占位块)+ 项目名 +「重点项目/一般项目」徽章 + 价格;AI 推荐徽章固定于卡片右上角
|
||||
- 必检项目列表(无勾选框、整卡只读)
|
||||
- 选检项目列表(按 AI 推荐等级降序)
|
||||
- AI 推荐徽章三档:强烈推荐、建议加做、可选参考
|
||||
- 「确认提交」弹窗:体检项目数、项目总额、必检项目费用、体检总额度、可用额度;「取消 / 确认提交」
|
||||
- 「✨ 智能推荐」弹窗:项目名、推荐等级徽章、等级说明、推荐理由、按钮「知道了」
|
||||
- 「🔗 关联项目提醒」弹窗:关联说明 + 两项目费用;「取消选择 / 同步选中」
|
||||
- 「⚠️ 互斥项目提醒」弹窗:互斥说明 + 两项目单选列表;「取消 / 确定」
|
||||
- 「💰 额度不足提醒」弹窗:超额说明;按钮「知道了」
|
||||
- 底部双按钮:「上一步」/「提交项目」
|
||||
|
||||

|
||||
@@ -249,15 +253,18 @@
|
||||

|
||||
|
||||
**业务规则:**
|
||||
- 可用额度 = 年度总额度 − 必检合计 − 选检已选合计;可用额度为负时显示 ¥0.00 并标红,进度条封顶并变红(仅视觉警示,不阻止提交)
|
||||
- 可用额度 = 年度总额度(实际个人总额度+所属项目模板中的折扣金额,折扣金额是隐藏的,不体现) − 必检合计 − 选检已选合计;单项选择后总额将超出额度时弹「额度不足提醒」且选择不生效;可用额度为 0 后剩余未选项目置灰不可再选(额度进度条超支变红仅作视觉警示)
|
||||
- 关联项目:选中其一时若另一项未选,弹「关联项目提醒」,「同步选中」后两项一起勾选(两项合计超出剩余额度则转额度不足提醒);取消其一时另一项同步取消
|
||||
- 互斥项目:只能同时体检其中一个。选中其一时若另一项已选,弹「互斥项目提醒」列出两项单选,确定后替换已选项(替换后超出额度则提示额度不足)
|
||||
- 必检项目固定包含,不可取消;选检项目点击整卡切换勾选,默认选中胸部X光
|
||||
- 选检列表按 AI 推荐等级降序排列(强烈推荐 > 建议加做 > 可选参考 > 无推荐)
|
||||
- AI 推荐理由基于员工健康画像生成,示例:腹部B超(BMI 超重+血脂偏高,脂肪肝高风险)、甲状腺彩超(既往甲状腺结节随访)、肿瘤标志物(家族史+年龄段)、心脏彩超(血压正常高值建立基线)、幽门螺杆菌(首次筛查建议)
|
||||
- 金额千分位两位小数格式化
|
||||
|
||||
- 提交项目时需要判断当前员工选择的医院是否符合最终条件,例如已被纳入指定医院体检/已被纳入职业体检,医院需开启职业体检
|
||||
**交互说明:**
|
||||
- 点击 Tab 切换选检/必检列表
|
||||
- 点击选检项目卡勾选/取消勾选,额度卡片金额即时联动
|
||||
- 点击选检项目卡勾选/取消勾选,额度卡片金额即时联动;额度已满时点击置灰项目卡无响应
|
||||
- 选择关联/互斥项目时按弹窗指引确认;「取消选择」/「取消」不改变当前勾选状态
|
||||
- 点击卡片右侧箭头跳转到项目详情页
|
||||
- 点击 AI 推荐徽章打开智能推荐理由弹窗(不触发勾选)
|
||||
- 点击「提交项目」打开确认提交弹窗,「确认提交」跳转到已选项目确认页
|
||||
@@ -328,12 +335,13 @@
|
||||

|
||||
|
||||
**业务规则:**
|
||||
- 可约范围 = 当天 ~ 近 30 天;已过日期与超范围日期不可选
|
||||
- 可约范围 = 当天 ~ 近 30 天(该30天作为动态字段,不是写死的,通过后台接口传递);已过日期与超范围日期不可选
|
||||
- 周末不可约(显示「不可约」);工作日号源随机模拟,约满日显示「不可约」且禁点
|
||||
- 不能翻到当月之前或可约范围所在月份之后
|
||||
- 默认选中当天;未选中日期时「确定预约」不响应
|
||||
- 可供员工预约的日期范围是医院承检日期+单位允许日期范围的交叉日期,并且在可预约日期的前一天/当天(当天可能是刚创建体检计划,但是预约日期也是当天)给员工发送短信,提醒员工进行预约体检
|
||||
|
||||
- 未开启预约时,隐藏日历,确定预约按钮置灰
|
||||
- 提交预约时需要判断当前员工选择的医院是否符合最终条件,例如已被纳入指定医院体检/已被纳入职业体检,医院需开启职业体检
|
||||
|
||||
**交互说明:**
|
||||
- 点击翻月按钮切换月份
|
||||
@@ -348,18 +356,18 @@
|
||||
|
||||

|
||||
|
||||
**功能说明:** 预约提交结果页,含「预约成功 / 预约失败」两态。成功态展示预约信息与体检须知,支持取消预约(必填原因);失败态展示失败原因并可重新预约。
|
||||
**功能说明:** 预约提交结果页,含「预约成功 / 预约失败」两态。成功态展示预约信息与体检须知,支持取消预约(二次确认);失败态展示失败原因并可重新预约。
|
||||
|
||||
**主要UI元素:**
|
||||
- 步骤条(三步全部完成;点击已完成步骤弹 Toast 阻止回跳)
|
||||
- 结果横幅:
|
||||
- 成功态(绿色,圆形对勾图标):「预约成功」
|
||||
- 成功态(绿色,圆形对勾图标):「预约成功」+ 提示「请按预约日期准时到检」
|
||||
- 失败态(红色,圆形叉图标):「预约失败」+ 失败原因 + 红色「?」帮助按钮
|
||||
- 预约信息卡片:体检医院、体检员工、体检地址、体检日期(高亮)、体检项目数
|
||||
- 体检须知卡片(仅成功态显示)
|
||||
- 成功态按钮:「取消预约」(红色)/「查看预约详情」(主色);失败态按钮:「重新预约」(独占一行)
|
||||
- 「失败原因详情」弹窗:失败原因、发生时间、处理建议
|
||||
- 「确认取消预约」弹窗(见下方表单字段表)
|
||||
- 成功态按钮:「取消预约」(红色)/「现场体检」(主色);失败态按钮:「重新预约」(独占一行)
|
||||
- 「失败原因详情」弹窗:失败原因、发生时间
|
||||
- 「确认取消预约」弹窗:说明文案 + 医院与日期信息;「再想想 / 确认取消」
|
||||
|
||||

|
||||
|
||||
@@ -370,24 +378,16 @@
|
||||
**业务规则:**
|
||||
- 失败语义为号源争抢失败(所选日期号源已被其他员工约满);失败态隐藏体检须知,引导重新预约
|
||||
- 已预约状态下点击步骤条弹 Toast「当前已预约体检,无法重新选择,请先取消预约」;失败态 Toast 文案切换为「预约未成功,请点击下方『重新预约』按钮重新预约」
|
||||
- 取消预约必须选择原因;选择「其他」时必须填写文字说明(上限 100 字)
|
||||
- 取消成功后 Toast「预约已取消」并返回预约日期页重新预约
|
||||
- 取消预约为二次确认弹窗,无需填写原因;确认后名额释放,Toast「预约已取消」并返回预约日期页重新预约
|
||||
- 取消时限约束:至少提前一天操作
|
||||
|
||||
**交互说明:**
|
||||
- 失败态点击「?」打开失败原因详情弹窗
|
||||
- 成功态点击「取消预约」打开取消预约弹窗,校验通过确认后返回预约日期页
|
||||
- 成功态点击「查看预约详情」跳转到「现场体检」(常规体检·待体检)
|
||||
- 成功态点击「取消预约」打开二次确认弹窗,「确认取消」后返回预约日期页
|
||||
- 成功态点击「现场体检」跳转到「现场体检」(常规体检·已预约,含签到码)
|
||||
- 失败态点击「重新预约」跳转到预约日期页
|
||||
- 点击返回回到健康体检主页
|
||||
|
||||
**表单字段表(取消预约弹窗):**
|
||||
|
||||
| 字段名 | 类型 | 是否必填 | 校验规则 |
|
||||
|--------|------|----------|----------|
|
||||
| 取消原因 | chip 单选(时间冲突/医院选择不当/日期选择不当/个人健康原因/其他) | 是 | 未选择时提示「请选择或填写取消原因」 |
|
||||
| 其他原因说明 | 多行文本(maxlength=100) | 选「其他」时必填 | 去空格后非空,否则提示同上 |
|
||||
|
||||
---
|
||||
|
||||
## 四、胃肠镜体检预约流程
|
||||
@@ -499,10 +499,11 @@
|
||||
- 体检须知卡片(仅成功态)
|
||||
- 成功态按钮「取消预约 / 查看预约详情」;失败态按钮「重新预约」
|
||||
- 「失败原因详情」弹窗:失败原因说明 + 处理建议
|
||||
- 「确认取消预约」弹窗(原因 chips + 其他说明,与常规流程一致)
|
||||
- 「确认取消预约」弹窗:取消原因 chip 单选(时间冲突/医院选择不当/日期选择不当/个人健康原因/其他),选「其他」需填写文字说明
|
||||
|
||||
**业务规则:**
|
||||
- 与常规预约结果页一致:失败态隐藏须知、取消必填原因、取消成功后返回预约日期页
|
||||
- 失败态隐藏体检须知,引导重新预约
|
||||
- 取消预约必须选择原因,选择「其他」时必须填写文字说明;取消成功后返回预约日期页
|
||||
- 已预约状态下点击步骤条弹 Toast 阻止回跳
|
||||
|
||||
**交互说明:**
|
||||
@@ -514,31 +515,32 @@
|
||||
|
||||
## 五、胃肠镜医院预选
|
||||
|
||||
> 独立于正式预约的意向征集活动:征集期内员工对下一年度承检医院进行意向多选,每人仅可填写一次、提交后不可修改。
|
||||
> 独立于正式预约的意向征集活动:征集期内员工对下一年度承检医院进行意向多选(至少 2 家、最多 3 家),提交后可在完成页重新填写调整。
|
||||
|
||||
### 13. 医院预选填写(gastro-preselect.html)
|
||||
|
||||

|
||||
|
||||
**功能说明:** 胃肠镜体检医院意向征集填写页,员工多选意向医院后经二次确认提交。
|
||||
**功能说明:** 胃肠镜体检医院意向征集填写页,员工多选意向医院(至少 2 家、最多 3 家)后经二次确认提交,可再次进入调整重新提交。
|
||||
|
||||
**主要UI元素:**
|
||||
- 征集说明卡:征集标题、预选日期、红色警示条
|
||||
- 区块标题「选择意向医院」+「点击卡片可多选,当前已选 N 家」(计数实时更新)
|
||||
- 医院多选卡片(方形复选框,选中态青色对勾):各带省市信息与类型标签
|
||||
- 「确认提交预选」弹窗:警示文案 + 已选医院数量与名称列表;「返回修改 / 确认提交」
|
||||
- 征集说明卡:征集标题、预选日期
|
||||
- 区块标题「选择意向医院」+「点击卡片可多选,至少选择2家、最多3家,当前已选 N 家」(计数实时更新)
|
||||
- 医院多选卡片(方形复选框,选中态青色对勾):各带省市信息
|
||||
- 「确认提交预选」弹窗:已选医院数量与名称列表;「返回修改 / 确认提交」
|
||||
- Toast 轻提示:数量不满足 2~3 家时的校验提醒
|
||||
- 底部「提交预选」按钮(选中后文案带已选数量)
|
||||
|
||||

|
||||
|
||||
**业务规则:**
|
||||
- 多选互不影响,已选 0 家时提交按钮禁用
|
||||
- 提交前强制二次确认(因仅可填写一次)
|
||||
- 每人限提交一次,提交后不可修改
|
||||
- 数量校验:少于 2 家提示「至少选择2家意向医院,请继续选择」,多于 3 家提示「最多选择3家意向医院,请调整后再提交」;校验通过才进入二次确认
|
||||
- 提交前二次确认核对已选医院;支持重复提交,再次提交覆盖上一次意向
|
||||
|
||||
**交互说明:**
|
||||
- 点击医院卡片勾选/取消勾选,按钮文案与计数联动
|
||||
- 点击「提交预选」打开确认弹窗(未选医院时按钮禁用)
|
||||
- 点击「提交预选」先校验数量(2~3 家),通过后打开确认弹窗(未选医院时按钮禁用)
|
||||
- 弹窗「返回修改」关闭弹窗,「确认提交」跳转到预选提交完成页
|
||||
- 点击返回回到健康体检主页
|
||||
|
||||
@@ -548,19 +550,20 @@
|
||||
|
||||

|
||||
|
||||
**功能说明:** 预选提交成功后的只读回显页。
|
||||
**功能说明:** 预选提交成功后的回显页,展示当前提交的意向医院,支持重新填写调整。
|
||||
|
||||
**主要UI元素:**
|
||||
- 成功卡:绿色对勾图标、「预选提交成功」、提交时间、绿色提示框
|
||||
- 「我选择的意向医院」区块:只读回显说明 + 只读已选医院卡片(固定青色描边 + 对勾)
|
||||
- 底部「返回首页」按钮
|
||||
- 成功卡:绿色对勾图标、「预选提交成功」、提交时间
|
||||
- 「我选择的意向医院」区块:当前提交的意向医院卡片(固定青色描边 + 对勾)
|
||||
- 底部「重新填写」按钮
|
||||
|
||||
**业务规则:**
|
||||
- 纯只读展示,医院卡片不可点击
|
||||
- 展示当前提交的意向医院,医院卡片不可直接点击
|
||||
- 返回主页后,主页预选通知条变为「预选已完成」态
|
||||
|
||||
**交互说明:**
|
||||
- 点击「返回首页」或返回箭头回到健康体检主页
|
||||
- 点击「重新填写」回到预选填写页,可修改意向医院后再次提交
|
||||
- 点击返回箭头回到健康体检主页
|
||||
|
||||
---
|
||||
|
||||
@@ -627,10 +630,12 @@
|
||||
- 预约信息卡片:体检医院、体检员工、体检地址、体检日期、体检项目
|
||||
- 体检须知卡片(仅成功态)
|
||||
- 成功态按钮「取消预约 / 查看预约详情」;失败态按钮「重新预约」
|
||||
- 「失败原因详情」弹窗与「确认取消预约」弹窗(与常规流程一致)
|
||||
- 「失败原因详情」弹窗:失败原因说明 + 处理建议
|
||||
- 「确认取消预约」弹窗:取消原因 chip 单选(时间冲突/医院选择不当/日期选择不当/个人健康原因/其他),选「其他」需填写文字说明
|
||||
|
||||
**业务规则:**
|
||||
- 与常规预约结果页一致:失败态隐藏须知、取消必填原因、取消成功后返回预约日期页
|
||||
- 失败态隐藏体检须知,引导重新预约
|
||||
- 取消预约必须选择原因,选择「其他」时必须填写文字说明;取消成功后返回预约日期页
|
||||
|
||||
**交互说明:**
|
||||
- 成功态「查看预约详情」跳转到「现场体检」(冠脉CTA体检页签)
|
||||
@@ -645,17 +650,17 @@
|
||||
|
||||

|
||||
|
||||
**功能说明:** 查看各类体检的预约详情与现场体检信息:体检签到码(条形码/二维码)、预约概要、体检须知、已检/未检项目进度;无预约时提供立即预约入口。
|
||||
**功能说明:** 查看各类体检的预约详情与现场体检信息:体检签到码(条形码)、预约概要、体检须知、已检/未检项目进度;无预约时提供立即预约入口。
|
||||
|
||||

|
||||
|
||||
**主要UI元素:**
|
||||
- 体检类型 Tab(吸顶,3 等分):常规体检 / 胃肠镜体检 / 冠脉CTA体检
|
||||
- 常规体检·待体检视图:
|
||||
- 「体检签到码」卡片:条形码/二维码双选项卡切换,条形码下编号,提示「点击条码可放大查看」;点击打开放大遮罩
|
||||
- 预约概要卡:体检医院、预约日期、体检员工、单位部门、状态徽章(待体检=橙 / 已参检=绿)
|
||||
- 常规体检·已预约视图:
|
||||
- 「体检签到码」卡片:条形码 + 编号,提示「点击条码可放大查看」;点击打开放大遮罩
|
||||
- 预约概要卡:体检医院、体检地址、预约日期、体检员工、单位部门
|
||||
- 体检进度卡:Tab「已检项目 (N) / 未检项目 (M)」,常规项目列表,已检=绿色✓「已参检」、未检=橙色●「未检」
|
||||
- 胃肠镜/冠脉CTA视图:预约概要卡 + 体检须知卡(6 条,与预约结果页一致)
|
||||
- 胃肠镜/冠脉CTA视图:预约概要卡(体检员工、体检地址、体检日期、体检项目)+ 体检须知卡(6 条,与预约结果页一致)
|
||||
- 无预约空态:图标 +「暂无XX体检预约」+ 说明文案 +「立即预约」按钮
|
||||
|
||||
**业务规则:** 如未预约,显示未预约的提示页面
|
||||
@@ -663,19 +668,17 @@
|
||||

|
||||
|
||||
**业务规则:**
|
||||
- 预约状态三态:待体检(橙)/ 已参检(绿)/ 无预约信息(空态);已完成视图无签到码卡片,进度为全部已检
|
||||
- 签到码仅「常规体检·待体检」状态展示
|
||||
- 预约状态两态演示:已预约 / 无预约信息(空态);已参检视图无签到码卡片,进度为全部已检
|
||||
- 签到码仅「常规体检·已预约」状态展示
|
||||
- 已检/未检列表空态文案:「暂无已检项目」/「当前预约项目已全部完成」
|
||||
|
||||
**交互说明:**
|
||||
- 点击类型 Tab 切换对应体检面板
|
||||
- 点击「条形码/二维码」切换签到码形态;点击码打开放大遮罩,点击遮罩空白关闭
|
||||
- 点击签到码打开放大遮罩,点击遮罩空白关闭
|
||||
- 点击已检/未检 Tab 切换项目列表
|
||||
- 空态「立即预约」按类型分流:常规跳转到选择体检类型页,胃肠镜跳转到胃肠镜·选择医院,冠脉CTA跳转到冠脉CTA·选择医院
|
||||
- 点击返回回到健康体检主页
|
||||
|
||||
**业务规则:** 如未预约,显示未预约的提示页面
|
||||
|
||||
---
|
||||
|
||||
## 八、体检报告与指标对比
|
||||
@@ -684,19 +687,22 @@
|
||||
|
||||

|
||||
|
||||
**功能说明:** 历年体检报告汇总入口页,展示体检年份统计、历年体检趋势分析入口和按年度/报告类型分类的历年报告列表。
|
||||
**功能说明:** 历年体检报告汇总入口页,展示体检年份统计、历年体检趋势分析入口和历年报告列表,支持按年份与体检类型筛选。
|
||||
|
||||
**主要UI元素:**
|
||||
- 汇总卡(青色渐变):累计体检年份、起始年份、报告总数、年度时间轴装饰
|
||||
- 历年体检趋势分析入口条:重点指标数目 · 纵向对比历年体检数据 + 右箭头
|
||||
- 报告筛选栏:年份选择(日历面板:全部/2021~2025)+ 体检类型下拉(全部类型/常规体检/胃肠镜体检/冠脉CTA体检),默认「全部」
|
||||
- 历年报告列表(图标 + 标题 + 类型标签 + 机构名 + 箭头):同一年份可有多类报告
|
||||
|
||||
**业务规则:**
|
||||
- 报告类型标签三色:常规体检(蓝)、胃肠镜体检(青)、冠脉CTA体检(红)
|
||||
- 报告按年度倒序排列
|
||||
- 年份与类型两个筛选条件叠加过滤;选择非「全部」时对应入口按钮高亮
|
||||
|
||||
**交互说明:**
|
||||
- 点击历年体检趋势分析条跳转到指标纵向对比页
|
||||
- 点击年份/类型入口打开面板选择筛选条件,报告列表即时过滤;点击面板外部收起
|
||||
- 点击常规体检报告跳转到常规体检报告页
|
||||
- 点击胃肠镜体检报告跳转到胃肠镜报告页
|
||||
- 点击冠脉CTA体检报告跳转到冠脉CTA报告页
|
||||
@@ -765,7 +771,7 @@
|
||||
- 报告头:报告标题 + 类型标签 + 基本信息
|
||||
- 胃镜检查(橙色标题条,4 个可折叠字段):食管、胃、十二指肠所见描述;诊断结果
|
||||
- 肠镜检查(青绿标题条,3 个字段):结肠所见;诊断结果;病理诊断
|
||||
- 影像报告:胃镜报告、肠镜报告、活检报告「查看」入口
|
||||
- 报告图片:胃镜报告、肠镜报告、活检报告「查看」入口
|
||||
- 底部「返回报告列表」
|
||||
|
||||
**业务规则:**
|
||||
@@ -867,11 +873,13 @@
|
||||
**功能说明:** 集中展示体检报告中的异常指标(按检查大类分组表格呈现),每个子项提供「专家库一键咨询」入口。
|
||||
|
||||
**主要UI元素:**
|
||||
- 顶部体检信息栏:当前咨询数据的体检年份
|
||||
- 大分类区块,每区块下分子项(子项名 + 右侧红色「专家库一键咨询 ›」链接):化学检查、常规检查、影像检查、肠胃镜检查
|
||||
- 异常结果表:四列(名称/结果/单位/参考值),结果列红色加粗;肠胃镜为两列(名称/结果)
|
||||
|
||||
**业务规则:**
|
||||
- 仅展示异常项,结果列统一红色加粗标记异常
|
||||
- 数据为员工最近一次的体检数据,顶部展示对应体检年份
|
||||
|
||||
**交互说明:**
|
||||
- 点击「专家库一键咨询 ›」跳转到健康咨询模块的专家列表页,每个分类会关联科室或者疾病,优先跳对应科室,如没有科室,跳对应疾病,如两者都没,跳默认
|
||||
|
||||
@@ -15,7 +15,7 @@ const docDir = __dirname;
|
||||
const root = path.resolve(__dirname, '..');
|
||||
|
||||
// mode: auto(短页面最低 844 / 长页面真实高度)
|
||||
const tasks = [
|
||||
const baseTasks = [
|
||||
// ========== 模块主页 ==========
|
||||
{ html: 'index.html', out: 'index' },
|
||||
|
||||
@@ -29,6 +29,8 @@ const tasks = [
|
||||
{ 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: 'booking-date-selected.html', out: 'booking-date-selected-reason', script: () => openReasonModal() },
|
||||
{ html: 'booking-date-selected.html', out: 'booking-date-selected-cancel', script: () => openCancelModal() },
|
||||
{ html: 'project-detail.html', out: 'project-detail', query: '?id=general' },
|
||||
|
||||
// ========== 胃肠镜体检流程 ==========
|
||||
@@ -39,6 +41,7 @@ const tasks = [
|
||||
{ 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.html', out: 'gastro-preselect-dialog', script: () => { document.querySelectorAll('.hospital-card')[0].click(); document.querySelectorAll('.hospital-card')[1].click(); openConfirm(); } },
|
||||
{ html: 'gastro-preselect-done.html', out: 'gastro-preselect-done' },
|
||||
|
||||
// ========== 冠脉CTA体检流程 ==========
|
||||
@@ -71,6 +74,13 @@ const tasks = [
|
||||
];
|
||||
|
||||
(async () => {
|
||||
// 支持命令行按 out 名称过滤,只重截部分截图:node screenshot.mjs index reports
|
||||
const only = process.argv.slice(2);
|
||||
const tasks = only.length ? baseTasks.filter(t => only.includes(t.out)) : baseTasks;
|
||||
if (only.length && tasks.length === 0) {
|
||||
console.error('未匹配到任何截图任务,可用名称:', baseTasks.map(t => t.out).join(', '));
|
||||
process.exit(1);
|
||||
}
|
||||
const browser = await chromium.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });
|
||||
const context = await browser.newContext({ viewport: { width: 390, height: 4000 } });
|
||||
|
||||
@@ -104,6 +114,12 @@ const tasks = [
|
||||
await page.waitForTimeout(250);
|
||||
}
|
||||
|
||||
// 自定义脚本(如打开弹窗后再截图)
|
||||
if (t.script) {
|
||||
await page.evaluate(t.script);
|
||||
await page.waitForTimeout(250);
|
||||
}
|
||||
|
||||
// 解除 phone-shell 高度限制:短页面保底 844,长页面按内容展开
|
||||
await page.evaluate(() => {
|
||||
const shell = document.querySelector('.phone-shell');
|
||||
|
||||
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 56 KiB |
@@ -48,7 +48,7 @@
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: linear-gradient(180deg, #effbfb 0%, #f7f9fb 220px, #f7f9fb 100%); padding-bottom: 120px; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
.page-body { padding: 16px; }
|
||||
/* 提交成功卡:绿色对勾 + 提交时间 + 不可修改说明 */
|
||||
/* 提交成功卡:绿色对勾 + 提交时间 */
|
||||
.success-card {
|
||||
background: #fff; border-radius: 18px; padding: 24px 16px 18px; margin-bottom: 18px;
|
||||
box-shadow: var(--shadow); border: 1px solid var(--border); text-align: center;
|
||||
@@ -60,15 +60,10 @@
|
||||
box-shadow: 0 10px 24px rgba(82, 196, 26, 0.28);
|
||||
}
|
||||
.success-card__title { font-size: 18px; font-weight: 700; margin-bottom: 6px; }
|
||||
.success-card__time { font-size: 12px; color: var(--text-muted); margin-bottom: 12px; }
|
||||
.success-card__note {
|
||||
display: inline-block; padding: 6px 12px; border-radius: 12px;
|
||||
background: #f6ffed; border: 1px solid #b7eb8f;
|
||||
font-size: 12px; color: #52c41a; line-height: 1.6;
|
||||
}
|
||||
.success-card__time { font-size: 12px; color: var(--text-muted); }
|
||||
.section-title { font-size: 16px; font-weight: 700; margin-bottom: 6px; }
|
||||
.section-sub { font-size: 12px; color: var(--text-muted); margin-bottom: 12px; }
|
||||
/* 已选医院只读卡片:不可点击,右侧固定绿色对勾 */
|
||||
/* 已选医院回显卡片:右侧固定绿色对勾 */
|
||||
.hospital-card {
|
||||
background: #fff; border-radius: 18px; padding: 16px; margin-bottom: 12px;
|
||||
border: 2px solid var(--primary); box-shadow: var(--shadow);
|
||||
@@ -122,11 +117,10 @@
|
||||
</div>
|
||||
<div class="success-card__title">预选提交成功</div>
|
||||
<div class="success-card__time">提交时间:2026-09-03 12:00</div>
|
||||
<div class="success-card__note">感谢您的参与,您的意向将作为2027年度承检医院安排参考<br>预选结果提交后不可修改</div>
|
||||
</div>
|
||||
|
||||
<div class="section-title">我选择的意向医院</div>
|
||||
<div class="section-sub">共 <b style="color:#0f9b9b;">2</b> 家,以下为只读回显,不可再次编辑</div>
|
||||
<div class="section-sub">共 <b style="color:#0f9b9b;">2</b> 家,以下为当前提交的意向医院,可重新填写调整</div>
|
||||
|
||||
<div class="hospital-card">
|
||||
<div class="hospital-card__info">
|
||||
@@ -163,8 +157,8 @@
|
||||
</div>
|
||||
|
||||
<div class="bottom-actions">
|
||||
<!-- [交互] 点击返回首页: index.html,首页通知条同步变为「预选已完成」态 -->
|
||||
<button class="bottom-actions__btn" onclick="location.href='index.html'">返回首页</button>
|
||||
<!-- [交互] 重新填写:返回预选表单 gastro-preselect.html,可修改后再次提交 -->
|
||||
<button class="bottom-actions__btn" onclick="location.href='gastro-preselect.html'">重新填写</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: linear-gradient(180deg, #effbfb 0%, #f7f9fb 180px, #f7f9fb 100%); padding-bottom: 120px; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
.page-body { padding: 16px; }
|
||||
/* 征集说明卡:目的、周期、不可逆提示 */
|
||||
/* 征集说明卡:征集活动说明与周期 */
|
||||
.intro-card {
|
||||
background: #fff; border-radius: 18px; padding: 16px; margin-bottom: 18px;
|
||||
box-shadow: var(--shadow); border: 1px solid var(--border);
|
||||
@@ -62,11 +62,6 @@
|
||||
.intro-card__field span { color: var(--text-muted); }
|
||||
.intro-card__field b { color: var(--text-primary); font-weight: 600; white-space: nowrap; }
|
||||
.intro-card__field:last-of-type { border-bottom: none; padding-bottom: 2px; }
|
||||
.intro-card__warn {
|
||||
margin-top: 10px; padding: 8px 10px; border-radius: 10px;
|
||||
background: #fff2f0; border: 1px solid #ffccc7;
|
||||
font-size: 12px; color: #f5222d; line-height: 1.6;
|
||||
}
|
||||
.section-title { font-size: 16px; font-weight: 700; margin-bottom: 6px; }
|
||||
.section-sub { font-size: 12px; color: var(--text-muted); margin-bottom: 12px; }
|
||||
.hospital-card {
|
||||
@@ -83,10 +78,6 @@
|
||||
}
|
||||
.hospital-card__name { font-size: 15px; font-weight: 600; color: var(--text-primary); margin-bottom: 2px; }
|
||||
.hospital-card__addr { font-size: 12px; color: var(--text-muted); }
|
||||
.hospital-card__tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
|
||||
.htag { font-size: 10px; line-height: 16px; padding: 0 8px; border-radius: 8px; }
|
||||
.htag--gastro { background: #f6ffed; color: #52c41a; }
|
||||
.htag--routine { background: #e6f7ff; color: #1890ff; }
|
||||
/* 多选复选框:区别于正式预约的单选圆点 */
|
||||
.check-box {
|
||||
width: 22px; height: 22px; border-radius: 6px; border: 2px solid #d9d9d9;
|
||||
@@ -108,7 +99,7 @@
|
||||
.bottom-actions__btn:disabled {
|
||||
background: #d9d9d9; color: #fff; box-shadow: none; cursor: not-allowed;
|
||||
}
|
||||
/* 提交二次确认弹窗:因预选仅可填写一次,提交前强制确认 */
|
||||
/* 提交二次确认弹窗:提交前列出已选医院供用户核对 */
|
||||
.modal-overlay {
|
||||
position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 100;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
@@ -117,7 +108,6 @@
|
||||
.modal-card { width: 340px; background: #fff; border-radius: 24px; padding: 24px 20px; box-shadow: 0 20px 60px rgba(0,0,0,0.18); }
|
||||
.modal-card__title { font-size: 18px; font-weight: 700; text-align: center; margin-bottom: 6px; }
|
||||
.modal-card__sub { font-size: 13px; color: var(--text-muted); text-align: center; margin-bottom: 16px; line-height: 1.6; }
|
||||
.modal-card__sub b { color: #f5222d; }
|
||||
.modal-hospital-list { background: #f7f9fb; border-radius: 14px; padding: 12px 14px; margin-bottom: 20px; }
|
||||
.modal-hospital-list__title { font-size: 12px; color: var(--text-muted); margin-bottom: 8px; }
|
||||
.modal-hospital-list__item {
|
||||
@@ -135,6 +125,14 @@
|
||||
background: linear-gradient(135deg, #13c2c2 0%, #36cfc9 100%);
|
||||
color: #fff; box-shadow: 0 8px 20px rgba(19, 194, 194, 0.2);
|
||||
}
|
||||
/* 轻提示 toast:选择数量不满足 2~3 家时给出校验提醒 */
|
||||
.toast {
|
||||
position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%) scale(0.9);
|
||||
background: rgba(0,0,0,0.75); color: #fff; padding: 14px 22px; border-radius: 12px;
|
||||
font-size: 13px; line-height: 1.6; text-align: center; z-index: 200;
|
||||
opacity: 0; pointer-events: none; transition: all 0.25s ease; max-width: 280px;
|
||||
}
|
||||
.toast.show { opacity: 1; transform: translate(-50%, -50%) scale(1); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -158,23 +156,17 @@
|
||||
<div class="intro-card">
|
||||
<div class="intro-card__title">📋 2027 年度胃肠镜体检医院意向征集</div>
|
||||
<div class="intro-card__field"><span>预选日期: 2026-07-01至2026-10-20</span></div>
|
||||
<div class="intro-card__warn">⚠️ 本次预选每人仅可填写一次,提交后不可修改,请谨慎选择。</div>
|
||||
</div>
|
||||
|
||||
<div class="section-title">选择意向医院</div>
|
||||
<div class="section-sub">点击卡片可多选,当前已选 <span id="selectedCount">0</span> 家</div>
|
||||
<div class="section-sub">点击卡片可多选,至少选择2家、最多3家,当前已选 <span id="selectedCount">0</span> 家</div>
|
||||
|
||||
<div class="hospital-card" onclick="toggleHospital(this)">
|
||||
<div class="hospital-card__info">
|
||||
<div class="hospital-card__icon">🏥</div>
|
||||
<div>
|
||||
<div class="hospital-card__name">宁夏宝石花医院</div>
|
||||
<div class="hospital-card__addr">宁夏银川市</div>
|
||||
<div class="hospital-card__tags">
|
||||
<span class="htag htag--gastro">胃肠镜体检</span>
|
||||
<span class="htag htag--routine">常规体检</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hospital-card__addr">宁夏银川市</div> </div>
|
||||
</div>
|
||||
<div class="check-box"></div>
|
||||
</div>
|
||||
@@ -184,11 +176,7 @@
|
||||
<div class="hospital-card__icon">🏥</div>
|
||||
<div>
|
||||
<div class="hospital-card__name">CQ星龙园医院</div>
|
||||
<div class="hospital-card__addr">陕西西安市</div>
|
||||
<div class="hospital-card__tags">
|
||||
<span class="htag htag--gastro">胃肠镜体检</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hospital-card__addr">陕西西安市</div> </div>
|
||||
</div>
|
||||
<div class="check-box"></div>
|
||||
</div>
|
||||
@@ -198,11 +186,7 @@
|
||||
<div class="hospital-card__icon">🏥</div>
|
||||
<div>
|
||||
<div class="hospital-card__name">唐都医院</div>
|
||||
<div class="hospital-card__addr">陕西西安市</div>
|
||||
<div class="hospital-card__tags">
|
||||
<span class="htag htag--gastro">胃肠镜体检</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hospital-card__addr">陕西西安市</div> </div>
|
||||
</div>
|
||||
<div class="check-box"></div>
|
||||
</div>
|
||||
@@ -212,12 +196,7 @@
|
||||
<div class="hospital-card__icon">🏥</div>
|
||||
<div>
|
||||
<div class="hospital-card__name">西安市第四医院</div>
|
||||
<div class="hospital-card__addr">陕西西安市</div>
|
||||
<div class="hospital-card__tags">
|
||||
<span class="htag htag--gastro">胃肠镜体检</span>
|
||||
<span class="htag htag--routine">常规体检</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hospital-card__addr">陕西西安市</div> </div>
|
||||
</div>
|
||||
<div class="check-box"></div>
|
||||
</div>
|
||||
@@ -227,11 +206,7 @@
|
||||
<div class="hospital-card__icon">🏥</div>
|
||||
<div>
|
||||
<div class="hospital-card__name">银川市第一人民医院</div>
|
||||
<div class="hospital-card__addr">宁夏银川市</div>
|
||||
<div class="hospital-card__tags">
|
||||
<span class="htag htag--gastro">胃肠镜体检</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hospital-card__addr">宁夏银川市</div> </div>
|
||||
</div>
|
||||
<div class="check-box"></div>
|
||||
</div>
|
||||
@@ -247,7 +222,7 @@
|
||||
<div class="modal-overlay hidden" id="confirmModal">
|
||||
<div class="modal-card">
|
||||
<div class="modal-card__title">确认提交预选</div>
|
||||
<div class="modal-card__sub">本次预选<b>仅可填写一次,提交后不可修改</b><br>请确认以下意向医院无误</div>
|
||||
<div class="modal-card__sub">请确认以下意向医院无误</div>
|
||||
<div class="modal-hospital-list">
|
||||
<div class="modal-hospital-list__title">已选 <span id="modalCount">0</span> 家医院</div>
|
||||
<div id="modalHospitalList"></div>
|
||||
@@ -258,6 +233,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@@ -274,10 +251,21 @@
|
||||
btn.disabled = count === 0;
|
||||
btn.textContent = count === 0 ? '提交预选' : '提交预选(已选 ' + count + ' 家)';
|
||||
}
|
||||
// 打开二次确认弹窗前,将已选医院名称注入弹窗列表
|
||||
// toast 轻提示:展示 2.2 秒后自动消失
|
||||
var toastTimer = null;
|
||||
function showToast(msg) {
|
||||
var t = document.getElementById('toast');
|
||||
t.textContent = msg;
|
||||
t.classList.add('show');
|
||||
clearTimeout(toastTimer);
|
||||
toastTimer = setTimeout(function () { t.classList.remove('show'); }, 2200);
|
||||
}
|
||||
// 打开二次确认弹窗前校验数量(至少2家、最多3家),并将已选医院名称注入弹窗列表
|
||||
function openConfirm() {
|
||||
var actives = document.querySelectorAll('.hospital-card.active');
|
||||
if (actives.length === 0) return;
|
||||
if (actives.length < 2) { showToast('至少选择2家意向医院,请继续选择'); return; }
|
||||
if (actives.length > 3) { showToast('最多选择3家意向医院,请调整后再提交'); return; }
|
||||
var html = '';
|
||||
actives.forEach(function (card) {
|
||||
html += '<div class="modal-hospital-list__item">' + card.querySelector('.hospital-card__name').textContent + '</div>';
|
||||
|
||||
@@ -464,7 +464,7 @@
|
||||
<span class="banner-slide__ring"></span>
|
||||
<span class="banner-slide__deco">🩺</span>
|
||||
<div class="banner-slide__title">单位已制定2026年度常规体检计划</div>
|
||||
<div class="banner-slide__date">🗓 体检日期:2026-09-01 至 2026-12-31</div>
|
||||
<div class="banner-slide__date">🗓 起止日期:2026-09-01 至 2026-12-31</div>
|
||||
<div class="banner-slide__fee">
|
||||
<span class="banner-chip">💰 体检费用额度 <b>¥1500.00</b></span>
|
||||
</div>
|
||||
@@ -483,7 +483,7 @@
|
||||
<span class="banner-slide__ring"></span>
|
||||
<span class="banner-slide__deco">🔬</span>
|
||||
<div class="banner-slide__title">单位已拟定2026年度胃肠镜体检计划</div>
|
||||
<div class="banner-slide__date">🗓 体检日期:2026-10-08 至 2026-12-20</div>
|
||||
<div class="banner-slide__date">🗓 起止日期:2026-10-08 至 2026-12-20</div>
|
||||
<!-- 圆圈进度(右下角):已预约 = 60%(已选项目20%→已预约60%→体检中80%→已参检100%),dashoffset = 131.9 × 40% ≈ 52.8 -->
|
||||
<div class="banner-progress">
|
||||
<svg width="52" height="52" viewBox="0 0 52 52" fill="none">
|
||||
@@ -499,7 +499,7 @@
|
||||
<span class="banner-slide__ring"></span>
|
||||
<span class="banner-slide__deco">🫀</span>
|
||||
<div class="banner-slide__title">单位已拟定2026年度冠脉CTA体检计划</div>
|
||||
<div class="banner-slide__date">🗓 体检日期:2026-10-08 至 2026-12-20</div>
|
||||
<div class="banner-slide__date">🗓 起止日期:2026-10-08 至 2026-12-20</div>
|
||||
<!-- 圆圈进度(右下角):已预约 = 60%(已选项目20%→已预约60%→体检中80%→已参检100%),dashoffset = 131.9 × 40% ≈ 52.8 -->
|
||||
<div class="banner-progress">
|
||||
<svg width="52" height="52" viewBox="0 0 52 52" fill="none">
|
||||
|
||||
@@ -199,37 +199,6 @@
|
||||
border: 1px solid #e4f7f5;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.person-card__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.code-switch {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
padding: 2px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid #e4f7f5;
|
||||
background: #f2fbfa;
|
||||
}
|
||||
.code-switch__opt {
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
color: var(--text-secondary);
|
||||
padding: 5px 10px;
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.code-switch__opt--active {
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 2px 6px rgba(19, 194, 194, 0.35);
|
||||
}
|
||||
.qrcode-wrap { display: flex; flex-direction: column; align-items: center; gap: 8px; }
|
||||
.code-img {
|
||||
background: #fff;
|
||||
@@ -239,14 +208,8 @@
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
.code-img:hover { transform: scale(1.04); }
|
||||
.code-img--qr { width: 160px; height: 160px; }
|
||||
.code-img--bar { width: 224px; height: 132px; }
|
||||
.qrcode-wrap__hint { font-size: 12px; color: var(--text-muted); }
|
||||
/* 条形码/二维码互斥显隐 */
|
||||
.person-card .code-only--bar { display: flex; }
|
||||
.person-card .code-only--qr { display: none; }
|
||||
.person-card--qr .code-only--bar { display: none; }
|
||||
.person-card--qr .code-only--qr { display: flex; }
|
||||
/* 放大遮罩 */
|
||||
.qr-overlay {
|
||||
display: none;
|
||||
@@ -259,7 +222,6 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
.qr-overlay--visible { display: flex; }
|
||||
.qr-overlay__img--qr { width: 260px; height: 260px; border-radius: 16px; box-shadow: 0 20px 60px rgba(0,0,0,0.3); background:#fff; }
|
||||
.qr-overlay__img--bar { width: 300px; height: 176px; border-radius: 16px; box-shadow: 0 20px 60px rgba(0,0,0,0.3); background:#fff; }
|
||||
/* 体检须知 */
|
||||
.tips-card {
|
||||
@@ -376,8 +338,7 @@
|
||||
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><path d="M6 9l6 6 6-6"/></svg>
|
||||
</button>
|
||||
<div class="demo-select__menu hidden" id="demoMenu">
|
||||
<div class="demo-select__item demo-select__item--active" data-status="pending" onclick="setDemoStatus('pending')">待体检<span class="check">✓</span></div>
|
||||
<div class="demo-select__item" data-status="done" onclick="setDemoStatus('done')">已完成<span class="check">✓</span></div>
|
||||
<div class="demo-select__item demo-select__item--active" data-status="pending" onclick="setDemoStatus('pending')">已预约<span class="check">✓</span></div>
|
||||
<div class="demo-select__item" data-status="none" onclick="setDemoStatus('none')">无预约信息<span class="check">✓</span></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -394,54 +355,24 @@
|
||||
<!-- ======================= 常规体检 · 待体检 ======================= -->
|
||||
<div class="panel" data-type="routine" data-status="pending">
|
||||
<div class="person-card" id="codeRoutine">
|
||||
<div class="person-card__header">
|
||||
<div class="section-title" style="margin-bottom:0">体检签到码</div>
|
||||
<!-- [交互] 点击右上角「条形码/二维码」双选项卡切换签到码展示 -->
|
||||
<div class="code-switch">
|
||||
<button class="code-switch__opt code-switch__opt--active" type="button" id="codeRoutineTabBar" onclick="setCodeMode('codeRoutine', 'bar')">条形码</button>
|
||||
<button class="code-switch__opt" type="button" id="codeRoutineTabQr" onclick="setCodeMode('codeRoutine', 'qr')">二维码</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qrcode-wrap code-only--bar">
|
||||
<div class="qrcode-wrap">
|
||||
<!-- [交互] 点击条码放大展示 -->
|
||||
<svg class="code-img code-img--bar" onclick="openCodeOverlay('codeRoutine')" viewBox="0 0 200 110" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg class="code-img code-img--bar" onclick="openCodeOverlay()" viewBox="0 0 200 110" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="200" height="110" fill="#fff"/>
|
||||
<rect x="10" y="10" width="3" height="72" fill="#1a1a1a"/><rect x="16" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="20" y="10" width="2" height="72" fill="#1a1a1a"/><rect x="25" y="10" width="4" height="72" fill="#1a1a1a"/><rect x="32" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="36" y="10" width="2.5" height="72" fill="#1a1a1a"/><rect x="41" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="45" y="10" width="3" height="72" fill="#1a1a1a"/><rect x="50" y="10" width="2" height="72" fill="#1a1a1a"/><rect x="54" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="58" y="10" width="4" height="72" fill="#1a1a1a"/><rect x="65" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="69" y="10" width="2.5" height="72" fill="#1a1a1a"/><rect x="74" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="78" y="10" width="3" height="72" fill="#1a1a1a"/><rect x="83" y="10" width="2" height="72" fill="#1a1a1a"/><rect x="87" y="10" width="4" height="72" fill="#1a1a1a"/><rect x="94" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="98" y="10" width="2" height="72" fill="#1a1a1a"/><rect x="102" y="10" width="3" height="72" fill="#1a1a1a"/><rect x="107" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="111" y="10" width="4" height="72" fill="#1a1a1a"/><rect x="118" y="10" width="2" height="72" fill="#1a1a1a"/><rect x="122" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="126" y="10" width="3" height="72" fill="#1a1a1a"/><rect x="131" y="10" width="2.5" height="72" fill="#1a1a1a"/><rect x="136" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="140" y="10" width="4" height="72" fill="#1a1a1a"/><rect x="147" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="151" y="10" width="2" height="72" fill="#1a1a1a"/><rect x="155" y="10" width="3" height="72" fill="#1a1a1a"/><rect x="160" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="164" y="10" width="2.5" height="72" fill="#1a1a1a"/><rect x="169" y="10" width="4" height="72" fill="#1a1a1a"/><rect x="176" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="180" y="10" width="2" height="72" fill="#1a1a1a"/><rect x="184" y="10" width="3" height="72" fill="#1a1a1a"/><rect x="189" y="10" width="2.5" height="72" fill="#1a1a1a"/>
|
||||
<text x="100" y="97" text-anchor="middle" font-size="10" font-family="monospace" fill="#666">TJ2026032300871</text>
|
||||
</svg>
|
||||
<span class="qrcode-wrap__hint">点击条码可放大查看</span>
|
||||
</div>
|
||||
<div class="qrcode-wrap code-only--qr">
|
||||
<!-- [交互] 点击二维码放大展示 -->
|
||||
<svg class="code-img code-img--qr" onclick="openCodeOverlay('codeRoutine')" viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="160" height="160" fill="#fff"/>
|
||||
<rect x="12" y="12" width="40" height="40" rx="4" fill="#1a1a1a"/><rect x="18" y="18" width="28" height="28" rx="2" fill="#fff"/><rect x="24" y="24" width="16" height="16" rx="2" fill="#1a1a1a"/>
|
||||
<rect x="108" y="12" width="40" height="40" rx="4" fill="#1a1a1a"/><rect x="114" y="18" width="28" height="28" rx="2" fill="#fff"/><rect x="120" y="24" width="16" height="16" rx="2" fill="#1a1a1a"/>
|
||||
<rect x="12" y="108" width="40" height="40" rx="4" fill="#1a1a1a"/><rect x="18" y="114" width="28" height="28" rx="2" fill="#fff"/><rect x="24" y="120" width="16" height="16" rx="2" fill="#1a1a1a"/>
|
||||
<rect x="60" y="12" width="8" height="8" fill="#1a1a1a"/><rect x="76" y="12" width="8" height="8" fill="#1a1a1a"/><rect x="92" y="12" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="60" y="24" width="8" height="8" fill="#1a1a1a"/><rect x="84" y="24" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="68" y="36" width="8" height="8" fill="#1a1a1a"/><rect x="92" y="36" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="12" y="60" width="8" height="8" fill="#1a1a1a"/><rect x="28" y="60" width="8" height="8" fill="#1a1a1a"/><rect x="44" y="60" width="8" height="8" fill="#1a1a1a"/><rect x="68" y="60" width="8" height="8" fill="#1a1a1a"/><rect x="92" y="60" width="8" height="8" fill="#1a1a1a"/><rect x="108" y="60" width="8" height="8" fill="#1a1a1a"/><rect x="132" y="60" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="20" y="72" width="8" height="8" fill="#1a1a1a"/><rect x="44" y="72" width="8" height="8" fill="#1a1a1a"/><rect x="60" y="72" width="8" height="8" fill="#1a1a1a"/><rect x="84" y="72" width="8" height="8" fill="#1a1a1a"/><rect x="108" y="72" width="8" height="8" fill="#1a1a1a"/><rect x="124" y="72" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="12" y="84" width="8" height="8" fill="#1a1a1a"/><rect x="36" y="84" width="8" height="8" fill="#1a1a1a"/><rect x="60" y="84" width="8" height="8" fill="#1a1a1a"/><rect x="76" y="84" width="8" height="8" fill="#1a1a1a"/><rect x="100" y="84" width="8" height="8" fill="#1a1a1a"/><rect x="140" y="84" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="28" y="96" width="8" height="8" fill="#1a1a1a"/><rect x="52" y="96" width="8" height="8" fill="#1a1a1a"/><rect x="68" y="96" width="8" height="8" fill="#1a1a1a"/><rect x="92" y="96" width="8" height="8" fill="#1a1a1a"/><rect x="116" y="96" width="8" height="8" fill="#1a1a1a"/><rect x="140" y="96" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="60" y="108" width="8" height="8" fill="#1a1a1a"/><rect x="76" y="108" width="8" height="8" fill="#1a1a1a"/><rect x="100" y="108" width="8" height="8" fill="#1a1a1a"/><rect x="124" y="108" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="60" y="120" width="8" height="8" fill="#1a1a1a"/><rect x="84" y="120" width="8" height="8" fill="#1a1a1a"/><rect x="108" y="120" width="8" height="8" fill="#1a1a1a"/><rect x="140" y="120" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="60" y="132" width="8" height="8" fill="#1a1a1a"/><rect x="76" y="132" width="8" height="8" fill="#1a1a1a"/><rect x="92" y="132" width="8" height="8" fill="#1a1a1a"/><rect x="116" y="132" width="8" height="8" fill="#1a1a1a"/><rect x="140" y="132" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="68" y="140" width="8" height="8" fill="#1a1a1a"/><rect x="100" y="140" width="8" height="8" fill="#1a1a1a"/><rect x="132" y="140" width="8" height="8" fill="#1a1a1a"/>
|
||||
</svg>
|
||||
<span class="qrcode-wrap__hint">点击二维码可放大查看</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="section-title">常规体检</div>
|
||||
<div class="summary-list">
|
||||
<div class="summary-item"><div class="summary-item__label">体检医院</div><div class="summary-item__value">宁夏宝石花医院</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检地址</div><div class="summary-item__value">银川市西夏区怀远路148号</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">预约日期</div><div class="summary-item__value">2026-03-23</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检员工</div><div class="summary-item__value">张旭</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">单位部门</div><div class="summary-item__value">采油一厂·xx作业区</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">状态</div><div class="summary-item__value" style="color:#fa8c16;">待体检</div></div>
|
||||
</div>
|
||||
<div class="summary-item"><div class="summary-item__label">单位部门</div><div class="summary-item__value">采油一厂·xx作业区</div></div> </div>
|
||||
</div>
|
||||
<div class="progress-card">
|
||||
<!-- [交互] 点击切换已检/未检 Tab -->
|
||||
@@ -460,11 +391,10 @@
|
||||
<div class="section-title">常规体检</div>
|
||||
<div class="summary-list">
|
||||
<div class="summary-item"><div class="summary-item__label">体检医院</div><div class="summary-item__value">宁夏宝石花医院</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检地址</div><div class="summary-item__value">银川市西夏区怀远路148号</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">预约日期</div><div class="summary-item__value">2026-03-23</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检员工</div><div class="summary-item__value">张旭</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">单位部门</div><div class="summary-item__value">采油一厂·xx作业区</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">状态</div><div class="summary-item__value" style="color:#52c41a;">已参检</div></div>
|
||||
</div>
|
||||
<div class="summary-item"><div class="summary-item__label">单位部门</div><div class="summary-item__value">采油一厂·xx作业区</div></div> </div>
|
||||
</div>
|
||||
<div class="progress-card">
|
||||
<!-- [交互] 点击切换已检/未检 Tab -->
|
||||
@@ -499,9 +429,7 @@
|
||||
<div class="summary-item"><div class="summary-item__label">体检员工</div><div class="summary-item__value">刘韵琴</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检地址</div><div class="summary-item__value">银川市西夏区怀远路148号</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检日期</div><div class="summary-item__value">2026年3月23日</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检项目</div><div class="summary-item__value">胃肠镜体检</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">状态</div><div class="summary-item__value" style="color:#fa8c16;">待体检</div></div>
|
||||
</div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检项目</div><div class="summary-item__value">胃肠镜体检</div></div> </div>
|
||||
</div>
|
||||
<div class="tips-card">
|
||||
<div class="tips-card__title">体检须知</div>
|
||||
@@ -523,9 +451,7 @@
|
||||
<div class="summary-item"><div class="summary-item__label">体检员工</div><div class="summary-item__value">刘韵琴</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检地址</div><div class="summary-item__value">银川市西夏区怀远路148号</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检日期</div><div class="summary-item__value">2026年3月23日</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检项目</div><div class="summary-item__value">胃肠镜体检</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">状态</div><div class="summary-item__value" style="color:#52c41a;">已参检</div></div>
|
||||
</div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检项目</div><div class="summary-item__value">胃肠镜体检</div></div> </div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -551,9 +477,7 @@
|
||||
<div class="summary-item"><div class="summary-item__label">体检员工</div><div class="summary-item__value">刘韵琴</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检地址</div><div class="summary-item__value">银川市西夏区怀远路148号</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检日期</div><div class="summary-item__value">2026年3月23日</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检项目</div><div class="summary-item__value">冠脉CTA体检</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">状态</div><div class="summary-item__value" style="color:#fa8c16;">待体检</div></div>
|
||||
</div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检项目</div><div class="summary-item__value">冠脉CTA体检</div></div> </div>
|
||||
</div>
|
||||
<div class="tips-card">
|
||||
<div class="tips-card__title">体检须知</div>
|
||||
@@ -575,9 +499,7 @@
|
||||
<div class="summary-item"><div class="summary-item__label">体检员工</div><div class="summary-item__value">刘韵琴</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检地址</div><div class="summary-item__value">银川市西夏区怀远路148号</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检日期</div><div class="summary-item__value">2026年3月23日</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检项目</div><div class="summary-item__value">冠脉CTA体检</div></div>
|
||||
<div class="summary-item"><div class="summary-item__label">状态</div><div class="summary-item__value" style="color:#52c41a;">已参检</div></div>
|
||||
</div>
|
||||
<div class="summary-item"><div class="summary-item__label">体检项目</div><div class="summary-item__value">冠脉CTA体检</div></div> </div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -599,28 +521,11 @@
|
||||
<!-- 签到码放大遮罩 -->
|
||||
<div class="qr-overlay" id="qrOverlay" onclick="this.classList.remove('qr-overlay--visible')">
|
||||
<div onclick="event.stopPropagation()">
|
||||
<svg class="qr-overlay__img--bar" id="ovlBarcode" viewBox="0 0 200 110" xmlns="http://www.w3.org/2000/svg" style="display:none;">
|
||||
<svg class="qr-overlay__img--bar" id="ovlBarcode" viewBox="0 0 200 110" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="200" height="110" fill="#fff"/>
|
||||
<rect x="10" y="10" width="3" height="72" fill="#1a1a1a"/><rect x="16" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="20" y="10" width="2" height="72" fill="#1a1a1a"/><rect x="25" y="10" width="4" height="72" fill="#1a1a1a"/><rect x="32" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="36" y="10" width="2.5" height="72" fill="#1a1a1a"/><rect x="41" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="45" y="10" width="3" height="72" fill="#1a1a1a"/><rect x="50" y="10" width="2" height="72" fill="#1a1a1a"/><rect x="54" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="58" y="10" width="4" height="72" fill="#1a1a1a"/><rect x="65" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="69" y="10" width="2.5" height="72" fill="#1a1a1a"/><rect x="74" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="78" y="10" width="3" height="72" fill="#1a1a1a"/><rect x="83" y="10" width="2" height="72" fill="#1a1a1a"/><rect x="87" y="10" width="4" height="72" fill="#1a1a1a"/><rect x="94" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="98" y="10" width="2" height="72" fill="#1a1a1a"/><rect x="102" y="10" width="3" height="72" fill="#1a1a1a"/><rect x="107" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="111" y="10" width="4" height="72" fill="#1a1a1a"/><rect x="118" y="10" width="2" height="72" fill="#1a1a1a"/><rect x="122" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="126" y="10" width="3" height="72" fill="#1a1a1a"/><rect x="131" y="10" width="2.5" height="72" fill="#1a1a1a"/><rect x="136" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="140" y="10" width="4" height="72" fill="#1a1a1a"/><rect x="147" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="151" y="10" width="2" height="72" fill="#1a1a1a"/><rect x="155" y="10" width="3" height="72" fill="#1a1a1a"/><rect x="160" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="164" y="10" width="2.5" height="72" fill="#1a1a1a"/><rect x="169" y="10" width="4" height="72" fill="#1a1a1a"/><rect x="176" y="10" width="1.5" height="72" fill="#1a1a1a"/><rect x="180" y="10" width="2" height="72" fill="#1a1a1a"/><rect x="184" y="10" width="3" height="72" fill="#1a1a1a"/><rect x="189" y="10" width="2.5" height="72" fill="#1a1a1a"/>
|
||||
<text x="100" y="97" text-anchor="middle" font-size="10" font-family="monospace" fill="#666">签到码编号</text>
|
||||
</svg>
|
||||
<svg class="qr-overlay__img--qr" id="ovlQr" viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg" style="display:none;">
|
||||
<rect width="160" height="160" fill="#fff"/>
|
||||
<rect x="12" y="12" width="40" height="40" rx="4" fill="#1a1a1a"/><rect x="18" y="18" width="28" height="28" rx="2" fill="#fff"/><rect x="24" y="24" width="16" height="16" rx="2" fill="#1a1a1a"/>
|
||||
<rect x="108" y="12" width="40" height="40" rx="4" fill="#1a1a1a"/><rect x="114" y="18" width="28" height="28" rx="2" fill="#fff"/><rect x="120" y="24" width="16" height="16" rx="2" fill="#1a1a1a"/>
|
||||
<rect x="12" y="108" width="40" height="40" rx="4" fill="#1a1a1a"/><rect x="18" y="114" width="28" height="28" rx="2" fill="#fff"/><rect x="24" y="120" width="16" height="16" rx="2" fill="#1a1a1a"/>
|
||||
<rect x="60" y="12" width="8" height="8" fill="#1a1a1a"/><rect x="76" y="12" width="8" height="8" fill="#1a1a1a"/><rect x="92" y="12" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="60" y="24" width="8" height="8" fill="#1a1a1a"/><rect x="84" y="24" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="68" y="36" width="8" height="8" fill="#1a1a1a"/><rect x="92" y="36" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="12" y="60" width="8" height="8" fill="#1a1a1a"/><rect x="28" y="60" width="8" height="8" fill="#1a1a1a"/><rect x="44" y="60" width="8" height="8" fill="#1a1a1a"/><rect x="68" y="60" width="8" height="8" fill="#1a1a1a"/><rect x="92" y="60" width="8" height="8" fill="#1a1a1a"/><rect x="108" y="60" width="8" height="8" fill="#1a1a1a"/><rect x="132" y="60" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="20" y="72" width="8" height="8" fill="#1a1a1a"/><rect x="44" y="72" width="8" height="8" fill="#1a1a1a"/><rect x="60" y="72" width="8" height="8" fill="#1a1a1a"/><rect x="84" y="72" width="8" height="8" fill="#1a1a1a"/><rect x="108" y="72" width="8" height="8" fill="#1a1a1a"/><rect x="124" y="72" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="12" y="84" width="8" height="8" fill="#1a1a1a"/><rect x="36" y="84" width="8" height="8" fill="#1a1a1a"/><rect x="60" y="84" width="8" height="8" fill="#1a1a1a"/><rect x="76" y="84" width="8" height="8" fill="#1a1a1a"/><rect x="100" y="84" width="8" height="8" fill="#1a1a1a"/><rect x="140" y="84" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="28" y="96" width="8" height="8" fill="#1a1a1a"/><rect x="52" y="96" width="8" height="8" fill="#1a1a1a"/><rect x="68" y="96" width="8" height="8" fill="#1a1a1a"/><rect x="92" y="96" width="8" height="8" fill="#1a1a1a"/><rect x="116" y="96" width="8" height="8" fill="#1a1a1a"/><rect x="140" y="96" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="60" y="108" width="8" height="8" fill="#1a1a1a"/><rect x="76" y="108" width="8" height="8" fill="#1a1a1a"/><rect x="100" y="108" width="8" height="8" fill="#1a1a1a"/><rect x="124" y="108" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="60" y="120" width="8" height="8" fill="#1a1a1a"/><rect x="84" y="120" width="8" height="8" fill="#1a1a1a"/><rect x="108" y="120" width="8" height="8" fill="#1a1a1a"/><rect x="140" y="120" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="60" y="132" width="8" height="8" fill="#1a1a1a"/><rect x="76" y="132" width="8" height="8" fill="#1a1a1a"/><rect x="92" y="132" width="8" height="8" fill="#1a1a1a"/><rect x="116" y="132" width="8" height="8" fill="#1a1a1a"/><rect x="140" y="132" width="8" height="8" fill="#1a1a1a"/>
|
||||
<rect x="68" y="140" width="8" height="8" fill="#1a1a1a"/><rect x="100" y="140" width="8" height="8" fill="#1a1a1a"/><rect x="132" y="140" width="8" height="8" fill="#1a1a1a"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -668,19 +573,8 @@
|
||||
}
|
||||
});
|
||||
|
||||
// ===== 签到码:条形码 ↔ 二维码切换 =====
|
||||
// [交互] 点击右上角双选项卡切换条形码/二维码,默认条形码,当前模式选项高亮
|
||||
function setCodeMode(cardId, mode) {
|
||||
var isQr = mode === 'qr';
|
||||
document.getElementById(cardId).classList.toggle('person-card--qr', isQr);
|
||||
document.getElementById(cardId + 'TabBar').classList.toggle('code-switch__opt--active', !isQr);
|
||||
document.getElementById(cardId + 'TabQr').classList.toggle('code-switch__opt--active', isQr);
|
||||
}
|
||||
// [交互] 点击签到码放大查看(遮罩跟随当前类型)
|
||||
function openCodeOverlay(cardId) {
|
||||
var isQr = document.getElementById(cardId).classList.contains('person-card--qr');
|
||||
document.getElementById('ovlQr').style.display = isQr ? 'block' : 'none';
|
||||
document.getElementById('ovlBarcode').style.display = isQr ? 'none' : 'block';
|
||||
// [交互] 点击条码放大查看
|
||||
function openCodeOverlay() {
|
||||
document.getElementById('qrOverlay').classList.add('qr-overlay--visible');
|
||||
}
|
||||
|
||||
|
||||
@@ -421,9 +421,9 @@
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<!-- ========== 影像报告 ========== -->
|
||||
<!-- ========== 报告图片 ========== -->
|
||||
<div class="report-section">
|
||||
<div class="report-section__title">影像报告</div>
|
||||
<div class="report-section__title">报告图片</div>
|
||||
<div class="image-section__label">胃镜报告</div>
|
||||
<div class="image-view-link">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
|
||||
|
||||
@@ -83,6 +83,42 @@
|
||||
.trend-entry__go svg { width: 14px; height: 14px; }
|
||||
/* 报告列表 */
|
||||
.section-title { font-size: 16px; font-weight: 700; color: #1a1a1a; margin: 22px 2px 12px; }
|
||||
/* 报告筛选:年份日历 + 体检类型下拉,默认全部 */
|
||||
.filter-bar { display: flex; gap: 10px; margin: 0 2px 14px; position: relative; z-index: 5; }
|
||||
.filter-picker { position: relative; }
|
||||
.filter-picker__trigger {
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
height: 32px; padding: 0 12px; border-radius: 16px;
|
||||
border: 1px solid #e8e8e8; background: #fff;
|
||||
font-size: 13px; color: #1a1a1a; cursor: pointer; transition: all 0.2s;
|
||||
}
|
||||
.filter-picker__trigger--active { border-color: #13c2c2; color: #0f9b9b; font-weight: 600; }
|
||||
.year-panel {
|
||||
position: absolute; top: 38px; left: 0; width: 236px;
|
||||
background: #fff; border-radius: 16px; padding: 12px;
|
||||
border: 1px solid #f0f0f0; box-shadow: 0 12px 32px rgba(0,0,0,0.12); z-index: 10;
|
||||
}
|
||||
.year-panel.hidden, .type-menu.hidden { display: none; }
|
||||
.year-panel__title { font-size: 13px; font-weight: 700; text-align: center; margin-bottom: 10px; }
|
||||
.year-panel__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
|
||||
.year-cell {
|
||||
height: 34px; display: flex; align-items: center; justify-content: center;
|
||||
border-radius: 10px; background: #f7f9fb; font-size: 13px; color: #1a1a1a; cursor: pointer; transition: all 0.2s;
|
||||
}
|
||||
.year-cell.selected { background: #e6fffb; color: #0f9b9b; font-weight: 700; }
|
||||
.type-menu {
|
||||
position: absolute; top: 38px; left: 0; min-width: 132px;
|
||||
background: #fff; border-radius: 14px; padding: 6px;
|
||||
border: 1px solid #f0f0f0; box-shadow: 0 12px 32px rgba(0,0,0,0.12); z-index: 10;
|
||||
}
|
||||
.type-menu__item {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
padding: 9px 12px; border-radius: 10px; font-size: 13px; color: #1a1a1a; cursor: pointer;
|
||||
}
|
||||
.type-menu__item:hover { background: #f7f9fb; }
|
||||
.type-menu__item.selected { background: #e6fffb; color: #0f9b9b; font-weight: 700; }
|
||||
.type-menu__item .check { visibility: hidden; font-size: 12px; }
|
||||
.type-menu__item.selected .check { visibility: visible; }
|
||||
.report-list { display: flex; flex-direction: column; gap: 12px; }
|
||||
.report-item {
|
||||
background: #fff; border-radius: 16px; padding: 16px; display: flex; align-items: center; gap: 14px;
|
||||
@@ -165,9 +201,42 @@
|
||||
|
||||
<!-- 报告列表 -->
|
||||
<div class="section-title">我的历年报告</div>
|
||||
<div class="report-list">
|
||||
<!-- [交互] 报告筛选:年份点开日历面板选择,体检类型下拉选择,默认「全部」,两个条件叠加过滤 -->
|
||||
<div class="filter-bar">
|
||||
<div class="filter-picker">
|
||||
<button class="filter-picker__trigger" type="button" id="yearTrigger" onclick="toggleYearPanel(event)">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
|
||||
<span id="yearTriggerText">全部年份</span>
|
||||
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg>
|
||||
</button>
|
||||
<div class="year-panel hidden" id="yearPanel">
|
||||
<div class="year-panel__title">选择年份</div>
|
||||
<div class="year-panel__grid">
|
||||
<span class="year-cell selected" onclick="pickYear('all', this)">全部</span>
|
||||
<span class="year-cell" onclick="pickYear('2025', this)">2025</span>
|
||||
<span class="year-cell" onclick="pickYear('2024', this)">2024</span>
|
||||
<span class="year-cell" onclick="pickYear('2023', this)">2023</span>
|
||||
<span class="year-cell" onclick="pickYear('2022', this)">2022</span>
|
||||
<span class="year-cell" onclick="pickYear('2021', this)">2021</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-picker">
|
||||
<button class="filter-picker__trigger" type="button" id="typeTrigger" onclick="toggleTypeMenu(event)">
|
||||
<span id="typeTriggerText">全部类型</span>
|
||||
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg>
|
||||
</button>
|
||||
<div class="type-menu hidden" id="typeMenu">
|
||||
<div class="type-menu__item selected" onclick="pickType('all', this)">全部类型<span class="check">✓</span></div>
|
||||
<div class="type-menu__item" onclick="pickType('regular', this)">常规体检<span class="check">✓</span></div>
|
||||
<div class="type-menu__item" onclick="pickType('gastro', this)">胃肠镜体检<span class="check">✓</span></div>
|
||||
<div class="type-menu__item" onclick="pickType('cta', this)">冠脉CTA体检<span class="check">✓</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="report-list" id="reportList">
|
||||
<!-- [交互] 点击跳转至: report-gastro.html(胃肠镜报告) -->
|
||||
<div class="report-item" onclick="location.href='report-gastro.html'">
|
||||
<div class="report-item" data-year="2025" data-type="gastro" onclick="location.href='report-gastro.html'">
|
||||
<div class="report-item__icon" style="background:#e6fffb;color:#08979c;">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
||||
</div>
|
||||
@@ -181,7 +250,7 @@
|
||||
<span class="report-item__arrow">›</span>
|
||||
</div>
|
||||
<!-- [交互] 点击跳转至: report-cta.html(冠脉CTA报告) -->
|
||||
<div class="report-item" onclick="location.href='report-cta.html'">
|
||||
<div class="report-item" data-year="2025" data-type="cta" onclick="location.href='report-cta.html'">
|
||||
<div class="report-item__icon" style="background:#fff1f0;color:#cf1322;">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"/><path d="M3.2 12h5.3l1.5-3 2.5 6 1.5-3h5.3"/></svg>
|
||||
</div>
|
||||
@@ -195,7 +264,7 @@
|
||||
<span class="report-item__arrow">›</span>
|
||||
</div>
|
||||
<!-- [交互] 点击跳转至: report-query.html(常规体检) -->
|
||||
<div class="report-item" onclick="location.href='report-query.html'">
|
||||
<div class="report-item" data-year="2025" data-type="regular" onclick="location.href='report-query.html'">
|
||||
<div class="report-item__icon" style="background:#e6f7ff;color:#096dd9;">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="14" y2="17"/></svg>
|
||||
</div>
|
||||
@@ -209,7 +278,7 @@
|
||||
<span class="report-item__arrow">›</span>
|
||||
</div>
|
||||
<!-- [交互] 点击跳转至: report-query.html(常规体检) -->
|
||||
<div class="report-item" onclick="location.href='report-query.html'">
|
||||
<div class="report-item" data-year="2024" data-type="regular" onclick="location.href='report-query.html'">
|
||||
<div class="report-item__icon" style="background:#e6f7ff;color:#096dd9;">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="14" y2="17"/></svg>
|
||||
</div>
|
||||
@@ -223,7 +292,7 @@
|
||||
<span class="report-item__arrow">›</span>
|
||||
</div>
|
||||
<!-- [交互] 点击跳转至: report-query.html(常规体检) -->
|
||||
<div class="report-item" onclick="location.href='report-query.html'">
|
||||
<div class="report-item" data-year="2023" data-type="regular" onclick="location.href='report-query.html'">
|
||||
<div class="report-item__icon" style="background:#e6f7ff;color:#096dd9;">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="14" y2="17"/></svg>
|
||||
</div>
|
||||
@@ -237,7 +306,7 @@
|
||||
<span class="report-item__arrow">›</span>
|
||||
</div>
|
||||
<!-- [交互] 点击跳转至: report-query.html(常规体检) -->
|
||||
<div class="report-item" onclick="location.href='report-query.html'">
|
||||
<div class="report-item" data-year="2022" data-type="regular" onclick="location.href='report-query.html'">
|
||||
<div class="report-item__icon" style="background:#e6f7ff;color:#096dd9;">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="14" y2="17"/></svg>
|
||||
</div>
|
||||
@@ -251,7 +320,7 @@
|
||||
<span class="report-item__arrow">›</span>
|
||||
</div>
|
||||
<!-- [交互] 点击跳转至: report-query.html(常规体检) -->
|
||||
<div class="report-item" onclick="location.href='report-query.html'">
|
||||
<div class="report-item" data-year="2021" data-type="regular" onclick="location.href='report-query.html'">
|
||||
<div class="report-item__icon" style="background:#e6f7ff;color:#096dd9;">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="14" y2="17"/></svg>
|
||||
</div>
|
||||
@@ -269,5 +338,51 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// 报告筛选:年份日历 + 体检类型下拉,两个条件叠加过滤,默认「全部」
|
||||
var filterYear = 'all';
|
||||
var filterType = 'all';
|
||||
function toggleYearPanel(e) {
|
||||
e.stopPropagation();
|
||||
closeTypeMenu();
|
||||
document.getElementById('yearPanel').classList.toggle('hidden');
|
||||
}
|
||||
function toggleTypeMenu(e) {
|
||||
e.stopPropagation();
|
||||
closeYearPanel();
|
||||
document.getElementById('typeMenu').classList.toggle('hidden');
|
||||
}
|
||||
function closeYearPanel() { document.getElementById('yearPanel').classList.add('hidden'); }
|
||||
function closeTypeMenu() { document.getElementById('typeMenu').classList.add('hidden'); }
|
||||
function pickYear(year, el) {
|
||||
filterYear = year;
|
||||
el.parentNode.querySelectorAll('.year-cell').forEach(function (c) { c.classList.remove('selected'); });
|
||||
el.classList.add('selected');
|
||||
document.getElementById('yearTriggerText').textContent = year === 'all' ? '全部年份' : year + '年';
|
||||
document.getElementById('yearTrigger').classList.toggle('filter-picker__trigger--active', year !== 'all');
|
||||
closeYearPanel();
|
||||
applyReportFilter();
|
||||
}
|
||||
function pickType(type, el) {
|
||||
filterType = type;
|
||||
el.parentNode.querySelectorAll('.type-menu__item').forEach(function (i) { i.classList.remove('selected'); });
|
||||
el.classList.add('selected');
|
||||
document.getElementById('typeTriggerText').textContent = el.textContent.replace('✓', '').trim();
|
||||
document.getElementById('typeTrigger').classList.toggle('filter-picker__trigger--active', type !== 'all');
|
||||
closeTypeMenu();
|
||||
applyReportFilter();
|
||||
}
|
||||
function applyReportFilter() {
|
||||
document.querySelectorAll('#reportList .report-item').forEach(function (item) {
|
||||
var show = (filterYear === 'all' || item.dataset.year === filterYear) &&
|
||||
(filterType === 'all' || item.dataset.type === filterType);
|
||||
item.style.display = show ? 'flex' : 'none';
|
||||
});
|
||||
}
|
||||
// 点击弹层外部收起面板
|
||||
document.addEventListener('click', function (e) {
|
||||
if (!e.target.closest('.filter-picker')) { closeYearPanel(); closeTypeMenu(); }
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||