更新
This commit is contained in:
@@ -1544,7 +1544,9 @@ async function loadCreateOrderPaidOrders() {
|
||||
}
|
||||
try {
|
||||
createOrderPaidOrdersLoading.value = true
|
||||
const res: any = await prescriptionOrderPaidPayOrders({ diagnosis_id: did })
|
||||
const res: any = await prescriptionOrderPaidPayOrders({
|
||||
diagnosis_id: did
|
||||
})
|
||||
const lists = res?.lists ?? res?.data?.lists ?? []
|
||||
createOrderPaidOrders.value = Array.isArray(lists) ? lists : []
|
||||
const dep = Number(res?.deposit_min_amount ?? res?.data?.deposit_min_amount) || 0
|
||||
|
||||
@@ -444,10 +444,10 @@
|
||||
<el-descriptions-item label="处方日期">{{ detailPrescription.prescription_date || '—' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="医师">{{ detailPrescription.doctor_name || '—' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="类型">{{ detailPrescription.prescription_type || '—' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="临床诊断" :span="2">
|
||||
<el-descriptions-item label="临床诊断" :span="2" >
|
||||
{{ detailPrescription.clinical_diagnosis || '—' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="剂数 / 用法" :span="2">
|
||||
<el-descriptions-item label="剂数 / 用法" :span="2" v-if="showPrescriptionAuditFilter">
|
||||
{{ detailData.dose_count ?? detailPrescription.dose_count ?? '—' }} {{ detailData.dose_unit || '剂' }} ·
|
||||
{{ detailPrescription.usage_instruction || detailPrescription.usage_method || '—' }}
|
||||
</el-descriptions-item>
|
||||
@@ -1357,35 +1357,60 @@
|
||||
<!-- 处方详情查看(处方单样式) -->
|
||||
<el-drawer
|
||||
v-model="prescriptionViewVisible"
|
||||
title="查看处方"
|
||||
size="920px"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between w-full pr-2 gap-3">
|
||||
<span class="text-base font-medium text-gray-800">查看处方</span>
|
||||
<div v-if="prescriptionViewData && !prescriptionViewLoading" class="flex items-center gap-2 shrink-0">
|
||||
<el-button
|
||||
size="small"
|
||||
:loading="prescriptionSlipExporting"
|
||||
@click="downloadPrescriptionSlipImage"
|
||||
>
|
||||
下载图片
|
||||
</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
:loading="prescriptionSlipExporting"
|
||||
@click="downloadPrescriptionSlipPdf"
|
||||
>
|
||||
下载PDF
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div v-loading="prescriptionViewLoading" class="cf-slip-wrap">
|
||||
<div v-if="prescriptionViewData" class="cf-slip-print">
|
||||
<div v-if="prescriptionViewData" ref="prescriptionSlipPrintRef" class="cf-slip-print">
|
||||
<div class="cf-slip-header">
|
||||
<h2 class="cf-slip-title">{{ SLIP_HOSPITAL_NAME }}处方笺</h2>
|
||||
<div class="cf-slip-type">
|
||||
<el-tag v-if="Number(prescriptionViewData.void_status) === 1" type="danger" size="small">已作废</el-tag>
|
||||
<el-tag
|
||||
v-if="Number(prescriptionViewData.void_status) === 1"
|
||||
type="danger"
|
||||
size="small"
|
||||
class="cf-slip-no-export"
|
||||
>已作废</el-tag>
|
||||
<el-tag
|
||||
v-else-if="Number(prescriptionViewData.business_prescription_audit_rejected) === 1"
|
||||
type="danger"
|
||||
size="small"
|
||||
class="mr-1"
|
||||
class="mr-1 cf-slip-no-export"
|
||||
>已驳回</el-tag>
|
||||
<el-tag
|
||||
v-else-if="Number(prescriptionViewData.audit_status) === 1"
|
||||
type="success"
|
||||
size="small"
|
||||
class="mr-1"
|
||||
class="mr-1 cf-slip-no-export"
|
||||
>已通过</el-tag>
|
||||
<el-tag
|
||||
v-else-if="Number(prescriptionViewData.audit_status) === 0"
|
||||
type="warning"
|
||||
size="small"
|
||||
class="mr-1"
|
||||
class="mr-1 cf-slip-no-export"
|
||||
>待审核</el-tag>
|
||||
<el-tag v-else type="danger" size="small" class="mr-1">已驳回</el-tag>
|
||||
<el-tag v-else type="danger" size="small" class="mr-1 cf-slip-no-export">已驳回</el-tag>
|
||||
<template v-if="Number(prescriptionViewData.void_status) !== 1">
|
||||
<div>普通处方</div>
|
||||
<div class="text-sm">当日有效</div>
|
||||
@@ -1397,7 +1422,7 @@
|
||||
</div>
|
||||
<div
|
||||
v-else-if="Number(prescriptionViewData.business_prescription_audit_rejected) === 1"
|
||||
class="rounded border border-red-200 bg-red-50 text-red-800 text-sm px-3 py-2 mb-3"
|
||||
class="cf-slip-no-export rounded border border-red-200 bg-red-50 text-red-800 text-sm px-3 py-2 mb-3"
|
||||
>
|
||||
<div class="font-medium">审核状态:已驳回(业务订单·处方审核)</div>
|
||||
<div v-if="prescriptionViewData.business_prescription_audit_remark" class="mt-1">
|
||||
@@ -1407,7 +1432,7 @@
|
||||
</div>
|
||||
<div
|
||||
v-else-if="Number(prescriptionViewData.audit_status) === 2"
|
||||
class="rounded border border-red-200 bg-red-50 text-red-800 text-sm px-3 py-2 mb-3"
|
||||
class="cf-slip-no-export rounded border border-red-200 bg-red-50 text-red-800 text-sm px-3 py-2 mb-3"
|
||||
>
|
||||
<div class="font-medium">消费者处方审核:已驳回</div>
|
||||
<div v-if="prescriptionViewData.audit_remark" class="mt-1">驳回意见:{{ prescriptionViewData.audit_remark }}</div>
|
||||
@@ -1451,6 +1476,9 @@
|
||||
<span class="cf-slip-inline-gap" />
|
||||
服用方式: {{ prescriptionViewData.usage_way ? ' ' + prescriptionViewData.usage_way : '' }}
|
||||
</div>
|
||||
<div v-if="slipChuwanVisible">
|
||||
出丸:{{ slipPillGrams === null ? '—' : slipPillGrams }} 克
|
||||
</div>
|
||||
<div v-if="slipDietaryText" class="cf-slip-dietary">忌口:{{ slipDietaryText }}</div>
|
||||
<div v-if="prescriptionViewData.usage_notes" class="cf-slip-notes">{{ prescriptionViewData.usage_notes }}</div>
|
||||
</div>
|
||||
@@ -1642,6 +1670,8 @@ import {
|
||||
prescriptionOrderPreviewGancaoRecipel,
|
||||
prescriptionDetail
|
||||
} from '@/api/tcm'
|
||||
import html2canvas from 'html2canvas'
|
||||
import { jsPDF } from 'jspdf'
|
||||
import { getDictData } from '@/api/app'
|
||||
import { usePaging } from '@/hooks/usePaging'
|
||||
import feedback from '@/utils/feedback'
|
||||
@@ -1926,10 +1956,19 @@ function formatTime(v: unknown) {
|
||||
return String(v)
|
||||
}
|
||||
|
||||
function canEditRow(row: { fulfillment_status?: number }) {
|
||||
function canEditRow(row: {
|
||||
fulfillment_status?: number
|
||||
gancao_reciperl_order_no?: string | null
|
||||
gancao_submit_time?: number | null
|
||||
}) {
|
||||
// 已发货(5)、已签收(6)、已完成(3)、已取消(4) 不可编辑
|
||||
const fs = Number(row.fulfillment_status)
|
||||
return fs === 1 || fs === 2
|
||||
if (fs !== 1 && fs !== 2) return false
|
||||
// 已成功提交甘草(已生成甘草处方单号 或 提交时间 > 0)不允许再编辑
|
||||
const gcNo = String(row.gancao_reciperl_order_no || '').trim()
|
||||
const gcTime = Number(row.gancao_submit_time || 0)
|
||||
if (gcNo !== '' || gcTime > 0) return false
|
||||
return true
|
||||
}
|
||||
|
||||
function canRxAudit(row: { prescription_audit_status?: number; fulfillment_status?: number }) {
|
||||
@@ -2097,7 +2136,7 @@ async function loadDetailUnlinkedPayOrders(diagnosisId: number, prescriptionOrde
|
||||
prescription_order_id: prescriptionOrderId
|
||||
})
|
||||
const lists = res?.lists ?? res?.data?.lists ?? []
|
||||
// 过滤掉已关联的支付单
|
||||
// 列表已由服务端限制为 2026-04-20 及之后创建的支付单(本单已关联除外);此处再过滤已关联项
|
||||
const filtered = Array.isArray(lists)
|
||||
? lists.filter((item: any) => !linkedIds.includes(item.id))
|
||||
: []
|
||||
@@ -2386,6 +2425,7 @@ async function loadEditPaidOrders(diagnosisId: number, prescriptionOrderId?: num
|
||||
...(prescriptionOrderId ? { prescription_order_id: prescriptionOrderId } : {})
|
||||
})
|
||||
const lists = res?.lists ?? res?.data?.lists ?? []
|
||||
// 可选支付单:服务端仅 2026-04-20 及之后;编辑时含本单已关联的旧单
|
||||
editPaidOrders.value = Array.isArray(lists) ? lists : []
|
||||
const dep = Number(res?.deposit_min_amount ?? res?.data?.deposit_min_amount)
|
||||
if (!Number.isNaN(dep) && dep >= 0) {
|
||||
@@ -2993,7 +3033,7 @@ async function loadAddPayOrderAvailable(diagnosisId: number, prescriptionOrderId
|
||||
prescription_order_id: prescriptionOrderId
|
||||
})
|
||||
const lists = res?.lists ?? res?.data?.lists ?? []
|
||||
// 过滤掉当前订单已关联的支付单
|
||||
// 服务端仅 2026-04-20 及之后;再排除当前订单已关联
|
||||
const filtered = Array.isArray(lists)
|
||||
? lists.filter((item: any) => !currentLinkedIds.includes(item.id))
|
||||
: []
|
||||
@@ -3155,6 +3195,8 @@ const SLIP_ADDRESS_LINE = '地址:四川省成都市双流区黄甲街道黄
|
||||
const prescriptionViewVisible = ref(false)
|
||||
const prescriptionViewLoading = ref(false)
|
||||
const prescriptionViewData = ref<any>(null)
|
||||
const prescriptionSlipPrintRef = ref<HTMLElement | null>(null)
|
||||
const prescriptionSlipExporting = ref(false)
|
||||
|
||||
// 处方单辅助函数
|
||||
const slipHerbsList = computed(() => {
|
||||
@@ -3169,6 +3211,23 @@ const slipDietaryText = computed(() => {
|
||||
return ''
|
||||
})
|
||||
|
||||
const slipChuwanVisible = computed(() => {
|
||||
const d = prescriptionViewData.value
|
||||
if (!d) return false
|
||||
return (d.prescription_type || '浓缩水丸') === '浓缩水丸'
|
||||
})
|
||||
|
||||
const slipPillGrams = computed(() => {
|
||||
const d = prescriptionViewData.value
|
||||
if (!d || (d.prescription_type || '浓缩水丸') !== '浓缩水丸') return null
|
||||
const days = Number(d.usage_days ?? d.dose_count)
|
||||
const times = Number(d.times_per_day)
|
||||
const doseG = Number(d.dosage_amount)
|
||||
if (!Number.isFinite(days) || !Number.isFinite(times) || !Number.isFinite(doseG)) return null
|
||||
if (days <= 0 || times <= 0 || doseG <= 0) return null
|
||||
return days * times * doseG
|
||||
})
|
||||
|
||||
function formatAuditTime(ts: number | null | undefined) {
|
||||
if (!ts) return ''
|
||||
const d = new Date(ts * 1000)
|
||||
@@ -3215,6 +3274,93 @@ async function openPrescriptionView(row: any) {
|
||||
prescriptionViewLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function preloadSlipImagesToDataUrl(el: HTMLElement): Promise<void> {
|
||||
const imgs = el.querySelectorAll<HTMLImageElement>('img[src^="http"]')
|
||||
const tasks = Array.from(imgs).map(async (img) => {
|
||||
try {
|
||||
const res = await fetch(img.src, { mode: 'cors' })
|
||||
if (!res.ok) return
|
||||
const blob = await res.blob()
|
||||
const dataUrl = await new Promise<string>((resolve, reject) => {
|
||||
const r = new FileReader()
|
||||
r.onload = () => resolve(r.result as string)
|
||||
r.onerror = reject
|
||||
r.readAsDataURL(blob)
|
||||
})
|
||||
img.src = dataUrl
|
||||
} catch {
|
||||
/* 跨域失败时保留原 src */
|
||||
}
|
||||
})
|
||||
await Promise.allSettled(tasks)
|
||||
}
|
||||
|
||||
async function capturePrescriptionSlipCanvas(): Promise<HTMLCanvasElement> {
|
||||
await nextTick()
|
||||
const el = prescriptionSlipPrintRef.value
|
||||
if (!el) throw new Error('未找到处方笺内容')
|
||||
el.scrollIntoView({ behavior: 'instant', block: 'nearest' })
|
||||
await preloadSlipImagesToDataUrl(el)
|
||||
await new Promise((r) => setTimeout(r, 200))
|
||||
return html2canvas(el, {
|
||||
scale: 2,
|
||||
useCORS: true,
|
||||
logging: false,
|
||||
backgroundColor: '#ffffff',
|
||||
ignoreElements: (node) =>
|
||||
node instanceof HTMLElement && node.classList.contains('cf-slip-no-export')
|
||||
})
|
||||
}
|
||||
|
||||
function slipDownloadBaseName() {
|
||||
const name = prescriptionViewData.value?.patient_name
|
||||
const safe = typeof name === 'string' && name.trim() ? name.trim().replace(/[\\/:*?"<>|]/g, '_') : '未命名'
|
||||
return `处方_${safe}_${Date.now()}`
|
||||
}
|
||||
|
||||
async function downloadPrescriptionSlipImage() {
|
||||
if (!prescriptionViewData.value) return
|
||||
prescriptionSlipExporting.value = true
|
||||
try {
|
||||
const canvas = await capturePrescriptionSlipCanvas()
|
||||
const link = document.createElement('a')
|
||||
link.download = `${slipDownloadBaseName()}.png`
|
||||
link.href = canvas.toDataURL('image/png')
|
||||
link.click()
|
||||
feedback.msgSuccess('图片已下载')
|
||||
} catch {
|
||||
feedback.msgError('下载图片失败')
|
||||
} finally {
|
||||
prescriptionSlipExporting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadPrescriptionSlipPdf() {
|
||||
if (!prescriptionViewData.value) return
|
||||
prescriptionSlipExporting.value = true
|
||||
try {
|
||||
const canvas = await capturePrescriptionSlipCanvas()
|
||||
const imgData = canvas.toDataURL('image/png')
|
||||
const pdf = new jsPDF({
|
||||
orientation: 'portrait',
|
||||
unit: 'mm',
|
||||
format: 'a5'
|
||||
})
|
||||
const pageW = pdf.internal.pageSize.getWidth()
|
||||
const pageH = pdf.internal.pageSize.getHeight()
|
||||
const scale = Math.min(pageW / canvas.width, pageH / canvas.height)
|
||||
const imgW = canvas.width * scale
|
||||
const imgH = canvas.height * scale
|
||||
pdf.addImage(imgData, 'PNG', 0, 0, imgW, imgH)
|
||||
pdf.save(`${slipDownloadBaseName()}.pdf`)
|
||||
feedback.msgSuccess('PDF已下载')
|
||||
} catch {
|
||||
feedback.msgError('下载PDF失败')
|
||||
} finally {
|
||||
prescriptionSlipExporting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
Reference in New Issue
Block a user