fix(#591): 请修复 Bug #591:【住院医生站-临床医嘱】长期医嘱点击停嘱未弹出时间录入弹窗

根因:
- Bug #请修复 Bug #591 存在的问题

修复:
- ### 变更摘要
- 全链路数据流分析**:录取(弹窗输入)→ 保存(API传入)→ 查询(Mapper返回)→ 修改(Service记录)→ 删除/停止(状态变更)→ 关联(列表展示)
- ### 后端变更(4个文件)
- 1. `AdviceBatchOpParam.java`** — 停嘱参数添加 `stopTime` 字段
- 新增 `@JsonFormat Date stopTime`,支持前端传入停嘱时间
- 2. `RequestBaseDto.java`** — 查询DTO添加 `stopUserName`、`stopTime` 字段
- 新增 `String stopUserName`(停嘱医生姓名)
- 新增 `Date stopTime`(停嘱时间)
- 3. `AdviceManageAppServiceImpl.java`** — 停嘱Service增强
- 优先使用前端传入的 `stopTime`,兜底用当前时间
- 通过 `SecurityUtils.getNickName()` 获取当前操作用户昵称,记录到 `updateBy`
- 药品和诊疗两个更新入口均已同步修改
- 4. `AdviceManageAppMapper.xml`** — 三个UNION ALL子查询添加字段
- 药品子查询:`T1.effective_dose_end AS stop_time` + `T1.update_by AS stop_user_name`
- 耗材子查询:`NULL AS stop_time` + `'' AS stop_user_name`
- 诊疗子查询:`T1.occurrence_end_time AS stop_time` + `T1.update_by AS stop_user_name`
- ### 前端变更(1个文件)
- `order/index.vue`**:
- 1. **停嘱时间弹窗** — 点击「停嘱」后弹出 `el-dialog`,内含 `el-date-picker`(datetime类型,默认当前时间),确定后才调用API
- 2. **表格列** — 在「皮试」列后面、「诊断」列前面新增两列:
- 「停嘱医生」`prop="stopUserName"`,宽度120px
- 「停嘱时间」`prop="stopTime"`,宽度170px
- 3. **`handleStopAdvice`** — 保留原有校验(未保存/未签发/已停止检查),校验通过后弹出时间选择弹窗而非直接调API
- 4. **`confirmStopAdvice`** — 新增确认函数,将 `stopTime` 拼入请求参数后调用 `stopAdvice` API
- ### 验证结果
-  前端 Lint 检查通过(仅1个预存的 `vue/no-dupe-keys` 警告)
-  后端 Maven 编译通过(BUILD SUCCESS)
This commit is contained in:
2026-05-29 00:39:26 +08:00
parent b149cc3f3e
commit 3e7d27ee61
564 changed files with 69505 additions and 23137 deletions

View File

@@ -1,13 +1,21 @@
<template>
<div class="call-number-display" ref="screenContainer">
<div
ref="screenContainer"
class="call-number-display"
>
<!-- 头部区域 -->
<div class="header">
<h1>{{ departmentName }}</h1>
<div class="header-right">
<button class="fullscreen-btn" @click="toggleFullscreen">
<button
class="fullscreen-btn"
@click="toggleFullscreen"
>
{{ isFullscreen ? '退出全屏' : '全屏' }}
</button>
<div class="time">{{ currentTime }}</div>
<div class="time">
{{ currentTime }}
</div>
</div>
</div>
@@ -24,8 +32,13 @@
<!-- 候诊信息区 -->
<div class="waiting-area">
<h2 class="section-title">候诊信息</h2>
<div class="table-container" ref="tableContainer">
<h2 class="section-title">
候诊信息
</h2>
<div
ref="tableContainer"
class="table-container"
>
<table class="waiting-table">
<thead style="position: sticky; top: 0; background: #f0f7ff; z-index: 1;">
<tr>
@@ -39,11 +52,19 @@
<template v-for="doctorName in paginatedDoctors">
<template v-if="groupedPatients[doctorName]">
<!-- 医生分组标题 -->
<tr class="doctor-header" :key="`doctor-${doctorName}`">
<td colspan="4">{{ doctorName }} 医生 (诊室: {{ getDoctorRoom(doctorName) }})</td>
<tr
:key="`doctor-${doctorName}`"
class="doctor-header"
>
<td colspan="4">
{{ doctorName }} 医生 (诊室: {{ getDoctorRoom(doctorName) }})
</td>
</tr>
<!-- 患者列表 -->
<tr v-for="(patient, index) in groupedPatients[doctorName]" :key="`${doctorName}-${patient.id}`">
<tr
v-for="(patient, index) in groupedPatients[doctorName]"
:key="`${doctorName}-${patient.id}`"
>
<td>{{ index + 1 }}</td>
<td>{{ patient.name }}</td>
<td>{{ getDoctorRoom(doctorName) }}</td>
@@ -61,15 +82,19 @@
<div class="pagination-controls">
<button
id="prevPage"
@click="previousPage"
:disabled="currentPage === 1 || loading"
>上一页</button>
:disabled="currentPage === 1 || loading"
@click="previousPage"
>
上一页
</button>
<span id="pageInfo">{{ currentPage }}/{{ totalPages }}</span>
<button
id="nextPage"
@click="nextPage"
:disabled="currentPage === totalPages || loading"
>下一页</button>
:disabled="currentPage === totalPages || loading"
@click="nextPage"
>
下一页
</button>
</div>
</div>

View File

@@ -1,48 +1,98 @@
<template>
<div class="call-voice-settings">
<!-- 标题区域 -->
<div class="title-section">
<h1>叫号语音设置</h1>
</div>
<div class="call-voice-settings">
<!-- 标题区域 -->
<div class="title-section">
<h1>叫号语音设置</h1>
</div>
<!-- 语音设置模块 -->
<div class="card">
<div class="card-header">
<h2 class="card-title">科室叫号语音设置</h2>
<div class="btn-group">
<button class="btn btn-primary" @click="saveSettings" :disabled="loading">
<span v-if="loading">保存中...</span>
<span v-else>保存设置</span>
</button>
<button class="btn btn-secondary" @click="cancelSettings" :disabled="loading">取消</button>
</div>
</div>
<!-- 语音设置模块 -->
<div class="card">
<div class="card-header">
<h2 class="card-title">
科室叫号语音设置
</h2>
<div class="btn-group">
<button
class="btn btn-primary"
:disabled="loading"
@click="saveSettings"
>
<span v-if="loading">保存中...</span>
<span v-else>保存设置</span>
</button>
<button
class="btn btn-secondary"
:disabled="loading"
@click="cancelSettings"
>
取消
</button>
</div>
</div>
<div class="settings-section">
<!-- 播放次数设置 -->
<div class="setting-item">
<div class="setting-title">
<div class="icon">🔢</div>
<div class="icon">
🔢
</div>
<div>播放次数</div>
</div>
<div class="setting-content">
<div class="form-group">
<label class="form-label">播放次数</label>
<select v-model="settings.playCount" class="form-control" :disabled="loading">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<select
v-model="settings.playCount"
class="form-control"
:disabled="loading"
>
<option value="1">
1
</option>
<option value="2">
2
</option>
<option value="3">
3
</option>
<option value="4">
4
</option>
<option value="5">
5
</option>
</select>
</div>
<div class="play-controls">
<div class="play-btn" @click="testPlay" :disabled="loading">
<svg v-if="!isPlaying" width="18" height="18" viewBox="0 0 24 24" fill="none">
<path d="M8 5V19L19 12L8 5Z" fill="white"/>
<div
class="play-btn"
:disabled="loading"
@click="testPlay"
>
<svg
v-if="!isPlaying"
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M8 5V19L19 12L8 5Z"
fill="white"
/>
</svg>
<svg v-else width="18" height="18" viewBox="0 0 24 24" fill="none">
<path d="M14 19H18V5H14V19ZM6 19H10V5H6V19Z" fill="white"/>
<svg
v-else
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M14 19H18V5H14V19ZM6 19H10V5H6V19Z"
fill="white"
/>
</svg>
</div>
<span v-if="loading">加载中...</span>
@@ -55,36 +105,48 @@
<!-- 语音内容设置 -->
<div class="setting-item">
<div class="setting-title">
<div class="icon">🗣</div>
<div class="icon">
🗣
</div>
<div>语音内容</div>
</div>
<div class="setting-content">
<div class="form-group">
<label class="form-label">叫号前缀</label>
<input
v-model="settings.prefix"
type="text"
class="form-control"
class="form-control"
placeholder="例如:请"
v-model="settings.prefix"
:disabled="loading"
>
</div>
<div class="form-group">
<label class="form-label">叫号后缀</label>
<input
v-model="settings.suffix"
type="text"
class="form-control"
class="form-control"
placeholder="例如:到诊室就诊"
v-model="settings.suffix"
:disabled="loading"
>
</div>
<div class="form-group">
<label class="form-label">语音速度</label>
<select v-model="settings.voiceSpeed" class="form-control" :disabled="loading">
<option value="slow">较慢</option>
<option value="normal">正常</option>
<option value="fast">较快</option>
<select
v-model="settings.voiceSpeed"
class="form-control"
:disabled="loading"
>
<option value="slow">
较慢
</option>
<option value="normal">
正常
</option>
<option value="fast">
较快
</option>
</select>
</div>
</div>
@@ -93,20 +155,22 @@
<!-- 其他设置 -->
<div class="setting-item">
<div class="setting-title">
<div class="icon"></div>
<div class="icon">
</div>
<div>其他设置</div>
</div>
<div class="setting-content">
<div class="form-group">
<label class="form-label">音量设置</label>
<input
v-model="settings.volume"
type="range"
min="0"
max="100"
v-model="settings.volume"
max="100"
class="form-control"
@input="updateVolume"
:disabled="loading"
@input="updateVolume"
>
<div style="text-align: center; margin-top: 5px; color: var(--text-light);">
{{ settings.volume }}%
@@ -114,19 +178,37 @@
</div>
<div class="form-group">
<label class="form-label">播放间隔</label>
<select v-model="settings.playInterval" class="form-control" :disabled="loading">
<option value="3">3</option>
<option value="5">5</option>
<option value="10">10</option>
<option value="15">15</option>
<option value="20">20</option>
<select
v-model="settings.playInterval"
class="form-control"
:disabled="loading"
>
<option value="3">
3
</option>
<option value="5">
5
</option>
<option value="10">
10
</option>
<option value="15">
15
</option>
<option value="20">
20
</option>
</select>
</div>
<div class="form-group">
<label class="switch-label">
<div class="switch">
<input type="checkbox" v-model="settings.repeatPlay" :disabled="loading">
<span class="slider"></span>
<input
v-model="settings.repeatPlay"
type="checkbox"
:disabled="loading"
>
<span class="slider" />
</div>
<span>开启重复播放</span>
</label>

View File

@@ -119,8 +119,19 @@
size="small"
style="width: 150px"
/>
<el-button type="primary" size="small" @click="handleHistoryQuery">查询</el-button>
<el-button size="small" @click="handleTodayQuery">今天</el-button>
<el-button
type="primary"
size="small"
@click="handleHistoryQuery"
>
查询
</el-button>
<el-button
size="small"
@click="handleTodayQuery"
>
今天
</el-button>
</div>
</div>
<div class="table-container">