2774 lines
110 KiB
Vue
2774 lines
110 KiB
Vue
<template>
|
||
<view class="safe-area-inset-bottom page-bg">
|
||
<!-- #ifdef MP-WEIXIN -->
|
||
<page-container
|
||
:if="pageBackGuardShow"
|
||
:overlay="false"
|
||
@leave="onPageBackGuardLeave"
|
||
/>
|
||
<!-- #endif -->
|
||
<!-- 导航栏 -->
|
||
<u-navbar class="navbar" :is-back="true" :title="navbarTitle" :custom-back="boundCustomBack" title-color="#000" background="{ background: '#fff' }">
|
||
</u-navbar>
|
||
|
||
<!-- 处方类型Tab切换 -->
|
||
<view v-if="!isSalespersonTransferMode" 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="!isSalespersonTransferMode && registerModeHint" class="register-mode-hint mx-32 m-t-12">
|
||
<text class="register-mode-hint__text">{{ registerModeHint }}</text>
|
||
</view>
|
||
|
||
<view
|
||
v-if="!isSalespersonTransferMode && hasSpecialPrescriptionRecord"
|
||
class="special-rx-card mx-32 m-t-12"
|
||
>
|
||
<view class="special-rx-card__inner flex-row flex-ali-center">
|
||
<u-image
|
||
v-if="specialPrescriptionRecord.special_prescription && specialPrescriptionRecord.special_prescription.cover_image"
|
||
width="96rpx"
|
||
height="96rpx"
|
||
border-radius="12"
|
||
:src="specialPrescriptionRecord.special_prescription.cover_image"
|
||
/>
|
||
<view class="flex-1 m-l-16">
|
||
<view class="fs-28 font-bold text-gray">
|
||
{{ (specialPrescriptionRecord.special_prescription && specialPrescriptionRecord.special_prescription.name) || '特色方' }}
|
||
</view>
|
||
<view class="fs-24 color-sub">
|
||
剂量:{{ specialPrescriptionRecord.dose_count }} 剂
|
||
</view>
|
||
<view class="fs-24 color-sub">
|
||
规格:{{ specialPrescriptionPurchaseLabel }}
|
||
</view>
|
||
<view class="">
|
||
<u-tag
|
||
v-if="Number(specialPrescriptionRecord.status) === 0"
|
||
text="待导入"
|
||
type="warning"
|
||
size="mini"
|
||
/>
|
||
<u-tag
|
||
v-else-if="Number(specialPrescriptionRecord.status) === 1"
|
||
text="已应用"
|
||
type="success"
|
||
size="mini"
|
||
/>
|
||
<u-tag v-else text="已完成" type="info" size="mini" />
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="special-rx-card__action m-t-16">
|
||
<u-button
|
||
size="default"
|
||
type="primary"
|
||
:loading="applyingSpecialPrescription"
|
||
:custom-style="{ backgroundColor: '#6ACDBB', color: '#fff', border: 'none', width: '100%' }"
|
||
@click="handleApplySpecialPrescription"
|
||
>
|
||
导入
|
||
</u-button>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="!isSalespersonTransferMode && allowInsuranceCategory" class="mx-32 m-t-12 flex flex-ali-center">
|
||
<u-button size="mini" :type="feeCategory === 1 ? 'success' : 'default'" @click="feeCategory = 1">自费</u-button>
|
||
<u-button size="mini" class="m-l-16" :type="feeCategory === 2 ? 'success' : 'default'" @click="feeCategory = 2">医保</u-button>
|
||
</view>
|
||
|
||
<view v-if="!isSalespersonTransferMode && activeCategory === 1 && hasSalespersonTransfer" class="mx-32 m-t-12">
|
||
<u-button size="mini" type="primary" plain @click="openSalespersonTransfer">查看传方</u-button>
|
||
</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_id、method_id、syndrome_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 v-if="!isSpecialPrescriptionCartLocked" 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 v-if="!isSpecialPrescriptionCartLocked" class="action-btn-text danger" @click="handleRemoveDrug(index)">
|
||
<u-icon name="trash" size="28"></u-icon> 删除
|
||
</view>
|
||
<view v-if="!isSpecialPrescriptionCartLocked" 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 && !isSpecialPrescriptionCartLocked">
|
||
<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="!isSalespersonTransferMode && !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 v-if="!isSpecialPrescriptionCartLocked" 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">
|
||
<template v-if="!isSpecialPrescriptionCartLocked">
|
||
<text class="fs-26 color-primary m-r-32" @click="handleOpenChineseMedicineModal">修改剂量</text>
|
||
<text class="fs-26 color-danger" @click="handleRemoveAllDrugs">清空</text>
|
||
</template>
|
||
<text
|
||
v-else
|
||
class="fs-26 color-danger"
|
||
@click="handleClearPrescriptionCart"
|
||
>清空药方</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="!isSpecialPrescriptionCartLocked && 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>
|
||
<text
|
||
v-if="seeRate == 1 && getChineseItemMargin(it) !== '--'"
|
||
class="tcm-margin"
|
||
>毛利率{{ getChineseItemMargin(it) }}%</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="flex-row flex-jus-center m-t-64" v-else-if="!isSpecialPrescriptionCartLocked">
|
||
<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 v-if="!isSpecialPrescriptionCartLocked" 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 v-if="!isSpecialPrescriptionCartLocked" 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" />
|
||
</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"
|
||
:disabled="isSpecialPrescriptionCartLocked"
|
||
: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 v-if="isTransferFeeHidden" class="transfer-fee-hidden-tip flex-col">
|
||
<text class="fs-28 color-title font-bold">本店已关闭推广员查看费用</text>
|
||
<text class="fs-24 color-sub m-t-8">提交后由接诊医生确认价格</text>
|
||
</view>
|
||
<template v-else>
|
||
<view v-if="!isSalespersonTransferMode" 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
|
||
v-if="!isSalespersonTransferMode && processingFee > 0"
|
||
class="flex-row flex-jus-sp flex-ali-center m-b-24">
|
||
<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">
|
||
<view class="flex-col">
|
||
<text class="fs-28 color-sub">商品计费</text>
|
||
<text
|
||
v-if="grossMarginText"
|
||
class="fs-24 color-primary m-t-8"
|
||
>毛利率 {{ grossMarginText }}%</text>
|
||
</view>
|
||
<text
|
||
v-if="canPreSendPriceAdjust"
|
||
class="fs-30 color-title font-bold price-link"
|
||
@click="openPreSendOrderPriceAdjust"
|
||
>¥{{totalProductCost.toFixed(2)}}</text>
|
||
<text v-else class="fs-30 color-title font-bold">¥{{totalProductCost.toFixed(2)}}</text>
|
||
</view>
|
||
|
||
<view
|
||
v-if="canPreSendPriceAdjust && currentDrugs.length > 0"
|
||
class="flex-row flex-jus-sp flex-ali-center m-b-24"
|
||
>
|
||
<text class="fs-26 color-sub">当前浮动:{{ preSendDiscountLabel || '无' }}</text>
|
||
<text
|
||
v-if="priceDiscount !== 100"
|
||
class="fs-26 color-primary"
|
||
@click="clearPreSendPriceDiscount"
|
||
>清除浮动</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>
|
||
</template>
|
||
</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="!isSalespersonTransferMode && !isCommonPrescription && supportsCommonPrescriptionTemplate"
|
||
class="flex-row flex-ali-center"
|
||
>
|
||
<view @click="handleSaveAsCommonPrescription" class="btnText">另存常用方</view>
|
||
</view>
|
||
<u-button
|
||
:throttle-time="0"
|
||
@click="handleSendPrescription"
|
||
shape="circle"
|
||
:custom-style="{
|
||
backgroundColor: isSubmitting ? '#A5DCD2' : '#6ACDBB',
|
||
color: '#fff',
|
||
height: '86rpx',
|
||
width: bottomSendBtnWidth
|
||
}"
|
||
:disabled="isSubmitting">
|
||
{{ isCommonPrescription ? '保存常用方' : (isSalespersonTransferMode ? '提交传方' : '发送处方') }}
|
||
</u-button>
|
||
</view>
|
||
|
||
<TraditionalTermPickerModal
|
||
v-model="showTcmPicker"
|
||
:title="tcmPickerTitle"
|
||
:options="tcmPickerList"
|
||
:selected-id="tcmPickerCurrentSelectedId"
|
||
@confirm="handleTcmPickerConfirm"
|
||
/>
|
||
|
||
<!-- 诊断选择弹窗 -->
|
||
<DiagnosisModal
|
||
v-model="showDiagnosisModal"
|
||
:selectedDiagnosis="diagnosisText"
|
||
:salesperson-transfer-mode="isSalespersonTransferMode"
|
||
@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"
|
||
:register-id="registerId"
|
||
:see-rate="seeRate"
|
||
:salesperson-transfer-mode="isSalespersonTransferMode"
|
||
:show-drug-price="showSalespersonTransferPrice"
|
||
@select="handleSelectChineseDrug"
|
||
/>
|
||
|
||
<TransferPatientDrawer
|
||
v-model="showTransferPatientDrawer"
|
||
:submitting="transferDrawerSubmitting"
|
||
ref="transferPatientDrawer"
|
||
@confirm="handleTransferPatientConfirm"
|
||
/>
|
||
|
||
<!-- 简单产品选择弹窗 -->
|
||
<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>
|
||
|
||
<order-price-percent-adjust-popup
|
||
:visible="priceAdjustVisible"
|
||
:current-discount="priceDiscount"
|
||
:quick-options="priceAdjustQuickOptions"
|
||
@close="closePreSendPriceAdjust"
|
||
@confirm="onPreSendPriceAdjustConfirm"
|
||
/>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
// 注意:这部分保持你原有的逻辑代码,不进行任何修改,确保业务完全正常
|
||
import {
|
||
addWestPrescription,
|
||
checkChineseMedicineConflictApi,
|
||
getDiseaseList,
|
||
getDrugUseList,
|
||
getProductListDoctorReception,
|
||
getPatientInfoByPatientId,
|
||
getPatientItem,
|
||
applySpecialPrescriptionApi,
|
||
getProcessRuleList,
|
||
getCommonPrescriptionListApi,
|
||
saveWestCommonPrescriptionApi,
|
||
saveChineseCommonPrescriptionApi,
|
||
getCurrentStoreTypeApi,
|
||
getPriceAdjustConfigApi,
|
||
getSalespersonTransferByRegisterApi,
|
||
getPrescriptionInfoApi,
|
||
getTraditionalChineseMedicineJson
|
||
} from '@/api/reception.js';
|
||
import { parseTransferPrescriptionContent } from '@/subPackages/sub_online_reception/utils/transferPrescriptionImport.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';
|
||
import TransferPatientDrawer from './components/modals/TransferPatientDrawer.vue';
|
||
import OrderPricePercentAdjustPopup from '@/subPackages/sub_business_shared/components/OrderPricePercentAdjustPopup.vue';
|
||
import { applyRatioToDrugs, formatPriceDiscountLabel, normalizeQuickOptions } from '@/subPackages/sub_business_shared/common/pricePercentAdjust.js';
|
||
import {
|
||
createClinicSalespersonTransferPrescription,
|
||
getClinicSalespersonSeePriceConfig,
|
||
getClinicSalespersonProcessRuleList,
|
||
} from '@/api/clinicSalesperson.js';
|
||
import {
|
||
pickSpecialPrescriptionRecord,
|
||
applySpecialPrescriptionPayload,
|
||
resolveSpecialPrescriptionPurchaseLabel,
|
||
clearAppliedSpecialPrescription,
|
||
isSpecialPrescriptionCartLocked,
|
||
guardSpecialPrescriptionCartEdit,
|
||
} from './utils/specialPrescription.js';
|
||
|
||
const PENDING_RX_FROM_CHAT = 'xk_pending_rx_from_chat';
|
||
const SALESPERSON_TRANSFER_STORAGE_KEY = 'salesperson_transfer';
|
||
const SALESPERSON_HOME_URL = '/subPackages/sub_clinic_salesperson/home/index';
|
||
|
||
/** 与 closeTopOverlayIfAny 一致:任意为 true 时启用微信小程序 page-container 返回拦截 */
|
||
const PRESCRIPTION_OVERLAY_KEYS = [
|
||
'showWesternUsageModal',
|
||
'showTcmPicker',
|
||
'showWesternMedicineModal',
|
||
'showChineseMedicineModal',
|
||
'showSimpleProductModal',
|
||
'showCommonPrescriptionModal',
|
||
'showDiagnosisModal',
|
||
'showDoctorOrderModal',
|
||
'showSaveCommonPrescriptionModal',
|
||
'showTransferPatientDrawer'
|
||
];
|
||
|
||
export default {
|
||
name: 'PrescriptionV2',
|
||
components: {
|
||
DiagnosisModal,
|
||
DoctorOrderModal,
|
||
CommonPrescriptionModal,
|
||
WesternMedicineModal,
|
||
ChineseMedicineModal,
|
||
SimpleProductModal,
|
||
WesternMedicineUsageModal,
|
||
ChineseMedicineConfig,
|
||
TraditionalTermPickerModal,
|
||
TransferPatientDrawer,
|
||
OrderPricePercentAdjustPopup,
|
||
},
|
||
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,
|
||
feeCategory: 1,
|
||
salespersonTransferPrescriptionId: 0,
|
||
hasSalespersonTransfer: false,
|
||
/** 是否可查看毛利率 0/1(xk-api see_rate) */
|
||
seeRate: 0,
|
||
enableOrderPricePercentAdjust: 0,
|
||
priceAdjustVisible: false,
|
||
priceDiscount: 100,
|
||
priceAdjustQuickOptions: [],
|
||
priceAdjustScopeMode: 'sale_only',
|
||
sendMode: 0,
|
||
selectedStoreId: null,
|
||
registerOrderType: null,
|
||
specialPrescriptionRecord: null,
|
||
applyingSpecialPrescription: false,
|
||
pendingImportSpecial: false,
|
||
/** 医生已导入的特色方 ID,仅 >0 时提交走特色方计价 */
|
||
appliedSpecialPrescriptionId: 0,
|
||
appliedSpecialPrescriptionFreeShipping: false,
|
||
/** 特色方 apply 返回的套餐/贴数总价,用于底部合计 */
|
||
appliedSpecialPrescriptionExpectedTotal: 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'
|
||
},
|
||
/** 微信小程序 page-container:有抽屉/弹层时为 true,拦截侧滑等返回 */
|
||
pageBackGuardShow: false,
|
||
/** 程序化隐藏 page-container 时抑制 @leave,避免误触发页面退出确认 */
|
||
_suppressPageBackGuardLeave: false,
|
||
/** 推广员传方模式 */
|
||
isSalespersonTransferMode: false,
|
||
/** 推广员是否可查看售价 0/1(门店 salesperson see_price) */
|
||
salespersonSeePrice: 0,
|
||
showTransferPatientDrawer: false,
|
||
transferDrawerSubmitting: false,
|
||
};
|
||
},
|
||
computed: {
|
||
allowInsuranceCategory() {
|
||
return Number(this.registerStoreInfo?.allow_insurance_category ?? 0) === 1;
|
||
},
|
||
canPreSendPriceAdjust() {
|
||
return Number(this.enableOrderPricePercentAdjust) === 1
|
||
&& this.currentDrugs.length > 0
|
||
&& !this.isSpecialPrescriptionCartLocked;
|
||
},
|
||
preSendDiscountLabel() {
|
||
return formatPriceDiscountLabel(this.priceDiscount);
|
||
},
|
||
effectivePriceAdjustStoreId() {
|
||
return this.selectedStoreId
|
||
|| this.registerStoreInfo?.store_id
|
||
|| uni.getStorageSync('store_id')
|
||
|| null;
|
||
},
|
||
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 expected = this.appliedSpecialPrescriptionExpectedTotal;
|
||
if (expected != null && !Number.isNaN(Number(expected)) && Number(expected) > 0) {
|
||
const base = parseFloat(expected);
|
||
const fee = parseFloat(this.treatmentPrice || 0);
|
||
const process = this.activeCategory === 1 ? parseFloat(this.processingFee || 0) : 0;
|
||
return (base + fee + process).toFixed(2);
|
||
}
|
||
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);
|
||
},
|
||
grossMarginText() {
|
||
if (this.activeCategory !== 1 || Number(this.seeRate) !== 1) {
|
||
return '';
|
||
}
|
||
return PrescriptionCalculator.calculateChineseTotalGrossMarginPercent(
|
||
this.currentDrugs,
|
||
this.chineseConfig.dosage
|
||
);
|
||
},
|
||
showSalespersonTransferPrice() {
|
||
return !this.isSalespersonTransferMode || Number(this.salespersonSeePrice) === 1;
|
||
},
|
||
isTransferFeeHidden() {
|
||
return this.isSalespersonTransferMode && Number(this.salespersonSeePrice) === 0;
|
||
},
|
||
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 ? '当前:在线复诊开方(提交后将向患者发送处方消息)' : '当前:线下开方';
|
||
},
|
||
hasSpecialPrescriptionRecord() {
|
||
return !!this.specialPrescriptionRecord;
|
||
},
|
||
/** 导入卡片:SKU 名或单剂 */
|
||
specialPrescriptionPurchaseLabel() {
|
||
return resolveSpecialPrescriptionPurchaseLabel(this.specialPrescriptionRecord);
|
||
},
|
||
/** 已导入特色方时锁定药方不可编辑 */
|
||
isSpecialPrescriptionCartLocked() {
|
||
return isSpecialPrescriptionCartLocked(this);
|
||
},
|
||
/** 底部发送按钮宽度(左侧仅「另存常用方」时需留出空间) */
|
||
bottomSendBtnWidth() {
|
||
if (this.isSalespersonTransferMode || this.isCommonPrescription) {
|
||
return '686rpx';
|
||
}
|
||
if (this.supportsCommonPrescriptionTemplate) {
|
||
return '400rpx';
|
||
}
|
||
return '686rpx';
|
||
},
|
||
navbarTitle() {
|
||
if (this.isSalespersonTransferMode) {
|
||
return '传方';
|
||
}
|
||
if (this.registerOrderType === null || this.registerOrderType === undefined || this.registerOrderType === '') {
|
||
return '开方';
|
||
}
|
||
return this.isOnlineRevisit ? '开方 · 在线复诊' : '开方 · 线下';
|
||
},
|
||
hasTransferDraft() {
|
||
if (!this.isSalespersonTransferMode) return false;
|
||
return this.currentDrugs.length > 0
|
||
|| this.diagnoses.length > 0
|
||
|| !!(this.medicalAdvice && String(this.medicalAdvice).trim());
|
||
},
|
||
shouldEnablePageBackGuard() {
|
||
return this.hasPrescriptionOverlay;
|
||
},
|
||
scrollStyle() {
|
||
try {
|
||
const sys = uni.getSystemInfoSync();
|
||
const rpxRatio = sys.windowWidth / 750;
|
||
const topRpx = this.isSalespersonTransferMode ? 500 : 600;
|
||
const bottomRpx = 200;
|
||
const heightPx = sys.windowHeight - topRpx * rpxRatio - bottomRpx * rpxRatio;
|
||
return {
|
||
height: `${Math.max(Math.floor(heightPx), 200)}px`,
|
||
marginBottom: '200rpx',
|
||
};
|
||
} catch (e) {
|
||
const topRpx = this.isSalespersonTransferMode ? 500 : 600;
|
||
return {
|
||
height: `calc(100vh - ${topRpx}rpx)`,
|
||
marginBottom: '200rpx',
|
||
};
|
||
}
|
||
},
|
||
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
|
||
shouldEnablePageBackGuard(val) {
|
||
this.setPageBackGuardShow(!!val, { suppressLeave: !val });
|
||
this.syncSalespersonTransferUnloadAlert();
|
||
},
|
||
hasTransferDraft() {
|
||
this.syncSalespersonTransferUnloadAlert();
|
||
},
|
||
// #endif
|
||
},
|
||
created() {
|
||
// u-navbar 在小程序内 bind($parent) 可能拿不到页面实例,用箭头函数固定 this
|
||
this.boundCustomBack = () => this.handleCustomBack();
|
||
},
|
||
onLoad(options) {
|
||
this.isSalespersonTransferMode = String(options.salesperson_transfer) === '1';
|
||
if (this.isSalespersonTransferMode) {
|
||
this.registerId = SALESPERSON_TRANSFER_STORAGE_KEY;
|
||
this._presetActiveCategory = 1;
|
||
} else {
|
||
this.registerId = options.register_id || '';
|
||
}
|
||
this.patientId = options.patient_id || '';
|
||
this.pendingReusePrescriptionId = options.reuse_prescription_id ? String(options.reuse_prescription_id) : '';
|
||
this.pendingImportSpecial = String(options.import_special) === '1';
|
||
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.isSalespersonTransferMode && this.activeCategory === 1) {
|
||
await this.checkAndShowTransferTip();
|
||
}
|
||
},
|
||
onUnload() {
|
||
if (this.isCommonPrescription) {
|
||
uni.removeStorageSync('add');
|
||
}
|
||
// #ifdef MP-WEIXIN
|
||
if (this.isSalespersonTransferMode) {
|
||
uni.disableAlertBeforeUnload();
|
||
}
|
||
// #endif
|
||
},
|
||
methods: {
|
||
// #ifdef MP-WEIXIN
|
||
setPageBackGuardShow(show, { suppressLeave = false } = {}) {
|
||
if (suppressLeave) this._suppressPageBackGuardLeave = true;
|
||
this.pageBackGuardShow = !!show;
|
||
},
|
||
syncSalespersonTransferUnloadAlert() {
|
||
if (!this.isSalespersonTransferMode) return;
|
||
if (this.hasTransferDraft && !this.hasPrescriptionOverlay) {
|
||
uni.enableAlertBeforeUnload({ message: '有未提交的传方内容,确定退出?' });
|
||
} else {
|
||
uni.disableAlertBeforeUnload();
|
||
}
|
||
},
|
||
// #endif
|
||
async initializePageData() {
|
||
try {
|
||
this.restoreFromLocalStorage();
|
||
if (this.isSalespersonTransferMode) {
|
||
await this.loadSalespersonTransferConfig();
|
||
await this.loadBasicConfigDataForTransfer();
|
||
} else {
|
||
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();
|
||
}
|
||
if (!this.isSalespersonTransferMode) {
|
||
await this.maybeApplyReusePrescription();
|
||
if (this.activeCategory === 1) await this.checkAndShowTransferTip();
|
||
this.applyPendingExperienceDrugFromChat();
|
||
if (this.pendingImportSpecial && this.hasSpecialPrescriptionRecord) {
|
||
await this.handleApplySpecialPrescription();
|
||
this.pendingImportSpecial = false;
|
||
}
|
||
}
|
||
// #ifdef MP-WEIXIN
|
||
this.$nextTick(() => {
|
||
this.setPageBackGuardShow(this.shouldEnablePageBackGuard);
|
||
this.syncSalespersonTransferUnloadAlert();
|
||
});
|
||
// #endif
|
||
} catch (error) {
|
||
console.error('初始化页面数据失败:', error);
|
||
this.$toast('初始化失败,请重试');
|
||
}
|
||
},
|
||
async loadSalespersonTransferConfig() {
|
||
try {
|
||
const wrap = await getClinicSalespersonSeePriceConfig();
|
||
if (wrap && wrap.ok) {
|
||
this.salespersonSeePrice = Number(wrap.data?.see_price ?? 0);
|
||
}
|
||
} catch (error) {
|
||
console.error('获取推广员价格配置失败:', error);
|
||
}
|
||
},
|
||
async loadBasicConfigDataForTransfer() {
|
||
try {
|
||
if (this.activeCategory === 1 && this.processRuleList.length === 0) {
|
||
await this.loadProcessRuleList(0, 0);
|
||
}
|
||
} catch (error) {
|
||
console.error('加载基础配置数据失败:', error);
|
||
}
|
||
},
|
||
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;
|
||
this.specialPrescriptionRecord = 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;
|
||
}
|
||
this.specialPrescriptionRecord = pickSpecialPrescriptionRecord(data);
|
||
} catch (e) {
|
||
console.warn(e);
|
||
this.registerOrderType = null;
|
||
this.specialPrescriptionRecord = 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);
|
||
}
|
||
},
|
||
getChineseItemMargin(drug) {
|
||
if (Number(this.seeRate) !== 1) {
|
||
return '';
|
||
}
|
||
return PrescriptionCalculator.calculateItemGrossMarginPercent(
|
||
drug.price,
|
||
drug.buy_price
|
||
);
|
||
},
|
||
async loadPriceAdjustConfigForStore(storeId) {
|
||
try {
|
||
const res = await getPriceAdjustConfigApi(storeId);
|
||
if (res) {
|
||
this.priceAdjustScopeMode = res.order_price_adjust_scope === 'both' ? 'both' : 'sale_only';
|
||
this.priceAdjustQuickOptions = normalizeQuickOptions(res.order_discount_quick_options);
|
||
if (res.enable_order_price_percent_adjust != null) {
|
||
this.enableOrderPricePercentAdjust = Number(res.enable_order_price_percent_adjust);
|
||
}
|
||
}
|
||
} catch (e) {
|
||
console.error('获取调价配置失败:', e);
|
||
}
|
||
},
|
||
snapshotDrugOrigins(drugs) {
|
||
return (drugs || []).map((drug) => ({
|
||
...drug,
|
||
origin_price: drug.origin_price ?? drug.price,
|
||
origin_buy_price: drug.origin_buy_price ?? drug.buy_price,
|
||
}));
|
||
},
|
||
prepareDrugForCart(drug) {
|
||
const [prepared] = applyRatioToDrugs(
|
||
this.snapshotDrugOrigins([drug]),
|
||
this.priceDiscount,
|
||
this.priceAdjustScopeMode,
|
||
);
|
||
return prepared;
|
||
},
|
||
applyPreSendPriceDiscount(discount) {
|
||
this.priceDiscount = discount;
|
||
const scope = this.priceAdjustScopeMode;
|
||
this.currentDrugs = applyRatioToDrugs(this.snapshotDrugOrigins(this.currentDrugs), discount, scope);
|
||
uni.showToast({ title: discount === 100 ? '已清除浮动' : '调价成功', icon: 'none' });
|
||
},
|
||
clearPreSendPriceDiscount() {
|
||
if (guardSpecialPrescriptionCartEdit(this)) return;
|
||
this.applyPreSendPriceDiscount(100);
|
||
},
|
||
openPreSendOrderPriceAdjust() {
|
||
if (guardSpecialPrescriptionCartEdit(this)) return;
|
||
if (!this.canPreSendPriceAdjust) return;
|
||
this.currentDrugs = this.snapshotDrugOrigins(this.currentDrugs);
|
||
this.priceAdjustVisible = true;
|
||
},
|
||
closePreSendPriceAdjust() {
|
||
this.priceAdjustVisible = false;
|
||
},
|
||
onPreSendPriceAdjustConfirm(payload) {
|
||
this.applyPreSendPriceDiscount(payload.priceDiscount);
|
||
this.closePreSendPriceAdjust();
|
||
},
|
||
async fetchStoreSeeRate() {
|
||
try {
|
||
const storeId = uni.getStorageSync('store_id');
|
||
const params = {};
|
||
if (storeId) {
|
||
params.store_id = storeId;
|
||
}
|
||
if (this.registerId) {
|
||
params.register_id = this.registerId;
|
||
}
|
||
if (!params.store_id && !params.register_id) {
|
||
return;
|
||
}
|
||
const res = await getCurrentStoreTypeApi(params);
|
||
if (res) {
|
||
this.seeRate = Number(res.see_rate ?? 0);
|
||
this.enableOrderPricePercentAdjust = Number(res.enable_order_price_percent_adjust ?? 0);
|
||
await this.loadPriceAdjustConfigForStore(params.store_id || storeId);
|
||
}
|
||
} catch (error) {
|
||
console.error('获取毛利率权限失败:', error);
|
||
}
|
||
},
|
||
async loadRegisterStoreInfo() {
|
||
if (!this.registerId) {
|
||
await this.fetchStoreSeeRate();
|
||
return;
|
||
}
|
||
try {
|
||
const storeId = uni.getStorageSync('store_id');
|
||
const res = await getCurrentStoreTypeApi({
|
||
register_id: this.registerId,
|
||
...(storeId ? { store_id: storeId } : {})
|
||
});
|
||
if (res) {
|
||
this.registerStoreInfo = res;
|
||
this.seeRate = Number(res.see_rate ?? 0);
|
||
if (Number(res.allow_insurance_category ?? 0) !== 1) {
|
||
this.feeCategory = 1;
|
||
}
|
||
this.checkSalespersonTransfer();
|
||
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;
|
||
}
|
||
const priceStoreId = this.selectedStoreId || res.store_id || storeId;
|
||
this.enableOrderPricePercentAdjust = Number(res.enable_order_price_percent_adjust ?? 0);
|
||
await this.loadPriceAdjustConfigForStore(priceStoreId);
|
||
}
|
||
} catch (error) {
|
||
console.error('获取挂号诊所信息失败:', error);
|
||
}
|
||
},
|
||
async checkSalespersonTransfer() {
|
||
if (!this.registerId) {
|
||
this.hasSalespersonTransfer = false;
|
||
return;
|
||
}
|
||
try {
|
||
const res = await getSalespersonTransferByRegisterApi(this.registerId);
|
||
const list = res?.result || res?.data || res;
|
||
this.hasSalespersonTransfer = Array.isArray(list) && list.length > 0;
|
||
} catch {
|
||
this.hasSalespersonTransfer = false;
|
||
}
|
||
},
|
||
async openSalespersonTransfer() {
|
||
try {
|
||
const res = await getSalespersonTransferByRegisterApi(this.registerId);
|
||
const list = res?.result || res?.data || res;
|
||
if (!Array.isArray(list) || !list.length) {
|
||
this.$toast('暂无待导入传方');
|
||
return;
|
||
}
|
||
const item = list[0];
|
||
const parsed = parseTransferPrescriptionContent(item);
|
||
if (!parsed || !parsed.drugList?.length) {
|
||
this.$toast('传方数据无效');
|
||
return;
|
||
}
|
||
this.salespersonTransferPrescriptionId = item.id;
|
||
this.activeCategory = 1;
|
||
parsed.drugList.forEach((drug) => {
|
||
this.currentDrugs.push(this.prepareDrugForCart({
|
||
index_id: drug.index_id ?? drug.drug_id ?? drug.id,
|
||
id: drug.drug_id || drug.id,
|
||
drug_id: drug.drug_id || drug.id,
|
||
drug_name: drug.drug_name || drug.name,
|
||
name: drug.drug_name || drug.name,
|
||
number: drug.number || 1,
|
||
way_id: drug.way_id || 0,
|
||
price: drug.price ?? 0,
|
||
buy_price: drug.buy_price,
|
||
}));
|
||
});
|
||
if (parsed.clinical_diagnose) {
|
||
this.diagnoses = [{ id: Date.now(), name: parsed.clinical_diagnose }];
|
||
}
|
||
if (parsed.doctor_order) this.medicalAdvice = parsed.doctor_order;
|
||
this.saveToLocalStorage();
|
||
this.$toast('传方已导入');
|
||
} catch (e) {
|
||
console.error(e);
|
||
this.$toast('加载传方失败');
|
||
}
|
||
},
|
||
async handleSwitchCategory(category) {
|
||
this.saveToLocalStorage();
|
||
this.activeCategory = category;
|
||
this.loadCurrentCategoryDrugs();
|
||
if (category === 1) {
|
||
await this.checkSalespersonTransfer();
|
||
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 handleApplySpecialPrescription() {
|
||
if (!this.registerId || this.applyingSpecialPrescription) return;
|
||
this.applyingSpecialPrescription = true;
|
||
try {
|
||
const res = await applySpecialPrescriptionApi({ register_id: this.registerId });
|
||
const data = res.result || res.data || res;
|
||
applySpecialPrescriptionPayload(this, data);
|
||
await this.loadRegisterOrderType();
|
||
this.$toast(`已导入特色方:${data.special_prescription_name || ''}`);
|
||
if (data.price_hint) {
|
||
uni.showModal({
|
||
title: '价格提示',
|
||
content: data.price_hint,
|
||
showCancel: false,
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('导入特色方失败:', error);
|
||
this.$toast('导入特色方失败,请稍后重试');
|
||
} finally {
|
||
this.applyingSpecialPrescription = false;
|
||
}
|
||
},
|
||
async handleSelectCommonPrescription(item) {
|
||
try {
|
||
clearAppliedSpecialPrescription(this);
|
||
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(this.prepareDrugForCart(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(this.prepareDrugForCart({ ...product }));
|
||
added++;
|
||
}
|
||
this.saveToLocalStorage();
|
||
if (added > 0) {
|
||
this.$toast(`已添加 ${added} 味药`);
|
||
} else {
|
||
this.$toast('药品已在列表中');
|
||
}
|
||
},
|
||
handleOpenWesternMedicineModal() {
|
||
if (guardSpecialPrescriptionCartEdit(this)) return;
|
||
this.westernModalInitialKeyword = '';
|
||
this.showWesternMedicineModal = true;
|
||
},
|
||
handleSelectWesternDrug(drug) {
|
||
if (guardSpecialPrescriptionCartEdit(this)) return;
|
||
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(this.prepareDrugForCart(newDrug));
|
||
const index = this.currentDrugs.length - 1;
|
||
this.handleEditWesternDrug(this.currentDrugs[index], index);
|
||
this.saveToLocalStorage();
|
||
this.$toast(`已添加 ${newDrug.drug_name}`);
|
||
},
|
||
handleOpenChineseMedicineModal() {
|
||
if (guardSpecialPrescriptionCartEdit(this)) return;
|
||
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) {
|
||
if (guardSpecialPrescriptionCartEdit(this)) return;
|
||
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) {
|
||
if (guardSpecialPrescriptionCartEdit(this)) return;
|
||
this.currentDrugs = applyRatioToDrugs(
|
||
this.snapshotDrugOrigins(drugs || []),
|
||
this.priceDiscount,
|
||
this.priceAdjustScopeMode,
|
||
);
|
||
this.saveToLocalStorage();
|
||
},
|
||
handleOpenSimpleProductModal() {
|
||
if (guardSpecialPrescriptionCartEdit(this)) return;
|
||
this.showSimpleProductModal = true;
|
||
},
|
||
handleSelectSimpleProduct(product) {
|
||
if (guardSpecialPrescriptionCartEdit(this)) return;
|
||
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(this.prepareDrugForCart(newProduct));
|
||
this.saveToLocalStorage();
|
||
this.$toast(`已添加 ${newProduct.drug_name}`);
|
||
},
|
||
handleEditWesternDrug(drug, index) {
|
||
if (guardSpecialPrescriptionCartEdit(this)) return;
|
||
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) {
|
||
if (guardSpecialPrescriptionCartEdit(this)) return;
|
||
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() {
|
||
if (guardSpecialPrescriptionCartEdit(this)) return;
|
||
uni.showModal({
|
||
title: '清空药材',
|
||
content: '确定要清空所有中药材吗?',
|
||
confirmColor: '#FC3636',
|
||
success: ({ confirm }) => {
|
||
if (confirm) {
|
||
this.currentDrugs = [];
|
||
this.saveToLocalStorage();
|
||
}
|
||
}
|
||
});
|
||
},
|
||
async handleUpdateChineseConfig(config) {
|
||
if (guardSpecialPrescriptionCartEdit(this)) return;
|
||
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 };
|
||
let list = [];
|
||
if (this.isSalespersonTransferMode) {
|
||
const wrap = await getClinicSalespersonProcessRuleList(data);
|
||
if (wrap && wrap.ok) {
|
||
list = Array.isArray(wrap.data) ? wrap.data : [];
|
||
}
|
||
} else {
|
||
const res = await getProcessRuleList(data);
|
||
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; }
|
||
|
||
if (this.isSalespersonTransferMode) {
|
||
this.showTransferPatientDrawer = true;
|
||
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: this.feeCategory, 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,
|
||
salesperson_transfer_prescription_id: this.salespersonTransferPrescriptionId || undefined,
|
||
price_discount: this.priceDiscount,
|
||
special_prescription_id: Number(this.appliedSpecialPrescriptionId) || 0,
|
||
};
|
||
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;
|
||
clearAppliedSpecialPrescription(this);
|
||
},
|
||
/**
|
||
* 清空药方(含特色方导入状态),与 PC 接诊「清空药方」一致
|
||
*/
|
||
handleClearPrescriptionCart() {
|
||
const hasContent = this.currentDrugs.length > 0
|
||
|| this.diagnoses.length > 0
|
||
|| !!(this.diagnosisText && String(this.diagnosisText).trim())
|
||
|| !!(this.medicalAdvice && String(this.medicalAdvice).trim())
|
||
|| Number(this.appliedSpecialPrescriptionId) > 0;
|
||
if (!hasContent) {
|
||
this.$toast('当前无药方内容');
|
||
return;
|
||
}
|
||
uni.showModal({
|
||
title: '清空药方',
|
||
content: '确定清空当前药方吗?特色方将需重新导入。',
|
||
confirmColor: '#FC3636',
|
||
success: ({ confirm }) => {
|
||
if (!confirm) return;
|
||
this.clearPrescriptionData();
|
||
this.saveToLocalStorage();
|
||
PrescriptionStorage.clearAllPrescriptionData(this.registerId);
|
||
this.$toast('已清空药方');
|
||
},
|
||
});
|
||
},
|
||
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('保存常用方失败,请重试'); }
|
||
},
|
||
buildSalespersonTransferPayload(patientData) {
|
||
const clinicalDiagnose = this.diagnosisText || this.diagnoses.map((item) => item.name).join(',');
|
||
const drugs = this.currentDrugs.map((drug) => ({
|
||
drug_id: drug.id || drug.drug_id || drug.index_id,
|
||
drug_name: drug.drug_name || drug.name,
|
||
number: drug.number || drug._quantity || 1,
|
||
way_id: drug.way_id || 0,
|
||
}));
|
||
return {
|
||
patient_name: patientData.patient_name,
|
||
patient_mobile: patientData.patient_mobile,
|
||
patient_address: patientData.patient_address,
|
||
prescription_images: patientData.prescription_images || [],
|
||
clinical_diagnose: clinicalDiagnose,
|
||
doctor_order: this.medicalAdvice || '',
|
||
dosage: this.chineseConfig.dosage || 7,
|
||
day_dosage: this.chineseConfig.dayDosage || 2,
|
||
drugs,
|
||
};
|
||
},
|
||
async handleTransferPatientConfirm(patientData) {
|
||
this.transferDrawerSubmitting = true;
|
||
try {
|
||
const wrap = await createClinicSalespersonTransferPrescription(
|
||
this.buildSalespersonTransferPayload(patientData)
|
||
);
|
||
if (wrap && wrap.ok) {
|
||
PrescriptionStorage.clearAllPrescriptionData(SALESPERSON_TRANSFER_STORAGE_KEY);
|
||
this.showTransferPatientDrawer = false;
|
||
if (this.$refs.transferPatientDrawer && this.$refs.transferPatientDrawer.resetForm) {
|
||
this.$refs.transferPatientDrawer.resetForm();
|
||
}
|
||
// #ifdef MP-WEIXIN
|
||
this.setPageBackGuardShow(false, { suppressLeave: true });
|
||
uni.disableAlertBeforeUnload();
|
||
// #endif
|
||
this.$toast('提交成功');
|
||
setTimeout(() => {
|
||
uni.navigateTo({ url: '/subPackages/sub_clinic_salesperson/transfer-prescription/list' });
|
||
}, 500);
|
||
} else {
|
||
this.$toast(wrap?.res?.msg || wrap?.res?.message || '提交失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('提交传方失败:', error);
|
||
this.$toast('提交传方失败,请重试');
|
||
} finally {
|
||
this.transferDrawerSubmitting = false;
|
||
}
|
||
},
|
||
tryLeaveSalespersonTransferPage(onConfirm) {
|
||
if (this.hasTransferDraft) {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '有未提交的传方内容,确定退出?',
|
||
success: ({ confirm }) => {
|
||
if (confirm) {
|
||
// #ifdef MP-WEIXIN
|
||
this.setPageBackGuardShow(false, { suppressLeave: true });
|
||
uni.disableAlertBeforeUnload();
|
||
// #endif
|
||
if (typeof onConfirm === 'function') onConfirm();
|
||
} else {
|
||
// #ifdef MP-WEIXIN
|
||
this.setPageBackGuardShow(this.shouldEnablePageBackGuard, {
|
||
suppressLeave: !this.shouldEnablePageBackGuard,
|
||
});
|
||
// #endif
|
||
}
|
||
},
|
||
});
|
||
return;
|
||
}
|
||
// #ifdef MP-WEIXIN
|
||
this.setPageBackGuardShow(false, { suppressLeave: true });
|
||
uni.disableAlertBeforeUnload();
|
||
// #endif
|
||
if (typeof onConfirm === 'function') onConfirm();
|
||
},
|
||
navigateToSalespersonWorkbench() {
|
||
const pages = getCurrentPages();
|
||
if (pages.length > 1) {
|
||
this.safeNavigateBack(0);
|
||
return;
|
||
}
|
||
// #ifdef MP-WEIXIN
|
||
this.setPageBackGuardShow(false, { suppressLeave: true });
|
||
uni.disableAlertBeforeUnload();
|
||
// #endif
|
||
uni.reLaunch({ url: SALESPERSON_HOME_URL });
|
||
},
|
||
/** 若有弹层打开则关闭第一个并返回 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.setPageBackGuardShow(false, { suppressLeave: true });
|
||
setTimeout(() => {
|
||
uni.navigateBack();
|
||
}, 16);
|
||
// #endif
|
||
// #ifndef MP-WEIXIN
|
||
uni.navigateBack();
|
||
// #endif
|
||
};
|
||
if (delayMs > 0) {
|
||
setTimeout(runNav, delayMs);
|
||
} else {
|
||
runNav();
|
||
}
|
||
},
|
||
// #ifdef MP-WEIXIN
|
||
onPageBackGuardLeave() {
|
||
if (this._suppressPageBackGuardLeave) {
|
||
this._suppressPageBackGuardLeave = false;
|
||
return;
|
||
}
|
||
if (this.closeTopOverlayIfAny()) {
|
||
this.$nextTick(() => {
|
||
this.setPageBackGuardShow(this.shouldEnablePageBackGuard, { suppressLeave: true });
|
||
this.syncSalespersonTransferUnloadAlert();
|
||
});
|
||
return;
|
||
}
|
||
this.setPageBackGuardShow(false);
|
||
if (this.isSalespersonTransferMode) {
|
||
this.tryLeaveSalespersonTransferPage(() => this.navigateToSalespersonWorkbench());
|
||
return;
|
||
}
|
||
this.safeNavigateBack(0);
|
||
},
|
||
// #endif
|
||
handleCustomBack() {
|
||
if (this.closeTopOverlayIfAny()) return;
|
||
if (this.isSalespersonTransferMode) {
|
||
this.tryLeaveSalespersonTransferPage(() => this.navigateToSalespersonWorkbench());
|
||
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; }
|
||
.price-link { color: #6ACDBB; text-decoration: underline; }
|
||
.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;
|
||
}
|
||
.tcm-margin {
|
||
font-size: 22rpx;
|
||
color: #ff9800;
|
||
margin-left: 8rpx;
|
||
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;
|
||
}
|
||
.special-rx-card {
|
||
padding: 20rpx 24rpx;
|
||
background: #fffaf5;
|
||
border-radius: 12rpx;
|
||
border: 1rpx solid #ffe0c2;
|
||
}
|
||
.special-rx-card__inner {
|
||
width: 100%;
|
||
}
|
||
.special-rx-card__action {
|
||
width: 100%;
|
||
}
|
||
.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;
|
||
}
|
||
.btnText--danger {
|
||
color: #FC3636;
|
||
}
|
||
</style> |