feat: 应急就医多端原型优化与PRD文档更新

- 通话记录新增未知员工补充信息弹窗交互
- 大病就医列表新增操作人员派单/取消操作
- 新增应急工单从通话记录进入时隐藏非必要字段
- 统一三端结束应急弹窗文案
- 排班日历增加排班日高亮样式与图例
- 驻场端大病就医新增已取消详情页与Tab重构
- 专业人员工作台首页视频卡片导航优化
- 更新各模块PRD文档与页面截图
- index导航页同步新增页面条目

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-08 17:51:21 +08:00
co-authored by Claude Opus 4.6
parent 42b48437d2
commit b0bed17cc7
35 changed files with 649 additions and 82 deletions
+40 -16
View File
@@ -14,7 +14,8 @@
│ │ └── 已完成 → 工单详情(已完成)
│ └── 大病就医 → 大病就医列表
│ ├── 待处理 → 大病就医详情(待处理)
── 已完成 → 大病就医详情(已完成)
── 已完成 → 大病就医详情(已完成)
│ └── 已取消 → 大病就医详情(已取消)
├── 知识库(底部Tab
│ ├── 知识文章(分类Tab)→ 知识详情
│ └── 规章制度(PDF列表)
@@ -42,6 +43,8 @@ stateDiagram-v2
[*] --> 待处理 : 操作人员确认预约并派单
待处理 --> 已完成 : 驻场人员提交挂号结果
待处理 --> 待处理 : 驻场人员转单给其他驻场人员
待处理 --> 已取消 : 操作人员取消预约
待处理 --> 已取消 : 员工本人取消预约
```
## 页面清单
@@ -54,13 +57,14 @@ stateDiagram-v2
| 4 | workbench/serious-illness-list.html | 大病就医列表 | 工作台·大病就医 |
| 5 | workbench/serious-illness-detail-pending.html | 大病就医详情(待处理) | 工作台·大病就医 |
| 6 | workbench/serious-illness-detail-done.html | 大病就医详情(已完成) | 工作台·大病就医 |
| 7 | knowledge/index.html | 知识库首页 | 知识库 |
| 8 | knowledge/article-detail.html | 知识详情 | 知识库 |
| 9 | ../ai-assistant/index.html | AI 助手 | AI 助手 |
| 10 | ../message/index.html | 消息列表 | 消息 |
| 11 | profile/index.html | 个人中心主页 | 我的 |
| 12 | profile/edit-profile.html | 修改个人信息 | 我的 |
| 13 | profile/change-pwd.html | 修改密码 | 我的 |
| 7 | workbench/serious-illness-detail-cancelled.html | 大病就医详情(已取消) | 工作台·大病就医 |
| 8 | knowledge/index.html | 知识库首页 | 知识库 |
| 9 | knowledge/article-detail.html | 知识详情 | 知识库 |
| 10 | ../ai-assistant/index.html | AI 助手 | AI 助手 |
| 11 | ../message/index.html | 消息列表 | 消息 |
| 12 | profile/index.html | 个人中心主页 | 我的 |
| 13 | profile/edit-profile.html | 修改个人信息 | 我的 |
| 14 | profile/change-pwd.html | 修改密码 | 我的 |
## 逐页说明
@@ -153,16 +157,18 @@ stateDiagram-v2
![页面截图](screenshots/serious-illness-list.jpg)
**功能说明:** 大病就医任务列表,按待处理/已完成分类展示。
**功能说明:** 大病就医任务列表,按待处理/已结束分类展示。
**业务规则:**
- 二级 Tab 切换:待处理(含数量角标)/ 已完成
- 二级 Tab 切换:待处理(含数量角标)/ 已结束
- 卡片展示:预约医院、状态标签、申请员工、科室、挂号类别、预约时间
- 待处理标签为橙色,已完成标签为绿色
- 待处理标签为橙色,已完成标签为绿色,已取消标签为灰色
- 已结束面板同时包含"已完成"和"已取消"两种状态的卡片
**交互说明:**
- 点击待处理卡片:跳转到大病就医详情(待处理)页
- 点击已完成卡片:跳转到大病就医详情(已完成)页
- 点击已取消卡片:跳转到大病就医详情(已取消)页,通过 `?from=operator``?from=employee` 参数区分取消来源
- 点击返回:返回工作台首页
---
@@ -216,9 +222,27 @@ stateDiagram-v2
---
### 7. 大病就医详情(已取消)
![页面截图](screenshots/serious-illness-detail-cancelled.jpg)
**功能说明:** 展示已取消的大病就医预约详情,包含取消原因和取消人信息,纯只读页面。
**业务规则:**
- 三个可折叠卡片:取消信息、申请员工信息、预约信息
- 取消信息卡片展示:取消状态描述、取消人、取消时间、取消原因
- 通过 URL 参数 `from` 区分取消来源:`from=operator` 为操作人员取消,`from=employee` 为员工本人取消
- 不同取消来源展示不同的取消人和描述文案
**交互说明:**
- 点击卡片标题:折叠/展开卡片
- 点击返回:返回大病就医列表
---
## 四、知识库模块
### 7. 知识库首页
### 8. 知识库首页
**功能说明:** 等待后续规划,提示“功能开发中,敬请期待~”
@@ -226,7 +250,7 @@ stateDiagram-v2
---
### 8. 知识详情
### 9. 知识详情
@@ -237,7 +261,7 @@ stateDiagram-v2
## 五、个人中心模块
### 9. 个人中心主页
### 10. 个人中心主页
![页面截图](screenshots/profile-index.jpg)
@@ -255,7 +279,7 @@ stateDiagram-v2
---
### 10. 修改个人信息
### 11. 修改个人信息
![页面截图](screenshots/edit-profile.jpg)
@@ -274,7 +298,7 @@ stateDiagram-v2
---
### 11. 修改密码
### 12. 修改密码
![页面截图](screenshots/change-pwd.jpg)
Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 50 KiB

@@ -0,0 +1,117 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>驻场人员 - 大病就医详情(已取消) | 健康长庆原型</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
.phone-shell { width: 390px; height: 844px; background: #fff; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; position: relative; display: flex; flex-direction: column; flex-shrink: 0; }
.status-bar { height: 44px; background: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; }
.status-bar .time { font-size: 15px; font-weight: 700; color: #1a1a1a; }
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 12px; color: #1a1a1a; }
.nav-bar { height: 44px; display: flex; align-items: center; padding: 0 16px; background: #fff; border-bottom: 1px solid #f0f0f0; flex-shrink: 0; position: relative; }
.back-btn { display: flex; align-items: center; gap: 4px; color: #1677ff; font-size: 15px; cursor: pointer; background: none; border: none; padding: 4px 0; }
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
.scroll-content { flex: 1; overflow-y: auto; background: #f5f5f5; }
.scroll-content::-webkit-scrollbar { display: none; }
.status-area { padding: 32px 16px 24px; text-align: center; background: #fff; }
.status-area__title { font-size: 22px; font-weight: 700; color: #999; margin-bottom: 8px; }
.status-area__desc { font-size: 14px; color: #999; }
.info-card { background: #fff; margin: 12px 16px; border-radius: 12px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); overflow: hidden; }
.info-card__header { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px; cursor: pointer; }
.info-card__title { font-size: 15px; font-weight: 600; color: #1a1a1a; }
.info-card__toggle { display: inline-flex; align-items: center; gap: 4px; color: #1677ff; font-size: 12px; font-weight: 600; }
.info-card__arrow { width: 14px; height: 14px; transition: transform .2s ease; }
.info-card__body { padding: 0 16px 16px; }
.info-card--collapsed .info-card__body { display: none; }
.info-card--collapsed .info-card__arrow { transform: rotate(-90deg); }
.info-card__row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #f5f5f5; font-size: 14px; }
.info-card__row:last-child { border-bottom: none; }
.info-card__label { color: #999; }
.info-card__value { color: #333; font-weight: 500; }
</style>
</head>
<body>
<div class="phone-shell">
<div class="status-bar"><span class="time">9:41</span><div class="icons"><span>●●●</span><span>WiFi</span><span>🔋</span></div></div>
<div class="nav-bar">
<button class="back-btn" onclick="history.back()"><svg width="10" height="16" viewBox="0 0 10 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 1L2 8l6 7"/></svg>返回</button>
<span class="nav-title">就医详情</span>
</div>
<div class="scroll-content">
<div class="status-area">
<div class="status-area__title">已取消</div>
<div class="status-area__desc" id="status-desc">该预约已被取消</div>
</div>
<div class="info-card" id="cancel-card">
<div class="info-card__header" onclick="toggleCard('cancel-card', this)">
<div class="info-card__title">取消信息</div>
<div class="info-card__toggle"><span>收起</span><svg class="info-card__arrow" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6l5 5 5-5"/></svg></div>
</div>
<div class="info-card__body">
<div class="info-card__row"><span class="info-card__label">取消人</span><span class="info-card__value" id="cancel-person">操作人员(刘旭)</span></div>
<div class="info-card__row"><span class="info-card__label">取消时间</span><span class="info-card__value" id="cancel-time">2026-04-25 11:20</span></div>
<div class="info-card__row"><span class="info-card__label">取消原因</span><span class="info-card__value" id="cancel-reason">患者病情好转,暂不需要就医</span></div>
</div>
</div>
<div class="info-card" id="employee-card">
<div class="info-card__header" onclick="toggleCard('employee-card', this)">
<div class="info-card__title">申请员工信息</div>
<div class="info-card__toggle"><span>收起</span><svg class="info-card__arrow" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6l5 5 5-5"/></svg></div>
</div>
<div class="info-card__body">
<div class="info-card__row"><span class="info-card__label">姓名</span><span class="info-card__value">王磊</span></div>
<div class="info-card__row"><span class="info-card__label">性别</span><span class="info-card__value"></span></div>
<div class="info-card__row"><span class="info-card__label">年龄</span><span class="info-card__value">42岁</span></div>
<div class="info-card__row"><span class="info-card__label">员工编号</span><span class="info-card__value">CY3-20180156</span></div>
<div class="info-card__row"><span class="info-card__label">所属单位</span><span class="info-card__value">采油三厂</span></div>
<div class="info-card__row"><span class="info-card__label">联系电话</span><span class="info-card__value">139-0088-7712</span></div>
</div>
</div>
<div class="info-card" id="booking-card">
<div class="info-card__header" onclick="toggleCard('booking-card', this)">
<div class="info-card__title">预约信息</div>
<div class="info-card__toggle"><span>收起</span><svg class="info-card__arrow" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6l5 5 5-5"/></svg></div>
</div>
<div class="info-card__body">
<div class="info-card__row"><span class="info-card__label">预约医院</span><span class="info-card__value">西安交大一附院</span></div>
<div class="info-card__row"><span class="info-card__label">科室</span><span class="info-card__value">消化内科</span></div>
<div class="info-card__row"><span class="info-card__label">医生</span><span class="info-card__value">孙建华</span></div>
<div class="info-card__row"><span class="info-card__label">挂号类别</span><span class="info-card__value">专家号</span></div>
<div class="info-card__row"><span class="info-card__label">预约时间</span><span class="info-card__value">2026-04-25 10:30</span></div>
<div class="info-card__row"><span class="info-card__label">病情描述</span><span class="info-card__value">反复胃痛两周,需做胃镜检查</span></div>
</div>
</div>
<div style="height:16px;"></div>
</div>
</div>
<script>
function toggleCard(cardId, headerEl) {
var card = document.getElementById(cardId);
if (!card) return;
card.classList.toggle('info-card--collapsed');
var isCollapsed = card.classList.contains('info-card--collapsed');
var toggle = headerEl ? headerEl.querySelector('.info-card__toggle span') : null;
if (toggle) toggle.textContent = isCollapsed ? '展开' : '收起';
}
(function(){
var params = new URLSearchParams(window.location.search);
var from = params.get('from');
if (from === 'employee') {
document.getElementById('status-desc').textContent = '员工本人取消了该预约';
document.getElementById('cancel-person').textContent = '员工本人(赵刚)';
document.getElementById('cancel-time').textContent = '2026-04-23 09:45';
document.getElementById('cancel-reason').textContent = '症状已缓解,暂不需要就医';
}
})();
</script>
</body>
</html>
@@ -35,6 +35,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
.card__status { font-size: 12px; padding: 2px 10px; border-radius: 10px; font-weight: 500; }
.card__status--pending { background: #fff7e6; color: #fa8c16; }
.card__status--done { background: #f6ffed; color: #52c41a; }
.card__status--cancelled { background: #f5f5f5; color: #999; }
.card__info { font-size: 13px; color: #666; line-height: 1.8; }
.card__info .card__employee { color: #1a1a1a; font-weight: 500; }
.card__tip { font-size: 12px; color: #999; margin-top: 6px; }
@@ -72,7 +73,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<!-- 二级Tab:待处理 / 已完成 -->
<div class="seg-tabs">
<div class="seg-tab active" onclick="switchTab(this,'panel-pending')">待处理<span class="badge">3</span></div>
<div class="seg-tab" onclick="switchTab(this,'panel-done')">完成</div>
<div class="seg-tab" onclick="switchTab(this,'panel-done')">结束</div>
</div>
<div class="scroll-content">
@@ -124,7 +125,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div style="height:16px;"></div>
</div>
<!--完成 -->
<!--结束 -->
<div id="panel-done" class="content-panel">
<div style="height:10px;"></div>
@@ -155,6 +156,34 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
</div>
<div class="card__tip">已完成挂号,排队序号:12</div>
</div>
<div class="card" onclick="location.href='./serious-illness-detail-cancelled.html?from=operator'">
<div class="card__header">
<span class="card__hospital">西安交大一附院</span>
<span class="card__status card__status--cancelled">已取消</span>
</div>
<div class="card__info">
<div>申请员工:<span class="card__employee">王磊 · 采油三厂</span></div>
<div>科室:消化内科 · 孙建华</div>
<div>挂号类别:专家号</div>
<div>预约时间:2026-04-25 10:30</div>
</div>
<div class="card__tip">操作人员已取消该预约</div>
</div>
<div class="card" onclick="location.href='./serious-illness-detail-cancelled.html?from=employee'">
<div class="card__header">
<span class="card__hospital">庆阳市人民医院</span>
<span class="card__status card__status--cancelled">已取消</span>
</div>
<div class="card__info">
<div>申请员工:<span class="card__employee">赵刚 · 采气一厂</span></div>
<div>科室:泌尿外科 · 李国强</div>
<div>挂号类别:普通号</div>
<div>预约时间:2026-04-23 15:00</div>
</div>
<div class="card__tip">员工本人取消预约</div>
</div>
<div style="height:16px;"></div>
</div>
</div>
+3 -3
View File
@@ -132,7 +132,7 @@ stateDiagram-v2
- 点击"救护车支援":跳转到救护车支援页
- 点击"救助信息":跳转到救助信息汇总页
- 点击"员工位置":跳转到患者定位地图页
- 点击"结束应急":弹出二次确认弹窗,确认后跳转回工作台首页(已完成 Tab)
- 点击"结束应急":弹出二次确认弹窗(标题"是否结束应急",内容"请确保人员已妥善救助,现场风险及隐患已全部排查解除。"),确认后跳转回工作台首页(已完成 Tab)
- 点击"🎤"图标:切换语音/文字输入模式
- 点击"+"图标:展开/收起媒体选择面板
- 点击"➤"发送按钮:将输入框内容发送为操作人员消息气泡
@@ -273,7 +273,7 @@ stateDiagram-v2
**业务规则:**
- 基本信息卡片:工单编号、应急中心、求助员工、部门、求助方式、时间、位置、操作人员、专业人员、状态
- 救助信息卡片:救助意见(只读)、救助结果(可编辑)、相关照片(可上传/删除)、补充小结(可新增/编辑/删除)、保存按钮
- 救助信息卡片:救助意见(只读)、救助结果(可编辑)、相关照片(可上传/删除)、补充小结(可新增/编辑/删除)
- 派单信息卡片:展示已派单记录或空状态提示
- 救护车支援卡片:展示救护车详情,支持编辑
- 根据 URL 参数 method 动态设置求助方式和返回目标:应急视频返回聊天页,应急电话/拨打120 显示结束应急按钮
@@ -283,7 +283,7 @@ stateDiagram-v2
- 点击"新增/编辑"(救助结果):打开编辑弹窗
- 点击"新增/编辑"(补充小结):打开小结编辑弹窗
- 点击"编辑"(救护车):打开救护车编辑弹窗(含搜索选择和行程信息)
- 点击"结束应急"(仅非视频求助):弹出确认弹窗,确认后跳转回工作台
- 点击"结束应急"(仅非视频求助):弹出确认弹窗(标题"是否结束应急",内容"请确保人员已妥善救助,现场风险及隐患已全部排查解除。"),确认后跳转回工作台
---
Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 78 KiB

@@ -236,8 +236,8 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<!-- 结束应急确认弹窗 -->
<div id="confirm-mask" class="confirm-mask" onclick="closeEndConfirm(event)">
<div class="confirm-dialog">
<div class="confirm-dialog__head">是否确认结束应急</div>
<div class="confirm-dialog__body">结束后本次应急会话将进入"已结束"列表,仅支持查看记录,不可继续发送消息</div>
<div class="confirm-dialog__head">是否结束应急</div>
<div class="confirm-dialog__body">请确保人员已妥善救助,现场风险及隐患已全部排查解除</div>
<div class="confirm-dialog__actions">
<button class="confirm-dialog__btn confirm-dialog__btn--cancel" onclick="closeEndConfirm(event)">取消</button>
<button class="confirm-dialog__btn confirm-dialog__btn--confirm" onclick="confirmEndEmergency(event)">确认结束</button>
@@ -187,9 +187,6 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
</div>
<div id="summary-list-ongoing" class="summary-list"></div>
</div>
<div class="action-row">
<button class="save-btn" onclick="saveSection('救助信息')">保存救助信息</button>
</div>
</div>
</div>
@@ -227,7 +224,6 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="ambulance-display__row"><span class="ambulance-display__label">目的地</span><span id="amb-d-dest" class="ambulance-display__value">华池县人民医院急诊科</span></div>
<div class="ambulance-display__row"><span class="ambulance-display__label">备注</span><span id="amb-d-remark" class="ambulance-display__value">患者左膝受伤,需担架转运</span></div>
</div>
<div class="tip-text">操作人员可点击编辑修改救护车支援信息。</div>
</div>
</div>
@@ -320,8 +316,8 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<!-- 结束应急确认弹窗 -->
<div id="confirm-mask" class="confirm-mask" onclick="closeEndConfirm(event)">
<div class="confirm-dialog">
<div class="confirm-dialog__head">是否确认结束应急</div>
<div class="confirm-dialog__body">结束后本次应急工单将更改为“已完成”状态</div>
<div class=confirm-dialog__head>是否结束应急</div>
<div class=confirm-dialog__body>请确保人员已妥善救助,现场风险及隐患已全部排查解除</div>
<div class="confirm-dialog__actions">
<button class="confirm-dialog__btn confirm-dialog__btn--cancel" onclick="closeEndConfirm(event)">取消</button>
<button class="confirm-dialog__btn confirm-dialog__btn--confirm" onclick="confirmEndEmergency(event)">确认结束</button>
+2 -1
View File
@@ -98,7 +98,7 @@ stateDiagram-v2
- 点击"查看工单":跳转到工单详情(进行中)页
- 点击"救助意见":跳转到救助意见表单页,确认完后在聊天页发送一条自定义救助意见卡片消息
- 点击"患者定位":跳转到患者定位地图页
- 点击"结束应急":弹出二次确认弹窗,确认后发送一条结束应急的卡片消息,并跳转回工作台首页(已结束 Tab),
- 点击"结束应急":弹出二次确认弹窗(标题"是否结束应急",内容"请确保人员已妥善救助,现场风险及隐患已全部排查解除。"),确认后发送一条结束应急的卡片消息,并跳转回工作台首页(已结束 Tab),
- 点击"🎤"图标:切换语音/文字输入模式
- 点击"+"图标:展开/收起媒体选择面板
- 点击"➤"发送按钮:将输入框内容发送为专业人员消息气泡
@@ -180,6 +180,7 @@ stateDiagram-v2
**交互说明:**
- 点击卡片标题:折叠/展开卡片
- 点击返回:返回应急聊天页
- 非视频求助方式下显示"结束应急"按钮和救助意见"编辑"按钮;点击"结束应急"弹出确认弹窗(标题"是否结束应急",内容"请确保人员已妥善救助,现场风险及隐患已全部排查解除。"),确认后跳转回工作台
---
Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 48 KiB

@@ -70,7 +70,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<span style="font-size:11px;color:#666;">求助时间:2026-04-24 09:15</span>
</div>
<!-- [交互] 点击跳转至: ./work-order-detail.html -->
<button onclick="location.href='./work-order-detail.html'" style="font-size:12px;color:#fa8c16;background:none;border:1px solid #fa8c16;border-radius:6px;padding:4px 10px;cursor:pointer;">查看工单</button>
<button onclick="sessionStorage.setItem('professionalWorkOrderDetailSource','./emergency-chat-done.html');location.href='./work-order-detail.html'" style="font-size:12px;color:#fa8c16;background:none;border:1px solid #fa8c16;border-radius:6px;padding:4px 10px;cursor:pointer;">查看工单</button>
</div>
<div id="emergency-info-detail" class="info-detail">
<div class="info-avatar">👩</div>
@@ -200,8 +200,8 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div id="confirm-mask" class="confirm-mask" onclick="closeEndConfirm(event)">
<div class="confirm-dialog">
<div class="confirm-dialog__head">是否确认结束应急</div>
<div class="confirm-dialog__body">结束后本次应急会话将进入“已结束”列表,仅支持查看记录,不可继续发送消息</div>
<div class="confirm-dialog__head">是否结束应急</div>
<div class="confirm-dialog__body">请确保人员已妥善救助,现场风险及隐患已全部排查解除</div>
<div class="confirm-dialog__actions">
<button class="confirm-dialog__btn confirm-dialog__btn--cancel" onclick="closeEndConfirm(event)">取消</button>
<button class="confirm-dialog__btn confirm-dialog__btn--confirm" onclick="confirmEndEmergency(event)">确认结束</button>
@@ -122,8 +122,8 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<!-- 已结束列表 -->
<div id="panel-done" style="display:none;">
<!-- [交互] 点击跳转至: ./work-order-detail.html -->
<div class="emergency-card" onclick="sessionStorage.setItem('professionalWorkOrderDetailSource','./index.html');sessionStorage.setItem('professionalWorkOrderMethod','应急视频');location.href='./work-order-detail.html'">
<!-- [交互] 点击跳转至: ./emergency-chat-done.html(应急视频) -->
<div class="emergency-card" onclick="location.href='./emergency-chat-done.html'">
<div class="ec-top">
<div class="ec-avatar">🚑</div>
<div class="ec-info">
@@ -120,6 +120,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="desc-block">
<div style="display: flex; align-items: center; justify-content: space-between;">
<div class="desc-block__label">救助意见:</div>
<button class="edit-btn" id="edit-advice-btn" style="display:none;" onclick="openEditAdvice()">编辑</button>
</div>
<div class="desc-block__text" id="advice-text">-</div>
</div>
@@ -197,8 +198,8 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<!-- 结束应急确认弹窗 -->
<div id="confirm-mask" class="confirm-mask" onclick="closeEndConfirm(event)">
<div class="confirm-dialog">
<div class="confirm-dialog__head">是否确认结束应急</div>
<div class="confirm-dialog__body">结束后本次应急工单将更改为"已完成"状态</div>
<div class="confirm-dialog__head">是否结束应急</div>
<div class="confirm-dialog__body">请确保人员已妥善救助,现场风险及隐患已全部排查解除</div>
<div class="confirm-dialog__actions">
<button class="confirm-dialog__btn confirm-dialog__btn--cancel" onclick="closeEndConfirm(event)">取消</button>
<button class="confirm-dialog__btn confirm-dialog__btn--confirm" onclick="confirmEndEmergency(event)">确认结束</button>
@@ -223,9 +224,10 @@ function goBackToSource() {
var method = sessionStorage.getItem('professionalWorkOrderMethod');
if (method) {
document.getElementById('help-method').textContent = method;
// 如果求助方式是"应急电话"或"拨打120",显示结束应急按钮
// 如果求助方式是"应急电话"或"拨打120",显示结束应急按钮和救助意见编辑按钮
if (method === '应急电话' || method === '拨打120') {
document.getElementById('end-bar').style.display = 'block';
document.getElementById('edit-advice-btn').style.display = '';
}
}
+2 -1
View File
@@ -504,7 +504,8 @@ const SITE_MAP = [
{file:'work-order-detail-ongoing.html',label:'工单详情(待处理)'},
{file:'work-order-detail.html',label:'工单详情(已完成)'},
{file:'serious-illness-detail-pending.html',label:'大病就医详情(待处理)'},
{file:'serious-illness-detail-done.html',label:'大病就医详情(已完成)'}
{file:'serious-illness-detail-done.html',label:'大病就医详情(已完成)'},
{file:'serious-illness-detail-cancelled.html',label:'大病就医详情(已取消)'}
]},
{name:'知识库',dir:'emergency-app/onsite/knowledge',pages:[
{file:'index.html',label:'知识库首页'},{file:'article-detail.html',label:'知识详情'}
@@ -289,9 +289,25 @@ tbody tr:hover{background:#F8FBFF;}
<td>12:18</td>
<td><div class="action-btns"><a class="link-success" href="center-work-order-detail.html">查看应急工单</a></div></td>
</tr>
<tr>
<tr id="unknown-row">
<td class="col-fixed col-fixed-1">4</td>
<td class="col-fixed col-fixed-2" style="font-family:monospace;color:var(--text-secondary);">TH20260419004</td>
<td class="col-fixed col-fixed-3" id="unknown-name"><span style="color:var(--text-placeholder);">未知</span></td>
<td id="unknown-code"><span style="color:var(--text-placeholder);"></span></td>
<td id="unknown-dept"><span style="color:var(--text-placeholder);"></span></td>
<td>长庆油田应急中心</td>
<td>ZX-10001</td>
<td>15887656617</td>
<td>2026-04-19 18:30:12</td>
<td><span class="tag tag-red">未接听</span></td>
<td></td>
<td></td>
<td></td>
<td><div class="action-btns"><a class="link" id="btn-fill-info" onclick="openFillModal()">补充信息</a><a class="link" id="btn-new-order" style="display:none;" href="center-work-order-add.html?from=call">新建应急工单</a></div></td>
</tr>
<tr>
<td class="col-fixed col-fixed-1">5</td>
<td class="col-fixed col-fixed-2" style="font-family:monospace;color:var(--text-secondary);">TH20260419005</td>
<td class="col-fixed col-fixed-3">刘志强</td>
<td>EMP-20456</td>
<td>采油二厂/工程技术科</td>
@@ -306,7 +322,7 @@ tbody tr:hover{background:#F8FBFF;}
<td><div class="action-btns"><a class="link" href="center-work-order-add.html?from=call&name=刘志强&code=EMP-20456&org=采油二厂&dept=工程技术科">新建应急工单</a></div></td>
</tr>
<tr>
<td class="col-fixed col-fixed-1">5</td>
<td class="col-fixed col-fixed-1">6</td>
<td class="col-fixed col-fixed-2" style="font-family:monospace;color:var(--text-secondary);">TH20260419005</td>
<td class="col-fixed col-fixed-3">赵国庆</td>
<td>EMP-40321</td>
@@ -322,7 +338,7 @@ tbody tr:hover{background:#F8FBFF;}
<td><div class="action-btns"><a class="link" href="center-work-order-add.html?from=call&name=赵国庆&code=EMP-40321&org=长庆工程监督处&dept=质量监督科">新建应急工单</a></div></td>
</tr>
<tr>
<td class="col-fixed col-fixed-1">6</td>
<td class="col-fixed col-fixed-1">7</td>
<td class="col-fixed col-fixed-2" style="font-family:monospace;color:var(--text-secondary);">TH20260419006</td>
<td class="col-fixed col-fixed-3">孙明亮</td>
<td>EMP-10234</td>
@@ -338,7 +354,7 @@ tbody tr:hover{background:#F8FBFF;}
<td><div class="action-btns"><a class="link" href="center-work-order-add.html?from=call&name=孙明亮&code=EMP-10234&org=采油三厂&dept=综合管理科">新建应急工单</a></div></td>
</tr>
<tr>
<td class="col-fixed col-fixed-1">7</td>
<td class="col-fixed col-fixed-1">8</td>
<td class="col-fixed col-fixed-2" style="font-family:monospace;color:var(--text-secondary);">TH20260419007</td>
<td class="col-fixed col-fixed-3">周文博</td>
<td>EMP-50178</td>
@@ -354,7 +370,7 @@ tbody tr:hover{background:#F8FBFF;}
<td><div class="action-btns"><a class="link" href="center-work-order-add.html?from=call&name=周文博&code=EMP-50178&org=勘探开发研究院&dept=地质所">新建应急工单</a></div></td>
</tr>
<tr>
<td class="col-fixed col-fixed-1">8</td>
<td class="col-fixed col-fixed-1">9</td>
<td class="col-fixed col-fixed-2" style="font-family:monospace;color:var(--text-secondary);">TH20260419008</td>
<td class="col-fixed col-fixed-3">吴海涛</td>
<td>EMP-20789</td>
@@ -385,7 +401,97 @@ tbody tr:hover{background:#F8FBFF;}
</div>
</div>
</div>
<!-- 补充信息弹窗 -->
<div id="fill-modal" style="display:none;position:fixed;inset:0;z-index:1000;background:rgba(0,0,0,0.45);display:none;align-items:center;justify-content:center;">
<div style="background:#fff;border-radius:var(--radius-lg);width:520px;max-height:80vh;display:flex;flex-direction:column;box-shadow:0 8px 32px rgba(0,0,0,0.18);">
<div style="display:flex;align-items:center;justify-content:space-between;padding:20px 24px;border-bottom:1px solid var(--border);">
<span style="font-size:var(--font-base);font-weight:600;">补充员工信息</span>
<span style="cursor:pointer;font-size:20px;color:var(--text-secondary);line-height:1;" onclick="closeFillModal()">&times;</span>
</div>
<div style="padding:20px 24px;">
<div style="display:flex;gap:8px;margin-bottom:16px;">
<input id="emp-search" class="filter-input" style="flex:1;" type="text" placeholder="输入姓名或工号搜索员工" oninput="filterEmployees()">
</div>
<div id="emp-list" style="max-height:320px;overflow-y:auto;border:1px solid var(--border);border-radius:var(--radius-sm);">
</div>
<div id="emp-selected" style="display:none;margin-top:12px;padding:10px 14px;background:var(--primary-light);border-radius:var(--radius-sm);font-size:var(--font-sm);color:var(--primary);">已选择:<span id="emp-selected-text"></span></div>
</div>
<div style="display:flex;justify-content:flex-end;gap:12px;padding:16px 24px;border-top:1px solid var(--border);">
<button class="btn btn-default" onclick="closeFillModal()">取消</button>
<button class="btn btn-primary" id="btn-confirm-fill" onclick="confirmSelect()" disabled style="opacity:0.5;cursor:not-allowed;">确认</button>
</div>
</div>
</div>
<script>
/* 员工搜索弹窗逻辑 */
var employeeData=[
{name:'刘志强',code:'EMP-20456',dept:'采油二厂/工程技术科'},
{name:'马晓峰',code:'EMP-30567',dept:'第三采气厂/生产技术科'},
{name:'李建华',code:'EMP-10345',dept:'采油一厂/综合管理科'},
{name:'杨秀英',code:'EMP-40123',dept:'长庆工程监督处/安全科'},
{name:'黄志远',code:'EMP-50234',dept:'勘探开发研究院/开发所'},
{name:'郑国强',code:'EMP-20890',dept:'采油三厂/工程技术科'},
{name:'林小红',code:'EMP-10678',dept:'油气工艺研究院/化学所'},
{name:'何大伟',code:'EMP-30456',dept:'第五采气厂/生产运行科'}
];
var selectedEmp=null;
function renderEmpList(list){
var html='';
list.forEach(function(emp){
var isSelected=selectedEmp&&selectedEmp.code===emp.code;
html+='<div style="padding:12px 16px;border-bottom:1px solid var(--border);cursor:pointer;transition:background .2s;background:'+(isSelected?'var(--primary-light)':'#fff')+';" onmouseenter="if(!this.classList.contains(\'selected\'))this.style.background=\'#F8FBFF\'" onmouseleave="if(!this.classList.contains(\'selected\'))this.style.background=\'#fff\'" onclick="pickEmployee(\''+emp.name+'\',\''+emp.code+'\',\''+emp.dept+'\')"'+(isSelected?' class="selected"':'')+'>';
html+='<div style="font-size:var(--font-sm);font-weight:500;">'+emp.name+'<span style="color:var(--text-secondary);font-weight:400;margin-left:12px;">'+emp.code+'</span></div>';
html+='<div style="font-size:var(--font-xs);color:var(--text-secondary);margin-top:4px;">'+emp.dept+'</div>';
html+='</div>';
});
if(!list.length) html='<div style="padding:24px;text-align:center;color:var(--text-placeholder);font-size:var(--font-sm);">未找到匹配的员工</div>';
document.getElementById('emp-list').innerHTML=html;
}
function openFillModal(){
var modal=document.getElementById('fill-modal');
modal.style.display='flex';
selectedEmp=null;
document.getElementById('emp-search').value='';
document.getElementById('emp-selected').style.display='none';
var btn=document.getElementById('btn-confirm-fill');
btn.disabled=true;btn.style.opacity='0.5';btn.style.cursor='not-allowed';
renderEmpList(employeeData);
}
function closeFillModal(){
document.getElementById('fill-modal').style.display='none';
}
function filterEmployees(){
var kw=document.getElementById('emp-search').value.trim().toLowerCase();
if(!kw){renderEmpList(employeeData);return;}
var filtered=employeeData.filter(function(e){return e.name.toLowerCase().indexOf(kw)>-1||e.code.toLowerCase().indexOf(kw)>-1;});
renderEmpList(filtered);
}
function pickEmployee(name,code,dept){
selectedEmp={name:name,code:code,dept:dept};
document.getElementById('emp-selected').style.display='block';
document.getElementById('emp-selected-text').textContent=name+' ('+code+') - '+dept;
var btn=document.getElementById('btn-confirm-fill');
btn.disabled=false;btn.style.opacity='1';btn.style.cursor='pointer';
renderEmpList(employeeData.filter(function(e){
var kw=document.getElementById('emp-search').value.trim().toLowerCase();
if(!kw)return true;
return e.name.toLowerCase().indexOf(kw)>-1||e.code.toLowerCase().indexOf(kw)>-1;
}));
}
function confirmSelect(){
if(!selectedEmp)return;
document.getElementById('unknown-name').innerHTML=selectedEmp.name;
document.getElementById('unknown-code').innerHTML=selectedEmp.code;
document.getElementById('unknown-dept').innerHTML=selectedEmp.dept;
document.getElementById('btn-fill-info').style.display='none';
var orderBtn=document.getElementById('btn-new-order');
orderBtn.style.display='inline';
orderBtn.href='center-work-order-add.html?from=call&name='+encodeURIComponent(selectedEmp.name)+'&code='+encodeURIComponent(selectedEmp.code)+'&org='+encodeURIComponent(selectedEmp.dept.split('/')[0])+'&dept='+encodeURIComponent(selectedEmp.dept.split('/')[1]||'');
closeFillModal();
}
document.getElementById('fill-modal').addEventListener('click',function(e){if(e.target===this)closeFillModal();});
(function(){
var params=new URLSearchParams(window.location.search);
var role=params.get('role');
@@ -89,6 +89,45 @@
.col-fixed-3{left:180px;min-width:120px;}
.col-fixed-3::after{content:'';position:absolute;top:0;right:-4px;bottom:0;width:4px;background:linear-gradient(to right,rgba(0,0,0,0.04),transparent);pointer-events:none;}
.col-fixed-end{right:0;min-width:80px;box-shadow:-2px 0 4px rgba(0,0,0,0.04);}
/* 操作链接 */
.op-link{font-size:var(--font-sm);color:var(--primary);cursor:pointer;text-decoration:none;margin-left:12px;white-space:nowrap;}
.op-link:hover{text-decoration:underline;}
.op-link--danger{color:var(--danger);}
.op-link--danger:hover{color:#ff7875;}
/* 弹窗通用 */
.modal-mask{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.45);z-index:1000;align-items:center;justify-content:center;}
.modal-mask.open{display:flex;}
.modal-box{background:#fff;border-radius:var(--radius-md);width:520px;max-height:85vh;display:flex;flex-direction:column;box-shadow:0 4px 24px rgba(0,0,0,0.18);}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border);}
.modal-title{font-size:var(--font-base);font-weight:600;}
.modal-close{width:32px;height:32px;border-radius:50%;background:rgba(0,0,0,0.04);border:none;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center;color:#999;transition:all .15s;}
.modal-close:hover{background:rgba(0,0,0,0.08);color:#333;}
.modal-body{flex:1;overflow-y:auto;padding:24px;}
.modal-footer{padding:16px 24px;border-top:1px solid var(--border);display:flex;justify-content:flex-end;gap:12px;}
.field{margin-bottom:20px;}.field:last-child{margin-bottom:0;}
.field__label{font-size:var(--font-sm);color:var(--text-primary);margin-bottom:8px;display:flex;align-items:center;gap:4px;}
.field__label .req{color:var(--danger);}
.field__textarea{width:100%;min-height:80px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:10px 12px;font-size:var(--font-sm);outline:none;resize:vertical;font-family:inherit;line-height:1.6;}
.field__textarea:focus{border-color:var(--primary);}
.btn{display:inline-flex;align-items:center;justify-content:center;height:36px;padding:0 20px;border-radius:var(--radius-sm);font-size:var(--font-sm);cursor:pointer;border:1px solid var(--border);background:#fff;color:var(--text-primary);transition:all .15s;font-family:inherit;}
.btn:hover{border-color:var(--primary);color:var(--primary);}
.btn--primary{background:var(--primary);color:#fff;border-color:var(--primary);}
.btn--primary:hover{background:#40a9ff;border-color:#40a9ff;color:#fff;}
/* 可搜索下拉 */
.sel-search{position:relative;}
.sel-search__input{width:100%;height:36px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 32px 0 12px;font-size:var(--font-sm);outline:none;cursor:pointer;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none'%3E%3Cpath d='M3 4.5l3 3 3-3' stroke='%23999' stroke-width='1.2' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat right 12px center;}
.sel-search__input:focus{border-color:var(--primary);}
.sel-search__drop{display:none;position:absolute;top:calc(100% + 4px);left:0;right:0;background:#fff;border:1px solid var(--border);border-radius:var(--radius-sm);box-shadow:0 4px 12px rgba(0,0,0,0.12);z-index:10;max-height:200px;overflow-y:auto;}
.sel-search__drop.open{display:block;}
.sel-search__opt{padding:10px 12px;cursor:pointer;transition:background .12s;border-bottom:1px solid #f5f5f5;}
.sel-search__opt:last-child{border-bottom:none;}
.sel-search__opt:hover{background:var(--primary-light);}
.sel-search__opt.selected{background:var(--primary-light);color:var(--primary);}
.sel-search__name{font-size:var(--font-sm);color:var(--text-primary);font-weight:500;}
.sel-search__sub{font-size:var(--font-xs);color:var(--text-placeholder);margin-top:2px;}
.sel-search__empty{padding:16px;text-align:center;font-size:var(--font-xs);color:var(--text-placeholder);}
.person-tel{margin-top:4px;font-size:var(--font-sm);color:var(--text-secondary);}
.person-tel a{color:var(--primary);text-decoration:none;}
</style>
</head>
<body>
@@ -260,7 +299,7 @@
<td><span class="tag tag-green">已完成</span></td>
<td>2026-03-16 12:23:32</td>
<td>2026-03-18 15:42:10</td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=completed">详细过程</a></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=completed">查看详情</a></td>
</tr>
<tr>
<td class="col-fixed col-fixed-1">2</td>
@@ -277,7 +316,7 @@
<td><span class="tag tag-blue">已确认</span></td>
<td>2026-03-16 12:25:18</td>
<td></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=confirmed">详细过程</a></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=confirmed">查看详情</a></td>
</tr>
<tr>
<td class="col-fixed col-fixed-1">3</td>
@@ -294,7 +333,7 @@
<td><span class="tag tag-orange">待确认</span></td>
<td>2026-03-16 12:28:45</td>
<td></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=pending">详细过程</a></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=pending">查看详情</a></td>
</tr>
<tr>
<td class="col-fixed col-fixed-1">4</td>
@@ -311,7 +350,7 @@
<td><span class="tag tag-blue">已确认</span></td>
<td>2026-04-14 16:05:18</td>
<td></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=confirmed">详细过程</a></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=confirmed">查看详情</a></td>
</tr>
<tr>
<td class="col-fixed col-fixed-1">5</td>
@@ -328,7 +367,7 @@
<td><span class="tag tag-orange">待确认</span></td>
<td>2026-04-11 09:32:47</td>
<td></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=pending">详细过程</a></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=pending">查看详情</a></td>
</tr>
<tr>
<td class="col-fixed col-fixed-1">6</td>
@@ -345,7 +384,7 @@
<td><span class="tag tag-green">已完成</span></td>
<td>2026-04-07 22:18:05</td>
<td>2026-04-10 09:15:33</td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=completed">详细过程</a></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=completed">查看详情</a></td>
</tr>
<tr>
<td class="col-fixed col-fixed-1">7</td>
@@ -362,7 +401,7 @@
<td><span class="tag tag-blue">已确认</span></td>
<td>2026-03-23 14:50:33</td>
<td></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=confirmed">详细过程</a></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=confirmed">查看详情</a></td>
</tr>
<tr>
<td class="col-fixed col-fixed-1">8</td>
@@ -379,7 +418,7 @@
<td><span class="tag tag-green">已完成</span></td>
<td>2026-03-17 10:25:41</td>
<td>2026-03-20 11:08:22</td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=completed">详细过程</a></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=completed">查看详情</a></td>
</tr>
<tr>
<td class="col-fixed col-fixed-1">9</td>
@@ -396,7 +435,7 @@
<td><span class="tag tag-gray">已取消</span></td>
<td>2026-03-09 15:42:18</td>
<td></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=cancelled">详细过程</a></td>
<td class="col-fixed col-fixed-end"><a class="link" href="center-serious-illness-detail.html?status=cancelled">查看详情</a></td>
</tr>
</tbody>
</table>
@@ -414,6 +453,48 @@
</div>
</div>
</div>
<!-- 取消预约弹窗 -->
<div class="modal-mask" id="cancelModal" onclick="if(event.target===this)closeCancelModal()">
<div class="modal-box" style="width:480px;">
<div class="modal-header"><span class="modal-title">取消申请</span><button class="modal-close" onclick="closeCancelModal()"></button></div>
<div class="modal-body">
<div class="field">
<div class="field__label">取消原因<span class="req">*</span></div>
<textarea class="field__textarea" id="cancelReason" placeholder="请输入取消原因..."></textarea>
</div>
</div>
<div class="modal-footer">
<button class="btn" onclick="closeCancelModal()">返回</button>
<button class="btn btn--primary" onclick="submitCancel()">确认取消</button>
</div>
</div>
</div>
<!-- 驻场派单弹窗 -->
<div class="modal-mask" id="dispatchModal" onclick="if(event.target===this)closeDispatchModal()">
<div class="modal-box" style="width:560px;">
<div class="modal-header"><span class="modal-title">驻场派单</span><button class="modal-close" onclick="closeDispatchModal()"></button></div>
<div class="modal-body">
<div class="field">
<div class="field__label">选择驻场人员<span class="req">*</span></div>
<div class="sel-search" id="personSelect">
<input class="sel-search__input" id="personInput" placeholder="姓名/医院搜索" autocomplete="off" onclick="togglePersonDrop()" oninput="filterPersons()">
<div class="sel-search__drop" id="personDrop"></div>
</div>
<div class="person-tel" id="personTelInfo" style="display:none;">联系电话:<a id="personTel" href=""></a></div>
</div>
<div class="field">
<div class="field__label">派单说明</div>
<textarea class="field__textarea" id="dispatchNote" placeholder="请输入派单说明..."></textarea>
</div>
</div>
<div class="modal-footer">
<button class="btn" onclick="closeDispatchModal()">取消</button>
<button class="btn btn--primary" onclick="submitDispatch()">确定派单</button>
</div>
</div>
</div>
<script>
(function(){
var params=new URLSearchParams(window.location.search);
@@ -439,8 +520,129 @@
u.searchParams.set('role','operator');
a.href=u.pathname+u.search;
});
/* 为操作列动态插入按钮 */
document.querySelectorAll('tbody tr').forEach(function(tr){
var tagEl=tr.querySelector('.tag');
if(!tagEl)return;
var statusText=tagEl.textContent.trim();
var opTd=tr.querySelector('.col-fixed-end');
if(!opTd)return;
var btns='';
if(statusText==='待确认'){
btns='<a class="op-link" onclick="openDispatchModal(this)">立即派单</a><a class="op-link op-link--danger" onclick="openCancelModal(this)">取消预约</a>';
}else if(statusText==='已确认'){
btns='<a class="op-link op-link--danger" onclick="openCancelModal(this)">取消预约</a>';
}
if(btns) opTd.insertAdjacentHTML('beforeend',btns);
});
}
})();
/* === 当前操作行 === */
var _activeRow=null;
/* === 取消预约弹窗 === */
function openCancelModal(btn){
_activeRow=btn.closest('tr');
document.getElementById('cancelModal').classList.add('open');
document.body.style.overflow='hidden';
document.getElementById('cancelReason').value='';
document.getElementById('cancelReason').style.borderColor='';
}
function closeCancelModal(){
document.getElementById('cancelModal').classList.remove('open');
document.body.style.overflow='';
}
function submitCancel(){
var reason=document.getElementById('cancelReason').value.trim();
if(!reason){
var ta=document.getElementById('cancelReason');
ta.style.borderColor='var(--danger)';ta.focus();return;
}
/* 更新行状态为已取消 */
var tagEl=_activeRow.querySelector('.tag');
tagEl.className='tag tag-gray';
tagEl.textContent='已取消';
/* 移除操作链接 */
_activeRow.querySelectorAll('.op-link').forEach(function(b){b.remove();});
closeCancelModal();
}
/* === 驻场派单弹窗 === */
var _persons=[
{name:'王旭',hospital:'长庆油田职工医院',tel:'138-9201-3001'},
{name:'刘鑫',hospital:'长庆油田职工医院',tel:'138-9201-3002'},
{name:'陈浩',hospital:'采油一厂卫生所',tel:'138-9201-3003'},
{name:'赵旭',hospital:'西安交通大学第一附属医院',tel:'138-9201-3004'},
{name:'孙俪',hospital:'采油一厂卫生所',tel:'138-9201-3005'},
{name:'周西',hospital:'陕西省人民医院',tel:'138-9201-3006'},
{name:'吴晓',hospital:'长庆油田职工医院',tel:'138-9201-3007'},
{name:'郑立',hospital:'西安交通大学第一附属医院',tel:'138-9201-3008'}
];
var _selPerson=null;
function openDispatchModal(btn){
_activeRow=btn.closest('tr');
document.getElementById('dispatchModal').classList.add('open');
document.body.style.overflow='hidden';
_selPerson=null;
document.getElementById('personInput').value='';
document.getElementById('personInput').style.borderColor='';
document.getElementById('personTelInfo').style.display='none';
document.getElementById('dispatchNote').value='';
renderPersonDrop('');
}
function closeDispatchModal(){
document.getElementById('dispatchModal').classList.remove('open');
document.body.style.overflow='';
document.getElementById('personDrop').classList.remove('open');
}
function renderPersonDrop(kw){
var drop=document.getElementById('personDrop');
kw=kw.toLowerCase();var html='',count=0;
_persons.forEach(function(p,i){
if(kw&&p.name.toLowerCase().indexOf(kw)<0&&p.hospital.toLowerCase().indexOf(kw)<0)return;
var sel=(_selPerson&&_selPerson.name===p.name)?' selected':'';
html+='<div class="sel-search__opt'+sel+'" onclick="pickPerson('+i+')"><div class="sel-search__name">'+p.name+'</div><div class="sel-search__sub">'+p.hospital+'</div></div>';
count++;
});
if(!count)html='<div class="sel-search__empty">无匹配人员</div>';
drop.innerHTML=html;
}
function togglePersonDrop(){
var drop=document.getElementById('personDrop');
if(drop.classList.contains('open')){drop.classList.remove('open');return;}
renderPersonDrop(document.getElementById('personInput').value);
drop.classList.add('open');
}
function filterPersons(){
renderPersonDrop(document.getElementById('personInput').value);
document.getElementById('personDrop').classList.add('open');
}
function pickPerson(idx){
_selPerson=_persons[idx];
document.getElementById('personInput').value=_selPerson.name+' · '+_selPerson.hospital;
document.getElementById('personDrop').classList.remove('open');
document.getElementById('personTelInfo').style.display='';
var tel=document.getElementById('personTel');
tel.textContent=_selPerson.tel;tel.href='tel:'+_selPerson.tel.replace(/-/g,'');
}
function submitDispatch(){
if(!_selPerson){
var inp=document.getElementById('personInput');
inp.style.borderColor='var(--danger)';inp.focus();return;
}
/* 更新行状态为已确认 */
var tagEl=_activeRow.querySelector('.tag');
tagEl.className='tag tag-blue';
tagEl.textContent='已确认';
/* 移除立即派单链接,保留取消预约 */
_activeRow.querySelectorAll('.op-link:not(.op-link--danger)').forEach(function(b){b.remove();});
closeDispatchModal();
}
document.addEventListener('click',function(e){
if(!e.target.closest('#personSelect'))document.getElementById('personDrop').classList.remove('open');
});
</script>
</body>
@@ -170,7 +170,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
</div>
</div>
</div>
<div class="form-row">
<div class="form-row" id="row-finish-time">
<div class="form-group">
<label class="form-label">完成时间:</label>
<div class="form-control-wrap" style="display:flex;gap:8px;">
@@ -179,7 +179,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
</div>
</div>
</div>
<div class="form-row">
<div class="form-row" id="row-advice">
<div class="form-group">
<label class="form-label">救助意见:</label>
<div class="form-control-wrap form-control-wrap--wide">
@@ -253,7 +253,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
</div>
</div>
</div>
<div class="form-row">
<div class="form-row" id="row-end-time">
<div class="form-group">
<label class="form-label">结束时间:</label>
<div class="form-control-wrap" style="display:flex;gap:8px;">
@@ -262,7 +262,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei
</div>
</div>
</div>
<div class="form-row">
<div class="form-row" id="row-station-note">
<div class="form-group">
<label class="form-label">驻场说明:</label>
<div class="form-control-wrap form-control-wrap--wide">
@@ -460,6 +460,11 @@ document.addEventListener('click',function(e){
var readonlyItems=document.querySelectorAll('.form-readonly__item');
if(readonlyItems.length){readonlyItems[0].querySelector('.form-readonly__value').textContent='应急电话工单';}
document.getElementById('helpTypeText').textContent='应急电话';
/* 隐藏不需要的字段 */
document.getElementById('row-advice').style.display='none';
document.getElementById('row-finish-time').style.display='none';
document.getElementById('row-end-time').style.display='none';
document.getElementById('row-station-note').style.display='none';
/* 回填员工信息 */
var name=params.get('name')||'';
var code=params.get('code')||'';
@@ -793,7 +793,8 @@ function confirmEndEmergency(){
<div class="end-confirm__box">
<div class="end-confirm__body">
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" style="margin-bottom:16px;"><circle cx="24" cy="24" r="24" fill="#FAAD14"/><text x="24" y="33" text-anchor="middle" fill="#fff" font-size="28" font-weight="700">!</text></svg>
<div style="font-size:var(--font-base);color:var(--text-primary);line-height:1.8;">请确定本次应急求助已完成后再执行该操作</div>
<div style="font-size:var(--font-lg);font-weight:600;color:var(--text-primary);margin-bottom:8px;">是否结束应急</div>
<div style="font-size:var(--font-base);color:var(--text-secondary);line-height:1.8;">请确保人员已妥善救助,现场风险及隐患已全部排查解除。</div>
</div>
<div class="end-confirm__footer">
<button class="btn btn-default" onclick="closeEndConfirm()">取消</button>
+30 -2
View File
@@ -831,6 +831,7 @@ stateDiagram-v2
**交互说明:**
- 支持查看地图弹窗(展示求助位置)
- 操作人员/专业人员视角下点击"结束应急":弹出二次确认弹窗(标题"是否结束应急",内容"请确保人员已妥善救助,现场风险及隐患已全部排查解除。"),确认后工单状态变为已完成
- 面包屑返回应急工单列表
---
@@ -868,9 +869,17 @@ stateDiagram-v2
**交互说明:**
- 点击"查看应急工单"跳转工单详情
- 点击"新建应急工单"跳转新增工单页面,自动回填员工信息和求助方式(应急电话)
- 点击"新建应急工单"跳转新增工单页面`center-work-order-add.html?from=call`),自动回填员工信息和求助方式(应急电话),同时隐藏"完成时间"、"救助意见"、"结束时间"、"驻场说明"四个表单字段
- 未知员工行(员工姓名/编号/单位部门显示为占位符"未知"/"—"):操作列仅显示"补充信息"链接,点击后弹出补充员工信息弹窗;确认选择后该行员工信息回填,"补充信息"链接隐藏,显示"新建应急工单"链接
- 支持导出列表数据、查看导出任务
**补充员工信息弹窗:**
| 字段名 | 类型 | 必填 | 校验规则 |
|--------|------|------|----------|
| 员工搜索 | 文本输入 | — | 输入姓名或工号实时过滤员工列表 |
| 员工选择 | 列表单选 | 是 | 必须选中一名员工后启用确认按钮 |
---
### 38. 大病就医(center-serious-illness.html
@@ -887,10 +896,29 @@ stateDiagram-v2
- 应急中心管理员只能看到当前应急中心的大病就医记录
**交互说明:**
- 点击"详细过程"跳转大病就医详情
- 点击"查看详情"跳转大病就医详情
- 操作人员视角显示"新增大病就医"按钮,管理员无此权限
- 操作人员视角下,操作列在"查看详情"链接后根据状态动态追加操作链接:
- 待确认状态:显示"立即派单"和"取消预约"两个操作链接
- 已确认状态:显示"取消预约"操作链接
- 已完成/已取消状态:无额外操作链接
- 点击"立即派单":弹出驻场派单弹窗,选择驻场人员后确认派单,该行状态变为"已确认"
- 点击"取消预约":弹出取消预约弹窗,填写取消原因后确认,该行状态变为"已取消"
- 支持导出列表数据、查看导出任务
**立即派单弹窗表单(操作人员视角):**
| 字段名 | 类型 | 必填 | 校验规则 |
|--------|------|------|----------|
| 驻场人员 | 搜索下拉选择 | 是 | 必须选择一名人员,选中后启用确认按钮 |
| 派单说明 | 多行文本 | 否 | 无 |
**取消预约弹窗表单(操作人员视角):**
| 字段名 | 类型 | 必填 | 校验规则 |
|--------|------|------|----------|
| 取消原因 | 多行文本 | 是 | 不能为空,输入后启用确认按钮 |
---
Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 648 KiB

After

Width:  |  Height:  |  Size: 141 KiB

@@ -95,7 +95,7 @@ stateDiagram-v2
右侧值班面板:
- 标题"值班信息"
- 统计卡片 2×2 网格:当日应急人数(红色)、当月应急人数(蓝色)、应急响应及时率(绿色)、应急任务完成率(橙色)
- 月视图日历:年月切换箭头、星期行、日期网格(今日高亮、有排班日期带蓝色圆点标记)
- 月视图日历:年月切换箭头、星期行、日期网格(今日高亮蓝底白字、排班日浅蓝底+蓝色边框高亮、有排班日期带蓝色圆点标记)、底部图例(今天/排班日)
- 今日值班人员列表:头像、姓名(含职称)、角色标签
**业务规则:**
@@ -281,7 +281,8 @@ stateDiagram-v2
**布局说明:**
- 警告图标(黄色圆形感叹号)居中展示
- 提示文字:"请确定本次应急求助已完成后再执行该操作"
- 标题文字:"是否结束应急"
- 说明文字:"请确保人员已妥善救助,现场风险及隐患已全部排查解除。"
- 底部按钮:取消 / 确认结束(danger 样式)
**业务规则:**
@@ -319,7 +320,7 @@ stateDiagram-v2
### 2-1. 新增应急工单(center-work-order-add.html
![页面截图](../admin/doc/screenshots/center-work-order-add.jpg)
![页面截图](../../admin/doc/screenshots/center-work-order-add.jpg)
**功能说明:**
操作人员新建应急工单的录入页面,用于补录线下应急事件,或将通话记录快速转换为应急工单。页面按"基本信息"、"派单信息"、"救护车支援"三段式组织表单内容,支持在录入工单基础信息的同时补充驻场与转运安排。
Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 117 KiB

@@ -250,12 +250,22 @@
.cal-week{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;font-size:var(--font-xs);color:var(--text-placeholder);margin-bottom:4px;}
.cal-week span{padding:4px 0;}
.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;gap:2px;}
.cal-day{position:relative;padding:6px 0;font-size:var(--font-xs);color:var(--text-primary);border-radius:var(--radius-sm);cursor:default;line-height:1;}
.cal-day{position:relative;padding:5px 0;font-size:var(--font-xs);color:var(--text-primary);border-radius:var(--radius-sm);cursor:default;line-height:1;width:32px;height:32px;display:flex;flex-direction:column;align-items:center;justify-content:center;margin:0 auto;}
.cal-day--other{color:var(--text-placeholder);}
.cal-day--today{background:var(--primary);color:#fff;border-radius:50%;font-weight:600;}
.cal-day--duty{background:#E6F7FF;border:1px solid #BAE7FF;border-radius:var(--radius-sm);color:var(--primary);font-weight:500;}
.cal-day--today{background:var(--primary);color:#fff;border-radius:var(--radius-sm);font-weight:600;border:none;}
.cal-day--today.cal-day--duty{background:var(--primary);color:#fff;border:none;}
.cal-day--today .cal-dot{background:#fff;}
.cal-dot{width:4px;height:4px;border-radius:50%;background:var(--primary);margin:2px auto 0;display:block;}
.cal-dot--danger{background:var(--danger);}
.cal-day--duty .cal-dot{background:var(--primary);}
.cal-day--today .cal-dot{background:#fff;}
.cal-day--selected{background:#BAE7FF;border:1px solid var(--primary);border-radius:var(--radius-sm);color:var(--primary);font-weight:600;cursor:pointer;}
.cal-day--today.cal-day--selected{background:var(--primary);color:#fff;border:none;}
.cal-legend{display:flex;align-items:center;gap:16px;padding:8px 16px 0;font-size:var(--font-xs);color:var(--text-secondary);}
.cal-legend__item{display:flex;align-items:center;gap:4px;}
.cal-legend__dot{width:8px;height:8px;border-radius:50%;}
.cal-legend__dot--today{background:var(--primary);}
.cal-legend__dot--duty{background:#91D5FF;}
.duty-detail{padding:0 16px 16px;}
.duty-detail__title{font-size:var(--font-xs);color:var(--text-secondary);margin-bottom:8px;}
.duty-detail__item{display:flex;align-items:center;gap:8px;padding:8px 10px;background:#FAFAFA;border-radius:var(--radius-sm);margin-bottom:6px;font-size:var(--font-xs);}
@@ -494,6 +504,10 @@
</div>
<div class="cal-week"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<div class="cal-grid" id="calGrid"></div>
<div class="cal-legend">
<div class="cal-legend__item"><span class="cal-legend__dot cal-legend__dot--today"></span>今天</div>
<div class="cal-legend__item"><span class="cal-legend__dot cal-legend__dot--duty"></span>排班日</div>
</div>
</div>
<!-- 今日值班详情 -->
<div class="duty-detail">
@@ -786,7 +800,8 @@
<div class="end-modal__box" style="width:400px;">
<div class="end-modal__body" style="padding:32px 24px;text-align:center;">
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" style="margin-bottom:16px;"><circle cx="24" cy="24" r="24" fill="#FAAD14"/><text x="24" y="33" text-anchor="middle" fill="#fff" font-size="28" font-weight="700">!</text></svg>
<div style="font-size:var(--font-base);color:var(--text-primary);line-height:1.8;">请确定本次应急求助已完成后再执行该操作</div>
<div style="font-size:var(--font-lg);font-weight:600;color:var(--text-primary);margin-bottom:8px;">是否结束应急</div>
<div style="font-size:var(--font-base);color:var(--text-secondary);line-height:1.8;">请确保人员已妥善救助,现场风险及隐患已全部排查解除。</div>
</div>
<div class="end-modal__footer">
<button class="btn btn-default" onclick="closeEndEmergency()">取消</button>
@@ -1030,7 +1045,8 @@ document.addEventListener('click',function(e){
});
/* 月视图日历 */
var _calYear,_calMonth;
var _dutyDays={2026:{4:[1,2,3,7,8,9,10,14,15,16,17,21,22,23,24,28,29,30]}};
var _calSelectedDay=null;
var _dutyDays={2026:{4:[1,2,3,7,8,9,10,14,15,16,17,21,22,23,24,28,29,30],5:[5,6,7,8,9,12,13,14,15,16,19,20,21,22,23,26,27,28,29,30]}};
function initCalendar(){
var d=new Date();_calYear=d.getFullYear();_calMonth=d.getMonth()+1;
renderCalendar();
@@ -1054,11 +1070,17 @@ function renderCalendar(){
}
for(var d=1;d<=daysInMonth;d++){
var el=document.createElement('div');el.className='cal-day';
if(isThisMonth&&d===today.getDate())el.className+=' cal-day--today';
var isDuty=duties.indexOf(d)>=0;
var isToday=isThisMonth&&d===today.getDate();
if(isDuty)el.className+=' cal-day--duty';
if(isToday){el.className+=' cal-day--today cal-day--selected';_calSelectedDay=d;}
el.textContent=d;
if(duties.indexOf(d)>=0){
if(isDuty){
var dot=document.createElement('span');dot.className='cal-dot';el.appendChild(dot);
}
el.style.cursor='pointer';
el.setAttribute('data-day',d);
el.addEventListener('click',function(){selectCalDay(parseInt(this.getAttribute('data-day')));});
grid.appendChild(el);
}
var total=firstDay+daysInMonth;var remain=total%7===0?0:7-total%7;
@@ -1067,6 +1089,12 @@ function renderCalendar(){
}
}
initCalendar();
function selectCalDay(day){
_calSelectedDay=day;
document.querySelectorAll('#calGrid .cal-day').forEach(function(el){el.classList.remove('cal-day--selected');});
var target=document.querySelector('#calGrid .cal-day[data-day="'+day+'"]');
if(target)target.classList.add('cal-day--selected');
}
/* 救助信息弹窗 */
var _summaryId=2;
function openSummaryModal(){document.getElementById('summaryModal').classList.add('open');document.body.style.overflow='hidden';updateSummaryCount();}
@@ -108,7 +108,7 @@ sequenceDiagram
右侧值班面板:
- 标题”值班信息”
- 统计卡片 2×2 网格:当日应急人数(红色)、当月应急人数(蓝色)、应急响应及时率(绿色)、应急任务完成率(橙色)
- 月视图日历:年月切换、星期行、日期网格(今日蓝色圆高亮、有排班日期带蓝色圆点)
- 月视图日历:年月切换、星期行、日期网格(今日蓝色圆角高亮、排班日浅蓝底+蓝色边框高亮、有排班日期带蓝色圆点)、底部图例(今天/排班日)
- 今日值班人员列表:头像(姓氏首字)、姓名(含职称)、角色标签(操作人员 / 专业人员)
---
@@ -175,7 +175,7 @@ sequenceDiagram
- 已结束状态下,救助意见按钮同步置灰禁用。
**交互说明:**
- 弹窗内容:警告图标(黄色圆形感叹号)+ 提示文字”请确定本次应急求助已完成后再执行该操作”。
- 弹窗内容:警告图标(黄色圆形感叹号)+ 标题”是否结束应急” + 说明文字”请确保人员已妥善救助,现场风险及隐患已全部排查解除。”
- 底部按钮:取消(关闭弹窗,不执行结束)/ 确认结束(danger 红色,执行结束流程)。
- 点击”确认结束”后,弹窗关闭,页面进入已结束结果态。
Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 126 KiB

@@ -187,12 +187,22 @@
.cal-week{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;font-size:var(--font-xs);color:var(--text-placeholder);margin-bottom:4px;}
.cal-week span{padding:4px 0;}
.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;gap:2px;}
.cal-day{position:relative;padding:6px 0;font-size:var(--font-xs);color:var(--text-primary);border-radius:var(--radius-sm);cursor:default;line-height:1;}
.cal-day{position:relative;padding:5px 0;font-size:var(--font-xs);color:var(--text-primary);border-radius:var(--radius-sm);cursor:default;line-height:1;width:32px;height:32px;display:flex;flex-direction:column;align-items:center;justify-content:center;margin:0 auto;}
.cal-day--other{color:var(--text-placeholder);}
.cal-day--today{background:var(--primary);color:#fff;border-radius:50%;font-weight:600;}
.cal-day--duty{background:#E6F7FF;border:1px solid #BAE7FF;border-radius:var(--radius-sm);color:var(--primary);font-weight:500;}
.cal-day--today{background:var(--primary);color:#fff;border-radius:var(--radius-sm);font-weight:600;border:none;}
.cal-day--today.cal-day--duty{background:var(--primary);color:#fff;border:none;}
.cal-day--today .cal-dot{background:#fff;}
.cal-dot{width:4px;height:4px;border-radius:50%;background:var(--primary);margin:2px auto 0;display:block;}
.cal-dot--danger{background:var(--danger);}
.cal-day--duty .cal-dot{background:var(--primary);}
.cal-day--today .cal-dot{background:#fff;}
.cal-day--selected{background:#BAE7FF;border:1px solid var(--primary);border-radius:var(--radius-sm);color:var(--primary);font-weight:600;cursor:pointer;}
.cal-day--today.cal-day--selected{background:var(--primary);color:#fff;border:none;}
.cal-legend{display:flex;align-items:center;gap:16px;padding:8px 16px 0;font-size:var(--font-xs);color:var(--text-secondary);}
.cal-legend__item{display:flex;align-items:center;gap:4px;}
.cal-legend__dot{width:8px;height:8px;border-radius:50%;}
.cal-legend__dot--today{background:var(--primary);}
.cal-legend__dot--duty{background:#91D5FF;}
/* 值班详情 */
.duty-detail{padding:0 16px 16px;}
.duty-detail__title{font-size:var(--font-xs);color:var(--text-secondary);margin-bottom:8px;}
@@ -439,6 +449,10 @@
</div>
<div class="cal-week"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<div class="cal-grid" id="calGrid"></div>
<div class="cal-legend">
<div class="cal-legend__item"><span class="cal-legend__dot cal-legend__dot--today"></span>今天</div>
<div class="cal-legend__item"><span class="cal-legend__dot cal-legend__dot--duty"></span>排班日</div>
</div>
</div>
<!-- 今日值班详情 -->
<div class="duty-detail">
@@ -737,7 +751,8 @@
<div class="end-modal__box" style="width:400px;">
<div class="end-modal__body" style="padding:32px 24px;text-align:center;">
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" style="margin-bottom:16px;"><circle cx="24" cy="24" r="24" fill="#FAAD14"/><text x="24" y="33" text-anchor="middle" fill="#fff" font-size="28" font-weight="700">!</text></svg>
<div style="font-size:var(--font-base);color:var(--text-primary);line-height:1.8;">请确定本次应急求助已完成后再执行该操作</div>
<div style="font-size:var(--font-lg);font-weight:600;color:var(--text-primary);margin-bottom:8px;">是否结束应急</div>
<div style="font-size:var(--font-base);color:var(--text-secondary);line-height:1.8;">请确保人员已妥善救助,现场风险及隐患已全部排查解除。</div>
</div>
<div class="end-modal__footer">
<button class="btn btn-default" onclick="closeEndEmergency()">取消</button>
@@ -749,8 +764,9 @@
<script>
/* 月视图日历 */
var _calYear,_calMonth;
var _calSelectedDay=null;
// 有排班的日期(模拟数据:工作日有排班)
var _dutyDays={2026:{4:[1,2,3,7,8,9,10,14,15,16,17,21,22,23,24,28,29,30]}};
var _dutyDays={2026:{4:[1,2,3,7,8,9,10,14,15,16,17,21,22,23,24,28,29,30],5:[5,6,7,8,9,12,13,14,15,16,19,20,21,22,23,26,27,28,29,30]}};
function initCalendar(){
var d=new Date();_calYear=d.getFullYear();_calMonth=d.getMonth()+1;
renderCalendar();
@@ -776,13 +792,17 @@ function renderCalendar(){
// 当月
for(var d=1;d<=daysInMonth;d++){
var el=document.createElement('div');el.className='cal-day';
if(isThisMonth&&d===today.getDate())el.className+=' cal-day--today';
var isDuty=duties.indexOf(d)>=0;
var isToday=isThisMonth&&d===today.getDate();
if(isDuty)el.className+=' cal-day--duty';
if(isToday){el.className+=' cal-day--today cal-day--selected';_calSelectedDay=d;}
el.textContent=d;
if(duties.indexOf(d)>=0){
var dot=document.createElement('span');
dot.className=(isThisMonth&&d===today.getDate())?'cal-dot':'cal-dot';
el.appendChild(dot);
if(isDuty){
var dot=document.createElement('span');dot.className='cal-dot';el.appendChild(dot);
}
el.style.cursor='pointer';
el.setAttribute('data-day',d);
el.addEventListener('click',function(){selectCalDay(parseInt(this.getAttribute('data-day')));});
grid.appendChild(el);
}
// 下月补位
@@ -792,6 +812,12 @@ function renderCalendar(){
}
}
initCalendar();
function selectCalDay(day){
_calSelectedDay=day;
document.querySelectorAll('#calGrid .cal-day').forEach(function(el){el.classList.remove('cal-day--selected');});
var target=document.querySelector('#calGrid .cal-day[data-day="'+day+'"]');
if(target)target.classList.add('cal-day--selected');
}
/* 资源Tab切换 */
function switchResTab(cat,el){
document.querySelectorAll('.res-tab').forEach(function(t){t.classList.remove('active');});