|
@@ -0,0 +1,472 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <view class="container">
|
|
|
|
|
+ <!-- 加载中 -->
|
|
|
|
|
+ <view v-if="loading" class="loading-wrapper">
|
|
|
|
|
+ <text class="loading-text">加载中...</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 订单完成内容 -->
|
|
|
|
|
+ <view v-else-if="order" class="content">
|
|
|
|
|
+ <!-- 顶部成功状态 -->
|
|
|
|
|
+ <view class="success-header">
|
|
|
|
|
+ <view class="success-icon-wrapper">
|
|
|
|
|
+ <view class="success-icon">
|
|
|
|
|
+ <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
|
|
|
|
+ <circle cx="50" cy="50" r="45" fill="#07C160" />
|
|
|
|
|
+ <path d="M 30 50 L 45 65 L 70 35" stroke="#fff" stroke-width="6" fill="none" stroke-linecap="round" stroke-linejoin="round" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <text class="success-title">已完成</text>
|
|
|
|
|
+ <text class="success-subtitle">计入按时支付记录</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 商户信息 -->
|
|
|
|
|
+ <view class="merchant-section">
|
|
|
|
|
+ <view class="merchant-header">
|
|
|
|
|
+ <view class="merchant-icon">
|
|
|
|
|
+ <svg viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
|
|
|
|
|
+ <circle cx="20" cy="20" r="18" fill="#FF9800" />
|
|
|
|
|
+ <path d="M 12 28 L 20 12 L 28 28 Z" fill="#fff" />
|
|
|
|
|
+ <rect x="17" y="20" width="6" height="8" fill="#FF9800" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <text class="merchant-name">AI零售柜</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="merchant-info-row">
|
|
|
|
|
+ <text class="info-label">先享服务</text>
|
|
|
|
|
+ <text class="info-value">自助先购后付</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="merchant-info-row">
|
|
|
|
|
+ <text class="info-label">服务信息</text>
|
|
|
|
|
+ <text class="info-value">智慧零售</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 商品信息 -->
|
|
|
|
|
+ <view class="products-section">
|
|
|
|
|
+ <view class="section-label">商品信息</view>
|
|
|
|
|
+ <view v-for="(product, index) in order.products" :key="index" class="product-row">
|
|
|
|
|
+ <text class="product-name">{{ product.name }}</text>
|
|
|
|
|
+ <view class="product-right">
|
|
|
|
|
+ <text class="product-qty">X{{ product.quantity }}</text>
|
|
|
|
|
+ <text class="product-price">¥{{ (product.price * product.quantity).toFixed(2) }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 总计支付 -->
|
|
|
|
|
+ <view class="total-section">
|
|
|
|
|
+ <text class="total-label">总计支付</text>
|
|
|
|
|
+ <view class="total-amount-wrapper">
|
|
|
|
|
+ <text class="total-symbol">¥</text>
|
|
|
|
|
+ <text class="total-amount">{{ (order.paidAmount || order.totalAmount || 0).toFixed(2) }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 订单详情 -->
|
|
|
|
|
+ <view class="detail-section">
|
|
|
|
|
+ <view class="detail-row">
|
|
|
|
|
+ <text class="detail-label">付款方式</text>
|
|
|
|
|
+ <text class="detail-value">服务结束后自动扣费</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="detail-row" v-if="order.storeName">
|
|
|
|
|
+ <text class="detail-label">服务地点</text>
|
|
|
|
|
+ <text class="detail-value">{{ order.storeName }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="detail-row">
|
|
|
|
|
+ <text class="detail-label">开始时间</text>
|
|
|
|
|
+ <text class="detail-value">{{ formatTime(order.createTime) }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="detail-row" v-if="order.payTime">
|
|
|
|
|
+ <text class="detail-label">结束时间</text>
|
|
|
|
|
+ <text class="detail-value">{{ formatTime(order.payTime) }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="detail-row">
|
|
|
|
|
+ <text class="detail-label">服务单号</text>
|
|
|
|
|
+ <text class="detail-value detail-value-long">{{ order.outTradeNo }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="detail-row">
|
|
|
|
|
+ <text class="detail-label">商户单号</text>
|
|
|
|
|
+ <text class="detail-value detail-value-long">{{ order.orderNo }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="detail-row detail-row-link" @click="goToOrderDetail">
|
|
|
|
|
+ <text class="detail-label">交易账单</text>
|
|
|
|
|
+ <view class="detail-link">
|
|
|
|
|
+ <text class="link-text">详情</text>
|
|
|
|
|
+ <text class="link-arrow">></text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 按时支付记录 -->
|
|
|
|
|
+ <view class="payment-record-section" @click="goToOrderDetail">
|
|
|
|
|
+ <text class="payment-record-text">按时支付记录</text>
|
|
|
|
|
+ <text class="payment-record-arrow">></text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup lang="ts">
|
|
|
|
|
+import { ref } from 'vue';
|
|
|
|
|
+import { onLoad } from '@dcloudio/uni-app';
|
|
|
|
|
+import { getOrderDetail } from '../../api/order';
|
|
|
|
|
+import type { OrderInfo } from '../../api/order';
|
|
|
|
|
+import { logger } from '../../utils/logger';
|
|
|
|
|
+
|
|
|
|
|
+const order = ref<OrderInfo | null>(null);
|
|
|
|
|
+const loading = ref(true);
|
|
|
|
|
+
|
|
|
|
|
+const formatTime = (time: string | undefined) => {
|
|
|
|
|
+ if (!time) return '-';
|
|
|
|
|
+ if (typeof time === 'string' && time.includes('-')) {
|
|
|
|
|
+ return time.replace('T', ' ').substring(0, 19);
|
|
|
|
|
+ }
|
|
|
|
|
+ return time;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const loadOrderDetail = async (orderId: string) => {
|
|
|
|
|
+ loading.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ uni.showLoading({ title: '加载中...', mask: true });
|
|
|
|
|
+ const orderDetail = await getOrderDetail({ orderId });
|
|
|
|
|
+ order.value = orderDetail;
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ } catch (error: any) {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ logger.error('加载订单完成页失败:', error);
|
|
|
|
|
+ // 调试:API 失败时展示占位数据方便调试样式
|
|
|
|
|
+ order.value = {
|
|
|
|
|
+ id: '0',
|
|
|
|
|
+ orderNo: orderId,
|
|
|
|
|
+ outTradeNo: 'TEST_OUT_TRADE_NO_123456',
|
|
|
|
|
+ hahaOrderNo: '',
|
|
|
|
|
+ deviceId: 'TEST_DEVICE_001',
|
|
|
|
|
+ totalAmount: 12.50,
|
|
|
|
|
+ paidAmount: 12.50,
|
|
|
|
|
+ payStatus: 'PAID',
|
|
|
|
|
+ status: 3,
|
|
|
|
|
+ products: [
|
|
|
|
|
+ { name: '芝士牛肉卷', quantity: 1, price: 8.50 },
|
|
|
|
|
+ { name: '可乐330ml', quantity: 1, price: 4.00 }
|
|
|
|
|
+ ],
|
|
|
|
|
+ storeName: '人民广场旗舰店',
|
|
|
|
|
+ createTime: new Date().toISOString(),
|
|
|
|
|
+ payTime: new Date().toISOString()
|
|
|
|
|
+ } as OrderInfo;
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const goToOrderDetail = () => {
|
|
|
|
|
+ if (!order.value) return;
|
|
|
|
|
+ uni.navigateTo({
|
|
|
|
|
+ url: '/pages/orderDetail/orderDetail?orderId=' + String(order.value.id)
|
|
|
|
|
+ });
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+onLoad((options: any) => {
|
|
|
|
|
+ const orderId = options?.orderNo || options?.orderId;
|
|
|
|
|
+ if (orderId) {
|
|
|
|
|
+ loadOrderDetail(orderId);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ uni.showToast({ title: '订单信息不存在', icon: 'none' });
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ uni.navigateBack();
|
|
|
|
|
+ }, 1500);
|
|
|
|
|
+ }
|
|
|
|
|
+});
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss">
|
|
|
|
|
+.container {
|
|
|
|
|
+ min-height: 100vh;
|
|
|
|
|
+ background: $color-bg-secondary;
|
|
|
|
|
+ padding-bottom: env(safe-area-inset-bottom);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.loading-wrapper {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ min-height: 600rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.loading-text {
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ color: $color-text-secondary;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.content {
|
|
|
|
|
+ padding-bottom: $spacing-xxl;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ========== 顶部成功状态 ========== */
|
|
|
|
|
+.success-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: $spacing-xxl 0 $spacing-xl;
|
|
|
|
|
+ background: $color-bg-primary;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.success-icon-wrapper {
|
|
|
|
|
+ width: 140rpx;
|
|
|
|
|
+ height: 140rpx;
|
|
|
|
|
+ margin-bottom: $spacing-md;
|
|
|
|
|
+ animation: successPop 0.4s ease;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.success-icon {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+
|
|
|
|
|
+ svg {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.success-title {
|
|
|
|
|
+ font-size: 44rpx;
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+ color: $color-text-primary;
|
|
|
|
|
+ margin-bottom: $spacing-xs;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.success-subtitle {
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: $color-text-secondary;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+@keyframes successPop {
|
|
|
|
|
+ 0% {
|
|
|
|
|
+ transform: scale(0.5);
|
|
|
|
|
+ opacity: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ 60% {
|
|
|
|
|
+ transform: scale(1.1);
|
|
|
|
|
+ }
|
|
|
|
|
+ 100% {
|
|
|
|
|
+ transform: scale(1);
|
|
|
|
|
+ opacity: 1;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ========== 商户信息 ========== */
|
|
|
|
|
+.merchant-section {
|
|
|
|
|
+ background: $color-bg-primary;
|
|
|
|
|
+ margin-top: $spacing-md;
|
|
|
|
|
+ padding: $spacing-lg;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.merchant-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-bottom: $spacing-md;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.merchant-icon {
|
|
|
|
|
+ width: 48rpx;
|
|
|
|
|
+ height: 48rpx;
|
|
|
|
|
+ margin-right: $spacing-sm;
|
|
|
|
|
+
|
|
|
|
|
+ svg {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.merchant-name {
|
|
|
|
|
+ font-size: 32rpx;
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+ color: $color-text-primary;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.merchant-info-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: $spacing-sm 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.info-label {
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: $color-text-secondary;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.info-value {
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: $color-text-primary;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ========== 商品信息 ========== */
|
|
|
|
|
+.products-section {
|
|
|
|
|
+ background: $color-bg-primary;
|
|
|
|
|
+ margin-top: $spacing-md;
|
|
|
|
|
+ padding: $spacing-lg;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.section-label {
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: $color-text-secondary;
|
|
|
|
|
+ margin-bottom: $spacing-md;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.product-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: $spacing-sm 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.product-name {
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ color: $color-text-primary;
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ margin-right: $spacing-md;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.product-right {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.product-qty {
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: $color-text-secondary;
|
|
|
|
|
+ margin-right: $spacing-md;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.product-price {
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ color: $color-text-primary;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ min-width: 120rpx;
|
|
|
|
|
+ text-align: right;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ========== 总计支付 ========== */
|
|
|
|
|
+.total-section {
|
|
|
|
|
+ background: $color-bg-primary;
|
|
|
|
|
+ margin-top: $spacing-md;
|
|
|
|
|
+ padding: $spacing-lg;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: baseline;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.total-label {
|
|
|
|
|
+ font-size: 30rpx;
|
|
|
|
|
+ color: $color-text-secondary;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.total-amount-wrapper {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: baseline;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.total-symbol {
|
|
|
|
|
+ font-size: 32rpx;
|
|
|
|
|
+ color: $color-text-primary;
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+ margin-right: 4rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.total-amount {
|
|
|
|
|
+ font-size: 56rpx;
|
|
|
|
|
+ color: $color-text-primary;
|
|
|
|
|
+ font-weight: 800;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ========== 订单详情 ========== */
|
|
|
|
|
+.detail-section {
|
|
|
|
|
+ background: $color-bg-primary;
|
|
|
|
|
+ margin-top: $spacing-md;
|
|
|
|
|
+ padding: $spacing-lg;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.detail-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: flex-start;
|
|
|
|
|
+ padding: $spacing-md 0;
|
|
|
|
|
+ border-bottom: 1rpx solid $color-bg-secondary;
|
|
|
|
|
+
|
|
|
|
|
+ &:last-child {
|
|
|
|
|
+ border-bottom: none;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.detail-row-link {
|
|
|
|
|
+ &:active {
|
|
|
|
|
+ opacity: 0.6;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.detail-label {
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: $color-text-secondary;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ margin-right: $spacing-lg;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.detail-value {
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: $color-text-primary;
|
|
|
|
|
+ text-align: right;
|
|
|
|
|
+ word-break: break-all;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.detail-value-long {
|
|
|
|
|
+ max-width: 420rpx;
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.detail-link {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.link-text {
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: $color-wechat-green;
|
|
|
|
|
+ margin-right: 4rpx;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.link-arrow {
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: $color-wechat-green;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ========== 按时支付记录 ========== */
|
|
|
|
|
+.payment-record-section {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ background: $color-bg-primary;
|
|
|
|
|
+ margin-top: $spacing-md;
|
|
|
|
|
+ padding: $spacing-lg;
|
|
|
|
|
+
|
|
|
|
|
+ &:active {
|
|
|
|
|
+ opacity: 0.7;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.payment-record-text {
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ color: $color-text-primary;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.payment-record-arrow {
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ color: $color-text-tertiary;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|