Files
xk-doctor-wx/subPackages/sub_workbench/prescription_v2/index.vue

1525 lines
63 KiB
Vue
Raw Normal View History

2026-03-06 13:59:22 +08:00
<template>
<view class="safe-area-inset-bottom page-bg">
2026-03-06 13:59:22 +08:00
<!-- 导航栏 -->
<u-navbar class="navbar" :is-back="true" title="开方" :custom-back="handleCustomBack" title-color="#000" background="{ background: '#fff' }">
2026-03-06 13:59:22 +08:00
</u-navbar>
<!-- 处方类型Tab切换 -->
<view class="tabs flex p-32 flex-ali-center flex-jus-sp shadow-sm" style="overflow-x: auto; position: relative; z-index: 10;">
<u-button
:throttle-time="0"
:plain="true"
:type="activeCategory === category.value ? 'success' : 'default'"
v-for="(category, index) in prescriptionCategories"
:key="category.value"
:custom-style="tabsBtnStyle"
@click="handleSwitchCategory(category.value)"
:hairline="true"
:hoverStayTime="0"
:style="{
2026-03-06 13:59:22 +08:00
display: (index === 0 && identity === 2) || identity === 1 ? 'block' : 'none',
marginLeft: '10rpx',
}">
{{ category.label }}
</u-button>
</view>
<!-- 诊断输入区域 -->
<view class="top white p-32 flex-col m-t-16 radius-12 mx-32">
2026-03-06 13:59:22 +08:00
<view class="top_title flex-row flex-ali-center">
<image :src="require('@/static/image/js.png')" class="size-32"></image>
<d-text text="临床诊断" className="fs-32 m-l-16 font-bold" color="#333"></d-text>
2026-03-06 13:59:22 +08:00
</view>
<view class="m-t-16 flex flex-wrap">
<view class="m-r-16 m-t-16" v-for="(item, i) in diagnoses" :key="item.id">
<u-tag
shape="circle"
:text="item.name"
bg-color="#E8F6F4"
color="#6ACDBB"
border-color="#E8F6F4"
close-color="#6ACDBB"
:closeable="true"
@close="handleRemoveDiagnosis(i)" />
2026-03-06 13:59:22 +08:00
</view>
</view>
<view class="m-t-24">
<u-input
disabled
placeholder="请选择或输入疾病诊断"
:custom-style="illnessStyle"
@click="handleOpenDiagnosisModal" />
2026-03-06 13:59:22 +08:00
</view>
</view>
<!-- 滚动内容区域 -->
<scroll-view :style="scrollStyle" scroll-y="true">
2026-03-06 13:59:22 +08:00
<!-- 西药列表 -->
<view class="mx-32 m-t-24" v-if="activeCategory === 2">
<view class="flex-row flex-jus-sp flex-ali-center m-b-24">
<view class="flex-row flex-ali-center">
<view class="rp-icon">Rp</view>
<text class="fs-28 text-gray m-l-8">西药处方</text>
</view>
<view class="flex-row" style="height: 50rpx;">
<u-button
v-if="!isCommonPrescription && supportsCommonPrescriptionTemplate"
:throttle-time="0"
shape="circle"
size="mini"
:custom-style="{backgroundColor: 'transparent !important',border:'1px solid #6ACDBB',color:'#6ACDBB'}"
plain
@click="handleOpenCommonPrescriptionModal"
:ripple="true">
2026-03-06 13:59:22 +08:00
常用方
</u-button>
<view class="m-l-16">
<u-button
:throttle-time="0"
shape="circle"
size="mini"
:custom-style="{ backgroundColor:'#6ACDBB',color:'#fff', border: 'none' }"
@click="handleOpenWesternMedicineModal">
<u-icon name="plus" size="22" class="m-r-4"></u-icon> 添加药品
2026-03-06 13:59:22 +08:00
</u-button>
</view>
</view>
</view>
<!-- 西药卡片设计 -->
<view class="medicine-card" v-for="(item, index) in currentDrugs" :key="item.index_id">
<view class="flex-row">
<image
v-if="item.image"
:src="item.image"
class="drug-image-modern"
mode="aspectFill"
2026-03-06 13:59:22 +08:00
></image>
<view class="flex-1 m-l-24 flex-col">
<view class="flex-row flex-jus-sp flex-ali-start">
<text class="fs-30 font-bold color-title line-clamp-2 w-70">{{index+1}}. {{item.drug_name}}</text>
<text class="fs-32 font-bold color-price">{{parseFloat(item.price || 0).toFixed(2)}}</text>
2026-03-06 13:59:22 +08:00
</view>
<view class="flex-row flex-jus-sp flex-ali-center m-t-12">
<text class="fs-24 color-sub">规格{{item.specification || '--'}}</text>
<text class="fs-26 color-title font-bold">×{{item.select_number || item.number}}</text>
2026-03-06 13:59:22 +08:00
</view>
<view class="m-t-16 usage-capsule">
<u-icon name="info-circle" size="24" color="#6ACDBB" class="m-r-8"></u-icon>
<text class="fs-24" style="color:#008771">{{formatDrugUsage(item) || '请设置用法用量'}}</text>
2026-03-06 13:59:22 +08:00
</view>
</view>
</view>
<!-- 内敛的卡片操作区 -->
<view class="card-actions flex-row flex-jus-sp flex-ali-center">
<view class="action-btn-text danger" @click="handleRemoveDrug(index)">
<u-icon name="trash" size="28"></u-icon> 删除
</view>
<view class="action-btn-ghost primary" @click="handleEditWesternDrug(item, index)">
调整用量
</view>
2026-03-06 13:59:22 +08:00
</view>
</view>
<view class="white p-32 radius-12 m-t-24 flex-col" v-if="currentDrugs.length > 0">
2026-03-06 13:59:22 +08:00
<view class="flex-jus-sp flex-row flex-ali-center">
<d-text text="医嘱补充" color="#333" className="font-bold"></d-text>
<d-text @click="handleOpenDoctorOrderModal" text="选择常用医嘱" color="#6ACDBB"></d-text>
2026-03-06 13:59:22 +08:00
</view>
<u-input v-model="medicalAdvice" placeholder="请输入医嘱注意事项..." :custom-style="entrustStyle" />
2026-03-06 13:59:22 +08:00
</view>
<view class="flex-row flex-jus-center m-t-64" v-if="currentDrugs.length === 0">
2026-03-06 13:59:22 +08:00
<d-empty @click="handleOpenWesternMedicineModal"></d-empty>
</view>
</view>
<!-- 中药列表 -->
<view class="mx-32 m-t-24" v-if="activeCategory === 1">
<view class="flex-row flex-jus-sp flex-ali-center m-b-24">
<view class="flex-row flex-ali-center">
<view class="rp-icon">Rp</view>
<text class="fs-28 text-gray m-l-8">中药处方</text>
2026-03-06 13:59:22 +08:00
</view>
<view class="flex-row" style="height: 50rpx;">
<u-button
v-if="!isCommonPrescription && supportsCommonPrescriptionTemplate"
:throttle-time="0"
shape="circle"
size="mini"
:custom-style="{backgroundColor: 'transparent !important',border:'1px solid #6ACDBB',color:'#6ACDBB'}"
plain
@click="handleOpenCommonPrescriptionModal"
:ripple="true">
2026-03-06 13:59:22 +08:00
常用方
</u-button>
<view class="m-l-16">
<u-button
:throttle-time="0"
:custom-style="{ backgroundColor:'#6ACDBB',color:'#fff', border: 'none' }"
shape="circle"
size="mini"
@click="handleOpenChineseMedicineModal">
<u-icon name="plus" size="22" class="m-r-4"></u-icon> 添加药材
2026-03-06 13:59:22 +08:00
</u-button>
</view>
</view>
</view>
<!-- 中药极简高密度标签云设计 -->
<view class="white radius-12 p-32" v-if="currentDrugs.length > 0">
<view class="flex-row flex-jus-sp flex-ali-center m-b-24">
<text class="fs-28 font-bold color-title">药材清单 ({{currentDrugs.length}})</text>
<view class="flex-row">
<text class="fs-26 color-primary m-r-32" @click="handleOpenChineseMedicineModal">修改剂量</text>
<text class="fs-26 color-danger" @click="handleRemoveAllDrugs">清空</text>
2026-03-06 13:59:22 +08:00
</view>
</view>
<view class="tcm-tag-cloud">
<view class="tcm-tag" v-for="(it) in currentDrugs" :key="it.id">
<text class="tcm-name">{{it.drug_name || it.name}}</text>
<text class="tcm-weight">{{String(it.number)}}{{it.unit ? it.unit.name : 'g'}}</text>
</view>
2026-03-06 13:59:22 +08:00
</view>
</view>
<view class="flex-row flex-jus-center m-t-64" v-else>
2026-03-06 13:59:22 +08:00
<d-empty @click="handleOpenChineseMedicineModal"></d-empty>
</view>
</view>
<!-- 简单产品列表保健食品产品服务包非药品医疗器械 -->
<view class="mx-32 m-t-24" v-if="[3, 5, 6, 7].includes(activeCategory)">
<view class="flex-row flex-jus-sp flex-ali-center m-b-24">
<view class="flex-row flex-ali-center">
<view class="rp-icon">Rp</view>
<text class="fs-28 text-gray m-l-8">产品/器械</text>
</view>
2026-03-06 13:59:22 +08:00
<view class="flex-row m-l-163" style="height: 50rpx;">
<view class="m-l-16">
<u-button
:throttle-time="0"
:custom-style="{ backgroundColor:'#6ACDBB',color:'#fff', border: 'none' }"
shape="circle"
size="mini"
@click="handleOpenSimpleProductModal">
<u-icon name="plus" size="22" class="m-r-4"></u-icon> 添加商品
2026-03-06 13:59:22 +08:00
</u-button>
</view>
</view>
</view>
<!-- 简单产品卡片设计 -->
<view class="medicine-card" v-for="(item, index) in currentDrugs" :key="item.index_id">
<view class="flex-row">
<image
v-if="item.image"
:src="item.image"
class="drug-image-modern"
mode="aspectFill"
2026-05-07 11:04:56 +08:00
></image>
<view class="flex-1 m-l-24 flex-col">
<view class="flex-row flex-jus-sp flex-ali-start">
<text class="fs-30 font-bold color-title line-clamp-2 w-70">{{index+1}}. {{item.drug_name}}</text>
<text class="fs-32 font-bold color-price">{{parseFloat(item.price || 0).toFixed(2)}}</text>
2026-05-07 11:04:56 +08:00
</view>
<view class="flex-row flex-jus-sp flex-ali-center m-t-12">
<text class="fs-24 color-sub">规格{{item.specification || '--'}}</text>
<!-- 精致步进器 -->
<view class="modern-stepper flex-row flex-ali-center">
<view class="stepper-btn" @click.stop="handleDecrementSimpleProduct(index)">-</view>
<text class="stepper-val fs-26">{{item.select_number || item.number}}{{getProductUnit(activeCategory)}}</text>
<view class="stepper-btn" @click.stop="handleIncrementSimpleProduct(index)">+</view>
2026-05-07 11:04:56 +08:00
</view>
</view>
2026-03-06 13:59:22 +08:00
</view>
</view>
<view class="card-actions flex-row flex-jus-end">
<view class="action-btn-text danger" @click="handleRemoveDrug(index)">
<u-icon name="trash" size="28"></u-icon> 删除
</view>
2026-03-06 13:59:22 +08:00
</view>
</view>
<view class="white p-32 radius-12 m-t-24 flex-col" v-if="currentDrugs.length > 0">
2026-03-06 13:59:22 +08:00
<view class="flex-jus-sp flex-row flex-ali-center">
<d-text text="医嘱补充" color="#333" className="font-bold"></d-text>
<d-text @click="handleOpenDoctorOrderModal" text="选择常用医嘱" color="#6ACDBB"></d-text>
2026-03-06 13:59:22 +08:00
</view>
<u-input v-model="medicalAdvice" placeholder="请输入注意事项..." :custom-style="entrustStyle" />
2026-03-06 13:59:22 +08:00
</view>
<view class="flex-row flex-jus-center m-t-64" v-if="currentDrugs.length === 0">
2026-03-06 13:59:22 +08:00
<d-empty @click="handleOpenSimpleProductModal"></d-empty>
</view>
</view>
<!-- 医嘱输入区域中药和简单产品共用 -->
<view class="flex-col white p-32 radius-12 mx-32 m-t-24" v-if="activeCategory === 1 && currentDrugs.length > 0">
2026-03-06 13:59:22 +08:00
<view class="flex-jus-sp flex-row flex-ali-center">
<d-text text="医嘱补充" color="#333" className="font-bold"></d-text>
<d-text @click="handleOpenDoctorOrderModal" text="选择常用医嘱" color="#6ACDBB"></d-text>
2026-03-06 13:59:22 +08:00
</view>
<u-input v-model="medicalAdvice" placeholder="请输入服药注意事项..." :custom-style="entrustStyle" />
2026-03-06 13:59:22 +08:00
</view>
<!-- 中药配置区域 -->
<view class="white radius-12 p-32 mx-32 m-t-24" v-if="activeCategory === 1">
<ChineseMedicineConfig
:config="chineseConfig"
:processRuleList="processRuleList"
:childProcessRuleList="childProcessRuleList"
:processRuleNoteList="processRuleNoteList"
@update:config="handleUpdateChineseConfig"
2026-03-06 13:59:22 +08:00
/>
</view>
<!-- 费用计算区域 -->
<view class="fee-summary white radius-12 p-32 mx-32 m-t-24 m-b-40">
<view class="flex-row flex-jus-sp flex-ali-center m-b-24">
<text class="fs-28 color-sub">诊疗费</text>
<view class="flex-row flex-ali-center">
<text class="fs-28 m-r-8"></text>
<u-input
v-model="treatmentPrice"
placeholder="0.00"
input-align="right"
:custom-style="priceInputStyle" />
</view>
2026-03-06 13:59:22 +08:00
</view>
<view class="flex-row flex-jus-sp flex-ali-center m-b-24" v-if="processingFee > 0">
<text class="fs-28 color-sub">加工费</text>
<text class="fs-30 color-title font-bold">{{processingFee.toFixed(2)}}</text>
</view>
<view class="flex-row flex-jus-sp flex-ali-center m-b-32">
<text class="fs-28 color-sub">商品计费</text>
<text class="fs-30 color-title font-bold">{{totalProductCost.toFixed(2)}}</text>
2026-03-06 13:59:22 +08:00
</view>
<!-- 总价显示 -->
<view class="total-price-bar flex-row flex-jus-sp flex-ali-center pt-32 border-t-dashed" v-if="currentDrugs.length > 0">
<text class="fs-30 font-bold color-title">合计</text>
<text class="fs-48 font-bold color-price">{{totalPrice}}</text>
2026-03-06 13:59:22 +08:00
</view>
</view>
<!-- 提示信息 -->
<view class="ac p-b-40 p-x-32 flex-row flex-jus-center">
<u-icon name="shield-check" color="#B0B6C2" size="28" class="m-r-8"></u-icon>
<text class="fs-24 color-sub">请确认患者已在实体医院就诊并有明确诊断</text>
2026-03-06 13:59:22 +08:00
</view>
</scroll-view>
<!-- 底部操作栏 -->
<view class="bottom flex-jus-sp flex-ali-center safe-area-inset-bottom">
<view v-if="!isCommonPrescription && supportsCommonPrescriptionTemplate" @click="handleSaveAsCommonPrescription" class="btnText">另存常用方</view>
<u-button
:throttle-time="0"
@click="handleSendPrescription"
shape="circle"
:custom-style="{
2026-03-06 13:59:22 +08:00
backgroundColor: isSubmitting ? '#A5DCD2' : '#6ACDBB',
color: '#fff',
height: '86rpx',
width: (isCommonPrescription || !supportsCommonPrescriptionTemplate) ? '686rpx' : '448rpx'
2026-03-06 13:59:22 +08:00
}"
:disabled="isSubmitting">
2026-03-06 13:59:22 +08:00
{{ isCommonPrescription ? '保存常用方' : '发送处方' }}
</u-button>
</view>
<!-- 诊断选择弹窗 -->
<DiagnosisModal
v-model="showDiagnosisModal"
:selectedDiagnosis="diagnosisText"
@confirm="handleDiagnosisConfirm"
2026-03-06 13:59:22 +08:00
/>
2026-03-06 13:59:22 +08:00
<!-- 医嘱选择弹窗 -->
<DoctorOrderModal
v-model="showDoctorOrderModal"
:selectedDoctorOrder="medicalAdvice"
@confirm="handleDoctorOrderConfirm"
2026-03-06 13:59:22 +08:00
/>
<!-- 常用方选择弹窗 -->
<CommonPrescriptionModal
v-model="showCommonPrescriptionModal"
:prescriptionType="activeCategory"
@select="handleSelectCommonPrescription"
2026-03-06 13:59:22 +08:00
/>
<!-- 西药选择弹窗 -->
<WesternMedicineModal
v-model="showWesternMedicineModal"
:currentDrugs="currentDrugs"
@select="handleSelectWesternDrug"
2026-03-06 13:59:22 +08:00
/>
<!-- 中药选择弹窗 -->
<ChineseMedicineModal
v-model="showChineseMedicineModal"
:currentDrugs="currentDrugs"
@select="handleSelectChineseDrug"
2026-03-06 13:59:22 +08:00
/>
<!-- 简单产品选择弹窗 -->
<SimpleProductModal
v-model="showSimpleProductModal"
:productType="activeCategory"
:currentProducts="currentDrugs"
@select="handleSelectSimpleProduct"
2026-03-06 13:59:22 +08:00
/>
<!-- 西药用法用量设置弹窗 -->
<WesternMedicineUsageModal
v-model="showWesternUsageModal"
:drug="editingDrug"
@confirm="handleConfirmWesternUsage"
2026-03-06 13:59:22 +08:00
/>
<!-- 保存常用方弹窗 -->
<u-modal
v-model="showSaveCommonPrescriptionModal"
:show-cancel-button="true"
title="保存常用方"
@confirm="handleConfirmSaveCommonPrescription"
@cancel="showSaveCommonPrescriptionModal = false">
2026-03-06 13:59:22 +08:00
<view class="slot-content" style="padding: 20rpx;">
<u-input
v-model="commonPrescriptionName"
placeholder="请输入处方名称"
type="text"
:border="true" />
2026-03-06 13:59:22 +08:00
</view>
</u-modal>
</view>
</template>
<script>
// 注意:这部分保持你原有的逻辑代码,不进行任何修改,确保业务完全正常
import {
addWestPrescription,
2026-03-06 13:59:22 +08:00
checkChineseMedicineConflictApi,
getDiseaseList,
getDrugUseList,
getProductListDoctorReception,
getPatientInfoByPatientId,
getProcessRuleList,
getCommonPrescriptionListApi,
saveWestCommonPrescriptionApi,
saveChineseCommonPrescriptionApi,
getCurrentStoreTypeApi,
getPrescriptionInfoApi
2026-03-06 13:59:22 +08:00
} from '@/api/reception.js';
import { PrescriptionStorage } from './utils/prescriptionStorage.js';
import { PrescriptionCalculator } from './utils/prescriptionCalculator.js';
import { PrescriptionValidator } from './utils/prescriptionValidator.js';
import DiagnosisModal from './components/modals/DiagnosisModal.vue';
import DoctorOrderModal from './components/modals/DoctorOrderModal.vue';
import CommonPrescriptionModal from './components/modals/CommonPrescriptionModal.vue';
import WesternMedicineModal from './components/modals/WesternMedicineModal.vue';
import ChineseMedicineModal from './components/modals/ChineseMedicineModal.vue';
import SimpleProductModal from './components/modals/SimpleProductModal.vue';
import WesternMedicineUsageModal from './components/modals/WesternMedicineUsageModal.vue';
import ChineseMedicineConfig from './components/ChineseMedicineConfig.vue';
export default {
name: 'PrescriptionV2',
components: {
DiagnosisModal,
DoctorOrderModal,
CommonPrescriptionModal,
WesternMedicineModal,
ChineseMedicineModal,
SimpleProductModal,
WesternMedicineUsageModal,
ChineseMedicineConfig
},
data() {
return {
registerId: '',
patientId: '',
pendingReusePrescriptionId: '',
2026-03-06 13:59:22 +08:00
patientInfo: null,
prescriptionCategories: [
{ label: '中药', value: 1 },
{ label: '西药', value: 2 },
{ label: '保健食品', value: 3 },
{ label: '产品服务包', value: 5 },
{ label: '非药品', value: 6 },
{ label: '医疗器械', value: 7 }
],
activeCategory: 2,
currentDrugs: [],
diagnoses: [],
diagnosisText: '',
2026-03-06 13:59:22 +08:00
medicalAdvice: '',
treatmentPrice: '',
chineseConfig: {
ruleType: 1,
packageMethodId: null,
processRuleId: null,
childProcessRuleId: null,
processRuleNoteId: null,
dosage: 7,
dayDosage: 2
2026-03-06 13:59:22 +08:00
},
processRuleList: [],
childProcessRuleList: [],
processRuleNoteList: [],
drugUseList: {
drug_use_num: [],
drug_use_frequency: [],
drug_use_type: [],
drug_unit: [],
drug_time: [],
drug_use_way: []
},
showDiagnosisModal: false,
showDoctorOrderModal: false,
showCommonPrescriptionModal: false,
showWesternMedicineModal: false,
showChineseMedicineModal: false,
showSimpleProductModal: false,
showWesternUsageModal: false,
showSaveCommonPrescriptionModal: false,
editingDrug: null,
editingDrugIndex: -1,
commonPrescriptionName: '',
isCommonPrescription: false,
_presetActiveCategory: null,
2026-03-06 13:59:22 +08:00
isSubmitting: false,
identity: uni.getStorageSync('role'),
registerStoreInfo: null,
sendMode: 0,
selectedStoreId: null,
// UI Styles
2026-03-06 13:59:22 +08:00
tabsBtnStyle: {
padding: '8rpx 32rpx',
height: '60rpx',
fontSize: '28rpx',
borderRadius: '30rpx'
2026-03-06 13:59:22 +08:00
},
illnessStyle: {
fontSize: '28rpx',
backgroundColor: '#F7F8FA',
borderRadius: '16rpx',
height: '76rpx',
padding: '0 32rpx'
2026-03-06 13:59:22 +08:00
},
entrustStyle: {
fontSize: '28rpx',
backgroundColor: '#F7F8FA',
height: '80rpx',
padding: '0 24rpx',
borderRadius: '12rpx',
marginTop: '20rpx'
2026-03-06 13:59:22 +08:00
},
priceInputStyle: {
fontSize: '32rpx',
fontWeight: 'bold',
color: '#333',
width: '160rpx',
height: '60rpx',
backgroundColor: '#F7F8FA',
2026-03-06 13:59:22 +08:00
borderRadius: '8rpx',
padding: '0 16rpx'
2026-03-06 13:59:22 +08:00
},
scrollStyle: {
height: 'calc(100vh - 600rpx)',
marginBottom: '200rpx'
}
};
},
computed: {
totalProductCost() {
if (this.currentDrugs.length === 0) return 0;
2026-03-06 13:59:22 +08:00
if (this.activeCategory === 1) {
return PrescriptionCalculator.calculateChineseMedicineProductPrice(this.currentDrugs, this.chineseConfig.dosage);
2026-03-06 13:59:22 +08:00
} else if (this.activeCategory === 2) {
return PrescriptionCalculator.calculateWesternMedicineProductPrice(this.currentDrugs);
} else if ([3, 5, 6, 7].includes(this.activeCategory)) {
return PrescriptionCalculator.calculateSimpleProductPrice(this.currentDrugs);
}
return 0;
},
processingFee() {
if (this.activeCategory !== 1 || this.chineseConfig.ruleType !== 2) return 0;
const processRule = this.childProcessRuleList.find(item => item.id === this.chineseConfig.childProcessRuleId);
if (!processRule) return 0;
const totalDrugQuantity = this.currentDrugs.reduce((sum, drug) => sum + parseFloat(drug.number || 1), 0);
return PrescriptionCalculator.calculateProcessingFee(processRule, this.chineseConfig.dosage, totalDrugQuantity);
2026-03-06 13:59:22 +08:00
},
totalPrice() {
const total = PrescriptionCalculator.calculateTotalPrice({
category: this.activeCategory,
drugs: this.currentDrugs,
dosage: this.chineseConfig.dosage,
processingFee: this.processingFee,
treatmentPrice: parseFloat(this.treatmentPrice || 0)
});
return total.toFixed(2);
},
supportsCommonPrescriptionTemplate() {
return [1, 2].includes(this.activeCategory);
2026-03-06 13:59:22 +08:00
}
},
onLoad(options) {
this.registerId = options.register_id || '';
this.patientId = options.patient_id || '';
this.pendingReusePrescriptionId = options.reuse_prescription_id ? String(options.reuse_prescription_id) : '';
this.isCommonPrescription = options.save_common === '1' || !!uni.getStorageSync('add');
if (options.initial_category !== undefined && options.initial_category !== '') {
const n = parseInt(options.initial_category, 10);
if (!Number.isNaN(n)) this._presetActiveCategory = n;
}
2026-03-06 13:59:22 +08:00
this.initializePageData();
},
async onShow() {
this.loadCurrentCategoryDrugs();
if (this.activeCategory === 1) await this.checkAndShowTransferTip();
2026-03-06 13:59:22 +08:00
},
methods: {
async initializePageData() {
try {
this.restoreFromLocalStorage();
await this.loadPatientInfo();
await this.loadBasicConfigData();
await this.loadRegisterStoreInfo();
this.loadCurrentCategoryDrugs();
await this.maybeApplyReusePrescription();
if (this.activeCategory === 1) await this.checkAndShowTransferTip();
2026-03-06 13:59:22 +08:00
} catch (error) {
console.error('初始化页面数据失败:', error);
this.$toast('初始化失败,请重试');
}
},
restoreFromLocalStorage() {
if (this._presetActiveCategory !== null && this._presetActiveCategory !== undefined && !Number.isNaN(this._presetActiveCategory)) {
this.activeCategory = this._presetActiveCategory;
this._presetActiveCategory = null;
return;
}
2026-03-06 13:59:22 +08:00
const savedCategory = PrescriptionStorage.getActiveCategory(this.registerId);
if (savedCategory) {
this.activeCategory = savedCategory;
} else {
const categories = [1, 2, 3, 5, 6, 7];
for (const category of categories) {
const data = PrescriptionStorage.loadPrescriptionData(category, this.registerId);
if (data && data.drugs && data.drugs.length > 0) {
this.activeCategory = category;
break;
}
}
}
},
loadCurrentCategoryDrugs() {
const data = PrescriptionStorage.loadPrescriptionData(this.activeCategory, this.registerId);
if (data) {
this.currentDrugs = data.drugs || [];
this.diagnoses = data.diagnoses || [];
this.diagnosisText = data.diagnosisText || '';
this.medicalAdvice = data.medicalAdvice || '';
this.treatmentPrice = data.treatmentPrice || '';
if (data.chineseConfig) this.chineseConfig = { ...this.chineseConfig, ...data.chineseConfig };
2026-03-06 13:59:22 +08:00
} else {
this.currentDrugs = [];
}
},
saveToLocalStorage() {
const data = {
drugs: this.currentDrugs,
diagnoses: this.diagnoses,
diagnosisText: this.diagnosisText,
medicalAdvice: this.medicalAdvice,
treatmentPrice: this.treatmentPrice,
chineseConfig: this.activeCategory === 1 ? this.chineseConfig : null
};
PrescriptionStorage.savePrescriptionData(this.activeCategory, this.registerId, data);
PrescriptionStorage.saveActiveCategory(this.activeCategory, this.registerId);
},
async loadPatientInfo() {
if (!this.patientId) return;
2026-03-06 13:59:22 +08:00
try {
const res = await getPatientInfoByPatientId(this.patientId);
const data = res.result || res.data || res;
if (data && data.user_patient) {
this.patientInfo = {
id: data.user_patient.id || this.patientId,
2026-03-06 13:59:22 +08:00
name: data.user_patient.name,
mobile: data.user_patient.mobile,
age: data.user_patient.age,
sex: data.user_patient.sex
};
}
} catch (error) {
console.error('获取患者信息失败:', error);
}
},
async loadBasicConfigData() {
try {
const drugUseRes = await getDrugUseList();
if (drugUseRes) {
const inner = drugUseRes.result || drugUseRes.data;
this.drugUseList = inner && (inner.drug_time != null || inner.drug_use_type != null || inner.drug_use_way != null) ? inner : drugUseRes;
2026-03-06 13:59:22 +08:00
}
if (this.activeCategory === 1 && this.processRuleList.length === 0) {
await this.loadProcessRuleList(0, 0);
}
} catch (error) {
console.error('加载基础配置数据失败:', error);
}
},
async loadRegisterStoreInfo() {
if (!this.registerId) return;
2026-03-06 13:59:22 +08:00
try {
const res = await getCurrentStoreTypeApi({ register_id: this.registerId });
if (res) {
this.registerStoreInfo = res;
if (res.is_from_transfer === 1 && res.delegate_store_id) {
this.selectedStoreId = res.delegate_store_id;
this.sendMode = 1;
2026-03-06 13:59:22 +08:00
} else if (res.store_id) {
this.selectedStoreId = res.store_id;
this.sendMode = res.can_change ? 1 : 0;
2026-03-06 13:59:22 +08:00
}
}
} catch (error) {
console.error('获取挂号诊所信息失败:', error);
}
},
async handleSwitchCategory(category) {
this.saveToLocalStorage();
this.activeCategory = category;
this.loadCurrentCategoryDrugs();
if (category === 1) {
await this.checkAndShowTransferTip();
if (this.processRuleList.length === 0) await this.loadProcessRuleList(0, 0);
2026-03-06 13:59:22 +08:00
}
},
async checkAndShowTransferTip() {
try {
if (!this.registerStoreInfo) await this.loadRegisterStoreInfo();
2026-03-06 13:59:22 +08:00
const storeInfo = this.registerStoreInfo;
if (!storeInfo) return;
2026-03-06 13:59:22 +08:00
if (storeInfo.clinic_type === 1 && storeInfo.delegate_store) {
const delegateStore = storeInfo.delegate_store;
const doctorName = delegateStore.doctor?.name || '委托医生';
const storeName = delegateStore.name || '委托诊所';
uni.showModal({
title: '转诊提示',
content: `检测到当前诊所为西医诊所,本次处方开具后自动转接到【${storeName}】的【${doctorName}】的在线复诊中`,
showCancel: false,
confirmText: '我知道了'
});
}
} catch (error) {
console.error('获取诊所信息失败:', error);
}
},
handleOpenDiagnosisModal() { this.showDiagnosisModal = true; },
2026-03-06 13:59:22 +08:00
handleDiagnosisConfirm(diagnosisText) {
this.diagnosisText = diagnosisText;
if (diagnosisText) {
const diagnosisNames = diagnosisText.split('').filter(Boolean);
this.diagnoses = diagnosisNames.map((name, index) => ({ id: `temp_${index}`, name: name }));
2026-03-06 13:59:22 +08:00
} else {
this.diagnoses = [];
}
this.saveToLocalStorage();
},
handleRemoveDiagnosis(index) {
this.diagnoses.splice(index, 1);
this.diagnosisText = this.diagnoses.map(item => item.name).join('');
this.saveToLocalStorage();
},
handleOpenDoctorOrderModal() { this.showDoctorOrderModal = true; },
2026-03-06 13:59:22 +08:00
handleDoctorOrderConfirm(doctorOrderText) {
this.medicalAdvice = doctorOrderText;
this.saveToLocalStorage();
},
handleOpenCommonPrescriptionModal() { this.showCommonPrescriptionModal = true; },
2026-05-07 14:25:26 +08:00
async handleSelectCommonPrescription(item) {
2026-03-06 13:59:22 +08:00
try {
2026-05-07 14:25:26 +08:00
const payload = item && item.apply_payload;
if (!payload || !Array.isArray(payload.drugs)) {
this.$toast('常用方数据异常');
2026-03-06 13:59:22 +08:00
return;
}
2026-05-07 14:25:26 +08:00
this.currentDrugs.splice(0, this.currentDrugs.length, ...payload.drugs);
if (payload.diagnosisText) {
this.diagnosisText = payload.diagnosisText;
const names = payload.diagnosisText.split('').filter(Boolean);
this.diagnoses = names.map((name, index) => ({ id: `temp_${index}`, name }));
2026-05-07 14:25:26 +08:00
}
if (payload.medicalAdvice) this.medicalAdvice = payload.medicalAdvice;
2026-05-07 14:25:26 +08:00
if (this.activeCategory === 1 && payload.chineseConfig) {
this.chineseConfig = { ...this.chineseConfig, ...payload.chineseConfig };
if (this.chineseConfig.processRuleId) await this.loadProcessRuleList(this.chineseConfig.processRuleId, 0);
if (this.chineseConfig.childProcessRuleId) await this.loadProcessRuleList(0, this.chineseConfig.childProcessRuleId);
2026-03-06 13:59:22 +08:00
}
this.saveToLocalStorage();
this.$toast('常用方已填充');
} catch (error) {
console.error('选择常用方失败:', error);
this.$toast('选择常用方失败');
}
},
getCommonPrescriptionType(category) {
if (category === 1) return 'chinese';
else if (category === 2) return 'west';
else return 'granular';
2026-03-06 13:59:22 +08:00
},
handleOpenWesternMedicineModal() { this.showWesternMedicineModal = true; },
2026-03-06 13:59:22 +08:00
handleSelectWesternDrug(drug) {
if (PrescriptionValidator.isDrugExists(this.currentDrugs, drug)) {
this.$toast('该药品已在列表中');
return;
}
const newDrug = {
index_id: drug.id,
id: drug.drug_id || drug.drug?.id || drug.id,
drug_id: drug.drug_id || drug.drug?.id || drug.id,
drug_name: drug.drug_name || drug.drug?.drug_name,
number: drug.number || 1,
select_number: drug.select_number || 1,
price: drug.price || 0,
specification: drug.specification || drug.drug?.specification || '',
image: drug.image || drug.drug?.image || '',
instruction: drug.instruction || drug.drug?.instruction || '',
time_id: drug.time_id || drug.drug?.time_id || 0,
type_id: drug.type_id || drug.drug?.type_id || 0,
frequency_id: drug.frequency_id || drug.drug?.frequency_id || 0,
unit_id: drug.unit_id || drug.drug?.unit_id || 0,
use_num: this.drugUseList.drug_time?.find(item => item.id === (drug.time_id || drug.drug?.time_id)),
use_type: this.drugUseList.drug_use_type?.find(item => item.id === (drug.type_id || drug.drug?.type_id)),
use_frequency: this.drugUseList.drug_use_frequency?.find(item => item.id === (drug.frequency_id || drug.drug?.frequency_id)),
unit: this.drugUseList.drug_unit?.find(item => item.id === (drug.unit_id || drug.drug?.unit_id))
};
this.currentDrugs.push(newDrug);
const index = this.currentDrugs.length - 1;
this.handleEditWesternDrug(this.currentDrugs[index], index);
this.saveToLocalStorage();
this.$toast(`已添加 ${newDrug.drug_name}`);
2026-03-06 13:59:22 +08:00
},
handleOpenChineseMedicineModal() { this.showChineseMedicineModal = true; },
2026-03-06 13:59:22 +08:00
handleSelectChineseDrug(drugs) {
this.currentDrugs = drugs || [];
this.saveToLocalStorage();
},
handleOpenSimpleProductModal() { this.showSimpleProductModal = true; },
2026-03-06 13:59:22 +08:00
handleSelectSimpleProduct(product) {
if (PrescriptionValidator.isDrugExists(this.currentDrugs, product)) {
this.$toast('该产品已在列表中');
return;
}
const newProduct = {
index_id: product.id,
id: product.drug_id || product.drug?.id || product.id,
drug_name: product.drug_name || product.drug?.drug_name || product.name,
number: 1,
price: product.price || 0,
image: product.image || product.drug?.image || '',
2026-05-07 11:04:56 +08:00
instruction: product.instruction || product.drug?.instruction || '',
type: product.drug?.type || product.type || this.activeCategory,
select_number: 1
2026-03-06 13:59:22 +08:00
};
this.currentDrugs.push(newProduct);
this.saveToLocalStorage();
this.$toast(`已添加 ${newProduct.drug_name}`);
2026-03-06 13:59:22 +08:00
},
handleEditWesternDrug(drug, index) {
this.editingDrug = JSON.parse(JSON.stringify(drug));
this.editingDrugIndex = index;
this.showWesternUsageModal = true;
},
handleConfirmWesternUsage(usageData) {
if (this.editingDrugIndex >= 0) {
const drug = this.currentDrugs[this.editingDrugIndex];
drug.time_id = usageData.time_id;
drug.type_id = usageData.type_id;
drug.frequency_id = usageData.frequency_id;
drug.unit_id = usageData.unit_id;
drug.number = usageData.number;
drug.select_number = usageData.select_number || drug.select_number;
drug.use_num = usageData.use_num;
drug.use_type = usageData.use_type;
drug.use_frequency = usageData.use_frequency;
drug.unit = usageData.unit;
this.saveToLocalStorage();
}
this.editingDrug = null;
this.editingDrugIndex = -1;
},
handleRemoveDrug(index) {
uni.showModal({
title: '移除药品',
content: '确定要从处方中移除该药品吗?',
confirmColor: '#FC3636',
2026-03-06 13:59:22 +08:00
success: ({ confirm }) => {
if (confirm) {
this.currentDrugs.splice(index, 1);
this.saveToLocalStorage();
}
}
});
},
2026-05-07 11:04:56 +08:00
handleIncrementSimpleProduct(index) {
if (index >= 0 && index < this.currentDrugs.length) {
const product = this.currentDrugs[index];
const currentNumber = product.select_number || product.number || 1;
this.$set(product, 'select_number', currentNumber + 1);
this.saveToLocalStorage();
}
},
handleDecrementSimpleProduct(index) {
if (index >= 0 && index < this.currentDrugs.length) {
const product = this.currentDrugs[index];
const currentNumber = product.select_number || product.number || 1;
if (currentNumber > 1) {
this.$set(product, 'select_number', currentNumber - 1);
this.saveToLocalStorage();
} else {
this.handleRemoveDrug(index);
2026-05-07 11:04:56 +08:00
}
}
},
2026-03-06 13:59:22 +08:00
handleRemoveAllDrugs() {
uni.showModal({
title: '清空药材',
content: '确定要清空所有中药材吗?',
confirmColor: '#FC3636',
2026-03-06 13:59:22 +08:00
success: ({ confirm }) => {
if (confirm) {
this.currentDrugs = [];
this.saveToLocalStorage();
}
}
});
},
async handleUpdateChineseConfig(config) {
const oldRuleType = this.chineseConfig.ruleType;
const oldProcessRuleId = this.chineseConfig.processRuleId;
const oldChildProcessRuleId = this.chineseConfig.childProcessRuleId;
2026-03-06 13:59:22 +08:00
if (config.ruleType === 2 && config.ruleType !== oldRuleType) {
if (this.processRuleList.length === 0) await this.loadProcessRuleList(0, 0);
2026-03-06 13:59:22 +08:00
}
if (config.ruleType === 1 && oldRuleType === 2) {
config.processRuleId = null;
config.childProcessRuleId = null;
config.processRuleNoteId = null;
this.processRuleList = [];
this.childProcessRuleList = [];
this.processRuleNoteList = [];
}
if (config.processRuleId && config.processRuleId !== oldProcessRuleId) {
config.childProcessRuleId = null;
config.processRuleNoteId = null;
this.childProcessRuleList = [];
this.processRuleNoteList = [];
}
if (config.childProcessRuleId && config.childProcessRuleId !== oldChildProcessRuleId) {
config.processRuleNoteId = null;
this.processRuleNoteList = [];
}
this.chineseConfig = { ...this.chineseConfig, ...config };
if (config.processRuleId && config.processRuleId !== oldProcessRuleId) {
await this.loadProcessRuleList(config.processRuleId, 0);
}
if (config.childProcessRuleId && config.childProcessRuleId !== oldChildProcessRuleId) {
await this.loadProcessRuleList(0, config.childProcessRuleId);
}
this.saveToLocalStorage();
},
async loadProcessRuleList(pid = 0, ruleId = 0) {
try {
const data = ruleId === 0 ? { pid } : { rule_id: ruleId };
const res = await getProcessRuleList(data);
const list = res?.data || res?.result || res || [];
if (ruleId !== 0) {
this.processRuleNoteList = list;
} else if (pid === 0) {
this.processRuleList = list;
} else {
this.childProcessRuleList = list;
}
} catch (error) {
console.error('加载加工规则列表失败:', error);
this.$toast('加载加工规则列表失败');
}
},
parsePrescriptionDetailContent(detail) {
let c = detail && detail.content;
if (typeof c === 'string') {
try { c = JSON.parse(c); } catch (e) { c = {}; }
2026-03-06 13:59:22 +08:00
}
return c && typeof c === 'object' ? c : {};
},
mapWestRepiceToProduct(recipe) {
if (!recipe) return null;
let drugObj = {};
try {
const raw = recipe.content;
drugObj = typeof raw === 'string' ? JSON.parse(raw) : (raw || {});
} catch (e) { return null; }
const drugId = Number(drugObj.id);
if (!drugId) return null;
const selectNumber = Math.max(1, Number(recipe.number ?? drugObj.select_number ?? drugObj.number ?? 1) || 1);
const grainNumber = Math.max(1, Number(drugObj.number ?? drugObj.grain_number ?? recipe.grain_number ?? 1) || 1);
const timeId = recipe.time_id ?? drugObj.time_id;
const typeId = recipe.type_id ?? drugObj.type_id;
const freqId = recipe.f_id ?? drugObj.frequency_id;
const unitId = recipe.wu_id ?? drugObj.unit_id;
const list = this.drugUseList || {};
const wayId = drugObj.way_id;
return {
index_id: drugId, id: drugId,
drug_name: drugObj.drug_name || drugObj.name || '',
number: grainNumber,
use_num: (list.drug_time || []).find((item) => item.id === timeId),
use_type: (list.drug_use_type || []).find((item) => item.id === typeId),
use_frequency: (list.drug_use_frequency || []).find((item) => item.id === freqId),
unit: (list.drug_unit || []).find((item) => item.id === unitId),
price: Number(drugObj.sell_price ?? drugObj.price ?? 0),
way_id: wayId,
use_ways: (list.drug_use_way || []).find((item) => item.id === wayId),
time_id: timeId, type_id: typeId, frequency_id: freqId, unit_id: unitId,
image: drugObj.image || '', instruction: drugObj.instruction || '',
type: drugObj.type, select_number: selectNumber, specification: drugObj.specification || ''
};
},
async applyHistoricalPrescriptionDetail(detail) {
const content = this.parsePrescriptionDetailContent(detail);
const pt = Number(detail.prescription_type);
if (![1, 2, 3, 5, 6, 7].includes(pt)) {
this.$toast('该处方类型暂不支持复用');
return false;
}
if (!this.patientId) {
this.$toast('患者信息异常');
return false;
}
this.saveToLocalStorage();
this.activeCategory = pt;
PrescriptionStorage.saveActiveCategory(pt, this.registerId);
const repiceList = Array.isArray(content.repice) ? content.repice : [];
if (pt === 1) {
const rep0 = repiceList[0];
if (!rep0) return false;
let rows = [];
try {
const raw = rep0.content;
rows = typeof raw === 'string' ? JSON.parse(raw) : (raw || []);
} catch (e) { return false; }
if (!Array.isArray(rows) || rows.length === 0) return false;
const list = this.drugUseList || {};
this.currentDrugs = rows.map((d) => {
const drugId = Number(d.drug_id ?? d.id);
const wayId = d.way_id ?? d.use_way?.id ?? d.useWay?.id ?? d.order;
const unitId = d.unit_id;
return {
index_id: d.id ?? drugId, id: drugId,
drug_name: d.name || d.drug_name || '',
number: d.number ?? 1, price: Number(d.price ?? 0),
way_id: wayId,
use_ways: (list.drug_use_way || []).find((item) => item.id === wayId) ?? d.use_way ?? d.useWay,
use_num: (list.drug_time || []).find((item) => item.id === d.time_id),
use_type: (list.drug_use_type || []).find((item) => item.id === d.type_id),
use_frequency: (list.drug_use_frequency || []).find((item) => item.id === d.frequency_id),
unit: (list.drug_unit || []).find((item) => item.id === unitId) || d.unit,
time_id: d.time_id, type_id: d.type_id, frequency_id: d.frequency_id, unit_id: unitId,
image: d.image || '', instruction: d.instruction || '', type: d.type
};
});
const ruleType = rep0.deployment === 2 ? 1 : 2;
this.chineseConfig = {
...this.chineseConfig, ruleType,
dosage: Number(rep0.dosage ?? 7), dayDosage: Number(rep0.consumption ?? 2),
packageMethodId: rep0.package_method_id ?? 2,
processRuleId: rep0.process_rule_id && Number(rep0.process_rule_id) > 0 ? rep0.process_rule_id : null,
childProcessRuleId: rep0.child_process_rule_id && Number(rep0.child_process_rule_id) > 0 ? rep0.child_process_rule_id : null,
processRuleNoteId: rep0.process_rule_note_id && Number(rep0.process_rule_note_id) > 0 ? rep0.process_rule_note_id : null
};
if (ruleType === 2 && (!this.processRuleList || this.processRuleList.length === 0)) await this.loadProcessRuleList(0, 0);
if (this.chineseConfig.processRuleId) await this.loadProcessRuleList(this.chineseConfig.processRuleId, 0);
if (this.chineseConfig.childProcessRuleId) await this.loadProcessRuleList(0, this.chineseConfig.childProcessRuleId);
} else {
const mapped = [];
for (const recipe of repiceList) {
const row = this.mapWestRepiceToProduct(recipe);
if (row) mapped.push(row);
}
if (mapped.length === 0) return false;
this.currentDrugs = mapped;
}
const dx = detail.clinical_diagnose ?? content.clinical_diagnose ?? '';
this.diagnosisText = dx;
if (dx) {
const names = String(dx).split('').filter(Boolean);
this.diagnoses = names.map((name, index) => ({ id: `temp_${index}`, name }));
} else {
this.diagnoses = [];
}
this.medicalAdvice = detail.doctor_order ?? content.doctor_order ?? '';
this.saveToLocalStorage();
return true;
},
async maybeApplyReusePrescription() {
const rawId = this.pendingReusePrescriptionId;
if (!rawId) return;
this.pendingReusePrescriptionId = '';
const pid = parseInt(rawId, 10);
if (!pid || !this.registerId) return;
const hasDraft = PrescriptionStorage.hasDraftWithDrugs(this.registerId);
const run = async () => {
try {
const res = await getPrescriptionInfoApi(pid);
if (res && ((typeof res.code === 'number' && res.code !== 0) || (typeof res.errcode === 'number' && res.errcode !== 0))) {
this.$toast(res.msg || res.message || '加载处方详情失败');
return;
}
const detail = res.result || res.data || res;
const ok = await this.applyHistoricalPrescriptionDetail(detail);
if (ok) this.$toast('已复用历史处方,请核对后发送');
} catch (e) {
console.error('复用处方失败:', e);
this.$toast('加载处方详情失败');
}
};
if (hasDraft) {
uni.showModal({
title: '覆盖当前草稿?', content: '当前处方清单中有药品,复用将替换为所选历史处方内容。',
success: (r) => { if (r.confirm) run(); }
});
} else {
await run();
}
},
formatDrugUsage(drug) {
if (!drug.use_type || !drug.use_frequency || !drug.use_num || !drug.unit) return '';
2026-03-06 13:59:22 +08:00
return `${drug.use_type.name}${drug.use_frequency.name}${drug.use_num.name},每次${drug.number}${drug.unit.name}`;
},
getProductUnit(category) {
if (category === 5) return '周期';
return '件';
2026-03-06 13:59:22 +08:00
},
validatePrescriptionData() {
return PrescriptionValidator.validatePrescriptionData({
category: this.activeCategory, drugs: this.currentDrugs, diagnoses: this.diagnoses,
medicalAdvice: this.medicalAdvice, chineseConfig: this.activeCategory === 1 ? this.chineseConfig : null
2026-03-06 13:59:22 +08:00
});
},
async checkChineseMedicineConflict() {
if (this.activeCategory !== 1) return { hasConflict: false };
2026-03-06 13:59:22 +08:00
try {
const names = this.currentDrugs.map((item) => item.drug_name || item.name);
const res = await checkChineseMedicineConflictApi({ names });
if (res && res.is_exist === true) return { hasConflict: true, message: res.message || '检测到该处方内具有药物相冲' };
2026-03-06 13:59:22 +08:00
return { hasConflict: false };
} catch (error) {
console.error('检查中药相冲失败:', error);
return { hasConflict: false };
}
},
async handleSendPrescription(doctorSecondSign = 0) {
if (this.isSubmitting) { this.$toast('正在处理中,请勿重复提交'); return; }
if (this.isCommonPrescription) { this.handleSaveAsCommonPrescription(); return; }
2026-03-06 13:59:22 +08:00
const validation = this.validatePrescriptionData();
if (!validation.valid) { this.$toast(validation.message); return; }
2026-03-06 13:59:22 +08:00
this.isSubmitting = true;
try {
if (!this.registerStoreInfo) await this.loadRegisterStoreInfo();
2026-03-06 13:59:22 +08:00
if (this.activeCategory === 1) {
const conflictCheck = await this.checkChineseMedicineConflict();
if (conflictCheck.hasConflict) {
uni.showModal({
title: '药物相冲提示',
content: conflictCheck.message || '检测到该处方内具有药物相冲,是否继续开方?',
showCancel: true,
success: ({ confirm }) => {
if (confirm) this.handleSendPrescriptionWithStoreSelection(1);
else this.isSubmitting = false;
2026-03-06 13:59:22 +08:00
}
});
return;
}
}
await this.handleSendPrescriptionWithStoreSelection(doctorSecondSign);
} catch (error) {
console.error('发送处方失败:', error);
this.$toast('发送处方失败,请重试');
this.isSubmitting = false;
}
},
async handleSendPrescriptionWithStoreSelection(doctorSecondSign = 0) {
const storeInfo = this.registerStoreInfo;
if (storeInfo?.is_from_transfer === 1 && storeInfo?.delegate_store_id) {
await this.executeSendPrescription(doctorSecondSign, 1, storeInfo.delegate_store_id);
} else if (storeInfo?.can_change) {
const registerStoreName = storeInfo?.store_name || '挂号诊所';
const registerStoreId = storeInfo?.store_id;
const currentStoreName = storeInfo?.current_store_name || '当前诊所';
uni.showModal({
title: '选择诊所',
content: `请选择使用哪个诊所开方:\n\n挂号诊所${registerStoreName}\n当前诊所${currentStoreName}`,
confirmText: '使用挂号诊所',
cancelText: '使用当前诊所',
success: ({ confirm, cancel }) => {
if (confirm) this.executeSendPrescription(doctorSecondSign, 1, registerStoreId);
else if (cancel) this.executeSendPrescription(doctorSecondSign, 0, null);
else this.isSubmitting = false;
2026-03-06 13:59:22 +08:00
},
fail: () => { this.isSubmitting = false; }
2026-03-06 13:59:22 +08:00
});
} else {
await this.executeSendPrescription(doctorSecondSign, 0, null);
}
},
async executeSendPrescription(doctorSecondSign = 0, sendMode = 0, customStoreId = null) {
try {
if (this.activeCategory === 2) {
if (!this.patientInfo || !this.patientId) {
if (this.patientId && !this.patientInfo) await this.loadPatientInfo();
2026-03-06 13:59:22 +08:00
if (!this.patientInfo || !this.patientId) {
this.$toast('患者信息缺失,无法发送处方');
this.isSubmitting = false; return;
2026-03-06 13:59:22 +08:00
}
}
const invalidDrug = this.currentDrugs.find((drug) => {
return !(drug.id && (drug.select_number || drug.number) && drug.time_id && drug.type_id && drug.frequency_id && drug.unit_id && drug.use_type && drug.use_type.name && drug.use_num && drug.use_num.name && drug.unit && drug.unit.name);
2026-03-06 13:59:22 +08:00
});
if (invalidDrug) { this.$toast('请先为西药设置完整的用法用量'); return; }
2026-03-06 13:59:22 +08:00
}
let finalSendMode = sendMode; let finalStoreId = customStoreId;
2026-03-06 13:59:22 +08:00
const storeInfo = this.registerStoreInfo;
if (storeInfo?.is_from_transfer === 1 && storeInfo?.delegate_store_id) {
finalSendMode = 1; finalStoreId = storeInfo.delegate_store_id;
2026-03-06 13:59:22 +08:00
}
2026-03-06 13:59:22 +08:00
const clinical_diagnose = this.diagnosisText || this.diagnoses.map((item) => item.name).join(',');
let doctorSecondSignValue = typeof doctorSecondSign === 'number' ? doctorSecondSign : (typeof doctorSecondSign === 'object' && doctorSecondSign !== null && typeof doctorSecondSign.value === 'number' ? doctorSecondSign.value : (typeof doctorSecondSign === 'string' ? parseInt(doctorSecondSign, 10) || 0 : (doctorSecondSign ? 1 : 0)));
const patientData = { id: this.patientInfo.id || this.patientId, user_id: this.patientInfo.user_id || null, name: this.patientInfo.name || '', age: this.patientInfo.age || 0, sex: this.patientInfo.sex || 0, mobile: this.patientInfo.mobile || '' };
2026-03-06 13:59:22 +08:00
let drugsData;
if (this.activeCategory === 1) {
drugsData = this.currentDrugs.map((drug) => ({ index_id: drug.index_id, id: drug.id, drug_name: drug.drug_name || drug.name, number: drug.number || drug._quantity || 0, price: drug.price || '0.0000', way_id: drug.way_id || 0, select_number: drug.select_number || 1 }));
2026-05-07 11:04:56 +08:00
} else if ([3, 5, 6, 7].includes(this.activeCategory)) {
drugsData = this.currentDrugs.map((drug) => {
const cleanDrug = { index_id: drug.index_id, id: drug.id, drug_name: drug.drug_name || drug.name, number: drug.number || 1, price: drug.price || '0.0000', select_number: drug.select_number || 1 };
if (drug.image) cleanDrug.image = drug.image;
if (drug.instruction) cleanDrug.instruction = drug.instruction;
if (drug.type) cleanDrug.type = drug.type;
2026-03-06 13:59:22 +08:00
return cleanDrug;
});
} else {
drugsData = this.currentDrugs.map(drug => {
const drugData = { ...drug };
if (!drugData.use_type || typeof drugData.use_type !== 'object' || !drugData.use_type.name) drugData.use_type = (drugData.type_id && this.drugUseList.drug_use_type) ? this.drugUseList.drug_use_type.find(item => item.id === drugData.type_id) || { name: '' } : { name: '' };
if (!drugData.use_num || typeof drugData.use_num !== 'object' || !drugData.use_num.name) drugData.use_num = (drugData.time_id && this.drugUseList.drug_time) ? this.drugUseList.drug_time.find(item => item.id === drugData.time_id) || { name: '' } : { name: '' };
if (!drugData.unit || typeof drugData.unit !== 'object' || !drugData.unit.name) drugData.unit = (drugData.unit_id && this.drugUseList.drug_unit) ? this.drugUseList.drug_unit.find(item => item.id === drugData.unit_id) || { name: '' } : { name: '' };
2026-03-06 13:59:22 +08:00
return drugData;
});
}
2026-03-06 13:59:22 +08:00
const params = {
patient: patientData, drugs: drugsData, diagnosis: clinical_diagnose, medicalAdvice: this.medicalAdvice, total: parseFloat(this.totalPrice), category: 1, drug_type: 2, register_id: parseInt(this.registerId), treatment_price: parseFloat(this.treatmentPrice || 0), prescription_type: this.activeCategory, doctor_second_sign: doctorSecondSignValue, send_mode: finalSendMode, custom_store_id: finalSendMode === 1 ? finalStoreId : null
2026-03-06 13:59:22 +08:00
};
if (this.activeCategory === 1) {
params.package_method_id = this.chineseConfig.packageMethodId || null; params.process_rule_id = this.chineseConfig.processRuleId || null; params.process_rule_note_id = this.chineseConfig.processRuleNoteId || null; params.child_process_rule_id = this.chineseConfig.childProcessRuleId || null; params.process_rule_type = this.chineseConfig.ruleType || 1; params.processing_fee = this.processingFee; params.dosage = this.chineseConfig.dosage || 7; params.day_dosage = this.chineseConfig.dayDosage || 2;
2026-03-06 13:59:22 +08:00
}
2026-03-06 13:59:22 +08:00
const res = await addWestPrescription(params);
if (res && (res.code === 0 || res.errcode === 0)) {
this.$toast('发送成功');
const needTransfer = res?.result?.need_transfer || res?.data?.need_transfer || res?.need_transfer;
if (needTransfer) {
const transferId = res?.result?.transfer_prescription_id || res?.data?.transfer_prescription_id || res?.transfer_prescription_id;
if (transferId) {
uni.showModal({
title: '转诊提示', content: '该处方已触发转诊流程,转诊消息已发送给委托诊所的在线问诊医生。', showCancel: false, confirmText: '确定',
success: () => { this.clearPrescriptionData(); PrescriptionStorage.clearAllPrescriptionData(this.registerId); setTimeout(() => { uni.navigateBack(); }, 500); }
2026-03-06 13:59:22 +08:00
});
return;
}
}
this.clearPrescriptionData();
PrescriptionStorage.clearAllPrescriptionData(this.registerId);
setTimeout(() => { uni.navigateBack(); }, 1500);
2026-03-06 13:59:22 +08:00
} else {
this.$toast(res.msg || res.message || '发送失败');
}
} catch (error) {
console.error('发送处方失败:', error);
this.$toast('发送处方失败,请重试');
throw error;
} finally {
this.isSubmitting = false;
}
},
clearPrescriptionData() {
this.currentDrugs = []; this.diagnoses = []; this.diagnosisText = ''; this.medicalAdvice = ''; this.treatmentPrice = '';
this.chineseConfig = { ruleType: 1, packageMethodId: null, processRuleId: null, childProcessRuleId: null, processRuleNoteId: null, dosage: 7, dayDosage: 2 };
2026-03-06 13:59:22 +08:00
},
handleSaveAsCommonPrescription() {
if (this.currentDrugs.length === 0) { this.$toast('请先添加药品后再保存为常用方'); return; }
if (![1, 2].includes(this.activeCategory)) { this.$toast('当前分类不支持保存为常用方'); return; }
2026-03-06 13:59:22 +08:00
this.showSaveCommonPrescriptionModal = true;
},
async handleConfirmSaveCommonPrescription() {
if (!this.commonPrescriptionName || !this.commonPrescriptionName.trim()) { this.$toast('请输入常用方名称'); return; }
if (![1, 2].includes(this.activeCategory)) { this.$toast('当前分类不支持保存为常用方'); return; }
2026-03-06 13:59:22 +08:00
try {
const storeId = uni.getStorageSync('store_id') || 11001;
if (this.activeCategory === 1) {
const drugs = this.currentDrugs.map((drug) => ({ drug_id: drug.id || drug.drug_id, drug_name: drug.drug_name || drug.name, number: drug.number || 1, price: drug.price || 0, way_id: drug.way_id || 0 }));
const rt = this.chineseConfig.ruleType;
const payload = { name: this.commonPrescriptionName.trim(), drugs, store_id: storeId, clinical_diagnose: this.diagnosisText || '', doctor_order: this.medicalAdvice || '', category: '1', dosage: this.chineseConfig.dosage || 7, day_dosage: this.chineseConfig.dayDosage || 2, rule_type: rt };
if (rt === 1) payload.package_method_id = this.chineseConfig.packageMethodId;
if (rt === 2) { payload.process_rule_id = this.chineseConfig.processRuleId || undefined; payload.child_process_rule_id = this.chineseConfig.childProcessRuleId || undefined; payload.process_rule_note_id = this.chineseConfig.processRuleNoteId || undefined; }
const resCn = await saveChineseCommonPrescriptionApi(payload);
if (!resCn || resCn.code !== 0) { this.$toast(resCn.msg || resCn.message || '保存失败'); return; }
2026-03-06 13:59:22 +08:00
} else {
const drugs = this.currentDrugs.map((drug) => ({ drug_id: drug.id || drug.drug_id, drug_name: drug.drug_name || drug.name, number: drug.number || 1, select_number: drug.select_number || 1, price: drug.price || 0, time_id: drug.time_id || 0, type_id: drug.type_id || 0, frequency_id: drug.frequency_id || 0, unit_id: drug.unit_id || 0, image: drug.image || '', instruction: drug.instruction || '' }));
const resW = await saveWestCommonPrescriptionApi({ name: this.commonPrescriptionName.trim(), drugs, store_id: storeId, clinical_diagnose: this.diagnosisText || '', doctor_order: this.medicalAdvice || '', category: '1' });
if (!resW || resW.code !== 0) { this.$toast(resW.msg || resW.message || '保存失败'); return; }
2026-03-06 13:59:22 +08:00
}
this.$toast('保存成功');
this.showSaveCommonPrescriptionModal = false; this.commonPrescriptionName = '';
if (this.isCommonPrescription) { uni.removeStorageSync('add'); setTimeout(() => uni.navigateBack(), 400); }
} catch (error) { console.error('保存常用方失败:', error); this.$toast('保存常用方失败,请重试'); }
2026-03-06 13:59:22 +08:00
},
handleCustomBack() { uni.navigateBack(); }
2026-03-06 13:59:22 +08:00
}
};
</script>
<style lang="scss" scoped>
/* 基础与通用样式 */
.page-bg {
background-color: #F4F6F8;
min-height: 100vh;
2026-03-06 13:59:22 +08:00
}
.safe-area-inset-bottom { padding-bottom: env(safe-area-inset-bottom); }
.mx-32 { margin-left: 32rpx; margin-right: 32rpx; }
.m-x-32 { margin-left: 32rpx; margin-right: 32rpx; }
.m-b-24 { margin-bottom: 24rpx; }
.m-b-32 { margin-bottom: 32rpx; }
.m-b-40 { margin-bottom: 40rpx; }
.m-t-12 { margin-top: 12rpx; }
.m-t-16 { margin-top: 16rpx; }
.m-t-24 { margin-top: 24rpx; }
.m-t-64 { margin-top: 64rpx; }
.m-l-8 { margin-left: 8rpx; }
.m-l-16 { margin-left: 16rpx; }
.m-l-24 { margin-left: 24rpx; }
.m-l-32 { margin-left: 32rpx; }
.m-r-4 { margin-right: 4rpx; }
.m-r-8 { margin-right: 8rpx; }
.m-r-16 { margin-right: 16rpx; }
.m-r-32 { margin-right: 32rpx; }
.p-32 { padding: 32rpx; }
.p-b-40 { padding-bottom: 40rpx; }
.p-x-32 { padding-left: 32rpx; padding-right: 32rpx; }
.pt-20 { padding-top: 20rpx; }
.pt-32 { padding-top: 32rpx; }
/* 字体与颜色层级 */
.fs-24 { font-size: 24rpx; }
.fs-26 { font-size: 26rpx; }
.fs-28 { font-size: 28rpx; }
.fs-30 { font-size: 30rpx; }
.fs-32 { font-size: 32rpx; }
.fs-48 { font-size: 48rpx; }
.font-bold { font-weight: bold; }
.color-title { color: #2A2E35; }
.color-sub { color: #8A92A3; }
.color-primary { color: #00A88A; }
.color-danger { color: #FF4D4F; }
.color-price { color: #F53F3F; }
.text-gray { color: #6C7380; }
.white { background: #fff; }
.radius-12 { border-radius: 12rpx; }
.shadow-sm { box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.03); }
.border-t-dashed { border-top: 1px dashed #E2E8F0; }
.line-clamp-2 {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
2026-03-06 13:59:22 +08:00
}
.w-70 { width: 70%; }
/* Flex 布局辅助 */
.flex { display: flex; }
.flex-wrap { flex-wrap: wrap; }
.flex-row { display: flex; flex-direction: row; }
.flex-col { display: flex; flex-direction: column; }
.flex-jus-sp { justify-content: space-between; }
.flex-ali-center { align-items: center; }
.flex-ali-start { align-items: flex-start; }
.flex-jus-center { justify-content: center; }
.flex-1 { flex: 1; }
.ac { text-align: center; }
/* 定制化组件样式 */
.rp-icon {
background: #2A2E35;
color: #fff;
font-size: 20rpx;
font-weight: bold;
padding: 4rpx 10rpx;
border-radius: 6rpx 2rpx 6rpx 2rpx;
2026-03-06 13:59:22 +08:00
}
.tabs {
background: #fff;
border-bottom: 1px solid #F0F2F5;
2026-03-06 13:59:22 +08:00
}
/* 现代卡片设计 (西药 / 产品) */
.medicine-card {
background: #fff;
border-radius: 16rpx;
padding: 24rpx;
margin-bottom: 24rpx;
box-shadow: 0 4rpx 16rpx rgba(42, 46, 53, 0.04);
position: relative;
overflow: hidden;
2026-03-06 13:59:22 +08:00
}
.drug-image-modern {
width: 140rpx;
height: 140rpx;
border-radius: 12rpx;
background-color: #F7F8FA;
flex-shrink: 0;
border: 1px solid #F0F2F5;
2026-03-06 13:59:22 +08:00
}
.usage-capsule {
display: inline-flex;
align-items: center;
background: #E8F6F4;
padding: 8rpx 16rpx;
border-radius: 6rpx;
2026-03-06 13:59:22 +08:00
}
.card-actions {
2026-03-06 13:59:22 +08:00
margin-top: 24rpx;
padding-top: 20rpx;
border-top: 1px dashed #F0F2F5;
2026-03-06 13:59:22 +08:00
}
.action-btn-text {
2026-05-07 11:04:56 +08:00
display: flex;
align-items: center;
font-size: 26rpx;
&.danger { color: #8A92A3; } /* 弱化删除,避免误触 */
2026-03-06 13:59:22 +08:00
}
.action-btn-ghost {
padding: 10rpx 32rpx;
border-radius: 30rpx;
font-size: 26rpx;
font-weight: bold;
&.primary {
color: #00A88A;
background: #E8F6F4;
}
2026-03-06 13:59:22 +08:00
}
/* 中药极简高密度标签云 */
.tcm-tag-cloud {
2026-03-06 13:59:22 +08:00
display: flex;
flex-wrap: wrap;
gap: 16rpx;
2026-03-06 13:59:22 +08:00
}
.tcm-tag {
display: inline-flex;
2026-03-06 13:59:22 +08:00
align-items: center;
background: #F7F8FA;
padding: 12rpx 20rpx;
2026-03-06 13:59:22 +08:00
border-radius: 8rpx;
border: 1px solid #EBEFF5;
transition: all 0.2s;
2026-03-06 13:59:22 +08:00
.tcm-name {
font-size: 28rpx;
color: #2A2E35;
font-weight: 500;
}
.tcm-weight {
font-size: 26rpx;
color: #00A88A;
margin-left: 12rpx;
font-weight: bold;
}
2026-03-06 13:59:22 +08:00
}
/* 简单产品精美步进器 */
.modern-stepper {
background: #F7F8FA;
2026-03-06 13:59:22 +08:00
border-radius: 8rpx;
overflow: hidden;
border: 1px solid #E2E8F0;
.stepper-btn {
width: 50rpx;
height: 50rpx;
display: flex;
align-items: center;
justify-content: center;
color: #6C7380;
font-size: 32rpx;
font-weight: bold;
background: #fff;
}
.stepper-val {
min-width: 60rpx;
text-align: center;
color: #2A2E35;
font-weight: bold;
}
2026-03-06 13:59:22 +08:00
}
/* 底部操作栏(恢复原状) */
2026-03-06 13:59:22 +08:00
.bottom {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 32rpx;
background: #fff;
border-top: 1px solid #f0f0f0;
z-index: 99;
2026-05-07 11:04:56 +08:00
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
2026-03-06 13:59:22 +08:00
}
.btnText {
color: #6ACDBB;
font-size: 28rpx;
padding: 0 32rpx;
2026-05-07 11:04:56 +08:00
flex-shrink: 0;
2026-03-06 13:59:22 +08:00
}
</style>