挂号补单功能的完善
This commit is contained in:
@@ -547,47 +547,21 @@ function formatDateTime(date) {
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
// 计算流水号:格式为 YYYYMMDD-XXX,其中 XXX 为后端按"科室+医生+当日"自增的 displayOrder
|
||||
// 确保同一科室同一医生同一天内是 001、002、003... 递增
|
||||
// 计算流水号:直接使用挂号记录表的主键ID(encounterId)
|
||||
function calculateSerialNo(row) {
|
||||
if (!row) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
// 获取挂号日期(YYYYMMDD格式)
|
||||
let dateStr = '';
|
||||
if (row.registerTime) {
|
||||
const date = new Date(row.registerTime);
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
dateStr = `${year}${month}${day}`;
|
||||
// 直接使用主键ID作为流水号
|
||||
if (row.encounterId != null && row.encounterId !== undefined) {
|
||||
return String(row.encounterId);
|
||||
} else if (row.id != null && row.id !== undefined) {
|
||||
// 兼容其他可能的ID字段名
|
||||
return String(row.id);
|
||||
} else {
|
||||
// 如果没有挂号时间,使用当前日期
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = String(now.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(now.getDate()).padStart(2, '0');
|
||||
dateStr = `${year}${month}${day}`;
|
||||
return '-';
|
||||
}
|
||||
|
||||
// 获取序号部分(3位数字,001-999)
|
||||
// 直接使用后端返回的 displayOrder,自增逻辑在后端按"科室+医生+当日"保证
|
||||
let serialNum = 1;
|
||||
if (row.displayOrder != null && row.displayOrder !== undefined) {
|
||||
const num = Number(row.displayOrder) || 0;
|
||||
serialNum = num > 0 ? num : 1;
|
||||
} else if (row.serialNo) {
|
||||
// 兼容旧数据:如果有已有的 serialNo 字段
|
||||
const num = Number(row.serialNo) || 0;
|
||||
serialNum = num > 0 ? num : 1;
|
||||
} else {
|
||||
// 兜底:没有任何序号信息时,给 1
|
||||
serialNum = 1;
|
||||
}
|
||||
|
||||
// 格式:YYYYMMDD-XXX(例如:20250113-001)
|
||||
return `${dateStr}-${String(serialNum).padStart(3, '0')}`;
|
||||
}
|
||||
|
||||
// 提交补打挂号
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
<template>
|
||||
<div class="cardiology-queue">
|
||||
<div class="app-container">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="title">心内科分诊排队管理</span>
|
||||
<div class="header-actions">
|
||||
<el-button type="primary" @click="refreshData" :loading="loading">
|
||||
<el-icon><Refresh /></el-icon>
|
||||
刷新
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 当前呼叫区 -->
|
||||
<div class="current-call-section">
|
||||
<div class="call-box">
|
||||
<div class="call-text">
|
||||
请 <span class="highlight">{{ currentCall?.number || '-' }}</span> 号
|
||||
<span class="highlight">{{ currentCall?.name || '-' }}</span>
|
||||
到 <span class="highlight">{{ currentCall?.room || '-' }}</span> 诊室就诊
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 候诊队列 -->
|
||||
<div class="queue-section">
|
||||
<h3 class="section-title">候诊队列</h3>
|
||||
<el-table
|
||||
:data="queueList"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
border
|
||||
style="width: 100%"
|
||||
:default-sort="{ prop: 'displayOrder', order: 'ascending' }"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="patientName" label="患者姓名" width="120" align="center">
|
||||
<template #default="scope">
|
||||
{{ formatPatientName(scope.row.patientName) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="practitionerName" label="医生" width="120" align="center" />
|
||||
<el-table-column prop="room" label="诊室" width="100" align="center" />
|
||||
<el-table-column prop="displayOrder" label="流水号" width="120" align="center">
|
||||
<template #default="scope">
|
||||
{{ formatSerialNo(scope.row) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getStatusType(scope.row.status)">
|
||||
{{ getStatusText(scope.row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="registerTime" label="挂号时间" width="180" align="center">
|
||||
<template #default="scope">
|
||||
{{ formatTime(scope.row.registerTime) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleCall(scope.row)"
|
||||
:disabled="scope.row.status === 'CALLED'"
|
||||
>
|
||||
叫号
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
v-model:current-page="queryParams.pageNo"
|
||||
v-model:page-size="queryParams.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Refresh } from '@element-plus/icons-vue'
|
||||
import { parseTime } from '@/utils/his'
|
||||
import { getOutpatientRegistrationCurrent } from '@/views/charge/outpatientregistration/components/outpatientregistration'
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false)
|
||||
const queueList = ref([])
|
||||
const total = ref(0)
|
||||
const currentCall = ref({
|
||||
number: '-',
|
||||
name: '-',
|
||||
room: '-'
|
||||
})
|
||||
|
||||
// 查询参数
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 20,
|
||||
searchKey: '',
|
||||
organizationId: null // 心内科科室ID,可以从路由参数或配置中获取
|
||||
})
|
||||
|
||||
// 计算流水号:直接使用挂号记录表的主键ID(encounterId)
|
||||
function formatSerialNo(row) {
|
||||
if (!row) return '-'
|
||||
|
||||
// 直接使用主键ID作为流水号
|
||||
if (row.encounterId != null && row.encounterId !== undefined) {
|
||||
return String(row.encounterId)
|
||||
} else if (row.id != null && row.id !== undefined) {
|
||||
// 兼容其他可能的ID字段名
|
||||
return String(row.id)
|
||||
} else {
|
||||
return '-'
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化患者姓名(脱敏)
|
||||
function formatPatientName(name) {
|
||||
if (!name || typeof name !== 'string') return '-'
|
||||
if (name.length <= 2) return name.charAt(0) + '*'
|
||||
return name.charAt(0) + '*' + name.slice(-1)
|
||||
}
|
||||
|
||||
// 格式化时间
|
||||
function formatTime(time) {
|
||||
if (!time) return '-'
|
||||
return parseTime(time, '{y}-{m}-{d} {h}:{i}:{s}')
|
||||
}
|
||||
|
||||
// 获取状态类型
|
||||
function getStatusType(status) {
|
||||
const statusMap = {
|
||||
'WAITING': 'info',
|
||||
'CALLED': 'warning',
|
||||
'IN_PROGRESS': 'success',
|
||||
'COMPLETED': ''
|
||||
}
|
||||
return statusMap[status] || ''
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
function getStatusText(status) {
|
||||
const statusMap = {
|
||||
'WAITING': '等待',
|
||||
'CALLED': '已叫号',
|
||||
'IN_PROGRESS': '就诊中',
|
||||
'COMPLETED': '已完成'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
}
|
||||
|
||||
// 获取队列数据
|
||||
async function fetchQueueData() {
|
||||
try {
|
||||
loading.value = true
|
||||
|
||||
// 调用API获取当日就诊数据
|
||||
const response = await getOutpatientRegistrationCurrent({
|
||||
searchKey: queryParams.searchKey,
|
||||
pageNo: queryParams.pageNo,
|
||||
pageSize: queryParams.pageSize
|
||||
})
|
||||
|
||||
if (response && response.code === 200) {
|
||||
// 获取记录数据
|
||||
const records = response.data?.records || response.data || []
|
||||
|
||||
// 过滤心内科的数据(如果有organizationId)
|
||||
let filteredData = records
|
||||
if (queryParams.organizationId) {
|
||||
filteredData = records.filter(item => item.organizationId === queryParams.organizationId)
|
||||
}
|
||||
|
||||
// 转换为队列数据格式
|
||||
queueList.value = filteredData.map(item => ({
|
||||
id: item.encounterId,
|
||||
patientName: item.patientName,
|
||||
practitionerName: item.practitionerName || '-',
|
||||
organizationName: item.organizationName,
|
||||
room: item.organizationName || '-', // 使用科室名称作为诊室
|
||||
displayOrder: item.displayOrder,
|
||||
registerTime: item.registerTime,
|
||||
status: 'WAITING' // 默认状态,实际应该从后端获取
|
||||
}))
|
||||
|
||||
total.value = response.data?.total || filteredData.length || 0
|
||||
} else {
|
||||
queueList.value = []
|
||||
total.value = 0
|
||||
if (response && response.msg) {
|
||||
ElMessage.warning('获取数据失败: ' + response.msg)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取队列数据失败:', error)
|
||||
ElMessage.error('获取队列数据失败: ' + (error.message || '未知错误'))
|
||||
queueList.value = []
|
||||
total.value = 0
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新数据
|
||||
function refreshData() {
|
||||
queryParams.pageNo = 1
|
||||
fetchQueueData()
|
||||
}
|
||||
|
||||
// 叫号
|
||||
async function handleCall(row) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确认叫号:${formatPatientName(row.patientName)}(${formatSerialNo(row)})?`,
|
||||
'确认叫号',
|
||||
{
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}
|
||||
)
|
||||
|
||||
// TODO: 调用叫号API
|
||||
// await callPatient(row.id)
|
||||
|
||||
// 更新当前呼叫信息
|
||||
currentCall.value = {
|
||||
number: row.displayOrder || '-',
|
||||
name: formatPatientName(row.patientName),
|
||||
room: row.room
|
||||
}
|
||||
|
||||
// 更新状态
|
||||
row.status = 'CALLED'
|
||||
|
||||
ElMessage.success('叫号成功')
|
||||
|
||||
// 刷新数据
|
||||
await fetchQueueData()
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
console.error('叫号失败:', error)
|
||||
ElMessage.error('叫号失败: ' + (error.message || '未知错误'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页大小改变
|
||||
function handleSizeChange(val) {
|
||||
queryParams.pageSize = val
|
||||
queryParams.pageNo = 1
|
||||
fetchQueueData()
|
||||
}
|
||||
|
||||
// 页码改变
|
||||
function handlePageChange(val) {
|
||||
queryParams.pageNo = val
|
||||
fetchQueueData()
|
||||
}
|
||||
|
||||
// 组件挂载时获取数据
|
||||
onMounted(() => {
|
||||
fetchQueueData()
|
||||
|
||||
// 定时刷新数据(每30秒)
|
||||
const refreshInterval = setInterval(() => {
|
||||
fetchQueueData()
|
||||
}, 30000)
|
||||
|
||||
// 组件卸载时清理定时器
|
||||
return () => {
|
||||
clearInterval(refreshInterval)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cardiology-queue {
|
||||
.app-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.current-call-section {
|
||||
margin: 20px 0;
|
||||
text-align: center;
|
||||
|
||||
.call-box {
|
||||
display: inline-block;
|
||||
padding: 20px 40px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.3);
|
||||
animation: pulse 2s infinite;
|
||||
|
||||
.call-text {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
letter-spacing: 2px;
|
||||
|
||||
.highlight {
|
||||
color: #ffd700;
|
||||
font-size: 28px;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.queue-section {
|
||||
margin-top: 20px;
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
padding-left: 10px;
|
||||
border-left: 4px solid #667eea;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
70% {
|
||||
box-shadow: 0 0 0 15px rgba(102, 126, 234, 0);
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 rgba(102, 126, 234, 0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user