This commit is contained in:
Your Name
2026-05-29 14:45:56 +08:00
parent 94e787ae80
commit 17ad153821
9 changed files with 1795 additions and 623 deletions
+168 -51
View File
@@ -518,6 +518,13 @@
</div>
<div v-else class="rx-wrap">
<el-tabs
v-model="prescriptionTabType"
class="rx-slip-tabs"
>
<el-tab-pane label="药房联" name="internal" />
<el-tab-pane label="处方联" name="user" />
</el-tabs>
<div class="rx-toolbar">
<el-tag v-if="savedPrescription.void_status === 1" type="danger" size="small">已作废</el-tag>
<el-tag v-else-if="approvedPreviewOnly" type="success" size="small">已通过</el-tag>
@@ -597,49 +604,76 @@
</div>
<div class="rx-rp">
<div class="rx-watermark">药房联</div>
<div class="rx-watermark">{{ prescriptionTabType === 'internal' ? '药房联' : '处方联' }}</div>
<div class="rx-rp-head">
<div class="rx-rp-label">Rp.</div>
<div class="rx-rp-cols-head">
<div class="rx-rp-col-head">
<span>用药 (单剂)</span>
<span>总量</span>
<span>{{ prescriptionTabType === 'user' ? '用量' : '总量' }}</span>
</div>
<div class="rx-rp-col-head">
<span>用药 (单剂)</span>
<span>总量</span>
<span>{{ prescriptionTabType === 'user' ? '用量' : '总量' }}</span>
</div>
</div>
</div>
<div class="rx-herbs">
<template v-if="savedMainHerbs.length">
<div class="rx-herb-section-label">主方</div>
<div
v-for="(h, i) in savedMainHerbs"
:key="'main-' + i"
class="rx-herb-cell"
>
<span class="rx-herb-name">{{ h.name }} ({{ h.dosage }})</span>
<span class="rx-herb-total">{{ rxHerbTotal(h.dosage) }}</span>
</div>
<template v-if="prescriptionTabType === 'internal'">
<template v-if="savedMainHerbs.length">
<div class="rx-herb-section-label">主方</div>
<div
v-for="(h, i) in savedMainHerbs"
:key="'main-' + i"
class="rx-herb-cell"
>
<span class="rx-herb-name">{{ h.name }} ({{ h.dosage }})</span>
<span class="rx-herb-total">{{ rxHerbTotal(h.dosage) }}</span>
</div>
</template>
<template v-if="savedAuxHerbs.length">
<div class="rx-herb-section-label rx-herb-section-label--aux">辅方</div>
<div
v-for="(h, i) in savedAuxHerbs"
:key="'aux-' + i"
class="rx-herb-cell"
>
<span class="rx-herb-name">{{ h.name }} ({{ h.dosage }})</span>
<span class="rx-herb-total">{{ rxHerbTotal(h.dosage) }}</span>
</div>
</template>
</template>
<template v-if="savedAuxHerbs.length">
<div class="rx-herb-section-label rx-herb-section-label--aux">辅方</div>
<div
v-for="(h, i) in savedAuxHerbs"
:key="'aux-' + i"
class="rx-herb-cell"
>
<span class="rx-herb-name">{{ h.name }} ({{ h.dosage }})</span>
<span class="rx-herb-total">{{ rxHerbTotal(h.dosage) }}</span>
</div>
<template v-else>
<template v-if="savedMainHerbs.length">
<div class="rx-herb-section-label">主方</div>
<div
v-for="(h, i) in savedMainHerbs"
:key="'user-main-' + i"
class="rx-herb-cell"
>
<span class="rx-herb-name">{{ h.name }}</span>
<span class="rx-herb-total">{{ h.dosage }}</span>
</div>
</template>
<template v-if="savedAuxHerbs.length">
<div class="rx-herb-section-label rx-herb-section-label--aux">辅方</div>
<div
v-for="(h, i) in savedAuxHerbs"
:key="'user-aux-' + i"
class="rx-herb-cell"
>
<span class="rx-herb-name">{{ h.name }}</span>
<span class="rx-herb-total">{{ h.dosage }}</span>
</div>
</template>
</template>
</div>
</div>
<div class="rx-text">
<p>主方服法{{ rxUsageText }}</p>
<p v-if="savedAuxUsageText">辅方服法{{ savedAuxUsageText }}</p>
<p v-if="prescriptionTabType === 'internal' || savedAuxUsageText">主方服法{{ rxUsageText }}</p>
<p v-else>服法{{ rxUsageText }}</p>
<p v-if="savedAuxUsageText">{{ prescriptionTabType === 'user' ? '辅服法' : '辅方服法' }}{{ savedAuxUsageText }}</p>
<p v-if="rxAdviceText">医嘱{{ rxAdviceText }}</p>
<p v-if="rxRemarkText">备注{{ rxRemarkText }}</p>
<p v-if="savedPrescription.dietary_taboo && savedPrescription.dietary_taboo.length">
@@ -671,18 +705,22 @@
</div>
<div class="rx-bot-cell rx-bot-meta">
<span class="rx-bot-meta-key">天数:</span>
<span class="rx-bot-meta-val">{{ savedPrescription.dose_count || '—' }}</span>
<span class="rx-bot-meta-val">{{ rxSlipMedicationDaysText }}</span>
</div>
<div class="rx-bot-cell rx-bot-meta">
<span class="rx-bot-meta-key">剂量:</span>
<span class="rx-bot-meta-key">剂量:</span>
<span class="rx-bot-meta-val">{{ rxPerDoseAmount }}</span>
</div>
</div>
<div v-if="prescriptionTabType === 'user'" class="rx-bot-row rx-hospital-row">
<div class="rx-hospital-line">成都双流甄养堂互联网医院有限公司 联系方式4001667339</div>
<div class="rx-hospital-line">地址四川省成都市双流区黄甲街道黄龙大道二段280号</div>
</div>
</div>
</div>
<!-- 详细病历 - 单独A3纸张 -->
<div v-if="savedPrescription.case_record" ref="caseRecordPrintRef" class="case-record-a3">
<div v-if="savedPrescription.case_record && !hideCaseRecordPreview" ref="caseRecordPrintRef" class="case-record-a3">
<div class="case-record-a3-inner">
<h2 class="case-record-a3-title">{{ templateConfig.stationName }} 详细病历</h2>
<div class="case-record-a3-body">
@@ -1148,6 +1186,10 @@ const signatureActivePointerId = ref<number | null>(null)
const SIGNATURE_CSS_W = 560
const SIGNATURE_CSS_H = 168
const savedPrescription = ref<any>(null)
/** 预览联次:药房联 / 处方联(与消费者处方查看一致) */
const prescriptionTabType = ref<'internal' | 'user'>('internal')
/** 诊单列表「查看」仅展示处方联,不展示详细病历 A3 */
const hideCaseRecordPreview = ref(false)
/** 已通过且未作废:与消费者处方「查看」一致,仅预览,不可作废/再开新方 */
const approvedPreviewOnly = computed(() => {
@@ -1279,38 +1321,76 @@ const rxPharmacyRemarkText = computed(() => {
return v.pharmacy_remark || v.pharmacy_note || ''
})
const rxOutPelletText = computed(() => {
/** 笺面用药天数:与 consumer/prescription/order_list 一致 */
const rxSlipMedicationDaysText = computed(() => {
const v = savedPrescription.value as any
if (!v) return ''
const out = computeRxOutPellet(v)
return out ? `${out}` : ''
if (!v) return ''
const md = v.medication_days ?? v.usage_days
if (md != null && String(md).trim() !== '') return `${md}`
const dc = v.dose_count
if (dc != null && String(dc).trim() !== '' && Number(dc) > 0) return `${dc}`
return '—'
})
function computeRxOutPellet(v: any): string {
/** 主方出丸:用药疗程 medication_days → usage_days → dose_count;出丸 = 每袋用量×袋数×每天次数×服用天数 */
const slipPillGrams = computed(() => {
const d = savedPrescription.value as any
if (!d || (d.prescription_type || '浓缩水丸') !== '浓缩水丸') return null
const days = Number(d.medication_days ?? d.usage_days ?? d.dose_count)
const times = Number(d.times_per_day)
const doseG = Number(d.dosage_amount)
const bags = Number(d.dosage_bag_count) > 0 ? Number(d.dosage_bag_count) : 1
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 * bags
})
/** 辅方出丸:公式同主方,用 aux_usage 字段 */
const slipAuxPillGrams = computed(() => {
const d = savedPrescription.value as any
if (!d || (d.prescription_type || '浓缩水丸') !== '浓缩水丸') return null
if (!savedAuxHerbs.value.length) return null
const aux = normalizeAuxUsageForm(d.aux_usage, d.prescription_type || '浓缩水丸')
const days = Number(d.medication_days ?? aux.usage_days)
const times = Number(aux.times_per_day)
const doseG = Number(aux.dosage_amount)
const bags = Number(aux.dosage_bag_count) > 0 ? Number(aux.dosage_bag_count) : 1
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 * bags
})
/** 出丸:优先 slipPillGrams + slipAuxPillGrams,否则 out_pellet / 药材总量×剂数 */
const rxOutPelletGrams = computed(() => {
const main = slipPillGrams.value
const aux = slipAuxPillGrams.value
const mainNum = typeof main === 'number' && isFinite(main) && main > 0 ? main : 0
const auxNum = typeof aux === 'number' && isFinite(aux) && aux > 0 ? aux : 0
const sum = mainNum + auxNum
if (sum > 0) return formatRxNum(sum)
const v = savedPrescription.value as any
if (!v) return ''
if ((v.prescription_type || '浓缩水丸') === '浓缩水丸') {
const days = Number(v.usage_days ?? v.dose_count)
const times = Number(v.times_per_day)
const doseG = Number(v.dosage_amount)
const bags = Number(v.dosage_bag_count) > 0 ? Number(v.dosage_bag_count) : 1
if (
Number.isFinite(days) &&
Number.isFinite(times) &&
Number.isFinite(doseG) &&
days > 0 &&
times > 0 &&
doseG > 0
) {
return formatRxNum(days * times * doseG * bags)
}
}
const explicit = v.out_pellet || v.total_weight
if (explicit && Number(explicit) > 0) return formatRxNum(Number(explicit))
const list = savedSlipHerbsList.value
if (!list.length) return ''
const perDose = list.reduce((acc: number, h: any) => acc + (Number(h?.dosage) || 0), 0)
return formatRxNum(perDose * rxDoseCount.value)
}
})
const rxOutPelletText = computed(() => {
const out = rxOutPelletGrams.value
if (!out) return ''
const main = slipPillGrams.value
const aux = slipAuxPillGrams.value
if (
typeof main === 'number' && isFinite(main) && main > 0 &&
typeof aux === 'number' && isFinite(aux) && aux > 0
) {
return `${out}克(主方 ${formatRxNum(main)}克 + 辅方 ${formatRxNum(aux)}克)`
}
return `${out}`
})
function formatRxNum(n: number): string {
if (!isFinite(n)) return '0'
@@ -1790,7 +1870,14 @@ const open = async (data: any, options?: { templateId?: number; stationName?: st
}
}
const openById = async (prescriptionId: number) => {
type OpenByIdOptions = {
/** 默认 internal;诊单列表查看传 user 展示处方联 */
slipType?: 'internal' | 'user'
/** 为 true 时不展示详细病历 A3 */
hideCaseRecord?: boolean
}
const openById = async (prescriptionId: number, options?: OpenByIdOptions) => {
// 防止重复打开
if (isOpening.value) {
console.warn('处方正在打开中,请勿重复点击')
@@ -1798,6 +1885,8 @@ const openById = async (prescriptionId: number) => {
}
isOpening.value = true
prescriptionTabType.value = options?.slipType ?? 'internal'
hideCaseRecordPreview.value = options?.hideCaseRecord ?? false
try {
const res = await prescriptionDetail({ id: prescriptionId })
@@ -1819,6 +1908,8 @@ const openById = async (prescriptionId: number) => {
const handleClose = () => {
visible.value = false
savedPrescription.value = null
prescriptionTabType.value = 'internal'
hideCaseRecordPreview.value = false
}
/**
@@ -2549,6 +2640,15 @@ defineExpose({
margin: -20px;
}
.rx-slip-tabs {
margin-bottom: 0;
z-index: 1;
position: relative;
background: #fff;
padding: 0 4px;
border-radius: 6px 6px 0 0;
}
.rx-toolbar {
display: flex;
align-items: center;
@@ -2813,6 +2913,23 @@ defineExpose({
min-height: 70px;
}
.rx-hospital-row {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: 2px;
padding: 10px 12px;
min-height: 52px;
text-align: left;
}
.rx-hospital-line {
font-size: 12px;
color: #374151;
line-height: 1.6;
}
.rx-bot-cell {
border-right: 1px solid #c8c8c8;
padding: 6px 10px;
+30 -1
View File
@@ -272,6 +272,24 @@
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="渠道来源" prop="create_source">
<el-select
v-model="formData.create_source"
placeholder="请选择渠道来源"
class="w-full"
:popper-options="{ strategy: 'fixed' }"
popper-class="high-z-index"
>
<el-option
v-for="item in createSourceOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
@@ -855,9 +873,18 @@ const formData = ref({
remark: '',
current_medications: '',
status: 1,
create_source: 'admin',
external_userid: ''
})
/** 就诊卡创建来源(与 zyt_tcm_diagnosis.create_source 一致) */
const createSourceOptions = [
{ value: '', label: '未设置' },
{ value: 'admin', label: '后台建档' },
{ value: 'mnp', label: '小程序完整建档' },
{ value: 'mnp_daily', label: '小程序手机号快捷建档' }
]
// 保存原始完整数据
const originalPhone = ref('')
const originalIdCard = ref('')
@@ -1127,6 +1154,7 @@ async function loadDiagnosisDetailIntoForm(id: number): Promise<void> {
data.id_card = maskIdCard(data.id_card || '')
formData.value = data
formData.value.create_source = data.create_source ?? ''
const y = data.diabetes_discovery_year
formData.value.diabetes_discovery_year = y == null || y === '' ? '' : String(y)
}
@@ -1215,7 +1243,7 @@ const handleSubmit = async () => {
}
const handleViewCase = (row: any) => {
prescriptionRef.value?.openById(row.id)
prescriptionRef.value?.openById(row.id, { slipType: 'user', hideCaseRecord: true })
}
// 开方:传入当前诊单数据,包含详细病历(深拷贝避免响应式引用)
@@ -1288,6 +1316,7 @@ const handleClose = () => {
remark: '',
current_medications: '',
status: 1,
create_source: 'admin',
external_userid: ''
}