feat: 中药导入模块修复、部门财务的优化、队列的优化管理
This commit is contained in:
@@ -68,6 +68,7 @@ import GoldenFormulaModal from '#/views/doctor/doctor-reception/components/Golde
|
||||
import InfoModal from '#/components/modal/InfoModal.vue';
|
||||
// 药品搜索选择组件
|
||||
import { DrugSearchSelect } from '#/components/drug-search-select';
|
||||
import { ChineseDrugNameBubble } from '#/components/chinese-drug-name-bubble';
|
||||
import { formatPriceDisplay } from '#/utils/formatPrice';
|
||||
import ChineseMedicineConfig from '#/views/doctor/doctor-reception/components/ChineseMedicineConfig.vue';
|
||||
import { getDeliveryWarehouseOptionsByDrugs, getPrescriptionInfoApi } from '#/views/doctor/doctor-reception/api';
|
||||
@@ -1408,69 +1409,53 @@ const cancelSaveCommonPrescription = () => {
|
||||
<div>
|
||||
<span class="card-index">{{ index + 1 }}、</span>
|
||||
<p>
|
||||
<Select
|
||||
v-model:value="drug.id"
|
||||
:filter-option="false"
|
||||
class="old-select-drug-name w-full mb-2"
|
||||
<ChineseDrugNameBubble
|
||||
:display-name="drug.drug_name"
|
||||
:store-id="prescriptionStore.myStoreId"
|
||||
:register-id="Number(prescriptionStore.currentRegisterId || 0)"
|
||||
:type="1"
|
||||
compact
|
||||
input-class="old-select-drug-name"
|
||||
placeholder="药名"
|
||||
show-search
|
||||
@change="prescriptionStore.selectOldDrugInfo"
|
||||
@dropdown-visible-change="
|
||||
prescriptionStore.setSelectChineseIndex(index, drug.id)
|
||||
@select="
|
||||
(item) =>
|
||||
prescriptionStore.onSelectOldChineseDrug(index, item)
|
||||
"
|
||||
@search="searchOption"
|
||||
/>
|
||||
,
|
||||
<InputNumber
|
||||
v-model:value="drug.number"
|
||||
:class="`old-number-input-${index}`"
|
||||
:controls="false"
|
||||
style="width: 80px; min-width: 80px"
|
||||
@blur="prescriptionStore.updateChineseNumber"
|
||||
@keydown="
|
||||
prescriptionStore.updateChineseNumberGoNewDrug($event)
|
||||
"
|
||||
>
|
||||
<template #addonAfter>{{ drug.unit?.name || 'g' }}</template>
|
||||
</InputNumber>
|
||||
,
|
||||
<Select
|
||||
:value="drug?.way_id"
|
||||
placeholder="用法"
|
||||
style="width: 88px; min-width: 72px"
|
||||
@change="prescriptionStore.selectDrugUseWayChange"
|
||||
@dropdown-visible-change="
|
||||
prescriptionStore.selectProductChange(drug.index_id)
|
||||
"
|
||||
>
|
||||
<SelectOption :value="0">煎服</SelectOption>
|
||||
<SelectOption
|
||||
v-if="prescriptionStore.drugList.length === 0"
|
||||
:value="drug.id"
|
||||
v-for="(
|
||||
value, wayIndex
|
||||
) in prescriptionStore.drugUseWay"
|
||||
:key="wayIndex"
|
||||
:value="value.id"
|
||||
>
|
||||
{{ drug.drug_name }}
|
||||
</SelectOption>
|
||||
<SelectOption
|
||||
v-for="(value, drugIndex) in prescriptionStore.drugList"
|
||||
v-else
|
||||
:key="drugIndex"
|
||||
:value="value.drug.id"
|
||||
>
|
||||
{{ value.drug.drug_name }}
|
||||
{{ value.name }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
|
||||
<div class="flex gap-1 items-center">
|
||||
<InputNumber
|
||||
v-model:value="drug.number"
|
||||
:class="`old-number-input-${index}`"
|
||||
:controls="false"
|
||||
style="width: 80px"
|
||||
@blur="prescriptionStore.updateChineseNumber"
|
||||
@keydown="
|
||||
prescriptionStore.updateChineseNumberGoNewDrug($event)
|
||||
"
|
||||
>
|
||||
<template #addonAfter>{{ drug.unit?.name || 'g' }}</template>
|
||||
</InputNumber>
|
||||
|
||||
<Select
|
||||
:value="drug?.way_id"
|
||||
placeholder="用法"
|
||||
style="flex:1"
|
||||
@change="prescriptionStore.selectDrugUseWayChange"
|
||||
@dropdown-visible-change="
|
||||
prescriptionStore.selectProductChange(drug.index_id)
|
||||
"
|
||||
>
|
||||
<SelectOption :value="0">煎服</SelectOption>
|
||||
<SelectOption
|
||||
v-for="(
|
||||
value, wayIndex
|
||||
) in prescriptionStore.drugUseWay"
|
||||
:key="wayIndex"
|
||||
:value="value.id"
|
||||
>
|
||||
{{ value.name }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
</p>
|
||||
<p class="card-price">
|
||||
¥<span>{{ (drug.price * drug.number).toFixed(2) }}</span>
|
||||
@@ -1498,58 +1483,49 @@ const cancelSaveCommonPrescription = () => {
|
||||
<div>
|
||||
<span class="card-index">{{ prescriptionStore.currentDrugs.length + 1 }}、</span>
|
||||
<div>
|
||||
<Select
|
||||
v-model:value="prescriptionStore.newDrugInfo.id"
|
||||
:filter-option="false"
|
||||
class="new-select-drug-name w-full mb-2"
|
||||
<ChineseDrugNameBubble
|
||||
:display-name="prescriptionStore.newDrugInfo.name || ''"
|
||||
:store-id="prescriptionStore.myStoreId"
|
||||
:register-id="Number(prescriptionStore.currentRegisterId || 0)"
|
||||
:type="1"
|
||||
compact
|
||||
input-class="new-select-drug-name"
|
||||
placeholder="药名"
|
||||
show-search
|
||||
@change="prescriptionStore.selectNewDrugInfo"
|
||||
@search="searchOption"
|
||||
@select="prescriptionStore.onSelectNewChineseDrug"
|
||||
/>
|
||||
,
|
||||
<InputNumber
|
||||
v-model:value="prescriptionStore.newDrugInfo.number"
|
||||
class="new-number-input"
|
||||
style="width: 80px; min-width: 80px"
|
||||
@blur="newDrugBlur"
|
||||
@keydown="
|
||||
prescriptionStore.selectDrugByNewDrugInfo($event, true)
|
||||
"
|
||||
>
|
||||
<template #addonAfter>{{ prescriptionStore.newDrugInfo.unit?.name || 'g' }}</template>
|
||||
</InputNumber>
|
||||
,
|
||||
<Select
|
||||
v-model:value="prescriptionStore.newDrugInfo.way_id"
|
||||
placeholder="用法"
|
||||
style="width: 88px; min-width: 72px"
|
||||
@keydown="
|
||||
prescriptionStore.selectDrugByNewDrugInfo($event, true)
|
||||
"
|
||||
>
|
||||
<SelectOption :value="0">煎服</SelectOption>
|
||||
<SelectOption
|
||||
v-for="(value, drugIndex) in prescriptionStore.drugList"
|
||||
:key="drugIndex"
|
||||
:value="value.drug_id"
|
||||
v-for="(
|
||||
value, wayIndex
|
||||
) in prescriptionStore.drugUseWay"
|
||||
:key="wayIndex"
|
||||
:value="value.id"
|
||||
>
|
||||
{{ value.drug.drug_name }}
|
||||
{{ value.name }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
|
||||
<div class="flex gap-1 items-center">
|
||||
<InputNumber
|
||||
v-model:value="prescriptionStore.newDrugInfo.number"
|
||||
class="new-number-input"
|
||||
style="width: 80px"
|
||||
@blur="newDrugBlur"
|
||||
@keydown="
|
||||
prescriptionStore.selectDrugByNewDrugInfo($event, true)
|
||||
"
|
||||
>
|
||||
<template #addonAfter>{{ prescriptionStore.newDrugInfo.unit?.name || 'g' }}</template>
|
||||
</InputNumber>
|
||||
|
||||
<Select
|
||||
v-model:value="prescriptionStore.newDrugInfo.way_id"
|
||||
placeholder="用法"
|
||||
style="flex:1"
|
||||
@keydown="
|
||||
prescriptionStore.selectDrugByNewDrugInfo($event, true)
|
||||
"
|
||||
>
|
||||
<SelectOption :value="0">煎服</SelectOption>
|
||||
<SelectOption
|
||||
v-for="(
|
||||
value, wayIndex
|
||||
) in prescriptionStore.drugUseWay"
|
||||
:key="wayIndex"
|
||||
:value="value.id"
|
||||
>
|
||||
{{ value.name }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<p class="card-price">
|
||||
¥<span>{{
|
||||
(
|
||||
@@ -2122,6 +2098,18 @@ const cancelSaveCommonPrescription = () => {
|
||||
position: relative;
|
||||
min-height: 120px;
|
||||
}
|
||||
/* 中药卡片:药名/克数/用法同一行,药名气泡锁宽 */
|
||||
.prescription-card :deep(.chinese-drug-name-bubble) {
|
||||
width: 100px !important;
|
||||
min-width: 88px !important;
|
||||
max-width: 110px !important;
|
||||
flex: 0 0 100px !important;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.prescription-card > div > p,
|
||||
.prescription-card > div > div {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.drug-categories {
|
||||
display: flex;
|
||||
|
||||
@@ -15,12 +15,9 @@ import {
|
||||
Select,
|
||||
SelectOption,
|
||||
} from 'ant-design-vue';
|
||||
import { debounce } from 'lodash-es';
|
||||
|
||||
import {
|
||||
getDrugUseList,
|
||||
getProductListDoctorReception,
|
||||
} from '#/views/doctor/doctor-reception/api';
|
||||
import { ChineseDrugNameBubble } from '#/components/chinese-drug-name-bubble';
|
||||
import { getDrugUseList } from '#/views/doctor/doctor-reception/api';
|
||||
|
||||
import PrescriptionDiagnosisOrderCards from './PrescriptionDiagnosisOrderCards.vue';
|
||||
|
||||
@@ -118,7 +115,6 @@ const doctorOrderModel = computed({
|
||||
});
|
||||
|
||||
const drugUseWay = ref<any[]>([]);
|
||||
const chineseSearchResults = ref<any[]>([]);
|
||||
const newDrugInfo = ref<{
|
||||
id?: number;
|
||||
name?: string;
|
||||
@@ -151,48 +147,36 @@ function syncToParent() {
|
||||
emit('update:dayDosage', dayDosageLocal.value);
|
||||
}
|
||||
|
||||
const searchChineseDrugs = debounce(async (keyword: string) => {
|
||||
if (!keyword || keyword.length < 1) {
|
||||
chineseSearchResults.value = [];
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await getProductListDoctorReception({
|
||||
name: keyword,
|
||||
type: 1,
|
||||
store_id: userStore.userInfo?.store_id || 2,
|
||||
});
|
||||
chineseSearchResults.value = Array.isArray(res) ? res : [];
|
||||
} catch {
|
||||
chineseSearchResults.value = [];
|
||||
}
|
||||
}, 300);
|
||||
|
||||
function selectNewDrug(drugId: number) {
|
||||
/**
|
||||
* 中药气泡:选中新增行
|
||||
* @param selectedItem 商品检索完整行
|
||||
*/
|
||||
function selectNewDrug(selectedItem: any) {
|
||||
const drugId = Number(selectedItem?.drug?.id || selectedItem?.drug_id || 0);
|
||||
if (!drugId) return;
|
||||
const exists = drugList.value.some(
|
||||
(item) => item.id === drugId || item.drug_id === drugId,
|
||||
);
|
||||
if (exists) {
|
||||
message.warning('该药品已在列表中');
|
||||
newDrugInfo.value.id = undefined;
|
||||
newDrugInfo.value.name = '';
|
||||
return;
|
||||
}
|
||||
const selectedItem = chineseSearchResults.value.find(
|
||||
(item) => item.drug?.id === drugId || item.drug_id === drugId,
|
||||
);
|
||||
if (selectedItem) {
|
||||
newDrugInfo.value.name = selectedItem.drug?.drug_name || '';
|
||||
newDrugInfo.value.price = selectedItem.price || 0;
|
||||
newDrugInfo.value.way_id = 0;
|
||||
newDrugInfo.value.unit =
|
||||
selectedItem.drug?.unit || selectedItem.unit || null;
|
||||
newDrugInfo.value.unit_id =
|
||||
selectedItem.drug?.unit_id || selectedItem.unit_id || 0;
|
||||
nextTick(() => {
|
||||
const numberInput = document.querySelector('.new-chinese-number input') as HTMLInputElement;
|
||||
numberInput?.focus();
|
||||
});
|
||||
}
|
||||
newDrugInfo.value.id = drugId;
|
||||
newDrugInfo.value.name = selectedItem.drug?.drug_name || '';
|
||||
newDrugInfo.value.price = selectedItem.price || 0;
|
||||
newDrugInfo.value.way_id = 0;
|
||||
newDrugInfo.value.unit =
|
||||
selectedItem.drug?.unit || selectedItem.unit || null;
|
||||
newDrugInfo.value.unit_id =
|
||||
selectedItem.drug?.unit_id || selectedItem.unit_id || 0;
|
||||
nextTick(() => {
|
||||
const numberInput = document.querySelector(
|
||||
'.new-chinese-number input',
|
||||
) as HTMLInputElement;
|
||||
numberInput?.focus();
|
||||
});
|
||||
}
|
||||
|
||||
function addChineseDrug() {
|
||||
@@ -216,11 +200,12 @@ function addChineseDrug() {
|
||||
unit: newDrugInfo.value.unit || null,
|
||||
});
|
||||
newDrugInfo.value = {};
|
||||
chineseSearchResults.value = [];
|
||||
syncToParent();
|
||||
message.success('已添加药品');
|
||||
nextTick(() => {
|
||||
const nameInput = document.querySelector('.new-chinese-name input') as HTMLInputElement;
|
||||
const nameInput = document.querySelector(
|
||||
'.new-chinese-name input',
|
||||
) as HTMLInputElement;
|
||||
nameInput?.focus();
|
||||
});
|
||||
}
|
||||
@@ -234,34 +219,36 @@ function handleChineseKeydown(event: KeyboardEvent, isNew: boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
function changeChineseDrug(index: number, drugId: number) {
|
||||
/**
|
||||
* 中药气泡:替换已有行
|
||||
* @param index 行下标
|
||||
* @param selectedItem 商品检索完整行
|
||||
*/
|
||||
function changeChineseDrug(index: number, selectedItem: any) {
|
||||
const drugId = Number(selectedItem?.drug?.id || selectedItem?.drug_id || 0);
|
||||
if (!drugId) return;
|
||||
const exists = drugList.value.some(
|
||||
(item, i) => i !== index && (item.id === drugId || item.drug_id === drugId),
|
||||
);
|
||||
if (exists) {
|
||||
message.warning('该药品已在列表中');
|
||||
const drug = drugList.value[index];
|
||||
if (drug) drug.id = drug.drug_id;
|
||||
return;
|
||||
}
|
||||
const selectedItem = chineseSearchResults.value.find(
|
||||
(item) => item.drug?.id === drugId || item.drug_id === drugId,
|
||||
);
|
||||
if (selectedItem) {
|
||||
const drug = drugList.value[index];
|
||||
if (drug) {
|
||||
drug.id = drugId;
|
||||
drug.drug_id = drugId;
|
||||
drug.drug_name = selectedItem.drug?.drug_name || '';
|
||||
drug.price = selectedItem.price || 0;
|
||||
drug.unit = selectedItem.drug?.unit || selectedItem.unit || null;
|
||||
drug.unit_id = selectedItem.drug?.unit_id || selectedItem.unit_id || 0;
|
||||
syncToParent();
|
||||
nextTick(() => {
|
||||
const numberInput = document.querySelector(`.chinese-number-${index} input`) as HTMLInputElement;
|
||||
numberInput?.focus();
|
||||
});
|
||||
}
|
||||
const drug = drugList.value[index];
|
||||
if (drug) {
|
||||
drug.id = drugId;
|
||||
drug.drug_id = drugId;
|
||||
drug.drug_name = selectedItem.drug?.drug_name || '';
|
||||
drug.price = selectedItem.price || 0;
|
||||
drug.unit = selectedItem.drug?.unit || selectedItem.unit || null;
|
||||
drug.unit_id = selectedItem.drug?.unit_id || selectedItem.unit_id || 0;
|
||||
syncToParent();
|
||||
nextTick(() => {
|
||||
const numberInput = document.querySelector(
|
||||
`.chinese-number-${index} input`,
|
||||
) as HTMLInputElement;
|
||||
numberInput?.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,27 +410,15 @@ defineExpose({
|
||||
<span>{{ getWayName(drug.way_id) }}</span>
|
||||
</div>
|
||||
<div v-else class="chinese-drug-form">
|
||||
<Select
|
||||
v-model:value="drug.id"
|
||||
show-search
|
||||
:filter-option="false"
|
||||
<ChineseDrugNameBubble
|
||||
:display-name="drug.drug_name"
|
||||
:store-id="userStore.userInfo?.store_id || 0"
|
||||
:type="1"
|
||||
compact
|
||||
input-class="chinese-drug-name"
|
||||
placeholder="药名"
|
||||
class="chinese-drug-name"
|
||||
@search="searchChineseDrugs"
|
||||
@change="(val) => changeChineseDrug(index, val as number)"
|
||||
>
|
||||
<SelectOption v-if="chineseSearchResults.length === 0" :value="drug.id">
|
||||
{{ drug.drug_name }}
|
||||
</SelectOption>
|
||||
<SelectOption
|
||||
v-for="item in chineseSearchResults"
|
||||
v-else
|
||||
:key="item.drug?.id || item.id"
|
||||
:value="item.drug?.id || item.id"
|
||||
>
|
||||
{{ item.drug?.drug_name || item.drug_name }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
@select="(item) => changeChineseDrug(index, item)"
|
||||
/>
|
||||
<span class="chinese-drug-comma">,</span>
|
||||
<InputNumber
|
||||
v-model:value="drug.number"
|
||||
@@ -523,23 +498,15 @@ defineExpose({
|
||||
<div class="chinese-drug-content">
|
||||
<span class="chinese-drug-index">{{ drugList.length + 1 }}、</span>
|
||||
<div class="chinese-drug-form">
|
||||
<Select
|
||||
v-model:value="newDrugInfo.id"
|
||||
show-search
|
||||
:filter-option="false"
|
||||
<ChineseDrugNameBubble
|
||||
:display-name="newDrugInfo.name || ''"
|
||||
:store-id="userStore.userInfo?.store_id || 0"
|
||||
:type="1"
|
||||
compact
|
||||
input-class="chinese-drug-name new-chinese-name"
|
||||
placeholder="药名"
|
||||
class="chinese-drug-name new-chinese-name"
|
||||
@search="searchChineseDrugs"
|
||||
@change="selectNewDrug"
|
||||
>
|
||||
<SelectOption
|
||||
v-for="item in chineseSearchResults"
|
||||
:key="item.drug?.id || item.id"
|
||||
:value="item.drug?.id || item.id"
|
||||
>
|
||||
{{ item.drug?.drug_name || item.drug_name }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
@select="selectNewDrug"
|
||||
/>
|
||||
<span class="chinese-drug-comma">,</span>
|
||||
<InputNumber
|
||||
v-model:value="newDrugInfo.number"
|
||||
@@ -607,15 +574,18 @@ defineExpose({
|
||||
|
||||
.chinese-drug-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding-left: 28px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chinese-drug-name {
|
||||
min-width: 80px;
|
||||
max-width: 120px;
|
||||
/* 药名气泡锁宽,与克数/用法保持同一行 */
|
||||
.chinese-drug-form :deep(.chinese-drug-name-bubble) {
|
||||
width: 100px !important;
|
||||
min-width: 88px !important;
|
||||
max-width: 110px !important;
|
||||
flex: 0 0 100px !important;
|
||||
}
|
||||
|
||||
.chinese-drug-readonly {
|
||||
|
||||
@@ -100,7 +100,7 @@ const [Modal, modalApi] = useVbenModal({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal title="编辑药方" class="w-[80%] md:w-[50%] lg:w-[30%] h-[60%]">
|
||||
<Modal title="编辑药方" class="w-[80%]">
|
||||
<div v-if="prescriptionType === 'chinese'">
|
||||
<ChineseDrugEditor
|
||||
ref="chineseDrugEditorRef"
|
||||
|
||||
@@ -67,7 +67,7 @@ const [Modal, modalApi] = useVbenModal({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal :title="modalTitle" class="w-[420px]">
|
||||
<Modal :title="modalTitle" class="w-[80%]">
|
||||
<div class="free-shipping-dose-modal">
|
||||
<p v-if="spName" class="sp-name">特色方:{{ spName }}</p>
|
||||
<div class="form-row">
|
||||
|
||||
@@ -178,7 +178,7 @@ function bindPrescriptionTypeChange() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal :title="`${isUpdate ? '编辑' : '新增'}特色方`" class="w-[80%] md:w-[50%] lg:w-[30%] h-[60%]">
|
||||
<Modal :title="`${isUpdate ? '编辑' : '新增'}特色方`" class="w-[80%]">
|
||||
<Form />
|
||||
<div v-if="prescriptionType === 'chinese'" class="mt-4 border-t pt-4">
|
||||
<ChineseDrugEditor
|
||||
|
||||
@@ -91,7 +91,9 @@ const downloadQRCode = async (name: string, isQr = false) => {
|
||||
{{ data.qr_code.store.name }}
|
||||
</div>
|
||||
<div class="qrAddress">
|
||||
<span class="addressTitle">诊所地址:</span>{{ data.qr_code.store.position }}
|
||||
<span class="addressTitle">{{
|
||||
Number(data?.qr_code?.store?.type) === 1 ? '药店地址:' : '诊所地址:'
|
||||
}}</span>{{ data.qr_code.store.position }}
|
||||
</div>
|
||||
<Image :preview="false" :src="data.qr_code.qr_code" class="mt-3" height="30" width="30" />
|
||||
<div class="qrAddress">
|
||||
|
||||
@@ -484,6 +484,21 @@ export async function aiMatchPrescriptionDrugsApi(data: {
|
||||
return requestClient.post<any>(`${prefix}ai-match-prescription-drugs`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* AI 出方:改选对照药品并写回 result_json(标记 is_modified)
|
||||
*/
|
||||
export async function aiSavePrescriptionDrugSelectionApi(data: {
|
||||
generation_id: number;
|
||||
item_index: number;
|
||||
selected_drug_id: number;
|
||||
selected_drug_name?: string;
|
||||
}) {
|
||||
return requestClient.post<any>(
|
||||
`${prefix}ai-save-prescription-drug-selection`,
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
/** 金方列表(VIP:golden_formula) */
|
||||
export async function goldenFormulaListApi(data: {
|
||||
keyword?: string;
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
aiGeneratePrescriptionApi,
|
||||
aiListGenerationsApi,
|
||||
aiMatchPrescriptionDrugsApi,
|
||||
aiSavePrescriptionDrugSelectionApi,
|
||||
getProcessRuleList,
|
||||
} from '../api';
|
||||
import AiDisclaimerBanner from '#/views/doctor/components/AiDisclaimerBanner.vue';
|
||||
@@ -509,6 +510,46 @@ async function onSelectHistory(row: any) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 医生点选对照候选药:本地更新 + 同步写回 aijson(result_json)
|
||||
* @param mi matchedList 下标
|
||||
* @param candidate 候选药品
|
||||
*/
|
||||
async function onPickCandidate(mi: number, candidate: any) {
|
||||
const row = matchedList.value[mi];
|
||||
if (!row || !candidate) return;
|
||||
const drugId = Number(candidate.drug_id || 0);
|
||||
if (!drugId) return;
|
||||
if (Number(row.selected_drug_id) === drugId) return;
|
||||
const prevId = Number(row.selected_drug_id || 0);
|
||||
const prevModified = Number(row.is_modified || 0);
|
||||
row.selected_drug_id = drugId;
|
||||
row.is_modified = 1;
|
||||
const generationId = Number(activeId.value || 0);
|
||||
const itemIndex = Number(
|
||||
row.item_index !== undefined && row.item_index !== null
|
||||
? row.item_index
|
||||
: mi,
|
||||
);
|
||||
if (generationId <= 0) {
|
||||
message.warning('请先生成或选择历史处方后再改选');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await aiSavePrescriptionDrugSelectionApi({
|
||||
generation_id: generationId,
|
||||
item_index: itemIndex,
|
||||
selected_drug_id: drugId,
|
||||
selected_drug_name: String(candidate.drug_name || ''),
|
||||
});
|
||||
} catch (e: any) {
|
||||
// 回滚本地,避免 UI 与库不一致
|
||||
row.selected_drug_id = prevId;
|
||||
row.is_modified = prevModified;
|
||||
message.error(e?.message || e?.msg || '改选保存失败');
|
||||
}
|
||||
}
|
||||
|
||||
function onConfirmImport() {
|
||||
const drugs: any[] = [];
|
||||
for (const m of matchedList.value) {
|
||||
@@ -670,7 +711,16 @@ defineExpose({
|
||||
>
|
||||
<div class="flex items-start gap-1">
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="truncate text-xs font-medium">{{ m.ai_name }}</div>
|
||||
<div class="truncate text-xs font-medium">
|
||||
{{ m.ai_name }}
|
||||
<Tag
|
||||
v-if="Number(m.is_modified) === 1"
|
||||
color="orange"
|
||||
class="!m-0 !ml-1 !px-1 !text-[10px] !leading-4"
|
||||
>
|
||||
已改
|
||||
</Tag>
|
||||
</div>
|
||||
<div class="text-[11px] text-muted-foreground">
|
||||
{{ m.dose }}{{ m.unit }}{{ m.usage ? `·${m.usage}` : '' }}
|
||||
</div>
|
||||
@@ -687,7 +737,7 @@ defineExpose({
|
||||
? 'success'
|
||||
: undefined
|
||||
"
|
||||
@click="m.selected_drug_id = Number(c.drug_id)"
|
||||
@click="onPickCandidate(mi, c)"
|
||||
>
|
||||
{{ c.drug_name }}
|
||||
</Tag>
|
||||
@@ -701,7 +751,16 @@ defineExpose({
|
||||
class="rounded-lg border border-border bg-card p-2.5"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="min-w-0 flex-1 truncate font-medium">{{ m.ai_name }}</span>
|
||||
<span class="min-w-0 flex-1 truncate font-medium">
|
||||
{{ m.ai_name }}
|
||||
<Tag
|
||||
v-if="Number(m.is_modified) === 1"
|
||||
color="orange"
|
||||
class="!m-0 !ml-1 !text-[10px]"
|
||||
>
|
||||
已改
|
||||
</Tag>
|
||||
</span>
|
||||
<span class="text-xs text-muted-foreground">
|
||||
{{ m.dose }}{{ m.unit }}{{ m.usage ? `·${m.usage}` : '' }}
|
||||
</span>
|
||||
@@ -717,7 +776,7 @@ defineExpose({
|
||||
? 'success'
|
||||
: undefined
|
||||
"
|
||||
@click="m.selected_drug_id = Number(c.drug_id)"
|
||||
@click="onPickCandidate(mi, c)"
|
||||
>
|
||||
{{ c.drug_name }} ¥{{ Number(c.price || 0).toFixed(2) }}
|
||||
</Tag>
|
||||
|
||||
@@ -97,6 +97,8 @@ import SensitiveText from '#/components/sensitive-text/SensitiveText.vue';
|
||||
import { detailDoctorOrderToText } from '#/utils/prescriptionDoctorOrder';
|
||||
// 药品搜索选择组件
|
||||
import { DrugSearchSelect } from '#/components/drug-search-select';
|
||||
// 中药药名气泡(对齐诊断/医嘱浮层交互)
|
||||
import { ChineseDrugNameBubble } from '#/components/chinese-drug-name-bubble';
|
||||
// 保存常用方API
|
||||
import {
|
||||
saveChineseCommonPrescriptionApi,
|
||||
@@ -2599,28 +2601,114 @@ const getDrugListByWesternModal = debounce(async (searchText = '') => {
|
||||
|
||||
// getDrugListByWesternModal();
|
||||
|
||||
/** 新行中药气泡选中的完整商品(添加时用,避免再依赖 drugList) */
|
||||
const pendingNewChineseProduct = ref<any>(null);
|
||||
|
||||
/**
|
||||
* 选择药品
|
||||
* 中药气泡:选中新增行药名
|
||||
* @param item 商品检索完整行
|
||||
*/
|
||||
function onSelectNewChineseDrug(item: any) {
|
||||
const drugId = Number(item?.drug_id || item?.drug?.id || 0);
|
||||
if (!drugId) return;
|
||||
const check = currentDrugs.value.find((v) => Number(v.id) === drugId);
|
||||
if (check) {
|
||||
newDrugInfo.value.id = '';
|
||||
newDrugInfo.value.name = '';
|
||||
pendingNewChineseProduct.value = null;
|
||||
message.error('该药品已经在处方中了!');
|
||||
return;
|
||||
}
|
||||
pendingNewChineseProduct.value = item;
|
||||
newDrugInfo.value.id = drugId;
|
||||
newDrugInfo.value.price = item.price;
|
||||
newDrugInfo.value.name = item.drug?.drug_name || '';
|
||||
newDrugInfo.value.unit =
|
||||
item.drug?.unit ||
|
||||
drugUnit.value.find((u) => u.id === item.drug?.unit_id);
|
||||
newDrugInfo.value.unit_id = item.drug?.unit_id;
|
||||
setTimeout(() => {
|
||||
const newDrugNumberInput = document.querySelector(
|
||||
'.new-number-input input',
|
||||
);
|
||||
if (newDrugNumberInput) {
|
||||
(newDrugNumberInput as HTMLElement).focus();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* 中药气泡:替换已选行药名
|
||||
* @param index 行下标
|
||||
* @param item 商品检索完整行
|
||||
*/
|
||||
function onSelectOldChineseDrug(index: number, item: any) {
|
||||
if (guardSpecialPrescriptionCartEdit()) return;
|
||||
const drugId = Number(item?.drug?.id || item?.drug_id || 0);
|
||||
if (!drugId) return;
|
||||
const check = currentDrugs.value.find(
|
||||
(v, i) => i !== index && Number(v.id) === drugId,
|
||||
);
|
||||
if (check) {
|
||||
message.error('该药品已经在处方中了!');
|
||||
return;
|
||||
}
|
||||
const data = item;
|
||||
const newProduct = {
|
||||
index_id: data.id,
|
||||
id: data.drug.id,
|
||||
drug_name: data.drug.drug_name,
|
||||
number: data.drug.number,
|
||||
use_num: drugTime.value.find((u) => u.id === data.drug.time_id),
|
||||
use_type: drugUseType.value.find((u) => u.id === data.drug.type_id),
|
||||
use_frequency: drugUseFrequency.value.find(
|
||||
(u) => u.id === data.drug.frequency_id,
|
||||
),
|
||||
unit:
|
||||
data.drug?.unit ||
|
||||
drugUnit.value.find((u) => u.id === data.drug.unit_id),
|
||||
price: data.price,
|
||||
buy_price: data.buy_price,
|
||||
way_id: data.drug?.way_id,
|
||||
use_ways: drugUseWay.value.find((u) => u.id === data.drug.way_id),
|
||||
time_id: data.drug.time_id,
|
||||
type_id: data.drug.type_id,
|
||||
frequency_id: data.drug.frequency_id,
|
||||
unit_id: data.drug.unit_id,
|
||||
image: data.drug.image,
|
||||
instruction: data.drug.instruction,
|
||||
type: data.drug.type,
|
||||
};
|
||||
currentDrugs.value[index] = newProduct;
|
||||
updateLocalStorage();
|
||||
setTimeout(() => {
|
||||
const numberInput = document.querySelector(
|
||||
`.old-number-input-${index} input`,
|
||||
);
|
||||
if (numberInput) {
|
||||
(numberInput as HTMLElement).focus();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
/** 兼容西药等仍走 Select 的旧逻辑 */
|
||||
function selectNewDrugInfo() {
|
||||
// 如果是新药品输入框,调用添加新药品方法
|
||||
const check = currentDrugs.value.find((v) => v.id === newDrugInfo.value.id);
|
||||
if (check) {
|
||||
newDrugInfo.value.id = '';
|
||||
message.error('该药品已经在处方中了!');
|
||||
return;
|
||||
}
|
||||
|
||||
const data = drugList.value.find((v) => v.drug_id === newDrugInfo.value.id);
|
||||
if (!data) return;
|
||||
pendingNewChineseProduct.value = data;
|
||||
newDrugInfo.value.price = data.price;
|
||||
newDrugInfo.value.name = data.drug.drug_name;
|
||||
// 选药后立刻带上真实单位,供新行数量后缀展示(优先接口返回的 unit)
|
||||
newDrugInfo.value.unit =
|
||||
data.drug?.unit ||
|
||||
drugUnit.value.find((item) => item.id === data.drug?.unit_id);
|
||||
newDrugInfo.value.unit_id = data.drug?.unit_id;
|
||||
setTimeout(() => {
|
||||
// 获取新药品卡片中的数量输入框并聚焦
|
||||
const newDrugNumberInput = document.querySelector(
|
||||
'.new-number-input input',
|
||||
);
|
||||
@@ -2634,7 +2722,7 @@ const selectChineseIndex = ref(-1);
|
||||
const selectChineseId = ref(0);
|
||||
|
||||
/**
|
||||
* 选择药品
|
||||
* 选择药品(西药等 Select 仍用)
|
||||
* @param id
|
||||
*/
|
||||
function selectOldDrugInfo(id) {
|
||||
@@ -2648,59 +2736,36 @@ function selectOldDrugInfo(id) {
|
||||
message.error('该药品已经在处方中了!');
|
||||
return;
|
||||
}
|
||||
const oldDrugInfo = currentDrugs.value[selectChineseIndex.value];
|
||||
// 如果是新药品输入框,调用添加新药品方法
|
||||
const data = drugList.value.find((v) => v.drug_id === id);
|
||||
|
||||
// 创建新的商品对象(避免直接修改原始数据)
|
||||
if (!data) return;
|
||||
const newProduct = {
|
||||
// 索引ID(用于在列表中查找)
|
||||
index_id: data.id,
|
||||
// 药品ID
|
||||
id: data.drug.id,
|
||||
// 药品名称
|
||||
drug_name: data.drug.drug_name,
|
||||
// 药品数量
|
||||
number: data.drug.number,
|
||||
// 药品使用数量信息
|
||||
use_num: drugTime.value.find((item) => item.id === data.drug.time_id),
|
||||
// 药品使用类型信息
|
||||
use_type: drugUseType.value.find((item) => item.id === data.drug.type_id),
|
||||
// 药品使用频率信息
|
||||
use_frequency: drugUseFrequency.value.find(
|
||||
(item) => item.id === data.drug.frequency_id,
|
||||
),
|
||||
// 药品单位:优先用选药接口返回的 unit,再回退本地字典
|
||||
unit:
|
||||
data.drug?.unit ||
|
||||
drugUnit.value.find((item) => item.id === data.drug.unit_id),
|
||||
// 药品价格
|
||||
price: data.price,
|
||||
buy_price: data.buy_price,
|
||||
// 药品使用方式ID
|
||||
way_id: data.drug?.way_id,
|
||||
// 药品使用方式信息
|
||||
use_ways: drugUseWay.value.find((item) => item.id === data.drug.way_id),
|
||||
// 药品使用时间ID
|
||||
time_id: data.drug.time_id,
|
||||
// 药品类型ID
|
||||
type_id: data.drug.type_id,
|
||||
// 药品使用频率ID
|
||||
frequency_id: data.drug.frequency_id,
|
||||
// 药品单位ID
|
||||
unit_id: data.drug.unit_id,
|
||||
// 药品图片
|
||||
image: data.drug.image,
|
||||
// 药品说明书
|
||||
instruction: data.drug.instruction,
|
||||
// 药品类型
|
||||
type: data.drug.type,
|
||||
};
|
||||
currentDrugs.value[selectChineseIndex.value] = newProduct;
|
||||
updateLocalStorage();
|
||||
// const data = drugList.value.find((v) => v.drug_id === id);
|
||||
setTimeout(() => {
|
||||
// 获取新药品卡片中的克数输入框并聚焦
|
||||
const newDrugNumberInput = document.querySelector(
|
||||
`.old-number-input-${selectChineseIndex.value} input`,
|
||||
);
|
||||
@@ -2732,7 +2797,6 @@ function searchOption(inputValue) {
|
||||
*/
|
||||
function addDrugByChinese() {
|
||||
if (guardSpecialPrescriptionCartEdit()) return;
|
||||
// 如果是新药品输入框,调用添加新药品方法
|
||||
const check = currentDrugs.value.find(
|
||||
(v) => v.id === newDrugInfo.value.id,
|
||||
);
|
||||
@@ -2740,9 +2804,10 @@ function addDrugByChinese() {
|
||||
message.error('该药品已经在处方中了!');
|
||||
return;
|
||||
}
|
||||
const data = drugList.value.find(
|
||||
(v) => v.drug_id === newDrugInfo.value.id,
|
||||
);
|
||||
// 优先用气泡选中缓存,兼容西药 Select 仍写在 drugList 的场景
|
||||
const data =
|
||||
pendingNewChineseProduct.value ||
|
||||
drugList.value.find((v) => v.drug_id === newDrugInfo.value.id);
|
||||
if (data === null || data === undefined) {
|
||||
message.error('请选择药品');
|
||||
return;
|
||||
@@ -2751,6 +2816,7 @@ function addDrugByChinese() {
|
||||
data.drug.way_id = newDrugInfo.value.way_id;
|
||||
addProducts(data);
|
||||
newDrugInfo.value = {};
|
||||
pendingNewChineseProduct.value = null;
|
||||
}
|
||||
/**
|
||||
* 添加操作
|
||||
@@ -3430,32 +3496,17 @@ function onStoreSelectOpenChange(open: boolean) {
|
||||
<div>
|
||||
<span class="card-index">{{ index + 1 }}、</span>
|
||||
<p>
|
||||
<Select
|
||||
v-model:value="drug.id"
|
||||
<ChineseDrugNameBubble
|
||||
:display-name="drug.drug_name"
|
||||
:disabled="isSpecialPrescriptionCartLocked"
|
||||
:filter-option="false"
|
||||
class="old-select-drug-name"
|
||||
style="min-width: 100px"
|
||||
:store-id="myStoreId"
|
||||
:register-id="getRegisterId()"
|
||||
:type="1"
|
||||
compact
|
||||
input-class="old-select-drug-name"
|
||||
placeholder="药名"
|
||||
show-search
|
||||
@change="selectOldDrugInfo"
|
||||
@dropdown-visible-change="
|
||||
setSelectChineseIndex(index, drug.id)
|
||||
"
|
||||
@search="searchOption"
|
||||
>
|
||||
<SelectOption v-if="drugList.length === 0" :value="drug.id">
|
||||
{{ drug.drug_name }}
|
||||
</SelectOption>
|
||||
<SelectOption
|
||||
v-for="(value, index) in drugList"
|
||||
v-else
|
||||
:key="index"
|
||||
:value="value.drug.id"
|
||||
>
|
||||
{{ value.drug.drug_name }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
@select="(item) => onSelectOldChineseDrug(index, item)"
|
||||
/>
|
||||
,
|
||||
<InputNumber
|
||||
v-model:value="drug.number"
|
||||
@@ -3523,24 +3574,16 @@ function onStoreSelectOpenChange(open: boolean) {
|
||||
<div>
|
||||
<span class="card-index">{{ currentDrugs.length + 1 }}、</span>
|
||||
<div>
|
||||
<Select
|
||||
v-model:value="newDrugInfo.id"
|
||||
:filter-option="false"
|
||||
class="new-select-drug-name w-1/5"
|
||||
<ChineseDrugNameBubble
|
||||
:display-name="newDrugInfo.name || ''"
|
||||
:store-id="myStoreId"
|
||||
:register-id="getRegisterId()"
|
||||
:type="1"
|
||||
compact
|
||||
input-class="new-select-drug-name"
|
||||
placeholder="药名"
|
||||
show-search
|
||||
style="min-width: 100px"
|
||||
@change="selectNewDrugInfo"
|
||||
@search="searchOption"
|
||||
>
|
||||
<SelectOption
|
||||
v-for="(value, index) in drugList"
|
||||
:key="index"
|
||||
:value="value.drug_id"
|
||||
>
|
||||
{{ value.drug.drug_name }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
@select="onSelectNewChineseDrug"
|
||||
/>
|
||||
,
|
||||
<InputNumber
|
||||
v-model:value="newDrugInfo.number"
|
||||
@@ -4154,6 +4197,14 @@ function onStoreSelectOpenChange(open: boolean) {
|
||||
left: 10px;
|
||||
top: 0;
|
||||
}
|
||||
/* 中药卡片:药名气泡锁宽,与克数/用法保持同一行 */
|
||||
:deep(.chinese-drug-name-bubble) {
|
||||
width: 100px !important;
|
||||
min-width: 88px !important;
|
||||
max-width: 110px !important;
|
||||
flex: 0 0 100px !important;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.card-price {
|
||||
position: absolute;
|
||||
|
||||
@@ -40,8 +40,8 @@ import {
|
||||
SelectOption,
|
||||
Spin,
|
||||
} from 'ant-design-vue';
|
||||
import { debounce } from 'lodash-es';
|
||||
|
||||
import { ChineseDrugNameBubble } from '#/components/chinese-drug-name-bubble';
|
||||
import { DrugSearchSelect } from '#/components/drug-search-select';
|
||||
import {
|
||||
saveWestCommonPrescriptionApi,
|
||||
@@ -50,7 +50,6 @@ import {
|
||||
} from '#/views/doctor/settings/api';
|
||||
import {
|
||||
getDrugUseList,
|
||||
getProductListDoctorReception,
|
||||
getProcessRuleList,
|
||||
} from '#/views/doctor/doctor-reception/api';
|
||||
import {
|
||||
@@ -173,10 +172,6 @@ const processRuleNoteList = ref<any[]>([]);
|
||||
*/
|
||||
let onSaveCallback: (() => void) | null = null;
|
||||
|
||||
/**
|
||||
* 中药搜索关键词列表(每个药品对应一个搜索结果)
|
||||
*/
|
||||
const chineseSearchResults = ref<any[]>([]);
|
||||
|
||||
/**
|
||||
* 新药品输入数据
|
||||
@@ -364,75 +359,38 @@ function handleTypeChange() {
|
||||
// 切换类型时清空药品列表
|
||||
drugList.value = [];
|
||||
newDrugInfo.value = {};
|
||||
chineseSearchResults.value = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索中药(防抖)
|
||||
* @param keyword 搜索关键词
|
||||
* 中药气泡:选中新增行
|
||||
* @param selectedItem 商品检索完整行
|
||||
*/
|
||||
const searchChineseDrugs = debounce(async (keyword: string) => {
|
||||
if (!keyword || keyword.length < 1) {
|
||||
chineseSearchResults.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await getProductListDoctorReception({
|
||||
name: keyword,
|
||||
type: 1, // 中药类型
|
||||
store_id: userStore.userInfo?.store_id || 2,
|
||||
});
|
||||
|
||||
if (Array.isArray(res)) {
|
||||
chineseSearchResults.value = res;
|
||||
} else {
|
||||
chineseSearchResults.value = [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('搜索中药失败:', error);
|
||||
chineseSearchResults.value = [];
|
||||
}
|
||||
}, 300);
|
||||
|
||||
/**
|
||||
* 选择新药品
|
||||
* @param drugId 药品ID(drug.id)
|
||||
*/
|
||||
function selectNewDrug(drugId: number) {
|
||||
// 检查是否已存在
|
||||
function selectNewDrug(selectedItem: any) {
|
||||
const drugId = Number(selectedItem?.drug?.id || selectedItem?.drug_id || 0);
|
||||
if (!drugId) return;
|
||||
const exists = drugList.value.some(
|
||||
(item) => item.id === drugId || item.drug_id === drugId,
|
||||
);
|
||||
|
||||
if (exists) {
|
||||
message.warning('该药品已在列表中');
|
||||
newDrugInfo.value.id = undefined;
|
||||
newDrugInfo.value.name = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// 找到选中的药品信息
|
||||
const selectedItem = chineseSearchResults.value.find(
|
||||
(item) => item.drug?.id === drugId || item.drug_id === drugId,
|
||||
);
|
||||
|
||||
if (selectedItem) {
|
||||
newDrugInfo.value.name = selectedItem.drug?.drug_name || '';
|
||||
newDrugInfo.value.price = selectedItem.price || 0;
|
||||
newDrugInfo.value.way_id = 0;
|
||||
newDrugInfo.value.unit =
|
||||
selectedItem.drug?.unit || selectedItem.unit || null;
|
||||
newDrugInfo.value.unit_id =
|
||||
selectedItem.drug?.unit_id || selectedItem.unit_id || 0;
|
||||
|
||||
// 聚焦到数量输入框
|
||||
nextTick(() => {
|
||||
const numberInput = document.querySelector('.new-chinese-number input') as HTMLInputElement;
|
||||
if (numberInput) {
|
||||
numberInput.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
newDrugInfo.value.id = drugId;
|
||||
newDrugInfo.value.name = selectedItem.drug?.drug_name || '';
|
||||
newDrugInfo.value.price = selectedItem.price || 0;
|
||||
newDrugInfo.value.way_id = 0;
|
||||
newDrugInfo.value.unit =
|
||||
selectedItem.drug?.unit || selectedItem.unit || null;
|
||||
newDrugInfo.value.unit_id =
|
||||
selectedItem.drug?.unit_id || selectedItem.unit_id || 0;
|
||||
nextTick(() => {
|
||||
const numberInput = document.querySelector(
|
||||
'.new-chinese-number input',
|
||||
) as HTMLInputElement;
|
||||
numberInput?.focus();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -474,7 +432,6 @@ function addChineseDrug() {
|
||||
|
||||
// 清空并准备下一次输入
|
||||
newDrugInfo.value = {};
|
||||
chineseSearchResults.value = [];
|
||||
|
||||
message.success('已添加药品');
|
||||
|
||||
@@ -488,50 +445,35 @@ function addChineseDrug() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改已有中药(切换药品)
|
||||
* 中药气泡:替换已有行
|
||||
* @param index 药品索引
|
||||
* @param drugId 新药品ID
|
||||
* @param selectedItem 商品检索完整行
|
||||
*/
|
||||
function changeChineseDrug(index: number, drugId: number) {
|
||||
// 检查是否已存在(排除当前正在修改的)
|
||||
function changeChineseDrug(index: number, selectedItem: any) {
|
||||
const drugId = Number(selectedItem?.drug?.id || selectedItem?.drug_id || 0);
|
||||
if (!drugId) return;
|
||||
const exists = drugList.value.some(
|
||||
(item, i) => i !== index && (item.id === drugId || item.drug_id === drugId),
|
||||
);
|
||||
|
||||
if (exists) {
|
||||
message.warning('该药品已在列表中');
|
||||
// 恢复原来的值
|
||||
const drug = drugList.value[index];
|
||||
if (drug) {
|
||||
drug.id = drug.drug_id;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 找到选中的药品信息
|
||||
const selectedItem = chineseSearchResults.value.find(
|
||||
(item) => item.drug?.id === drugId || item.drug_id === drugId,
|
||||
);
|
||||
|
||||
if (selectedItem) {
|
||||
const drug = drugList.value[index];
|
||||
if (drug) {
|
||||
drug.id = drugId;
|
||||
drug.drug_id = drugId;
|
||||
drug.drug_name = selectedItem.drug?.drug_name || '';
|
||||
drug.price = selectedItem.price || 0;
|
||||
drug.unit = selectedItem.drug?.unit || selectedItem.unit || null;
|
||||
drug.unit_id = selectedItem.drug?.unit_id || selectedItem.unit_id || 0;
|
||||
}
|
||||
|
||||
// 聚焦到数量输入框
|
||||
nextTick(() => {
|
||||
const numberInput = document.querySelector(`.chinese-number-${index} input`) as HTMLInputElement;
|
||||
if (numberInput) {
|
||||
numberInput.focus();
|
||||
}
|
||||
});
|
||||
const drug = drugList.value[index];
|
||||
if (drug) {
|
||||
drug.id = drugId;
|
||||
drug.drug_id = drugId;
|
||||
drug.drug_name = selectedItem.drug?.drug_name || '';
|
||||
drug.price = selectedItem.price || 0;
|
||||
drug.unit = selectedItem.drug?.unit || selectedItem.unit || null;
|
||||
drug.unit_id = selectedItem.drug?.unit_id || selectedItem.unit_id || 0;
|
||||
}
|
||||
nextTick(() => {
|
||||
const numberInput = document.querySelector(
|
||||
`.chinese-number-${index} input`,
|
||||
) as HTMLInputElement;
|
||||
numberInput?.focus();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -779,7 +721,7 @@ async function handleSave() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal class="w-[900px]">
|
||||
<Modal class="w-[50%]">
|
||||
<Spin :spinning="isSaving">
|
||||
<div class="p-4">
|
||||
<!-- 类型选择 -->
|
||||
@@ -1100,30 +1042,15 @@ async function handleSave() {
|
||||
<div class="chinese-drug-content">
|
||||
<span class="chinese-drug-index">{{ index + 1 }}、</span>
|
||||
<div class="chinese-drug-form">
|
||||
<Select
|
||||
v-model:value="drug.id"
|
||||
show-search
|
||||
:filter-option="false"
|
||||
<ChineseDrugNameBubble
|
||||
:display-name="drug.drug_name"
|
||||
:store-id="userStore.userInfo?.store_id || 0"
|
||||
:type="1"
|
||||
compact
|
||||
input-class="chinese-drug-name"
|
||||
placeholder="药名"
|
||||
class="chinese-drug-name"
|
||||
@search="searchChineseDrugs"
|
||||
@change="(val) => changeChineseDrug(index, val)"
|
||||
>
|
||||
<SelectOption
|
||||
v-if="chineseSearchResults.length === 0"
|
||||
:value="drug.id"
|
||||
>
|
||||
{{ drug.drug_name }}
|
||||
</SelectOption>
|
||||
<SelectOption
|
||||
v-for="item in chineseSearchResults"
|
||||
v-else
|
||||
:key="item.drug?.id || item.id"
|
||||
:value="item.drug?.id || item.id"
|
||||
>
|
||||
{{ item.drug?.drug_name || item.drug_name }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
@select="(item) => changeChineseDrug(index, item)"
|
||||
/>
|
||||
<span class="chinese-drug-comma">,</span>
|
||||
<InputNumber
|
||||
v-model:value="drug.number"
|
||||
@@ -1169,23 +1096,15 @@ async function handleSave() {
|
||||
<div class="chinese-drug-content">
|
||||
<span class="chinese-drug-index">{{ drugList.length + 1 }}、</span>
|
||||
<div class="chinese-drug-form">
|
||||
<Select
|
||||
v-model:value="newDrugInfo.id"
|
||||
show-search
|
||||
:filter-option="false"
|
||||
<ChineseDrugNameBubble
|
||||
:display-name="newDrugInfo.name || ''"
|
||||
:store-id="userStore.userInfo?.store_id || 0"
|
||||
:type="1"
|
||||
compact
|
||||
input-class="chinese-drug-name new-chinese-name"
|
||||
placeholder="药名"
|
||||
class="chinese-drug-name new-chinese-name"
|
||||
@search="searchChineseDrugs"
|
||||
@change="selectNewDrug"
|
||||
>
|
||||
<SelectOption
|
||||
v-for="item in chineseSearchResults"
|
||||
:key="item.drug?.id || item.id"
|
||||
:value="item.drug?.id || item.id"
|
||||
>
|
||||
{{ item.drug?.drug_name || item.drug_name }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
@select="selectNewDrug"
|
||||
/>
|
||||
<span class="chinese-drug-comma">,</span>
|
||||
<InputNumber
|
||||
v-model:value="newDrugInfo.number"
|
||||
@@ -1301,15 +1220,18 @@ async function handleSave() {
|
||||
|
||||
.chinese-drug-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding-left: 28px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chinese-drug-name {
|
||||
min-width: 80px;
|
||||
max-width: 120px;
|
||||
/* 药名气泡锁宽,与克数/用法保持同一行 */
|
||||
.chinese-drug-form :deep(.chinese-drug-name-bubble) {
|
||||
width: 100px !important;
|
||||
min-width: 88px !important;
|
||||
max-width: 110px !important;
|
||||
flex: 0 0 100px !important;
|
||||
}
|
||||
|
||||
.chinese-drug-comma {
|
||||
|
||||
@@ -39,8 +39,7 @@ import {
|
||||
Spin,
|
||||
Tag,
|
||||
} from 'ant-design-vue';
|
||||
import { debounce } from 'lodash-es';
|
||||
|
||||
import { ChineseDrugNameBubble } from '#/components/chinese-drug-name-bubble';
|
||||
import { DrugSearchSelect } from '#/components/drug-search-select';
|
||||
import {
|
||||
updateWestCommonPrescriptionApi,
|
||||
@@ -49,7 +48,6 @@ import {
|
||||
} from '#/views/doctor/settings/api';
|
||||
import {
|
||||
getDrugUseList,
|
||||
getProductListDoctorReception,
|
||||
getProcessRuleList,
|
||||
} from '#/views/doctor/doctor-reception/api';
|
||||
import {
|
||||
@@ -173,10 +171,6 @@ const processRuleNoteList = ref<any[]>([]);
|
||||
*/
|
||||
let onSaveCallback: (() => void) | null = null;
|
||||
|
||||
/**
|
||||
* 中药搜索结果列表
|
||||
*/
|
||||
const chineseSearchResults = ref<any[]>([]);
|
||||
|
||||
/**
|
||||
* 新药品输入数据
|
||||
@@ -287,7 +281,7 @@ const [Modal, modalApi] = useVbenModal({
|
||||
loadDrugUseData();
|
||||
// 加载委托调剂选项(第一级:制剂)
|
||||
await loadProcessRuleData(0, 0);
|
||||
|
||||
|
||||
// 如果有已保存的委托调剂配置,需要级联加载(顺序执行)
|
||||
if (processRuleId.value) {
|
||||
await loadProcessRuleData(processRuleId.value, 0);
|
||||
@@ -410,72 +404,35 @@ function openDiagnosisModal() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索中药(防抖)
|
||||
* @param keyword 搜索关键词
|
||||
* 中药气泡:选中新增行
|
||||
* @param selectedItem 商品检索完整行
|
||||
*/
|
||||
const searchChineseDrugs = debounce(async (keyword: string) => {
|
||||
if (!keyword || keyword.length < 1) {
|
||||
chineseSearchResults.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await getProductListDoctorReception({
|
||||
name: keyword,
|
||||
type: 1, // 中药类型
|
||||
store_id: userStore.userInfo?.store_id || 2,
|
||||
});
|
||||
|
||||
if (Array.isArray(res)) {
|
||||
chineseSearchResults.value = res;
|
||||
} else {
|
||||
chineseSearchResults.value = [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('搜索中药失败:', error);
|
||||
chineseSearchResults.value = [];
|
||||
}
|
||||
}, 300);
|
||||
|
||||
/**
|
||||
* 选择新药品
|
||||
* @param drugId 药品ID
|
||||
*/
|
||||
function selectNewDrug(drugId: number) {
|
||||
// 检查是否已存在
|
||||
function selectNewDrug(selectedItem: any) {
|
||||
const drugId = Number(selectedItem?.drug?.id || selectedItem?.drug_id || 0);
|
||||
if (!drugId) return;
|
||||
const exists = drugList.value.some(
|
||||
(item) => item.id === drugId || item.drug_id === drugId,
|
||||
);
|
||||
|
||||
if (exists) {
|
||||
message.warning('该药品已在列表中');
|
||||
newDrugInfo.value.id = undefined;
|
||||
newDrugInfo.value.name = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// 找到选中的药品信息
|
||||
const selectedItem = chineseSearchResults.value.find(
|
||||
(item) => item.drug?.id === drugId || item.drug_id === drugId,
|
||||
);
|
||||
|
||||
if (selectedItem) {
|
||||
newDrugInfo.value.name = selectedItem.drug?.drug_name || '';
|
||||
newDrugInfo.value.price = selectedItem.price || 0;
|
||||
newDrugInfo.value.way_id = 0;
|
||||
// 选药后带上真实单位,供数量后缀展示
|
||||
newDrugInfo.value.unit =
|
||||
selectedItem.drug?.unit || selectedItem.unit || null;
|
||||
newDrugInfo.value.unit_id =
|
||||
selectedItem.drug?.unit_id || selectedItem.unit_id || 0;
|
||||
|
||||
// 聚焦到数量输入框
|
||||
nextTick(() => {
|
||||
const numberInput = document.querySelector('.edit-new-chinese-number input') as HTMLInputElement;
|
||||
if (numberInput) {
|
||||
numberInput.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
newDrugInfo.value.id = drugId;
|
||||
newDrugInfo.value.name = selectedItem.drug?.drug_name || '';
|
||||
newDrugInfo.value.price = selectedItem.price || 0;
|
||||
newDrugInfo.value.way_id = 0;
|
||||
newDrugInfo.value.unit =
|
||||
selectedItem.drug?.unit || selectedItem.unit || null;
|
||||
newDrugInfo.value.unit_id =
|
||||
selectedItem.drug?.unit_id || selectedItem.unit_id || 0;
|
||||
nextTick(() => {
|
||||
const numberInput = document.querySelector(
|
||||
'.edit-new-chinese-number input',
|
||||
) as HTMLInputElement;
|
||||
numberInput?.focus();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -517,7 +474,6 @@ function addChineseDrug() {
|
||||
|
||||
// 清空并准备下一次输入
|
||||
newDrugInfo.value = {};
|
||||
chineseSearchResults.value = [];
|
||||
|
||||
message.success('已添加药品');
|
||||
|
||||
@@ -531,50 +487,35 @@ function addChineseDrug() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改已有中药(切换药品)
|
||||
* 中药气泡:替换已有行
|
||||
* @param index 药品索引
|
||||
* @param drugId 新药品ID
|
||||
* @param selectedItem 商品检索完整行
|
||||
*/
|
||||
function changeChineseDrug(index: number, drugId: number) {
|
||||
// 检查是否已存在(排除当前正在修改的)
|
||||
function changeChineseDrug(index: number, selectedItem: any) {
|
||||
const drugId = Number(selectedItem?.drug?.id || selectedItem?.drug_id || 0);
|
||||
if (!drugId) return;
|
||||
const exists = drugList.value.some(
|
||||
(item, i) => i !== index && (item.id === drugId || item.drug_id === drugId),
|
||||
);
|
||||
|
||||
if (exists) {
|
||||
message.warning('该药品已在列表中');
|
||||
// 恢复原来的值
|
||||
const drug = drugList.value[index];
|
||||
if (drug) {
|
||||
drug.id = drug.drug_id;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 找到选中的药品信息
|
||||
const selectedItem = chineseSearchResults.value.find(
|
||||
(item) => item.drug?.id === drugId || item.drug_id === drugId,
|
||||
);
|
||||
|
||||
if (selectedItem) {
|
||||
const drug = drugList.value[index];
|
||||
if (drug) {
|
||||
drug.id = drugId;
|
||||
drug.drug_id = drugId;
|
||||
drug.drug_name = selectedItem.drug?.drug_name || '';
|
||||
drug.price = selectedItem.price || 0;
|
||||
drug.unit = selectedItem.drug?.unit || selectedItem.unit || null;
|
||||
drug.unit_id = selectedItem.drug?.unit_id || selectedItem.unit_id || 0;
|
||||
}
|
||||
|
||||
// 聚焦到数量输入框
|
||||
nextTick(() => {
|
||||
const numberInput = document.querySelector(`.edit-chinese-number-${index} input`) as HTMLInputElement;
|
||||
if (numberInput) {
|
||||
numberInput.focus();
|
||||
}
|
||||
});
|
||||
const drug = drugList.value[index];
|
||||
if (drug) {
|
||||
drug.id = drugId;
|
||||
drug.drug_id = drugId;
|
||||
drug.drug_name = selectedItem.drug?.drug_name || '';
|
||||
drug.price = selectedItem.price || 0;
|
||||
drug.unit = selectedItem.drug?.unit || selectedItem.unit || null;
|
||||
drug.unit_id = selectedItem.drug?.unit_id || selectedItem.unit_id || 0;
|
||||
}
|
||||
nextTick(() => {
|
||||
const numberInput = document.querySelector(
|
||||
`.edit-chinese-number-${index} input`,
|
||||
) as HTMLInputElement;
|
||||
numberInput?.focus();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -807,7 +748,7 @@ async function handleSave() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal class="w-[900px]">
|
||||
<Modal class="w-[50%]">
|
||||
<Spin :spinning="isSaving">
|
||||
<div class="p-4">
|
||||
<!-- 类型标签 -->
|
||||
@@ -1119,30 +1060,15 @@ async function handleSave() {
|
||||
<div class="chinese-drug-content">
|
||||
<span class="chinese-drug-index">{{ index + 1 }}、</span>
|
||||
<div class="chinese-drug-form">
|
||||
<Select
|
||||
v-model:value="drug.id"
|
||||
show-search
|
||||
:filter-option="false"
|
||||
<ChineseDrugNameBubble
|
||||
:display-name="drug.drug_name"
|
||||
:store-id="userStore.userInfo?.store_id || 0"
|
||||
:type="1"
|
||||
compact
|
||||
input-class="chinese-drug-name"
|
||||
placeholder="药名"
|
||||
class="chinese-drug-name"
|
||||
@search="searchChineseDrugs"
|
||||
@change="(val) => changeChineseDrug(index, val)"
|
||||
>
|
||||
<SelectOption
|
||||
v-if="chineseSearchResults.length === 0"
|
||||
:value="drug.id"
|
||||
>
|
||||
{{ drug.drug_name }}
|
||||
</SelectOption>
|
||||
<SelectOption
|
||||
v-for="item in chineseSearchResults"
|
||||
v-else
|
||||
:key="item.drug?.id || item.id"
|
||||
:value="item.drug?.id || item.id"
|
||||
>
|
||||
{{ item.drug?.drug_name || item.drug_name }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
@select="(item) => changeChineseDrug(index, item)"
|
||||
/>
|
||||
<span class="chinese-drug-comma">,</span>
|
||||
<InputNumber
|
||||
v-model:value="drug.number"
|
||||
@@ -1188,23 +1114,15 @@ async function handleSave() {
|
||||
<div class="chinese-drug-content">
|
||||
<span class="chinese-drug-index">{{ drugList.length + 1 }}、</span>
|
||||
<div class="chinese-drug-form">
|
||||
<Select
|
||||
v-model:value="newDrugInfo.id"
|
||||
show-search
|
||||
:filter-option="false"
|
||||
<ChineseDrugNameBubble
|
||||
:display-name="newDrugInfo.name || ''"
|
||||
:store-id="userStore.userInfo?.store_id || 0"
|
||||
:type="1"
|
||||
compact
|
||||
input-class="chinese-drug-name edit-new-chinese-name"
|
||||
placeholder="药名"
|
||||
class="chinese-drug-name edit-new-chinese-name"
|
||||
@search="searchChineseDrugs"
|
||||
@change="selectNewDrug"
|
||||
>
|
||||
<SelectOption
|
||||
v-for="item in chineseSearchResults"
|
||||
:key="item.drug?.id || item.id"
|
||||
:value="item.drug?.id || item.id"
|
||||
>
|
||||
{{ item.drug?.drug_name || item.drug_name }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
@select="selectNewDrug"
|
||||
/>
|
||||
<span class="chinese-drug-comma">,</span>
|
||||
<InputNumber
|
||||
v-model:value="newDrugInfo.number"
|
||||
@@ -1290,15 +1208,18 @@ async function handleSave() {
|
||||
|
||||
.chinese-drug-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding-left: 28px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chinese-drug-name {
|
||||
min-width: 80px;
|
||||
max-width: 120px;
|
||||
/* 药名气泡锁宽,与克数/用法保持同一行 */
|
||||
.chinese-drug-form :deep(.chinese-drug-name-bubble) {
|
||||
width: 100px !important;
|
||||
min-width: 88px !important;
|
||||
max-width: 110px !important;
|
||||
flex: 0 0 100px !important;
|
||||
}
|
||||
|
||||
.chinese-drug-comma {
|
||||
|
||||
@@ -110,12 +110,15 @@ function openStoreCard(row: Record<string, any>) {
|
||||
StoreCardModalApi.open();
|
||||
}
|
||||
|
||||
// 打开二维码预览弹窗
|
||||
const openQrCodeModal = (url, title, address) => {
|
||||
/**
|
||||
* 打开药店二维码预览(本页固定 type=1)
|
||||
*/
|
||||
const openQrCodeModal = (url, title, address, type = 1) => {
|
||||
QrCodePreviewApi.setData({
|
||||
values: url, // 二维码图片URL
|
||||
title, // 标题
|
||||
address, // 地址
|
||||
values: url,
|
||||
title,
|
||||
address,
|
||||
type,
|
||||
});
|
||||
QrCodePreviewApi.open();
|
||||
};
|
||||
@@ -534,6 +537,7 @@ const batchSyncDrugPrice = () => {
|
||||
row.qr_code,
|
||||
row.name,
|
||||
`${row.province.name}${row.city.name}${row.position}`,
|
||||
row.type ?? 1,
|
||||
)
|
||||
"
|
||||
/>
|
||||
|
||||
@@ -149,12 +149,15 @@ const openAddDoctorModal = (row: any) => {
|
||||
addDoctorModalApi.open();
|
||||
};
|
||||
|
||||
const openQrCodeModal = (url, title, address) => {
|
||||
/**
|
||||
* 打开诊所二维码预览(本页固定 type=0)
|
||||
*/
|
||||
const openQrCodeModal = (url, title, address, type = 0) => {
|
||||
QrCodePreviewApi.setData({
|
||||
// 表单值
|
||||
values: url,
|
||||
title,
|
||||
address,
|
||||
type,
|
||||
});
|
||||
QrCodePreviewApi.open();
|
||||
};
|
||||
@@ -618,6 +621,7 @@ const handleSwitchClinicType = (row: any) => {
|
||||
row.qr_code,
|
||||
row.name,
|
||||
`${row.province.name}${row.city.name}${row.position}`,
|
||||
row.type ?? 0,
|
||||
)
|
||||
"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user