shinnosuke
2026-08-05 25729fa1ae7b630cbd4a9547a5693acd03c09c2a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
<template>
    <view class="page">
        <view class="page-header">
            <view class="safe-space" :style="'height:' + navTop + 'px'"></view>
            <view class="nav-row" :style="'height:' + navHeight + 'px;padding-right:' + navRight + 'px'">
                <view class="back-button" hover-class="back-button-active" @tap="goBack"><image src="/static/news-assets/arrow-left.svg" mode="aspectFit"></image></view>
                <text class="nav-title">已取消</text>
                <view class="capsule-space" :style="'width:' + navWidth + 'px'"></view>
            </view>
        </view>
 
        <view v-if="loading" class="state-panel"><text>正在加载订单信息</text></view>
        <view v-else-if="loadError" class="state-panel"><text>订单信息加载失败</text><view class="state-action" @tap="loadOrder"><text>重新加载</text></view><view class="state-action secondary" @tap="goBack"><text>返回使用记录</text></view></view>
        <view v-else class="content">
            <view class="content-inner">
                <view class="product-card">
                    <image class="product-image" :src="productCoverUrl" mode="aspectFill"></image>
                    <view class="product-info"><text class="product-name">{{productName}}</text><text class="product-original">¥ {{originalAmount}}</text></view>
                    <view class="product-payment"><text class="payment-label">原计划实付</text><text class="payment-price">¥ {{plannedPayAmount}}</text></view>
                </view>
 
                <view class="merchant-card">
                    <view class="merchant-info"><text class="merchant-name">{{merchantName}}</text><text class="merchant-address">{{merchantAddress}}</text></view>
                    <view class="merchant-actions">
                        <view class="merchant-action" hover-class="action-active" @tap="openNavigation"><image src="/static/merchant-assets/navigation.svg" mode="aspectFit"></image><text>导航</text></view>
                        <view class="merchant-action" hover-class="action-active" @tap="callMerchant"><image src="/static/merchant-assets/phone.svg" mode="aspectFit"></image><text>电话</text></view>
                    </view>
                </view>
 
                <view class="order-card">
                    <text class="order-title">订单信息</text>
                    <view class="order-row"><text>订单号:</text><text>{{orderId}}</text></view>
                    <view class="order-row"><text>商品金额:</text><text>{{originalAmount}}元</text></view>
                    <view class="order-row"><text>人才折扣:</text><text>-{{subsidyAmount}}元</text></view>
                    <view class="order-row"><text>商品优惠:</text><text>-{{couponAmount}}元</text></view>
                    <view class="order-row"><text>实际支付:</text><text>{{actualPaidAmount}}元</text></view>
                    <view class="order-row"><text>取消来源:</text><text>{{cancelSource}}</text></view>
                    <view class="order-row"><text>取消原因:</text><text>{{cancelReason}}</text></view>
                    <view class="order-row"><text>退款状态:</text><text>{{refundStatusText}}</text></view>
                    <view v-if="refundAmount != '0.00'" class="order-row"><text>退款金额:</text><text>{{refundAmount}}元</text></view>
                    <view class="order-row"><text>取消时间:</text><text>{{cancelTime}}</text></view>
                </view>
                <view class="content-bottom"></view>
            </view>
        </view>
    </view>
</template>
 
