123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504 |
- <route lang="json5" type="page">
- {
- layout: 'default',
- style: {
- navigationBarTitleText: '%orderDetail.title%',
- navigationBarBackgroundColor: '#fff',
- },
- }
- </route>
- <script lang="ts" setup>
- import { getConfigByCode } from '@/api/common'
- import { orderCancel, orderDetail, orderPink, orderStatusEnum, payOrder } from '@/api/order'
- import { getWalletAccountInfo } from '@/api/wallet'
- import DialogBox from '@/components/DialogBox/DialogBox.vue'
- import { DialogUtils } from '@/components/DialogBox/utils'
- import { t } from '@/locale'
- import { formatNumber } from '@/utils'
- import { getPageParams, toPage } from '@/utils/page'
- import { toast } from '@/utils/toast'
- defineOptions({
- name: 'OrderDetail', // 订单详情
- })
- // z-paging
- const paging = ref(null)
- const id = ref<any>()
- const isPayOrder = ref<boolean>(false)
- const detail = ref<any>({})
- const orderStatusEnumData = ref<any>([])
- const openRedEnvelopeRate = ref<any>()
- const joinRedEnvelopeRate = ref<any>()
- const countdown = ref('00:00')
- const timer = ref()
- // DialogBox 函数式调用配置
- const dialogConfig = ref<any>({})
- const dialogType = ref<'cancel' | 'pay' | 'recharge' | ''>('')
- async function getConfig(code: string) {
- try {
- const res = await getConfigByCode({ code })
- if (res.code === '200') {
- switch (code) {
- case 'open_red_envelope_rate':
- openRedEnvelopeRate.value = res.data.valueInfo
- break
- case 'join_red_envelope_rate':
- joinRedEnvelopeRate.value = res.data.valueInfo
- break
- default:
- break
- }
- }
- }
- catch {
- }
- }
- async function getOrderStatus() {
- try {
- const res = await orderStatusEnum({ id: 1 })
- if (res.code === '200') {
- orderStatusEnumData.value = res.data
- }
- }
- catch {
- }
- }
- function startCountdown() {
- // 清除之前的定时器
- if (timer.value)
- clearInterval(timer.value)
- if (!detail.value?.createTime || detail.value?.status !== 1) {
- countdown.value = '00:00'
- return
- }
- // 计算过期时间(创建时间 + 20分钟)
- const createTime = new Date(detail.value.createTime).getTime()
- const expireTime = createTime + 20 * 60 * 1000
- timer.value = setInterval(() => {
- const now = Date.now()
- const diff = expireTime - now
- if (diff <= 0) {
- clearInterval(timer.value)
- countdown.value = '00:00'
- getDetail() // 刷新订单状态
- return
- }
- const minutes = Math.floor(diff / 1000 / 60)
- const seconds = Math.floor((diff / 1000) % 60)
- countdown.value = `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`
- }, 1000)
- }
- async function getDetail() {
- uni.showLoading({
- title: t('orderDetail.loading'),
- })
- try {
- const res = await orderDetail({ id: id.value })
- if (res.code === '200') {
- detail.value = res.data
- if (detail.value?.status === 1) {
- startCountdown() // 开始倒计时
- // if (isPayOrder.value) {
- // // 自动调用支付接口
- // await goPay()
- // }
- }
- await getPink()
- paging.value.complete()
- }
- }
- finally {
- uni.hideLoading()
- }
- }
- const pinkList = ref<any>([])
- async function getPink() {
- try {
- const res = await orderPink({ id: detail.value?.storePink?.id })
- if (res.code === '200') {
- pinkList.value = res.data
- }
- }
- catch {
- }
- }
- // 跳转到地址簿选择地址
- function selectAddress() {
- toPage('/pages/mine/addressBook', {
- selectMode: true,
- orderId: detail.value?.orderId,
- })
- }
- // 显示取消订单确认对话框
- function showCancelOrderDialog() {
- dialogType.value = 'cancel'
- Object.assign(dialogConfig.value, DialogUtils.info(
- t('orderDetail.dialog.cancel.title'),
- {
- showCancel: true,
- confirmText: t('orderDetail.dialog.cancel.confirm'),
- cancelText: t('orderDetail.dialog.cancel.keep'),
- confirmPlain: true,
- },
- ))
- }
- // 取消订单
- async function cancelOrder() {
- try {
- uni.showLoading({
- title: t('orderDetail.cancel.loading'),
- mask: true,
- })
- const res = await orderCancel({ id: id.value })
- if (res.code === '200') {
- // 显示成功提示
- toast.success(t('orderDetail.cancel.success'))
- // 刷新订单详情
- getDetail()
- }
- else {
- // 显示错误提示
- toast.error(res.message || t('orderDetail.cancel.error'))
- }
- }
- catch (error: any) {
- console.error('Cancel order error:', error)
- // 显示错误提示
- toast.error(t('orderDetail.cancel.network'))
- }
- finally {
- uni.hideLoading()
- }
- }
- // 处理对话框确认事件
- function handleDialogConfirm() {
- if (dialogType.value === 'cancel') {
- cancelOrder()
- }
- else if (dialogType.value === 'pay') {
- goPay()
- }
- else if (dialogType.value === 'recharge') {
- toPage('/pages/wallet/recharge', { price: detail.value?.payPrice }, true)
- }
- // 关闭对话框
- handleDialogClose()
- }
- // 处理对话框关闭事件
- function handleDialogClose() {
- dialogConfig.value.show = false
- }
- // 支付
- // 显示支付余额去充值提示
- function showRechargeDialog() {
- dialogType.value = 'recharge'
- Object.assign(dialogConfig.value, DialogUtils.info(
- `Your wallet balance is insufficient. \n Please Recharge!`,
- {
- showCancel: false,
- confirmText: 'Recharge Now',
- cancelText: '',
- confirmPlain: true,
- },
- ))
- }
- // 显示支付确认对话框
- function showPayOrderDialog() {
- dialogType.value = 'pay'
- Object.assign(dialogConfig.value, DialogUtils.info(
- 'BandhuBuy Wallet Pay',
- {
- showCancel: false,
- cancelText: '',
- confirmText: 'DONE',
- confirmPlain: false,
- },
- ))
- }
- async function goPay() {
- const payRes = await payOrder({
- orderId: detail.value?.orderId,
- type: detail.value?.storePink?.kId ? 'join' : 'open',
- })
- console.log(payRes)
- if (payRes.code === '200') {
- toast.success(t('orderDetail.payment.success'))
- getDetail()
- }
- }
- function handleClick() {
- if (detail.value?.status === 1) {
- // 去支付
- showPayOrderDialog()
- }
- else {
- // 去分享
- }
- }
- const timeMap = {
- create_order: 'placed on',
- pay_success: 'paid on',
- delivery: 'shipped on',
- receive: 'completed on',
- }
- onLoad(async (options) => {
- getConfig('open_red_envelope_rate')
- getConfig('join_red_envelope_rate')
- const params = getPageParams(options)
- id.value = params.id
- isPayOrder.value = params.isPayOrder
- await getOrderStatus()
- })
- const balance = ref<number>(0)
- onShow(async () => {
- await getDetail()
- if (isPayOrder.value && detail.value?.status === 1) {
- const res = await getWalletAccountInfo()
- console.log(res)
- balance.value = res?.data?.balance
- if (balance.value < detail.value?.payPrice) {
- // 余额不足,提示去充值
- showRechargeDialog()
- }
- else {
- // 余额充足,显示支付对话框
- showPayOrderDialog()
- }
- }
- })
- onUnmounted(() => {
- if (timer.value)
- clearInterval(timer.value)
- })
- </script>
- <template>
- <z-paging ref="paging" refresher-only @refresh="getDetail">
- <view class="pt-20rpx">
- <!-- 状态显示 -->
- <template v-if="detail.status !== 4 && detail?.status !== 2">
- <!-- 已中奖 -->
- <view v-if="detail?.storePink?.status === 2 && detail?.storePink?.lId === 1" class="mb-20rpx bg-#17AA68/80 py-20rpx text-center text-28rpx text-white">
- {{ t('orderDetail.congrats') }}
- <br>
- {{ t('orderDetail.receiveReward') }}
- <text class="text-[var(--wot-color-theme)]">
- ৳{{ 10 }}
- </text>
- </view>
- <!-- 未中奖 -->
- <view v-else-if="detail?.storePink?.status === 2 && detail?.storePink?.lId === 0" class="mb-20rpx bg-#E61B28/80 py-20rpx text-center text-28rpx text-white">
- {{ t('orderDetail.sorry') }}
- <br>
- {{ t('orderDetail.receiveReward') }}
- <text class="text-#66C59B">
- ৳8
- </text>
- </view>
- <!-- 未开奖||未支付 -->
- <view v-else-if="detail?.storePink?.status === 1 || detail?.status === 1" class="mb-20rpx bg-#fff py-20rpx text-center text-28rpx text-white">
- <text v-if="detail?.storePink?.status === 1 && detail?.status !== 1" class="text-[var(--wot-color-theme)]">
- {{ t('orderDetail.waiting') }}
- </text>
- <text v-else class="text-[var(--wot-color-theme)]">
- {{ t('orderDetail.paymentCountdown') }} {{ countdown }}
- </text>
- </view>
- <!-- 拼团头像 -->
- <view v-if="pinkList && pinkList.length" class="mb-20rpx bg-white px-20rpx py-20rpx text-center">
- <image v-for="i in pinkList" :key="i" class="mx-4rpx mb-8rpx h-80rpx w-80rpx rounded-full" :src="i.avatar" />
- </view>
- </template>
- <!-- 地址 -->
- <view v-if="detail?.storePink?.status === 2 && detail?.storePink?.lId === 1" class="mb-20rpx bg-white px-24rpx py-20rpx">
- <!-- 无地址 -->
- <template v-if="!detail.orderAddressVO">
- <view class="flex items-center justify-between" @click="selectAddress">
- <view class="text-28rpx text-[var(--wot-color-theme)]">
- {{ t('orderDetail.address.add') }}
- </view>
- <wd-icon name="arrow-right" color="#7D7D7D" size="28rpx" />
- </view>
- </template>
- <!-- 有地址 -->
- <template v-else>
- <view v-if="detail.deliveryCode" class="mb-18rpx flex justify-between border-b-1 border-b-#E1E1E1 border-b-solid pb-18rpx text-24rpx">
- <!-- 物流信息 -->
- <view>{{ detail.deliveryName }}</view>
- <view> DHL:{{ detail.deliveryCode || '-' }}</view>
- </view>
- <view class="mb-20rpx text-24rpx">
- <text class="mr-20rpx">
- {{ detail?.orderAddressVO?.realName }}
- </text>
- <text>{{ detail?.orderAddressVO?.phone }}</text>
- </view>
- <view class="text-22rpx text-#3A444C">
- {{ detail?.orderAddressVO?.province }} {{ detail?.orderAddressVO?.city }} {{ detail?.orderAddressVO?.district }} {{ detail?.orderAddressVO?.detail }} {{ detail?.orderAddressVO?.postCode }}
- </view>
- </template>
- </view>
- <!-- 商品信息 -->
- <wd-card type="rectangle" custom-class="px-24rpx! py-6rpx!" custom-content-class="py-18rpx!" custom-title-class="py-18rpx!" @click="toPage('/pages/productDetail/productDetail', { productId: detail?.orderInfoVO?.[0].productId })">
- <template #title>
- <view class="flex items-center justify-between">
- <view class="text-28rpx text-#000">
- {{ t('orderDetail.address.orderNo') }}:{{ detail?.orderInfoVO?.[0].orderNo }}
- </view>
- <wd-text size="26rpx" type="primary" :text="orderStatusEnumData.find((i:any) => i.code === detail?.status)?.name" />
- </view>
- </template>
- <view class="flex items-center gap-24rpx">
- <view class="h-140rpx w-140rpx shrink-0">
- <image
- :src="detail?.orderInfoVO?.[0]?.image"
- class="h-full w-full"
- mode="aspectFit"
- />
- </view>
- <view class="flex-1">
- <view class="line-clamp-2 text-28rpx text-#000">
- {{ detail?.orderInfoVO?.[0].productName }}
- </view>
- <view class="py-4rpx text-24rpx text-#3A444C">
- {{ t('orderDetail.address.color') }}:{{ detail?.orderInfoVO?.[0].sku }}
- </view>
- <view class="flex items-center justify-between text-24rpx">
- <view class="text-[var(--wot-color-theme)]">
- ৳ {{ formatNumber(detail?.orderInfoVO?.[0].price) }}
- </view>
- <view class="text-#3A444C">
- {{ t('orderDetail.address.quantity') }}:{{ detail?.orderInfoVO?.[0].payNum }}
- </view>
- </view>
- </view>
- </view>
- </wd-card>
- <!-- 订单信息 -->
- <view class="bg-white px-24rpx">
- <view class="border-b-1 border-b-#E1E1E1 border-b-solid py-24rpx">
- <view class="mb-12rpx text-28rpx">
- {{ t('orderDetail.summary.title') }}
- </view>
- <view class="flex flex-col gap-16rpx text-#3A444C">
- <view class="flex items-center justify-between text-24rpx">
- <text>SubTotal</text>
- <text>৳{{ formatNumber(detail.totalPrice) }}</text>
- </view>
- </view>
- </view>
- <view class="border-b-1 border-b-#E1E1E1 border-b-solid py-24rpx">
- <view class="mb-12rpx text-28rpx">
- {{ t('orderDetail.payment.title') }}
- </view>
- <view class="flex flex-col gap-16rpx text-#3A444C">
- <view class="flex items-center justify-between text-24rpx">
- <text>SubTotal</text>
- <text>৳{{ formatNumber(detail.payPrice) }}</text>
- </view>
- </view>
- </view>
- <view v-if="detail?.orderStatusVO?.length" class="py-24rpx">
- <template v-for="i in detail?.orderStatusVO" :key="i.id">
- <view v-if="timeMap[i.changeType]" class="mb-16rpx flex flex-col text-#3A444C">
- <view class="flex items-center justify-between text-24rpx">
- <text>{{ timeMap[i.changeType] }}</text>
- <text>{{ i.createTime }}</text>
- </view>
- </view>
- </template>
- </view>
- </view>
- </view>
- <template #bottom>
- <view v-if="detail?.status === 1" class="flex items-center justify-end bg-white/60 px-28rpx py-30rpx backdrop-blur-20">
- <!-- 取消订单按钮 -->
- <wd-button
- v-if="detail?.status === 1"
- custom-class="mr-16rpx!"
- plain
- @click="showCancelOrderDialog"
- >
- {{ t('orderDetail.button.cancel') }}
- </wd-button>
- <wd-button @click="handleClick">
- {{ t('orderDetail.button.pay') }}
- </wd-button>
- </view>
- </template>
- <!-- DialogBox 函数式调用 -->
- <DialogBox
- v-bind="dialogConfig"
- @confirm="handleDialogConfirm"
- @cancel="handleDialogClose"
- @close="handleDialogClose"
- >
- <view v-if="dialogType === 'pay'">
- <view class="font-blod relative text-32rpx">
- <text>BandhuBuy Wallet Pay</text>
- <wd-icon name="close-normal" custom-class="absolute right-0 top-1/2 -translate-y-1/2" size="40rpx" @click="handleDialogClose" />
- </view>
- <view class="py-60rpx">
- <text class="text-40rpx">
- ৳
- </text>
- <text class="text-60rpx">
- {{ formatNumber(detail.payPrice) }}
- </text>
- </view>
- <view class="pb-28rpx text-left">
- <view class="text-24rpx font-bold">
- Payment Method
- </view>
- <view class="my-14rpx border-b-1px border-b-#EBEBEB border-b-solid" />
- <view class="flex items-center justify-between text-24rpx">
- <view class="flex items-center">
- <view class="text-24rpx">
- <text>BandhuBuy Wallet (</text>
- <text class="text-[var(--wot-color-theme)]">
- Balance: ৳{{ formatNumber(balance) }}
- </text>
- <text>)</text>
- </view>
- </view>
- <view>
- <image
- src="/static/icons/circle-check.png"
- class="h-36rpx w-36rpx"
- />
- </view>
- </view>
- </view>
- </view>
- </DialogBox>
- </z-paging>
- </template>
- <style lang="scss" scoped>
- //
- </style>
|