434 lines
32 KiB
Plaintext
434 lines
32 KiB
Plaintext
<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="鎮h€呭鍚?>
|
|
<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']">鏂板鎮h€?/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="鎮h€呭鍚? 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>鎮h€咃細{{ 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('鎮h€呬俊鎭笉瀹屾暣')
|
|
return
|
|
}
|
|
|
|
videoCallRef.value?.open({
|
|
diagnosisId: row.id,
|
|
patientId: row.patient_id,
|
|
patientName: row.patient_name,
|
|
userId: `patient_${row.patient_id}`, // 鎮h€呯殑鐢ㄦ埛ID
|
|
isGroup: false
|
|
})
|
|
}
|
|
|
|
// 缇ょ粍瑙嗛閫氳瘽锛堜笁鏂归€氳瘽锛?const handleGroupVideoCall = (row: any) => {
|
|
if (!row.patient_id) {
|
|
feedback.msgWarning('鎮h€呬俊鎭笉瀹屾暣')
|
|
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
|
|
})
|
|
}
|
|
|
|
// 鎮h€呮寕鍙?const handleAppointment = (row: any) => {
|
|
if (!row.patient_id) {
|
|
feedback.msgWarning('鎮h€呬俊鎭笉瀹屾暣')
|
|
return
|
|
}
|
|
|
|
appointmentRef.value?.open(row)
|
|
}
|
|
|
|
onMounted(async () => {
|
|
await getDictOptions()
|
|
getLists()
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped></style>
|