更新
This commit is contained in:
@@ -103,6 +103,15 @@
|
||||
>
|
||||
批量指派医助
|
||||
</el-button>
|
||||
<el-button
|
||||
v-perms="['tcm.diagnosis/assign']"
|
||||
type="warning"
|
||||
plain
|
||||
@click="handleBatchCancelAssign"
|
||||
:disabled="!canBatchCancelAssign"
|
||||
>
|
||||
批量取消指派
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-if="selectedIds.length > 0" class="list-selected">已选 {{ selectedIds.length }} 条</div>
|
||||
</div>
|
||||
@@ -263,9 +272,16 @@
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="hasPermission(['tcm.diagnosis/assign'])" command="assign"><el-icon><User /></el-icon>指派</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="hasPermission(['tcm.diagnosis/assign']) && hasAssignedAssistant(row)"
|
||||
command="cancelAssign"
|
||||
>
|
||||
<el-icon><Remove /></el-icon>取消指派
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="isAppointmentActiveForVideo(row) && hasPermission(['tcm.diagnosis/videoQr'])" command="videoQr"><el-icon><Picture /></el-icon>视频二维码</el-dropdown-item>
|
||||
<el-dropdown-item v-if="hasPermission(['tcm.diagnosis/guahao']) && isAppointmentActiveForVideo(row)" command="confirmQr"><el-icon><Picture /></el-icon>二维码</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canCancelAppointmentRow(row) && hasPermission(['tcm.diagnosis/guahao'])" command="cancelApt"><el-icon><CircleClose /></el-icon>取消挂号</el-dropdown-item>
|
||||
<el-dropdown-item v-if="hasPermission(['tcm.diagnosis/guahaoLogList'])" command="guahaoLogs"><el-icon><List /></el-icon>挂号日志</el-dropdown-item>
|
||||
<el-dropdown-item command="order" v-if="hasPermission(['tcm.diagnosis/order'])"><el-icon><Document /></el-icon>创建订单</el-dropdown-item>
|
||||
<el-dropdown-item v-if="hasPermission(['tcm.diagnosis/delete'])" command="delete" divided><el-icon><Delete /></el-icon><span class="text-danger">删除</span></el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
@@ -284,12 +300,37 @@
|
||||
<edit-popup ref="editRef" @success="refreshListAfterPopupSave" />
|
||||
<detail-popup ref="detailRef" />
|
||||
<tcm-prescription ref="prescriptionRef" @success="onPrescriptionSuccess" />
|
||||
<appointment-popup ref="appointmentRef" @success="refreshListAfterPopupSave" />
|
||||
<appointment-popup ref="appointmentRef" @success="handleAppointmentSaved" />
|
||||
<assistant-watch-call-dialog
|
||||
v-model="watchCallVisible"
|
||||
:diagnosis-id="watchCallDiagnosisId"
|
||||
@closed="getLists"
|
||||
/>
|
||||
|
||||
<el-drawer v-model="guahaoLogDrawerVisible" title="挂号操作日志" size="460px" destroy-on-close @closed="resetGuahaoLogDrawer">
|
||||
<div v-loading="guahaoLogLoading" class="min-h-[100px]">
|
||||
<div v-if="guahaoLogContextRow" class="text-sm text-gray-600 mb-4 pb-3 border-b border-gray-100">
|
||||
<span class="font-medium text-gray-800">{{ guahaoLogContextRow.patient_name }}</span>
|
||||
<span class="mx-2 text-gray-300">|</span>
|
||||
<span>诊单 #{{ guahaoLogContextRow.id }}</span>
|
||||
</div>
|
||||
<el-empty v-if="!guahaoLogLoading && guahaoLogRows.length === 0" description="暂无挂号/取消挂号操作记录" />
|
||||
<el-timeline v-else-if="guahaoLogRows.length > 0">
|
||||
<el-timeline-item
|
||||
v-for="(log, idx) in guahaoLogRows"
|
||||
:key="log.id ?? idx"
|
||||
:timestamp="log.create_time_text || '—'"
|
||||
placement="top"
|
||||
>
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<el-tag size="small" type="info">{{ log.action_desc }}</el-tag>
|
||||
<span class="text-sm font-medium text-gray-800">{{ formatGuahaoLogOperator(log) }}</span>
|
||||
</div>
|
||||
<div class="text-xs text-gray-600 mt-1.5 leading-relaxed">{{ log.summary }}</div>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
<!-- 小程序二维码弹窗 -->
|
||||
<el-dialog
|
||||
@@ -564,7 +605,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="tcmDiagnosis">
|
||||
import { tcmDiagnosisLists, tcmDiagnosisDelete, tcmDiagnosisAssign, getAssistants, generateMiniProgramQrcode, generateOrderQrcode, getWechatChatRecords, addWechatChatRecord, deleteWechatChatRecord, getWechatExternalContact, fillIdCard } from '@/api/tcm'
|
||||
import { tcmDiagnosisLists, tcmDiagnosisDelete, tcmDiagnosisAssign, tcmDiagnosisGuahaoLogList, getAssistants, generateMiniProgramQrcode, generateOrderQrcode, getWechatChatRecords, addWechatChatRecord, deleteWechatChatRecord, getWechatExternalContact, fillIdCard } from '@/api/tcm'
|
||||
import { orderCreate } from '@/api/order'
|
||||
import { cancelAppointment } from '@/api/doctor'
|
||||
import { usePaging } from '@/hooks/usePaging'
|
||||
@@ -572,7 +613,7 @@ import { getDictData } from '@/api/app'
|
||||
import { getWeappConfig } from '@/api/channel/weapp'
|
||||
import feedback from '@/utils/feedback'
|
||||
import { hasPermission } from '@/utils/perm'
|
||||
import { Loading, Warning, List, CircleCheck, Clock, ArrowDown, Picture, User, Document, Delete, CircleClose } from '@element-plus/icons-vue'
|
||||
import { Loading, Warning, List, CircleCheck, Clock, ArrowDown, Picture, User, Document, Delete, CircleClose, Remove } from '@element-plus/icons-vue'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { computed, defineAsyncComponent, onMounted, onUnmounted, watch } from 'vue'
|
||||
@@ -1116,6 +1157,19 @@ const handleSelectionChange = (selection: any[]) => {
|
||||
selectedIds.value = selection.map(item => item.id)
|
||||
}
|
||||
|
||||
/** 当前行是否已指派医助(用于取消指派入口) */
|
||||
const hasAssignedAssistant = (row: any) => {
|
||||
const id = Number(row?.assistant_id ?? row?.assistant ?? 0)
|
||||
return id > 0
|
||||
}
|
||||
|
||||
/** 当前页勾选记录中是否存在已指派医助的诊单(批量取消指派) */
|
||||
const canBatchCancelAssign = computed(() => {
|
||||
if (!selectedIds.value.length) return false
|
||||
const set = new Set(selectedIds.value)
|
||||
return pager.lists.some((r: any) => set.has(r.id) && hasAssignedAssistant(r))
|
||||
})
|
||||
|
||||
// 单独指派
|
||||
const handleSingleAssign = (row: any) => {
|
||||
assignMode.value = 'single'
|
||||
@@ -1172,6 +1226,34 @@ const handleConfirmAssign = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
/** 取消指派:将 assistant_id 置为 0(与后端 assign 一致) */
|
||||
const handleCancelAssign = async (row: any) => {
|
||||
if (!row?.id || !hasAssignedAssistant(row)) {
|
||||
feedback.msgWarning('该诊单未指派医助')
|
||||
return
|
||||
}
|
||||
await feedback.confirm('确定取消该诊单的医助指派吗?')
|
||||
await tcmDiagnosisAssign({ id: row.id, assistant_id: 0 })
|
||||
getLists()
|
||||
}
|
||||
|
||||
const handleBatchCancelAssign = async () => {
|
||||
if (!selectedIds.value.length) {
|
||||
feedback.msgWarning('请先选择诊单')
|
||||
return
|
||||
}
|
||||
const set = new Set(selectedIds.value)
|
||||
const rows = pager.lists.filter((r: any) => set.has(r.id) && hasAssignedAssistant(r))
|
||||
if (!rows.length) {
|
||||
feedback.msgWarning('所选诊单中没有已指派医助的记录')
|
||||
return
|
||||
}
|
||||
await feedback.confirm(`确定取消 ${rows.length} 条诊单的医助指派吗?`)
|
||||
await Promise.all(rows.map((r: any) => tcmDiagnosisAssign({ id: r.id, assistant_id: 0 })))
|
||||
selectedIds.value = []
|
||||
getLists()
|
||||
}
|
||||
|
||||
const handleAdd = () => {
|
||||
editRef.value.open('add')
|
||||
}
|
||||
@@ -1222,6 +1304,7 @@ const handleDelete = async (id: number) => {
|
||||
const handleRowAction = (cmd: string, row: any) => {
|
||||
switch (cmd) {
|
||||
case 'assign': handleSingleAssign(row); break
|
||||
case 'cancelAssign': handleCancelAssign(row); break
|
||||
case 'videoQr':
|
||||
if (!isAppointmentActiveForVideo(row)) {
|
||||
feedback.msgWarning('仅「已预约」状态可生成视频二维码')
|
||||
@@ -1231,6 +1314,7 @@ const handleRowAction = (cmd: string, row: any) => {
|
||||
break
|
||||
case 'confirmQr': handleMiniProgramQRCode(row); break
|
||||
case 'cancelApt': handleCancelAppointment(row); break
|
||||
case 'guahaoLogs': openGuahaoLogDrawer(row); break
|
||||
case 'order': handleCreateOrder(row); break
|
||||
case 'delete': handleDelete(row.id); break
|
||||
}
|
||||
@@ -1309,11 +1393,63 @@ const handleCancelAppointment = async (row: any) => {
|
||||
feedback.msgSuccess('取消挂号成功')
|
||||
getLists()
|
||||
fetchDateCounts()
|
||||
if (guahaoLogDrawerVisible.value && guahaoLogContextRow.value?.id === row.id) {
|
||||
await fetchGuahaoLogs(row.id)
|
||||
}
|
||||
} catch (e: any) {
|
||||
if (e !== 'cancel') feedback.msgError(e?.msg || '取消挂号失败')
|
||||
}
|
||||
}
|
||||
|
||||
const guahaoLogDrawerVisible = ref(false)
|
||||
const guahaoLogLoading = ref(false)
|
||||
const guahaoLogRows = ref<any[]>([])
|
||||
const guahaoLogContextRow = ref<any>(null)
|
||||
|
||||
function resetGuahaoLogDrawer() {
|
||||
guahaoLogRows.value = []
|
||||
guahaoLogContextRow.value = null
|
||||
}
|
||||
|
||||
function formatGuahaoLogOperator(log: any) {
|
||||
const name = String(log?.admin_name || '').trim()
|
||||
const aid = Number(log?.admin_id)
|
||||
if (name) return name
|
||||
if (aid > 0) return `管理员 #${aid}`
|
||||
return '—'
|
||||
}
|
||||
|
||||
async function fetchGuahaoLogs(diagnosisId: number) {
|
||||
guahaoLogLoading.value = true
|
||||
try {
|
||||
const res: any = await tcmDiagnosisGuahaoLogList({ id: diagnosisId })
|
||||
guahaoLogRows.value = Array.isArray(res?.data) ? res.data : Array.isArray(res) ? res : []
|
||||
} catch {
|
||||
guahaoLogRows.value = []
|
||||
} finally {
|
||||
guahaoLogLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function openGuahaoLogDrawer(row: any) {
|
||||
if (!row?.id) {
|
||||
feedback.msgWarning('诊单信息不完整')
|
||||
return
|
||||
}
|
||||
guahaoLogContextRow.value = row
|
||||
guahaoLogDrawerVisible.value = true
|
||||
await fetchGuahaoLogs(Number(row.id))
|
||||
}
|
||||
|
||||
/** 预约抽屉保存成功后:静默刷新列表 + 顶部计数;若挂号日志抽屉打开则同步日志 */
|
||||
async function handleAppointmentSaved() {
|
||||
await getLists({ silent: true })
|
||||
fetchDateCounts()
|
||||
if (guahaoLogDrawerVisible.value && guahaoLogContextRow.value?.id) {
|
||||
await fetchGuahaoLogs(Number(guahaoLogContextRow.value.id))
|
||||
}
|
||||
}
|
||||
|
||||
// 患者挂号
|
||||
const handleAppointment = (row: any) => {
|
||||
if (!row.patient_id) {
|
||||
|
||||
Reference in New Issue
Block a user