Lufaneng 11 months ago
parent 3d4a802ba5
commit d7c95a7d71

@ -1,5 +1,5 @@
{
"name": "lift-wechat",
"name": "lift-drawing-wechat",
"version": "1.0.0",
"description": "电梯图纸生成",
"main": "main.js",
@ -10,7 +10,7 @@
"commit": "git-cz"
},
"keywords": [
"卡叔电梯"
"智能电梯图纸生成"
],
"author": "Lufaneng",
"license": "MIT",

@ -49,7 +49,8 @@
"needLogin": true,
"style" :
{
"navigationBarTitleText" : "我的"
"navigationBarTitleText" : "我的",
"enablePullDownRefresh":true
}
},
{

@ -1,379 +1,316 @@
<template>
<view class="container">
<!-- 顶部筛选标签 -->
<view class="filter-tabs">
<view
class="tab-item"
:class="{ active: activeTab === 'all' }"
@click="switchTab('all')"
>
全部
</view>
<view
class="tab-item"
:class="{ active: activeTab === 'generate' }"
@click="switchTab('generate')"
>
生成
</view>
<view
class="tab-item"
:class="{ active: activeTab === 'member' }"
@click="switchTab('member')"
>
会员
</view>
<view
class="tab-item"
:class="{ active: activeTab === 'other' }"
@click="switchTab('other')"
>
其他
</view>
</view>
<!-- 消费记录列表 -->
<view class="consumption-list">
<view
class="consumption-item"
v-for="item in filteredConsumptions"
:key="item.id"
>
<!-- 消费项目和金额 -->
<view class="item-header">
<view class="item-title">{{ item.title }}</view>
<view
class="item-amount"
:class="{
<view class="container">
<!-- 顶部筛选标签 -->
<uv-sticky bgColor="#fff" offsetTop="0">
<div class="tabBox">
<div class="tabItem" :class="{selected:active==='全部'}" @click="switchTab('全部')"></div>
<div class="tabItem" :class="{selected:active==='生成'}" @click="switchTab('生成')"></div>
<div class="tabItem" :class="{selected:active==='会员'}" @click="switchTab('会员')"></div>
</div>
</uv-sticky>
<!-- 消费记录列表 -->
<view class="consumption-list">
<view class="consumption-item" v-for="item in list" :key="item.id">
<!-- 消费项目和金额 -->
<view class="item-header">
<view class="item-title">{{ item.type }}</view>
<view class="item-amount" :class="{
positive: item.amount > 0,
negative: item.amount < 0,
}"
>
{{ item.amount > 0 ? "+" : "-" }}¥{{
}">
{{ item.amount > 0 ? "+" : "-" }}¥{{
Math.abs(item.amount).toFixed(2)
}}
</view>
</view>
<!-- 消费详情 -->
<view class="item-details">
<view class="detail-row">
<text class="detail-label">消费编号:</text>
<text class="detail-value">{{ item.consumptionNumber }}</text>
</view>
<view class="detail-row">
<text class="detail-label">消费时间:</text>
<text class="detail-value">{{ item.consumptionTime }}</text>
</view>
<view class="balance-row">
<view class="balance-item">
<text class="balance-label">账前金额:</text>
<text class="balance-value">
¥{{ item.beforeBalance.toFixed(2) }}
</text>
</view>
<view class="balance-item">
<text class="balance-label">账后金额:</text>
<text class="balance-value">
¥{{ item.afterBalance.toFixed(2) }}
</text>
</view>
</view>
</view>
</view>
</view>
<!-- 空状态 -->
<view v-if="filteredConsumptions.length === 0" class="empty-state">
<u-icon name="file-text" size="60" color="#ccc"></u-icon>
<text class="empty-text">暂无消费记录</text>
</view>
<!-- 加载更多 -->
<view v-if="hasMore && filteredConsumptions.length > 0" class="load-more">
<u-button
type="default"
size="small"
:loading="loading"
@click="loadMore"
>
{{ loading ? "加载中..." : "加载更多" }}
</u-button>
</view>
</view>
</view>
</view>
<!-- 消费详情 -->
<view class="item-details">
<view class="detail-row">
<text class="detail-label">消费编号:</text>
<text class="detail-value">{{ item.order_no }}</text>
</view>
<view class="detail-row">
<text class="detail-label">消费时间:</text>
<text class="detail-value">{{ item.finished_at ? dayjs(item.finished_at * 1000).format('YYYY-MM-DD HH:mm:ss') :'' }}</text>
</view>
<view class="balance-row">
<view class="balance-item">
<text class="balance-label">账前金额:</text>
<text class="balance-value">
¥{{ item.balance_before_cents / 100 }}
</text>
</view>
<view class="balance-item">
<text class="balance-label">账后金额:</text>
<text class="balance-value">
¥{{ item.balance_after_cents / 100 }}
</text>
</view>
</view>
</view>
</view>
</view>
<!-- 空状态 -->
<view v-if="list.length === 0 && loadingStatus !== 'loading'" class="empty-state">
<u-icon name="file-text" size="60" color="#ccc"></u-icon>
<text class="empty-text">暂无消费记录</text>
</view>
<uv-load-more v-else :status="loadingStatus" />
</view>
</template>
<script setup>
import { computed, onMounted, ref } from "vue";
import { onShow } from "@dcloudio/uni-app";
import { useAuthStore, useUserStore } from "@/store";
import HeaderCustom from "/components/HeaderCustom/HeaderCustom.vue";
import RPC from "@/utils/request";
const authStore = useAuthStore();
const userStore = useUserStore();
//
const activeTab = ref("all");
const loading = ref(false);
const hasMore = ref(true);
const consumptions = ref([
{
id: 1,
title: "乘客电梯图纸生成",
amount: -30.0,
consumptionNumber: "CONS20230516024",
consumptionTime: "2025-05-16 14:30:22",
beforeBalance: 1250.0,
afterBalance: 1220.0,
type: "generate",
},
{
id: 2,
title: "货运电梯图纸生成",
amount: -45.0,
consumptionNumber: "CONS20230516024",
consumptionTime: "2025-05-16 14:30:22",
beforeBalance: 1295.0,
afterBalance: 1250.0,
type: "generate",
},
{
id: 3,
title: "包年会员订阅",
amount: -45.0,
consumptionNumber: "CONS20230516024",
consumptionTime: "2025-05-16 14:30:22",
beforeBalance: 1295.0,
afterBalance: 1250.0,
type: "member",
},
{
id: 4,
title: "账户充值",
amount: 1000.0,
consumptionNumber: "CONS20230516024",
consumptionTime: "2025-05-16 14:30:22",
beforeBalance: 1795.0,
afterBalance: 2795.0,
type: "other",
},
]);
//
const filteredConsumptions = computed(() => {
if (activeTab.value === "all") {
return consumptions.value;
}
return consumptions.value.filter((item) => item.type === activeTab.value);
});
//
const switchTab = (tab) => {
activeTab.value = tab;
};
//
const loadMore = async () => {
if (loading.value) return;
loading.value = true;
try {
// API
// const result = await RPC.get('/api/consumptions', {
// page: currentPage.value + 1,
// type: activeTab.value
// })
//
await new Promise((resolve) => setTimeout(resolve, 1000));
//
hasMore.value = false;
uni.showToast({
title: "没有更多数据了",
icon: "none",
});
} catch (error) {
console.error("加载更多失败:", error);
uni.showToast({
title: "加载失败,请重试",
icon: "none",
});
} finally {
loading.value = false;
}
};
//
const loadConsumptions = async () => {
try {
// API
// const result = await RPC.get('/api/consumptions', {
// type: activeTab.value
// })
// consumptions.value = result.data
} catch (error) {
console.error("加载消费记录失败:", error);
uni.showToast({
title: "加载失败,请重试",
icon: "none",
});
}
};
//
const onRefresh = async () => {
hasMore.value = true;
await loadConsumptions();
};
onMounted(() => {
loadConsumptions();
});
onShow(() => {
//
loadConsumptions();
});
import {
computed,
onMounted,
ref
} from "vue";
import {
onShow,
onReachBottom
} from "@dcloudio/uni-app";
import {
useAuthStore,
useUserStore
} from "@/store";
import HeaderCustom from "/components/HeaderCustom/HeaderCustom.vue";
import RPC from "@/utils/request";
import dayjs from "dayjs";
const authStore = useAuthStore();
const userStore = useUserStore();
const active = ref('全部')
const list = ref([{
id: 1,
title: "乘客电梯图纸生成",
amount: -30.0,
consumptionNumber: "CONS20230516024",
consumptionTime: "2025-05-16 14:30:22",
beforeBalance: 1250.0,
afterBalance: 1220.0,
type: "generate",
},
{
id: 2,
title: "货运电梯图纸生成",
amount: -45.0,
consumptionNumber: "CONS20230516024",
consumptionTime: "2025-05-16 14:30:22",
beforeBalance: 1295.0,
afterBalance: 1250.0,
type: "generate",
},
{
id: 3,
title: "包年会员订阅",
amount: -45.0,
consumptionNumber: "CONS20230516024",
consumptionTime: "2025-05-16 14:30:22",
beforeBalance: 1295.0,
afterBalance: 1250.0,
type: "member",
},
{
id: 4,
title: "账户充值",
amount: 1000.0,
consumptionNumber: "CONS20230516024",
consumptionTime: "2025-05-16 14:30:22",
beforeBalance: 1795.0,
afterBalance: 2795.0,
type: "other",
},
]);
const switchTab = (tab) => {
list.value = []
active.value = tab
page.value = 1
if(tab === '全部') {
typeParams.value = ''
}
if(tab === '生成') {
typeParams.value = '生成'
}
if(tab === '会员') {
typeParams.value = '会员'
}
getList()
}
const page = ref(1)
const typeParams = ref('')
const loadingStatus = ref('loadmore')
const count = ref(0);
//
const getList = () => {
uni.showLoading();
RPC.post('/wallet/txns/list', {
user_id: userStore.userInfo.id,
page:page.value,
size:20,
type:typeParams.value
}).then(res => {
list.value = [...list.value, ...res.list];
count.value = res.total;
if (list.value.length >= count.value) {
loadingStatus.value = "nomore";
} else {
loadingStatus.value = "loadmore";
}
}).catch(() => {
loadingStatus.value = "loadmore";
}).finally(() => {
uni.hideLoading();
})
}
onMounted(() => {
});
onReachBottom(() => {
if (list.value.length >= count.value || loadingStatus.value === "loading")
return;
console.log("上拉加载:");
loadingStatus.value = "loading";
page.value = ++page.value;
getList();
});
onShow(() => {
//
list.value = []
page.value = 1
active.value = '全部'
typeParams.value = ''
getList();
});
</script>
<style lang="scss" scoped>
.container {
font-size: 14px;
min-height: 100vh;
background-color: #f8f8f8;
}
.filter-tabs {
display: flex;
background: white;
padding: 0 16px;
border-bottom: 1px solid #e5e5e5;
.tab-item {
flex: 1;
text-align: center;
padding: 16px 0;
color: #666;
font-size: 14px;
position: relative;
&.active {
color: #4285f4;
font-weight: 500;
&::after {
content: "";
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 20px;
height: 2px;
background: #4285f4;
border-radius: 1px;
}
}
}
}
.consumption-list {
padding: 16px;
.consumption-item {
background: white;
border-radius: 12px;
padding: 16px;
margin-bottom: 12px;
.item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
.item-title {
font-size: 16px;
color: #333;
font-weight: 500;
}
.item-amount {
font-size: 16px;
font-weight: bold;
&.positive {
color: #52c41a;
}
&.negative {
color: #ff4d4f;
}
}
}
.item-details {
.detail-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 6px;
.detail-label {
color: #999;
font-size: 13px;
}
.detail-value {
color: #666;
font-size: 13px;
}
}
.balance-row {
display: flex;
justify-content: space-between;
margin-top: 8px;
.balance-item {
display: flex;
align-items: center;
gap: 4px;
.balance-label {
color: #999;
font-size: 13px;
}
.balance-value {
color: #333;
font-size: 13px;
font-weight: 500;
}
}
}
}
}
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80px 20px;
.empty-text {
color: #999;
font-size: 14px;
margin-top: 16px;
}
}
.container {
font-size: 14px;
min-height: 100vh;
background-color: #f8f8f8;
}
.tabBox {
height: 50px;
background-color: #fff;
display: flex;
.tabItem {
height: 100%;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
flex: 1;
&.selected {
color: #5479ED;
border-bottom: 1px solid #5479ED;
}
}
}
.consumption-list {
padding: 16px;
.consumption-item {
background: white;
border-radius: 12px;
padding: 16px;
margin-bottom: 12px;
.item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
.item-title {
font-size: 16px;
color: #333;
font-weight: 500;
}
.item-amount {
font-size: 16px;
font-weight: bold;
&.positive {
color: #52c41a;
}
&.negative {
color: #ff4d4f;
}
}
}
.item-details {
.detail-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 6px;
.detail-label {
color: #999;
font-size: 13px;
}
.detail-value {
color: #666;
font-size: 13px;
}
}
.balance-row {
display: flex;
justify-content: space-between;
margin-top: 8px;
.balance-item {
display: flex;
align-items: center;
gap: 4px;
.balance-label {
color: #999;
font-size: 13px;
}
.balance-value {
color: #333;
font-size: 13px;
font-weight: 500;
}
}
}
}
}
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80px 20px;
.empty-text {
color: #999;
font-size: 14px;
margin-top: 16px;
}
}
.load-more {
padding: 20px;
text-align: center;
}
</style>

