1. 特色方功能迭代(固定价格),固定价格目前统一使用药品id(-102),后期会考虑新增特色方的时候自动添加一个特色方药品
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled

2. 退款的时候可以退回分成
This commit is contained in:
李琦
2026-07-10 15:10:49 +08:00
parent a05917ac18
commit 026d0e0a48
9 changed files with 385 additions and 411 deletions

View File

@@ -22,6 +22,11 @@ import {
calcTotalMarginPercent,
isSeeRateEnabled,
} from '#/utils/chinesePrescriptionMargin';
import { calculateProcessingFee, parsePriceValue } from '#/utils/formatPrice';
import {
applySingleChildProcessRuleAutoSelect,
resolveProcessRuleLoadedLevel,
} from '#/utils/processRuleCascade';
import { getRegisterStoreInfo as getRegisterStoreInfoPharmacy } from '#/views/doctor/online-consultation/api';
import { getRegisterStoreInfo as getRegisterStoreInfoClinic } from '#/views/doctor/online-consultation-clinic/api';
import traditionalJson from '#/views/business/chat/config/traditional.json';
@@ -121,31 +126,16 @@ export const usePrescriptionStore = defineStore('prescription', () => {
);
});
const processRulePrice = ref(0);
const calcMethod = ref(0);
const processingFee = computed(() => {
if (ruleType.value === 1) return 0;
if (currentDrugs.value.length === 0) return 0;
if (ruleType.value !== 2 || currentDrugs.value.length === 0) return 0;
const processRule = childProcessRuleList.value.find(
(item) => item.id === childProcessRuleId.value,
);
if (!processRule) return 0;
calcMethod.value = processRule.calc_method;
processRulePrice.value = processRule.price;
if (calcMethod.value === 1) return processRulePrice.value;
if (calcMethod.value === 2) return processRulePrice.value * dosage.value;
if (calcMethod.value === 3) {
const totalNumber = currentDrugs.value.reduce(
(sum, drug) => sum + drug.number,
0,
);
return processRulePrice.value * dosage.value * totalNumber;
}
return 0;
const totalQty = currentDrugs.value.reduce(
(sum, drug) => sum + parsePriceValue(drug.number ?? 1),
0,
);
return calculateProcessingFee(processRule, dosage.value, totalQty);
});
const totalCost = computed(() => {
@@ -393,6 +383,38 @@ export const usePrescriptionStore = defineStore('prescription', () => {
} else {
childProcessRuleList.value = res;
}
await applySingleChildProcessRuleAutoSelect(
resolveProcessRuleLoadedLevel(pid, ruleId),
{
ruleType: ruleType.value,
processRuleId: processRuleId.value,
childProcessRuleId: childProcessRuleId.value,
processRuleNoteId: processRuleNoteId.value,
processRuleList: processRuleList.value,
childProcessRuleList: childProcessRuleList.value,
processRuleNoteList: processRuleNoteList.value,
load: getProcessRuleListData,
setProcessRuleId: (id) => {
processRuleId.value = id;
},
setChildProcessRuleId: (id) => {
childProcessRuleId.value = id;
},
setProcessRuleNoteId: (id) => {
processRuleNoteId.value = id;
},
clearBelowProcessRule: () => {
childProcessRuleId.value = undefined;
processRuleNoteId.value = undefined;
childProcessRuleList.value = [];
processRuleNoteList.value = [];
},
clearBelowChild: () => {
processRuleNoteId.value = undefined;
processRuleNoteList.value = [];
},
},
);
console.log('获取加工规则成功');
} catch (error) {
console.error('获取加工规则失败:', error);
@@ -796,6 +818,62 @@ export const usePrescriptionStore = defineStore('prescription', () => {
packageMethodId.value = id;
};
/**
* 中药配置变更(标签选择,对齐移动端级联逻辑)
*/
const handleChineseConfigChange = async (payload: {
ruleType?: number;
packageMethodId?: number | null;
processRuleId?: number | null;
childProcessRuleId?: number | null;
processRuleNoteId?: number | null;
dosage?: number;
dayDosage?: number;
}) => {
const oldRuleType = ruleType.value;
const oldProcessRuleId = processRuleId.value;
const oldChildProcessRuleId = childProcessRuleId.value;
if (payload.ruleType === 2 && payload.ruleType !== oldRuleType) {
if (processRuleList.value.length === 0) {
await getProcessRuleListData();
}
}
if (payload.ruleType === 1 && oldRuleType === 2) {
processRuleId.value = undefined;
childProcessRuleId.value = undefined;
processRuleNoteId.value = undefined;
processRuleList.value = [];
childProcessRuleList.value = [];
processRuleNoteList.value = [];
}
if (payload.processRuleId != null && payload.processRuleId !== oldProcessRuleId) {
childProcessRuleId.value = undefined;
processRuleNoteId.value = undefined;
childProcessRuleList.value = [];
processRuleNoteList.value = [];
}
if (payload.childProcessRuleId != null && payload.childProcessRuleId !== oldChildProcessRuleId) {
processRuleNoteId.value = undefined;
processRuleNoteList.value = [];
}
if (payload.ruleType != null) ruleType.value = payload.ruleType;
if (payload.packageMethodId !== undefined) packageMethodId.value = payload.packageMethodId ?? 2;
if (payload.processRuleId !== undefined) processRuleId.value = payload.processRuleId ?? undefined;
if (payload.childProcessRuleId !== undefined) childProcessRuleId.value = payload.childProcessRuleId ?? undefined;
if (payload.processRuleNoteId !== undefined) processRuleNoteId.value = payload.processRuleNoteId ?? undefined;
if (payload.dosage != null) dosage.value = payload.dosage;
if (payload.dayDosage != null) dayDosage.value = payload.dayDosage;
if (payload.processRuleId != null && payload.processRuleId !== oldProcessRuleId) {
await getProcessRuleListData(payload.processRuleId);
}
if (payload.childProcessRuleId != null && payload.childProcessRuleId !== oldChildProcessRuleId) {
await getProcessRuleListData(0, payload.childProcessRuleId);
}
};
// 中药相冲检查
const checkChineseMedicineConflict = async () => {
if (activeCategory.value === 2) {
@@ -897,7 +975,7 @@ export const usePrescriptionStore = defineStore('prescription', () => {
child_process_rule_id: childProcessRuleId.value,
process_rule_type: ruleType.value,
prescription_type: activeCategory.value,
processing_fee: processRulePrice.value,
processing_fee: processingFee.value,
dosage: dosage.value,
day_dosage: dayDosage.value,
doctor_second_sign: doctorSecondSignValue,
@@ -958,7 +1036,6 @@ export const usePrescriptionStore = defineStore('prescription', () => {
diagnosis.value = '';
medicalAdvice.value = '';
packageMethodId.value = 2;
processRulePrice.value = 0;
dosage.value = 7;
dayDosage.value = 2;
newDrugInfo.value = {};
@@ -1084,6 +1161,7 @@ export const usePrescriptionStore = defineStore('prescription', () => {
selectProcessRuleNot,
selectProcessRuleNotCommit,
selectPackageMethod,
handleChineseConfigChange,
checkChineseMedicineConflict,
sendPrescription,
resetForm,

View File

@@ -2,6 +2,7 @@ import { computed, ref, nextTick } from "vue"
import { message, notification } from "ant-design-vue"
import { debounce } from "lodash-es"
import { calculateProcessingFee, parsePriceValue } from '#/utils/formatPrice'
import {
addWestPrescription,
checkChineseMedicineConflictApi,
@@ -75,26 +76,14 @@ export const usePrescriptionStore = () => {
return currentDrugs.value.reduce((sum, drug) => sum + drug.price * (drug.select_number || 1), 0)
})
const processRulePrice = ref(0)
const calcMethod = ref(0)
const processingFee = computed(() => {
if (ruleType.value === 1) return 0
if (currentDrugs.value.length === 0) return 0
if (ruleType.value !== 2 || currentDrugs.value.length === 0) return 0
const processRule = childProcessRuleList.value.find((item) => item.id === childProcessRuleId.value)
if (!processRule) return 0
calcMethod.value = processRule.calc_method
processRulePrice.value = processRule.price
if (calcMethod.value === 1) return processRulePrice.value
if (calcMethod.value === 2) return processRulePrice.value * dosage.value
if (calcMethod.value === 3) {
const totalNumber = currentDrugs.value.reduce((sum, drug) => sum + drug.number, 0)
return processRulePrice.value * dosage.value * totalNumber
}
return 0
const totalQty = currentDrugs.value.reduce(
(sum, drug) => sum + parsePriceValue(drug.number ?? 1),
0,
)
return calculateProcessingFee(processRule, dosage.value, totalQty)
})
const totalCost = computed(() => {
@@ -548,7 +537,7 @@ export const usePrescriptionStore = () => {
child_process_rule_id: childProcessRuleId.value,
process_rule_type: ruleType.value,
prescription_type: activeCategory.value,
processing_fee: processRulePrice.value,
processing_fee: processingFee.value,
dosage: dosage.value,
day_dosage: dayDosage.value,
doctor_second_sign: doctorSecondSignValue,
@@ -569,7 +558,6 @@ export const usePrescriptionStore = () => {
diagnosis.value = ""
medicalAdvice.value = ""
packageMethodId.value = 2
processRulePrice.value = 0
dosage.value = 7
dayDosage.value = 2
newDrugInfo.value = {}

View File

@@ -67,3 +67,35 @@ export function calculateChineseProductPriceLikeBackend(
export function formatPriceDisplay(value: unknown): string {
return formatPriceLikeBackend(value).toFixed(2);
}
type ProcessRuleLine = {
calc_method?: number;
price?: unknown;
};
/**
* 计算委托调剂加工费(与移动端 PrescriptionCalculator.calculateProcessingFee 一致)
* calc_method: 1=固定价格2=按剂数3=按数量
*/
export function calculateProcessingFee(
processRule: ProcessRuleLine | null | undefined,
dosage = 7,
totalDrugQuantity = 0,
): number {
if (!processRule?.calc_method) {
return 0;
}
const price = parsePriceValue(processRule.price);
const dose = parsePriceValue(dosage);
const qty = parsePriceValue(totalDrugQuantity);
switch (processRule.calc_method) {
case 1:
return price;
case 2:
return price * dose;
case 3:
return price * dose * qty;
default:
return 0;
}
}

View File

@@ -53,7 +53,8 @@ import CommonPrescriptionModal from '#/views/doctor/doctor-reception/components/
// 信息提示模态框
import InfoModal from '#/components/modal/InfoModal.vue';
// 药品搜索选择组件
import { DrugSearchSelect } from '#/components/drug-search-select';
import { formatPriceDisplay } from '#/utils/formatPrice';
import ChineseMedicineConfig from '#/views/doctor/doctor-reception/components/ChineseMedicineConfig.vue';
const splitString = (input: string) => input.split(',');
@@ -82,11 +83,6 @@ const categories = [
{ label: '医疗器械', value: 7 },
];
const packageMethod = [
{ label: '味包', value: 1 },
{ label: '剂包', value: 2 },
];
// 使用 Pinia store
const prescriptionStore = usePrescriptionStore();
@@ -1361,165 +1357,21 @@ const cancelSaveCommonPrescription = () => {
/>
</div>
<!-- 中药配置 -->
<div v-if="prescriptionStore.activeCategory === 1" class="mb-5 border-t pt-4">
<RadioGroup v-model:value="prescriptionStore.ruleType">
<RadioButton :value="1">自制剂</RadioButton>
<RadioButton :value="2">委托调剂</RadioButton>
</RadioGroup>
<div v-if="prescriptionStore.ruleType === 1" class="mt-3">
<Select
:value="prescriptionStore.packageMethodId"
class="w-1/3"
placeholder="请选择包法"
@change="prescriptionStore.selectPackageMethod"
>
<SelectOption
v-for="(value, index) in packageMethod"
:key="index"
:value="value.value"
>
{{ value.label }}
</SelectOption>
</Select>
</div>
<div v-else-if="prescriptionStore.ruleType === 2" class="mt-3 flex gap-2">
<Select
:value="prescriptionStore.processRuleId"
class="flex-1"
placeholder="请选择制剂"
@change="prescriptionStore.selectProcessRule"
>
<SelectOption
v-for="(value, index) in prescriptionStore.processRuleList"
:key="index"
:value="value.id"
>
{{ value.name }}
</SelectOption>
</Select>
<Select
:value="prescriptionStore.childProcessRuleId"
class="flex-1"
placeholder="请选择煎法"
@change="prescriptionStore.selectProcessRuleNot"
>
<SelectOption
v-for="(value, index) in prescriptionStore.childProcessRuleList"
:key="index"
:value="value.id"
>
{{ value.name }}
</SelectOption>
</Select>
<Select
:value="prescriptionStore.processRuleNoteId"
class="flex-1"
placeholder="请选择备注"
@change="prescriptionStore.selectProcessRuleNotCommit"
>
<SelectOption
v-for="(value, index) in prescriptionStore.processRuleNoteList"
:key="index"
:value="value.id"
>
{{ value.note }}
</SelectOption>
</Select>
</div>
<div class="mt-5 flex gap-4 items-center flex-wrap">
<div class="flex items-center gap-2">
<span class="mr-2 whitespace-nowrap">用量:</span>
<div class="flex items-center border rounded" style="border-color: #d9d9d9;">
<Button
type="text"
size="small"
class="border-0 border-r rounded-l"
style="border-color: #d9d9d9;"
@click="
prescriptionStore.dosage =
prescriptionStore.dosage > 1
? prescriptionStore.dosage - 1
: 1
"
>
<MinusOutlined />
</Button>
<InputNumber
v-model:value="prescriptionStore.dosage"
:controls="false"
:min="1"
:max="100"
class="border-0"
style="width: 80px; text-align: center;"
/>
<Button
type="text"
size="small"
class="border-0 border-l rounded-r"
style="border-color: #d9d9d9;"
@click="
prescriptionStore.dosage =
prescriptionStore.dosage < 100
? prescriptionStore.dosage + 1
: 100
"
>
<PlusOutlined />
</Button>
</div>
<span class="ml-2 whitespace-nowrap">天 / {{ prescriptionStore.dosage }} 剂</span>
</div>
<div class="flex items-center gap-2">
<span class="mr-2 whitespace-nowrap">频次:</span>
<div class="flex items-center border rounded" style="border-color: #d9d9d9;">
<Button
type="text"
size="small"
class="border-0 border-r rounded-l"
style="border-color: #d9d9d9;"
@click="
prescriptionStore.dayDosage =
prescriptionStore.dayDosage > 1
? prescriptionStore.dayDosage - 1
: 1
"
>
<MinusOutlined />
</Button>
<InputNumber
v-model:value="prescriptionStore.dayDosage"
:controls="false"
:min="1"
:max="100"
class="border-0"
style="width: 80px; text-align: center;"
/>
<Button
type="text"
size="small"
class="border-0 border-l rounded-r"
style="border-color: #d9d9d9;"
@click="
prescriptionStore.dayDosage =
prescriptionStore.dayDosage < 100
? prescriptionStore.dayDosage + 1
: 100
"
>
<PlusOutlined />
</Button>
</div>
<span class="ml-2 whitespace-nowrap">次/天</span>
</div>
</div>
</div>
<ChineseMedicineConfig
v-if="prescriptionStore.activeCategory === 1"
:rule-type="prescriptionStore.ruleType"
:package-method-id="prescriptionStore.packageMethodId"
:process-rule-id="prescriptionStore.processRuleId"
:child-process-rule-id="prescriptionStore.childProcessRuleId"
:process-rule-note-id="prescriptionStore.processRuleNoteId"
:dosage="prescriptionStore.dosage"
:day-dosage="prescriptionStore.dayDosage"
:process-rule-list="prescriptionStore.processRuleList"
:child-process-rule-list="prescriptionStore.childProcessRuleList"
:process-rule-note-list="prescriptionStore.processRuleNoteList"
class="mb-5 border-t pt-4"
@change="prescriptionStore.handleChineseConfigChange"
/>
<!-- 诊疗费用 -->
<div class="mt-3 flex items-center">
@@ -1539,10 +1391,10 @@ const cancelSaveCommonPrescription = () => {
<div class="price-box mb-10">
<div class="flex justify-end gap-4 font-bold text-base mt-4">
<div v-if="prescriptionStore.processingFee > 0">
加工费:¥{{ prescriptionStore.processingFee.toFixed(2) }}
加工费:¥{{ formatPriceDisplay(prescriptionStore.processingFee) }}
</div>
<div>
商品价格:¥{{ prescriptionStore.totalProductCost.toFixed(2) }}
商品价格:¥{{ formatPriceDisplay(prescriptionStore.totalProductCost) }}
<span
v-if="prescriptionStore.chineseGrossMarginPercent !== null"
class="ml-3 text-orange-600"
@@ -1551,7 +1403,7 @@ const cancelSaveCommonPrescription = () => {
</span>
</div>
<div class="text-red-500">
总计:¥{{ prescriptionStore.totalCost.toFixed(2) }}
总计:¥{{ formatPriceDisplay(prescriptionStore.totalCost) }}
</div>
</div>
</div>

View File

@@ -14,6 +14,7 @@ import { formatPriceDiscountLabel, normalizeQuickOptions } from '#/utils/pricePe
import { expressDetailByOrderId, getOrderInfo } from '../api';
import SensitiveText from '#/components/sensitive-text/SensitiveText.vue';
import { formatDoctorOrderText } from '#/utils/prescriptionDoctorOrder';
defineOptions({
name: 'DetailModal',
@@ -414,7 +415,7 @@ function prescriptionStatusColor() {
{{ data.prescription.content.clinical_diagnose }}
</Descriptions.Item>
<Descriptions.Item label="医嘱">
{{ data.prescription.content.doctor_order }}
{{ formatDoctorOrderText(data.prescription) }}
</Descriptions.Item>
<Descriptions.Item label="开药医生">
{{ data.prescription.content.doctor.name }}

View File

@@ -6,6 +6,7 @@ import { Page, useVbenModal } from '@vben/common-ui';
import { Button } from 'ant-design-vue';
import { getPrescriptionInfoApi } from '#/views/doctor/doctor-reception/api';
import { formatDoctorOrderText } from '#/utils/prescriptionDoctorOrder';
const item = ref<Record<string, any>>({});
@@ -228,7 +229,7 @@ function parseRecipeContent(content: string | Record<string, unknown>) {
<div class="footer-section">
<div class="medical-advice">
<label>医嘱:</label>
{{ item.content?.doctor_order }}
{{ formatDoctorOrderText(item) }}
</div>
<div class="signature-area">
<div class="signature">

View File

@@ -6,8 +6,6 @@ import {useUserStore} from '@vben/stores';
import {
DeleteTwoTone,
MinusOutlined,
PlusOutlined,
SaveOutlined,
} from '@ant-design/icons-vue';
import {
@@ -67,6 +65,7 @@ import ConfirmModal from './components/ConfirmModal.vue';
// 信息提示模态框组件
import InfoModal from '#/components/modal/InfoModal.vue';
import SensitiveText from '#/components/sensitive-text/SensitiveText.vue';
import { detailDoctorOrderToText } from '#/utils/prescriptionDoctorOrder';
// 药品搜索选择组件
import { DrugSearchSelect } from '#/components/drug-search-select';
// 保存常用方API
@@ -96,7 +95,12 @@ import {
formatPriceDiscountLabel,
normalizeQuickOptions,
} from '#/utils/pricePercentAdjust';
import { calculateChineseProductPriceLikeBackend } from '#/utils/formatPrice';
import { calculateChineseProductPriceLikeBackend, calculateProcessingFee, formatPriceDisplay, parsePriceValue } from '#/utils/formatPrice';
import {
applySingleChildProcessRuleAutoSelect,
resolveProcessRuleLoadedLevel,
} from '#/utils/processRuleCascade';
import ChineseMedicineConfig, { type ChineseMedicineConfigChange } from './components/ChineseMedicineConfig.vue';
interface Patient {
id: number;
@@ -533,43 +537,21 @@ const totalCost = computed(() => {
return totalProductCost.value + processingFee.value;
});
const processRulePrice = ref(0);
const calcMethod = ref(0);
/**
* 计算加工费
* 计算加工费(委托调剂)
*/
const processingFee = computed(() => {
if (ruleType.value === 1) {
if (ruleType.value !== 2 || currentDrugs.value.length === 0) {
return 0;
}
// 已选择药品为空的时候是0
if (currentDrugs.value.length === 0) {
return 0;
}
// 获取本次选择的加工规则
childProcessRuleList.value.find((item) => {
if (item.id === childProcessRuleId.value) {
calcMethod.value = item.calc_method;
processRulePrice.value = item.price;
}
});
// 模式1固定价格模式
if (calcMethod.value === 1) {
return processRulePrice.value;
}
// 模式2单价*用量
if (calcMethod.value === 2) {
return processRulePrice.value * dosage.value;
}
// 模式2单价*用量
if (calcMethod.value === 3) {
const number = currentDrugs.value.reduce(
(sum, drug) => sum + drug.number,
0,
);
return processRulePrice.value * dosage.value * number;
}
return 0;
const processRule = childProcessRuleList.value.find(
(item) => item.id === childProcessRuleId.value,
);
const totalQty = currentDrugs.value.reduce(
(sum, drug) => sum + parsePriceValue(drug.number ?? 1),
0,
);
return calculateProcessingFee(processRule, dosage.value, totalQty);
});
const visible = ref<boolean>(false);
@@ -602,7 +584,7 @@ const setVisible = (value, instruction = ''): void => {
* @param patient
* @param isUpdateTabType
*/
const selectPatient = (patient: Patient, isUpdateTabType = true) => {
const selectPatient = async (patient: Patient, isUpdateTabType = true) => {
clearAppliedSpecialPrescription();
selectPatientId.value = patient.id;
receptionStatus.value = patient.status;
@@ -620,7 +602,7 @@ const selectPatient = (patient: Patient, isUpdateTabType = true) => {
const registerId = patient.id;
// 优先恢复完整草稿(诊断、医嘱、诊疗费、中药配置等)
const hasDraft = restoreReceptionDraft(registerId);
const hasDraft = await restoreReceptionDraft(registerId);
if (!hasDraft) {
const savedCategory = localStorage.getItem(`activeCategory${registerId}`);
if (savedCategory) {
@@ -735,7 +717,7 @@ function saveReceptionDraft() {
}
/** 恢复接诊草稿 */
function restoreReceptionDraft(registerId: number) {
async function restoreReceptionDraft(registerId: number) {
if (!registerId) return false;
const raw = localStorage.getItem(getDraftKey(registerId));
if (!raw) return false;
@@ -747,22 +729,25 @@ function restoreReceptionDraft(registerId: number) {
diagnosis.value = draft.diagnosis ?? '';
medicalAdvice.value = draft.medicalAdvice ?? '';
treatmentPrice.value = draft.treatmentPrice ?? 0;
ruleType.value = draft.ruleType ?? 1;
ruleType.value = Number(draft.ruleType ?? 1);
if (draft.packageMethodId != null) {
packageMethodId.value = draft.packageMethodId;
packageMethodId.value = Number(draft.packageMethodId);
}
if (draft.processRuleId != null) {
processRuleId.value = draft.processRuleId;
processRuleId.value = Number(draft.processRuleId);
}
if (draft.childProcessRuleId != null) {
childProcessRuleId.value = draft.childProcessRuleId;
childProcessRuleId.value = Number(draft.childProcessRuleId);
}
if (draft.processRuleNoteId != null) {
processRuleNoteId.value = draft.processRuleNoteId;
processRuleNoteId.value = Number(draft.processRuleNoteId);
}
if (draft.dosage != null) dosage.value = draft.dosage;
if (draft.dayDosage != null) dayDosage.value = draft.dayDosage;
if (draft.priceDiscount != null) priceDiscount.value = draft.priceDiscount;
if (activeCategory.value === 1 && ruleType.value === 2) {
await hydrateChineseProcessRuleListsFromConfig();
}
return true;
} catch {
return false;
@@ -922,12 +907,13 @@ const sendPrescription = () => {
message.error('请选择制剂');
return;
}
if (processRuleNoteId.value == null) {
message.error('请选择规格');
if (childProcessRuleId.value == null) {
message.error('请选择煎法');
return;
}
if (childProcessRuleId.value == null) {
if (processRuleNoteId.value == null) {
message.error('请选择备注');
return;
}
}
}
@@ -972,7 +958,7 @@ const sendPrescription = () => {
// 处方类型
prescription_type: activeCategory.value,
// 加工费
processing_fee: processRulePrice.value,
processing_fee: processingFee.value,
// 用药剂量
dosage: dosage.value,
// 每日用药次数
@@ -1003,7 +989,6 @@ const sendPrescription = () => {
clearReceptionDraft(getRegisterId());
tabType.value = 1;
salespersonTransferPrescriptionId.value = 0;
processRulePrice.value = 0;
checkSalespersonTransfer();
// 刷新患者信息
@@ -1205,7 +1190,7 @@ async function handleSelectCommonPrescription(data: any, type: number) {
diagnosis.value = prescription.clinical_diagnose;
}
if (prescription.doctor_order !== undefined && prescription.doctor_order !== null) {
medicalAdvice.value = prescription.doctor_order;
medicalAdvice.value = detailDoctorOrderToText(prescription.doctor_order);
}
// 保存到本地存储
@@ -1584,6 +1569,57 @@ async function loadProcessRuleData(pid = 0, ruleId = 0) {
} else {
childProcessRuleList.value = value;
}
await applySingleChildProcessRuleAutoSelect(
resolveProcessRuleLoadedLevel(pid, ruleId),
{
ruleType: ruleType.value,
disabled: isSpecialPrescriptionCartLocked.value,
processRuleId: processRuleId.value,
childProcessRuleId: childProcessRuleId.value,
processRuleNoteId: processRuleNoteId.value,
processRuleList: processRuleList.value,
childProcessRuleList: childProcessRuleList.value,
processRuleNoteList: processRuleNoteList.value,
load: loadProcessRuleData,
setProcessRuleId: (id) => {
processRuleId.value = id;
},
setChildProcessRuleId: (id) => {
childProcessRuleId.value = id;
},
setProcessRuleNoteId: (id) => {
processRuleNoteId.value = id;
},
clearBelowProcessRule: () => {
childProcessRuleId.value = undefined;
processRuleNoteId.value = undefined;
childProcessRuleList.value = [];
processRuleNoteList.value = [];
},
clearBelowChild: () => {
processRuleNoteId.value = undefined;
processRuleNoteList.value = [];
},
},
);
}
/**
* 从草稿 ID 级联拉取委托调剂选项列表(刷新恢复用,对齐移动端 hydrateChineseProcessRuleListsFromConfig
*/
async function hydrateChineseProcessRuleListsFromConfig() {
if (activeCategory.value !== 1 || ruleType.value !== 2) {
return;
}
if (processRuleList.value.length === 0) {
await loadProcessRuleData();
}
if (processRuleId.value) {
await loadProcessRuleData(Number(processRuleId.value));
}
if (childProcessRuleId.value) {
await loadProcessRuleData(0, Number(childProcessRuleId.value));
}
}
function parsePrescriptionDetailContent(detail: any): Record<string, any> {
@@ -1765,13 +1801,12 @@ async function applyHistoricalPrescriptionDetail(detail: any): Promise<boolean>
diagnosis.value =
detail.clinical_diagnose ?? content.clinical_diagnose ?? '';
medicalAdvice.value = detail.doctor_order ?? content.doctor_order ?? '';
medicalAdvice.value = content.doctor_order ?? detailDoctorOrderToText(detail.doctor_order) ?? '';
category.value =
detail.category === 2 || detail.category === '2' || content.category === '医保'
? 2
: 1;
doctorSecondSign.value = 0;
processRulePrice.value = 0;
localStorage.setItem(
getStorageKey(pid, activeCategory.value),
@@ -1853,46 +1888,55 @@ function confirmWithdrawPrescription(item: any) {
loadProcessRuleData();
/**
* 选择煎法
* @param id
* 中药配置变更(对齐移动端级联逻辑)
*/
function selectProcessRule(id) {
async function handleChineseConfigChange(payload: ChineseMedicineConfigChange) {
if (guardSpecialPrescriptionCartEdit()) return;
processRuleId.value = id;
loadProcessRuleData(id); // 加载煎法选项
}
const oldRuleType = ruleType.value;
const oldProcessRuleId = processRuleId.value;
const oldChildProcessRuleId = childProcessRuleId.value;
/**
* 选择规格
* @param id
*/
function selectProcessRuleNot(id) {
if (guardSpecialPrescriptionCartEdit()) return;
childProcessRuleId.value = id;
loadProcessRuleData(0, id); // 加载备注选项
}
if (payload.ruleType === 2 && payload.ruleType !== oldRuleType) {
if (processRuleList.value.length === 0) {
await loadProcessRuleData();
}
}
if (payload.ruleType === 1 && oldRuleType === 2) {
processRuleId.value = undefined;
childProcessRuleId.value = undefined;
processRuleNoteId.value = undefined;
processRuleList.value = [];
childProcessRuleList.value = [];
processRuleNoteList.value = [];
}
if (payload.processRuleId != null && payload.processRuleId !== oldProcessRuleId) {
childProcessRuleId.value = undefined;
processRuleNoteId.value = undefined;
childProcessRuleList.value = [];
processRuleNoteList.value = [];
}
if (payload.childProcessRuleId != null && payload.childProcessRuleId !== oldChildProcessRuleId) {
processRuleNoteId.value = undefined;
processRuleNoteList.value = [];
}
/**
* 选择备注
* @param id
*/
function selectProcessRuleNotCommit(id) {
if (guardSpecialPrescriptionCartEdit()) return;
processRuleNoteId.value = id;
if (payload.ruleType != null) ruleType.value = payload.ruleType;
if (payload.packageMethodId !== undefined) packageMethodId.value = payload.packageMethodId ?? 2;
if (payload.processRuleId !== undefined) processRuleId.value = payload.processRuleId ?? undefined;
if (payload.childProcessRuleId !== undefined) childProcessRuleId.value = payload.childProcessRuleId ?? undefined;
if (payload.processRuleNoteId !== undefined) processRuleNoteId.value = payload.processRuleNoteId ?? undefined;
if (payload.dosage != null) dosage.value = payload.dosage;
if (payload.dayDosage != null) dayDosage.value = payload.dayDosage;
if (payload.processRuleId != null && payload.processRuleId !== oldProcessRuleId) {
await loadProcessRuleData(payload.processRuleId);
}
if (payload.childProcessRuleId != null && payload.childProcessRuleId !== oldChildProcessRuleId) {
await loadProcessRuleData(0, payload.childProcessRuleId);
}
}
const packageMethodId = ref(2);
const packageMethod = [
{label: '味包', value: 1},
{label: '剂包', value: 2},
];
function selectPackageMethod(id) {
if (guardSpecialPrescriptionCartEdit()) return;
packageMethodId.value = id;
}
// jishu
const dosage = ref(7);
const dayDosage = ref(2);
@@ -3320,116 +3364,22 @@ watch(
<!-- 诊断和医嘱 -->
<div class="diagnosis-area">
<div v-if="activeCategory === 1" class="mb-5">
<RadioGroup v-model:value="ruleType" :disabled="isSpecialPrescriptionCartLocked">
<RadioButton :value="1">自制剂</RadioButton>
<RadioButton :value="2">委托调剂</RadioButton>
</RadioGroup>
<div v-if="ruleType === 1">
<!-- 选择包法-->
<Select
:value="packageMethodId"
:disabled="isSpecialPrescriptionCartLocked"
class="mt-3 w-1/5"
placeholder="请选择包法"
@change="selectPackageMethod"
>
<SelectOption
v-for="(value, index) in packageMethod"
:key="index"
:value="value.value"
>
{{ value.label }}
</SelectOption>
</Select>
</div>
<div v-else-if="ruleType === 2">
<!-- 选择制剂-->
<Select
v-model:value="processRuleId"
:disabled="isSpecialPrescriptionCartLocked"
class="mt-3 w-1/5"
placeholder="请选择制剂"
@change="selectProcessRule"
>
<SelectOption
v-for="(value, index) in processRuleList"
:key="index"
:value="value.id"
>
{{ value.name }}
</SelectOption>
</Select>
<!-- 选择规格-->
<Select
v-model:value="childProcessRuleId"
:disabled="isSpecialPrescriptionCartLocked"
class="ml-3 mt-3 w-1/5"
placeholder="请选择煎法"
@change="selectProcessRuleNot"
>
<SelectOption
v-for="(value, index) in childProcessRuleList"
:key="index"
:value="value.id"
>
{{ value.name }}
</SelectOption>
</Select>
<!-- 选择备注-->
<Select
v-model:value="processRuleNoteId"
:disabled="isSpecialPrescriptionCartLocked"
class="ml-3 mt-3 w-1/5"
placeholder="请选择备注"
@change="selectProcessRuleNotCommit"
>
<SelectOption
v-for="(value, index) in processRuleNoteList"
:key="index"
:value="value.id"
>
{{ value.note }}
</SelectOption>
</Select>
</div>
<div class="mt-5">
用量:
<InputNumber v-model:value="dosage" :disabled="isSpecialPrescriptionCartLocked" class="w-1/5">
<template #addonBefore>
<MinusOutlined
key="prop"
@click="!isSpecialPrescriptionCartLocked && (dosage = dosage > 1 ? dosage - 1 : 1)"
/>
</template>
<template #addonAfter>
<PlusOutlined
key="add"
@click="!isSpecialPrescriptionCartLocked && (dosage = dosage < 100 ? dosage + 1 : 100)"
/>
</template>
</InputNumber>
天 / {{ dosage }} 剂
</div>
<div class="mt-5">
频次:
<InputNumber v-model:value="dayDosage" :disabled="isSpecialPrescriptionCartLocked" class="w-1/5">
<template #addonBefore>
<MinusOutlined
key="prop"
@click="!isSpecialPrescriptionCartLocked && (dayDosage = dayDosage > 1 ? dayDosage - 1 : 1)"
/>
</template>
<template #addonAfter>
<PlusOutlined
key="add"
@click="!isSpecialPrescriptionCartLocked && (dayDosage = dayDosage < 100 ? dayDosage + 1 : 100)"
/>
</template>
</InputNumber>
次/天
</div>
</div>
<ChineseMedicineConfig
v-if="activeCategory === 1"
:rule-type="ruleType"
:package-method-id="packageMethodId"
:process-rule-id="processRuleId"
:child-process-rule-id="childProcessRuleId"
:process-rule-note-id="processRuleNoteId"
:dosage="dosage"
:day-dosage="dayDosage"
:process-rule-list="processRuleList"
:child-process-rule-list="childProcessRuleList"
:process-rule-note-list="processRuleNoteList"
:disabled="isSpecialPrescriptionCartLocked"
class="mb-5"
@change="handleChineseConfigChange"
/>
<Button type="primary" @click="openDiagnosisModal">
常用诊断
</Button>
@@ -3455,7 +3405,7 @@ watch(
<!-- 费用总计 -->
<div class="price-box">
<div class="total-cost">加工费:¥{{ processingFee.toFixed(2) }}</div>
<div class="total-cost">加工费:¥{{ formatPriceDisplay(processingFee) }}</div>
<div class="total-cost">
商品价格:
<Button
@@ -3464,9 +3414,9 @@ watch(
class="!p-0"
@click="openOrderPriceAdjust"
>
¥{{ totalProductCost.toFixed(2) }}
¥{{ formatPriceDisplay(totalProductCost) }}
</Button>
<template v-else>¥{{ totalProductCost.toFixed(2) }}</template>
<template v-else>¥{{ formatPriceDisplay(totalProductCost) }}</template>
<span
v-if="chineseGrossMarginPercent !== null"
class="ml-3 text-orange-600"
@@ -3474,7 +3424,7 @@ watch(
毛利率 {{ chineseGrossMarginPercent }}%
</span>
</div>
<div class="total-cost">总计:¥{{ totalCost.toFixed(2) }}</div>
<div class="total-cost">总计:¥{{ formatPriceDisplay(totalCost) }}</div>
<div v-if="priceAdjustEnabled && currentDrugs.length" class="mt-2 text-sm text-gray-600">
当前浮动:{{ priceDiscountLabel || '无' }}

View File

@@ -53,6 +53,10 @@ import {
getProductListDoctorReception,
getProcessRuleList,
} from '#/views/doctor/doctor-reception/api';
import {
applySingleChildProcessRuleAutoSelect,
resolveProcessRuleLoadedLevel,
} from '#/utils/processRuleCascade';
// 引入诊断和医嘱选择弹窗组件
import DiagnosisModal from '#/views/doctor/doctor-reception/components/DiagnosisModal.vue';
@@ -290,6 +294,38 @@ async function loadProcessRuleData(pid = 0, ruleId = 0) {
} else {
childProcessRuleList.value = res;
}
await applySingleChildProcessRuleAutoSelect(
resolveProcessRuleLoadedLevel(pid, ruleId),
{
ruleType: ruleType.value,
processRuleId: processRuleId.value,
childProcessRuleId: childProcessRuleId.value,
processRuleNoteId: processRuleNoteId.value,
processRuleList: processRuleList.value,
childProcessRuleList: childProcessRuleList.value,
processRuleNoteList: processRuleNoteList.value,
load: loadProcessRuleData,
setProcessRuleId: (id) => {
processRuleId.value = id;
},
setChildProcessRuleId: (id) => {
childProcessRuleId.value = id;
},
setProcessRuleNoteId: (id) => {
processRuleNoteId.value = id;
},
clearBelowProcessRule: () => {
childProcessRuleId.value = null;
processRuleNoteId.value = null;
childProcessRuleList.value = [];
processRuleNoteList.value = [];
},
clearBelowChild: () => {
processRuleNoteId.value = null;
processRuleNoteList.value = [];
},
},
);
} catch (error) {
console.error('加载委托调剂选项失败:', error);
}

View File

@@ -52,6 +52,10 @@ import {
getProductListDoctorReception,
getProcessRuleList,
} from '#/views/doctor/doctor-reception/api';
import {
applySingleChildProcessRuleAutoSelect,
resolveProcessRuleLoadedLevel,
} from '#/utils/processRuleCascade';
// 引入诊断和医嘱选择弹窗组件
import DiagnosisModal from '#/views/doctor/doctor-reception/components/DiagnosisModal.vue';
@@ -329,6 +333,38 @@ async function loadProcessRuleData(pid = 0, ruleId = 0) {
} else {
childProcessRuleList.value = res;
}
await applySingleChildProcessRuleAutoSelect(
resolveProcessRuleLoadedLevel(pid, ruleId),
{
ruleType: ruleType.value,
processRuleId: processRuleId.value,
childProcessRuleId: childProcessRuleId.value,
processRuleNoteId: processRuleNoteId.value,
processRuleList: processRuleList.value,
childProcessRuleList: childProcessRuleList.value,
processRuleNoteList: processRuleNoteList.value,
load: loadProcessRuleData,
setProcessRuleId: (id) => {
processRuleId.value = id;
},
setChildProcessRuleId: (id) => {
childProcessRuleId.value = id;
},
setProcessRuleNoteId: (id) => {
processRuleNoteId.value = id;
},
clearBelowProcessRule: () => {
childProcessRuleId.value = null;
processRuleNoteId.value = null;
childProcessRuleList.value = [];
processRuleNoteList.value = [];
},
clearBelowChild: () => {
processRuleNoteId.value = null;
processRuleNoteList.value = [];
},
},
);
} catch (error) {
console.error('加载委托调剂选项失败:', error);
}