<script setup lang="uts">
    import { apiEnvironment } from '../../config/api.uts'
    import { resolveApiUrl } from '../../services/http.uts'
    import { getCancelledOrder } from '../../services/portal.uts'
    import { safeBack } from '../../utils/navigation.uts'
 
    const navTop = ref(28)
    const navHeight = ref(32)
    const navWidth = ref(88)
    const navRight = ref(10)
    const recordId = ref('')
    const orderId = ref('')
    const talentId = ref('')
    const loading = ref(true)
    const loadError = ref(false)
    const productCoverUrl = ref('')
    const productName = ref('')
    const originalAmount = ref('0.00')
    const plannedPayAmount = ref('0.00')
    const actualPaidAmount = ref('0.00')
    const subsidyAmount = ref('0.00')
    const couponAmount = ref('0.00')
    const refundAmount = ref('0.00')
    const merchantName = ref('')
    const merchantAddress = ref('')
    const merchantMobile = ref('')
    const merchantLatitude = ref(0.0)
    const merchantLongitude = ref(0.0)
    const cancelSource = ref('')
    const cancelReason = ref('')
    const refundStatusText = ref('')
    const cancelTime = ref('-')
 
    onLoad((options: any) => {
        // #ifdef MP-WEIXIN
        const capsule = uni.getMenuButtonBoundingClientRect()
        const systemInfo = uni.getSystemInfoSync()
        navTop.value = capsule.top
        navHeight.value = capsule.height
        navWidth.value = capsule.width
        navRight.value = systemInfo.windowWidth - capsule.right
        // #endif
        if (options != null && options['recordId'] != null) recordId.value = decodeURIComponent(options['recordId'] as string)
        if (options != null && options['orderId'] != null) orderId.value = decodeURIComponent(options['orderId'] as string)
        talentId.value = options != null && options['talentId'] != null ? options['talentId'] as string : (apiEnvironment == 'development' ? '2' : '')
        loadOrder()
    })
 
    const goBack = () => safeBack('/pages/order/order')
    const loadOrder = () => {
        if (orderId.value == '' || talentId.value == '') { loading.value = false; loadError.value = true; return }
        loading.value = true
        loadError.value = false
        getCancelledOrder(orderId.value, talentId.value, (data: any) => {
        productCoverUrl.value = data.productCoverUrlSnapshot != null && data.productCoverUrlSnapshot != '' ? resolveApiUrl(data.productCoverUrlSnapshot as string) : ''
            productName.value = data.productNameSnapshot || '人才权益服务'
            originalAmount.value = Number(data.originalAmount).toFixed(2)
            plannedPayAmount.value = Number(data.payAmount).toFixed(2)
            actualPaidAmount.value = Number(data.actualPaidAmount).toFixed(2)
            subsidyAmount.value = Number(data.subsidyAmount).toFixed(2)
            couponAmount.value = Number(data.couponAmount).toFixed(2)
            refundAmount.value = Number(data.refundAmount).toFixed(2)
            merchantName.value = data.merchantNameSnapshot || '人才权益服务'
            merchantAddress.value = data.merchantAddressSnapshot || '商家暂未配置地址'
            merchantMobile.value = data.merchantMobileSnapshot || ''
            merchantLatitude.value = Number(data.merchantLatitudeSnapshot)
            merchantLongitude.value = Number(data.merchantLongitudeSnapshot)
            cancelSource.value = data.cancelSource || '订单取消'
            cancelReason.value = data.cancelReason || '订单已取消'
            refundStatusText.value = data.refundStatusText || '无需退款'
            cancelTime.value = data.cancelTime ? ('' + data.cancelTime).replace('T', ' ').substring(0, 19) : '-'
            loading.value = false
        }, () => { loading.value = false; loadError.value = true })
    }
    const openNavigation = () => { if (merchantLatitude.value == 0 || merchantLongitude.value == 0) { uni.showToast({ title: '商家暂未配置导航地址', icon: 'none' }); return }; uni.openLocation({ latitude: merchantLatitude.value, longitude: merchantLongitude.value, name: merchantName.value, address: merchantAddress.value, scale: 16 }) }
    const callMerchant = () => { if (merchantMobile.value == '') { uni.showToast({ title: '商家暂未配置联系电话', icon: 'none' }); return }; uni.makePhoneCall({ phoneNumber: merchantMobile.value }) }
</script>
 
