Files
xk-admin/apps/web-antd/src/store/usePrescription.ts
李琦 50fc55925f feat: 地区选择器改走接口、订单市价重算与资金流水、同步日志内容复用
region-address-picker 接 region-picker API;订单支持按进价重算 market_price、追踪页资金流水;MES/ERP/中台同步日志共用内容查看组件;地区管理支持 pid 下钻与拼音检索。
2026-10-15 10:01:20 +08:00

673 lines
19 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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,
getDrugUseList,
getMyStoreListApi,
getPatientItem,
getProcessRuleList,
getProductListDoctorReception,
} from "#/views/doctor/doctor-reception/api"
export const usePrescriptionStore = () => {
// 基础数据
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 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)
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 doctorSecondSign = ref(0)
const checkData = ref<any>({})
// 获取localStorage key(修改为在线复诊前缀)
const getStorageKey = () => `onlineConsultation-prescriptionData${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
})
// 重新设计的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[]) => {
// 使用splice确保响应式更新
currentDrugs.value.splice(0, currentDrugs.value.length, ...newDrugs)
syncToLocalStorage()
}
// 方法
const initializePrescription = async (registerId: number | string) => {
currentRegisterId.value = registerId
// 先加载localStorage数据
loadFromLocalStorage()
await Promise.all([getMyStoreList(), getDrugUseListData(), getProcessRuleListData(), getPatientInfo()])
}
/**
* 拉取门店并保留已选/本地缓存门店,避免每次重置为列表第一项导致预设按店查空
*/
const getMyStoreList = async () => {
try {
const res = await getMyStoreListApi()
myStoreList.value = res || []
if (!myStoreList.value.length) return
const preferred =
Number(myStoreId.value || 0) ||
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)
} 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
} 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
}
} catch (error) {
console.error("获取加工规则失败:", error)
}
}
const getPatientInfo = async () => {
try {
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
} catch (error) {
console.error("获取患者信息失败:", error)
}
}
// 药品搜索
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,
})
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)
// 药品操作
const addProducts = (data: any) => {
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: drugUnit.value.find((item) => item.id === data.drug.unit_id),
price: data.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,
instruction: data.drug.instruction,
type: data.drug.type,
select_number: 1,
}
// 使用新的更新方法
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 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) {
newDrugInfo.value.price = data.price
newDrugInfo.value.name = data.drug.drug_name
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: drugUnit.value.find((item) => item.id === data.drug.unit_id),
price: data.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,
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 = 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 = {}
}
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 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) => {
// 验证表单
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 {
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,
})
message.success("处方已发送")
resetForm()
return true
} catch (error) {
console.error("发送处方失败:", error)
message.error("发送处方失败")
return false
}
}
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) => {
activeCategory.value = categoryValue
updateCurrentDrugs([])
localStorage.setItem(`onlineConsultation-activeCategory${currentRegisterId.value}`, categoryValue.toString())
}
// 工具函数
const splitString = (str: string) => {
if (!str) return []
return str.split(",")
}
// 强制刷新currentDrugs(用于调试或特殊情况)
const refreshCurrentDrugs = () => {
loadFromLocalStorage()
}
return {
// 状态
patientInfo,
userPatientHealthInquiry,
prescriptionList,
currentRegisterId,
activePatient,
drugUseNum,
drugUseFrequency,
drugUseType,
drugUnit,
drugTime,
drugUseWay,
myStoreList,
myStoreId,
activeCategory,
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,
// 方法
initializePrescription,
getDrugList,
addProducts,
removeDrug,
updateDrugQuantity,
increment,
decrement,
selectNewDrugInfo,
selectOldDrugInfo,
setSelectChineseIndex,
addDrugByChinese,
selectDrugByNewDrugInfo,
updateChineseNumber,
updateChineseNumberGoNewDrug,
selectProductChange,
selectDrugUseWayChange,
selectProcessRule,
selectProcessRuleNot,
selectProcessRuleNotCommit,
selectPackageMethod,
checkChineseMedicineConflict,
sendPrescription,
resetForm,
changeCategory,
getProcessRuleListData,
splitString,
refreshCurrentDrugs,
// 新增的方法
syncToLocalStorage,
loadFromLocalStorage,
updateCurrentDrugs,
}
}