feat: 健康监测模块同步—清理废弃页面、补充环境监测页面、导航页与PRD对齐

- 删除 web-admin 健康监测 7 个废弃页面(survey-question/score/template、maxim、record-user/dept)
- 删除 employee-app 健康监测 5 个废弃健康排查页面与 3 个废弃体重监测截图
- 新增 employee-app 环境监测多分类截图(indoor/outdoor/water/pollen 各维度细分)
- 更新 index.html 导航页:健康监测条目对齐磁盘实际文件,web 端标记为已完成
- 同步更新 PRD、design-overview、CHANGELOG 及相关页面截图

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
liuyunqin
2026-06-09 17:53:44 +08:00
co-authored by Claude Opus 4.7
parent 7cd7e83679
commit 9b57f6164e
162 changed files with 1191 additions and 3373 deletions
@@ -0,0 +1,182 @@
/**
* 健康监测模块 PRD 截图脚本
*
* 用法:node screenshot-prd.js [--only=过滤]
*
* 行为:
* - 通过 file:// 加载 HTML(避免 server 登录),保持自包含原型可独立截图
* - 视口 1440×900;页面截图 fullPage=true;弹窗截图 fullPage=false
* - JPEG 质量 85%,保存到 doc/screenshots/ 下,路径与 PRD 引用一致
*/
const { chromium } = require('playwright');
const path = require('path');
const fs = require('fs');
const delay = ms => new Promise(r => setTimeout(r, ms));
const MODULE_DIR = path.resolve(__dirname, '..');
const SCREENSHOTS_DIR = path.join(__dirname, 'screenshots');
const baseUrl = 'file:///' + MODULE_DIR.replace(/\\/g, '/');
/* ========================
* 任务列表
* 每项:{ page, output, action?, fullPage? }
* - page: HTML 相对 MODULE_DIR 的路径
* - output: 截图相对 SCREENSHOTS_DIR 的路径
* - action: 弹窗触发 JS 字符串(可选;不传则为页面截图)
* - fullPage: 默认页面 true、弹窗 false;可手动覆盖
* ======================== */
const TASKS = [
// ===== 一、档案 =====
{ page: 'archive-personal.html', output: 'archive-personal.jpg' },
{ page: 'archive-personal-detail.html', output: 'archive-personal-detail.jpg' },
{ page: 'archive-unit.html', output: 'archive-unit.jpg' },
{ page: 'archive-unit-crowd-status-detail.html', output: 'archive-unit-crowd-status-detail.jpg' },
{ page: 'archive-unit-health-checkup-detail.html', output: 'archive-unit-health-checkup-detail.jpg' },
{ page: 'archive-unit-wearable-detail.html', output: 'archive-unit-wearable-detail.jpg' },
{ page: 'archive-unit-environment-detail.html', output: 'archive-unit-environment-detail.jpg' },
{ page: 'archive-algorithm.html', output: 'archive-algorithm.jpg' },
// ===== 二、健康现状 =====
{ page: 'crowd-status-employee.html', output: 'crowd-status-employee.jpg' },
{ page: 'crowd-status-unit.html', output: 'crowd-status-unit.jpg' },
// ===== 三、健康排查 =====
{ page: 'health-checkup/survey-manage.html', output: 'health-checkup/survey-manage.jpg' },
{ page: 'health-checkup/survey-edit.html', output: 'health-checkup/survey-edit.jpg' },
{ page: 'health-checkup/activity-manage.html', output: 'health-checkup/activity-manage.jpg' },
{ page: 'health-checkup/activity-edit.html', output: 'health-checkup/activity-edit.jpg' },
{ page: 'health-checkup/activity-detail.html', output: 'health-checkup/activity-detail.jpg' },
{ page: 'health-checkup/activity-stat.html', output: 'health-checkup/activity-stat.jpg' },
// ===== watch5 告警类 =====
{ page: 'wearable/ops/alarm-heartrate.html', output: 'wearable/ops/alarm-heartrate.jpg' },
{ page: 'wearable/ops/alarm-spo2.html', output: 'wearable/ops/alarm-spo2.jpg' },
{ page: 'wearable/ops/alarm-temp.html', output: 'wearable/ops/alarm-temp.jpg' },
{ page: 'wearable/ops/alarm-stress.html', output: 'wearable/ops/alarm-stress.jpg' },
{ page: 'wearable/ops/monitor-sleep-watch5.html', output: 'wearable/ops/monitor-sleep-watch5.jpg' },
// ===== 四、穿戴监测 =====
{ page: 'wearable/tool-manage.html', output: 'wearable/tool-manage.jpg' },
{ page: 'wearable/tool-manage.html', output: 'wearable/tool-manage/add.jpg',
action: `openAddModal()` },
{ page: 'wearable/tool-manage.html', output: 'wearable/tool-manage/bind.jpg',
action: `openBindModal('WD-2024-015','')` },
{ page: 'wearable/tool-manage.html', output: 'wearable/tool-manage/unbind-confirm.jpg',
action: `openUnbindConfirm('WD-2024-001','采油一厂','张伟')` },
{ page: 'wearable/tool-manage.html', output: 'wearable/tool-manage/bind-record.jpg',
action: `openBindRecord('WD-2024-001')` },
{ page: 'wearable/tool-manage.html', output: 'wearable/tool-manage/import.jpg',
action: `openImportModal()` },
{ page: 'wearable/tool-manage.html', output: 'wearable/tool-manage/monitor-switch.jpg',
action: `openMonitorSwitch('WD-2024-001')` },
{ page: 'wearable/bind-record.html', output: 'wearable/bind-record.jpg' },
{ page: 'wearable/user-data.html', output: 'wearable/user-data.jpg' },
{ page: 'wearable/user-data.html', output: 'wearable/user-data-detail.jpg',
action: `openDetail('张伟','CQ001234')` },
{ page: 'wearable/exception-event.html', output: 'wearable/exception-event.jpg' },
{ page: 'wearable/exception-event.html', output: 'wearable/exception-event-detail.jpg',
action: `clickFirstLink('详情')` },
{ page: 'wearable/notification.html', output: 'wearable/notification.jpg' },
{ page: 'wearable/notification.html', output: 'wearable/notification/send.jpg',
action: `openSendModal()` },
{ page: 'wearable/notification.html', output: 'wearable/notification/detail.jpg',
action: `openDetailModal(0)` },
{ page: 'wearable/notification.html', output: 'wearable/notification/read-stat.jpg',
action: `openReadStat()` },
{ page: 'wearable/dept-stat.html', output: 'wearable/dept-stat.jpg' },
{ page: 'wearable/dept-stat.html', output: 'wearable/dept-stat/detail.jpg',
action: `openDetailModal('采油一厂','')` },
{ page: 'wearable/dept-report.html', output: 'wearable/dept-report.jpg' },
{ page: 'wearable/personal-stat.html', output: 'wearable/personal-stat.jpg' },
// ===== 五、运维中心 =====
{ page: 'wearable/ops/terminal-default-config.html', output: 'wearable/ops/terminal-default-config.jpg' },
{ page: 'wearable/ops/terminal-config-info.html', output: 'wearable/ops/terminal-config-info.jpg' },
{ page: 'wearable/ops/terminal-config-info.html', output: 'wearable/ops/terminal-config-info-detail.jpg',
action: `clickFirstLink('详情')` },
...['monitor-ecg','monitor-spo2','monitor-temp','monitor-stress','monitor-exercise',
'monitor-heartrate','monitor-sleep','sdc-overview','monitor-activity','alarm-data',
'log-network','log-version','log-error','log-task','log-mqtt'
].flatMap(name => [
{ page: `wearable/ops/${name}.html`, output: `wearable/ops/${name}.jpg` },
{ page: `wearable/ops/${name}.html`, output: `wearable/ops/${name}-detail.jpg`,
action: `clickFirstLink('详情')` },
]),
// ===== 六、环境监测(PRD 只列了 indoor =====
{ page: 'environment/indoor-device-list.html', output: 'environment/indoor-device-list.jpg' },
{ page: 'environment/indoor-device-category.html', output: 'environment/indoor-device-category.jpg' },
{ page: 'environment/indoor-data-analysis.html', output: 'environment/indoor-data-analysis.jpg' },
{ page: 'environment/indoor-data-monitor.html', output: 'environment/indoor-data-monitor.jpg' },
{ page: 'environment/indoor-exception-alarm.html', output: 'environment/indoor-exception-alarm.jpg' },
{ page: 'environment/indoor-app-record.html', output: 'environment/indoor-app-record.jpg' },
{ page: 'environment/indoor-history-data.html', output: 'environment/indoor-history-data.jpg' },
{ page: 'environment/indoor-history-monitor-detail.html', output: 'environment/indoor-history-monitor-detail.jpg' },
{ page: 'environment/indoor-history-alarm-detail.html', output: 'environment/indoor-history-alarm-detail.jpg' },
// ===== 七、异常事件 =====
{ page: 'exception-dirty.html', output: 'exception-dirty.jpg' },
{ page: 'exception-result.html', output: 'exception-result.jpg' },
];
/* ========== 主流程 ========== */
(async () => {
const onlyArg = (process.argv.find(a => a.startsWith('--only=')) || '').slice('--only='.length);
const tasks = onlyArg ? TASKS.filter(t => t.output.includes(onlyArg)) : TASKS;
console.log(`[i] Total tasks: ${tasks.length}`);
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({ viewport: { width: 1440, height: 900 }, deviceScaleFactor: 1 });
const page = await context.newPage();
// 注入辅助函数:clickFirstLink(textIncludes) — 用于触发表格行内"详情"等 .link 链接
await context.addInitScript(() => {
window.clickFirstLink = function(text) {
const el = [...document.querySelectorAll('.link, .btn-link, a, span[onclick]')]
.find(e => e.textContent.trim() === text || e.textContent.includes(text));
if (el) el.click();
else throw new Error('clickFirstLink: not found: ' + text);
};
});
let ok = 0, fail = 0;
const failures = [];
for (const task of tasks) {
const fullPage = task.fullPage !== undefined ? task.fullPage : !task.action;
const outPath = path.join(SCREENSHOTS_DIR, task.output);
const outDir = path.dirname(outPath);
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
try {
await page.goto(`${baseUrl}/${task.page}`, { waitUntil: 'networkidle', timeout: 30000 });
await delay(150);
if (task.action) {
await page.evaluate(task.action);
await delay(350);
}
await page.screenshot({ path: outPath, type: 'jpeg', quality: 85, fullPage });
ok++;
console.log(`${task.output}`);
} catch (err) {
fail++;
failures.push({ output: task.output, error: err.message });
console.log(`${task.output} -- ${err.message}`);
}
}
await browser.close();
console.log(`\n[Done] success=${ok} fail=${fail} out=${SCREENSHOTS_DIR}`);
if (failures.length) {
console.log('\nFailures:');
failures.forEach(f => console.log(` - ${f.output}: ${f.error}`));
process.exit(1);
}
})();
Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 KiB

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 95 KiB

