feat: 新增员工端应用主页与个人中心,优化应急三端页面

- 新增 employee-app/home/index.html 应用主页(功能按钮收起展开、体重管理、健康数据、智能监测24h曲线、膳食摄入)
- 新增 employee-app/profile/ 个人中心模块(16页:个人资料、头像、密码、手机号、紧急联系人、设置等)
- 修复 health-consult/index.html 返回导航逻辑
- 优化应急三端(驻场/操作/专业人员端)页面交互与截图
- 新增操作人员端、专业人员端 PRD 文档
- 更新 SITE_MAP 导航页
- 新增截图工具脚本(gen_screenshots.py、screenshot.js)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-29 09:55:33 +08:00
co-authored by Claude Opus 4.6
parent f8f710ad43
commit b8382c862f
40 changed files with 3026 additions and 234 deletions
+3 -20
View File
@@ -41,6 +41,7 @@ stateDiagram-v2
stateDiagram-v2
[*] --> 待处理 : 操作人员确认预约并派单
待处理 --> 已完成 : 驻场人员提交挂号结果
待处理 --> 待处理 : 驻场人员转单给其他驻场人员
```
## 页面清单
@@ -219,36 +220,18 @@ stateDiagram-v2
### 7. 知识库首页
![页面截图](screenshots/knowledge-index.jpg)
**功能说明:** 分类展示知识文章和规章制度。
**功能说明:** 等待后续规划,提示“功能开发中,敬请期待~”
**业务规则:**
- 一级 Tab:知识文章(默认)/ 规章制度
- 知识文章面板:二级 Tab 分类(调度流程、急救知识、沟通技巧),每个分类下展示知识卡片
- 规章制度面板:展示 PDF 文件列表
- 知识卡片展示:图标、标题、简要描述
**交互说明:**
- 点击一级 Tab:切换知识文章/规章制度面板
- 点击二级 Tab:切换知识分类
- 点击知识卡片:跳转到知识详情页
---
### 8. 知识详情
![页面截图](screenshots/knowledge-article-detail.jpg)
**功能说明:** 展示单篇知识文章的完整内容,根据 URL 参数动态渲染。
**业务规则**
- 通过 URL 参数 `?key=xxx` 获取知识条目标识
- 页面动态渲染:标题、分类标签、更新日期、概述、主要内容列表
- 内置 10 个知识条目数据
**功能说明** 等待后续规划,提示“功能开发中,敬请期待~”
**交互说明:**
- 点击返回:返回知识库首页
---
@@ -46,7 +46,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
.modal-center.active { display: flex; }
.modal-center.modal-bottom { align-items: flex-end; }
.modal-box { width: 280px; background: #fff; border-radius: 16px; overflow: hidden; }
.transfer-modal { width: calc(100% - 24px); max-width: 366px; height: 88vh; max-height: 88vh; border-radius: 20px 20px 0 0; overflow: visible; padding-bottom: 6px; display: flex; flex-direction: column; }
.transfer-modal { width: calc(100% - 24px); max-width: 366px; height: 50vh; max-height: 50vh; border-radius: 20px 20px 0 0; overflow: visible; padding-bottom: 6px; display: flex; flex-direction: column; }
.person-select { position: relative; padding: 0 16px; }
.person-select__input-wrap { position: relative; }
.person-select__input { width: 100%; height: 40px; border: 1px solid #e8e8e8; border-radius: 8px; padding: 0 38px 0 12px; font-size: 14px; outline: none; color: #1a1a1a; background: #fff; }
@@ -258,10 +258,6 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="person-info__row"><span class="person-info__label">联系方式</span><span id="info-phone" class="person-info__value">-</span></div>
<div class="person-info__row"><span class="person-info__label">当前状态</span><span id="info-status" class="person-info__value">-</span></div>
</div>
<div class="transfer-note">
<div class="transfer-note__label"><span class="required">*</span>转单说明</div>
<textarea class="transfer-note__textarea" placeholder="请输入转单原因或补充说明,如:当前医院距离较远,转交附近驻场人员接单处理"></textarea>
</div>
</div>
<div style="display:flex;border-top:1px solid #f0f0f0;margin-top:0;flex-shrink:0;background:#fff;">
<button onclick="closeTransferModal()" style="flex:1;padding:14px;font-size:16px;cursor:pointer;background:none;border:none;color:#666;border-right:1px solid #f0f0f0;">取消</button>
@@ -48,7 +48,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
.modal-center.active { display: flex; }
.modal-center.modal-bottom { align-items: flex-end; }
.modal-box { width: 280px; background: #fff; border-radius: 16px; overflow: hidden; }
.transfer-modal { width: calc(100% - 24px); max-width: 366px; height: 88vh; max-height: 88vh; border-radius: 20px 20px 0 0; overflow: visible; padding-bottom: 6px; display: flex; flex-direction: column; }
.transfer-modal { width: calc(100% - 24px); max-width: 366px; height: 50vh; max-height: 50vh; border-radius: 20px 20px 0 0; overflow: visible; padding-bottom: 6px; display: flex; flex-direction: column; }
.person-select { position: relative; padding: 0 16px; }
.person-select__input-wrap { position: relative; }
.person-select__input { width: 100%; height: 40px; border: 1px solid #e8e8e8; border-radius: 8px; padding: 0 38px 0 12px; font-size: 14px; outline: none; color: #1a1a1a; background: #fff; }
@@ -141,6 +141,14 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="desc-block__label">救助结果:</div>
<div class="desc-block__text" style="color:#999;">暂未填写</div>
</div>
<div class="desc-block">
<div class="desc-block__label">相关照片:</div>
<div class="desc-block__text" style="color:#999;">暂未上传</div>
</div>
<div class="desc-block">
<div class="desc-block__label">补充小结:</div>
<div class="desc-block__text" style="color:#999;">暂未填写</div>
</div>
</div>
</div>
@@ -252,10 +260,6 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="person-info__row"><span class="person-info__label">联系方式</span><span id="info-phone" class="person-info__value">-</span></div>
<div class="person-info__row"><span class="person-info__label">当前状态</span><span id="info-status" class="person-info__value">-</span></div>
</div>
<div class="transfer-note">
<div class="transfer-note__label"><span class="required">*</span>转单说明</div>
<textarea class="transfer-note__textarea" placeholder="请输入转单原因或补充说明,如:当前现场距离较远,转交附近驻场人员前往处理"></textarea>
</div>
</div>
<div style="display:flex;border-top:1px solid #f0f0f0;margin-top:0;flex-shrink:0;background:#fff;">
<button onclick="closeTransferModal()" style="flex:1;padding:14px;font-size:16px;cursor:pointer;background:none;border:none;color:#666;border-right:1px solid #f0f0f0;">取消</button>
@@ -36,6 +36,9 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
.desc-block__text { font-size: 13px; color: #333; line-height: 1.8; }
.photo-list { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 2px; }
.photo-item { width: 90px; height: 68px; border-radius: 8px; background: linear-gradient(135deg, #e6f7ff, #bae7ff); border: 1px solid #d9d9d9; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #1677ff; }
.summary-list { display: flex; flex-direction: column; gap: 8px; }
.summary-item { font-size: 13px; color: #333; line-height: 1.8; padding: 8px 12px; background: #f7f8fa; border-radius: 8px; position: relative; padding-left: 22px; }
.summary-item::before { content: ''; position: absolute; left: 10px; top: 14px; width: 5px; height: 5px; border-radius: 50%; background: #1677ff; }
</style>
</head>
<body>
@@ -87,6 +90,21 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="desc-block__label">救助结果:</div>
<div class="desc-block__text">员工已送达长庆油田职工医院急诊科,完成头颅CT检查,排除脑出血,诊断为高血压引起的眩晕,已开具降压药物并留观。</div>
</div>
<div class="desc-block">
<div class="desc-block__label">相关照片:</div>
<div class="photo-list">
<div class="photo-item">照片 1</div>
<div class="photo-item">照片 2</div>
</div>
</div>
<div class="desc-block">
<div class="desc-block__label">补充小结:</div>
<div class="summary-list">
<div class="summary-item">患者血压已从180/110mmHg降至145/90mmHg,头晕症状明显缓解,意识清醒。</div>
<div class="summary-item">已与家属沟通病情,建议留院观察24小时,家属表示同意。</div>
<div class="summary-item">后续需定期监测血压,按时服用降压药物,一周后门诊复查。</div>
</div>
</div>
</div>
</div>
+527
View File
@@ -0,0 +1,527 @@
# 操作人员端(健康应急APP)产品需求文档
## 模块概述
操作人员端为应急调度中心的操作人员提供移动端工作平台,负责接收员工应急求助(视频/电话/120),在线实时沟通调度,协调专业人员、驻场人员、救护车等资源完成应急救助闭环。同时承担大病就医预约的确认、派单和取消管理。操作人员是整个应急流程的核心调度枢纽。
### 页面导航结构
```
操作人员端
├── 工作台(底部Tab
│ ├── 应急求助
│ │ ├── 进行中 → 应急聊天(进行中)
│ │ │ ├── 驻场派单
│ │ │ ├── 救护车支援
│ │ │ ├── 救助信息汇总
│ │ │ ├── 患者定位地图
│ │ │ └── 工单详情(进行中)
│ │ └── 已完成 → 应急聊天(已结束)
│ │ └── 工单详情(已完成)
│ └── 大病就医
│ ├── 待确认 → 大病就医详情(待确认)
│ ├── 已确认 → 大病就医详情(已确认)
│ ├── 已完成 → 大病就医详情(已完成)
│ └── 已取消 → 大病就医详情(已取消)
├── 知识库(底部Tab
│ ├── 知识文章(分类Tab)→ 知识详情
│ └── 规章制度(PDF列表)
├── AI助手(底部Tab
├── 消息(底部Tab
└── 我的(底部Tab
├── 值班信息 → 排班配置
├── 修改个人信息
├── 修改密码
└── 退出登录(确认弹窗)
```
### 应急工单状态流转图
```mermaid
stateDiagram-v2
[*] --> 进行中 : 未结束的应急工单
进行中 --> 已结束 : 员工/操作人员/专业人员任意一方结束应急
```
### 大病就医状态流转图
```mermaid
stateDiagram-v2
[*] --> 待确认 : 员工发起大病就医预约
待确认 --> 已确认 : 操作人员确认预约并派单
待确认 --> 已取消 : 操作人员/员工取消预约
已确认 --> 已完成 : 驻场人员提交挂号结果
已确认 --> 已取消 : 操作人员/员工取消预约
```
## 页面清单
| 序号 | 文件名 | 页面名称 | 所属模块 |
|------|--------|----------|----------|
| 1 | workbench/index.html | 工作台首页 | 工作台 |
| 2 | workbench/emergency-chat.html | 应急聊天(进行中) | 工作台·应急求助 |
| 3 | workbench/emergency-chat-done.html | 应急聊天(已结束) | 工作台·应急求助 |
| 4 | workbench/dispatch-onsite.html | 驻场派单 | 工作台·应急求助 |
| 5 | workbench/dispatch-ambulance.html | 救护车支援 | 工作台·应急求助 |
| 6 | workbench/rescue-summary.html | 救助信息汇总 | 工作台·应急求助 |
| 7 | workbench/patient-location.html | 患者定位地图 | 工作台·应急求助 |
| 8 | workbench/work-order-detail-ongoing.html | 工单详情(进行中) | 工作台·应急求助 |
| 9 | workbench/work-order-detail.html | 工单详情(已完成) | 工作台·应急求助 |
| 10 | workbench/serious-illness-list.html | 大病就医列表 | 工作台·大病就医 |
| 11 | workbench/serious-illness-detail-pending.html | 大病就医详情(待确认) | 工作台·大病就医 |
| 12 | workbench/serious-illness-detail-confirmed.html | 大病就医详情(已确认) | 工作台·大病就医 |
| 13 | workbench/serious-illness-detail-done.html | 大病就医详情(已完成) | 工作台·大病就医 |
| 14 | workbench/serious-illness-detail-cancelled.html | 大病就医详情(已取消) | 工作台·大病就医 |
| 15 | knowledge/index.html | 知识库首页 | 知识库 |
| 16 | knowledge/article-detail.html | 知识详情 | 知识库 |
| 17 | ../ai-assistant/index.html | AI 助手 | AI 助手 |
| 18 | ../message/index.html | 消息列表 | 消息 |
| 19 | profile/index.html | 个人中心主页 | 我的 |
| 20 | profile/edit-profile.html | 修改个人信息 | 我的 |
| 21 | profile/change-pwd.html | 修改密码 | 我的 |
| 22 | profile/duty-schedule.html | 值班信息 | 我的 |
| 23 | profile/duty-config.html | 排班配置 | 我的 |
## 逐页说明
---
## 一、工作台模块
### 1. 工作台首页
![页面截图](screenshots/index.jpg)
**功能说明:** 操作人员工作台入口,展示应急求助和大病就医两大业务的任务队列,按状态分类管理。
**业务规则:**
- 顶部统计卡片展示:应急进行中数量、大病待确认数量
- 一级 Tab 切换:应急求助(默认)/ 大病就医
- 应急求助面板:二级 Tab 切换进行中 / 已完成
- 大病就医面板:跳转至大病就医列表页
- 应急卡片展示:患者姓名、年龄、求助方式标签、求助时间
- 应急求助方式分为“拨打120”、“应急视频”、“应急电话”、“线下应急”四种,“线下应急”为操作人员手动录入工单方式。
- 已完成卡片额外展示完成时间
**交互说明:**
- 点击进行中卡片:求助方式如果是“应急视频”则跳转到应急聊天(进行中)页,其余跳转到工单详情(进行中)页
- 点击已结束卡片:求助方式如果是“应急视频”则跳转到应急聊天(已结束)页, 其余跳转到工单详情(已完成)页
- 点击大病就医 Tab:跳转到大病就医列表页
- 底部导航栏 5 个 Tab:工作台、知识库、AI 助手、消息、我的
---
## 二、应急求助业务线
### 2. 应急聊天(进行中)
![页面截图](screenshots/emergency-chat.jpg)
**功能说明:** 操作人员与患者、专业人员的实时三方聊天界面,同时提供调度操作入口(驻场派单、救护车支援、救助信息、患者定位)。
**业务规则:**
- 患者信息条(可折叠)展示:求助时间、患者姓名、年龄、所属单位、联系电话、求助方式、查看工单入口
- 聊天区域展示三方消息:患者(左侧气泡)、操作人员(右侧气泡)、专业人员(左侧色气泡)
- 救助意见以绿色卡片形式展示在聊天区
- 操作按钮栏固定在输入区上方,提供 4 个调度快捷入口
- 输入区支持语音/文字模式切换和媒体选择面板
**交互说明:**
- 点击"查看工单":跳转到工单详情(进行中)页,
- 点击"驻场派单":跳转到驻场派单页
- 点击"救护车支援":跳转到救护车支援页
- 点击"救助信息":跳转到救助信息汇总页
- 点击"员工位置":跳转到患者定位地图页
- 点击"结束应急":弹出二次确认弹窗,确认后跳转回工作台首页(已完成 Tab)
- 点击"🎤"图标:切换语音/文字输入模式
- 点击"+"图标:展开/收起媒体选择面板
- 点击"➤"发送按钮:将输入框内容发送为操作人员消息气泡
---
### 3. 应急聊天(已结束)
![页面截图](screenshots/emergency-chat-done.jpg)
**功能说明:** 查看已结束应急的完整聊天记录,只读模式,不可发送消息。
**业务规则:**
- 患者信息条(可折叠)展示患者基本信息
- 聊天区域展示完整历史消息
- 应急结束卡片以灰色样式展示结束时间
- 底部固定提示条:"本次应急已结束"
**交互说明:**
- 点击"查看工单":跳转到工单详情(已完成)页
- 点击返回:跳转回工作台首页(已完成 Tab)
---
### 4. 驻场派单
![页面截图](screenshots/dispatch-onsite.jpg)
**功能说明:** 操作人员选择驻场人员并下发派单指令,派单成功后展示派单结果。
**业务规则:**
- 患者信息摘要条展示患者姓名、年龄、求助方式
- 驻场人员列表支持按姓名或所在医院搜索过滤
- 每个驻场人员展示:姓名、所在医院、联系方式、当前状态(空闲/有派单)
- 选中人员后自动展示详细信息卡片
- 确认派单后表单区域隐藏,显示派单结果卡片(含派单时间、人员、状态、说明)
**交互说明:**
- 点击搜索框:展开驻场人员下拉列表
- 输入关键词:实时过滤匹配的人员
- 选择人员:自动填充信息卡片,启用确认按钮
- 点击"确认派单":隐藏选择表单,显示派单结果
- 点击返回:返回应急聊天页
**表单字段表:**
| 字段名 | 类型 | 必填 | 校验规则 |
|--------|------|------|----------|
| 驻场人员 | 搜索下拉选择 | 是 | 必须选择一名人员 |
| 派单说明 | 多行文本 | 否 | 无 |
---
### 5. 救护车支援
![页面截图](screenshots/dispatch-ambulance.jpg)
**功能说明:** 操作人员选择救护车并填写行程信息,完成救护车调度。
**业务规则:**
- 患者信息摘要条展示患者基本信息
- 救护车列表支持按医疗点或医院名称搜索过滤
- 每辆救护车展示:车牌号、所属医疗点、所属医院、驾驶员、联系电话
- 选中救护车后自动展示详细信息卡片
- 目的地为必填项,其余行程信息选填
**交互说明:**
- 点击搜索框:展开救护车下拉列表
- 输入关键词:实时过滤匹配的救护车
- 选择救护车:自动填充信息卡片
- 点击"确认填写":验证目的地必填,提示成功后返回上一页
**表单字段表:**
| 字段名 | 类型 | 必填 | 校验规则 |
|--------|------|------|----------|
| 救护车 | 搜索下拉选择 | 是 | 必须选择一辆救护车 |
| 随行人 | 单行文本 | 否 | 无 |
| 随行人电话 | 电话输入 | 否 | 无 |
| 目的地 | 单行文本 | 是 | 不能为空 |
| 备注信息 | 多行文本 | 否 | 无 |
---
### 6. 救助信息汇总
![页面截图](screenshots/rescue-summary.jpg)
**功能说明:** 集中管理救助过程中的补充小结、救助结果和相关照片,支持新增、编辑、删除操作。
**业务规则:**
- 患者信息摘要条展示患者基本信息
- 三个可折叠区块:补充小结、救助结果、相关照片
- 补充小结支持多条记录,每条展示时间、内容、作者,支持编辑和删除
- 新增小结输入区展示字数统计(上限 200 字)
- 救助结果为单条文本,支持切换编辑模式
- 相关照片展示已上传照片列表,支持上传和删除
**交互说明:**
- 点击区块标题:折叠/展开对应区块
- 点击"添加"(小结):展开输入区,填写后插入列表
- 点击"编辑"(小结):进入编辑模式
- 点击"删除"(小结):确认后删除,更新计数
- 点击"编辑"(救助结果):切换为编辑模式
- 点击"保存"(救助结果):保存并切换回展示模式
- 点击"上传照片":添加照片
- 点击"删除"(照片):确认后删除,更新计数
---
### 7. 患者定位地图
![页面截图](screenshots/patient-location.jpg)
**功能说明:** 地图展示患者实时位置和周边医疗资源分布,支持按资源类型筛选查看。
**业务规则:**
- 地图中心展示患者位置标记(红色脉冲动画)
- 资源类型 Tab 栏:油田医院、合作医院、医疗点、救护车、AED、急救包
- 不同类型资源使用不同颜色标记
- 资源卡片展示:名称、所属机构、距离患者距离、电话、地址
- 卡片提供"联系"和"导航"两个操作按钮
**交互说明:**
- 点击资源类型 Tab:切换显示对应类型的资源标记
- 点击资源标记:底部弹出资源详情卡片
- 点击"联系":拨打资源联系电话
- 点击"导航":打开导航应用
- 点击地图空白处:关闭资源卡片
---
### 8. 工单详情(进行中)
![页面截图](screenshots/work-order-detail-ongoing.jpg)
**功能说明:** 展示进行中工单的完整信息,支持编辑救助信息和救护车信息。包含基本信息、救助信息、派单信息、救护车支援四个可折叠卡片。
**业务规则:**
- 基本信息卡片:工单编号、应急中心、求助员工、部门、求助方式、时间、位置、操作人员、专业人员、状态
- 救助信息卡片:救助意见(只读)、救助结果(可编辑)、相关照片(可上传/删除)、补充小结(可新增/编辑/删除)、保存按钮
- 派单信息卡片:展示已派单记录或空状态提示
- 救护车支援卡片:展示救护车详情,支持编辑
- 根据 URL 参数 method 动态设置求助方式和返回目标:应急视频返回聊天页,应急电话/拨打120 显示结束应急按钮
**交互说明:**
- 点击卡片标题:折叠/展开卡片
- 点击"新增/编辑"(救助结果):打开编辑弹窗
- 点击"新增/编辑"(补充小结):打开小结编辑弹窗
- 点击"编辑"(救护车):打开救护车编辑弹窗(含搜索选择和行程信息)
- 点击"结束应急"(仅非视频求助):弹出确认弹窗,确认后跳转回工作台
---
### 9. 工单详情(已完成)
![页面截图](screenshots/work-order-detail.jpg)
**功能说明:** 展示已完成工单的完整信息,结构与进行中版本一致,救助信息、派单信息、救护车信息均已填充完整数据。
**业务规则:**
- 四个可折叠卡片结构同进行中版本
- 救助结果、补充小结、相关照片均展示已填写内容
- 派单信息展示完整派单历史(派单时间、驻场人员、状态、说明)
- 救护车支援展示完整调度记录
**交互说明:**
- 点击卡片标题:折叠/展开卡片
- 点击返回:跳转到应急聊天(已结束)页
---
## 三、大病就医业务线
### 10. 大病就医列表
![页面截图](screenshots/serious-illness-list.jpg)
**功能说明:** 大病就医预约任务列表,按状态分类展示,支持 Tab 切换。
**业务规则:**
- 二级 Tab 切换:待确认(含数量角标)、已确认、已完成、已取消
- 卡片展示:预约医院、状态标签、申请员工、科室、医生、挂号类别、预约时间
- 不同状态使用不同颜色标签:待确认(橙色)、已确认(蓝色)、已完成(绿色)、已取消(灰色)
**交互说明:**
- 点击待确认卡片:跳转到大病就医详情(待确认)页
- 点击已确认卡片:跳转到大病就医详情(已确认)页
- 点击已完成卡片:跳转到大病就医详情(已完成)页
- 点击已取消卡片:跳转到大病就医详情(已取消)页
---
### 11. 大病就医详情(待确认)
![页面截图](screenshots/serious-illness-detail-pending.jpg)
**功能说明:** 展示员工大病就医预约详情,操作人员可确认预约并派单,或取消预约。
**业务规则:**
- 申请员工信息卡片(可折叠):姓名、性别、年龄、员工编号、所属单位、所属部门、联系电话、身份证
- 预约信息卡片(可折叠):发起预约时间、预约医院、科室、医生、挂号类别、期望预约时间、病情描述
- 底部双按钮:取消预约、确认预约
**交互说明:**
- 点击"确认预约":弹出确认派单弹窗,需选择驻场人员后方可确认,确认后跳转回大病就医列表
- 点击"取消预约":弹出取消确认弹窗,需填写取消原因后方可确认,确认后跳转回大病就医列表
**确认派单弹窗表单:**
| 字段名 | 类型 | 必填 | 校验规则 |
|--------|------|------|----------|
| 驻场人员 | 搜索下拉选择 | 是 | 必须选择一名人员,选中后启用确认按钮 |
**取消预约弹窗表单:**
| 字段名 | 类型 | 必填 | 校验规则 |
|--------|------|------|----------|
| 取消原因 | 多行文本 | 是 | 不能为空,输入后启用确认按钮 |
---
### 12. 大病就医详情(已确认)
![页面截图](screenshots/serious-illness-detail-confirmed.jpg)
**功能说明:** 展示已确认的大病就医预约详情,操作人员可联系驻场人员或取消预约。
**业务规则:**
- 申请员工信息卡片和预约信息卡片内容同待确认页
- 底部双按钮:取消预约、联系驻场人员
**交互说明:**
- 点击"取消预约":弹出取消确认弹窗,需填写取消原因,确认后跳转回大病就医列表
- 点击"联系驻场人员":触发联系操作
---
### 13. 大病就医详情(已完成)
![页面截图](screenshots/serious-illness-detail-done.jpg)
**功能说明:** 展示已完成的大病就医预约详情,包含驻场人员提交的挂号结果。
**业务规则:**
- 申请员工信息卡片和预约信息卡片内容同上
- 新增挂号结果卡片(可折叠):就诊科室、就诊医生、就诊时段、排队序号、就诊医院、挂号类别、备注
- 底部单按钮:联系驻场人员
**交互说明:**
- 点击卡片标题:折叠/展开卡片
- 点击"联系驻场人员":触发联系操作
---
### 14. 大病就医详情(已取消)
![页面截图](screenshots/serious-illness-detail-cancelled.jpg)
**功能说明:** 展示已取消的大病就医预约详情,包含取消原因。
**业务规则:**
- 申请员工信息卡片和预约信息卡片内容同上
- 取消信息展示:取消时间、取消原因
- 无操作按钮,纯只读页面
**交互说明:**
- 点击卡片标题:折叠/展开卡片
- 点击返回:返回大病就医列表
---
## 四、知识库模块
### 15. 知识库首页
**功能说明:** 等待后续规划,提示“功能开发中,敬请期待~”
---
### 16. 知识详情
**功能说明:** 等待后续规划,提示“功能开发中,敬请期待~”
---
## 五、个人中心模块
### 17. 个人中心主页
![页面截图](screenshots/profile-index.jpg)
**功能说明:** 用户信息展示和功能菜单导航,展示头像、姓名、角色和所属应急中心。
**业务规则:**
- 用户信息区:头像、姓名(王昊)、角色(操作人员)、所属应急中心
- 菜单项:值班信息、修改个人信息、修改密码、关于我们
- 退出登录按钮
**交互说明:**
- 点击"值班信息":跳转到值班信息页
- 点击"修改个人信息":跳转到修改个人信息页
- 点击"修改密码":跳转到修改密码页
- 点击"退出登录":弹出二次确认弹窗
---
### 18. 修改个人信息
![页面截图](screenshots/edit-profile.jpg)
**功能说明:** 编辑用户头像和姓名。
**交互说明:**
- 点击头像:弹出底部操作菜单(拍照/从相册选择)
- 点击"保存":验证姓名非空,显示保存成功提示
**表单字段表:**
| 字段名 | 类型 | 必填 | 校验规则 |
|--------|------|------|----------|
| 头像 | 图片选择 | 否 | 支持拍照或从相册选择 |
| 姓名 | 单行文本 | 是 | 不能为空 |
---
### 19. 修改密码
![页面截图](screenshots/change-pwd.jpg)
**功能说明:** 修改用户登录密码。
**交互说明:**
- 点击"保存修改":弹出修改成功确认弹窗,确认后跳转回个人中心
**表单字段表:**
| 字段名 | 类型 | 必填 | 校验规则 |
|--------|------|------|----------|
| 当前密码 | 密码输入 | 是 | 不能为空 |
| 新密码 | 密码输入 | 是 | 不能为空 |
| 确认新密码 | 密码输入 | 是 | 必须与新密码一致 |
---
### 20. 值班信息
![页面截图](screenshots/duty-schedule.jpg)
**功能说明:** 查看值班日历和当日值班人员安排。
**业务规则:**
- 日历网格展示当前月份,标记今天(蓝色背景)和排班日(浅蓝色背景+蓝色圆点)
- 下方展示当日值班人员列表
- 支持月份前后切换
**交互说明:**
- 点击月份导航箭头:切换上/下月
- 点击"修改":跳转到排班配置页
---
### 21. 排班配置
![页面截图](screenshots/duty-config.jpg)
**功能说明:** 配置周排班,为每天选择专业人员和操作人员。
**业务规则:**
- 按周展示排班表,每天可配置专业人员和操作人员
- 人员选择为多选下拉,支持搜索
- 支持"复制上周排班"快捷操作
**交互说明:**
- 点击周导航箭头:切换上/下周
- 点击"复制上周排班":复制上周配置,无数据时提示
- 点击人员下拉:展开多选列表
- 点击"保存":保存成功后跳转回值班信息页
**表单字段表:**
| 字段名 | 类型 | 必填 | 校验规则 |
|--------|------|------|----------|
| 专业人员 | 多选下拉 | 否 | 可选多人 |
| 操作人员 | 多选下拉 | 否 | 可选多人 |
Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 22 KiB

@@ -63,7 +63,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
</button>
<span style="font-size:11px;color:#666;">求助时间:2026-04-24 14:30</span>
</div>
<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('operatorWorkOrderDetailSource','./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>
@@ -77,13 +77,13 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="scroll-content" style="padding:12px 16px;">
<div style="text-align:center;margin:8px 0;"><span style="font-size:11px;color:#bbb;background:#ebebeb;padding:3px 10px;border-radius:10px;">14:30</span></div>
<div style="text-align:center;margin:8px 0 14px;"><span style="font-size:11px;color:#fa8c16;background:#fff7e6;padding:4px 12px;border-radius:10px;border:1px solid #ffe7ba;">新应急事件 · 陈伟发起求助</span></div>
<!-- <div style="text-align:center;margin:8px 0 14px;"><span style="font-size:11px;color:#fa8c16;background:#fff7e6;padding:4px 12px;border-radius:10px;border:1px solid #ffe7ba;">新应急事件 · 陈伟发起求助</span></div>-->
<div style="display:flex;gap:8px;margin-bottom:14px;">
<div style="width:36px;height:36px;border-radius:50%;background:linear-gradient(135deg,#ffe0e0,#ffb3b3);display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0;">👨</div>
<div>
<div style="font-size:11px;color:#999;margin-bottom:4px;">陈伟(患者)</div>
<div style="background:#fff;border-radius:0 12px 12px 12px;padding:10px 14px;font-size:14px;color:#1a1a1a;max-width:220px;box-shadow:0 1px 4px rgba(0,0,0,0.06);line-height:1.5;">我胸口很闷,呼吸困难,已经持续20分钟了。</div>
<div style="background:#fff;border-radius:0 12px 12px 12px;padding:10px 14px;font-size:14px;color:#1a1a1a;max-width:220px;box-shadow:0 1px 4px rgba(0,0,0,0.06);line-height:1.5;">📹 通话时长 12:01</div>
</div>
</div>
@@ -95,7 +95,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
</div>
</div>
<div style="text-align:center;margin:8px 0 14px;"><span style="font-size:11px;color:#1677ff;background:#e6f4ff;padding:4px 12px;border-radius:10px;border:1px solid #bae0ff;">已派专业人员:张旭 | 已派救护车</span></div>
<!-- <div style="text-align:center;margin:8px 0 14px;"><span style="font-size:11px;color:#1677ff;background:#e6f4ff;padding:4px 12px;border-radius:10px;border:1px solid #bae0ff;">已派专业人员:张旭 | 已派救护车</span></div>-->
<div style="text-align:center;margin:8px 0;"><span style="font-size:11px;color:#bbb;background:#ebebeb;padding:3px 10px;border-radius:10px;">14:38</span></div>
@@ -1,147 +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>操作人员 - 结束应急 | 健康长庆原型</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: #f7f8fa; }
.scroll-content::-webkit-scrollbar { display: none; }
.form-section { background: #fff; margin: 12px 16px; border-radius: 12px; padding: 16px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
.form-section__title { font-size: 15px; font-weight: 600; color: #1a1a1a; margin-bottom: 14px; display: flex; align-items: center; gap: 6px; }
.form-section__title::before { content: ''; width: 3px; height: 16px; background: #1677ff; border-radius: 2px; }
.form-field { margin-bottom: 16px; }
.form-field:last-child { margin-bottom: 0; }
.form-label { font-size: 13px; color: #333; margin-bottom: 6px; display: flex; align-items: center; gap: 4px; }
.form-label .required { color: #ff4d4f; }
.form-input { width: 100%; height: 40px; border: 1px solid #e8e8e8; border-radius: 8px; padding: 0 12px; font-size: 14px; outline: none; color: #1a1a1a; background: #fff; }
.form-input:focus { border-color: #1677ff; }
.form-textarea { width: 100%; min-height: 100px; border: 1px solid #e8e8e8; border-radius: 8px; padding: 10px 12px; font-size: 14px; outline: none; resize: vertical; font-family: inherit; line-height: 1.6; color: #1a1a1a; }
.form-textarea:focus { border-color: #1677ff; }
.form-select { width: 100%; height: 40px; border: 1px solid #e8e8e8; border-radius: 8px; padding: 0 12px; font-size: 14px; outline: none; color: #1a1a1a; background: #fff; appearance: none; background-image: 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"); background-repeat: no-repeat; background-position: right 12px center; }
.form-select:focus { border-color: #1677ff; }
/* 患者信息卡 */
.patient-card { background: #fff7e6; border: 1px solid #ffe7ba; border-radius: 10px; padding: 12px 14px; display: flex; align-items: center; gap: 10px; }
.patient-card__avatar { width: 40px; height: 40px; border-radius: 50%; background: linear-gradient(135deg,#fff1f0,#ffccc7); display: flex; align-items: center; justify-content: center; font-size: 20px; flex-shrink: 0; }
.patient-card__info { flex: 1; }
.patient-card__name { font-size: 15px; font-weight: 600; color: #1a1a1a; }
.patient-card__detail { font-size: 12px; color: #666; margin-top: 2px; }
/* 照片上传 */
.photo-grid { display: flex; gap: 10px; flex-wrap: wrap; }
.photo-item { width: 72px; height: 72px; border-radius: 8px; border: 1px solid #e8e8e8; overflow: hidden; background: #fafafa; display: flex; align-items: center; justify-content: center; }
.photo-item img { width: 100%; height: 100%; object-fit: cover; }
.photo-add { width: 72px; height: 72px; border-radius: 8px; border: 2px dashed #d9d9d9; display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; color: #bbb; font-size: 24px; transition: all .15s; }
.photo-add:hover { border-color: #1677ff; color: #1677ff; }
.photo-add span { font-size: 10px; margin-top: 2px; }
/* 底部按钮 */
.bottom-bar { padding: 12px 16px 28px; background: #fff; border-top: 1px solid #f0f0f0; flex-shrink: 0; }
.btn-submit { width: 100%; height: 44px; border-radius: 10px; font-size: 16px; font-weight: 600; cursor: pointer; border: none; background: #ff4d4f; color: #fff; transition: background .2s; }
.btn-submit:hover { background: #ff7875; }
</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">
<!-- [交互] 点击返回: ./emergency-chat.html -->
<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 style="padding:12px 16px 0;">
<div class="patient-card">
<div class="patient-card__avatar">👨</div>
<div class="patient-card__info">
<div class="patient-card__name">陈伟 · 男 · 47岁</div>
<div class="patient-card__detail">采油三厂 · 第二作业区 | 求助时间:14:30</div>
</div>
</div>
</div>
<!-- 结束原因 -->
<div class="form-section">
<div class="form-section__title">结束信息</div>
<div class="form-field">
<div class="form-label"><span class="required">*</span>结束原因</div>
<select class="form-select">
<option value="">请选择结束原因</option>
<option selected>患者已送达医院</option>
<option>患者症状缓解</option>
<option>误报/取消求助</option>
<option>转交其他机构处理</option>
<option>其他</option>
</select>
</div>
<div class="form-field">
<div class="form-label"><span class="required">*</span>处理结果</div>
<textarea class="form-textarea" placeholder="请描述本次应急的处理结果...">患者已由救护车送达西安市第一人民医院急诊科,初步诊断为心绞痛,目前状态稳定,已安排住院观察。</textarea>
</div>
<div class="form-field">
<div class="form-label">送达医院</div>
<input class="form-input" type="text" value="西安市第一人民医院" placeholder="请输入送达医院名称" />
</div>
</div>
<!-- 现场照片 -->
<div class="form-section">
<div class="form-section__title">现场照片</div>
<div class="form-field">
<div class="photo-grid">
<div class="photo-item" style="background:linear-gradient(135deg,#e6f4ff,#bae0ff);font-size:28px;color:#1677ff;">🏥</div>
<div class="photo-item" style="background:linear-gradient(135deg,#f6ffed,#d9f7be);font-size:28px;color:#52c41a;">📋</div>
<div class="photo-add">+<span>添加</span></div>
</div>
<div style="font-size:11px;color:#999;margin-top:6px;">已上传 2/9 张</div>
</div>
</div>
<!-- 备注 -->
<div class="form-section">
<div class="form-section__title">补充说明</div>
<div class="form-field">
<textarea class="form-textarea" placeholder="如有其他需要补充的信息,请在此填写..." style="min-height:80px;"></textarea>
</div>
</div>
<div style="height:16px;"></div>
</div>
<!-- 底部提交按钮 -->
<div class="bottom-bar">
<!-- [交互] 点击确认结束应急,返回工作台 -->
<button class="btn-submit" onclick="confirmEnd()">确认结束应急</button>
</div>
</div>
<script>
sessionStorage.setItem('appRole', 'operator');
function confirmEnd() {
if (confirm('确认结束本次应急?结束后不可撤销。')) {
sessionStorage.setItem('operatorWorkbenchTab', 'done');
location.href = './index.html';
}
}
</script>
</body>
</html>
+2 -2
View File
@@ -134,7 +134,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<!-- 已完成 -->
<div id="panel-done" class="content-panel">
<div style="height:10px;"></div>
<div class="case-card" onclick="location.href='./work-order-detail.html'">
<div class="case-card" onclick="sessionStorage.setItem('operatorWorkOrderDetailSource','./index.html');location.href='./work-order-detail.html'">
<div class="case-head">
<div class="case-avatar case-avatar-emergency"></div>
<div class="case-main">
@@ -149,7 +149,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
</div>
</div>
<div class="case-card" onclick="location.href='./emergency-chat.html'">
<div class="case-card" onclick="location.href='./emergency-chat-done.html'">
<div class="case-head">
<div class="case-avatar case-avatar-emergency">📄</div>
<div class="case-main">
@@ -137,7 +137,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="bottom-btns">
<button class="bottom-btns__btn bottom-btns__btn--cancel" onclick="document.getElementById('cancelModal').classList.add('modal-mask--show')">取消预约</button>
<button class="bottom-btns__btn bottom-btns__btn--primary" onclick="document.getElementById('confirmModal').classList.add('modal-mask--show')">确认预约</button>
<button class="bottom-btns__btn bottom-btns__btn--primary" onclick="document.getElementById('confirmModal').classList.add('modal-mask--show')">立即派单</button>
</div>
<div class="modal-mask" id="confirmModal">
@@ -173,6 +173,10 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
</div>
</div>
</div>
<div class="modal__field">
<div class="modal__field-label">派单说明</div>
<textarea id="dispatchRemark" class="modal__textarea" placeholder="请输入派单说明(将同步给驻场人员)"></textarea>
</div>
<div class="modal__btns">
<button class="modal__btn modal__btn--cancel" onclick="closeConfirmModal()">取消</button>
<button class="modal__btn modal__btn--primary disabled" id="confirmBookBtn" onclick="doConfirmBooking()">确认派单</button>
@@ -204,6 +208,12 @@ function toggleInfoCard(cardId, trigger) {
var selectedPerson = null;
function updateConfirmBookBtn() {
var btn = document.getElementById('confirmBookBtn');
if (!btn) return;
btn.classList.toggle('disabled', !selectedPerson);
}
function openPersonDrop() {
document.getElementById('personSelect').classList.add('open');
}
@@ -217,7 +227,7 @@ function selectPerson(el) {
selectedPerson = el.getAttribute('data-name');
document.getElementById('personSearch').value = selectedPerson;
closePersonDrop();
document.getElementById('confirmBookBtn').classList.remove('disabled');
updateConfirmBookBtn();
}
function filterPersons() {
@@ -233,7 +243,10 @@ function filterPersons() {
});
document.getElementById('personEmpty').classList.toggle('show', visible === 0);
openPersonDrop();
if (!keyword) { selectedPerson = null; document.getElementById('confirmBookBtn').classList.add('disabled'); }
if (!keyword) {
selectedPerson = null;
updateConfirmBookBtn();
}
}
function closeConfirmModal() {
@@ -241,10 +254,18 @@ function closeConfirmModal() {
}
function doConfirmBooking() {
if (!selectedPerson) return;
if (!selectedPerson) {
alert('请选择驻场人员');
return;
}
location.href = './serious-illness-list.html';
}
var dispatchRemarkEl = document.getElementById('dispatchRemark');
if (dispatchRemarkEl) {
dispatchRemarkEl.addEventListener('input', updateConfirmBookBtn);
}
document.addEventListener('click', function(e) {
var sel = document.getElementById('personSelect');
if (sel && !sel.contains(e.target)) {
@@ -110,8 +110,8 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
</div>
<div class="nav-bar">
<!-- [交互] 点击返回: ./emergency-chat-done.html -->
<button class="back-btn" onclick="location.href='./emergency-chat-done.html'">
<!-- [交互] 点击返回: 来源页面(无来源则 ./index.html -->
<button class="back-btn" onclick="goBackToSource()">
<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>
@@ -309,6 +309,15 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<script>
sessionStorage.setItem('appRole', 'operator');
function goBackToSource() {
var src = sessionStorage.getItem('operatorWorkOrderDetailSource');
if (src) {
location.href = src;
return;
}
location.href = './index.html';
}
function toggleCard(cardId, headerEl) {
var card = document.getElementById(cardId);
card.classList.toggle('card--collapsed');
+292
View File
@@ -0,0 +1,292 @@
# 专业人员端(健康应急APP)产品需求文档
## 模块概述
专业人员端为具备医学专业背景的应急人员提供移动端工作平台,负责在应急求助过程中提供专业医学指导,包括实时聊天沟通、给出救助意见、查看患者定位和周边医疗资源。专业人员通过聊天界面与操作人员、患者进行三方协作,是应急救助中的医学决策支撑角色。
### 页面导航结构
```
专业人员端
├── 工作台(底部Tab
│ ├── 进行中 → 应急聊天(进行中)
│ │ ├── 救助意见表单
│ │ ├── 患者定位地图
│ │ └── 工单详情(进行中)
│ └── 已结束 → 应急聊天(已结束)
│ └── 工单详情(已完成)
├── 知识库(底部Tab
│ ├── 知识文章(分类Tab)→ 知识详情
│ └── 规章制度(PDF列表)
├── AI助手(底部Tab
├── 消息(底部Tab
└── 我的(底部Tab
├── 值班信息
├── 修改个人信息
├── 修改密码
└── 退出登录(确认弹窗)
```
### 应急状态流转图
```mermaid
stateDiagram-v2
[*] --> 进行中 : 未结束的应急工单
进行中 --> 已结束 : 员工/操作人员/专业人员任意一方结束应急
```
## 页面清单
| 序号 | 文件名 | 页面名称 | 所属模块 |
|------|--------|----------|----------|
| 1 | workbench/index.html | 工作台首页 | 工作台 |
| 2 | workbench/emergency-chat-ongoing.html | 应急聊天(进行中) | 工作台·应急求助 |
| 3 | workbench/emergency-chat-done.html | 应急聊天(已结束) | 工作台·应急求助 |
| 4 | workbench/rescue-opinion.html | 救助意见表单 | 工作台·应急求助 |
| 5 | workbench/patient-location.html | 患者定位地图 | 工作台·应急求助 |
| 6 | workbench/work-order-detail-ongoing.html | 工单详情(进行中) | 工作台·应急求助 |
| 7 | workbench/work-order-detail.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 | 修改密码 | 我的 |
| 15 | profile/duty-schedule.html | 值班信息 | 我的 |
## 逐页说明
---
## 一、工作台模块
### 1. 工作台首页
![页面截图](screenshots/index.jpg)
**功能说明:** 专业人员工作台入口,展示当前参与的应急工单列表,按进行中/已结束分类管理。
**业务规则:**
- 二级 Tab 切换:进行中(含数量角标)/ 已结束(含数量角标)
- 应急卡片展示:患者姓名、年龄、求助方式标签、求助时间
- 应急求助方式分为“拨打120”、“应急视频”、“应急电话”、“线下应急”四种,“线下应急”为操作人员手动录入工单方式。
- 已结束卡片额外展示结束时间
**交互说明:**
- 点击进行中卡片:求助方式如果是“应急视频”则跳转到应急聊天(进行中)页,其余跳转到工单详情(进行中)页
- 点击已结束卡片:求助方式如果是“应急视频”则跳转到应急聊天(已结束)页,其余跳转到工单详情(已完成)页
- 底部导航栏 5 个 Tab:工作台、知识库、AI 助手、消息、我的
---
## 二、应急求助业务线
### 2. 应急聊天(进行中)
![页面截图](screenshots/emergency-chat-ongoing.jpg)
**功能说明:** 专业人员与患者、操作人员的实时三方聊天界面。
**业务规则:**
- 患者信息条(可折叠)展示:求助时间、患者姓名、年龄、所属单位、联系电话、求助方式、查看工单详情入口
- 聊天区域展示三方消息:患者(左侧气泡)、专业人员(右侧气泡)、操作人员(左侧气泡)
- 操作按钮栏提供 2 个功能入口:救助意见、患者定位
- 输入区支持语音/文字模式切换和媒体选择面板,媒体选择支持拍照、图库、视频通话。
**交互说明:**
- 点击"查看工单":跳转到工单详情(进行中)页
- 点击"救助意见":跳转到救助意见表单页,确认完后在聊天页发送一条自定义救助意见卡片消息
- 点击"患者定位":跳转到患者定位地图页
- 点击"结束应急":弹出二次确认弹窗,确认后发送一条结束应急的卡片消息,并跳转回工作台首页(已结束 Tab),
- 点击"🎤"图标:切换语音/文字输入模式
- 点击"+"图标:展开/收起媒体选择面板
- 点击"➤"发送按钮:将输入框内容发送为专业人员消息气泡
---
### 3. 应急聊天(已结束)
![页面截图](screenshots/emergency-chat-done.jpg)
**功能说明:** 查看已结束应急的完整聊天记录,只读模式。
**业务规则:**
- 患者信息条(可折叠)展示患者基本信息
- 聊天区域展示完整历史消息
- 应急结束卡片以灰色样式展示结束时间
- 底部固定提示条:"本次应急已结束"
**交互说明:**
- 点击"查看工单":跳转到工单详情(已完成)页
- 点击返回:跳转回工作台首页(已结束 Tab)
---
### 4. 救助意见表单
![页面截图](screenshots/rescue-opinion.jpg)
**功能说明:** 专业人员填写救助意见,提交后意见将发送到聊天页面中。
**业务规则:**
- 患者信息展示区(只读):患者姓名、性别、年龄、单位、部门
- 救助意见输入区:多行文本输入
**交互说明:**
- 点击"提交":提交救助意见,跳转回应急聊天页,发送救助意见卡片消息在聊天页中
- 点击返回:返回应急聊天页
**表单字段表:**
| 字段名 | 类型 | 必填 | 校验规则 |
|--------|------|----|----------|
| 救助意见 | 多行文本 | 否 | 最大限制200字 |
---
### 5. 患者定位地图
![页面截图](screenshots/patient-location.jpg)
**功能说明:** 地图展示患者实时位置和周边医疗资源分布,功能与操作人员端一致。
**业务规则:**
- 地图中心展示患者位置标记
- 资源类型 Tab 栏:油田医院、合作医院、医疗点、救护车、AED、急救包
- 不同类型资源使用不同颜色标记
- 资源卡片展示:点击资源图标后,底部弹窗显示资源卡片,显示资源图片、名称、所属单位/机构、距离、电话、地址
**交互说明:**
- 点击资源类型 Tab:切换显示对应类型的资源标记
- 点击资源标记:底部弹出资源详情卡片
- 点击地图空白处:关闭资源卡片
---
### 6. 工单详情(进行中)
![页面截图](screenshots/work-order-detail-ongoing.jpg)
**功能说明:** 展示进行中工单的完整信息。
**业务规则:**
- 四个可折叠卡片:基本信息、救助信息、派单信息、救护车支援
- 基本信息:工单编号、类型、应急中心、求助员工、部门、求助方式、时间、位置、操作人员、专业人员、状态
- 救助信息:救助意见、救助结果、相关照片、补充小结。除了应急视频,其余的求助方式可以编辑救助意见。在救助信息意见显示“编辑”按钮,参考已完成状态的工单详情
- 派单信息和救护车支援:展示已有记录或空状态提示
**交互说明:**
- 点击卡片标题:折叠/展开卡片
- 点击返回:返回应急聊天页
---
### 7. 工单详情(已完成)
![页面截图](screenshots/work-order-detail.jpg)
**功能说明:** 展示已完成工单的完整信息,所有卡片数据均已填充。
**业务规则:**
- 四个可折叠卡片结构同进行中版本
- 救助信息展示完整的救助意见、救助结果、相关照片、补充小结
- 派单信息展示完整派单历史
- 救护车支援展示完整调度记录
**交互说明:**
- 点击卡片标题:折叠/展开卡片
- 点击返回:返回应急聊天(已结束)页
---
## 三、知识库模块
### 8. 知识库首页
**功能说明:** 等待后续规划,提示“功能开发中,敬请期待~”
### 9. 知识详情
**功能说明:** 等待后续规划,提示“功能开发中,敬请期待~”
## 四、个人中心模块
### 10. 个人中心主页
![页面截图](screenshots/profile-index.jpg)
**功能说明:** 用户信息展示和功能菜单导航。
**业务规则:**
- 用户信息区:头像、姓名、角色(专业人员)、所属应急中心
- 菜单项:值班信息、修改个人信息、修改密码、关于我们
- 退出登录按钮
**交互说明:**
- 点击"值班信息":跳转到值班信息页
- 点击"修改个人信息":跳转到修改个人信息页
- 点击"修改密码":跳转到修改密码页
- 点击"退出登录":弹出二次确认弹窗
---
### 11. 修改个人信息
![页面截图](screenshots/edit-profile.jpg)
**功能说明:** 编辑用户头像和姓名。
**交互说明:**
- 点击头像:弹出底部操作菜单(拍照/从相册选择)
- 点击"保存":验证姓名非空,显示保存成功提示
**表单字段表:**
| 字段名 | 类型 | 必填 | 校验规则 |
|--------|------|------|----------|
| 头像 | 图片选择 | 否 | 支持拍照或从相册选择 |
| 姓名 | 单行文本 | 是 | 不能为空 |
---
### 12. 修改密码
![页面截图](screenshots/change-pwd.jpg)
**功能说明:** 修改用户登录密码。
**交互说明:**
- 点击"保存修改":弹出修改成功确认弹窗,确认后跳转回个人中心
**表单字段表:**
| 字段名 | 类型 | 必填 | 校验规则 |
|--------|------|------|----------|
| 当前密码 | 密码输入 | 是 | 不能为空 |
| 新密码 | 密码输入 | 是 | 不能为空 |
| 确认新密码 | 密码输入 | 是 | 必须与新密码一致 |
---
### 13. 值班信息
![页面截图](screenshots/duty-schedule.jpg)
**功能说明:** 查看值班日历和当日值班人员安排。
**业务规则:**
- 日历网格展示当前月份,标记今天(蓝色背景)和排班日(浅蓝色背景+蓝色圆点)
- 下方展示当日值班人员列表
- 支持月份前后切换
**交互说明:**
- 点击月份导航箭头:切换上/下月
- 点击返回:返回个人中心
Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 40 KiB

@@ -82,7 +82,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-ongoing.html -->
<button onclick="location.href='./work-order-detail-ongoing.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('professionalWorkOrderOngoingSource','./emergency-chat-ongoing.html');sessionStorage.setItem('professionalWorkOrderMethod','应急视频');location.href='./work-order-detail-ongoing.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>
@@ -31,6 +31,8 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
.tag-blue { background: #e6f4ff; color: #1677ff; }
.tag-green { background: #f6ffed; color: #52c41a; }
.tag-gray { background: #f5f5f5; color: #999; }
.tag-purple { background: #f9f0ff; color: #722ed1; }
.tag-orange { background: #fff7e6; color: #fa8c16; }
/* 应急卡片 */
.emergency-card { background: #fff; border-radius: 12px; margin: 10px 16px 0; padding: 14px; cursor: pointer; box-shadow: 0 1px 4px rgba(0,0,0,0.06); transition: transform 0.15s; }
.emergency-card:active { transform: scale(0.98); }
@@ -70,7 +72,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<!-- 二级Tab:进行中 / 已结束 -->
<div class="seg-tabs" style="flex-shrink:0;">
<div class="seg-tab active" onclick="switchTab(this,'panel-ongoing')">进行中<span class="badge" style="background:#fa8c16;">2</span></div>
<div class="seg-tab active" onclick="switchTab(this,'panel-ongoing')">进行中<span class="badge" style="background:#fa8c16;">3</span></div>
<div class="seg-tab" onclick="switchTab(this,'panel-done')">已结束</div>
</div>
@@ -85,20 +87,34 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="ec-avatar">🚑</div>
<div class="ec-info">
<div class="ec-name">陈伟<span class="age">47岁</span></div>
<div class="ec-time">求助方式:<span class="tag tag-blue">应急视频</span></div>
<div class="ec-time">求助时间:2026-04-23 14:30</div>
</div>
<span class="tag tag-blue">进行中</span>
<span class="tag tag-red">进行中</span>
</div>
</div>
<!-- [交互] 点击跳转至: ./emergency-chat-ongoing.html -->
<div class="emergency-card" onclick="location.href='./emergency-chat-ongoing.html'">
<!-- [交互] 点击跳转至: ./work-order-detail-ongoing.html -->
<div class="emergency-card" onclick="sessionStorage.setItem('professionalWorkOrderOngoingSource','./index.html');sessionStorage.setItem('professionalWorkOrderMethod','应急电话');location.href='./work-order-detail-ongoing.html'">
<div class="ec-top">
<div class="ec-avatar">🚑</div>
<div class="ec-info">
<div class="ec-name">刘海波<span class="age">55岁</span></div>
<div class="ec-time">求助方式:<span class="tag tag-purple">应急电话</span></div>
<div class="ec-time">求助时间:2026-04-23 10:20</div>
</div>
<span class="tag tag-blue">进行中</span>
<span class="tag tag-red">进行中</span>
</div>
</div>
<!-- [交互] 点击跳转至: ./work-order-detail-ongoing.html -->
<div class="emergency-card" onclick="sessionStorage.setItem('professionalWorkOrderOngoingSource','./index.html');sessionStorage.setItem('professionalWorkOrderMethod','拨打120');location.href='./work-order-detail-ongoing.html'">
<div class="ec-top">
<div class="ec-avatar">🚑</div>
<div class="ec-info">
<div class="ec-name">王建国<span class="age">38岁</span></div>
<div class="ec-time">求助方式:<span class="tag tag-orange">拨打120</span></div>
<div class="ec-time">求助时间:2026-04-23 08:15</div>
</div>
<span class="tag tag-red">进行中</span>
</div>
</div>
<div style="height:16px;"></div>
@@ -106,24 +122,26 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<!-- 已结束列表 -->
<div id="panel-done" style="display:none;">
<!-- [交互] 点击跳转至: ./emergency-chat-done.html -->
<div class="emergency-card" onclick="location.href='./emergency-chat-done.html'">
<!-- [交互] 点击跳转至: ./work-order-detail.html -->
<div class="emergency-card" onclick="sessionStorage.setItem('professionalWorkOrderDetailSource','./index.html');sessionStorage.setItem('professionalWorkOrderMethod','应急视频');location.href='./work-order-detail.html'">
<div class="ec-top">
<div class="ec-avatar">🚑</div>
<div class="ec-info">
<div class="ec-name">孙丽<span class="age">41岁</span></div>
<div class="ec-time">求助方式:<span class="tag tag-blue">应急视频</span></div>
<div class="ec-time">求助时间:2026-04-22 16:00</div>
<div class="ec-time">结束时间:2026-04-22 17:35</div>
</div>
<span class="tag tag-green">已结束</span>
</div>
</div>
<!-- [交互] 点击跳转至: ./emergency-chat-done.html -->
<div class="emergency-card" onclick="location.href='./emergency-chat-done.html'">
<!-- [交互] 点击跳转至: ./work-order-detail.html -->
<div class="emergency-card" onclick="sessionStorage.setItem('professionalWorkOrderDetailSource','./index.html');sessionStorage.setItem('professionalWorkOrderMethod','线下应急');location.href='./work-order-detail.html'">
<div class="ec-top">
<div class="ec-avatar">🚑</div>
<div class="ec-info">
<div class="ec-name">周明<span class="age">33岁</span></div>
<div class="ec-time">求助方式:<span class="tag tag-orange">线下应急</span></div>
<div class="ec-time">求助时间:2026-04-21 09:45</div>
<div class="ec-time">结束时间:2026-04-21 11:20</div>
</div>
@@ -16,8 +16,15 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
.scroll-content::-webkit-scrollbar { display: none; }
.card { background: #fff; border-radius: 12px; margin: 12px 16px 0; padding: 16px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
.card__title { font-size: 15px; font-weight: 700; color: #1a1a1a; margin-bottom: 12px; padding-bottom: 8px; border-bottom: 1px solid #f0f0f0; }
.card { background: #fff; border-radius: 12px; margin: 12px 16px 0; box-shadow: 0 1px 4px rgba(0,0,0,0.06); overflow: hidden; }
.card__header { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px; border-bottom: 1px solid #f0f0f0; cursor: pointer; }
.card__title { font-size: 15px; font-weight: 700; color: #1a1a1a; }
.card__toggle { display: inline-flex; align-items: center; gap: 4px; color: #1677ff; font-size: 12px; font-weight: 600; }
.card__arrow { width: 14px; height: 14px; transition: transform .2s ease; }
.card__body { padding: 0 16px 16px; }
.card--collapsed .card__body { display: none; }
.card--collapsed .card__arrow { transform: rotate(-90deg); }
.card--collapsed .card__header { border-bottom: none; }
.info-item { display: flex; font-size: 13px; line-height: 1.6; padding: 5px 0; }
.info-item__label { color: #999; min-width: 72px; flex-shrink: 0; }
.info-item__value { color: #333; flex: 1; word-break: break-all; }
@@ -36,6 +43,33 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
.empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 28px 0 12px; }
.empty-state__icon { font-size: 36px; margin-bottom: 8px; opacity: .35; }
.empty-state__text { font-size: 13px; color: #bbb; }
/* 编辑按钮 */
.edit-btn { background: none; border: none; color: #1677ff; font-size: 13px; cursor: pointer; padding: 0; margin-left: 8px; }
/* 编辑弹窗 */
.edit-mask { position: absolute; inset: 0; background: rgba(0,0,0,0.45); display: none; align-items: center; justify-content: center; z-index: 30; padding: 24px; }
.edit-mask.show { display: flex; }
.edit-dialog { width: 100%; background: #fff; border-radius: 16px; overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,0.2); max-height: 80vh; display: flex; flex-direction: column; }
.edit-dialog__head { padding: 18px 20px; font-size: 17px; font-weight: 700; color: #1a1a1a; border-bottom: 1px solid #f0f0f0; }
.edit-dialog__body { flex: 1; overflow-y: auto; padding: 20px; }
.edit-dialog__textarea { width: 100%; min-height: 120px; padding: 12px; border: 1px solid #d9d9d9; border-radius: 8px; font-size: 14px; font-family: inherit; resize: vertical; }
.edit-dialog__actions { display: flex; gap: 8px; padding: 16px 20px; border-top: 1px solid #f0f0f0; }
.edit-dialog__btn { flex: 1; height: 40px; border: none; border-radius: 8px; font-size: 15px; cursor: pointer; font-weight: 600; }
.edit-dialog__btn--cancel { background: #f5f5f5; color: #666; }
.edit-dialog__btn--confirm { background: #1677ff; color: #fff; }
/* 底部结束应急按钮 */
.end-bar { padding: 12px 16px; background: #fff; border-top: 1px solid #f0f0f0; flex-shrink: 0; display: none; }
.end-btn { width: 100%; height: 44px; border: none; border-radius: 10px; background: #ff4d4f; color: #fff; font-size: 15px; font-weight: 600; cursor: pointer; }
/* 二次确认弹窗 */
.confirm-mask { position: absolute; inset: 0; background: rgba(0,0,0,0.45); display: none; align-items: center; justify-content: center; z-index: 30; padding: 24px; }
.confirm-mask.show { display: flex; }
.confirm-dialog { width: 100%; background: #fff; border-radius: 16px; overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,0.2); }
.confirm-dialog__head { padding: 18px 20px 8px; font-size: 17px; font-weight: 700; color: #1a1a1a; text-align: center; }
.confirm-dialog__body { padding: 0 20px 20px; font-size: 14px; line-height: 1.7; color: #666; text-align: center; }
.confirm-dialog__actions { display: flex; border-top: 1px solid #f0f0f0; }
.confirm-dialog__btn { flex: 1; height: 48px; border: none; background: #fff; font-size: 15px; cursor: pointer; }
.confirm-dialog__btn + .confirm-dialog__btn { border-left: 1px solid #f0f0f0; }
.confirm-dialog__btn--cancel { color: #666; }
.confirm-dialog__btn--confirm { color: #ff4d4f; font-weight: 600; }
</style>
</head>
<body>
@@ -46,8 +80,8 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
</div>
<div class="nav-bar">
<!-- [交互] 点击返回: ./emergency-chat-ongoing.html -->
<button class="back-btn" onclick="location.href='./emergency-chat-ongoing.html'">
<!-- [交互] 点击返回: 来源页面(无来源则 ./index.html -->
<button class="back-btn" onclick="goBackToSource()">
<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>
@@ -55,28 +89,39 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="scroll-content">
<!-- 基本信息 -->
<div class="card">
<div class="card__title">基本信息</div>
<div class="card" id="basic-info-card">
<div class="card__header" onclick="toggleCard('basic-info-card', this)">
<div class="card__title">基本信息</div>
<div class="card__toggle"><span>收起</span><svg class="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="card__body">
<div class="info-item"><span class="info-item__label">工单编号</span><span class="info-item__value">YJ5633280</span></div>
<div class="info-item"><span class="info-item__label">工单类型</span><span class="info-item__value">正常派单</span></div>
<div class="info-item"><span class="info-item__label">应急中心</span><span class="info-item__value">西安应急中心</span></div>
<div class="info-item"><span class="info-item__label">求助员工</span><span class="info-item__value">陈伟(EMP-71023</span></div>
<div class="info-item"><span class="info-item__label">所属单位</span><span class="info-item__value">采油一厂</span></div>
<div class="info-item"><span class="info-item__label">所属部门</span><span class="info-item__value">第一作业区</span></div>
<div class="info-item"><span class="info-item__label">求助方式</span><span class="info-item__value">应急视频</span></div>
<div class="info-item"><span class="info-item__label">求助方式</span><span class="info-item__value" id="help-method">应急视频</span></div>
<div class="info-item"><span class="info-item__label">求助时间</span><span class="info-item__value">2026-04-23 14:30:00</span></div>
<div class="info-item"><span class="info-item__label">位置信息</span><span class="info-item__value"><span class="location-link"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M8 1C5.24 1 3 3.24 3 6c0 3.75 5 7 5 7s5-3.25 5-7c0-2.76-2.24-5-5-5z" stroke="currentColor" stroke-width="1.4"/><circle cx="8" cy="6" r="1.5" stroke="currentColor" stroke-width="1.2"/></svg>陕西省庆阳市华池县采油一厂作业区</span></span></div>
<div class="info-item"><span class="info-item__label">操作人员</span><span class="info-item__value">刘旭</span></div>
<div class="info-item"><span class="info-item__label">专业人员</span><span class="info-item__value">张旭</span></div>
<div class="info-item"><span class="info-item__label">工单状态</span><span class="info-item__value"><span class="tag tag-blue">进行中</span></span></div>
</div>
</div>
<!-- 救助信息 -->
<div class="card">
<div class="card__title">救助信息</div>
<div class="card" id="rescue-info-card">
<div class="card__header" onclick="toggleCard('rescue-info-card', this)">
<div class="card__title">救助信息</div>
<div class="card__toggle"><span>收起</span><svg class="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="card__body">
<div class="desc-block">
<div class="desc-block__label">救助意见:</div>
<div class="desc-block__text">-</div>
<div style="display: flex; align-items: center; justify-content: space-between;">
<div class="desc-block__label">救助意见:</div>
</div>
<div class="desc-block__text" id="advice-text">-</div>
</div>
<div class="desc-block">
<div class="desc-block__label">救助结果:</div>
@@ -96,33 +141,142 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<li class="summary-item"><span class="summary-item__idx">2.</span><span>已联系操作人员安排驻场人员前往现场协助转运</span></li>
</ul>
</div>
</div>
</div>
<!-- 派单信息 -->
<div class="card">
<div class="card__title">派单信息</div>
<div class="card" id="dispatch-info-card">
<div class="card__header" onclick="toggleCard('dispatch-info-card', this)">
<div class="card__title">派单信息</div>
<div class="card__toggle"><span>收起</span><svg class="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="card__body">
<div class="empty-state">
<div class="empty-state__icon">📋</div>
<div class="empty-state__text">暂无派单信息</div>
</div>
</div>
</div>
<!-- 救护车支援 -->
<div class="card">
<div class="card__title">救护车支援</div>
<div class="card" id="ambulance-card">
<div class="card__header" onclick="toggleCard('ambulance-card', this)">
<div class="card__title">救护车支援</div>
<div class="card__toggle"><span>收起</span><svg class="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="card__body">
<div class="empty-state">
<div class="empty-state__icon">🚑</div>
<div class="empty-state__text">暂无救护车支援信息</div>
</div>
</div>
</div>
<div style="height:16px;"></div>
</div>
<!-- 编辑弹窗 -->
<div id="edit-mask" class="edit-mask" onclick="closeEditAdvice(event)">
<div class="edit-dialog">
<div class="edit-dialog__head">编辑救助意见</div>
<div class="edit-dialog__body">
<textarea id="edit-textarea" class="edit-dialog__textarea" placeholder="请输入救助意见..."></textarea>
</div>
<div class="edit-dialog__actions">
<button class="edit-dialog__btn edit-dialog__btn--cancel" onclick="closeEditAdvice(event)">取消</button>
<button class="edit-dialog__btn edit-dialog__btn--confirm" onclick="saveEditAdvice(event)">保存</button>
</div>
</div>
</div>
<!-- 底部结束应急按钮 -->
<div id="end-bar" class="end-bar">
<button class="end-btn" onclick="openEndConfirm()">结束应急</button>
</div>
<!-- 结束应急确认弹窗 -->
<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__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>
</div>
</div>
</div>
</div>
<script>
sessionStorage.setItem('appRole', 'professional');
function goBackToSource() {
var src = sessionStorage.getItem('professionalWorkOrderOngoingSource');
if (src) {
location.href = src;
return;
}
location.href = './index.html';
}
// 读取并显示求助方式
var method = sessionStorage.getItem('professionalWorkOrderMethod');
if (method) {
document.getElementById('help-method').textContent = method;
// 如果求助方式是"应急电话"或"拨打120",显示结束应急按钮
if (method === '应急电话' || method === '拨打120') {
document.getElementById('end-bar').style.display = 'block';
}
}
function toggleCard(cardId, headerEl) {
var card = document.getElementById(cardId);
if (!card) return;
card.classList.toggle('card--collapsed');
var isCollapsed = card.classList.contains('card--collapsed');
var toggle = headerEl ? headerEl.querySelector('.card__toggle span') : null;
if (toggle) toggle.textContent = isCollapsed ? '展开' : '收起';
}
function openEditAdvice() {
var text = document.getElementById('advice-text').textContent;
document.getElementById('edit-textarea').value = text === '-' ? '' : text;
document.getElementById('edit-mask').classList.add('show');
}
function closeEditAdvice(event) {
if (event) {
event.stopPropagation();
if (event.currentTarget !== event.target && !event.target.classList.contains('edit-dialog__btn--cancel')) return;
}
document.getElementById('edit-mask').classList.remove('show');
}
function saveEditAdvice(event) {
event.stopPropagation();
var text = document.getElementById('edit-textarea').value.trim();
document.getElementById('advice-text').textContent = text || '-';
closeEditAdvice();
}
function openEndConfirm() {
document.getElementById('confirm-mask').classList.add('show');
}
function closeEndConfirm(event) {
if (event) {
event.stopPropagation();
if (event.currentTarget !== event.target && !event.target.classList.contains('confirm-dialog__btn--cancel')) return;
}
document.getElementById('confirm-mask').classList.remove('show');
}
function confirmEndEmergency(event) {
event.stopPropagation();
sessionStorage.setItem('professionalWorkbenchTab', 'done');
location.href = './index.html';
}
</script>
</body>
</html>
@@ -16,8 +16,15 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
.nav-title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 17px; font-weight: 600; color: #1a1a1a; white-space: nowrap; }
.scroll-content { flex: 1; overflow-y: auto; background: #f7f8fa; }
.scroll-content::-webkit-scrollbar { display: none; }
.card { background: #fff; border-radius: 12px; margin: 12px 16px 0; padding: 16px; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
.card__title { font-size: 15px; font-weight: 700; color: #1a1a1a; margin-bottom: 12px; padding-bottom: 8px; border-bottom: 1px solid #f0f0f0; }
.card { background: #fff; border-radius: 12px; margin: 12px 16px 0; box-shadow: 0 1px 4px rgba(0,0,0,0.06); overflow: hidden; }
.card__header { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px; border-bottom: 1px solid #f0f0f0; cursor: pointer; }
.card__title { font-size: 15px; font-weight: 700; color: #1a1a1a; }
.card__toggle { display: inline-flex; align-items: center; gap: 4px; color: #1677ff; font-size: 12px; font-weight: 600; }
.card__arrow { width: 14px; height: 14px; transition: transform .2s ease; }
.card__body { padding: 0 16px 16px; }
.card--collapsed .card__body { display: none; }
.card--collapsed .card__arrow { transform: rotate(-90deg); }
.card--collapsed .card__header { border-bottom: none; }
.info-item { display: flex; font-size: 13px; line-height: 1.6; padding: 5px 0; }
.info-item__label { color: #999; min-width: 72px; flex-shrink: 0; }
.info-item__value { color: #333; flex: 1; word-break: break-all; }
@@ -68,8 +75,12 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="scroll-content">
<!-- 基本信息 -->
<div class="card">
<div class="card__title">基本信息</div>
<div class="card" id="basic-info-card">
<div class="card__header" onclick="toggleCard('basic-info-card', this)">
<div class="card__title">基本信息</div>
<div class="card__toggle"><span>收起</span><svg class="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="card__body">
<div class="info-item"><span class="info-item__label">工单编号</span><span class="info-item__value">YJ5633256</span></div>
<div class="info-item"><span class="info-item__label">工单类型</span><span class="info-item__value">正常派单</span></div>
<div class="info-item"><span class="info-item__label">应急中心</span><span class="info-item__value">西安应急中心</span></div>
@@ -83,11 +94,16 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="info-item"><span class="info-item__label">专业人员</span><span class="info-item__value">刘旭</span></div>
<div class="info-item"><span class="info-item__label">工单状态</span><span class="info-item__value"><span class="tag tag-green">已完成</span></span></div>
<div class="info-item"><span class="info-item__label">完成时间</span><span class="info-item__value">2026-03-21 16:45:00</span></div>
</div>
</div>
<!-- 救助信息 -->
<div class="card">
<div class="card__title">救助信息</div>
<div class="card" id="rescue-info-card">
<div class="card__header" onclick="toggleCard('rescue-info-card', this)">
<div class="card__title">救助信息</div>
<div class="card__toggle"><span>收起</span><svg class="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="card__body">
<div class="desc-block">
<div style="display: flex; align-items: center; justify-content: space-between;">
<div class="desc-block__label">救助意见:</div>
@@ -115,11 +131,16 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<li class="summary-item"><span class="summary-item__idx">3.</span><span>已完成头颅CT检测,员工由同事留守陪护,已告知家属及部门负责人</span></li>
</ul>
</div>
</div>
</div>
<!-- 派单信息 -->
<div class="card">
<div class="card__title">派单信息</div>
<div class="card" id="dispatch-info-card">
<div class="card__header" onclick="toggleCard('dispatch-info-card', this)">
<div class="card__title">派单信息</div>
<div class="card__toggle"><span>收起</span><svg class="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="card__body">
<div class="info-item"><span class="info-item__label">派单时间</span><span class="info-item__value">2026-03-21 15:18:00</span></div>
<div class="info-item"><span class="info-item__label">驻场人员</span><span class="info-item__value">王希(138-9201-3001</span></div>
<div class="info-item"><span class="info-item__label">派单状态</span><span class="info-item__value"><span class="tag tag-green">已完成</span></span></div>
@@ -132,11 +153,16 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="desc-block__label">驻场说明:</div>
<div class="desc-block__text">已经挂号并且开了头颅CT检查单,已陪同就诊完毕,员工状态稳定</div>
</div>
</div>
</div>
<!-- 救护车支援 -->
<div class="card">
<div class="card__title">救护车支援</div>
<div class="card" id="ambulance-card">
<div class="card__header" onclick="toggleCard('ambulance-card', this)">
<div class="card__title">救护车支援</div>
<div class="card__toggle"><span>收起</span><svg class="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="card__body">
<div class="info-item"><span class="info-item__label">车牌号</span><span class="info-item__value">陕A·120-01</span></div>
<div class="info-item"><span class="info-item__label">所属医疗点</span><span class="info-item__value">长庆油田职工医疗点</span></div>
<div class="info-item"><span class="info-item__label">所属机构</span><span class="info-item__value">长庆油田职工医院</span></div>
@@ -144,6 +170,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
<div class="info-item"><span class="info-item__label">驾驶人电话</span><span class="info-item__value">138-9101-2001</span></div>
<div class="info-item"><span class="info-item__label">随行人</span><span class="info-item__value">张伟</span></div>
<div class="info-item"><span class="info-item__label">随行人电话</span><span class="info-item__value">138-9201-5001</span></div>
</div>
</div>
<div style="height:16px;"></div>
@@ -202,6 +229,16 @@ function closeEditAdvice(event) {
document.getElementById('edit-mask').classList.remove('show');
}
function toggleCard(cardId, headerEl) {
var card = document.getElementById(cardId);
if (!card) return;
card.classList.toggle('card--collapsed');
var isCollapsed = card.classList.contains('card--collapsed');
var toggle = headerEl ? headerEl.querySelector('.card__toggle span') : null;
if (toggle) toggle.textContent = isCollapsed ? '展开' : '收起';
}
function saveEditAdvice(event) {
event.stopPropagation();
var text = document.getElementById('edit-textarea').value.trim();