region-address-picker 接 region-picker API;订单支持按进价重算 market_price、追踪页资金流水;MES/ERP/中台同步日志共用内容查看组件;地区管理支持 pid 下钻与拼音检索。
1492 lines
49 KiB
TypeScript
1492 lines
49 KiB
TypeScript
import { computed, nextTick, ref, watch } from 'vue';
|
||
|
||
import { message, notification } from 'ant-design-vue';
|
||
import { debounce } from 'lodash-es';
|
||
import { defineStore } from 'pinia';
|
||
|
||
import { useUserStore as useVbenUserStore } from '@vben/stores';
|
||
|
||
import { useChatStore } from '#/views/business/chat/stores/chat';
|
||
import { useUserStore } from '#/views/business/chat/stores/user';
|
||
import { sendMessage } from '#/views/business/chat/utils/request';
|
||
import {
|
||
addWestPrescription,
|
||
checkChineseMedicineConflictApi,
|
||
getCurrentStoreTypeApi,
|
||
getPrescriptionTypeOptionsApi,
|
||
getDrugUseList,
|
||
getMyStoreListApi,
|
||
getPatientItem,
|
||
getProcessRuleList,
|
||
getProductListDoctorReception,
|
||
} from '#/views/doctor/doctor-reception/api';
|
||
import {
|
||
calcItemMarginPercent,
|
||
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';
|
||
|
||
export const usePrescriptionStore = defineStore('prescription', () => {
|
||
// 基础数据
|
||
const patientInfo = ref<any | null>(null);
|
||
const userPatientHealthInquiry = ref<any | null>(null);
|
||
const prescriptionList = ref([]);
|
||
const currentRegisterId = ref<number | string>('');
|
||
const activePatient = ref<any | null>(null);
|
||
|
||
const userStore = useUserStore();
|
||
const chatStore = useChatStore();
|
||
|
||
// 药品使用相关数据
|
||
const drugUseNum = ref([]);
|
||
const drugUseFrequency = ref([]);
|
||
const drugUseType = ref([]);
|
||
const drugUnit = ref([]);
|
||
const drugTime = ref([]);
|
||
const drugUseWay = ref([]);
|
||
const myStoreList = ref([]);
|
||
|
||
// 处方状态
|
||
const myStoreId = ref(0);
|
||
const activeCategory = ref(2);
|
||
/** 后端下发的处方类型列表(含可选 icon / icon_text) */
|
||
const categories = ref([
|
||
{ label: '中药', value: 1, icon: '', icon_text: '' },
|
||
{ label: '西(中成)药', value: 2, icon: '', icon_text: '' },
|
||
{ label: '保健食品', value: 3, icon: '', icon_text: '' },
|
||
{ label: '产品服务包', value: 5, icon: '', icon_text: '' },
|
||
{ label: '非药品', value: 6, icon: '', icon_text: '' },
|
||
{ label: '医疗器械', value: 7, icon: '', icon_text: '' },
|
||
]);
|
||
const prescriptionTypeDefault = ref(2);
|
||
/** 开方种类权限校验中(进入开方页先 loading) */
|
||
const prescriptionTypeLoading = ref(false);
|
||
/** 当前门店是否有可开方种类 */
|
||
const prescriptionTypeAllowed = ref(true);
|
||
const prescriptionTypeDenyMessage = ref('');
|
||
const diagnosis = ref('');
|
||
const medicalAdvice = ref('');
|
||
const treatmentPrice = ref(0);
|
||
const ruleType = ref(1);
|
||
const drugList = ref([]);
|
||
const currentDrugs = ref([]);
|
||
const category = ref(1);
|
||
const selectProductId = ref(0);
|
||
|
||
// 中药相关配置
|
||
const processRuleList = ref([]);
|
||
const childProcessRuleList = ref([]);
|
||
const processRuleNoteList = ref([]);
|
||
const processRuleId = ref();
|
||
const processRuleNoteId = ref();
|
||
const childProcessRuleId = ref();
|
||
const packageMethodId = ref(2);
|
||
const dosage = ref(7);
|
||
const dayDosage = ref(2);
|
||
|
||
// 新药品相关
|
||
const newDrugInfo = ref<any>({});
|
||
const selectChineseIndex = ref(-1);
|
||
const selectChineseId = ref(0);
|
||
/** 中药气泡选中的完整商品行(添加时优先使用) */
|
||
const pendingNewChineseProduct = ref<any>(null);
|
||
|
||
// 二次签名相关
|
||
const doctorSecondSign = ref(0);
|
||
const checkData = ref<any>({});
|
||
|
||
// 初始化状态标记
|
||
const isInitialized = ref(false);
|
||
const isPatientInfoLoaded = ref(false);
|
||
|
||
const traditionalChineseMedicine = ref(traditionalJson);
|
||
const diseasesSelected = ref();
|
||
const methodSelected = ref();
|
||
const syndromeSelected = ref();
|
||
|
||
// 诊所选择相关状态
|
||
const registerStoreInfo = ref<any>(null); // 挂号诊所信息
|
||
const selectedStoreId = ref<number | null>(null); // 用户选择的诊所ID
|
||
const sendMode = ref(0); // 0=默认(使用医生当前诊所),1=自定义(使用挂号诊所)
|
||
|
||
// 存储前缀(用于区分在线复诊-药店和在线复诊-诊所)
|
||
const storagePrefix = ref('onlineConsultation-'); // 默认前缀
|
||
|
||
/** 当前取价门店是否允许查看毛利率(0/1,来自 xk-api) */
|
||
const seeRate = ref(0);
|
||
|
||
// 获取localStorage key(按类型分开存储)
|
||
const getStorageKey = (category?: number) => {
|
||
const cat = category ?? activeCategory.value;
|
||
return `${storagePrefix.value}prescriptionData_${cat}_${currentRegisterId.value}`;
|
||
};
|
||
|
||
// 计算属性
|
||
const totalProductCost = computed(() => {
|
||
if (currentDrugs.value.length === 0) {
|
||
return 0;
|
||
}
|
||
if (activeCategory.value === 1) {
|
||
return currentDrugs.value.reduce(
|
||
(sum, drug) => sum + drug.price * (drug.number || 1) * dosage.value,
|
||
0,
|
||
);
|
||
}
|
||
return currentDrugs.value.reduce(
|
||
(sum, drug) => sum + drug.price * (drug.select_number || 1),
|
||
0,
|
||
);
|
||
});
|
||
|
||
const processingFee = computed(() => {
|
||
if (ruleType.value !== 2 || currentDrugs.value.length === 0) 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 totalCost = computed(() => {
|
||
return totalProductCost.value + processingFee.value;
|
||
});
|
||
|
||
/** 实际履约/开方门店:自定义挂号店时用 selectedStoreId,否则用医生当前店 */
|
||
const resolvePrescribingStoreId = () => {
|
||
if (sendMode.value === 1 && selectedStoreId.value) {
|
||
return Number(selectedStoreId.value);
|
||
}
|
||
return Number(myStoreId.value || 0);
|
||
};
|
||
/** 供模板绑定:煎药预设等按此门店隔离加载 */
|
||
const prescribingStoreId = computed(() => resolvePrescribingStoreId());
|
||
|
||
const fetchStoreSeeRate = async () => {
|
||
try {
|
||
const params: { register_id?: number; store_id?: number } = {};
|
||
const sid = resolvePrescribingStoreId();
|
||
if (sid) {
|
||
params.store_id = sid;
|
||
}
|
||
if (currentRegisterId.value) {
|
||
params.register_id = Number(currentRegisterId.value);
|
||
}
|
||
const res = await getCurrentStoreTypeApi(params);
|
||
seeRate.value = Number(res?.see_rate ?? 0);
|
||
} catch (error) {
|
||
console.error('获取毛利率权限失败:', error);
|
||
}
|
||
};
|
||
|
||
watch(
|
||
[myStoreId, selectedStoreId, sendMode, currentRegisterId],
|
||
() => {
|
||
if (myStoreId.value) {
|
||
fetchStoreSeeRate();
|
||
}
|
||
},
|
||
);
|
||
|
||
const chineseGrossMarginPercent = computed(() => {
|
||
if (!isSeeRateEnabled(seeRate.value) || activeCategory.value !== 1) {
|
||
return null;
|
||
}
|
||
return calcTotalMarginPercent(currentDrugs.value, dosage.value);
|
||
});
|
||
|
||
const getChineseItemMargin = (drug: {
|
||
price?: number | string;
|
||
buy_price?: number | string;
|
||
}) => {
|
||
if (!isSeeRateEnabled(seeRate.value)) {
|
||
return null;
|
||
}
|
||
return calcItemMarginPercent(drug.price, drug.buy_price);
|
||
};
|
||
|
||
/**
|
||
* 拉取后端处方类型列表与默认选中;无绑定时清空 list 并返回 false
|
||
*/
|
||
const loadPrescriptionTypeOptions = async (registerId?: number | string) => {
|
||
prescriptionTypeLoading.value = true;
|
||
try {
|
||
const params: { register_id?: number; store_id?: number } = {};
|
||
const rid = Number(registerId || currentRegisterId.value);
|
||
if (rid) params.register_id = rid;
|
||
if (myStoreId.value) params.store_id = myStoreId.value;
|
||
const res = await getPrescriptionTypeOptionsApi(params);
|
||
const list = Array.isArray(res?.list) ? res.list : [];
|
||
categories.value = list.map((item) => ({
|
||
value: Number(item.value),
|
||
label: item.label || '',
|
||
icon: item.icon || '',
|
||
icon_text: item.icon_text || '',
|
||
}));
|
||
const def = Number(res?.default) || 0;
|
||
prescriptionTypeDefault.value = def;
|
||
const allowed =
|
||
res?.allowed !== false && list.length > 0;
|
||
prescriptionTypeAllowed.value = allowed;
|
||
prescriptionTypeDenyMessage.value = allowed
|
||
? ''
|
||
: (res?.message || '当前门店未开通开方权限');
|
||
// 当前 Tab 不在 allowed 内时强制切到 default
|
||
if (allowed && def && !categories.value.some((c) => c.value === activeCategory.value)) {
|
||
activeCategory.value = def;
|
||
}
|
||
return allowed;
|
||
} catch (error) {
|
||
console.error('加载处方类型失败:', error);
|
||
categories.value = [];
|
||
prescriptionTypeAllowed.value = false;
|
||
prescriptionTypeDenyMessage.value = '处方类型加载失败,请稍后重试';
|
||
message.warning('处方类型加载失败,请稍后重试');
|
||
return false;
|
||
} finally {
|
||
prescriptionTypeLoading.value = false;
|
||
}
|
||
};
|
||
|
||
// localStorage同步方法
|
||
const syncToLocalStorage = () => {
|
||
try {
|
||
const storageKey = getStorageKey();
|
||
localStorage.setItem(storageKey, JSON.stringify(currentDrugs.value));
|
||
console.log('已同步到localStorage:', storageKey, currentDrugs.value);
|
||
} catch (error) {
|
||
console.error('保存到localStorage失败:', error);
|
||
}
|
||
};
|
||
|
||
const loadFromLocalStorage = () => {
|
||
try {
|
||
const storageKey = getStorageKey();
|
||
const stored = localStorage.getItem(storageKey);
|
||
console.log('从localStorage加载:', storageKey, stored);
|
||
|
||
if (stored) {
|
||
const parsedData = JSON.parse(stored);
|
||
currentDrugs.value.splice(0, currentDrugs.value.length, ...parsedData);
|
||
} else {
|
||
currentDrugs.value.splice(0, currentDrugs.value.length);
|
||
}
|
||
} catch (error) {
|
||
console.error('从localStorage加载失败:', error);
|
||
currentDrugs.value.splice(0, currentDrugs.value.length);
|
||
}
|
||
};
|
||
|
||
// 更新currentDrugs并同步到localStorage
|
||
const updateCurrentDrugs = (newDrugs: any[]) => {
|
||
currentDrugs.value.splice(0, currentDrugs.value.length, ...newDrugs);
|
||
// 更新总价
|
||
syncToLocalStorage();
|
||
};
|
||
|
||
// 基础数据初始化(不包含患者信息)
|
||
const initializeBasicData = async () => {
|
||
if (isInitialized.value) {
|
||
console.log('基础数据已初始化,跳过重复请求');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await Promise.all([
|
||
getMyStoreList(),
|
||
getDrugUseListData(),
|
||
getProcessRuleListData(),
|
||
]);
|
||
isInitialized.value = true;
|
||
console.log('基础数据初始化完成');
|
||
} catch (error) {
|
||
console.error('基础数据初始化失败:', error);
|
||
}
|
||
};
|
||
|
||
// 完整初始化(包含患者信息,仅用于 PrescriptionModal)
|
||
const initializePrescription = async (
|
||
registerId: number | string,
|
||
shouldFetchPatientInfo: boolean = false,
|
||
prefix: string = 'onlineConsultation-'
|
||
) => {
|
||
// 设置存储前缀
|
||
storagePrefix.value = prefix;
|
||
|
||
// 设置当前注册ID
|
||
currentRegisterId.value = registerId;
|
||
|
||
// 先拉类型选项,再决定默认 Tab(无本地记忆时用后端 default)
|
||
if (!isInitialized.value) {
|
||
await initializeBasicData();
|
||
}
|
||
await loadPrescriptionTypeOptions(registerId);
|
||
|
||
// 恢复之前保存的 activeCategory
|
||
const savedCategory = localStorage.getItem(
|
||
`${storagePrefix.value}activeCategory${registerId}`
|
||
);
|
||
if (savedCategory) {
|
||
activeCategory.value = Number.parseInt(savedCategory);
|
||
} else {
|
||
// 检查哪个存储键有数据
|
||
const chineseData = localStorage.getItem(
|
||
`${storagePrefix.value}prescriptionData_1_${registerId}`
|
||
);
|
||
const westData = localStorage.getItem(
|
||
`${storagePrefix.value}prescriptionData_2_${registerId}`
|
||
);
|
||
if (chineseData && JSON.parse(chineseData).length > 0) {
|
||
activeCategory.value = 1;
|
||
} else if (westData && JSON.parse(westData).length > 0) {
|
||
activeCategory.value = 2;
|
||
} else if (prescriptionTypeDefault.value) {
|
||
activeCategory.value = prescriptionTypeDefault.value;
|
||
}
|
||
}
|
||
|
||
// 加载localStorage数据
|
||
loadFromLocalStorage();
|
||
|
||
await fetchStoreSeeRate();
|
||
|
||
// 获取患者信息(只在需要时调用,如 PrescriptionModal)
|
||
if (shouldFetchPatientInfo) {
|
||
if (
|
||
!isPatientInfoLoaded.value ||
|
||
patientInfo.value?.register_id !== registerId
|
||
) {
|
||
await getPatientInfo();
|
||
isPatientInfoLoaded.value = true;
|
||
}
|
||
}
|
||
};
|
||
|
||
// 轻量级初始化(仅用于 WesternModal 等子组件)
|
||
const initializeForModal = async (registerId: number | string, prefix: string = 'onlineConsultation-') => {
|
||
console.log('轻量级初始化,registerId:', registerId);
|
||
|
||
// 设置存储前缀
|
||
storagePrefix.value = prefix;
|
||
|
||
// 设置当前注册ID
|
||
currentRegisterId.value = registerId;
|
||
|
||
// 恢复之前保存的 activeCategory
|
||
const savedCategory = localStorage.getItem(
|
||
`${storagePrefix.value}activeCategory${registerId}`
|
||
);
|
||
if (savedCategory) {
|
||
activeCategory.value = Number.parseInt(savedCategory);
|
||
} else {
|
||
// 检查哪个存储键有数据
|
||
const chineseData = localStorage.getItem(
|
||
`${storagePrefix.value}prescriptionData_1_${registerId}`
|
||
);
|
||
const westData = localStorage.getItem(
|
||
`${storagePrefix.value}prescriptionData_2_${registerId}`
|
||
);
|
||
if (chineseData && JSON.parse(chineseData).length > 0) {
|
||
activeCategory.value = 1;
|
||
} else if (westData && JSON.parse(westData).length > 0) {
|
||
activeCategory.value = 2;
|
||
}
|
||
}
|
||
|
||
// 加载localStorage数据
|
||
loadFromLocalStorage();
|
||
|
||
// 如果基础数据未初始化,先初始化基础数据
|
||
if (!isInitialized.value) {
|
||
await initializeBasicData();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 拉取医生门店列表并解析当前履约门店。
|
||
* 为什么:旧逻辑每次把 myStoreId 强制写成 res[0],换店/登录态门店会被冲掉,
|
||
* 煎药预设按 doctor+store 隔离时就会表现为「以前加的方案不见了」。
|
||
*/
|
||
const getMyStoreList = async () => {
|
||
try {
|
||
const res = await getMyStoreListApi();
|
||
myStoreList.value = res || [];
|
||
if (!myStoreList.value.length) {
|
||
console.log('获取诊所列表成功(空)');
|
||
return;
|
||
}
|
||
// 优先:当前已选 → 后台登录态门店 → 本地缓存;最后才回落列表第一项
|
||
const vbenStoreId = Number(
|
||
useVbenUserStore().userInfo?.store_id || 0,
|
||
);
|
||
const preferred =
|
||
Number(myStoreId.value || 0) ||
|
||
vbenStoreId ||
|
||
Number(localStorage.getItem('myStoreId') || 0);
|
||
const hit = myStoreList.value.find(
|
||
(s: any) => Number(s.id) === preferred,
|
||
);
|
||
myStoreId.value = hit
|
||
? Number(hit.id)
|
||
: Number(myStoreList.value[0].id);
|
||
console.log('获取诊所列表成功');
|
||
} catch (error) {
|
||
console.error('获取诊所列表失败:', error);
|
||
}
|
||
};
|
||
|
||
const getDrugUseListData = async () => {
|
||
try {
|
||
const res = await getDrugUseList();
|
||
drugUseNum.value = res.drug_use_num;
|
||
drugUseFrequency.value = res.drug_use_frequency;
|
||
drugUseType.value = res.drug_use_type;
|
||
drugUnit.value = res.drug_unit;
|
||
drugTime.value = res.drug_time;
|
||
drugUseWay.value = res.drug_use_way;
|
||
console.log('获取药品使用列表成功');
|
||
} catch (error) {
|
||
console.error('获取药品使用列表失败:', error);
|
||
}
|
||
};
|
||
|
||
const getProcessRuleListData = async (pid = 0, ruleId = 0) => {
|
||
try {
|
||
const data = ruleId === 0 ? { pid } : { rule_id: ruleId };
|
||
const res = await getProcessRuleList(data);
|
||
|
||
if (ruleId !== 0) {
|
||
processRuleNoteList.value = res;
|
||
} else if (pid === 0) {
|
||
processRuleList.value = res;
|
||
} 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);
|
||
}
|
||
};
|
||
|
||
const getPatientInfo = async () => {
|
||
try {
|
||
console.log('开始获取患者信息,registerId:', currentRegisterId.value);
|
||
const res = await getPatientItem(currentRegisterId.value);
|
||
patientInfo.value = res;
|
||
activePatient.value = res.user_patient;
|
||
userPatientHealthInquiry.value = res.user_patient_health_inquiry;
|
||
prescriptionList.value = res.prescription;
|
||
console.log('获取患者信息成功:', activePatient.value);
|
||
} catch (error) {
|
||
console.error('获取患者信息失败:', error);
|
||
}
|
||
};
|
||
|
||
// 获取挂号诊所信息(同时包含当前诊所信息)
|
||
const fetchRegisterStoreInfo = async () => {
|
||
if (!currentRegisterId.value) {
|
||
console.warn('currentRegisterId为空,无法获取挂号诊所信息');
|
||
return;
|
||
}
|
||
try {
|
||
// 根据storagePrefix判断使用哪个API
|
||
const getRegisterStoreInfoFn = storagePrefix.value === 'onlineConsultationClinic-'
|
||
? getRegisterStoreInfoClinic
|
||
: getRegisterStoreInfoPharmacy;
|
||
|
||
const res = await getRegisterStoreInfoFn(Number(currentRegisterId.value));
|
||
registerStoreInfo.value = res;
|
||
|
||
// 如果是转诊挂号,自动使用承接方诊所ID(转接方开处方时)
|
||
if (res && res.is_from_transfer === 1 && res.delegate_store_id) {
|
||
// 转接方开处方时,自动设置store_id为承接方诊所ID
|
||
selectedStoreId.value = res.delegate_store_id;
|
||
sendMode.value = 1; // 使用自定义模式,但使用承接方诊所ID
|
||
} else if (res && res.store_id) {
|
||
selectedStoreId.value = res.store_id;
|
||
sendMode.value = 1;
|
||
}
|
||
console.log('获取挂号诊所信息成功:', res);
|
||
await fetchStoreSeeRate();
|
||
} catch (error) {
|
||
console.error('获取挂号诊所信息失败:', error);
|
||
}
|
||
};
|
||
|
||
// 切换诊所选择
|
||
const toggleStoreSelection = (useRegisterStore: boolean) => {
|
||
if (useRegisterStore && registerStoreInfo.value?.store_id) {
|
||
selectedStoreId.value = registerStoreInfo.value.store_id;
|
||
sendMode.value = 1;
|
||
} else {
|
||
selectedStoreId.value = null;
|
||
sendMode.value = 0;
|
||
}
|
||
};
|
||
|
||
// 计算当前诊所名称(医生所属诊所,优先使用后端返回的数据)
|
||
const currentStoreName = computed(() => {
|
||
// 优先使用后端返回的当前诊所名称
|
||
if (registerStoreInfo.value?.current_store_name) {
|
||
return registerStoreInfo.value.current_store_name;
|
||
}
|
||
// 回退到本地诊所列表
|
||
const currentStore = myStoreList.value.find((s: any) => s.id === myStoreId.value);
|
||
return currentStore?.name || '当前诊所';
|
||
});
|
||
|
||
// 计算目标诊所名称(根据发送模式决定)
|
||
const targetStoreName = computed(() => {
|
||
if (sendMode.value === 1 && registerStoreInfo.value?.store_name) {
|
||
return registerStoreInfo.value.store_name;
|
||
}
|
||
// 默认使用医生当前诊所
|
||
return currentStoreName.value;
|
||
});
|
||
|
||
// 是否可以更改诊所(转诊挂号时不允许更改,使用承接方诊所ID)
|
||
const canChangeStore = computed(() => {
|
||
// 如果是转诊挂号,不允许更改诊所(自动使用承接方诊所ID)
|
||
if (registerStoreInfo.value?.is_from_transfer === 1) {
|
||
return false;
|
||
}
|
||
// 非转诊挂号,使用后端返回的 can_change 字段
|
||
return registerStoreInfo.value?.can_change === true;
|
||
});
|
||
|
||
// 药品搜索
|
||
const getDrugList = debounce(async (searchText = '') => {
|
||
if (searchText === '' && activeCategory.value === 1) {
|
||
drugList.value = [];
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const res = await getProductListDoctorReception({
|
||
store_id: myStoreId.value,
|
||
type: activeCategory.value,
|
||
name: searchText,
|
||
...(currentRegisterId.value
|
||
? { register_id: Number(currentRegisterId.value) }
|
||
: {}),
|
||
});
|
||
|
||
drugList.value = res.map((item) => {
|
||
const matched = currentDrugs.value.find((v) => v.index_id === item.id);
|
||
return {
|
||
...item,
|
||
select_number: matched?.select_number || 0,
|
||
drug: {
|
||
...item.drug,
|
||
number: matched?.number || 1,
|
||
},
|
||
};
|
||
});
|
||
} catch (error) {
|
||
console.error('获取药品列表失败:', error);
|
||
message.error('获取药品列表失败');
|
||
}
|
||
}, 300);
|
||
|
||
/**
|
||
* 从商品/药品数据解析处方分类 tab(与 activeCategory 对齐)
|
||
* 1 中药 / 2 西药 / 3 保健食品 / 5 产品服务包 / 6 非药品 / 7 医疗器械
|
||
* 缺省按西药 2,避免挂号选药误入中药开方
|
||
*/
|
||
const resolveDrugCategory = (data: any): number => {
|
||
const raw = data?.drug?.type ?? data?.type;
|
||
const n = Number(raw);
|
||
if (Number.isFinite(n) && n > 0) return n;
|
||
return 2;
|
||
};
|
||
|
||
// 药品操作:写入前按药型自动切到对应 tab,避免西药落入中药开方组件
|
||
const addProducts = (data: any) => {
|
||
const targetCategory = resolveDrugCategory(data);
|
||
if (Number(activeCategory.value) !== targetCategory) {
|
||
changeCategory(targetCategory);
|
||
}
|
||
|
||
const existItem = currentDrugs.value.find(
|
||
(item) => item.index_id === data.id,
|
||
);
|
||
if (existItem) {
|
||
message.warn('已经存在了');
|
||
return false;
|
||
}
|
||
|
||
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((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:
|
||
data.drug?.unit ||
|
||
drugUnit.value.find((item) => item.id === data.drug.unit_id),
|
||
price: data.price,
|
||
buy_price: data.buy_price,
|
||
way_id: data.drug?.way_id,
|
||
use_ways: drugUseWay.value.find((item) => item.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,
|
||
// 规格(选仓弹窗等处展示)
|
||
specification: data.drug?.specification || data.specification || '',
|
||
instruction: data.drug.instruction,
|
||
type: data.drug.type,
|
||
select_number: (() => {
|
||
const raw = Number(
|
||
data.select_number ?? data.purchase_quantity ?? data.purchase_number,
|
||
);
|
||
if (!Number.isFinite(raw) || raw < 1) return 1;
|
||
return Math.min(9999, Math.max(1, Math.floor(raw)));
|
||
})(),
|
||
};
|
||
|
||
const newDrugs = [...currentDrugs.value, newProduct];
|
||
updateCurrentDrugs(newDrugs);
|
||
|
||
message.success(`已将${newProduct.drug_name}添加到清单中!`);
|
||
return true;
|
||
};
|
||
|
||
const removeDrug = (index: number) => {
|
||
const newDrugs = currentDrugs.value.filter((_, i) => i !== index);
|
||
updateCurrentDrugs(newDrugs);
|
||
};
|
||
|
||
const updateDrugQuantity = (index: number, quantity: number) => {
|
||
if (quantity > 0) {
|
||
const newDrugs = [...currentDrugs.value];
|
||
newDrugs[index].select_number = quantity;
|
||
updateCurrentDrugs(newDrugs);
|
||
}
|
||
};
|
||
|
||
const increment = (index: number) => {
|
||
const newDrugs = [...currentDrugs.value];
|
||
newDrugs[index].select_number++;
|
||
updateCurrentDrugs(newDrugs);
|
||
};
|
||
|
||
const decrement = (index: number) => {
|
||
if (currentDrugs.value[index].select_number > 1) {
|
||
const newDrugs = [...currentDrugs.value];
|
||
newDrugs[index].select_number--;
|
||
updateCurrentDrugs(newDrugs);
|
||
}
|
||
};
|
||
|
||
// 切换药品用法编辑状态
|
||
const toggleEditDrug = (index: number) => {
|
||
const newDrugs = [...currentDrugs.value];
|
||
newDrugs[index].isEditing = !newDrugs[index].isEditing;
|
||
updateCurrentDrugs(newDrugs);
|
||
};
|
||
|
||
// 保存药品用法编辑
|
||
const saveEditDrug = (index: number) => {
|
||
const newDrugs = [...currentDrugs.value];
|
||
const drug = newDrugs[index];
|
||
// 更新 ID 字段
|
||
drug.type_id = drug.use_type?.id;
|
||
drug.frequency_id = drug.use_frequency?.id;
|
||
drug.time_id = drug.use_num?.id;
|
||
drug.unit_id = drug.unit?.id;
|
||
drug.isEditing = false;
|
||
updateCurrentDrugs(newDrugs);
|
||
};
|
||
|
||
// 更新药品用法字段
|
||
const updateDrugUsage = (index: number, field: string, value: any) => {
|
||
const newDrugs = [...currentDrugs.value];
|
||
newDrugs[index][field] = value;
|
||
updateCurrentDrugs(newDrugs);
|
||
};
|
||
|
||
/**
|
||
* 中药气泡:选中新增行药名
|
||
* @param item 商品检索完整行
|
||
*/
|
||
const 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;
|
||
nextTick(() => {
|
||
const input = document.querySelector(
|
||
'.new-number-input input',
|
||
) as HTMLElement;
|
||
input?.focus();
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 中药气泡:替换已选行药名
|
||
* @param index 行下标
|
||
* @param item 商品检索完整行
|
||
*/
|
||
const onSelectOldChineseDrug = (index: number, item: any) => {
|
||
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,
|
||
specification: data.drug?.specification || data.specification || '',
|
||
instruction: data.drug.instruction,
|
||
type: data.drug.type,
|
||
};
|
||
const newDrugs = [...currentDrugs.value];
|
||
newDrugs[index] = newProduct;
|
||
updateCurrentDrugs(newDrugs);
|
||
nextTick(() => {
|
||
const input = document.querySelector(
|
||
`.old-number-input-${index} input`,
|
||
) as HTMLElement;
|
||
input?.focus();
|
||
});
|
||
};
|
||
|
||
// 新药品操作(Select 兼容)
|
||
const 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) {
|
||
pendingNewChineseProduct.value = data;
|
||
newDrugInfo.value.price = data.price;
|
||
newDrugInfo.value.name = data.drug.drug_name;
|
||
// 选药后立刻带上真实单位,供新行数量后缀展示
|
||
newDrugInfo.value.unit =
|
||
data.drug?.unit ||
|
||
drugUnit.value.find((item) => item.id === data.drug?.unit_id);
|
||
newDrugInfo.value.unit_id = data.drug?.unit_id;
|
||
nextTick(() => {
|
||
const input = document.querySelector(
|
||
'.new-number-input input',
|
||
) as HTMLElement;
|
||
input?.focus();
|
||
});
|
||
}
|
||
};
|
||
|
||
const selectOldDrugInfo = (id: number) => {
|
||
const check = currentDrugs.value.find((v) => v.id === id);
|
||
|
||
if (check) {
|
||
const newDrugs = [...currentDrugs.value];
|
||
newDrugs[selectChineseIndex.value].id = selectChineseId.value;
|
||
updateCurrentDrugs(newDrugs);
|
||
drugList.value = [];
|
||
message.error('该药品已经在处方中了!');
|
||
return;
|
||
}
|
||
|
||
const data = drugList.value.find((v) => v.drug_id === id);
|
||
if (data) {
|
||
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((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:
|
||
data.drug?.unit ||
|
||
drugUnit.value.find((item) => item.id === data.drug.unit_id),
|
||
price: data.price,
|
||
buy_price: data.buy_price,
|
||
way_id: data.drug?.way_id,
|
||
use_ways: drugUseWay.value.find((item) => item.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,
|
||
// 规格(选仓弹窗等处展示)
|
||
specification: data.drug?.specification || data.specification || '',
|
||
instruction: data.drug.instruction,
|
||
type: data.drug.type,
|
||
};
|
||
|
||
const newDrugs = [...currentDrugs.value];
|
||
newDrugs[selectChineseIndex.value] = newProduct;
|
||
updateCurrentDrugs(newDrugs);
|
||
|
||
nextTick(() => {
|
||
const input = document.querySelector(
|
||
`.old-number-input-${selectChineseIndex.value} input`,
|
||
) as HTMLElement;
|
||
input?.focus();
|
||
});
|
||
}
|
||
};
|
||
|
||
const setSelectChineseIndex = (index: number, id: number) => {
|
||
selectChineseIndex.value = index;
|
||
selectChineseId.value = id;
|
||
};
|
||
|
||
const addDrugByChinese = () => {
|
||
const check = currentDrugs.value.find((v) => v.id === newDrugInfo.value.id);
|
||
if (check) {
|
||
message.error('该药品已经在处方中了!');
|
||
return false;
|
||
}
|
||
|
||
const data =
|
||
pendingNewChineseProduct.value ||
|
||
drugList.value.find((v) => v.drug_id === newDrugInfo.value.id);
|
||
if (!data) {
|
||
message.error('请选择药品');
|
||
return false;
|
||
}
|
||
|
||
data.drug.number = newDrugInfo.value.number;
|
||
data.drug.way_id = newDrugInfo.value.way_id;
|
||
const success = addProducts(data);
|
||
if (success) {
|
||
newDrugInfo.value = {};
|
||
pendingNewChineseProduct.value = null;
|
||
}
|
||
return success;
|
||
};
|
||
|
||
const selectDrugByNewDrugInfo = (
|
||
event: KeyboardEvent,
|
||
isNewDrug: boolean,
|
||
) => {
|
||
if (event.key === 'Enter') {
|
||
event.preventDefault();
|
||
if (isNewDrug) {
|
||
addDrugByChinese();
|
||
} else {
|
||
syncToLocalStorage();
|
||
}
|
||
nextTick(() => {
|
||
const input = document.querySelector(
|
||
'.new-select-drug-name input',
|
||
) as HTMLElement;
|
||
input?.focus();
|
||
});
|
||
}
|
||
};
|
||
|
||
const updateChineseNumber = () => {
|
||
syncToLocalStorage();
|
||
};
|
||
|
||
const updateChineseNumberGoNewDrug = (event: KeyboardEvent) => {
|
||
if (event.key === 'Enter') {
|
||
syncToLocalStorage();
|
||
nextTick(() => {
|
||
const input = document.querySelector(
|
||
'.new-select-drug-name input',
|
||
) as HTMLElement;
|
||
input?.focus();
|
||
});
|
||
}
|
||
};
|
||
|
||
// 药品用法选择
|
||
const selectProductChange = (id: number) => {
|
||
selectProductId.value = id;
|
||
};
|
||
|
||
const selectDrugUseWayChange = (id: number) => {
|
||
const newDrugs = currentDrugs.value.map((item) =>
|
||
item.index_id === selectProductId.value
|
||
? {
|
||
...item,
|
||
way_id: id,
|
||
use_ways: drugUseWay.value.find((value) => value.id === id),
|
||
}
|
||
: item,
|
||
);
|
||
updateCurrentDrugs(newDrugs);
|
||
};
|
||
|
||
// 加工规则操作
|
||
const selectProcessRule = (id: number) => {
|
||
processRuleId.value = id;
|
||
getProcessRuleListData(id);
|
||
};
|
||
|
||
const selectProcessRuleNot = (id: number) => {
|
||
childProcessRuleId.value = id;
|
||
getProcessRuleListData(0, id);
|
||
};
|
||
|
||
const selectProcessRuleNotCommit = (id: number) => {
|
||
processRuleNoteId.value = id;
|
||
};
|
||
|
||
const selectPackageMethod = (id: number) => {
|
||
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;
|
||
// 预设整包回填时同一次已带下级 ID,勿误清空(对齐接诊页 / 小程序)
|
||
const keepChild =
|
||
payload.childProcessRuleId != null && Number(payload.childProcessRuleId) > 0;
|
||
const keepNote =
|
||
payload.processRuleNoteId != null && Number(payload.processRuleNoteId) > 0;
|
||
|
||
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) {
|
||
if (!keepChild) {
|
||
childProcessRuleId.value = undefined;
|
||
processRuleNoteId.value = undefined;
|
||
}
|
||
childProcessRuleList.value = [];
|
||
processRuleNoteList.value = [];
|
||
}
|
||
if (payload.childProcessRuleId != null && payload.childProcessRuleId !== oldChildProcessRuleId) {
|
||
if (!keepNote) {
|
||
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) {
|
||
return { hasConflict: false };
|
||
}
|
||
|
||
notification.info({
|
||
message: '正在检查药物相冲',
|
||
duration: 1,
|
||
description: '正在检查药物相冲,请稍等...',
|
||
});
|
||
|
||
try {
|
||
const names = currentDrugs.value.map((item) => item.drug_name);
|
||
const res = await checkChineseMedicineConflictApi({ names });
|
||
|
||
if (res.is_exist === true) {
|
||
checkData.value = { message: res.message };
|
||
return { hasConflict: true, message: res.message };
|
||
} else {
|
||
notification.success({
|
||
message: '检查成功',
|
||
duration: 3,
|
||
description: '暂无相冲药品',
|
||
});
|
||
return { hasConflict: false };
|
||
}
|
||
} catch (error) {
|
||
console.error('检查药物相冲失败:', error);
|
||
return { hasConflict: false };
|
||
}
|
||
};
|
||
|
||
// 发送处方
|
||
const sendPrescription = async (
|
||
doctorSecondSignValue = 0,
|
||
customSendMode: number = 0,
|
||
customStoreId: number | null = null,
|
||
warehouseMap: Record<number, number> | null = null,
|
||
) => {
|
||
if (currentDrugs.value.length === 0) {
|
||
message.error('请选择药品');
|
||
return false;
|
||
}
|
||
|
||
if (activeCategory.value === 1) {
|
||
if (ruleType.value === 1 && packageMethodId.value == null) {
|
||
message.error('请选择包法');
|
||
return false;
|
||
}
|
||
if (ruleType.value === 2) {
|
||
if (processRuleId.value == null) {
|
||
message.error('请选择制剂');
|
||
return false;
|
||
}
|
||
if (processRuleNoteId.value == null) {
|
||
message.error('请选择规格');
|
||
return false;
|
||
}
|
||
if (childProcessRuleId.value == null) {
|
||
message.error('请选择备注');
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!diagnosis.value) {
|
||
message.error('诊断结果不能为空');
|
||
return false;
|
||
}
|
||
|
||
if (!medicalAdvice.value) {
|
||
message.error('医嘱不能为空');
|
||
return false;
|
||
}
|
||
try {
|
||
// 如果是转诊挂号,自动使用承接方诊所ID(转接方开处方时)
|
||
let finalSendMode = customSendMode;
|
||
let finalStoreId = customStoreId;
|
||
|
||
if (registerStoreInfo.value?.is_from_transfer === 1 && registerStoreInfo.value?.delegate_store_id) {
|
||
// 转接方开处方时,自动使用承接方诊所ID,不需要在模态框选择
|
||
finalSendMode = 1;
|
||
finalStoreId = registerStoreInfo.value.delegate_store_id;
|
||
}
|
||
|
||
const response = await addWestPrescription({
|
||
patient: activePatient.value,
|
||
drugs: currentDrugs.value,
|
||
diagnosis: diagnosis.value,
|
||
medicalAdvice: medicalAdvice.value,
|
||
total: totalCost.value,
|
||
category: category.value,
|
||
drug_type: 2,
|
||
register_id: currentRegisterId.value,
|
||
treatment_price: treatmentPrice.value,
|
||
package_method_id: packageMethodId.value,
|
||
process_rule_id: processRuleId.value,
|
||
process_rule_note_id: processRuleNoteId.value,
|
||
child_process_rule_id: childProcessRuleId.value,
|
||
process_rule_type: ruleType.value,
|
||
prescription_type: activeCategory.value,
|
||
processing_fee: processingFee.value,
|
||
dosage: dosage.value,
|
||
day_dosage: dayDosage.value,
|
||
doctor_second_sign: doctorSecondSignValue,
|
||
// 中医在线问诊所需的东西
|
||
diseases_id: diseasesSelected.value,
|
||
method_id: methodSelected.value,
|
||
syndrome_id: syndromeSelected.value,
|
||
// 诊所选择参数(转诊挂号时自动使用承接方诊所ID)
|
||
send_mode: finalSendMode,
|
||
custom_store_id: finalSendMode === 1 ? finalStoreId : null,
|
||
// 在线复诊手选仓:列表格式避免数字键对象序列化丢失
|
||
warehouse_map: warehouseMap
|
||
? Object.entries(warehouseMap).map(([drug_id, warehouse_id]) => ({
|
||
drug_id: Number(drug_id),
|
||
warehouse_id: Number(warehouse_id),
|
||
}))
|
||
: undefined,
|
||
});
|
||
|
||
const res = await response;
|
||
message.success('处方已发送');
|
||
sendMessage({
|
||
roomId: chatStore.currentFriend.room_id,
|
||
senderId: userStore.currentUser.doctor_id,
|
||
receiverId: chatStore.currentFriend.id,
|
||
type: 'prescription',
|
||
content: JSON.stringify(res),
|
||
});
|
||
chatStore.addMessage(
|
||
{
|
||
id: Date.now().toString(),
|
||
room_id: chatStore.currentFriend.room_id,
|
||
sender_user_id: `doctor-${userStore.currentUser.doctor_id}`,
|
||
receiver_user_id: chatStore.currentFriend.id,
|
||
message_type: 4,
|
||
message_content: JSON.stringify(res),
|
||
messageTypeName: 'prescription',
|
||
created_at: Date.now(),
|
||
created_at_text: new Date().toLocaleTimeString().slice(0, 5),
|
||
timestamp: Date.now(),
|
||
isSent: true,
|
||
read: true,
|
||
duration: 0,
|
||
},
|
||
userStore.currentUser.doctor_id,
|
||
);
|
||
// 在线复诊开方后自动连发购药指引与用药温馨提示(小助手发送)
|
||
const tipTexts = [
|
||
'根据您的病情描述,已为您开具电子处方,请点击上方的‘立即支付’,进行购药;如有商品价格和订单等问题请咨询平台客服。',
|
||
'温馨提示:用药前请详细阅读药品说明书,并严格按照线下医嘱用药。如用药过程中出现病情变化或其它不适症状,请立即停药并及时就医。(请您注意,如果您尚未在医院就诊或未曾使用过本次申请的药品,请暂时不要支付订单。我们建议您在医生的指导下使用药品,以确保用药安全。)',
|
||
];
|
||
tipTexts.forEach((tip, tipIdx) => {
|
||
sendMessage({
|
||
roomId: chatStore.currentFriend.room_id,
|
||
senderId: 'doctor_assistant',
|
||
receiverId: chatStore.currentFriend.id,
|
||
type: 'text',
|
||
content: tip,
|
||
});
|
||
chatStore.addMessage(
|
||
{
|
||
id: `${Date.now()}_tip_${tipIdx}`,
|
||
room_id: chatStore.currentFriend.room_id,
|
||
sender_user_id: 'doctor_assistant',
|
||
receiver_user_id: chatStore.currentFriend.id,
|
||
message_type: 0,
|
||
message_content: tip,
|
||
messageTypeName: 'text',
|
||
created_at: Date.now() + tipIdx + 1,
|
||
created_at_text: new Date().toLocaleTimeString().slice(0, 5),
|
||
timestamp: Date.now() + tipIdx + 1,
|
||
isSent: true,
|
||
read: true,
|
||
duration: 0,
|
||
},
|
||
userStore.currentUser.doctor_id,
|
||
);
|
||
});
|
||
resetForm();
|
||
// 发送成功后清空本挂号下全部分类草稿(含另一分类与 activeCategory)
|
||
clearLocalPrescriptionCache();
|
||
|
||
// 返回包含转诊信息的响应数据
|
||
return {
|
||
success: true,
|
||
result: res?.result || res?.data || res,
|
||
need_transfer: res?.result?.need_transfer || res?.data?.need_transfer || res?.need_transfer,
|
||
transfer_prescription_id: res?.result?.transfer_prescription_id || res?.data?.transfer_prescription_id || res?.transfer_prescription_id,
|
||
};
|
||
} catch (error) {
|
||
console.error('发送处方失败:', error);
|
||
message.error('发送处方失败');
|
||
return false;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 清除当前挂号会话的处方 localStorage 草稿
|
||
* 原因:resetForm 只会把当前分类写成空数组,另一分类与 activeCategory 会残留,再次打开仍会回填
|
||
*/
|
||
const clearLocalPrescriptionCache = () => {
|
||
const registerId = currentRegisterId.value;
|
||
if (!registerId) return;
|
||
try {
|
||
// 与小程序 PrescriptionStorage.clearAllPrescriptionData 对齐的分类集合
|
||
const categories = [1, 2, 3, 5, 6, 7];
|
||
categories.forEach((cat) => {
|
||
localStorage.removeItem(
|
||
`${storagePrefix.value}prescriptionData_${cat}_${registerId}`,
|
||
);
|
||
// 清理历史双横线孤儿 key(旧版弹窗 `${prefix}-prescriptionData_`)
|
||
localStorage.removeItem(
|
||
`${storagePrefix.value}-prescriptionData_${cat}_${registerId}`,
|
||
);
|
||
});
|
||
localStorage.removeItem(
|
||
`${storagePrefix.value}activeCategory${registerId}`,
|
||
);
|
||
} catch (error) {
|
||
console.error('清除处方本地缓存失败:', error);
|
||
}
|
||
};
|
||
|
||
const resetForm = () => {
|
||
updateCurrentDrugs([]);
|
||
diagnosis.value = '';
|
||
medicalAdvice.value = '';
|
||
packageMethodId.value = 2;
|
||
dosage.value = 7;
|
||
dayDosage.value = 2;
|
||
newDrugInfo.value = {};
|
||
doctorSecondSign.value = 0;
|
||
};
|
||
|
||
const changeCategory = (categoryValue: number) => {
|
||
// 先保存当前类型的药品数据
|
||
localStorage.setItem(
|
||
getStorageKey(activeCategory.value),
|
||
JSON.stringify(currentDrugs.value),
|
||
);
|
||
|
||
// 保存 Tab 类型
|
||
localStorage.setItem(
|
||
`${storagePrefix.value}activeCategory${currentRegisterId.value}`,
|
||
categoryValue.toString(),
|
||
);
|
||
activeCategory.value = categoryValue;
|
||
|
||
// 加载新类型对应的药品数据
|
||
const stored = localStorage.getItem(getStorageKey(categoryValue));
|
||
if (stored) {
|
||
currentDrugs.value.splice(0, currentDrugs.value.length, ...JSON.parse(stored));
|
||
} else {
|
||
currentDrugs.value.splice(0, currentDrugs.value.length);
|
||
}
|
||
// 切换后聚焦 Tab 栏当前项
|
||
nextTick(() => {
|
||
const el = document.getElementById(`rx-modal-tab-${categoryValue}`);
|
||
el?.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' });
|
||
});
|
||
};
|
||
|
||
// 工具函数
|
||
const splitString = (str: string) => {
|
||
if (!str) return [];
|
||
return str.split(',');
|
||
};
|
||
|
||
const refreshCurrentDrugs = () => {
|
||
loadFromLocalStorage();
|
||
};
|
||
|
||
// 重置初始化状态(用于切换患者时)
|
||
const resetInitializationState = () => {
|
||
isInitialized.value = false;
|
||
isPatientInfoLoaded.value = false;
|
||
patientInfo.value = null;
|
||
activePatient.value = null;
|
||
userPatientHealthInquiry.value = null;
|
||
prescriptionList.value = [];
|
||
console.log('重置初始化状态');
|
||
};
|
||
|
||
return {
|
||
// 状态
|
||
patientInfo,
|
||
userPatientHealthInquiry,
|
||
prescriptionList,
|
||
currentRegisterId,
|
||
activePatient,
|
||
drugUseNum,
|
||
drugUseFrequency,
|
||
drugUseType,
|
||
drugUnit,
|
||
drugTime,
|
||
drugUseWay,
|
||
myStoreList,
|
||
myStoreId,
|
||
activeCategory,
|
||
categories,
|
||
prescriptionTypeDefault,
|
||
prescriptionTypeLoading,
|
||
prescriptionTypeAllowed,
|
||
prescriptionTypeDenyMessage,
|
||
diagnosis,
|
||
medicalAdvice,
|
||
treatmentPrice,
|
||
ruleType,
|
||
drugList,
|
||
currentDrugs,
|
||
category,
|
||
selectProductId,
|
||
processRuleList,
|
||
childProcessRuleList,
|
||
processRuleNoteList,
|
||
processRuleId,
|
||
processRuleNoteId,
|
||
childProcessRuleId,
|
||
packageMethodId,
|
||
dosage,
|
||
dayDosage,
|
||
newDrugInfo,
|
||
selectChineseIndex,
|
||
selectChineseId,
|
||
doctorSecondSign,
|
||
checkData,
|
||
|
||
// 计算属性
|
||
totalProductCost,
|
||
processingFee,
|
||
totalCost,
|
||
seeRate,
|
||
chineseGrossMarginPercent,
|
||
getChineseItemMargin,
|
||
fetchStoreSeeRate,
|
||
|
||
// 方法
|
||
initializePrescription,
|
||
initializeForModal,
|
||
initializeBasicData,
|
||
loadPrescriptionTypeOptions,
|
||
resetInitializationState,
|
||
getDrugList,
|
||
addProducts,
|
||
resolveDrugCategory,
|
||
removeDrug,
|
||
updateDrugQuantity,
|
||
increment,
|
||
decrement,
|
||
toggleEditDrug,
|
||
saveEditDrug,
|
||
updateDrugUsage,
|
||
selectNewDrugInfo,
|
||
selectOldDrugInfo,
|
||
onSelectNewChineseDrug,
|
||
onSelectOldChineseDrug,
|
||
setSelectChineseIndex,
|
||
addDrugByChinese,
|
||
selectDrugByNewDrugInfo,
|
||
updateChineseNumber,
|
||
updateChineseNumberGoNewDrug,
|
||
selectProductChange,
|
||
selectDrugUseWayChange,
|
||
selectProcessRule,
|
||
selectProcessRuleNot,
|
||
selectProcessRuleNotCommit,
|
||
selectPackageMethod,
|
||
handleChineseConfigChange,
|
||
checkChineseMedicineConflict,
|
||
sendPrescription,
|
||
resetForm,
|
||
clearLocalPrescriptionCache,
|
||
changeCategory,
|
||
getProcessRuleListData,
|
||
splitString,
|
||
refreshCurrentDrugs,
|
||
syncToLocalStorage,
|
||
loadFromLocalStorage,
|
||
updateCurrentDrugs,
|
||
traditionalChineseMedicine,
|
||
diseasesSelected,
|
||
methodSelected,
|
||
syndromeSelected,
|
||
// 诊所选择相关
|
||
registerStoreInfo,
|
||
selectedStoreId,
|
||
sendMode,
|
||
resolvePrescribingStoreId,
|
||
prescribingStoreId,
|
||
fetchRegisterStoreInfo,
|
||
toggleStoreSelection,
|
||
currentStoreName,
|
||
targetStoreName,
|
||
canChangeStore,
|
||
};
|
||
});
|