@@ -157,11 +157,8 @@
<aside class="sidebar">
<div class="sidebar-menu__title">健康排查</div>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-manage.html" class="sidebar-item active">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item active" id="sidebarActManage">活动管理</a>
<a href="activity-stat.html" class="sidebar-item" id="sidebarActStat">活动统计</a>
</aside>
<main class="main">
<!-- 面包屑 -->
@@ -209,9 +209,6 @@
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item active">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item active">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
</aside>
<main class="main">
<div class="form-card">
@@ -134,9 +134,6 @@
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item active">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item active">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
</aside>
<main class="main">
<!-- 筛选栏 -->
@@ -118,9 +118,6 @@
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item active">活动统计</a>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item active">活动统计</a>
</aside>
<main class="main">
<!-- 筛选栏 -->
@@ -1,231 +0,0 @@
<!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>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.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);}
.filter-bar{display:flex;align-items:center;gap:16px;margin-bottom:16px;background:#fff;padding:16px 24px;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;}
.form-control{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;}
.form-control:focus{border-color:var(--primary);}
textarea.form-control{height:auto;padding:10px 12px;resize:vertical;}
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
table{width:100%;border-collapse:collapse;}
thead th{background:#FAFAFA;padding:12px 16px;text-align:left;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.link{color:var(--primary);cursor:pointer;font-size:var(--font-sm);}.link:hover{color:#40a9ff;}
.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;}
.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);}
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:560px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal__header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal__header h3{font-size:var(--font-lg);font-weight:600;}
.modal__close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:20px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal__close:hover{background:#f5f5f5;}
.modal__body{padding:24px;}
.modal__footer{padding:16px 24px;border-top:1px solid var(--border);display:flex;justify-content:flex-end;gap:8px;}
.form-group{display:flex;flex-direction:column;gap:6px;margin-bottom:16px;}
.form-group label{font-size:var(--font-sm);color:var(--text-secondary);}
.td-content{max-width:360px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg> 健康监测</div>
<nav class="top-bar__nav">
<a href="../archive-personal.html">档案</a>
<a href="../crowd-status-employee.html">健康现状</a>
<a href="../health-checkup/survey-category.html" class="active">健康排查</a>
<a href="../wearable/tool-manage.html">穿戴监测</a>
<a href="../environment/indoor-device-list.html">健康环境</a>
<a href="../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">健康排查</div>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
</aside>
<main class="main">
<div class="filter-bar">
<div class="filter-item">
<span class="filter-item__label">格言内容</span>
<input class="form-control" id="filterContent" placeholder="请输入关键词" style="width:240px;">
</div>
<button class="btn btn-primary" onclick="filterTable()">查询</button>
<button class="btn btn-default" onclick="resetFilter()">重置</button>
</div>
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">格言列表</span>
<button class="btn btn-primary" onclick="openModal(null)">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
新增
</button>
</div>
<table>
<thead>
<tr>
<th>格言内容</th>
<th>格言作者</th>
<th>格言来源</th>
<th>创建日期</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tbody"></tbody>
</table>
</div>
</main>
<!-- 新增/编辑弹窗 -->
<div class="modal-mask" id="editModal">
<div class="modal">
<div class="modal__header">
<h3 id="modalTitle">新增格言</h3>
<button class="modal__close" onclick="closeModal()">×</button>
</div>
<div class="modal__body">
<div class="form-group">
<label>格言内容 <span style="color:var(--danger)">*</span></label>
<textarea class="form-control" id="editContent" rows="4" placeholder="请输入格言内容"></textarea>
</div>
<div class="form-group">
<label>格言作者</label>
<input class="form-control" id="editAuthor" placeholder="请输入作者">
</div>
<div class="form-group">
<label>格言来源</label>
<input class="form-control" id="editSource" placeholder="请输入来源">
</div>
</div>
<div class="modal__footer">
<button class="btn btn-default" onclick="closeModal()">取消</button>
<button class="btn btn-primary" onclick="saveMaxim()">确定</button>
</div>
</div>
</div>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var s=a.closest('.sidebar-subgroup');if(s)s.classList.add('open');})();
var maxims=[
{content:'健康是人生第一财富。',author:'爱默生',source:'《处世之道》',date:'2026-03-10'},
{content:'早睡早起,使人健康、富有、明智。',author:'富兰克林',source:'《穷理查年鉴》',date:'2026-03-12'},
{content:'运动是一切生命的源泉。',author:'达·芬奇',source:'《笔记》',date:'2026-03-15'},
{content:'保持身体健康是一种责任,否则我们将无法保持头脑清醒和强健。',author:'释迦牟尼',source:'佛经',date:'2026-03-18'},
{content:'饮食有节,起居有常,不妄作劳,故能形与神俱。',author:'黄帝内经',source:'《素问·上古天真论》',date:'2026-04-01'},
{content:'生命在于运动。',author:'伏尔泰',source:'',date:'2026-04-05'},
{content:'心宽体健,乐观长寿。',author:'民间谚语',source:'',date:'2026-04-10'}
];
var editingIdx=null;
function renderTable(data){
var html='';
data.forEach(function(m){
var idx=maxims.indexOf(m);
html+='<tr>';
html+='<td class="td-content" title="'+m.content+'">'+m.content+'</td>';
html+='<td>'+m.author+'</td>';
html+='<td>'+(m.source||'-')+'</td>';
html+='<td>'+m.date+'</td>';
html+='<td><span class="link" onclick="openModal('+idx+')">编辑</span>';
html+='<span style="color:var(--border);margin:0 6px;">|</span>';
html+='<span class="link" style="color:var(--danger);">删除</span></td>';
html+='</tr>';
});
document.getElementById('tbody').innerHTML=html||'<tr><td colspan="5" style="text-align:center;padding:40px;color:var(--text-placeholder);">暂无数据</td></tr>';
}
function filterTable(){
var kw=document.getElementById('filterContent').value.trim().toLowerCase();
var filtered=maxims.filter(function(m){
return !kw||m.content.toLowerCase().indexOf(kw)>-1;
});
renderTable(filtered);
}
function resetFilter(){
document.getElementById('filterContent').value='';
renderTable(maxims);
}
function openModal(idx){
editingIdx=idx;
if(idx===null){
document.getElementById('modalTitle').textContent='新增格言';
document.getElementById('editContent').value='';
document.getElementById('editAuthor').value='';
document.getElementById('editSource').value='';
}else{
var m=maxims[idx];
document.getElementById('modalTitle').textContent='编辑格言';
document.getElementById('editContent').value=m.content;
document.getElementById('editAuthor').value=m.author;
document.getElementById('editSource').value=m.source;
}
document.getElementById('editModal').classList.add('show');
}
function closeModal(){document.getElementById('editModal').classList.remove('show');}
function saveMaxim(){closeModal();}
renderTable(maxims);
document.getElementById('editModal').addEventListener('click',function(e){if(e.target===this)closeModal();});
</script>
</body>
</html>
@@ -1,332 +0,0 @@
<!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>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.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);}
.filter-bar{display:flex;align-items:center;gap:16px;margin-bottom:16px;background:#fff;padding:16px 24px;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item__label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.form-control{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;}
.form-control:focus{border-color:var(--primary);}
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
table{width:100%;border-collapse:collapse;}
thead th{background:#FAFAFA;padding:12px 16px;text-align:left;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.link{color:var(--primary);cursor:pointer;font-size:var(--font-sm);}.link:hover{color:#40a9ff;}
.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;}
.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);}
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:780px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal__header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal__header h3{font-size:var(--font-lg);font-weight:600;}
.modal__close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:20px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal__close:hover{background:#f5f5f5;}
.modal__body{padding:24px;}
.modal__footer{padding:16px 24px;border-top:1px solid var(--border);display:flex;justify-content:flex-end;gap:8px;}
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
.toast.show{opacity:1;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg> 健康监测</div>
<nav class="top-bar__nav">
<a href="../archive-personal.html">档案</a>
<a href="../crowd-status-employee.html">健康现状</a>
<a href="../health-checkup/survey-category.html" class="active">健康排查</a>
<a href="../wearable/tool-manage.html">穿戴监测</a>
<a href="../environment/indoor-device-list.html">健康环境</a>
<a href="../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">健康排查</div>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
</aside>
<main class="main">
<div class="filter-bar">
<div class="filter-item">
<span class="filter-item__label">记录日期</span>
<input class="form-control" id="filterDate" type="date" value="2026-05-13">
</div>
<div class="filter-item">
<span class="filter-item__label">单位</span>
<select class="form-control" id="filterUnit">
<option value="">全部单位</option>
</select>
</div>
<button class="btn btn-primary" onclick="filterTable()">查询</button>
<button class="btn btn-default" onclick="resetFilter()">重置</button>
</div>
<div style="margin-left:auto;display:flex;gap:8px;">
<button class="btn btn-default" onclick="showToast('导出任务已创建')">导出列表数据</button>
<button class="btn btn-default" onclick="showToast('暂无导出任务')">查看导出任务</button>
</div>
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">单位排查统计</span>
</div>
<table>
<thead>
<tr>
<th>单位名称</th>
<th>员工总数</th>
<th>已记录人数</th>
<th>未记录人数</th>
<th>记录日期</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tbody"></tbody>
</table>
</div>
</main>
<!-- 排查记录弹窗 -->
<div class="modal-mask" id="recordModal">
<div class="modal">
<div class="modal__header">
<h3 id="recordTitle">排查记录</h3>
<button class="modal__close" onclick="closeModal()">×</button>
</div>
<div class="modal__body">
<div style="display:flex;justify-content:flex-end;margin-bottom:12px;">
<button class="btn btn-default" onclick="showToast('导出成功')">导出</button>
</div>
<table>
<thead>
<tr>
<th>员工姓名</th>
<th>员工编号</th>
<th>单位名称</th>
<th>部门名称</th>
<th>是否记录</th>
<th>记录时间</th>
</tr>
</thead>
<tbody id="recordTbody"></tbody>
</table>
</div>
<div class="modal__footer">
<button class="btn btn-default" onclick="closeModal()">关闭</button>
</div>
</div>
</div>
<!-- 员工列表弹窗 -->
<div class="modal-mask" id="employeeModal">
<div class="modal">
<div class="modal__header">
<h3 id="employeeTitle">员工列表</h3>
<button class="modal__close" onclick="closeEmployeeModal()">×</button>
</div>
<div class="modal__body">
<div style="display:flex;justify-content:flex-end;margin-bottom:12px;">
<button class="btn btn-default" onclick="showToast('导出成功')">导出</button>
</div>
<table>
<thead>
<tr>
<th>员工姓名</th>
<th>员工编号</th>
<th>单位名称</th>
<th>部门名称</th>
<th id="signTimeHeader" style="display:none;">记录时间</th>
</tr>
</thead>
<tbody id="employeeTbody"></tbody>
</table>
</div>
<div class="modal__footer">
<button class="btn btn-default" onclick="closeEmployeeModal()">关闭</button>
</div>
</div>
</div>
<div class="toast" id="toast"></div>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var s=a.closest('.sidebar-subgroup');if(s)s.classList.add('open');})();
var units=['CQ能源公司','西安分公司','庆阳分公司'];
var deptData=[
{unit:'CQ能源公司',total:320,checked:298,unchecked:22,date:'2026-05-13'},
{unit:'西安分公司',total:85,checked:79,unchecked:6,date:'2026-05-13'},
{unit:'庆阳分公司',total:120,checked:108,unchecked:12,date:'2026-05-13'}
];
var recordData=[
{name:'张伟',code:'CQ10021',unit:'CQ能源公司',dept:'采油一厂',checked:'是',time:'2026-05-13 07:45'},
{name:'李娜',code:'CQ10035',unit:'CQ能源公司',dept:'采油二厂',checked:'是',time:'2026-05-13 08:02'},
{name:'王强',code:'CQ10048',unit:'CQ能源公司',dept:'采气一厂',checked:'是',time:'2026-05-13 07:30'},
{name:'马超',code:'CQ10055',unit:'CQ能源公司',dept:'采油一厂',checked:'否',time:'-'},
{name:'赵敏',code:'XA20012',unit:'CQ能源公司',dept:'输油处',checked:'是',time:'2026-05-13 08:15'},
{name:'刘洋',code:'CQ10070',unit:'CQ能源公司',dept:'采油三厂',checked:'否',time:'-'}
];
function initUnitSelect(){
var s=document.getElementById('filterUnit');
s.innerHTML='<option value="">全部单位</option>';
units.forEach(function(u){s.innerHTML+='<option>'+u+'</option>';});
}
function renderTable(data){
var html='';
data.forEach(function(d,i){
html+='<tr>';
html+='<td>'+d.unit+'</td>';
html+='<td>'+d.total+'</td>';
html+='<td><span class="link" onclick="openEmployeeModal('+i+', \'checked\')">'+d.checked+'</span></td>';
html+='<td><span class="link" onclick="openEmployeeModal('+i+', \'unchecked\')">'+d.unchecked+'</span></td>';
html+='<td>'+d.date+'</td>';
html+='<td><span class="link" onclick="showToast(\'导出成功\')">按日导出</span>';
html+='<span style="color:var(--border);margin:0 6px;">|</span>';
html+='<span class="link" onclick="openRecordModal('+i+')">排查记录</span></td>';
html+='</tr>';
});
document.getElementById('tbody').innerHTML=html||'<tr><td colspan="6" style="text-align:center;padding:40px;color:var(--text-placeholder);">暂无数据</td></tr>';
}
function filterTable(){
var unit=document.getElementById('filterUnit').value;
var filtered=deptData.filter(function(d){
if(unit&&d.unit!==unit)return false;
return true;
});
renderTable(filtered);
}
function resetFilter(){
document.getElementById('filterUnit').value='';
document.getElementById('filterDate').value='2026-05-13';
renderTable(deptData);
}
function openRecordModal(idx){
var d=deptData[idx];
document.getElementById('recordTitle').textContent=d.unit+' - 排查记录';
var html='';
recordData.forEach(function(r){
var checkedColor=r.checked==='是'?'var(--success)':'var(--danger)';
html+='<tr>';
html+='<td>'+r.name+'</td>';
html+='<td>'+r.code+'</td>';
html+='<td>'+r.unit+'</td>';
html+='<td>'+r.dept+'</td>';
html+='<td><span style="color:'+checkedColor+'">'+r.checked+'</span></td>';
html+='<td>'+r.time+'</td>';
html+='</tr>';
});
document.getElementById('recordTbody').innerHTML=html;
document.getElementById('recordModal').classList.add('show');
}
function closeModal(){document.getElementById('recordModal').classList.remove('show');}
function openEmployeeModal(idx, type){
var d=deptData[idx];
var isChecked=type==='checked';
var title=d.unit+' - '+(isChecked?'已记录':'未记录')+'员工列表';
document.getElementById('employeeTitle').textContent=title;
var signTimeHeader=document.getElementById('signTimeHeader');
if(isChecked){
signTimeHeader.style.display='';
}else{
signTimeHeader.style.display='none';
}
var html='';
recordData.forEach(function(r){
var isMatch=(isChecked&&r.checked==='是')||(isChecked===false&&r.checked==='否');
if(isMatch){
html+='<tr>';
html+='<td>'+r.name+'</td>';
html+='<td>'+r.code+'</td>';
html+='<td>'+r.unit+'</td>';
html+='<td>'+r.dept+'</td>';
if(isChecked){
html+='<td>'+r.time+'</td>';
}
html+='</tr>';
}
});
document.getElementById('employeeTbody').innerHTML=html||'<tr><td colspan="'+(isChecked?5:4)+'" style="text-align:center;padding:40px;color:var(--text-placeholder);">暂无数据</td></tr>';
document.getElementById('employeeModal').classList.add('show');
}
function closeEmployeeModal(){document.getElementById('employeeModal').classList.remove('show');}
function showToast(msg){
var t=document.getElementById('toast');
t.textContent=msg;t.classList.add('show');
setTimeout(function(){t.classList.remove('show');},2000);
}
initUnitSelect();
renderTable(deptData);
document.getElementById('recordModal').addEventListener('click',function(e){if(e.target===this)closeModal();});
document.getElementById('employeeModal').addEventListener('click',function(e){if(e.target===this)closeEmployeeModal();});
</script>
</body>
</html>
@@ -1,386 +0,0 @@
<!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>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.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);}
.filter-bar{display:flex;align-items:center;gap:16px;margin-bottom:16px;background:#fff;padding:16px 24px;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);flex-wrap:wrap;}
.filter-item{display:flex;align-items:center;gap:8px;}
.filter-item__label{font-size:var(--font-sm);color:var(--text-secondary);white-space:nowrap;}
.form-control{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;}
.form-control:focus{border-color:var(--primary);}
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
.table-card__actions{display:flex;gap:8px;}
table{width:100%;border-collapse:collapse;}
thead th{background:#FAFAFA;padding:12px 16px;text-align:left;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.link{color:var(--primary);cursor:pointer;font-size:var(--font-sm);}.link:hover{color:#40a9ff;}
.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;}
.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);}
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:560px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-lg{width:780px;}
.modal__header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal__header h3{font-size:var(--font-lg);font-weight:600;}
.modal__close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:20px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal__close:hover{background:#f5f5f5;}
.modal__body{padding:24px;}
.modal__footer{padding:16px 24px;border-top:1px solid var(--border);display:flex;justify-content:flex-end;gap:8px;}
.form-group{display:flex;flex-direction:column;gap:6px;margin-bottom:16px;}
.form-group label{font-size:var(--font-sm);color:var(--text-secondary);}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:16px;}
.info-card{background:var(--primary-light);border-radius:var(--radius-md);padding:16px 20px;margin-bottom:16px;display:flex;gap:24px;flex-wrap:wrap;}
.info-card__item{display:flex;flex-direction:column;gap:2px;}
.info-card__label{font-size:var(--font-xs);color:var(--text-secondary);}
.info-card__value{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;}
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:#333;color:#fff;padding:10px 24px;border-radius:var(--radius-sm);font-size:var(--font-sm);z-index:9999;opacity:0;transition:opacity .2s;pointer-events:none;}
.toast.show{opacity:1;}
.cascade-wrap{display:flex;gap:8px;}
.cascade-wrap select{flex:1;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg> 健康监测</div>
<nav class="top-bar__nav">
<a href="../archive-personal.html">档案</a>
<a href="../crowd-status-employee.html">健康现状</a>
<a href="../health-checkup/survey-category.html" class="active">健康排查</a>
<a href="../wearable/tool-manage.html">穿戴监测</a>
<a href="../environment/indoor-device-list.html">健康环境</a>
<a href="../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">健康排查</div>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
</aside>
<main class="main">
<div class="filter-bar">
<div class="filter-item">
<span class="filter-item__label">姓名</span>
<input class="form-control" id="filterName" placeholder="请输入姓名" style="width:140px;">
</div>
<div class="filter-item">
<span class="filter-item__label">员工编号</span>
<input class="form-control" id="filterCode" placeholder="请输入编号" style="width:140px;">
</div>
<div class="filter-item">
<span class="filter-item__label">单位部门</span>
<select class="form-control" id="filterUnit" onchange="onUnitChange()">
<option value="">选择</option>
</select>
</div>
<button class="btn btn-primary" onclick="filterTable()">查询</button>
<button class="btn btn-default" onclick="resetFilter()">重置</button>
</div>
<div style="margin-left:auto;display:flex;gap:8px;">
<button class="btn btn-default" onclick="showToast('导出任务已创建')">导出列表数据</button>
<button class="btn btn-default" onclick="showToast('暂无导出任务')">查看导出任务</button>
</div>
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">员工排查统计</span>
</div>
<table>
<thead>
<tr>
<th>姓名</th>
<th>员工编号</th>
<th>单位名称</th>
<th>部门名称</th>
<th>总计积分</th>
<th>连续记录天数</th>
<th>最新记录时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tbody"></tbody>
</table>
</div>
</main>
<!-- 按月导出弹窗 -->
<div class="modal-mask" id="exportModal">
<div class="modal">
<div class="modal__header">
<h3>按月导出</h3>
<button class="modal__close" onclick="closeModal('exportModal')">×</button>
</div>
<div class="modal__body">
<div class="form-row">
<div class="form-group">
<label>开始月份 <span style="color:var(--danger)">*</span></label>
<input class="form-control" id="exportStart" type="month" value="2026-01">
</div>
<div class="form-group">
<label>结束月份 <span style="color:var(--danger)">*</span></label>
<input class="form-control" id="exportEnd" type="month" value="2026-05">
</div>
</div>
</div>
<div class="modal__footer">
<button class="btn btn-default" onclick="closeModal('exportModal')">取消</button>
<button class="btn btn-primary" onclick="doExport()">确认</button>
</div>
</div>
</div>
<!-- 排查记录弹窗 -->
<div class="modal-mask" id="recordModal">
<div class="modal modal-lg">
<div class="modal__header">
<h3>排查记录</h3>
<button class="modal__close" onclick="closeModal('recordModal')">×</button>
</div>
<div class="modal__body">
<div class="info-card" id="recordInfoCard"></div>
<table>
<thead>
<tr>
<th>记录时间</th>
<th>增加积分</th>
<th>操作</th>
</tr>
</thead>
<tbody id="recordTbody"></tbody>
</table>
</div>
<div class="modal__footer">
<button class="btn btn-default" onclick="closeModal('recordModal')">关闭</button>
</div>
</div>
</div>
<!-- 查看问卷弹窗 -->
<div class="modal-mask" id="surveyModal">
<div class="modal modal-lg">
<div class="modal__header">
<h3>问卷详情</h3>
<button class="modal__close" onclick="closeModal('surveyModal')">×</button>
</div>
<div class="modal__body" style="padding:0;">
<table>
<thead>
<tr>
<th>问题分类</th>
<th>问题描述</th>
<th>员工选项</th>
</tr>
</thead>
<tbody id="surveyTbody"></tbody>
</table>
</div>
<div class="modal__footer">
<button class="btn btn-default" onclick="closeModal('surveyModal')">关闭</button>
</div>
</div>
</div>
<div class="toast" id="toast"></div>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var s=a.closest('.sidebar-subgroup');if(s)s.classList.add('open');})();
var orgTree=[
{label:'CQ能源公司',children:['采油一厂','采油二厂','采油三厂','采气一厂','输油处']},
{label:'西安分公司',children:['技术中心','信息中心','后勤服务中心']},
{label:'庆阳分公司',children:['生产运行部','安全环保部','人力资源部']}
];
var employees=[
{name:'张伟',code:'CQ10021',unit:'CQ能源公司',dept:'采油一厂',score:186,days:32,lastTime:'2026-05-13 07:45'},
{name:'李娜',code:'CQ10035',unit:'CQ能源公司',dept:'采油二厂',score:152,days:18,lastTime:'2026-05-13 08:02'},
{name:'王强',code:'CQ10048',unit:'CQ能源公司',dept:'采气一厂',score:210,days:45,lastTime:'2026-05-12 07:30'},
{name:'赵敏',code:'XA20012',unit:'西安分公司',dept:'技术中心',score:98,days:12,lastTime:'2026-05-13 08:15'},
{name:'刘洋',code:'XA20025',unit:'西安分公司',dept:'信息中心',score:134,days:22,lastTime:'2026-05-11 07:55'},
{name:'陈静',code:'QY30008',unit:'庆阳分公司',dept:'生产运行部',score:167,days:28,lastTime:'2026-05-13 07:38'},
{name:'周磊',code:'QY30015',unit:'庆阳分公司',dept:'安全环保部',score:78,days:8,lastTime:'2026-05-10 08:20'},
{name:'孙丽',code:'CQ10062',unit:'CQ能源公司',dept:'输油处',score:145,days:20,lastTime:'2026-05-12 08:10'}
];
var checkRecords=[
{time:'2026-05-13 07:45',score:5,status:'已完成'},
{time:'2026-05-12 07:42',score:5,status:'已完成'},
{time:'2026-05-11 07:50',score:5,status:'已完成'},
{time:'2026-05-10 07:38',score:3,status:'部分完成'},
{time:'2026-05-09 07:55',score:5,status:'已完成'},
{time:'2026-05-08 08:01',score:5,status:'已完成'}
];
var surveyAnswers=[
{cat:'饮食习惯',desc:'今天是否按时吃早餐?',answer:'是'},
{cat:'饮食习惯',desc:'今天饮水量是否达到1500ml',answer:'是'},
{cat:'运动锻炼',desc:'今天是否进行了30分钟以上运动?',answer:'否'},
{cat:'睡眠质量',desc:'昨晚睡眠时间是否达到7小时?',answer:'是'},
{cat:'心理状态',desc:'今天是否感到焦虑或压力过大?',answer:'否'}
];
// 初始化单位下拉
function initUnitSelect(){
var s=document.getElementById('filterUnit');
s.innerHTML='<option value="">请选择</option>';
orgTree.forEach(function(o){s.innerHTML+='<option>'+o.label+'</option>';});
}
function onUnitChange(){
var s1=document.getElementById('filterUnit'),s2=document.getElementById('filterDept');
s2.innerHTML='<option value="">请选择</option>';
if(!s1.value)return;
var node=orgTree.find(function(o){return o.label===s1.value;});
if(node)node.children.forEach(function(d){s2.innerHTML+='<option>'+d+'</option>';});
}
function renderTable(data){
var html='';
data.forEach(function(e,i){
var idx=employees.indexOf(e);
html+='<tr>';
html+='<td>'+e.name+'</td>';
html+='<td>'+e.code+'</td>';
html+='<td>'+e.unit+'</td>';
html+='<td>'+e.dept+'</td>';
html+='<td style="font-weight:600;color:var(--primary);">'+e.score+'</td>';
html+='<td>'+e.days+'天</td>';
html+='<td>'+e.lastTime+'</td>';
html+='<td><span class="link" onclick="openExportModal('+idx+')">按月导出</span>';
html+='<span style="color:var(--border);margin:0 6px;">|</span>';
html+='<span class="link" onclick="openRecordModal('+idx+')">排查记录</span></td>';
html+='</tr>';
});
document.getElementById('tbody').innerHTML=html||'<tr><td colspan="8" style="text-align:center;padding:40px;color:var(--text-placeholder);">暂无数据</td></tr>';
}
function filterTable(){
var name=document.getElementById('filterName').value.trim();
var code=document.getElementById('filterCode').value.trim();
var unit=document.getElementById('filterUnit').value;
var dept=document.getElementById('filterDept').value;
var filtered=employees.filter(function(e){
if(name&&e.name.indexOf(name)===-1)return false;
if(code&&e.code.indexOf(code)===-1)return false;
if(unit&&e.unit!==unit)return false;
if(dept&&e.dept!==dept)return false;
return true;
});
renderTable(filtered);
}
function resetFilter(){
document.getElementById('filterName').value='';
document.getElementById('filterCode').value='';
document.getElementById('filterUnit').value='';
document.getElementById('filterDept').innerHTML='<option value="">选择部门</option>';
renderTable(employees);
}
function openExportModal(){document.getElementById('exportModal').classList.add('show');}
function doExport(){
closeModal('exportModal');
showToast('导出成功');
}
function openRecordModal(idx){
var e=employees[idx];
var card=document.getElementById('recordInfoCard');
card.innerHTML='<div class="info-card__item"><span class="info-card__label">姓名</span><span class="info-card__value">'+e.name+'</span></div>'
+'<div class="info-card__item"><span class="info-card__label">员工编号</span><span class="info-card__value">'+e.code+'</span></div>'
+'<div class="info-card__item"><span class="info-card__label">单位</span><span class="info-card__value">'+e.unit+'</span></div>'
+'<div class="info-card__item"><span class="info-card__label">部门</span><span class="info-card__value">'+e.dept+'</span></div>'
+'<div class="info-card__item"><span class="info-card__label">总积分</span><span class="info-card__value">'+e.score+'</span></div>'
+'<div class="info-card__item"><span class="info-card__label">连续记录</span><span class="info-card__value">'+e.days+'天</span></div>';
var html='';
checkRecords.forEach(function(r,i){
html+='<tr>';
html+='<td>'+r.time+'</td>';
html+='<td>+'+r.score+'</td>';
html+='<td><span class="link" onclick="openSurveyModal()">查看问卷</span></td>';
html+='</tr>';
});
document.getElementById('recordTbody').innerHTML=html;
document.getElementById('recordModal').classList.add('show');
}
function openSurveyModal(){
var html='';
surveyAnswers.forEach(function(s){
html+='<tr><td>'+s.cat+'</td><td>'+s.desc+'</td><td>'+s.answer+'</td></tr>';
});
document.getElementById('surveyTbody').innerHTML=html;
document.getElementById('surveyModal').classList.add('show');
}
function closeModal(id){document.getElementById(id).classList.remove('show');}
function showToast(msg){
var t=document.getElementById('toast');
t.textContent=msg;t.classList.add('show');
setTimeout(function(){t.classList.remove('show');},2000);
}
// 初始化
initUnitSelect();
renderTable(employees);
document.querySelectorAll('.modal-mask').forEach(function(m){
m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});
});
</script>
</body>
</html>
@@ -129,9 +129,6 @@
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
</aside>
<main class="main">
<!-- 筛选栏 -->
@@ -252,9 +252,6 @@
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
</aside>
<main class="main">
<div class="editor-layout">
@@ -1,420 +0,0 @@
<!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>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.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);}
.filter-bar{display:flex;align-items:center;gap:16px;margin-bottom:16px;flex-wrap:wrap;background:#fff;padding:16px 24px;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-bar .form-control{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;min-width:140px;}
.filter-bar .form-control:focus{border-color:var(--primary);}
/* 级联下拉 */
.cascade-select{position:relative;display:inline-block;}
.cascade-select__trigger{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 32px 0 12px;font-size:var(--font-sm);background:#fff;cursor:pointer;display:flex;align-items:center;min-width:180px;color:var(--text-primary);user-select:none;}
.cascade-select__trigger.placeholder{color:var(--text-placeholder);}
.cascade-select__trigger::after{content:'';position:absolute;right:12px;top:50%;transform:translateY(-50%);border:4px solid transparent;border-top:5px solid #999;}
.cascade-select__panel{position:absolute;top:100%;left:0;margin-top:4px;background:#fff;border:1px solid var(--border);border-radius:var(--radius-md);box-shadow:0 4px 12px rgba(0,0,0,0.12);z-index:300;display:none;white-space:nowrap;}
.cascade-select__panel.show{display:flex;}
.cascade-select__col{min-width:140px;max-height:260px;overflow-y:auto;border-right:1px solid var(--border);padding:6px 0;}
.cascade-select__col:last-child{border-right:none;}
.cascade-select__opt{padding:8px 16px;font-size:var(--font-sm);cursor:pointer;transition:background .1s;}
.cascade-select__opt:hover{background:#F5F7FA;}
.cascade-select__opt.active{color:var(--primary);background:var(--primary-light);}
/* 问题选项 */
.option-list{display:flex;flex-direction:column;gap:8px;}
.option-item{display:flex;align-items:center;gap:8px;}
.option-item input{flex:1;height:32px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 10px;font-size:var(--font-sm);outline:none;}
.option-item input:focus{border-color:var(--primary);}
.option-item .btn-icon{width:28px;height:28px;border:none;background:none;cursor:pointer;border-radius:var(--radius-sm);display:flex;align-items:center;justify-content:center;color:var(--text-secondary);transition:all .15s;}
.option-item .btn-icon:hover{background:#FFF1F0;color:var(--danger);}
.btn-add-option{display:inline-flex;align-items:center;gap:4px;color:var(--primary);font-size:var(--font-sm);cursor:pointer;padding:4px 0;border:none;background:none;}
.btn-add-option:hover{color:#40a9ff;}
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
table{width:100%;border-collapse:collapse;}
thead th{background:#FAFAFA;padding:12px 16px;text-align:left;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-blue{background:var(--primary-light);color:var(--primary);}
.tag-green{background:#F6FFED;color:var(--success);}
.tag-gray{background:#F5F5F5;color:#666;}
.link{color:var(--primary);cursor:pointer;font-size:var(--font-sm);}.link:hover{color:#40a9ff;}
.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;}
.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);}
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:640px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal__header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal__header h3{font-size:var(--font-lg);font-weight:600;}
.modal__close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:20px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal__close:hover{background:#f5f5f5;}
.modal__body{padding:24px;}
.modal__footer{padding:16px 24px;border-top:1px solid var(--border);display:flex;justify-content:flex-end;gap:8px;}
.form-group{display:flex;flex-direction:column;gap:6px;margin-bottom:16px;}
.form-group label{font-size:var(--font-sm);color:var(--text-secondary);}
.form-group .form-control{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;}
.form-group .form-control:focus{border-color:var(--primary);}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg> 健康监测</div>
<nav class="top-bar__nav">
<a href="../archive-personal.html">档案</a>
<a href="../crowd-status-employee.html">健康现状</a>
<a href="../health-checkup/survey-category.html" class="active">健康排查</a>
<a href="../wearable/tool-manage.html">穿戴监测</a>
<a href="../environment/indoor-device-list.html">健康环境</a>
<a href="../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">健康排查</div>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
</aside>
<main class="main">
<div class="filter-bar">
<div class="filter-item">
<span class="filter-item__label">问题分类</span>
<div class="cascade-select" id="filterCascade">
<div class="cascade-select__trigger placeholder" onclick="toggleCascade('filterCascade')">请选择分类</div>
<div class="cascade-select__panel" id="filterPanel">
<div class="cascade-select__col" id="filterCol1"></div>
<div class="cascade-select__col" id="filterCol2" style="display:none;"></div>
</div>
</div>
</div>
<div class="filter-item">
<span class="filter-item__label">问题描述</span>
<input class="form-control" id="filterDesc" placeholder="请输入关键词" style="width:200px;">
</div>
<button class="btn btn-primary" onclick="filterTable()">查询</button>
<button class="btn btn-default" onclick="resetFilter()">重置</button>
</div>
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">问题列表</span>
<button class="btn btn-primary" onclick="openModal(null)">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
新增
</button>
</div>
<table>
<thead>
<tr>
<th>问题分类</th>
<th>问题描述</th>
<th>问题类型</th>
<th>问题排序</th>
<th>是否必填</th>
<th>频次</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tbody"></tbody>
</table>
</div>
</main>
<!-- 新增/编辑弹窗 -->
<div class="modal-mask" id="editModal">
<div class="modal">
<div class="modal__header">
<h3 id="modalTitle">新增问题</h3>
<button class="modal__close" onclick="closeModal()">×</button>
</div>
<div class="modal__body">
<div class="form-group">
<label>问题分类 <span style="color:var(--danger)">*</span></label>
<div class="cascade-select" id="editCascade">
<div class="cascade-select__trigger placeholder" onclick="toggleCascade('editCascade')">请选择分类</div>
<div class="cascade-select__panel" id="editPanel">
<div class="cascade-select__col" id="editCol1"></div>
<div class="cascade-select__col" id="editCol2" style="display:none;"></div>
</div>
</div>
</div>
<div class="form-group">
<label>问题描述 <span style="color:var(--danger)">*</span></label>
<input class="form-control" id="editDesc" placeholder="请输入问题描述">
</div>
<div class="form-row">
<div class="form-group">
<label>问题类型 <span style="color:var(--danger)">*</span></label>
<select class="form-control" id="editType" onchange="onTypeChange()">
<option>单选</option>
<option>多选</option>
</select>
</div>
<div class="form-group">
<label>问题排序</label>
<input class="form-control" id="editSort" type="number" placeholder="数字越小越靠前" min="1">
</div>
</div>
<div class="form-group">
<label>问题选项 <span style="color:var(--danger)">*</span></label>
<div class="option-list" id="optionList"></div>
<button class="btn-add-option" id="btnAddOption" onclick="addOption()" style="display:none;">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
添加选项
</button>
</div>
<div class="form-row">
<div class="form-group">
<label>是否必填</label>
<select class="form-control" id="editRequired">
<option value="是"></option>
<option value="否"></option>
</select>
</div>
<div class="form-group">
<label>频次 <span style="color:var(--danger)">*</span></label>
<select class="form-control" id="editFreq">
<option>每日</option>
<option>每周</option>
<option>每月</option>
<option>每季</option>
<option>每半年</option>
<option>每年</option>
<option>自定义时间</option>
</select>
</div>
</div>
</div>
<div class="modal__footer">
<button class="btn btn-default" onclick="closeModal()">取消</button>
<button class="btn btn-primary" onclick="saveQuestion()">确定</button>
</div>
</div>
</div>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var s=a.closest('.sidebar-subgroup');if(s)s.classList.add('open');})();
var categoryTree=[
{label:'生活习惯',children:['饮食习惯','运动锻炼','睡眠质量','体重管理']},
{label:'心理健康',children:['心理状态','压力管理','情绪调节']},
{label:'疾病管理',children:['慢病管理','用药提醒','康复训练']},
{label:'职业防护',children:['职业健康','劳动防护','职业禁忌']}
];
var questions=[
{cat1:'生活习惯',cat2:'饮食习惯',desc:'今天是否按时吃早餐?',type:'单选',sort:1,required:'是',freq:'每日',options:['是','否']},
{cat1:'生活习惯',cat2:'饮食习惯',desc:'今天饮水量是否达到1500ml',type:'单选',sort:2,required:'是',freq:'每日',options:['是','否']},
{cat1:'生活习惯',cat2:'运动锻炼',desc:'今天是否进行了30分钟以上运动?',type:'单选',sort:3,required:'是',freq:'每日',options:['是','否']},
{cat1:'生活习惯',cat2:'睡眠质量',desc:'昨晚睡眠时间是否达到7小时?',type:'单选',sort:4,required:'是',freq:'每日',options:['是','否']},
{cat1:'心理健康',cat2:'心理状态',desc:'今天是否感到焦虑或压力过大?',type:'单选',sort:5,required:'否',freq:'每周',options:['是','否']},
{cat1:'心理健康',cat2:'压力管理',desc:'本周是否进行了放松训练?',type:'多选',sort:6,required:'否',freq:'每周',options:['冥想','运动','阅读','听音乐','其他']},
{cat1:'疾病管理',cat2:'慢病管理',desc:'今天是否按时服药?',type:'单选',sort:7,required:'是',freq:'每日',options:['是','否']},
{cat1:'职业防护',cat2:'职业健康',desc:'今天工作中是否佩戴了防护用品?',type:'单选',sort:8,required:'是',freq:'每日',options:['是','否']},
{cat1:'职业防护',cat2:'劳动防护',desc:'本月是否参加了安全培训?',type:'单选',sort:9,required:'否',freq:'每月',options:['是','否']}
];
var editingIdx=null;
var currentOptions=[];
/* ===== 级联选择 ===== */
var cascadeState={filterCascade:{cat1:'',cat2:''},editCascade:{cat1:'',cat2:''}};
function toggleCascade(id){
var panel=document.getElementById(id==='filterCascade'?'filterPanel':'editPanel');
var isShow=panel.classList.contains('show');
closeAllCascade();
if(!isShow){panel.classList.add('show');renderCascadeCol1(id);}
}
function closeAllCascade(){
document.querySelectorAll('.cascade-select__panel').forEach(function(p){p.classList.remove('show');});
}
function renderCascadeCol1(id){
var col1=document.getElementById(id==='filterCascade'?'filterCol1':'editCol1');
var col2=document.getElementById(id==='filterCascade'?'filterCol2':'editCol2');
var state=cascadeState[id];
var html='';
categoryTree.forEach(function(c){
html+='<div class="cascade-select__opt'+(state.cat1===c.label?' active':'')+'" onclick="selectCat1(\''+id+'\',\''+c.label+'\')">'+c.label+'</div>';
});
col1.innerHTML=html;
if(state.cat1){renderCascadeCol2(id);}else{col2.style.display='none';}
}
function renderCascadeCol2(id){
var col2=document.getElementById(id==='filterCascade'?'filterCol2':'editCol2');
var state=cascadeState[id];
var node=categoryTree.find(function(c){return c.label===state.cat1;});
if(!node){col2.style.display='none';return;}
col2.style.display='';
var html='';
node.children.forEach(function(ch){
html+='<div class="cascade-select__opt'+(state.cat2===ch?' active':'')+'" onclick="selectCat2(\''+id+'\',\''+ch+'\')">'+ch+'</div>';
});
col2.innerHTML=html;
}
function selectCat1(id,val){
cascadeState[id].cat1=val;cascadeState[id].cat2='';
renderCascadeCol1(id);
}
function selectCat2(id,val){
cascadeState[id].cat2=val;
var trigger=document.querySelector('#'+id+' .cascade-select__trigger');
trigger.textContent=cascadeState[id].cat1+' / '+val;
trigger.classList.remove('placeholder');
closeAllCascade();
}
function setCascadeValue(id,cat1,cat2){
cascadeState[id]={cat1:cat1,cat2:cat2};
var trigger=document.querySelector('#'+id+' .cascade-select__trigger');
if(cat1&&cat2){trigger.textContent=cat1+' / '+cat2;trigger.classList.remove('placeholder');}
else{trigger.textContent='请选择分类';trigger.classList.add('placeholder');}
}
/* ===== 问题选项 ===== */
function renderOptions(){
var list=document.getElementById('optionList');
var html='';
currentOptions.forEach(function(opt,i){
html+='<div class="option-item">';
html+='<input value="'+opt+'" onchange="currentOptions['+i+']=this.value">';
html+='<button class="btn-icon" onclick="removeOption('+i+')" title="删除"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M3 3l8 8M11 3l-8 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg></button>';
html+='</div>';
});
list.innerHTML=html;
document.getElementById('btnAddOption').style.display='';
}
function addOption(){currentOptions.push('选项'+(currentOptions.length+1));renderOptions();}
function removeOption(i){if(currentOptions.length<=2)return;currentOptions.splice(i,1);renderOptions();}
function onTypeChange(){
var type=document.getElementById('editType').value;
if(type==='单选'){currentOptions=['是','否'];}
renderOptions();
}
/* ===== 表格 ===== */
function renderTable(data){
var html='';
data.forEach(function(q){
var idx=questions.indexOf(q);
html+='<tr>';
html+='<td>'+q.cat1+' / '+q.cat2+'</td>';
html+='<td>'+q.desc+'</td>';
html+='<td><span class="tag '+(q.type==='单选'?'tag-blue':'tag-green')+'">'+q.type+'</span></td>';
html+='<td>'+q.sort+'</td>';
html+='<td>'+q.required+'</td>';
html+='<td>'+q.freq+'</td>';
html+='<td><span class="link" onclick="openModal('+idx+')">编辑</span>';
html+='<span style="color:var(--border);margin:0 6px;">|</span>';
html+='<span class="link" style="color:var(--danger);">删除</span></td>';
html+='</tr>';
});
document.getElementById('tbody').innerHTML=html||'<tr><td colspan="7" style="text-align:center;padding:40px;color:var(--text-placeholder);">暂无数据</td></tr>';
}
function filterTable(){
var state=cascadeState.filterCascade;
var desc=document.getElementById('filterDesc').value.trim().toLowerCase();
var filtered=questions.filter(function(q){
if(state.cat1&&q.cat1!==state.cat1)return false;
if(state.cat2&&q.cat2!==state.cat2)return false;
if(desc&&q.desc.toLowerCase().indexOf(desc)===-1)return false;
return true;
});
renderTable(filtered);
}
function resetFilter(){
setCascadeValue('filterCascade','','');
document.getElementById('filterDesc').value='';
renderTable(questions);
}
/* ===== 弹窗 ===== */
function openModal(idx){
editingIdx=idx;
if(idx===null){
document.getElementById('modalTitle').textContent='新增问题';
setCascadeValue('editCascade','','');
document.getElementById('editDesc').value='';
document.getElementById('editType').value='单选';
document.getElementById('editSort').value='';
document.getElementById('editRequired').value='是';
document.getElementById('editFreq').value='每日';
currentOptions=['是','否'];
}else{
var q=questions[idx];
document.getElementById('modalTitle').textContent='编辑问题';
setCascadeValue('editCascade',q.cat1,q.cat2);
document.getElementById('editDesc').value=q.desc;
document.getElementById('editType').value=q.type;
document.getElementById('editSort').value=q.sort;
document.getElementById('editRequired').value=q.required;
document.getElementById('editFreq').value=q.freq;
currentOptions=q.options.slice();
}
renderOptions();
document.getElementById('editModal').classList.add('show');
}
function closeModal(){document.getElementById('editModal').classList.remove('show');closeAllCascade();}
function saveQuestion(){closeModal();}
// 初始化
renderTable(questions);
document.addEventListener('click',function(e){
if(!e.target.closest('.cascade-select'))closeAllCascade();
});
document.getElementById('editModal').addEventListener('click',function(e){if(e.target===this)closeModal();});
</script>
</body>
</html>
@@ -1,127 +0,0 @@
<!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>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.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);}
.score-wrap{display:flex;align-items:center;justify-content:center;height:calc(100vh - 56px - 48px);}
.score-card{background:#fff;border-radius:var(--radius-lg);box-shadow:var(--shadow-sm);padding:40px 48px;width:480px;}
.score-card__title{font-size:var(--font-lg);font-weight:600;margin-bottom:32px;text-align:center;}
.score-form-group{margin-bottom:24px;}
.score-form-group label{display:block;font-size:var(--font-sm);color:var(--text-secondary);margin-bottom:8px;}
.score-form-group .score-input{width:100%;height:40px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 14px;font-size:var(--font-sm);outline:none;transition:border-color .2s;}
.score-form-group .score-input:focus{border-color:var(--primary);}
.score-form-group .score-hint{font-size:var(--font-xs);color:var(--text-placeholder);margin-top:6px;}
.score-actions{display:flex;gap:12px;justify-content:center;margin-top:36px;}
.score-actions .btn{height:40px;padding:0 28px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:none;transition:all .2s;}
.score-actions .btn-primary{background:var(--primary);color:#fff;}
.score-actions .btn-primary:hover{background:#40a9ff;}
.score-actions .btn-default{background:#fff;color:var(--text-primary);border:1px solid var(--border);}
.score-actions .btn-default:hover{color:var(--primary);border-color:var(--primary);}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg> 健康监测</div>
<nav class="top-bar__nav">
<a href="../archive-personal.html">档案</a>
<a href="../crowd-status-employee.html">健康现状</a>
<a href="../health-checkup/survey-category.html" class="active">健康排查</a>
<a href="../wearable/tool-manage.html">穿戴监测</a>
<a href="../environment/indoor-device-list.html">健康环境</a>
<a href="../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">健康排查</div>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item active">活动统计</a>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
</aside>
<main class="main">
<div class="score-wrap">
<div class="score-card">
<div class="score-card__title">积分规则设置</div>
<div class="score-form-group">
<label>积分奖励起始值</label>
<input class="score-input" type="number" value="10" min="0">
<div class="score-hint">用户首次完成排查获得的基础积分</div>
</div>
<div class="score-form-group">
<label>积分奖励递增值</label>
<input class="score-input" type="number" value="5" min="0">
<div class="score-hint">连续完成排查时每次递增的积分数</div>
</div>
<div class="score-form-group">
<label>积分奖励最大值</label>
<input class="score-input" type="number" value="50" min="0">
<div class="score-hint">单次排查可获得的积分上限</div>
</div>
<div class="score-actions">
<button class="btn btn-primary" onclick="saveScore()">保存</button>
<button class="btn btn-default" onclick="resetScore()">重置</button>
</div>
</div>
</div>
</main>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var s=a.closest('.sidebar-subgroup');if(s)s.classList.add('open');})();
var defaults={start:10,step:5,max:50};
function saveScore(){alert('保存成功');}
function resetScore(){
var inputs=document.querySelectorAll('.score-input');
inputs[0].value=defaults.start;
inputs[1].value=defaults.step;
inputs[2].value=defaults.max;
}
</script>
</body>
</html>
@@ -1,478 +0,0 @@
<!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>
*{box-sizing:border-box;margin:0;padding:0;}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:#F5F7FA;color:#333;min-width:1280px;}
:root{
--primary:#1890FF;--primary-light:#E6F7FF;--success:#52C41A;--warning:#FAAD14;--danger:#FF4D4F;
--text-primary:#333;--text-secondary:#666;--text-placeholder:#999;--border:#E8E8E8;--background:#F5F7FA;
--font-xs:11px;--font-sm:13px;--font-base:15px;--font-lg:17px;
--radius-sm:4px;--radius-md:8px;--radius-lg:12px;
--shadow-sm:0 1px 4px rgba(0,0,0,0.08);
}
.top-bar{display:flex;align-items:center;height:56px;background:#001529;padding:0 24px;position:fixed;top:0;left:0;right:0;z-index:100;}
.top-bar__logo{display:flex;align-items:center;gap:8px;color:#fff;font-size:var(--font-lg);font-weight:600;white-space:nowrap;width:240px;flex-shrink:0;}
.top-bar__logo svg{width:28px;height:28px;}
.top-bar__right{display:flex;align-items:center;gap:16px;color:rgba(255,255,255,0.65);font-size:var(--font-sm);}
.btn-back{color:rgba(255,255,255,0.65);cursor:pointer;display:flex;align-items:center;gap:4px;text-decoration:none;}
.btn-back:hover{color:#fff;}
.avatar{width:32px;height:32px;border-radius:50%;background:#1890FF;display:flex;align-items:center;justify-content:center;color:#fff;font-size:var(--font-sm);cursor:pointer;}
.top-bar__nav{display:flex;align-items:center;gap:4px;flex:1;}
.top-bar__nav a{color:rgba(255,255,255,0.65);text-decoration:none;padding:6px 16px;border-radius:var(--radius-sm);font-size:var(--font-sm);transition:all .2s;}
.top-bar__nav a:hover{color:#fff;background:rgba(255,255,255,0.08);}
.top-bar__nav a.active{color:#fff;background:var(--primary);}
.sidebar{position:fixed;top:56px;left:0;bottom:0;width:240px;background:#001529;overflow-y:auto;z-index:90;padding-top:8px;}
.sidebar-menu__title{color:rgba(255,255,255,0.35);font-size:var(--font-xs);padding:16px 24px 8px;letter-spacing:.5px;}
.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);}
.table-card{background:#fff;border-radius:var(--radius-md);box-shadow:var(--shadow-sm);overflow:hidden;}
.table-card__header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);}
.table-card__title{font-size:var(--font-base);font-weight:600;}
table{width:100%;border-collapse:collapse;}
thead th{background:#FAFAFA;padding:12px 16px;text-align:left;font-size:var(--font-sm);color:var(--text-secondary);font-weight:500;border-bottom:1px solid var(--border);}
tbody td{padding:14px 16px;font-size:var(--font-sm);color:var(--text-primary);border-bottom:1px solid var(--border);}
tbody tr:last-child td{border-bottom:none;}
tbody tr:hover{background:#F8FBFF;}
.tag{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:var(--font-xs);}
.tag-green{background:#F6FFED;color:var(--success);}
.tag-gray{background:#F5F5F5;color:#666;}
/* Switch 开关 */
.switch{position:relative;display:inline-flex;align-items:center;gap:8px;cursor:pointer;user-select:none;}
.switch__track{width:36px;height:20px;border-radius:10px;background:#ccc;transition:background .2s;position:relative;flex-shrink:0;}
.switch__track.on{background:var(--primary);}
.switch__thumb{position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,0.2);transition:left .2s;}
.switch__track.on .switch__thumb{left:18px;}
.link{color:var(--primary);cursor:pointer;font-size:var(--font-sm);}.link:hover{color:#40a9ff;}
.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;}
.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);}
/* 弹窗 */
.modal-mask{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:500;display:flex;align-items:center;justify-content:center;opacity:0;pointer-events:none;transition:opacity .15s;}
.modal-mask.show{opacity:1;pointer-events:auto;}
.modal{background:#fff;border-radius:var(--radius-lg);width:640px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 40px rgba(0,0,0,0.18);}
.modal-lg{width:860px;}
.modal__header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid var(--border);}
.modal__header h3{font-size:var(--font-lg);font-weight:600;}
.modal__close{width:32px;height:32px;border:none;background:none;cursor:pointer;font-size:20px;color:var(--text-secondary);border-radius:var(--radius-sm);}
.modal__close:hover{background:#f5f5f5;}
.modal__body{padding:24px;}
.modal__footer{padding:16px 24px;border-top:1px solid var(--border);display:flex;justify-content:flex-end;gap:8px;}
.form-group{display:flex;flex-direction:column;gap:6px;margin-bottom:16px;}
.form-group label{font-size:var(--font-sm);color:var(--text-secondary);}
.form-control{height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 12px;font-size:var(--font-sm);outline:none;}
.form-control:focus{border-color:var(--primary);}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px;}
/* 多选标签 */
.tag-select{border:1px solid var(--border);border-radius:var(--radius-sm);padding:6px 10px;min-height:36px;display:flex;flex-wrap:wrap;gap:6px;align-items:center;cursor:text;position:relative;}
.tag-select:focus-within{border-color:var(--primary);}
.tag-select__tag{display:inline-flex;align-items:center;gap:4px;background:var(--primary-light);color:var(--primary);padding:2px 8px;border-radius:var(--radius-sm);font-size:var(--font-xs);}
.tag-select__tag .tag-remove{cursor:pointer;font-size:14px;line-height:1;}
.tag-select__tag .tag-remove:hover{color:var(--danger);}
.tag-select__input{border:none;outline:none;font-size:var(--font-sm);flex:1;min-width:80px;padding:0;}
.tag-select__dropdown{position:absolute;top:100%;left:-1px;right:-1px;margin-top:4px;background:#fff;border:1px solid var(--border);border-radius:var(--radius-md);box-shadow:0 4px 12px rgba(0,0,0,0.12);z-index:300;max-height:260px;overflow-y:auto;display:none;padding:8px 0;}
.tag-select__dropdown.show{display:block;}
/* 树状节点 */
.tree-node{user-select:none;}
.tree-node__header{display:flex;align-items:center;gap:6px;padding:6px 12px;font-size:var(--font-sm);cursor:pointer;transition:background .1s;border-radius:var(--radius-sm);margin:0 4px;}
.tree-node__header:hover{background:#F5F7FA;}
.tree-node__arrow{width:12px;height:12px;transition:transform .2s;flex-shrink:0;display:flex;align-items:center;justify-content:center;}
.tree-node__arrow svg{width:10px;height:10px;}
.tree-node__arrow.expanded{transform:rotate(90deg);}
.tree-node__arrow.hidden{visibility:hidden;}
.tree-node__checkbox{width:16px;height:16px;border:1px solid var(--border);border-radius:3px;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:all .15s;}
.tree-node__checkbox.checked{background:var(--primary);border-color:var(--primary);}
.tree-node__checkbox.checked::after{content:'';width:4px;height:8px;border:solid #fff;border-width:0 1.5px 1.5px 0;transform:rotate(45deg);margin-top:-2px;}
.tree-node__checkbox.indeterminate{border-color:var(--primary);}
.tree-node__checkbox.indeterminate::after{content:'';width:8px;height:2px;background:var(--primary);}
.tree-node__label{font-size:var(--font-sm);color:var(--text-primary);}
.tree-node__children{padding-left:24px;display:none;}
.tree-node__children.expanded{display:block;}
</style>
</head>
<body>
<div class="top-bar">
<div class="top-bar__logo"><svg viewBox="0 0 28 28" fill="none"><rect width="28" height="28" rx="6" fill="#1890FF"/><path d="M7 14h14M14 7v14" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/></svg> 健康监测</div>
<nav class="top-bar__nav">
<a href="../archive-personal.html">档案</a>
<a href="../crowd-status-employee.html">健康现状</a>
<a href="../health-checkup/survey-category.html" class="active">健康排查</a>
<a href="../wearable/tool-manage.html">穿戴监测</a>
<a href="../environment/indoor-device-list.html">健康环境</a>
<a href="../exception-dirty.html">异常事件</a>
</nav>
<div class="top-bar__right">
<a class="btn-back" href="../../../index.html">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
返回首页
</a>
<div class="avatar"></div>
<span style="color:rgba(255,255,255,0.65);">系统管理员 ▾</span>
</div>
</div>
<aside class="sidebar">
<div class="sidebar-menu__title">健康排查</div>
<a href="survey-manage.html" class="sidebar-item">问卷管理</a>
<a href="activity-manage.html" class="sidebar-item">活动管理</a>
<a href="activity-stat.html" class="sidebar-item">活动统计</a>
</aside>
<main class="main">
<div class="table-card">
<div class="table-card__header">
<span class="table-card__title">模板列表</span>
<button class="btn btn-primary" onclick="openEditModal(null)">
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
新增模板
</button>
</div>
<table>
<thead>
<tr>
<th>模板名称</th>
<th>用户类别</th>
<th>模板状态</th>
<th>操作</th>
</tr>
</thead>
<tbody id="templateTbody">
</tbody>
</table>
</div>
</main>
<!-- 查看弹窗 -->
<div class="modal-mask" id="viewModal">
<div class="modal modal-lg">
<div class="modal__header">
<h3 id="viewModalTitle">查看模板 - 健康记录-E类</h3>
<button class="modal__close" onclick="closeModal('viewModal')">×</button>
</div>
<div class="modal__body" style="padding:0;">
<table>
<thead>
<tr>
<th>问题分类</th>
<th>问题描述</th>
<th>问题类型</th>
<th>选项</th>
</tr>
</thead>
<tbody id="viewTbody">
</tbody>
</table>
</div>
<div class="modal__footer">
<button class="btn btn-default" onclick="closeModal('viewModal')">关闭</button>
</div>
</div>
</div>
<!-- 编辑弹窗 -->
<div class="modal-mask" id="editModal">
<div class="modal">
<div class="modal__header">
<h3 id="editModalTitle">编辑模板</h3>
<button class="modal__close" onclick="closeModal('editModal')">×</button>
</div>
<div class="modal__body">
<div class="form-group">
<label>模板名称 <span style="color:var(--danger)">*</span></label>
<input class="form-control" id="editName" placeholder="请输入模板名称">
</div>
<div class="form-row">
<div class="form-group">
<label>用户类别 <span style="color:var(--danger)">*</span></label>
<select class="form-control" id="editCategory">
<option value="">请选择</option>
<option>A类</option>
<option>B类</option>
<option>C类</option>
<option>D类</option>
<option>E类</option>
</select>
</div>
<div class="form-group">
<label>模板状态</label>
<div class="switch" id="editStatusSwitch" onclick="toggleEditSwitch()">
<span class="switch__track on"><span class="switch__thumb"></span></span>
</div>
</div>
</div>
<div class="form-group">
<label>问题分类 <span style="color:var(--danger)">*</span></label>
<div class="tag-select" id="tagSelect" onclick="toggleTreeDropdown(event)">
<span class="tag-select__tag" data-val="饮食习惯">饮食习惯<span class="tag-remove" onclick="removeTag(this,event)">×</span></span>
<span class="tag-select__tag" data-val="运动锻炼">运动锻炼<span class="tag-remove" onclick="removeTag(this,event)">×</span></span>
<input class="tag-select__input" id="tagInput" placeholder="搜索问题分类" oninput="filterTree()" onfocus="openTreeDropdown()">
<div class="tag-select__dropdown" id="catDropdown"></div>
</div>
</div>
</div>
<div class="modal__footer">
<button class="btn btn-default" onclick="closeModal('editModal')">取消</button>
<button class="btn btn-primary" onclick="closeModal('editModal')">确定</button>
</div>
</div>
</div>
<script>
function toggleSubgroup(h){h.parentElement.classList.toggle('open');}
(function(){var a=document.querySelector('.sidebar-item.active');if(!a)return;var s=a.closest('.sidebar-subgroup');if(s)s.classList.add('open');})();
var templates=[
{name:'健康记录-E类',cat:'E类',enabled:true,questions:[
{cat:'饮食习惯',desc:'今天是否按时吃早餐?',type:'单选题',options:['是','否']},
{cat:'饮食习惯',desc:'今天饮水量是否达到1500ml',type:'单选题',options:['是','否']},
{cat:'运动锻炼',desc:'今天是否进行了30分钟以上运动?',type:'单选题',options:['是','否']},
{cat:'睡眠质量',desc:'昨晚睡眠时间是否达到7小时?',type:'单选题',options:['是','否']},
{cat:'心理状态',desc:'今天是否感到焦虑或压力过大?',type:'单选题',options:['是','否']}
]},
{name:'健康记录-D类',cat:'D类',enabled:true,questions:[
{cat:'饮食习惯',desc:'今天是否摄入了足够的蔬菜水果?',type:'单选题',options:['是','否']},
{cat:'运动锻炼',desc:'今天是否完成了步行目标?',type:'单选题',options:['是','否']},
{cat:'慢病管理',desc:'今天是否按时服药?',type:'单选题',options:['是','否']},
{cat:'睡眠质量',desc:'昨晚是否有失眠情况?',type:'单选题',options:['是','否']}
]},
{name:'健康记录-C类',cat:'C类',enabled:true,questions:[
{cat:'饮食习惯',desc:'今天是否控制了高盐高油饮食?',type:'单选题',options:['是','否']},
{cat:'运动锻炼',desc:'今天是否进行了有氧运动?',type:'单选题',options:['是','否']},
{cat:'心理状态',desc:'今天情绪是否稳定?',type:'单选题',options:['是','否']}
]},
{name:'健康记录-B类',cat:'B类',enabled:true,questions:[
{cat:'运动锻炼',desc:'今天是否完成了体能训练?',type:'单选题',options:['是','否']},
{cat:'睡眠质量',desc:'昨晚睡眠质量是否良好?',type:'单选题',options:['是','否']},
{cat:'职业健康',desc:'今天工作中是否佩戴了防护用品?',type:'单选题',options:['是','否']}
]},
{name:'健康记录-A类',cat:'A类',enabled:true,questions:[
{cat:'饮食习惯',desc:'今天三餐是否规律?',type:'单选题',options:['是','否']},
{cat:'运动锻炼',desc:'今天是否进行了户外活动?',type:'单选题',options:['是','否']},
{cat:'心理状态',desc:'今天是否有充足的休息时间?',type:'单选题',options:['是','否']},
{cat:'职业健康',desc:'今天是否有身体不适症状?',type:'单选题',options:['是','否']}
]}
];
// 渲染表格
function renderTable(){
var tbody=document.getElementById('templateTbody');
var html='';
templates.forEach(function(t,i){
var trackCls='switch__track'+(t.enabled?' on':'');
var labelTxt=t.enabled?'已启用':'已停用';
html+='<tr>';
html+='<td>'+t.name+'</td>';
html+='<td>'+t.cat+'</td>';
html+='<td><div class="switch" onclick="toggleTemplateStatus('+i+')"><span class="'+trackCls+'"><span class="switch__thumb"></span></span></div></td>';
html+='<td>';
html+='<span class="link" onclick="openEditModal('+i+')">编辑</span>';
html+='<span style="color:var(--border);margin:0 6px;">|</span>';
html+='<span class="link" style="color:var(--danger);" onclick="void(0)">删除</span>';
html+='<span style="color:var(--border);margin:0 6px;">|</span>';
html+='<span class="link" onclick="openViewModal('+i+')">查看</span>';
html+='</td></tr>';
});
tbody.innerHTML=html;
}
// 切换模板状态(互斥:同一用户类别只能开启一个)
function toggleTemplateStatus(idx){
var t=templates[idx];
if(t.enabled){
// 关闭当前
t.enabled=false;
}else{
// 开启当前,关闭同类别的其他模板
templates.forEach(function(item){
if(item.cat===t.cat)item.enabled=false;
});
t.enabled=true;
}
renderTable();
}
// 编辑弹窗开关
var editSwitchOn=true;
function toggleEditSwitch(){
editSwitchOn=!editSwitchOn;
var track=document.querySelector('#editStatusSwitch .switch__track');
if(editSwitchOn){track.classList.add('on');}
else{track.classList.remove('on');}
}
function setEditSwitch(val){
editSwitchOn=val;
var track=document.querySelector('#editStatusSwitch .switch__track');
if(val){track.classList.add('on');}
else{track.classList.remove('on');}
}
renderTable();
// 树状分类数据
var categoryTree=[
{label:'生活习惯',children:[
{label:'饮食习惯'},{label:'运动锻炼'},{label:'睡眠质量'},{label:'体重管理'}
]},
{label:'心理健康',children:[
{label:'心理状态'},{label:'压力管理'},{label:'情绪调节'}
]},
{label:'疾病管理',children:[
{label:'慢病管理'},{label:'用药提醒'},{label:'康复训练'}
]},
{label:'职业防护',children:[
{label:'职业健康'},{label:'劳动防护'},{label:'职业禁忌'}
]}
];
function closeModal(id){document.getElementById(id).classList.remove('show');}
function openViewModal(idx){
var t=templates[idx];
document.getElementById('viewModalTitle').textContent='查看模板 - '+t.name;
var html='';
t.questions.forEach(function(q){
var optHtml=q.options.map(function(o){return '<div style="line-height:1.8;">'+o+'</div>';}).join('');
html+='<tr><td>'+q.cat+'</td><td>'+q.desc+'</td><td>'+q.type+'</td><td>'+optHtml+'</td></tr>';
});
document.getElementById('viewTbody').innerHTML=html;
document.getElementById('viewModal').classList.add('show');
}
function openEditModal(idx){
if(idx===null){
document.getElementById('editModalTitle').textContent='新增模板';
document.getElementById('editName').value='';
document.getElementById('editCategory').value='';
setEditSwitch(true);
clearAllTags();
}else{
var t=templates[idx];
document.getElementById('editModalTitle').textContent='编辑模板';
document.getElementById('editName').value=t.name;
document.getElementById('editCategory').value=t.cat;
setEditSwitch(t.enabled);
clearAllTags();
var cats=[];t.questions.forEach(function(q){if(cats.indexOf(q.cat)===-1)cats.push(q.cat);});
cats.forEach(function(c){addTag(c);});
}
document.getElementById('editModal').classList.add('show');
}
function clearAllTags(){
document.getElementById('tagSelect').querySelectorAll('.tag-select__tag').forEach(function(el){el.remove();});
}
function addTag(val){
var container=document.getElementById('tagSelect');
var input=document.getElementById('tagInput');
var span=document.createElement('span');
span.className='tag-select__tag';span.setAttribute('data-val',val);
span.innerHTML=val+'<span class="tag-remove" onclick="removeTag(this,event)">×</span>';
container.insertBefore(span,input);
}
function removeTag(el,e){
e.stopPropagation();
el.parentElement.remove();
renderTree();
}
function getSelectedTags(){
var tags=[];
document.getElementById('tagSelect').querySelectorAll('.tag-select__tag').forEach(function(t){tags.push(t.getAttribute('data-val'));});
return tags;
}
function toggleTreeDropdown(e){
if(e.target.closest('.tag-remove'))return;
document.getElementById('tagInput').focus();
}
function openTreeDropdown(){
renderTree();
document.getElementById('catDropdown').classList.add('show');
}
function filterTree(){renderTree();document.getElementById('catDropdown').classList.add('show');}
function renderTree(){
var dd=document.getElementById('catDropdown');
var keyword=document.getElementById('tagInput').value.toLowerCase();
var selected=getSelectedTags();
var html='';
categoryTree.forEach(function(parent,pi){
var visibleChildren=parent.children.filter(function(c){
return !keyword||c.label.toLowerCase().indexOf(keyword)>-1;
});
if(visibleChildren.length===0)return;
// 父节点checkbox状态
var checkedCount=0;
visibleChildren.forEach(function(c){if(selected.indexOf(c.label)>-1)checkedCount++;});
var allChecked=checkedCount===visibleChildren.length;
var someChecked=checkedCount>0&&!allChecked;
var cbCls='tree-node__checkbox'+(allChecked?' checked':'')+(someChecked?' indeterminate':'');
html+='<div class="tree-node">';
html+='<div class="tree-node__header" onclick="toggleTreeExpand(this)">';
html+='<span class="tree-node__arrow expanded"><svg viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke="#999" stroke-width="1.5" stroke-linecap="round"/></svg></span>';
html+='<span class="'+cbCls+'" onclick="toggleParentCheck(event,'+pi+')"></span>';
html+='<span class="tree-node__label" style="font-weight:500;">'+parent.label+'</span>';
html+='</div>';
html+='<div class="tree-node__children expanded">';
visibleChildren.forEach(function(child){
var isChecked=selected.indexOf(child.label)>-1;
var childCbCls='tree-node__checkbox'+(isChecked?' checked':'');
html+='<div class="tree-node__header" onclick="toggleLeafCheck(event,\''+child.label+'\')">';
html+='<span class="tree-node__arrow hidden"><svg viewBox="0 0 12 12"><path d="M4 2l4 4-4 4" fill="none" stroke="#999" stroke-width="1.5" stroke-linecap="round"/></svg></span>';
html+='<span class="'+childCbCls+'"></span>';
html+='<span class="tree-node__label">'+child.label+'</span>';
html+='</div>';
});
html+='</div></div>';
});
dd.innerHTML=html||'<div style="padding:12px;text-align:center;color:var(--text-placeholder);font-size:var(--font-sm);">无匹配项</div>';
}
function toggleTreeExpand(header){
var arrow=header.querySelector('.tree-node__arrow');
var children=header.nextElementSibling;
if(!children||!children.classList.contains('tree-node__children'))return;
arrow.classList.toggle('expanded');
children.classList.toggle('expanded');
}
function toggleParentCheck(e,pi){
e.stopPropagation();
var selected=getSelectedTags();
var parent=categoryTree[pi];
var keyword=document.getElementById('tagInput').value.toLowerCase();
var visibleChildren=parent.children.filter(function(c){return !keyword||c.label.toLowerCase().indexOf(keyword)>-1;});
var allChecked=visibleChildren.every(function(c){return selected.indexOf(c.label)>-1;});
if(allChecked){
visibleChildren.forEach(function(c){
document.getElementById('tagSelect').querySelectorAll('.tag-select__tag[data-val="'+c.label+'"]').forEach(function(t){t.remove();});
});
}else{
visibleChildren.forEach(function(c){
if(selected.indexOf(c.label)===-1)addTag(c.label);
});
}
renderTree();
}
function toggleLeafCheck(e,label){
e.stopPropagation();
var selected=getSelectedTags();
if(selected.indexOf(label)>-1){
document.getElementById('tagSelect').querySelectorAll('.tag-select__tag[data-val="'+label+'"]').forEach(function(t){t.remove();});
}else{
addTag(label);
}
renderTree();
}
document.addEventListener('click',function(e){
if(!e.target.closest('.tag-select'))document.getElementById('catDropdown').classList.remove('show');
});
document.querySelectorAll('.modal-mask').forEach(function(m){
m.addEventListener('click',function(e){if(e.target===m)m.classList.remove('show');});
});
</script>
</body>
</html>