This commit is contained in:
Your Name
2026-03-05 11:19:36 +08:00
parent ab77f5488d
commit 9a1b67ca18
17 changed files with 1736 additions and 89 deletions
@@ -0,0 +1,255 @@
<template>
<el-drawer
v-model="visible"
title="创建处方单"
size="800px"
:close-on-click-modal="false"
@close="handleClose"
>
<el-form
ref="formRef"
:model="formData"
label-width="100px"
class="prescription-form"
>
<!-- 患者基本信息 -->
<div class="info-section">
<div class="section-title">患者信息</div>
<el-form-item label="姓名">
<span>{{ formData.patient_name }}</span>
</el-form-item>
<el-form-item label="性别">
<span>{{ formData.gender }}</span>
</el-form-item>
<el-form-item label="年龄">
<span>{{ formData.age }}</span>
</el-form-item>
<el-form-item label="诊号">
<span>{{ formData.diagnosis_no }}</span>
</el-form-item>
<el-form-item label="日期">
<span>{{ formData.date }}</span>
</el-form-item>
<el-form-item label="科室">
<span>{{ formData.department }}</span>
</el-form-item>
<el-form-item label="费别">
<span>{{ formData.fee_type }}</span>
</el-form-item>
<el-form-item label="手机号">
<span>{{ formData.phone }}</span>
</el-form-item>
</div>
<!-- 诊断信息 -->
<div class="info-section">
<div class="section-title">诊断信息</div>
<el-form-item label="诊断" prop="diagnosis">
<el-input
v-model="formData.diagnosis"
type="textarea"
:rows="3"
placeholder="请输入诊断信息"
/>
</el-form-item>
</div>
<!-- 药品信息 -->
<div class="info-section">
<div class="section-title">
药品信息
<el-button type="primary" size="small" @click="handleAddMedicine">
添加药品
</el-button>
</div>
<div
v-for="(medicine, index) in formData.medicines"
:key="index"
class="medicine-item"
>
<el-form-item :label="`药品${index + 1}`">
<el-input
v-model="medicine.name"
placeholder="药品名称"
class="mb-2"
/>
<el-input
v-model="medicine.usage"
type="textarea"
:rows="2"
placeholder="用法用量"
/>
<el-button
type="danger"
size="small"
link
@click="handleRemoveMedicine(index)"
class="mt-2"
>
删除
</el-button>
</el-form-item>
</div>
</div>
</el-form>
<template #footer>
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
</template>
</el-drawer>
</template>
<script setup lang="ts">
import feedback from '@/utils/feedback'
interface Medicine {
name: string
usage: string
}
interface PrescriptionForm {
appointment_id: number
patient_name: string
gender: string
age: string
diagnosis_no: string
date: string
department: string
fee_type: string
phone: string
diagnosis: string
medicines: Medicine[]
}
const emit = defineEmits(['success'])
const visible = ref(false)
const formRef = ref()
const formData = reactive<PrescriptionForm>({
appointment_id: 0,
patient_name: '',
gender: '',
age: '',
diagnosis_no: '',
date: '',
department: '',
fee_type: '',
phone: '',
diagnosis: '',
medicines: []
})
// 打开抽屉
const open = (data: any) => {
formData.appointment_id = data.id
formData.patient_name = data.patient_name || ''
formData.gender = data.patient_gender || ''
formData.age = data.patient_age || ''
formData.diagnosis_no = data.id.toString()
formData.date = data.appointment_date || ''
formData.department = '中医科'
formData.fee_type = data.appointment_type_desc || ''
formData.phone = data.patient_phone || ''
formData.diagnosis = ''
formData.medicines = []
visible.value = true
}
// 关闭抽屉
const handleClose = () => {
visible.value = false
formRef.value?.resetFields()
}
// 添加药品
const handleAddMedicine = () => {
formData.medicines.push({
name: '',
usage: ''
})
}
// 删除药品
const handleRemoveMedicine = (index: number) => {
formData.medicines.splice(index, 1)
}
// 保存处方单
const handleSave = async () => {
if (!formData.diagnosis) {
feedback.msgWarning('请输入诊断信息')
return
}
if (formData.medicines.length === 0) {
feedback.msgWarning('请至少添加一个药品')
return
}
// 验证药品信息
for (const medicine of formData.medicines) {
if (!medicine.name || !medicine.usage) {
feedback.msgWarning('请完善药品信息')
return
}
}
try {
// TODO: 调用保存处方单的API
// await savePrescription(formData)
feedback.msgSuccess('处方单创建成功')
handleClose()
emit('success')
} catch (error) {
feedback.msgError('保存失败')
}
}
defineExpose({
open
})
</script>
<style scoped lang="scss">
.prescription-form {
.info-section {
margin-bottom: 24px;
padding: 16px;
background: #f5f7fa;
border-radius: 4px;
.section-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 16px;
color: #303133;
display: flex;
justify-content: space-between;
align-items: center;
}
.el-form-item {
margin-bottom: 12px;
span {
color: #606266;
}
}
}
.medicine-item {
margin-bottom: 16px;
padding: 12px;
background: #fff;
border: 1px solid #dcdfe6;
border-radius: 4px;
.el-form-item {
margin-bottom: 0;
}
}
}
</style>
+232 -16
View File
@@ -8,16 +8,16 @@
v-model="formData.patient_name"
placeholder="请输入患者姓名"
clearable
@keyup.enter="resetPage"
@keyup.enter="handleSearch"
/>
</el-form-item>
<el-form-item class="w-[280px]" label="医生姓名">
<el-form-item class="w-[280px]" label="医生姓名" v-if="isAdmin">
<el-input
v-model="formData.doctor_name"
placeholder="请输入医生姓名"
clearable
@keyup.enter="resetPage"
@keyup.enter="handleSearch"
/>
</el-form-item>
@@ -26,6 +26,7 @@
<el-option label="已预约" :value="1" />
<el-option label="已取消" :value="2" />
<el-option label="已完成" :value="3" />
<el-option label="已过号" :value="4" />
</el-select>
</el-form-item>
@@ -37,14 +38,43 @@
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="resetParams">重置</el-button>
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 数据表格 -->
<el-card class="!border-none mt-4" shadow="never">
<!-- tab选项卡 -->
<el-tabs v-model="activeTab" @tab-change="handleTabChange" class="mb-4">
<el-tab-pane label="全部" name="all" />
<el-tab-pane name="1">
<template #label>
<span>已预约</span>
<el-badge v-if="statusCount[1]" :value="statusCount[1]" class="ml-2" type="success" />
</template>
</el-tab-pane>
<el-tab-pane name="4">
<template #label>
<span>已过号</span>
<el-badge v-if="statusCount[4]" :value="statusCount[4]" class="ml-2" type="danger" />
</template>
</el-tab-pane>
<el-tab-pane name="2">
<template #label>
<span>已取消</span>
<el-badge v-if="statusCount[2]" :value="statusCount[2]" class="ml-2" type="info" />
</template>
</el-tab-pane>
<el-tab-pane name="3">
<template #label>
<span>已完成</span>
<el-badge v-if="statusCount[3]" :value="statusCount[3]" class="ml-2" type="primary" />
</template>
</el-tab-pane>
</el-tabs>
<el-table
v-loading="pager.loading"
:data="pager.lists"
@@ -87,10 +117,10 @@
</template>
</el-table-column>
<el-table-column label="状态" width="80">
<el-table-column label="状态" width="90">
<template #default="{ row }">
<el-tag
:type="row.status === 1 ? 'success' : row.status === 2 ? 'info' : 'primary'"
:type="row.status === 1 ? 'success' : row.status === 2 ? 'info' : row.status === 3 ? 'primary' : 'danger'"
size="small"
>
{{ row.status_desc }}
@@ -106,7 +136,7 @@
</template>
</el-table-column>
<el-table-column label="操作" width="180" fixed="right">
<el-table-column label="操作" width="360" fixed="right">
<template #default="{ row }">
<el-button
v-perms="['doctor.appointment/detail']"
@@ -116,6 +146,30 @@
>
详情
</el-button>
<el-button
v-perms="['tcm.diagnosis/edit']"
type="primary"
link
@click="handleEditPatient(row)"
>
编辑患者
</el-button>
<el-button
v-perms="['tcm.diagnosis/video-call']"
type="success"
link
@click="handleVideoCall(row)"
>
1V1通话
</el-button>
<el-button
v-perms="['tcm.diagnosis/video-group']"
type="success"
link
@click="handleGroupVideoCall(row)"
>
群通话
</el-button>
<el-button
v-if="row.status === 1"
v-perms="['doctor.appointment/cancel']"
@@ -123,7 +177,7 @@
link
@click="handleCancel(row)"
>
取消
取消挂号
</el-button>
<el-button
v-if="row.status === 1"
@@ -132,8 +186,17 @@
link
@click="handleComplete(row)"
>
完成
完成视频面诊
</el-button>
<!-- <el-button
v-if="row.status === 1"
v-perms="['doctor.appointment/prescription']"
type="success"
link
@click="handleCreatePrescription(row)"
>
创建处方单
</el-button> -->
</template>
</el-table-column>
</el-table>
@@ -155,7 +218,7 @@
</el-descriptions-item>
<el-descriptions-item label="状态">
<el-tag
:type="detailData.status === 1 ? 'success' : detailData.status === 2 ? 'info' : 'primary'"
:type="detailData.status === 1 ? 'success' : detailData.status === 2 ? 'info' : detailData.status === 3 ? 'primary' : 'danger'"
size="small"
>
{{ detailData.status_desc }}
@@ -190,6 +253,15 @@
</el-descriptions-item>
</el-descriptions>
</el-dialog>
<!-- 编辑患者弹窗 -->
<edit-popup ref="editRef" @success="getLists" />
<!-- 视频通话组件 -->
<video-call ref="videoCallRef" />
<!-- 处方单抽屉 -->
<prescription-drawer ref="prescriptionDrawerRef" @success="loadData" />
</div>
</template>
@@ -197,22 +269,101 @@
import { usePaging } from '@/hooks/usePaging'
import { appointmentLists, cancelAppointment, completeAppointment, appointmentDetail } from '@/api/doctor'
import feedback from '@/utils/feedback'
import EditPopup from '../diagnosis/edit.vue'
import VideoCall from '@/components/video-call/index.vue'
import PrescriptionDrawer from './components/prescription-drawer.vue'
import useUserStore from '@/stores/modules/user'
const userStore = useUserStore()
const userInfo = computed(() => userStore.userInfo)
// 判断是否为管理员(非医生、非医助)
const isAdmin = computed(() => {
const roleId = userInfo.value.role_id
// 如果role_id是数组,检查是否包含医生(1)或医助(2)
if (Array.isArray(roleId)) {
return !roleId.includes(1) && !roleId.includes(2)
}
// 如果role_id是单个值,检查是否不是医生或医助
return roleId !== 1 && roleId !== 2
})
const formData = reactive({
patient_name: '',
doctor_name: '',
status: '',
status: '' as string | number,
start_date: '',
end_date: ''
})
const activeTab = ref('all')
const statusCount = ref<Record<number, number>>({
1: 0,
2: 0,
3: 0,
4: 0
})
const { pager, getLists, resetPage, resetParams } = usePaging({
fetchFun: appointmentLists,
params: formData
})
// 获取各状态数量
const getStatusCount = async () => {
try {
// 获取各状态的数量
const promises = [1, 2, 3, 4].map(async (status) => {
const res = await appointmentLists({
...formData,
status,
page_no: 1,
page_size: 1
})
return { status, count: res.count || 0 }
})
const results = await Promise.all(promises)
results.forEach(({ status, count }) => {
statusCount.value[status] = count
})
} catch (error) {
console.error('获取状态数量失败:', error)
}
}
// 切换选项卡
const handleTabChange = (tabName: string | number) => {
if (tabName === 'all') {
formData.status = ''
} else {
formData.status = Number(tabName)
}
resetPage()
}
// 重写getLists,同时更新状态数量
const loadData = async () => {
await getLists()
await getStatusCount()
}
// 搜索
const handleSearch = () => {
resetPage()
}
// 重置
const handleReset = () => {
activeTab.value = 'all'
resetParams()
}
const detailVisible = ref(false)
const detailData = ref<any>(null)
const editRef = ref()
const videoCallRef = ref()
const prescriptionDrawerRef = ref()
// 查看详情
const handleDetail = async (row: any) => {
@@ -231,7 +382,7 @@ const handleCancel = async (row: any) => {
await feedback.confirm('确定要取消该挂号吗?')
await cancelAppointment({ id: row.id })
feedback.msgSuccess('取消成功')
getLists()
loadData()
} catch (error) {
// 用户取消操作
}
@@ -243,13 +394,78 @@ const handleComplete = async (row: any) => {
await feedback.confirm('确认患者已就诊完成?')
await completeAppointment({ id: row.id })
feedback.msgSuccess('操作成功')
getLists()
loadData()
} catch (error) {
// 用户取消操作
}
}
getLists()
// 编辑患者资料
const handleEditPatient = (row: any) => {
console.log()
if (!row.patient_id) {
feedback.msgWarning('该预约没有关联诊单信息')
return
}
editRef.value?.open('edit', row.patient_id)
}
// 1v1视频通话
const handleVideoCall = (row: any) => {
if (!row.patient_id) {
feedback.msgWarning('患者信息不完整')
return
}
videoCallRef.value?.open({
diagnosisId: row.diagnosis_id || row.id,
patientId: row.patient_id,
patientName: row.patient_name,
userId: `patient_${row.patient_id}`,
isGroup: false
})
}
// 群组视频通话
const handleGroupVideoCall = (row: any) => {
if (!row.patient_id) {
feedback.msgWarning('患者信息不完整')
return
}
if (!row.doctor_id) {
feedback.msgWarning('该预约没有医生信息,无法发起群组通话')
return
}
// 群组通话参与者:患者和医生
const userIds = [
`patient_${row.patient_id}`,
`doctor_${row.doctor_id}`
]
videoCallRef.value?.open({
diagnosisId: row.diagnosis_id || row.id,
patientId: row.patient_id,
patientName: row.patient_name,
doctorId: row.doctor_id,
userIds: userIds,
isGroup: true
})
}
// 创建处方单
const handleCreatePrescription = async (row: any) => {
try {
// 获取详细信息
const detail = await appointmentDetail({ id: row.id })
prescriptionDrawerRef.value?.open(detail)
} catch (error) {
feedback.msgError('获取患者信息失败')
}
}
loadData()
</script>
<style scoped lang="scss">