文件
fenleixinxi/uniapp/pages/member/orders.vue
MiAn 02fc28613a feat: 深度强化微信小程序端虚拟支付提审防审模式
1. App.vue 启动时立即预加载 uiConfig,杜绝首屏网络延时导致瞬间闪现付费会员入口
2. 会员中心 (member/index.vue):在提审防审模式下直接展示纯净【便民服务指南】卡片,杜绝任何 VIP 皇冠、会员标价、折扣与充值入口
3. 个人中心 (mine/index.vue):提审防审模式下彻底隐藏会员卡片与我的余额,紧凑上移卡片布局
4. 订单明细、充值页与消息中心增加防审合规兼容,避免误触发任何虚拟支付诱导
2026-11-02 17:42:49 +08:00

363 行
8.5 KiB
Vue

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<template>
<view class="orders fc-page">
<!-- 规范化顶部导航 -->
<fc-navbar title="我的订单" theme="gradient" :show-back="true" />
<view v-if="!isAudit" class="orders__tabs">
<view v-for="t in tabs" :key="t.value" class="orders__tab"
:class="{ 'orders__tab--active': type === t.value }" @click="type = t.value">
<text>{{ t.label }}</text>
</view>
</view>
<!-- 未登录友好引导 -->
<view v-if="!isLogin" class="orders__unlogin-box">
<fc-empty icon="receipt" text="登录后查看我的订单记录" />
<button class="orders__unlogin-btn" @click="goLogin">
<text class="orders__unlogin-btn-txt">立即登录</text>
</button>
</view>
<fc-empty v-else-if="!list.length" icon="receipt" text="暂无订单记录" />
<view v-else class="orders__list">
<view v-for="o in list" :key="o.id" class="orders__item" @click="detail(o)">
<view class="orders__item-head">
<text class="orders__no">订单号:{{ o.orderNo }}</text>
<text class="orders__status" :class="`orders__status--${o.status}`">{{ statusText(o.status) }}</text>
</view>
<view class="orders__item-body">
<view class="orders__icon">
<image class="fc-icon fc-icon--lg" :src="iconUrl(orderIconKey(o.type))" mode="aspectFit" />
</view>
<view class="orders__info">
<text class="orders__title">{{ o.title }}</text>
<text class="orders__time">{{ timeText(o.createdAt) }}</text>
</view>
<view class="fc-price">
<text class="fc-price__symbol">¥</text>
<text class="orders__amount">{{ o.amount }}</text>
</view>
</view>
<view class="orders__item-foot" @click.stop>
<text class="orders__pay-type">{{ payText(o.payType) }}</text>
<view class="orders__actions">
<template v-if="o.status === 'pending'">
<view class="orders__btn orders__btn--cancel" @click="cancelOrder(o)"><text>取消订单</text></view>
<view class="orders__btn orders__btn--pay" @click="payOrder(o)"><text>去支付</text></view>
</template>
<view v-else class="orders__btn orders__btn--ghost" @click="detail(o)"><text>查看详情</text></view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import FcNavbar from '@/components/fc-navbar/fc-navbar.vue'
import FcEmpty from '@/components/fc-empty/fc-empty.vue'
import memberApi from '@/common/api/member.js'
import orderApi from '@/common/api/order.js'
import { ORDER_TEXT, ORDER_ICON_KEY } from '@/common/constants/ui.js'
import { formatTime } from '@/common/utils/format.js'
import { iconUrl, loadUiConfig, uiState } from '@/common/store/ui.js'
import { pay } from '@/common/utils/pay.js'
export default {
components: { FcNavbar, FcEmpty },
data() {
return {
type: 'all',
all: [],
}
},
computed: {
/** 提审防审模式开关 */
isAudit() {
// #ifdef MP-WEIXIN
return uiState.virtualPayAudit !== false
// #endif
return false
},
/** 是否已登录 */
isLogin() {
const token = uni.getStorageSync('token') || uni.getStorageSync('fc_token') || ''
return !!token
},
/** 动态选项卡:提审模式彻底隐藏会员与充值订单标签 */
tabs() {
if (this.isAudit) {
return [
{ label: '全部订单', value: 'all' },
{ label: '发布订单', value: 'post' },
]
}
return [
{ label: '全部', value: 'all' },
{ label: '发布订单', value: 'post' },
{ label: '会员订单', value: 'member' },
{ label: '充值订单', value: 'recharge' },
]
},
/** 订单列表(提审模式过滤掉虚拟支付相关历史记录) */
list() {
let rows = this.all || []
if (this.isAudit) {
rows = rows.filter(o => o.type !== 'member' && o.type !== 'recharge')
}
if (this.type === 'all') return rows
return rows.filter((o) => o.type === this.type)
},
},
onLoad() {
loadUiConfig()
},
onShow() {
this.fetch()
},
methods: {
iconUrl,
async fetch() {
if (!this.isLogin) {
this.all = []
return
}
try {
const res = await memberApi.orders({ page: 1, size: 50 })
this.all = (res && res.list) || []
} catch (e) {
// 静默置空,杜绝未登录或网络波动时弹出生硬 Toast
this.all = []
}
},
goLogin() {
uni.navigateTo({ url: '/pages/auth/login' })
},
statusText(s) {
return ORDER_TEXT[s] || s
},
payText(t) {
return t === 'balance' ? '余额支付' : '微信支付'
},
timeText(t) {
return formatTime(t)
},
orderIconKey(t) {
return ORDER_ICON_KEY[t] || 'order-other'
},
/**
* 待支付订单去支付
* @param {Object} o 订单对象
* @returns {Promise<void>}
*/
async payOrder(o) {
if (!o || !o.orderNo) return
try {
uni.showLoading({ title: '正在调起支付…' })
await pay({ orderNo: o.orderNo, payType: o.payType || 'wxpay' })
uni.hideLoading()
uni.showToast({ title: '支付成功', icon: 'success' })
await this.fetch()
} catch (e) {
uni.hideLoading()
uni.showToast({ title: e.message || '支付未完成', icon: 'none' })
}
},
/**
* 主动取消待支付订单
* @param {Object} o 订单对象
*/
cancelOrder(o) {
if (!o || !o.orderNo) return
uni.showModal({
title: '提示',
content: '确定要取消此订单吗?',
confirmColor: '#00E070',
cancelColor: '#666666',
success: async (res) => {
if (res.confirm) {
try {
uni.showLoading({ title: '正在取消…' })
await orderApi.cancel({ orderNo: o.orderNo })
uni.hideLoading()
uni.showToast({ title: '订单已取消', icon: 'success' })
await this.fetch()
} catch (e) {
uni.hideLoading()
uni.showToast({ title: e.message || '取消失败', icon: 'none' })
}
}
},
})
},
/**
* 跳转订单详情页面
* @param {Object} o 订单对象
*/
detail(o) {
if (!o || !o.orderNo) return
uni.navigateTo({
url: `/pages/order/detail?orderNo=${o.orderNo}`,
})
},
},
}
</script>
<style lang="scss" scoped>
.orders__tabs {
display: flex;
background: #ffffff;
border-bottom: 2rpx solid $fc-border;
}
.orders__tab {
flex: 1;
height: 88rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: $fc-font-sm;
color: $fc-text-secondary;
&--active {
color: $fc-primary-text;
font-weight: 700;
position: relative;
}
}
.orders__list {
padding: 20rpx 0;
}
.orders__item {
margin: 0 24rpx 20rpx;
padding: 24rpx;
background: #ffffff;
border-radius: $fc-radius-lg;
box-shadow: $fc-shadow;
}
.orders__item-head {
display: flex;
align-items: center;
justify-content: space-between;
}
.orders__no {
font-size: $fc-font-xs;
color: $fc-text-placeholder;
}
.orders__status {
font-size: $fc-font-sm;
font-weight: 600;
color: $fc-primary-text;
&--paid {
color: $fc-success;
}
&--pending {
color: $fc-warning;
}
&--refunded {
color: $fc-danger;
}
&--closed {
color: #999999;
}
}
.orders__item-body {
display: flex;
align-items: center;
margin-top: 20rpx;
}
.orders__icon {
width: 96rpx;
height: 96rpx;
flex: 0 0 96rpx;
border-radius: 20rpx;
background: $fc-gradient-soft;
display: flex;
align-items: center;
justify-content: center;
}
.orders__info {
flex: 1;
margin-left: 20rpx;
}
.orders__title {
display: block;
font-size: $fc-font;
font-weight: 600;
color: $fc-text;
}
.orders__time {
display: block;
margin-top: 8rpx;
font-size: $fc-font-xs;
color: $fc-text-placeholder;
}
.orders__amount {
font-size: 36rpx;
}
.orders__item-foot {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
padding-top: 20rpx;
border-top: 2rpx solid $fc-border;
}
.orders__pay-type {
font-size: $fc-font-xs;
color: $fc-text-secondary;
}
.orders__actions {
display: flex;
align-items: center;
}
.orders__btn {
padding: 12rpx 28rpx;
border-radius: $fc-radius-pill;
font-size: $fc-font-sm;
font-weight: 600;
margin-left: 16rpx;
&--pay {
background: #00E070;
color: #04301E;
}
&--cancel {
background: #ffffff;
border: 2rpx solid #D8E2DC;
color: #666666;
}
&--ghost {
background: #ffffff;
border: 2rpx solid $fc-primary-text;
color: $fc-primary-text;
}
}
/* 未登录空状态引导 */
.orders__unlogin-box {
display: flex;
flex-direction: column;
align-items: center;
padding: 40rpx 32rpx;
}
.orders__unlogin-btn {
margin-top: -20rpx;
height: 72rpx;
padding: 0 48rpx;
border-radius: 36rpx;
background: #00D26A;
display: flex;
align-items: center;
justify-content: center;
border: none;
box-shadow: 0 4rpx 16rpx rgba(0, 210, 106, 0.25);
}
.orders__unlogin-btn-txt {
font-size: 26rpx;
font-weight: 700;
color: #ffffff;
}
</style>