Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fc599fabe | ||
|
|
80b0c78bdd | ||
|
|
4767c24d3d | ||
|
|
44d7d0b219 | ||
|
|
8e6c10f0bc | ||
|
|
a900886061 | ||
|
|
71ddc7fa0a | ||
|
|
63407a20c2 |
@@ -238,7 +238,7 @@
|
||||
- 员工信息:姓名(张晓红)、性别、年龄、部门
|
||||
- 数据对比表:初始数据 / 目标数据 / 当前数据(体重、BMI、体脂率、腰围)
|
||||
- 变化指标:绿色显示下降数值
|
||||
- 体重记录列表:按时间倒序,每条显示时间、体重、体脂率、腰围、来源标签(身高秤、蓝牙称、体脂仪、自记)
|
||||
- 体重记录列表:按时间倒序,每条显示时间、体重、体脂率、腰围、来源标签(体重秤、蓝牙称、体脂仪、自记)
|
||||
|
||||
**交互说明:**
|
||||
- 点击返回:返回体重记录页
|
||||
|
||||
@@ -158,7 +158,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
<div class="record-item__metric"><div class="record-item__metric-label">体重</div><div class="record-item__metric-val">66.8<span class="record-item__metric-unit">kg</span></div></div>
|
||||
<div class="record-item__metric"><div class="record-item__metric-label">体脂率</div><div class="record-item__metric-val">29.1<span class="record-item__metric-unit">%</span></div></div>
|
||||
<div class="record-item__metric"><div class="record-item__metric-label">腰围</div><div class="record-item__metric-val">80.5<span class="record-item__metric-unit">cm</span></div></div>
|
||||
<div class="record-item__source"><span class="source-badge source-badge--scale">身高秤</span></div>
|
||||
<div class="record-item__source"><span class="source-badge source-badge--scale">体重秤</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -129,7 +129,8 @@ function initTabLinks() {
|
||||
professional: '../professional',
|
||||
operator: '../operator',
|
||||
onsite: '../onsite',
|
||||
admin: '../admin'
|
||||
admin: '../admin',
|
||||
nutritionist: '../nutritionist'
|
||||
};
|
||||
var base = roleBaseMap[role] || '../expert';
|
||||
document.getElementById('link-workbench').href = base + '/workbench/index.html';
|
||||
|
||||
@@ -265,7 +265,8 @@ function initTabLinks() {
|
||||
professional: '../professional',
|
||||
operator: '../operator',
|
||||
onsite: '../onsite',
|
||||
admin: '../admin'
|
||||
admin: '../admin',
|
||||
nutritionist: '../nutritionist'
|
||||
};
|
||||
var base = roleBaseMap[role] || '../expert';
|
||||
document.getElementById('link-workbench').href = base + '/workbench/index.html';
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>营养知识详情 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #fff; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.nav-bar { height: 44px; display: flex; align-items: center; padding: 0 16px; background: #fff; border-bottom: 1px solid #f0f0f0; flex-shrink: 0; position: relative; }
|
||||
.back-btn { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<div class="nav-bar">
|
||||
<button class="back-btn" onclick="window.location.href='./index.html'">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title" id="kd-nav-title">知识详情</span>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content" style="padding:16px;">
|
||||
<div id="kd-content" style="background:#fff;border-radius:16px;padding:20px;box-shadow:0 1px 6px rgba(0,0,0,0.06);"></div>
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 营养知识库数据集合 */
|
||||
var KB_DATA = {
|
||||
'pyramid': {
|
||||
icon: '🥗', bg: '#f6ffed', title: '中国居民膳食宝塔(2022)', cat: '膳食营养', date: '2026-03-15',
|
||||
summary: '膳食宝塔是中国居民平衡膳食的指导框架,将食物分为五大类,按推荐摄入量由多到少排列,是制定食谱与营养指导的基础依据。',
|
||||
items: [
|
||||
{ color: '#52c41a', name: '谷薯类', desc: '每日 250-400g,其中全谷物和杂豆 50-150g,薯类 50-100g。谷类是膳食能量的主要来源,建议粗细搭配。' },
|
||||
{ color: '#1677ff', name: '蔬菜水果', desc: '每日蔬菜 300-500g(深色蔬菜占一半),水果 200-350g。保证维生素、矿物质和膳食纤维摄入。' },
|
||||
{ color: '#fa8c16', name: '畜禽鱼蛋', desc: '每日畜禽肉 40-75g、水产品 40-75g、蛋类 40-50g。优先选择鱼禽,减少肥肉和加工肉制品。' },
|
||||
{ color: '#722ed1', name: '奶豆坚果', desc: '每日奶及奶制品 300-500g,大豆及坚果 25-35g。是优质蛋白和钙的重要来源。' }
|
||||
]
|
||||
},
|
||||
'macro': {
|
||||
icon: '🍚', bg: '#e6f4ff', title: '三大营养素摄入指南', cat: '膳食营养', date: '2026-03-10',
|
||||
summary: '蛋白质、脂肪、碳水化合物是人体必需的三大产能营养素,合理配比是维持健康体重和代谢功能的关键。',
|
||||
items: [
|
||||
{ color: '#1677ff', name: '碳水化合物', desc: '供能比 50-65%。优先选择全谷物、杂豆、薯类等复合碳水,限制添加糖摄入(每日<25g)。' },
|
||||
{ color: '#52c41a', name: '蛋白质', desc: '供能比 15-20%。优质蛋白来源包括鱼、禽、蛋、奶、豆制品。轻体力成人每日约 1.0g/kg 体重。' },
|
||||
{ color: '#fa8c16', name: '脂肪', desc: '供能比 20-30%。优先不饱和脂肪酸(橄榄油、坚果、鱼类),限制饱和脂肪(<10%)和反式脂肪(<1%)。' }
|
||||
]
|
||||
},
|
||||
'vitamin': {
|
||||
icon: '🍎', bg: '#fff7e6', title: '维生素与矿物质需求', cat: '膳食营养', date: '2026-03-05',
|
||||
summary: '维生素和矿物质虽然需求量小,却是维持正常生理功能不可或缺的微量营养素,缺乏时会出现特定症状。',
|
||||
items: [
|
||||
{ color: '#fa8c16', name: '维生素 C', desc: '每日 100mg。来源:新鲜果蔬(猕猴桃、橙子、青椒)。缺乏可致牙龈出血、伤口愈合不良。' },
|
||||
{ color: '#1677ff', name: '钙', desc: '每日 800-1000mg。来源:奶制品、豆制品、绿叶菜。缺乏可致骨质疏松、肌肉痉挛。' },
|
||||
{ color: '#ff4d4f', name: '铁', desc: '男性每日 12mg、女性 20mg。来源:动物肝脏、瘦肉、动物血。缺乏可致缺铁性贫血。' }
|
||||
]
|
||||
},
|
||||
'fatloss': {
|
||||
icon: '🏃', bg: '#f6ffed', title: '科学减脂饮食原则', cat: '减脂控糖', date: '2026-02-28',
|
||||
summary: '减脂的核心是热量缺口,但必须在保证营养均衡的前提下进行,避免极端节食导致肌肉流失和代谢下降。',
|
||||
items: [
|
||||
{ color: '#52c41a', name: '热量缺口', desc: '每日热量缺口 300-500kcal,减重速度以每周 0.5-1kg 为宜。避免过度节食(不低于基础代谢)。' },
|
||||
{ color: '#1677ff', name: '高蛋白饮食', desc: '蛋白质供能比可提高至 20-30%,增加饱腹感并减少肌肉流失。选择鸡胸、鱼虾、蛋白、豆制品。' },
|
||||
{ color: '#fa8c16', name: '控制精制碳水', desc: '减少白米饭、白面包等精制碳水,替换为全谷物、杂豆,稳定血糖、增强饱腹感。' }
|
||||
]
|
||||
},
|
||||
'lowgi': {
|
||||
icon: '🍬', bg: '#e6f4ff', title: '低 GI 饮食控糖策略', cat: '减脂控糖', date: '2026-02-20',
|
||||
summary: '低升糖指数(GI)饮食可延缓血糖上升速度,是糖尿病管理和预防的重要饮食策略。',
|
||||
items: [
|
||||
{ color: '#1677ff', name: '食物选择', desc: '优先低 GI 食物:全谷物、豆类、大部分蔬菜、低糖水果。避免精制米面、含糖饮料、糕点。' },
|
||||
{ color: '#52c41a', name: '进餐顺序', desc: '先吃蔬菜和蛋白质,再吃主食,可显著降低餐后血糖峰值,改善血糖控制。' },
|
||||
{ color: '#fa8c16', name: '烹饪方式', desc: '主食不要煮得过烂,粗细搭配;避免勾芡、油炸;控制每餐主食总量,少量多餐。' }
|
||||
]
|
||||
},
|
||||
'hyperlipid': {
|
||||
icon: '🫀', bg: '#fff7e6', title: '高血脂饮食管理', cat: '慢性病营养', date: '2026-03-01',
|
||||
summary: '高血脂是动脉粥样硬化的重要危险因素,饮食管理重点是限制饱和脂肪和反式脂肪,增加膳食纤维。',
|
||||
items: [
|
||||
{ color: '#ff4d4f', name: '限制饱和脂肪', desc: '每日饱和脂肪<总能量10%。减少肥肉、动物内脏、黄油、椰子油,选择瘦肉和低脂奶制品。' },
|
||||
{ color: '#fa8c16', name: '杜绝反式脂肪', desc: '避免人造黄油、植脂末、油炸食品、起酥点心。反式脂肪显著升高 LDL-C,增加心血管风险。' },
|
||||
{ color: '#52c41a', name: '增加膳食纤维', desc: '每日 25-30g 膳食纤维。多吃燕麦、豆类、蔬菜、水果,可降低胆固醇吸收。' }
|
||||
]
|
||||
},
|
||||
'uric': {
|
||||
icon: '🦴', bg: '#fff1f0', title: '高尿酸人群饮食禁忌', cat: '慢性病营养', date: '2026-02-15',
|
||||
summary: '高尿酸血症是痛风的生化基础,通过限制高嘌呤食物、增加水分摄入可有效降低尿酸水平。',
|
||||
items: [
|
||||
{ color: '#ff4d4f', name: '限制高嘌呤食物', desc: '避免动物内脏、浓肉汤、海鲜(沙丁鱼、贝类)、啤酒。嘌呤>150mg/100g 的食物应严格限制。' },
|
||||
{ color: '#fa8c16', name: '低嘌呤食物选择', desc: '优先选择蛋类、奶类、蔬菜、水果、谷物。肉类焯水后再烹饪可减少嘌呤含量。' },
|
||||
{ color: '#1677ff', name: '多饮水', desc: '每日饮水 2000ml 以上,促进尿酸排泄。避免含糖饮料和酒精,尤其是啤酒和白酒。' }
|
||||
]
|
||||
},
|
||||
'safety': {
|
||||
icon: '🧪', bg: '#f6ffed', title: '食品添加剂使用规范', cat: '食品安全', date: '2026-02-25',
|
||||
summary: '食品添加剂在合规使用范围内是安全的,了解常见添加剂的用途和限量有助于科学评估食品安全。',
|
||||
items: [
|
||||
{ color: '#52c41a', name: '防腐剂', desc: '如苯甲酸钠、山梨酸钾。用于抑制微生物生长,延长保质期。在规定限量内使用安全。' },
|
||||
{ color: '#1677ff', name: '抗氧化剂', desc: '如 BHA、BHT、维生素 E。防止油脂氧化酸败,常用于食用油和坚果制品。' },
|
||||
{ color: '#fa8c16', name: '着色剂', desc: '如焦糖色、胭脂红。用于改善食品色泽。天然色素(姜黄、红曲)安全性更高。' }
|
||||
]
|
||||
},
|
||||
'trace': {
|
||||
icon: '🔍', bg: '#e6f4ff', title: '食材溯源与质量安全', cat: '食品安全', date: '2026-02-10',
|
||||
summary: '食材溯源是通过溯源码记录食材从种植养殖、加工、运输到餐桌的全链路信息,保障食品安全可追溯。',
|
||||
items: [
|
||||
{ color: '#1677ff', name: '溯源码体系', desc: '每一批次食材赋予唯一溯源码,关联产地、检测报告、流转节点,实现一物一码、全程可查。' },
|
||||
{ color: '#52c41a', name: '质量检测节点', desc: '毛菜入库时进行农残/重金属/微生物检测,净菜加工后二次质检,合格品方可进入厨房。' },
|
||||
{ color: '#fa8c16', name: '异常处置', desc: '检测不合格的食材立即隔离并追溯同批次产品,防止问题食材流入餐桌。' }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
/* 页面加载时根据URL参数渲染知识详情 */
|
||||
function renderDetail() {
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
var key = params.get('key') || 'pyramid';
|
||||
var d = KB_DATA[key];
|
||||
if (!d) d = KB_DATA['pyramid'];
|
||||
|
||||
document.getElementById('kd-nav-title').textContent = d.title;
|
||||
|
||||
var itemsHtml = d.items.map(function(it) {
|
||||
return '<div style="background:#f7f8fa;border-radius:10px;padding:14px;margin-bottom:12px;">' +
|
||||
'<div style="font-size:13px;font-weight:600;color:' + it.color + ';margin-bottom:6px;">' + it.name + '</div>' +
|
||||
'<div style="font-size:13px;color:#444;line-height:1.7;">' + it.desc + '</div>' +
|
||||
'</div>';
|
||||
}).join('');
|
||||
|
||||
document.getElementById('kd-content').innerHTML =
|
||||
'<div style="display:flex;align-items:center;gap:12px;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid #f5f5f5;">' +
|
||||
'<div style="width:48px;height:48px;border-radius:12px;background:' + d.bg + ';display:flex;align-items:center;justify-content:center;font-size:24px;">' + d.icon + '</div>' +
|
||||
'<div><div style="font-size:17px;font-weight:700;color:#1a1a1a;">' + d.title + '</div><div style="font-size:12px;color:#999;margin-top:3px;">' + d.cat + ' · 更新于 ' + d.date + '</div></div>' +
|
||||
'</div>' +
|
||||
'<div style="font-size:15px;font-weight:700;color:#1a1a1a;margin-bottom:8px;">概述</div>' +
|
||||
'<div style="font-size:14px;color:#444;line-height:1.8;margin-bottom:16px;">' + d.summary + '</div>' +
|
||||
'<div style="font-size:15px;font-weight:700;color:#1a1a1a;margin-bottom:8px;">主要内容</div>' +
|
||||
itemsHtml;
|
||||
}
|
||||
|
||||
renderDetail();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,153 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>营养师 - 知识库 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #fff; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
.sub-tabs { display: flex; gap: 8px; padding: 10px 16px; background: #fff; flex-shrink: 0; }
|
||||
.sub-tab { font-size: 12px; padding: 4px 14px; border-radius: 16px; background: #f5f5f5; color: #666; cursor: pointer; transition: all 0.2s; white-space: nowrap; }
|
||||
.sub-tab.active { background: #e6f4ff; color: #1677ff; font-weight: 600; }
|
||||
.tab-bar { height: 83px; background: #fff; border-top: 1px solid #e8e8e8; display: flex; align-items: flex-start; padding-top: 8px; flex-shrink: 0; }
|
||||
.tab-item { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; cursor: pointer; padding: 4px 0; position: relative; text-decoration: none; }
|
||||
.tab-item .tab-icon { font-size: 22px; line-height: 1; }
|
||||
.tab-item .tab-label { font-size: 10px; color: #999; font-weight: 500; }
|
||||
.tab-item.active .tab-label { color: #1677ff; }
|
||||
.tab-badge { position: absolute; top: 2px; right: 18px; background: #ff4d4f; color: #fff; font-size: 10px; font-weight: 700; min-width: 16px; height: 16px; border-radius: 8px; display: flex; align-items: center; justify-content: center; padding: 0 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 蓝色渐变头部 -->
|
||||
<div style="background:linear-gradient(135deg,#1677ff,#0958d9);padding:16px 20px 20px;flex-shrink:0;">
|
||||
<div style="color:rgba(255,255,255,0.75);font-size:12px;margin-bottom:2px;">营养专业参考</div>
|
||||
<div style="color:#fff;font-size:20px;font-weight:700;">知识库</div>
|
||||
</div>
|
||||
|
||||
<!-- 子分类Tab -->
|
||||
<div class="sub-tabs">
|
||||
<div class="sub-tab active" onclick="switchKbTab(this,'kb-diet')">膳食营养</div>
|
||||
<div class="sub-tab" onclick="switchKbTab(this,'kb-weight')">减脂控糖</div>
|
||||
<div class="sub-tab" onclick="switchKbTab(this,'kb-chronic')">慢性病营养</div>
|
||||
<div class="sub-tab" onclick="switchKbTab(this,'kb-safe')">食品安全</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
<!-- 膳食营养 -->
|
||||
<div id="kb-diet">
|
||||
<div style="padding:12px 16px 0;">
|
||||
<div style="background:#fff;border-radius:10px;padding:12px 14px;display:flex;align-items:center;gap:10px;box-shadow:0 1px 4px rgba(0,0,0,0.06);margin-bottom:10px;cursor:pointer;" onclick="goDetail('pyramid')">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#f6ffed;display:flex;align-items:center;justify-content:center;font-size:22px;flex-shrink:0;">🥗</div>
|
||||
<div style="flex:1;"><div style="font-size:14px;font-weight:600;color:#1a1a1a;">中国居民膳食宝塔(2022)</div><div style="font-size:12px;color:#999;margin-top:3px;">五大类食物推荐摄入量与搭配原则</div></div>
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="#ccc" stroke-width="1.5"><path d="M1 1l5 5-5 5"/></svg>
|
||||
</div>
|
||||
<div style="background:#fff;border-radius:10px;padding:12px 14px;display:flex;align-items:center;gap:10px;box-shadow:0 1px 4px rgba(0,0,0,0.06);margin-bottom:10px;cursor:pointer;" onclick="goDetail('macro')">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#e6f4ff;display:flex;align-items:center;justify-content:center;font-size:22px;flex-shrink:0;">🍚</div>
|
||||
<div style="flex:1;"><div style="font-size:14px;font-weight:600;color:#1a1a1a;">三大营养素摄入指南</div><div style="font-size:12px;color:#999;margin-top:3px;">蛋白质、脂肪、碳水化合物的合理配比</div></div>
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="#ccc" stroke-width="1.5"><path d="M1 1l5 5-5 5"/></svg>
|
||||
</div>
|
||||
<div style="background:#fff;border-radius:10px;padding:12px 14px;display:flex;align-items:center;gap:10px;box-shadow:0 1px 4px rgba(0,0,0,0.06);margin-bottom:10px;cursor:pointer;" onclick="goDetail('vitamin')">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#fff7e6;display:flex;align-items:center;justify-content:center;font-size:22px;flex-shrink:0;">🍎</div>
|
||||
<div style="flex:1;"><div style="font-size:14px;font-weight:600;color:#1a1a1a;">维生素与矿物质需求</div><div style="font-size:12px;color:#999;margin-top:3px;">常见微量营养素的食物来源与缺乏症状</div></div>
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="#ccc" stroke-width="1.5"><path d="M1 1l5 5-5 5"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 减脂控糖 -->
|
||||
<div id="kb-weight" style="display:none;">
|
||||
<div style="padding:12px 16px 0;">
|
||||
<div style="background:#fff;border-radius:10px;padding:12px 14px;display:flex;align-items:center;gap:10px;box-shadow:0 1px 4px rgba(0,0,0,0.06);margin-bottom:10px;cursor:pointer;" onclick="goDetail('fatloss')">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#f6ffed;display:flex;align-items:center;justify-content:center;font-size:22px;flex-shrink:0;">🏃</div>
|
||||
<div style="flex:1;"><div style="font-size:14px;font-weight:600;color:#1a1a1a;">科学减脂饮食原则</div><div style="font-size:12px;color:#999;margin-top:3px;">热量缺口与营养均衡的减脂方案</div></div>
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="#ccc" stroke-width="1.5"><path d="M1 1l5 5-5 5"/></svg>
|
||||
</div>
|
||||
<div style="background:#fff;border-radius:10px;padding:12px 14px;display:flex;align-items:center;gap:10px;box-shadow:0 1px 4px rgba(0,0,0,0.06);margin-bottom:10px;cursor:pointer;" onclick="goDetail('lowgi')">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#e6f4ff;display:flex;align-items:center;justify-content:center;font-size:22px;flex-shrink:0;">🍬</div>
|
||||
<div style="flex:1;"><div style="font-size:14px;font-weight:600;color:#1a1a1a;">低 GI 饮食控糖策略</div><div style="font-size:12px;color:#999;margin-top:3px;">低升糖指数食物选择与餐序调整</div></div>
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="#ccc" stroke-width="1.5"><path d="M1 1l5 5-5 5"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 慢性病营养 -->
|
||||
<div id="kb-chronic" style="display:none;">
|
||||
<div style="padding:12px 16px 0;">
|
||||
<div style="background:#fff;border-radius:10px;padding:12px 14px;display:flex;align-items:center;gap:10px;box-shadow:0 1px 4px rgba(0,0,0,0.06);margin-bottom:10px;cursor:pointer;" onclick="goDetail('hyperlipid')">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#fff7e6;display:flex;align-items:center;justify-content:center;font-size:22px;flex-shrink:0;">🫀</div>
|
||||
<div style="flex:1;"><div style="font-size:14px;font-weight:600;color:#1a1a1a;">高血脂饮食管理</div><div style="font-size:12px;color:#999;margin-top:3px;">限制饱和脂肪与反式脂肪的摄入</div></div>
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="#ccc" stroke-width="1.5"><path d="M1 1l5 5-5 5"/></svg>
|
||||
</div>
|
||||
<div style="background:#fff;border-radius:10px;padding:12px 14px;display:flex;align-items:center;gap:10px;box-shadow:0 1px 4px rgba(0,0,0,0.06);margin-bottom:10px;cursor:pointer;" onclick="goDetail('uric')">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#fff1f0;display:flex;align-items:center;justify-content:center;font-size:22px;flex-shrink:0;">🦴</div>
|
||||
<div style="flex:1;"><div style="font-size:14px;font-weight:600;color:#1a1a1a;">高尿酸人群饮食禁忌</div><div style="font-size:12px;color:#999;margin-top:3px;">嘌呤含量分级与低嘌呤饮食建议</div></div>
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="#ccc" stroke-width="1.5"><path d="M1 1l5 5-5 5"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 食品安全 -->
|
||||
<div id="kb-safe" style="display:none;">
|
||||
<div style="padding:12px 16px 0;">
|
||||
<div style="background:#fff;border-radius:10px;padding:12px 14px;display:flex;align-items:center;gap:10px;box-shadow:0 1px 4px rgba(0,0,0,0.06);margin-bottom:10px;cursor:pointer;" onclick="goDetail('safety')">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#f6ffed;display:flex;align-items:center;justify-content:center;font-size:22px;flex-shrink:0;">🧪</div>
|
||||
<div style="flex:1;"><div style="font-size:14px;font-weight:600;color:#1a1a1a;">食品添加剂使用规范</div><div style="font-size:12px;color:#999;margin-top:3px;">常见添加剂的安全性与使用限量</div></div>
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="#ccc" stroke-width="1.5"><path d="M1 1l5 5-5 5"/></svg>
|
||||
</div>
|
||||
<div style="background:#fff;border-radius:10px;padding:12px 14px;display:flex;align-items:center;gap:10px;box-shadow:0 1px 4px rgba(0,0,0,0.06);margin-bottom:10px;cursor:pointer;" onclick="goDetail('trace')">
|
||||
<div style="width:44px;height:44px;border-radius:10px;background:#e6f4ff;display:flex;align-items:center;justify-content:center;font-size:22px;flex-shrink:0;">🔍</div>
|
||||
<div style="flex:1;"><div style="font-size:14px;font-weight:600;color:#1a1a1a;">食材溯源与质量安全</div><div style="font-size:12px;color:#999;margin-top:3px;">从田间到餐桌的全链路安全把控</div></div>
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="#ccc" stroke-width="1.5"><path d="M1 1l5 5-5 5"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部Tab栏 -->
|
||||
<div class="tab-bar">
|
||||
<a class="tab-item" href="../workbench/index.html"><span class="tab-icon">🏥</span><span class="tab-label">工作台</span><span class="tab-badge">2</span></a>
|
||||
<a class="tab-item active" href="./index.html"><span class="tab-icon">📚</span><span class="tab-label">知识库</span></a>
|
||||
<a class="tab-item" href="../../ai-assistant/index.html"><span class="tab-icon">🤖</span><span class="tab-label">AI助手</span></a>
|
||||
<a class="tab-item" href="../../message/index.html"><span class="tab-icon">💬</span><span class="tab-label">消息</span><span class="tab-badge">2</span></a>
|
||||
<a class="tab-item" href="../profile/index.html"><span class="tab-icon">👤</span><span class="tab-label">我的</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
|
||||
/* 切换知识库分类Tab */
|
||||
function switchKbTab(el, panelId) {
|
||||
el.closest('.sub-tabs').querySelectorAll('.sub-tab').forEach(function(t) { t.classList.remove('active'); });
|
||||
el.classList.add('active');
|
||||
['kb-diet','kb-weight','kb-chronic','kb-safe'].forEach(function(id) {
|
||||
document.getElementById(id).style.display = id === panelId ? 'block' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
/* 跳转到知识详情页 */
|
||||
function goDetail(key) {
|
||||
window.location.href = './detail.html?key=' + key;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,82 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师 - 修改密码 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #fff; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.nav-bar { height: 44px; display: flex; align-items: center; padding: 0 16px; background: #fff; border-bottom: 1px solid #f0f0f0; flex-shrink: 0; position: relative; }
|
||||
.back-btn { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
.btn-primary { background: #1677ff; color: #fff; border: none; border-radius: 10px; padding: 12px 24px; font-size: 15px; font-weight: 600; cursor: pointer; width: 100%; }
|
||||
.modal-center { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.5); z-index: 200; align-items: center; justify-content: center; }
|
||||
.modal-center.active { display: flex; }
|
||||
.modal-box { width: 280px; background: #fff; border-radius: 16px; overflow: hidden; }
|
||||
.modal-box .modal-title { padding: 20px 20px 8px; font-size: 17px; font-weight: 700; text-align: center; color: #1a1a1a; }
|
||||
.modal-box .modal-body { padding: 8px 20px 20px; font-size: 14px; color: #666; text-align: center; line-height: 1.6; }
|
||||
.modal-box .modal-actions { display: flex; border-top: 1px solid #f0f0f0; }
|
||||
.modal-box .modal-actions button { flex: 1; padding: 14px; font-size: 16px; cursor: pointer; background: none; border: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<div class="nav-bar">
|
||||
<button class="back-btn" onclick="location.href='./index.html'">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title">修改密码</span>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content" style="padding:16px;">
|
||||
<div style="background:#fff;border-radius:12px;overflow:hidden;box-shadow:0 1px 6px rgba(0,0,0,0.06);margin-bottom:20px;">
|
||||
<div style="display:flex;align-items:center;padding:14px 16px;border-bottom:1px solid #f5f5f5;">
|
||||
<span style="font-size:14px;color:#999;width:80px;flex-shrink:0;">当前密码</span>
|
||||
<input type="password" placeholder="请输入当前密码" style="flex:1;border:none;font-size:14px;color:#1a1a1a;outline:none;text-align:right;" />
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;padding:14px 16px;border-bottom:1px solid #f5f5f5;">
|
||||
<span style="font-size:14px;color:#999;width:80px;flex-shrink:0;">新密码</span>
|
||||
<input type="password" placeholder="请输入新密码" style="flex:1;border:none;font-size:14px;color:#1a1a1a;outline:none;text-align:right;" />
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;padding:14px 16px;">
|
||||
<span style="font-size:14px;color:#999;width:80px;flex-shrink:0;">确认新密码</span>
|
||||
<input type="password" placeholder="再次输入新密码" style="flex:1;border:none;font-size:14px;color:#1a1a1a;outline:none;text-align:right;" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button onclick="openModal('modal-pwd-saved')" class="btn-primary">保存修改</button>
|
||||
</div>
|
||||
|
||||
<div id="modal-pwd-saved" class="modal-center">
|
||||
<div class="modal-box">
|
||||
<div class="modal-title">修改成功</div>
|
||||
<div class="modal-body">密码已更新,下次登录请使用新密码。</div>
|
||||
<div class="modal-actions">
|
||||
<button onclick="closeModal('modal-pwd-saved');location.href='./index.html'" style="color:#1677ff;font-weight:600;flex:1;padding:14px;font-size:16px;cursor:pointer;background:none;border:none;">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
|
||||
function openModal(id) { var m = document.getElementById(id); if (m) m.classList.add('active'); }
|
||||
function closeModal(id) { var m = document.getElementById(id); if (m) m.classList.remove('active'); }
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,92 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师 - 个人信息设置 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #fff; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.nav-bar { height: 44px; display: flex; align-items: center; padding: 0 16px; background: #fff; border-bottom: 1px solid #f0f0f0; flex-shrink: 0; position: relative; }
|
||||
.back-btn { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.nav-right { margin-left: auto; color: #1677ff; font-size: 14px; cursor: pointer; background: none; border: none; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<div class="nav-bar">
|
||||
<button class="back-btn" onclick="location.href='./index.html'">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title">个人信息设置</span>
|
||||
<button class="nav-right">保存</button>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content" style="padding:16px;">
|
||||
<!-- 头像区 -->
|
||||
<div style="background:#fff;border-radius:12px;padding:20px;margin-bottom:12px;text-align:center;box-shadow:0 1px 6px rgba(0,0,0,0.06);">
|
||||
<div style="position:relative;display:inline-block;">
|
||||
<div style="width:80px;height:80px;border-radius:50%;background:linear-gradient(135deg,#e8f4ff,#bdd7ff);display:flex;align-items:center;justify-content:center;font-size:40px;">🥗</div>
|
||||
<div style="position:absolute;bottom:0;right:0;width:26px;height:26px;background:#1677ff;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:13px;border:2px solid #fff;cursor:pointer;">📷</div>
|
||||
</div>
|
||||
<div style="font-size:13px;color:#999;margin-top:10px;">点击更换头像</div>
|
||||
</div>
|
||||
|
||||
<!-- 擅长领域 -->
|
||||
<div style="font-size:13px;font-weight:600;color:#999;margin:0 4px 8px;">擅长领域</div>
|
||||
<div style="background:#fff;border-radius:12px;padding:14px 16px;box-shadow:0 1px 6px rgba(0,0,0,0.06);margin-bottom:16px;">
|
||||
<div style="display:flex;flex-wrap:wrap;gap:8px;">
|
||||
<div onclick="toggleTag(this)" style="padding:6px 14px;border-radius:16px;font-size:13px;background:#1677ff;color:#fff;border:1px solid #1677ff;cursor:pointer;">减脂</div>
|
||||
<div onclick="toggleTag(this)" style="padding:6px 14px;border-radius:16px;font-size:13px;background:#1677ff;color:#fff;border:1px solid #1677ff;cursor:pointer;">控糖</div>
|
||||
<div onclick="toggleTag(this)" style="padding:6px 14px;border-radius:16px;font-size:13px;background:#1677ff;color:#fff;border:1px solid #1677ff;cursor:pointer;">增肌</div>
|
||||
<div onclick="toggleTag(this)" style="padding:6px 14px;border-radius:16px;font-size:13px;background:#f5f5f5;color:#666;border:1px solid #e8e8e8;cursor:pointer;">高血脂</div>
|
||||
<div onclick="toggleTag(this)" style="padding:6px 14px;border-radius:16px;font-size:13px;background:#f5f5f5;color:#666;border:1px solid #e8e8e8;cursor:pointer;">高尿酸</div>
|
||||
<div onclick="toggleTag(this)" style="padding:6px 14px;border-radius:16px;font-size:13px;background:#f5f5f5;color:#666;border:1px solid #e8e8e8;cursor:pointer;">术后营养</div>
|
||||
<div onclick="toggleTag(this)" style="padding:6px 14px;border-radius:16px;font-size:13px;background:#f5f5f5;color:#666;border:1px solid #e8e8e8;cursor:pointer;">孕期营养</div>
|
||||
</div>
|
||||
<div style="font-size:11px;color:#bbb;margin-top:10px;">点击标签切换选中状态</div>
|
||||
</div>
|
||||
|
||||
<!-- 个人简介 -->
|
||||
<div style="font-size:13px;font-weight:600;color:#999;margin:0 4px 8px;">个人简介</div>
|
||||
<div style="background:#fff;border-radius:12px;padding:14px 16px;box-shadow:0 1px 6px rgba(0,0,0,0.06);margin-bottom:16px;">
|
||||
<textarea style="width:100%;border:none;font-size:14px;color:#1a1a1a;outline:none;resize:none;line-height:1.7;background:transparent;" rows="4" placeholder="请输入个人简介...">注册营养师,从事营养健康管理工作 8 年,擅长体重管理、慢性病营养干预与个性化食谱制定,累计服务员工 2000 余人次。</textarea>
|
||||
<div style="text-align:right;font-size:11px;color:#bbb;">已输入 68/300 字</div>
|
||||
</div>
|
||||
|
||||
<!-- 职业经历 -->
|
||||
<div style="font-size:13px;font-weight:600;color:#999;margin:0 4px 8px;">职业经历</div>
|
||||
<div style="background:#fff;border-radius:12px;padding:14px 16px;box-shadow:0 1px 6px rgba(0,0,0,0.06);margin-bottom:20px;">
|
||||
<textarea style="width:100%;border:none;font-size:14px;color:#1a1a1a;outline:none;resize:none;line-height:1.7;background:transparent;" rows="4" placeholder="请描述您的职业经历..."></textarea>
|
||||
<div style="text-align:right;font-size:11px;color:#bbb;">已输入 62/300 字</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
|
||||
/* 切换擅长领域标签选中状态 */
|
||||
function toggleTag(el) {
|
||||
var isOn = el.style.background === 'rgb(22, 119, 255)' || el.style.background === '#1677ff';
|
||||
el.style.background = isOn ? '#f5f5f5' : '#1677ff';
|
||||
el.style.color = isOn ? '#666' : '#fff';
|
||||
el.style.borderColor = isOn ? '#e8e8e8' : '#1677ff';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,155 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师 - 个人中心 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #fff; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
.modal-center { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.5); z-index: 200; align-items: center; justify-content: center; }
|
||||
.modal-center.active { display: flex; }
|
||||
.modal-box { width: 280px; background: #fff; border-radius: 16px; overflow: hidden; }
|
||||
.modal-box .modal-title { padding: 20px 20px 8px; font-size: 17px; font-weight: 700; text-align: center; color: #1a1a1a; }
|
||||
.modal-box .modal-body { padding: 8px 20px 20px; font-size: 14px; color: #666; text-align: center; line-height: 1.6; }
|
||||
.modal-box .modal-actions { display: flex; border-top: 1px solid #f0f0f0; }
|
||||
.modal-box .modal-actions button { flex: 1; padding: 14px; font-size: 16px; cursor: pointer; background: none; border: none; }
|
||||
.modal-box .modal-actions button:first-child { color: #666; border-right: 1px solid #f0f0f0; }
|
||||
.modal-box .modal-actions button:last-child { color: #1677ff; font-weight: 600; }
|
||||
.tab-bar { height: 83px; background: #fff; border-top: 1px solid #e8e8e8; display: flex; align-items: flex-start; padding-top: 8px; flex-shrink: 0; }
|
||||
.tab-item { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; cursor: pointer; padding: 4px 0; position: relative; }
|
||||
.tab-item .tab-icon { font-size: 22px; line-height: 1; }
|
||||
.tab-item .tab-label { font-size: 10px; color: #999; font-weight: 500; }
|
||||
.tab-item.active .tab-label { color: #1677ff; }
|
||||
.tab-badge { position: absolute; top: 2px; right: 18px; background: #ff4d4f; color: #fff; font-size: 10px; font-weight: 700; min-width: 16px; height: 16px; border-radius: 8px; display: flex; align-items: center; justify-content: center; padding: 0 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar" style="background:transparent;position:absolute;top:0;left:0;right:0;z-index:10;">
|
||||
<span class="time" style="color:#fff;">9:41</span>
|
||||
<div class="icons" style="color:#fff;"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 蓝色渐变头部 -->
|
||||
<div style="background:linear-gradient(135deg,#1677ff,#0958d9);padding:30px 20px 24px;flex-shrink:0;padding-top:60px;">
|
||||
<div style="display:flex;align-items:center;gap:16px;">
|
||||
<div style="width:68px;height:68px;border-radius:50%;background:linear-gradient(135deg,#e8f4ff,#bdd7ff);display:flex;align-items:center;justify-content:center;font-size:34px;border:3px solid rgba(255,255,255,0.5);">🥗</div>
|
||||
<div>
|
||||
<div style="color:#fff;font-size:20px;font-weight:700;">李静</div>
|
||||
<div style="color:rgba(255,255,255,0.8);font-size:13px;margin-top:3px;">注册营养师</div>
|
||||
<div style="color:rgba(255,255,255,0.65);font-size:12px;margin-top:2px;">健康管理科</div>
|
||||
</div>
|
||||
<!-- 服务中按钮 -->
|
||||
<button onclick="togglePause()" id="pause-btn-mine" style="margin-left:auto;display:flex;align-items:center;gap:6px;background:rgba(255,255,255,0.2);border:1px solid rgba(255,255,255,0.4);border-radius:20px;padding:6px 12px;color:#fff;font-size:12px;cursor:pointer;">
|
||||
<span style="width:7px;height:7px;border-radius:50%;background:#52c41a;display:inline-block;"></span><span id="pause-text">咨询已开启</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 功能列表滚动区域 -->
|
||||
<div class="scroll-content" style="padding:12px 16px;">
|
||||
<div style="background:#fff;border-radius:12px;overflow:hidden;box-shadow:0 1px 6px rgba(0,0,0,0.06);margin-bottom:12px;">
|
||||
<div onclick="location.href='./stats.html'" style="display:flex;align-items:center;padding:16px;cursor:pointer;border-bottom:1px solid #f5f5f5;">
|
||||
<span style="font-size:18px;margin-right:12px;">📊</span><span style="font-size:15px;color:#1a1a1a;flex:1;">营养咨询统计</span>
|
||||
<span style="font-size:13px;color:#1677ff;margin-right:8px;">今日 12 次</span>
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="#ccc" stroke-width="1.5"><path d="M1 1l5 5-5 5"/></svg>
|
||||
</div>
|
||||
<div onclick="location.href='./schedule.html'" style="display:flex;align-items:center;padding:16px;cursor:pointer;border-bottom:1px solid #f5f5f5;">
|
||||
<span style="font-size:18px;margin-right:12px;">📅</span><span style="font-size:15px;color:#1a1a1a;flex:1;">排班设置</span>
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="#ccc" stroke-width="1.5"><path d="M1 1l5 5-5 5"/></svg>
|
||||
</div>
|
||||
<div onclick="location.href='./edit-profile.html'" style="display:flex;align-items:center;padding:16px;cursor:pointer;">
|
||||
<span style="font-size:18px;margin-right:12px;">👤</span><span style="font-size:15px;color:#1a1a1a;flex:1;">个人信息设置</span>
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="#ccc" stroke-width="1.5"><path d="M1 1l5 5-5 5"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="background:#fff;border-radius:12px;overflow:hidden;box-shadow:0 1px 6px rgba(0,0,0,0.06);margin-bottom:12px;">
|
||||
<div onclick="location.href='./change-pwd.html'" style="display:flex;align-items:center;padding:16px;border-bottom:1px solid #f5f5f5;cursor:pointer;">
|
||||
<span style="font-size:18px;margin-right:12px;">🔒</span><span style="font-size:15px;color:#1a1a1a;flex:1;">修改密码</span>
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="#ccc" stroke-width="1.5"><path d="M1 1l5 5-5 5"/></svg>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;padding:16px;">
|
||||
<span style="font-size:18px;margin-right:12px;">ℹ️</span><span style="font-size:15px;color:#1a1a1a;flex:1;">关于我们</span>
|
||||
<svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="#ccc" stroke-width="1.5"><path d="M1 1l5 5-5 5"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button onclick="openModal('modal-logout')" style="width:100%;padding:14px;background:#fff;color:#ff4d4f;border:none;border-radius:12px;font-size:15px;font-weight:600;cursor:pointer;box-shadow:0 1px 6px rgba(0,0,0,0.06);">退出登录</button>
|
||||
</div>
|
||||
|
||||
<!-- 退出确认弹窗 -->
|
||||
<div id="modal-logout" class="modal-center">
|
||||
<div class="modal-box">
|
||||
<div class="modal-title">退出登录</div>
|
||||
<div class="modal-body">确认退出当前账号?</div>
|
||||
<div class="modal-actions">
|
||||
<button onclick="closeModal('modal-logout')">取消</button>
|
||||
<button onclick="closeModal('modal-logout')" style="color:#ff4d4f;">确认退出</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 咨询状态切换确认弹窗 -->
|
||||
<div id="modal-pause" class="modal-center">
|
||||
<div class="modal-box">
|
||||
<div class="modal-title" id="pause-modal-title">关闭咨询</div>
|
||||
<div class="modal-body" id="pause-modal-body">是否要关闭营养咨询?关闭后,员工无法发起营养咨询。</div>
|
||||
<div class="modal-actions">
|
||||
<button onclick="closeModal('modal-pause')">取消</button>
|
||||
<button onclick="confirmTogglePause()">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部Tab栏,我的为active状态 -->
|
||||
<div class="tab-bar">
|
||||
<div class="tab-item" onclick="location.href='../workbench/index.html'"><span class="tab-icon">🏥</span><span class="tab-label">工作台</span><span class="tab-badge">2</span></div>
|
||||
<div class="tab-item" onclick="location.href='../knowledge/index.html'"><span class="tab-icon">📚</span><span class="tab-label">知识库</span></div>
|
||||
<div class="tab-item" onclick="location.href='../../ai-assistant/index.html'"><span class="tab-icon">🤖</span><span class="tab-label">AI助手</span></div>
|
||||
<div class="tab-item" onclick="location.href='../../message/index.html'"><span class="tab-icon">💬</span><span class="tab-label">消息</span><span class="tab-badge">2</span></div>
|
||||
<div class="tab-item active" onclick="location.href='./index.html'"><span class="tab-icon">👤</span><span class="tab-label">我的</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
|
||||
let isPaused = false;
|
||||
|
||||
function togglePause() {
|
||||
var title = isPaused ? '开启咨询' : '关闭咨询';
|
||||
var body = isPaused ? '是否要开启营养咨询?开启后,员工可发起营养咨询。' : '是否要关闭营养咨询?关闭后,员工无法发起营养咨询。';
|
||||
document.getElementById('pause-modal-title').textContent = title;
|
||||
document.getElementById('pause-modal-body').textContent = body;
|
||||
openModal('modal-pause');
|
||||
}
|
||||
|
||||
function confirmTogglePause() {
|
||||
isPaused = !isPaused;
|
||||
var bg = isPaused ? '#ff4d4f' : '#52c41a';
|
||||
var text = isPaused ? '咨询已关闭' : '咨询已开启';
|
||||
var mineBtn = document.getElementById('pause-btn-mine');
|
||||
if (mineBtn) {
|
||||
var dot = mineBtn.querySelector('span');
|
||||
if (dot) dot.style.background = bg;
|
||||
var pauseText = document.getElementById('pause-text');
|
||||
if (pauseText) pauseText.textContent = text;
|
||||
}
|
||||
closeModal('modal-pause');
|
||||
}
|
||||
|
||||
function openModal(id) { var m = document.getElementById(id); if (m) m.classList.add('active'); }
|
||||
function closeModal(id) { var m = document.getElementById(id); if (m) m.classList.remove('active'); }
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,183 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师 - 排班设置 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #fff; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.nav-bar { height: 44px; display: flex; align-items: center; padding: 0 16px; background: #fff; border-bottom: 1px solid #f0f0f0; flex-shrink: 0; position: relative; }
|
||||
.back-btn { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.nav-right { margin-left: auto; color: #1677ff; font-size: 14px; cursor: pointer; background: none; border: none; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
.toggle { position: relative; width: 44px; height: 24px; border-radius: 12px; background: #e0e0e0; cursor: pointer; transition: background .2s; flex-shrink: 0; }
|
||||
.toggle.on { background: #4cd964; }
|
||||
.toggle::after { content: ''; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.2); transition: transform .2s; }
|
||||
.toggle.on::after { transform: translateX(20px); }
|
||||
.day-card { background: #fff; border-radius: 12px; margin: 0 16px 10px; box-shadow: 0 1px 4px rgba(0,0,0,0.05); overflow: hidden; }
|
||||
.day-header { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px; cursor: pointer; -webkit-tap-highlight-color: transparent; }
|
||||
.day-header .day-name { font-size: 15px; font-weight: 600; color: #1a1a1a; }
|
||||
.day-header .day-summary { font-size: 12px; color: #999; }
|
||||
.day-header .arrow { width: 16px; height: 16px; color: #ccc; transition: transform .2s; flex-shrink: 0; }
|
||||
.day-header .arrow.open { transform: rotate(180deg); }
|
||||
.day-body { max-height: 0; overflow: hidden; transition: max-height .25s ease; }
|
||||
.day-body.open { max-height: 400px; }
|
||||
.day-body-inner { padding: 0 16px 14px; }
|
||||
.slot-row { display: flex; align-items: center; padding: 10px 0; border-top: 1px solid #f5f5f5; }
|
||||
.slot-row:first-child { border-top: none; }
|
||||
.slot-info { flex: 1; min-width: 0; }
|
||||
.slot-period { font-size: 11px; color: #1677ff; font-weight: 500; margin-bottom: 1px; }
|
||||
.slot-time { font-size: 13px; color: #1a1a1a; }
|
||||
.slot-right { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
|
||||
.slot-toggle { position: relative; width: 40px; height: 22px; border-radius: 11px; background: #e0e0e0; cursor: pointer; transition: background .2s; }
|
||||
.slot-toggle.on { background: #4cd964; }
|
||||
.slot-toggle::after { content: ''; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.2); transition: transform .2s; }
|
||||
.slot-toggle.on::after { transform: translateX(18px); }
|
||||
.slot-count { display: flex; align-items: center; gap: 4px; }
|
||||
.count-btn { width: 26px; height: 26px; border-radius: 50%; border: 1px solid #e8e8e8; background: #fff; font-size: 15px; color: #666; cursor: pointer; display: flex; align-items: center; justify-content: center; line-height: 1; }
|
||||
.count-btn:active { background: #f5f5f5; }
|
||||
.count-val { font-size: 15px; font-weight: 700; color: #1677ff; min-width: 18px; text-align: center; }
|
||||
.count-unit { font-size: 11px; color: #999; }
|
||||
.slot-row.disabled .slot-time { color: #ccc; }
|
||||
.slot-row.disabled .slot-period { color: #b8d4ff; }
|
||||
.slot-row.disabled .count-val { color: #ccc; }
|
||||
.slot-row.disabled .count-btn { border-color: #f0f0f0; color: #ccc; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
<div class="nav-bar">
|
||||
<button class="back-btn" onclick="location.href='./index.html'">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title">排班设置</span>
|
||||
<button class="nav-right">保存</button>
|
||||
</div>
|
||||
<div class="scroll-content">
|
||||
<!-- 开启营养咨询 -->
|
||||
<div style="background:#fff;padding:14px 16px;display:flex;align-items:center;gap:10px;margin-bottom:10px;">
|
||||
<span style="font-size:14px;color:#1a1a1a;font-weight:500;">开启营养咨询</span>
|
||||
<div class="toggle on" onclick="this.classList.toggle('on');var t=this.nextElementSibling;t.textContent=this.classList.contains('on')?'已开启 — 员工可发起营养咨询':'已关闭';t.style.color=this.classList.contains('on')?'#4cd964':'#999';"></div>
|
||||
<span style="font-size:12px;color:#4cd964;flex:1;">已开启 — 员工可发起营养咨询</span>
|
||||
</div>
|
||||
<!-- 标题 -->
|
||||
<div style="padding:2px 16px 10px;display:flex;align-items:center;gap:6px;">
|
||||
<span style="width:3px;height:14px;background:#1677ff;border-radius:2px;display:inline-block;"></span>
|
||||
<span style="font-size:14px;font-weight:600;color:#1a1a1a;">每周排班设置</span>
|
||||
</div>
|
||||
<div id="cardList"></div>
|
||||
<div style="height:20px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var DAYS = ['周一','周二','周三','周四','周五','周六','周日'];
|
||||
var SLOTS = [
|
||||
{ period: '上午', time: '8:00 – 10:00' },
|
||||
{ period: '上午', time: '10:00 – 12:00' },
|
||||
{ period: '下午', time: '14:00 – 16:00' },
|
||||
{ period: '下午', time: '16:00 – 18:00' }
|
||||
];
|
||||
var DATA = DAYS.map(function(_, i) {
|
||||
var off = i >= 5;
|
||||
return { slots: SLOTS.map(function(_, si) {
|
||||
return { on: !off, n: off ? 0 : (si < 2 ? 5 : 4) };
|
||||
})};
|
||||
});
|
||||
|
||||
var arrowSvg = '<svg class="arrow" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 6l4 4 4-4"/></svg>';
|
||||
|
||||
function getSummary(di) {
|
||||
var d = DATA[di], cnt = 0;
|
||||
d.slots.forEach(function(s) { if (s.on) cnt++; });
|
||||
return cnt > 0 ? cnt + '个时段开诊' : '休息';
|
||||
}
|
||||
|
||||
function render() {
|
||||
var wrap = document.getElementById('cardList');
|
||||
wrap.innerHTML = '';
|
||||
DAYS.forEach(function(day, di) {
|
||||
var card = document.createElement('div');
|
||||
card.className = 'day-card';
|
||||
card.innerHTML =
|
||||
'<div class="day-header" onclick="toggle(' + di + ')">' +
|
||||
'<div><span class="day-name">' + day + '</span> ' +
|
||||
'<span class="day-summary">' + getSummary(di) + '</span></div>' +
|
||||
arrowSvg +
|
||||
'</div>' +
|
||||
'<div class="day-body" id="body-' + di + '">' +
|
||||
'<div class="day-body-inner">' + renderSlots(di) + '</div>' +
|
||||
'</div>';
|
||||
wrap.appendChild(card);
|
||||
});
|
||||
var first = document.getElementById('body-0');
|
||||
if (first) { first.classList.add('open'); first.previousElementSibling.querySelector('.arrow').classList.add('open'); }
|
||||
}
|
||||
|
||||
function renderSlots(di) {
|
||||
var html = '';
|
||||
DATA[di].slots.forEach(function(s, si) {
|
||||
var dis = s.on ? '' : ' disabled';
|
||||
var tCls = s.on ? 'slot-toggle on' : 'slot-toggle';
|
||||
html += '<div class="slot-row' + dis + '">' +
|
||||
'<div class="slot-info">' +
|
||||
'<div class="slot-period">' + SLOTS[si].period + '</div>' +
|
||||
'<div class="slot-time">' + SLOTS[si].time + '</div>' +
|
||||
'</div>' +
|
||||
'<div class="slot-right">' +
|
||||
'<div class="' + tCls + '" onclick="toggleSlot(' + di + ',' + si + ')"></div>' +
|
||||
'<div class="slot-count">' +
|
||||
'<button class="count-btn" ' + (s.on ? '' : 'disabled ') + 'onclick="adj(' + di + ',' + si + ',-1)">−</button>' +
|
||||
'<span class="count-val">' + (s.on ? s.n : '—') + '</span>' +
|
||||
'<button class="count-btn" ' + (s.on ? '' : 'disabled ') + 'onclick="adj(' + di + ',' + si + ',1)">+</button>' +
|
||||
'<span class="count-unit">人</span>' +
|
||||
'</div>' +
|
||||
'</div></div>';
|
||||
});
|
||||
return html;
|
||||
}
|
||||
|
||||
function toggle(di) {
|
||||
var body = document.getElementById('body-' + di);
|
||||
var arrow = body.previousElementSibling.querySelector('.arrow');
|
||||
body.classList.toggle('open');
|
||||
arrow.classList.toggle('open');
|
||||
}
|
||||
|
||||
function toggleSlot(di, si) {
|
||||
var s = DATA[di].slots[si];
|
||||
s.on = !s.on;
|
||||
if (s.on && s.n === 0) s.n = 3;
|
||||
refreshCard(di);
|
||||
}
|
||||
|
||||
function adj(di, si, delta) {
|
||||
var s = DATA[di].slots[si];
|
||||
if (!s.on) return;
|
||||
s.n = Math.max(1, Math.min(20, s.n + delta));
|
||||
refreshCard(di);
|
||||
}
|
||||
|
||||
function refreshCard(di) {
|
||||
var body = document.getElementById('body-' + di);
|
||||
var wasOpen = body.classList.contains('open');
|
||||
body.querySelector('.day-body-inner').innerHTML = renderSlots(di);
|
||||
var header = body.previousElementSibling;
|
||||
header.querySelector('.day-summary').textContent = getSummary(di);
|
||||
if (wasOpen) body.classList.add('open');
|
||||
}
|
||||
|
||||
render();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,143 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师 - 营养咨询统计 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #fff; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.nav-bar { height: 44px; display: flex; align-items: center; padding: 0 16px; background: #fff; border-bottom: 1px solid #f0f0f0; flex-shrink: 0; position: relative; }
|
||||
.back-btn { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="phone-shell">
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<div class="nav-bar">
|
||||
<button class="back-btn" onclick="location.href='./index.html'">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title">营养咨询统计</span>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content" style="padding:16px;">
|
||||
|
||||
<!-- 月度统计 -->
|
||||
<div style="background:#fff;border-radius:12px;padding:20px;margin-bottom:16px;box-shadow:0 1px 6px rgba(0,0,0,0.06);">
|
||||
<div style="display:flex;align-items:center;justify-content:center;gap:16px;margin-bottom:20px;">
|
||||
<button onclick="prevMonth()" style="background:none;border:none;color:#1677ff;font-size:18px;cursor:pointer;padding:4px 8px;">
|
||||
<svg width="8" height="14" viewBox="0 0 8 14" fill="none" stroke="currentColor" stroke-width="2"><path d="M7 1L1 7l6 6"/></svg>
|
||||
</button>
|
||||
<div style="font-size:17px;font-weight:600;color:#1a1a1a;min-width:120px;text-align:center;" id="current-month">2026年9月</div>
|
||||
<button onclick="nextMonth()" style="background:none;border:none;color:#1677ff;font-size:18px;cursor:pointer;padding:4px 8px;">
|
||||
<svg width="8" height="14" viewBox="0 0 8 14" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 1l6 6-6 6"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 概览(3列) -->
|
||||
<div style="display:flex;gap:8px;margin-bottom:24px;">
|
||||
<div style="flex:1;background:#e6f4ff;border-radius:10px;padding:14px 8px;text-align:center;">
|
||||
<div style="font-size:20px;font-weight:700;color:#1677ff;">213</div>
|
||||
<div style="font-size:11px;color:#666;margin-top:4px;">营养咨询</div>
|
||||
</div>
|
||||
<div style="flex:1;background:#f6ffed;border-radius:10px;padding:14px 8px;text-align:center;">
|
||||
<div style="font-size:20px;font-weight:700;color:#52c41a;">48</div>
|
||||
<div style="font-size:11px;color:#666;margin-top:4px;">营养方案</div>
|
||||
</div>
|
||||
<div style="flex:1;background:#fff7e6;border-radius:10px;padding:14px 8px;text-align:center;">
|
||||
<div style="font-size:20px;font-weight:700;color:#fa8c16;">12</div>
|
||||
<div style="font-size:11px;color:#666;margin-top:4px;">发布食谱</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 咨询主题分布(饼状图) -->
|
||||
<div style="display:flex;align-items:center;gap:24px;margin-bottom:24px;">
|
||||
<svg width="130" height="130" viewBox="0 0 100 100" style="flex-shrink:0;">
|
||||
<circle cx="50" cy="50" r="40" fill="none" stroke="#1677ff" stroke-width="20"
|
||||
stroke-dasharray="126 250" stroke-dashoffset="0" transform="rotate(-90 50 50)"/>
|
||||
<circle cx="50" cy="50" r="40" fill="none" stroke="#52c41a" stroke-width="20"
|
||||
stroke-dasharray="75 250" stroke-dashoffset="-126" transform="rotate(-90 50 50)"/>
|
||||
<circle cx="50" cy="50" r="40" fill="none" stroke="#fa8c16" stroke-width="20"
|
||||
stroke-dasharray="49 250" stroke-dashoffset="-201" transform="rotate(-90 50 50)"/>
|
||||
<circle cx="50" cy="50" r="28" fill="#fff"/>
|
||||
<text x="50" y="48" text-anchor="middle" font-size="18" font-weight="700" fill="#1a1a1a">213</text>
|
||||
<text x="50" y="60" text-anchor="middle" font-size="10" fill="#999">总咨询</text>
|
||||
</svg>
|
||||
|
||||
<div style="flex:1;">
|
||||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:12px;">
|
||||
<div style="width:12px;height:12px;background:#1677ff;border-radius:3px;flex-shrink:0;"></div>
|
||||
<div style="flex:1;"><span style="font-size:13px;color:#666;">减脂控糖</span></div>
|
||||
<span style="font-size:15px;font-weight:700;color:#1a1a1a;">107<span style="font-size:11px;color:#999;"> (50%)</span></span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:12px;">
|
||||
<div style="width:12px;height:12px;background:#52c41a;border-radius:3px;flex-shrink:0;"></div>
|
||||
<div style="flex:1;"><span style="font-size:13px;color:#666;">慢性病营养</span></div>
|
||||
<span style="font-size:15px;font-weight:700;color:#1a1a1a;">64<span style="font-size:11px;color:#999;"> (30%)</span></span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<div style="width:12px;height:12px;background:#fa8c16;border-radius:3px;flex-shrink:0;"></div>
|
||||
<div style="flex:1;"><span style="font-size:13px;color:#666;">其他</span></div>
|
||||
<span style="font-size:15px;font-weight:700;color:#1a1a1a;">42<span style="font-size:11px;color:#999;"> (20%)</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 月度趋势折线图 -->
|
||||
<div style="border-top:1px solid #f0f0f0;padding-top:20px;">
|
||||
<div style="font-size:14px;font-weight:600;color:#1a1a1a;margin-bottom:16px;">月度趋势</div>
|
||||
<svg width="100%" height="180" viewBox="0 0 340 180" style="overflow:visible;">
|
||||
<line x1="0" y1="150" x2="340" y2="150" stroke="#f0f0f0" stroke-width="1"/>
|
||||
<line x1="0" y1="120" x2="340" y2="120" stroke="#f0f0f0" stroke-width="1"/>
|
||||
<line x1="0" y1="90" x2="340" y2="90" stroke="#f0f0f0" stroke-width="1"/>
|
||||
<line x1="0" y1="60" x2="340" y2="60" stroke="#f0f0f0" stroke-width="1"/>
|
||||
<line x1="0" y1="30" x2="340" y2="30" stroke="#f0f0f0" stroke-width="1"/>
|
||||
|
||||
<polyline points="5,126 27,108 49,90 71,60 93,138 115,48 137,96 159,78 181,114 203,66 225,132 247,90 269,120 291,54 313,144 335,42"
|
||||
fill="none" stroke="#1677ff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
|
||||
<circle cx="93" cy="138" r="3.5" fill="#1677ff"/>
|
||||
<circle cx="159" cy="78" r="3.5" fill="#1677ff"/>
|
||||
<circle cx="203" cy="66" r="6" fill="#1677ff" stroke="#fff" stroke-width="2.5"/>
|
||||
|
||||
<text x="93" y="168" text-anchor="middle" font-size="11" fill="#bbb">6</text>
|
||||
<text x="159" y="168" text-anchor="middle" font-size="11" fill="#bbb">12</text>
|
||||
<text x="203" y="168" text-anchor="middle" font-size="11" fill="#1677ff" font-weight="600">今</text>
|
||||
<text x="335" y="168" text-anchor="middle" font-size="11" fill="#bbb">30</text>
|
||||
|
||||
<text x="203" y="54" text-anchor="middle" font-size="12" fill="#1677ff" font-weight="600">15</text>
|
||||
<text x="-5" y="153" text-anchor="end" font-size="10" fill="#bbb">0</text>
|
||||
<text x="-5" y="123" text-anchor="end" font-size="10" fill="#bbb">5</text>
|
||||
<text x="-5" y="93" text-anchor="end" font-size="10" fill="#bbb">10</text>
|
||||
<text x="-5" y="63" text-anchor="end" font-size="10" fill="#bbb">15</text>
|
||||
<text x="-5" y="33" text-anchor="end" font-size="10" fill="#bbb">20</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="height:20px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
|
||||
function prevMonth() { alert('切换到上个月(演示)'); }
|
||||
function nextMonth() { alert('切换到下个月(演示)'); }
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师工作台 - 营养咨询聊天(已结束) | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #fff; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.nav-bar { height: 44px; display: flex; align-items: center; padding: 0 16px; background: #fff; border-bottom: 1px solid #f0f0f0; flex-shrink: 0; position: relative; }
|
||||
.back-btn { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 导航栏 -->
|
||||
<div class="nav-bar">
|
||||
<button class="back-btn" onclick="location.href='./index.html'">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title">赵磊</span>
|
||||
</div>
|
||||
|
||||
<!-- 咨询已结束提示条 -->
|
||||
<div style="background:#fff7e6;padding:8px 16px;font-size:12px;color:#d46b08;flex-shrink:0;text-align:center;">本次营养咨询已结束,仅可查看历史记录</div>
|
||||
|
||||
<!-- 消息区(只读) -->
|
||||
<div class="scroll-content" style="padding:12px 16px;">
|
||||
<div style="text-align:center;margin:8px 0;"><span style="font-size:11px;color:#bbb;background:#ebebeb;padding:3px 10px;border-radius:10px;">昨天 08:30</span></div>
|
||||
<!-- 员工消息 -->
|
||||
<div style="display:flex;gap:8px;margin-bottom:14px;">
|
||||
<div style="width:36px;height:36px;border-radius:50%;background:linear-gradient(135deg,#ffe0e0,#ffb3b3);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;">👨</div>
|
||||
<div><div style="font-size:11px;color:#999;margin-bottom:4px;">赵磊</div>
|
||||
<div style="background:#fff;border-radius:0 12px 12px 12px;padding:10px 14px;font-size:14px;color:#1a1a1a;max-width:220px;box-shadow:0 1px 4px rgba(0,0,0,0.06);line-height:1.5;">营养师您好,我最近体检尿酸偏高,日常饮食要注意什么?</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 营养师消息 -->
|
||||
<div style="display:flex;gap:8px;margin-bottom:14px;flex-direction:row-reverse;">
|
||||
<div style="width:36px;height:36px;border-radius:50%;background:linear-gradient(135deg,#e8f4ff,#bdd7ff);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;">🥗</div>
|
||||
<div style="display:flex;flex-direction:column;align-items:flex-end;">
|
||||
<div style="font-size:11px;color:#999;margin-bottom:4px;">李营养师(我)</div>
|
||||
<div style="background:#1677ff;border-radius:12px 0 12px 12px;padding:10px 14px;font-size:14px;color:#fff;max-width:220px;line-height:1.5;">高尿酸人群建议限制高嘌呤食物(动物内脏、海鲜、浓肉汤),避免饮酒,多饮水,每日 2000ml 以上,控制体重。</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align:center;margin:8px 0;"><span style="font-size:11px;color:#bbb;background:#ebebeb;padding:3px 10px;border-radius:10px;">昨天 08:45</span></div>
|
||||
<!-- 员工结束消息 -->
|
||||
<div style="display:flex;gap:8px;margin-bottom:14px;">
|
||||
<div style="width:36px;height:36px;border-radius:50%;background:linear-gradient(135deg,#ffe0e0,#ffb3b3);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;">👨</div>
|
||||
<div><div style="font-size:11px;color:#999;margin-bottom:4px;">赵磊</div>
|
||||
<div style="background:#fff;border-radius:0 12px 12px 12px;padding:10px 14px;font-size:14px;color:#1a1a1a;max-width:220px;box-shadow:0 1px 4px rgba(0,0,0,0.06);line-height:1.5;">谢谢营养师,方案很实用,我会坚持执行。</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 结束标记 -->
|
||||
<div style="text-align:center;margin:16px 0;">
|
||||
<span style="font-size:12px;color:#bbb;">— 咨询已结束 —</span>
|
||||
</div>
|
||||
<div style="height:8px;"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,328 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师工作台 - 营养咨询聊天 | 健康CQ原型</title>
|
||||
<style>
|
||||
/* 公共重置与布局 */
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #fff; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
/* 导航栏 */
|
||||
.nav-bar { height: 44px; display: flex; align-items: center; padding: 0 16px; background: #fff; border-bottom: 1px solid #f0f0f0; flex-shrink: 0; position: relative; }
|
||||
.back-btn { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.nav-right { margin-left: auto; color: #ff4d4f; font-size: 14px; cursor: pointer; background: none; border: none; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
.modal-center { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.5); z-index: 200; align-items: center; justify-content: center; }
|
||||
.modal-center.active { display: flex; }
|
||||
.modal-box { width: 280px; background: #fff; border-radius: 16px; overflow: hidden; }
|
||||
.modal-box .modal-title { padding: 20px 20px 8px; font-size: 17px; font-weight: 700; text-align: center; color: #1a1a1a; }
|
||||
.modal-box .modal-body { padding: 8px 20px 20px; font-size: 14px; color: #666; text-align: center; line-height: 1.6; }
|
||||
.modal-box .modal-actions { display: flex; border-top: 1px solid #f0f0f0; }
|
||||
.modal-box .modal-actions button { flex: 1; padding: 14px; font-size: 16px; cursor: pointer; background: none; border: none; }
|
||||
.modal-box .modal-actions button:first-child { color: #666; border-right: 1px solid #f0f0f0; }
|
||||
.modal-box .modal-actions button:last-child { color: #1677ff; font-weight: 600; }
|
||||
/* 员工档案卡片 */
|
||||
.bubble-record { max-width: 260px; border-radius: 0 12px 12px 12px; overflow: hidden; background: #fff; border: 1px solid #e8e8e8; box-shadow: 0 1px 4px rgba(0,0,0,0.06); cursor: pointer; }
|
||||
.bubble-record__header { display: flex; align-items: center; gap: 8px; padding: 10px 12px; background: linear-gradient(135deg, #e8f4ff, #bae0ff); }
|
||||
.bubble-record__avatar { width: 32px; height: 32px; border-radius: 50%; background: #fff; display: flex; align-items: center; justify-content: center; font-size: 16px; flex-shrink: 0; }
|
||||
.bubble-record__name { font-size: 13px; font-weight: 600; color: #333; }
|
||||
.bubble-record__meta { font-size: 11px; color: #666; }
|
||||
.bubble-record__body { padding: 10px 12px; }
|
||||
.bubble-record__title { font-size: 13px; font-weight: 600; color: #333; margin-bottom: 4px; }
|
||||
.bubble-record__desc { font-size: 12px; color: #666; line-height: 1.5; }
|
||||
.bubble-record__tags { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 6px; }
|
||||
.bubble-record__tag { font-size: 10px; padding: 2px 6px; border-radius: 4px; }
|
||||
.bubble-record__tag--green { color: #52c41a; background: #f6ffed; }
|
||||
.bubble-record__tag--orange { color: #d46b08; background: #fff7e6; }
|
||||
/* 常用语分类与列表 */
|
||||
.quick-cat { font-size: 12px; padding: 4px 12px; border-radius: 14px; background: #f5f5f5; color: #666; cursor: pointer; user-select: none; transition: all .2s; }
|
||||
.quick-cat.active { background: #e6f4ff; color: #1677ff; font-weight: 600; }
|
||||
.quick-item { font-size: 13px; color: #1a1a1a; padding: 8px 0; border-bottom: 1px solid #f0f0f0; cursor: pointer; }
|
||||
.quick-item:last-child { border-bottom: none; }
|
||||
.quick-item:active { color: #1677ff; }
|
||||
/* 快捷操作栏 */
|
||||
.action-bar { display: flex; gap: 8px; background: #fff; border-bottom: 1px solid #f0f0f0; padding: 8px 16px; flex-shrink: 0; }
|
||||
.action-btn { flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px; padding: 8px 0; border-radius: 8px; font-size: 13px; cursor: pointer; }
|
||||
.action-btn--blue { background: #e6f4ff; color: #1677ff; }
|
||||
.action-btn--green { background: #f6ffed; color: #52c41a; }
|
||||
/* 底部弹层 */
|
||||
.sheet-mask { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 300; align-items: flex-end; justify-content: center; }
|
||||
.sheet-mask.active { display: flex; }
|
||||
.sheet-panel { width: 100%; max-height: 80%; background: #fff; border-radius: 16px 16px 0 0; display: flex; flex-direction: column; overflow: hidden; }
|
||||
.sheet-header { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px; border-bottom: 0.5px solid #f0f0f0; flex-shrink: 0; }
|
||||
.sheet-header .s-cancel { font-size: 14px; color: #999; cursor: pointer; background: none; border: none; }
|
||||
.sheet-header .s-title { font-size: 15px; font-weight: 600; color: #1a1a1a; }
|
||||
.sheet-header .s-save { font-size: 14px; color: #1677ff; font-weight: 600; cursor: pointer; background: none; border: none; }
|
||||
.sheet-body { padding: 12px 16px 20px; overflow-y: auto; flex: 1; }
|
||||
.sheet-body::-webkit-scrollbar { display: none; }
|
||||
.form-item { margin-bottom: 14px; }
|
||||
.form-item__label { font-size: 13px; font-weight: 600; color: #1a1a1a; margin-bottom: 8px; }
|
||||
.form-input { width: 100%; border: 1px solid #e8e8e8; border-radius: 8px; padding: 10px 12px; font-size: 14px; outline: none; color: #1a1a1a; }
|
||||
.form-input:focus { border-color: #1677ff; }
|
||||
.ratio-row { display: flex; gap: 8px; }
|
||||
.ratio-row .form-input { flex: 1; text-align: center; }
|
||||
.tag-picker { display: flex; gap: 6px; flex-wrap: wrap; }
|
||||
.tag-picker .tag-opt { font-size: 12px; padding: 5px 12px; border-radius: 14px; background: #f5f5f5; color: #666; cursor: pointer; }
|
||||
.tag-picker .tag-opt.active { background: #e6f4ff; color: #1677ff; font-weight: 600; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 导航栏 -->
|
||||
<div class="nav-bar">
|
||||
<!-- [交互] 点击返回: ./index.html -->
|
||||
<button class="back-btn" onclick="location.href='./index.html'">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title">张小红</span>
|
||||
<!-- [交互] 点击打开结束咨询弹窗 -->
|
||||
<button class="nav-right" onclick="openModal('modal-end-confirm')">结束咨询</button>
|
||||
</div>
|
||||
|
||||
<!-- 快捷操作栏 -->
|
||||
<div class="action-bar">
|
||||
<!-- [交互] 点击跳转至: ./employee-health.html 查看员工健康档案 -->
|
||||
<div class="action-btn action-btn--blue" onclick="location.href='./employee-health.html'">📋 健康档案</div>
|
||||
<!-- [交互] 点击打开制定营养方案弹层 -->
|
||||
<div class="action-btn action-btn--green" onclick="openSheet('sheet-plan')">🎯 制定方案</div>
|
||||
</div>
|
||||
|
||||
<!-- 消息区 -->
|
||||
<div class="scroll-content" id="chat-scroll" style="padding:12px 16px;">
|
||||
<!-- 时间标记 -->
|
||||
<div style="text-align:center;margin:8px 0;"><span style="font-size:11px;color:#bbb;background:#ebebeb;padding:3px 10px;border-radius:10px;">10:20</span></div>
|
||||
<!-- [交互] 员工营养档案卡片 - 点击查看员工营养详情 -->
|
||||
<div style="display:flex;gap:8px;margin-bottom:14px;">
|
||||
<div style="width:36px;height:36px;border-radius:50%;background:linear-gradient(135deg,#ffe0e0,#ffb3b3);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;">👩</div>
|
||||
<div><div style="font-size:11px;color:#999;margin-bottom:4px;">张小红</div>
|
||||
<div class="bubble-record" onclick="location.href='./employee-detail.html'">
|
||||
<div class="bubble-record__header">
|
||||
<div class="bubble-record__avatar">👩</div>
|
||||
<div>
|
||||
<div class="bubble-record__name">张小红 · 女 · 32岁</div>
|
||||
<div class="bubble-record__meta">162cm · 67kg · BMI 25.6</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bubble-record__body">
|
||||
<div class="bubble-record__title">减脂营养咨询</div>
|
||||
<div class="bubble-record__desc">食堂饭菜偏油,想请教日常减脂怎么搭配饮食</div>
|
||||
<div class="bubble-record__tags">
|
||||
<span class="bubble-record__tag bubble-record__tag--green">目标:减脂 5kg</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 员工消息(左侧) -->
|
||||
<div style="display:flex;gap:8px;margin-bottom:14px;">
|
||||
<div style="width:36px;height:36px;border-radius:50%;background:linear-gradient(135deg,#ffe0e0,#ffb3b3);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;">👩</div>
|
||||
<div><div style="font-size:11px;color:#999;margin-bottom:4px;">张小红</div>
|
||||
<div style="background:#fff;border-radius:0 12px 12px 12px;padding:10px 14px;font-size:14px;color:#1a1a1a;max-width:220px;box-shadow:0 1px 4px rgba(0,0,0,0.06);line-height:1.5;">营养师您好,我最近在减脂,但食堂的红烧肉、油炸类菜品偏多,不知道怎么吃才不会超标。</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 时间标记 -->
|
||||
<div style="text-align:center;margin:8px 0;"><span style="font-size:11px;color:#bbb;background:#ebebeb;padding:3px 10px;border-radius:10px;">10:23</span></div>
|
||||
<!-- 营养师消息(右侧) -->
|
||||
<div style="display:flex;gap:8px;margin-bottom:14px;flex-direction:row-reverse;">
|
||||
<div style="width:36px;height:36px;border-radius:50%;background:linear-gradient(135deg,#e8f4ff,#bdd7ff);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;">🥗</div>
|
||||
<div style="display:flex;flex-direction:column;align-items:flex-end;">
|
||||
<div style="font-size:11px;color:#999;margin-bottom:4px;">李营养师(我)</div>
|
||||
<div style="background:#1677ff;border-radius:12px 0 12px 12px;padding:10px 14px;font-size:14px;color:#fff;max-width:220px;line-height:1.5;">您好,减脂期在食堂就餐建议:主菜优先选清蒸、白灼、凉拌类,肉类选去皮鸡胸、鱼虾;主食粗细搭配,每餐一拳主食、一掌蛋白质、两拳蔬菜。</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 营养师消息:推荐食谱卡片 -->
|
||||
<div style="display:flex;gap:8px;margin-bottom:14px;flex-direction:row-reverse;">
|
||||
<div style="width:36px;height:36px;border-radius:50%;background:linear-gradient(135deg,#e8f4ff,#bdd7ff);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;">🥗</div>
|
||||
<div style="display:flex;flex-direction:column;align-items:flex-end;">
|
||||
<div style="font-size:11px;color:#999;margin-bottom:4px;">李营养师(我)</div>
|
||||
<div style="background:#fff;border-radius:12px 0 12px 12px;padding:10px;max-width:220px;box-shadow:0 1px 4px rgba(0,0,0,0.08);cursor:pointer;" onclick="location.href='./plan-detail.html'">
|
||||
<div style="font-size:12px;color:#999;margin-bottom:6px;">为您推荐个性化营养方案</div>
|
||||
<div style="font-size:14px;font-weight:600;color:#1a1a1a;">减脂期一周饮食方案</div>
|
||||
<div style="font-size:12px;color:#666;margin-top:4px;line-height:1.5;">每日热量 1400 kcal · 蛋白质 25% · 脂肪 20% · 碳水 55%</div>
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-top:8px;padding-top:8px;border-top:1px solid #f0f0f0;">
|
||||
<span style="font-size:11px;color:#52c41a;">● 已生成</span>
|
||||
<span style="font-size:12px;color:#1677ff;">查看详情 ›</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height:8px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 常用语面板 -->
|
||||
<div id="quick-panel" style="display:none;background:#fff;border-top:1px solid #f0f0f0;padding:10px 16px;flex-shrink:0;max-height:200px;overflow-y:auto;">
|
||||
<div style="display:flex;gap:6px;margin-bottom:10px;">
|
||||
<span class="quick-cat active" data-cat="all" onclick="filterQuick(this)">全部</span>
|
||||
<span class="quick-cat" data-cat="greet" onclick="filterQuick(this)">问候语</span>
|
||||
<span class="quick-cat" data-cat="ask" onclick="filterQuick(this)">问询</span>
|
||||
<span class="quick-cat" data-cat="advice" onclick="filterQuick(this)">建议</span>
|
||||
<span class="quick-cat" data-cat="end" onclick="filterQuick(this)">结束语</span>
|
||||
</div>
|
||||
<div id="quick-list">
|
||||
<div class="quick-item" data-cat="greet" onclick="useQuick(this)">您好,我是您的专属营养师</div>
|
||||
<div class="quick-item" data-cat="greet" onclick="useQuick(this)">您好,请描述您的饮食与健康目标</div>
|
||||
<div class="quick-item" data-cat="ask" onclick="useQuick(this)">请问您目前的身高体重是多少?</div>
|
||||
<div class="quick-item" data-cat="ask" onclick="useQuick(this)">是否有高血脂、糖尿病等慢性病史?</div>
|
||||
<div class="quick-item" data-cat="ask" onclick="useQuick(this)">平时主要在食堂就餐还是自带餐?</div>
|
||||
<div class="quick-item" data-cat="advice" onclick="useQuick(this)">建议主食粗细搭配,每餐一拳量</div>
|
||||
<div class="quick-item" data-cat="advice" onclick="useQuick(this)">优先选择清蒸、白灼类菜品</div>
|
||||
<div class="quick-item" data-cat="advice" onclick="useQuick(this)">控制油脂摄入,每日不超过 25g</div>
|
||||
<div class="quick-item" data-cat="end" onclick="useQuick(this)">如有不适请及时调整并反馈</div>
|
||||
<div class="quick-item" data-cat="end" onclick="useQuick(this)">祝您健康,欢迎随时咨询!</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 输入区 -->
|
||||
<div style="background:#fff;border-top:1px solid #f0f0f0;padding:8px 12px 14px;flex-shrink:0;">
|
||||
<div style="display:flex;align-items:center;gap:6px;">
|
||||
<button onclick="toggleQuick()" style="width:34px;height:34px;border-radius:50%;background:#f5f5f5;border:none;font-size:16px;cursor:pointer;flex-shrink:0;">⚡</button>
|
||||
<button id="voice-btn" onclick="toggleVoice()" style="width:34px;height:34px;border-radius:50%;background:#f5f5f5;border:none;font-size:16px;cursor:pointer;flex-shrink:0;">🎤</button>
|
||||
<input id="chat-input" type="text" placeholder="输入营养建议..." style="flex:1;background:#f5f5f5;border:none;border-radius:20px;padding:8px 14px;font-size:14px;outline:none;color:#1a1a1a;" />
|
||||
<button id="voice-record-btn" style="display:none;flex:1;height:36px;background:#f5f5f5;border:1.5px solid #d9d9d9;border-radius:20px;font-size:13px;color:#555;cursor:pointer;text-align:center;align-items:center;justify-content:center;letter-spacing:1px;">按住说话</button>
|
||||
<button onclick="sendMsg()" style="width:34px;height:34px;border-radius:50%;background:#1677ff;border:none;font-size:16px;cursor:pointer;flex-shrink:0;color:#fff;display:flex;align-items:center;justify-content:center;">➤</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 结束咨询确认弹窗 -->
|
||||
<div id="modal-end-confirm" class="modal-center">
|
||||
<div class="modal-box">
|
||||
<div class="modal-title">结束咨询</div>
|
||||
<div class="modal-body">确认结束与张小红的营养咨询?结束后将无法继续发送消息。</div>
|
||||
<div class="modal-actions">
|
||||
<button onclick="closeModal('modal-end-confirm')">取消</button>
|
||||
<button onclick="closeModal('modal-end-confirm');location.href='./index.html'">确认结束</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 制定营养方案底部弹层 -->
|
||||
<div id="sheet-plan" class="sheet-mask" onclick="if(event.target===this)closeSheet('sheet-plan')">
|
||||
<div class="sheet-panel" onclick="event.stopPropagation()">
|
||||
<div class="sheet-header">
|
||||
<button class="s-cancel" onclick="closeSheet('sheet-plan')">取消</button>
|
||||
<span class="s-title">为张小红制定营养方案</span>
|
||||
<button class="s-save" onclick="savePlan()">保存</button>
|
||||
</div>
|
||||
<div class="sheet-body">
|
||||
<div class="form-item">
|
||||
<div class="form-item__label">目标热量(kcal/日)</div>
|
||||
<input class="form-input" type="text" value="1400" />
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-item__label">三大营养素占比(%)</div>
|
||||
<div class="ratio-row">
|
||||
<input class="form-input" type="text" value="25" placeholder="蛋白" />
|
||||
<input class="form-input" type="text" value="20" placeholder="脂肪" />
|
||||
<input class="form-input" type="text" value="55" placeholder="碳水" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-item__label">饮食禁忌</div>
|
||||
<div class="tag-picker">
|
||||
<span class="tag-opt active" onclick="toggleTag(this)">高糖</span>
|
||||
<span class="tag-opt active" onclick="toggleTag(this)">高脂</span>
|
||||
<span class="tag-opt" onclick="toggleTag(this)">高盐</span>
|
||||
<span class="tag-opt active" onclick="toggleTag(this)">高嘌呤</span>
|
||||
<span class="tag-opt" onclick="toggleTag(this)">乳糖</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-item__label">目标描述</div>
|
||||
<input class="form-input" type="text" value="减脂 5kg,控制尿酸" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
|
||||
function openModal(id) { var m = document.getElementById(id); if (m) m.classList.add('active'); }
|
||||
function closeModal(id) { var m = document.getElementById(id); if (m) m.classList.remove('active'); }
|
||||
|
||||
/* 切换常用语面板 */
|
||||
function toggleQuick() {
|
||||
var p = document.getElementById('quick-panel');
|
||||
p.style.display = p.style.display === 'none' ? 'block' : 'none';
|
||||
}
|
||||
|
||||
/* 语音模式状态 */
|
||||
var isVoiceMode = false;
|
||||
function toggleVoice() {
|
||||
isVoiceMode = !isVoiceMode;
|
||||
var input = document.getElementById('chat-input');
|
||||
var voiceBtn = document.getElementById('voice-btn');
|
||||
var recordBtn = document.getElementById('voice-record-btn');
|
||||
if (isVoiceMode) {
|
||||
input.style.display = 'none';
|
||||
recordBtn.style.display = 'flex';
|
||||
voiceBtn.textContent = '⌨️';
|
||||
voiceBtn.style.background = '#e6f4ff';
|
||||
} else {
|
||||
input.style.display = '';
|
||||
recordBtn.style.display = 'none';
|
||||
voiceBtn.textContent = '🎤';
|
||||
voiceBtn.style.background = '#f5f5f5';
|
||||
}
|
||||
}
|
||||
|
||||
/* 使用常用语填充输入框 */
|
||||
function useQuick(el) {
|
||||
document.getElementById('chat-input').value = el.textContent;
|
||||
document.getElementById('quick-panel').style.display = 'none';
|
||||
}
|
||||
|
||||
/* 常用语分类筛选 */
|
||||
function filterQuick(tab) {
|
||||
tab.parentElement.querySelectorAll('.quick-cat').forEach(function(t) { t.classList.remove('active'); });
|
||||
tab.classList.add('active');
|
||||
var cat = tab.dataset.cat;
|
||||
document.querySelectorAll('#quick-list .quick-item').forEach(function(item) {
|
||||
item.style.display = (cat === 'all' || item.dataset.cat === cat) ? '' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
/* 发送消息,在聊天区追加一条营养师消息气泡 */
|
||||
function sendMsg() {
|
||||
var input = document.getElementById('chat-input');
|
||||
var text = input.value.trim();
|
||||
if (!text) return;
|
||||
var scroll = document.getElementById('chat-scroll');
|
||||
var bubble = document.createElement('div');
|
||||
bubble.style.cssText = 'display:flex;gap:8px;margin-bottom:14px;flex-direction:row-reverse;';
|
||||
bubble.innerHTML = '<div style="width:36px;height:36px;border-radius:50%;background:linear-gradient(135deg,#e8f4ff,#bdd7ff);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;">🥗</div><div style="display:flex;flex-direction:column;align-items:flex-end;"><div style="font-size:11px;color:#999;margin-bottom:4px;">李营养师(我)</div><div style="background:#1677ff;border-radius:12px 0 12px 12px;padding:10px 14px;font-size:14px;color:#fff;max-width:220px;line-height:1.5;">' + text + '</div></div>';
|
||||
scroll.insertBefore(bubble, scroll.lastElementChild);
|
||||
input.value = '';
|
||||
scroll.scrollTop = scroll.scrollHeight;
|
||||
}
|
||||
|
||||
/* 打开底部弹层 */
|
||||
function openSheet(id) { var m = document.getElementById(id); if (m) m.classList.add('active'); }
|
||||
/* 关闭底部弹层 */
|
||||
function closeSheet(id) { var m = document.getElementById(id); if (m) m.classList.remove('active'); }
|
||||
/* 禁忌标签选择 */
|
||||
function toggleTag(el) { el.classList.toggle('active'); }
|
||||
/* 保存方案并关闭弹层 */
|
||||
function savePlan() {
|
||||
closeSheet('sheet-plan');
|
||||
alert('营养方案已保存,系统将自动生成一周专属食谱并推送至员工端(原型演示)');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,249 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师工作台 - 员工营养详情 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #f7f8fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; position: relative; }
|
||||
.nav-back { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 员工信息头 */
|
||||
.emp-header { background: linear-gradient(135deg,#1677ff,#0958d9); padding: 16px 20px; color: #fff; }
|
||||
.emp-header__name { font-size: 18px; font-weight: 700; }
|
||||
.emp-header__meta { font-size: 12px; color: rgba(255,255,255,0.85); margin-top: 4px; }
|
||||
.emp-header__tags { display: flex; gap: 6px; margin-top: 10px; flex-wrap: wrap; }
|
||||
.emp-header__tag { font-size: 11px; padding: 3px 10px; border-radius: 12px; background: rgba(255,255,255,0.2); }
|
||||
/* 区块卡片 */
|
||||
.card { background: #fff; border-radius: 12px; margin: 10px 12px 0; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
|
||||
.card__title { font-size: 14px; font-weight: 700; color: #1a1a1a; margin-bottom: 10px; display: flex; align-items: center; justify-content: space-between; }
|
||||
.card__title-extra { font-size: 12px; color: #1677ff; font-weight: 400; cursor: pointer; }
|
||||
/* 达标概览 */
|
||||
.overview-row { display: flex; }
|
||||
.overview-item { flex: 1; text-align: center; }
|
||||
.overview-item + .overview-item { border-left: 1px solid #f0f0f0; }
|
||||
.overview-item__val { font-size: 18px; font-weight: 700; }
|
||||
.overview-item__val--good { color: #52c41a; }
|
||||
.overview-item__val--bad { color: #ff4d4f; }
|
||||
.overview-item__label { font-size: 11px; color: #999; margin-top: 2px; }
|
||||
/* 膳食宝塔 */
|
||||
.pyramid { display: flex; flex-direction: column; gap: 6px; }
|
||||
.pyramid-row { display: flex; align-items: center; gap: 8px; }
|
||||
.pyramid-row__label { width: 56px; font-size: 12px; color: #666; flex-shrink: 0; }
|
||||
.pyramid-row__bar { flex: 1; height: 10px; background: #f0f0f0; border-radius: 5px; overflow: hidden; }
|
||||
.pyramid-row__fill { height: 100%; border-radius: 5px; }
|
||||
.pyramid-row__val { width: 40px; font-size: 11px; color: #999; text-align: right; flex-shrink: 0; }
|
||||
/* 摄入明细 */
|
||||
.meal-row { display: flex; align-items: center; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid #f5f5f5; }
|
||||
.meal-row:last-child { border-bottom: none; }
|
||||
.meal-row__left { display: flex; align-items: center; gap: 8px; }
|
||||
.meal-row__icon { font-size: 18px; }
|
||||
.meal-row__name { font-size: 14px; color: #1a1a1a; font-weight: 500; }
|
||||
.meal-row__kcal { font-size: 14px; font-weight: 700; color: #fa8c16; }
|
||||
.meal-row__kcal span { font-size: 11px; font-weight: 400; color: #999; }
|
||||
/* 营养方案 */
|
||||
.plan-box { background: #f6ffed; border: 1px solid #b7eb8f; border-radius: 10px; padding: 12px; }
|
||||
.plan-box__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
|
||||
.plan-box__name { font-size: 14px; font-weight: 600; color: #1a1a1a; }
|
||||
.plan-box__status { font-size: 11px; color: #52c41a; font-weight: 600; }
|
||||
.plan-box__row { display: flex; justify-content: space-between; font-size: 12px; color: #666; padding: 3px 0; }
|
||||
.plan-box__row .val { color: #333; font-weight: 600; }
|
||||
/* 方案编辑表单 */
|
||||
.plan-form { background: #fff; border-radius: 12px; margin: 10px 12px 0; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
|
||||
.form-item { margin-bottom: 14px; }
|
||||
.form-item__label { font-size: 13px; font-weight: 600; color: #1a1a1a; margin-bottom: 8px; }
|
||||
.form-input { width: 100%; border: 1px solid #e8e8e8; border-radius: 8px; padding: 10px 12px; font-size: 14px; outline: none; color: #1a1a1a; }
|
||||
.form-input:focus { border-color: #1677ff; }
|
||||
.ratio-row { display: flex; gap: 8px; }
|
||||
.ratio-row .form-input { flex: 1; text-align: center; }
|
||||
.tag-picker { display: flex; gap: 6px; flex-wrap: wrap; }
|
||||
.tag-picker .tag-opt { font-size: 12px; padding: 5px 12px; border-radius: 14px; background: #f5f5f5; color: #666; cursor: pointer; }
|
||||
.tag-picker .tag-opt.active { background: #e6f4ff; color: #1677ff; font-weight: 600; }
|
||||
.btn-primary { width: 100%; padding: 12px; background: #1677ff; color: #fff; border: none; border-radius: 10px; font-size: 15px; font-weight: 600; cursor: pointer; }
|
||||
.btn-ghost { width: 100%; padding: 12px; background: #fff; color: #1677ff; border: 1px solid #1677ff; border-radius: 10px; font-size: 15px; font-weight: 600; cursor: pointer; }
|
||||
.modal-center { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.5); z-index: 200; align-items: center; justify-content: center; }
|
||||
.modal-center.active { display: flex; }
|
||||
.modal-box { width: 280px; background: #fff; border-radius: 16px; overflow: hidden; }
|
||||
.modal-box .modal-title { padding: 20px 20px 8px; font-size: 17px; font-weight: 700; text-align: center; color: #1a1a1a; }
|
||||
.modal-box .modal-body { padding: 8px 20px 20px; font-size: 14px; color: #666; text-align: center; line-height: 1.6; }
|
||||
.modal-box .modal-actions { display: flex; border-top: 1px solid #f0f0f0; }
|
||||
.modal-box .modal-actions button { flex: 1; padding: 14px; font-size: 16px; cursor: pointer; background: none; border: none; }
|
||||
.modal-box .modal-actions button:first-child { color: #666; border-right: 1px solid #f0f0f0; }
|
||||
.modal-box .modal-actions button:last-child { color: #1677ff; font-weight: 600; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 导航栏 -->
|
||||
<div class="nav-bar">
|
||||
<button class="nav-back" onclick="location.href='./employee-list.html'">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title">员工营养详情</span>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
|
||||
<!-- 员工信息头 -->
|
||||
<div class="emp-header">
|
||||
<div style="display:flex;justify-content:space-between;align-items:flex-start;">
|
||||
<div>
|
||||
<div class="emp-header__name">张小红</div>
|
||||
<div class="emp-header__meta">女 · 32岁 · 公司机关 · 办公室 · 162cm · 67.2kg · BMI 25.6</div>
|
||||
</div>
|
||||
<!-- [交互] 点击跳转至: ./employee-health.html 查看员工健康档案 -->
|
||||
<button onclick="location.href='./employee-health.html'" style="display:flex;align-items:center;gap:4px;background:rgba(255,255,255,0.2);border:1px solid rgba(255,255,255,0.4);border-radius:16px;padding:6px 12px;color:#fff;font-size:12px;cursor:pointer;flex-shrink:0;">📋 健康档案</button>
|
||||
</div>
|
||||
<div class="emp-header__tags">
|
||||
<span class="emp-header__tag">减脂需求</span>
|
||||
<span class="emp-header__tag">轻体力活动</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 营养达标概览 -->
|
||||
<div class="card">
|
||||
<div class="card__title">营养达标概览</div>
|
||||
<div class="overview-row">
|
||||
<div class="overview-item"><div class="overview-item__val overview-item__val--bad">68%</div><div class="overview-item__label">综合达标率</div></div>
|
||||
<div class="overview-item"><div class="overview-item__val">22</div><div class="overview-item__label">本月用餐天数</div></div>
|
||||
<div class="overview-item"><div class="overview-item__val">1890</div><div class="overview-item__label">日均摄入(kcal)</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 膳食宝塔评估 -->
|
||||
<div class="card">
|
||||
<div class="card__title">膳食宝塔评估</div>
|
||||
<div class="pyramid">
|
||||
<div class="pyramid-row"><span class="pyramid-row__label">谷薯类</span><div class="pyramid-row__bar"><div class="pyramid-row__fill" style="width:82%;background:#52c41a;"></div></div><span class="pyramid-row__val">82%</span></div>
|
||||
<div class="pyramid-row"><span class="pyramid-row__label">蔬菜水果</span><div class="pyramid-row__bar"><div class="pyramid-row__fill" style="width:45%;background:#fa8c16;"></div></div><span class="pyramid-row__val">45%</span></div>
|
||||
<div class="pyramid-row"><span class="pyramid-row__label">畜禽鱼蛋</span><div class="pyramid-row__bar"><div class="pyramid-row__fill" style="width:110%;background:#ff4d4f;"></div></div><span class="pyramid-row__val">110%</span></div>
|
||||
<div class="pyramid-row"><span class="pyramid-row__label">奶豆坚果</span><div class="pyramid-row__bar"><div class="pyramid-row__fill" style="width:38%;background:#fa8c16;"></div></div><span class="pyramid-row__val">38%</span></div>
|
||||
<div class="pyramid-row"><span class="pyramid-row__label">油盐</span><div class="pyramid-row__bar"><div class="pyramid-row__fill" style="width:135%;background:#ff4d4f;"></div></div><span class="pyramid-row__val">135%</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 今日摄入明细 -->
|
||||
<div class="card">
|
||||
<div class="card__title">今日摄入明细<span class="card__title-extra" onclick="location.href='./employee-diet-history.html'">查看历史 ›</span></div>
|
||||
<div class="meal-row"><div class="meal-row__left"><span class="meal-row__icon">🥣</span><span class="meal-row__name">早餐</span></div><div class="meal-row__kcal">486 <span>kcal</span></div></div>
|
||||
<div class="meal-row"><div class="meal-row__left"><span class="meal-row__icon">🍱</span><span class="meal-row__name">午餐</span></div><div class="meal-row__kcal">720 <span>kcal</span></div></div>
|
||||
<div class="meal-row"><div class="meal-row__left"><span class="meal-row__icon">🍎</span><span class="meal-row__name">加餐</span></div><div class="meal-row__kcal">185 <span>kcal</span></div></div>
|
||||
<div class="meal-row"><div class="meal-row__left"><span class="meal-row__icon">🍽️</span><span class="meal-row__name">晚餐</span></div><div class="meal-row__kcal">560 <span>kcal</span></div></div>
|
||||
</div>
|
||||
|
||||
<!-- 营养方案 -->
|
||||
<div class="card">
|
||||
<div class="card__title">营养方案</div>
|
||||
<div class="plan-box" id="plan-box">
|
||||
<div class="plan-box__head">
|
||||
<span class="plan-box__name">减脂期一周饮食方案</span>
|
||||
<span class="plan-box__status">执行中</span>
|
||||
</div>
|
||||
<div class="plan-box__row"><span>目标热量</span><span class="val">1400 kcal/日</span></div>
|
||||
<div class="plan-box__row"><span>蛋白质 : 脂肪 : 碳水</span><span class="val">25% : 20% : 55%</span></div>
|
||||
<div class="plan-box__row"><span>饮食禁忌</span><span class="val">高糖 · 高脂</span></div>
|
||||
<div class="plan-box__row"><span>执行进度</span><span class="val">第 3 天 / 7 天</span></div>
|
||||
</div>
|
||||
<div style="display:flex;gap:10px;margin-top:12px;">
|
||||
<!-- [交互] 点击跳转至: ./plan-detail.html 查看方案详情 -->
|
||||
<button onclick="location.href='./plan-detail.html'" style="flex:1;padding:12px;background:#fff;color:#1677ff;border:1px solid #1677ff;border-radius:10px;font-size:15px;font-weight:600;cursor:pointer;">查看详情</button>
|
||||
<!-- [交互] 点击展开方案编辑表单 -->
|
||||
<button onclick="togglePlanForm()" style="flex:1;padding:12px;background:#1677ff;color:#fff;border:none;border-radius:10px;font-size:15px;font-weight:600;cursor:pointer;">调整方案</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 方案编辑表单 -->
|
||||
<div class="plan-form" id="plan-form" style="display:none;">
|
||||
<div class="form-item">
|
||||
<div class="form-item__label">目标热量(kcal/日)</div>
|
||||
<input class="form-input" type="text" value="1400" />
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-item__label">三大营养素占比(%)</div>
|
||||
<div class="ratio-row">
|
||||
<input class="form-input" type="text" value="25" placeholder="蛋白" />
|
||||
<input class="form-input" type="text" value="20" placeholder="脂肪" />
|
||||
<input class="form-input" type="text" value="55" placeholder="碳水" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-item__label">饮食禁忌</div>
|
||||
<div class="tag-picker">
|
||||
<span class="tag-opt active" onclick="toggleTag(this)">高糖</span>
|
||||
<span class="tag-opt active" onclick="toggleTag(this)">高脂</span>
|
||||
<span class="tag-opt" onclick="toggleTag(this)">高盐</span>
|
||||
<span class="tag-opt" onclick="toggleTag(this)">高嘌呤</span>
|
||||
<span class="tag-opt" onclick="toggleTag(this)">乳糖</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-item__label">目标描述</div>
|
||||
<input class="form-input" type="text" value="减脂 5kg,控制体脂率" />
|
||||
</div>
|
||||
<!-- [交互] 点击保存方案 -->
|
||||
<button class="btn-primary" onclick="savePlan()">保存方案</button>
|
||||
</div>
|
||||
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 保存成功弹窗 -->
|
||||
<div id="modal-saved" class="modal-center">
|
||||
<div class="modal-box">
|
||||
<div class="modal-title">保存成功</div>
|
||||
<div class="modal-body">营养方案已保存,系统将自动生成一周专属食谱并推送至员工端小程序。</div>
|
||||
<div class="modal-actions">
|
||||
<button onclick="closeModal('modal-saved')">知道了</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
|
||||
/* 展开/收起方案编辑表单 */
|
||||
function togglePlanForm() {
|
||||
var form = document.getElementById('plan-form');
|
||||
var isHidden = form.style.display === 'none';
|
||||
form.style.display = isHidden ? 'block' : 'none';
|
||||
if (isHidden) {
|
||||
/* 展开后自动滚动到表单位置,避免表单在视口外用户看不到 */
|
||||
setTimeout(function() {
|
||||
form.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
|
||||
/* 禁忌标签选择 */
|
||||
function toggleTag(el) {
|
||||
el.classList.toggle('active');
|
||||
}
|
||||
|
||||
/* 保存方案 */
|
||||
function savePlan() {
|
||||
document.getElementById('plan-form').style.display = 'none';
|
||||
openModal('modal-saved');
|
||||
}
|
||||
|
||||
function openModal(id) { var m = document.getElementById(id); if (m) m.classList.add('active'); }
|
||||
function closeModal(id) { var m = document.getElementById(id); if (m) m.classList.remove('active'); }
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,284 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师工作台 - 员工饮食记录 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #f7f8fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; position: relative; }
|
||||
.nav-back { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 员工信息 */
|
||||
.emp-info { background: linear-gradient(135deg,#1677ff,#0958d9); padding: 14px 20px; color: #fff; display: flex; align-items: center; gap: 12px; }
|
||||
.emp-info__avatar { width: 42px; height: 42px; border-radius: 50%; background: rgba(255,255,255,0.25); border: 2px solid rgba(255,255,255,0.4); display: flex; align-items: center; justify-content: center; font-size: 20px; flex-shrink: 0; }
|
||||
.emp-info__name { font-size: 16px; font-weight: 700; }
|
||||
.emp-info__meta { font-size: 12px; color: rgba(255,255,255,0.85); margin-top: 2px; }
|
||||
/* 日期导航 */
|
||||
.date-nav { display: flex; align-items: center; justify-content: center; gap: 8px; padding: 10px 16px; background: #fff; border-bottom: 1px solid #f0f0f0; position: relative; flex-shrink: 0; }
|
||||
.date-nav__arrow { width: 32px; height: 32px; border-radius: 50%; background: #f5f5f5; display: flex; align-items: center; justify-content: center; cursor: pointer; border: none; color: #666; font-size: 16px; flex-shrink: 0; }
|
||||
.date-nav__arrow:active { background: #e6f4ff; }
|
||||
.date-nav__text { font-size: 15px; font-weight: 600; color: #1a1a1a; min-width: 110px; text-align: center; }
|
||||
.date-nav__cal { width: 28px; height: 28px; border-radius: 6px; background: none; display: flex; align-items: center; justify-content: center; cursor: pointer; border: none; font-size: 16px; flex-shrink: 0; color: #1677ff; }
|
||||
/* 日历面板 */
|
||||
.cal-panel { display: none; position: absolute; top: 42px; left: 16px; right: 16px; background: #fff; border-radius: 14px; box-shadow: 0 8px 30px rgba(0,0,0,0.15); z-index: 100; padding: 16px; }
|
||||
.cal-panel.active { display: block; }
|
||||
.cal-panel__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
|
||||
.cal-panel__month { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.cal-panel__nav { width: 28px; height: 28px; border-radius: 50%; border: none; background: #f5f5f5; cursor: pointer; font-size: 14px; color: #666; display: flex; align-items: center; justify-content: center; }
|
||||
.cal-panel__weekdays { display: flex; margin-bottom: 6px; }
|
||||
.cal-panel__weekday { flex: 1; text-align: center; font-size: 11px; color: #999; padding: 4px 0; }
|
||||
.cal-panel__grid { display: flex; flex-wrap: wrap; }
|
||||
.cal-panel__day { width: calc(100% / 7); text-align: center; padding: 8px 0; font-size: 13px; color: #333; cursor: pointer; border-radius: 8px; }
|
||||
.cal-panel__day--other { color: #ddd; }
|
||||
.cal-panel__day:hover { background: #f5f5f5; }
|
||||
.cal-panel__day--today { font-weight: 700; color: #1677ff; }
|
||||
.cal-panel__day--selected { background: #1677ff; color: #fff; font-weight: 700; }
|
||||
/* 摄入汇总 */
|
||||
.summary-card { background: #fff; border-radius: 12px; margin: 10px 12px 0; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
|
||||
.summary-card__title { font-size: 14px; font-weight: 700; color: #1a1a1a; margin-bottom: 10px; }
|
||||
.summary-row { display: flex; }
|
||||
.summary-item { flex: 1; text-align: center; }
|
||||
.summary-item + .summary-item { border-left: 1px solid #f0f0f0; }
|
||||
.summary-item__val { font-size: 18px; font-weight: 700; }
|
||||
.summary-item__val--over { color: #ff4d4f; }
|
||||
.summary-item__val--ok { color: #52c41a; }
|
||||
.summary-item__label { font-size: 11px; color: #999; margin-top: 2px; }
|
||||
/* 三餐明细 */
|
||||
.section-title { font-size: 14px; font-weight: 700; color: #1a1a1a; margin: 14px 12px 6px; }
|
||||
.meal-card { background: #fff; border-radius: 12px; margin: 8px 12px 0; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
|
||||
.meal-card__head { display: flex; align-items: center; margin-bottom: 8px; }
|
||||
.meal-card__name { font-size: 14px; font-weight: 600; color: #1a1a1a; }
|
||||
.meal-card__time { font-size: 12px; color: #999; margin-left: 8px; }
|
||||
.meal-card__kcal { margin-left: auto; font-size: 15px; font-weight: 700; color: #fa8c16; }
|
||||
.meal-card__kcal span { font-size: 11px; font-weight: 400; color: #999; }
|
||||
.meal-card__foods { display: flex; flex-wrap: wrap; gap: 6px; }
|
||||
.food-tag { font-size: 12px; padding: 4px 10px; border-radius: 12px; background: #f0f6ff; color: #1677ff; }
|
||||
.meal-card__source { margin-top: 8px; font-size: 11px; color: #999; }
|
||||
.tag { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 10px; font-weight: 600; }
|
||||
.tag-blue { background: #e6f4ff; color: #1677ff; }
|
||||
.tag-purple { background: #f9f0ff; color: #722ed1; }
|
||||
/* 空状态 */
|
||||
.empty-state { text-align: center; padding: 40px 0; color: #bbb; font-size: 13px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 导航栏 -->
|
||||
<div class="nav-bar">
|
||||
<button class="nav-back" onclick="location.href='./employee-detail.html'">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title">饮食记录</span>
|
||||
</div>
|
||||
|
||||
<!-- 员工信息 -->
|
||||
<div class="emp-info">
|
||||
<div class="emp-info__avatar">👩</div>
|
||||
<div>
|
||||
<div class="emp-info__name">张小红</div>
|
||||
<div class="emp-info__meta">女 · 32岁 · 公司机关 · 办公室</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 日期导航 -->
|
||||
<div class="date-nav">
|
||||
<button class="date-nav__arrow" onclick="changeDate(-1)">‹</button>
|
||||
<button class="date-nav__cal" onclick="toggleCalPanel()">📅</button>
|
||||
<span class="date-nav__text" id="dateText">2026-06-22</span>
|
||||
<button class="date-nav__arrow" onclick="changeDate(1)">›</button>
|
||||
<!-- 日历选择面板 -->
|
||||
<div class="cal-panel" id="calPanel">
|
||||
<div class="cal-panel__head">
|
||||
<button class="cal-panel__nav" onclick="calPrevMonth(event)">‹</button>
|
||||
<span class="cal-panel__month" id="calMonthLabel">2026年6月</span>
|
||||
<button class="cal-panel__nav" onclick="calNextMonth(event)">›</button>
|
||||
</div>
|
||||
<div class="cal-panel__weekdays">
|
||||
<div class="cal-panel__weekday">日</div><div class="cal-panel__weekday">一</div><div class="cal-panel__weekday">二</div><div class="cal-panel__weekday">三</div><div class="cal-panel__weekday">四</div><div class="cal-panel__weekday">五</div><div class="cal-panel__weekday">六</div>
|
||||
</div>
|
||||
<div class="cal-panel__grid" id="calGrid"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
<!-- 摄入汇总 -->
|
||||
<div class="summary-card" id="summary-card">
|
||||
<div class="summary-card__title">每日摄入汇总</div>
|
||||
<div class="summary-row" id="summary-row"></div>
|
||||
</div>
|
||||
|
||||
<!-- 当日三餐明细 -->
|
||||
<div class="section-title">当日三餐明细</div>
|
||||
<div id="meal-list"></div>
|
||||
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
|
||||
/* ===== 饮食记录历史数据 ===== */
|
||||
var DIET_HISTORY = {
|
||||
'2026-06-22': {
|
||||
target: 1400,
|
||||
meals: [
|
||||
{ icon: '🥣', name: '早餐', time: '07:30', kcal: 486, source: '智记', cls: 'tag-blue', foods: ['全麦面包 80g', '水煮蛋 60g', '牛奶 250ml'] },
|
||||
{ icon: '🍱', name: '午餐', time: '12:15', kcal: 720, source: '智记', cls: 'tag-blue', foods: ['清蒸鲈鱼 150g', '杂粮饭 200g', '蒜蓉西兰花 150g'] },
|
||||
{ icon: '🍎', name: '加餐', time: '15:40', kcal: 185, source: '自记', cls: 'tag-purple', foods: ['苹果 1个', '坚果 30g'] },
|
||||
{ icon: '🍽️', name: '晚餐', time: '18:30', kcal: 560, source: '智记', cls: 'tag-blue', foods: ['香煎鸡胸 120g', '蔬菜沙拉 200g', '小米粥 200g'] }
|
||||
]
|
||||
},
|
||||
'2026-06-21': {
|
||||
target: 1400,
|
||||
meals: [
|
||||
{ icon: '🥣', name: '早餐', time: '07:42', kcal: 450, source: '智记', cls: 'tag-blue', foods: ['燕麦牛奶 300ml', '水煮蛋 60g'] },
|
||||
{ icon: '🍱', name: '午餐', time: '12:08', kcal: 680, source: '智记', cls: 'tag-blue', foods: ['白灼虾 150g', '糙米饭 200g', '清炒时蔬 150g'] },
|
||||
{ icon: '🍎', name: '加餐', time: '15:30', kcal: 120, source: '自记', cls: 'tag-purple', foods: ['酸奶 1杯'] },
|
||||
{ icon: '🍽️', name: '晚餐', time: '18:45', kcal: 520, source: '智记', cls: 'tag-blue', foods: ['蔬菜豆腐汤 300g', '杂粮馒头 100g'] }
|
||||
]
|
||||
},
|
||||
'2026-06-20': {
|
||||
target: 1400,
|
||||
meals: [
|
||||
{ icon: '🥣', name: '早餐', time: '07:35', kcal: 470, source: '智记', cls: 'tag-blue', foods: ['水煮蛋 60g', '豆浆 250ml', '蒸红薯 100g'] },
|
||||
{ icon: '🍱', name: '午餐', time: '12:20', kcal: 660, source: '智记', cls: 'tag-blue', foods: ['卤牛肉 100g', '荞麦面 200g', '凉拌黄瓜 150g'] },
|
||||
{ icon: '🍽️', name: '晚餐', time: '18:20', kcal: 540, source: '智记', cls: 'tag-blue', foods: ['清炒时蔬 200g', '玉米 150g', '菌菇汤 200g'] }
|
||||
]
|
||||
},
|
||||
'2026-06-19': {
|
||||
target: 1400,
|
||||
meals: [
|
||||
{ icon: '🥣', name: '早餐', time: '07:50', kcal: 430, source: '智记', cls: 'tag-blue', foods: ['杂粮粥 300g', '水煮蛋 60g'] },
|
||||
{ icon: '🍱', name: '午餐', time: '12:10', kcal: 700, source: '智记', cls: 'tag-blue', foods: ['香煎鸡胸 150g', '藜麦饭 150g', '西兰花 150g'] },
|
||||
{ icon: '🍎', name: '加餐', time: '16:00', kcal: 150, source: '自记', cls: 'tag-purple', foods: ['虾仁沙拉 200g'] },
|
||||
{ icon: '🍽️', name: '晚餐', time: '18:40', kcal: 480, source: '智记', cls: 'tag-blue', foods: ['蔬菜沙拉 200g', '全麦面包 50g'] }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
var currentDate = new Date(2026, 5, 22);
|
||||
var calViewYear = currentDate.getFullYear();
|
||||
var calViewMonth = currentDate.getMonth();
|
||||
|
||||
/* 计算某天总摄入 */
|
||||
function dayTotal(data) {
|
||||
return data.meals.reduce(function(s, m) { return s + m.kcal; }, 0);
|
||||
}
|
||||
|
||||
/* 格式化日期为 YYYY-MM-DD */
|
||||
function fmtDate(d) {
|
||||
var y = d.getFullYear();
|
||||
var m = String(d.getMonth() + 1).padStart(2, '0');
|
||||
var day = String(d.getDate()).padStart(2, '0');
|
||||
return y + '-' + m + '-' + day;
|
||||
}
|
||||
|
||||
/* 渲染当前日期的饮食记录 */
|
||||
function render() {
|
||||
var key = fmtDate(currentDate);
|
||||
document.getElementById('dateText').textContent = key;
|
||||
var data = DIET_HISTORY[key];
|
||||
|
||||
if (!data) {
|
||||
document.getElementById('summary-card').style.display = 'none';
|
||||
document.getElementById('meal-list').innerHTML = '<div class="empty-state">当日暂无饮食记录</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('summary-card').style.display = 'block';
|
||||
var total = dayTotal(data);
|
||||
var diff = total - data.target;
|
||||
var diffText = diff > 0 ? '+' + diff : diff;
|
||||
var diffCls = diff > 0 ? 'summary-item__val--over' : 'summary-item__val--ok';
|
||||
|
||||
document.getElementById('summary-row').innerHTML =
|
||||
'<div class="summary-item"><div class="summary-item__val" style="color:#1677ff;">' + total + '</div><div class="summary-item__label">总摄入 kcal</div></div>' +
|
||||
'<div class="summary-item"><div class="summary-item__val" style="color:#333;">' + data.target + '</div><div class="summary-item__label">目标 kcal</div></div>' +
|
||||
'<div class="summary-item"><div class="summary-item__val ' + diffCls + '">' + diffText + '</div><div class="summary-item__label">与目标差值</div></div>';
|
||||
|
||||
var mealsHtml = data.meals.map(function(m) {
|
||||
var foodsHtml = m.foods.map(function(f) {
|
||||
return '<span class="food-tag">' + f + '</span>';
|
||||
}).join('');
|
||||
return '<div class="meal-card">' +
|
||||
'<div class="meal-card__head"><span class="meal-card__name">' + m.icon + ' ' + m.name + '</span><span class="meal-card__time">' + m.time + '</span><span class="meal-card__kcal">' + m.kcal + ' <span>kcal</span></span></div>' +
|
||||
'<div class="meal-card__foods">' + foodsHtml + '</div>' +
|
||||
'<div class="meal-card__source"><span class="tag ' + m.cls + '">' + m.source + '</span></div>' +
|
||||
'</div>';
|
||||
}).join('');
|
||||
document.getElementById('meal-list').innerHTML = mealsHtml;
|
||||
}
|
||||
|
||||
/* 切换日期 */
|
||||
function changeDate(delta) {
|
||||
currentDate.setDate(currentDate.getDate() + delta);
|
||||
calViewYear = currentDate.getFullYear();
|
||||
calViewMonth = currentDate.getMonth();
|
||||
render();
|
||||
}
|
||||
|
||||
/* 日历面板 */
|
||||
function toggleCalPanel() {
|
||||
var panel = document.getElementById('calPanel');
|
||||
if (panel.classList.contains('active')) { panel.classList.remove('active'); return; }
|
||||
calViewYear = currentDate.getFullYear();
|
||||
calViewMonth = currentDate.getMonth();
|
||||
renderCal();
|
||||
panel.classList.add('active');
|
||||
}
|
||||
function calPrevMonth(e) { e.stopPropagation(); calViewMonth--; if (calViewMonth < 0) { calViewMonth = 11; calViewYear--; } renderCal(); }
|
||||
function calNextMonth(e) { e.stopPropagation(); calViewMonth++; if (calViewMonth > 11) { calViewMonth = 0; calViewYear++; } renderCal(); }
|
||||
|
||||
function renderCal() {
|
||||
document.getElementById('calMonthLabel').textContent = calViewYear + '年' + (calViewMonth + 1) + '月';
|
||||
var firstDay = new Date(calViewYear, calViewMonth, 1).getDay();
|
||||
var daysInMonth = new Date(calViewYear, calViewMonth + 1, 0).getDate();
|
||||
var today = new Date(2026, 5, 22);
|
||||
var html = '';
|
||||
for (var i = 0; i < firstDay; i++) { html += '<div class="cal-panel__day cal-panel__day--other"></div>'; }
|
||||
for (var d = 1; d <= daysInMonth; d++) {
|
||||
var cls = 'cal-panel__day';
|
||||
if (calViewYear === today.getFullYear() && calViewMonth === today.getMonth() && d === today.getDate()) cls += ' cal-panel__day--today';
|
||||
if (calViewYear === currentDate.getFullYear() && calViewMonth === currentDate.getMonth() && d === currentDate.getDate()) cls += ' cal-panel__day--selected';
|
||||
html += '<div class="' + cls + '" onclick="selectCalDay(event,' + d + ')">' + d + '</div>';
|
||||
}
|
||||
document.getElementById('calGrid').innerHTML = html;
|
||||
}
|
||||
|
||||
function selectCalDay(e, day) {
|
||||
e.stopPropagation();
|
||||
currentDate = new Date(calViewYear, calViewMonth, day);
|
||||
calViewYear = currentDate.getFullYear();
|
||||
calViewMonth = currentDate.getMonth();
|
||||
render();
|
||||
document.getElementById('calPanel').classList.remove('active');
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
if (!e.target.closest('.date-nav') && !e.target.closest('.cal-panel')) {
|
||||
document.getElementById('calPanel').classList.remove('active');
|
||||
}
|
||||
});
|
||||
|
||||
/* 初始化渲染 */
|
||||
render();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,269 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师工作台 - 员工健康档案 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #f7f8fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; position: relative; }
|
||||
.nav-back { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 员工卡片 */
|
||||
.emp-card { background: linear-gradient(135deg,#1677ff,#0958d9); padding: 16px 20px; color: #fff; }
|
||||
.emp-card__row { display: flex; align-items: center; gap: 12px; }
|
||||
.emp-card__avatar { width: 48px; height: 48px; border-radius: 50%; background: rgba(255,255,255,0.25); border: 2px solid rgba(255,255,255,0.4); display: flex; align-items: center; justify-content: center; font-size: 24px; flex-shrink: 0; }
|
||||
.emp-card__name { font-size: 18px; font-weight: 700; }
|
||||
.emp-card__meta { font-size: 12px; color: rgba(255,255,255,0.85); margin-top: 2px; }
|
||||
.emp-card__tags { display: flex; gap: 6px; margin-top: 10px; flex-wrap: wrap; }
|
||||
.emp-card__tag { font-size: 11px; padding: 3px 10px; border-radius: 12px; background: rgba(255,255,255,0.2); }
|
||||
/* 卡片区块 */
|
||||
.card { background: #fff; border-radius: 12px; margin: 10px 12px 0; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
|
||||
.card__title { font-size: 14px; font-weight: 700; color: #1a1a1a; margin-bottom: 10px; display: flex; align-items: center; gap: 6px; }
|
||||
.card__title .readonly { font-size: 10px; color: #999; font-weight: 400; background: #f5f5f5; padding: 1px 6px; border-radius: 8px; }
|
||||
/* 关键摘要 */
|
||||
.alert-item { display: flex; align-items: flex-start; gap: 8px; padding: 8px 0; border-bottom: 1px solid #f5f5f5; }
|
||||
.alert-item:last-child { border-bottom: none; }
|
||||
.alert-item__label { font-size: 12px; color: #999; width: 64px; flex-shrink: 0; margin-top: 2px; }
|
||||
.alert-item__tags { flex: 1; display: flex; flex-wrap: wrap; gap: 6px; }
|
||||
.atag { font-size: 12px; padding: 3px 10px; border-radius: 12px; }
|
||||
.atag--danger { background: #fff1f0; color: #f5222d; }
|
||||
.atag--warn { background: #fff7e6; color: #fa8c16; }
|
||||
.atag--blue { background: #f0f7ff; color: #1677ff; }
|
||||
.atag--normal { background: #f6ffed; color: #52c41a; }
|
||||
/* 信息行 */
|
||||
.info-row { display: flex; align-items: center; justify-content: space-between; padding: 9px 0; border-bottom: 0.5px solid #f5f5f5; }
|
||||
.info-row:last-child { border-bottom: none; }
|
||||
.info-row .i-label { font-size: 13px; color: #666; }
|
||||
.info-row .i-value { font-size: 13px; color: #333; font-weight: 500; }
|
||||
.info-row .i-value .i-unit { font-size: 11px; color: #999; margin-left: 2px; }
|
||||
/* 标签组 */
|
||||
.tag-group { display: flex; flex-wrap: wrap; gap: 6px; }
|
||||
.tag-group .tg { font-size: 12px; padding: 4px 10px; border-radius: 12px; background: #f0f7ff; color: #1677ff; }
|
||||
.tag-group .tg.warn { background: #fff7e6; color: #fa8c16; }
|
||||
.tag-group .tg.danger { background: #fff1f0; color: #f5222d; }
|
||||
.tag-group .tg.green { background: #f6ffed; color: #52c41a; }
|
||||
/* 子标签 */
|
||||
.sub-label { font-size: 12px; color: #999; margin-bottom: 6px; }
|
||||
.sub-block { padding: 8px 0; border-bottom: 0.5px solid #f5f5f5; }
|
||||
.sub-block:last-child { border-bottom: none; }
|
||||
/* 餐次配比 */
|
||||
.ratio-bar { display: flex; height: 10px; border-radius: 5px; overflow: hidden; background: #f0f0f0; margin-bottom: 10px; }
|
||||
.ratio-bar .ratio-seg { height: 100%; }
|
||||
.ratio-list { display: flex; }
|
||||
.ratio-list .ratio-item { flex: 1; display: flex; align-items: center; gap: 4px; font-size: 12px; }
|
||||
.ratio-list .ratio-item .r-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
||||
.ratio-list .ratio-item .r-name { color: #999; }
|
||||
.ratio-list .ratio-item .r-val { color: #333; font-weight: 600; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 导航栏 -->
|
||||
<div class="nav-bar">
|
||||
<!-- [交互] 点击返回上一页 -->
|
||||
<button class="nav-back" onclick="history.back()">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title">员工健康档案</span>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
|
||||
<!-- 员工卡片 -->
|
||||
<div class="emp-card">
|
||||
<div class="emp-card__row">
|
||||
<div class="emp-card__avatar">👩</div>
|
||||
<div>
|
||||
<div class="emp-card__name">张小红</div>
|
||||
<div class="emp-card__meta">女 · 32岁 · 公司机关 · 办公室 · 162cm · 67.2kg · BMI 25.6</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="emp-card__tags">
|
||||
<span class="emp-card__tag">减脂需求</span>
|
||||
<span class="emp-card__tag">中度活动</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 关键摘要(营养师定制方案重点参考) -->
|
||||
<div class="card" style="border-left:3px solid #1677ff;">
|
||||
<div class="card__title">🎯 方案定制关键信息</div>
|
||||
<div class="alert-item">
|
||||
<span class="alert-item__label">体检异常</span>
|
||||
<div class="alert-item__tags">
|
||||
<span class="atag atag--warn">尿酸 380 偏高</span>
|
||||
<span class="atag atag--normal">血压/血糖正常</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert-item">
|
||||
<span class="alert-item__label">疾病史</span>
|
||||
<div class="alert-item__tags">
|
||||
<span class="atag atag--danger">胃炎</span>
|
||||
<span class="atag atag--danger">高尿酸</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert-item">
|
||||
<span class="alert-item__label">用药情况</span>
|
||||
<div class="alert-item__tags">
|
||||
<span class="atag atag--blue">别嘌醇片</span>
|
||||
<span class="atag atag--blue">依那普利</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert-item">
|
||||
<span class="alert-item__label">过敏原</span>
|
||||
<div class="alert-item__tags">
|
||||
<span class="atag atag--danger">🥜 花生</span>
|
||||
<span class="atag atag--danger">🦐 海鲜</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert-item">
|
||||
<span class="alert-item__label">饮食禁忌</span>
|
||||
<div class="alert-item__tags">
|
||||
<span class="atag atag--warn">🌶️ 少辣</span>
|
||||
<span class="atag atag--warn">🧂 低盐</span>
|
||||
<span class="atag atag--warn">🍬 控糖</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 1. 身体指标 -->
|
||||
<div class="card">
|
||||
<div class="card__title">📏 身体指标</div>
|
||||
<div class="info-row"><span class="i-label">身高</span><span class="i-value">172<span class="i-unit">cm</span></span></div>
|
||||
<div class="info-row"><span class="i-label">体重</span><span class="i-value">68<span class="i-unit">kg</span></span></div>
|
||||
<div class="info-row"><span class="i-label">BMI</span><span class="i-value">23.0 <span style="color:#52c41a;font-size:11px;">正常</span></span></div>
|
||||
<div class="info-row"><span class="i-label">体脂率</span><span class="i-value">18.5% <span style="color:#52c41a;font-size:11px;">标准</span></span></div>
|
||||
<div class="info-row"><span class="i-label">活动水平</span><span class="i-value">中度活动<span class="i-unit">每周3-5次</span></span></div>
|
||||
</div>
|
||||
|
||||
<!-- 2. 体检信息 -->
|
||||
<div class="card">
|
||||
<div class="card__title">🩺 体检信息<span class="readonly">只读</span></div>
|
||||
<div class="info-row"><span class="i-label">体检日期</span><span class="i-value">2026-03-15</span></div>
|
||||
<div class="info-row"><span class="i-label">血压</span><span class="i-value">125/80<span class="i-unit">mmHg</span></span></div>
|
||||
<div class="info-row"><span class="i-label">空腹血糖</span><span class="i-value">5.2<span class="i-unit">mmol/L</span></span></div>
|
||||
<div class="info-row"><span class="i-label">血脂</span><span class="i-value">正常</span></div>
|
||||
<div class="info-row"><span class="i-label">尿酸</span><span class="i-value" style="color:#fa8c16;">380<span class="i-unit">μmol/L</span> <span style="color:#fa8c16;font-size:11px;">偏高</span></span></div>
|
||||
<div class="info-row"><span class="i-label">肝功能</span><span class="i-value">正常</span></div>
|
||||
<div class="info-row"><span class="i-label">肾功能</span><span class="i-value">正常</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 3. 疾病信息 -->
|
||||
<div class="card">
|
||||
<div class="card__title">🏥 疾病信息</div>
|
||||
<div class="sub-block">
|
||||
<div class="sub-label">疾病史</div>
|
||||
<div class="tag-group"><span class="tg danger">胃炎</span><span class="tg danger">高尿酸</span></div>
|
||||
</div>
|
||||
<div class="sub-block">
|
||||
<div class="sub-label">用药情况</div>
|
||||
<div class="tag-group"><span class="tg">别嘌醇片</span><span class="tg">依那普利</span></div>
|
||||
</div>
|
||||
<div class="sub-block">
|
||||
<div class="sub-label">家族病史</div>
|
||||
<div class="tag-group"><span class="tg warn">高血压</span><span class="tg warn">糖尿病</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 4. 口味偏好 -->
|
||||
<div class="card">
|
||||
<div class="card__title">👅 口味偏好</div>
|
||||
<div class="sub-block">
|
||||
<div class="sub-label">口味偏好</div>
|
||||
<div class="tag-group"><span class="tg">偏辣</span></div>
|
||||
</div>
|
||||
<div class="sub-block">
|
||||
<div class="sub-label">地域菜系</div>
|
||||
<div class="tag-group"><span class="tg">川菜</span><span class="tg">湘菜</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 5. 禁忌关联 -->
|
||||
<div class="card">
|
||||
<div class="card__title">🚫 禁忌关联</div>
|
||||
<div class="sub-block">
|
||||
<div class="sub-label">饮食禁忌</div>
|
||||
<div class="tag-group"><span class="tg warn">🌶️ 少辣</span><span class="tg warn">🧂 低盐</span><span class="tg warn">🍬 控糖</span></div>
|
||||
</div>
|
||||
<div class="sub-block">
|
||||
<div class="sub-label">过敏原</div>
|
||||
<div class="tag-group"><span class="tg danger">🥜 花生</span><span class="tg danger">🦐 海鲜</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 6. 动态生理 -->
|
||||
<div class="card">
|
||||
<div class="card__title">📊 动态生理<span class="readonly">只读</span></div>
|
||||
<div class="info-row"><span class="i-label">日均运动量</span><span class="i-value">6000步/日</span></div>
|
||||
<div class="info-row"><span class="i-label">静息心率</span><span class="i-value">68<span class="i-unit">bpm</span></span></div>
|
||||
<div class="info-row"><span class="i-label">平均睡眠</span><span class="i-value">7.5h</span></div>
|
||||
<div class="info-row"><span class="i-label">压力指数</span><span class="i-value">低</span></div>
|
||||
<div class="info-row"><span class="i-label">数据来源</span><span class="i-value">智能手环</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 7. 菜品偏好 -->
|
||||
<div class="card">
|
||||
<div class="card__title">🍲 菜品偏好</div>
|
||||
<div class="sub-block">
|
||||
<div class="sub-label">常点菜品</div>
|
||||
<div class="tag-group"><span class="tg green">宫保鸡丁</span><span class="tg green">清炒西兰花</span><span class="tg green">杂粮饭</span></div>
|
||||
</div>
|
||||
<div class="sub-block">
|
||||
<div class="sub-label">忌口菜品</div>
|
||||
<div class="tag-group"><span class="tg warn">油炸花生</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 8. 妈妈味道 -->
|
||||
<div class="card">
|
||||
<div class="card__title">🏡 妈妈味道</div>
|
||||
<div class="info-row"><span class="i-label">家乡</span><span class="i-value">四川成都</span></div>
|
||||
<div class="sub-block">
|
||||
<div class="sub-label">口味标签</div>
|
||||
<div class="tag-group"><span class="tg warn">麻辣</span><span class="tg warn">红油</span><span class="tg warn">鲜香</span></div>
|
||||
</div>
|
||||
<div class="sub-block">
|
||||
<div class="sub-label">思乡菜清单</div>
|
||||
<div class="tag-group"><span class="tg warn">回锅肉</span><span class="tg warn">麻婆豆腐</span><span class="tg warn">水煮鱼</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 9. 餐次配比 -->
|
||||
<div class="card">
|
||||
<div class="card__title">⚖️ 餐次配比</div>
|
||||
<div class="ratio-bar">
|
||||
<span class="ratio-seg" style="width:30%; background:#FFB84C;"></span>
|
||||
<span class="ratio-seg" style="width:40%; background:#52C41A;"></span>
|
||||
<span class="ratio-seg" style="width:30%; background:#1677FF;"></span>
|
||||
</div>
|
||||
<div class="ratio-list">
|
||||
<div class="ratio-item"><span class="r-dot" style="background:#FFB84C;"></span><span class="r-name">早餐</span><span class="r-val">30%</span></div>
|
||||
<div class="ratio-item"><span class="r-dot" style="background:#52C41A;"></span><span class="r-name">午餐</span><span class="r-val">40%</span></div>
|
||||
<div class="ratio-item"><span class="r-dot" style="background:#1677FF;"></span><span class="r-name">晚餐</span><span class="r-val">30%</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,192 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师工作台 - 员工营养管理 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #f7f8fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; position: relative; }
|
||||
.nav-back { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 搜索与筛选 */
|
||||
.search-bar { background: #fff; padding: 10px 16px; border-bottom: 1px solid #f0f0f0; flex-shrink: 0; }
|
||||
.search-input { display: flex; align-items: center; gap: 8px; background: #f5f5f5; border-radius: 20px; padding: 8px 14px; }
|
||||
.search-input input { flex: 1; border: none; background: none; font-size: 14px; outline: none; color: #1a1a1a; }
|
||||
/* Tab */
|
||||
.seg-tabs { display: flex; background: #fff; border-bottom: 1px solid #f0f0f0; flex-shrink: 0; }
|
||||
.seg-tab { flex: 1; text-align: center; padding: 12px 0; font-size: 14px; color: #666; cursor: pointer; border-bottom: 2px solid transparent; }
|
||||
.seg-tab.active { color: #1677ff; border-bottom-color: #1677ff; font-weight: 600; }
|
||||
.seg-tab .badge { display: inline-block; background: #e8e8e8; color: #666; font-size: 10px; font-weight: 700; min-width: 16px; height: 16px; border-radius: 8px; padding: 0 4px; margin-left: 4px; vertical-align: middle; line-height: 16px; }
|
||||
.seg-tab.active .badge { background: #e6f4ff; color: #1677ff; }
|
||||
/* 员工卡片 */
|
||||
.employee-card { background: #fff; border-radius: 12px; margin: 10px 12px 0; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); display: flex; align-items: center; gap: 10px; cursor: pointer; }
|
||||
.employee-card:active { transform: scale(0.98); }
|
||||
.employee-card__avatar { width: 44px; height: 44px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 20px; flex-shrink: 0; }
|
||||
.employee-card__info { flex: 1; min-width: 0; }
|
||||
.employee-card__name { font-size: 15px; font-weight: 600; color: #1a1a1a; }
|
||||
.employee-card__meta { font-size: 12px; color: #999; margin-top: 3px; display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
.employee-card__rate { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
|
||||
.employee-card__rate-num { font-size: 15px; font-weight: 700; }
|
||||
.employee-card__rate-num--good { color: #52c41a; }
|
||||
.employee-card__rate-num--bad { color: #ff4d4f; }
|
||||
.tag { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 10px; font-weight: 600; }
|
||||
.tag-green { background: #f6ffed; color: #52c41a; }
|
||||
.tag-orange { background: #fff7e6; color: #fa8c16; }
|
||||
.tag-red { background: #fff1f0; color: #ff4d4f; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 导航栏 -->
|
||||
<div class="nav-bar">
|
||||
<button class="nav-back" onclick="location.href='./index.html'">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title">员工营养管理</span>
|
||||
</div>
|
||||
|
||||
<!-- 搜索与筛选 -->
|
||||
<div class="search-bar">
|
||||
<div class="search-input">
|
||||
<span style="font-size:14px;">🔍</span>
|
||||
<input type="text" placeholder="搜索员工姓名 / 工号" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab:全部 / 达标 / 未达标 -->
|
||||
<div class="seg-tabs">
|
||||
<div class="seg-tab active" onclick="switchTab(this,'panel-all')">全部<span class="badge">86</span></div>
|
||||
<div class="seg-tab" onclick="switchTab(this,'panel-good')">达标<span class="badge">62</span></div>
|
||||
<div class="seg-tab" onclick="switchTab(this,'panel-bad')">未达标<span class="badge">24</span></div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
<!-- 全部列表 -->
|
||||
<div id="panel-all">
|
||||
<!-- [交互] 点击跳转至: ./employee-detail.html -->
|
||||
<div class="employee-card" onclick="location.href='./employee-detail.html'">
|
||||
<div class="employee-card__avatar" style="background:linear-gradient(135deg,#ffe0e0,#ffb3b3);">👩</div>
|
||||
<div class="employee-card__info">
|
||||
<div class="employee-card__name">张小红</div>
|
||||
<div class="employee-card__meta"><span>女 · 32岁</span><span>公司机关 · 办公室</span></div>
|
||||
</div>
|
||||
<div class="employee-card__rate"><span class="employee-card__rate-num employee-card__rate-num--bad">68%</span><span class="tag tag-red">未达标</span></div>
|
||||
</div>
|
||||
<div class="employee-card" onclick="location.href='./employee-detail.html'">
|
||||
<div class="employee-card__avatar" style="background:linear-gradient(135deg,#e8f4ff,#bdd7ff);">👨</div>
|
||||
<div class="employee-card__info">
|
||||
<div class="employee-card__name">李建国</div>
|
||||
<div class="employee-card__meta"><span>男 · 45岁</span><span>采油一厂 · 技术部</span></div>
|
||||
</div>
|
||||
<div class="employee-card__rate"><span class="employee-card__rate-num employee-card__rate-num--bad">71%</span><span class="tag tag-orange">待干预</span></div>
|
||||
</div>
|
||||
<div class="employee-card" onclick="location.href='./employee-detail.html'">
|
||||
<div class="employee-card__avatar" style="background:linear-gradient(135deg,#f6ffed,#b7eb8f);">👩</div>
|
||||
<div class="employee-card__info">
|
||||
<div class="employee-card__name">王芳</div>
|
||||
<div class="employee-card__meta"><span>女 · 28岁</span><span>信息技术中心 · 数据部</span></div>
|
||||
</div>
|
||||
<div class="employee-card__rate"><span class="employee-card__rate-num employee-card__rate-num--good">92%</span><span class="tag tag-green">达标</span></div>
|
||||
</div>
|
||||
<div class="employee-card" onclick="location.href='./employee-detail.html'">
|
||||
<div class="employee-card__avatar" style="background:linear-gradient(135deg,#e8f4ff,#bdd7ff);">👨</div>
|
||||
<div class="employee-card__info">
|
||||
<div class="employee-card__name">陈伟</div>
|
||||
<div class="employee-card__meta"><span>男 · 36岁</span><span>安全环保部 · 安环部</span></div>
|
||||
</div>
|
||||
<div class="employee-card__rate"><span class="employee-card__rate-num employee-card__rate-num--good">88%</span><span class="tag tag-green">达标</span></div>
|
||||
</div>
|
||||
<div class="employee-card" onclick="location.href='./employee-detail.html'">
|
||||
<div class="employee-card__avatar" style="background:linear-gradient(135deg,#fff7e6,#ffd591);">👨</div>
|
||||
<div class="employee-card__info">
|
||||
<div class="employee-card__name">赵志强</div>
|
||||
<div class="employee-card__meta"><span>男 · 61岁</span><span>公司机关 · 后勤部</span></div>
|
||||
</div>
|
||||
<div class="employee-card__rate"><span class="employee-card__rate-num employee-card__rate-num--bad">59%</span><span class="tag tag-red">未达标</span></div>
|
||||
</div>
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 达标列表 -->
|
||||
<div id="panel-good" style="display:none;">
|
||||
<div class="employee-card" onclick="location.href='./employee-detail.html'">
|
||||
<div class="employee-card__avatar" style="background:linear-gradient(135deg,#f6ffed,#b7eb8f);">👩</div>
|
||||
<div class="employee-card__info">
|
||||
<div class="employee-card__name">王芳</div>
|
||||
<div class="employee-card__meta"><span>女 · 28岁</span><span>信息技术中心 · 数据部</span></div>
|
||||
</div>
|
||||
<div class="employee-card__rate"><span class="employee-card__rate-num employee-card__rate-num--good">92%</span><span class="tag tag-green">达标</span></div>
|
||||
</div>
|
||||
<div class="employee-card" onclick="location.href='./employee-detail.html'">
|
||||
<div class="employee-card__avatar" style="background:linear-gradient(135deg,#e8f4ff,#bdd7ff);">👨</div>
|
||||
<div class="employee-card__info">
|
||||
<div class="employee-card__name">陈伟</div>
|
||||
<div class="employee-card__meta"><span>男 · 36岁</span><span>安全环保部 · 安环部</span></div>
|
||||
</div>
|
||||
<div class="employee-card__rate"><span class="employee-card__rate-num employee-card__rate-num--good">88%</span><span class="tag tag-green">达标</span></div>
|
||||
</div>
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 未达标列表 -->
|
||||
<div id="panel-bad" style="display:none;">
|
||||
<div class="employee-card" onclick="location.href='./employee-detail.html'">
|
||||
<div class="employee-card__avatar" style="background:linear-gradient(135deg,#ffe0e0,#ffb3b3);">👩</div>
|
||||
<div class="employee-card__info">
|
||||
<div class="employee-card__name">张小红</div>
|
||||
<div class="employee-card__meta"><span>女 · 32岁</span><span>公司机关 · 办公室</span></div>
|
||||
</div>
|
||||
<div class="employee-card__rate"><span class="employee-card__rate-num employee-card__rate-num--bad">68%</span><span class="tag tag-red">未达标</span></div>
|
||||
</div>
|
||||
<div class="employee-card" onclick="location.href='./employee-detail.html'">
|
||||
<div class="employee-card__avatar" style="background:linear-gradient(135deg,#e8f4ff,#bdd7ff);">👨</div>
|
||||
<div class="employee-card__info">
|
||||
<div class="employee-card__name">李建国</div>
|
||||
<div class="employee-card__meta"><span>男 · 45岁</span><span>采油一厂 · 技术部</span></div>
|
||||
</div>
|
||||
<div class="employee-card__rate"><span class="employee-card__rate-num employee-card__rate-num--bad">71%</span><span class="tag tag-orange">待干预</span></div>
|
||||
</div>
|
||||
<div class="employee-card" onclick="location.href='./employee-detail.html'">
|
||||
<div class="employee-card__avatar" style="background:linear-gradient(135deg,#fff7e6,#ffd591);">👨</div>
|
||||
<div class="employee-card__info">
|
||||
<div class="employee-card__name">赵志强</div>
|
||||
<div class="employee-card__meta"><span>男 · 61岁</span><span>公司机关 · 后勤部</span></div>
|
||||
</div>
|
||||
<div class="employee-card__rate"><span class="employee-card__rate-num employee-card__rate-num--bad">59%</span><span class="tag tag-red">未达标</span></div>
|
||||
</div>
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
|
||||
/* Tab 切换 */
|
||||
function switchTab(el, panelId) {
|
||||
el.closest('.seg-tabs').querySelectorAll('.seg-tab').forEach(function(t) { t.classList.remove('active'); });
|
||||
el.classList.add('active');
|
||||
['panel-all','panel-good','panel-bad'].forEach(function(id) {
|
||||
document.getElementById(id).style.display = id === panelId ? 'block' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,229 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师工作台 - 工作台主页 | 健康CQ原型</title>
|
||||
<style>
|
||||
/* 公共重置与布局 */
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
/* 手机壳容器 */
|
||||
.phone-shell { width: 390px; height: 844px; background: #fff; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
/* 状态栏 */
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
/* 滚动内容区 */
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 底部Tab栏 */
|
||||
.tab-bar { height: 83px; background: #fff; border-top: 1px solid #e8e8e8; display: flex; align-items: flex-start; padding-top: 8px; flex-shrink: 0; }
|
||||
.tab-item { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; cursor: pointer; padding: 4px 0; position: relative; }
|
||||
.tab-item .tab-icon { font-size: 22px; line-height: 1; }
|
||||
.tab-item .tab-label { font-size: 10px; color: #999; font-weight: 500; }
|
||||
.tab-item.active .tab-label { color: #1677ff; }
|
||||
.tab-badge { position: absolute; top: 2px; right: 18px; background: #ff4d4f; color: #fff; font-size: 10px; font-weight: 700; min-width: 16px; height: 16px; border-radius: 8px; display: flex; align-items: center; justify-content: center; padding: 0 4px; }
|
||||
/* 分段Tab */
|
||||
.seg-tabs { display: flex; background: #fff; border-bottom: 1px solid #f0f0f0; flex-shrink: 0; }
|
||||
.seg-tab { flex: 1; text-align: center; padding: 12px 0; font-size: 14px; color: #666; cursor: pointer; border-bottom: 2px solid transparent; transition: all 0.2s; }
|
||||
.seg-tab.active { color: #1677ff; border-bottom-color: #1677ff; font-weight: 600; }
|
||||
.seg-tab .badge { display: inline-block; background: #e8e8e8; color: #666; font-size: 10px; font-weight: 700; min-width: 16px; height: 16px; border-radius: 8px; padding: 0 4px; margin-left: 4px; vertical-align: middle; line-height: 16px; }
|
||||
.seg-tab.active .badge { background: #e6f4ff; color: #1677ff; }
|
||||
/* 标签 */
|
||||
.tag { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; }
|
||||
.tag-blue { background: #e6f4ff; color: #1677ff; }
|
||||
.tag-green { background: #f6ffed; color: #52c41a; }
|
||||
.tag-orange { background: #fff7e6; color: #fa8c16; }
|
||||
.tag-red { background: #fff1f0; color: #ff4d4f; }
|
||||
.tag-gray { background: #f5f5f5; color: #999; }
|
||||
/* 快捷入口网格 */
|
||||
.quick-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 10px 16px 0; }
|
||||
.quick-card { background: #fff; border-radius: 12px; padding: 14px; cursor: pointer; box-shadow: 0 1px 4px rgba(0,0,0,0.06); display: flex; align-items: center; gap: 10px; transition: transform 0.15s; }
|
||||
.quick-card:active { transform: scale(0.98); }
|
||||
.quick-card__icon { width: 42px; height: 42px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 20px; flex-shrink: 0; }
|
||||
.quick-card__info { flex: 1; min-width: 0; }
|
||||
.quick-card__title { font-size: 14px; font-weight: 600; color: #1a1a1a; }
|
||||
.quick-card__desc { font-size: 11px; color: #999; margin-top: 2px; }
|
||||
/* 咨询卡片 */
|
||||
.consult-card { background: #fff; border-radius: 12px; margin: 10px 16px 0; padding: 14px; cursor: pointer; box-shadow: 0 1px 4px rgba(0,0,0,0.06); transition: transform 0.15s; }
|
||||
.consult-card:active { transform: scale(0.98); }
|
||||
.cc-top { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
|
||||
.cc-avatar { width: 42px; height: 42px; border-radius: 50%; background: linear-gradient(135deg, #e8f4ff, #bdd7ff); display: flex; align-items: center; justify-content: center; font-size: 20px; flex-shrink: 0; }
|
||||
.cc-info { flex: 1; min-width: 0; }
|
||||
.cc-name { font-size: 15px; font-weight: 600; color: #1a1a1a; }
|
||||
.cc-meta { font-size: 12px; color: #999; margin-top: 2px; }
|
||||
.cc-bottom { display: flex; align-items: center; justify-content: space-between; }
|
||||
.cc-preview { font-size: 13px; color: #666; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 210px; }
|
||||
.cc-time { font-size: 12px; color: #bbb; flex-shrink: 0; }
|
||||
.unread-dot { width: 8px; height: 8px; border-radius: 50%; background: #ff4d4f; flex-shrink: 0; }
|
||||
/* 弹窗样式 */
|
||||
.modal-center { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.5); z-index: 200; align-items: center; justify-content: center; }
|
||||
.modal-center.active { display: flex; }
|
||||
.modal-box { width: 280px; background: #fff; border-radius: 16px; overflow: hidden; }
|
||||
.modal-box .modal-title { padding: 20px 20px 8px; font-size: 17px; font-weight: 700; text-align: center; color: #1a1a1a; }
|
||||
.modal-box .modal-body { padding: 8px 20px 20px; font-size: 14px; color: #666; text-align: center; line-height: 1.6; }
|
||||
.modal-box .modal-actions { display: flex; border-top: 1px solid #f0f0f0; }
|
||||
.modal-box .modal-actions button { flex: 1; padding: 14px; font-size: 16px; cursor: pointer; background: none; border: none; }
|
||||
.modal-box .modal-actions button:first-child { color: #666; border-right: 1px solid #f0f0f0; }
|
||||
.modal-box .modal-actions button:last-child { color: #1677ff; font-weight: 600; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
|
||||
<!-- 状态栏 -->
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 蓝色渐变头部区域 -->
|
||||
<div style="background:linear-gradient(135deg,#1677ff,#0958d9);padding:16px 20px 20px;flex-shrink:0;">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;">
|
||||
<div>
|
||||
<div style="color:rgba(255,255,255,0.75);font-size:12px;margin-bottom:2px;">你好,李营养师</div>
|
||||
<div style="color:#fff;font-size:20px;font-weight:700;">工作台</div>
|
||||
</div>
|
||||
<!-- [交互] 点击切换营养咨询服务状态 -->
|
||||
<button id="wb-pause-btn" onclick="togglePause()" style="display:flex;align-items:center;gap:6px;background:rgba(255,255,255,0.2);border:1px solid rgba(255,255,255,0.4);border-radius:20px;padding:6px 14px;color:#fff;font-size:13px;cursor:pointer;">
|
||||
<span id="pause-dot" style="width:8px;height:8px;border-radius:50%;background:#52c41a;display:inline-block;flex-shrink:0;"></span>
|
||||
<span id="pause-label">咨询已开启</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- 统计数字 -->
|
||||
<div style="display:flex;">
|
||||
<div style="flex:1;text-align:center;"><div style="color:#fff;font-size:22px;font-weight:700;">2</div><div style="color:rgba(255,255,255,0.75);font-size:11px;margin-top:2px;">营养咨询待回复</div></div>
|
||||
<div style="width:1px;background:rgba(255,255,255,0.25);margin:4px 0;"></div>
|
||||
<div style="flex:1;text-align:center;"><div style="color:#fff;font-size:22px;font-weight:700;">3</div><div style="color:rgba(255,255,255,0.75);font-size:11px;margin-top:2px;">方案待跟进</div></div>
|
||||
<div style="width:1px;background:rgba(255,255,255,0.25);margin:4px 0;"></div>
|
||||
<div style="flex:1;text-align:center;"><div style="color:#fff;font-size:22px;font-weight:700;">5</div><div style="color:rgba(255,255,255,0.75);font-size:11px;margin-top:2px;">食谱被引用</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
|
||||
<!-- 快捷功能入口(2 个大 tab) -->
|
||||
<div style="display:flex;gap:10px;margin:10px 16px 0;">
|
||||
<!-- [交互] 点击跳转至: ./employee-list.html -->
|
||||
<div onclick="location.href='./employee-list.html'" style="flex:1;background:#fff;border-radius:12px;padding:16px 14px;cursor:pointer;box-shadow:0 1px 4px rgba(0,0,0,0.06);text-align:center;transition:transform 0.15s;">
|
||||
<div style="width:48px;height:48px;border-radius:14px;background:linear-gradient(135deg,#e6f4ff,#b7d8ff);display:flex;align-items:center;justify-content:center;font-size:24px;margin:0 auto 8px;">👥</div>
|
||||
<div style="font-size:15px;font-weight:600;color:#1a1a1a;">员工营养管理</div>
|
||||
<div style="font-size:11px;color:#999;margin-top:4px;">达标监控 · 一对一指导</div>
|
||||
</div>
|
||||
<!-- [交互] 点击跳转至: ./recipe-list.html -->
|
||||
<div onclick="location.href='./recipe-list.html'" style="flex:1;background:#fff;border-radius:12px;padding:16px 14px;cursor:pointer;box-shadow:0 1px 4px rgba(0,0,0,0.06);text-align:center;transition:transform 0.15s;">
|
||||
<div style="width:48px;height:48px;border-radius:14px;background:linear-gradient(135deg,#fff7e6,#ffd591);display:flex;align-items:center;justify-content:center;font-size:24px;margin:0 auto 8px;">🥗</div>
|
||||
<div style="font-size:15px;font-weight:600;color:#1a1a1a;">我的食谱</div>
|
||||
<div style="font-size:11px;color:#999;margin-top:4px;">按周发布 · 引用查看</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 营养咨询列表 -->
|
||||
<div id="consult-list" style="margin-top:4px;">
|
||||
<div class="seg-tabs">
|
||||
<div class="seg-tab active" onclick="switchWorkTab(this,'wb-text-pending')">待回复<span class="badge">2</span></div>
|
||||
<div class="seg-tab" onclick="switchWorkTab(this,'wb-text-ongoing')">进行中<span class="badge" style="background:#fff7e6;color:#fa8c16;">1</span></div>
|
||||
<div class="seg-tab" onclick="switchWorkTab(this,'wb-text-done')">已结束</div>
|
||||
</div>
|
||||
|
||||
<!-- 待回复列表 -->
|
||||
<div id="wb-text-pending">
|
||||
<!-- [交互] 点击跳转至: ./consult-chat.html -->
|
||||
<div class="consult-card" onclick="location.href='./consult-chat.html'">
|
||||
<div class="cc-top"><div class="cc-avatar">👩</div><div class="cc-info"><div class="cc-name">张小红</div><div class="cc-meta">女 · 32岁 · 减脂需求</div></div><span class="tag tag-red">待回复</span></div>
|
||||
<div class="cc-bottom"><div class="cc-preview">食堂太油了,想请教怎么吃才能减脂...</div><div style="display:flex;align-items:center;gap:6px;"><span class="cc-time">10:23</span><span class="unread-dot"></span></div></div>
|
||||
</div>
|
||||
<!-- [交互] 点击跳转至: ./consult-chat.html -->
|
||||
<div class="consult-card" onclick="location.href='./consult-chat.html'">
|
||||
<div class="cc-top"><div class="cc-avatar">👨</div><div class="cc-info"><div class="cc-name">李建国</div><div class="cc-meta">男 · 45岁 · 高血脂</div></div><span class="tag tag-red">待回复</span></div>
|
||||
<div class="cc-bottom"><div class="cc-preview">血脂偏高,日常饮食有什么忌口...</div><div style="display:flex;align-items:center;gap:6px;"><span class="cc-time">09:55</span><span class="unread-dot"></span></div></div>
|
||||
</div>
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
<!-- 进行中列表 -->
|
||||
<div id="wb-text-ongoing" style="display:none;">
|
||||
<!-- [交互] 点击跳转至: ./consult-chat.html -->
|
||||
<div class="consult-card" onclick="location.href='./consult-chat.html'">
|
||||
<div class="cc-top"><div class="cc-avatar">👨</div><div class="cc-info"><div class="cc-name">陈伟</div><div class="cc-meta">男 · 36岁 · 增肌需求</div></div><span class="tag tag-blue">进行中</span></div>
|
||||
<div class="cc-bottom"><div class="cc-preview">好的,我按您给的食谱吃一周看看</div><span class="cc-time">昨天</span></div>
|
||||
</div>
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
<!-- 已结束列表 -->
|
||||
<div id="wb-text-done" style="display:none;">
|
||||
<!-- [交互] 点击跳转至: ./consult-chat-done.html -->
|
||||
<div class="consult-card" onclick="location.href='./consult-chat-done.html'">
|
||||
<div class="cc-top"><div class="cc-avatar">👨</div><div class="cc-info"><div class="cc-name">赵磊</div><div class="cc-meta">男 · 35岁</div></div><span class="tag tag-green">已完成</span></div>
|
||||
<div class="cc-bottom"><div class="cc-preview">谢谢营养师,方案很实用</div><span class="cc-time">08:40</span></div>
|
||||
</div>
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 服务状态切换确认弹窗 -->
|
||||
<div id="modal-pause" class="modal-center">
|
||||
<div class="modal-box">
|
||||
<div class="modal-title" id="pause-modal-title">关闭咨询</div>
|
||||
<div class="modal-body" id="pause-modal-body">是否要关闭营养咨询?关闭后,员工无法发起营养咨询。</div>
|
||||
<div class="modal-actions">
|
||||
<button onclick="closeModal('modal-pause')">取消</button>
|
||||
<button onclick="confirmTogglePause()">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部5Tab导航栏 -->
|
||||
<div class="tab-bar">
|
||||
<div class="tab-item active" onclick="location.href='./index.html'"><span class="tab-icon">🏥</span><span class="tab-label">工作台</span><span class="tab-badge">2</span></div>
|
||||
<div class="tab-item" onclick="location.href='../knowledge/index.html'"><span class="tab-icon">📚</span><span class="tab-label">知识库</span></div>
|
||||
<div class="tab-item" onclick="location.href='../../ai-assistant/index.html'"><span class="tab-icon">🤖</span><span class="tab-label">AI助手</span></div>
|
||||
<div class="tab-item" onclick="location.href='../../message/index.html'"><span class="tab-icon">💬</span><span class="tab-label">消息</span><span class="tab-badge">2</span></div>
|
||||
<div class="tab-item" onclick="location.href='../profile/index.html'"><span class="tab-icon">👤</span><span class="tab-label">我的</span></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师,供共用页面(消息、AI助手)判断返回目标 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
|
||||
/**
|
||||
* 切换二级Tab(待回复/进行中/已结束)
|
||||
* @param {HTMLElement} el - 被点击的Tab元素
|
||||
* @param {string} panelId - 目标面板ID
|
||||
*/
|
||||
function switchWorkTab(el, panelId) {
|
||||
el.closest('.seg-tabs').querySelectorAll('.seg-tab').forEach(function(t) { t.classList.remove('active'); });
|
||||
el.classList.add('active');
|
||||
var scrollContent = el.closest('.seg-tabs').nextElementSibling;
|
||||
Array.from(scrollContent.children).forEach(function(p) {
|
||||
if (p.id) p.style.display = p.id === panelId ? 'block' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
/* 服务状态切换 */
|
||||
var isPaused = false;
|
||||
function togglePause() {
|
||||
var title = isPaused ? '开启咨询' : '关闭咨询';
|
||||
var body = isPaused ? '是否要开启营养咨询?开启后,员工可发起营养咨询。' : '是否要关闭营养咨询?关闭后,员工无法发起营养咨询。';
|
||||
document.getElementById('pause-modal-title').textContent = title;
|
||||
document.getElementById('pause-modal-body').textContent = body;
|
||||
openModal('modal-pause');
|
||||
}
|
||||
function confirmTogglePause() {
|
||||
isPaused = !isPaused;
|
||||
var bg = isPaused ? '#ff4d4f' : '#52c41a';
|
||||
var text = isPaused ? '咨询已关闭' : '咨询已开启';
|
||||
document.getElementById('pause-dot').style.background = bg;
|
||||
document.getElementById('pause-label').textContent = text;
|
||||
closeModal('modal-pause');
|
||||
}
|
||||
function openModal(id) { var m = document.getElementById(id); if (m) m.classList.add('active'); }
|
||||
function closeModal(id) { var m = document.getElementById(id); if (m) m.classList.remove('active'); }
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,407 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师工作台 - 营养方案详情 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #f7f8fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; position: relative; }
|
||||
.nav-back { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 头部 */
|
||||
.plan-header { background: linear-gradient(135deg,#1677ff,#0958d9); padding: 16px 20px; color: #fff; }
|
||||
.plan-header__top { display: flex; align-items: center; gap: 12px; }
|
||||
.plan-header__avatar { width: 48px; height: 48px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 24px; flex-shrink: 0; background: rgba(255,255,255,0.25); border: 2px solid rgba(255,255,255,0.4); }
|
||||
.plan-header__name { font-size: 17px; font-weight: 700; }
|
||||
.plan-header__meta { font-size: 12px; color: rgba(255,255,255,0.85); margin-top: 2px; }
|
||||
.plan-header__tag { margin-left: auto; font-size: 12px; padding: 4px 12px; border-radius: 14px; background: rgba(255,255,255,0.2); }
|
||||
/* 卡片 */
|
||||
.card { background: #fff; border-radius: 12px; margin: 10px 12px 0; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
|
||||
.card__title { font-size: 14px; font-weight: 700; color: #1a1a1a; margin-bottom: 10px; display: flex; align-items: center; }
|
||||
/* 营养目标 */
|
||||
.goal-row { display: flex; }
|
||||
.goal-item { flex: 1; text-align: center; }
|
||||
.goal-item + .goal-item { border-left: 1px solid #f0f0f0; }
|
||||
.goal-item__val { font-size: 16px; font-weight: 700; color: #1677ff; }
|
||||
.goal-item__label { font-size: 11px; color: #999; margin-top: 2px; }
|
||||
/* 三大营养素 */
|
||||
.macro-bar { display: flex; height: 24px; border-radius: 6px; overflow: hidden; margin-bottom: 8px; }
|
||||
.macro-bar__seg { display: flex; align-items: center; justify-content: center; font-size: 11px; color: #fff; font-weight: 600; }
|
||||
.macro-legend { display: flex; gap: 12px; }
|
||||
.macro-legend__item { display: flex; align-items: center; gap: 4px; font-size: 11px; color: #666; }
|
||||
.macro-legend__dot { width: 8px; height: 8px; border-radius: 50%; }
|
||||
/* 一周饮食安排(按天折叠,每天三餐,食物含分量与热量) */
|
||||
.day-card { background: #fff; border: 1px solid #e8e8e8; border-radius: 10px; margin-bottom: 10px; overflow: hidden; }
|
||||
.day-card:last-child { margin-bottom: 0; }
|
||||
.day-header { display: flex; align-items: center; justify-content: space-between; padding: 12px; cursor: pointer; }
|
||||
.day-header__day { font-size: 14px; font-weight: 600; color: #1a1a1a; }
|
||||
.day-header__summary { font-size: 12px; color: #999; }
|
||||
.day-header__kcal { font-size: 12px; color: #fa8c16; font-weight: 600; }
|
||||
.day-header .arrow { transition: transform .2s; flex-shrink: 0; }
|
||||
.day-header .arrow.open { transform: rotate(180deg); }
|
||||
.day-body { display: none; padding: 0 12px 12px; }
|
||||
.day-body.open { display: block; }
|
||||
.meal-block { background: #fafafa; border-radius: 8px; padding: 10px; margin-bottom: 8px; }
|
||||
.meal-block:last-child { margin-bottom: 0; }
|
||||
.meal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
|
||||
.meal-head__name { font-size: 13px; font-weight: 600; color: #1a1a1a; }
|
||||
.meal-head__subtotal { font-size: 12px; color: #fa8c16; font-weight: 600; }
|
||||
.food-row { display: flex; align-items: center; gap: 6px; padding: 6px 0; border-bottom: 1px dashed #f0f0f0; }
|
||||
.food-row:last-child { border-bottom: none; }
|
||||
.food-row__name { flex: 1; font-size: 13px; color: #333; }
|
||||
.food-row__amount { font-size: 12px; color: #666; width: 44px; text-align: right; flex-shrink: 0; }
|
||||
.food-row__kcal { font-size: 12px; color: #fa8c16; font-weight: 600; width: 56px; text-align: right; flex-shrink: 0; }
|
||||
/* 执行进度 */
|
||||
.checkin-row { display: flex; gap: 6px; }
|
||||
.checkin-day { flex: 1; text-align: center; }
|
||||
.checkin-day__dot { width: 26px; height: 26px; border-radius: 50%; margin: 0 auto; display: flex; align-items: center; justify-content: center; font-size: 12px; }
|
||||
.checkin-day__dot--done { background: #52c41a; color: #fff; }
|
||||
.checkin-day__dot--today { background: #e6f4ff; color: #1677ff; border: 1px solid #1677ff; }
|
||||
.checkin-day__dot--pending { background: #f5f5f5; color: #bbb; }
|
||||
.checkin-day__label { font-size: 10px; color: #999; margin-top: 4px; }
|
||||
.tag { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; }
|
||||
.tag-red { background: #fff1f0; color: #ff4d4f; }
|
||||
.tag-orange { background: #fff7e6; color: #fa8c16; }
|
||||
/* 底部弹层 */
|
||||
.sheet-mask { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.45); z-index: 300; align-items: flex-end; justify-content: center; }
|
||||
.sheet-mask.active { display: flex; }
|
||||
.sheet-panel { width: 100%; max-height: 80%; background: #fff; border-radius: 16px 16px 0 0; display: flex; flex-direction: column; overflow: hidden; }
|
||||
.sheet-header { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px; border-bottom: 0.5px solid #f0f0f0; flex-shrink: 0; }
|
||||
.sheet-header .s-cancel { font-size: 14px; color: #999; cursor: pointer; background: none; border: none; }
|
||||
.sheet-header .s-title { font-size: 15px; font-weight: 600; color: #1a1a1a; }
|
||||
.sheet-header .s-save { font-size: 14px; color: #1677ff; font-weight: 600; cursor: pointer; background: none; border: none; }
|
||||
.sheet-body { padding: 12px 16px 20px; overflow-y: auto; flex: 1; }
|
||||
.sheet-body::-webkit-scrollbar { display: none; }
|
||||
.sheet-tip { font-size: 12px; color: #999; background: #fafafa; border-radius: 8px; padding: 10px 12px; line-height: 1.6; margin-bottom: 12px; }
|
||||
.adj-meal { margin-bottom: 14px; }
|
||||
.adj-meal__label { font-size: 13px; font-weight: 600; color: #1a1a1a; margin-bottom: 8px; }
|
||||
.adj-dish { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; padding: 5px 10px; border-radius: 14px; background: #f0f6ff; color: #1677ff; margin: 0 6px 6px 0; cursor: pointer; }
|
||||
.adj-dish .x { color: #999; font-size: 12px; line-height: 1; }
|
||||
.adj-add { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; padding: 5px 12px; border-radius: 14px; border: 1px dashed #1677ff; color: #1677ff; margin-bottom: 6px; cursor: pointer; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 导航栏 -->
|
||||
<div class="nav-bar">
|
||||
<button class="nav-back" onclick="location.href='./employee-detail.html'">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title">营养方案详情</span>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
|
||||
<!-- 头部 -->
|
||||
<div class="plan-header">
|
||||
<div class="plan-header__top">
|
||||
<div class="plan-header__avatar">👩</div>
|
||||
<div>
|
||||
<div class="plan-header__name">张小红</div>
|
||||
<div class="plan-header__meta">减脂期一周饮食方案 · 女 32岁</div>
|
||||
</div>
|
||||
<span class="plan-header__tag">执行中</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 方案依据(健康档案摘要) -->
|
||||
<div class="card" style="border-left:3px solid #1677ff;">
|
||||
<div class="card__title">🎯 方案依据<span style="font-size:12px;color:#1677ff;font-weight:400;margin-left:auto;cursor:pointer;" onclick="location.href='./employee-health.html'">查看完整健康档案 ›</span></div>
|
||||
<div style="display:flex;flex-wrap:wrap;gap:6px;">
|
||||
<span class="tag tag-orange">尿酸 380 偏高</span>
|
||||
<span class="tag tag-red">胃炎</span>
|
||||
<span class="tag tag-red">高尿酸</span>
|
||||
<span class="tag tag-red">过敏原:花生</span>
|
||||
<span class="tag tag-red">过敏原:海鲜</span>
|
||||
<span class="tag tag-orange">少辣 · 低盐 · 控糖</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 营养目标 -->
|
||||
<div class="card">
|
||||
<div class="card__title">营养目标</div>
|
||||
<div class="goal-row">
|
||||
<div class="goal-item"><div class="goal-item__val">1400</div><div class="goal-item__label">热量 kcal/日</div></div>
|
||||
<div class="goal-item"><div class="goal-item__val">75</div><div class="goal-item__label">蛋白质 g</div></div>
|
||||
<div class="goal-item"><div class="goal-item__val">30</div><div class="goal-item__label">脂肪 g</div></div>
|
||||
<div class="goal-item"><div class="goal-item__val">190</div><div class="goal-item__label">碳水 g</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 三大营养素占比 -->
|
||||
<div class="card">
|
||||
<div class="card__title">三大营养素占比</div>
|
||||
<div class="macro-bar">
|
||||
<div class="macro-bar__seg" style="width:25%;background:#1677ff;">蛋白25%</div>
|
||||
<div class="macro-bar__seg" style="width:20%;background:#fa8c16;">脂肪20%</div>
|
||||
<div class="macro-bar__seg" style="width:55%;background:#52c41a;">碳水55%</div>
|
||||
</div>
|
||||
<div class="macro-legend">
|
||||
<span class="macro-legend__item"><span class="macro-legend__dot" style="background:#1677ff;"></span>蛋白质</span>
|
||||
<span class="macro-legend__item"><span class="macro-legend__dot" style="background:#fa8c16;"></span>脂肪</span>
|
||||
<span class="macro-legend__item"><span class="macro-legend__dot" style="background:#52c41a;"></span>碳水化合物</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 饮食禁忌 -->
|
||||
<div class="card">
|
||||
<div class="card__title">饮食禁忌</div>
|
||||
<div style="display:flex;gap:6px;">
|
||||
<span class="tag tag-red">高糖</span>
|
||||
<span class="tag tag-red">高脂</span>
|
||||
<span class="tag tag-orange">高盐</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 一周饮食安排 -->
|
||||
<div class="card">
|
||||
<div class="card__title">一周饮食安排<span style="font-size:10px;color:#52c41a;font-weight:400;background:#f6ffed;padding:2px 8px;border-radius:8px;margin-left:8px;">系统生成</span><span style="font-size:12px;color:#1677ff;font-weight:400;margin-left:auto;cursor:pointer;" onclick="openSheet('sheet-adjust')">微调食谱 ›</span></div>
|
||||
<div id="day-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- 执行进度 -->
|
||||
<div class="card">
|
||||
<div class="card__title">执行进度<span style="font-size:12px;color:#999;font-weight:400;margin-left:8px;">第 3 天 / 7 天</span></div>
|
||||
<div class="checkin-row">
|
||||
<div class="checkin-day"><div class="checkin-day__dot checkin-day__dot--done">✓</div><div class="checkin-day__label">周一</div></div>
|
||||
<div class="checkin-day"><div class="checkin-day__dot checkin-day__dot--done">✓</div><div class="checkin-day__label">周二</div></div>
|
||||
<div class="checkin-day"><div class="checkin-day__dot checkin-day__dot--today">3</div><div class="checkin-day__label">周三</div></div>
|
||||
<div class="checkin-day"><div class="checkin-day__dot checkin-day__dot--pending">4</div><div class="checkin-day__label">周四</div></div>
|
||||
<div class="checkin-day"><div class="checkin-day__dot checkin-day__dot--pending">5</div><div class="checkin-day__label">周五</div></div>
|
||||
<div class="checkin-day"><div class="checkin-day__dot checkin-day__dot--pending">6</div><div class="checkin-day__label">周六</div></div>
|
||||
<div class="checkin-day"><div class="checkin-day__dot checkin-day__dot--pending">7</div><div class="checkin-day__label">周日</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 微调食谱底部弹层 -->
|
||||
<div id="sheet-adjust" class="sheet-mask" onclick="if(event.target===this)closeSheet('sheet-adjust')">
|
||||
<div class="sheet-panel" onclick="event.stopPropagation()">
|
||||
<div class="sheet-header">
|
||||
<button class="s-cancel" onclick="closeSheet('sheet-adjust')">取消</button>
|
||||
<span class="s-title">微调一周食谱</span>
|
||||
<button class="s-save" onclick="closeSheet('sheet-adjust');alert('食谱已微调(原型演示)')">保存</button>
|
||||
</div>
|
||||
<div class="sheet-body">
|
||||
<div class="sheet-tip">系统已根据方案参数(1400kcal/日 · 蛋白25% · 脂肪20% · 碳水55% · 禁忌:高糖、高脂、高嘌呤)生成一周专属食谱,可替换任意餐品。</div>
|
||||
<div id="adjust-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
|
||||
/* ===== 一周专属食谱数据(每天三餐,每餐食物含分量与热量) ===== */
|
||||
var WEEK = [
|
||||
{ day: '周一', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '全麦面包', amount: 80, unit: 'g', kcal: 200 },
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 },
|
||||
{ name: '牛奶', amount: 250, unit: 'ml', kcal: 65 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '清蒸鲈鱼', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '杂粮饭', amount: 200, unit: 'g', kcal: 240 },
|
||||
{ name: '蒜蓉西兰花', amount: 150, unit: 'g', kcal: 60 },
|
||||
{ name: '紫菜蛋花汤', amount: 200, unit: 'ml', kcal: 40 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '香煎鸡胸', amount: 120, unit: 'g', kcal: 200 },
|
||||
{ name: '蔬菜沙拉', amount: 200, unit: 'g', kcal: 80 },
|
||||
{ name: '小米粥', amount: 200, unit: 'g', kcal: 120 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周二', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '燕麦牛奶', amount: 300, unit: 'ml', kcal: 220 },
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '白灼虾', amount: 150, unit: 'g', kcal: 140 },
|
||||
{ name: '糙米饭', amount: 200, unit: 'g', kcal: 230 },
|
||||
{ name: '清炒时蔬', amount: 150, unit: 'g', kcal: 55 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '蔬菜豆腐汤', amount: 300, unit: 'g', kcal: 150 },
|
||||
{ name: '杂粮馒头', amount: 100, unit: 'g', kcal: 220 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周三', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 },
|
||||
{ name: '豆浆', amount: 250, unit: 'ml', kcal: 80 },
|
||||
{ name: '蒸红薯', amount: 100, unit: 'g', kcal: 90 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '卤牛肉', amount: 100, unit: 'g', kcal: 160 },
|
||||
{ name: '荞麦面', amount: 200, unit: 'g', kcal: 230 },
|
||||
{ name: '凉拌黄瓜', amount: 150, unit: 'g', kcal: 40 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '清炒时蔬', amount: 200, unit: 'g', kcal: 60 },
|
||||
{ name: '玉米', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '菌菇汤', amount: 200, unit: 'g', kcal: 50 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周四', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '杂粮粥', amount: 300, unit: 'g', kcal: 200 },
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '香煎鸡胸', amount: 150, unit: 'g', kcal: 250 },
|
||||
{ name: '藜麦饭', amount: 150, unit: 'g', kcal: 180 },
|
||||
{ name: '西兰花', amount: 150, unit: 'g', kcal: 60 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '虾仁沙拉', amount: 200, unit: 'g', kcal: 150 },
|
||||
{ name: '全麦面包', amount: 50, unit: 'g', kcal: 120 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周五', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '全麦面包', amount: 80, unit: 'g', kcal: 200 },
|
||||
{ name: '牛奶', amount: 250, unit: 'ml', kcal: 65 },
|
||||
{ name: '香蕉', amount: 100, unit: 'g', kcal: 90 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '清蒸鱼', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '玉米', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '凉拌木耳', amount: 100, unit: 'g', kcal: 40 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '菌菇汤', amount: 300, unit: 'g', kcal: 120 },
|
||||
{ name: '杂粮饭', amount: 150, unit: 'g', kcal: 180 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周六', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 },
|
||||
{ name: '燕麦', amount: 50, unit: 'g', kcal: 190 },
|
||||
{ name: '牛奶', amount: 250, unit: 'ml', kcal: 65 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '白灼虾', amount: 150, unit: 'g', kcal: 140 },
|
||||
{ name: '杂粮饭', amount: 200, unit: 'g', kcal: 240 },
|
||||
{ name: '蔬菜沙拉', amount: 150, unit: 'g', kcal: 60 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '蔬菜沙拉', amount: 200, unit: 'g', kcal: 80 },
|
||||
{ name: '鸡胸肉', amount: 100, unit: 'g', kcal: 170 },
|
||||
{ name: '玉米', amount: 100, unit: 'g', kcal: 110 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周日', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '豆浆', amount: 250, unit: 'ml', kcal: 80 },
|
||||
{ name: '玉米', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '卤牛肉', amount: 100, unit: 'g', kcal: 160 },
|
||||
{ name: '糙米饭', amount: 200, unit: 'g', kcal: 230 },
|
||||
{ name: '清炒时蔬', amount: 150, unit: 'g', kcal: 55 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '鸡胸沙拉', amount: 250, unit: 'g', kcal: 200 },
|
||||
{ name: '小米粥', amount: 200, unit: 'g', kcal: 120 }
|
||||
]}
|
||||
]}
|
||||
];
|
||||
|
||||
/* 计算某餐总热量 */
|
||||
function mealSubtotal(di, mi) {
|
||||
return WEEK[di].meals[mi].foods.reduce(function(s, f) { return s + f.kcal; }, 0);
|
||||
}
|
||||
/* 计算某天总热量 */
|
||||
function dayTotal(di) {
|
||||
return WEEK[di].meals.reduce(function(s, m, mi) { return s + mealSubtotal(di, mi); }, 0);
|
||||
}
|
||||
/* 某天三餐小计摘要 */
|
||||
function daySummary(di) {
|
||||
return WEEK[di].meals.map(function(m, mi) { return m.name.charAt(0) + mealSubtotal(di, mi); }).join(' · ');
|
||||
}
|
||||
|
||||
/* 渲染一周饮食安排(折叠卡片,只读) */
|
||||
function renderDayList() {
|
||||
var html = '';
|
||||
WEEK.forEach(function(day, di) {
|
||||
html += '<div class="day-card">' +
|
||||
'<div class="day-header" onclick="toggleDay(' + di + ')">' +
|
||||
'<span class="day-header__day">' + day.day + '</span>' +
|
||||
'<span class="day-header__summary">' + daySummary(di) + '</span>' +
|
||||
'<span class="day-header__kcal">' + dayTotal(di) + ' kcal</span>' +
|
||||
'<svg class="arrow" id="arrow-' + di + '" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="#999" stroke-width="2"><path d="M4 6l4 4 4-4"/></svg>' +
|
||||
'</div>' +
|
||||
'<div class="day-body" id="day-body-' + di + '">' +
|
||||
day.meals.map(function(m, mi) {
|
||||
return '<div class="meal-block">' +
|
||||
'<div class="meal-head"><span class="meal-head__name">' + m.icon + ' ' + m.name + '</span><span class="meal-head__subtotal">小计 ' + mealSubtotal(di, mi) + ' kcal</span></div>' +
|
||||
m.foods.map(function(f) {
|
||||
return '<div class="food-row"><span class="food-row__name">' + f.name + '</span><span class="food-row__amount">' + f.amount + f.unit + '</span><span class="food-row__kcal">' + f.kcal + ' kcal</span></div>';
|
||||
}).join('') +
|
||||
'</div>';
|
||||
}).join('') +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
});
|
||||
document.getElementById('day-list').innerHTML = html;
|
||||
/* 默认展开周一 */
|
||||
document.getElementById('day-body-0').classList.add('open');
|
||||
document.getElementById('arrow-0').classList.add('open');
|
||||
}
|
||||
|
||||
/* 渲染微调弹层(食物带分量与热量) */
|
||||
function renderAdjustList() {
|
||||
var html = '';
|
||||
WEEK.forEach(function(day) {
|
||||
html += '<div class="adj-meal"><div class="adj-meal__label">' + day.day + '</div>';
|
||||
day.meals.forEach(function(m) {
|
||||
m.foods.forEach(function(f) {
|
||||
html += '<span class="adj-dish">' + m.name.charAt(0) + '·' + f.name + ' ' + f.amount + f.unit + '·' + f.kcal + 'kcal<span class="x">×</span></span>';
|
||||
});
|
||||
});
|
||||
html += '<span class="adj-add">+ 添加餐品</span></div>';
|
||||
});
|
||||
document.getElementById('adjust-list').innerHTML = html;
|
||||
}
|
||||
|
||||
/* 折叠/展开某天 */
|
||||
function toggleDay(di) {
|
||||
var body = document.getElementById('day-body-' + di);
|
||||
var arrow = document.getElementById('arrow-' + di);
|
||||
body.classList.toggle('open');
|
||||
arrow.classList.toggle('open');
|
||||
}
|
||||
|
||||
/* 打开底部弹层 */
|
||||
function openSheet(id) { var m = document.getElementById(id); if (m) m.classList.add('active'); }
|
||||
/* 关闭底部弹层 */
|
||||
function closeSheet(id) { var m = document.getElementById(id); if (m) m.classList.remove('active'); }
|
||||
|
||||
/* 初始化渲染 */
|
||||
renderDayList();
|
||||
renderAdjustList();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,408 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师工作台 - 制定食谱 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #f7f8fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; position: relative; }
|
||||
.nav-back { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 表单 */
|
||||
.form-card { background: #fff; border-radius: 12px; margin: 10px 12px 0; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
|
||||
.form-card__title { font-size: 14px; font-weight: 700; color: #1a1a1a; margin-bottom: 12px; }
|
||||
.form-item { margin-bottom: 14px; }
|
||||
.form-item:last-child { margin-bottom: 0; }
|
||||
.form-item__label { font-size: 13px; font-weight: 600; color: #1a1a1a; margin-bottom: 8px; }
|
||||
.form-item__label .req { color: #ff4d4f; margin-left: 2px; }
|
||||
.form-input { width: 100%; border: 1px solid #e8e8e8; border-radius: 8px; padding: 10px 12px; font-size: 14px; outline: none; color: #1a1a1a; }
|
||||
.form-input:focus { border-color: #1677ff; }
|
||||
/* 分段选择 */
|
||||
.seg-picker { display: flex; background: #f5f5f5; border-radius: 8px; padding: 3px; }
|
||||
.seg-picker__opt { flex: 1; text-align: center; padding: 7px 0; font-size: 13px; color: #666; border-radius: 6px; cursor: pointer; }
|
||||
.seg-picker__opt.active { background: #fff; color: #1677ff; font-weight: 600; box-shadow: 0 1px 4px rgba(0,0,0,0.1); }
|
||||
/* 日期范围 */
|
||||
.date-range { display: flex; align-items: center; gap: 8px; }
|
||||
.date-range .form-input { flex: 1; text-align: center; }
|
||||
.date-range .sep { color: #999; flex-shrink: 0; }
|
||||
/* 餐次配置 */
|
||||
.meal-item { border: 1px solid #e8e8e8; border-radius: 10px; padding: 12px; margin-bottom: 10px; }
|
||||
.meal-item:last-child { margin-bottom: 0; }
|
||||
.meal-item__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
|
||||
.meal-item__name { font-size: 14px; font-weight: 600; color: #1a1a1a; }
|
||||
.meal-item__add { font-size: 12px; color: #1677ff; cursor: pointer; }
|
||||
.meal-item__dishes { display: flex; flex-wrap: wrap; gap: 6px; }
|
||||
.dish-chip { font-size: 11px; padding: 4px 10px; border-radius: 12px; background: #f0f6ff; color: #1677ff; }
|
||||
/* 营养汇总 */
|
||||
.nutri-summary { display: flex; gap: 8px; }
|
||||
.nutri-summary__item { flex: 1; text-align: center; background: #fafafa; border-radius: 8px; padding: 8px 0; }
|
||||
.nutri-summary__val { font-size: 14px; font-weight: 700; color: #1677ff; }
|
||||
.nutri-summary__label { font-size: 10px; color: #999; margin-top: 2px; }
|
||||
/* 底部操作 */
|
||||
.bottom-bar { background: #fff; border-top: 1px solid #f0f0f0; padding: 10px 16px 14px; flex-shrink: 0; display: flex; gap: 10px; }
|
||||
.btn-draft { flex: 1; padding: 12px; background: #fff; color: #1677ff; border: 1px solid #1677ff; border-radius: 10px; font-size: 15px; font-weight: 600; cursor: pointer; }
|
||||
.btn-pub { flex: 1; padding: 12px; background: #1677ff; color: #fff; border: none; border-radius: 10px; font-size: 15px; font-weight: 600; cursor: pointer; }
|
||||
.modal-center { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.5); z-index: 200; align-items: center; justify-content: center; }
|
||||
.modal-center.active { display: flex; }
|
||||
.modal-box { width: 280px; background: #fff; border-radius: 16px; overflow: hidden; }
|
||||
.modal-box .modal-title { padding: 20px 20px 8px; font-size: 17px; font-weight: 700; text-align: center; color: #1a1a1a; }
|
||||
.modal-box .modal-body { padding: 8px 20px 20px; font-size: 14px; color: #666; text-align: center; line-height: 1.6; }
|
||||
.modal-box .modal-actions { display: flex; border-top: 1px solid #f0f0f0; }
|
||||
.modal-box .modal-actions button { flex: 1; padding: 14px; font-size: 16px; cursor: pointer; background: none; border: none; }
|
||||
.modal-box .modal-actions button:first-child { color: #666; border-right: 1px solid #f0f0f0; }
|
||||
.modal-box .modal-actions button:last-child { color: #1677ff; font-weight: 600; }
|
||||
/* 按周折叠卡片 */
|
||||
.day-card { background: #fff; border: 1px solid #e8e8e8; border-radius: 10px; margin-bottom: 10px; overflow: hidden; }
|
||||
.day-card:last-child { margin-bottom: 0; }
|
||||
.day-header { display: flex; align-items: center; justify-content: space-between; padding: 12px; cursor: pointer; }
|
||||
.day-header__day { font-size: 14px; font-weight: 600; color: #1a1a1a; }
|
||||
.day-header__summary { font-size: 12px; color: #999; }
|
||||
.day-header__kcal { font-size: 12px; color: #fa8c16; font-weight: 600; }
|
||||
.day-header .arrow { transition: transform .2s; flex-shrink: 0; }
|
||||
.day-header .arrow.open { transform: rotate(180deg); }
|
||||
.day-body { display: none; padding: 0 12px 12px; }
|
||||
.day-body.open { display: block; }
|
||||
/* 每餐块 */
|
||||
.meal-block { background: #fafafa; border-radius: 8px; padding: 10px; margin-bottom: 8px; }
|
||||
.meal-block:last-child { margin-bottom: 0; }
|
||||
.meal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
|
||||
.meal-head__name { font-size: 13px; font-weight: 600; color: #1a1a1a; }
|
||||
.meal-head__subtotal { font-size: 12px; color: #fa8c16; font-weight: 600; }
|
||||
/* 食物行 */
|
||||
.food-row { display: flex; align-items: center; gap: 6px; padding: 6px 0; border-bottom: 1px dashed #f0f0f0; }
|
||||
.food-row:last-child { border-bottom: none; }
|
||||
.food-row__name { flex: 1; font-size: 13px; color: #333; }
|
||||
.food-row__input { width: 52px; border: 1px solid #e8e8e8; border-radius: 6px; padding: 4px 6px; font-size: 12px; text-align: center; outline: none; color: #333; background: #fff; }
|
||||
.food-row__input:focus { border-color: #1677ff; }
|
||||
.food-row__unit { font-size: 11px; color: #999; }
|
||||
.food-row__del { width: 20px; height: 20px; border-radius: 50%; border: none; background: #f0f0f0; color: #999; font-size: 12px; cursor: pointer; flex-shrink: 0; line-height: 1; }
|
||||
/* 添加食物 */
|
||||
.add-food { display: flex; align-items: center; justify-content: center; gap: 4px; padding: 6px 0; font-size: 12px; color: #1677ff; border: 1px dashed #1677ff; border-radius: 8px; cursor: pointer; margin-top: 8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 导航栏 -->
|
||||
<div class="nav-bar">
|
||||
<button class="nav-back" onclick="location.href='./recipe-list.html'">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title">制定食谱</span>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
|
||||
<!-- 基本信息 -->
|
||||
<div class="form-card">
|
||||
<div class="form-card__title">基本信息</div>
|
||||
<div class="form-item">
|
||||
<div class="form-item__label">食谱名称<span class="req">*</span></div>
|
||||
<input class="form-input" type="text" placeholder="如:机关减脂周菜单(第 38 周)" />
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-item__label">食谱类型<span class="req">*</span></div>
|
||||
<div class="seg-picker">
|
||||
<div class="seg-picker__opt active" onclick="segPick(this)">周菜单</div>
|
||||
<div class="seg-picker__opt" onclick="segPick(this)">季节菜单</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-item__label">发布周期<span class="req">*</span></div>
|
||||
<div class="date-range">
|
||||
<input class="form-input" type="text" value="2026-09-21" />
|
||||
<span class="sep">至</span>
|
||||
<input class="form-input" type="text" value="2026-09-27" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-item__label">适用食堂</div>
|
||||
<div class="seg-picker">
|
||||
<div class="seg-picker__opt active" onclick="segPick(this)">全部食堂</div>
|
||||
<div class="seg-picker__opt" onclick="segPick(this)">指定食堂</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 餐次配置(按周 · 每天三餐) -->
|
||||
<div class="form-card">
|
||||
<div class="form-card__title">餐次配置(按周 · 每天三餐)</div>
|
||||
<div id="day-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- 营养汇总 -->
|
||||
<div class="form-card">
|
||||
<div class="form-card__title">营养汇总(日均估算)</div>
|
||||
<div class="nutri-summary">
|
||||
<div class="nutri-summary__item"><div class="nutri-summary__val">1380</div><div class="nutri-summary__label">热量 kcal</div></div>
|
||||
<div class="nutri-summary__item"><div class="nutri-summary__val">78</div><div class="nutri-summary__label">蛋白质 g</div></div>
|
||||
<div class="nutri-summary__item"><div class="nutri-summary__val">32</div><div class="nutri-summary__label">脂肪 g</div></div>
|
||||
<div class="nutri-summary__item"><div class="nutri-summary__val">188</div><div class="nutri-summary__label">碳水 g</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 底部操作 -->
|
||||
<div class="bottom-bar">
|
||||
<button class="btn-draft" onclick="location.href='./recipe-list.html'">存为草稿</button>
|
||||
<button class="btn-pub" onclick="openModal('modal-pub')">发布食谱</button>
|
||||
</div>
|
||||
|
||||
<!-- 发布确认弹窗 -->
|
||||
<div id="modal-pub" class="modal-center">
|
||||
<div class="modal-box">
|
||||
<div class="modal-title">发布食谱</div>
|
||||
<div class="modal-body">发布后该食谱将推送给适用食堂,食堂可引用至食谱排期。确认发布?</div>
|
||||
<div class="modal-actions">
|
||||
<button onclick="closeModal('modal-pub')">取消</button>
|
||||
<button onclick="closeModal('modal-pub');location.href='./recipe-list.html'">确认发布</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
|
||||
/* 分段选择 */
|
||||
function segPick(el) {
|
||||
el.parentElement.querySelectorAll('.seg-picker__opt').forEach(function(o) { o.classList.remove('active'); });
|
||||
el.classList.add('active');
|
||||
}
|
||||
|
||||
/* ===== 一周食谱数据(每天三餐,每餐食物含摄入量与热量) ===== */
|
||||
var WEEK = [
|
||||
{ day: '周一', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '全麦面包', amount: 80, unit: 'g', kcal: 200 },
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 },
|
||||
{ name: '牛奶', amount: 250, unit: 'ml', kcal: 65 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '清蒸鲈鱼', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '杂粮饭', amount: 200, unit: 'g', kcal: 240 },
|
||||
{ name: '蒜蓉西兰花', amount: 150, unit: 'g', kcal: 60 },
|
||||
{ name: '紫菜蛋花汤', amount: 200, unit: 'ml', kcal: 40 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '香煎鸡胸', amount: 120, unit: 'g', kcal: 200 },
|
||||
{ name: '蔬菜沙拉', amount: 200, unit: 'g', kcal: 80 },
|
||||
{ name: '小米粥', amount: 200, unit: 'g', kcal: 120 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周二', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '燕麦牛奶', amount: 300, unit: 'ml', kcal: 220 },
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '白灼虾', amount: 150, unit: 'g', kcal: 140 },
|
||||
{ name: '糙米饭', amount: 200, unit: 'g', kcal: 230 },
|
||||
{ name: '清炒时蔬', amount: 150, unit: 'g', kcal: 55 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '蔬菜豆腐汤', amount: 300, unit: 'g', kcal: 150 },
|
||||
{ name: '杂粮馒头', amount: 100, unit: 'g', kcal: 220 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周三', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 },
|
||||
{ name: '豆浆', amount: 250, unit: 'ml', kcal: 80 },
|
||||
{ name: '蒸红薯', amount: 100, unit: 'g', kcal: 90 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '卤牛肉', amount: 100, unit: 'g', kcal: 160 },
|
||||
{ name: '荞麦面', amount: 200, unit: 'g', kcal: 230 },
|
||||
{ name: '凉拌黄瓜', amount: 150, unit: 'g', kcal: 40 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '清炒时蔬', amount: 200, unit: 'g', kcal: 60 },
|
||||
{ name: '玉米', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '菌菇汤', amount: 200, unit: 'g', kcal: 50 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周四', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '杂粮粥', amount: 300, unit: 'g', kcal: 200 },
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '香煎鸡胸', amount: 150, unit: 'g', kcal: 250 },
|
||||
{ name: '藜麦饭', amount: 150, unit: 'g', kcal: 180 },
|
||||
{ name: '西兰花', amount: 150, unit: 'g', kcal: 60 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '虾仁沙拉', amount: 200, unit: 'g', kcal: 150 },
|
||||
{ name: '全麦面包', amount: 50, unit: 'g', kcal: 120 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周五', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '全麦面包', amount: 80, unit: 'g', kcal: 200 },
|
||||
{ name: '牛奶', amount: 250, unit: 'ml', kcal: 65 },
|
||||
{ name: '香蕉', amount: 100, unit: 'g', kcal: 90 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '清蒸鱼', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '玉米', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '凉拌木耳', amount: 100, unit: 'g', kcal: 40 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '菌菇汤', amount: 300, unit: 'g', kcal: 120 },
|
||||
{ name: '杂粮饭', amount: 150, unit: 'g', kcal: 180 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周六', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 },
|
||||
{ name: '燕麦', amount: 50, unit: 'g', kcal: 190 },
|
||||
{ name: '牛奶', amount: 250, unit: 'ml', kcal: 65 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '白灼虾', amount: 150, unit: 'g', kcal: 140 },
|
||||
{ name: '杂粮饭', amount: 200, unit: 'g', kcal: 240 },
|
||||
{ name: '蔬菜沙拉', amount: 150, unit: 'g', kcal: 60 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '蔬菜沙拉', amount: 200, unit: 'g', kcal: 80 },
|
||||
{ name: '鸡胸肉', amount: 100, unit: 'g', kcal: 170 },
|
||||
{ name: '玉米', amount: 100, unit: 'g', kcal: 110 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周日', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '豆浆', amount: 250, unit: 'ml', kcal: 80 },
|
||||
{ name: '玉米', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '卤牛肉', amount: 100, unit: 'g', kcal: 160 },
|
||||
{ name: '糙米饭', amount: 200, unit: 'g', kcal: 230 },
|
||||
{ name: '清炒时蔬', amount: 150, unit: 'g', kcal: 55 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '鸡胸沙拉', amount: 250, unit: 'g', kcal: 200 },
|
||||
{ name: '小米粥', amount: 200, unit: 'g', kcal: 120 }
|
||||
]}
|
||||
]}
|
||||
];
|
||||
|
||||
/* 计算某餐总热量 */
|
||||
function mealSubtotal(di, mi) {
|
||||
return WEEK[di].meals[mi].foods.reduce(function(s, f) { return s + (parseInt(f.kcal) || 0); }, 0);
|
||||
}
|
||||
/* 计算某天总热量 */
|
||||
function dayTotal(di) {
|
||||
return WEEK[di].meals.reduce(function(s, m, mi) { return s + mealSubtotal(di, mi); }, 0);
|
||||
}
|
||||
/* 某天三餐小计摘要 */
|
||||
function daySummary(di) {
|
||||
return WEEK[di].meals.map(function(m, mi) { return m.name.charAt(0) + mealSubtotal(di, mi); }).join(' · ');
|
||||
}
|
||||
|
||||
/* 渲染单个食物行 */
|
||||
function renderFood(di, mi, fi) {
|
||||
var f = WEEK[di].meals[mi].foods[fi];
|
||||
return '<div class="food-row">' +
|
||||
'<span class="food-row__name">' + f.name + '</span>' +
|
||||
'<input class="food-row__input" type="text" value="' + f.amount + '" oninput="updateAmount(' + di + ',' + mi + ',' + fi + ',this)" />' +
|
||||
'<span class="food-row__unit">' + f.unit + '</span>' +
|
||||
'<input class="food-row__input" type="text" value="' + f.kcal + '" oninput="updateKcal(' + di + ',' + mi + ',' + fi + ',this)" />' +
|
||||
'<span class="food-row__unit">kcal</span>' +
|
||||
'<button class="food-row__del" onclick="removeFood(' + di + ',' + mi + ',' + fi + ')">×</button>' +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
/* 渲染某餐块 */
|
||||
function renderMeal(di, mi) {
|
||||
var m = WEEK[di].meals[mi];
|
||||
var html = '<div class="meal-block">' +
|
||||
'<div class="meal-head"><span class="meal-head__name">' + m.icon + ' ' + m.name + '</span><span class="meal-head__subtotal" id="meal-sub-' + di + '-' + mi + '">小计 ' + mealSubtotal(di, mi) + ' kcal</span></div>';
|
||||
m.foods.forEach(function(f, fi) { html += renderFood(di, mi, fi); });
|
||||
html += '<div class="add-food" onclick="addFood(' + di + ',' + mi + ')">+ 添加食物</div></div>';
|
||||
return html;
|
||||
}
|
||||
|
||||
/* 渲染整周折叠卡片 */
|
||||
function renderDayList() {
|
||||
var html = '';
|
||||
WEEK.forEach(function(day, di) {
|
||||
html += '<div class="day-card">' +
|
||||
'<div class="day-header" onclick="toggleDay(' + di + ')">' +
|
||||
'<span class="day-header__day">' + day.day + '</span>' +
|
||||
'<span class="day-header__summary">' + daySummary(di) + '</span>' +
|
||||
'<span class="day-header__kcal" id="day-kcal-' + di + '">' + dayTotal(di) + ' kcal</span>' +
|
||||
'<svg class="arrow" id="arrow-' + di + '" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="#999" stroke-width="2"><path d="M4 6l4 4 4-4"/></svg>' +
|
||||
'</div>' +
|
||||
'<div class="day-body" id="day-body-' + di + '">' +
|
||||
day.meals.map(function(m, mi) { return renderMeal(di, mi); }).join('') +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
});
|
||||
document.getElementById('day-list').innerHTML = html;
|
||||
/* 默认展开周一 */
|
||||
document.getElementById('day-body-0').classList.add('open');
|
||||
document.getElementById('arrow-0').classList.add('open');
|
||||
}
|
||||
|
||||
/* 折叠/展开某天 */
|
||||
function toggleDay(di) {
|
||||
var body = document.getElementById('day-body-' + di);
|
||||
var arrow = document.getElementById('arrow-' + di);
|
||||
body.classList.toggle('open');
|
||||
arrow.classList.toggle('open');
|
||||
}
|
||||
|
||||
/* 更新摄入量 */
|
||||
function updateAmount(di, mi, fi, el) {
|
||||
WEEK[di].meals[mi].foods[fi].amount = el.value;
|
||||
}
|
||||
|
||||
/* 更新热量并重算小计与总计 */
|
||||
function updateKcal(di, mi, fi, el) {
|
||||
WEEK[di].meals[mi].foods[fi].kcal = parseInt(el.value) || 0;
|
||||
document.getElementById('meal-sub-' + di + '-' + mi).textContent = '小计 ' + mealSubtotal(di, mi) + ' kcal';
|
||||
document.getElementById('day-kcal-' + di).textContent = dayTotal(di) + ' kcal';
|
||||
}
|
||||
|
||||
/* 添加食物 */
|
||||
function addFood(di, mi) {
|
||||
WEEK[di].meals[mi].foods.push({ name: '新食物', amount: 100, unit: 'g', kcal: 100 });
|
||||
var body = document.getElementById('day-body-' + di);
|
||||
body.innerHTML = WEEK[di].meals.map(function(m, mi2) { return renderMeal(di, mi2); }).join('');
|
||||
}
|
||||
|
||||
/* 删除食物 */
|
||||
function removeFood(di, mi, fi) {
|
||||
WEEK[di].meals[mi].foods.splice(fi, 1);
|
||||
var body = document.getElementById('day-body-' + di);
|
||||
body.innerHTML = WEEK[di].meals.map(function(m, mi2) { return renderMeal(di, mi2); }).join('');
|
||||
document.getElementById('day-kcal-' + di).textContent = dayTotal(di) + ' kcal';
|
||||
}
|
||||
|
||||
/* 初始化渲染 */
|
||||
renderDayList();
|
||||
|
||||
function openModal(id) { var m = document.getElementById(id); if (m) m.classList.add('active'); }
|
||||
function closeModal(id) { var m = document.getElementById(id); if (m) m.classList.remove('active'); }
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,309 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师工作台 - 食谱详情 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #f7f8fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; position: relative; }
|
||||
.nav-back { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
/* 头部 */
|
||||
.recipe-header { background: linear-gradient(135deg,#1677ff,#0958d9); padding: 16px 20px; color: #fff; }
|
||||
.recipe-header__name { font-size: 18px; font-weight: 700; }
|
||||
.recipe-header__meta { font-size: 12px; color: rgba(255,255,255,0.85); margin-top: 6px; }
|
||||
.recipe-header__tags { display: flex; gap: 6px; margin-top: 10px; flex-wrap: wrap; }
|
||||
.recipe-header__tag { font-size: 11px; padding: 3px 10px; border-radius: 12px; background: rgba(255,255,255,0.2); }
|
||||
/* 卡片 */
|
||||
.card { background: #fff; border-radius: 12px; margin: 10px 12px 0; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
|
||||
.card__title { font-size: 14px; font-weight: 700; color: #1a1a1a; margin-bottom: 10px; }
|
||||
/* 引用统计 */
|
||||
.cite-stat { display: flex; gap: 8px; }
|
||||
.cite-stat__item { flex: 1; text-align: center; background: #fafafa; border-radius: 8px; padding: 10px 0; }
|
||||
.cite-stat__val { font-size: 16px; font-weight: 700; color: #1677ff; }
|
||||
.cite-stat__label { font-size: 11px; color: #999; margin-top: 2px; }
|
||||
/* 食堂引用列表 */
|
||||
.canteen-item { display: flex; align-items: center; gap: 10px; padding: 12px 0; border-bottom: 1px solid #f5f5f5; }
|
||||
.canteen-item:last-child { border-bottom: none; }
|
||||
.canteen-item__icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 20px; flex-shrink: 0; }
|
||||
.canteen-item__info { flex: 1; min-width: 0; }
|
||||
.canteen-item__name { font-size: 14px; font-weight: 600; color: #1a1a1a; }
|
||||
.canteen-item__meta { font-size: 12px; color: #999; margin-top: 2px; }
|
||||
.tag { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; }
|
||||
.tag-green { background: #f6ffed; color: #52c41a; }
|
||||
.tag-orange { background: #fff7e6; color: #fa8c16; }
|
||||
/* 一周餐次安排(按天折叠,每天三餐,食物含摄入量与热量) */
|
||||
.day-card { background: #fff; border: 1px solid #e8e8e8; border-radius: 10px; margin-bottom: 10px; overflow: hidden; }
|
||||
.day-card:last-child { margin-bottom: 0; }
|
||||
.day-header { display: flex; align-items: center; justify-content: space-between; padding: 12px; cursor: pointer; }
|
||||
.day-header__day { font-size: 14px; font-weight: 600; color: #1a1a1a; }
|
||||
.day-header__summary { font-size: 12px; color: #999; }
|
||||
.day-header__kcal { font-size: 12px; color: #fa8c16; font-weight: 600; }
|
||||
.day-header .arrow { transition: transform .2s; flex-shrink: 0; }
|
||||
.day-header .arrow.open { transform: rotate(180deg); }
|
||||
.day-body { display: none; padding: 0 12px 12px; }
|
||||
.day-body.open { display: block; }
|
||||
.meal-block { background: #fafafa; border-radius: 8px; padding: 10px; margin-bottom: 8px; }
|
||||
.meal-block:last-child { margin-bottom: 0; }
|
||||
.meal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
|
||||
.meal-head__name { font-size: 13px; font-weight: 600; color: #1a1a1a; }
|
||||
.meal-head__subtotal { font-size: 12px; color: #fa8c16; font-weight: 600; }
|
||||
.food-row { display: flex; align-items: center; gap: 6px; padding: 6px 0; border-bottom: 1px dashed #f0f0f0; }
|
||||
.food-row:last-child { border-bottom: none; }
|
||||
.food-row__name { flex: 1; font-size: 13px; color: #333; }
|
||||
.food-row__amount { font-size: 12px; color: #666; width: 44px; text-align: right; flex-shrink: 0; }
|
||||
.food-row__kcal { font-size: 12px; color: #fa8c16; font-weight: 600; width: 56px; text-align: right; flex-shrink: 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 导航栏 -->
|
||||
<div class="nav-bar">
|
||||
<button class="nav-back" onclick="location.href='./recipe-list.html'">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title">食谱详情</span>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
|
||||
<!-- 头部 -->
|
||||
<div class="recipe-header">
|
||||
<div class="recipe-header__name">机关减脂周菜单(第 37 周)</div>
|
||||
<div class="recipe-header__meta">周菜单 · 2026-09-14 至 09-20 · 李营养师</div>
|
||||
<div class="recipe-header__tags">
|
||||
<span class="recipe-header__tag">低脂</span>
|
||||
<span class="recipe-header__tag">均衡营养</span>
|
||||
<span class="recipe-header__tag">已发布</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 引用情况 -->
|
||||
<div class="card">
|
||||
<div class="card__title">引用情况</div>
|
||||
<div class="cite-stat">
|
||||
<div class="cite-stat__item"><div class="cite-stat__val">5</div><div class="cite-stat__label">已引用食堂</div></div>
|
||||
<div class="cite-stat__item"><div class="cite-stat__val">3</div><div class="cite-stat__label">待确认</div></div>
|
||||
<div class="cite-stat__item"><div class="cite-stat__val">0</div><div class="cite-stat__label">已拒绝</div></div>
|
||||
</div>
|
||||
<div style="margin-top:12px;">
|
||||
<div class="canteen-item">
|
||||
<div class="canteen-item__icon" style="background:linear-gradient(135deg,#f6ffed,#b7eb8f);">🏢</div>
|
||||
<div class="canteen-item__info"><div class="canteen-item__name">机关食堂</div><div class="canteen-item__meta">公司机关 · 已排期</div></div>
|
||||
<span class="tag tag-green">已引用</span>
|
||||
</div>
|
||||
<div class="canteen-item">
|
||||
<div class="canteen-item__icon" style="background:linear-gradient(135deg,#e6f4ff,#bdd7ff);">🏭</div>
|
||||
<div class="canteen-item__info"><div class="canteen-item__name">采油一厂食堂</div><div class="canteen-item__meta">采油一厂 · 已排期</div></div>
|
||||
<span class="tag tag-green">已引用</span>
|
||||
</div>
|
||||
<div class="canteen-item">
|
||||
<div class="canteen-item__icon" style="background:linear-gradient(135deg,#fff7e6,#ffd591);">🏪</div>
|
||||
<div class="canteen-item__info"><div class="canteen-item__name">信息中心食堂</div><div class="canteen-item__meta">信息技术中心 · 待确认</div></div>
|
||||
<span class="tag tag-orange">待确认</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 一周餐次安排 -->
|
||||
<div class="card">
|
||||
<div class="card__title">一周餐次安排</div>
|
||||
<div id="day-list"></div>
|
||||
</div>
|
||||
|
||||
<div style="height:16px;"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
|
||||
/* ===== 一周食谱数据(每天三餐,每餐食物含摄入量与热量) ===== */
|
||||
var WEEK = [
|
||||
{ day: '周一', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '全麦面包', amount: 80, unit: 'g', kcal: 200 },
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 },
|
||||
{ name: '牛奶', amount: 250, unit: 'ml', kcal: 65 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '清蒸鲈鱼', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '杂粮饭', amount: 200, unit: 'g', kcal: 240 },
|
||||
{ name: '蒜蓉西兰花', amount: 150, unit: 'g', kcal: 60 },
|
||||
{ name: '紫菜蛋花汤', amount: 200, unit: 'ml', kcal: 40 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '香煎鸡胸', amount: 120, unit: 'g', kcal: 200 },
|
||||
{ name: '蔬菜沙拉', amount: 200, unit: 'g', kcal: 80 },
|
||||
{ name: '小米粥', amount: 200, unit: 'g', kcal: 120 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周二', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '燕麦牛奶', amount: 300, unit: 'ml', kcal: 220 },
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '白灼虾', amount: 150, unit: 'g', kcal: 140 },
|
||||
{ name: '糙米饭', amount: 200, unit: 'g', kcal: 230 },
|
||||
{ name: '清炒时蔬', amount: 150, unit: 'g', kcal: 55 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '蔬菜豆腐汤', amount: 300, unit: 'g', kcal: 150 },
|
||||
{ name: '杂粮馒头', amount: 100, unit: 'g', kcal: 220 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周三', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 },
|
||||
{ name: '豆浆', amount: 250, unit: 'ml', kcal: 80 },
|
||||
{ name: '蒸红薯', amount: 100, unit: 'g', kcal: 90 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '卤牛肉', amount: 100, unit: 'g', kcal: 160 },
|
||||
{ name: '荞麦面', amount: 200, unit: 'g', kcal: 230 },
|
||||
{ name: '凉拌黄瓜', amount: 150, unit: 'g', kcal: 40 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '清炒时蔬', amount: 200, unit: 'g', kcal: 60 },
|
||||
{ name: '玉米', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '菌菇汤', amount: 200, unit: 'g', kcal: 50 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周四', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '杂粮粥', amount: 300, unit: 'g', kcal: 200 },
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '香煎鸡胸', amount: 150, unit: 'g', kcal: 250 },
|
||||
{ name: '藜麦饭', amount: 150, unit: 'g', kcal: 180 },
|
||||
{ name: '西兰花', amount: 150, unit: 'g', kcal: 60 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '虾仁沙拉', amount: 200, unit: 'g', kcal: 150 },
|
||||
{ name: '全麦面包', amount: 50, unit: 'g', kcal: 120 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周五', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '全麦面包', amount: 80, unit: 'g', kcal: 200 },
|
||||
{ name: '牛奶', amount: 250, unit: 'ml', kcal: 65 },
|
||||
{ name: '香蕉', amount: 100, unit: 'g', kcal: 90 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '清蒸鱼', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '玉米', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '凉拌木耳', amount: 100, unit: 'g', kcal: 40 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '菌菇汤', amount: 300, unit: 'g', kcal: 120 },
|
||||
{ name: '杂粮饭', amount: 150, unit: 'g', kcal: 180 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周六', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 },
|
||||
{ name: '燕麦', amount: 50, unit: 'g', kcal: 190 },
|
||||
{ name: '牛奶', amount: 250, unit: 'ml', kcal: 65 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '白灼虾', amount: 150, unit: 'g', kcal: 140 },
|
||||
{ name: '杂粮饭', amount: 200, unit: 'g', kcal: 240 },
|
||||
{ name: '蔬菜沙拉', amount: 150, unit: 'g', kcal: 60 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '蔬菜沙拉', amount: 200, unit: 'g', kcal: 80 },
|
||||
{ name: '鸡胸肉', amount: 100, unit: 'g', kcal: 170 },
|
||||
{ name: '玉米', amount: 100, unit: 'g', kcal: 110 }
|
||||
]}
|
||||
]},
|
||||
{ day: '周日', meals: [
|
||||
{ icon: '🥣', name: '早餐', foods: [
|
||||
{ name: '豆浆', amount: 250, unit: 'ml', kcal: 80 },
|
||||
{ name: '玉米', amount: 150, unit: 'g', kcal: 160 },
|
||||
{ name: '水煮蛋', amount: 60, unit: 'g', kcal: 70 }
|
||||
]},
|
||||
{ icon: '🍱', name: '午餐', foods: [
|
||||
{ name: '卤牛肉', amount: 100, unit: 'g', kcal: 160 },
|
||||
{ name: '糙米饭', amount: 200, unit: 'g', kcal: 230 },
|
||||
{ name: '清炒时蔬', amount: 150, unit: 'g', kcal: 55 }
|
||||
]},
|
||||
{ icon: '🍽️', name: '晚餐', foods: [
|
||||
{ name: '鸡胸沙拉', amount: 250, unit: 'g', kcal: 200 },
|
||||
{ name: '小米粥', amount: 200, unit: 'g', kcal: 120 }
|
||||
]}
|
||||
]}
|
||||
];
|
||||
|
||||
/* 计算某餐总热量 */
|
||||
function mealSubtotal(di, mi) {
|
||||
return WEEK[di].meals[mi].foods.reduce(function(s, f) { return s + f.kcal; }, 0);
|
||||
}
|
||||
/* 计算某天总热量 */
|
||||
function dayTotal(di) {
|
||||
return WEEK[di].meals.reduce(function(s, m, mi) { return s + mealSubtotal(di, mi); }, 0);
|
||||
}
|
||||
/* 某天三餐小计摘要 */
|
||||
function daySummary(di) {
|
||||
return WEEK[di].meals.map(function(m, mi) { return m.name.charAt(0) + mealSubtotal(di, mi); }).join(' · ');
|
||||
}
|
||||
|
||||
/* 渲染整周折叠卡片(只读) */
|
||||
function renderDayList() {
|
||||
var html = '';
|
||||
WEEK.forEach(function(day, di) {
|
||||
html += '<div class="day-card">' +
|
||||
'<div class="day-header" onclick="toggleDay(' + di + ')">' +
|
||||
'<span class="day-header__day">' + day.day + '</span>' +
|
||||
'<span class="day-header__summary">' + daySummary(di) + '</span>' +
|
||||
'<span class="day-header__kcal">' + dayTotal(di) + ' kcal</span>' +
|
||||
'<svg class="arrow" id="arrow-' + di + '" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="#999" stroke-width="2"><path d="M4 6l4 4 4-4"/></svg>' +
|
||||
'</div>' +
|
||||
'<div class="day-body" id="day-body-' + di + '">' +
|
||||
day.meals.map(function(m, mi) {
|
||||
return '<div class="meal-block">' +
|
||||
'<div class="meal-head"><span class="meal-head__name">' + m.icon + ' ' + m.name + '</span><span class="meal-head__subtotal">小计 ' + mealSubtotal(di, mi) + ' kcal</span></div>' +
|
||||
m.foods.map(function(f) {
|
||||
return '<div class="food-row"><span class="food-row__name">' + f.name + '</span><span class="food-row__amount">' + f.amount + f.unit + '</span><span class="food-row__kcal">' + f.kcal + ' kcal</span></div>';
|
||||
}).join('') +
|
||||
'</div>';
|
||||
}).join('') +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
});
|
||||
document.getElementById('day-list').innerHTML = html;
|
||||
/* 默认展开周一 */
|
||||
document.getElementById('day-body-0').classList.add('open');
|
||||
document.getElementById('arrow-0').classList.add('open');
|
||||
}
|
||||
|
||||
/* 折叠/展开某天 */
|
||||
function toggleDay(di) {
|
||||
var body = document.getElementById('day-body-' + di);
|
||||
var arrow = document.getElementById('arrow-' + di);
|
||||
body.classList.toggle('open');
|
||||
arrow.classList.toggle('open');
|
||||
}
|
||||
|
||||
/* 初始化渲染 */
|
||||
renderDayList();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,175 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>营养师工作台 - 我的食谱 | 健康CQ原型</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #f7f8fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
|
||||
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; z-index: 10; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
|
||||
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; position: relative; }
|
||||
.nav-back { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
|
||||
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
|
||||
.nav-add { margin-left: auto; color: #1677ff; font-size: 14px; cursor: pointer; background: none; border: none; font-weight: 600; }
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
.seg-tabs { display: flex; background: #fff; border-bottom: 1px solid #f0f0f0; flex-shrink: 0; }
|
||||
.seg-tab { flex: 1; text-align: center; padding: 12px 0; font-size: 14px; color: #666; cursor: pointer; border-bottom: 2px solid transparent; }
|
||||
.seg-tab.active { color: #1677ff; border-bottom-color: #1677ff; font-weight: 600; }
|
||||
.seg-tab .badge { display: inline-block; background: #e8e8e8; color: #666; font-size: 10px; font-weight: 700; min-width: 16px; height: 16px; border-radius: 8px; padding: 0 4px; margin-left: 4px; vertical-align: middle; line-height: 16px; }
|
||||
.seg-tab.active .badge { background: #e6f4ff; color: #1677ff; }
|
||||
/* 食谱卡片 */
|
||||
.recipe-card { background: #fff; border-radius: 12px; margin: 10px 12px 0; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); cursor: pointer; }
|
||||
.recipe-card:active { transform: scale(0.98); }
|
||||
.recipe-card__head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
|
||||
.recipe-card__icon { width: 44px; height: 44px; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 22px; flex-shrink: 0; }
|
||||
.recipe-card__info { flex: 1; min-width: 0; }
|
||||
.recipe-card__name { font-size: 15px; font-weight: 600; color: #1a1a1a; }
|
||||
.recipe-card__meta { font-size: 12px; color: #999; margin-top: 2px; }
|
||||
.recipe-card__footer { display: flex; align-items: center; justify-content: space-between; padding-top: 10px; border-top: 1px solid #f5f5f5; }
|
||||
.recipe-card__cite { font-size: 12px; color: #666; }
|
||||
.recipe-card__cite .num { font-weight: 700; color: #1677ff; }
|
||||
.tag { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; }
|
||||
.tag-green { background: #f6ffed; color: #52c41a; }
|
||||
.tag-gray { background: #f5f5f5; color: #999; }
|
||||
.tag-blue { background: #e6f4ff; color: #1677ff; }
|
||||
/* 制定食谱按钮 */
|
||||
.fab { position: absolute; right: 20px; bottom: 100px; width: 56px; height: 56px; border-radius: 50%; background: #1677ff; color: #fff; display: flex; align-items: center; justify-content: center; font-size: 28px; cursor: pointer; box-shadow: 0 4px 12px rgba(22,119,255,0.4); z-index: 50; }
|
||||
.fab:active { transform: scale(0.94); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
|
||||
<div class="status-bar">
|
||||
<span class="time">9:41</span>
|
||||
<div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div>
|
||||
</div>
|
||||
|
||||
<!-- 导航栏 -->
|
||||
<div class="nav-bar">
|
||||
<button class="nav-back" onclick="location.href='./index.html'">
|
||||
<svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回
|
||||
</button>
|
||||
<span class="nav-title">我的食谱</span>
|
||||
<!-- [交互] 点击跳转至: ./recipe-create.html -->
|
||||
<button class="nav-add" onclick="location.href='./recipe-create.html'">制定食谱</button>
|
||||
</div>
|
||||
|
||||
<!-- Tab -->
|
||||
<div class="seg-tabs">
|
||||
<div class="seg-tab active" onclick="switchTab(this,'panel-all')">全部<span class="badge">6</span></div>
|
||||
<div class="seg-tab" onclick="switchTab(this,'panel-pub')">已发布<span class="badge">4</span></div>
|
||||
<div class="seg-tab" onclick="switchTab(this,'panel-draft')">草稿<span class="badge">2</span></div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
<div id="panel-all">
|
||||
<!-- [交互] 点击跳转至: ./recipe-detail.html -->
|
||||
<div class="recipe-card" onclick="location.href='./recipe-detail.html'">
|
||||
<div class="recipe-card__head">
|
||||
<div class="recipe-card__icon" style="background:linear-gradient(135deg,#f6ffed,#b7eb8f);">🥗</div>
|
||||
<div class="recipe-card__info">
|
||||
<div class="recipe-card__name">机关减脂周菜单(第 37 周)</div>
|
||||
<div class="recipe-card__meta">周菜单 · 早/中/晚 · 2026-09-14 ~ 09-20</div>
|
||||
</div>
|
||||
<span class="tag tag-green">已发布</span>
|
||||
</div>
|
||||
<div class="recipe-card__footer">
|
||||
<span class="recipe-card__cite">被 <span class="num">5</span> 个食堂引用</span>
|
||||
<span style="font-size:12px;color:#1677ff;">查看详情 ›</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="recipe-card" onclick="location.href='./recipe-detail.html'">
|
||||
<div class="recipe-card__head">
|
||||
<div class="recipe-card__icon" style="background:linear-gradient(135deg,#fff7e6,#ffd591);">🍚</div>
|
||||
<div class="recipe-card__info">
|
||||
<div class="recipe-card__name">一线高能量周菜单(第 37 周)</div>
|
||||
<div class="recipe-card__meta">周菜单 · 早/中/晚 · 2026-09-14 ~ 09-20</div>
|
||||
</div>
|
||||
<span class="tag tag-green">已发布</span>
|
||||
</div>
|
||||
<div class="recipe-card__footer">
|
||||
<span class="recipe-card__cite">被 <span class="num">3</span> 个食堂引用</span>
|
||||
<span style="font-size:12px;color:#1677ff;">查看详情 ›</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="recipe-card" onclick="location.href='./recipe-detail.html'">
|
||||
<div class="recipe-card__head">
|
||||
<div class="recipe-card__icon" style="background:linear-gradient(135deg,#e6f4ff,#bdd7ff);">🍂</div>
|
||||
<div class="recipe-card__info">
|
||||
<div class="recipe-card__name">秋季养生季节菜单</div>
|
||||
<div class="recipe-card__meta">季节菜单 · 早/中/晚 · 2026-09 ~ 11</div>
|
||||
</div>
|
||||
<span class="tag tag-green">已发布</span>
|
||||
</div>
|
||||
<div class="recipe-card__footer">
|
||||
<span class="recipe-card__cite">被 <span class="num">8</span> 个食堂引用</span>
|
||||
<span style="font-size:12px;color:#1677ff;">查看详情 ›</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="recipe-card" onclick="location.href='./recipe-detail.html'">
|
||||
<div class="recipe-card__head">
|
||||
<div class="recipe-card__icon" style="background:linear-gradient(135deg,#f9f0ff,#d3adf7);">🥩</div>
|
||||
<div class="recipe-card__info">
|
||||
<div class="recipe-card__name">控糖低 GI 周菜单(第 38 周)</div>
|
||||
<div class="recipe-card__meta">周菜单 · 早/中/晚 · 2026-09-21 ~ 09-27</div>
|
||||
</div>
|
||||
<span class="tag tag-gray">草稿</span>
|
||||
</div>
|
||||
<div class="recipe-card__footer">
|
||||
<span class="recipe-card__cite">尚未发布</span>
|
||||
<span style="font-size:12px;color:#1677ff;">继续编辑 ›</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height:90px;"></div>
|
||||
</div>
|
||||
|
||||
<div id="panel-pub" style="display:none;">
|
||||
<div class="recipe-card" onclick="location.href='./recipe-detail.html'">
|
||||
<div class="recipe-card__head">
|
||||
<div class="recipe-card__icon" style="background:linear-gradient(135deg,#f6ffed,#b7eb8f);">🥗</div>
|
||||
<div class="recipe-card__info"><div class="recipe-card__name">机关减脂周菜单(第 37 周)</div><div class="recipe-card__meta">周菜单 · 2026-09-14 ~ 09-20</div></div>
|
||||
<span class="tag tag-green">已发布</span>
|
||||
</div>
|
||||
<div class="recipe-card__footer"><span class="recipe-card__cite">被 <span class="num">5</span> 个食堂引用</span><span style="font-size:12px;color:#1677ff;">查看详情 ›</span></div>
|
||||
</div>
|
||||
<div style="height:90px;"></div>
|
||||
</div>
|
||||
|
||||
<div id="panel-draft" style="display:none;">
|
||||
<div class="recipe-card" onclick="location.href='./recipe-detail.html'">
|
||||
<div class="recipe-card__head">
|
||||
<div class="recipe-card__icon" style="background:linear-gradient(135deg,#f9f0ff,#d3adf7);">🥩</div>
|
||||
<div class="recipe-card__info"><div class="recipe-card__name">控糖低 GI 周菜单(第 38 周)</div><div class="recipe-card__meta">周菜单 · 2026-09-21 ~ 09-27</div></div>
|
||||
<span class="tag tag-gray">草稿</span>
|
||||
</div>
|
||||
<div class="recipe-card__footer"><span class="recipe-card__cite">尚未发布</span><span style="font-size:12px;color:#1677ff;">继续编辑 ›</span></div>
|
||||
</div>
|
||||
<div style="height:90px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 制定食谱悬浮按钮 -->
|
||||
<div class="fab" onclick="location.href='./recipe-create.html'">+</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* 标记当前角色为营养师 */
|
||||
sessionStorage.setItem('appRole', 'nutritionist');
|
||||
|
||||
function switchTab(el, panelId) {
|
||||
el.closest('.seg-tabs').querySelectorAll('.seg-tab').forEach(function(t) { t.classList.remove('active'); });
|
||||
el.classList.add('active');
|
||||
['panel-all','panel-pub','panel-draft'].forEach(function(id) {
|
||||
document.getElementById(id).style.display = id === panelId ? 'block' : 'none';
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -17,7 +17,7 @@
|
||||
│ ├── 吃动平衡
|
||||
│ ├── 饮食记录 → 饮食录入 → 拍照识别
|
||||
│ ├── 运动记录 → 运动录入
|
||||
│ ├── 体重记录 → 详细报告 / 体脂仪报告 / 身高秤报告
|
||||
│ ├── 体重记录 → 详细报告 / 体脂仪报告 / 体重秤报告
|
||||
│ ├── 今日饮食建议
|
||||
│ ├── 智能运动计划
|
||||
│ ├── 排行榜
|
||||
@@ -89,7 +89,7 @@ stateDiagram-v2
|
||||
| 17 | 体重记录 | weight-detail-v2.html | 页面 |
|
||||
| 18 | 详细报告 | report-detail.html | 页面 |
|
||||
| 19 | 体脂仪报告 | body-fat-report.html | 页面 |
|
||||
| 20 | 身高秤报告 | height-scale-report.html | 页面 |
|
||||
| 20 | 体重秤报告 | height-scale-report.html | 页面 |
|
||||
| 21 | 体重报告 | weight-report.html | 页面 |
|
||||
| 22 | 数据明细 | weight-record-detail-v2.html | 页面 |
|
||||
| 23 | 排行榜 | weight-ranking.html | 页面 |
|
||||
@@ -693,9 +693,9 @@ stateDiagram-v2
|
||||
- 无记录日期显示空状态("立即称重"按钮)
|
||||
- BMI 分档:<18.5 偏瘦 / 18.5-24 正常 / 24-28 超重 / ≥28 肥胖
|
||||
- 非自记来源(蓝牙称/体重秤/体脂仪)记录可点击查看详细报告,自记不可点击;蓝牙称跳 report-detail.html,体脂仪跳 body-fat-report.html,体重秤跳 height-scale-report.html
|
||||
- 原"记录体重"底部按钮已移除,记录入口收敛至数据来源卡片的"自记"卡片;原"身高秤"来源在本页统一更名为"体重秤"(对应报告页 height-scale-report.html 仍为身高秤报告)
|
||||
- 原"记录体重"底部按钮已移除,记录入口收敛至数据来源卡片的"自记"卡片
|
||||
- 当日最新记录与上一次记录对比显示变化,无历史记录时显示"首次记录"
|
||||
- 体重数据来源目前有体检数据、自记数据、后台管理员记录、身高秤、蓝牙秤、体脂仪这6种,其中体检数据和后台管理员需要更新最新体重但记录不计入员工打卡行动,另外三种测量设备的数据可能出现延迟上传的情况,系统至多允许补录前一天的体重数据(定时修正前一天的行动状态和排名数据),再早的数据补传后不计入体重管理行动体重打卡
|
||||
- 体重数据来源目前有体检数据、自记数据、后台管理员记录、体重秤、蓝牙秤、体脂仪这6种,其中体检数据和后台管理员需要更新最新体重但记录不计入员工打卡行动,另外三种测量设备的数据可能出现延迟上传的情况,系统至多允许补录前一天的体重数据(定时修正前一天的行动状态和排名数据),再早的数据补传后不计入体重管理行动体重打卡
|
||||
---
|
||||
|
||||
### 18. 详细报告(report-detail.html)
|
||||
@@ -718,7 +718,7 @@ stateDiagram-v2
|
||||
| 蓝牙秤(device=bluetooth) | 基础指标、身体成分、脂肪分析、体态管理、体重管控、细胞液分析(8电极)、进阶成分(8电极)、躯干/四肢脂肪(8电极)、躯干/四肢肌肉(8电极) |
|
||||
| 体脂仪(device=fat) | 基础指标、体脂分析、体成分、体重管理、节段脂肪、节段肌肉 |
|
||||
|
||||
注:体重记录页中"体重秤"(原身高秤)来源的记录已改跳转至独立页面 height-scale-report.html,"体脂仪"来源的记录已改跳转至 body-fat-report.html,本页 device=fat / device=scale 模式保留用于兼容。
|
||||
注:体重记录页中"体重秤"来源的记录已改跳转至独立页面 height-scale-report.html,"体脂仪"来源的记录已改跳转至 body-fat-report.html,本页 device=fat / device=scale 模式保留用于兼容。
|
||||
|
||||
**交互说明:**
|
||||
- 点击返回按钮返回来源页
|
||||
@@ -750,16 +750,16 @@ stateDiagram-v2
|
||||
|
||||
---
|
||||
|
||||
### 20. 身高秤报告(height-scale-report.html)
|
||||
### 20. 体重秤报告(height-scale-report.html)
|
||||
|
||||

|
||||
|
||||
**功能说明:** 展示身高秤单次测量的身体成分报告,含身高、体重及身体成分、体态相关指标。
|
||||
**功能说明:** 展示体重秤单次测量的身体成分报告,含身高、体重及身体成分、体态相关指标。
|
||||
|
||||
**页面状态:** 从体重记录页(weight-detail-v2.html)记录明细列表中体重秤(原身高秤)来源的记录跳转进入,页面只读。
|
||||
**页面状态:** 从体重记录页(weight-detail-v2.html)记录明细列表中体重秤来源的记录跳转进入,页面只读。
|
||||
|
||||
**主要UI元素:**
|
||||
- 报告头部(蓝青渐变卡片):测量时间、设备标签「身高秤」、当前体重(大字)、BMI 状态标签、较上次变化
|
||||
- 报告头部(蓝青渐变卡片):测量时间、设备标签「体重秤」、当前体重(大字)、BMI 状态标签、较上次变化
|
||||
- 基础指标:身高 / 体重 / BMI / 体脂率(含 BMI 指示条:消瘦/正常/超重/肥胖四段色轨 + 指针)
|
||||
- 身体成分:体脂肪 / 水分率 / 水分量 / 肌肉率 / 肌肉量 / 骨量 / 去脂体重
|
||||
- 体态分析:内脏脂肪 / 体型 / 理想体重 / 超重百分比 / 体表面积
|
||||
|
||||
@@ -350,7 +350,7 @@ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-
|
||||
<section class="section" id="sec-history">
|
||||
<div class="section__header">
|
||||
<h2 class="section__title">四、历史记录与报告详情</h2>
|
||||
<span class="section__count">16 屏</span>
|
||||
<span class="section__count">14 屏</span>
|
||||
</div>
|
||||
<div class="sub-title">记录明细(周视图 / 月历浮层 / 数据点浮签 / 设备来源)</div>
|
||||
<div class="scroll-row">
|
||||
@@ -408,16 +408,8 @@ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sub-title">详细报告(report-detail.html 三设备 + 体脂 / 身高报告)</div>
|
||||
<div class="sub-title">详细报告(report-detail.html 蓝牙秤 + 体脂 / 身高报告)</div>
|
||||
<div class="scroll-row">
|
||||
<div class="card" onclick="openLightbox('screenshots/report-detail-fat.jpg','详细报告 · 体脂仪')">
|
||||
<div class="card__img"><img src="screenshots/report-detail-fat.jpg" alt=""></div>
|
||||
<div class="card__label">报告 · 体脂仪</div>
|
||||
</div>
|
||||
<div class="card" onclick="openLightbox('screenshots/report-detail-scale.jpg','详细报告 · 体重秤')">
|
||||
<div class="card__img"><img src="screenshots/report-detail-scale.jpg" alt=""></div>
|
||||
<div class="card__label">报告 · 体重秤</div>
|
||||
</div>
|
||||
<div class="card" onclick="openLightbox('screenshots/report-detail-bluetooth.jpg','详细报告 · 蓝牙秤')">
|
||||
<div class="card__img"><img src="screenshots/report-detail-bluetooth.jpg" alt=""></div>
|
||||
<div class="card__label">报告 · 蓝牙秤</div>
|
||||
@@ -426,9 +418,9 @@ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-
|
||||
<div class="card__img"><img src="screenshots/body-fat-report.jpg" alt=""></div>
|
||||
<div class="card__label">体脂报告</div>
|
||||
</div>
|
||||
<div class="card" onclick="openLightbox('screenshots/height-scale-report.jpg','身高测量报告')">
|
||||
<div class="card" onclick="openLightbox('screenshots/height-scale-report.jpg','体重秤报告')">
|
||||
<div class="card__img"><img src="screenshots/height-scale-report.jpg" alt=""></div>
|
||||
<div class="card__label">身高测量报告</div>
|
||||
<div class="card__label">体重秤报告</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
@@ -87,7 +87,7 @@ function goBack() {
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
* 身高秤报告数据
|
||||
* 体重秤报告数据
|
||||
* 字段名沿用统一后的命名:脂肪率→体脂率、脂肪量→体脂肪
|
||||
* ======================================================================== */
|
||||
var report = {
|
||||
@@ -183,7 +183,7 @@ var changeText = (report.weightChange < 0 ? '' : '+') + fmtVal(report.weightChan
|
||||
document.getElementById('reportHeader').innerHTML =
|
||||
'<div class="report-header__top">' +
|
||||
'<div class="report-header__time"><svg width="14" height="14" fill="none"><circle cx="7" cy="7" r="6" stroke="#fff" stroke-width="1.5"/><path d="M7 4v3.5l2.5 1.5" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg> ' + report.time + '</div>' +
|
||||
'<span class="device-tag device-tag--stadiometer">身高秤</span>' +
|
||||
'<span class="device-tag device-tag--stadiometer">体重秤</span>' +
|
||||
'</div>' +
|
||||
'<div class="report-header__main">' +
|
||||
'<div class="report-header__weight"><span class="report-header__weight-num">' + fmtVal(report.weight) + '</span><span class="report-header__weight-unit">kg</span></div>' +
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
body { background: var(--background); font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', 'Segoe UI', sans-serif; color: var(--text-primary); min-height: 100vh; }
|
||||
|
||||
/* ===== Header ===== */
|
||||
.header { position: relative; background: linear-gradient(135deg, #0b3d91 0%, var(--primary) 40%, #4facfe 100%); color: #fff; padding: 40px 48px 20px; overflow: hidden; }
|
||||
.header { position: sticky; top: 0; z-index: 300; background: linear-gradient(135deg, #0b3d91 0%, var(--primary) 40%, #4facfe 100%); color: #fff; padding: 40px 48px 20px; overflow: hidden; }
|
||||
.header::before { content: ''; position: absolute; top: -60px; right: -40px; width: 260px; height: 260px; background: radial-gradient(circle, rgba(255,255,255,0.12) 0%, transparent 70%); border-radius: 50%; }
|
||||
.header::after { content: ''; position: absolute; bottom: -80px; left: 20%; width: 360px; height: 360px; background: radial-gradient(circle, rgba(255,255,255,0.06) 0%, transparent 70%); border-radius: 50%; }
|
||||
.header__inner { position: relative; z-index: 1; max-width: 1400px; margin: 0 auto; text-align: center; }
|
||||
@@ -219,6 +219,7 @@ const SITE_MAP = [
|
||||
{ file:'config-standard-category.html', label:'体检项目分类' },
|
||||
{ file:'config-standard-basic.html', label:'体检基本项目' },
|
||||
{ file:'config-standard-hospital.html', label:'医院体检项目' },
|
||||
{ file:'agent-device.html', label:'前置机管理' },
|
||||
{ file:'pre-hospital-scope.html', label:'医院承检范围' },
|
||||
{ file:'pre-plan.html', label:'单位体检计划管理' },
|
||||
{ file:'pre-quota-group.html', label:'群体额度配置' },
|
||||
@@ -254,6 +255,7 @@ const SITE_MAP = [
|
||||
{ file:'post-unit-count.html', label:'单位体检人数统计' },
|
||||
{ file:'post-unit-cost-stat.html', label:'单位体检费用统计' },
|
||||
{ file:'post-unit-item-stat.html', label:'单位体检项目统计' },
|
||||
{ file:'post-result-comprehensive-stat.html', label:'项目结果综合统计' },
|
||||
{ file:'post-hospital-count.html', label:'医院体检人数统计' },
|
||||
{ file:'post-doctor-count.html', label:'医生检查人数统计' },
|
||||
{ file:'post-item-stat.html', label:'医院体检项目统计' },
|
||||
@@ -277,7 +279,6 @@ const SITE_MAP = [
|
||||
{ file:'post-imc-class.html', label:'用户影像文件分类' },
|
||||
{ file:'post-imc-info.html', label:'用户影像文件详细' },
|
||||
{ file:'post-imc-log.html', label:'文件处理日志' },
|
||||
{ file:'agent-device.html', label:'前置机管理 · 常规体检前置服务' },
|
||||
{ file:'exception-dirty.html', label:'系统脏数据' },
|
||||
{ file:'exception-result.html', label:'结果异常' }
|
||||
]},
|
||||
@@ -707,7 +708,7 @@ const SITE_MAP = [
|
||||
{ file:'weight-detail-v2.html', label:'体重明细' },
|
||||
{ file:'report-detail.html', label:'测量报告详情' },
|
||||
{ file:'body-fat-report.html', label:'体脂报告' },
|
||||
{ file:'height-scale-report.html', label:'身高测量报告' },
|
||||
{ file:'height-scale-report.html', label:'体重秤报告' },
|
||||
{ file:'diet-advice-v2.html', label:'膳食建议' },
|
||||
{ file:'exercise-advice-v2.html', label:'运动建议' },
|
||||
{ file:'weight-record-detail-v2.html', label:'体重记录明细' },
|
||||
@@ -839,7 +840,7 @@ const SITE_MAP = [
|
||||
{ file:'phone-list.html', label:'手机号' }
|
||||
]}
|
||||
]},
|
||||
{ id:'emergency-app', label:'健康应急 APP', icon:'emergency', color:'#ffc069',
|
||||
{ id:'emergency-app', label:'健康服务 APP', icon:'emergency', color:'#ffc069',
|
||||
roles:[
|
||||
{ role:'咨询专家', id:'expert', modules:[
|
||||
{ name:'工作台', dir:'emergency-app/expert/workbench', prd:'emergency-app/expert/doc/PRD.md', done:true, pages:[
|
||||
@@ -958,6 +959,31 @@ const SITE_MAP = [
|
||||
{file:'index.html',label:'个人中心'},
|
||||
{file:'edit-profile.html',label:'修改个人信息'},{file:'change-pwd.html',label:'修改密码'}
|
||||
]}
|
||||
]},
|
||||
{ role:'营养师', id:'nutritionist', modules:[
|
||||
{name:'工作台',dir:'emergency-app/nutritionist/workbench',pages:[
|
||||
{file:'index.html',label:'工作台首页'},
|
||||
{file:'consult-chat.html',label:'营养咨询聊天'},
|
||||
{file:'consult-chat-done.html',label:'营养咨询聊天(已结束)'},
|
||||
{file:'employee-list.html',label:'员工营养管理'},
|
||||
{file:'employee-detail.html',label:'员工营养详情'},
|
||||
{file:'employee-health.html',label:'员工健康档案'},
|
||||
{file:'employee-diet-history.html',label:'员工饮食记录'},
|
||||
{file:'plan-detail.html',label:'营养方案详情'},
|
||||
{file:'recipe-list.html',label:'我的食谱'},
|
||||
{file:'recipe-create.html',label:'制定食谱'},
|
||||
{file:'recipe-detail.html',label:'食谱详情'}
|
||||
]},
|
||||
{name:'知识库',dir:'emergency-app/nutritionist/knowledge',pages:[
|
||||
{file:'index.html',label:'知识库首页'},{file:'detail.html',label:'知识详情'}
|
||||
]},
|
||||
{name:'我的',dir:'emergency-app/nutritionist/profile',pages:[
|
||||
{file:'index.html',label:'个人中心'},
|
||||
{file:'edit-profile.html',label:'编辑资料'},
|
||||
{file:'schedule.html',label:'排班设置'},
|
||||
{file:'stats.html',label:'营养咨询统计'},
|
||||
{file:'change-pwd.html',label:'修改密码'}
|
||||
]}
|
||||
]}
|
||||
],
|
||||
shared:[
|
||||
|
||||
@@ -45,6 +45,32 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.filter-select{height:36px;min-width:140px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 8px center;cursor:pointer;outline:none;appearance:none;-webkit-appearance:none;}
|
||||
.filter-input{height:36px;min-width:140px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;}
|
||||
.filter-input:focus{border-color:var(--primary);}
|
||||
/* 单位部门级联筛选 + 站点搜索下拉 */
|
||||
.org-wrap{position:relative;display:inline-block;}
|
||||
.org-trigger{height:36px;min-width:130px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 8px center;cursor:pointer;display:flex;align-items:center;user-select:none;white-space:nowrap;}
|
||||
.org-trigger.open,.org-trigger:hover{border-color:var(--primary);}
|
||||
.org-panel{display:none;position:absolute;top:36px;left:0;z-index:310;background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);width:380px;}
|
||||
.org-panel.open{display:flex;}
|
||||
.org-col{flex:1;overflow-y:auto;max-height:200px;border-right:1px solid var(--border);}
|
||||
.org-col:last-child{border-right:none;}
|
||||
.org-col__title{padding:6px 12px;font-size:var(--font-sm);color:var(--text-placeholder);background:#FAFAFA;border-bottom:1px solid var(--border);font-weight:500;}
|
||||
.org-item{padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:4px;}
|
||||
.org-item:hover{background:#F0F8FF;color:var(--primary);}
|
||||
.org-item.active{background:var(--primary-light);color:var(--primary);font-weight:500;}
|
||||
.station-search{position:relative;}
|
||||
.station-search__panel{display:none;position:absolute;top:34px;left:0;right:0;z-index:320;background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);max-height:240px;overflow-y:auto;}
|
||||
.station-search__panel.open{display:block;}
|
||||
.station-search__item{padding:8px 12px;cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:8px;}
|
||||
.station-search__item:hover{background:#F0F8FF;}
|
||||
.station-search__item .ss-name{color:var(--text-primary);font-weight:500;}
|
||||
.station-search__item .ss-org{color:var(--text-placeholder);font-size:var(--font-xs);}
|
||||
.station-search__empty{padding:16px 12px;text-align:center;color:var(--text-placeholder);font-size:var(--font-sm);}
|
||||
.map-picker{width:100%;height:200px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#e6f7ff;display:flex;align-items:center;justify-content:center;color:var(--primary);font-size:var(--font-sm);gap:6px;cursor:pointer;position:relative;overflow:hidden;transition:border-color .2s;}
|
||||
.map-picker:hover{border-color:var(--primary);}
|
||||
.map-picker__bg{position:absolute;inset:0;opacity:.15;background:repeating-linear-gradient(0deg,transparent,transparent 19px,#91d5ff 19px,#91d5ff 20px),repeating-linear-gradient(90deg,transparent,transparent 19px,#91d5ff 19px,#91d5ff 20px);}
|
||||
.map-picker__pin{position:absolute;top:50%;left:50%;transform:translate(-50%,-100%);z-index:2;display:none;}
|
||||
.map-picker__label{position:relative;z-index:2;display:flex;align-items:center;gap:6px;}
|
||||
.map-picker__coord{position:absolute;bottom:8px;left:50%;transform:translateX(-50%);background:rgba(255,255,255,0.92);padding:4px 14px;border-radius:12px;font-size:var(--font-xs);box-shadow:0 1px 4px rgba(0,0,0,0.1);z-index:3;display:none;white-space:nowrap;color:var(--text-primary);max-width:calc(100% - 16px);overflow:hidden;text-overflow:ellipsis;}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
@@ -155,16 +181,20 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<!-- [交互] 筛选栏:单位→部门→站点三级级联 -->
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item">
|
||||
<label>所属单位</label>
|
||||
<select class="filter-select" id="filterUnit" onchange="onFilterUnit()">
|
||||
<option value="">全部单位</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>所属部门</label>
|
||||
<select class="filter-select" id="filterDepart" onchange="onFilterDepart()" style="min-width:130px;">
|
||||
<option value="">全部部门</option>
|
||||
</select>
|
||||
<label>所属单位部门</label>
|
||||
<div class="org-wrap" id="orgWrap">
|
||||
<div class="org-trigger" id="orgTrigger" onclick="toggleOrg()">全部单位/部门</div>
|
||||
<div class="org-panel" id="orgPanel">
|
||||
<div class="org-col" id="unitCol">
|
||||
<div class="org-col__title">单位</div>
|
||||
<div class="org-item active" onclick="selectUnit(this,'')">全部单位/部门</div>
|
||||
</div>
|
||||
<div class="org-col" id="deptCol">
|
||||
<div class="org-col__title">部门</div>
|
||||
<div class="org-item active" onclick="selectDept(this,'')">全部部门</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>所属站点</label>
|
||||
@@ -200,7 +230,7 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:40px;"><input type="checkbox" id="ckAll" onchange="toggleAll(this)"></th>
|
||||
<th style="width:56px;">序号</th><th>所属单位</th><th>所属部门</th><th style="min-width:120px;">所属站点</th><th style="min-width:140px;">楼栋名称</th>
|
||||
<th style="width:56px;">序号</th><th style="min-width:140px;">楼栋名称</th><th style="min-width:120px;">所属站点</th><th style="min-width:160px;">所属单位部门</th>
|
||||
<th style="min-width:220px;">详细地址</th><th>宿舍数量</th><th>负责人</th><th style="min-width:110px;">负责人电话</th><th style="width:110px;">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -215,28 +245,25 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<div class="modal-mask" id="editMask">
|
||||
<div class="modal--wide">
|
||||
<div class="modal__title" id="editTitle">新增楼栋信息</div>
|
||||
<div class="form-row">
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 所属单位</span>
|
||||
<select class="form-control" id="eUnit" onchange="onEditUnit()"><option value="">请选择单位</option></select>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 所属部门</span>
|
||||
<select class="form-control" id="eDepart"><option value="">请先选择单位</option></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 所属站点</span>
|
||||
<select class="form-control" id="eStation"><option value="">请先选择部门</option></select>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 楼栋名称</span>
|
||||
<input class="form-control" id="eName" placeholder="如:樊学倒班宿舍1号楼">
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 所属站点</span>
|
||||
<div class="station-search" id="stationSearch">
|
||||
<input class="form-control" id="eStation" placeholder="请输入站点名称搜索" autocomplete="off" oninput="onStationInput()" onfocus="onStationFocus()">
|
||||
<div class="station-search__panel" id="stationPanel"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 楼栋名称</span>
|
||||
<input class="form-control" id="eName" placeholder="如:樊学倒班宿舍1号楼">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 详细地址</span>
|
||||
<div class="map-picker" id="mapPicker" onclick="pickLocation(event)">
|
||||
<div class="map-picker__bg"></div>
|
||||
<svg class="map-picker__pin" id="mapPin" width="28" height="36" viewBox="0 0 28 36" fill="none"><path d="M14 0C6.27 0 0 6.27 0 14c0 10.5 14 22 14 22s14-11.5 14-22C28 6.27 21.73 0 14 0z" fill="#1890FF"/><circle cx="14" cy="14" r="6" fill="#fff"/></svg>
|
||||
<span class="map-picker__label" id="mapLabel"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1C4.24 1 2 3.24 2 6c0 3.75 5 7 5 7s5-3.25 5-7c0-2.76-2.24-5-5-5z" stroke="currentColor" stroke-width="1.2"/><circle cx="7" cy="6" r="1.5" stroke="currentColor" stroke-width="1"/></svg>在地图上点击选择坐标位置</span>
|
||||
<div class="map-picker__coord" id="mapCoord"></div>
|
||||
</div>
|
||||
<input class="form-control" id="eAddr" placeholder="楼栋详细地址">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
@@ -262,7 +289,10 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<div class="modal__title">批量导入数据</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 选择站点(导入的楼栋将挂在该站点下)</span>
|
||||
<select class="form-control" id="iStation"><option value="">请选择站点</option><option>樊学站点基地</option><option>麻子山站点</option><option>桐园站点基地</option><option>西峰基地</option><option>姬圪台站点</option><option>靖边气田站点</option></select>
|
||||
<div class="station-search" id="importStationSearch">
|
||||
<input class="form-control" id="iStation" placeholder="请输入站点名称搜索" autocomplete="off" oninput="onImportStationInput()" onfocus="onImportStationFocus()">
|
||||
<div class="station-search__panel" id="importStationPanel"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 上传文件</span>
|
||||
@@ -359,49 +389,73 @@ var bldDorms={
|
||||
{name:'503室',beds:4,manager:'田广润',mobile:'13991923747',alloc:0,dev:'—'}
|
||||
]
|
||||
};
|
||||
function fillOptions(sel,opts,keepVal){
|
||||
var v=keepVal||'';
|
||||
sel.innerHTML='<option value="">'+(sel.dataset.tip||'全部')+'</option>'+opts.map(function(o){return '<option'+(o===v?' selected':'')+'>'+o+'</option>';}).join('');
|
||||
var selUnit='',selDept='',stationList=[],stationMeta={};
|
||||
function fillOptions(sel,opts){
|
||||
sel.innerHTML='<option value="">'+(sel.dataset.tip||'全部')+'</option>'+opts.map(function(o){return '<option>'+o+'</option>';}).join('');
|
||||
}
|
||||
function buildStationMeta(){
|
||||
stationList=[];stationMeta={};
|
||||
Object.keys(unitDeparts).forEach(function(u){
|
||||
unitDeparts[u].forEach(function(d){
|
||||
(depStations[d]||[]).forEach(function(st){
|
||||
stationList.push({name:st,unit:u,depart:d});
|
||||
stationMeta[st]={unit:u,depart:d};
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
function initFilters(){
|
||||
var su=document.getElementById('filterUnit');su.dataset.tip='全部单位';
|
||||
su.innerHTML='<option value="">全部单位</option>'+Object.keys(unitDeparts).map(function(u){return '<option>'+u+'</option>';}).join('');
|
||||
document.getElementById('filterDepart').dataset.tip='全部部门';
|
||||
document.getElementById('filterStation').dataset.tip='全部站点';
|
||||
document.getElementById('eUnit').innerHTML='<option value="">请选择单位</option>'+Object.keys(unitDeparts).map(function(u){return '<option>'+u+'</option>';}).join('');
|
||||
var unitHtml=Object.keys(unitDeparts).map(function(u){return '<div class="org-item" onclick="selectUnit(this,\''+u+'\')">'+u+'</div>';}).join('');
|
||||
document.getElementById('unitCol').insertAdjacentHTML('beforeend',unitHtml);
|
||||
var allStations=Object.keys(depStations).reduce(function(a,k){return a.concat(depStations[k]);},[]);
|
||||
var fs=document.getElementById('filterStation');fs.dataset.tip='全部站点';
|
||||
fillOptions(fs,allStations);
|
||||
buildStationMeta();
|
||||
}
|
||||
/* [交互] 单位变更时级联刷新部门与站点 */
|
||||
function onFilterUnit(){
|
||||
var u=document.getElementById('filterUnit').value;
|
||||
var depSel=document.getElementById('filterDepart'),staSel=document.getElementById('filterStation');
|
||||
var deps=u?unitDeparts[u]:Object.keys(unitDeparts).reduce(function(a,u2){return a.concat(unitDeparts[u2]);},[]);
|
||||
depSel.dataset.tip='全部部门';fillOptions(depSel,deps);
|
||||
var stas=deps.reduce(function(a,d){return a.concat(depStations[d]||[]);},[]);
|
||||
staSel.dataset.tip='全部站点';fillOptions(staSel,stas);
|
||||
/* [交互] 单位部门级联筛选 */
|
||||
function toggleOrg(){
|
||||
document.getElementById('orgPanel').classList.toggle('open');
|
||||
document.getElementById('orgTrigger').classList.toggle('open');
|
||||
}
|
||||
function selectUnit(elem,unitName){
|
||||
document.querySelectorAll('#unitCol .org-item').forEach(function(i){i.classList.remove('active');});
|
||||
elem.classList.add('active');
|
||||
selUnit=unitName;
|
||||
var html='<div class="org-col__title">部门</div><div class="org-item active" onclick="selectDept(this,\'\')">全部部门</div>';
|
||||
(unitDeparts[unitName]||[]).forEach(function(d){html+='<div class="org-item" onclick="selectDept(this,\''+d+'\')">'+d+'</div>';});
|
||||
document.getElementById('deptCol').innerHTML=html;
|
||||
selDept='';
|
||||
renderTable();
|
||||
}
|
||||
function onFilterDepart(){
|
||||
var d=document.getElementById('filterDepart').value;
|
||||
var staSel=document.getElementById('filterStation');
|
||||
staSel.dataset.tip='全部站点';
|
||||
var stas=d?(depStations[d]||[]):Object.keys(depStations).reduce(function(a,k){return a.concat(depStations[k]);},[]);
|
||||
fillOptions(staSel,stas);
|
||||
function selectDept(elem,deptName){
|
||||
document.querySelectorAll('#deptCol .org-item').forEach(function(i){i.classList.remove('active');});
|
||||
elem.classList.add('active');
|
||||
selDept=deptName;
|
||||
document.getElementById('orgTrigger').textContent=(selUnit||'全部单位')+' / '+(selDept||'全部部门');
|
||||
renderTable();
|
||||
}
|
||||
function resetOrg(){
|
||||
selUnit='';selDept='';
|
||||
document.getElementById('orgTrigger').textContent='全部单位/部门';
|
||||
document.getElementById('orgPanel').classList.remove('open');
|
||||
document.getElementById('orgTrigger').classList.remove('open');
|
||||
document.querySelectorAll('#unitCol .org-item').forEach(function(i,idx){i.classList.toggle('active',idx===0);});
|
||||
document.getElementById('deptCol').innerHTML='<div class="org-col__title">部门</div><div class="org-item active" onclick="selectDept(this,\'\')">全部部门</div>';
|
||||
}
|
||||
function renderTable(){
|
||||
var u=document.getElementById('filterUnit').value,d=document.getElementById('filterDepart').value,s=document.getElementById('filterStation').value,k=document.getElementById('filterName').value.trim();
|
||||
var list=buildings.filter(function(b){return (!u||b.unit===u)&&(!d||b.depart===d)&&(!s||b.station===s)&&(!k||b.name.indexOf(k)>=0);});
|
||||
var s=document.getElementById('filterStation').value,k=document.getElementById('filterName').value.trim();
|
||||
var list=buildings.filter(function(b){return (!selUnit||b.unit===selUnit)&&(!selDept||b.depart===selDept)&&(!s||b.station===s)&&(!k||b.name.indexOf(k)>=0);});
|
||||
document.getElementById('tbody').innerHTML=list.map(function(b){
|
||||
var i=buildings.indexOf(b);
|
||||
return '<tr><td><input type="checkbox" class="rowCk" value="'+i+'" onchange="syncAllCk()"></td>'
|
||||
+'<td>'+(i+1)+'</td><td>'+b.unit+'</td><td>'+b.depart+'</td><td>'+b.station+'</td><td style="font-weight:500;">'+b.name+'</td>'
|
||||
+'<td>'+(i+1)+'</td><td style="font-weight:500;">'+b.name+'</td><td>'+b.station+'</td><td>'+b.unit+' / '+b.depart+'</td>'
|
||||
+'<td>'+b.addr+'</td><td><span class="link-num" onclick="openDorm('+i+')">'+b.dorms+'</span></td><td>'+b.manager+'</td><td>'+b.mobile+'</td>'
|
||||
+'<td><button class="btn btn-link" onclick="openEdit('+i+')">编辑</button><button class="btn btn-link--danger" onclick="askDelete('+i+')">删除</button></td></tr>';
|
||||
}).join('')||'<tr><td class="td-empty" colspan="11">没有符合条件的楼栋</td></tr>';
|
||||
}).join('')||'<tr><td class="td-empty" colspan="10">没有符合条件的楼栋</td></tr>';
|
||||
document.getElementById('totalTip').textContent='共 '+list.length+' 栋';
|
||||
document.getElementById('ckAll').checked=false;
|
||||
}
|
||||
function resetFilter(){['filterUnit','filterDepart','filterStation'].forEach(function(id){document.getElementById(id).value='';});document.getElementById('filterName').value='';onFilterUnit();}
|
||||
function resetFilter(){resetOrg();document.getElementById('filterStation').value='';document.getElementById('filterName').value='';renderTable();}
|
||||
/* [交互] 复选框与批量删除 */
|
||||
function toggleAll(ck){document.querySelectorAll('.rowCk').forEach(function(c){c.checked=ck.checked;});}
|
||||
function syncAllCk(){
|
||||
@@ -416,51 +470,101 @@ function batchDelete(){
|
||||
document.getElementById('confirmMask').classList.add('open');
|
||||
}
|
||||
/* [交互] 新增/编辑 */
|
||||
var editIdx=-1;
|
||||
function onEditUnit(){
|
||||
var u=document.getElementById('eUnit').value;
|
||||
var depSel=document.getElementById('eDepart'),staSel=document.getElementById('eStation');
|
||||
depSel.innerHTML='<option value="">请选择部门</option>'+(u?unitDeparts[u]:[]).map(function(d){return '<option>'+d+'</option>';}).join('');
|
||||
staSel.innerHTML='<option value="">请先选择部门</option>';
|
||||
var editIdx=-1,selStation='';
|
||||
function onStationInput(){selStation='';renderStationPanel();}
|
||||
function onStationFocus(){renderStationPanel();}
|
||||
function renderStationPanel(){
|
||||
var q=document.getElementById('eStation').value.trim();
|
||||
var list=stationList.filter(function(st){return !q||st.name.indexOf(q)>=0;});
|
||||
document.getElementById('stationPanel').innerHTML=list.map(function(st){
|
||||
return '<div class="station-search__item" onclick="pickStation(\''+st.name+'\')"><span class="ss-name">'+st.name+'</span><span class="ss-org">'+st.unit+' / '+st.depart+'</span></div>';
|
||||
}).join('')||'<div class="station-search__empty">未查询到站点</div>';
|
||||
document.getElementById('stationPanel').classList.add('open');
|
||||
}
|
||||
function onEditDepart(){
|
||||
var d=document.getElementById('eDepart').value;
|
||||
document.getElementById('eStation').innerHTML='<option value="">请选择站点</option>'+(d?depStations[d]:[]).map(function(s){return '<option>'+s+'</option>';}).join('');
|
||||
function pickStation(name){
|
||||
selStation=name;
|
||||
document.getElementById('eStation').value=name;
|
||||
document.getElementById('stationPanel').classList.remove('open');
|
||||
}
|
||||
/* [交互] 地图选点:点击地图生成坐标并回填详细地址 */
|
||||
function pickLocation(e){
|
||||
var picker=document.getElementById('mapPicker');
|
||||
var rect=picker.getBoundingClientRect();
|
||||
var x=e.clientX-rect.left;
|
||||
var y=e.clientY-rect.top;
|
||||
var pin=document.getElementById('mapPin');
|
||||
pin.style.display='block';
|
||||
pin.style.left=x+'px';
|
||||
pin.style.top=y+'px';
|
||||
document.getElementById('mapLabel').style.display='none';
|
||||
var addresses=['樊学作业区基地营地东侧','麻子山作业区站点北门','桐园作业区生活区西区','西峰基地食堂南侧','靖边气田综合管理营地北侧'];
|
||||
var idx=Math.floor(Math.random()*addresses.length);
|
||||
var coord=document.getElementById('mapCoord');
|
||||
coord.innerHTML='<svg width="12" height="12" viewBox="0 0 14 14" fill="none" style="vertical-align:-1px;margin-right:4px;"><path d="M7 1C4.24 1 2 3.24 2 6c0 3.75 5 7 5 7s5-3.25 5-7c0-2.76-2.24-5-5-5z" stroke="#1890FF" stroke-width="1.2"/><circle cx="7" cy="6" r="1.5" stroke="#1890FF" stroke-width="1"/></svg>'+addresses[idx];
|
||||
coord.style.display='block';
|
||||
document.getElementById('eAddr').value=addresses[idx];
|
||||
}
|
||||
function resetMapPicker(){
|
||||
document.getElementById('mapPin').style.display='none';
|
||||
document.getElementById('mapLabel').style.display='flex';
|
||||
document.getElementById('mapCoord').style.display='none';
|
||||
document.getElementById('mapCoord').innerHTML='';
|
||||
}
|
||||
function openEdit(i){
|
||||
editIdx=i;
|
||||
resetMapPicker();
|
||||
document.getElementById('editTitle').textContent=i<0?'新增楼栋信息':'编辑楼栋信息';
|
||||
onEditUnit();
|
||||
if(i>=0){
|
||||
var b=buildings[i];
|
||||
document.getElementById('eUnit').value=b.unit;onEditUnit();
|
||||
document.getElementById('eDepart').innerHTML='<option>请选择部门</option>'+unitDeparts[b.unit].map(function(d){return '<option'+(d===b.depart?' selected':'')+'>'+d+'</option>';}).join('');
|
||||
onEditDepart();
|
||||
document.getElementById('eStation').innerHTML='<option>请选择站点</option>'+depStations[b.depart].map(function(s){return '<option'+(s===b.station?' selected':'')+'>'+s+'</option>';}).join('');
|
||||
selStation=b.station;
|
||||
document.getElementById('eStation').value=b.station;
|
||||
document.getElementById('eName').value=b.name;document.getElementById('eAddr').value=b.addr;
|
||||
document.getElementById('eManager').value=b.manager;document.getElementById('eMobile').value=b.mobile;
|
||||
}else{
|
||||
['eName','eAddr','eManager','eMobile'].forEach(function(id){document.getElementById(id).value='';});
|
||||
document.getElementById('eUnit').value='';onEditUnit();
|
||||
selStation='';
|
||||
['eStation','eName','eAddr','eManager','eMobile'].forEach(function(id){document.getElementById(id).value='';});
|
||||
}
|
||||
document.getElementById('stationPanel').classList.remove('open');
|
||||
document.getElementById('editMask').classList.add('open');
|
||||
}
|
||||
function closeEdit(){document.getElementById('editMask').classList.remove('open');}
|
||||
function saveEdit(){
|
||||
var u=document.getElementById('eUnit').value,d=document.getElementById('eDepart').value,s=document.getElementById('eStation').value;
|
||||
var s=selStation||document.getElementById('eStation').value.trim();
|
||||
var n=document.getElementById('eName').value.trim(),a=document.getElementById('eAddr').value.trim();
|
||||
if(!u||!d||!s||!n||!a){showToast('请完整填写带 * 的必填项');return;}
|
||||
var meta=stationMeta[s];
|
||||
if(!s||!meta||!n||!a){showToast('请完整填写带 * 的必填项');return;}
|
||||
var dup=buildings.some(function(b,i){return i!==editIdx&&b.station===s&&b.name===n;});
|
||||
if(dup){showToast('该站点下已存在同名楼栋');return;}
|
||||
var obj={unit:u,depart:d,station:s,name:n,addr:a,dorms:editIdx>=0?buildings[editIdx].dorms:0,manager:document.getElementById('eManager').value.trim()||'—',mobile:document.getElementById('eMobile').value.trim()||'—'};
|
||||
var obj={unit:meta.unit,depart:meta.depart,station:s,name:n,addr:a,dorms:editIdx>=0?buildings[editIdx].dorms:0,manager:document.getElementById('eManager').value.trim()||'—',mobile:document.getElementById('eMobile').value.trim()||'—'};
|
||||
if(editIdx<0)buildings.push(obj);else buildings[editIdx]=obj;
|
||||
closeEdit();renderTable();showToast(editIdx<0?'楼栋已新增':'楼栋已更新');
|
||||
}
|
||||
/* [交互] 导入 */
|
||||
function openImport(){document.getElementById('importMask').classList.add('open');}
|
||||
var selImportStation='';
|
||||
function onImportStationInput(){selImportStation='';renderImportStationPanel();}
|
||||
function onImportStationFocus(){renderImportStationPanel();}
|
||||
function renderImportStationPanel(){
|
||||
var q=document.getElementById('iStation').value.trim();
|
||||
var list=stationList.filter(function(st){return !q||st.name.indexOf(q)>=0;});
|
||||
document.getElementById('importStationPanel').innerHTML=list.map(function(st){
|
||||
return '<div class="station-search__item" onclick="pickImportStation(\''+st.name+'\')"><span class="ss-name">'+st.name+'</span><span class="ss-org">'+st.unit+' / '+st.depart+'</span></div>';
|
||||
}).join('')||'<div class="station-search__empty">未查询到站点</div>';
|
||||
document.getElementById('importStationPanel').classList.add('open');
|
||||
}
|
||||
function pickImportStation(name){
|
||||
selImportStation=name;
|
||||
document.getElementById('iStation').value=name;
|
||||
document.getElementById('importStationPanel').classList.remove('open');
|
||||
}
|
||||
function openImport(){
|
||||
selImportStation='';
|
||||
document.getElementById('iStation').value='';
|
||||
document.getElementById('importStationPanel').classList.remove('open');
|
||||
document.getElementById('importMask').classList.add('open');
|
||||
}
|
||||
function closeImport(){document.getElementById('importMask').classList.remove('open');}
|
||||
function doImport(){
|
||||
if(!document.getElementById('iStation').value){showToast('请先选择导入目标站点');return;}
|
||||
if(!selImportStation){showToast('请先选择导入目标站点');return;}
|
||||
closeImport();showToast('导入任务已提交,请到「查看导入任务」查看结果');
|
||||
}
|
||||
/* [交互] 导入任务(异步任务演示) */
|
||||
@@ -515,7 +619,16 @@ function showToast(msg){
|
||||
var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');
|
||||
clearTimeout(t._timer);t._timer=setTimeout(function(){t.classList.remove('show');},2200);
|
||||
}
|
||||
initFilters();onFilterUnit();
|
||||
/* [交互] 点击面板外部关闭下拉 */
|
||||
document.addEventListener('click',function(e){
|
||||
var ow=document.getElementById('orgWrap');
|
||||
if(ow&&!ow.contains(e.target)){document.getElementById('orgPanel').classList.remove('open');document.getElementById('orgTrigger').classList.remove('open');}
|
||||
var ss=document.getElementById('stationSearch');
|
||||
if(ss&&!ss.contains(e.target)){document.getElementById('stationPanel').classList.remove('open');}
|
||||
var is=document.getElementById('importStationSearch');
|
||||
if(is&&!is.contains(e.target)){document.getElementById('importStationPanel').classList.remove('open');}
|
||||
});
|
||||
initFilters();renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -45,6 +45,17 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.filter-select{height:36px;min-width:140px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 8px center;cursor:pointer;outline:none;appearance:none;-webkit-appearance:none;}
|
||||
.filter-input{height:36px;min-width:120px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;}
|
||||
.filter-input:focus{border-color:var(--primary);}
|
||||
.org-wrap{position:relative;display:inline-block;}
|
||||
.org-trigger{height:36px;min-width:130px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 8px center;cursor:pointer;display:flex;align-items:center;user-select:none;white-space:nowrap;}
|
||||
.org-trigger.open,.org-trigger:hover{border-color:var(--primary);}
|
||||
.org-panel{display:none;position:absolute;top:36px;left:0;z-index:310;background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);width:380px;}
|
||||
.org-panel.open{display:flex;}
|
||||
.org-col{flex:1;overflow-y:auto;max-height:200px;border-right:1px solid var(--border);}
|
||||
.org-col:last-child{border-right:none;}
|
||||
.org-col__title{padding:6px 12px;font-size:var(--font-sm);color:var(--text-placeholder);background:#FAFAFA;border-bottom:1px solid var(--border);font-weight:500;}
|
||||
.org-item{padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:4px;}
|
||||
.org-item:hover{background:#F0F8FF;color:var(--primary);}
|
||||
.org-item.active{background:var(--primary-light);color:var(--primary);font-weight:500;}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
@@ -152,16 +163,28 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<!-- [交互] 筛选栏 -->
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item">
|
||||
<label>所属单位</label>
|
||||
<select class="filter-select" id="filterUnit" onchange="onFilterUnit()"><option value="">全部单位</option></select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>所属部门</label>
|
||||
<select class="filter-select" id="filterDepart" onchange="renderTable()" style="min-width:130px;"><option value="">全部部门</option></select>
|
||||
<label>所属单位部门</label>
|
||||
<div class="org-wrap" id="orgWrap">
|
||||
<div class="org-trigger" id="orgTrigger" onclick="toggleOrg()">全部单位/部门</div>
|
||||
<div class="org-panel" id="orgPanel">
|
||||
<div class="org-col" id="unitCol">
|
||||
<div class="org-col__title">单位</div>
|
||||
<div class="org-item active" onclick="selectUnit(this,'')">全部单位/部门</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'采油一厂')">采油一厂</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'采油二厂')">采油二厂</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'第四采油厂')">第四采油厂</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'采气一厂')">采气一厂</div>
|
||||
</div>
|
||||
<div class="org-col" id="deptCol">
|
||||
<div class="org-col__title">部门</div>
|
||||
<div class="org-item active" onclick="selectDept(this,'')">全部部门</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>设备编号</label>
|
||||
<input class="filter-input" id="filterCode" placeholder="如:HC-" oninput="renderTable()">
|
||||
<input class="filter-input" id="filterCode" placeholder="请输入" oninput="renderTable()">
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>分配状态</label>
|
||||
@@ -189,7 +212,7 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:56px;">序号</th><th>所属单位</th><th>所属部门</th><th style="min-width:100px;">设备编号</th><th>分配状态</th><th>分配类型</th>
|
||||
<th style="width:56px;">序号</th><th>所属单位</th><th>所属部门</th><th style="min-width:100px;">设备编号</th><th style="min-width:130px;">MAC地址</th><th>分配状态</th><th>分配类型</th>
|
||||
<th style="min-width:230px;">分配宿舍/床位</th><th style="min-width:100px;">分配日期</th><th style="width:150px;">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -289,43 +312,65 @@ var dormTree={
|
||||
};
|
||||
/* 与「设备列表」呼叫设备一致;alloc:1宿舍/2床位 */
|
||||
var devices=[
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-01',alloc:1,type:2,space:'樊学倒班宿舍1号楼 · 101-1',time:'2026-03-05'},
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-02',alloc:1,type:2,space:'樊学倒班宿舍1号楼 · 101-2',time:'2026-03-05'},
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-03',alloc:1,type:2,space:'樊学倒班宿舍1号楼 · 102-1',time:'2026-03-05'},
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-04',alloc:1,type:1,space:'樊学倒班宿舍1号楼 · 101室',time:'2026-03-05'},
|
||||
{unit:'采油一厂',depart:'麻子山作业区',code:'HC-MZ-01',alloc:1,type:1,space:'麻子山倒班宿舍楼 · 101室',time:'2026-03-19'},
|
||||
{unit:'采油二厂',depart:'桐园作业区',code:'HC-TY-01',alloc:1,type:2,space:'桐园倒班宿舍1号楼 · 301-1',time:'2026-04-10'},
|
||||
{unit:'采油二厂',depart:'桐园作业区',code:'HC-TY-02',alloc:1,type:1,space:'桐园倒班宿舍1号楼 · 201室',time:'2026-04-10'},
|
||||
{unit:'第四采油厂',depart:'西峰作业区',code:'HC-XF-01',alloc:1,type:2,space:'西峰基地综合宿舍楼 · 301-1',time:'2026-05-12'},
|
||||
{unit:'第四采油厂',depart:'西峰作业区',code:'HC-XF-02',alloc:1,type:2,space:'西峰基地综合宿舍楼 · 302-1',time:'2026-05-12'},
|
||||
{unit:'第四采油厂',depart:'西峰作业区',code:'HC-XF-03',alloc:1,type:1,space:'西峰基地综合宿舍楼 · 402室',time:'2026-05-12'},
|
||||
{unit:'采气一厂',depart:'靖边气田',code:'HC-JB-01',alloc:1,type:2,space:'靖边气田倒班宿舍楼 · 401-1',time:'2026-06-24'},
|
||||
{unit:'采气一厂',depart:'靖边气田',code:'HC-JB-02',alloc:0,type:0,space:'',time:''}
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-01',mac:'00:1A:2B:3C:4D:01',alloc:1,type:2,space:'樊学倒班宿舍1号楼 · 101-1',time:'2026-03-05'},
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-02',mac:'00:1A:2B:3C:4D:02',alloc:1,type:2,space:'樊学倒班宿舍1号楼 · 101-2',time:'2026-03-05'},
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-03',mac:'00:1A:2B:3C:4D:03',alloc:1,type:2,space:'樊学倒班宿舍1号楼 · 102-1',time:'2026-03-05'},
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-04',mac:'00:1A:2B:3C:4D:04',alloc:1,type:1,space:'樊学倒班宿舍1号楼 · 101室',time:'2026-03-05'},
|
||||
{unit:'采油一厂',depart:'麻子山作业区',code:'HC-MZ-01',mac:'00:1A:2B:3C:4D:05',alloc:1,type:1,space:'麻子山倒班宿舍楼 · 101室',time:'2026-03-19'},
|
||||
{unit:'采油二厂',depart:'桐园作业区',code:'HC-TY-01',mac:'00:1A:2B:3C:4D:06',alloc:1,type:2,space:'桐园倒班宿舍1号楼 · 301-1',time:'2026-04-10'},
|
||||
{unit:'采油二厂',depart:'桐园作业区',code:'HC-TY-02',mac:'00:1A:2B:3C:4D:07',alloc:1,type:1,space:'桐园倒班宿舍1号楼 · 201室',time:'2026-04-10'},
|
||||
{unit:'第四采油厂',depart:'西峰作业区',code:'HC-XF-01',mac:'00:1A:2B:3C:4D:08',alloc:1,type:2,space:'西峰基地综合宿舍楼 · 301-1',time:'2026-05-12'},
|
||||
{unit:'第四采油厂',depart:'西峰作业区',code:'HC-XF-02',mac:'00:1A:2B:3C:4D:09',alloc:1,type:2,space:'西峰基地综合宿舍楼 · 302-1',time:'2026-05-12'},
|
||||
{unit:'第四采油厂',depart:'西峰作业区',code:'HC-XF-03',mac:'00:1A:2B:3C:4D:0A',alloc:1,type:1,space:'西峰基地综合宿舍楼 · 402室',time:'2026-05-12'},
|
||||
{unit:'采气一厂',depart:'靖边气田',code:'HC-JB-01',mac:'00:1A:2B:3C:4D:0B',alloc:1,type:2,space:'靖边气田倒班宿舍楼 · 401-1',time:'2026-06-24'},
|
||||
{unit:'采气一厂',depart:'靖边气田',code:'HC-JB-02',mac:'00:1A:2B:3C:4D:0C',alloc:0,type:0,space:'',time:''}
|
||||
];
|
||||
function onFilterUnit(){
|
||||
var u=document.getElementById('filterUnit').value;
|
||||
var depSel=document.getElementById('filterDepart');
|
||||
var deps=u?unitDeparts[u]:Object.keys(unitDeparts).reduce(function(a,u2){return a.concat(unitDeparts[u2]);},[]);
|
||||
var uniq=[];deps.forEach(function(x){if(uniq.indexOf(x)<0)uniq.push(x);});
|
||||
depSel.innerHTML='<option value="">全部部门</option>'+uniq.map(function(d){return '<option>'+d+'</option>';}).join('');
|
||||
renderTable();
|
||||
var selUnit='',selDept='';
|
||||
function toggleOrg(){
|
||||
document.getElementById('orgPanel').classList.toggle('open');
|
||||
document.getElementById('orgTrigger').classList.toggle('open');
|
||||
}
|
||||
function selectUnit(elem,unitName){
|
||||
document.querySelectorAll('#unitCol .org-item').forEach(function(i){i.classList.remove('active');});
|
||||
elem.classList.add('active');
|
||||
selUnit=unitName;
|
||||
var html='<div class="org-col__title">部门</div><div class="org-item active" onclick="selectDept(this,\'\')">全部部门</div>';
|
||||
(unitDeparts[unitName]||[]).forEach(function(d){
|
||||
html+='<div class="org-item" onclick="selectDept(this,\''+d+'\')">'+d+'</div>';
|
||||
});
|
||||
document.getElementById('deptCol').innerHTML=html;
|
||||
selDept='';
|
||||
}
|
||||
function selectDept(elem,deptName){
|
||||
document.querySelectorAll('#deptCol .org-item').forEach(function(i){i.classList.remove('active');});
|
||||
elem.classList.add('active');
|
||||
selDept=deptName;
|
||||
document.getElementById('orgTrigger').textContent=(selUnit||'全部单位')+' / '+(selDept||'全部部门');
|
||||
}
|
||||
function resetOrg(){
|
||||
selUnit='';selDept='';
|
||||
document.getElementById('orgTrigger').textContent='全部单位/部门';
|
||||
document.getElementById('orgPanel').classList.remove('open');
|
||||
document.getElementById('orgTrigger').classList.remove('open');
|
||||
document.querySelectorAll('#unitCol .org-item').forEach(function(i,idx){i.classList.toggle('active',idx===0);});
|
||||
document.getElementById('deptCol').innerHTML='<div class="org-col__title">部门</div><div class="org-item active" onclick="selectDept(this,\'\')">全部部门</div>';
|
||||
}
|
||||
function renderTable(){
|
||||
var u=document.getElementById('filterUnit').value,d=document.getElementById('filterDepart').value,k=document.getElementById('filterCode').value.trim().toUpperCase(),s=document.getElementById('filterStatus').value;
|
||||
var u=selUnit,d=selDept,k=document.getElementById('filterCode').value.trim().toUpperCase(),s=document.getElementById('filterStatus').value;
|
||||
var list=devices.filter(function(r){return (!u||r.unit===u)&&(!d||r.depart===d)&&(!k||r.code.toUpperCase().indexOf(k)>=0)&&(s===''||String(r.alloc)===s);});
|
||||
document.getElementById('tbody').innerHTML=list.map(function(r){
|
||||
var i=devices.indexOf(r);
|
||||
var typeTxt=r.alloc?('<span class="badge '+(r.type===1?'badge--info':'badge--success')+'">'+(r.type===1?'宿舍':'床位')+'</span>'):'<span class="badge badge--muted">-</span>';
|
||||
var typeTxt=r.alloc?(r.type===1?'宿舍':'床位'):'-';
|
||||
var ops=r.alloc
|
||||
?'<button class="btn btn-link" onclick="openAlloc('+i+')">重新分配</button><button class="btn btn-link--danger" onclick="askUnbind('+i+')">解除分配</button>'
|
||||
:'<button class="btn btn-link" onclick="openAlloc('+i+')">设备分配</button>';
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+r.unit+'</td><td>'+r.depart+'</td><td style="font-family:monospace;font-weight:500;">'+r.code+'</td>'
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+r.unit+'</td><td>'+r.depart+'</td><td style="font-family:monospace;font-weight:500;">'+r.code+'</td><td style="font-family:monospace;">'+(r.mac||'—')+'</td>'
|
||||
+'<td>'+(r.alloc?'<span class="badge badge--success">已分配</span>':'<span class="badge badge--warning">未分配</span>')+'</td>'
|
||||
+'<td>'+typeTxt+'</td><td>'+(r.space||'-')+'</td><td>'+(r.time||'-')+'</td><td>'+ops+'</td></tr>';
|
||||
}).join('')||'<tr><td class="td-empty" colspan="9">没有符合条件的设备</td></tr>';
|
||||
}).join('')||'<tr><td class="td-empty" colspan="10">没有符合条件的设备</td></tr>';
|
||||
document.getElementById('totalTip').textContent='共 '+devices.length+' 台 · 已分配 '+devices.filter(function(r){return r.alloc;}).length+' 台';
|
||||
}
|
||||
function resetFilter(){['filterUnit','filterDepart','filterStatus'].forEach(function(id){document.getElementById(id).value='';});document.getElementById('filterCode').value='';onFilterUnit();}
|
||||
function resetFilter(){resetOrg();document.getElementById('filterStatus').value='';document.getElementById('filterCode').value='';renderTable();}
|
||||
/* [交互] 设备分配/重新分配 */
|
||||
var allocIdx=-1;
|
||||
function openAlloc(i){
|
||||
@@ -400,8 +445,8 @@ function showToast(msg){
|
||||
var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');
|
||||
clearTimeout(t._timer);t._timer=setTimeout(function(){t.classList.remove('show');},2200);
|
||||
}
|
||||
document.getElementById('filterUnit').innerHTML='<option value="">全部单位</option>'+Object.keys(unitDeparts).map(function(u){return '<option>'+u+'</option>';}).join('');
|
||||
onFilterUnit();
|
||||
resetOrg();
|
||||
renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -45,6 +45,17 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.filter-select{height:36px;min-width:140px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 8px center;cursor:pointer;outline:none;appearance:none;-webkit-appearance:none;}
|
||||
.filter-input{height:36px;min-width:120px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;}
|
||||
.filter-input:focus{border-color:var(--primary);}
|
||||
.org-wrap{position:relative;display:inline-block;}
|
||||
.org-trigger{height:36px;min-width:130px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 8px center;cursor:pointer;display:flex;align-items:center;user-select:none;white-space:nowrap;}
|
||||
.org-trigger.open,.org-trigger:hover{border-color:var(--primary);}
|
||||
.org-panel{display:none;position:absolute;top:36px;left:0;z-index:310;background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);width:380px;}
|
||||
.org-panel.open{display:flex;}
|
||||
.org-col{flex:1;overflow-y:auto;max-height:200px;border-right:1px solid var(--border);}
|
||||
.org-col:last-child{border-right:none;}
|
||||
.org-col__title{padding:6px 12px;font-size:var(--font-sm);color:var(--text-placeholder);background:#FAFAFA;border-bottom:1px solid var(--border);font-weight:500;}
|
||||
.org-item{padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:4px;}
|
||||
.org-item:hover{background:#F0F8FF;color:var(--primary);}
|
||||
.org-item.active{background:var(--primary-light);color:var(--primary);font-weight:500;}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
@@ -155,21 +166,33 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<!-- [交互] 筛选栏 -->
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item">
|
||||
<label>所属单位</label>
|
||||
<select class="filter-select" id="filterUnit" onchange="onFilterUnit()"><option value="">全部单位</option></select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>所属部门</label>
|
||||
<select class="filter-select" id="filterDepart" onchange="renderAll()" style="min-width:130px;"><option value="">全部部门</option></select>
|
||||
<label>所属单位部门</label>
|
||||
<div class="org-wrap" id="orgWrap">
|
||||
<div class="org-trigger" id="orgTrigger" onclick="toggleOrg()">全部单位/部门</div>
|
||||
<div class="org-panel" id="orgPanel">
|
||||
<div class="org-col" id="unitCol">
|
||||
<div class="org-col__title">单位</div>
|
||||
<div class="org-item active" onclick="selectUnit(this,'')">全部单位/部门</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'采油一厂')">采油一厂</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'采油二厂')">采油二厂</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'第四采油厂')">第四采油厂</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'采气一厂')">采气一厂</div>
|
||||
</div>
|
||||
<div class="org-col" id="deptCol">
|
||||
<div class="org-col__title">部门</div>
|
||||
<div class="org-item active" onclick="selectDept(this,'')">全部部门</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>设备编号</label>
|
||||
<input class="filter-input" id="filterCode" placeholder="如:HC-FX" oninput="renderAll()">
|
||||
<input class="filter-input" id="filterCode" placeholder="请输入" oninput="renderAll()">
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>设备状态</label>
|
||||
<select class="filter-select" id="filterStatus" onchange="renderAll()" style="min-width:100px;">
|
||||
<option value="">全部</option><option value="0">正常</option><option value="1">故障</option><option value="2">停用</option>
|
||||
<option value="">全部</option><option value="0">在线</option><option value="1">离线</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="btn btn-primary" onclick="renderAll();showToast('查询完成')">
|
||||
@@ -217,53 +240,57 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<select class="form-control" id="eUnit" onchange="onEditUnit()"><option value="">请选择单位</option></select>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 所属部门</span>
|
||||
<span class="form-label">所属部门</span>
|
||||
<select class="form-control" id="eDepart"><option value="">请选择部门</option></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 设备编号</span>
|
||||
<input class="form-control" id="eCode" placeholder="全局唯一,如:HC-FX-05">
|
||||
<input class="form-control" id="eCode" placeholder="请输入">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> <span id="eNameLabel">设备名称</span></span>
|
||||
<input class="form-control" id="eName" placeholder="如:床头呼叫按钮">
|
||||
<input class="form-control" id="eName" placeholder="请输入">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-item">
|
||||
<span class="form-label">设备型号</span>
|
||||
<input class="form-control" id="eModel" placeholder="如:KQ-P1">
|
||||
<input class="form-control" id="eModel" placeholder="请输入">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label">入库日期</span>
|
||||
<input class="form-control" id="eStore" type="date">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label">MAC地址</span>
|
||||
<input class="form-control" id="eMac" placeholder="请输入">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-item">
|
||||
<span class="form-label">设备状态</span>
|
||||
<select class="form-control" id="eStatus"><option value="0">正常</option><option value="1">故障</option><option value="2">停用</option></select>
|
||||
<select class="form-control" id="eStatus"><option value="0">在线</option><option value="1">离线</option></select>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label">管理人</span>
|
||||
<input class="form-control" id="eManager" placeholder="设备管理人姓名">
|
||||
<input class="form-control" id="eManager" placeholder="请输入">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-item">
|
||||
<span class="form-label">管理人电话</span>
|
||||
<input class="form-control" id="eMphone" placeholder="11位手机号">
|
||||
<input class="form-control" id="eMphone" placeholder="请输入">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label">设备厂家</span>
|
||||
<input class="form-control" id="eMfr" placeholder="生产厂家名称">
|
||||
<input class="form-control" id="eMfr" placeholder="请输入">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label">厂家电话</span>
|
||||
<input class="form-control" id="eMfrTel" placeholder="厂家售后服务电话">
|
||||
<input class="form-control" id="eMfrTel" placeholder="请输入">
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeEdit()">取消</button>
|
||||
@@ -282,7 +309,7 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<select class="form-control" id="iUnit"><option value="">请选择单位</option></select>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 所属部门</span>
|
||||
<span class="form-label">所属部门</span>
|
||||
<select class="form-control" id="iDepart"><option value="">请选择部门</option></select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -329,52 +356,52 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
|
||||
<script>
|
||||
var unitDeparts={'采油一厂':['樊学作业区','麻子山作业区'],'采油二厂':['桐园作业区','姬圪台作业区'],'第四采油厂':['西峰作业区'],'采气一厂':['靖边气田']};
|
||||
var statusBadge={'0':'badge--success','1':'badge--danger','2':'badge--muted'};
|
||||
var statusText={'0':'正常','1':'故障','2':'停用'};
|
||||
/* 呼叫设备:分配关系与「分配管理」「床位信息」勾稽(HC-FX-03 故障见告警记录演示) */
|
||||
var statusBadge={'0':'badge--success','1':'badge--muted'};
|
||||
var statusText={'0':'在线','1':'离线'};
|
||||
/* 呼叫设备:分配关系与「分配管理」「床位信息」勾稽(HC-FX-03 离线见告警记录演示) */
|
||||
var callDevices=[
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-01',name:'床头呼叫按钮',model:'KQ-P1',store:'2026-03-02',status:'0',manager:'王守正',mphone:'13991203456',mfr:'CQ中控医疗',mfrTel:'029-86521700'},
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-02',name:'床头呼叫按钮',model:'KQ-P1',store:'2026-03-02',status:'0',manager:'王守正',mphone:'13991203456',mfr:'CQ中控医疗',mfrTel:'029-86521700'},
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-03',name:'床头呼叫按钮',model:'KQ-P1',store:'2026-03-02',status:'1',manager:'王守正',mphone:'13991203456',mfr:'CQ中控医疗',mfrTel:'029-86521700'},
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-04',name:'房间一键呼叫面板',model:'KQ-P2',store:'2026-03-02',status:'0',manager:'王守正',mphone:'13991203456',mfr:'CQ中控医疗',mfrTel:'029-86521700'},
|
||||
{unit:'采油一厂',depart:'麻子山作业区',code:'HC-MZ-01',name:'房间一键呼叫面板',model:'KQ-P2',store:'2026-03-18',status:'0',manager:'安伟',mphone:'13991345012',mfr:'CQ中控医疗',mfrTel:'029-86521700'},
|
||||
{unit:'采油二厂',depart:'桐园作业区',code:'HC-TY-01',name:'床头呼叫按钮',model:'KQ-P1',store:'2026-04-09',status:'0',manager:'陈国栋',mphone:'13991567208',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'采油二厂',depart:'桐园作业区',code:'HC-TY-02',name:'房间一键呼叫面板',model:'KQ-P2',store:'2026-04-09',status:'0',manager:'陈国栋',mphone:'13991567208',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'第四采油厂',depart:'西峰作业区',code:'HC-XF-01',name:'床头呼叫按钮',model:'KQ-P1',store:'2026-05-11',status:'0',manager:'马文秀',mphone:'13991784320',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'第四采油厂',depart:'西峰作业区',code:'HC-XF-02',name:'床头呼叫按钮',model:'KQ-P1',store:'2026-05-11',status:'0',manager:'马文秀',mphone:'13991784320',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'第四采油厂',depart:'西峰作业区',code:'HC-XF-03',name:'房间一键呼叫面板',model:'KQ-P2',store:'2026-05-11',status:'0',manager:'马文秀',mphone:'13991784320',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'采气一厂',depart:'靖边气田',code:'HC-JB-01',name:'床头呼叫按钮',model:'KQ-P1',store:'2026-06-23',status:'0',manager:'周铁祥',mphone:'13991923745',mfr:'CQ中控医疗',mfrTel:'029-86521700'},
|
||||
{unit:'采气一厂',depart:'靖边气田',code:'HC-JB-02',name:'床头呼叫按钮',model:'KQ-P1',store:'2026-09-01',status:'0',manager:'周铁祥',mphone:'13991923745',mfr:'CQ中控医疗',mfrTel:'029-86521700'}
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-01',name:'床头呼叫按钮',model:'KQ-P1',mac:'00:1A:2B:3C:4D:01',store:'2026-03-02',status:'0',manager:'王守正',mphone:'13991203456',mfr:'CQ中控医疗',mfrTel:'029-86521700'},
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-02',name:'床头呼叫按钮',model:'KQ-P1',mac:'00:1A:2B:3C:4D:02',store:'2026-03-02',status:'0',manager:'王守正',mphone:'13991203456',mfr:'CQ中控医疗',mfrTel:'029-86521700'},
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-03',name:'床头呼叫按钮',model:'KQ-P1',mac:'00:1A:2B:3C:4D:03',store:'2026-03-02',status:'1',manager:'王守正',mphone:'13991203456',mfr:'CQ中控医疗',mfrTel:'029-86521700'},
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HC-FX-04',name:'房间一键呼叫面板',model:'KQ-P2',mac:'00:1A:2B:3C:4D:04',store:'2026-03-02',status:'0',manager:'王守正',mphone:'13991203456',mfr:'CQ中控医疗',mfrTel:'029-86521700'},
|
||||
{unit:'采油一厂',depart:'麻子山作业区',code:'HC-MZ-01',name:'房间一键呼叫面板',model:'KQ-P2',mac:'00:1A:2B:3C:4D:05',store:'2026-03-18',status:'0',manager:'安伟',mphone:'13991345012',mfr:'CQ中控医疗',mfrTel:'029-86521700'},
|
||||
{unit:'采油二厂',depart:'桐园作业区',code:'HC-TY-01',name:'床头呼叫按钮',model:'KQ-P1',mac:'00:1A:2B:3C:4D:06',store:'2026-04-09',status:'0',manager:'陈国栋',mphone:'13991567208',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'采油二厂',depart:'桐园作业区',code:'HC-TY-02',name:'房间一键呼叫面板',model:'KQ-P2',mac:'00:1A:2B:3C:4D:07',store:'2026-04-09',status:'0',manager:'陈国栋',mphone:'13991567208',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'第四采油厂',depart:'西峰作业区',code:'HC-XF-01',name:'床头呼叫按钮',model:'KQ-P1',mac:'00:1A:2B:3C:4D:08',store:'2026-05-11',status:'0',manager:'马文秀',mphone:'13991784320',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'第四采油厂',depart:'西峰作业区',code:'HC-XF-02',name:'床头呼叫按钮',model:'KQ-P1',mac:'00:1A:2B:3C:4D:09',store:'2026-05-11',status:'0',manager:'马文秀',mphone:'13991784320',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'第四采油厂',depart:'西峰作业区',code:'HC-XF-03',name:'房间一键呼叫面板',model:'KQ-P2',mac:'00:1A:2B:3C:4D:0A',store:'2026-05-11',status:'0',manager:'马文秀',mphone:'13991784320',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'采气一厂',depart:'靖边气田',code:'HC-JB-01',name:'床头呼叫按钮',model:'KQ-P1',mac:'00:1A:2B:3C:4D:0B',store:'2026-06-23',status:'0',manager:'周铁祥',mphone:'13991923745',mfr:'CQ中控医疗',mfrTel:'029-86521700'},
|
||||
{unit:'采气一厂',depart:'靖边气田',code:'HC-JB-02',name:'床头呼叫按钮',model:'KQ-P1',mac:'00:1A:2B:3C:4D:0C',store:'2026-09-01',status:'0',manager:'周铁祥',mphone:'13991923745',mfr:'CQ中控医疗',mfrTel:'029-86521700'}
|
||||
];
|
||||
/* 终端设备:值班室固定部署,不参与宿舍/床位分配 */
|
||||
var termDevices=[
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HD-FX-01',name:'值班室接收终端',model:'KQ-T10',store:'2026-03-02',status:'0',manager:'王守正',mphone:'13991203456',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'采油一厂',depart:'麻子山作业区',code:'HD-MZ-01',name:'值班室接收终端',model:'KQ-T10',store:'2026-03-18',status:'0',manager:'安伟',mphone:'13991345012',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'采油二厂',depart:'桐园作业区',code:'HD-TY-01',name:'值班室接收终端',model:'KQ-T10',store:'2026-04-09',status:'0',manager:'陈国栋',mphone:'13991567208',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'第四采油厂',depart:'西峰作业区',code:'HD-XF-01',name:'值班室接收终端',model:'KQ-T10',store:'2026-05-11',status:'1',manager:'马文秀',mphone:'13991784320',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'采气一厂',depart:'靖边气田',code:'HD-JB-01',name:'值班室接收终端',model:'KQ-T10',store:'2026-06-23',status:'0',manager:'周铁祥',mphone:'13991923745',mfr:'华旭智能',mfrTel:'029-87334210'}
|
||||
{unit:'采油一厂',depart:'樊学作业区',code:'HD-FX-01',name:'值班室接收终端',model:'KQ-T10',mac:'00:1A:2B:3C:4D:11',store:'2026-03-02',status:'0',manager:'王守正',mphone:'13991203456',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'采油一厂',depart:'麻子山作业区',code:'HD-MZ-01',name:'值班室接收终端',model:'KQ-T10',mac:'00:1A:2B:3C:4D:12',store:'2026-03-18',status:'0',manager:'安伟',mphone:'13991345012',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'采油二厂',depart:'桐园作业区',code:'HD-TY-01',name:'值班室接收终端',model:'KQ-T10',mac:'00:1A:2B:3C:4D:13',store:'2026-04-09',status:'0',manager:'陈国栋',mphone:'13991567208',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'第四采油厂',depart:'西峰作业区',code:'HD-XF-01',name:'值班室接收终端',model:'KQ-T10',mac:'00:1A:2B:3C:4D:14',store:'2026-05-11',status:'1',manager:'马文秀',mphone:'13991784320',mfr:'华旭智能',mfrTel:'029-87334210'},
|
||||
{unit:'采气一厂',depart:'靖边气田',code:'HD-JB-01',name:'值班室接收终端',model:'KQ-T10',mac:'00:1A:2B:3C:4D:15',store:'2026-06-23',status:'0',manager:'周铁祥',mphone:'13991923745',mfr:'华旭智能',mfrTel:'029-87334210'}
|
||||
];
|
||||
var curTab='call';
|
||||
function tabName(){return curTab==='call'?'呼叫设备':'终端设备';}
|
||||
function headRow(){
|
||||
var name=curTab==='call'?'设备名称':'终端名称';
|
||||
return '<tr><th style="width:40px;"><input type="checkbox" id="ckAll" onchange="toggleAll(this)"></th>'
|
||||
+'<th style="width:56px;">序号</th><th>所属单位</th><th>所属部门</th><th style="min-width:100px;">设备编号</th><th style="min-width:120px;">'+name+'</th><th>设备型号</th><th>入库日期</th><th>设备状态</th><th>管理人</th><th style="min-width:105px;">管理人电话</th><th style="min-width:110px;">设备厂家</th><th style="min-width:110px;">厂家电话</th><th style="width:110px;">操作</th></tr>';
|
||||
+'<th style="width:56px;">序号</th><th>所属单位</th><th>所属部门</th><th style="min-width:100px;">设备编号</th><th style="min-width:120px;">'+name+'</th><th>设备型号</th><th style="min-width:130px;">MAC地址</th><th>入库日期</th><th>设备状态</th><th>管理人</th><th style="min-width:105px;">管理人电话</th><th style="min-width:110px;">设备厂家</th><th style="min-width:110px;">厂家电话</th><th style="width:110px;">操作</th></tr>';
|
||||
}
|
||||
function renderAll(){
|
||||
var u=document.getElementById('filterUnit').value,d=document.getElementById('filterDepart').value,k=document.getElementById('filterCode').value.trim().toUpperCase(),s=document.getElementById('filterStatus').value;
|
||||
var u=selUnit,d=selDept,k=document.getElementById('filterCode').value.trim().toUpperCase(),s=document.getElementById('filterStatus').value;
|
||||
var src=curTab==='call'?callDevices:termDevices;
|
||||
var list=src.filter(function(r){return (!u||r.unit===u)&&(!d||r.depart===d)&&(!k||r.code.toUpperCase().indexOf(k)>=0)&&(s===''||r.status===s);});
|
||||
document.getElementById('thead').innerHTML=headRow();
|
||||
document.getElementById('tbody').innerHTML=list.map(function(r){
|
||||
var i=src.indexOf(r);
|
||||
return '<tr><td><input type="checkbox" class="rowCk" value="'+i+'" onchange="syncAllCk()"></td>'
|
||||
+'<td>'+(i+1)+'</td><td>'+r.unit+'</td><td>'+r.depart+'</td><td style="font-family:monospace;font-weight:500;">'+r.code+'</td><td>'+r.name+'</td><td>'+r.model+'</td><td>'+r.store+'</td>'
|
||||
+'<td>'+(i+1)+'</td><td>'+r.unit+'</td><td>'+r.depart+'</td><td style="font-family:monospace;font-weight:500;">'+r.code+'</td><td>'+r.name+'</td><td>'+r.model+'</td><td style="font-family:monospace;">'+(r.mac||'—')+'</td><td>'+r.store+'</td>'
|
||||
+'<td><span class="badge '+statusBadge[r.status]+'">'+statusText[r.status]+'</span></td>'
|
||||
+'<td>'+r.manager+'</td><td>'+r.mphone+'</td><td>'+r.mfr+'</td><td>'+r.mfrTel+'</td>'
|
||||
+'<td><button class="btn btn-link" onclick="openEdit('+i+')">编辑</button><button class="btn btn-link--danger" onclick="askDelete('+i+')">删除</button></td></tr>';
|
||||
}).join('')||'<tr><td class="td-empty" colspan="14">没有符合条件的设备</td></tr>';
|
||||
document.getElementById('totalTip').textContent='共 '+list.length+' 台(正常 '+list.filter(function(r){return r.status==='0';}).length+' / 故障 '+list.filter(function(r){return r.status==='1';}).length+' / 停用 '+list.filter(function(r){return r.status==='2';}).length+')';
|
||||
}).join('')||'<tr><td class="td-empty" colspan="15">没有符合条件的设备</td></tr>';
|
||||
document.getElementById('totalTip').textContent='共 '+list.length+' 台(在线 '+list.filter(function(r){return r.status==='0';}).length+' / 离线 '+list.filter(function(r){return r.status==='1';}).length+')';
|
||||
}
|
||||
function switchTab(t){
|
||||
curTab=t;
|
||||
@@ -382,15 +409,37 @@ function switchTab(t){
|
||||
document.getElementById('tabTerm').classList.toggle('active',t==='term');
|
||||
renderAll();
|
||||
}
|
||||
function onFilterUnit(){
|
||||
var u=document.getElementById('filterUnit').value;
|
||||
var depSel=document.getElementById('filterDepart');
|
||||
var deps=u?unitDeparts[u]:Object.keys(unitDeparts).reduce(function(a,u2){return a.concat(unitDeparts[u2]);},[]);
|
||||
var uniq=[];deps.forEach(function(x){if(uniq.indexOf(x)<0)uniq.push(x);});
|
||||
depSel.innerHTML='<option value="">全部部门</option>'+uniq.map(function(d){return '<option>'+d+'</option>';}).join('');
|
||||
renderAll();
|
||||
var selUnit='',selDept='';
|
||||
function toggleOrg(){
|
||||
document.getElementById('orgPanel').classList.toggle('open');
|
||||
document.getElementById('orgTrigger').classList.toggle('open');
|
||||
}
|
||||
function resetFilter(){['filterUnit','filterDepart','filterStatus'].forEach(function(id){document.getElementById(id).value='';});document.getElementById('filterCode').value='';onFilterUnit();}
|
||||
function selectUnit(elem,unitName){
|
||||
document.querySelectorAll('#unitCol .org-item').forEach(function(i){i.classList.remove('active');});
|
||||
elem.classList.add('active');
|
||||
selUnit=unitName;
|
||||
var html='<div class="org-col__title">部门</div><div class="org-item active" onclick="selectDept(this,\'\')">全部部门</div>';
|
||||
(unitDeparts[unitName]||[]).forEach(function(d){
|
||||
html+='<div class="org-item" onclick="selectDept(this,\''+d+'\')">'+d+'</div>';
|
||||
});
|
||||
document.getElementById('deptCol').innerHTML=html;
|
||||
selDept='';
|
||||
}
|
||||
function selectDept(elem,deptName){
|
||||
document.querySelectorAll('#deptCol .org-item').forEach(function(i){i.classList.remove('active');});
|
||||
elem.classList.add('active');
|
||||
selDept=deptName;
|
||||
document.getElementById('orgTrigger').textContent=(selUnit||'全部单位')+' / '+(selDept||'全部部门');
|
||||
}
|
||||
function resetOrg(){
|
||||
selUnit='';selDept='';
|
||||
document.getElementById('orgTrigger').textContent='全部单位/部门';
|
||||
document.getElementById('orgPanel').classList.remove('open');
|
||||
document.getElementById('orgTrigger').classList.remove('open');
|
||||
document.querySelectorAll('#unitCol .org-item').forEach(function(i,idx){i.classList.toggle('active',idx===0);});
|
||||
document.getElementById('deptCol').innerHTML='<div class="org-col__title">部门</div><div class="org-item active" onclick="selectDept(this,\'\')">全部部门</div>';
|
||||
}
|
||||
function resetFilter(){resetOrg();document.getElementById('filterStatus').value='';document.getElementById('filterCode').value='';renderAll();}
|
||||
/* [交互] 复选框与批量删除 */
|
||||
function toggleAll(ck){document.querySelectorAll('.rowCk').forEach(function(c){c.checked=ck.checked;});}
|
||||
function syncAllCk(){
|
||||
@@ -420,13 +469,13 @@ function openEdit(i){
|
||||
document.getElementById('eUnit').value=r.unit;onEditUnit();
|
||||
document.getElementById('eDepart').innerHTML='<option value="">请选择部门</option>'+unitDeparts[r.unit].map(function(d){return '<option'+(d===r.depart?' selected':'')+'>'+d+'</option>';}).join('');
|
||||
document.getElementById('eCode').value=r.code;document.getElementById('eName').value=r.name;
|
||||
document.getElementById('eModel').value=r.model;document.getElementById('eStore').value=r.store;
|
||||
document.getElementById('eModel').value=r.model;document.getElementById('eMac').value=r.mac;document.getElementById('eStore').value=r.store;
|
||||
document.getElementById('eStatus').value=r.status;document.getElementById('eManager').value=r.manager;
|
||||
document.getElementById('eMphone').value=r.mphone;document.getElementById('eMfr').value=r.mfr;
|
||||
document.getElementById('eMfrTel').value=r.mfrTel;
|
||||
}else{
|
||||
document.getElementById('eUnit').value='';onEditUnit();
|
||||
['eCode','eName','eModel','eStore','eManager','eMphone','eMfr','eMfrTel'].forEach(function(id){document.getElementById(id).value='';});
|
||||
['eCode','eName','eModel','eMac','eStore','eManager','eMphone','eMfr','eMfrTel'].forEach(function(id){document.getElementById(id).value='';});
|
||||
document.getElementById('eStatus').value='0';
|
||||
}
|
||||
document.getElementById('editMask').classList.add('open');
|
||||
@@ -434,11 +483,11 @@ function openEdit(i){
|
||||
function closeEdit(){document.getElementById('editMask').classList.remove('open');}
|
||||
function saveEdit(){
|
||||
var u=document.getElementById('eUnit').value,d=document.getElementById('eDepart').value,c=document.getElementById('eCode').value.trim(),n=document.getElementById('eName').value.trim();
|
||||
if(!u||!d||!c||!n){showToast('请完整填写带 * 的必填项');return;}
|
||||
if(!u||!c||!n){showToast('请完整填写带 * 的必填项');return;}
|
||||
var src=curTab==='call'?callDevices:termDevices;
|
||||
var dup=callDevices.concat(termDevices).some(function(r){return r!==src[editIdx]&&r.code===c;});
|
||||
if(dup){showToast('设备编号已存在,须全局唯一');return;}
|
||||
var obj={unit:u,depart:d,code:c,name:n,model:document.getElementById('eModel').value.trim()||'—',store:document.getElementById('eStore').value||'—',status:document.getElementById('eStatus').value,manager:document.getElementById('eManager').value.trim()||'—',mphone:document.getElementById('eMphone').value.trim()||'—',mfr:document.getElementById('eMfr').value.trim()||'—',mfrTel:document.getElementById('eMfrTel').value.trim()||'—'};
|
||||
var obj={unit:u,depart:d,code:c,name:n,model:document.getElementById('eModel').value.trim()||'—',mac:document.getElementById('eMac').value.trim(),store:document.getElementById('eStore').value||'—',status:document.getElementById('eStatus').value,manager:document.getElementById('eManager').value.trim()||'—',mphone:document.getElementById('eMphone').value.trim()||'—',mfr:document.getElementById('eMfr').value.trim()||'—',mfrTel:document.getElementById('eMfrTel').value.trim()||'—'};
|
||||
if(editIdx<0)src.push(obj);else src[editIdx]=obj;
|
||||
closeEdit();renderAll();showToast(editIdx<0?tabName()+'已新增':tabName()+'已更新');
|
||||
}
|
||||
@@ -455,7 +504,7 @@ function openImport(){
|
||||
}
|
||||
function closeImport(){document.getElementById('importMask').classList.remove('open');}
|
||||
function doImport(){
|
||||
if(!document.getElementById('iUnit').value||!document.getElementById('iDepart').value){showToast('请选择单位与部门');return;}
|
||||
if(!document.getElementById('iUnit').value){showToast('请选择单位');return;}
|
||||
closeImport();showToast('导入任务已提交,请到「查看导入任务」查看结果');
|
||||
}
|
||||
/* [交互] 导入任务(异步任务演示) */
|
||||
@@ -495,8 +544,8 @@ function showToast(msg){
|
||||
var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');
|
||||
clearTimeout(t._timer);t._timer=setTimeout(function(){t.classList.remove('show');},2200);
|
||||
}
|
||||
document.getElementById('filterUnit').innerHTML='<option value="">全部单位</option>'+Object.keys(unitDeparts).map(function(u){return '<option>'+u+'</option>';}).join('');
|
||||
onFilterUnit();
|
||||
resetOrg();
|
||||
renderAll();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -45,6 +45,18 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.filter-select{height:36px;min-width:140px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 8px center;cursor:pointer;outline:none;appearance:none;-webkit-appearance:none;}
|
||||
.filter-input{height:36px;min-width:140px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;}
|
||||
.filter-input:focus{border-color:var(--primary);}
|
||||
/* 单位部门级联筛选 */
|
||||
.org-wrap{position:relative;display:inline-block;}
|
||||
.org-trigger{height:36px;min-width:130px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 8px center;cursor:pointer;display:flex;align-items:center;user-select:none;white-space:nowrap;}
|
||||
.org-trigger.open,.org-trigger:hover{border-color:var(--primary);}
|
||||
.org-panel{display:none;position:absolute;top:36px;left:0;z-index:310;background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);width:380px;}
|
||||
.org-panel.open{display:flex;}
|
||||
.org-col{flex:1;overflow-y:auto;max-height:200px;border-right:1px solid var(--border);}
|
||||
.org-col:last-child{border-right:none;}
|
||||
.org-col__title{padding:6px 12px;font-size:var(--font-sm);color:var(--text-placeholder);background:#FAFAFA;border-bottom:1px solid var(--border);font-weight:500;}
|
||||
.org-item{padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:4px;}
|
||||
.org-item:hover{background:#F0F8FF;color:var(--primary);}
|
||||
.org-item.active{background:var(--primary-light);color:var(--primary);font-weight:500;}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
@@ -152,6 +164,28 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
|
||||
<!-- [交互] 筛选栏 -->
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item">
|
||||
<label>所属单位部门</label>
|
||||
<div class="org-wrap" id="orgWrap">
|
||||
<div class="org-trigger" id="orgTrigger" onclick="toggleOrg()">全部单位/部门</div>
|
||||
<div class="org-panel" id="orgPanel">
|
||||
<div class="org-col" id="unitCol">
|
||||
<div class="org-col__title">单位</div>
|
||||
<div class="org-item active" onclick="selectUnit(this,'')">全部单位/部门</div>
|
||||
</div>
|
||||
<div class="org-col" id="deptCol">
|
||||
<div class="org-col__title">部门</div>
|
||||
<div class="org-item active" onclick="selectDept(this,'')">全部部门</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>所属站点</label>
|
||||
<select class="filter-select" id="filterStation" onchange="renderTable()" style="min-width:140px;">
|
||||
<option value="">全部站点</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>所属楼栋</label>
|
||||
<select class="filter-select" id="filterBuilding" onchange="renderTable()" style="min-width:180px;">
|
||||
@@ -192,8 +226,8 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:40px;"><input type="checkbox" id="ckAll" onchange="toggleAll(this)"></th>
|
||||
<th style="width:56px;">序号</th><th style="min-width:110px;">宿舍名称</th><th style="min-width:180px;">所属楼栋</th><th>床位数量</th><th>负责人</th>
|
||||
<th style="min-width:110px;">负责人电话</th><th>是否分配设备</th><th style="min-width:110px;">设备编号</th><th style="width:110px;">操作</th>
|
||||
<th style="width:56px;">序号</th><th style="min-width:110px;">宿舍名称</th><th style="min-width:180px;">所属楼栋</th><th style="min-width:120px;">所属站点</th><th style="min-width:160px;">所属单位部门</th>
|
||||
<th>床位数量</th><th>是否分配设备</th><th style="min-width:110px;">设备编号</th><th>负责人</th><th style="min-width:110px;">负责人电话</th><th style="width:110px;">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tbody"></tbody>
|
||||
@@ -302,6 +336,17 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<script>
|
||||
/* 楼栋清单与「楼栋信息」页勾稽 */
|
||||
var buildings=['樊学倒班宿舍1号楼','麻子山倒班宿舍楼','桐园倒班宿舍1号楼','西峰基地综合宿舍楼','靖边气田倒班宿舍楼'];
|
||||
/* 单位→部门→站点三级映射与楼栋归属,与「楼栋信息」页口径一致 */
|
||||
var unitDeparts={'采油一厂':['樊学作业区','麻子山作业区'],'采油二厂':['桐园作业区','姬圪台作业区'],'第四采油厂':['西峰作业区'],'采气一厂':['靖边气田']};
|
||||
var depStations={'樊学作业区':['樊学站点基地'],'麻子山作业区':['麻子山站点'],'桐园作业区':['桐园站点基地'],'姬圪台作业区':['姬圪台站点'],'西峰作业区':['西峰基地'],'靖边气田':['靖边气田站点']};
|
||||
var buildingMeta={
|
||||
'樊学倒班宿舍1号楼':{station:'樊学站点基地',unit:'采油一厂',depart:'樊学作业区'},
|
||||
'麻子山倒班宿舍楼':{station:'麻子山站点',unit:'采油一厂',depart:'麻子山作业区'},
|
||||
'桐园倒班宿舍1号楼':{station:'桐园站点基地',unit:'采油二厂',depart:'桐园作业区'},
|
||||
'西峰基地综合宿舍楼':{station:'西峰基地',unit:'第四采油厂',depart:'西峰作业区'},
|
||||
'靖边气田倒班宿舍楼':{station:'靖边气田站点',unit:'采气一厂',depart:'靖边气田'}
|
||||
};
|
||||
var selUnit='',selDept='';
|
||||
/* alloc:绑定到宿舍本身的设备(房间级呼叫);床位级绑定见「分配管理」 */
|
||||
var dorms=[
|
||||
{name:'101室',building:'樊学倒班宿舍1号楼',beds:4,manager:'石维国',mobile:'13991203456',alloc:1,device:'HC-FX-04'},
|
||||
@@ -341,26 +386,65 @@ var bedAssigns={
|
||||
'靖边气田倒班宿舍楼|401-1':'CQ036441','靖边气田倒班宿舍楼|401-2':'CQ029905'
|
||||
};
|
||||
function initFilters(){
|
||||
var unitHtml=Object.keys(unitDeparts).map(function(u){return '<div class="org-item" onclick="selectUnit(this,\''+u+'\')">'+u+'</div>';}).join('');
|
||||
document.getElementById('unitCol').insertAdjacentHTML('beforeend',unitHtml);
|
||||
var opts='<option value="">全部楼栋</option>'+buildings.map(function(b){return '<option>'+b+'</option>';}).join('');
|
||||
document.getElementById('filterBuilding').innerHTML=opts;
|
||||
document.getElementById('eBuilding').innerHTML='<option value="">请选择楼栋</option>'+buildings.map(function(b){return '<option>'+b+'</option>';}).join('');
|
||||
document.getElementById('iBuilding').innerHTML='<option value="">请选择楼栋</option>'+buildings.map(function(b){return '<option>'+b+'</option>';}).join('');
|
||||
var allStations=Object.keys(depStations).reduce(function(a,k){return a.concat(depStations[k]);},[]);
|
||||
document.getElementById('filterStation').innerHTML='<option value="">全部站点</option>'+allStations.map(function(s){return '<option>'+s+'</option>';}).join('');
|
||||
}
|
||||
/* [交互] 单位部门级联筛选 */
|
||||
function toggleOrg(){
|
||||
document.getElementById('orgPanel').classList.toggle('open');
|
||||
document.getElementById('orgTrigger').classList.toggle('open');
|
||||
}
|
||||
function selectUnit(elem,unitName){
|
||||
document.querySelectorAll('#unitCol .org-item').forEach(function(i){i.classList.remove('active');});
|
||||
elem.classList.add('active');
|
||||
selUnit=unitName;
|
||||
var html='<div class="org-col__title">部门</div><div class="org-item active" onclick="selectDept(this,\'\')">全部部门</div>';
|
||||
(unitDeparts[unitName]||[]).forEach(function(d){html+='<div class="org-item" onclick="selectDept(this,\''+d+'\')">'+d+'</div>';});
|
||||
document.getElementById('deptCol').innerHTML=html;
|
||||
selDept='';
|
||||
renderTable();
|
||||
}
|
||||
function selectDept(elem,deptName){
|
||||
document.querySelectorAll('#deptCol .org-item').forEach(function(i){i.classList.remove('active');});
|
||||
elem.classList.add('active');
|
||||
selDept=deptName;
|
||||
document.getElementById('orgTrigger').textContent=(selUnit||'全部单位')+' / '+(selDept||'全部部门');
|
||||
renderTable();
|
||||
}
|
||||
function resetOrg(){
|
||||
selUnit='';selDept='';
|
||||
document.getElementById('orgTrigger').textContent='全部单位/部门';
|
||||
document.getElementById('orgPanel').classList.remove('open');
|
||||
document.getElementById('orgTrigger').classList.remove('open');
|
||||
document.querySelectorAll('#unitCol .org-item').forEach(function(i,idx){i.classList.toggle('active',idx===0);});
|
||||
document.getElementById('deptCol').innerHTML='<div class="org-col__title">部门</div><div class="org-item active" onclick="selectDept(this,\'\')">全部部门</div>';
|
||||
}
|
||||
function renderTable(){
|
||||
var b=document.getElementById('filterBuilding').value,n=document.getElementById('filterName').value.trim(),a=document.getElementById('filterAlloc').value;
|
||||
var list=dorms.filter(function(r){return (!b||r.building===b)&&(!n||r.name.indexOf(n)>=0)&&(a===''||String(r.alloc)===a);});
|
||||
var s=document.getElementById('filterStation').value,b=document.getElementById('filterBuilding').value,n=document.getElementById('filterName').value.trim(),a=document.getElementById('filterAlloc').value;
|
||||
var list=dorms.filter(function(r){
|
||||
var meta=buildingMeta[r.building]||{};
|
||||
return (!selUnit||meta.unit===selUnit)&&(!selDept||meta.depart===selDept)&&(!s||meta.station===s)&&(!b||r.building===b)&&(!n||r.name.indexOf(n)>=0)&&(a===''||String(r.alloc)===a);
|
||||
});
|
||||
document.getElementById('tbody').innerHTML=list.map(function(r){
|
||||
var i=dorms.indexOf(r);
|
||||
var meta=buildingMeta[r.building]||{};
|
||||
return '<tr><td><input type="checkbox" class="rowCk" value="'+i+'" onchange="syncAllCk()"></td>'
|
||||
+'<td>'+(i+1)+'</td><td style="font-weight:500;">'+r.name+'</td><td>'+r.building+'</td><td><span class="link-num" onclick="openBed('+i+')">'+r.beds+'</span></td><td>'+r.manager+'</td><td>'+r.mobile+'</td>'
|
||||
+'<td>'+(i+1)+'</td><td style="font-weight:500;">'+r.name+'</td><td>'+r.building+'</td><td>'+(meta.station||'')+'</td><td>'+(meta.unit?meta.unit+' / '+meta.depart:'')+'</td>'
|
||||
+'<td><span class="link-num" onclick="openBed('+i+')">'+r.beds+'</span></td>'
|
||||
+'<td>'+(r.alloc?'<span class="badge badge--success">已分配</span>':'<span class="badge badge--muted">未分配</span>')+'</td>'
|
||||
+'<td style="font-family:monospace;">'+(r.device||'-')+'</td>'
|
||||
+'<td style="font-family:monospace;">'+(r.device||'-')+'</td><td>'+r.manager+'</td><td>'+r.mobile+'</td>'
|
||||
+'<td><button class="btn btn-link" onclick="openEdit('+i+')">编辑</button><button class="btn btn-link--danger" onclick="askDelete('+i+')">删除</button></td></tr>';
|
||||
}).join('')||'<tr><td class="td-empty" colspan="10">没有符合条件的宿舍</td></tr>';
|
||||
}).join('')||'<tr><td class="td-empty" colspan="12">没有符合条件的宿舍</td></tr>';
|
||||
document.getElementById('totalTip').textContent='共 '+list.length+' 间 · 房间级设备 '+dorms.filter(function(r){return r.alloc;}).length+' 台';
|
||||
document.getElementById('ckAll').checked=false;
|
||||
}
|
||||
function resetFilter(){['filterBuilding','filterAlloc'].forEach(function(id){document.getElementById(id).value='';});document.getElementById('filterName').value='';renderTable();}
|
||||
function resetFilter(){resetOrg();['filterStation','filterBuilding','filterAlloc'].forEach(function(id){document.getElementById(id).value='';});document.getElementById('filterName').value='';renderTable();}
|
||||
/* [交互] 复选框与批量删除 */
|
||||
function toggleAll(ck){document.querySelectorAll('.rowCk').forEach(function(c){c.checked=ck.checked;});}
|
||||
function syncAllCk(){
|
||||
@@ -459,6 +543,11 @@ function showToast(msg){
|
||||
var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');
|
||||
clearTimeout(t._timer);t._timer=setTimeout(function(){t.classList.remove('show');},2200);
|
||||
}
|
||||
/* [交互] 点击面板外部关闭下拉 */
|
||||
document.addEventListener('click',function(e){
|
||||
var ow=document.getElementById('orgWrap');
|
||||
if(ow&&!ow.contains(e.target)){document.getElementById('orgPanel').classList.remove('open');document.getElementById('orgTrigger').classList.remove('open');}
|
||||
});
|
||||
initFilters();renderTable();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -45,6 +45,17 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.filter-select{height:36px;min-width:140px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 8px center;cursor:pointer;outline:none;appearance:none;-webkit-appearance:none;}
|
||||
.filter-input{height:36px;min-width:140px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);color:var(--text-primary);outline:none;}
|
||||
.filter-input:focus{border-color:var(--primary);}
|
||||
.org-wrap{position:relative;display:inline-block;}
|
||||
.org-trigger{height:36px;min-width:130px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 8px center;cursor:pointer;display:flex;align-items:center;user-select:none;white-space:nowrap;}
|
||||
.org-trigger.open,.org-trigger:hover{border-color:var(--primary);}
|
||||
.org-panel{display:none;position:absolute;top:36px;left:0;z-index:310;background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);width:380px;}
|
||||
.org-panel.open{display:flex;}
|
||||
.org-col{flex:1;overflow-y:auto;max-height:200px;border-right:1px solid var(--border);}
|
||||
.org-col:last-child{border-right:none;}
|
||||
.org-col__title{padding:6px 12px;font-size:var(--font-sm);color:var(--text-placeholder);background:#FAFAFA;border-bottom:1px solid var(--border);font-weight:500;}
|
||||
.org-item{padding:8px 12px;font-size:var(--font-sm);color:var(--text-primary);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:4px;}
|
||||
.org-item:hover{background:#F0F8FF;color:var(--primary);}
|
||||
.org-item.active{background:var(--primary-light);color:var(--primary);font-weight:500;}
|
||||
.btn{height:36px;padding:0 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
|
||||
.btn-primary{background:var(--primary);color:#fff;}.btn-primary:hover{background:#40a9ff;}
|
||||
.btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}.btn-default:hover{color:var(--primary);border-color:var(--primary);}
|
||||
@@ -151,16 +162,24 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<!-- [交互] 筛选栏:单位→部门级联 + 站点名称 -->
|
||||
<div class="filter-bar">
|
||||
<div class="filter-item">
|
||||
<label>所属单位</label>
|
||||
<select class="filter-select" id="filterUnit" onchange="onFilterUnit()">
|
||||
<option value="">全部单位</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>所属部门</label>
|
||||
<select class="filter-select" id="filterDepart" onchange="renderTable()" style="min-width:130px;">
|
||||
<option value="">全部部门</option>
|
||||
</select>
|
||||
<label>所属单位部门</label>
|
||||
<div class="org-wrap" id="orgWrap">
|
||||
<div class="org-trigger" id="orgTrigger" onclick="toggleOrg()">全部单位/部门</div>
|
||||
<div class="org-panel" id="orgPanel">
|
||||
<div class="org-col" id="unitCol">
|
||||
<div class="org-col__title">单位</div>
|
||||
<div class="org-item active" onclick="selectUnit(this,'')">全部单位/部门</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'采油一厂')">采油一厂</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'采油二厂')">采油二厂</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'第四采油厂')">第四采油厂</div>
|
||||
<div class="org-item" onclick="selectUnit(this,'采气一厂')">采气一厂</div>
|
||||
</div>
|
||||
<div class="org-col" id="deptCol">
|
||||
<div class="org-col__title">部门</div>
|
||||
<div class="org-item active" onclick="selectDept(this,'')">全部部门</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<label>站点名称</label>
|
||||
@@ -186,7 +205,7 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:56px;">序号</th><th>所属单位</th><th>所属部门</th><th style="min-width:140px;">站点名称</th>
|
||||
<th style="width:56px;">序号</th><th style="min-width:140px;">站点名称</th><th>所属单位</th><th>所属部门</th>
|
||||
<th style="min-width:220px;">详细地址</th><th>负责人</th><th style="min-width:110px;">联系电话</th>
|
||||
<th style="min-width:100px;">设立日期</th><th style="min-width:220px;">简介</th><th style="width:110px;">操作</th>
|
||||
</tr>
|
||||
@@ -198,7 +217,7 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- [交互] 新增/编辑站点:地点支持地图选点/手动输入双模式 -->
|
||||
<!-- [交互] 新增/编辑站点:地点采用地图选点 + 详细地址 -->
|
||||
<div class="modal-mask" id="editMask">
|
||||
<div class="modal--wide">
|
||||
<div class="modal__title" id="editTitle">新增站点</div>
|
||||
@@ -218,41 +237,14 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 地点</span>
|
||||
<div class="radio-line">
|
||||
<label><input type="radio" name="geoType" value="0" checked onchange="switchGeoType()"> 地图选点</label>
|
||||
<label><input type="radio" name="geoType" value="1" onchange="switchGeoType()"> 手动输入</label>
|
||||
<div class="map-pick" id="mapPick" onclick="demoPickPoint()">
|
||||
<svg width="26" height="26" viewBox="0 0 26 26" fill="none"><path d="M13 3c4 0 7 3 7 6.8 0 5-7 13.2-7 13.2S6 14.8 6 9.8C6 6 9 3 13 3z" stroke="#1890FF" stroke-width="1.6" fill="none"/><circle cx="13" cy="9.8" r="2.4" stroke="#1890FF" stroke-width="1.6"/></svg>
|
||||
<span id="mapPickText">点击在地图上拾取站点坐标</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 地图选点模式 -->
|
||||
<div id="geoMapMode">
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 地图选点</span>
|
||||
<div class="map-pick" id="mapPick" onclick="demoPickPoint()">
|
||||
<svg width="26" height="26" viewBox="0 0 26 26" fill="none"><path d="M13 3c4 0 7 3 7 6.8 0 5-7 13.2-7 13.2S6 14.8 6 9.8C6 6 9 3 13 3z" stroke="#1890FF" stroke-width="1.6" fill="none"/><circle cx="13" cy="9.8" r="2.4" stroke="#1890FF" stroke-width="1.6"/></svg>
|
||||
<span id="mapPickText">点击在地图上拾取站点坐标</span>
|
||||
</div>
|
||||
<div class="form-item" style="margin-bottom:0;">
|
||||
<span class="form-label">选址地址</span>
|
||||
<input class="form-control" id="eMapAddr" readonly placeholder="选点后自动回填地址">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 手动输入模式 -->
|
||||
<div id="geoInputMode" style="display:none;">
|
||||
<div class="form-row">
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 经度</span>
|
||||
<input class="form-control" id="eLng" placeholder="如:107.3412">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 纬度</span>
|
||||
<input class="form-control" id="eLat" placeholder="如:36.1147">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label"><span class="req">*</span> 详细地址</span>
|
||||
<input class="form-control" id="eAddr2" placeholder="站点详细地址">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<span class="form-label">详细地址</span>
|
||||
<input class="form-control" id="eAddr" placeholder="请补充详细地址,如:站点基地东侧">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-item">
|
||||
@@ -305,37 +297,52 @@ var stations=[
|
||||
{unit:'第四采油厂',depart:'西峰作业区',name:'西峰基地',addr:'甘肃省西峰市西峰基地食堂南侧',manager:'马文秀',mobile:'13991784320',setUp:'2017-09-01',desc:'第四采油厂机关基地,医疗点与救护车驻点合一。'},
|
||||
{unit:'采气一厂',depart:'靖边气田',name:'靖边气田站点',addr:'陕西省靖边县靖边气田综合管理营地北侧',manager:'周铁祥',mobile:'13991923745',setUp:'2020-11-11',desc:'靖边气田处理厂站点,负责气田倒班人员床头呼叫值守。'}
|
||||
];
|
||||
function fillOptions(sel,opts,keepVal){
|
||||
var v=keepVal||'';
|
||||
sel.innerHTML='<option value="">'+(sel.dataset.tip||'全部')+'</option>'+opts.map(function(o){return '<option'+(o===v?' selected':'')+'>'+o+'</option>';}).join('');
|
||||
}
|
||||
function initFilters(){
|
||||
var su=document.getElementById('filterUnit');su.dataset.tip='全部单位';
|
||||
su.innerHTML='<option value="">全部单位</option>'+Object.keys(unitDeparts).map(function(u){return '<option>'+u+'</option>';}).join('');
|
||||
document.getElementById('filterDepart').dataset.tip='全部部门';
|
||||
document.getElementById('eUnit').innerHTML='<option value="">请选择单位</option>'+Object.keys(unitDeparts).map(function(u){return '<option>'+u+'</option>';}).join('');
|
||||
}
|
||||
/* [交互] 筛选单位变更时级联刷新部门 */
|
||||
function onFilterUnit(){
|
||||
var u=document.getElementById('filterUnit').value;
|
||||
var depSel=document.getElementById('filterDepart');
|
||||
var deps=u?unitDeparts[u]:Object.keys(unitDeparts).reduce(function(a,u2){return a.concat(unitDeparts[u2]);},[]);
|
||||
depSel.dataset.tip='全部部门';fillOptions(depSel,deps);
|
||||
renderTable();
|
||||
var selUnit='',selDept='';
|
||||
function toggleOrg(){
|
||||
document.getElementById('orgPanel').classList.toggle('open');
|
||||
document.getElementById('orgTrigger').classList.toggle('open');
|
||||
}
|
||||
function selectUnit(elem,unitName){
|
||||
document.querySelectorAll('#unitCol .org-item').forEach(function(i){i.classList.remove('active');});
|
||||
elem.classList.add('active');
|
||||
selUnit=unitName;
|
||||
var html='<div class="org-col__title">部门</div><div class="org-item active" onclick="selectDept(this,\'\')">全部部门</div>';
|
||||
(unitDeparts[unitName]||[]).forEach(function(d){
|
||||
html+='<div class="org-item" onclick="selectDept(this,\''+d+'\')">'+d+'</div>';
|
||||
});
|
||||
document.getElementById('deptCol').innerHTML=html;
|
||||
selDept='';
|
||||
}
|
||||
function selectDept(elem,deptName){
|
||||
document.querySelectorAll('#deptCol .org-item').forEach(function(i){i.classList.remove('active');});
|
||||
elem.classList.add('active');
|
||||
selDept=deptName;
|
||||
document.getElementById('orgTrigger').textContent=(selUnit||'全部单位')+' / '+(selDept||'全部部门');
|
||||
}
|
||||
function resetOrg(){
|
||||
selUnit='';selDept='';
|
||||
document.getElementById('orgTrigger').textContent='全部单位/部门';
|
||||
document.getElementById('orgPanel').classList.remove('open');
|
||||
document.getElementById('orgTrigger').classList.remove('open');
|
||||
document.querySelectorAll('#unitCol .org-item').forEach(function(i,idx){i.classList.toggle('active',idx===0);});
|
||||
document.getElementById('deptCol').innerHTML='<div class="org-col__title">部门</div><div class="org-item active" onclick="selectDept(this,\'\')">全部部门</div>';
|
||||
}
|
||||
function renderTable(){
|
||||
var u=document.getElementById('filterUnit').value,d=document.getElementById('filterDepart').value,k=document.getElementById('filterName').value.trim();
|
||||
var u=selUnit,d=selDept,k=document.getElementById('filterName').value.trim();
|
||||
var list=stations.filter(function(s){return (!u||s.unit===u)&&(!d||s.depart===d)&&(!k||s.name.indexOf(k)>=0);});
|
||||
document.getElementById('tbody').innerHTML=list.map(function(s){
|
||||
var i=stations.indexOf(s);
|
||||
return '<tr><td>'+(i+1)+'</td><td>'+s.unit+'</td><td>'+s.depart+'</td><td style="font-weight:500;">'+s.name+'</td>'
|
||||
return '<tr><td>'+(i+1)+'</td><td style="font-weight:500;">'+s.name+'</td><td>'+s.unit+'</td><td>'+s.depart+'</td>'
|
||||
+'<td>'+s.addr+'</td><td>'+s.manager+'</td><td>'+s.mobile+'</td><td>'+s.setUp+'</td>'
|
||||
+'<td style="white-space:normal;min-width:220px;">'+s.desc+'</td>'
|
||||
+'<td><button class="btn btn-link" onclick="openEdit('+i+')">编辑</button><button class="btn btn-link--danger" onclick="askDelete('+i+')">删除</button></td></tr>';
|
||||
}).join('')||'<tr><td class="td-empty" colspan="10">没有符合条件的站点</td></tr>';
|
||||
document.getElementById('totalTip').textContent='共 '+list.length+' 个站点';
|
||||
}
|
||||
function resetFilter(){['filterUnit','filterDepart'].forEach(function(id){document.getElementById(id).value='';});document.getElementById('filterName').value='';onFilterUnit();}
|
||||
function resetFilter(){resetOrg();document.getElementById('filterName').value='';renderTable();}
|
||||
/* [交互] 新增/编辑 */
|
||||
var editIdx=-1;
|
||||
function onEditUnit(){
|
||||
@@ -343,19 +350,15 @@ function onEditUnit(){
|
||||
var depSel=document.getElementById('eDepart');
|
||||
depSel.innerHTML='<option value="">请选择部门</option>'+(u?unitDeparts[u]:[]).map(function(d){return '<option>'+d+'</option>';}).join('');
|
||||
}
|
||||
function geoTypeVal(){var r=document.querySelector('input[name="geoType"]:checked');return r?r.value:'0';}
|
||||
function switchGeoType(){
|
||||
var map=geoTypeVal()==='0';
|
||||
document.getElementById('geoMapMode').style.display=map?'':'none';
|
||||
document.getElementById('geoInputMode').style.display=map?'none':'';
|
||||
}
|
||||
/* [交互] 地图选点演示:点击拾取坐标并回填地址 */
|
||||
/* [交互] 地图选点演示:点击拾取坐标并回填详细地址 */
|
||||
var pickedPoint=null;
|
||||
function demoPickPoint(){
|
||||
pickedPoint={lng:'107.3412',lat:'36.1147'};
|
||||
document.getElementById('mapPickText').innerHTML='<span class="picked">已选坐标:107.3412, 36.1147(点击可重选)</span>';
|
||||
var addr=document.getElementById('eName').value.trim();
|
||||
document.getElementById('eMapAddr').value='已拾取:'+(addr||'站点位置')+'(经度107.3412 纬度36.1147)';
|
||||
if(!document.getElementById('eAddr').value){
|
||||
var nm=document.getElementById('eName').value.trim();
|
||||
document.getElementById('eAddr').value='陕西省延安市吴起县'+(nm||'站点')+'基地';
|
||||
}
|
||||
showToast('地图选点完成');
|
||||
}
|
||||
function openEdit(i){
|
||||
@@ -363,21 +366,19 @@ function openEdit(i){
|
||||
document.getElementById('editTitle').textContent=i<0?'新增站点':'编辑站点';
|
||||
onEditUnit();
|
||||
pickedPoint=null;document.getElementById('mapPickText').textContent='点击在地图上拾取站点坐标';
|
||||
document.getElementById('eMapAddr').value='';
|
||||
document.getElementById('eAddr').value='';
|
||||
if(i>=0){
|
||||
var s=stations[i];
|
||||
document.getElementById('eUnit').value=s.unit;onEditUnit();
|
||||
document.getElementById('eDepart').innerHTML='<option>请选择部门</option>'+unitDeparts[s.unit].map(function(d){return '<option'+(d===s.depart?' selected':'')+'>'+d+'</option>';}).join('');
|
||||
document.getElementById('eName').value=s.name;
|
||||
document.querySelector('input[name="geoType"][value="0"]').checked=true;switchGeoType();
|
||||
document.getElementById('eMapAddr').value='已拾取:'+s.addr;
|
||||
document.getElementById('eAddr').value=s.addr;
|
||||
document.getElementById('mapPickText').innerHTML='<span class="picked">已选坐标:107.3412, 36.1147(点击可重选)</span>';
|
||||
document.getElementById('eManager').value=s.manager;document.getElementById('eMobile').value=s.mobile;
|
||||
document.getElementById('eSetUp').value=s.setUp;document.getElementById('eDesc').value=s.desc;
|
||||
}else{
|
||||
['eName','eManager','eMobile','eSetUp','eDesc','eLng','eLat','eAddr2'].forEach(function(id){document.getElementById(id).value='';});
|
||||
['eName','eManager','eMobile','eSetUp','eDesc','eAddr'].forEach(function(id){document.getElementById(id).value='';});
|
||||
document.getElementById('eUnit').value='';onEditUnit();
|
||||
document.querySelector('input[name="geoType"][value="0"]').checked=true;switchGeoType();
|
||||
}
|
||||
document.getElementById('editMask').classList.add('open');
|
||||
}
|
||||
@@ -385,15 +386,8 @@ function closeEdit(){document.getElementById('editMask').classList.remove('open'
|
||||
function saveEdit(){
|
||||
var u=document.getElementById('eUnit').value,d=document.getElementById('eDepart').value,n=document.getElementById('eName').value.trim();
|
||||
if(!u||!d||!n){showToast('请完整填写带 * 的必填项');return;}
|
||||
var addr;
|
||||
if(geoTypeVal()==='0'){
|
||||
if(!document.getElementById('eMapAddr').value){showToast('请先在地图上拾取站点坐标');return;}
|
||||
addr=document.getElementById('eMapAddr').value;
|
||||
}else{
|
||||
var lng=document.getElementById('eLng').value.trim(),lat=document.getElementById('eLat').value.trim(),a2=document.getElementById('eAddr2').value.trim();
|
||||
if(!lng||!lat||!a2){showToast('手动输入模式下经度/纬度/详细地址为必填');return;}
|
||||
addr=a2;
|
||||
}
|
||||
var addr=document.getElementById('eAddr').value.trim();
|
||||
if(!addr){showToast('请先在地图上拾取站点坐标并补充详细地址');return;}
|
||||
var dup=stations.some(function(s,i){return i!==editIdx&&s.unit===u&&s.name===n;});
|
||||
if(dup){showToast('该单位下已存在同名站点');return;}
|
||||
var obj={unit:u,depart:d,name:n,addr:addr,
|
||||
@@ -419,7 +413,7 @@ function showToast(msg){
|
||||
var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');
|
||||
clearTimeout(t._timer);t._timer=setTimeout(function(){t.classList.remove('show');},2200);
|
||||
}
|
||||
initFilters();onFilterUnit();
|
||||
initFilters();resetOrg();renderTable();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -96,6 +96,15 @@ tbody tr:hover td:last-child{background:#F8FBFF;}
|
||||
.form-control:focus{border-color:var(--primary);}
|
||||
.form-control:disabled{background:#F5F5F5;color:var(--text-secondary);cursor:not-allowed;}
|
||||
select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 10px center;appearance:none;-webkit-appearance:none;padding-right:28px;cursor:pointer;}
|
||||
.search-select{position:relative;}
|
||||
.search-select__list{position:absolute;top:100%;left:0;right:0;background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);max-height:260px;overflow-y:auto;z-index:30;display:none;margin-top:2px;}
|
||||
.search-select__list.open{display:block;}
|
||||
.search-select__item{padding:9px 12px;font-size:var(--font-sm);cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:10px;border-bottom:1px solid #F5F5F5;}
|
||||
.search-select__item:last-child{border-bottom:none;}
|
||||
.search-select__item:hover,.search-select__item.active{background:var(--primary-light);}
|
||||
.search-select__item .plate{font-weight:600;color:var(--text-primary);}
|
||||
.search-select__item .point{color:var(--text-secondary);font-size:var(--font-xs);}
|
||||
.search-select__empty{padding:12px;color:var(--text-placeholder);font-size:var(--font-sm);text-align:center;}
|
||||
.radio-group{display:flex;gap:20px;height:36px;align-items:center;flex-wrap:wrap;}
|
||||
.radio{display:flex;align-items:center;gap:6px;font-size:var(--font-sm);color:var(--text-primary);cursor:pointer;}
|
||||
.radio input{accent-color:var(--primary);cursor:pointer;}
|
||||
@@ -246,9 +255,12 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<div class="form-section">救护车归属</div>
|
||||
<div class="form-grid">
|
||||
<div class="form-item"><span class="form-label"><span class="req">*</span> 所属医疗点</span>
|
||||
<select class="form-control" id="fPoint" onchange="onFormPoint()"><option value="">请选择医疗点</option><option>樊学作业区医疗点</option><option>安塞采油队长住点医疗室</option><option>姬塬作业区医疗点</option><option>姬圪台作业区医疗点</option><option>桐园作业区医疗点</option><option>西峰基地医疗点</option><option>靖边气田医疗点</option><option>乌审旗采气区医疗点</option></select></div>
|
||||
<input class="form-control" id="fPoint" disabled placeholder="默认医疗点"></div>
|
||||
<div class="form-item"><span class="form-label"><span class="req">*</span> 救护车</span>
|
||||
<select class="form-control" id="fAmb" onchange="onFormAmb()"><option value="">请先选择医疗点</option></select></div>
|
||||
<div class="search-select">
|
||||
<input class="form-control" id="fAmb" placeholder="请输入车牌号搜索" autocomplete="off" oninput="onAmbSearch()" onfocus="onAmbSearch()">
|
||||
<div class="search-select__list" id="fAmbList"></div>
|
||||
</div></div>
|
||||
<div class="form-item"><span class="form-label">救护类型</span>
|
||||
<input class="form-control" id="fAmbulanceType" disabled placeholder="选择救护车后自动带出"></div>
|
||||
</div>
|
||||
@@ -263,11 +275,10 @@ select.form-control{background:#fff url("data:image/svg+xml,%3Csvg xmlns='http:/
|
||||
<label class="radio"><input type="radio" name="fDispatch" value="平诊转运">平诊转运</label>
|
||||
<label class="radio"><input type="radio" name="fDispatch" value="日常巡诊">日常巡诊</label>
|
||||
<label class="radio"><input type="radio" name="fDispatch" value="应急戒备">应急戒备</label>
|
||||
<label class="radio"><input type="radio" name="fDispatch" value="床头呼叫">床头呼叫</label>
|
||||
<label class="radio"><input type="radio" name="fDispatch" value="其他">其他</label>
|
||||
</div></div>
|
||||
<div class="form-item"><span class="form-label"><span class="req">*</span> 出勤司机</span>
|
||||
<select class="form-control" id="fDriver" onchange="onFormDriver()"><option value="">请选择司机</option></select></div>
|
||||
<input class="form-control" id="fDriver" disabled placeholder="选择救护车后自动带出"></div>
|
||||
<div class="form-item"><span class="form-label">司机电话</span>
|
||||
<input class="form-control" id="fTel" disabled placeholder="选择司机后自动带出"></div>
|
||||
<div class="form-item form-item--full"><span class="form-label"><span class="req">*</span> 随车医护</span>
|
||||
@@ -366,14 +377,6 @@ var ambulances=[
|
||||
{plate:'CQ·0917E',point:'安塞采油队长住点医疗室',type:'转运型',model:'江淮瑞风转运型救护车',driver:'苏文斌',tel:'15598486703'},
|
||||
{plate:'CQ·2201F',point:'乌审旗采气区医疗点',type:'急救型',model:'红旗轻型监护型救护车',driver:'曹雪芹',tel:'18642802940'}
|
||||
];
|
||||
/* 救护车司机列表:从救护车台账驾驶员去重提取 */
|
||||
var drivers=[];
|
||||
(function(){
|
||||
var seen={};
|
||||
ambulances.forEach(function(a){
|
||||
if(!seen[a.driver]){seen[a.driver]=true;drivers.push({name:a.driver,tel:a.tel});}
|
||||
});
|
||||
})();
|
||||
/* 医护人员池:与「基础配置·医护人员管理」一致 */
|
||||
var medStaff=[
|
||||
{id:1,name:'韩东学',job:'主治医师',post:'医生',point:'樊学作业区医疗点'},
|
||||
@@ -406,7 +409,6 @@ var attendances=[
|
||||
];
|
||||
var nextId=13,editingId=null,pendingDelId=null;
|
||||
var dispatchBadge={'急诊转运':'badge--danger','平诊转运':'badge--info','日常巡诊':'badge--success','应急戒备':'badge--warning','床头呼叫':'badge--info','其他':'badge--muted'};
|
||||
var typeBadge={'急救型':'badge--danger','转运型':'badge--info'};
|
||||
|
||||
/* ===== 筛选与渲染 ===== */
|
||||
var pageSize=10,currentPage=1;
|
||||
@@ -448,15 +450,15 @@ function renderTable(){
|
||||
html+='<tr>'
|
||||
+'<td>'+(start+i+1)+'</td>'
|
||||
+'<td>'+r.date+'</td>'
|
||||
+'<td style="text-align:left;">'+r.point+'</td>'
|
||||
+'<td>'+r.point+'</td>'
|
||||
+'<td style="font-weight:600;">'+r.plate+'</td>'
|
||||
+'<td><span class="badge '+typeBadge[r.type]+'">'+r.type+'</span></td>'
|
||||
+'<td>'+r.type+'</td>'
|
||||
+'<td><span class="badge '+dispatchBadge[r.dispatch]+'">'+r.dispatch+'</span></td>'
|
||||
+'<td>'+r.driver+'</td>'
|
||||
+'<td>'+r.tel+'</td>'
|
||||
+'<td style="text-align:left;">'+(r.staff.join('、'))+'</td>'
|
||||
+'<td style="text-align:left;max-width:180px;overflow:hidden;text-overflow:ellipsis;">'+r.out+'</td>'
|
||||
+'<td style="text-align:left;max-width:180px;overflow:hidden;text-overflow:ellipsis;">'+r.to+'</td>'
|
||||
+'<td>'+(r.staff.join('、'))+'</td>'
|
||||
+'<td style="max-width:180px;overflow:hidden;text-overflow:ellipsis;">'+r.out+'</td>'
|
||||
+'<td style="max-width:180px;overflow:hidden;text-overflow:ellipsis;">'+r.to+'</td>'
|
||||
+'<td class="td-actions">'
|
||||
+'<button class="btn btn-link" onclick="openDetail('+r.id+')">详情</button>'
|
||||
+'<button class="btn btn-link" onclick="openForm('+r.id+')">编辑</button>'
|
||||
@@ -482,36 +484,27 @@ function turnPage(d){
|
||||
}
|
||||
|
||||
/* ===== 新增/编辑抽屉 ===== */
|
||||
function fillAmb(point,keep){
|
||||
var sel=document.getElementById('fAmb');
|
||||
sel.innerHTML='<option value="">请选择救护车</option>';
|
||||
ambulances.filter(function(a){return !point||a.point===point;}).forEach(function(a){
|
||||
var o=document.createElement('option');o.textContent=a.plate;
|
||||
if(keep&&a.plate===keep)o.selected=true;
|
||||
sel.appendChild(o);
|
||||
});
|
||||
var DEFAULT_POINT='樊学作业区医疗点';
|
||||
function onAmbSearch(){
|
||||
var kw=document.getElementById('fAmb').value.trim().toUpperCase();
|
||||
var list=ambulances.filter(function(a){return !kw||a.plate.toUpperCase().indexOf(kw)!==-1;});
|
||||
var box=document.getElementById('fAmbList');
|
||||
box.innerHTML=list.length?list.map(function(a){
|
||||
return '<div class="search-select__item" onmousedown="selectAmb(\''+a.plate+'\')">'
|
||||
+'<span class="plate">'+a.plate+'</span>'
|
||||
+'<span class="point">'+a.point+' · '+a.type+'</span></div>';
|
||||
}).join(''):'<div class="search-select__empty">无匹配救护车</div>';
|
||||
box.classList.add('open');
|
||||
}
|
||||
function fillDriverSel(keep){
|
||||
var sel=document.getElementById('fDriver');
|
||||
sel.innerHTML='<option value="">请选择司机</option>';
|
||||
drivers.forEach(function(d){
|
||||
var o=document.createElement('option');o.textContent=d.name;
|
||||
if(keep&&d.name===keep)o.selected=true;
|
||||
sel.appendChild(o);
|
||||
});
|
||||
}
|
||||
function onFormPoint(){fillAmb(document.getElementById('fPoint').value);clearAmbType();}
|
||||
function onFormAmb(){
|
||||
var plate=document.getElementById('fAmb').value;
|
||||
function selectAmb(plate){
|
||||
var a=ambulances.find(function(x){return x.plate===plate;});
|
||||
document.getElementById('fAmb').value=plate;
|
||||
document.getElementById('fAmbulanceType').value=a?a.type:'';
|
||||
document.getElementById('fDriver').value=a?a.driver:'';
|
||||
document.getElementById('fTel').value=a?a.tel:'';
|
||||
document.getElementById('fAmbList').classList.remove('open');
|
||||
}
|
||||
function clearAmbType(){document.getElementById('fAmbulanceType').value='';}
|
||||
function onFormDriver(){
|
||||
var name=document.getElementById('fDriver').value;
|
||||
var d=drivers.find(function(x){return x.name===name;});
|
||||
document.getElementById('fTel').value=d?d.tel:'';
|
||||
}
|
||||
function closeAmbList(){document.getElementById('fAmbList').classList.remove('open');}
|
||||
var selectedStaffIds=[];
|
||||
function setRadio(name,val){
|
||||
document.querySelectorAll('input[name="'+name+'"]').forEach(function(r){r.checked=(r.value===val);});
|
||||
@@ -535,23 +528,24 @@ function openForm(id){
|
||||
editingId=id||null;
|
||||
document.getElementById('formTitle').textContent=id?'编辑出勤记录':'新增出勤';
|
||||
var r=id?attendances.find(function(x){return x.id===id;}):null;
|
||||
document.getElementById('fPoint').value=r?r.point:'';
|
||||
fillAmb(r?r.point:'',r?r.plate:'');
|
||||
if(!r)document.getElementById('fAmb').innerHTML='<option value="">请先选择医疗点</option>';
|
||||
fillDriverSel(r?r.driver:'');
|
||||
document.getElementById('fDate').value=r?r.date:'';
|
||||
document.getElementById('fPoint').value=r?r.point:DEFAULT_POINT;
|
||||
document.getElementById('fAmb').value=r?r.plate:'';
|
||||
document.getElementById('fAmbulanceType').value=r?r.type:'';
|
||||
document.getElementById('fDriver').value=r?r.driver:'';
|
||||
document.getElementById('fTel').value=r?r.tel:'';
|
||||
document.getElementById('fDate').value=r?r.date:todayStr();
|
||||
setRadio('fDispatch',r?r.dispatch:'急诊转运');
|
||||
selectedStaffIds=(r?r.staff.slice():[]).map(function(n){var m=medStaff.find(function(x){return x.name===n;});return m?m.id:null;}).filter(function(id){return id!=null;});
|
||||
renderStaffChips();
|
||||
document.getElementById('fOut').value=r?r.out:'';
|
||||
document.getElementById('fTo').value=r?r.to:'';
|
||||
if(r){onFormAmb();onFormDriver();}else{clearAmbType();document.getElementById('fTel').value='';}
|
||||
closeAmbList();
|
||||
document.getElementById('formMask').classList.add('open');
|
||||
document.getElementById('formDrawer').classList.add('open');
|
||||
}
|
||||
function saveForm(){
|
||||
var point=document.getElementById('fPoint').value;
|
||||
var plate=document.getElementById('fAmb').value;
|
||||
var plate=document.getElementById('fAmb').value.trim();
|
||||
var date=document.getElementById('fDate').value;
|
||||
var dispatch=getRadio('fDispatch');
|
||||
var driver=document.getElementById('fDriver').value;
|
||||
@@ -565,12 +559,11 @@ function saveForm(){
|
||||
if(!out){showToast('请填写出勤地点');return;}
|
||||
if(!to){showToast('请填写到达地点');return;}
|
||||
var a=ambulances.find(function(x){return x.plate===plate;});
|
||||
var d=drivers.find(function(x){return x.name===driver;});
|
||||
var staffNames=selectedStaffIds.map(function(id){return medStaff.find(function(m){return m.id===id;}).name;});
|
||||
var obj={
|
||||
id:editingId||nextId++,
|
||||
date:date,point:point,plate:plate,type:a.type,dispatch:dispatch,
|
||||
driver:driver,tel:d.tel,staff:staffNames,out:out,to:to
|
||||
driver:driver,tel:a.tel,staff:staffNames,out:out,to:to
|
||||
};
|
||||
if(editingId){
|
||||
attendances.splice(attendances.findIndex(function(x){return x.id===editingId;}),1,obj);
|
||||
@@ -588,7 +581,7 @@ function openDetail(id){
|
||||
function d(k,v,full){return '<div class="detail-item'+(full?' detail-item--full':'')+'"><div class="dk">'+k+'</div><div class="dv">'+(v===''||v==null?'—':v)+'</div></div>';}
|
||||
document.getElementById('detailBody').innerHTML=
|
||||
'<div class="form-section" style="margin-top:0;">救护车信息</div>'
|
||||
+'<div class="detail-grid">'+d('所属医疗点',r.point)+d('救护车',r.plate)+d('救护类型','<span class="badge '+typeBadge[r.type]+'">'+r.type+'</span>')+'</div>'
|
||||
+'<div class="detail-grid">'+d('所属医疗点',r.point)+d('救护车',r.plate)+d('救护类型',r.type)+'</div>'
|
||||
+'<div class="form-section">出勤信息</div>'
|
||||
+'<div class="detail-grid">'
|
||||
+d('出勤日期',r.date)
|
||||
@@ -606,7 +599,8 @@ function openDetail(id){
|
||||
/* ===== 随车医护选择弹窗 ===== */
|
||||
function renderStaffList(){
|
||||
var kw=document.getElementById('staffKeyword').value.trim();
|
||||
var list=medStaff.filter(function(m){return !kw||m.name.indexOf(kw)!==-1;});
|
||||
var point=document.getElementById('fPoint').value;
|
||||
var list=medStaff.filter(function(m){return (!point||m.point===point)&&(!kw||m.name.indexOf(kw)!==-1);});
|
||||
var body=document.getElementById('staffListBody');
|
||||
if(!list.length){body.innerHTML='<tr><td colspan="5" class="td-empty">暂无匹配人员</td></tr>';return;}
|
||||
body.innerHTML=list.map(function(m){
|
||||
@@ -652,6 +646,13 @@ function closeDrawer(k){
|
||||
document.getElementById(k+'Drawer').classList.remove('open');
|
||||
}
|
||||
function closeModal(id){document.getElementById(id).classList.remove('open');}
|
||||
function todayStr(){
|
||||
var d=new Date();
|
||||
return d.getFullYear()+'-'+String(d.getMonth()+1).padStart(2,'0')+'-'+String(d.getDate()).padStart(2,'0');
|
||||
}
|
||||
document.addEventListener('click',function(e){
|
||||
if(!e.target.closest('.search-select'))closeAmbList();
|
||||
});
|
||||
function showToast(msg){
|
||||
var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');
|
||||
clearTimeout(t._timer);t._timer=setTimeout(function(){t.classList.remove('show');},2200);
|
||||
|
||||
@@ -30,7 +30,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:9px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.main{margin-left:240px;margin-top:56px;padding:16px 20px;min-height:calc(100vh - 56px);}
|
||||
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:9px 24px;font-size:var(--font-sm);color:rgba(255,255,255,0.45);cursor:pointer;user-select:none;}
|
||||
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);}
|
||||
.sidebar-subgroup__header .arrow{width:10px;height:10px;stroke:currentColor;transition:transform .2s;}
|
||||
@@ -39,28 +39,29 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.sidebar-subgroup.open .sidebar-subgroup__body{display:block;}
|
||||
.sidebar-subgroup__body .sidebar-item{padding-left:40px;}
|
||||
/* [交互] 所属单位→所属医疗点级联;清空单位回到全局统计(与老系统 allowClear 一致) */
|
||||
.filter-bar{background:#fff;padding:16px 24px;display:flex;align-items:center;gap:16px;flex-wrap:wrap;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
|
||||
.filter-bar{background:#fff;padding:12px 20px;display:flex;align-items:center;gap:16px;flex-wrap:wrap;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);}
|
||||
.filter-item{display:flex;align-items:center;gap:8px;}
|
||||
.filter-item label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
|
||||
.filter-select{height:36px;min-width:140px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 28px 0 12px;font-size:var(--font-sm);color:var(--text-primary);background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 8px center;cursor:pointer;outline:none;appearance:none;-webkit-appearance:none;}
|
||||
.filter-select:disabled{background-color:#F5F5F5;color:var(--text-placeholder);cursor:not-allowed;}
|
||||
/* 卡片:基本数据(32%)+出勤次数(66%),布局与老系统 number-container 一致 */
|
||||
.num-row{display:flex;gap:16px;margin-top:16px;align-items:stretch;}
|
||||
.stat-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);padding:16px 20px;}
|
||||
.stat-card__title{font-size:var(--font-base);font-weight:600;color:var(--text-primary);margin-bottom:12px;font-size:var(--font-base);}
|
||||
.stat-card__grid{display:flex;justify-content:space-around;background:#F8F8FA;border-radius:10px;padding:14px 8px;}
|
||||
.num-row{display:flex;gap:16px;margin-top:12px;align-items:stretch;}
|
||||
.stat-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);padding:12px 16px;}
|
||||
.stat-card__title{font-size:var(--font-base);font-weight:600;color:var(--text-primary);margin-bottom:8px;}
|
||||
.stat-card__grid{display:flex;justify-content:space-around;background:#F8F8FA;border-radius:10px;padding:10px 8px;}
|
||||
.stat-cell{text-align:center;}
|
||||
.stat-cell__val{font-size:22px;font-weight:600;color:var(--text-primary);}
|
||||
.stat-cell__val{font-size:20px;font-weight:600;color:var(--text-primary);}
|
||||
.stat-cell__val small{font-size:var(--font-xs);font-weight:400;color:var(--text-placeholder);margin-left:2px;}
|
||||
.stat-cell__name{font-size:var(--font-sm);color:var(--text-secondary);margin-top:4px;}
|
||||
.stat-cell__name{font-size:var(--font-sm);color:var(--text-secondary);margin-top:2px;}
|
||||
.num-card--l{width:32%;}.num-card--r{width:68%;}
|
||||
.chart-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px;margin-top:16px;}
|
||||
.chart-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);padding:18px 22px;}
|
||||
.chart-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px;margin-top:12px;}
|
||||
.chart-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);padding:14px 18px;}
|
||||
.chart-card--full{grid-column:1/-1;}
|
||||
.chart-card__title{font-size:var(--font-sm);font-weight:600;color:var(--text-primary);display:flex;align-items:center;justify-content:space-between;}
|
||||
.chart-card__title .lg{display:flex;gap:12px;font-size:var(--font-xs);font-weight:400;color:var(--text-secondary);}
|
||||
.chart-card__title .lg i{display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:4px;vertical-align:-1px;}
|
||||
.chart-card svg{width:100%;height:auto;display:block;margin-top:10px;}
|
||||
.chart-card--full svg{max-height:230px;}
|
||||
.wk-switch{display:inline-flex;height:26px;line-height:26px;text-align:center;font-weight:400;cursor:pointer;font-size:var(--font-sm);}
|
||||
.wk-switch span{width:50px;border:1px solid var(--primary);}
|
||||
.wk-switch span:first-child{border-radius:var(--radius-sm) 0 0 var(--radius-sm);}
|
||||
@@ -155,13 +156,13 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
<div class="chart-grid">
|
||||
<div class="chart-card">
|
||||
<div class="chart-card__title">救护车类型占比<span style="font-weight:400;color:var(--text-placeholder);font-size:var(--font-xs);">(辆)</span></div>
|
||||
<svg id="pieType" viewBox="0 0 560 240"></svg>
|
||||
<svg id="pieType" viewBox="0 0 560 220"></svg>
|
||||
</div>
|
||||
<div class="chart-card">
|
||||
<div class="chart-card__title">出勤次数占比
|
||||
<span class="wk-switch" id="wkDisp"><span class="on" onclick="setWeek('wkDisp',true)">本周</span><span class="off" onclick="setWeek('wkDisp',false)">累计</span></span>
|
||||
</div>
|
||||
<svg id="pieDisp" viewBox="0 0 560 260"></svg>
|
||||
<svg id="pieDisp" viewBox="0 0 560 230"></svg>
|
||||
</div>
|
||||
<div class="chart-card">
|
||||
<div class="chart-card__title">医护人员出勤次数排名TOP5
|
||||
@@ -182,7 +183,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
<div class="chart-card__title">本周出勤次数变化趋势
|
||||
<span class="lg" id="trendLg"></span>
|
||||
</div>
|
||||
<svg id="chartTrend" viewBox="0 0 1120 280"></svg>
|
||||
<svg id="chartTrend" viewBox="0 0 1120 200"></svg>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
@@ -191,38 +192,38 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
|
||||
<script>
|
||||
/* 数据源与「救护车配置」页勾稽:6 辆车=4 急救型+2 转运型,辐射人数取车辆覆盖人数;
|
||||
出勤五类口径:急救转运/平诊转运/日常巡诊/应急戒备/其他出勤(dispatch_type 字典) */
|
||||
var TYPES=['jz','pz','rc','yj','qt'];
|
||||
var TYPE_NAME={jz:'急救转运',pz:'平诊转运',rc:'日常巡诊',yj:'应急戒备',qt:'其他出勤'};
|
||||
var DISC=['#5087ec','#68bbc4','#58a55c','#f2bd42','#ee752f'];
|
||||
出勤六类口径:急救转运/平诊转运/日常巡诊/应急戒备/床头呼叫/其他出勤(dispatch_type 字典) */
|
||||
var TYPES=['jz','pz','rc','yj','ct','qt'];
|
||||
var TYPE_NAME={jz:'急救转运',pz:'平诊转运',rc:'日常巡诊',yj:'应急戒备',ct:'床头呼叫',qt:'其他出勤'};
|
||||
var DISC=['#5087ec','#68bbc4','#58a55c','#f2bd42','#9966cc','#ee752f'];
|
||||
var pts=[
|
||||
{unit:'采油一厂',name:'樊学作业区医疗点',total:1,jj:1,zy:0,rad:860,
|
||||
w:{jz:3,pz:2,rc:5,yj:1,qt:1},t:{jz:42,pz:28,rc:76,yj:15,qt:9},
|
||||
staff:[{name:'李桂芳',w:{jz:2,pz:1,rc:3,yj:1,qt:1},t:{jz:24,pz:16,rc:41,yj:8,qt:5}},
|
||||
{name:'石维国',w:{jz:1,pz:1,rc:2,yj:0,qt:0},t:{jz:18,pz:12,rc:35,yj:7,qt:4}}]},
|
||||
w:{jz:3,pz:2,rc:5,yj:1,qt:1,ct:0},t:{jz:42,pz:28,rc:76,yj:15,qt:9,ct:0},
|
||||
staff:[{name:'李桂芳',w:{jz:2,pz:1,rc:3,yj:1,qt:1,ct:0},t:{jz:24,pz:16,rc:41,yj:8,qt:5,ct:0}},
|
||||
{name:'石维国',w:{jz:1,pz:1,rc:2,yj:0,qt:0,ct:0},t:{jz:18,pz:12,rc:35,yj:7,qt:4,ct:0}}]},
|
||||
{unit:'采油一厂',name:'安塞采油队长住点医疗室',total:1,jj:0,zy:1,rad:540,
|
||||
w:{jz:0,pz:3,rc:2,yj:0,qt:1},t:{jz:9,pz:41,rc:33,yj:6,qt:10},
|
||||
staff:[{name:'周娟',w:{jz:0,pz:3,rc:2,yj:0,qt:1},t:{jz:9,pz:41,rc:33,yj:6,qt:10}}]},
|
||||
w:{jz:0,pz:3,rc:2,yj:0,qt:1,ct:0},t:{jz:9,pz:41,rc:33,yj:6,qt:10,ct:0},
|
||||
staff:[{name:'周娟',w:{jz:0,pz:3,rc:2,yj:0,qt:1,ct:0},t:{jz:9,pz:41,rc:33,yj:6,qt:10,ct:0}}]},
|
||||
{unit:'采油一厂',name:'姬塬作业区医疗点',total:0,jj:0,zy:0,rad:0,
|
||||
w:{jz:0,pz:0,rc:0,yj:0,qt:0},t:{jz:0,pz:0,rc:0,yj:0,qt:0},staff:[]},
|
||||
w:{jz:0,pz:0,rc:0,yj:0,qt:0,ct:0},t:{jz:0,pz:0,rc:0,yj:0,qt:0,ct:0},staff:[]},
|
||||
{unit:'采油二厂',name:'姬圪台作业区医疗点',total:1,jj:1,zy:0,rad:1240,
|
||||
w:{jz:2,pz:1,rc:4,yj:2,qt:0},t:{jz:35,pz:22,rc:61,yj:18,qt:7},
|
||||
staff:[{name:'曲志明',w:{jz:1,pz:1,rc:2,yj:1,qt:0},t:{jz:19,pz:13,rc:34,yj:10,qt:4}},
|
||||
{name:'张秀兰',w:{jz:1,pz:0,rc:2,yj:1,qt:0},t:{jz:16,pz:9,rc:27,yj:8,qt:3}}]},
|
||||
w:{jz:2,pz:1,rc:4,yj:2,qt:0,ct:0},t:{jz:35,pz:22,rc:61,yj:18,qt:7,ct:0},
|
||||
staff:[{name:'曲志明',w:{jz:1,pz:1,rc:2,yj:1,qt:0,ct:0},t:{jz:19,pz:13,rc:34,yj:10,qt:4,ct:0}},
|
||||
{name:'张秀兰',w:{jz:1,pz:0,rc:2,yj:1,qt:0,ct:0},t:{jz:16,pz:9,rc:27,yj:8,qt:3,ct:0}}]},
|
||||
{unit:'采油二厂',name:'桐园作业区医疗点',total:0,jj:0,zy:0,rad:0,
|
||||
w:{jz:0,pz:0,rc:0,yj:0,qt:0},t:{jz:0,pz:0,rc:0,yj:0,qt:0},staff:[]},
|
||||
w:{jz:0,pz:0,rc:0,yj:0,qt:0,ct:0},t:{jz:0,pz:0,rc:0,yj:0,qt:0,ct:0},staff:[]},
|
||||
{unit:'第四采油厂',name:'西峰基地医疗点',total:1,jj:0,zy:1,rad:2100,
|
||||
w:{jz:1,pz:6,rc:7,yj:3,qt:2},t:{jz:18,pz:88,rc:97,yj:26,qt:14},
|
||||
staff:[{name:'高建军',w:{jz:1,pz:3,rc:3,yj:2,qt:1},t:{jz:10,pz:45,rc:49,yj:14,qt:8}},
|
||||
{name:'闫婷',w:{jz:0,pz:3,rc:4,yj:1,qt:1},t:{jz:8,pz:43,rc:48,yj:12,qt:6}}]},
|
||||
w:{jz:1,pz:6,rc:7,yj:3,qt:2,ct:0},t:{jz:18,pz:88,rc:97,yj:26,qt:14,ct:0},
|
||||
staff:[{name:'高建军',w:{jz:1,pz:3,rc:3,yj:2,qt:1,ct:0},t:{jz:10,pz:45,rc:49,yj:14,qt:8,ct:0}},
|
||||
{name:'闫婷',w:{jz:0,pz:3,rc:4,yj:1,qt:1,ct:0},t:{jz:8,pz:43,rc:48,yj:12,qt:6,ct:0}}]},
|
||||
{unit:'采气一厂',name:'靖边气田医疗点',total:1,jj:1,zy:0,rad:760,
|
||||
w:{jz:2,pz:1,rc:3,yj:1,qt:1},t:{jz:27,pz:19,rc:48,yj:12,qt:6},
|
||||
staff:[{name:'刘玉梅',w:{jz:2,pz:1,rc:2,yj:1,qt:0},t:{jz:16,pz:11,rc:29,yj:7,qt:3}},
|
||||
{name:'呼建国',w:{jz:0,pz:0,rc:1,yj:0,qt:1},t:{jz:11,pz:8,rc:19,yj:5,qt:3}}]},
|
||||
w:{jz:2,pz:1,rc:3,yj:1,qt:1,ct:0},t:{jz:27,pz:19,rc:48,yj:12,qt:6,ct:0},
|
||||
staff:[{name:'刘玉梅',w:{jz:2,pz:1,rc:2,yj:1,qt:0,ct:0},t:{jz:16,pz:11,rc:29,yj:7,qt:3,ct:0}},
|
||||
{name:'呼建国',w:{jz:0,pz:0,rc:1,yj:0,qt:1,ct:0},t:{jz:11,pz:8,rc:19,yj:5,qt:3,ct:0}}]},
|
||||
{unit:'采气一厂',name:'乌审旗采气区医疗点',total:1,jj:1,zy:0,rad:680,
|
||||
w:{jz:1,pz:1,rc:3,yj:2,qt:0},t:{jz:22,pz:14,rc:40,yj:16,qt:5},
|
||||
staff:[{name:'徐立成',w:{jz:1,pz:0,rc:2,yj:1,qt:0},t:{jz:13,pz:8,rc:24,yj:10,qt:3}},
|
||||
{name:'马丽华',w:{jz:0,pz:1,rc:1,yj:1,qt:0},t:{jz:9,pz:6,rc:16,yj:6,qt:2}}]}
|
||||
w:{jz:1,pz:1,rc:3,yj:2,qt:0,ct:0},t:{jz:22,pz:14,rc:40,yj:16,qt:5,ct:0},
|
||||
staff:[{name:'徐立成',w:{jz:1,pz:0,rc:2,yj:1,qt:0,ct:0},t:{jz:13,pz:8,rc:24,yj:10,qt:3,ct:0}},
|
||||
{name:'马丽华',w:{jz:0,pz:1,rc:1,yj:1,qt:0,ct:0},t:{jz:9,pz:6,rc:16,yj:6,qt:2,ct:0}}]}
|
||||
];
|
||||
var weekState={wkDisp:true,wkTop:true};
|
||||
function esc(s){return String(s).replace(/&/g,'&').replace(/</g,'<');}
|
||||
@@ -307,7 +308,7 @@ function drawTop5(id,data,color,unit){
|
||||
svg.innerHTML=html;
|
||||
svg.setAttribute('viewBox','0 0 '+W+' '+h);
|
||||
}
|
||||
/* ===== 本周逐日堆积柱状(5系列 stack,照搬老系统 barCharts) ===== */
|
||||
/* ===== 本周逐日堆积柱状(6系列 stack,照搬老系统 barCharts) ===== */
|
||||
var DAYS=['周一','周二','周三','周四','周五','周六','周日'];
|
||||
var WT=[2,1,2,1,3,2,1];
|
||||
function splitWeek(v){
|
||||
@@ -323,7 +324,7 @@ function renderTrend(){
|
||||
return {name:TYPE_NAME[k],color:DISC[i],data:days};
|
||||
});
|
||||
document.getElementById('trendLg').innerHTML=series.map(function(s){return '<span><i style="background:'+s.color+';"></i>'+s.name+'</span>';}).join('');
|
||||
var svg=document.getElementById('chartTrend'),W=1120,H=280,left=44,bottom=34,top=12,right=16;
|
||||
var svg=document.getElementById('chartTrend'),W=1120,H=200,left=44,bottom=34,top=12,right=16;
|
||||
var max=0;DAYS.forEach(function(d,i){var s=0;series.forEach(function(se){s+=se.data[i];});if(s>max)max=s;});
|
||||
max=max||1;
|
||||
var step=(W-left-right)/7,bw=Math.min(56,step*0.5),html='';
|
||||
@@ -375,7 +376,7 @@ function showToast(msg){
|
||||
var t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');
|
||||
clearTimeout(t._timer);t._timer=setTimeout(function(){t.classList.remove('show');},2200);
|
||||
}
|
||||
/* 初始化:单位下拉 + 出勤类型下拉(dispatch_type 字典五类) */
|
||||
/* 初始化:单位下拉 + 出勤类型下拉(dispatch_type 字典六类) */
|
||||
(function(){
|
||||
var us=[];pts.forEach(function(p){if(us.indexOf(p.unit)<0)us.push(p.unit);});
|
||||
document.getElementById('selUnit').innerHTML='<option value="">全部单位</option>'+us.map(function(u){return '<option>'+esc(u)+'</option>';}).join('');
|
||||
|
||||
@@ -39,6 +39,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.sidebar-subgroup__body .sidebar-item{padding-left:40px;}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
.toolbar{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;}
|
||||
.action-bar{display:flex;justify-content:flex-start;gap:8px;margin-top:16px;}
|
||||
.date-switch{display:inline-flex;height:32px;line-height:32px;border:1px solid var(--primary);border-radius:var(--radius-sm);overflow:hidden;font-size:var(--font-sm);}
|
||||
.date-switch span{padding:0 16px;cursor:pointer;color:var(--primary);background:#fff;border-right:1px solid var(--primary);white-space:nowrap;}
|
||||
.date-switch span:last-child{border-right:none;}
|
||||
@@ -62,7 +63,7 @@ thead tr.grp th{background:#F0F5FF;color:var(--text-primary);border-right:1px so
|
||||
tbody td{padding:12px 14px;border-bottom:1px solid #F0F0F0;text-align:center;white-space:nowrap;font-size:var(--font-sm);}
|
||||
tbody tr:hover td{background:#F8FBFF;}
|
||||
.td-empty{text-align:center;padding:48px 0;color:var(--text-placeholder);}
|
||||
.num-cur{color:var(--primary);font-weight:600;}
|
||||
.num-cur{color:var(--text-primary);font-weight:600;}
|
||||
.num-total{color:var(--text-secondary);}
|
||||
.badge{display:inline-block;padding:1px 8px;border-radius:10px;font-size:var(--font-xs);line-height:18px;}
|
||||
.badge--danger{background:#FFF1F0;color:#FF4D4F;border:1px solid #FFA39E;}
|
||||
@@ -130,7 +131,7 @@ tbody tr:hover td{background:#F8FBFF;}
|
||||
|
||||
<!-- 主内容 -->
|
||||
<main class="main">
|
||||
<!-- 时间切换 + 导出操作(照搬老系统 DateButtonSelector + 导出按钮) -->
|
||||
<!-- 时间切换(照搬老系统 DateButtonSelector) -->
|
||||
<div class="toolbar">
|
||||
<div class="date-switch" id="dateSwitch">
|
||||
<span class="on" data-type="week" onclick="switchDateType('week')">本周</span>
|
||||
@@ -138,10 +139,6 @@ tbody tr:hover td{background:#F8FBFF;}
|
||||
<span data-type="year" onclick="switchDateType('year')">本年</span>
|
||||
<span data-type="picker" onclick="switchDateType('picker')">自定义</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;">
|
||||
<button class="btn btn-primary" onclick="doExport()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 10v2h10v-2M7 9V2M4.5 4.5L7 2l2.5 2.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>导出</button>
|
||||
<button class="btn btn-default" onclick="openExportLog()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6.5" cy="6.5" r="4.5" stroke="currentColor" stroke-width="1.4"/><path d="M10 10l3 3" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>查看导出记录</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选栏:单位→医疗点级联 + 救护类型 + 时间 -->
|
||||
@@ -178,7 +175,11 @@ tbody tr:hover td{background:#F8FBFF;}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分组报表:基础信息 + 五类出勤次数(本周/累计) -->
|
||||
<!-- 分组报表:基础信息 + 六类出勤次数(本周/累计) -->
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="doExport()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 10v2h10v-2M7 9V2M4.5 4.5L7 2l2.5 2.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>导出列表数据</button>
|
||||
<button class="btn btn-default" onclick="openExportLog()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6.5" cy="6.5" r="4.5" stroke="currentColor" stroke-width="1.4"/><path d="M10 10l3 3" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>查看导出记录</button>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
<table>
|
||||
@@ -193,6 +194,7 @@ tbody tr:hover td{background:#F8FBFF;}
|
||||
<th colspan="2">平诊转运</th>
|
||||
<th colspan="2">日常巡诊</th>
|
||||
<th colspan="2">应急戒备</th>
|
||||
<th colspan="2">床头呼叫</th>
|
||||
<th colspan="2">其他</th>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -206,6 +208,8 @@ tbody tr:hover td{background:#F8FBFF;}
|
||||
<th>累计出勤次数</th>
|
||||
<th><span class="period-text">本周</span>出勤次数</th>
|
||||
<th>累计出勤次数</th>
|
||||
<th><span class="period-text">本周</span>出勤次数</th>
|
||||
<th>累计出勤次数</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tbody"></tbody>
|
||||
@@ -233,23 +237,23 @@ tbody tr:hover td{background:#F8FBFF;}
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
/* 数据源:6 辆救护车(与「救护车配置」页车牌/车型/救护类型勾稽,与「救护车统计-图表」五类出勤口径同源);
|
||||
出勤五类:急诊转运/平诊转运/日常巡诊/应急戒备/其他,各分 本周/累计 出勤次数 */
|
||||
/* 数据源:6 辆救护车(与「救护车配置」页车牌/车型/救护类型勾稽,与「救护车统计-图表」六类出勤口径同源);
|
||||
出勤六类:急诊转运/平诊转运/日常巡诊/应急戒备/床头呼叫/其他,各分 本周/累计 出勤次数 */
|
||||
var cars=[
|
||||
{unit:'采油一厂',point:'樊学作业区医疗点',type:'急救型',model:'江铃轻型监护型救护车',plate:'CQ·0712A',
|
||||
w:{jz:3,pz:2,rc:5,yj:1,qt:1},t:{jz:42,pz:28,rc:76,yj:15,qt:9}},
|
||||
w:{jz:3,pz:2,rc:5,yj:1,qt:1,ct:0},t:{jz:42,pz:28,rc:76,yj:15,qt:9,ct:0}},
|
||||
{unit:'采油二厂',point:'姬圪台作业区医疗点',type:'急救型',model:'福田图雅诺监护型救护车',plate:'CQ·1366B',
|
||||
w:{jz:2,pz:1,rc:4,yj:2,qt:0},t:{jz:35,pz:22,rc:61,yj:18,qt:7}},
|
||||
w:{jz:2,pz:1,rc:4,yj:2,qt:0,ct:0},t:{jz:35,pz:22,rc:61,yj:18,qt:7,ct:0}},
|
||||
{unit:'第四采油厂',point:'西峰基地医疗点',type:'转运型',model:'福特全顺转运型救护车',plate:'CQ·0208C',
|
||||
w:{jz:1,pz:6,rc:7,yj:3,qt:2},t:{jz:18,pz:88,rc:97,yj:26,qt:14}},
|
||||
w:{jz:1,pz:6,rc:7,yj:3,qt:2,ct:0},t:{jz:18,pz:88,rc:97,yj:26,qt:14,ct:0}},
|
||||
{unit:'采气一厂',point:'靖边气田医疗点',type:'急救型',model:'东风轻型救护车',plate:'CQ·1533D',
|
||||
w:{jz:2,pz:1,rc:3,yj:1,qt:1},t:{jz:27,pz:19,rc:48,yj:12,qt:6}},
|
||||
w:{jz:2,pz:1,rc:3,yj:1,qt:1,ct:0},t:{jz:27,pz:19,rc:48,yj:12,qt:6,ct:0}},
|
||||
{unit:'采油一厂',point:'安塞采油队长住点医疗室',type:'转运型',model:'江淮瑞风转运型救护车',plate:'CQ·0917E',
|
||||
w:{jz:0,pz:3,rc:2,yj:0,qt:1},t:{jz:9,pz:41,rc:33,yj:6,qt:10}},
|
||||
w:{jz:0,pz:3,rc:2,yj:0,qt:1,ct:0},t:{jz:9,pz:41,rc:33,yj:6,qt:10,ct:0}},
|
||||
{unit:'采气一厂',point:'乌审旗采气区医疗点',type:'急救型',model:'红旗轻型监护型救护车',plate:'CQ·2201F',
|
||||
w:{jz:1,pz:1,rc:3,yj:2,qt:0},t:{jz:22,pz:14,rc:40,yj:16,qt:5}}
|
||||
w:{jz:1,pz:1,rc:3,yj:2,qt:0,ct:0},t:{jz:22,pz:14,rc:40,yj:16,qt:5,ct:0}}
|
||||
];
|
||||
var TYPES=['jz','pz','rc','yj','qt'];
|
||||
var TYPES=['jz','pz','rc','yj','ct','qt'];
|
||||
var dateType='week';
|
||||
var PERIOD_TEXT={week:'本周',month:'本月',year:'本年',picker:'时段内'};
|
||||
function esc(s){return String(s).replace(/&/g,'&').replace(/</g,'<');}
|
||||
|
||||
@@ -38,9 +38,9 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
.sidebar-subgroup.open .sidebar-subgroup__body{display:block;}
|
||||
.sidebar-subgroup__body .sidebar-item{padding-left:40px;}
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
/* 工具栏:时间切换 + 导出操作 */
|
||||
/* 工具栏:时间切换 */
|
||||
.toolbar{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;}
|
||||
.action-bar{display:flex;justify-content:flex-end;margin-top:16px;}
|
||||
.action-bar{display:flex;justify-content:flex-start;gap:8px;margin-top:16px;}
|
||||
.date-switch{display:inline-flex;height:32px;line-height:32px;border:1px solid var(--primary);border-radius:var(--radius-sm);overflow:hidden;font-size:var(--font-sm);}
|
||||
.date-switch span{padding:0 16px;cursor:pointer;color:var(--primary);background:#fff;border-right:1px solid var(--primary);white-space:nowrap;}
|
||||
.date-switch span:last-child{border-right:none;}
|
||||
@@ -135,7 +135,7 @@ th.sortable:hover{color:var(--primary);}
|
||||
|
||||
<!-- 主内容 -->
|
||||
<main class="main">
|
||||
<!-- 时间切换 + 导出操作(照搬老系统 DateButtonSelector + 导出按钮) -->
|
||||
<!-- 时间切换(照搬老系统 DateButtonSelector) -->
|
||||
<div class="toolbar">
|
||||
<div class="date-switch" id="dateSwitch">
|
||||
<span class="on" data-type="week" onclick="switchDateType('week')">本周</span>
|
||||
@@ -143,10 +143,6 @@ th.sortable:hover{color:var(--primary);}
|
||||
<span data-type="year" onclick="switchDateType('year')">本年</span>
|
||||
<span data-type="picker" onclick="switchDateType('picker')">自定义</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;">
|
||||
<button class="btn btn-primary" onclick="doExport()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 10v2h10v-2M7 9V2M4.5 4.5L7 2l2.5 2.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>导出</button>
|
||||
<button class="btn btn-default" onclick="openExportLog()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6.5" cy="6.5" r="4.5" stroke="currentColor" stroke-width="1.4"/><path d="M10 10l3 3" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>查看导出记录</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选栏:所属单位 + 时间 -->
|
||||
@@ -176,6 +172,7 @@ th.sortable:hover{color:var(--primary);}
|
||||
<!-- 分组大表:就诊人次 / 慢病管理 / 培训宣教 / 体检报告解读 多级表头 -->
|
||||
<div class="action-bar">
|
||||
<button class="btn btn-primary" onclick="doExport()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 10v2h10v-2M7 9V2M4.5 4.5L7 2l2.5 2.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>导出列表数据</button>
|
||||
<button class="btn btn-default" onclick="openExportLog()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="6.5" cy="6.5" r="4.5" stroke="currentColor" stroke-width="1.4"/><path d="M10 10l3 3" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>查看导出记录</button>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<div class="table-card__content">
|
||||
|
||||
@@ -135,11 +135,8 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
<option value="">全部</option>
|
||||
</select>
|
||||
</div>
|
||||
<button class="btn btn-primary" onclick="openImport()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 10v2h10v-2M7 9V2M4.5 4.5L7 2l2.5 2.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>批量导入数据</button>
|
||||
<button class="btn btn-primary" onclick="openImport()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 10v2h10v-2M7 9V2M4.5 4.5L7 2l2.5 2.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>导入模板数据</button>
|
||||
<button class="btn btn-default" onclick="openImportTasks()"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="2" y="2" width="10" height="10" rx="1.5" stroke="currentColor" stroke-width="1.4"/><path d="M4 5h6M4 7.5h4" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/></svg>查看导入任务</button>
|
||||
<button class="btn btn-default" onclick="showToast('救助物品模板下载功能演示')">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v7M4.5 6.5L7 9l2.5-2.5M2 12h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>救助物品模板下载
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 小药棒:6 项指标通栏 -->
|
||||
@@ -181,6 +178,9 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
|
||||
<div class="modal__title"><svg width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M10 14V3M6.5 6.5L10 3l3.5 3.5M3 16h14" stroke="#1890FF" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg> 导入救助物品数据</div>
|
||||
<div style="margin-top:14px;">
|
||||
<div class="drop-zone" onclick="showToast('演示环境请选择本地文件(仅支持.xlsx)')">点击选择或拖拽文件到此处上传<br>救助物品模板.xlsx</div>
|
||||
<div style="font-size:var(--font-xs);color:var(--text-placeholder);margin-top:6px;">
|
||||
<a href="javascript:void(0)" style="color:var(--primary);text-decoration:none;" onclick="showToast('模板下载中…')">下载导入模板</a> · 请按模板列整理后上传
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeImport()">取消</button>
|
||||
|
||||
@@ -33,6 +33,15 @@
|
||||
.sidebar-item{display:flex;align-items:center;gap:8px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;text-decoration:none;}
|
||||
.sidebar-item:hover{color:#fff;background:rgba(255,255,255,0.06);}
|
||||
.sidebar-item.active{color:#fff;background:var(--primary);}
|
||||
.sidebar-subgroup__header{display:flex;align-items:center;gap:6px;padding:10px 24px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);cursor:pointer;transition:all .15s;user-select:none;}
|
||||
.sidebar-subgroup__header:hover{color:rgba(255,255,255,0.85);background:rgba(255,255,255,0.04);}
|
||||
.sidebar-subgroup__header .arrow{width:10px;height:10px;transition:transform .2s;flex-shrink:0;}
|
||||
.sidebar-subgroup__header .arrow path{stroke:rgba(255,255,255,0.45);}
|
||||
.sidebar-subgroup.open>.sidebar-subgroup__header{color:rgba(255,255,255,0.85);}
|
||||
.sidebar-subgroup.open>.sidebar-subgroup__header .arrow{transform:rotate(90deg);}
|
||||
.sidebar-subgroup__body{display:none;padding-left:16px;}
|
||||
.sidebar-subgroup.open>.sidebar-subgroup__body{display:block;}
|
||||
.sidebar-subgroup__body .sidebar-item{padding-left:36px;font-size:12px;}
|
||||
/* 主内容 */
|
||||
.main{margin-left:240px;margin-top:56px;padding:24px;min-height:calc(100vh - 56px);}
|
||||
/* 按钮行 */
|
||||
@@ -168,11 +177,10 @@
|
||||
</div>
|
||||
<nav class="top-bar__nav">
|
||||
<a href="archive-personal.html">档案</a>
|
||||
<a href="config-material-notice.html">基础配置</a>
|
||||
<a href="config-material-notice.html" class="active">基础配置</a>
|
||||
<a href="pre-hospital-scope.html">检前</a>
|
||||
<a href="mid-appointment-track.html">检中</a>
|
||||
<a href="post-unit-count.html">检后</a>
|
||||
<a href="agent-device.html" class="active">前置机管理</a>
|
||||
<a href="exception-dirty.html">异常事件</a>
|
||||
</nav>
|
||||
<div class="top-bar__right">
|
||||
@@ -187,8 +195,40 @@
|
||||
|
||||
<!-- 侧边栏 -->
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-menu__title">前置机管理</div>
|
||||
<a href="agent-device.html" class="sidebar-item active">常规体检前置服务</a>
|
||||
<div class="sidebar-menu__title">基础配置</div>
|
||||
<div class="sidebar-subgroup">
|
||||
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)">
|
||||
<svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg>
|
||||
素材信息
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="config-material-notice.html" class="sidebar-item">体检须知</a>
|
||||
<a href="config-material-video.html" class="sidebar-item">操作说明</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-subgroup">
|
||||
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)">
|
||||
<svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg>
|
||||
医院配置
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="config-hospital-basic.html" class="sidebar-item">基本信息配置</a>
|
||||
<a href="config-hospital-combo.html" class="sidebar-item">检查项组合配置</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="config-report-template.html" class="sidebar-item">体检导入模板管理</a>
|
||||
<div class="sidebar-subgroup">
|
||||
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)">
|
||||
<svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg>
|
||||
体检标准化项目
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="config-standard-category.html" class="sidebar-item">体检项目分类</a>
|
||||
<a href="config-standard-basic.html" class="sidebar-item">体检基本项目</a>
|
||||
<a href="config-standard-hospital.html" class="sidebar-item">医院体检项目</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="agent-device.html" class="sidebar-item active">前置机管理</a>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
@@ -726,6 +766,18 @@ datasource:
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
/* 侧边栏展开/折叠交互 */
|
||||
function toggleSubgroup(header){
|
||||
header.parentElement.classList.toggle('open');
|
||||
}
|
||||
/* 页面加载时自动展开当前页面所在的子分组 */
|
||||
(function(){
|
||||
var active=document.querySelector('.sidebar-item.active');
|
||||
if(!active)return;
|
||||
var sub=active.closest('.sidebar-subgroup');
|
||||
if(sub)sub.classList.add('open');
|
||||
})();
|
||||
|
||||
/* 弹窗开关 */
|
||||
function openModal(id){ document.getElementById(id).classList.add('open'); }
|
||||
function closeModal(id){ document.getElementById(id).classList.remove('open'); }
|
||||
|
||||
@@ -204,6 +204,7 @@
|
||||
<a href="config-standard-hospital.html" class="sidebar-item">医院体检项目</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="agent-device.html" class="sidebar-item">前置机管理</a>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
|
||||
@@ -171,6 +171,7 @@
|
||||
<a href="config-standard-hospital.html" class="sidebar-item">医院体检项目</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="agent-device.html" class="sidebar-item">前置机管理</a>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
|
||||
@@ -166,6 +166,7 @@
|
||||
<a href="config-standard-hospital.html" class="sidebar-item">医院体检项目</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="agent-device.html" class="sidebar-item">前置机管理</a>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
|
||||
@@ -198,6 +198,7 @@
|
||||
<a href="config-standard-hospital.html" class="sidebar-item">医院体检项目</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="agent-device.html" class="sidebar-item">前置机管理</a>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
|
||||
@@ -208,6 +208,7 @@
|
||||
<a href="config-standard-hospital.html" class="sidebar-item">医院体检项目</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="agent-device.html" class="sidebar-item">前置机管理</a>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
|
||||
@@ -215,6 +215,7 @@
|
||||
<a href="config-standard-hospital.html" class="sidebar-item">医院体检项目</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="agent-device.html" class="sidebar-item">前置机管理</a>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
|
||||
@@ -219,6 +219,7 @@
|
||||
<a href="config-standard-hospital.html" class="sidebar-item">医院体检项目</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="agent-device.html" class="sidebar-item">前置机管理</a>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
|
||||
@@ -160,6 +160,7 @@
|
||||
<a href="config-standard-hospital.html" class="sidebar-item active">医院体检项目</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="agent-device.html" class="sidebar-item">前置机管理</a>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# 健康体检模块 CHANGELOG
|
||||
|
||||
## [Unreleased] 2026-09-20
|
||||
|
||||
### Added
|
||||
- 检后「体检统计汇总」分组新增「结果动态综合统计」页面 `post-result-comprehensive-stat.html`:以 2×2 网格展示 4 张堆积柱状图,统计维度固定为性别/年龄/部门/岗位,每张图自带「项目」「维度」下拉可独立切换,查看该维度各取值下的正常/异常人数及占比——竖向堆积柱状图(X 轴为维度取值、Y 轴为人数,每柱正常在下绿/异常在上红堆叠,柱顶标总数、段内标百分比、悬停显示明细);纯手写 SVG,无第三方图表库;体检项目下拉 12 项数据驱动,异常判定按年龄/性别/岗位浮动、哈希保证结果稳定;4 个面板互相独立,默认项目均为血常规、维度分别为性别/年龄/部门/岗位
|
||||
- 23 个检后页面侧边栏「体检统计汇总」分组批量同步新增「结果动态综合统计」菜单项(紧邻「单位体检项目统计」之后)
|
||||
- `index.html` SITE_MAP 健康体检模块新增「结果动态综合统计」入口(紧邻「单位体检项目统计」之后)
|
||||
- `PRD.md`:补全缺失的「单位体检项目统计(post-unit-item-stat.html)」文档,新增「结果动态综合统计」导航节点/页面清单条目/逐页说明(52、53 节),页面清单与逐页说明 52 节及之后编号整体顺延 +2(原 52–68 → 54–70)
|
||||
- `PRD.md` 按实际页面补全 6 个此前未入册的页面文档并配截图——检中「体检预约跟踪(mid-appointment-track2.html,4 页签贯穿应检→已选→已预约→已参检)」、检后常规体检「单位群体报告(post-group-report.html,10 张概览卡含较上年趋势 + 6 个报告卡片)」、检后新增「体检影像管理」分组 4 页(用户体检信息/用户影像文件分类/用户影像文件详细/文件处理日志);导航树新增「体检影像管理」分组节点,页面清单与逐页说明编号顺延(33–45 → 34–46、46–67 → 48–69、68–70 → 74–76,新增 33/47/70–73 六节)
|
||||
- `screenshot-prd.js` TASKS 新增 6 页并重拍截图 `mid-appointment-track2 / post-group-report / post-imc-user / post-imc-class / post-imc-info / post-imc-log`
|
||||
|
||||
## [Unreleased] 2026-09-18
|
||||
|
||||
### Added
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
│ ├── 基础配置 → config-material-notice.html
|
||||
│ ├── 检前 → pre-hospital-scope.html
|
||||
│ ├── 检中 → mid-appointment-track.html
|
||||
│ │ ├── 体检预约跟踪 → mid-appointment-track2.html
|
||||
│ ├── 检后 → post-unit-count.html
|
||||
│ ├── 前置机管理 → agent-device.html
|
||||
│ └── 异常事件 → exception-dirty.html
|
||||
@@ -93,6 +94,7 @@
|
||||
├── 检后(侧边栏)
|
||||
│ ├── 常规体检
|
||||
│ │ ├── 常规体检报告 → post-report-employee.html
|
||||
│ │ ├── 单位群体报告 → post-group-report.html
|
||||
│ │ ├── 员工体检大表 → post-employee-master.html
|
||||
│ │ ├── 大病人员信息 → post-illness-personnel.html
|
||||
│ │ ├── 指标异常通知 → post-indicator-notify.html
|
||||
@@ -102,6 +104,8 @@
|
||||
│ │ │ └── Tab:二级单位 / 三级单位 / 体检医院
|
||||
│ │ ├── 单位体检费用统计 → post-unit-cost-stat.html
|
||||
│ │ │ └── Tab:二级单位 / 三级单位
|
||||
│ │ ├── 单位体检项目统计 → post-unit-item-stat.html
|
||||
│ │ ├── 项目结果综合统计 → post-result-comprehensive-stat.html
|
||||
│ │ ├── 医院体检人数统计 → post-hospital-count.html
|
||||
│ │ ├── 医生检查人数统计 → post-doctor-count.html
|
||||
│ │ ├── 医院体检项目统计 → post-item-stat.html
|
||||
@@ -117,10 +121,15 @@
|
||||
│ │ ├── 胃肠镜体检报告 → post-report-gastro.html
|
||||
│ │ └── 胃肠镜体检统计 → post-gastro-stat.html
|
||||
│ │ └── Tab:二级单位 / 三级单位
|
||||
│ └── 冠脉CTA体检
|
||||
│ ├── 冠脉CTA体检
|
||||
│ ├── 冠脉CTA体检报告 → post-cta-report.html
|
||||
│ └── 冠脉CTA体检统计 → post-cta-stat.html
|
||||
│ └── Tab:二级单位 / 三级单位
|
||||
│ └── 体检影像管理
|
||||
│ ├── 用户体检信息 → post-imc-user.html
|
||||
│ ├── 用户影像文件分类 → post-imc-class.html
|
||||
│ ├── 用户影像文件详细 → post-imc-info.html
|
||||
│ └── 文件处理日志 → post-imc-log.html
|
||||
│
|
||||
├── 前置机管理(侧边栏)
|
||||
│ └── 常规体检前置服务 → agent-device.html
|
||||
@@ -196,57 +205,65 @@
|
||||
| 序号 | 页面/弹窗 | 文件 | 类型 |
|
||||
|------|-----------|------|------|
|
||||
| 32 | 体检预约 | mid-appointment-track.html | 页面 |
|
||||
| 33 | 已选项目 | mid-selected-items.html | 页面 |
|
||||
| 34 | 已检员工 | mid-participation.html | 页面 |
|
||||
| 35 | 单位预约人数统计 | mid-unit-appointment.html | 页面 |
|
||||
| 36 | 医院实时预约人数 | mid-hospital-realtime.html | 页面 |
|
||||
| 37 | 医生实时检查情况 | mid-doctor-realtime.html | 页面 |
|
||||
| 38 | 医院预约人数统计 | mid-hospital-appointment.html | 页面 |
|
||||
| 39 | 签约单位应检人数 | mid-unit-expected.html | 页面 |
|
||||
| 40 | 员工预约跟踪(胃肠镜) | mid-gastro-appointment-track.html | 页面 |
|
||||
| 41 | 单位预约统计(胃肠镜) | mid-gastro-unit-appointment.html | 页面 |
|
||||
| 42 | 胃肠镜问卷信息 | mid-gastro-questionnaire.html | 页面 |
|
||||
| 43 | 员工预约跟踪(冠脉CTA) | mid-cta-appointment-track.html | 页面 |
|
||||
| 44 | 单位预约统计(冠脉CTA) | mid-cta-unit-appointment.html | 页面 |
|
||||
| 33 | 体检预约跟踪 | mid-appointment-track2.html | 页面 |
|
||||
| 34 | 已选项目 | mid-selected-items.html | 页面 |
|
||||
| 35 | 已检员工 | mid-participation.html | 页面 |
|
||||
| 36 | 单位预约人数统计 | mid-unit-appointment.html | 页面 |
|
||||
| 37 | 医院实时预约人数 | mid-hospital-realtime.html | 页面 |
|
||||
| 38 | 医生实时检查情况 | mid-doctor-realtime.html | 页面 |
|
||||
| 39 | 医院预约人数统计 | mid-hospital-appointment.html | 页面 |
|
||||
| 40 | 签约单位应检人数 | mid-unit-expected.html | 页面 |
|
||||
| 41 | 员工预约跟踪(胃肠镜) | mid-gastro-appointment-track.html | 页面 |
|
||||
| 42 | 单位预约统计(胃肠镜) | mid-gastro-unit-appointment.html | 页面 |
|
||||
| 43 | 胃肠镜问卷信息 | mid-gastro-questionnaire.html | 页面 |
|
||||
| 44 | 员工预约跟踪(冠脉CTA) | mid-cta-appointment-track.html | 页面 |
|
||||
| 45 | 单位预约统计(冠脉CTA) | mid-cta-unit-appointment.html | 页面 |
|
||||
|
||||
### 五、检后(侧边栏:检后)
|
||||
|
||||
| 序号 | 页面/弹窗 | 文件 | 类型 |
|
||||
|------|-----------|------|------|
|
||||
| 45 | 常规体检报告 | post-report-employee.html | 页面 |
|
||||
| 46 | 员工体检大表 | post-employee-master.html | 页面 |
|
||||
| 47 | 大病人员信息 | post-illness-personnel.html | 页面 |
|
||||
| 48 | 指标异常通知 | post-indicator-notify.html | 页面 |
|
||||
| 49 | 体检报告未匹配项目 | post-report-unmatched.html | 页面 |
|
||||
| 50 | 单位体检人数统计 | post-unit-count.html | 页面 |
|
||||
| 51 | 单位体检费用统计 | post-unit-cost-stat.html | 页面 |
|
||||
| 52 | 医院体检人数统计 | post-hospital-count.html | 页面 |
|
||||
| 53 | 医生检查人数统计 | post-doctor-count.html | 页面 |
|
||||
| 54 | 医院体检项目统计 | post-item-stat.html | 页面 |
|
||||
| 55 | 防癌筛查人数统计 | post-cancer-screening.html | 页面 |
|
||||
| 56 | 系统标准化项目统计 | post-standard-stat.html | 页面 |
|
||||
| 57 | 签约医院人数统计 | post-contracted-hospital.html | 页面 |
|
||||
| 58 | 重点指标异常统计 | post-key-indicator-stat.html | 页面 |
|
||||
| 59 | 病种信息配置 | post-disease-info.html | 页面 |
|
||||
| 60 | 体检结论关联病种 | post-conclusion-disease.html | 页面 |
|
||||
| 61 | 员工病种信息 | post-auto-select-disease.html | 页面 |
|
||||
| 62 | 胃肠镜体检报告 | post-report-gastro.html | 页面 |
|
||||
| 63 | 胃肠镜体检统计 | post-gastro-stat.html | 页面 |
|
||||
| 64 | 冠脉CTA体检报告 | post-cta-report.html | 页面 |
|
||||
| 65 | 冠脉CTA体检统计 | post-cta-stat.html | 页面 |
|
||||
| 46 | 常规体检报告 | post-report-employee.html | 页面 |
|
||||
| 47 | 单位群体报告 | post-group-report.html | 页面 |
|
||||
| 48 | 员工体检大表 | post-employee-master.html | 页面 |
|
||||
| 49 | 大病人员信息 | post-illness-personnel.html | 页面 |
|
||||
| 50 | 指标异常通知 | post-indicator-notify.html | 页面 |
|
||||
| 51 | 体检报告未匹配项目 | post-report-unmatched.html | 页面 |
|
||||
| 52 | 单位体检人数统计 | post-unit-count.html | 页面 |
|
||||
| 53 | 单位体检费用统计 | post-unit-cost-stat.html | 页面 |
|
||||
| 54 | 单位体检项目统计 | post-unit-item-stat.html | 页面 |
|
||||
| 55 | 项目结果综合统计 | post-result-comprehensive-stat.html | 页面 |
|
||||
| 56 | 医院体检人数统计 | post-hospital-count.html | 页面 |
|
||||
| 57 | 医生检查人数统计 | post-doctor-count.html | 页面 |
|
||||
| 58 | 医院体检项目统计 | post-item-stat.html | 页面 |
|
||||
| 59 | 防癌筛查人数统计 | post-cancer-screening.html | 页面 |
|
||||
| 60 | 系统标准化项目统计 | post-standard-stat.html | 页面 |
|
||||
| 61 | 签约医院人数统计 | post-contracted-hospital.html | 页面 |
|
||||
| 62 | 重点指标异常统计 | post-key-indicator-stat.html | 页面 |
|
||||
| 63 | 病种信息配置 | post-disease-info.html | 页面 |
|
||||
| 64 | 体检结论关联病种 | post-conclusion-disease.html | 页面 |
|
||||
| 65 | 员工病种信息 | post-auto-select-disease.html | 页面 |
|
||||
| 66 | 胃肠镜体检报告 | post-report-gastro.html | 页面 |
|
||||
| 67 | 胃肠镜体检统计 | post-gastro-stat.html | 页面 |
|
||||
| 68 | 冠脉CTA体检报告 | post-cta-report.html | 页面 |
|
||||
| 69 | 冠脉CTA体检统计 | post-cta-stat.html | 页面 |
|
||||
| 70 | 用户体检信息 | post-imc-user.html | 页面 |
|
||||
| 71 | 用户影像文件分类 | post-imc-class.html | 页面 |
|
||||
| 72 | 用户影像文件详细 | post-imc-info.html | 页面 |
|
||||
| 73 | 文件处理日志 | post-imc-log.html | 页面 |
|
||||
|
||||
### 六、前置机管理(侧边栏:前置机管理)
|
||||
|
||||
| 序号 | 页面/弹窗 | 文件 | 类型 |
|
||||
|------|-----------|------|------|
|
||||
| 66 | 常规体检前置服务(含设备详情/编辑设备/日志查看/升级管理/接口测试/操作审计/重启确认弹窗) | agent-device.html | 页面 |
|
||||
| 74 | 常规体检前置服务(含设备详情/编辑设备/日志查看/升级管理/接口测试/操作审计/重启确认弹窗) | agent-device.html | 页面 |
|
||||
|
||||
### 七、异常事件(侧边栏:异常事件)
|
||||
|
||||
| 序号 | 页面/弹窗 | 文件 | 类型 |
|
||||
|------|-----------|------|------|
|
||||
| 67 | 系统脏数据 | exception-dirty.html | 页面 |
|
||||
| 68 | 结果异常 | exception-result.html | 页面 |
|
||||
| 75 | 系统脏数据 | exception-dirty.html | 页面 |
|
||||
| 76 | 结果异常 | exception-result.html | 页面 |
|
||||
|
||||
---
|
||||
|
||||
@@ -978,7 +995,27 @@
|
||||
|
||||
---
|
||||
|
||||
#### 33. 已选项目(mid-selected-items.html)
|
||||
#### 33. 体检预约跟踪(mid-appointment-track2.html)
|
||||
|
||||

|
||||
|
||||
**功能说明:** 以 4 个页签纵向贯穿「应检 → 已选项目 → 已预约 → 已参检」的完整预约跟踪流程,支持批量状态流转与逐项置检/弃检。
|
||||
|
||||
**Tab 切换:** 所有员工 / 已选项目员工 / 已预约员工 / 已参检员工
|
||||
|
||||
**筛选条件:** 体检年份(年份选择控件,默认当年)、单位部门、医院选择、姓名、员工编号、身份证号,另有性别/年龄范围/机构分类/是否上市员工/防癌项/体检状态/预约状态/前置机预约状态(仅所有员工页签);已参检页签额外含体检编码、系统体检状态、医院体检状态、体检日期起止;各页签均带查询/重置
|
||||
|
||||
**操作按钮:** 所有员工——导出列表数据、查看导出任务、同步医院体检预约信息;已选项目员工——导出列表/项目/预约数据、查看导出任务;已预约员工——置为已体检、置为未体检、取消预约、导出列表/项目/预约数据、查看导出任务;已参检员工——导出项目状态、导出体检指引单、查看导出任务
|
||||
|
||||
**表格列(按页签):** 所有员工单级表头(姓名/员工编号/性别/年龄/身份证号/单位/部门/机构分类/体检编码/用工形式/婚姻状态/防癌项/是否上市员工/预约状态/前置机预约状态/预约日期/体检状态/体检日期/体检年份/体检计划/操作);已选项目员工两级表头(体检明细费用下分必检/选检/妇科/防癌筛查费用 4 子列,另含体检项目数/体检总费用/提交项目日期等);已预约员工单级表头(含体检编码/预约日期);已参检员工单级表头(含系统体检状态/医院体检状态/已检项/全部)
|
||||
|
||||
**详情弹窗(4 个页签各 1 个):** 所有员工「预约跟踪详情」(基本信息 + 预约与体检信息);已选项目员工(信息卡 + 已选项目列表含费用合计);已预约/已参检员工(信息卡 + 3 个 Tab:员工体检表信息/已体检项目/未体检项目,支持逐项置为已检/未检/弃检)
|
||||
|
||||
**业务规则:** 状态彩色标签(未预约橙/已预约绿/已取消红/未体检橙/体检中与已体检蓝);前置机预约状态独立枚举(未预约/预约成功/已取消预约/预约失败/预约中/取消预约失败);已预约页签批量置为已体检/未体检/取消预约需先勾选行;已参检员工区分系统体检状态与医院体检状态双口径。
|
||||
|
||||
---
|
||||
|
||||
#### 34. 已选项目(mid-selected-items.html)
|
||||
|
||||

|
||||
|
||||
@@ -1000,7 +1037,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 34. 已检员工(mid-participation.html)
|
||||
#### 35. 已检员工(mid-participation.html)
|
||||
|
||||

|
||||
|
||||
@@ -1020,7 +1057,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 35. 单位预约人数统计(mid-unit-appointment.html)
|
||||
#### 36. 单位预约人数统计(mid-unit-appointment.html)
|
||||
|
||||

|
||||
|
||||
@@ -1036,7 +1073,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 36. 医院实时预约人数(mid-hospital-realtime.html)
|
||||
#### 37. 医院实时预约人数(mid-hospital-realtime.html)
|
||||
|
||||

|
||||
|
||||
@@ -1050,7 +1087,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 37. 医生实时检查情况(mid-doctor-realtime.html)
|
||||
#### 38. 医生实时检查情况(mid-doctor-realtime.html)
|
||||
|
||||

|
||||
|
||||
@@ -1064,7 +1101,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 38. 医院预约人数统计(mid-hospital-appointment.html)
|
||||
#### 39. 医院预约人数统计(mid-hospital-appointment.html)
|
||||
|
||||

|
||||
|
||||
@@ -1078,7 +1115,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 39. 签约单位应检人数(mid-unit-expected.html)
|
||||
#### 40. 签约单位应检人数(mid-unit-expected.html)
|
||||
|
||||

|
||||
|
||||
@@ -1094,7 +1131,7 @@
|
||||
|
||||
### 胃肠镜体检
|
||||
|
||||
#### 40. 员工预约跟踪(胃肠镜)(mid-gastro-appointment-track.html)
|
||||
#### 41. 员工预约跟踪(胃肠镜)(mid-gastro-appointment-track.html)
|
||||
|
||||

|
||||
|
||||
@@ -1114,7 +1151,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 41. 单位预约统计(胃肠镜)(mid-gastro-unit-appointment.html)
|
||||
#### 42. 单位预约统计(胃肠镜)(mid-gastro-unit-appointment.html)
|
||||
|
||||

|
||||
|
||||
@@ -1130,7 +1167,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 42. 胃肠镜问卷信息(mid-gastro-questionnaire.html)
|
||||
#### 43. 胃肠镜问卷信息(mid-gastro-questionnaire.html)
|
||||
|
||||

|
||||
|
||||
@@ -1148,7 +1185,7 @@
|
||||
|
||||
### 冠脉CTA体检
|
||||
|
||||
#### 43. 员工预约跟踪(冠脉CTA)(mid-cta-appointment-track.html)
|
||||
#### 44. 员工预约跟踪(冠脉CTA)(mid-cta-appointment-track.html)
|
||||
|
||||

|
||||
|
||||
@@ -1157,7 +1194,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 44. 单位预约统计(冠脉CTA)(mid-cta-unit-appointment.html)
|
||||
#### 45. 单位预约统计(冠脉CTA)(mid-cta-unit-appointment.html)
|
||||
|
||||

|
||||
|
||||
@@ -1170,7 +1207,7 @@
|
||||
|
||||
### 常规体检
|
||||
|
||||
#### 45. 常规体检报告(post-report-employee.html)
|
||||
#### 46. 常规体检报告(post-report-employee.html)
|
||||
|
||||

|
||||
|
||||
@@ -1190,7 +1227,25 @@
|
||||
|
||||
---
|
||||
|
||||
#### 46. 员工体检大表(post-employee-master.html)
|
||||
#### 47. 单位群体报告(post-group-report.html)
|
||||
|
||||

|
||||
|
||||
**功能说明:** 选定某单位与体检年份后,以概览指标卡 + 图表 + 表格呈现该单位群体体检的受检/检出/异常/疾病/专项筛查情况,并支持导出 CSV。
|
||||
|
||||
**筛选条件:** 体检年份(年份选择控件,默认当年)、单位(左侧列表,含单位名称模糊搜索)
|
||||
|
||||
**操作按钮:** 导出群体报告(导出 CSV)
|
||||
|
||||
**概览指标卡(5 列 × 2 行共 10 张):** 应检人数、已检人数、受检率(绿)、检出率(橙)、异常人数(红)、重点指标异常(红)、复查率、数据完整率、平均年龄、未见异常(绿);每张卡下方带「较上年」趋势标注(率类 ±X.Xpp、人数/年龄类整数 + 单位,按指标方向判定绿 good/红 bad/灰 flat)
|
||||
|
||||
**报告卡片(6 个):** ① 近三年趋势(受检率/检出率双折线图);② 异常率 × 年龄/性别(表:年龄区间/男性异常率/女性异常率/合计异常率/异常人数,含合计行);③ 异常指标排名(横向条形,按检出人数降序,top1 红/top2 橙/top3 绿、其余蓝,附上年对照与趋势);④ 重点指标异常拆解(表:重点指标/异常人数/检出率/较上年,5 项:血压/血脂/空腹血糖/高尿酸/超重 BMI);⑤ 疾病(病种)分布(按 8 类病种分组归类,表列:病种/人数/占比/较上年);⑥ 专项筛查结果(防癌筛查 Septin9、CA724、冠脉 CTA、胃肠镜 4 项,阳性/异常率 + 已筛人数 + 较上年)
|
||||
|
||||
**业务规则:** 受检率 = 已检 ÷ 应检、检出率 = 异常 ÷ 已检,各率保留 1 位小数、除数为 0 显示 0.0%;同单位同一年数据恒定(确定性伪随机);报告头元信息含体检年份/承检医院/体检计划起止/同比基准上一年。
|
||||
|
||||
---
|
||||
|
||||
#### 48. 员工体检大表(post-employee-master.html)
|
||||
|
||||

|
||||
|
||||
@@ -1211,7 +1266,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 47. 大病人员信息(post-illness-personnel.html)
|
||||
#### 49. 大病人员信息(post-illness-personnel.html)
|
||||
|
||||

|
||||
|
||||
@@ -1235,7 +1290,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 48. 指标异常通知(post-indicator-notify.html)
|
||||
#### 50. 指标异常通知(post-indicator-notify.html)
|
||||
|
||||

|
||||
|
||||
@@ -1251,7 +1306,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 49. 体检报告未匹配项目(post-report-unmatched.html)
|
||||
#### 51. 体检报告未匹配项目(post-report-unmatched.html)
|
||||
|
||||

|
||||
|
||||
@@ -1267,7 +1322,7 @@
|
||||
|
||||
### 体检统计汇总
|
||||
|
||||
#### 50. 单位体检人数统计(post-unit-count.html)
|
||||
#### 52. 单位体检人数统计(post-unit-count.html)
|
||||
|
||||

|
||||
|
||||
@@ -1291,7 +1346,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 51. 单位体检费用统计(post-unit-cost-stat.html)
|
||||
#### 53. 单位体检费用统计(post-unit-cost-stat.html)
|
||||
|
||||

|
||||
|
||||
@@ -1317,7 +1372,39 @@
|
||||
|
||||
---
|
||||
|
||||
#### 52. 医院体检人数统计(post-hospital-count.html)
|
||||
#### 54. 单位体检项目统计(post-unit-item-stat.html)
|
||||
|
||||

|
||||
|
||||
**功能说明:** 按"单位 × 体检医院 × 体检项目"维度统计各体检项目的已选/已检/异常人数及患病率,人数列可点击下钻查看对应人员明细。
|
||||
|
||||
**筛选条件:** 体检年份(年份日历选择控件,默认当年)、单位(下拉)、医院(下拉)、项目名称(输入)、项目编码(输入)
|
||||
|
||||
**操作按钮:** 导出列表数据、查看导出任务
|
||||
|
||||
**表格列:** 序号、单位、体检医院、体检项目名称、项目编码、已选人数、已检人数、异常人数、患病率
|
||||
|
||||
**业务规则:** 患病率 = 异常人数 ÷ 已检人数,患病率 ≥10% 标红;已选/已检/异常三列数字为蓝色链接,点击打开对应口径人员列表弹窗(列:序号、姓名、员工编号、部门、体检医院、体检日期、体检状态/体检结果/异常结果)。
|
||||
|
||||
---
|
||||
|
||||
#### 55. 项目结果综合统计(post-result-comprehensive-stat.html)
|
||||
|
||||

|
||||
|
||||
**功能说明:** 以 2×2 网格展示 4 张堆积柱状图,统计维度固定为性别/年龄/部门/岗位;每张图自带「项目」「维度」两个下拉,可独立切换体检项目与统计维度,查看该维度各取值下的正常/异常人数及占比。
|
||||
|
||||
**筛选条件:** 体检年份(年份日历选择控件,默认当年)、单位(下拉,默认第一采油厂)
|
||||
|
||||
**图表面板:** 每个面板顶部为标题 + 项目下拉(12 项)+ 维度下拉(性别/年龄/部门/岗位)+ 正常/异常图例,下方为竖向堆积柱状图。
|
||||
|
||||
**图表展示:** 竖向堆积柱状图——X 轴为所选维度取值(性别→男/女、年龄→各年龄段、部门→各部门、岗位→各岗位),Y 轴为人数;每根柱子正常在下(绿)/异常在上(红)堆叠,柱顶标总数、段内标百分比,悬停显示明细。
|
||||
|
||||
**业务规则:** 4 个面板互相独立,默认项目均为血常规、维度分别为性别/年龄/部门/岗位;异常率 = 异常人数 ÷ 受检人数;维度取值(性别男/女、年龄 5 档、部门 6 个、岗位 6 个)。
|
||||
|
||||
---
|
||||
|
||||
#### 56. 医院体检人数统计(post-hospital-count.html)
|
||||
|
||||

|
||||
|
||||
@@ -1331,7 +1418,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 53. 医生检查人数统计(post-doctor-count.html)
|
||||
#### 57. 医生检查人数统计(post-doctor-count.html)
|
||||
|
||||

|
||||
|
||||
@@ -1345,7 +1432,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 54. 医院体检项目统计(post-item-stat.html)
|
||||
#### 58. 医院体检项目统计(post-item-stat.html)
|
||||
|
||||

|
||||
|
||||
@@ -1359,7 +1446,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 55. 防癌筛查人数统计(post-cancer-screening.html)
|
||||
#### 59. 防癌筛查人数统计(post-cancer-screening.html)
|
||||
|
||||

|
||||
|
||||
@@ -1373,7 +1460,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 56. 系统标准化项目统计(post-standard-stat.html)
|
||||
#### 60. 系统标准化项目统计(post-standard-stat.html)
|
||||
|
||||

|
||||
|
||||
@@ -1387,7 +1474,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 57. 签约医院人数统计(post-contracted-hospital.html)
|
||||
#### 61. 签约医院人数统计(post-contracted-hospital.html)
|
||||
|
||||

|
||||
|
||||
@@ -1401,7 +1488,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 58. 重点指标异常统计(post-key-indicator-stat.html)
|
||||
#### 62. 重点指标异常统计(post-key-indicator-stat.html)
|
||||
|
||||

|
||||
|
||||
@@ -1421,7 +1508,7 @@
|
||||
|
||||
### 病种信息管理
|
||||
|
||||
#### 59. 病种信息配置(post-disease-info.html)
|
||||
#### 63. 病种信息配置(post-disease-info.html)
|
||||
|
||||

|
||||
|
||||
@@ -1441,7 +1528,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 60. 体检结论关联病种(post-conclusion-disease.html)
|
||||
#### 64. 体检结论关联病种(post-conclusion-disease.html)
|
||||
|
||||

|
||||
|
||||
@@ -1461,7 +1548,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 61. 员工病种信息(post-auto-select-disease.html)
|
||||
#### 65. 员工病种信息(post-auto-select-disease.html)
|
||||
|
||||

|
||||
|
||||
@@ -1484,7 +1571,7 @@
|
||||
|
||||
### 胃肠镜体检
|
||||
|
||||
#### 62. 胃肠镜体检报告(post-report-gastro.html)
|
||||
#### 66. 胃肠镜体检报告(post-report-gastro.html)
|
||||
|
||||

|
||||
|
||||
@@ -1519,7 +1606,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 63. 胃肠镜体检统计(post-gastro-stat.html)
|
||||
#### 67. 胃肠镜体检统计(post-gastro-stat.html)
|
||||
|
||||

|
||||
|
||||
@@ -1542,7 +1629,7 @@
|
||||
|
||||
### 冠脉CTA体检
|
||||
|
||||
#### 64. 冠脉CTA体检报告(post-cta-report.html)
|
||||
#### 68. 冠脉CTA体检报告(post-cta-report.html)
|
||||
|
||||

|
||||
|
||||
@@ -1572,7 +1659,7 @@
|
||||
|
||||
---
|
||||
|
||||
#### 65. 冠脉CTA体检统计(post-cta-stat.html)
|
||||
#### 69. 冠脉CTA体检统计(post-cta-stat.html)
|
||||
|
||||

|
||||
|
||||
@@ -1582,9 +1669,85 @@
|
||||
|
||||
---
|
||||
|
||||
### 体检影像管理
|
||||
|
||||
#### 70. 用户体检信息(post-imc-user.html)
|
||||
|
||||

|
||||
|
||||
**功能说明:** 以「人」为维度聚合展示用户体检影像信息,行内可展开查看该人各项检查项目的影像与报告处理情况。
|
||||
|
||||
**筛选条件:** 姓名、身份证号、体检年份(年份选择控件,默认当年)、医院名称
|
||||
|
||||
**操作按钮:** 批量删除
|
||||
|
||||
**表格列:** 复选框、序号、展开箭头列、单位信息、姓名、身份证号、体检年份、医院名称、体检编号、创建日期、操作(删除)
|
||||
|
||||
**展开子表列:** 序号、检查项目名称、处理状态、影像信息、影像报告;影像信息列渲染「预览」链接(无数据显示「暂无」)、影像报告列渲染「查看」链接(无数据显示「无文件」)、子表无数据显示「暂无检查项目数据」
|
||||
|
||||
**业务规则:** 姓名/身份证号/医院名称为模糊匹配、体检年份精确匹配;分页 10/20/50 条/页;删除/批量删除带确认。
|
||||
|
||||
---
|
||||
|
||||
#### 71. 用户影像文件分类(post-imc-class.html)
|
||||
|
||||

|
||||
|
||||
**功能说明:** 按「检查项目」维度展示影像文件与报告文件的类型分类、处理状态与结果。
|
||||
|
||||
**筛选条件:** 影像分类(超声/CT/MRI/X射线/心电)、检查项目名称、处理状态
|
||||
|
||||
**操作按钮:** 批量删除
|
||||
|
||||
**表格列:** 复选框、序号、影像分类、检查项目名称、影像文件类型、报告文件类型、处理状态、检查结果、错误信息、出报告时间、创建日期、操作(详情 + 删除)
|
||||
|
||||
**详情弹窗:** 标题「用户影像文件分类详情」,字段:用户体检信息ID、影像分类、检查项目名称、影像文件类型、报告文件类型、处理状态、检查结果、错误信息、出报告时间、创建日期
|
||||
|
||||
**业务规则:** 检查结果/错误信息超 18 字符截断并悬停显示全文、空值显示「—」;影像文件类型 dcm/非DICOM、报告文件类型 pdf/png/jpg。
|
||||
|
||||
---
|
||||
|
||||
#### 72. 用户影像文件详细(post-imc-info.html)
|
||||
|
||||

|
||||
|
||||
**功能说明:** 文件级别的影像/报告明细,展示单个文件的存储地址、DICOM 实例与研究/患者标识。
|
||||
|
||||
**筛选条件:** 文件类型(影像/报告)、患者ID、研究实例ID
|
||||
|
||||
**操作按钮:** 批量删除
|
||||
|
||||
**表格列:** 复选框、序号、文件类型(影像蓝标签/报告紫标签)、影像序号、错误信息、文件地址(下载链接)、dcm实例ID、研究实例ID、患者ID、研究ID、创建日期、操作(详情 + 删除)
|
||||
|
||||
**详情弹窗:** 标题「用户影像文件详细」,字段:用户影像文件分类ID、文件类型、影像序号、错误信息、文件地址、dcm实例ID、研究实例ID、患者ID、研究ID、创建日期
|
||||
|
||||
**业务规则:** 错误信息超 18 字符截断并悬停全文;患者ID/dcm实例ID/错误信息可为空(空显示「—」,报告的 dcm实例ID 恒为空)。
|
||||
|
||||
---
|
||||
|
||||
#### 73. 文件处理日志(post-imc-log.html)
|
||||
|
||||

|
||||
|
||||
**功能说明:** 展示影像压缩包的传输、解析全过程日志(时间线 + 状态 + 原始 json)。
|
||||
|
||||
**筛选条件:** 身份证号、体检年份(年份选择控件)、体检编号、影像分类(超声/CT/MRI/X射线/心电)、处理状态
|
||||
|
||||
**操作按钮:** 批量删除
|
||||
|
||||
**表格列:** 复选框、序号、医院名称、姓名、身份证号、体检年份、体检编号、影像分类、json数据、文件地址(下载链接)、文件大小(MB)、处理状态、错误信息、传输开始时间、传输完成时间、解析开始时间、解析完成时间、操作(详情 + 删除)
|
||||
|
||||
**详情弹窗:** 标题「文件处理日志详情」,字段含医院名称/姓名/身份证号/体检年份/体检编号/影像分类/json 数据(代码块展示)/文件地址/文件大小(MB)/处理状态/错误信息/传输开始/传输完成/解析开始/解析完成时间
|
||||
|
||||
**业务规则:** json 数据超 24 字符截断为等宽字体并悬停全文、详情弹窗内 json 代码块可滚动;错误信息超 18 字符截断;空时间显示「—」;示例数据按传输开始时间倒序。
|
||||
|
||||
**数据字典(四页通用):** 处理状态 1 新建(蓝)/2 待解析(灰)/3 失败(红)/4 解析中(橙)/5 成功(绿)/6 失败待重试(橙)/7 最终失败(红)。
|
||||
|
||||
---
|
||||
|
||||
## 六、前置机管理
|
||||
|
||||
### 66. 常规体检前置服务(agent-device.html)
|
||||
### 74. 常规体检前置服务(agent-device.html)
|
||||
|
||||

|
||||
|
||||
@@ -1625,7 +1788,7 @@
|
||||
|
||||
## 七、异常事件
|
||||
|
||||
### 67. 系统脏数据(exception-dirty.html)
|
||||
### 75. 系统脏数据(exception-dirty.html)
|
||||
|
||||

|
||||
|
||||
@@ -1643,7 +1806,7 @@
|
||||
|
||||
---
|
||||
|
||||
### 68. 结果异常(exception-result.html)
|
||||
### 76. 结果异常(exception-result.html)
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ const TASKS = [
|
||||
{ page: 'pre-special-cta.html', output: 'pre-special-cta.jpg' },
|
||||
// 四、检中 · 常规体检
|
||||
{ page: 'mid-appointment-track.html', output: 'mid-appointment-track.jpg' },
|
||||
{ page: 'mid-appointment-track2.html', output: 'mid-appointment-track2.jpg' },
|
||||
{ page: 'mid-selected-items.html', output: 'mid-selected-items.jpg' },
|
||||
{ page: 'mid-participation.html', output: 'mid-participation.jpg' },
|
||||
{ page: 'mid-unit-appointment.html', output: 'mid-unit-appointment.jpg' },
|
||||
@@ -71,6 +72,7 @@ const TASKS = [
|
||||
{ page: 'mid-cta-unit-appointment.html', output: 'mid-cta-unit-appointment.jpg' },
|
||||
// 五、检后 · 常规体检
|
||||
{ page: 'post-report-employee.html', output: 'post-report-employee.jpg' },
|
||||
{ page: 'post-group-report.html', output: 'post-group-report.jpg' },
|
||||
{ page: 'post-employee-master.html', output: 'post-employee-master.jpg' },
|
||||
{ page: 'post-illness-personnel.html', output: 'post-illness-personnel.jpg' },
|
||||
{ page: 'post-indicator-notify.html', output: 'post-indicator-notify.jpg' },
|
||||
@@ -78,6 +80,8 @@ const TASKS = [
|
||||
// 五、检后 · 体检统计汇总
|
||||
{ page: 'post-unit-count.html', output: 'post-unit-count.jpg' },
|
||||
{ page: 'post-unit-cost-stat.html', output: 'post-unit-cost-stat.jpg' },
|
||||
{ page: 'post-unit-item-stat.html', output: 'post-unit-item-stat.jpg' },
|
||||
{ page: 'post-result-comprehensive-stat.html', output: 'post-result-comprehensive-stat.jpg' },
|
||||
{ page: 'post-hospital-count.html', output: 'post-hospital-count.jpg' },
|
||||
{ page: 'post-doctor-count.html', output: 'post-doctor-count.jpg' },
|
||||
{ page: 'post-item-stat.html', output: 'post-item-stat.jpg' },
|
||||
@@ -95,6 +99,11 @@ const TASKS = [
|
||||
// 五、检后 · 冠脉CTA体检
|
||||
{ page: 'post-cta-report.html', output: 'post-cta-report.jpg' },
|
||||
{ page: 'post-cta-stat.html', output: 'post-cta-stat.jpg' },
|
||||
// 五、检后 · 体检影像管理
|
||||
{ page: 'post-imc-user.html', output: 'post-imc-user.jpg' },
|
||||
{ page: 'post-imc-class.html', output: 'post-imc-class.jpg' },
|
||||
{ page: 'post-imc-info.html', output: 'post-imc-info.jpg' },
|
||||
{ page: 'post-imc-log.html', output: 'post-imc-log.jpg' },
|
||||
// 六、异常事件
|
||||
{ page: 'exception-dirty.html', output: 'exception-dirty.jpg' },
|
||||
{ page: 'exception-result.html', output: 'exception-result.jpg' },
|
||||
|
||||
|
After Width: | Height: | Size: 131 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 310 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 115 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 181 KiB |
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 216 KiB |
@@ -158,9 +158,9 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="mid-appointment-track.html" class="sidebar-item active">体检预约</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-selected-items.html" class="sidebar-item">已选项目</a>
|
||||
<a href="mid-participation.html" class="sidebar-item">已检员工</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-unit-appointment.html" class="sidebar-item">单位预约人数统计</a>
|
||||
<a href="mid-hospital-realtime.html" class="sidebar-item">医院实时预约人数</a>
|
||||
<a href="mid-doctor-realtime.html" class="sidebar-item">医生实时检查情况</a>
|
||||
|
||||
@@ -184,9 +184,9 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="mid-appointment-track.html" class="sidebar-item">体检预约</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item active">体检预约跟踪</a>
|
||||
<a href="mid-selected-items.html" class="sidebar-item">已选项目</a>
|
||||
<a href="mid-participation.html" class="sidebar-item">已检员工</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item active">体检预约跟踪</a>
|
||||
<a href="mid-unit-appointment.html" class="sidebar-item">单位预约人数统计</a>
|
||||
<a href="mid-hospital-realtime.html" class="sidebar-item">医院实时预约人数</a>
|
||||
<a href="mid-doctor-realtime.html" class="sidebar-item">医生实时检查情况</a>
|
||||
|
||||
@@ -151,9 +151,9 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="mid-appointment-track.html" class="sidebar-item">体检预约</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-selected-items.html" class="sidebar-item">已选项目</a>
|
||||
<a href="mid-participation.html" class="sidebar-item">已检员工</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-unit-appointment.html" class="sidebar-item">单位预约人数统计</a>
|
||||
<a href="mid-hospital-realtime.html" class="sidebar-item">医院实时预约人数</a>
|
||||
<a href="mid-doctor-realtime.html" class="sidebar-item">医生实时检查情况</a>
|
||||
|
||||
@@ -125,9 +125,9 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="mid-appointment-track.html" class="sidebar-item">体检预约</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-selected-items.html" class="sidebar-item">已选项目</a>
|
||||
<a href="mid-participation.html" class="sidebar-item">已检员工</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-unit-appointment.html" class="sidebar-item">单位预约人数统计</a>
|
||||
<a href="mid-hospital-realtime.html" class="sidebar-item">医院实时预约人数</a>
|
||||
<a href="mid-doctor-realtime.html" class="sidebar-item">医生实时检查情况</a>
|
||||
|
||||
@@ -129,9 +129,9 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="mid-appointment-track.html" class="sidebar-item">体检预约</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-selected-items.html" class="sidebar-item">已选项目</a>
|
||||
<a href="mid-participation.html" class="sidebar-item">已检员工</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-unit-appointment.html" class="sidebar-item">单位预约人数统计</a>
|
||||
<a href="mid-hospital-realtime.html" class="sidebar-item">医院实时预约人数</a>
|
||||
<a href="mid-doctor-realtime.html" class="sidebar-item active">医生实时检查情况</a>
|
||||
|
||||
@@ -151,9 +151,9 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="mid-appointment-track.html" class="sidebar-item">体检预约</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-selected-items.html" class="sidebar-item">已选项目</a>
|
||||
<a href="mid-participation.html" class="sidebar-item">已检员工</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-unit-appointment.html" class="sidebar-item">单位预约人数统计</a>
|
||||
<a href="mid-hospital-realtime.html" class="sidebar-item">医院实时预约人数</a>
|
||||
<a href="mid-doctor-realtime.html" class="sidebar-item">医生实时检查情况</a>
|
||||
|
||||
@@ -130,9 +130,9 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="mid-appointment-track.html" class="sidebar-item">体检预约</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-selected-items.html" class="sidebar-item">已选项目</a>
|
||||
<a href="mid-participation.html" class="sidebar-item">已检员工</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-unit-appointment.html" class="sidebar-item">单位预约人数统计</a>
|
||||
<a href="mid-hospital-realtime.html" class="sidebar-item">医院实时预约人数</a>
|
||||
<a href="mid-doctor-realtime.html" class="sidebar-item">医生实时检查情况</a>
|
||||
|
||||
@@ -125,9 +125,9 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="mid-appointment-track.html" class="sidebar-item">体检预约</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-selected-items.html" class="sidebar-item">已选项目</a>
|
||||
<a href="mid-participation.html" class="sidebar-item">已检员工</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-unit-appointment.html" class="sidebar-item">单位预约人数统计</a>
|
||||
<a href="mid-hospital-realtime.html" class="sidebar-item">医院实时预约人数</a>
|
||||
<a href="mid-doctor-realtime.html" class="sidebar-item">医生实时检查情况</a>
|
||||
|
||||
@@ -125,9 +125,9 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="mid-appointment-track.html" class="sidebar-item">体检预约</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-selected-items.html" class="sidebar-item">已选项目</a>
|
||||
<a href="mid-participation.html" class="sidebar-item">已检员工</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-unit-appointment.html" class="sidebar-item">单位预约人数统计</a>
|
||||
<a href="mid-hospital-realtime.html" class="sidebar-item">医院实时预约人数</a>
|
||||
<a href="mid-doctor-realtime.html" class="sidebar-item">医生实时检查情况</a>
|
||||
|
||||
@@ -129,9 +129,9 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="mid-appointment-track.html" class="sidebar-item">体检预约</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-selected-items.html" class="sidebar-item">已选项目</a>
|
||||
<a href="mid-participation.html" class="sidebar-item">已检员工</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-unit-appointment.html" class="sidebar-item">单位预约人数统计</a>
|
||||
<a href="mid-hospital-realtime.html" class="sidebar-item active">医院实时预约人数</a>
|
||||
<a href="mid-doctor-realtime.html" class="sidebar-item">医生实时检查情况</a>
|
||||
|
||||
@@ -148,9 +148,9 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="mid-appointment-track.html" class="sidebar-item">体检预约</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-selected-items.html" class="sidebar-item">已选项目</a>
|
||||
<a href="mid-participation.html" class="sidebar-item active">已检员工</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-unit-appointment.html" class="sidebar-item">单位预约人数统计</a>
|
||||
<a href="mid-hospital-realtime.html" class="sidebar-item">医院实时预约人数</a>
|
||||
<a href="mid-doctor-realtime.html" class="sidebar-item">医生实时检查情况</a>
|
||||
|
||||
@@ -148,9 +148,9 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="mid-appointment-track.html" class="sidebar-item">体检预约</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-selected-items.html" class="sidebar-item active">已选项目</a>
|
||||
<a href="mid-participation.html" class="sidebar-item">已检员工</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-unit-appointment.html" class="sidebar-item">单位预约人数统计</a>
|
||||
<a href="mid-hospital-realtime.html" class="sidebar-item">医院实时预约人数</a>
|
||||
<a href="mid-doctor-realtime.html" class="sidebar-item">医生实时检查情况</a>
|
||||
|
||||
@@ -134,9 +134,9 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="mid-appointment-track.html" class="sidebar-item">体检预约</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-selected-items.html" class="sidebar-item">已选项目</a>
|
||||
<a href="mid-participation.html" class="sidebar-item">已检员工</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-unit-appointment.html" class="sidebar-item active">单位预约人数统计</a>
|
||||
<a href="mid-hospital-realtime.html" class="sidebar-item">医院实时预约人数</a>
|
||||
<a href="mid-doctor-realtime.html" class="sidebar-item">医生实时检查情况</a>
|
||||
|
||||
@@ -114,9 +114,9 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="mid-appointment-track.html" class="sidebar-item">体检预约</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-selected-items.html" class="sidebar-item">已选项目</a>
|
||||
<a href="mid-participation.html" class="sidebar-item">已检员工</a>
|
||||
<a href="mid-appointment-track2.html" class="sidebar-item">体检预约跟踪</a>
|
||||
<a href="mid-unit-appointment.html" class="sidebar-item">单位预约人数统计</a>
|
||||
<a href="mid-hospital-realtime.html" class="sidebar-item">医院实时预约人数</a>
|
||||
<a href="mid-doctor-realtime.html" class="sidebar-item">医生实时检查情况</a>
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -158,6 +158,7 @@
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -186,7 +187,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -196,7 +197,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -142,6 +142,7 @@
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -170,7 +171,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -180,7 +181,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -168,6 +168,7 @@
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -196,7 +197,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -206,7 +207,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -132,6 +132,7 @@
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -160,7 +161,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -170,7 +171,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -199,6 +199,7 @@
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -227,7 +228,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -237,7 +238,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item active">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item active">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -158,6 +158,7 @@
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -186,7 +187,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -196,7 +197,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item active">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -166,6 +166,7 @@
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -194,7 +195,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -204,7 +205,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -142,6 +142,7 @@
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item active">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -170,7 +171,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -180,7 +181,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -105,6 +105,20 @@
|
||||
.year-picker__dropdown div{padding:8px 14px;font-size:var(--font-sm);cursor:pointer;}
|
||||
.year-picker__dropdown div:hover{background:var(--primary-light);}
|
||||
.year-picker__dropdown div.selected{color:var(--primary);font-weight:600;}
|
||||
/* 高级查询 */
|
||||
.adv-panel{background:#fff;border-radius:var(--radius-md);padding:16px 24px;margin-bottom:16px;box-shadow:var(--shadow-sm);display:none;}
|
||||
.adv-panel.open{display:block;}
|
||||
.adv-panel__head{font-size:var(--font-base);font-weight:600;margin-bottom:12px;}
|
||||
.adv-cond-row{display:flex;align-items:center;gap:8px;margin-bottom:10px;}
|
||||
.adv-field{min-width:210px;}
|
||||
.adv-op{min-width:90px;}
|
||||
.adv-value-wrap{display:flex;align-items:center;gap:8px;flex:1;max-width:440px;}
|
||||
.adv-value{flex:1;min-width:0;}
|
||||
.adv-range-sep{color:var(--text-secondary);flex-shrink:0;}
|
||||
.adv-del{width:32px;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);background:#fff;color:var(--text-secondary);cursor:pointer;flex-shrink:0;font-size:var(--font-sm);line-height:1;}
|
||||
.adv-del:hover{color:var(--danger);border-color:var(--danger);}
|
||||
.adv-actions{display:flex;gap:12px;margin-top:2px;}
|
||||
.adv-arrow{font-size:10px;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -142,7 +156,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item active">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -158,6 +172,7 @@
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -186,7 +201,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -196,7 +211,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -258,6 +273,18 @@
|
||||
</div>
|
||||
<button class="btn btn-primary" onclick="applyFilter()">查询</button>
|
||||
<button class="btn btn-default" onclick="resetFilter()">重置</button>
|
||||
<button class="btn btn-default" id="advToggle" onclick="toggleAdvanced()">高级查询 <span class="adv-arrow">▾</span></button>
|
||||
</div>
|
||||
|
||||
<!-- 高级查询 -->
|
||||
<div class="adv-panel" id="advPanel">
|
||||
<div class="adv-panel__head">高级查询</div>
|
||||
<div id="advConditions"></div>
|
||||
<div class="adv-actions">
|
||||
<button class="btn btn-default" onclick="addAdvCondition()">+ 添加条件</button>
|
||||
<button class="btn btn-primary" onclick="applyFilter()">查询</button>
|
||||
<button class="btn btn-default" onclick="clearAdvanced()">清空</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作栏 -->
|
||||
@@ -531,21 +558,130 @@ function hasAbnormal(r){
|
||||
for(var k in r.r){if(r.r[k][1])return true;}
|
||||
return false;
|
||||
}
|
||||
/* 按筛选条件取当前展示行:异常员工 + 姓名/员工编号/身份证号模糊匹配 */
|
||||
/* 按筛选条件取当前展示行:异常员工 + 姓名/员工编号/身份证号模糊匹配 + 高级查询条件 */
|
||||
function getDisplayRows(){
|
||||
var v=document.getElementById('abnormalFilter').value;
|
||||
var name=document.getElementById('fName').value.trim();
|
||||
var empNo=document.getElementById('fEmpNo').value.trim();
|
||||
var idCard=document.getElementById('fIdCard').value.trim();
|
||||
var conds=readAdvancedConditions();
|
||||
return MASTER_ROWS.filter(function(r){
|
||||
if(v==='abnormal'&&!hasAbnormal(r))return false;
|
||||
if(v==='normal'&&hasAbnormal(r))return false;
|
||||
if(name&&r.name.indexOf(name)<0)return false;
|
||||
if(empNo&&r.empNo.indexOf(empNo)<0)return false;
|
||||
if(idCard&&r.idCard.indexOf(idCard)<0)return false;
|
||||
for(var i=0;i<conds.length;i++){if(!matchCondition(r,conds[i]))return false;}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
/* ============ 高级查询 ============ */
|
||||
var ADV_OPS=['包含','=','!=','>','>=','<','<=','范围'];
|
||||
var ADV_FIELD_OPTS='';
|
||||
/* 字段下拉选项:基本信息 + 全部体检项目(按一级分类分组,二级分类·项目名 去重) */
|
||||
function buildAdvFieldOpts(){
|
||||
var o='<optgroup label="基本信息">';
|
||||
BASE_COLS.forEach(function(c){if(c.key!=='idx')o+='<option value="'+c.key+'">'+c.label+'</option>';});
|
||||
o+='</optgroup>';
|
||||
ITEM_TREE.forEach(function(g){
|
||||
o+='<optgroup label="'+g.lvl1+'">';
|
||||
g.lvl2.forEach(function(s){
|
||||
s.items.forEach(function(it){o+='<option value="'+s.name+'|'+it+'">'+s.name+'·'+it+'</option>';});
|
||||
});
|
||||
o+='</optgroup>';
|
||||
});
|
||||
return o;
|
||||
}
|
||||
function advConditionRowHTML(){
|
||||
return '<div class="adv-cond-row">'
|
||||
+'<select class="filter-select adv-field">'+ADV_FIELD_OPTS+'</select>'
|
||||
+'<select class="filter-select adv-op" onchange="onAdvOpChange(this)">'+ADV_OPS.map(function(o){return '<option value="'+o+'">'+o+'</option>';}).join('')+'</select>'
|
||||
+'<span class="adv-value-wrap"><input class="filter-input adv-value" type="text" placeholder="请输入值"></span>'
|
||||
+'<button class="adv-del" type="button" title="删除该条件" onclick="removeAdvCondition(this)">✕</button>'
|
||||
+'</div>';
|
||||
}
|
||||
/* 运算符切换为"范围"时,值区域变成最小/最大两个输入框 */
|
||||
function onAdvOpChange(sel){
|
||||
var wrap=sel.parentElement.querySelector('.adv-value-wrap');
|
||||
var isRange=sel.value==='范围';
|
||||
var alreadyRange=!!wrap.querySelector('.adv-range-from');
|
||||
if(isRange&&!alreadyRange){
|
||||
wrap.innerHTML='<input class="filter-input adv-value adv-range-from" type="text" placeholder="最小值">'
|
||||
+'<span class="adv-range-sep">~</span>'
|
||||
+'<input class="filter-input adv-value adv-range-to" type="text" placeholder="最大值">';
|
||||
}else if(!isRange&&alreadyRange){
|
||||
wrap.innerHTML='<input class="filter-input adv-value" type="text" placeholder="请输入值">';
|
||||
}
|
||||
}
|
||||
function addAdvCondition(){
|
||||
document.getElementById('advConditions').insertAdjacentHTML('beforeend',advConditionRowHTML());
|
||||
}
|
||||
function removeAdvCondition(el){el.parentElement.remove();}
|
||||
function toggleAdvanced(){
|
||||
var p=document.getElementById('advPanel');
|
||||
var open=p.classList.toggle('open');
|
||||
var arr=document.getElementById('advToggle').querySelector('.adv-arrow');
|
||||
if(arr)arr.textContent=open?'▴':'▾';
|
||||
if(open&&!p.querySelector('.adv-cond-row'))addAdvCondition();
|
||||
}
|
||||
function clearAdvanced(){
|
||||
document.getElementById('advConditions').innerHTML='';
|
||||
renderBigTable();
|
||||
showToast('已清空高级查询条件');
|
||||
}
|
||||
/* 读取面板中已填值的条件(忽略值为空的行;范围条件任一边有值即计入) */
|
||||
function readAdvancedConditions(){
|
||||
var conds=[];
|
||||
document.querySelectorAll('#advConditions .adv-cond-row').forEach(function(row){
|
||||
var field=row.querySelector('.adv-field').value;
|
||||
var op=row.querySelector('.adv-op').value;
|
||||
if(op==='范围'){
|
||||
var from=row.querySelector('.adv-range-from').value.trim();
|
||||
var to=row.querySelector('.adv-range-to').value.trim();
|
||||
if(from!==''||to!=='')conds.push({field:field,op:op,from:from,to:to});
|
||||
}else{
|
||||
var value=row.querySelector('.adv-value').value.trim();
|
||||
if(value!=='')conds.push({field:field,op:op,value:value});
|
||||
}
|
||||
});
|
||||
return conds;
|
||||
}
|
||||
/* 取某字段在某员工上的值:基本信息直接用 key,项目结果取"结果"字符串 */
|
||||
function getFieldRaw(row,field){
|
||||
if(field.indexOf('|')>=0){
|
||||
var i=field.indexOf('|');
|
||||
return resultVal(row,{cat:field.slice(0,i),name:field.slice(i+1)});
|
||||
}
|
||||
return row[field];
|
||||
}
|
||||
/* 单条条件匹配:包含/=/!= 按字符串,>、>=、<、<=、范围 按数值 */
|
||||
function matchCondition(row,cond){
|
||||
var raw=getFieldRaw(row,cond.field);
|
||||
var str=String(raw==null?'':raw);
|
||||
if(cond.op==='包含')return str.indexOf(cond.value)>=0;
|
||||
if(cond.op==='=')return str===cond.value;
|
||||
if(cond.op==='!=')return str!==cond.value;
|
||||
var n=numericOf(str);
|
||||
if(n===null)return false;
|
||||
if(cond.op==='范围'){
|
||||
if(cond.from!==''){
|
||||
var lo=parseFloat(cond.from);
|
||||
if(!isNaN(lo)&&n<lo)return false;
|
||||
}
|
||||
if(cond.to!==''){
|
||||
var hi=parseFloat(cond.to);
|
||||
if(!isNaN(hi)&&n>hi)return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
var c=parseFloat(cond.value);
|
||||
if(isNaN(c))return false;
|
||||
if(cond.op==='>')return n>c;
|
||||
if(cond.op==='>=')return n>=c;
|
||||
if(cond.op==='<')return n<c;
|
||||
if(cond.op==='<=')return n<=c;
|
||||
return true;
|
||||
}
|
||||
function renderBigTable(){
|
||||
document.getElementById('bigTable').innerHTML=buildHead()+buildBody();
|
||||
document.getElementById('pageTotal').textContent='共 '+getDisplayRows().length+' 条';
|
||||
@@ -579,6 +715,7 @@ function resetFilter(){
|
||||
showToast('已重置筛选条件');
|
||||
}
|
||||
renderBigTable();
|
||||
ADV_FIELD_OPTS=buildAdvFieldOpts();
|
||||
/* 体检年份选择控件 */
|
||||
function pickYear(el){
|
||||
var dp=el.parentElement,input=dp.parentElement.querySelector('input');
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -158,6 +158,7 @@
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -186,7 +187,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item active">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -196,7 +197,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
.report-head__meta{display:flex;align-items:center;gap:24px;margin-top:10px;font-size:var(--font-sm);color:var(--text-secondary);flex-wrap:wrap;}
|
||||
.report-head__meta b{color:var(--text-primary);font-weight:500;}
|
||||
/* 概览指标卡 */
|
||||
.overview-cards{display:grid;grid-template-columns:repeat(6,1fr);gap:12px;margin-bottom:16px;}
|
||||
.overview-cards{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin-bottom:16px;}
|
||||
.ov-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);padding:18px 12px;text-align:center;}
|
||||
.ov-card__value{font-size:var(--font-xxl);font-weight:600;color:var(--text-primary);line-height:1.2;}
|
||||
.ov-card__value--primary{color:var(--primary);}
|
||||
@@ -98,6 +98,10 @@
|
||||
.ov-card__value--warning{color:var(--warning);}
|
||||
.ov-card__value--danger{color:var(--danger);}
|
||||
.ov-card__label{font-size:var(--font-xs);color:var(--text-placeholder);margin-top:8px;}
|
||||
.ov-card__trend{font-size:var(--font-xs);color:var(--text-placeholder);margin-top:6px;font-variant-numeric:tabular-nums;}
|
||||
.trend-good{color:var(--success);}
|
||||
.trend-bad{color:var(--danger);}
|
||||
.trend-flat{color:var(--text-placeholder);}
|
||||
/* 报告卡片 */
|
||||
.report-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);margin-bottom:16px;overflow:hidden;}
|
||||
.report-card__header{padding:14px 20px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px;}
|
||||
@@ -123,16 +127,12 @@
|
||||
.bar-row__fill.top1{background:linear-gradient(90deg,#FF9C6E,#FF4D4F);}
|
||||
.bar-row__fill.top2{background:linear-gradient(90deg,#FFD591,#FAAD14);}
|
||||
.bar-row__fill.top3{background:linear-gradient(90deg,#95DE64,#52C41A);}
|
||||
.bar-row__val{width:140px;flex-shrink:0;font-size:var(--font-sm);color:var(--text-secondary);font-variant-numeric:tabular-nums;}
|
||||
.bar-row__val{width:210px;flex-shrink:0;font-size:var(--font-sm);color:var(--text-secondary);font-variant-numeric:tabular-nums;}
|
||||
.bar-row__val b{color:var(--text-primary);font-weight:600;}
|
||||
/* 专项筛查卡片项 */
|
||||
.screen-item{display:flex;align-items:center;padding:13px 0;border-bottom:1px solid #F0F0F0;}
|
||||
.screen-item:first-child{padding-top:0;}
|
||||
.screen-item:last-child{border-bottom:none;padding-bottom:0;}
|
||||
.screen-item__name{width:180px;flex-shrink:0;font-size:var(--font-sm);color:var(--text-primary);}
|
||||
.screen-item__val{font-size:var(--font-base);font-weight:600;color:var(--danger);margin-right:6px;font-variant-numeric:tabular-nums;}
|
||||
.screen-item__unit{font-size:var(--font-sm);color:var(--text-secondary);}
|
||||
.screen-item__rate{margin-left:auto;font-size:var(--font-sm);color:var(--text-placeholder);font-variant-numeric:tabular-nums;}
|
||||
.bar-row__delta{font-size:var(--font-xs);color:var(--text-placeholder);margin-top:2px;}
|
||||
/* 趋势图例 */
|
||||
.trend-legend{display:flex;gap:18px;font-size:var(--font-xs);color:var(--text-secondary);margin-bottom:10px;}
|
||||
.trend-legend i{display:inline-block;width:10px;height:10px;border-radius:50%;margin-right:5px;vertical-align:-1px;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -170,7 +170,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item active">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -185,6 +185,7 @@
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -213,7 +214,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -223,10 +224,22 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-subgroup">
|
||||
<div class="sidebar-subgroup__header" onclick="toggleSubgroup(this)">
|
||||
<svg class="arrow" viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke-width="1.5" stroke-linecap="round"/></svg>
|
||||
体检影像管理
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-imc-user.html" class="sidebar-item">用户体检信息</a>
|
||||
<a href="post-imc-class.html" class="sidebar-item">用户影像文件分类</a>
|
||||
<a href="post-imc-info.html" class="sidebar-item">用户影像文件详细</a>
|
||||
<a href="post-imc-log.html" class="sidebar-item">文件处理日志</a>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容 -->
|
||||
@@ -274,6 +287,8 @@
|
||||
/* 确定性伪随机(0-1),保证同一单位每次打开数据一致 */
|
||||
function pseudo(i){var x=Math.sin(i*127.1)*43758.5453;return x-Math.floor(x);}
|
||||
function fmt(n){return String(n).replace(/\B(?=(\d{3})+(?!\d))/g,',');}
|
||||
function pct(a,b){return b?((a/b)*100).toFixed(1)+'%':'0.0%';}
|
||||
function pct1(n){return (n==null?'0.0':n.toFixed(1))+'%';}
|
||||
|
||||
var UNITS=['公司机关','第一采油厂','第二采油厂','第三采油厂','第八采油厂','第九采油厂','第十一采油厂','采气一厂','水电厂','公用事业公司','运输公司','伴生气综合利用项目部','质量安全环保技术监督中心'];
|
||||
var HOSPITALS=['宝石花医院','延安医院','西安高新医院','长安心血管医院','宁夏宝石花','CQ总医院'];
|
||||
@@ -282,6 +297,8 @@ var HOSPITALS=['宝石花医院','延安医院','西安高新医院','长安心
|
||||
var AGE_BANDS=['35岁以下','35岁至44岁','45岁及以上'];
|
||||
/* 异常指标排名(名称 / 排名着色 class) */
|
||||
var INDICATORS=['血脂异常','血压升高','超重(肥胖)','高尿酸','脂肪肝','空腹血糖升高','甲状腺结节','肺部结节','肝功能异常','心电图异常'];
|
||||
/* 重点指标(管理层关注的核心指标,逐项拆解) */
|
||||
var KEY_INDICATORS=['血压异常','血脂异常','空腹血糖升高','高尿酸','超重(BMI)'];
|
||||
/* 疾病(病种)分布,按病种类别分组 */
|
||||
var DISEASE_CATS=[
|
||||
{name:'血液及动脉病种',items:['高脂血','高血压','痛风(高尿酸)','动脉斑块']},
|
||||
@@ -296,24 +313,44 @@ var DISEASE_CATS=[
|
||||
|
||||
var state={unitIdx:0, year:'2026', keyword:''};
|
||||
|
||||
/* 某单位某年的群体基础数据(确定性生成) */
|
||||
/* 某单位某年的群体基础数据(确定性生成,显式传单位/年份) */
|
||||
function yearSeed(idx,year){return idx*13.7+parseInt(year,10)*5.3;}
|
||||
function unitData(idx){
|
||||
var s=yearSeed(idx,state.year);
|
||||
function unitData(idx,year){
|
||||
var s=yearSeed(idx,year);
|
||||
var total=500+Math.floor(pseudo(s+1.3)*7500); // 应检人数 500~8000
|
||||
var examined=Math.round(total*(0.75+pseudo(s+2.1)*0.20)); // 已检人数
|
||||
var abnormal=Math.round(examined*(0.22+pseudo(s+3.7)*0.38)); // 异常人数
|
||||
var keyAbn=Math.round(abnormal*(0.25+pseudo(s+4.9)*0.30)); // 重点指标异常人数
|
||||
var cancerPos=Math.round(total*(0.008+pseudo(s+5.3)*0.022)); // 防癌筛查阳性人数
|
||||
var ctaAbn=Math.round(examined*(0.012+pseudo(s+6.1)*0.038)); // 冠脉CTA异常人数
|
||||
var healthy=examined-abnormal; // 未见异常人数
|
||||
var recheckAdvised=Math.round(abnormal*(0.55+pseudo(s+12.3)*0.25));// 建议复查人数
|
||||
var recheckDone=Math.round(recheckAdvised*(0.60+pseudo(s+13.1)*0.30)); // 已完成复查人数
|
||||
var completeCnt=Math.round(examined*(0.90+pseudo(s+14.7)*0.09)); // 数据完整人数
|
||||
var avgAge=34+Math.round(pseudo(s+15.2)*16); // 平均年龄 34~50
|
||||
return {
|
||||
name:UNITS[idx], total:total, examined:examined, abnormal:abnormal, keyAbn:keyAbn,
|
||||
cancerPos:cancerPos, ctaAbn:ctaAbn, hospital:HOSPITALS[idx%HOSPITALS.length]
|
||||
name:UNITS[idx], total:total, examined:examined, abnormal:abnormal, keyAbn:keyAbn, healthy:healthy,
|
||||
recheckAdvised:recheckAdvised, recheckDone:recheckDone, completeCnt:completeCnt, avgAge:avgAge,
|
||||
hospital:HOSPITALS[idx%HOSPITALS.length]
|
||||
};
|
||||
}
|
||||
/* 汇总数值统计(含各类率,用于同比对比) */
|
||||
function computeStats(idx,year){
|
||||
var d=unitData(idx,year);
|
||||
var ag=ageGender(idx,year);
|
||||
var male=ag.reduce(function(a,r){return a+r.male;},0);
|
||||
var female=ag.reduce(function(a,r){return a+r.female;},0);
|
||||
return {
|
||||
total:d.total, examined:d.examined, attendRate:d.examined/d.total*100,
|
||||
abnormal:d.abnormal, detectRate:d.abnormal/d.examined*100, keyAbn:d.keyAbn, healthy:d.healthy,
|
||||
recheckAdvised:d.recheckAdvised, recheckDone:d.recheckDone,
|
||||
recheckRate:d.recheckAdvised?d.recheckDone/d.recheckAdvised*100:0,
|
||||
completeCnt:d.completeCnt, completeRate:d.examined?d.completeCnt/d.examined*100:0,
|
||||
avgAge:d.avgAge, male:male, female:female
|
||||
};
|
||||
}
|
||||
/* 年龄×性别分布 */
|
||||
function ageGender(d){
|
||||
var s=yearSeed(state.unitIdx,state.year);
|
||||
function ageGender(idx,year){
|
||||
var d=unitData(idx,year);
|
||||
var s=yearSeed(idx,year);
|
||||
var a35=Math.round(d.examined*(0.26+pseudo(s+7.7)*0.10));
|
||||
var a44=Math.round(d.examined*(0.32+pseudo(s+8.3)*0.08));
|
||||
var a45=d.examined-a35-a44;
|
||||
@@ -325,8 +362,9 @@ function ageGender(d){
|
||||
];
|
||||
}
|
||||
/* 异常指标排名(人数近似递减) */
|
||||
function indicatorRank(d){
|
||||
var s=yearSeed(state.unitIdx,state.year);
|
||||
function indicatorRank(idx,year){
|
||||
var d=unitData(idx,year);
|
||||
var s=yearSeed(idx,year);
|
||||
var list=INDICATORS.map(function(name,ki){
|
||||
var share=(0.05+pseudo(s+ki*2.9)*0.16)*(INDICATORS.length-ki)/INDICATORS.length;
|
||||
return {name:name, cnt:Math.max(3,Math.round(d.examined*share))};
|
||||
@@ -334,9 +372,41 @@ function indicatorRank(d){
|
||||
list.sort(function(a,b){return b.cnt-a.cnt;});
|
||||
return list;
|
||||
}
|
||||
/* 重点指标异常拆解(人次,同一人可有多项) */
|
||||
function keyIndicatorDetail(idx,year){
|
||||
var d=unitData(idx,year);
|
||||
var s=yearSeed(idx,year);
|
||||
var list=KEY_INDICATORS.map(function(name,ki){
|
||||
var share=(0.10+pseudo(s+ki*3.5+0.7)*0.15)*(KEY_INDICATORS.length-ki)/KEY_INDICATORS.length;
|
||||
return {name:name, cnt:Math.max(1,Math.round(d.keyAbn*share))};
|
||||
});
|
||||
list.sort(function(a,b){return b.cnt-a.cnt;});
|
||||
return list;
|
||||
}
|
||||
/* 异常率×年龄/性别 交叉(异常人数归一化到总体异常人数) */
|
||||
function ageGenderAbnormal(idx,year){
|
||||
var d=unitData(idx,year);
|
||||
var ag=ageGender(idx,year);
|
||||
var s=yearSeed(idx,year);
|
||||
var rows=ag.map(function(r,bi){
|
||||
var mAbn=Math.round(r.male*(0.15+pseudo(s+bi*4.7+2.3)*0.35));
|
||||
var fAbn=Math.round(r.female*(0.12+pseudo(s+bi*4.7+3.9)*0.32));
|
||||
return {band:r.band, male:r.male, female:r.female, maleAbn:mAbn, femaleAbn:fAbn};
|
||||
});
|
||||
var sumAbn=rows.reduce(function(a,r){return a+r.maleAbn+r.femaleAbn;},0);
|
||||
if(sumAbn>0){var k=d.abnormal/sumAbn;rows.forEach(function(r){r.maleAbn=Math.round(r.maleAbn*k);r.femaleAbn=Math.round(r.femaleAbn*k);});}
|
||||
rows.forEach(function(r){
|
||||
r.total=r.male+r.female; r.totalAbn=r.maleAbn+r.femaleAbn;
|
||||
r.maleRate=r.male?r.maleAbn/r.male*100:0;
|
||||
r.femaleRate=r.female?r.femaleAbn/r.female*100:0;
|
||||
r.rate=r.total?r.totalAbn/r.total*100:0;
|
||||
});
|
||||
return rows;
|
||||
}
|
||||
/* 疾病(病种)分布:按病种类别分组,类别与病种均按人数降序 */
|
||||
function diseaseDist(d){
|
||||
var s=yearSeed(state.unitIdx,state.year);
|
||||
function diseaseDist(idx,year){
|
||||
var d=unitData(idx,year);
|
||||
var s=yearSeed(idx,year);
|
||||
var groups=DISEASE_CATS.map(function(cat,ci){
|
||||
var items=cat.items.map(function(name,ii){
|
||||
var share=(0.018+pseudo(s+ci*3.3+ii*1.9)*0.11)*(DISEASE_CATS.length-ci)/DISEASE_CATS.length;
|
||||
@@ -348,6 +418,25 @@ function diseaseDist(d){
|
||||
groups.sort(function(a,b){return b.items[0].cnt-a.items[0].cnt;});
|
||||
return groups;
|
||||
}
|
||||
/* 体检计划周期(随年份与单位动态) */
|
||||
function planPeriod(idx,year){
|
||||
var s=yearSeed(idx,year);
|
||||
var sm=4+Math.floor(pseudo(s+19.1)*3);
|
||||
var sd=5+Math.floor(pseudo(s+19.2)*20);
|
||||
var em=sm+2, ed=10+Math.floor(pseudo(s+19.3)*20);
|
||||
function p(n){return (n<10?'0':'')+n;}
|
||||
return year+'-'+p(sm)+'-'+p(sd)+' 至 '+year+'-'+p(em)+'-'+p(ed);
|
||||
}
|
||||
/* 同比变化(带方向着色):goodDir=up/down 表示"升是好事/降是好事",flat 中性 */
|
||||
function trendSpan(numDelta,isRate,goodDir,unit){
|
||||
if(Math.abs(numDelta)<0.05)return '<span class="trend-flat">— 持平</span>';
|
||||
var up=numDelta>0, arrow=up?'↑':'↓';
|
||||
var txt=(up?'+':'')+(isRate?Math.abs(numDelta).toFixed(1)+'pp':fmt(Math.abs(Math.round(numDelta)))+(unit||''));
|
||||
var cls='trend-flat';
|
||||
if(goodDir==='up')cls=up?'trend-good':'trend-bad';
|
||||
else if(goodDir==='down')cls=up?'trend-bad':'trend-good';
|
||||
return '<span class="'+cls+'">'+arrow+' '+txt+'</span>';
|
||||
}
|
||||
|
||||
/* ============ 左侧单位列表 ============ */
|
||||
function renderUnitList(){
|
||||
@@ -356,7 +445,7 @@ function renderUnitList(){
|
||||
if(!list.length){box.innerHTML='<div class="unit-list__empty">未找到匹配单位</div>';return;}
|
||||
var html=list.map(function(u){
|
||||
var idx=UNITS.indexOf(u);
|
||||
var d=unitData(idx);
|
||||
var d=unitData(idx,state.year);
|
||||
return '<div class="unit-list__item'+(idx===state.unitIdx?' active':'')+'" onclick="selectUnit('+idx+')">'
|
||||
+'<div class="unit-list__name">'+u+'</div>'
|
||||
+'<div class="unit-list__meta"><span>应检 '+fmt(d.total)+'</span><span>检出率 '+pct(d.abnormal,d.examined)+'</span></div>'
|
||||
@@ -366,107 +455,207 @@ function renderUnitList(){
|
||||
}
|
||||
function filterUnits(kw){state.keyword=kw.trim();renderUnitList();}
|
||||
function selectUnit(idx){state.unitIdx=idx;renderUnitList();renderReport();}
|
||||
function pct(a,b){return b?((a/b)*100).toFixed(1)+'%':'0.0%';}
|
||||
|
||||
/* ============ 近三年趋势图(受检率 / 检出率 折线) ============ */
|
||||
function trendChartSvg(idx,years){
|
||||
var attend=[],detect=[];
|
||||
years.forEach(function(y){var s=computeStats(idx,y);attend.push(s.attendRate);detect.push(s.detectRate);});
|
||||
var all=attend.concat(detect);
|
||||
var min=Math.floor(Math.min.apply(null,all))-3, max=Math.ceil(Math.max.apply(null,all))+3;
|
||||
var W=560,H=150,padL=38,padR=14,padT=14,padB=26;
|
||||
var iw=W-padL-padR, ih=H-padT-padB;
|
||||
function x(i){return padL+(years.length===1?iw/2:iw*i/(years.length-1));}
|
||||
function y(v){return padT+ih*(1-(v-min)/(max-min));}
|
||||
var grid='';
|
||||
for(var g=0;g<=4;g++){
|
||||
var gv=min+(max-min)*g/4, gy=y(gv).toFixed(1);
|
||||
grid+='<line x1="'+padL+'" y1="'+gy+'" x2="'+(W-padR)+'" y2="'+gy+'" stroke="#F0F0F0"/>'
|
||||
+'<text x="'+(padL-6)+'" y="'+(parseFloat(gy)+4).toFixed(1)+'" text-anchor="end" font-size="10" fill="#999">'+gv.toFixed(0)+'</text>';
|
||||
}
|
||||
function pline(arr,color){return '<polyline points="'+arr.map(function(v,i){return x(i).toFixed(1)+','+y(v).toFixed(1);}).join(' ')+'" fill="none" stroke="'+color+'" stroke-width="2"/>';}
|
||||
var dots='';
|
||||
attend.forEach(function(v,i){dots+='<circle cx="'+x(i).toFixed(1)+'" cy="'+y(v).toFixed(1)+'" r="3.5" fill="#1890FF"/>';});
|
||||
detect.forEach(function(v,i){dots+='<circle cx="'+x(i).toFixed(1)+'" cy="'+y(v).toFixed(1)+'" r="3.5" fill="#FAAD14"/>';});
|
||||
var labels='';
|
||||
years.forEach(function(yr,i){
|
||||
var active=yr===state.year;
|
||||
labels+='<text x="'+x(i).toFixed(1)+'" y="'+(H-8)+'" text-anchor="middle" font-size="11" '+(active?'font-weight="600" fill="#1890FF"':'fill="#666"')+'>'+yr+'</text>';
|
||||
});
|
||||
return '<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;height:auto;">'+grid
|
||||
+pline(attend,'#1890FF')+pline(detect,'#FAAD14')+dots+labels+'</svg>';
|
||||
}
|
||||
|
||||
/* ============ 右侧群体分析报告 ============ */
|
||||
function renderReport(){
|
||||
var d=unitData(state.unitIdx);
|
||||
var ag=ageGender(d);
|
||||
var rank=indicatorRank(d);
|
||||
var dist=diseaseDist(d);
|
||||
var maxCnt=rank[0].cnt;
|
||||
var idx=state.unitIdx, year=state.year;
|
||||
var prevYear=String(parseInt(year,10)-1);
|
||||
var d=unitData(idx,year);
|
||||
var cur=computeStats(idx,year);
|
||||
var prev=computeStats(idx,prevYear);
|
||||
var rank=indicatorRank(idx,year);
|
||||
var rankPrevMap={}; indicatorRank(idx,prevYear).forEach(function(r){rankPrevMap[r.name]={cnt:r.cnt,rate:r.cnt/unitData(idx,prevYear).examined*100};});
|
||||
var keyList=keyIndicatorDetail(idx,year);
|
||||
var keyPrevMap={}; keyIndicatorDetail(idx,prevYear).forEach(function(k){keyPrevMap[k.name]=k.cnt;});
|
||||
var dist=diseaseDist(idx,year);
|
||||
var distPrevMap={}; diseaseDist(idx,prevYear).forEach(function(g){g.items.forEach(function(x){distPrevMap[x.name]=x.cnt;});});
|
||||
var cross=ageGenderAbnormal(idx,year);
|
||||
var years=[String(parseInt(year,10)-2),prevYear,year];
|
||||
var panel=document.getElementById('report-panel');
|
||||
|
||||
/* 概览指标卡 */
|
||||
/* 概览指标卡(含同比) */
|
||||
var cards=[
|
||||
['应检人数',fmt(d.total),''],
|
||||
['已检人数',fmt(d.examined),'ov-card__value--primary'],
|
||||
['受检率',pct(d.examined,d.total),'ov-card__value--success'],
|
||||
['检出率',pct(d.abnormal,d.examined),'ov-card__value--warning'],
|
||||
['异常人数',fmt(d.abnormal),'ov-card__value--danger'],
|
||||
['重点指标异常',fmt(d.keyAbn),'ov-card__value--danger']
|
||||
['应检人数',fmt(cur.total),'',cur.total-prev.total,false,'flat','人'],
|
||||
['已检人数',fmt(cur.examined),'ov-card__value--primary',cur.examined-prev.examined,false,'flat','人'],
|
||||
['受检率',pct1(cur.attendRate),'ov-card__value--success',cur.attendRate-prev.attendRate,true,'up',''],
|
||||
['检出率',pct1(cur.detectRate),'ov-card__value--warning',cur.detectRate-prev.detectRate,true,'down',''],
|
||||
['异常人数',fmt(cur.abnormal),'ov-card__value--danger',cur.abnormal-prev.abnormal,false,'down','人'],
|
||||
['重点指标异常',fmt(cur.keyAbn),'ov-card__value--danger',cur.keyAbn-prev.keyAbn,false,'down','人'],
|
||||
['复查率',pct1(cur.recheckRate),'',cur.recheckRate-prev.recheckRate,true,'up',''],
|
||||
['数据完整率',pct1(cur.completeRate),'',cur.completeRate-prev.completeRate,true,'up',''],
|
||||
['平均年龄',cur.avgAge+'岁','',cur.avgAge-prev.avgAge,false,'flat','岁'],
|
||||
['未见异常',fmt(cur.healthy),'ov-card__value--success',cur.healthy-prev.healthy,false,'up','人']
|
||||
].map(function(c){
|
||||
return '<div class="ov-card"><div class="ov-card__value '+c[2]+'">'+c[1]+'</div><div class="ov-card__label">'+c[0]+'</div></div>';
|
||||
return '<div class="ov-card"><div class="ov-card__value '+c[2]+'">'+c[1]+'</div><div class="ov-card__label">'+c[0]+'</div><div class="ov-card__trend">较上年 '+trendSpan(c[3],c[4],c[5],c[6])+'</div></div>';
|
||||
}).join('');
|
||||
|
||||
/* 年龄性别分布表 */
|
||||
var agRows=ag.map(function(r){
|
||||
return '<tr><td>'+r.band+'</td><td class="num">'+fmt(r.male)+'</td><td class="num">'+fmt(r.female)+'</td><td class="num">'+fmt(r.male+r.female)+'</td><td class="rate">'+pct(r.male+r.female,d.examined)+'</td></tr>';
|
||||
}).join('');
|
||||
var agTotal=ag.reduce(function(a,r){return a+r.male+r.female;},0);
|
||||
var agMale=ag.reduce(function(a,r){return a+r.male;},0);
|
||||
var agFemale=ag.reduce(function(a,r){return a+r.female;},0);
|
||||
|
||||
/* 异常指标条形图 */
|
||||
/* 异常指标条形图(带上年对照) */
|
||||
var maxCnt=rank[0].cnt;
|
||||
var bars=rank.map(function(r,i){
|
||||
var cls=i===0?'top1':(i===1?'top2':(i===2?'top3':''));
|
||||
var pv=rankPrevMap[r.name]||{cnt:0,rate:0};
|
||||
var delta=r.cnt-pv.cnt;
|
||||
return '<div class="bar-row">'
|
||||
+'<div class="bar-row__label">'+r.name+'</div>'
|
||||
+'<div class="bar-row__track"><div class="bar-row__fill '+cls+'" style="width:'+(r.cnt/maxCnt*100).toFixed(1)+'%;"></div></div>'
|
||||
+'<div class="bar-row__val"><b>'+fmt(r.cnt)+'</b> 人 · '+pct(r.cnt,d.examined)+'</div>'
|
||||
+'<div class="bar-row__val"><div><b>'+fmt(r.cnt)+'</b> 人 · '+pct(r.cnt,d.examined)+'</div><div class="bar-row__delta">上年 '+pct1(pv.rate)+' · '+trendSpan(delta,false,'down','人')+'</div></div>'
|
||||
+'</div>';
|
||||
}).join('');
|
||||
|
||||
/* 疾病分布表 */
|
||||
/* 重点指标异常拆解 */
|
||||
var keyRows=keyList.map(function(k){
|
||||
var pv=keyPrevMap[k.name]||0;
|
||||
return '<tr><td>'+k.name+'</td><td class="num">'+fmt(k.cnt)+'</td><td class="rate">'+pct(k.cnt,d.examined)+'</td><td>'+trendSpan(k.cnt-pv,false,'down','人')+'</td></tr>';
|
||||
}).join('');
|
||||
|
||||
/* 异常率×年龄/性别 交叉 */
|
||||
var crossRows=cross.map(function(r){
|
||||
return '<tr><td>'+r.band+'</td><td class="rate">'+pct1(r.maleRate)+'</td><td class="rate">'+pct1(r.femaleRate)+'</td><td class="rate">'+pct1(r.rate)+'</td><td class="num">'+fmt(r.totalAbn)+'</td></tr>';
|
||||
}).join('');
|
||||
var crossTotalAbn=cross.reduce(function(a,r){return a+r.totalAbn;},0);
|
||||
var crossMaleAbn=cross.reduce(function(a,r){return a+r.maleAbn;},0);
|
||||
var crossFemaleAbn=cross.reduce(function(a,r){return a+r.femaleAbn;},0);
|
||||
var crossMale=cross.reduce(function(a,r){return a+r.male;},0);
|
||||
var crossFemale=cross.reduce(function(a,r){return a+r.female;},0);
|
||||
var crossMaleRate=crossMale?crossMaleAbn/crossMale*100:0;
|
||||
var crossFemaleRate=crossFemale?crossFemaleAbn/crossFemale*100:0;
|
||||
|
||||
/* 疾病分布(带较上年) */
|
||||
var distRows='';
|
||||
dist.forEach(function(g){
|
||||
distRows+='<tr class="cat-row"><td colspan="4">'+g.cat+'</td></tr>';
|
||||
distRows+='<tr class="cat-row"><td colspan="5">'+g.cat+'</td></tr>';
|
||||
g.items.forEach(function(x){
|
||||
distRows+='<tr><td></td><td>'+x.name+'</td><td class="num">'+fmt(x.cnt)+'</td><td class="rate">'+pct(x.cnt,d.examined)+'</td></tr>';
|
||||
var pv=distPrevMap[x.name]||0;
|
||||
distRows+='<tr><td></td><td>'+x.name+'</td><td class="num">'+fmt(x.cnt)+'</td><td class="rate">'+pct(x.cnt,d.examined)+'</td><td>'+trendSpan(x.cnt-pv,false,'down','人')+'</td></tr>';
|
||||
});
|
||||
});
|
||||
|
||||
/* 近三年趋势 */
|
||||
var trendLegend='<div class="trend-legend"><span><i style="background:#1890FF"></i>受检率</span><span><i style="background:#FAAD14"></i>检出率</span></div>';
|
||||
|
||||
panel.innerHTML=
|
||||
'<div class="report-head">'
|
||||
+'<div class="report-head__title">'+d.name+' · 群体分析报告</div>'
|
||||
+'<div class="report-head__meta">'
|
||||
+'<span>体检年份:<b>'+state.year+'</b></span>'
|
||||
+'<span>体检年份:<b>'+year+'</b></span>'
|
||||
+'<span>承检医院:<b>'+d.hospital+'</b></span>'
|
||||
+'<span>体检计划:<b>2026-06-23 至 2026-08-31</b></span>'
|
||||
+'<span>体检计划:<b>'+planPeriod(idx,year)+'</b></span>'
|
||||
+'<span>同比基准:<b>'+prevYear+' 年</b></span>'
|
||||
+'</div></div>'
|
||||
|
||||
+'<div class="overview-cards">'+cards+'</div>'
|
||||
|
||||
+'<div class="report-card">'
|
||||
+'<div class="report-card__header"><div class="report-card__bar"></div><div class="report-card__title">年龄与性别分布</div><div class="report-card__sub">按已检人数统计</div></div>'
|
||||
+'<div class="report-card__header"><div class="report-card__bar"></div><div class="report-card__title">近三年趋势</div><div class="report-card__sub">受检率 / 检出率</div></div>'
|
||||
+'<div class="report-card__body">'+trendLegend+trendChartSvg(idx,years)+'</div></div>'
|
||||
|
||||
+'<div class="report-card">'
|
||||
+'<div class="report-card__header"><div class="report-card__bar"></div><div class="report-card__title">异常率 × 年龄 / 性别</div><div class="report-card__sub">各年龄段、性别异常检出率</div></div>'
|
||||
+'<div class="report-card__body"><table class="dist-table">'
|
||||
+'<thead><tr><th>年龄区间</th><th>男</th><th>女</th><th>合计</th><th>占比</th></tr></thead>'
|
||||
+'<tbody>'+agRows
|
||||
+'<tr><td style="font-weight:600;">合计</td><td class="num" style="font-weight:600;">'+fmt(agMale)+'</td><td class="num" style="font-weight:600;">'+fmt(agFemale)+'</td><td class="num" style="font-weight:600;">'+fmt(agTotal)+'</td><td class="rate">100%</td></tr>'
|
||||
+'<thead><tr><th>年龄区间</th><th>男性异常率</th><th>女性异常率</th><th>合计异常率</th><th>异常人数</th></tr></thead>'
|
||||
+'<tbody>'+crossRows
|
||||
+'<tr><td style="font-weight:600;">合计</td><td class="rate" style="font-weight:600;">'+pct1(crossMaleRate)+'</td><td class="rate" style="font-weight:600;">'+pct1(crossFemaleRate)+'</td><td class="rate" style="font-weight:600;">'+pct1(cur.detectRate)+'</td><td class="num" style="font-weight:600;">'+fmt(crossTotalAbn)+'</td></tr>'
|
||||
+'</tbody></table></div></div>'
|
||||
|
||||
+'<div class="report-card">'
|
||||
+'<div class="report-card__header"><div class="report-card__bar"></div><div class="report-card__title">异常指标排名</div><div class="report-card__sub">按检出人数排序</div></div>'
|
||||
+'<div class="report-card__header"><div class="report-card__bar"></div><div class="report-card__title">异常指标排名</div><div class="report-card__sub">按检出人数排序 · 附上年对照</div></div>'
|
||||
+'<div class="report-card__body">'+bars+'</div></div>'
|
||||
|
||||
+'<div class="report-card">'
|
||||
+'<div class="report-card__header"><div class="report-card__bar"></div><div class="report-card__title">疾病(病种)分布</div><div class="report-card__sub">按病种字典归类</div></div>'
|
||||
+'<div class="report-card__header"><div class="report-card__bar"></div><div class="report-card__title">重点指标异常拆解</div><div class="report-card__sub">同一人可有多项异常</div></div>'
|
||||
+'<div class="report-card__body"><table class="dist-table">'
|
||||
+'<thead><tr><th style="width:24px;"></th><th>病种</th><th>人数</th><th>占比</th></tr></thead>'
|
||||
+'<tbody>'+distRows+'</tbody></table></div></div>'
|
||||
+'<thead><tr><th>重点指标</th><th>异常人数</th><th>检出率</th><th>较上年</th></tr></thead>'
|
||||
+'<tbody>'+keyRows+'</tbody></table></div></div>'
|
||||
|
||||
+'<div class="report-card">'
|
||||
+'<div class="report-card__header"><div class="report-card__bar"></div><div class="report-card__title">专项筛查结果</div></div>'
|
||||
+'<div class="report-card__body">'
|
||||
+'<div class="screen-item"><div class="screen-item__name">防癌筛查 · Septin9</div><span class="screen-item__val">'+d.cancerPos+'</span><span class="screen-item__unit">人阳性</span><span class="screen-item__rate">占应检 '+pct(d.cancerPos,d.total)+'</span></div>'
|
||||
+'<div class="screen-item"><div class="screen-item__name">防癌筛查 · CA724</div><span class="screen-item__val">'+Math.max(1,Math.round(d.cancerPos*0.8))+'</span><span class="screen-item__unit">人阳性</span><span class="screen-item__rate">占应检 '+pct(Math.round(d.cancerPos*0.8),d.total)+'</span></div>'
|
||||
+'<div class="screen-item"><div class="screen-item__name">冠脉CTA</div><span class="screen-item__val">'+d.ctaAbn+'</span><span class="screen-item__unit">人异常</span><span class="screen-item__rate">占已检 '+pct(d.ctaAbn,d.examined)+'</span></div>'
|
||||
+'</div></div>';
|
||||
+'<div class="report-card__header"><div class="report-card__bar"></div><div class="report-card__title">疾病(病种)分布</div><div class="report-card__sub">按病种字典归类 · 附较上年</div></div>'
|
||||
+'<div class="report-card__body"><table class="dist-table">'
|
||||
+'<thead><tr><th style="width:24px;"></th><th>病种</th><th>人数</th><th>占比</th><th>较上年</th></tr></thead>'
|
||||
+'<tbody>'+distRows+'</tbody></table></div></div>';
|
||||
}
|
||||
|
||||
/* 导出群体报告(CSV,Excel 兼容) */
|
||||
function exportReport(){
|
||||
var d=unitData(state.unitIdx);
|
||||
var rank=indicatorRank(d);
|
||||
var dist=diseaseDist(d);
|
||||
var rows=[['单位群体报告',''],['单位',d.name],['体检年份',state.year],['承检医院',d.hospital],[],
|
||||
['应检人数',d.total],['已检人数',d.examined],['受检率',pct(d.examined,d.total)],['检出率',pct(d.abnormal,d.examined)],['异常人数',d.abnormal],['重点指标异常人数',d.keyAbn],[],
|
||||
['异常指标排名','人数'],[]].concat(rank.map(function(r){return [r.name,r.cnt];})).concat([[],['疾病(病种)分布','人数']]);
|
||||
dist.forEach(function(g){g.items.forEach(function(x){rows.push([g.cat+' · '+x.name,x.cnt]);});});
|
||||
var idx=state.unitIdx, year=state.year;
|
||||
var prevYear=String(parseInt(year,10)-1);
|
||||
var d=unitData(idx,year), pd=unitData(idx,prevYear);
|
||||
var cur=computeStats(idx,year), prev=computeStats(idx,prevYear);
|
||||
var rank=indicatorRank(idx,year);
|
||||
var rankPrevMap={}; indicatorRank(idx,prevYear).forEach(function(r){rankPrevMap[r.name]=r.cnt;});
|
||||
var keyList=keyIndicatorDetail(idx,year);
|
||||
var keyPrevMap={}; keyIndicatorDetail(idx,prevYear).forEach(function(k){keyPrevMap[k.name]=k.cnt;});
|
||||
var dist=diseaseDist(idx,year);
|
||||
var distPrevMap={}; diseaseDist(idx,prevYear).forEach(function(g){g.items.forEach(function(x){distPrevMap[x.name]=x.cnt;});});
|
||||
var cross=ageGenderAbnormal(idx,year);
|
||||
var years=[String(parseInt(year,10)-2),prevYear,year];
|
||||
|
||||
var rows=[];
|
||||
rows.push(['单位群体报告',''],['单位',d.name],['体检年份',year],['承检医院',d.hospital],['体检计划',planPeriod(idx,year)],['同比基准',prevYear+'年'],[]);
|
||||
rows.push(['概览指标','今年','上年','较上年']);
|
||||
rows.push(['应检人数',d.total,pd.total,d.total-pd.total]);
|
||||
rows.push(['已检人数',d.examined,pd.examined,d.examined-pd.examined]);
|
||||
rows.push(['受检率(%)',cur.attendRate.toFixed(1),prev.attendRate.toFixed(1),(cur.attendRate-prev.attendRate).toFixed(1)]);
|
||||
rows.push(['检出率(%)',cur.detectRate.toFixed(1),prev.detectRate.toFixed(1),(cur.detectRate-prev.detectRate).toFixed(1)]);
|
||||
rows.push(['异常人数',d.abnormal,pd.abnormal,d.abnormal-pd.abnormal]);
|
||||
rows.push(['重点指标异常人数',d.keyAbn,pd.keyAbn,d.keyAbn-pd.keyAbn]);
|
||||
rows.push(['复查率(%)',cur.recheckRate.toFixed(1),prev.recheckRate.toFixed(1),(cur.recheckRate-prev.recheckRate).toFixed(1)]);
|
||||
rows.push(['数据完整率(%)',cur.completeRate.toFixed(1),prev.completeRate.toFixed(1),(cur.completeRate-prev.completeRate).toFixed(1)]);
|
||||
rows.push(['平均年龄',cur.avgAge,prev.avgAge,cur.avgAge-prev.avgAge]);
|
||||
rows.push(['未见异常人数',d.healthy,pd.healthy,d.healthy-pd.healthy]);
|
||||
rows.push([]);
|
||||
|
||||
rows.push(['异常率×年龄/性别','男性异常率(%)','女性异常率(%)','合计异常率(%)','异常人数']);
|
||||
cross.forEach(function(r){rows.push([r.band,r.maleRate.toFixed(1),r.femaleRate.toFixed(1),r.rate.toFixed(1),r.totalAbn]);});
|
||||
rows.push([]);
|
||||
|
||||
rows.push(['异常指标排名','人数','检出率','上年人数','较上年']);
|
||||
rank.forEach(function(r){var pv=rankPrevMap[r.name]||0;rows.push([r.name,r.cnt,pct(r.cnt,d.examined),pv,r.cnt-pv]);});
|
||||
rows.push([]);
|
||||
|
||||
rows.push(['重点指标异常','异常人数','检出率','上年人数','较上年']);
|
||||
keyList.forEach(function(k){var pv=keyPrevMap[k.name]||0;rows.push([k.name,k.cnt,pct(k.cnt,d.examined),pv,k.cnt-pv]);});
|
||||
rows.push([]);
|
||||
|
||||
rows.push(['疾病(病种)分布','人数','占比','上年人数','较上年']);
|
||||
dist.forEach(function(g){g.items.forEach(function(x){var pv=distPrevMap[x.name]||0;rows.push([g.cat+' · '+x.name,x.cnt,pct(x.cnt,d.examined),pv,x.cnt-pv]);});});
|
||||
rows.push([]);
|
||||
|
||||
rows.push(['近三年趋势','受检率(%)','检出率(%)']);
|
||||
years.forEach(function(y){var s=computeStats(idx,y);rows.push([y+'年',s.attendRate.toFixed(1),s.detectRate.toFixed(1)]);});
|
||||
|
||||
var csv=rows.map(function(r){return r.map(function(c){return '"'+String(c).replace(/"/g,'""')+'"';}).join(',');}).join('\r\n');
|
||||
var a=document.createElement('a');
|
||||
a.href=URL.createObjectURL(new Blob([csv],{type:'text/csv;charset=utf-8'}));
|
||||
a.download=d.name+'_'+state.year+'年_群体分析报告.csv';
|
||||
a.download=d.name+'_'+year+'年_群体分析报告.csv';
|
||||
document.body.appendChild(a);a.click();document.body.removeChild(a);
|
||||
setTimeout(function(){URL.revokeObjectURL(a.href);},1000);
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -142,6 +142,7 @@
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item active">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -170,7 +171,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -180,7 +181,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item active">大病人员信息</a>
|
||||
@@ -168,6 +168,7 @@
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -196,7 +197,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -206,7 +207,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -145,6 +145,7 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
<a href="post-indicator-notify.html" class="sidebar-item">指标异常通知</a>
|
||||
@@ -157,6 +158,8 @@
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -256,19 +259,7 @@
|
||||
</div>
|
||||
|
||||
<div style="display:flex;gap:12px;margin-bottom:16px;align-items:center;">
|
||||
<button class="btn btn-primary" onclick="openForm(null)">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="#fff" stroke-width="1.6" stroke-linecap="round"/></svg>
|
||||
新增
|
||||
</button>
|
||||
<button class="btn btn-default" onclick="exportList()">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v7M4 6l3 3 3-3M2 12.5h10" stroke="#666" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
导出
|
||||
</button>
|
||||
<button class="btn btn-default" onclick="importList()">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 9V2M4 5l3-3 3 3M2 12.5h10" stroke="#666" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
导入
|
||||
</button>
|
||||
<button class="btn btn-default" onclick="batchDelete()" style="margin-left:auto;">
|
||||
<button class="btn btn-default" onclick="batchDelete()">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 3.5h10M5.5 3.5V2h3v1.5M3.5 3.5l.7 8.5h5.6l.7-8.5" stroke="#666" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
批量删除
|
||||
</button>
|
||||
@@ -300,85 +291,6 @@
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="modal-mask" id="formMask" onclick="if(event.target===this)closeForm()">
|
||||
<div class="modal">
|
||||
<div class="modal__header">
|
||||
<span class="modal__close" onclick="closeForm()">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3.5 3.5l9 9M12.5 3.5l-9 9" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>
|
||||
</span>
|
||||
<span class="modal__title" id="formTitle">新增用户影像文件分类</span>
|
||||
</div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item">
|
||||
<div class="form-label">用户体检信息ID</div>
|
||||
<input class="form-input" id="formMuid" type="text" placeholder="请输入用户体检信息ID">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label"><span class="required">*</span> 影像分类</div>
|
||||
<select class="form-select" id="formImgclass">
|
||||
<option value="超声">超声</option>
|
||||
<option value="CT">CT</option>
|
||||
<option value="MRI">MRI</option>
|
||||
<option value="X射线">X射线</option>
|
||||
<option value="心电">心电</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label"><span class="required">*</span> 检查项目名称</div>
|
||||
<input class="form-input" id="formName" type="text" placeholder="请输入检查项目名称">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">影像文件类型</div>
|
||||
<select class="form-select" id="formImgtype">
|
||||
<option value="非DICOM">非DICOM</option>
|
||||
<option value="dic">dic</option>
|
||||
<option value="dcm">dcm</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">报告文件类型</div>
|
||||
<select class="form-select" id="formReptype">
|
||||
<option value="png">png</option>
|
||||
<option value="jpg">jpg</option>
|
||||
<option value="pdf">pdf</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">处理状态</div>
|
||||
<select class="form-select" id="formStatus">
|
||||
<option value="1">新建</option>
|
||||
<option value="2">待解析</option>
|
||||
<option value="3">失败</option>
|
||||
<option value="4">解析中</option>
|
||||
<option value="5">成功</option>
|
||||
<option value="6">失败待重试</option>
|
||||
<option value="7">最终失败</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">检查结果</div>
|
||||
<textarea class="form-textarea" id="formContent" placeholder="请输入检查结果"></textarea>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">错误信息</div>
|
||||
<textarea class="form-textarea" id="formMsg" placeholder="请输入错误信息"></textarea>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">出报告时间</div>
|
||||
<input class="form-input" id="formReportdate" type="text" placeholder="如 2026-08-15 12:00:00">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">创建日期</div>
|
||||
<input class="form-input" id="formCreatetime" type="text" placeholder="如 2026-08-15 11:30:00">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeForm()">取消</button>
|
||||
<button class="btn btn-primary" onclick="saveForm()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-mask" id="detailMask" onclick="if(event.target===this)closeDetail()">
|
||||
<div class="modal">
|
||||
<div class="modal__header">
|
||||
@@ -460,7 +372,7 @@ function renderTable(){
|
||||
+'<td>'+r.imgClass+'</td><td>'+r.name+'</td><td>'+r.imgType+'</td><td>'+r.repType+'</td>'
|
||||
+'<td>'+statusTag(r.status)+'</td><td style="text-align:left;">'+content+'</td><td style="text-align:left;">'+msg+'</td>'
|
||||
+'<td>'+(r.reportDate||'<span class="muted">—</span>')+'</td><td>'+r.createTime+'</td>'
|
||||
+'<td><span class="link" onclick="openForm('+idx+')">编辑</span> <span class="link" style="margin-left:8px;" onclick="openDetail('+idx+')">详情</span> <span class="link-danger" style="margin-left:8px;" onclick="deleteRow('+idx+')">删除</span></td>'
|
||||
+'<td><span class="link" onclick="openDetail('+idx+')">详情</span> <span class="link-danger" style="margin-left:8px;" onclick="deleteRow('+idx+')">删除</span></td>'
|
||||
+'</tr>';
|
||||
}).join(''):'<tr><td colspan="12"><div class="empty-tip">暂无数据</div></td></tr>';
|
||||
var all=tbody.querySelectorAll('.row-check');
|
||||
@@ -524,64 +436,6 @@ function deleteRow(idx){
|
||||
rows.splice(idx,1);
|
||||
renderTable();
|
||||
}
|
||||
function exportList(){alert('导出当前筛选结果(Excel)');}
|
||||
function importList(){alert('导入影像文件分类数据(Excel)');}
|
||||
|
||||
var editingIdx=null;
|
||||
function openForm(idx){
|
||||
editingIdx=idx;
|
||||
document.getElementById('formTitle').textContent=idx===null?'新增用户影像文件分类':'编辑用户影像文件分类';
|
||||
if(idx===null){
|
||||
document.getElementById('formMuid').value='';
|
||||
document.getElementById('formImgclass').value='超声';
|
||||
document.getElementById('formName').value='';
|
||||
document.getElementById('formImgtype').value='dcm';
|
||||
document.getElementById('formReptype').value='pdf';
|
||||
document.getElementById('formStatus').value='1';
|
||||
document.getElementById('formContent').value='';
|
||||
document.getElementById('formMsg').value='';
|
||||
document.getElementById('formReportdate').value='';
|
||||
document.getElementById('formCreatetime').value='';
|
||||
}else{
|
||||
var r=rows[idx];
|
||||
document.getElementById('formMuid').value=r.muId;
|
||||
document.getElementById('formImgclass').value=r.imgClass;
|
||||
document.getElementById('formName').value=r.name;
|
||||
document.getElementById('formImgtype').value=r.imgType;
|
||||
document.getElementById('formReptype').value=r.repType;
|
||||
document.getElementById('formStatus').value=String(r.status);
|
||||
document.getElementById('formContent').value=r.content;
|
||||
document.getElementById('formMsg').value=r.msg;
|
||||
document.getElementById('formReportdate').value=r.reportDate;
|
||||
document.getElementById('formCreatetime').value=r.createTime;
|
||||
}
|
||||
document.getElementById('formMask').classList.add('open');
|
||||
}
|
||||
function closeForm(){document.getElementById('formMask').classList.remove('open');}
|
||||
function saveForm(){
|
||||
var name=document.getElementById('formName').value.trim();
|
||||
if(!name){alert('请输入检查项目名称');return;}
|
||||
var data={
|
||||
imgClass:document.getElementById('formImgclass').value,
|
||||
name:name,
|
||||
imgType:document.getElementById('formImgtype').value,
|
||||
repType:document.getElementById('formReptype').value,
|
||||
status:parseInt(document.getElementById('formStatus').value,10),
|
||||
content:document.getElementById('formContent').value.trim(),
|
||||
msg:document.getElementById('formMsg').value.trim(),
|
||||
reportDate:document.getElementById('formReportdate').value.trim(),
|
||||
createTime:document.getElementById('formCreatetime').value.trim(),
|
||||
muId:document.getElementById('formMuid').value.trim()
|
||||
};
|
||||
if(editingIdx===null){
|
||||
rows.unshift(data);
|
||||
}else{
|
||||
rows[editingIdx]=data;
|
||||
}
|
||||
closeForm();
|
||||
renderTable();
|
||||
}
|
||||
|
||||
function openDetail(idx){
|
||||
var r=rows[idx];
|
||||
document.getElementById('detailBody').innerHTML=
|
||||
@@ -601,7 +455,7 @@ function openDetail(idx){
|
||||
}
|
||||
function closeDetail(){document.getElementById('detailMask').classList.remove('open');}
|
||||
document.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){closeForm();closeDetail();}
|
||||
if(e.key==='Escape'){closeDetail();}
|
||||
});
|
||||
|
||||
function toggleSubgroup(header){
|
||||
|
||||
@@ -142,6 +142,7 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
<a href="post-indicator-notify.html" class="sidebar-item">指标异常通知</a>
|
||||
@@ -154,6 +155,8 @@
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -241,19 +244,7 @@
|
||||
</div>
|
||||
|
||||
<div style="display:flex;gap:12px;margin-bottom:16px;align-items:center;">
|
||||
<button class="btn btn-primary" onclick="openForm(null)">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="#fff" stroke-width="1.6" stroke-linecap="round"/></svg>
|
||||
新增
|
||||
</button>
|
||||
<button class="btn btn-default" onclick="exportList()">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v7M4 6l3 3 3-3M2 12.5h10" stroke="#666" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
导出
|
||||
</button>
|
||||
<button class="btn btn-default" onclick="importList()">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 9V2M4 5l3-3 3 3M2 12.5h10" stroke="#666" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
导入
|
||||
</button>
|
||||
<button class="btn btn-default" onclick="batchDelete()" style="margin-left:auto;">
|
||||
<button class="btn btn-default" onclick="batchDelete()">
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 3.5h10M5.5 3.5V2h3v1.5M3.5 3.5l.7 8.5h5.6l.7-8.5" stroke="#666" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
批量删除
|
||||
</button>
|
||||
@@ -285,66 +276,6 @@
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="modal-mask" id="formMask" onclick="if(event.target===this)closeForm()">
|
||||
<div class="modal">
|
||||
<div class="modal__header">
|
||||
<span class="modal__close" onclick="closeForm()">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3.5 3.5l9 9M12.5 3.5l-9 9" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>
|
||||
</span>
|
||||
<span class="modal__title" id="formTitle">新增用户影像文件详细</span>
|
||||
</div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item">
|
||||
<div class="form-label">用户影像文件分类ID</div>
|
||||
<input class="form-input" id="formMuicid" type="text" placeholder="请输入用户影像文件分类ID">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label"><span class="required">*</span> 文件类型</div>
|
||||
<select class="form-select" id="formFiletype">
|
||||
<option value="影像">影像</option>
|
||||
<option value="报告">报告</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">影像序号</div>
|
||||
<input class="form-input" id="formImageno" type="text" placeholder="请输入影像序号">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">错误信息</div>
|
||||
<textarea class="form-textarea" id="formMsg" placeholder="请输入错误信息"></textarea>
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label"><span class="required">*</span> 文件地址</div>
|
||||
<input class="form-input" id="formFileurl" type="text" placeholder="请输入文件地址">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">dcm实例ID</div>
|
||||
<input class="form-input" id="formInsid" type="text" placeholder="请输入dcm实例ID">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">研究实例ID</div>
|
||||
<input class="form-input" id="formStudyins" type="text" placeholder="请输入研究实例ID">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">患者ID</div>
|
||||
<input class="form-input" id="formPatient" type="text" placeholder="请输入患者ID">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">研究ID</div>
|
||||
<input class="form-input" id="formStudyid" type="text" placeholder="请输入研究ID">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">创建日期</div>
|
||||
<input class="form-input" id="formCreatetime" type="text" placeholder="如 2026-08-15 11:30:00">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeForm()">取消</button>
|
||||
<button class="btn btn-primary" onclick="saveForm()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-mask" id="detailMask" onclick="if(event.target===this)closeDetail()">
|
||||
<div class="modal">
|
||||
<div class="modal__header">
|
||||
@@ -418,7 +349,7 @@ function renderTable(){
|
||||
+'<td><span class="link" onclick="downloadFile(\''+r.fileUrl+'\')">下载</span></td>'
|
||||
+'<td>'+(r.insId||'<span class="muted">—</span>')+'</td><td>'+r.studyInsId+'</td><td>'+(r.patientId||'<span class="muted">—</span>')+'</td>'
|
||||
+'<td>'+r.studyId+'</td><td>'+r.createTime+'</td>'
|
||||
+'<td><span class="link" onclick="openForm('+idx+')">编辑</span> <span class="link" style="margin-left:8px;" onclick="openDetail('+idx+')">详情</span> <span class="link-danger" style="margin-left:8px;" onclick="deleteRow('+idx+')">删除</span></td>'
|
||||
+'<td><span class="link" onclick="openDetail('+idx+')">详情</span> <span class="link-danger" style="margin-left:8px;" onclick="deleteRow('+idx+')">删除</span></td>'
|
||||
+'</tr>';
|
||||
}).join(''):'<tr><td colspan="12"><div class="empty-tip">暂无数据</div></td></tr>';
|
||||
var all=tbody.querySelectorAll('.row-check');
|
||||
@@ -485,64 +416,6 @@ function deleteRow(idx){
|
||||
rows.splice(idx,1);
|
||||
renderTable();
|
||||
}
|
||||
function exportList(){alert('导出当前筛选结果(Excel)');}
|
||||
function importList(){alert('导入影像文件详细数据(Excel)');}
|
||||
|
||||
var editingIdx=null;
|
||||
function openForm(idx){
|
||||
editingIdx=idx;
|
||||
document.getElementById('formTitle').textContent=idx===null?'新增用户影像文件详细':'编辑用户影像文件详细';
|
||||
if(idx===null){
|
||||
document.getElementById('formMuicid').value='';
|
||||
document.getElementById('formFiletype').value='影像';
|
||||
document.getElementById('formImageno').value='';
|
||||
document.getElementById('formMsg').value='';
|
||||
document.getElementById('formFileurl').value='';
|
||||
document.getElementById('formInsid').value='';
|
||||
document.getElementById('formStudyins').value='';
|
||||
document.getElementById('formPatient').value='';
|
||||
document.getElementById('formStudyid').value='';
|
||||
document.getElementById('formCreatetime').value='';
|
||||
}else{
|
||||
var r=rows[idx];
|
||||
document.getElementById('formMuicid').value=r.muicId;
|
||||
document.getElementById('formFiletype').value=r.fileType;
|
||||
document.getElementById('formImageno').value=r.imageNo;
|
||||
document.getElementById('formMsg').value=r.msg;
|
||||
document.getElementById('formFileurl').value=r.fileUrl;
|
||||
document.getElementById('formInsid').value=r.insId;
|
||||
document.getElementById('formStudyins').value=r.studyInsId;
|
||||
document.getElementById('formPatient').value=r.patientId;
|
||||
document.getElementById('formStudyid').value=r.studyId;
|
||||
document.getElementById('formCreatetime').value=r.createTime;
|
||||
}
|
||||
document.getElementById('formMask').classList.add('open');
|
||||
}
|
||||
function closeForm(){document.getElementById('formMask').classList.remove('open');}
|
||||
function saveForm(){
|
||||
var fileUrl=document.getElementById('formFileurl').value.trim();
|
||||
if(!fileUrl){alert('请输入文件地址');return;}
|
||||
var data={
|
||||
muicId:document.getElementById('formMuicid').value.trim(),
|
||||
fileType:document.getElementById('formFiletype').value,
|
||||
imageNo:document.getElementById('formImageno').value.trim(),
|
||||
msg:document.getElementById('formMsg').value.trim(),
|
||||
fileUrl:fileUrl,
|
||||
insId:document.getElementById('formInsid').value.trim(),
|
||||
studyInsId:document.getElementById('formStudyins').value.trim(),
|
||||
patientId:document.getElementById('formPatient').value.trim(),
|
||||
studyId:document.getElementById('formStudyid').value.trim(),
|
||||
createTime:document.getElementById('formCreatetime').value.trim()
|
||||
};
|
||||
if(editingIdx===null){
|
||||
rows.unshift(data);
|
||||
}else{
|
||||
rows[editingIdx]=data;
|
||||
}
|
||||
closeForm();
|
||||
renderTable();
|
||||
}
|
||||
|
||||
function openDetail(idx){
|
||||
var r=rows[idx];
|
||||
document.getElementById('detailBody').innerHTML=
|
||||
@@ -562,7 +435,7 @@ function openDetail(idx){
|
||||
}
|
||||
function closeDetail(){document.getElementById('detailMask').classList.remove('open');}
|
||||
document.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){closeForm();closeDetail();}
|
||||
if(e.key==='Escape'){closeDetail();}
|
||||
});
|
||||
|
||||
function toggleSubgroup(header){
|
||||
|
||||
@@ -143,6 +143,7 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
<a href="post-indicator-notify.html" class="sidebar-item">指标异常通知</a>
|
||||
@@ -155,6 +156,8 @@
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
|
||||
@@ -171,6 +171,7 @@
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
<a href="post-indicator-notify.html" class="sidebar-item">指标异常通知</a>
|
||||
@@ -183,6 +184,8 @@
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -313,65 +316,6 @@
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- 编辑弹窗 -->
|
||||
<div class="modal-mask" id="formMask" onclick="if(event.target===this)closeForm()">
|
||||
<div class="modal">
|
||||
<div class="modal__header">
|
||||
<span class="modal__close" onclick="closeForm()">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3.5 3.5l9 9M12.5 3.5l-9 9" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>
|
||||
</span>
|
||||
<span class="modal__title" id="formTitle">编辑用户体检信息</span>
|
||||
</div>
|
||||
<div class="modal__body">
|
||||
<div class="form-item">
|
||||
<div class="form-label">单位信息</div>
|
||||
<input class="form-input" id="formUnit" type="text" placeholder="请输入单位信息">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label"><span class="required">*</span> 姓名</div>
|
||||
<input class="form-input" id="formName" type="text" placeholder="请输入姓名">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label"><span class="required">*</span> 身份证号</div>
|
||||
<input class="form-input" id="formIdcard" type="text" placeholder="请输入身份证号">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">体检年份</div>
|
||||
<input class="form-input" id="formYear" type="text" placeholder="请输入体检年份">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">体检编号</div>
|
||||
<input class="form-input" id="formPeid" type="text" placeholder="请输入体检编号">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">医院ID</div>
|
||||
<input class="form-input" id="formHospid" type="text" placeholder="请输入医院ID">
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<div class="form-label">医院名称</div>
|
||||
<input class="form-input" id="formHospital" type="text" placeholder="请输入医院名称">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__footer">
|
||||
<button class="btn btn-default" onclick="closeForm()">取消</button>
|
||||
<button class="btn btn-primary" onclick="saveForm()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 详情弹窗 -->
|
||||
<div class="modal-mask" id="detailMask" onclick="if(event.target===this)closeDetail()">
|
||||
<div class="modal">
|
||||
<div class="modal__header">
|
||||
<span class="modal__close" onclick="closeDetail()">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3.5 3.5l9 9M12.5 3.5l-9 9" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>
|
||||
</span>
|
||||
<span class="modal__title">用户体检信息详情</span>
|
||||
</div>
|
||||
<div class="modal__body" id="detailBody"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ============ 数据 ============ */
|
||||
var handleStatusMap={1:'新建',2:'待解析',3:'失败',4:'解析中',5:'成功',6:'失败待重试',7:'最终失败'};
|
||||
@@ -481,7 +425,7 @@ function renderTable(){
|
||||
+'</span></td>'
|
||||
+'<td>'+u.unit+'</td><td>'+u.realname+'</td><td>'+u.idCard+'</td><td>'+u.medicalYear+'</td>'
|
||||
+'<td>'+u.hospitalName+'</td><td>'+u.peId+'</td><td>'+u.createTime+'</td>'
|
||||
+'<td><span class="link" onclick="openForm('+i+')">编辑</span> <span class="link" style="margin-left:8px;" onclick="openDetail('+i+')">详情</span> <span class="link-danger" style="margin-left:8px;" onclick="deleteRow('+i+')">删除</span></td>'
|
||||
+'<td><span class="link-danger" onclick="deleteRow('+i+')">删除</span></td>'
|
||||
+'</tr>';
|
||||
if(isOpen)html+=renderExpandRow(i);
|
||||
return html;
|
||||
@@ -495,21 +439,21 @@ function renderExpandRow(i){
|
||||
var u=users[i];
|
||||
var body='';
|
||||
if(!u.children.length){
|
||||
body='<tr><td colspan="4"><div class="inner-empty" style="padding:16px 0;text-align:center;">暂无检查项目数据</div></td></tr>';
|
||||
body='<tr><td colspan="5"><div class="inner-empty" style="padding:16px 0;text-align:center;">暂无检查项目数据</div></td></tr>';
|
||||
}else{
|
||||
body=u.children.map(function(c){
|
||||
body=u.children.map(function(c,ci){
|
||||
var studiesHtml=c.studies.length?c.studies.map(function(s){
|
||||
return '<span class="link" style="margin-right:6px;" onclick="previewStudy(\''+s+'\')">预览</span>';
|
||||
}).join(''):'<span class="inner-empty">暂无</span>';
|
||||
var filesHtml=c.files.length?c.files.map(function(f){
|
||||
return '<span class="link" style="margin-right:6px;" onclick="viewReport(\''+f+'\')">查看</span>';
|
||||
}).join(''):'<span class="inner-empty">无文件</span>';
|
||||
return '<tr><td>'+c.name+'</td><td>'+statusTag(c.status)+'</td><td>'+studiesHtml+'</td><td>'+filesHtml+'</td></tr>';
|
||||
return '<tr><td>'+(ci+1)+'</td><td>'+c.name+'</td><td>'+statusTag(c.status)+'</td><td>'+studiesHtml+'</td><td>'+filesHtml+'</td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
return '<tr class="expand-row"><td colspan="11"><div class="inner-wrap">'
|
||||
+'<table class="inner-table"><thead><tr>'
|
||||
+'<th>检查项目名称</th><th>处理状态</th><th>影像信息</th><th>影像报告</th>'
|
||||
+'<th style="width:56px;">序号</th><th>检查项目名称</th><th>处理状态</th><th>影像信息</th><th>影像报告</th>'
|
||||
+'</tr></thead><tbody>'+body+'</tbody></table>'
|
||||
+'</div></td></tr>';
|
||||
}
|
||||
@@ -588,59 +532,6 @@ function batchDelete(){
|
||||
renderTable();
|
||||
}
|
||||
|
||||
/* ============ 详情 ============ */
|
||||
function openDetail(idx){
|
||||
var u=users[idx];
|
||||
document.getElementById('detailBody').innerHTML=
|
||||
'<table class="detail-table"><tbody>'
|
||||
+'<tr><th>单位信息</th><td>'+u.unit+'</td></tr>'
|
||||
+'<tr><th>姓名</th><td>'+u.realname+'</td></tr>'
|
||||
+'<tr><th>身份证号</th><td>'+u.idCard+'</td></tr>'
|
||||
+'<tr><th>体检年份</th><td>'+u.medicalYear+'</td></tr>'
|
||||
+'<tr><th>体检编号</th><td>'+u.peId+'</td></tr>'
|
||||
+'<tr><th>医院ID</th><td>'+u.hospitalId+'</td></tr>'
|
||||
+'<tr><th>医院名称</th><td>'+u.hospitalName+'</td></tr>'
|
||||
+'</tbody></table>';
|
||||
document.getElementById('detailMask').classList.add('open');
|
||||
}
|
||||
function closeDetail(){document.getElementById('detailMask').classList.remove('open');}
|
||||
|
||||
/* ============ 编辑 ============ */
|
||||
var editingIdx=null;
|
||||
function openForm(idx){
|
||||
editingIdx=idx;
|
||||
document.getElementById('formTitle').textContent='编辑用户体检信息';
|
||||
var u=users[idx];
|
||||
document.getElementById('formUnit').value=u.unit;
|
||||
document.getElementById('formName').value=u.realname;
|
||||
document.getElementById('formIdcard').value=u.idCard;
|
||||
document.getElementById('formYear').value=u.medicalYear;
|
||||
document.getElementById('formPeid').value=u.peId;
|
||||
document.getElementById('formHospid').value=u.hospitalId;
|
||||
document.getElementById('formHospital').value=u.hospitalName;
|
||||
document.getElementById('formMask').classList.add('open');
|
||||
}
|
||||
function closeForm(){document.getElementById('formMask').classList.remove('open');}
|
||||
function saveForm(){
|
||||
var name=document.getElementById('formName').value.trim();
|
||||
var idcard=document.getElementById('formIdcard').value.trim();
|
||||
if(!name){alert('请输入姓名');return;}
|
||||
if(!idcard){alert('请输入身份证号');return;}
|
||||
var u=users[editingIdx];
|
||||
u.unit=document.getElementById('formUnit').value.trim();
|
||||
u.realname=name;
|
||||
u.idCard=idcard;
|
||||
u.medicalYear=document.getElementById('formYear').value.trim();
|
||||
u.peId=document.getElementById('formPeid').value.trim();
|
||||
u.hospitalId=document.getElementById('formHospid').value.trim();
|
||||
u.hospitalName=document.getElementById('formHospital').value.trim();
|
||||
closeForm();
|
||||
renderTable();
|
||||
}
|
||||
document.addEventListener('keydown',function(e){
|
||||
if(e.key==='Escape'){closeForm();closeDetail();}
|
||||
});
|
||||
|
||||
/* ============ 通用 ============ */
|
||||
function toggleSubgroup(header){
|
||||
header.parentElement.classList.toggle('open');
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -140,6 +140,7 @@
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -168,7 +169,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -178,7 +179,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -132,6 +132,7 @@
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item active">医院体检项目统计</a>
|
||||
@@ -160,7 +161,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -170,7 +171,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
常规体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-employee.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-employee.html" class="sidebar-item">常规体检报告</a>
|
||||
<a href="post-group-report.html" class="sidebar-item">单位群体报告</a>
|
||||
<a href="post-employee-master.html" class="sidebar-item">员工体检大表</a>
|
||||
<a href="post-illness-personnel.html" class="sidebar-item">大病人员信息</a>
|
||||
@@ -165,6 +165,7 @@
|
||||
<a href="post-unit-count.html" class="sidebar-item">单位体检人数统计</a>
|
||||
<a href="post-unit-cost-stat.html" class="sidebar-item">单位体检费用统计</a>
|
||||
<a href="post-unit-item-stat.html" class="sidebar-item">单位体检项目统计</a>
|
||||
<a href="post-result-comprehensive-stat.html" class="sidebar-item">项目结果综合统计</a>
|
||||
<a href="post-hospital-count.html" class="sidebar-item">医院体检人数统计</a>
|
||||
<a href="post-doctor-count.html" class="sidebar-item">医生检查人数统计</a>
|
||||
<a href="post-item-stat.html" class="sidebar-item">医院体检项目统计</a>
|
||||
@@ -193,7 +194,7 @@
|
||||
胃肠镜体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-report-gastro.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-report-gastro.html" class="sidebar-item">胃肠镜体检报告</a>
|
||||
<a href="post-gastro-stat.html" class="sidebar-item">胃肠镜体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -203,7 +204,7 @@
|
||||
冠脉CTA体检
|
||||
</div>
|
||||
<div class="sidebar-subgroup__body">
|
||||
<a href="post-cta-report.html" class="sidebar-item">员工体检报告</a>
|
||||
<a href="post-cta-report.html" class="sidebar-item">冠脉CTA体检报告</a>
|
||||
<a href="post-cta-stat.html" class="sidebar-item">冠脉CTA体检统计</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||