Files
xk-doctor-wx/subPackages/sub_workbench/prescription_v2/index.vue
李琦 d4a66b7d90 1. 优化了一些交互,中药药品编辑交互
2. dev和生产环境统一鉴别
2026-05-15 16:59:16 +08:00

2057 lines
83 KiB
Vue
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.
<template>
<view class="safe-area-inset-bottom page-bg">
<!-- #ifdef MP-WEIXIN -->
<page-container
:show="pageBackGuardShow"
:overlay="false"
@leave="onPageBackGuardLeave"
/>
<!-- #endif -->
<!-- 导航栏 -->
<u-navbar class="navbar" :is-back="true" :title="navbarTitle" :custom-back="handleCustomBack" title-color="#000" background="{ background: '#fff' }">
</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="{
display: (index === 0 && identity === 2) || identity === 1 ? 'block' : 'none',
marginLeft: '10rpx',
}">
{{ category.label }}
</u-button>
</view>
<view v-if="registerModeHint" class="register-mode-hint mx-32 m-t-12">
<text class="register-mode-hint__text">{{ registerModeHint }}</text>
</view>
<!-- 诊断输入区域 -->
<view class="top white p-32 flex-col m-t-16 radius-12 mx-32">
<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>
</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)" />
</view>
</view>
<view class="m-t-24">
<u-input
disabled
placeholder="请选择或输入疾病诊断"
:custom-style="illnessStyle"
@click="handleOpenDiagnosisModal" />
</view>
</view>
<!-- 滚动内容区域 -->
<scroll-view :style="scrollStyle" scroll-y="true">
<!-- 在线复诊 + 中药证候/治法/中医疾病接口 diseases_idmethod_idsyndrome_id PC 在线问诊处方一致 -->
<view v-if="activeCategory === 1 && isOnlineRevisit" class="white p-32 radius-12 mx-32 m-t-24 flex-col">
<view class="top_title flex-row flex-ali-center m-b-16">
<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>
</view>
<view class="m-t-8">
<d-text text="中医证候" className="fs-26 color-sub"></d-text>
<u-input
disabled
:value="onlineTcmDiseasesLabel"
placeholder="请点击选择中医证候"
:custom-style="illnessStyle"
class="m-t-8"
@click="handleOpenTcmPicker('diseases')" />
</view>
<view class="m-t-24">
<d-text text="中医治法" className="fs-26 color-sub"></d-text>
<u-input
disabled
:value="onlineTcmMethodLabel"
placeholder="请点击选择中医治法"
:custom-style="illnessStyle"
class="m-t-8"
@click="handleOpenTcmPicker('method')" />
</view>
<view class="m-t-24">
<d-text text="中医疾病" className="fs-26 color-sub"></d-text>
<u-input
disabled
:value="onlineTcmSyndromeLabel"
placeholder="请点击选择中医疾病"
:custom-style="illnessStyle"
class="m-t-8"
@click="handleOpenTcmPicker('syndrome')" />
</view>
</view>
<!-- 西药列表 -->
<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">
常用方
</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> 添加药品
</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"
></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>
</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>
</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>
</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>
</view>
</view>
<view class="white p-32 radius-12 m-t-24 flex-col" v-if="currentDrugs.length > 0">
<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>
</view>
<u-input v-model="medicalAdvice" placeholder="请输入医嘱注意事项..." :custom-style="entrustStyle" />
</view>
<view class="flex-row flex-jus-center m-t-64" v-if="currentDrugs.length === 0">
<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>
</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">
常用方
</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> 添加药材
</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>
</view>
</view>
<view class="tcm-tag-cloud">
<view
class="tcm-tag"
v-for="(it, tcmIndex) in currentDrugs"
:key="tcmTagKey(it, tcmIndex)"
:data-idx="tcmIndex"
@longpress.stop="onTcmTagLongPress">
<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>
</view>
</view>
<view class="flex-row flex-jus-center m-t-64" v-else>
<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>
<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> 添加商品
</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"
></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>
</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>
</view>
</view>
</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>
</view>
</view>
<view class="white p-32 radius-12 m-t-24 flex-col" v-if="currentDrugs.length > 0">
<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>
</view>
<u-input v-model="medicalAdvice" placeholder="请输入注意事项..." :custom-style="entrustStyle" />
</view>
<view class="flex-row flex-jus-center m-t-64" v-if="currentDrugs.length === 0">
<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">
<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>
</view>
<u-input v-model="medicalAdvice" placeholder="请输入服药注意事项..." :custom-style="entrustStyle" />
</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"
/>
</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>
</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>
</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>
</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>
</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="{
backgroundColor: isSubmitting ? '#A5DCD2' : '#6ACDBB',
color: '#fff',
height: '86rpx',
width: (isCommonPrescription || !supportsCommonPrescriptionTemplate) ? '686rpx' : '448rpx'
}"
:disabled="isSubmitting">
{{ isCommonPrescription ? '保存常用方' : '发送处方' }}
</u-button>
</view>
<TraditionalTermPickerModal
v-model="showTcmPicker"
:title="tcmPickerTitle"
:options="tcmPickerList"
:selected-id="tcmPickerCurrentSelectedId"
@confirm="handleTcmPickerConfirm"
/>
<!-- 诊断选择弹窗 -->
<DiagnosisModal
v-model="showDiagnosisModal"
:selectedDiagnosis="diagnosisText"
@confirm="handleDiagnosisConfirm"
/>
<!-- 医嘱选择弹窗 -->
<DoctorOrderModal
v-model="showDoctorOrderModal"
:selectedDoctorOrder="medicalAdvice"
@confirm="handleDoctorOrderConfirm"
/>
<!-- 常用方选择弹窗 -->
<CommonPrescriptionModal
v-model="showCommonPrescriptionModal"
:prescriptionType="activeCategory"
@select="handleSelectCommonPrescription"
/>
<!-- 西药选择弹窗 -->
<WesternMedicineModal
v-model="showWesternMedicineModal"
:currentDrugs="currentDrugs"
:initial-search-key="westernModalInitialKeyword"
@select="handleSelectWesternDrug"
/>
<!-- 中药选择弹窗 -->
<ChineseMedicineModal
v-model="showChineseMedicineModal"
:currentDrugs="currentDrugs"
:initial-search-key="chineseModalInitialKeyword"
@select="handleSelectChineseDrug"
/>
<!-- 简单产品选择弹窗 -->
<SimpleProductModal
v-model="showSimpleProductModal"
:productType="activeCategory"
:currentProducts="currentDrugs"
@select="handleSelectSimpleProduct"
/>
<!-- 西药用法用量设置弹窗 -->
<WesternMedicineUsageModal
v-model="showWesternUsageModal"
:drug="editingDrug"
@confirm="handleConfirmWesternUsage"
/>
<!-- 保存常用方弹窗 -->
<u-modal
v-model="showSaveCommonPrescriptionModal"
:show-cancel-button="true"
:mask-close-able="true"
title="保存常用方"
@confirm="handleConfirmSaveCommonPrescription"
@cancel="showSaveCommonPrescriptionModal = false">
<view class="slot-content" style="padding: 20rpx;">
<u-input
v-model="commonPrescriptionName"
placeholder="请输入处方名称"
type="text"
:border="true" />
</view>
</u-modal>
</view>
</template>
<script>
// 注意:这部分保持你原有的逻辑代码,不进行任何修改,确保业务完全正常
import {
addWestPrescription,
checkChineseMedicineConflictApi,
getDiseaseList,
getDrugUseList,
getProductListDoctorReception,
getPatientInfoByPatientId,
getPatientItem,
getProcessRuleList,
getCommonPrescriptionListApi,
saveWestCommonPrescriptionApi,
saveChineseCommonPrescriptionApi,
getCurrentStoreTypeApi,
getPrescriptionInfoApi,
getTraditionalChineseMedicineJson
} from '@/api/reception.js';
import { getChatRoomByRegisterApi, sendToUserHttpApi } from '@/api/chat.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';
import TraditionalTermPickerModal from './components/modals/TraditionalTermPickerModal.vue';
const PENDING_RX_FROM_CHAT = 'xk_pending_rx_from_chat';
/** 与 closeTopOverlayIfAny 一致:任意为 true 时启用微信小程序 page-container 返回拦截 */
const PRESCRIPTION_OVERLAY_KEYS = [
'showWesternUsageModal',
'showTcmPicker',
'showWesternMedicineModal',
'showChineseMedicineModal',
'showSimpleProductModal',
'showCommonPrescriptionModal',
'showDiagnosisModal',
'showDoctorOrderModal',
'showSaveCommonPrescriptionModal'
];
export default {
name: 'PrescriptionV2',
components: {
DiagnosisModal,
DoctorOrderModal,
CommonPrescriptionModal,
WesternMedicineModal,
ChineseMedicineModal,
SimpleProductModal,
WesternMedicineUsageModal,
ChineseMedicineConfig,
TraditionalTermPickerModal
},
data() {
return {
registerId: '',
patientId: '',
pendingReusePrescriptionId: '',
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: '',
medicalAdvice: '',
treatmentPrice: '',
chineseConfig: {
ruleType: 1,
packageMethodId: null,
processRuleId: null,
childProcessRuleId: null,
processRuleNoteId: null,
dosage: 7,
dayDosage: 2
},
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,
westernModalInitialKeyword: '',
showChineseMedicineModal: false,
chineseModalInitialKeyword: '',
showSimpleProductModal: false,
showWesternUsageModal: false,
showSaveCommonPrescriptionModal: false,
editingDrug: null,
editingDrugIndex: -1,
commonPrescriptionName: '',
isCommonPrescription: false,
_presetActiveCategory: null,
isSubmitting: false,
identity: uni.getStorageSync('role'),
registerStoreInfo: null,
sendMode: 0,
selectedStoreId: null,
registerOrderType: null,
/** 在线复诊中药术语表HTTP 拉取,内存缓存) */
traditionalTcmData: null,
traditionalTcmLoadPromise: null,
showTcmPicker: false,
tcmPickerTitle: '',
tcmPickerField: '',
tcmPickerList: [],
/** 与 PC prescriptionStore 提交字段一致diseases_id←证候(diseases)method_id←治法syndrome_id←中医疾病(syndrome) */
onlineTcmDiseasesId: null,
onlineTcmMethodId: null,
onlineTcmSyndromeId: null,
// UI Styles
tabsBtnStyle: {
padding: '8rpx 32rpx',
height: '60rpx',
fontSize: '28rpx',
borderRadius: '30rpx'
},
illnessStyle: {
fontSize: '28rpx',
backgroundColor: '#F7F8FA',
borderRadius: '16rpx',
height: '76rpx',
padding: '0 32rpx'
},
entrustStyle: {
fontSize: '28rpx',
backgroundColor: '#F7F8FA',
height: '80rpx',
padding: '0 24rpx',
borderRadius: '12rpx',
marginTop: '20rpx'
},
priceInputStyle: {
fontSize: '32rpx',
fontWeight: 'bold',
color: '#333',
width: '160rpx',
height: '60rpx',
backgroundColor: '#F7F8FA',
borderRadius: '8rpx',
padding: '0 16rpx'
},
scrollStyle: {
height: 'calc(100vh - 600rpx)',
marginBottom: '200rpx'
},
/** 微信小程序 page-container有抽屉/弹层时为 true拦截侧滑等返回 */
pageBackGuardShow: false
};
},
computed: {
totalProductCost() {
if (this.currentDrugs.length === 0) return 0;
if (this.activeCategory === 1) {
return PrescriptionCalculator.calculateChineseMedicineProductPrice(this.currentDrugs, this.chineseConfig.dosage);
} 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);
},
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);
},
isOnlineRevisit() {
const t = Number(this.registerOrderType);
return t === 2 || t === 3;
},
registerModeHint() {
if (this.registerOrderType === null || this.registerOrderType === undefined || this.registerOrderType === '') return '';
return this.isOnlineRevisit ? '当前:在线复诊开方(提交后将向患者发送处方消息)' : '当前:线下开方';
},
navbarTitle() {
if (this.registerOrderType === null || this.registerOrderType === undefined || this.registerOrderType === '') {
return '开方';
}
return this.isOnlineRevisit ? '开方 · 在线复诊' : '开方 · 线下';
},
onlineTcmDiseasesLabel() {
const data = this.traditionalTcmData;
const id = this.onlineTcmDiseasesId;
if (!data || id == null || id === '') return '';
const row = (data.diseases || []).find((x) => Number(x.id) === Number(id));
return row ? row.name : '';
},
onlineTcmMethodLabel() {
const data = this.traditionalTcmData;
const id = this.onlineTcmMethodId;
if (!data || id == null || id === '') return '';
const row = (data.method || []).find((x) => Number(x.id) === Number(id));
return row ? row.name : '';
},
onlineTcmSyndromeLabel() {
const data = this.traditionalTcmData;
const id = this.onlineTcmSyndromeId;
if (!data || id == null || id === '') return '';
const row = (data.syndrome || []).find((x) => Number(x.id) === Number(id));
return row ? row.name : '';
},
tcmPickerCurrentSelectedId() {
if (this.tcmPickerField === 'diseases') return this.onlineTcmDiseasesId;
if (this.tcmPickerField === 'method') return this.onlineTcmMethodId;
if (this.tcmPickerField === 'syndrome') return this.onlineTcmSyndromeId;
return null;
},
hasPrescriptionOverlay() {
for (let i = 0; i < PRESCRIPTION_OVERLAY_KEYS.length; i++) {
if (this[PRESCRIPTION_OVERLAY_KEYS[i]]) return true;
}
return false;
}
},
watch: {
showWesternMedicineModal(val) {
if (!val) this.westernModalInitialKeyword = '';
},
showChineseMedicineModal(val) {
if (!val) this.chineseModalInitialKeyword = '';
},
// #ifdef MP-WEIXIN
hasPrescriptionOverlay(val) {
this.pageBackGuardShow = !!val;
},
// #endif
},
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 = String(options.save_common) === '1';
if (!this.isCommonPrescription) {
uni.removeStorageSync('add');
}
if (options.initial_category !== undefined && options.initial_category !== '') {
const n = parseInt(options.initial_category, 10);
if (!Number.isNaN(n)) this._presetActiveCategory = n;
}
this.initializePageData();
},
async onShow() {
this.loadCurrentCategoryDrugs();
if (this.activeCategory === 1 && this.chineseConfig.ruleType === 2) {
await this.hydrateChineseProcessRuleListsFromConfig();
}
if (this.activeCategory === 1) await this.checkAndShowTransferTip();
},
onUnload() {
if (this.isCommonPrescription) {
uni.removeStorageSync('add');
}
},
methods: {
async initializePageData() {
try {
this.restoreFromLocalStorage();
await this.loadPatientInfo();
await this.loadRegisterOrderType();
await this.loadBasicConfigData();
await this.loadRegisterStoreInfo();
this.loadCurrentCategoryDrugs();
if (this.activeCategory === 1 && this.chineseConfig.ruleType === 2) {
await this.hydrateChineseProcessRuleListsFromConfig();
}
await this.maybeApplyReusePrescription();
if (this.activeCategory === 1) await this.checkAndShowTransferTip();
this.applyPendingExperienceDrugFromChat();
} 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;
}
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 };
if (this.activeCategory === 1) {
if (data.onlineTcmDiseasesId !== undefined && data.onlineTcmDiseasesId !== null) this.onlineTcmDiseasesId = data.onlineTcmDiseasesId;
else this.onlineTcmDiseasesId = null;
if (data.onlineTcmMethodId !== undefined && data.onlineTcmMethodId !== null) this.onlineTcmMethodId = data.onlineTcmMethodId;
else this.onlineTcmMethodId = null;
if (data.onlineTcmSyndromeId !== undefined && data.onlineTcmSyndromeId !== null) this.onlineTcmSyndromeId = data.onlineTcmSyndromeId;
else this.onlineTcmSyndromeId = null;
} else {
this.onlineTcmDiseasesId = null;
this.onlineTcmMethodId = null;
this.onlineTcmSyndromeId = null;
}
} else {
this.currentDrugs = [];
this.onlineTcmDiseasesId = null;
this.onlineTcmMethodId = null;
this.onlineTcmSyndromeId = null;
}
},
/**
* 从 chineseConfig 中的 ID 拉取委托调剂三级列表(本地缓存只存 ID不存列表
*/
async hydrateChineseProcessRuleListsFromConfig() {
if (this.activeCategory !== 1 || this.chineseConfig.ruleType !== 2) return;
if (!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);
}
},
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,
onlineTcmDiseasesId: this.activeCategory === 1 ? this.onlineTcmDiseasesId : undefined,
onlineTcmMethodId: this.activeCategory === 1 ? this.onlineTcmMethodId : undefined,
onlineTcmSyndromeId: this.activeCategory === 1 ? this.onlineTcmSyndromeId : undefined
};
PrescriptionStorage.savePrescriptionData(this.activeCategory, this.registerId, data);
PrescriptionStorage.saveActiveCategory(this.activeCategory, this.registerId);
},
async loadPatientInfo() {
if (!this.patientId) return;
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,
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 loadRegisterOrderType() {
if (!this.registerId) {
this.registerOrderType = null;
return;
}
try {
const res = await getPatientItem(this.registerId);
const data = res.result || res.data || res;
if (data && data.type !== undefined && data.type !== null) {
this.registerOrderType = data.type;
} else {
this.registerOrderType = null;
}
} catch (e) {
console.warn(e);
this.registerOrderType = null;
}
},
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;
}
if (this.activeCategory === 1 && this.processRuleList.length === 0) {
await this.loadProcessRuleList(0, 0);
}
} catch (error) {
console.error('加载基础配置数据失败:', error);
}
},
async loadRegisterStoreInfo() {
if (!this.registerId) return;
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;
} else if (res.store_id) {
this.selectedStoreId = res.store_id;
this.sendMode = res.can_change ? 1 : 0;
}
}
} 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);
}
},
async checkAndShowTransferTip() {
try {
if (!this.registerStoreInfo) await this.loadRegisterStoreInfo();
const storeInfo = this.registerStoreInfo;
if (!storeInfo) return;
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; },
async ensureTraditionalTcmData() {
if (this.traditionalTcmData) return this.traditionalTcmData;
if (this.traditionalTcmLoadPromise) return this.traditionalTcmLoadPromise;
this.traditionalTcmLoadPromise = getTraditionalChineseMedicineJson()
.then((d) => {
this.traditionalTcmData = d;
return d;
})
.finally(() => {
this.traditionalTcmLoadPromise = null;
});
return this.traditionalTcmLoadPromise;
},
async handleOpenTcmPicker(field) {
if (!this.isOnlineRevisit || this.activeCategory !== 1) return;
try {
uni.showLoading({ title: '加载中', mask: true });
await this.ensureTraditionalTcmData();
uni.hideLoading();
this.tcmPickerField = field;
this.tcmPickerTitle = field === 'diseases' ? '中医证候' : field === 'method' ? '中医治法' : '中医疾病';
const d = this.traditionalTcmData;
this.tcmPickerList = field === 'diseases' ? (d.diseases || []) : field === 'method' ? (d.method || []) : (d.syndrome || []);
this.showTcmPicker = true;
} catch (e) {
uni.hideLoading();
console.error(e);
uni.showToast({ title: '术语表加载失败', icon: 'none' });
}
},
handleTcmPickerConfirm(id) {
const nid = id != null ? Number(id) : null;
if (this.tcmPickerField === 'diseases') this.onlineTcmDiseasesId = nid;
else if (this.tcmPickerField === 'method') this.onlineTcmMethodId = nid;
else if (this.tcmPickerField === 'syndrome') this.onlineTcmSyndromeId = nid;
this.saveToLocalStorage();
this.showTcmPicker = false;
},
handleDiagnosisConfirm(diagnosisText) {
this.diagnosisText = diagnosisText;
if (diagnosisText) {
const diagnosisNames = diagnosisText.split('').filter(Boolean);
this.diagnoses = diagnosisNames.map((name, index) => ({ id: `temp_${index}`, name: name }));
} 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; },
handleDoctorOrderConfirm(doctorOrderText) {
this.medicalAdvice = doctorOrderText;
this.saveToLocalStorage();
},
handleOpenCommonPrescriptionModal() { this.showCommonPrescriptionModal = true; },
async handleSelectCommonPrescription(item) {
try {
const payload = item && item.apply_payload;
if (!payload || !Array.isArray(payload.drugs)) {
this.$toast('常用方数据异常');
return;
}
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 }));
}
if (payload.medicalAdvice) this.medicalAdvice = payload.medicalAdvice;
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);
}
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';
},
applyPendingExperienceDrugFromChat() {
let raw;
try {
raw = uni.getStorageSync(PENDING_RX_FROM_CHAT);
} catch (e) {
return;
}
if (!raw) return;
let p;
try {
p = typeof raw === 'string' ? JSON.parse(raw) : raw;
} catch (e2) {
try {
uni.removeStorageSync(PENDING_RX_FROM_CHAT);
} catch (e3) {}
return;
}
if (!p || String(p.register_id) !== String(this.registerId)) return;
if (p.source === 'register_drugs' && Array.isArray(p.drugs) && p.drugs.length > 0) {
try {
uni.removeStorageSync(PENDING_RX_FROM_CHAT);
} catch (e4) {}
this.activeCategory = 2;
this.saveToLocalStorage();
this.loadCurrentCategoryDrugs();
this.mergeWesternRowsFromRegisterDrugs(p.drugs);
return;
}
if (p.source === 'transfer_import' && Array.isArray(p.drugs) && p.drugs.length > 0) {
try {
uni.removeStorageSync(PENDING_RX_FROM_CHAT);
} catch (e5) {}
this.activeCategory = 1;
this.saveToLocalStorage();
this.loadCurrentCategoryDrugs();
this.mergeTransferChineseRows(p.drugs);
if (p.diagnosisText) {
this.diagnosisText = String(p.diagnosisText);
const names = this.diagnosisText.split('').filter(Boolean);
this.diagnoses = names.map((name, index) => ({ id: `temp_${index}`, name }));
}
if (p.medicalAdvice != null && String(p.medicalAdvice).trim() !== '') {
this.medicalAdvice = String(p.medicalAdvice);
}
this.saveToLocalStorage();
return;
}
try {
uni.removeStorageSync(PENDING_RX_FROM_CHAT);
} catch (e4) {}
this.activeCategory = 2;
this.westernModalInitialKeyword = String(p.drug_name || '').trim();
this.saveToLocalStorage();
this.loadCurrentCategoryDrugs();
this.$nextTick(() => {
this.showWesternMedicineModal = true;
});
},
mergeWesternRowsFromRegisterDrugs(rows) {
let added = 0;
for (const row of rows) {
const d = row.drug || {};
const qtyRaw = row.purchase_quantity != null ? Number(row.purchase_quantity) : null;
const qty =
qtyRaw != null && !Number.isNaN(qtyRaw) && qtyRaw >= 1 ? Math.min(99, qtyRaw) : Number(d.number || 1) || 1;
const drugId = row.drug_id || d.id;
const synthetic = {
id: drugId,
drug_id: drugId,
drug_name: d.drug_name,
number: qty,
select_number: qty,
price: parseFloat(row.price) || 0,
specification: d.specification || '',
image: d.image || '',
instruction: d.instruction || '',
time_id: d.time_id || 0,
type_id: d.type_id || 0,
frequency_id: d.frequency_id || 0,
unit_id: d.unit_id || 0,
drug: d
};
if (PrescriptionValidator.isDrugExists(this.currentDrugs, synthetic)) {
continue;
}
const newDrug = {
index_id: row.id,
id: drugId,
drug_id: drugId,
drug_name: d.drug_name,
number: qty,
select_number: qty,
price: parseFloat(row.price) || 0,
specification: d.specification || '',
image: d.image || '',
instruction: d.instruction || '',
time_id: d.time_id || 0,
type_id: d.type_id || 0,
frequency_id: d.frequency_id || 0,
unit_id: d.unit_id || 0,
use_num: this.drugUseList.drug_time?.find((item) => item.id === (d.time_id || 0)),
use_type: this.drugUseList.drug_use_type?.find((item) => item.id === (d.type_id || 0)),
use_frequency: this.drugUseList.drug_use_frequency?.find((item) => item.id === (d.frequency_id || 0)),
unit: this.drugUseList.drug_unit?.find((item) => item.id === (d.unit_id || 0))
};
this.currentDrugs.push(newDrug);
added++;
}
this.saveToLocalStorage();
if (added > 0) {
this.$toast(`已添加 ${added} 个药品`);
} else {
this.$toast('药品已在列表中或未能匹配');
}
},
mergeTransferChineseRows(rows) {
let added = 0;
for (const product of rows) {
if (PrescriptionValidator.isDrugExists(this.currentDrugs, product)) {
continue;
}
this.currentDrugs.push({ ...product });
added++;
}
this.saveToLocalStorage();
if (added > 0) {
this.$toast(`已添加 ${added} 味药`);
} else {
this.$toast('药品已在列表中');
}
},
handleOpenWesternMedicineModal() {
this.westernModalInitialKeyword = '';
this.showWesternMedicineModal = true;
},
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}`);
},
handleOpenChineseMedicineModal() {
this.chineseModalInitialKeyword = '';
this.showChineseMedicineModal = true;
},
/** 微信小程序 :key 中勿写 it.id || it.index_id 等表达式,会编译异常 */
tcmTagKey(it, tcmIndex) {
if (it && it.id != null && it.id !== '') return `tcm-${it.id}`;
if (it && it.index_id != null && it.index_id !== '') return `tcm-i-${it.index_id}`;
return `tcm-idx-${tcmIndex}`;
},
/**
* 中药标签长按菜单(小程序 showActionSheet 回调里勿依赖闭包 item用 dataset.idx + currentDrugs
*/
onTcmTagLongPress(e) {
const raw = e && e.currentTarget && e.currentTarget.dataset ? e.currentTarget.dataset.idx : undefined;
const idx = raw === undefined || raw === '' ? NaN : Number(raw);
if (Number.isNaN(idx) || idx < 0 || idx >= this.currentDrugs.length) return;
uni.showActionSheet({
itemList: ['编辑', '删除'],
success: (res) => {
const row = this.currentDrugs[idx];
if (!row) return;
if (res.tapIndex === 0) {
this.chineseModalInitialKeyword = String(row.drug_name || row.name || '').trim();
this.showChineseMedicineModal = true;
} else if (res.tapIndex === 1) {
this.handleRemoveDrug(idx);
}
}
});
},
handleSelectChineseDrug(drugs) {
this.currentDrugs = drugs || [];
this.saveToLocalStorage();
},
handleOpenSimpleProductModal() { this.showSimpleProductModal = true; },
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 || '',
instruction: product.instruction || product.drug?.instruction || '',
type: product.drug?.type || product.type || this.activeCategory,
select_number: 1
};
this.currentDrugs.push(newProduct);
this.saveToLocalStorage();
this.$toast(`已添加 ${newProduct.drug_name}`);
},
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',
success: ({ confirm }) => {
if (confirm) {
this.currentDrugs.splice(index, 1);
this.saveToLocalStorage();
}
}
});
},
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);
}
}
},
handleRemoveAllDrugs() {
uni.showModal({
title: '清空药材',
content: '确定要清空所有中药材吗?',
confirmColor: '#FC3636',
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;
if (config.ruleType === 2 && config.ruleType !== oldRuleType) {
if (this.processRuleList.length === 0) await this.loadProcessRuleList(0, 0);
}
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 = {}; }
}
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) await this.hydrateChineseProcessRuleListsFromConfig();
} 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 '';
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 '件';
},
validatePrescriptionData() {
return PrescriptionValidator.validatePrescriptionData({
category: this.activeCategory,
drugs: this.currentDrugs,
diagnoses: this.diagnoses,
medicalAdvice: this.medicalAdvice,
chineseConfig: this.activeCategory === 1 ? this.chineseConfig : null,
requireOnlineTcm: this.activeCategory === 1 && this.isOnlineRevisit,
onlineTcmDiseasesId: this.onlineTcmDiseasesId,
onlineTcmMethodId: this.onlineTcmMethodId,
onlineTcmSyndromeId: this.onlineTcmSyndromeId
});
},
async checkChineseMedicineConflict() {
if (this.activeCategory !== 1) return { hasConflict: false };
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 || '检测到该处方内具有药物相冲' };
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; }
const validation = this.validatePrescriptionData();
if (!validation.valid) { this.$toast(validation.message); return; }
this.isSubmitting = true;
try {
if (!this.registerStoreInfo) await this.loadRegisterStoreInfo();
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;
}
});
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;
},
fail: () => { this.isSubmitting = false; }
});
} 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();
if (!this.patientInfo || !this.patientId) {
this.$toast('患者信息缺失,无法发送处方');
this.isSubmitting = false; return;
}
}
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);
});
if (invalidDrug) { this.$toast('请先为西药设置完整的用法用量'); return; }
}
let finalSendMode = sendMode; let finalStoreId = customStoreId;
const storeInfo = this.registerStoreInfo;
if (storeInfo?.is_from_transfer === 1 && storeInfo?.delegate_store_id) {
finalSendMode = 1; finalStoreId = storeInfo.delegate_store_id;
}
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 || '' };
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 }));
} 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;
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: '' };
return drugData;
});
}
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
};
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;
if (this.isOnlineRevisit) {
params.diseases_id = this.onlineTcmDiseasesId;
params.method_id = this.onlineTcmMethodId;
params.syndrome_id = this.onlineTcmSyndromeId;
}
}
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); this.safeNavigateBack(500); }
});
return;
}
}
if (this.isOnlineRevisit) {
try {
await this.trySendPrescriptionChatMessage(res);
} catch (e) {
console.error('处方消息同步失败', e);
uni.showToast({ title: '处方消息同步失败', icon: 'none' });
}
}
this.clearPrescriptionData();
PrescriptionStorage.clearAllPrescriptionData(this.registerId);
this.safeNavigateBack(1500);
} else {
this.$toast(res.msg || res.message || '发送失败');
}
} catch (error) {
console.error('发送处方失败:', error);
this.$toast('发送处方失败,请重试');
throw error;
} finally {
this.isSubmitting = false;
}
},
async trySendPrescriptionChatMessage(res) {
const inner = res && (res.result !== undefined ? res.result : res.data !== undefined ? res.data : null);
if (!inner || typeof inner !== 'object') return;
if (!this.registerId) return;
const roomRes = await getChatRoomByRegisterApi(this.registerId);
const roomPayload = roomRes && (roomRes.result || roomRes.data || roomRes);
const roomId = roomPayload && roomPayload.room_id;
const receiverUserId = roomPayload && roomPayload.receiver_user_id;
if (!roomId || !receiverUserId) return;
const doctorId = uni.getStorageSync('doctor_id') || uni.getStorageSync('user_id');
if (!doctorId) return;
const senderUserId = String(doctorId).startsWith('doctor-') ? String(doctorId) : `doctor-${doctorId}`;
try {
await sendToUserHttpApi({
room_id: roomId,
sender_user_id: senderUserId,
receiver_user_id: receiverUserId,
message_type: 4,
message_content: JSON.stringify(inner),
duration: 0
});
} catch (e) {
console.warn('trySendPrescriptionChatMessage', e);
}
},
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 };
this.onlineTcmDiseasesId = null;
this.onlineTcmMethodId = null;
this.onlineTcmSyndromeId = null;
},
handleSaveAsCommonPrescription() {
if (this.currentDrugs.length === 0) { this.$toast('请先添加药品后再保存为常用方'); return; }
if (![1, 2].includes(this.activeCategory)) { this.$toast('当前分类不支持保存为常用方'); return; }
this.showSaveCommonPrescriptionModal = true;
},
async handleConfirmSaveCommonPrescription() {
if (!this.commonPrescriptionName || !this.commonPrescriptionName.trim()) { this.$toast('请输入常用方名称'); return; }
if (![1, 2].includes(this.activeCategory)) { this.$toast('当前分类不支持保存为常用方'); return; }
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; }
} 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 || '', specification: drug.specification || '' }));
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; }
}
this.$toast('保存成功');
this.showSaveCommonPrescriptionModal = false; this.commonPrescriptionName = '';
if (this.isCommonPrescription) { uni.removeStorageSync('add'); this.safeNavigateBack(400); }
} catch (error) { console.error('保存常用方失败:', error); this.$toast('保存常用方失败,请重试'); }
},
/** 若有弹层打开则关闭第一个并返回 true用于导航返回 / 微信 page-container leave 先关抽屉) */
closeTopOverlayIfAny() {
for (let i = 0; i < PRESCRIPTION_OVERLAY_KEYS.length; i++) {
const k = PRESCRIPTION_OVERLAY_KEYS[i];
if (this[k]) {
this[k] = false;
return true;
}
}
return false;
},
/** 微信小程序:先关闭 page-container 拦截再退栈,避免 navigateBack 被吞 */
safeNavigateBack(delayMs = 0) {
const runNav = () => {
// #ifdef MP-WEIXIN
this.pageBackGuardShow = false;
setTimeout(() => {
uni.navigateBack();
}, 16);
// #endif
// #ifndef MP-WEIXIN
uni.navigateBack();
// #endif
};
if (delayMs > 0) {
setTimeout(runNav, delayMs);
} else {
runNav();
}
},
// #ifdef MP-WEIXIN
onPageBackGuardLeave() {
this.closeTopOverlayIfAny();
this.$nextTick(() => {
this.pageBackGuardShow = this.hasPrescriptionOverlay;
});
},
// #endif
handleCustomBack() {
if (this.closeTopOverlayIfAny()) return;
this.safeNavigateBack(0);
}
}
};
</script>
<style lang="scss" scoped>
/* 基础与通用样式 */
.page-bg {
background-color: #F4F6F8;
min-height: 100vh;
}
.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;
}
.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;
}
.tabs {
background: #fff;
border-bottom: 1px solid #F0F2F5;
}
/* 现代卡片设计 (西药 / 产品) */
.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;
}
.drug-image-modern {
width: 140rpx;
height: 140rpx;
border-radius: 12rpx;
background-color: #F7F8FA;
flex-shrink: 0;
border: 1px solid #F0F2F5;
}
.usage-capsule {
display: inline-flex;
align-items: center;
background: #E8F6F4;
padding: 8rpx 16rpx;
border-radius: 6rpx;
}
.card-actions {
margin-top: 24rpx;
padding-top: 20rpx;
border-top: 1px dashed #F0F2F5;
}
.action-btn-text {
display: flex;
align-items: center;
font-size: 26rpx;
&.danger { color: #8A92A3; } /* 弱化删除,避免误触 */
}
.action-btn-ghost {
padding: 10rpx 32rpx;
border-radius: 30rpx;
font-size: 26rpx;
font-weight: bold;
&.primary {
color: #00A88A;
background: #E8F6F4;
}
}
/* 中药极简高密度标签云 */
.tcm-tag-cloud {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
}
.tcm-tag {
display: inline-flex;
align-items: center;
background: #F7F8FA;
padding: 12rpx 20rpx;
border-radius: 8rpx;
border: 1px solid #EBEFF5;
transition: all 0.2s;
.tcm-name {
font-size: 28rpx;
color: #2A2E35;
font-weight: 500;
}
.tcm-weight {
font-size: 26rpx;
color: #00A88A;
margin-left: 12rpx;
font-weight: bold;
}
}
/* 简单产品精美步进器 */
.modern-stepper {
background: #F7F8FA;
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;
}
}
/* 底部操作栏(恢复原状) */
.register-mode-hint {
padding: 16rpx 24rpx;
background: #f0faf8;
border-radius: 12rpx;
border: 1rpx solid #d4efe8;
}
.register-mode-hint__text {
font-size: 24rpx;
color: #008771;
line-height: 1.5;
}
.bottom {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 32rpx;
background: #fff;
border-top: 1px solid #f0f0f0;
z-index: 99;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.btnText {
color: #6ACDBB;
font-size: 28rpx;
padding: 0 32rpx;
flex-shrink: 0;
}
</style>