<style>
    .page { display: flex; width: 100%; height: 100vh; background-color: #F5F7FA; background-image: linear-gradient(180deg, #FFF0D7 0%, #FFF2DE 250rpx, #F5F7FA 520rpx); flex-direction: column; }
    .page-header { position: relative; z-index: 1; flex-shrink: 0; padding-bottom: 82rpx; }
    .safe-space { height: 28px; }
    .nav-row { display: flex; height: 32px; box-sizing: border-box; padding-left: 20rpx; padding-right: 10px; position: relative; flex-direction: row; align-items: center; justify-content: space-between; }
    .back-button { display: flex; width: 70rpx; height: 64rpx; margin-left: -4rpx; justify-content: center; align-items: center; }
    .back-button image { width: 36rpx; height: 36rpx; }
    .back-button-active { opacity: .55; }
    .nav-title { position: absolute; left: 50%; top: 50%; color: #171B22; font-size: 37rpx; line-height: 48rpx; font-weight: 700; transform: translate(-50%, -50%); white-space: nowrap; }
    .capsule-space { width: 88px; height: 100%; flex-shrink: 0; }
    .content { min-height: 0; z-index: 2; flex: 1; background-color: transparent; }
    .state-panel { display: flex; flex: 1; padding: 120rpx 48rpx; flex-direction: column; align-items: center; color: #7E8794; font-size: 27rpx; line-height: 40rpx; }
    .state-action { display: flex; min-width: 200rpx; height: 70rpx; margin-top: 30rpx; border-radius: 35rpx; background-color: #FF6330; color: #FFFFFF; font-size: 26rpx; justify-content: center; align-items: center; }
    .state-action.secondary { margin-top: 18rpx; background-color: #FFFFFF; color: #FF6330; }
    .content-inner { position: relative; z-index: 2; padding: 0 28rpx; }
    .product-card { display: flex; height: 190rpx; margin-top: -3rpx; box-sizing: border-box; padding: 25rpx 28rpx 25rpx 17rpx; border-radius: 25rpx; background-color: #FFFFFF; flex-direction: row; align-items: center; }
    .product-image { width: 168rpx; height: 140rpx; flex-shrink: 0; border-radius: 13rpx; background-color: #E7EBEF; }
    .product-info { display: flex; min-width: 0; flex: 1; height: 113rpx; margin-left: 22rpx; flex-direction: column; justify-content: space-between; }
    .product-name { color: #29303A; font-size: 29rpx; line-height: 41rpx; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .product-original { color: #A7AEB8; font-size: 22rpx; line-height: 31rpx; }
    .product-payment { display: flex; height: 105rpx; margin-left: 14rpx; flex-shrink: 0; flex-direction: column; align-items: flex-end; justify-content: space-between; }
    .payment-label { color: #79818D; font-size: 21rpx; line-height: 30rpx; }
    .payment-price { color: #FF542F; font-size: 31rpx; line-height: 39rpx; font-weight: 700; }
    .merchant-card { display: flex; min-height: 164rpx; margin-top: 28rpx; box-sizing: border-box; padding: 29rpx 27rpx; border-radius: 25rpx; background-color: #FFFFFF; flex-direction: row; align-items: center; }
    .merchant-info { min-width: 0; flex: 1; }
    .merchant-name { display: block; color: #29303A; font-size: 29rpx; line-height: 41rpx; font-weight: 700; }
    .merchant-address { display: block; margin-top: 14rpx; color: #A0A8B3; font-size: 21rpx; line-height: 30rpx; }
    .merchant-actions { display: flex; width: 137rpx; margin-left: 20rpx; flex-shrink: 0; flex-direction: row; justify-content: space-between; align-items: center; }
    .merchant-action { display: flex; width: 60rpx; flex-direction: column; align-items: center; }
    .merchant-action image { width: 39rpx; height: 39rpx; }
    .merchant-action text { margin-top: 10rpx; color: #303640; font-size: 20rpx; line-height: 27rpx; font-weight: 600; }
    .action-active { opacity: .55; }
    .order-card { margin-top: 28rpx; box-sizing: border-box; padding: 31rpx 28rpx 31rpx; border-radius: 25rpx; background-color: #FFFFFF; }
    .order-title { display: block; margin-bottom: 18rpx; color: #29303A; font-size: 28rpx; line-height: 39rpx; font-weight: 700; }
    .order-row { display: flex; min-height: 52rpx; flex-direction: row; align-items: center; justify-content: space-between; color: #7E8794; font-size: 23rpx; line-height: 34rpx; }
    .order-row text:last-child { margin-left: 24rpx; color: #303946; text-align: right; }
    .content-bottom { height: 40rpx; height: calc(40rpx + env(safe-area-inset-bottom)); }
</style>