2026-07-27 11:32:24 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<el-drawer v-loading="loading" :close-on-click-modal="false" :model-value="visible"
|
|
|
|
|
|
:title="data._id ? '编辑药品' : '新增药品'" size="70%" style="--el-drawer-padding-primary: 0" @close="close">
|
|
|
|
|
|
<my-layout>
|
|
|
|
|
|
<layout-main>
|
|
|
|
|
|
<el-form :label-width="140" :model="taskForm" label-suffix=":" class="p-15px pr-30px"
|
|
|
|
|
|
:class="loading ? 'pointer-events-none' : ''">
|
|
|
|
|
|
<div active-title-bar class="mb-2.5">药品基本信息</div>
|
|
|
|
|
|
<el-row>
|
|
|
|
|
|
<el-col :span="12" v-for="item in basicInfoList" :key="item.prop">
|
|
|
|
|
|
<el-form-item :label="item.label" :prop="item.prop" :class="requiredMap[item.prop] ? 'is-required' : ''">
|
|
|
|
|
|
<el-select v-if="item.options" filterable clearable :model-value="form[item.prop]"
|
|
|
|
|
|
:placeholder="`请选择${item.label}`" class="w-full" @update:model-value="changeValue($event, item.prop)">
|
|
|
|
|
|
<el-option v-for="option in item.options" :key="option" :label="option" :value="option" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
<el-input v-else clearable :model-value="form[item.prop]" :maxlength="item.maxlength"
|
|
|
|
|
|
:placeholder="`请输入${item.label}`" @update:model-value="changeValue($event, item.prop)" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
<div active-title-bar class="mb-2.5">药品标准用法用量</div>
|
|
|
|
|
|
<el-row>
|
|
|
|
|
|
<el-col :span="12" v-for="item in usageInfo" :key="item.prop">
|
|
|
|
|
|
<el-form-item :label="item.label" :prop="item.prop" :class="requiredMap[item.prop] ? 'is-required' : ''">
|
|
|
|
|
|
<el-select v-if="item.options" filterable clearable :model-value="form[item.prop]"
|
|
|
|
|
|
:placeholder="`请选择${item.label}`" class="w-full" @update:model-value="changeValue($event, item.prop)">
|
|
|
|
|
|
<el-option v-for="option in item.options" :key="option" :label="option" :value="option" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
<el-input v-else clearable :model-value="form[item.prop]" :maxlength="item.maxlength"
|
|
|
|
|
|
:placeholder="`请输入${item.label}`" @update:model-value="changeValue($event, item.prop)" />
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
2026-08-06 16:33:15 +08:00
|
|
|
|
<div active-title-bar class="mb-2.5">适应诊断</div>
|
2026-07-27 11:32:24 +08:00
|
|
|
|
<el-row>
|
2026-08-06 16:33:15 +08:00
|
|
|
|
<el-col :span="24">
|
|
|
|
|
|
<el-form-item label="适应诊断" prop="applicableDiagnosisIds">
|
|
|
|
|
|
<div class="w-full">
|
|
|
|
|
|
<el-popover v-model:visible="diagnosisPopoverVisible" placement="bottom-start" trigger="click"
|
|
|
|
|
|
:width="600">
|
|
|
|
|
|
<template #reference>
|
|
|
|
|
|
<el-input v-model="diagnosisKeyword" clearable placeholder="请输入诊断名称、编码或拼音码搜索"
|
|
|
|
|
|
@input="searchDiagnoses" />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<div v-loading="diagnosisLoading" class="diagnosis-dropdown">
|
|
|
|
|
|
<div v-for="item in diagnosisOptions" :key="item._id" class="diagnosis-option"
|
|
|
|
|
|
:class="{ 'diagnosis-option--selected': isDiagnosisSelected(item._id) }"
|
|
|
|
|
|
@click="toggleDiagnosis(item)">
|
|
|
|
|
|
<span class="diagnosis-option-label">{{ diagnosisLabel(item) }}</span>
|
|
|
|
|
|
<span v-if="isDiagnosisSelected(item._id)" class="diagnosis-option-check">√</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<el-empty v-if="!diagnosisLoading && !diagnosisOptions.length" :image-size="60"
|
|
|
|
|
|
description="暂无诊断" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-popover>
|
|
|
|
|
|
<div v-if="selectedDiagnosisOptions.length" class="selected-diagnoses">
|
|
|
|
|
|
<el-tag v-for="item in selectedDiagnosisOptions" :key="item._id" closable
|
|
|
|
|
|
@close="toggleDiagnosis(item)">
|
|
|
|
|
|
{{ diagnosisLabel(item) }}
|
|
|
|
|
|
</el-tag>
|
2026-07-27 11:32:24 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
</el-form>
|
|
|
|
|
|
</layout-main>
|
|
|
|
|
|
<layout-item>
|
|
|
|
|
|
<div common-shadow--r class="text-center py-10px">
|
|
|
|
|
|
<el-button class="w-100px" @click="close()">取消</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';
|
2026-08-05 18:39:39 +08:00
|
|
|
|
import { storeToRefs } from 'pinia';
|
2026-07-27 11:32:24 +08:00
|
|
|
|
import { ElMessage } from "element-plus";
|
2026-08-06 16:33:15 +08:00
|
|
|
|
import { addHlwDrugInfo, editHlwDrugInfo, addOnlineDrugInfo, editOnlineDrugInfo, getOnlineDrugRepeatTags, getHlwDiagnosisList } from "@/api/hlw";
|
2026-07-27 11:32:24 +08:00
|
|
|
|
import categoryList from '@/baseData/drug-category';
|
|
|
|
|
|
import dosageUnitList from '@/baseData/dosageUnit.js';
|
2026-08-05 18:39:39 +08:00
|
|
|
|
import medicineInfoStore from '@/store/medicine-info';
|
2026-07-30 16:49:15 +08:00
|
|
|
|
import { getDrugFieldDict, getDrugList } from './drug-dict.js'
|
2026-07-27 11:32:24 +08:00
|
|
|
|
|
|
|
|
|
|
import MyLayout, { LayoutMain, LayoutItem } from "@/components/layout";
|
|
|
|
|
|
|
|
|
|
|
|
const emits = defineEmits(['close', 'change'])
|
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
|
visible: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: false
|
|
|
|
|
|
},
|
|
|
|
|
|
// 库类型:hlw = 互联网医院药品库(drug-info),online = 配送/线上药品库(online-drug-info)
|
|
|
|
|
|
libType: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: 'hlw'
|
|
|
|
|
|
},
|
|
|
|
|
|
memberInfo: { type: Object, default: () => ({}) },
|
|
|
|
|
|
data: {
|
|
|
|
|
|
type: Object,
|
|
|
|
|
|
default: () => ({})
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2026-08-05 18:39:39 +08:00
|
|
|
|
const medicineStore = medicineInfoStore()
|
|
|
|
|
|
const { attachMedicineConfig } = medicineStore
|
|
|
|
|
|
const { onlineMedicine, storeMedicine } = storeToRefs(medicineStore)
|
|
|
|
|
|
const medicineUseInfo = computed(() => props.libType === 'online' ? onlineMedicine.value : storeMedicine.value)
|
|
|
|
|
|
const getOptionNames = list => [...new Set(list.map(item => typeof item === 'string' ? item : item?.name).filter(Boolean))]
|
|
|
|
|
|
const unitOptions = computed(() => getOptionNames(medicineUseInfo.value.unitList))
|
|
|
|
|
|
const dosageFormList = computed(() => getOptionNames(medicineUseInfo.value.dosageFormList ||[]))
|
|
|
|
|
|
const frequencyOptions = computed(() => getOptionNames(medicineUseInfo.value.frequencyList))
|
|
|
|
|
|
const usageOptions = computed(() => getOptionNames(medicineUseInfo.value.usageList))
|
|
|
|
|
|
|
2026-07-27 11:32:24 +08:00
|
|
|
|
const repeatTagList = ref([])
|
2026-08-06 16:33:15 +08:00
|
|
|
|
const diagnosisOptions = ref([])
|
|
|
|
|
|
const diagnosisDefaultOptions = ref([])
|
|
|
|
|
|
const diagnosisLoading = ref(false)
|
|
|
|
|
|
const diagnosisKeyword = ref('')
|
|
|
|
|
|
const diagnosisPopoverVisible = ref(false)
|
|
|
|
|
|
let diagnosisRequestId = 0
|
|
|
|
|
|
let diagnosisSearchTimer = null
|
2026-08-05 18:39:39 +08:00
|
|
|
|
const basicInfo = computed(() => [
|
2026-07-27 11:32:24 +08:00
|
|
|
|
{ label: '药品名称', prop: "name", maxlength: 100 },
|
|
|
|
|
|
{ label: '药品规格', prop: "specification", maxlength: 100 },
|
2026-08-05 18:39:39 +08:00
|
|
|
|
{ label: '包装单位', prop: "unit", options: unitOptions.value },
|
|
|
|
|
|
{ label: '剂型', prop: "dosage_form", options: dosageFormList.value },
|
2026-07-27 11:32:24 +08:00
|
|
|
|
{ label: '包装量', prop: "package_amount", maxlength: 100 },
|
|
|
|
|
|
{ label: '生产厂家', prop: "manufacturer", maxlength: 100 },
|
|
|
|
|
|
{ label: '商品条形码', prop: "barcode", maxlength: 100 },
|
|
|
|
|
|
{ label: '医保编码', prop: "insurance_code", maxlength: 100 },
|
|
|
|
|
|
{ label: '药品分类', prop: "category", options: categoryList },
|
|
|
|
|
|
{ label: '药品拼音码', prop: "pinyin_code", maxlength: 100 },
|
|
|
|
|
|
{ label: '通用名', prop: "generic_name", maxlength: 100 },
|
|
|
|
|
|
{ label: '通用名拼音码', prop: "generic_pinyin", maxlength: 100 },
|
2026-08-05 18:39:39 +08:00
|
|
|
|
])
|
2026-07-27 11:32:24 +08:00
|
|
|
|
|
|
|
|
|
|
// 在线药品库扩展字段:管理分类 + 剂型
|
|
|
|
|
|
const onlineBasicInfoExtra = [
|
|
|
|
|
|
{ label: '管理分类', prop: "manage_category", options: ['处方药', 'OTC'] },
|
|
|
|
|
|
{ label: '剂型', prop: "dosage_form", maxlength: 100 },
|
|
|
|
|
|
{ label: 'ERP编码', prop: "his_drug_code", maxlength: 100 },
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// 根据 libType 决定展示哪些基础信息字段
|
|
|
|
|
|
const basicInfoList = computed(() => {
|
2026-07-30 16:49:15 +08:00
|
|
|
|
const idField = props.libType === 'online'
|
|
|
|
|
|
? { label: '药库货品ID', prop: "product_id", maxlength: 100 }
|
|
|
|
|
|
: { label: 'ERP ID', prop: "erpId", maxlength: 100 };
|
2026-08-05 18:39:39 +08:00
|
|
|
|
const fields = [...basicInfo.value.slice(0, 9), idField, ...basicInfo.value.slice(9)];
|
2026-07-30 16:49:15 +08:00
|
|
|
|
return props.libType === 'online' ? [...fields, ...onlineBasicInfoExtra] : fields;
|
2026-07-27 11:32:24 +08:00
|
|
|
|
})
|
|
|
|
|
|
|
2026-08-05 18:39:39 +08:00
|
|
|
|
const usageInfo = computed(() => [
|
2026-07-27 11:32:24 +08:00
|
|
|
|
{ label: '单次标准剂量', prop: "dosage", maxlength: 100 },
|
|
|
|
|
|
{ label: '剂量单位', prop: "dosage_unit", options: dosageUnitList },
|
2026-08-05 18:39:39 +08:00
|
|
|
|
{ label: '给药标准频次', prop: "frequency", options: frequencyOptions.value },
|
|
|
|
|
|
{ label: '给药标准方式', prop: "administration_method", options: usageOptions.value },
|
2026-07-27 11:32:24 +08:00
|
|
|
|
{ label: '用药标准天数', prop: "days", maxlength: 100 },
|
|
|
|
|
|
{ label: '发药标准数量', prop: "recommended_quantity", maxlength: 100 },
|
2026-08-05 18:39:39 +08:00
|
|
|
|
])
|
2026-07-27 11:32:24 +08:00
|
|
|
|
const suitableInfo = [
|
|
|
|
|
|
{ label: '适用性别', prop: 'suitableGender', options: [{ label: '通用', value: 'common' }, { label: '男', value: 'male' }, { label: '女', value: 'female' }] },
|
|
|
|
|
|
{ label: '是否儿童用药', prop: 'suitableChild', options: [{ label: '是', value: true }, { label: '否', value: false }] },
|
|
|
|
|
|
// { label: '重复用药标识', prop: 'repeatTag', multiple: true, options: new Array(5).fill(1).map((_, index) => ({ label: index + 1, value: index + 1 })) },
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
const requiredMap = computed(() => {
|
2026-07-30 16:49:15 +08:00
|
|
|
|
const m = getDrugFieldDict(props.libType).reduce((acc, cur) => {
|
2026-07-27 11:32:24 +08:00
|
|
|
|
acc[cur.field] = typeof cur.required === 'boolean' ? cur.required : false
|
|
|
|
|
|
return acc
|
|
|
|
|
|
}, {})
|
|
|
|
|
|
m.medication_proof_desc = Boolean(m.medication_proof_desc);
|
|
|
|
|
|
m.usage_restriction_desc = Boolean(m.usage_restriction_desc);
|
|
|
|
|
|
if (props.libType === 'online') {
|
|
|
|
|
|
m.his_drug_code = true
|
|
|
|
|
|
}
|
|
|
|
|
|
return m
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const editForm = ref({})
|
|
|
|
|
|
const form = computed(() => ({ ...props.data, ...editForm.value }))
|
|
|
|
|
|
const tableRef = ref(null);
|
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
|
|
|
|
|
|
|
function changeValue(val, prop) {
|
|
|
|
|
|
editForm.value[prop] = val
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-06 16:33:15 +08:00
|
|
|
|
function diagnosisLabel(item) {
|
|
|
|
|
|
return item.code ? `${item.name}(${item.code})` : item.name;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const selectedDiagnosisOptions = computed(() => {
|
|
|
|
|
|
const optionMap = new Map(diagnosisOptions.value.map(item => [String(item._id), item]));
|
|
|
|
|
|
const defaultOptionMap = new Map(diagnosisDefaultOptions.value.map(item => [String(item._id), item]));
|
|
|
|
|
|
return (form.value.applicableDiagnosisIds || [])
|
|
|
|
|
|
.map(id => optionMap.get(String(id)) || defaultOptionMap.get(String(id)))
|
|
|
|
|
|
.filter(Boolean);
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
function isDiagnosisSelected(id) {
|
|
|
|
|
|
return (form.value.applicableDiagnosisIds || []).some(item => String(item) === String(id));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function toggleDiagnosis(item) {
|
|
|
|
|
|
const id = String(item._id);
|
|
|
|
|
|
const selectedIds = (form.value.applicableDiagnosisIds || []).map(itemId => String(itemId));
|
|
|
|
|
|
const nextIds = selectedIds.includes(id)
|
|
|
|
|
|
? selectedIds.filter(itemId => itemId !== id)
|
|
|
|
|
|
: [...selectedIds, id];
|
|
|
|
|
|
changeValue(nextIds, 'applicableDiagnosisIds');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function mergeDiagnosisOptions(items = []) {
|
|
|
|
|
|
const optionMap = new Map(diagnosisOptions.value.map(item => [String(item._id), item]));
|
|
|
|
|
|
items.forEach(item => optionMap.set(String(item._id), item));
|
|
|
|
|
|
diagnosisOptions.value = [...optionMap.values()];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function replaceDiagnosisOptions(items = []) {
|
|
|
|
|
|
const selectedIds = new Set((form.value.applicableDiagnosisIds || []).map(id => String(id)));
|
|
|
|
|
|
const selectedOptions = diagnosisOptions.value.filter(item => selectedIds.has(String(item._id)));
|
|
|
|
|
|
const optionMap = new Map(selectedOptions.map(item => [String(item._id), item]));
|
|
|
|
|
|
items.forEach(item => optionMap.set(String(item._id), item));
|
|
|
|
|
|
diagnosisOptions.value = [...optionMap.values()];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function fetchDiagnoses(params, requestId, replace = false) {
|
|
|
|
|
|
const res = await getHlwDiagnosisList({ page: 1, pageSize: 30, ...params });
|
|
|
|
|
|
if (requestId !== diagnosisRequestId) return;
|
|
|
|
|
|
if (!res.success) {
|
|
|
|
|
|
ElMessage.error(res.message || '适应诊断加载失败');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const list = res.data && Array.isArray(res.data.data) ? res.data.data : [];
|
|
|
|
|
|
if (replace) {
|
|
|
|
|
|
replaceDiagnosisOptions(list);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
mergeDiagnosisOptions(list);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function searchDiagnoses(keyword = '') {
|
|
|
|
|
|
if (diagnosisSearchTimer) {
|
|
|
|
|
|
clearTimeout(diagnosisSearchTimer);
|
|
|
|
|
|
diagnosisSearchTimer = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
const normalizedKeyword = typeof keyword === 'string' ? keyword.trim() : '';
|
|
|
|
|
|
const requestId = ++diagnosisRequestId;
|
|
|
|
|
|
if (!normalizedKeyword) {
|
|
|
|
|
|
diagnosisLoading.value = false;
|
|
|
|
|
|
replaceDiagnosisOptions(diagnosisDefaultOptions.value);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
diagnosisLoading.value = true;
|
|
|
|
|
|
diagnosisSearchTimer = setTimeout(async () => {
|
|
|
|
|
|
await fetchDiagnoses({ keyword: normalizedKeyword }, requestId, true);
|
|
|
|
|
|
if (requestId === diagnosisRequestId) diagnosisLoading.value = false;
|
|
|
|
|
|
diagnosisSearchTimer = null;
|
|
|
|
|
|
}, 300);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function initializeDiagnoses() {
|
|
|
|
|
|
diagnosisOptions.value = [];
|
|
|
|
|
|
const selectedIds = Array.isArray(props.data.applicableDiagnosisIds)
|
|
|
|
|
|
? props.data.applicableDiagnosisIds.map(id => String(id))
|
|
|
|
|
|
: [];
|
|
|
|
|
|
const requestId = ++diagnosisRequestId;
|
|
|
|
|
|
diagnosisLoading.value = true;
|
|
|
|
|
|
const requests = [fetchDiagnoses({}, requestId)];
|
|
|
|
|
|
if (selectedIds.length) {
|
|
|
|
|
|
requests.push(fetchDiagnoses({ ids: selectedIds, pageSize: Math.max(30, selectedIds.length) }, requestId));
|
|
|
|
|
|
}
|
|
|
|
|
|
await Promise.all(requests);
|
|
|
|
|
|
diagnosisDefaultOptions.value = [...diagnosisOptions.value];
|
|
|
|
|
|
if (requestId === diagnosisRequestId) diagnosisLoading.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-27 11:32:24 +08:00
|
|
|
|
|
|
|
|
|
|
function close() {
|
|
|
|
|
|
if (loading.value) return;
|
|
|
|
|
|
emits('close')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function save() {
|
|
|
|
|
|
if (loading.value) return;
|
|
|
|
|
|
const isEdit = Boolean(props.data._id);
|
2026-07-30 16:49:15 +08:00
|
|
|
|
const verifyData = isEdit ? form.value : editForm.value;
|
2026-08-05 18:39:39 +08:00
|
|
|
|
const [drug] = getDrugList([verifyData], 'field', true, props.libType, {
|
|
|
|
|
|
unit: unitOptions.value,
|
|
|
|
|
|
frequency: frequencyOptions.value,
|
|
|
|
|
|
administration_method: usageOptions.value,
|
|
|
|
|
|
});
|
2026-07-27 11:32:24 +08:00
|
|
|
|
if (drug.msgs.length) {
|
|
|
|
|
|
ElMessage.info(drug.msgs[0])
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (Object.keys(editForm.value).length) {
|
|
|
|
|
|
loading.value = true;
|
|
|
|
|
|
const isOnline = props.libType === 'online';
|
|
|
|
|
|
const apiMap = {
|
|
|
|
|
|
update: isOnline ? editOnlineDrugInfo : editHlwDrugInfo,
|
|
|
|
|
|
add: isOnline ? addOnlineDrugInfo : addHlwDrugInfo,
|
|
|
|
|
|
}
|
|
|
|
|
|
const api = props.data._id ? apiMap.update : apiMap.add;
|
|
|
|
|
|
const payload = {
|
|
|
|
|
|
params: { ...editForm.value },
|
|
|
|
|
|
id: props.data._id,
|
|
|
|
|
|
operator: props.memberInfo.anotherName,
|
|
|
|
|
|
operatorId: props.memberInfo._id,
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!props.data._id) {
|
|
|
|
|
|
payload.params.onSale = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
const { success, message } = await api(payload);
|
|
|
|
|
|
loading.value = false;
|
|
|
|
|
|
if (success) {
|
|
|
|
|
|
ElMessage.success(message)
|
|
|
|
|
|
emits('change')
|
|
|
|
|
|
close();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ElMessage.error(message)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function getRepeatTags() {
|
|
|
|
|
|
const res = await getOnlineDrugRepeatTags()
|
|
|
|
|
|
repeatTagList.value = res && res.data && Array.isArray(res.data.data) ? res.data.data.map(i => ({ label: `${i}`, value: i })) : [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-05 18:39:39 +08:00
|
|
|
|
watch(() => props.visible, async (val) => {
|
2026-07-27 11:32:24 +08:00
|
|
|
|
if (val) {
|
|
|
|
|
|
// reset local editForm when opening drawer
|
|
|
|
|
|
editForm.value = {}
|
2026-08-06 16:33:15 +08:00
|
|
|
|
diagnosisKeyword.value = ''
|
|
|
|
|
|
await Promise.all([attachMedicineConfig(), initializeDiagnoses()])
|
2026-07-27 11:32:24 +08:00
|
|
|
|
if (props.libType === 'online') {
|
|
|
|
|
|
getRepeatTags()
|
|
|
|
|
|
}
|
|
|
|
|
|
// initialize select values based on props.data for edit scenario
|
|
|
|
|
|
if (props.data) {
|
|
|
|
|
|
if (props.data.medication_proof_desc) {
|
|
|
|
|
|
editForm.value.medication_proof_desc = props.data.medication_proof_desc
|
|
|
|
|
|
editForm.value.need_medication_proof = true
|
|
|
|
|
|
} else {
|
|
|
|
|
|
editForm.value.need_medication_proof = false
|
|
|
|
|
|
}
|
|
|
|
|
|
if (props.data.usage_restriction_desc) {
|
|
|
|
|
|
editForm.value.usage_restriction_desc = props.data.usage_restriction_desc
|
|
|
|
|
|
editForm.value.has_usage_restriction = true
|
|
|
|
|
|
} else {
|
|
|
|
|
|
editForm.value.has_usage_restriction = false
|
|
|
|
|
|
}
|
|
|
|
|
|
if (props.data.repeatTag && !Array.isArray(props.data.repeatTag)) {
|
|
|
|
|
|
editForm.value.repeatTag = [props.data.repeatTag]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-08-06 16:33:15 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
diagnosisPopoverVisible.value = false
|
|
|
|
|
|
diagnosisRequestId += 1
|
|
|
|
|
|
diagnosisLoading.value = false
|
|
|
|
|
|
if (diagnosisSearchTimer) {
|
|
|
|
|
|
clearTimeout(diagnosisSearchTimer)
|
|
|
|
|
|
diagnosisSearchTimer = null
|
|
|
|
|
|
}
|
2026-07-27 11:32:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
function selectChange(prop, val) {
|
|
|
|
|
|
// store select value and clear description when selecting '否' (false)
|
|
|
|
|
|
changeValue(val, prop)
|
|
|
|
|
|
if (prop === 'need_medication_proof' && !val) {
|
|
|
|
|
|
changeValue('', 'medication_proof_desc')
|
|
|
|
|
|
}
|
|
|
|
|
|
if (prop === 'has_usage_restriction' && !val) {
|
|
|
|
|
|
changeValue('', 'usage_restriction_desc')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.other-info-row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
/* vertically center select and input */
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.other-info-select {
|
|
|
|
|
|
flex: 0 0 140px;
|
|
|
|
|
|
/* slightly wider to accommodate labels */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.other-info-desc {
|
|
|
|
|
|
flex: 1 1 0;
|
|
|
|
|
|
/* take remaining space */
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
/* allow input to shrink properly inside flex */
|
|
|
|
|
|
}
|
2026-08-06 16:33:15 +08:00
|
|
|
|
|
|
|
|
|
|
.diagnosis-dropdown {
|
|
|
|
|
|
min-height: 60px;
|
|
|
|
|
|
max-height: 320px;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.diagnosis-option {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
min-height: 36px;
|
|
|
|
|
|
padding: 0 12px;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
color: var(--el-text-color-regular);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.diagnosis-option:hover,
|
|
|
|
|
|
.diagnosis-option--selected {
|
|
|
|
|
|
background: var(--el-fill-color-light);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.diagnosis-option--selected {
|
|
|
|
|
|
color: var(--el-color-primary);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.diagnosis-option-label {
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.diagnosis-option-check {
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
margin-left: 16px;
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: var(--el-color-primary);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.selected-diagnoses {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
|
}
|
2026-07-27 11:32:24 +08:00
|
|
|
|
</style>
|