Files
property-resident-side/property-uniapp-project/pageSubPack/payment-list/paymentIndex.vue
2026-08-20 15:41:27 +08:00

599 lines
13 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="contentStyle">
<view class="topbox">
<image class="titleImg" src="https://wuye.ckdzkj.com/images/propertyImgs/payTitle.png"></image>
<image class="payImg" src="https://wuye.ckdzkj.com/images/propertyImgs/payImg.png"></image>
<!-- 小区选择 -->
<view class="community-bar" @click="navigateToSelectHome">
<image src="https://wuye.ckdzkj.com/images/home/adress.png" class="location-icon"></image>
<text class="community-name">{{ currentCommunity }}</text>
<u-icon name="arrow-down-fill" size="14" color="#222222"></u-icon>
</view>
</view>
<view class="page">
<view class="container">
<!-- /电费列表 -->
<scroll-view class="details-scroll" scroll-y="true" @scrolltolower="onPayLoadMore">
<view class="bill-list">
<template v-if="paymentList.length != 0">
<view class="bill-item" @click="goToBill(item)" v-for="item,index in paymentList" :key="index">
<image class="billIcon" src="https://wuye.ckdzkj.com/images/propertyImgs/water.png"
v-if="item.type=='水费'"></image>
<image class="billIcon" src="https://wuye.ckdzkj.com/images/propertyImgs/electric.png"
v-if="item.type=='电费'"></image>
<view class="bill-info">
<view class="bill-title">{{item.type}}
<view class="bill-status debt" v-if="item.balance<0">已欠费</view>
<text :class="item.balance<0 ? 'balance-debt' : 'balance-normal'">(余额{{item.balance|| 0.00}})</text>
</view>
<view class="bill-desc">{{item.villageName+item.buildingName+item.fullAddress}}</view>
</view>
<view class="arrow"></view>
</view>
<!-- 滚动加载状态 -->
<view class="load-more-status" v-if="payLoadingMore">
<text class="loading-text">加载中...</text>
</view>
<view class="load-more-status" v-else-if="!payHasMore && paymentList.length >= payPageSize">
<text class="no-more-text"> 没有更多了 </text>
</view>
</template>
<view class="empty-state" v-else>
<text class="empty-text">暂无数据</text>
</view>
</view>
</scroll-view>
<!-- 物业费/垃圾处理费列表 -->
<scroll-view class="details-scroll-bill" scroll-y="true" @scrolltolower="onLoadMore">
<view class="bill-list">
<template v-if="detailslist.length != 0">
<view class="bill-item" :class="{ 'bill-paid': !item.amount }" @click="!item.amount ? null : goToBill(item)" v-for="item,index in detailslist" :key="index">
<image class="billIcon" src="https://wuye.ckdzkj.com/images/propertyImgs/property.png"></image>
<view class="bill-info">
<view class="bill-title">{{ item.name }}
<view class="bill-status debt" v-if="item.amount">未缴纳</view>
<view class="bill-status done" v-if="!item.amount">已完成</view>
<!-- <view class="bill-amount">({{item.amount}})</view> -->
</view>
<view class="bill-desc">{{ item.unitNo}}</view>
</view>
<view class="arrow"></view>
</view>
<!-- 滚动加载状态 -->
<view class="load-more-status" v-if="loadingMore">
<text class="loading-text">加载中...</text>
</view>
<view class="load-more-status" v-else-if="!hasMore && detailslist.length >= pageSize">
<text class="no-more-text"> 没有更多了 </text>
</view>
</template>
<view class="empty-state" v-else>
<text class="empty-text">暂无数据</text>
</view>
</view>
</scroll-view>
<!-- 新增缴费区域 -->
<view class="add-section">
<view class="section-header">
<text class="section-title">新增缴费</text>
<text class="record-link" @click="goToRecord">缴费记录</text>
</view>
<view class="grid-list">
<view class="grid-item" v-for="(item, index) in addList" :key="index" @click="goToAdd(item)">
<view class="icon-box" :class="item.iconClass">
<image class="iconStyle" :src="item.icon"></image>
</view>
<!-- <text class="item-name">{{ item.name +'费'}}</text> -->
<text class="item-name">{{ item.name}}</text>
</view>
</view>
</view>
<view style="width: 100%;height: 30rpx;"></view>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onShow, onLoad, onBackPress, onUnload, onPullDownRefresh } from '@dcloudio/uni-app'
import { getTopUpDetails, getTopUpSelectByResident } from '/pageSubPack/api/apiSub.js'
import { getCurrentVillage } from '/pageSubPack/api/api.js'
// 响应式数据
const detailslist = ref([])
const pageNum = ref(1)
const pageSize = ref(5)
const total = ref(0)
const hasMore = ref(true)
const loadingMore = ref(false)
const payPageNum = ref(1)
const payPageSize = ref(5)
const payTotal = ref(0)
const payHasMore = ref(true)
const payLoadingMore = ref(false)
// 小区选择
const currentCommunity = ref('请绑定房屋')
const paymentList = ref([
{
id: 3,
name: '电费',
status: '已欠费',
address: '山东省日照市东港区桂花园别墅2号楼2层',
icon: "https://wuye.ckdzkj.com/images/propertyImgs/electric.png",
}
])
const addList = ref([
{
name: "水表",
type: "water",
icon: "https://wuye.ckdzkj.com/images/propertyImgs/water.png",
iconClass: "water"
},
{
name: "电表",
type: "electric",
icon: "https://wuye.ckdzkj.com/images/propertyImgs/electric.png",
iconClass: "electric"
},
])
// 获取当前小区
const getCurrentCommunityData = () => {
getCurrentVillage().then(res => {
if (res.code === 200 && res.data && res.data.villageId) {
currentCommunity.value = res.data.villageName || '未命名小区'
} else {
currentCommunity.value = '请绑定房屋'
}
}).catch(() => {})
}
// 接收小区切换事件
const slelctHomeData = (data) => {
if (data.name) currentCommunity.value = data.name
if (data.villageId) {
uni.setStorageSync('currentVillageId', data.villageId)
}
getBillDetails()
getPayList()
}
// 跳转小区选择
const navigateToSelectHome = () => {
const cachedVillageId = uni.getStorageSync('currentVillageId')
if (!cachedVillageId || cachedVillageId === '0' || cachedVillageId === 0) {
uni.navigateTo({ url: '/pageSubPack/my/myHouseIndex' })
} else {
uni.navigateTo({ url: `/pageSubPack/notice-list/selectHome?villageId=${cachedVillageId}` })
}
}
onShow(() => {
getCurrentCommunityData()
getBillDetails()
})
onLoad(() => {
uni.hideTabBar({ animation: false });
uni.$on('confirm', slelctHomeData)
getPayList()
})
onUnload(() => {
uni.$off('confirm', slelctHomeData)
})
// 页面返回拦截
onBackPress(() => {
const pages = getCurrentPages()
if (pages.length <= 1) {
uni.switchTab({ url: "/pages/serviceIndex/serviceIndex" })
return true
}
})
// 跳转账单
const goToBill = (item) => {
uni.setStorageSync('arrearsPayment', item)
// 水费、电费走欠费缴纳页
if (item.type === '水费' || item.type === '电费') {
uni.navigateTo({
url: '/pageSubPack/payment-list/arrearsPayment'
})
} else {
uni.navigateTo({
url: '/pageSubPack/payment-list/billPayment'
})
}
}
// 跳转缴费记录
const goToRecord = () => {
uni.navigateTo({
url: '/pageSubPack/payment-list/paymentRecord'
})
}
// 新增缴费
const goToAdd = (type) => {
uni.setStorageSync('addPaymentType', type.name)
if (type.name == '燃气' || type.name == '暖气') {
uni.navigateTo({
url: '/pageSubPack/payment-list/selectPaymentEntity'
})
} else if (type.name == '水表' || type.name == '电表') {
uni.navigateTo({
url: '/pageSubPack/payment-list/addHydropower'
})
}
}
// 获取物业费/车位费缴费列表
const getBillDetails = (isLoadMore = false) => {
if (isLoadMore) {
if (!hasMore.value || loadingMore.value) return
pageNum.value++
loadingMore.value = true
} else {
pageNum.value = 1
hasMore.value = true
}
getTopUpDetails({
userId: uni.getStorageSync('userId'),
villageId: uni.getStorageSync('currentVillageId'),
pageNum: pageNum.value,
pageSize: pageSize.value,
}).then(res => {
if (isLoadMore) {
detailslist.value = [...detailslist.value, ...(res.rows || [])]
loadingMore.value = false
} else {
detailslist.value = res.rows || []
}
total.value = res.total || 0
hasMore.value = detailslist.value.length < total.value
}).catch(() => {
if (isLoadMore) {
pageNum.value--
loadingMore.value = false
}
}).finally(() => {
uni.stopPullDownRefresh();
})
}
const onLoadMore = () => {
getBillDetails(true)
}
// 水电费列表
const getPayList = async (isLoadMore = false) => {
if (isLoadMore) {
if (!payHasMore.value || payLoadingMore.value) return
payPageNum.value++
payLoadingMore.value = true
} else {
payPageNum.value = 1
payHasMore.value = true
}
try {
const res = await getTopUpSelectByResident({
residentUserId: uni.getStorageSync('userId'),
pageNum: payPageNum.value,
pageSize: payPageSize.value,
villageId:uni.getStorageSync('currentVillageId')
})
const data = res.rows || res.data
if (isLoadMore) {
paymentList.value = [...paymentList.value, ...(data || [])]
payLoadingMore.value = false
} else {
paymentList.value = data || []
}
payTotal.value = res.total || 0
payHasMore.value = paymentList.value.length < payTotal.value
} catch (err) {
if (isLoadMore) {
payPageNum.value--
payLoadingMore.value = false
}
uni.showToast({
title: err.msg || '网络异常',
icon: 'none'
})
} finally {
uni.stopPullDownRefresh();
}
}
const onPayLoadMore = () => {
getPayList(true)
}
// 下拉刷新:同时刷新水电费和物业费列表
onPullDownRefresh(() => {
getBillDetails();
getPayList();
});
</script>
<style lang="scss">
page {
background: linear-gradient(180deg, #dfedfd, #F6FAFF);
}
</style>
<style scoped>
.contentStyle {
display: flex;
flex-direction: column;
min-height: 100vh;
background: linear-gradient(180deg, #dfedfd, #F6FAFF);
overflow-x: hidden;
}
.page {
padding: 0px 40rpx;
box-sizing: border-box;
}
.topbox {
height: 180rpx;
width: 100%;
position: relative;
}
.titleImg {
width: 262rpx;
height: 74rpx;
position: absolute;
left: 40rpx;
bottom: 60rpx;
}
.payImg {
width: 349.97rpx;
height: 313.57rpx;
position: absolute;
right: -80rpx;
bottom: -140rpx;
}
/* 小区选择栏 */
.community-bar {
position: absolute;
left: 40rpx;
bottom: 10rpx;
display: flex;
align-items: center;
}
.location-icon {
width: 48rpx;
height: 48rpx;
margin-right: 8rpx;
flex-shrink: 0;
}
.community-name {
font-size: 26rpx;
font-weight: 500;
color: #222;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 260rpx;
margin-right: 6rpx;
}
.container {}
.bill-list {
margin-bottom: 40rpx;
background-color: #fff;
padding: 30rpx;
border-radius: 10rpx;
min-height: 550rpx;
box-sizing: border-box;
}
.bill-item {
display: flex;
align-items: center;
background-color: #F6F9FE;
border-radius: 12rpx;
padding: 20rpx 20rpx 20rpx 0px;
margin-bottom: 20rpx;
}
.bill-item:last-child {
margin-bottom: 0rpx;
}
.bill-item.bill-paid {
opacity: 0.6;
}
.bill-info {
width: calc(90% - 100rpx);
flex: 1;
}
.billIcon {
width: 64rpx;
height: 64rpx;
margin: 20rpx;
}
.bill-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 10rpx;
display: flex;
align-items: center;
}
.bill-desc {
font-size: 24rpx;
font-weight: 600;
color: #999;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.bill-status {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 4rpx 14rpx;
border-radius: 30rpx;
font-size: 20rpx;
font-weight: 500;
color: #fff;
margin-left: 10rpx;
line-height: 1.4;
}
.bill-status.debt {
background-color: #E34D59;
}
.bill-status.done {
background-color: #999;
}
.arrow {
width: 12rpx;
height: 12rpx;
border-right: 4rpx solid #ccc;
border-bottom: 4rpx solid #ccc;
transform: rotate(-45deg);
}
.details-scroll {
height: 550rpx;
padding: 0 0 20rpx 0;
}
.details-scroll-bill{
height: 550rpx;
padding: 0 0 40rpx 0;
}
.load-more-status {
display: flex;
justify-content: center;
align-items: center;
padding: 20rpx 0;
}
.loading-text {
font-size: 26rpx;
color: #999;
}
.no-more-text {
font-size: 26rpx;
color: #ccc;
}
.balance-normal {
font-size: 28rpx;
color: #333;
}
.balance-debt {
font-size: 28rpx;
color: #E34D59;
}
.add-section {
background-color: #fff;
padding: 30rpx;
border-radius: 10rpx;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
}
.section-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.record-link {
font-size: 28rpx;
color: #1677ff;
}
.grid-list {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.grid-item {
width: calc(25% - 60rpx);
background-color: #F6F9FE;
border-radius: 12rpx;
padding: 20rpx;
margin-bottom: 20rpx;
margin-left: 20rpx;
display: flex;
align-items: center;
flex-direction: column;
}
.grid-item:nth-child(4n+1) {
margin-left: 0;
}
.icon-box {
width: 52rpx;
height: 52rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 40rpx;
}
.iconStyle {
width: 100%;
height: 100%;
}
.item-name {
font-size: 28rpx;
font-weight: 600;
color: #333;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 490rpx;
}
.empty-text {
font-size: 28rpx;
color: #999;
}
</style>