Merge branch 'long-0509'

This commit is contained in:
2026-05-09 17:14:13 +08:00
3 changed files with 173 additions and 7 deletions
+1
View File
@@ -30,3 +30,4 @@ bin-release/
/.claude /.claude
/.claude /.claude
/.kbctx /.kbctx
/server/.kbctx
@@ -740,7 +740,7 @@
改患者信息 改患者信息
</el-button> </el-button>
<el-button <el-button
v-if="detailData.prescription_id && showPrescriptionAuditFilter" v-if="detailData.prescription_id && canViewPrescriptionDetail"
type="primary" type="primary"
size="small" size="small"
link link
@@ -749,7 +749,7 @@
详细 详细
</el-button> </el-button>
<el-button <el-button
v-if="detailData.id && showPrescriptionAuditFilter" v-if="detailData.id && canViewPrescriptionDetail"
type="warning" type="warning"
size="small" size="small"
link link
@@ -802,7 +802,7 @@
<el-descriptions-item label="临床诊断" :span="2" > <el-descriptions-item label="临床诊断" :span="2" >
{{ detailPrescription.clinical_diagnosis || '—' }} {{ detailPrescription.clinical_diagnosis || '—' }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="剂数 / 用法" :span="2" v-if="showPrescriptionAuditFilter"> <el-descriptions-item label="剂数 / 用法" :span="2" v-if="canViewPrescriptionDetail">
{{ detailData.dose_count ?? detailPrescription.dose_count ?? '—' }} {{ detailData.dose_unit || '剂' }} · {{ detailData.dose_count ?? detailPrescription.dose_count ?? '—' }} {{ detailData.dose_unit || '剂' }} ·
{{ detailPrescription.usage_instruction || detailPrescription.usage_method || '—' }} {{ detailPrescription.usage_instruction || detailPrescription.usage_method || '—' }}
</el-descriptions-item> </el-descriptions-item>
@@ -858,7 +858,7 @@
</el-descriptions-item> </el-descriptions-item>
</el-descriptions> </el-descriptions>
<div v-if="detailHerbsVisible" class="mt-4"> <div v-if="canViewPrescriptionDetail && detailHerbsVisible" class="mt-4">
<div class="text-xs font-medium text-gray-500 mb-2 px-1">药材明细</div> <div class="text-xs font-medium text-gray-500 mb-2 px-1">药材明细</div>
<el-table v-if="detailRxHerbs.length" :data="detailRxHerbs" size="small" border stripe max-height="260"> <el-table v-if="detailRxHerbs.length" :data="detailRxHerbs" size="small" border stripe max-height="260">
<el-table-column type="index" label="#" width="48" align="center" /> <el-table-column type="index" label="#" width="48" align="center" />
@@ -1364,7 +1364,7 @@
</div> </div>
<div v-show="editOrderStep === 1" class="create-order-step-panel"> <div v-show="editOrderStep === 1" class="create-order-step-panel">
<el-row v-if="showPrescriptionAuditFilter" :gutter="20" class="mb-1"> <el-row v-if="canViewPrescriptionDetail" :gutter="20" class="mb-1">
<el-col :span="24"> <el-col :span="24">
<div class="flex flex-wrap items-center gap-2 pb-2 border-b border-gray-100"> <div class="flex flex-wrap items-center gap-2 pb-2 border-b border-gray-100">
<span class="text-sm font-medium text-gray-700 mr-1">处方</span> <span class="text-sm font-medium text-gray-700 mr-1">处方</span>
@@ -2408,10 +2408,12 @@ import feedback from '@/utils/feedback'
import { ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
import useUserStore from '@/stores/modules/user' import useUserStore from '@/stores/modules/user'
import { hasPermission } from '@/utils/perm'
const TcmDiagnosisEditView = defineAsyncComponent(() => import('@/views/tcm/diagnosis/edit.vue')) const TcmDiagnosisEditView = defineAsyncComponent(() => import('@/views/tcm/diagnosis/edit.vue'))
const userStore = useUserStore() const userStore = useUserStore()
const canViewPrescriptionDetail = computed(() => hasPermission(['tcm.prescriptionOrder/detail']))
const route = useRoute() const route = useRoute()
const diagnosisViewRef = ref<{ const diagnosisViewRef = ref<{
@@ -39,19 +39,139 @@
{{ formatTime(row.create_time) }} {{ formatTime(row.create_time) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="100" fixed="right">
<template #default="{ row }">
<el-button
v-perms="['tcm.prescriptionOrder/detail']"
type="primary"
link
@click="openDetail(row.id)"
>查看详情</el-button>
</template>
</el-table-column>
</el-table> </el-table>
<div class="flex justify-end mt-3"> <div class="flex justify-end mt-3">
<pagination v-model="pager" @change="getLists" /> <pagination v-model="pager" @change="getLists" />
</div> </div>
</template> </template>
<!-- 业务订单详情抽屉 -->
<el-drawer
v-model="detailVisible"
size="70%"
destroy-on-close
:close-on-click-modal="false"
append-to-body
>
<template #header>
<span class="font-semibold text-lg">业务订单详情</span>
<el-tag v-if="detailData?.order_no" type="primary" effect="plain" round class="ml-3">{{ detailData.order_no }}</el-tag>
</template>
<el-skeleton v-if="detailLoading" :rows="10" animated class="px-4 py-3" />
<div v-else-if="detailData" class="px-4 pb-4 overflow-y-auto">
<!-- 订单基本信息 -->
<el-descriptions :column="3" border size="small" class="mb-4">
<el-descriptions-item label="订单编号">{{ detailData.order_no || '—' }}</el-descriptions-item>
<el-descriptions-item label="处方ID">{{ detailData.prescription_id || '—' }}</el-descriptions-item>
<el-descriptions-item label="诊单ID">{{ detailData.diagnosis_id || '—' }}</el-descriptions-item>
<el-descriptions-item label="收货人">{{ detailData.recipient_name || '—' }}</el-descriptions-item>
<el-descriptions-item label="收货手机">{{ detailData.recipient_phone || '—' }}</el-descriptions-item>
<el-descriptions-item label="金额">
<span class="text-red-500 font-medium">¥{{ detailData.amount }}</span>
</el-descriptions-item>
<el-descriptions-item label="履约状态">
<el-tag :type="fulfillmentTagType(detailData.fulfillment_status)" size="small">
{{ fulfillmentText(detailData.fulfillment_status) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ formatTime(detailData.create_time) }}</el-descriptions-item>
<el-descriptions-item label="创建人">{{ detailData.creator_name || '—' }}</el-descriptions-item>
</el-descriptions>
<!-- 处方详情区域 -->
<el-card v-if="detailData.prescription" shadow="never" class="mb-4 border-gray-100">
<template #header>
<div class="flex items-center gap-3">
<span class="font-medium">处方信息</span>
<span v-if="detailData.doctor_name" class="text-xs text-gray-500">
开方人<span class="text-primary font-medium">{{ detailData.doctor_name }}</span>
</span>
</div>
</template>
<el-descriptions :column="2" border size="small">
<el-descriptions-item label="患者">{{ detailData.prescription.patient_name || '—' }}</el-descriptions-item>
<el-descriptions-item label="性别/年龄">
{{ detailData.prescription.gender_desc || '—' }} · {{ detailData.prescription.age ?? '—' }}
</el-descriptions-item>
<el-descriptions-item label="临床诊断" :span="2">{{ detailData.prescription.clinical_diagnosis || '—' }}</el-descriptions-item>
<el-descriptions-item v-if="canViewPrescriptionDetail" label="剂数/用法" :span="2">
{{ detailData.dose_count ?? detailData.prescription.dose_count ?? '' }} {{ detailData.dose_unit || '' }} ·
{{ detailData.prescription.usage_instruction || detailData.prescription.usage_method || '' }}
</el-descriptions-item>
</el-descriptions>
<!-- 药材明细 -->
<div v-if="canViewPrescriptionDetail && detailHerbsVisible && detailRxHerbs.length" class="mt-4">
<div class="text-xs font-medium text-gray-500 mb-2 px-1">药材明细</div>
<el-table :data="detailRxHerbs" size="small" border stripe max-height="260">
<el-table-column type="index" label="#" width="48" align="center" />
<el-table-column prop="name" label="药名" min-width="120" show-overflow-tooltip />
<el-table-column prop="dosage" label="用量(g)" width="96" align="right" />
</el-table>
</div>
</el-card>
<!-- 药方备注 -->
<el-card
v-if="canViewRemarkExtra && detailData.remark_extra"
shadow="never"
class="mb-4 border-gray-100"
>
<template #header>
<span class="font-medium">药方备注</span>
</template>
<div class="text-sm text-gray-700">{{ detailData.remark_extra }}</div>
</el-card>
<!-- 操作日志 -->
<el-card
v-if="canViewLogs"
shadow="never"
class="mb-4 border-gray-100"
>
<template #header>
<span class="font-medium">操作日志</span>
</template>
<el-timeline v-if="detailLogs.length" class="mt-2 pl-2">
<el-timeline-item
v-for="(log, idx) in detailLogs"
:key="log.id"
:type="idx === 0 ? 'primary' : 'info'"
:hollow="idx !== 0"
:timestamp="formatTime(log.create_time)"
placement="top"
>
<div class="flex items-center gap-2 mb-1">
<span class="font-medium text-[13px]">{{ log.admin_name }}</span>
<el-tag size="small" type="info">{{ log.action }}</el-tag>
</div>
<span class="text-gray-500">{{ log.summary }}</span>
</el-timeline-item>
</el-timeline>
<el-empty v-else description="暂无操作日志" :image-size="64" />
</el-card>
</div>
</el-drawer>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, watch } from 'vue' import { computed, watch, ref } from 'vue'
import { usePaging } from '@/hooks/usePaging' import { usePaging } from '@/hooks/usePaging'
import { prescriptionOrderLists } from '@/api/tcm' import { prescriptionOrderLists, prescriptionOrderDetail, prescriptionOrderLogs } from '@/api/tcm'
import { hasPermission } from '@/utils/perm'
import feedback from '@/utils/feedback'
const props = defineProps<{ const props = defineProps<{
diagnosisId: number diagnosisId: number
@@ -83,6 +203,49 @@ const buildParams = () => {
queryParams.scene = 'diagnosis_edit' queryParams.scene = 'diagnosis_edit'
} }
const canViewPrescriptionDetail = computed(() => hasPermission(['tcm.prescriptionOrder/detail']))
const canViewRemarkExtra = computed(() => hasPermission(['tcm.prescriptionOrder/editRemarkExtra']))
const canViewLogs = computed(() => hasPermission(['tcm.prescriptionOrder/logs']))
const detailVisible = ref(false)
const detailLoading = ref(false)
const detailData = ref<any>(null)
const detailLogs = ref<any[]>([])
const detailHerbsVisible = computed(() => detailData.value?.prescription_detail_herbs_visible !== false)
const detailRxHerbs = computed(() => {
const h = detailData.value?.prescription?.herbs
return Array.isArray(h) ? h : []
})
async function openDetail(id: number) {
detailVisible.value = true
detailLoading.value = true
detailData.value = null
detailLogs.value = []
try {
const res: any = await prescriptionOrderDetail({ id })
detailData.value = res?.data ?? res ?? null
if (canViewLogs.value) {
fetchLogs(id)
}
} catch (e: any) {
feedback.msgError(e?.message || '加载详情失败')
detailVisible.value = false
} finally {
detailLoading.value = false
}
}
async function fetchLogs(id: number) {
try {
const res: any = await prescriptionOrderLogs({ id })
detailLogs.value = res?.data ?? res ?? []
} catch {
detailLogs.value = []
}
}
const formatAmount = (value: unknown) => { const formatAmount = (value: unknown) => {
const n = Number(value) const n = Number(value)
return Number.isFinite(n) ? n.toFixed(2) : '0.00' return Number.isFinite(n) ? n.toFixed(2) : '0.00'