Files
RentWeAppFront/pages/unpaid/unpaid.vue
2025-11-14 11:39:33 +08:00

318 lines
7.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="pending-bill-page">
<!-- 自定义导航栏 -->
<custom-navbar title="我的待付" />
<scroll-view
scroll-y
class="scroll-content"
:refresher-enabled="true"
:refresher-triggered="isRefreshing"
@refresherrefresh="refresh"
@scrolltolower="loadMore"
>
<view v-if="bills.length > 0">
<view
class="bill-item"
v-for="item in bills"
:key="item.id"
>
<!-- 左侧勾选 + 信息 -->
<view class="bill-left">
<u-checkbox
v-model="item.checked"
@change="updateSelected"
size="32"
active-color="#007aff"
/>
<view class="bill-info">
<text class="bill-name">{{ item.feeName }}</text>
<text class="bill-date">缴费截止{{ item.dueDate }}</text>
</view>
</view>
<!-- 右侧金额 + 支付按钮 -->
<view class="bill-right">
<text class="amount">{{ formatMoney(item.amount) }}</text>
<u-button
size="small"
type="primary"
class="pay-btn"
@click="goPayTest([item])"
>去支付</u-button>
</view>
</view>
</view>
<view v-else class="empty">
<u-empty mode="list" text="暂无待支付账单" />
</view>
<u-loadmore :status="loadStatus" />
</scroll-view>
<!-- 底部批量支付栏 -->
<view v-if="selectedBills.length > 0" class="batch-pay-bar">
<text>已选 {{ selectedBills.length }} </text>
<u-button type="primary" size="small" @click="goPayTest(selectedBills)">
批量缴费
</u-button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
bills: [],
isRefreshing: false,
loadStatus: 'more',
selectedBills: [], // 勾选的账单集合
};
},
onLoad() {
this.loadBills();
},
methods: {
loadBills() {
this.bills = [
{
id: 'p101',
feeName: '第一期租金2024.12.01-2024.12.31',
dueDate: '2024-12-15',
amount: 3000,
checked: false,
},
{
id: 'p102',
feeName: '第二期物业费2025.01.01-2025.01.31',
dueDate: '2025-01-15',
amount: 500,
checked: false,
},
];
this.updateSelected();
},
refresh() {
this.isRefreshing = true;
setTimeout(() => {
this.loadBills();
this.isRefreshing = false;
}, 1000);
},
loadMore() {
this.loadStatus = 'noMore';
},
formatMoney(val) {
if (!val && val !== 0) return '—';
return '¥' + Number(val).toFixed(2);
},
updateSelected() {
this.selectedBills = [];
this.selectedBills = this.bills.filter((item) => item.checked);
console.log(this.selectedBill.length)
},
goPayTest(billList) {
if (!billList || billList.length === 0) return;
// 模拟后台生成订单返回
const order = {
timeStamp: String(Date.now()), // 时间戳
nonceStr: Math.random().toString(36).substr(2, 15), // 随机字符串
package: 'prepay_id=TEST1234567890', // 模拟预支付ID
signType: 'MD5',
paySign: 'TEST_SIGN', // 模拟签名
};
// 调用微信支付接口(测试)
uni.requestPayment({
...order,
success: () => {
uni.showToast({ title: '支付成功(测试)', icon: 'success' });
// 清空勾选状态
billList.forEach(b => b.checked = false);
this.updateSelected();
// 刷新列表(可选)
this.loadBills();
},
fail: () => {
uni.showToast({ title: '支付失败(测试)', icon: 'none' });
}
});
},
async goPay(billList) {
if (!billList || billList.length === 0) return;
try {
// 1. 请求后台生成订单
const res = await uni.request({
url: 'https://api.example.com/payments/create',
method: 'POST',
data: {
userId: this.userId,
bills: billList.map(b => b.id),
}
});
if (res[1].data.code !== 0) {
uni.showToast({ title: res[1].data.msg, icon: 'none' });
return;
}
const order = res[1].data.data; // 后台返回的支付参数
// 2. 调用微信支付
uni.requestPayment({
timeStamp: order.timeStamp,
nonceStr: order.nonceStr,
package: order.package,
signType: order.signType,
paySign: order.paySign,
success: () => {
uni.showToast({ title: '支付成功', icon: 'success' });
// 更新勾选状态
billList.forEach(b => b.checked = false);
this.updateSelected();
// 刷新列表
this.loadBills();
},
fail: () => {
uni.showToast({ title: '支付失败', icon: 'none' });
}
});
} catch (error) {
console.error('支付请求失败', error);
uni.showToast({ title: '支付请求失败', icon: 'none' });
}
},
},
computed: {
/** ✅ 已勾选账单列表 */
selectedBills() {
return this.bills.filter(item => item.checked);
},
/** ✅ 已勾选数量 */
selectedCount() {
return this.selectedBills.length;
},
/** ✅ 全选状态(双向绑定) */
allSelected: {
get() {
return this.bills.length > 0 && this.selectedBills.length === this.bills.length;
},
set(val) {
// 用 this.$set 保证响应式更新
this.bills.forEach((item, index) => {
this.$set(this.bills, index, { ...item, checked: val });
});
}
}
}
};
</script>
<style lang="scss" scoped>
.pending-bill-page {
background: #f7f8fa;
min-height: 100vh;
padding-top: 175rpx; /* 自定义导航栏高度 */
}
.scroll-content {
padding: 20rpx;
box-sizing: border-box;
}
.bill-item {
display: flex;
justify-content: space-between;
background: #fff;
margin-bottom: 20rpx;
border-radius: 12rpx;
padding: 20rpx;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.05);
}
.bill-left {
display: flex;
align-items: center;
.bill-info {
display: flex;
flex-direction: column;
margin-left: 12rpx;
.bill-name {
font-size: 28rpx;
color: #333;
font-weight: bold;
}
.bill-date {
font-size: 24rpx;
color: #666;
margin-top: 6rpx;
}
}
}
.bill-right {
display: flex;
flex-direction: column;
align-items: flex-end;
.amount {
font-size: 28rpx;
color: #333;
}
.pay-btn {
margin-top: 12rpx;
padding: 0 24rpx;
height: 60rpx;
line-height: 60rpx;
border-radius: 30rpx; // 圆角
font-size: 28rpx;
color: #fff;
background-color: #007aff; // 蓝色主色
text-align: center;
}
}
.batch-pay-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #fff;
height: 80rpx;
padding: 0 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 -2rpx 6rpx rgba(0, 0, 0, 0.08);
z-index: 999;
u-button {
height: 60rpx;
line-height: 60rpx;
padding: 0 30rpx;
border-radius: 30rpx;
font-size: 28rpx;
text-align: center;
}
}
.empty {
margin-top: 200rpx;
text-align: center;
}
</style>