hn-hlw-app/pages/consult/drug-purchase-order/drug-purchase-order.vue
2026-07-27 11:26:39 +08:00

358 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<full-page v-if="order" pageStyle="background:#f5f5f5">
<view :style="elderVarStyle">
<view class="bg-white flex items-center p-15 shadow-lg" @click="showAddressPopup()">
<view class="w-0 flex-grow flex mr-10">
<uni-icons class="flex-shrink-0 mr-10" type="location" size="32" :color="themeColor"></uni-icons>
<view v-if="address">
<view class="text-base text-dark leading-normal">{{ address.region.join(' ') }} {{ address.address }}</view>
<view class="text-base text-dark">{{ address.name }} {{ address.phone }}</view>
</view>
<view v-else class="text-base text-gray">请选择收货地址</view>
</view>
<uni-icons v-if="enableChangeAddress" class="flex-shrinl-0" type="arrowright" size="20"
color="#999"></uni-icons>
</view>
<view class="mt-15 bg-white shadow-lg">
<view class="flex justify-between items-center py-10 px-15 border-b">
<view class="flex-shrink-0 mr-10 text-base text-gray">配送方式</view>
<view v-if="address" class="flex items-center">
<view v-if="fengNiaoAvailable" class="flex items-center mr-10" @click="toggleShippingType('fengniao')">
<uni-icons :type="shippingType === 'fengniao' ? 'circle-filled' : 'circle'" size="20"
:color="themeColor"></uni-icons>
<view class="radio-text text-base text-dark">骑手配送</view>
</view>
<view class="flex items-center mr-10" @click="toggleShippingType('ems')">
<uni-icons :type="shippingType === 'ems' ? 'circle-filled' : 'circle'" size="20"
:color="themeColor"></uni-icons>
<view class="radio-text text-base text-dark">快递邮寄</view>
</view>
</view>
<view v-else class="text-base text-gray">请选择收货地址</view>
</view>
<view v-if="address" class="flex justify-between items-center py-10 px-15 border-b">
<view>
<text class="text-base text-gray">运费</text>
<text v-if="shippingInfo.shippingDiscount > 0" class="text-base text-gray">
(立减¥{{ countDetails.shippingDiscount }}
</text>
</view>
<view class="text-base text-danger">¥{{ countDetails.shippingFee }}</view>
</view>
</view>
<view class="mt-15 bg-white shadow-lg">
<view v-for="(med, idx) in order.drugs" class="px-15" :class="idx === order.drugs.length - 1 ? 'border-b' : ''">
<view class="flex justify-between py-10">
<view class="mr-15 text-base font-semibold">{{ med.drugName }}</view>
<view class="flex-shrink-0 text-base text-danger">¥{{ med.price }}</view>
</view>
<view class="flex pb-10">
<view class="flex-grow mr-10 w-0 truncate text-sm text-gray">规格:{{ med.spec }}</view>
<view class="flex-shrink-0 text-sm text-gray">x{{ med.quantity }}</view>
</view>
</view>
<view class="flex justify-between py-10 px-15">
<view class="text-base text-dark">药费合计:</view>
<view class="text-base text-danger">¥{{ countDetails.drugFee }}</view>
</view>
</view>
<view class="mt-12 bg-white shadow-lg flex justify-between py-10 px-15">
<view class="text-base text-dark">互联网诊查费:</view>
<view class="text-base text-danger">¥{{ countDetails.regFee }}</view>
</view>
<view style="height: 160rpx;"></view>
</view>
<template #footer>
<view class="relative px-15 bg-white leading-normal shadow-up" :style="elderVarStyle">
<view v-if="shippingInfo.shippingFee > 0 && address" class="pt-12">
<view>
<text class="mr-5 text-base text-dark">您将会分</text>
<text class="mr-5 text-base text-danger"> 2 </text>
<text class="text-base text-dark">次进行支付</text>
</view>
<view class="pt-5">
<text class="mr-5 text-base text-dark">第一笔: 药费+互联网诊查费</text>
<text class="mr-5 text-base text-danger"> ¥{{ countDetails.ybFee }} </text>
<text class="text-base text-dark">(医保结算)</text>
</view>
<view class="pt-5">
<text class="mr-5 text-base text-dark">第二笔: 运费</text>
<text class="mr-5 text-base text-danger"> ¥{{ countDetails.shippingFee }} </text>
<text class="text-base text-dark">(支付宝支付)</text>
</view>
</view>
<view class="py-12">
<view class="bg-primary border-primary text-base text-white text-center py-10 rounded"
@click="showConfirmPopup()">
立即支付 (¥{{ countDetails.ybFee }})
</view>
</view>
</view>
</template>
</full-page>
<address-popup :accountId="userInfo.userId" :visible="visible" @close="visible = false" @confirm="onSelect($event)" />
<comfirm-popup :elderMode="elderMode" :elderVarStyle="elderVarStyle" :visible="comfirmVisible"
@close="comfirmVisible = false" @confirm="toPay()" />
</template>
<script setup>
import { computed, ref, watch } from 'vue';
import { onLoad, onHide, onShow } from '@dcloudio/uni-app';
import BigNumber from 'bignumber.js';
import useElder from '@/hooks/useElder';
import useUser from '@/hooks/useUser';
import { getDefaultAddress, getMedicinePurchaseOrder, testFengniaoAvailable, getMedicineOrderTradeNo } from '@/utils/api';
import { toast, loading as showLoading, hideLoading, confirm } from '@/utils/widget';
import ybPlugin from "@/utils/insurance-plugin";
import { pay } from '@/utils/pay';
import { themeColor } from '@/utils/theme-config';
import fullPage from '@/components/full-page.vue';
import AddressPopup from './address-popup.vue';
import ComfirmPopup from './comfirm-popup.vue';
const { elderVarStyle, elderMode } = useElder();
const { userInfo, getAuthCode, myProfile } = useUser();
const address = ref(null)
const shippingType = ref('ems');
const visible = ref(false);
const comfirmVisible = ref(false);
const id = ref('')
const order = ref(null)
const fengNiaoAvailable = ref(false);
const enableChangeAddress = ref(false);
const disabledShippingTypeChange = ref(false);
const autoBack = ref(false);
const exprssFee = ref({});
const shippingInfo = computed(() => exprssFee.value[shippingType.value] || {})
let waitingYbPay = false;
const isFamilyPay = computed(() => myProfile.value && myProfile.value.patientid !== order.value.patientId);
const drugFee = computed(() => {
const drugs = order.value && Array.isArray(order.value.drugs) ? order.value.drugs : [];
const total = drugs.reduce((total, med) => {
return total.plus(med.totalPrice > 0 ? med.totalPrice : 0);
}, new BigNumber(0));
return total.toNumber();
})
const countDetails = computed(() => {
const shippingFee = shippingInfo.value && typeof shippingInfo.value.shippingFee === 'number' ? shippingInfo.value.shippingFee : undefined;
const shippingDiscount = shippingInfo.value && typeof shippingInfo.value.shippingDiscount === 'number' ? shippingInfo.value.shippingDiscount : undefined;
const regFee = order.value && typeof order.value.regFee === 'number' ? order.value.regFee : undefined;
const total = new BigNumber(drugFee.value).plus(regFee || 0).plus(shippingFee || 0);
const ybFee = new BigNumber(drugFee.value).plus(regFee || 0).toNumber();
return {
drugFee: drugFee.value.toFixed(2),
shippingFee: typeof shippingFee === 'number' ? shippingFee.toFixed(2) : '',
shippingDiscount: typeof shippingDiscount === 'number' ? shippingDiscount.toFixed(2) : '',
regFee: typeof regFee === 'number' ? regFee.toFixed(2) : '',
shippingFee: typeof shippingFee === 'number' ? shippingFee.toFixed(2) : '',
totalFee: total.toFixed(2),
ybFee: ybFee.toFixed(2),
}
})
function onSelect(item) {
visible.value = false
address.value = item
}
function showAddressPopup() {
if (enableChangeAddress.value) {
visible.value = true;
}
}
function toggleShippingType(type) {
if (disabledShippingTypeChange.value) return;
shippingType.value = type;
}
async function getAddress() {
const res = await getDefaultAddress(userInfo.value.userId);
address.value = res && res.data && res.data.id ? res.data : null;
}
async function getDetail(showYbPaidTip) {
showLoading()
const res = await getMedicinePurchaseOrder({ accountId: userInfo.value.userId, id: id.value, withExpressInfo: true });
hideLoading();
if (res && res.success) {
order.value = res.data;
exprssFee.value = res.exprssFee || {};
enableChangeAddress.value = order.value.status === 'unpay';
if (order.value.status === 'shipped' || order.value.status === 'ybPaid') {
// 支付宝医保支付回调提示用户继续完成剩下 自费部分费用支付
if (showYbPaidTip && order.value.status === 'ybPaid' && order.value.shippingFee > 0) {
await confirm(`您已完成第一笔药费+诊查费支付, 请继续支付第二笔运费(¥${order.value.shippingFee})支付`, { showCancel: false, confirmText: '继续支付' })
}
uni.redirectTo({
url: `/pages/consult/drug-purchase-list/detail?id=${id.value}&autoCallPay=YES`,
success: () => {
autoBack.value = true
}
});
return
}
if (order.value.status === 'expired') {
await toast('订单已过期')
uni.navigateBack();
return
}
if (order.value.status !== 'unpay') {
await toast('订单状态异常')
uni.navigateBack();
return
}
disabledShippingTypeChange.value = Boolean(order.value.shippingType);
initOrderAddress()
} else {
await toast(res.message || '获取在线配药订单详情失败');
uni.navigateBack();
}
}
async function initOrderAddress() {
// if (order.value.receivePhone) {
// address.value = {
// name: order.value.receiveName,
// phone: order.value.receivePhone,
// region: [...order.value.receiveRegion],
// address: order.value.receiveAddress,
// longitude: order.value.receiveLongitude,
// latitude: order.value.receiveLatitude,
// }
// } else {
getAddress();
// }
}
async function checkFengNiaoAvailable() {
if (address.value) {
const fullAddress = address.value.region.join('') + address.value.address;
const res = await testFengniaoAvailable({ orderNo: order.value.orderNo, address: fullAddress, longitude: address.value.longitude, latitude: address.value.latitude });
fengNiaoAvailable.value = res && res.data && typeof res.data.canDelivery === 'boolean' ? res.data.canDelivery : false;
if (fengNiaoAvailable.value) {
shippingType.value = 'fengniao';
} else {
shippingType.value = 'ems';
}
} else {
shippingType.value = 'ems';
fengNiaoAvailable.value = false
}
}
function showConfirmPopup() {
if (!address.value) {
return toast('请选择收货地址')
}
comfirmVisible.value = true;
}
async function toPay() {
const payload = {
accountId: userInfo.value.userId,
id: id.value,
shippingType: shippingType.value,
receiveName: address.value.name,
receivePhone: address.value.phone,
receiveRegion: address.value.region,
receiveAddress: address.value.address,
receiveLongitude: address.value.longitude,
receiveLatitude: address.value.latitude,
}
showLoading();
const res = await getMedicineOrderTradeNo(payload);
hideLoading();
if (res && res.success) {
if (res.statusChanged) {
await toast('订单状态已更新')
getDetail()
}
if (res.tradeNo && res.payType === 'ybPay') {
pluginPay(res.tradeNo);
} else if (res.tradeNo && res.payType === 'alipay') {
payTrade(res.tradeNo);
}
return
}
toast(res.message || '获取交易订单号失败')
}
async function payTrade(tradeNo) {
try {
await pay(tradeNo);
getDetail()
} catch (e) {
if (e === 'cancel') {
toast('支付已取消')
} else {
toast(e)
}
}
}
async function pluginPay(medOrgOrd) {
try {
const authCode = await getAuthCode("nhsamp");
const params = {
authCode,
cardNo: order.value.blhno,
medOrgOrd
}
if (isFamilyPay.value) {
params.anotherIdNo = order.value.anotherIdNo;
params.anotherName = order.value.anotherName;
}
showLoading('请稍等,正在为您接入医保支付...')
waitingYbPay = true;
ybPlugin.toAuthAndPay(params);
} catch (e) {
toast(e);
}
}
onLoad(options => {
id.value = options.id || '';
getDetail()
ybPlugin.init({
payCallback: () => {
getDetail(true)
},
tokenCallback: () => {
uni.redirectTo({
url: `/pages/consult/drug-purchase-order/drug-purchase-order?id=${id.value}`,
});
},
});
})
onHide(() => {
if (waitingYbPay) {
hideLoading();
}
})
onShow(() => {
if (autoBack.value) {
uni.navigateBack();
}
})
watch(address, n => checkFengNiaoAvailable())
</script>
<style lang="scss" scoped>
.radio-text {
line-height: 20px;
}
.pt-12 {
padding-top: 24rpx;
}
</style>