hn-hlw-pc/src/views/hlw-drug-manage/drug-detail-drawer.vue
huxuejian 5b316c61b0 feat: 需求调整
1.  电子处方笺 签章调整
2.  门店医保处方支持打印
3.  药品详情支持同步his功能
2026-09-20 17:32:57 +08:00

274 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-drawer v-loading="loading" :close-on-click-modal="false" :model-value="visible" title="药品详情" size="70%"
style="--el-drawer-padding-primary: 0" @close="close">
<my-layout>
<layout-main>
<el-form :label-width="140" label-suffix=":" class="p-15px pr-30px"
:class="loading ? 'pointer-events-none' : ''">
<div active-title-bar class="my-2.5">药品基本信息</div>
<el-row>
<el-col :span="12" v-for="item in basicInfoList" :key="item.prop">
<el-form-item class="mb-5px" :label="item.label" :prop="item.prop"
:class="requiredMap[item.prop] ? 'is-required' : ''">
{{ item.format ? item.format(form[item.prop]) : form[item.prop] }}
</el-form-item>
</el-col>
</el-row>
<div active-title-bar class="my-2.5">药品标准用法用量</div>
<el-row>
<el-col :span="12" v-for="item in usageInfo" :key="item.prop">
<el-form-item class="mb-5px" :label="item.label" :prop="item.prop"
:class="requiredMap[item.prop] ? 'is-required' : ''">
{{ form[item.prop] }}
</el-form-item>
</el-col>
</el-row>
<div active-title-bar class="my-2.5">药品规则配置</div>
<el-row>
<el-col :span="24">
<el-form-item class="mb-5px" label="适应诊断">
<span v-if="diagnosisLoading">加载中...</span>
<span v-else>{{ diagnosisText || '-' }}</span>
</el-form-item>
</el-col>
</el-row>
<div active-title-bar class="my-2.5">药品维护记录</div>
<el-row>
<el-col :span="12" v-for="item in maintenanceInfo" :key="item.prop">
<el-form-item class="mb-5px" :label="item.label" :prop="item.prop"
:class="requiredMap[item.prop] ? 'is-required' : ''">
{{ form[item.prop] }}
</el-form-item>
</el-col>
</el-row>
</el-form>
</layout-main>
<layout-item>
<div common-shadow--r class="text-center py-10px">
<el-button plain type="primary" class="w-100px" @click="close()">取消</el-button>
<el-button :type="data.onSale ? 'info' : 'success'" class="w-100px" @click="setOnSale()">
{{ data.onSale ? '下架' : '上架' }}
</el-button>
<el-button v-if="libType === 'hlw'" type="warning" class="w-100px" :loading="syncingHis" @click="syncHis">
同步 HIS
</el-button>
<el-button type="primary" class="w-100px" @click="edit()">编辑</el-button>
<!-- <el-button class="w-100px" :loading="loading" type="primary" @click="save()">保存</el-button> -->
</div>
</layout-item>
</my-layout>
</el-drawer>
</template>
<script setup>
import { computed, ref, watch } from 'vue';
import { storeToRefs } from "pinia";
import { ElMessage, ElMessageBox } from "element-plus";
import dayjs from "dayjs";
import { setHlwDrugOnSale, setOnlineDrugOnSale, getHlwDiagnosisList, updateHisDrugInfo } from "@/api/hlw";
import { getDrugFieldDict } from './drug-dict.js'
import { memberStore } from "@/store/member";
import MyLayout, { LayoutMain, LayoutItem } from "@/components/layout";
const antibioticLevelMap = { 0: '0 (无)', 1: '1 (非限制使用级)', 2: '2 (限制使用级)', 3: '3 (特殊使用级)' };
const tumorUseMap = { 0: '0 (无)', 1: '1 (免疫)', 2: '2 (普通)', 3: '3 (限制)' };
const emits = defineEmits(['close', 'edit', 'changeSale'])
const props = defineProps({
visible: {
type: Boolean,
default: false
},
// 库类型:hlw = 互联网医院药品库(drug-info),online = 配送/线上药品库(online-drug-info)
libType: {
type: String,
default: 'hlw'
},
data: {
type: Object,
default: () => ({})
}
})
const { memberInfo } = storeToRefs(memberStore());
const basicInfo = [
{ label: '药品名称', prop: "name" },
{ label: '药品规格', prop: "specification" },
{ label: '包装单位', prop: "unit" },
{ label: '包装量', prop: "package_amount" },
{ label: '生产厂家', prop: "manufacturer" },
{ label: '商品条形码', prop: "barcode" },
{ label: '医保编码', prop: "insurance_code" },
{ label: '药品类型', prop: "category" },
{ label: '药品拼音码', prop: "pinyin_code" },
{ label: '通用名', prop: "generic_name" },
{ label: '通用名拼音码', prop: "generic_pinyin" },
{ label: '抗生素级别', prop: "antibiotic_level", format: value => antibioticLevelMap[value] ?? '0 (无)' },
{ label: '肿瘤使用', prop: "tumor_use", format: value => tumorUseMap[value] ?? '0 (无)' },
]
// 在线药品库扩展展示字段:管理分类 + 剂型
const onlineBasicInfoExtra = [
{ label: '管理分类', prop: "manage_category" },
{ label: '剂型', prop: "dosage_form" },
{ label: 'hisID', prop: "his_drug_code" },
]
const basicInfoList = computed(() => {
const idField = props.libType === 'online'
? { label: '药库货品ID', prop: "product_id" }
: { label: 'ERP ID', prop: "erpId" };
const fields = [...basicInfo.slice(0, 9), idField, ...basicInfo.slice(9)];
return props.libType === 'online' ? [...fields, ...onlineBasicInfoExtra] : fields;
})
const usageInfo = [
{ label: '单次标准剂量', prop: "dosage" },
{ label: '剂量单位', prop: "dosage_unit" },
{ label: '给药标准频次', prop: "frequency" },
{ label: '给药标准方式', prop: "administration_method" },
{ label: '用药标准天数', prop: "days" },
{ label: '发药标准数量', prop: "recommended_quantity" },
]
const maintenanceInfo = [
{ label: '平台ID', prop: "_id" },
{ label: '当前状态', prop: "onSale" },
{ label: '创建时间', prop: "createTime" },
{ label: '创建人', prop: "creator" },
{ label: '最近更新时间', prop: "updateTime" },
{ label: '最近更新人', prop: "updater" },
]
const otherInfo = [
{ label: '适用性别', prop: 'suitableGender' },
{ label: '是否儿童用药', prop: 'suitableChild' },
{ label: '重复用药标识', prop: 'repeatTag' },
]
const requiredMap = computed(() => getDrugFieldDict(props.libType).reduce((m, cur) => {
m[cur.field] = typeof cur.required === 'boolean' ? cur.required : false
return m
}, {}))
const showForm = computed(() => {
const genderMap = { common: '通用', male: '男', female: '女' };
let repeatTag = props.data.repeatTag;
if (Array.isArray(repeatTag)) {
repeatTag = repeatTag.join(',');
}
return {
onSale: props.data.onSale ? '已上架' : '已下架',
createTime: props.data.createTime && dayjs(props.data.createTime).isValid() ? dayjs(props.data.createTime).format('YYYY-MM-DD HH:mm:ss') : '',
updateTime: props.data.updateTime && dayjs(props.data.updateTime).isValid() ? dayjs(props.data.updateTime).format('YYYY-MM-DD HH:mm:ss') : '',
// 如果存在描述文本,则认为为“是”,并展示描述;否则为“否”。保持与编辑抽屉的语义一致。
need_medication_proof: props.data.medication_proof_desc ? `是(${props.data.medication_proof_desc})` : '否',
has_usage_restriction: props.data.usage_restriction_desc ? `是(${props.data.usage_restriction_desc})` : '否',
suitableGender: genderMap[props.data.suitableGender] || props.data.suitableGender,
suitableChild: props.data.suitableChild ? '是' : '否',
repeatTag,
}
})
const form = computed(() => ({ ...props.data, ...showForm.value }))
const loading = ref(false)
const syncingHis = ref(false)
const diagnosisLoading = ref(false)
const diagnosisList = ref([])
let diagnosisRequestId = 0
const diagnosisText = computed(() => diagnosisList.value
.map(item => item.code ? `${item.name}(${item.code})` : item.name)
.filter(Boolean)
.join('、'))
async function loadDiagnoses() {
const requestId = ++diagnosisRequestId;
const codes = Array.isArray(props.data.applicableDiagnosisCodes)
? props.data.applicableDiagnosisCodes.map(code => String(code))
: [];
diagnosisList.value = [];
if (!codes.length) return;
diagnosisLoading.value = true;
const res = await getHlwDiagnosisList({ codes, page: 1, pageSize: Math.max(30, codes.length) });
if (requestId !== diagnosisRequestId) return;
diagnosisLoading.value = false;
if (res.success) {
const list = res.data && Array.isArray(res.data.data) ? res.data.data : [];
const diagnosisMap = new Map(list.map(item => [String(item.code), item]));
diagnosisList.value = codes.map(code => diagnosisMap.get(code)).filter(Boolean);
} else {
ElMessage.error(res.message || '适应诊断加载失败');
}
}
function close() {
if (loading.value) return;
emits('close', false)
}
function edit() {
if (loading.value) return;
close()
emits('edit')
}
async function setOnSale() {
await ElMessageBox.confirm(`确定${props.data.onSale ? '下架' : '上架'}药品吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
});
const onSale = !props.data.onSale;
const isOnline = props.libType === 'online';
const { success, message } = await (isOnline
? setOnlineDrugOnSale({
ids: [props.data._id],
onSale,
updater: memberInfo.value.anotherName,
updaterId: memberInfo.value._id,
})
: setHlwDrugOnSale({
ids: [props.data._id],
onSale,
updater: memberInfo.value.anotherName,
updaterId: memberInfo.value._id,
}));
if (success) {
ElMessage.success(message);
emits('changeSale', onSale)
} else {
ElMessage.error(message);
}
}
async function syncHis() {
if (!props.data._id || syncingHis.value) return;
syncingHis.value = true;
try {
const { success, message } = await updateHisDrugInfo({ id: props.data._id });
if (success) {
ElMessage.success(message || '同步 HIS 成功');
} else {
ElMessage.error(message || '同步 HIS 失败');
}
} catch (error) {
ElMessage.error(error?.message || '同步 HIS 失败');
} finally {
syncingHis.value = false;
}
}
watch(() => props.visible, (visible) => {
if (visible) {
loadDiagnoses();
} else {
diagnosisRequestId += 1;
diagnosisLoading.value = false;
}
});
</script>