Files
property-resident-side/property-uniapp-project/pageSubPack/payment-list/arrearsPayment.vue
2026-07-30 15:35:02 +08:00

684 lines
14 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" style="">
<view class="status-bar"></view>
<uni-nav-bar :title="switchStatus(paymentItem.type) || '缴费'" left-icon="left" @clickLeft="goBack"
backgroundColor="transparent" :border="false">
</uni-nav-bar>
<!-- 表单区域 -->
<scroll-view class="page" scroll-y="true">
<view class="container">
<!-- 1. 缴费详情 -->
<view v-if="currentStep === 1" class="pay-page">
<!-- 物业费缴费 -->
<!-- 金额展示 -->
<view class="amount-section" v-if="outstandingPayment">
<text class="amount-text"
:class="{ 'outstandingPaymentClass':outstandingPayment }">{{outstandingPayment?'-¥'+payAmount:'¥'+payAmount}}</text>
</view>
<view class="amount-section" v-else>
<text class="amount-text paymentClass">{{'¥'+payAmount}}</text>
</view>
<view style="border-bottom: 2rpx solid #ededed;margin:10rpx 0rpx;"></view>
<!-- 缴费信息 -->
<view class="info-section" style="">
<view>
<view class="info-item">
<text class="info-label">户号</text>
<text class="info-value">{{ paymentItem.deviceCode || '-' }}</text>
</view>
<view class="info-item">
<text class="info-label">户主</text>
<text class="info-value">{{ paymentItem.name || '-' }}</text>
</view>
<view class="info-item">
<text class="info-label">地址</text>
<text class="info-value">{{ paymentItem.fullAddress || '-' }}</text>
</view>
<!-- <view style="border-bottom: 2rpx solid #c7c7c7;padding-bottom:20rpx;"></view> -->
<!-- 缴费金额输入 -->
<!-- <view style="border-bottom: 2rpx solid #ededed;margin:10rpx 0rpx;"></view>
<view class="input-section" style="display: flex;">
<text class="amount-input" style="width: auto;margin: 0rpx 20rpx;">¥</text>
<input
type="digit"
:value="payNum"
@input="(e) => payNum = e.detail.value"
class="amount-input"
placeholder="点击输入缴费金额"
/>
</view>
<view style="border-bottom: 2rpx solid #ededed;margin:10rpx 0rpx;"></view> -->
<view class="arrears-row" v-if="outstandingPayment==true">
<text class="arrears-text">当前欠费金额¥{{ arrearsAmount }}</text>
</view>
<!-- <view class="arrears-row" v-if="outstandingPayment==false">
<text class="arrears-text">暂未查询到欠费</text>
</view> -->
</view>
</view>
</view>
<!-- 2. 缴费成功页 -->
<view class="container" v-if="currentStep==2">
<!-- 成功图标 -->
<view class="success-icon">
<text class="icon-check"></text>
</view>
<!-- 主标题 -->
<view class="title">缴费成功</view>
<!-- 提示文案 -->
<view class="desc">
成功缴纳{{ switchStatus(paymentItem.type) || '' }}费用 ¥{{ arrearsAmount || payAmount }}
</view>
</view>
</view>
</scroll-view>
<!-- 立即缴费按钮 -->
<view class="btn-section" v-if="currentStep === 1">
<button class="pay-btn" @click="handlePay">立即缴费</button>
</view>
<!-- 返回按钮 -->
<view class="btn-section" v-if="currentStep === 2">
<button class="pay-btn" @click="handleBackToList">返回生活缴费</button>
</view>
</view>
</template>
<script setup>
import {
ref,
reactive
} from 'vue'
import {
onShow,
onLoad
} from '@dcloudio/uni-app'
// 响应式数据
const outstandingPayment = ref(true)
const storageValue = uni.getStorageSync('arrearsPayment')
const paymentItem = reactive(typeof storageValue === 'object' && storageValue !== null ? storageValue : {})
const currentStep = ref(1)
const payAmount = ref('0.00')
const arrearsAmount = ref('0.00')
// 页面加载时初始化数据
onLoad(() => {
initPaymentData()
})
onShow(() => {})
// 初始化缴费数据
const initPaymentData = () => {
if (paymentItem) {
arrearsAmount.value = Math.abs(paymentItem.balance || 0).toFixed(2)
payAmount.value = Math.abs(paymentItem.balance || 0)
outstandingPayment.value = paymentItem.balance < 0
}
}
// 返回
const goBack = () => {
uni.navigateTo({
url: '/pageSubPack/payment-list/paymentIndex'
});
}
// 立即缴费 — 通过微信拉起日照银行小程序进行支付
const handlePay = () => {
const amount = arrearsAmount.value
try {
uni.showLoading({ title: '加载中...' })
// 设备类型映射电费→1(电表)水费→2(水表)
const deviceTypeMap = { '电费': '1', '水费': '2' }
const mappedDeviceType = deviceTypeMap[paymentItem.type] || paymentItem.deviceType || ''
// 直接从本地参数拼 path 查询字符串传给支付小程序,不走接口
const token = uni.getStorageSync('token') || ''
const params = {
acct: uni.getStorageSync('userId'),
orderType: '20',
deviceCode: paymentItem.deviceCode || '',
deviceType: mappedDeviceType,
billId: paymentItem.billId || '',
residentUserId: uni.getStorageSync('userId'),
// goodName: paymentItem.name || switchStatus(paymentItem.type) || '',
// remark: '服务费',
token: token
}
const queryString = Object.keys(params).map(k =>
encodeURIComponent(k) + '=' + encodeURIComponent(params[k])
).join('&')
uni.hideLoading()
console.log('传入中间小程序的path参数:', queryString)
// #ifdef APP-PLUS
// 原生App通过微信SDK拉起小程序
plus.share.getServices((services) => {
const weixin = services.find(s => s.id === 'weixin')
if (!weixin) {
uni.showToast({ title: '未检测到微信客户端', icon: 'none' })
return
}
if (!weixin.launchMiniProgram) {
uni.showToast({ title: '当前微信版本太低,不支持拉起小程序', icon: 'none' })
return
}
weixin.launchMiniProgram({
id: 'gh_a765aef0172c',
type: 1, // 0 正式版 / 1测试版 / 2预览版
path: 'pages/arrearsPayment/arrearsPayment?' + queryString,
}, (res) => {
console.log('回调---回调结果App', JSON.stringify(res))
}, (err) => {
console.error('err---拉起失败App', JSON.stringify(err))
uni.showToast({ title: '拉起支付小程序失败', icon: 'none' })
})
})
// #endif
} catch (err) {
uni.hideLoading()
console.error('拉起支付小程序异常', err)
uni.showToast({ title: '请求异常,请重试', icon: 'none' })
}
}
// 缴费成功推送通知
const sendPaySuccessPush = () => {
const userId = uni.getStorageSync('userId')
if (userId) {
getPushSingle({
userId: userId,
channel: 'resident',
title: '缴费成功',
content: `您已成功缴纳${switchStatus(paymentItem.type) || ''}费用 ¥${arrearsAmount.value || payAmount.value}`
}).catch(err => {
console.log('推送发送失败', err)
})
}
}
// 返回缴费列表
const handleBackToList = () => {
uni.navigateTo({
url: '/pageSubPack/payment-list/paymentIndex'
});
}
// 类型码转中文名展示
const switchStatus = (type) => {
const typeMap = {
'0': '物业费',
'1': '车位费',
'2': '垃圾处理费'
}
return typeMap[type] || type
}
</script>
<style lang="scss">
page {
background-color: #f9f9f9;
}
</style>
<style scoped>
.contentStyle {
display: flex;
flex-direction: column;
height: 100vh;
/* 关键:占满屏幕高度 */
background-color: #f9f9f9;
}
.page {
flex: 1;
overflow-y: auto;
padding: 0px 40rpx;
box-sizing: border-box;
background-color: #
/* fff */
;
}
/* 1. 物业费详情页 */
.pay-page {
width: 100%;
/* min-height: 100vh; */
/* background-color: #fff; */
}
.amount-section {
padding: 60rpx 0;
text-align: center;
}
.amount-text {
font-size: 56rpx;
font-weight: 600;
}
.outstandingPaymentClass {
color: #E34D59;
}
.paymentClass {
color: #00aaff;
}
.info-section {
padding-top: 20rpx;
/* margin-bottom: 40rpx; */
}
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
height: 80rpx;
}
.info-label {
font-size: 30rpx;
color: #666;
}
.info-value {
font-size: 30rpx;
color: #333;
font-weight: 600;
}
.info-payAmountItem {
height: 100rpx;
line-height: 100rpx;
margin-bottom: 60rpx;
}
.info-payAmount {
font-size: 50rpx;
color: #333;
font-weight: 600;
}
.input-section {
/* padding: 030rpx; */
}
.amount-input {
width: 100%;
height: 100rpx;
font-size: 32rpx;
line-height: 100rpx;
border: none;
outline: none;
margin-right: 10rpx;
}
.btn-section {
padding: 20rpx 30rpx 40rpx;
display: flex;
gap: 20rpx;
}
.pay-btn {
width: 100%;
height: 100rpx;
line-height: 100rpx;
background-color: #007aff;
color: #fff;
border-radius: 16rpx;
font-size: 32rpx;
border: none;
outline: none;
}
/* 2. 支付密码弹窗 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 999;
display: flex;
align-items: flex-end;
}
.password-modal {
width: 100%;
background-color: #fff;
border-radius: 24rpx 24rpx 0 0;
padding-bottom: 40rpx;
}
.modal-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 100rpx;
padding: 0 30rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.close-icon {
font-size: 44rpx;
width: 80rpx;
height: 100rpx;
display: flex;
align-items: center;
}
.modal-title {
font-size: 32rpx;
font-weight: 500;
color: #000;
}
.header-right {
width: 80rpx;
}
.pay-info {
padding: 40rpx 30rpx;
text-align: center;
}
.merchant-name {
display: block;
font-size: 32rpx;
color: #333;
margin-bottom: 20rpx;
}
.pay-amount {
font-size: 64rpx;
font-weight: 500;
color: #000;
}
.pay-way {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.way-label {
font-size: 30rpx;
color: #666;
}
.way-content {
display: flex;
align-items: center;
}
.bank-icon {
width: 32rpx;
height: 32rpx;
margin-right: 6rpx;
}
.bank-name {
font-size: 30rpx;
color: #333;
margin-right: 16rpx;
}
.arrow-icon {
font-size: 28rpx;
color: #999;
}
/* 银行卡列表 */
.bank-list {
padding: 030rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.bank-item {
display: flex;
align-items: center;
height: 100rpx;
border-bottom: 2rpx solid #f5f5f5;
}
.bank-item:last-child {
border-bottom: none;
}
.bank-item-icon {
width: 48rpx;
height: 48rpx;
margin-right: 20rpx;
}
.bank-item-name {
flex: 1;
font-size: 30rpx;
color: #333;
}
.check-icon {
font-size: 36rpx;
color: #007aff;
}
/* 密码输入框 */
.password-input {
display: flex;
justify-content: space-between;
padding: 40rpx 30rpx;
}
.password-item {
width: 100rpx;
height: 100rpx;
/* border: 2rpx solid #dcdcdc; */
background-color: #efefef;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
}
.password-dot {
width: 24rpx;
height: 24rpx;
background-color: #000;
border-radius: 50%;
}
/* 数字键盘 */
.keyboard {
width: 100%;
}
.keyboard-row {
display: flex;
}
.keyboard-item {
flex: 1;
height: 54px;
line-height: 54px;
text-align: center;
font-size: 48rpx;
color: #000;
border: 2rpx solid #f0f0f0;
background-color: #fff;
}
.keyboard-item:active {
background-color: #e5e5e5;
}
.keyboard-item.empty {
background-color: #f5f5f5;
border: none;
}
.keyboard-item.delete {
background-color: #f5f5f5;
border: none;
}
/* 3. 缴费成功页 */
/* 全局容器 */
.container {
display: flex;
flex-direction: column;
align-items: center;
}
/* 成功图标 */
.success-icon {
width: 220rpx;
height: 220rpx;
border-radius: 50%;
background-color: #1677ff;
display: flex;
align-items: center;
justify-content: center;
margin-top: 200rpx;
margin-bottom: 60rpx;
}
.icon-check {
color: #fff;
font-size: 130rpx;
font-weight: bold;
line-height: 1;
}
/* 主标题 */
.title {
font-size: 40rpx;
font-weight: bold;
color: #000;
margin-bottom: 20rpx;
}
/* 提示文案 */
.desc {
font-size: 32rpx;
color: #666;
line-height: 1.6;
text-align: center;
margin-bottom: 150rpx;
}
/* 支付方式选择 */
.pay-method-section {
margin-top: 30rpx;
padding: 0 20rpx;
}
.pay-method-title {
font-size: 30rpx;
color: #333;
font-weight: 600;
margin-bottom: 20rpx;
display: block;
}
.pay-method-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.pay-method-item {
display: flex;
align-items: center;
padding: 24rpx 30rpx;
background: #fff;
border-radius: 12rpx;
border: 2rpx solid #ededed;
}
.pay-method-item.active {
border-color: #1677ff;
background: #f0f7ff;
}
.pay-icon {
width: 48rpx;
height: 48rpx;
margin-right: 20rpx;
}
.pay-name {
flex: 1;
font-size: 30rpx;
color: #333;
}
.pay-check {
width: 32rpx;
height: 32rpx;
border-radius: 50%;
background: #1677ff;
position: relative;
}
.pay-check::after {
content: '';
position: absolute;
left: 10rpx;
top: 6rpx;
width: 8rpx;
height: 14rpx;
border: 2rpx solid #fff;
border-left: none;
border-top: none;
transform: rotate(45deg);
}
/* 核心:欠费金额行样式 */
.arrears-row {
display: flex;
align-items: center;
justify-content: space-between;
/* padding:30rpx; */
margin-bottom: 60rpx;
}
.arrears-text {
font-size: 28rpx;
color: #999;
}
.auto-fill-btn {
font-size: 28rpx;
color: #007aff;
/* 蓝色,匹配设计图 */
font-weight: 500;
padding: 10rpx 0;
}
.status-bar {
width: 100vw;
height: 46px;
}
</style>