新增功能

This commit is contained in:
Your Name
2026-03-04 15:32:30 +08:00
parent a07e844c47
commit ab77f5488d
2266 changed files with 177942 additions and 3444 deletions
+442
View File
@@ -0,0 +1,442 @@
<template>
<div class="tcm-diagnosis">
<el-card class="!border-none" shadow="never">
<el-form class="ls-form" :model="formData" inline>
<el-form-item class="w-[280px]" label="患者姓名">
<el-input
placeholder="请输入患者姓名"
v-model="formData.patient_name"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item class="w-[280px]" label="诊断类型">
<el-select v-model="formData.diagnosis_type" placeholder="请选择" clearable>
<el-option
v-for="item in diagnosisTypeOptions"
:key="item.value"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item class="w-[280px]" label="证型">
<el-select v-model="formData.syndrome_type" placeholder="请选择" clearable>
<el-option
v-for="item in syndromeTypeOptions"
:key="item.value"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item class="w-[280px]" label="医助">
<el-select v-model="formData.assistant_id" placeholder="请选择" clearable filterable>
<el-option
v-for="item in assistantOptions"
:key="item.id"
:label="item.name"
:value="Number(item.id)"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="resetParams">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="!border-none mt-4" shadow="never">
<div class="mb-4 flex justify-between items-center">
<div>
<el-button type="primary" @click="handleAdd" v-perms="['tcm.diagnosis/add']">新增患者</el-button>
<el-button
v-perms="['tcm.diagnosis/assign']"
type="success"
@click="handleBatchAssign"
:disabled="selectedIds.length === 0"
>
批量指派医助
</el-button>
</div>
<div v-if="selectedIds.length > 0" class="text-gray-500">
已选择 {{ selectedIds.length }} 条记录
</div>
</div>
<el-table
:data="pager.lists"
size="large"
v-loading="pager.loading"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column label="ID" prop="id" width="80" />
<el-table-column label="患者姓名" prop="patient_name" min-width="100" />
<el-table-column label="性别" prop="gender_desc" width="80" />
<el-table-column label="年龄" prop="age" width="80" />
<el-table-column label="诊断日期" prop="diagnosis_date_text" min-width="120" />
<el-table-column label="诊断类型" prop="diagnosis_type" min-width="100">
<template #default="{ row }">
<span>{{ getDictLabel(diagnosisTypeOptions, row.diagnosis_type) }}</span>
</template>
</el-table-column>
<el-table-column label="证型" prop="syndrome_type" min-width="100">
<template #default="{ row }">
<span>{{ getDictLabel(syndromeTypeOptions, row.syndrome_type) }}</span>
</template>
</el-table-column>
<el-table-column label="指派医助" prop="assistant_name" min-width="100">
<template #default="{ row }">
<span>{{ getAssistantName(row.assistant_id || row.assistant) }}</span>
</template>
</el-table-column>
<el-table-column label="状态" width="80">
<template #default="{ row }">
<el-tag v-if="row.status == 1" type="success">启用</el-tag>
<el-tag v-else type="danger">禁用</el-tag>
</template>
</el-table-column>
<el-table-column label="创建时间" prop="create_time" min-width="160" />
<el-table-column label="操作" width="240" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="handleDetail(row.id)">
查看
</el-button>
<el-button
v-perms="['tcm.diagnosis/assign']"
type="success"
link
@click="handleSingleAssign(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-perms="['tcm.diagnosis/guahao']"
type="success"
link
@click="handleAppointment(row)"
>
挂号
</el-button>
<el-button type="primary" link @click="handleEdit(row.id)" v-perms="['tcm.diagnosis/edit']">
编辑
</el-button>
<el-button type="danger" link @click="handleDelete(row.id)" v-perms="['tcm.diagnosis/delete']">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<div class="flex mt-4 justify-end">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<edit-popup ref="editRef" @success="getLists" />
<detail-popup ref="detailRef" />
<video-call ref="videoCallRef" />
<appointment-popup ref="appointmentRef" @success="getLists" />
<!-- 批量指派医助弹窗 -->
<el-dialog
v-model="assignDialogVisible"
:title="assignMode === 'batch' ? '批量指派医助' : '指派医助'"
width="500px"
>
<el-form :model="assignForm" label-width="100px">
<el-form-item label="选择医助" required>
<el-select
v-model="assignForm.assistant_id"
placeholder="请选择医助"
class="w-full"
filterable
clearable
value-key="id"
>
<el-option
v-for="item in assistantOptions"
:key="item.id"
:label="item.name"
:value="Number(item.id)"
/>
</el-select>
</el-form-item>
<el-form-item v-if="assignMode === 'batch'" label="已选择">
<div class="text-gray-500">{{ selectedIds.length }} 条诊单记录</div>
</el-form-item>
<el-form-item v-else label="诊单信息">
<div class="text-gray-500">
<div>患者{{ currentRow?.patient_name }}</div>
<div>诊断日期{{ currentRow?.diagnosis_date_text }}</div>
</div>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="assignDialogVisible = false">取消</el-button>
<el-button
type="primary"
@click="handleConfirmAssign"
:loading="assignLoading"
>
确定指派
</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="tcmDiagnosis">
import { tcmDiagnosisLists, tcmDiagnosisDelete, tcmDiagnosisAssign, getAssistants } from '@/api/tcm'
import { usePaging } from '@/hooks/usePaging'
import { getDictData } from '@/api/app'
import feedback from '@/utils/feedback'
import EditPopup from './edit.vue'
import DetailPopup from './detail.vue'
import VideoCall from '@/components/video-call/index.vue'
import AppointmentPopup from './appointment.vue'
const formData = ref({
patient_name: '',
diagnosis_type: '',
syndrome_type: '',
assistant_id: '',
start_time: '',
end_time: ''
})
// 获取字典选项
const diagnosisTypeOptions = ref<any[]>([])
const syndromeTypeOptions = ref<any[]>([])
const assistantOptions = ref<any[]>([])
const getDictOptions = async () => {
try {
const [diagnosisType, syndromeType, assistants] = await Promise.all([
getDictData({ type: 'diagnosis_type' }),
getDictData({ type: 'syndrome_type' }),
getAssistants()
])
diagnosisTypeOptions.value = diagnosisType?.diagnosis_type || []
syndromeTypeOptions.value = syndromeType?.syndrome_type || []
assistantOptions.value = assistants || []
// 调试:打印医助列表
console.log('医助列表数据:', assistants)
console.log('assistantOptions:', assistantOptions.value)
} catch (error) {
console.error('获取字典数据失败:', error)
}
}
// 获取字典标签
const getDictLabel = (options: any[], value: string) => {
const item = options.find(opt => opt.value === value)
return item ? item.name : value || '-'
}
// 获取医助名称
const getAssistantName = (assistantId: number | string) => {
// 如果没有assistant_id,返回"-"
if (!assistantId && assistantId !== 0) return '-'
// 确保类型匹配,转换为数字进行比较
const id = typeof assistantId === 'string' ? parseInt(assistantId) : assistantId
// 如果医助列表还没加载,返回"加载中..."
if (assistantOptions.value.length === 0) return '...'
const assistant = assistantOptions.value.find(item => {
const itemId = typeof item.id === 'string' ? parseInt(item.id) : item.id
return itemId === id
})
return assistant ? assistant.name : '-'
}
const { pager, getLists, resetParams, resetPage } = usePaging({
fetchFun: tcmDiagnosisLists,
params: formData.value
})
const editRef = ref()
const detailRef = ref()
const videoCallRef = ref()
const appointmentRef = ref()
// 批量指派相关
const selectedIds = ref<number[]>([])
const assignDialogVisible = ref(false)
const assignLoading = ref(false)
const assignMode = ref<'batch' | 'single'>('batch')
const currentRow = ref<any>(null)
const assignForm = ref({
assistant_id: null as number | null
})
const handleSelectionChange = (selection: any[]) => {
selectedIds.value = selection.map(item => item.id)
}
// 单独指派
const handleSingleAssign = (row: any) => {
assignMode.value = 'single'
currentRow.value = row
// 确保类型一致,转换为数字
assignForm.value.assistant_id = row.assistant_id ? Number(row.assistant_id) : null
assignDialogVisible.value = true
// 调试
console.log('当前行数据:', row)
console.log('assistant_id:', row.assistant_id, '类型:', typeof row.assistant_id)
console.log('转换后:', assignForm.value.assistant_id, '类型:', typeof assignForm.value.assistant_id)
console.log('医助选项:', assistantOptions.value)
}
// 批量指派
const handleBatchAssign = () => {
if (selectedIds.value.length === 0) {
feedback.msgWarning('请先选择要指派的诊单')
return
}
assignMode.value = 'batch'
currentRow.value = null
assignForm.value.assistant_id = null
assignDialogVisible.value = true
}
const handleConfirmAssign = async () => {
if (!assignForm.value.assistant_id) {
feedback.msgWarning('请选择医助')
return
}
assignLoading.value = true
try {
if (assignMode.value === 'single') {
// 单独指派
await tcmDiagnosisAssign({
id: currentRow.value.id,
assistant_id: assignForm.value.assistant_id
})
} else {
// 批量指派
const promises = selectedIds.value.map(id =>
tcmDiagnosisAssign({
id,
assistant_id: assignForm.value.assistant_id
})
)
await Promise.all(promises)
selectedIds.value = []
}
assignDialogVisible.value = false
getLists()
} catch (error) {
console.error('指派失败:', error)
} finally {
assignLoading.value = false
}
}
const handleAdd = () => {
editRef.value.open('add')
}
const handleEdit = (id: number) => {
editRef.value.open('edit', id)
}
const handleDetail = (id: number) => {
detailRef.value.open(id)
}
const handleDelete = async (id: number) => {
await feedback.confirm('确定要删除该诊单吗?')
await tcmDiagnosisDelete({ id })
getLists()
}
// 视频通话(一对一)
const handleVideoCall = (row: any) => {
if (!row.patient_id) {
feedback.msgWarning('患者信息不完整')
return
}
videoCallRef.value?.open({
diagnosisId: row.id,
patientId: row.patient_id,
patientName: row.patient_name,
userId: `patient_${row.patient_id}`, // 患者的用户ID
isGroup: false
})
}
// 群组视频通话(三方通话)
const handleGroupVideoCall = (row: any) => {
if (!row.patient_id) {
feedback.msgWarning('患者信息不完整')
return
}
if (!row.assistant_id) {
feedback.msgWarning('该诊单未指派医助,无法发起群组通话')
return
}
// 群组通话参与者顺序:当前登录用户(发起者)、患者、医助
const userIds = [
`patient_${row.patient_id}`, // 先邀请患者
`doctor_${row.assistant_id}` // 再邀请医助
]
videoCallRef.value?.open({
diagnosisId: row.id,
patientId: row.patient_id,
patientName: row.patient_name,
assistantId: row.assistant_id,
userIds: userIds,
isGroup: true
})
}
// 患者挂号
const handleAppointment = (row: any) => {
if (!row.patient_id) {
feedback.msgWarning('患者信息不完整')
return
}
appointmentRef.value?.open(row)
}
onMounted(async () => {
await getDictOptions()
getLists()
})
</script>
<style lang="scss" scoped></style>