This commit is contained in:
Your Name
2026-04-15 16:31:25 +08:00
parent 906684c1ed
commit 3d9c5dd8f5
47 changed files with 7963 additions and 10 deletions
+10
View File
@@ -326,6 +326,16 @@ export function prescriptionOrderComplete(params: { id: number }) {
return request.post({ url: '/tcm.prescriptionOrder/complete', params })
}
/** 甘草药管家:中药处方下单(服务端 CTM_PREVIEW → CTM_SUBMIT_RECIPEL */
export function prescriptionOrderSubmitGancaoRecipel(params: { id: number }) {
return request.post({ url: '/tcm.prescriptionOrder/submitGancaoRecipel', params })
}
/** 甘草药管家:预下单测试(仅 CTM_PREVIEW,不提交订单) */
export function prescriptionOrderPreviewGancaoRecipel(params: { id: number; dose_count?: number; medication_days?: number }) {
return request.post({ url: '/tcm.prescriptionOrder/previewGancaoRecipel', params })
}
/** 订单操作日志 */
export function prescriptionOrderLogs(params: { id: number }) {
return request.get({ url: '/tcm.prescriptionOrder/logs', params })
@@ -135,11 +135,72 @@
</el-select>
</el-form-item>
</el-col>
<!-- 用量字段 -->
<el-col :span="12">
<el-form-item label="用量" prop="dosage_amount">
<!-- 浓缩水丸1-10g 下拉选择 -->
<el-select
v-if="formData.prescription_type === '浓缩水丸'"
v-model="formData.dosage_amount"
placeholder="请选择用量"
class="!w-32"
>
<el-option :label="1 + 'g'" :value="1" />
<el-option :label="2 + 'g'" :value="2" />
<el-option :label="3 + 'g'" :value="3" />
<el-option :label="4 + 'g'" :value="4" />
<el-option :label="5 + 'g'" :value="5" />
<el-option :label="6 + 'g'" :value="6" />
<el-option :label="7 + 'g'" :value="7" />
<el-option :label="8 + 'g'" :value="8" />
<el-option :label="9 + 'g'" :value="9" />
<el-option :label="10 + 'g'" :value="10" />
</el-select>
<!-- 饮片50-250ml 下拉选择步进50 -->
<el-select
v-else-if="formData.prescription_type === '饮片'"
v-model="formData.dosage_amount"
placeholder="请选择用量"
class="!w-32"
>
<el-option label="50ml" :value="50" />
<el-option label="100ml" :value="100" />
<el-option label="150ml" :value="150" />
<el-option label="200ml" :value="200" />
<el-option label="250ml" :value="250" />
</el-select>
<!-- 其他类型自由输入 -->
<el-input-number
v-else
v-model="formData.dosage_amount"
:min="0"
:precision="2"
class="!w-32"
/>
<span v-if="formData.prescription_type !== '浓缩水丸' && formData.prescription_type !== '饮片'" class="ml-2">{{ formData.dosage_unit }}</span>
</el-form-item>
</el-col>
<!-- 饮片代煎选项 -->
<el-col v-if="formData.prescription_type === '饮片'" :span="12">
<el-form-item label="是否代煎" prop="need_decoction">
<el-radio-group v-model="formData.need_decoction">
<el-radio :label="true">代煎</el-radio>
<el-radio :label="false">不代煎</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="服用天数" prop="usage_days">
<el-input-number v-model="formData.usage_days" :min="1" :max="365" class="!w-full" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="每天几次" prop="times_per_day">
<el-input-number v-model="formData.times_per_day" :min="1" :max="10" class="!w-full" placeholder="每天服用次数" />
</el-form-item>
</el-col>
<!-- <el-col :span="8">
<el-form-item label="剂数" prop="dose_count">
<el-input-number v-model="formData.dose_count" :min="1" :max="999" class="!w-full" />
@@ -319,7 +380,7 @@
<div class="prescription-footer">
<div class="footer-left">
<div class="footer-dosage">
服用{{ savedPrescription.usage_days || savedPrescription.dose_count }}, {{ savedPrescription.prescription_type }}
服用{{ savedPrescription.usage_days || savedPrescription.dose_count }}{{ savedPrescription.times_per_day ? ',每天' + savedPrescription.times_per_day + '次' : '' }}, {{ savedPrescription.prescription_type }}
{{ savedPrescription.usage_instruction }}
</div>
@@ -577,6 +638,9 @@ interface PrescriptionForm {
appointment_id: number
prescription_name: string
prescription_type: string
dosage_amount: number | undefined // 用量数值
dosage_unit: string // 用量单位 (g 或 ml)
need_decoction: boolean // 是否代煎(仅饮片)
patient_name: string
gender: number
gender_desc: string
@@ -594,6 +658,7 @@ interface PrescriptionForm {
dose_count: number
dose_unit: string
usage_days: number
times_per_day: number
usage_instruction: string
usage_time: string
usage_way: string
@@ -653,6 +718,9 @@ const formData = reactive<PrescriptionForm>({
appointment_id: 0,
prescription_name: '',
prescription_type: '浓缩水丸',
dosage_amount: 1,
dosage_unit: 'g',
need_decoction: false,
patient_name: '',
gender: 0,
gender_desc: '女',
@@ -670,6 +738,7 @@ const formData = reactive<PrescriptionForm>({
dose_count: 1,
dose_unit: '剂',
usage_days: 7,
times_per_day: 2,
usage_instruction: '水煎服,一日二次',
usage_time: '饭前',
usage_way: '温水送服',
@@ -1054,6 +1123,23 @@ watch(showLibraryDialog, (newVal) => {
}
})
// 监听处方类型变化,自动调整用量单位和默认值
watch(() => formData.prescription_type, (newType) => {
if (newType === '浓缩水丸') {
formData.dosage_unit = 'g'
formData.dosage_amount = 1
formData.need_decoction = false
} else if (newType === '饮片') {
formData.dosage_unit = 'ml'
formData.dosage_amount = 50
// need_decoction 保持用户选择
} else {
formData.dosage_unit = 'g'
formData.dosage_amount = undefined
formData.need_decoction = false
}
})
const handleSave = async () => {
if (!formData.clinical_diagnosis?.trim()) {
feedback.msgWarning('请输入临床诊断')
@@ -1101,7 +1187,11 @@ const handleSave = async () => {
herbs: formData.herbs,
dose_count: formData.dose_count,
dose_unit: formData.dose_unit,
dosage_amount: formData.dosage_amount,
dosage_unit: formData.dosage_unit,
need_decoction: formData.need_decoction,
usage_days: formData.usage_days,
times_per_day: formData.times_per_day,
usage_instruction: formData.usage_instruction,
usage_time: formData.usage_time,
usage_way: formData.usage_way,
+243 -3
View File
@@ -576,6 +576,66 @@
<el-option label="汤剂" value="汤剂" />
</el-select>
</el-form-item> </el-col>
<!-- 用量字段 -->
<el-col :span="8">
<el-form-item label="用量" prop="dosage_amount">
<!-- 浓缩水丸:1-10g 下拉选择 -->
<el-select
v-if="editForm.prescription_type === '浓缩水丸'"
v-model="editForm.dosage_amount"
placeholder="请选择用量"
class="w-full"
>
<el-option :label="1 + 'g'" :value="1" />
<el-option :label="2 + 'g'" :value="2" />
<el-option :label="3 + 'g'" :value="3" />
<el-option :label="4 + 'g'" :value="4" />
<el-option :label="5 + 'g'" :value="5" />
<el-option :label="6 + 'g'" :value="6" />
<el-option :label="7 + 'g'" :value="7" />
<el-option :label="8 + 'g'" :value="8" />
<el-option :label="9 + 'g'" :value="9" />
<el-option :label="10 + 'g'" :value="10" />
</el-select>
<!-- 饮片:50-250ml 下拉选择,步进50 -->
<el-select
v-else-if="editForm.prescription_type === '饮片'"
v-model="editForm.dosage_amount"
placeholder="请选择用量"
class="w-full"
>
<el-option label="50ml" :value="50" />
<el-option label="100ml" :value="100" />
<el-option label="150ml" :value="150" />
<el-option label="200ml" :value="200" />
<el-option label="250ml" :value="250" />
</el-select>
<!-- 其他类型:自由输入 -->
<el-input-number
v-else
v-model="editForm.dosage_amount"
:min="0"
:precision="2"
class="w-full"
/>
</el-form-item>
</el-col>
<!-- 饮片代煎选项 -->
<el-col v-if="editForm.prescription_type === '饮片'" :span="8">
<el-form-item label="是否代煎" prop="need_decoction">
<el-radio-group v-model="editForm.need_decoction">
<el-radio :label="true">代煎</el-radio>
<el-radio :label="false">不代煎</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="每天几次" prop="times_per_day">
<el-input-number v-model="editForm.times_per_day" :min="1" :max="10" class="!w-full" placeholder="每天服用次数" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="服用天数" prop="usage_days">
<el-input-number
@@ -795,12 +855,26 @@
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="收货地址" prop="shipping_address">
<el-form-item label="省市区" prop="region">
<el-cascader
v-model="createOrderForm.region"
:options="regionOptions"
:props="{ value: 'name', label: 'name', children: 'children', emitPath: false, checkStrictly: false }"
placeholder="请选择省/市/区"
clearable
filterable
class="w-full"
@change="handleRegionChange"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="详细地址" prop="shipping_address">
<el-input
v-model="createOrderForm.shipping_address"
type="textarea"
:rows="2"
placeholder="完整收货地址"
placeholder="请输入街道、门牌号等详细地址"
maxlength="200"
show-word-limit
/>
@@ -1176,6 +1250,7 @@ const createOrderForm = reactive({
patient_id: '' as number | string,
recipient_name: '',
recipient_phone: '',
region: [] as string[],
shipping_address: '',
is_follow_up: 0,
medication_days: undefined as number | undefined,
@@ -1191,6 +1266,146 @@ const createOrderForm = reactive({
pay_order_ids: [] as number[]
})
// 省市区数据(简化版,实际项目中应该从 API 获取或使用完整的省市区数据)
const regionOptions = ref([
{
name: '四川省',
children: [
{
name: '成都市',
children: [
{ name: '锦江区' },
{ name: '青羊区' },
{ name: '金牛区' },
{ name: '武侯区' },
{ name: '成华区' },
{ name: '龙泉驿区' },
{ name: '青白江区' },
{ name: '新都区' },
{ name: '温江区' },
{ name: '双流区' },
{ name: '郫都区' },
{ name: '新津区' },
{ name: '都江堰市' },
{ name: '彭州市' },
{ name: '邛崃市' },
{ name: '崇州市' },
{ name: '简阳市' },
{ name: '金堂县' },
{ name: '大邑县' },
{ name: '蒲江县' }
]
},
{
name: '绵阳市',
children: [
{ name: '涪城区' },
{ name: '游仙区' },
{ name: '安州区' },
{ name: '江油市' },
{ name: '三台县' },
{ name: '盐亭县' },
{ name: '梓潼县' },
{ name: '北川羌族自治县' },
{ name: '平武县' }
]
}
]
},
{
name: '北京市',
children: [
{
name: '北京市',
children: [
{ name: '东城区' },
{ name: '西城区' },
{ name: '朝阳区' },
{ name: '丰台区' },
{ name: '石景山区' },
{ name: '海淀区' },
{ name: '门头沟区' },
{ name: '房山区' },
{ name: '通州区' },
{ name: '顺义区' },
{ name: '昌平区' },
{ name: '大兴区' },
{ name: '怀柔区' },
{ name: '平谷区' },
{ name: '密云区' },
{ name: '延庆区' }
]
}
]
},
{
name: '上海市',
children: [
{
name: '上海市',
children: [
{ name: '黄浦区' },
{ name: '徐汇区' },
{ name: '长宁区' },
{ name: '静安区' },
{ name: '普陀区' },
{ name: '虹口区' },
{ name: '杨浦区' },
{ name: '闵行区' },
{ name: '宝山区' },
{ name: '嘉定区' },
{ name: '浦东新区' },
{ name: '金山区' },
{ name: '松江区' },
{ name: '青浦区' },
{ name: '奉贤区' },
{ name: '崇明区' }
]
}
]
},
{
name: '广东省',
children: [
{
name: '广州市',
children: [
{ name: '荔湾区' },
{ name: '越秀区' },
{ name: '海珠区' },
{ name: '天河区' },
{ name: '白云区' },
{ name: '黄埔区' },
{ name: '番禺区' },
{ name: '花都区' },
{ name: '南沙区' },
{ name: '从化区' },
{ name: '增城区' }
]
},
{
name: '深圳市',
children: [
{ name: '罗湖区' },
{ name: '福田区' },
{ name: '南山区' },
{ name: '宝安区' },
{ name: '龙岗区' },
{ name: '盐田区' },
{ name: '龙华区' },
{ name: '坪山区' },
{ name: '光明区' }
]
}
]
}
])
// 处理省市区选择变化
const handleRegionChange = (value: string[]) => {
console.log('选择的省市区:', value)
}
const createOrderLinkedPaidTotal = computed(() => {
const ids = new Set(createOrderForm.pay_order_ids.map((x) => Number(x)))
let s = 0
@@ -1454,6 +1669,9 @@ const slipDietaryText = computed(() => {
const editForm = reactive({
id: 0,
prescription_type: '浓缩水丸',
dosage_amount: 1 as number | undefined,
dosage_unit: 'g',
need_decoction: false,
patient_name: '',
gender: 1,
age: 0,
@@ -1483,7 +1701,25 @@ const editForm = reactive({
diagnosis_id: 0,
/** 列表带入:业务订单「处方审核」驳回(消费者处方本身可能仍为已通过) */
business_prescription_audit_rejected: 0,
business_prescription_audit_remark: ''
business_prescription_audit_remark: '',
times_per_day: 2
})
// 监听处方类型变化,自动调整用量单位和默认值
watch(() => editForm.prescription_type, (newType) => {
if (newType === '浓缩水丸') {
editForm.dosage_unit = 'g'
editForm.dosage_amount = 1
editForm.need_decoction = false
} else if (newType === '饮片') {
editForm.dosage_unit = 'ml'
editForm.dosage_amount = 50
// need_decoction 保持用户选择
} else {
editForm.dosage_unit = 'g'
editForm.dosage_amount = undefined
editForm.need_decoction = false
}
})
// 表单验证规则
@@ -1863,6 +2099,9 @@ const handleEdit = (row: any) => {
// 深拷贝数据到表单
editForm.id = row.id
editForm.prescription_type = row.prescription_type || '浓缩水丸'
editForm.dosage_amount = row.dosage_amount ?? undefined
editForm.dosage_unit = row.dosage_unit || ''
editForm.need_decoction = row.need_decoction === 1 || row.need_decoction === true
editForm.patient_name = row.patient_name || ''
editForm.gender = row.gender ?? 1
editForm.age = row.age ?? 0
@@ -1877,6 +2116,7 @@ const handleEdit = (row: any) => {
editForm.dose_count = row.dose_count ?? 7
editForm.dose_unit = row.dose_unit || '剂'
editForm.usage_days = row.usage_days ?? 7
editForm.times_per_day = row.times_per_day ?? 2
editForm.usage_instruction = row.usage_instruction || '水煎服,一日二次'
editForm.usage_time = row.usage_time || '饭前'
editForm.usage_way = row.usage_way || '温水送服'
@@ -184,6 +184,14 @@
link
@click="confirmWithdraw(row)"
>撤回</el-button>
<el-button
v-if="canUploadGancaoRow(row)"
v-perms="['tcm.prescriptionOrder/submitGancaoRecipel']"
type="warning"
link
:loading="gancaoSubmitId === row.id"
@click="confirmSubmitGancaoRecipel(row)"
>上传药方</el-button>
</div>
</template>
</el-table-column>
@@ -206,6 +214,13 @@
<div class="flex items-center">
<span class="po-detail-drawer-title text-gray-800 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>
<el-tag
v-if="detailData?.gancao_reciperl_order_no"
type="success"
effect="plain"
round
class="ml-2"
>甘草 {{ detailData.gancao_reciperl_order_no }}</el-tag>
</div>
<div v-if="detailData" class="flex items-center gap-2 mr-6">
<el-button
@@ -364,6 +379,17 @@
>
详细
</el-button>
<el-button
v-if="detailData.id"
type="warning"
size="small"
link
:loading="gancaoPreviewLoading"
:icon="Search"
@click="testGancaoPreviewFromDetail"
>
测试价格
</el-button>
</div>
<span class="text-xs text-gray-400">ID: {{ detailData.prescription_id || '—' }}</span>
</div>
@@ -391,7 +417,7 @@
{{ detailPrescription.clinical_diagnosis || '—' }}
</el-descriptions-item>
<el-descriptions-item label="剂数 / 用法" :span="2">
{{ detailPrescription.dose_count ?? '—' }} ·
{{ detailData.dose_count ?? detailPrescription.dose_count ?? '—' }} {{ detailData.dose_unit || '剂' }} ·
{{ detailPrescription.usage_instruction || detailPrescription.usage_method || '—' }}
</el-descriptions-item>
<el-descriptions-item label="处方金额">
@@ -402,6 +428,23 @@
{{ consumerRxAuditText(detailPrescription.audit_status) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="用量">
<template v-if="detailPrescription.dosage_amount">
{{ detailPrescription.dosage_amount }}{{ detailPrescription.dosage_unit || 'g' }}
<span v-if="detailPrescription.prescription_type === '饮片' && detailPrescription.need_decoction !== null" class="ml-2 text-gray-500">
({{ detailPrescription.need_decoction ? '代煎' : '不代煎' }})
</span>
</template>
<template v-else></template>
</el-descriptions-item>
<el-descriptions-item label="服用方式">
<template v-if="detailPrescription.usage_days || detailPrescription.times_per_day">
<span v-if="detailPrescription.usage_days">服用{{ detailPrescription.usage_days }}</span>
<span v-if="detailPrescription.usage_days && detailPrescription.times_per_day"></span>
<span v-if="detailPrescription.times_per_day">每天{{ detailPrescription.times_per_day }}</span>
</template>
<template v-else></template>
</el-descriptions-item>
<el-descriptions-item label="状态" :span="2">
<el-tag :type="Number(detailPrescription.void_status) === 1 ? 'danger' : 'success'" size="small">
{{ Number(detailPrescription.void_status) === 1 ? '已作废' : '正常' }}
@@ -710,7 +753,17 @@
</el-col>
</el-row>
<el-form-item label="收货地址" prop="shipping_address">
<el-form-item label="省/市/区" prop="region">
<el-cascader
v-model="editForm.region"
:options="regionOptions"
placeholder="请选择省/市/区"
clearable
class="w-full"
/>
</el-form-item>
<el-form-item label="详细地址" prop="shipping_address">
<el-input v-model="editForm.shipping_address" type="textarea" :rows="2" maxlength="500" show-word-limit />
</el-form-item>
@@ -722,7 +775,55 @@
</el-col>
<el-col :span="12">
<el-form-item label="用药疗程">
<el-input-number v-model="editForm.medication_days" :min="1" :max="999" :step="1" class="w-full" placeholder="天数(选填)" />
<el-input-number v-model="editForm.medication_days" :min="1" :max="999" :step="1" class="w-full" placeholder="天数(选填)">
<template #append></template>
</el-input-number>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="剂数" prop="dose_count">
<el-input-number
v-model="editForm.dose_count"
:min="1"
placeholder="剂数"
class="w-full"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="剂量单位" prop="dose_unit">
<el-select v-model="editForm.dose_unit" placeholder="请选择" class="w-full">
<el-option label="剂" value="剂" />
<el-option label="丸" value="丸" />
<el-option label="袋" value="袋" />
<el-option label="盒" value="盒" />
<el-option label="瓶" value="瓶" />
<el-option label="膏" value="膏" />
<el-option label="贴" value="贴" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 甘草预下单测试按钮 -->
<el-row v-if="editForm.id" :gutter="24">
<el-col :span="24">
<el-form-item label="甘草预下单">
<el-button
type="primary"
plain
:loading="gancaoPreviewLoading"
:icon="Search"
@click="testGancaoPreview"
>
测试价格
</el-button>
<span class="ml-3 text-xs text-gray-400">
测试当前配置的甘草预下单价格不会真实提交订单
</span>
</el-form-item>
</el-col>
</el-row>
@@ -1194,12 +1295,142 @@
</div>
</div>
</el-drawer>
<!-- 甘草预下单结果抽屉 -->
<el-drawer
v-model="gancaoPreviewDrawerVisible"
title="甘草预下单测试结果"
size="800px"
destroy-on-close
>
<div v-if="gancaoPreviewData" class="px-4">
<!-- 价格信息 -->
<el-card shadow="never" class="mb-4">
<template #header>
<div class="flex items-center justify-between">
<span class="font-semibold">价格信息</span>
<el-tag type="success">预下单成功</el-tag>
</div>
</template>
<el-descriptions :column="2" border>
<el-descriptions-item label="药材成本">
<span class="text-lg font-semibold text-orange-600">¥{{ gancaoPreviewData.fee?.m_cost || '0.00' }}</span>
</el-descriptions-item>
<el-descriptions-item label="制作费">
<span class="text-lg font-semibold text-blue-600">¥{{ ((gancaoPreviewData.fee?.proces_cost || 0) ).toFixed(2) }}</span>
</el-descriptions-item>
<el-descriptions-item label="物流费">
<span class="text-lg font-semibold text-green-600">¥{{ ((gancaoPreviewData.fee?.lis_cost || 0) ).toFixed(2) }}</span>
</el-descriptions-item>
<el-descriptions-item label="总计">
<span class="text-xl font-bold text-red-600">
¥{{ calculateTotalFee(gancaoPreviewData.fee) }}
</span>
</el-descriptions-item>
</el-descriptions>
</el-card>
<!-- 配送信息 -->
<el-card shadow="never" class="mb-4">
<template #header>
<span class="font-semibold">配送信息</span>
</template>
<el-descriptions :column="2" border>
<el-descriptions-item label="调配中心">
{{ gancaoPreviewData.result?.ds_name || '—' }}
</el-descriptions-item>
<el-descriptions-item label="调配中心ID">
{{ gancaoPreviewData.result?.ds_id || '—' }}
</el-descriptions-item>
<el-descriptions-item label="服用天数范围" :span="2">
{{ gancaoPreviewData.result?.take_days?.min || '—' }} -
{{ gancaoPreviewData.result?.take_days?.max || '—' }}
默认: {{ gancaoPreviewData.result?.take_days?.default || '—' }}
</el-descriptions-item>
</el-descriptions>
</el-card>
<!-- 规则检查/医嘱备注 -->
<el-card v-if="gancaoPreviewData.result?.rule_check?.length" shadow="never" class="mb-4">
<template #header>
<span class="font-semibold">医嘱备注</span>
</template>
<div class="text-sm text-gray-700 leading-relaxed">
{{ gancaoPreviewData.result.rule_check.map(r => r.msg).join(' ') }}
</div>
</el-card>
<!-- 药材明细 -->
<el-card shadow="never">
<template #header>
<div class="flex items-center justify-between">
<span class="font-semibold">药材明细</span>
<span class="text-sm text-gray-500"> {{ gancaoPreviewData.result?.m_list?.length || 0 }} 味药</span>
</div>
</template>
<el-table
:data="gancaoPreviewData.result?.m_list || []"
border
stripe
max-height="400"
>
<el-table-column type="index" label="#" width="50" align="center" />
<el-table-column prop="title" label="药材名称" min-width="120" show-overflow-tooltip />
<el-table-column prop="quantity" label="用量" width="80" align="right">
<template #default="{ row }">
{{ row.quantity }}{{ row.unit }}
</template>
</el-table-column>
<el-table-column prop="price" label="单价(元/克)" width="110" align="right">
<template #default="{ row }">
¥{{ Number(row.price).toFixed(4) }}
</template>
</el-table-column>
<el-table-column label="小计" width="100" align="right">
<template #default="{ row }">
<span class="font-medium text-orange-600">
¥{{ (Number(row.price) * Number(row.quantity)).toFixed(2) }}
</span>
</template>
</el-table-column>
<el-table-column prop="is_available" label="库存状态" width="100" align="center">
<template #default="{ row }">
<el-tag :type="row.is_available === 1 ? 'success' : 'danger'" size="small">
{{ row.is_available === 1 ? '有货' : '缺货' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="brief" label="备注" min-width="120" show-overflow-tooltip />
</el-table>
</el-card>
<!-- 订单信息 -->
<el-card shadow="never" class="mt-4">
<template #header>
<span class="font-semibold">订单信息</span>
</template>
<el-descriptions :column="2" border>
<el-descriptions-item label="订单号" :span="2">
{{ gancaoPreviewData.order_no || '—' }}
</el-descriptions-item>
<el-descriptions-item label="剂数">
<span class="text-base font-medium">{{ gancaoPreviewData.dose_count || '—' }}</span>
</el-descriptions-item>
<el-descriptions-item label="单剂量">
<span class="text-base font-medium">
{{ calculateSingleDoseWeight(gancaoPreviewData.result?.m_list) }}
</span>
</el-descriptions-item>
</el-descriptions>
</el-card>
</div>
</el-drawer>
</div>
</template>
<script lang="ts" setup name="prescriptionOrderList">
import { computed, onMounted, reactive, ref, nextTick } from 'vue'
import { Refresh, Loading, ArrowDown, InfoFilled } from '@element-plus/icons-vue'
import { Refresh, Loading, ArrowDown, InfoFilled, Search } from '@element-plus/icons-vue'
import {
prescriptionOrderAuditPayment,
prescriptionOrderAuditPrescription,
@@ -1216,6 +1447,8 @@ import {
prescriptionOrderRevokeRxAudit,
prescriptionOrderRevokePayAudit,
prescriptionOrderLinkPayOrder,
prescriptionOrderSubmitGancaoRecipel,
prescriptionOrderPreviewGancaoRecipel,
prescriptionDetail
} from '@/api/tcm'
import { usePaging } from '@/hooks/usePaging'
@@ -1238,6 +1471,92 @@ const canViewFinanceFields = () => {
return FINANCE_ROLE_IDS.some((rid) => ids.includes(rid))
}
// 省市区数据
const regionOptions = [
{
value: '四川省',
label: '四川省',
children: [
{
value: '成都市',
label: '成都市',
children: [
{ value: '武侯区', label: '武侯区' },
{ value: '锦江区', label: '锦江区' },
{ value: '青羊区', label: '青羊区' },
{ value: '金牛区', label: '金牛区' },
{ value: '成华区', label: '成华区' },
{ value: '高新区', label: '高新区' }
]
},
{
value: '绵阳市',
label: '绵阳市',
children: [
{ value: '涪城区', label: '涪城区' },
{ value: '游仙区', label: '游仙区' }
]
}
]
},
{
value: '北京市',
label: '北京市',
children: [
{
value: '北京市',
label: '北京市',
children: [
{ value: '朝阳区', label: '朝阳区' },
{ value: '海淀区', label: '海淀区' },
{ value: '东城区', label: '东城区' },
{ value: '西城区', label: '西城区' }
]
}
]
},
{
value: '上海市',
label: '上海市',
children: [
{
value: '上海市',
label: '上海市',
children: [
{ value: '浦东新区', label: '浦东新区' },
{ value: '黄浦区', label: '黄浦区' },
{ value: '徐汇区', label: '徐汇区' },
{ value: '静安区', label: '静安区' }
]
}
]
},
{
value: '广东省',
label: '广东省',
children: [
{
value: '广州市',
label: '广州市',
children: [
{ value: '天河区', label: '天河区' },
{ value: '越秀区', label: '越秀区' },
{ value: '海珠区', label: '海珠区' }
]
},
{
value: '深圳市',
label: '深圳市',
children: [
{ value: '南山区', label: '南山区' },
{ value: '福田区', label: '福田区' },
{ value: '罗湖区', label: '罗湖区' }
]
}
]
}
]
const queryParams = reactive({
order_no: '',
prescription_id: '' as string | number,
@@ -1403,6 +1722,16 @@ function canQuickTrackRow(row: { fulfillment_status?: number }) {
return Number(row.fulfillment_status) === 5
}
function canUploadGancaoRow(row: {
prescription_audit_status?: number
gancao_reciperl_order_no?: string
}) {
// 处方审核已通过(1) 且没有甘草订单号时才显示
const rxStatus = Number(row.prescription_audit_status)
const gancaoOrderNo = String(row.gancao_reciperl_order_no || '').trim()
return rxStatus === 1 && gancaoOrderNo === ''
}
function orderStatusText(s: number | undefined) {
const m: Record<number, string> = {
1: '待支付',
@@ -1666,9 +1995,12 @@ const editForm = reactive({
diagnosis_id: 0,
recipient_name: '',
recipient_phone: '',
region: [] as string[],
shipping_address: '',
is_follow_up: 0,
medication_days: undefined as number | string | undefined,
dose_count: 1,
dose_unit: '剂',
prev_staff: '',
service_channel: '',
service_package: '',
@@ -1773,9 +2105,22 @@ async function openEdit(row: { id: number }) {
editForm.diagnosis_id = Number(d.diagnosis_id) || 0
editForm.recipient_name = d.recipient_name || ''
editForm.recipient_phone = d.recipient_phone || ''
// 填充省市区字段
const province = d.shipping_province || ''
const city = d.shipping_city || ''
const district = d.shipping_district || ''
if (province || city || district) {
editForm.region = [province, city, district].filter(v => v !== '')
} else {
editForm.region = []
}
editForm.shipping_address = d.shipping_address || ''
editForm.is_follow_up = d.is_follow_up ? 1 : 0
editForm.medication_days = d.medication_days > 0 ? d.medication_days : undefined
editForm.dose_count = d.dose_count > 0 ? d.dose_count : 1
editForm.dose_unit = d.dose_unit || '剂'
editForm.prev_staff = d.prev_staff || ''
editForm.service_channel = d.service_channel || ''
editForm.service_package = d.service_package || ''
@@ -1836,9 +2181,22 @@ async function submitEdit() {
// BUG FIX: 修复之前无法清空部分选填字段的问题
medication_days: (editForm.medication_days != null && String(editForm.medication_days).trim() !== '') ? editForm.medication_days : '',
dose_unit: editForm.dose_unit || '剂',
dose_count: editForm.dose_count || 1,
internal_cost: (editForm.internal_cost != null && String(editForm.internal_cost).trim() !== '') ? editForm.internal_cost : '',
}
// 添加省市区字段
if (editForm.region && editForm.region.length > 0) {
payload.shipping_province = editForm.region[0] || ''
payload.shipping_city = editForm.region[1] || ''
payload.shipping_district = editForm.region[2] || ''
} else {
payload.shipping_province = ''
payload.shipping_city = ''
payload.shipping_district = ''
}
payload.pay_order_ids = [...editForm.pay_order_ids]
await prescriptionOrderEdit(payload)
@@ -1923,6 +2281,121 @@ async function confirmWithdraw(row: { id: number }) {
}
}
const gancaoSubmitId = ref(0)
const gancaoPreviewDrawerVisible = ref(false)
const gancaoPreviewLoading = ref(false)
const gancaoPreviewData = ref<any>(null)
// 计算总费用
function calculateTotalFee(fee: any) {
if (!fee) return '0.00'
const mCost = Number(fee.m_cost) || 0
const procesCost = (Number(fee.proces_cost) || 0)
const lisCost = (Number(fee.lis_cost) || 0)
return (mCost + procesCost + lisCost).toFixed(2)
}
// 计算单剂量(所有药材用量总和)
function calculateSingleDoseWeight(mList: any[]) {
if (!Array.isArray(mList) || mList.length === 0) return '0'
const total = mList.reduce((sum, item) => {
return sum + (Number(item.quantity) || 0)
}, 0)
return total.toFixed(0)
}
async function testGancaoPreview() {
if (!editForm.id) {
feedback.msgError('请先保存订单')
return
}
gancaoPreviewLoading.value = true
try {
const res: any = await prescriptionOrderPreviewGancaoRecipel({
id: editForm.id,
dose_count: editForm.dose_count || 1,
medication_days: editForm.medication_days || undefined
})
const d = res?.data ?? res
if (d && d.success) {
gancaoPreviewData.value = d
gancaoPreviewDrawerVisible.value = true
feedback.msgSuccess('预下单测试成功')
} else {
feedback.msgError(d?.error || '预下单失败')
}
} catch (e: any) {
feedback.msgError(e?.message || '预下单失败')
} finally {
gancaoPreviewLoading.value = false
}
}
// 从详情页测试甘草价格
async function testGancaoPreviewFromDetail() {
if (!detailData.value?.id) {
feedback.msgError('订单数据不存在')
return
}
gancaoPreviewLoading.value = true
try {
const res: any = await prescriptionOrderPreviewGancaoRecipel({
id: detailData.value.id,
dose_count: detailData.value.dose_count || 1,
medication_days: detailData.value.medication_days || undefined
})
const d = res?.data ?? res
if (d && d.success) {
gancaoPreviewData.value = d
gancaoPreviewDrawerVisible.value = true
feedback.msgSuccess('预下单测试成功')
} else {
feedback.msgError(d?.error || '预下单失败')
}
} catch (e: any) {
feedback.msgError(e?.message || '预下单失败')
} finally {
gancaoPreviewLoading.value = false
}
}
async function confirmSubmitGancaoRecipel(row: { id: number }) {
try {
await ElMessageBox.confirm(
'将把本单关联处方提交至甘草药管家开放平台(先 CTM_PREVIEW 预检查再 CTM_SUBMIT_RECIPEL 正式下单;成功后将按甘草侧规则扣费,详见 https://apidoc.igancao.com/service-doc/scm-outer-recipel.html )。确定继续?',
'上传甘草药方',
{ type: 'warning', confirmButtonText: '确定上传', cancelButtonText: '取消' }
)
gancaoSubmitId.value = row.id
const res: any = await prescriptionOrderSubmitGancaoRecipel({ id: row.id })
const d = res?.data ?? res
const no = d?.recipel_order_no != null ? String(d.recipel_order_no) : ''
feedback.msgSuccess(no ? `上传成功,甘草处方单号:${no}` : '上传成功')
getLists()
if (detailVisible.value && Number(detailData.value?.id) === row.id) {
try {
const r: any = await prescriptionOrderDetail({ id: row.id })
const dd = r?.data ?? r ?? null
if (dd) detailData.value = dd
} catch {
/* 静默 */
}
}
} catch (e: any) {
if (e !== 'cancel' && e !== 'close') {
/* 拦截器已提示 */
}
} finally {
gancaoSubmitId.value = 0
}
}
onMounted(() => {
getLists()
})