@ -604,19 +604,19 @@
onMounted(() => {
checkEnvironment();
// #ifdef MP-WEIXIN
//
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get("code");
const from = urlParams.get("from");
console.log('from',from)
if (from && from === 'h5') {
handleWechatH5Callback(code);
}
// // #ifdef MP-WEIXIN
// //
// const urlParams = new URLSearchParams(window.location.search);
// const code = urlParams.get("code");
// const from = urlParams.get("from");
// console.log('from',from)
// if (from && from === 'h5') {
// handleWechatH5Callback(code);
// }
// JS-SDK
// initWechatJSSDK();
// #endif
// // JS-SDK
// // initWechatJSSDK();
// // #endif
});
</script>

@ -16,7 +16,9 @@
</view>
<view class="user-id">用户ID: {{userStore.userInfo.id}}</view>
<view class="membership">
会员等级: 年会员 (有效期至: 2026-05-15)
会员等级: <span v-if="memberInfo.is_vip">{{memberInfo.plan?.name}} (:
{{memberInfo.end_at ? dayjs(memberInfo.end_at * 1000).format('YYYY-MM-DD') : ''}})</span><span
v-else></span>
</view>
</view>
</view>
@ -31,7 +33,7 @@
<view class="balance-header">
<view class="balance-label">账户余额</view>
</view>
<view class="balance-amount">¥50.00</view>
<view class="balance-amount">¥{{memberInfo.wallet_balance || 0}}</view>
</div>
<uv-button type="primary" color="#fff" customStyle="color:#000;width:90px" shape="circle" @click="recharge">
充值
@ -45,7 +47,7 @@
:key="item.id" @click="selectPlan(item)">
<view class="tag" v-if="item.tags">{{item.tags}}</view>
<view class="plan-name">{{item.name}}</view>
<view class="plan-price">¥{{item.price_cents}}</view>
<view class="plan-price">¥{{item.price}}</view>
</view>
<!-- <view
class="membership-item"
@ -122,7 +124,8 @@
onMounted
} from "vue";
import {
onShow
onShow,
onPullDownRefresh
} from "@dcloudio/uni-app";
import HeaderCustom from "/components/HeaderCustom/HeaderCustom.vue";
import {
@ -130,11 +133,32 @@
useUserStore
} from "@/store";
import RPC from "@/utils/request";
import dayjs from 'dayjs'
const modal = ref(null);
const authStore = useAuthStore();
const userStore = useUserStore();
const balance = ref(null)
// const getBalance = () => {
// RPC.post('/wallet/balance', {
// user_id: userStore.userInfo.id
// }).then(res => {
// balance.value = res.balance_cents || 0
// })
// }
const memberInfo = ref({})
const getMemberInfo = () => {
uni.showLoading();
RPC.post('/membership/user/info', {
user_id: userStore.userInfo.id
}).then(res => {
memberInfo.value = res || {}
}).finally(() => {
uni.hideLoading();
})
}
//
const selectedPlan = ref("");
const selectedPayment = ref("wxpay"); //
@ -153,7 +177,6 @@
selectedPlan.value = planList.value[0] ? planList.value[0].id : ''
})
}
getPlanList()
//
const selectPlan = (plan) => {
selectedPlan.value = plan.id;
@ -213,7 +236,7 @@
return new Promise((resolve, reject) => {
WeixinJSBridge.invoke(
"getBrandWCPayRequest", {
appId: orderInfo.appId,
appId: 'wxc504638e03981812',
timeStamp: orderInfo.timeStamp,
nonceStr: orderInfo.nonceStr,
package: orderInfo.package,
@ -246,6 +269,20 @@
// #endif
};
function showModalAsync(options) {
return new Promise((resolve, reject) => {
uni.showModal({
...options,
success: (res) => {
resolve(res); // await
},
fail: (err) => {
reject(err); //
}
});
});
}
// H5
const alipayPay = async (orderInfo) => {
// #ifdef H5
@ -320,28 +357,45 @@
// 3.
let paymentResult;
if (selectedPayment.value === "wxpay") {
const orderResult = await RPC.post('/membership/order/pay_by_wechat', {
const res = await uni.login({
provider: 'weixin'
})
const orderResult = await RPC.post('/membership/order/pay_by_wechat_mini', {
code: res.code,
"order_no": orderNum.order_no
})
uni.showLoading({
title: "正在跳转微信支付...",
});
if (1 == 1) {
console.log('orderResult', orderResult)
return
}
paymentResult = await wechatPay(orderResult.wechatPayInfo);
console.log('orderResult', orderResult)
paymentResult = await wechatPay(orderResult);
} else if (selectedPayment.value === "alipay") {
uni.showLoading({
title: "正在跳转支付宝...",
});
paymentResult = await alipayPay(orderResult.alipayInfo);
} else if (selectedPayment.value === 'wallet') {
const res = await showModalAsync({
title: '确认支付',
content: '确认使用钱包余额支付?'
});
//
if (res.confirm) {
paymentResult = await RPC.post('/membership/order/pay_by_wallet', {
order_no: orderNum.order_no
})
console.log('paymentResult', paymentResult)
} else if (res.cancel) {
console.log('用户点击了取消');
paymentResult={success:false}
}
}
uni.hideLoading();
console.log('paymentResult111',paymentResult)
// 4.
if (paymentResult.success) {
if (paymentResult?.success) {
if (paymentResult.redirect) {
// H5
uni.showToast({
@ -351,21 +405,27 @@
});
} else {
//
uni.showToast({
title: "支付成功",
icon: "success",
});
setTimeout(() => {
uni.showToast({
title: "支付成功",
icon: "success",
});
setTimeout(()=>{
getMemberInfo()
},500)
}, 1000)
// getMemberInfo()
//
setTimeout(() => {
//
uni.navigateTo({
url: `/pages/order-detail/order-detail?orderId=${orderResult.orderId}`,
});
//
// loadUserInfo();
}, 1500);
// setTimeout(() => {
//
// uni.navigateTo({
// url: `/pages/order-detail/order-detail?orderId=${orderResult.orderId}`,
// });
//
// loadUserInfo();
// }, 1500);
}
}
} catch (error) {
@ -484,12 +544,20 @@
//
onMounted(() => {
checkEnvironment();
handlePaymentCallback();
getPlanList()
// handlePaymentCallback();
});
//
onShow(() => {
handlePaymentCallback();
// getBalance()
getMemberInfo()
});
onPullDownRefresh(() => {
getPlanList()
// getBalance()
getMemberInfo()
});
</script>

@ -2,22 +2,28 @@
<view class="container">
<uv-sticky bgColor="#fff" offsetTop="0">
<div class="tabBox">
<div class="tabItem" :class="{selected:active==='全部'}" @click="() => active = '全部'"></div>
<div class="tabItem" :class="{selected:active==='已支付'}" @click="() => active = '已支付'">已支付</div>
<div class="tabItem" :class="{selected:active==='待支付'}" @click="() => active = '待支付'">待支付</div>
<div class="tabItem" :class="{selected:active==='全部'}" @click="switchTab('全部')"></div>
<div class="tabItem" :class="{selected:active==='会员购买'}" @click="switchTab('会员购买')"></div>
<div class="tabItem" :class="{selected:active==='钱包充值'}" @click="switchTab('钱包充值')"></div>
</div>
</uv-sticky>
<!-- 订单列表 -->
<view class="order-list">
<view class="order-item" v-for="order in filteredOrders" :key="order.id">
<view class="order-item" v-for="order in list" :key="order.id">
<!-- 订单头部 -->
<view class="order-header">
<view class="order-info">
<text class="order-number">订单编号: {{ order.orderNumber }}</text>
<view class="order-type-tag"></view>
<text class="order-number">订单编号: {{ order.order_no }}</text>
<view class="order-type-tag" @click="copyOrderNo(order.order_no)"></view>
</view>
<view class="order-status" :class="order.status">
{{ order.statusText }}
<view class="order-status" :class="{paid:order.status === 'paid',pending:order.status === 'created' || order.status === 'pending',
cancelled:order.status === 'failed' || order.status === 'canceled' || order.status === 'refunded'}">
<span v-if="order.status === 'created'"></span>
<span v-if="order.status === 'pending'"></span>
<span v-if="order.status === 'paid'"></span>
<span v-if="order.status === 'failed'"></span>
<span v-if="order.status === 'canceled'"></span>
<span v-if="order.status === 'refunded'">退</span>
</view>
</view>
@ -25,50 +31,58 @@
<view class="order-details">
<view class="detail-row">
<text class="label">用户名称:</text>
<text class="value">{{ order.userName }}</text>
<text class="value">{{ order.user_name }}</text>
</view>
<view class="detail-row">
<text class="label">用户ID:</text>
<text class="value">{{ order.userId }}</text>
<text class="value">{{ order.user_id }}</text>
</view>
<view class="detail-row">
<text class="label">订单类型:</text>
<text class="value">{{ order.orderType }}</text>
<text class="value">{{ order.order_type }}</text>
</view>
<view class="detail-row">
<text class="label">订单金额:</text>
<text class="value price">¥{{ order.amount }}</text>
</view>
<view class="detail-row">
<text class="label">支付渠道:</text>
<text class="value">
<template v-if="order.pay_channel === 'wallet'"></template>
<template v-if="order.pay_channel === 'wxpay'"></template>
<template v-if="order.pay_channel === 'alipay'"></template>
</text>
</view>
<view class="detail-row" v-if="order.discount > 0">
<!-- <view class="detail-row" v-if="order.discount > 0">
<text class="label">折扣金额:</text>
<text class="value discount">-¥{{ order.discount }}</text>
</view>
<view class="detail-row">
</view> -->
<!-- <view class="detail-row">
<text class="label">实付金额:</text>
<text class="value final-price">¥{{ order.finalAmount }}</text>
</view>
</view> -->
<view class="detail-row">
<text class="label">{{ order.status === 'pending' ? '创建时间:' : '支付时间:' }}</text>
<text class="value">{{ order.payTime }}</text>
<text class="label">创建时间</text>
<text class="value">{{ order.created_at ? dayjs(order.created_at * 1000).format('YYYY-MM-DD HH:mm:ss') :'' }}</text>
</view>
</view>
<!-- 订单操作 -->
<view class="order-actions">
<view class="order-actions" v-if="order.status === 'pending' || order.status === 'created'">
<div>
<div class="countdown-text" v-if="order.status === 'pending'">: {{ order.countdown }}
</div>
<!-- <div class="countdown-text" v-if="order.status === 'pending'">: {{ order.countdown }}
</div> -->
</div>
<div class="buttonBox">
<template v-if="order.status === 'pending'">
<uv-button type="default" size="small" @click="cancelOrder(order)">
<template v-if="order.status === 'pending' || order.status === 'created'">
<uv-button type="error" size="small" @click="cancelOrder(order)">
取消订单
</uv-button>
<uv-button type="error" size="small" @click="payOrder(order)">
<uv-button type="primary" size="small" @click="payOrder(order)">
去支付
</uv-button>
</template>
<template v-else>
<!-- <template v-else>
<uv-button type="default" size="small" @click="deleteOrder(order)">
删除订单
@ -76,40 +90,18 @@
<uv-button type="primary" color="#3F70FF" size="small" @click="viewOrderDetail(order)">
查看详情
</uv-button>
</template>
</template> -->
</div>
</view>
<!-- 待支付订单底部 -->
<!-- <view v-if="order.status === 'pending'" class="pending-footer">
<view class="countdown">
<text class="countdown-text">支付剩余时间: {{ order.countdown }}</text>
</view>
<view class="pending-actions">
<uv-button
type="default"
size="large"
@click="cancelOrder(order)"
>
取消订单
</uv-button>
<uv-button
type="error"
size="large"
@click="payOrder(order)"
>
去支付
</uv-button>
</view>
</view> -->
</view>
</view>
<!-- 空状态 -->
<view v-if="filteredOrders.length === 0" class="empty-state">
<view v-if="list.length === 0 && loadingStatus !== 'loading'" class="empty-state">
<u-icon name="file-text" size="60" color="#ccc"></u-icon>
<text class="empty-text">暂无订单记录</text>
</view>
</view>
<uv-load-more v-else :status="loadingStatus" />
</view>
</template>
@ -120,7 +112,8 @@
ref
} from "vue";
import {
onShow
onShow,
onReachBottom
} from "@dcloudio/uni-app";
import {
useAuthStore,
@ -128,14 +121,26 @@
} from "@/store";
import HeaderCustom from '/components/HeaderCustom/HeaderCustom.vue'
import RPC from "@/utils/request";
import dayjs from "dayjs";
const active = ref('全部')
const authStore = useAuthStore()
const userStore = useUserStore()
const userStore = useUserStore()
const copyOrderNo = (orderNo) => {
uni.setClipboardData({
data: orderNo,
success: () => {
uni.showToast({
title: '订单号已复制',
icon: 'success'
})
}
})
}
//
const activeTab = ref('all')
const orders = ref([{
const list = ref([{
id: 1,
orderNumber: 'ORD20230515001',
typeLabel: '续费',
@ -183,17 +188,17 @@
}
])
//
const filteredOrders = computed(() => {
if (activeTab.value === 'all') {
return orders.value
}
return orders.value.filter(order => order.type === activeTab.value)
})
//
const switchTab = (tab) => {
activeTab.value = tab
list.value = []
active.value = tab
page.value = 1
if(tab === '全部') {
typeParams.value = ''
} else {
typeParams.value = tab
}
getList()
}
//
@ -212,13 +217,12 @@
if (res.confirm) {
try {
// API
// await RPC.post('/api/order/cancel', { orderId: order.id })
await RPC.post('/membership/order/cancel', { order_no: order.order_no })
//
const index = orders.value.findIndex(item => item.id === order.id)
const index = list.value.findIndex(item => item.id === order.id)
if (index !== -1) {
orders.value[index].status = 'cancelled'
orders.value[index].statusText = '已取消'
list.value[index].status = 'canceled'
}
uni.showToast({
@ -272,33 +276,63 @@
//
const payOrder = (order) => {
uni.navigateTo({
url: `/pages/payment/payment?orderId=${order.id}`
uni.showModal({
title: '确认支付',
content: '确定继续支付这个订单吗?',
success: async (res) => {
if (res.confirm) {
}
}
})
}
//
const loadOrders = async () => {
try {
// API
// const result = await RPC.get('/api/orders')
// orders.value = result.data
} catch (error) {
console.error('加载订单失败:', error)
uni.showToast({
title: '加载失败,请重试',
icon: 'none'
})
}
const page = ref(1)
const typeParams = ref('')
const loadingStatus = ref('loadmore')
const count = ref(0);
const getList = () => {
uni.showLoading();
RPC.post('/membership/order/list', {
user_id: userStore.userInfo.id,
page:page.value,
order_type:typeParams.value,
size:20
}).then(res => {
list.value = [...list.value, ...res.list];
count.value = res.total;
if (list.value.length >= count.value) {
loadingStatus.value = "nomore";
} else {
loadingStatus.value = "loadmore";
}
}).catch(() => {
loadingStatus.value = "loadmore";
}).finally(() => {
uni.hideLoading();
})
}
onMounted(() => {
loadOrders()
})
})
onReachBottom(() => {
if (list.value.length >= count.value || loadingStatus.value === "loading")
return;
console.log("上拉加载:");
loadingStatus.value = "loading";
page.value = ++page.value;
getList();
});
onShow(() => {
//
loadOrders()
//
list.value = []
page.value = 1
active.value = '全部'
typeParams.value = ''
getList()
})
</script>

@ -74,7 +74,7 @@
</view>
<!-- 加载更多 -->
<uv-load-more :status="loadingStatus" @loadmore="loadmore" />
<uv-load-more v-else :status="loadingStatus" @loadmore="loadmore" />
</view>
</template>
@ -128,7 +128,7 @@ const downloadRecord = (record) => {
// #ifdef MP-WEIXIN
// App使uni.downloadFile
uni.downloadFile({
url: 'https://ksdt-1255846884.cos.ap-shanghai.myqcloud.com/lift-result/2025/09/24/d6180add4cd94875a1854a4febce8966.pdf',
url: record.result_url,
success: (res) => {
console.log(res);
if (res.statusCode === 200) {
@ -200,6 +200,7 @@ const deleteRecord = (record) => {
//
const loadRecords = async () => {
uni.showLoading();
loadingStatus.value = "loading";
RPC.post("/planned_list", { page: page.value, page_size: 20 })
.then((res) => {
@ -213,7 +214,9 @@ const loadRecords = async () => {
})
.catch(() => {
loadingStatus.value = "loadmore";
});
}).finally(() => {
uni.hideLoading();
});
};
//

@ -0,0 +1,40 @@
订单列表的
"id": it.ID, // 订单ID
"order_no": it.OrderNo, // 订单号M=会员订单R=充值订单)
"user_id": it.UserID, // 用户ID
"user_name": userNameMap[it.UserID], // 用户名
"plan_id": it.PlanID, // 套餐ID充值订单为0
"plan_name": planName, // 套餐名称(充值订单固定为“钱包充值”)
"order_type": it.OrderType, // 订单类型:会员购买/钱包充值(中文)
"amount_cents": it.AmountCents.ToInt64(), // 订单金额(分)
"amount": it.AmountCents.String(), // 订单金额(元,字符串,保留两位小数)
"pay_channel": it.PayChannel, // 支付渠道wallet|wxpay|alipay|other
"status": it.Status, // 订单状态created|paid|canceled|refunded
"pay_time": it.PayTime, // 支付时间Unix 时间戳,秒)
"transaction_id": it.TransactionID, // 第三方交易号/平台流水号
"remark": it.Remark, // 备注
"created_at": it.CreatedAt, // 创建时间Unix 时间戳,秒)
"updated_at": it.UpdatedAt, // 更新时间Unix 时间戳,秒)
消费列表
"id": it.ID, // 流水ID
"user_id": it.UserID, // 用户ID
"user_name": userName, // 用户名
"type": it.Type, // 交易类型recharge(充值)|purchase(消费)
"amount_cents": it.AmountCents.ToInt64(), // 金额(分)
"amount": it.AmountCents.String(), // 金额(元,字符串,保留两位小数)
"related_order_id": it.RelatedOrderID, // 关联的订单ID可为空
"order_no": it.OrderNo, // 关联订单号M* 会员订单 / R* 充值订单)
"pay_channel": it.PayChannel, // 支付渠道wallet|wxpay|alipay|other
"status": it.Status, // 交易状态success|failed|pending
"remark": it.Remark, // 备注
"balance_before_cents": it.BalanceBeforeCents.ToInt64(), // 变动前余额(分)
"balance_after_cents": it.BalanceAfterCents.ToInt64(), // 变动后余额(分)
"finished_at": it.FinishedAt, // 完成时间Unix 时间戳,秒)
"external_txn_id": it.ExternalTxnID, // 外部交易号(第三方平台返回)
"currency": it.Currency, // 币种(默认 CNY
"created_at": it.CreatedAt, // 创建时间Unix 时间戳,秒)
})

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save