2026-07-27 11:26:39 +08:00

284 lines
8.8 KiB
Vue
Raw Permalink 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 pageStyle="background:#f5f5f5" @reachBottom="loadMore()">
<template #header>
<view class="header-tabs" :style="elderVarStyle">
<view v-for="tab in tabs" :key="tab.value" :class="['tab', { active: activeTab === tab.value }]"
@click="switchTab(tab.value)">
{{ tab.label }}
</view>
</view>
</template>
<view class="p-15" :style="elderVarStyle">
<view v-for="(item, index) in list" :key="item._id" class="px-15 bg-white shadow-lg rounded"
:class="index > 0 ? 'mt-15' : ''" @click="viewOrder(item)">
<view class="flex items-center py-12 border-b">
<view class="flex-grow mr-10 w-0 truncate text-base text-dark font-semibold">
{{ item.time }}
</view>
<view v-if="item.statusText" class="flex-shrink-0 text-base font-semibold" :class="item.statusClass">
{{ item.statusText }}
</view>
</view>
<view v-for="(med, idx) in item.drugs" :key="`${idx}_${med.id}`" class="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-dark">¥{{ 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="py-12">
<view class="flex justify-end pb-10">
<view v-if="item.hasShippingFee" class="text-sm text-gray">
含互联网诊查费¥{{ item.regFee }}{{ item.shippingFee > 0 ? '运费¥' + item.shippingFee : '免运费' }}
</view>
<view v-else class="text-sm text-gray">含互联网诊查费¥{{ item.regFee }}</view>
<view class="flex-shrink-0 text-sm text-dark">合计</view>
<view class="flex-shrink-0 text-sm text-dark">¥{{ item.totalFee }}</view>
</view>
<view class="flex justify-end flex-wrap">
<view v-if="item.canViewInvoice"
class="flex-shrink-0 border-primary text-base text-primary px-15 py-5 rounded"
@click.stop="viewInvoice(item.patientId, item.orderNo)">电子发票</view>
<view v-if="item.canViewDelivery"
class="flex-shrink-0 ml-10 bg-primary border-primary text-base text-white px-15 py-5 rounded"
@click.stop="viewShippingInfo(item._id)">查看物流</view>
<view v-else-if="item.status === 'ybPaid'"
class="flex-shrink-0 bg-primary border-primary text-base text-white px-15 py-5 rounded"
@click.stop="toPay(item)">
去支付</view>
</view>
</view>
</view>
<empty-data v-if="list.length === 0" />
</view>
</full-page>
<confirm-popup
:title="invoicePopup.title"
:content="invoicePopup.content"
:showCancel="false"
confirmText="知道了"
:visible="invoicePopup.visible"
@confirm="invoicePopup.visible = false"
@close="invoicePopup.visible = false" />
</template>
<script setup>
import { computed, ref } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import dayjs from 'dayjs';
import BigNumber from 'bignumber.js';
import useElder from '@/hooks/useElder';
import usePageList from '@/hooks/usePageList';
import useUser from '@/hooks/useUser';
import { getMedicinePurchaseList, getMedicineOrderTradeNo, getHisInvoice } from '@/utils/api';
import { pay } from '@/utils/pay';
import { loading as showLoading, hideLoading, toast } from '@/utils/widget';
import { viewShippingInfo } from './util';
import emptyData from '@/components/empty.vue';
import fullPage from '@/components/full-page.vue';
import confirmPopup from '@/components/confirm-popup.vue';
const statusSet = {
ybPaid: { text: '待支付运费', className: 'text-danger' },
shipped: { text: '已配送', className: 'text-success' },
refunded: { text: '已退费', className: 'text-gray' },
ybFeeRefunded: { text: '药诊费已退', className: 'text-gray' },
}
const tabs = [
{ label: '全部', value: 'all', statusList: [] },
{ label: '待支付', value: 'ybPaid', statusList: ['ybPaid'] },
{ label: '已配送', value: 'shipped', statusList: ['shipped'] },
{ label: '退费', value: 'refunded', statusList: ['refunded', 'ybFeeRefunded'] }
];
const activeTab = ref('all');
const { page, pageSize, list, pages, changePage, loading, hasMore } = usePageList(getList);
const { elderVarStyle } = useElder();
const { userInfo } = useUser();
const statusList = computed(() => {
if (activeTab.value === 'all') {
return tabs.reduce((list, item) => [...list, ...item.statusList], []);
}
const tab = tabs.find(item => item.value === activeTab.value);
return tab ? tab.statusList : [];
})
const invoicePopup = ref({
visible: false,
title: '提示',
content: ''
})
function switchTab(value) {
activeTab.value = value;
changePage(1)
}
function loadMore() {
if (hasMore.value && !loading.value) {
changePage(page.value + 1)
}
}
function viewOrder(item) {
uni.navigateTo({
url: `/pages/consult/drug-purchase-list/detail?id=${item._id}`
})
}
async function getList() {
if (loading.value || !userInfo.value?.userId) return;
loading.value = true;
const params = {
accountId: userInfo.value.userId,
page: page.value,
pageSize: pageSize.value,
statusList: statusList.value
}
showLoading();
const res = await getMedicinePurchaseList(params);
hideLoading()
const arr = res && Array.isArray(res.list) ? res.list.map(i => {
const item = { ...i };
const status = statusSet[i.status];
if (status) {
item.statusText = status.text;
item.statusClass = status.className;
}
item.hasShippingFee = 'shippingFee' in item;
let totalFee = new BigNumber(0);
item.drugs.forEach(med => {
totalFee = totalFee.plus(med.totalPrice > 0 ? med.totalPrice : 0);
});
totalFee = totalFee.plus(item.regFee > 0 ? item.regFee : 0);
totalFee = totalFee.plus(item.shippingFee > 0 ? item.shippingFee : 0);
item.totalFee = totalFee.toNumber();
item.time = dayjs(item.createTime).format('YYYY-MM-DD HH:mm');
item.canViewInvoice = 'shipped' === item.status;
item.canViewDelivery = ['shipped', 'ybFeeRefunded'].includes(item.status);
return item;
}) : [];
list.value = page.value === 1 ? arr : [...list.value, ...arr];
pages.value = res && res.pages > 0 ? res.pages : 0;
if (!res || !res.success) {
toast(res && res.message ? res.message : '获取列表失败');
};
loading.value = false;
}
async function toPay(item) {
showLoading();
const res = await getMedicineOrderTradeNo({
accountId: userInfo.value.userId,
id: item._id
});
hideLoading();
if (res && res.success) {
if (res.statusChanged) {
await toast('订单状态已更新')
getList()
}
if (res.tradeNo && res.payType === 'alipay') {
payTrade(res.tradeNo, item);
}
return
}
toast(res.message || '获取交易订单号失败')
}
async function payTrade(tradeNo, item) {
try {
await pay(tradeNo);
viewOrder(item);
} catch (e) {
if (e === 'cancel') {
toast('支付已取消')
} else {
toast(e)
}
}
}
onShow(() => {
changePage(1);
})
// 本地版本的viewInvoice使用自定义弹窗
async function viewInvoice(patientId, orderNo) {
showLoading()
const res = await getHisInvoice({
patientId,
orderNo
});
hideLoading()
if (res && res.success) {
const url = typeof res.data === 'string' ? res.data : ''
if (url) {
uni.setClipboardData({
data: url,
success: () => {
invoicePopup.value = {
visible: true,
title: '提示',
content: '已复制发票地址,请在浏览器中打开'
}
}
})
} else {
invoicePopup.value = {
visible: true,
title: '提示',
content: '发票正在开具中,请稍后再试!'
}
}
} else {
invoicePopup.value = {
visible: true,
title: '提示',
content: '发票正在开具中,请稍后再试!'
}
}
}
</script>
<style lang="scss" scoped>
.header-tabs {
display: flex;
background: #fff;
text-align: center;
.tab {
position: relative;
flex-grow: 1;
padding: 24rpx 30rpx;
font-size: var(--text-base);
color: #333;
&.active {
color: $theme-brown-primary;
font-weight: bold;
}
&.active::after {
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 0;
content: "";
width: 80rpx;
height: 8rpx;
border-radius: 4rpx;
background: $theme-brown-primary;
}
}
}
.ml-10 {
margin-left: 20rpx;
}
</style>