Files
2026-06-03 16:02:11 +08:00

414 lines
9.4 KiB
Vue
Raw Permalink 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="水电费待付" />
<DateFilter :start="startDate" :end="endDate" @update:start="startDate = $event"
@update:end="endDate = $event" @change="onDateFilterChange" />
<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.billNo">
<view class="bill-left">
<u-checkbox v-model="item.checked" @change="toggleCheck(item)" size="32"
active-color="#EA414A" />
<view class="bill-info">
<text class="bill-name">{{ item.billName }}</text>
<text class="bill-date">缴费截止<text class="date">{{ item.billEndDate }}</text></text>
</view>
</view>
<view class="bill-right">
<text class="amount">{{ formatMoney(item.billAmount) }}</text>
<button class="pay-btn" @click="goPay([item])" :disabled="isPaying">
去支付
</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">
<view class="batch-pay-bar-left"><text>已选 {{ selectedBills.length }} </text></view>
<view class="batch-pay-bar-center">
合计<text class="sumAmount">{{ formatMoney(sumAmount) }}</text>
</view>
<view class="batch-pay-bar-right">
<button class="bottomPayBtn" type="primary" size="small"
@click="goPay(selectedBills)"
:disabled="isPaying">
批量缴费
</button>
</view>
</view>
</view>
</template>
<script>
import DateFilter from '../../components/DatePicker/DateFilter.vue';
export default {
components: { DateFilter },
data() {
return {
pageNo: 1,
pageSize: 10,
bills: [],
isRefreshing: false,
loadStatus: 'more', // ✅ 修复为正确状态
sumAmount: 0,
selectedBills: [],
startDate: "",
endDate: "",
minDate: "2000-01-01",
maxDate: "2199-12-31",
isPaying: false
};
},
onLoad(options) {
// loadBills 移到 onShow 中,等 token 校验通过后再加载
},
async onShow() {
try {
await this.$checkToken(this.$getToken())
this.checkOaAuth()
this.loadBills()
} catch (e) {
return
}
},
// ❌ 已删除冲突的 onReachBottom
methods: {
checkOaAuth() {
const token = this.$getToken()
if (!token) return
const userInfo = uni.getStorageSync('userInfo')
if (!userInfo || !userInfo.oaAuth) {
uni.showModal({
title: '提示',
content: '您还未实名认证,请先完成实名认证',
showCancel: false,
confirmText: '去认证',
success: () => {
uni.redirectTo({ url: '/pages-biz/profile/profile' })
}
})
}
},
loadBills() {
// ✅ 正确判断状态
if (this.loadStatus !== 'more') return;
this.loadStatus = 'loading';
const token = this.$getToken();
let url = '/bill/pageQueryWaeBill'
this.$u.post(url, {
pageNo: this.pageNo,
pageSize: this.pageSize,
startDate: this.startDate,
endDate: this.endDate,
billStatus: '待缴费'
}, {
WT: token
}).then(res => {
const rows = res.data.result || [];
rows.forEach(item => {
item.checked = false;
});
if (this.pageNo === 1) this.bills = [];
this.bills = this.bills.concat(rows);
if (rows.length < this.pageSize) {
this.loadStatus = 'nomore';
} else {
this.pageNo++;
this.loadStatus = 'more'; // ✅ 恢复可加载
}
}).catch(err => {
console.log("获取水电费账单失败:", err);
this.loadStatus = 'more'; // ✅ 异常恢复
})
},
refresh() {
this.isRefreshing = true;
this.pageNo = 1;
this.selectedBills = [];
this.sumAmount = 0;
setTimeout(() => {
this.loadBills();
this.isRefreshing = false;
}, 500);
},
loadMore() {
this.loadBills()
},
onDateFilterChange({ start, end }) {
this.loadStatus = 'more'
this.refresh();
},
formatMoney(val) {
if (val === null || val === undefined || isNaN(val)) return '—';
val = Number(val);
if (val >= 10000) {
return '¥' + (val / 10000).toFixed(2) + '万';
}
return '¥' + val.toFixed(2);
},
toggleCheck(item) {
item.checked = !item.checked;
if (item.checked) {
if (!this.selectedBills.some(b => b.billNo === item.billNo)) {
this.selectedBills.push(item);
}
} else {
this.selectedBills = this.selectedBills.filter(b => b.billNo !== item.billNo);
}
this.calcTotalAmount();
},
calcTotalAmount() {
let sum = 0;
this.selectedBills.forEach(b => {
sum += Number(b.billAmount || 0);
});
this.sumAmount = sum;
},
updateSelected() {
if (!Array.isArray(this.bills)) return;
this.selectedBills = this.bills.filter(b => b.checked);
this.calcTotalAmount();
},
async goPay(billList) {
if (this.isPaying) return;
if (!billList || billList.length === 0) return;
this.isPaying = true;
const token = this.$getToken()
try {
let unpaidBillVos = []
let tempSumAmount = 0
billList.forEach(bill => {
let tempBill = {
billNo: bill.billNo,
bizType: 'wae',
amount: bill.billAmount
}
tempSumAmount += Number(bill.billAmount)
unpaidBillVos.push(tempBill)
})
const params = {
amount: tempSumAmount,
billVoList: unpaidBillVos
}
let url = '/bill/pay'
const res = await this.$u.post(url, params, { WT: token });
if (res.code !== 200) {
uni.showToast({ title: res.msg, icon: 'none' });
this.isPaying = false;
return;
}
const order = res.data;
let orderId = order.mainOrderId
uni.requestPayment({
timeStamp: order.miniPayRequest.timeStamp,
nonceStr: order.miniPayRequest.nonceStr,
package: order.miniPayRequest.packageStr,
signType: order.miniPayRequest.signType,
paySign: order.miniPayRequest.paySign,
success: () => {
billList.forEach(b => b.checked = false);
this.updateSelected();
this.refresh();
this.isPaying = false;
},
fail: (err) => {
this.payFailCallback(err, orderId);
this.isPaying = false;
}
});
} catch (error) {
console.error('支付请求异常', error);
uni.showToast({ title: '支付请求失败', icon: 'none' });
this.isPaying = false;
}
},
// ✅ 修复支付失败回调(参数+接口格式)
payFailCallback(err, orderId) {
let reason = "支付失败";
if (err.errMsg?.includes("cancel")) {
reason = "您已取消支付";
} else if (err.errMsg?.includes("fail")) {
reason = "支付失败,请重试";
}
this.$u.get(`/bill/paycallback`, {
orderId: orderId,
payResult: "FAIL"
}, {
WT: this.$getToken()
}).then(res => {
console.log("回调成功")
}).catch(err => {
console.log("回调失败", err)
})
uni.showToast({ title: reason, icon: 'none' });
}
}
};
</script>
<style lang="scss" scoped>
.pending-bill-page {
background: #f7f8fa;
min-height: 100vh;
padding-top: 175rpx;
box-sizing: border-box;
}
/* ✅ 核心修复:给滚动区域固定高度 */
.scroll-content {
height: calc(100vh - 175rpx - 110rpx);
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: 30rpx;
color: #2D2B2C;
font-weight: 500;
}
.bill-date {
font-size: 24rpx;
color: #86868C;
margin-top: 6rpx;
.date {
font-size: 24rpx;
color: #2D2B2C;
}
}
}
}
.bill-right {
flex-direction: column;
align-items: flex-end;
width: 30%;
.amount {
text-align: center;
height: 28rpx;
line-height: 28rpx;
font-size: 30rpx;
color: #EF8849;
}
.pay-btn {
margin-top: 12rpx;
padding: 0 40rpx;
height: 60rpx;
line-height: 60rpx;
border-radius: 6rpx;
font-size: 30rpx;
color: #fff;
background-color: #F34038;
text-align: center;
}
}
.batch-pay-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 110rpx;
padding: 0 30rpx;
background-color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 -4rpx 10rpx rgba(0, 0, 0, 0.08);
z-index: 999;
.batch-pay-bar-left {
font-size: 28rpx;
color: #86868C;
}
.batch-pay-bar-center {
font-size: 28rpx;
color: #222222;
.sumAmount {
font-size: 28rpx;
color: #ff7f00;
}
}
.batch-pay-bar-right {
flex-direction: column;
align-items: flex-end;
.bottomPayBtn {
height: 60rpx;
line-height: 60rpx;
padding: 0 40rpx;
border-radius: 6rpx;
font-size: 30rpx;
font-weight: bold;
text-align: center;
background: #F34038;
}
}
}
button[disabled] {
opacity: 0.5 !important;
background-color: #ccc !important;
color: #fff !important;
}
.empty {
margin-top: 200rpx;
text-align: center;
}
</style>