优化,完善代码

This commit is contained in:
2026-05-14 14:42:51 +08:00
parent 79a21ff0a5
commit 16c91facac
26 changed files with 1792 additions and 1322 deletions

View File

@@ -54,6 +54,9 @@
<u-icon name="arrow-right" size="32" color="#ccc"></u-icon>
</view>
</view>
<!-- 加载更多组件 -->
<u-loadmore :status="loadStatus" />
</view>
<view v-else class="empty">
@@ -70,8 +73,8 @@
pageNo: 1,
pageSize:10,
flowList: [],
loadStatus: 'loadmore',
activeTab: '收', // 默认显示“收”
loadStatus: 'more', // ✅ 修复为官方正确值
activeTab: '收',
tabs: [{
label: '收入',
value: '支'
@@ -81,7 +84,6 @@
value: '收'
},
],
// 年份筛选相关
currentYear: null,
years: [],
showYearPicker: false
@@ -99,6 +101,7 @@
onShow() {
this.$checkToken(this.$getToken())
},
// ✅ 删除和 scroll-view 冲突的 onReachBottom
watch: {
activeTab(newVal, oldVal) {
if (newVal !== oldVal) {
@@ -106,16 +109,16 @@
}
}
},
computed: {
},
methods: {
onTabClick(val) {
this.activeTab = val
this.resetAndLoad()
},
fetchPayRecord() {
if (this.loadStatus !== 'loadmore') return;
this.loadStatus = 'loading';
// ✅ 正确判断加载状态
if (this.loadStatus !== 'more') return;
this.loadStatus = 'loading';
let url = '/bill/pageQueryPayRecord'
this.$u.post(url, {
pageNo: this.pageNo,
@@ -128,22 +131,21 @@
const rows = res.data.result || [];
if (this.pageNo === 1) this.flowList = [];
this.flowList = this.flowList.concat(rows);
if (rows.length < this.pageSize) {
this.loadStatus = 'nomore';
} else {
this.pageNo++;
this.loadStatus = 'loadmore';
this.loadStatus = 'more';
}
}).catch(err => {
console.log("获取账单记录失败:", err)
this.loadStatus = 'loadmore';
this.loadStatus = 'more'; // ✅ 异常恢复
})
},
// 切换年份选择器显示
toggleYearPicker() {
this.showYearPicker = !this.showYearPicker;
},
// 选择年份
selectYear(year) {
this.currentYear = year;
this.showYearPicker = false;
@@ -154,21 +156,19 @@
return '¥' + Number(val).toFixed(2);
},
resetAndLoad(){
// 重新加载数据
this.loadStatus = 'loadmore';
this.loadStatus = 'more';
this.pageNo = 1;
this.flowList = [];
this.fetchPayRecord();
},
loadMore() {
// 只有在 loadStatus 为 'loadmore' 时才触发
if (this.loadStatus !== 'loadmore') return;
// 调用接口获取下一页
if (this.loadStatus !== 'more') return;
this.fetchPayRecord();
},
goDetail(item) {
},
},
}
};
</script>
@@ -177,159 +177,167 @@
background: #f8f8f8;
min-height: 100vh;
padding-top: 175rpx;
.filter-bar {
box-sizing: border-box;
}
.filter-bar {
display: flex;
justify-content: space-between;
align-items: center;
background: #fff;
padding: 24rpx 30rpx;
margin: 20rpx;
margin-bottom: 0;
border-radius: 12rpx;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.05);
}
/* 年份筛选 */
.year-filter {
display: flex;
align-items: center;
gap: 8rpx;
font-size: 32rpx;
color: #333;
cursor: pointer;
}
/* 支出/收入切换 */
.tab-bar {
display: flex;
gap: 20rpx;
}
.tab-item {
padding: 12rpx 32rpx;
font-size: 28rpx;
border-radius: 24rpx;
color: #333;
background-color: #f5f5f5;
transition: all 0.2s ease;
&.active {
color: #fff;
background: #ff3b30;
}
}
/* 自定义年份选择器样式 */
.year-picker-popup {
background: #fff;
padding: 30rpx 0;
}
.popup-header {
text-align: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.popup-title {
font-size: 34rpx;
font-weight: 600;
color: #333;
}
.year-list {
padding: 20rpx;
}
.year-item {
font-size: 32rpx;
color: #666;
text-align: center;
padding: 24rpx;
border-radius: 12rpx;
margin-bottom: 16rpx;
background: #f5f5f5;
transition: all 0.2s ease;
&:last-child {
margin-bottom: 0;
}
&.active {
background: #ff3b30;
color: #fff;
}
&:hover {
background: #ff5252;
color: #fff;
}
}
/* ✅ 正确的滚动高度 */
.scroll-content {
height: calc(100vh - 175rpx - 120rpx);
box-sizing: border-box;
}
.record-list {
padding: 20rpx;
.record-item {
display: flex;
justify-content: space-between;
align-items: center;
background: #fff;
padding: 24rpx 30rpx;
margin: 20rpx;
margin-bottom: 0;
border-radius: 12rpx;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.05);
}
/* 年份筛选 */
.year-filter {
display: flex;
align-items: center;
gap: 8rpx;
font-size: 32rpx;
color: #333;
cursor: pointer;
}
/* 支出/收入切换 */
.tab-bar {
display: flex;
gap: 20rpx;
}
.tab-item {
padding: 12rpx 32rpx;
font-size: 28rpx;
border-radius: 24rpx;
color: #333;
background-color: #f5f5f5;
transition: all 0.2s ease;
&.active {
color: #fff;
background: #ff3b30;
}
}
/* 自定义年份选择器样式 */
.year-picker-popup {
background: #fff;
padding: 30rpx 0;
}
.popup-header {
text-align: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.popup-title {
font-size: 34rpx;
font-weight: 600;
color: #333;
}
.year-list {
border-radius: 16rpx;
margin-bottom: 20rpx;
padding: 20rpx;
}
.year-item {
font-size: 32rpx;
color: #666;
text-align: center;
padding: 24rpx;
border-radius: 12rpx;
margin-bottom: 16rpx;
background: #f5f5f5;
transition: all 0.2s ease;
&:last-child {
margin-bottom: 0;
}
&.active {
background: #ff3b30;
color: #fff;
}
&:hover {
background: #ff5252;
color: #fff;
}
}
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.03);
.record-list {
padding: 20rpx;
.left {
flex: 1;
.record-item {
.title {
font-size: 28rpx;
font-weight:5600;
color: #2D2B2C;
}
.sub {
font-size: 24rpx;
color: #86868C;
margin-top: 18rpx;
}
.status {
font-size: 28rpx;
&.paid {
color: #73B936;
}
&.unpaid {
color: #F34038;
}
}
}
.right {
display: flex;
justify-content: space-between;
align-items: center;
background: #fff;
border-radius: 16rpx;
margin-bottom: 20rpx;
padding: 20rpx;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.03);
.left {
flex: 1;
.amount {
font-size: 28rpx;
font-weight: 500;
margin-right: 10rpx;
.title {
font-size: 28rpx;
font-weight:5600;
color: #2D2B2C;
&.income {
color: #73B936;
}
.sub {
font-size: 24rpx;
color: #86868C;
margin-top: 18rpx;
}
.status {
font-size: 28rpx;
&.paid {
color: #73B936;
}
&.unpaid {
color: #F34038;
}
}
}
.right {
display: flex;
align-items: center;
.amount {
font-size: 28rpx;
font-weight: 500;
margin-right: 10rpx;
&.income {
color: #73B936;
}
&.expense {
color: #F34038;
}
&.expense {
color: #F34038;
}
}
}
}
.empty {
margin-top: 100rpx;
}
}
.empty {
margin-top: 100rpx;
}
</style>

View File

@@ -1,8 +1,7 @@
<template>
<view class="contract-page">
<!-- 顶部导航栏 -->
<customNavbar title="我的合同" :showHome = "true"/>
<customNavbar title="我的合同" :showHome="true"/>
<!-- Tabs -->
<view class="tab-wrapper">
@@ -22,10 +21,9 @@
<view class="contract-info">
<view class="top-row">
<text class="asset-name">{{ $ellipsis(item.assetName,12) }}</text>
<text class="asset-name">{{ $ellipsis(item.contractName,12) }}</text>
<u-icon name="arrow-right" size="28" color="#ccc" />
</view>
<!-- <view class="asset-room">{{ item.assetRoom || "—" }}</view> -->
<view class="date-range">{{ item.startDate }} ~ {{ item.endDate }}</view>
<view :class="['status-tag', item.signStatus]">
@@ -41,65 +39,47 @@
<u-empty mode="list" text="暂无合同记录" />
</view>
</scroll-view>
</view>
</template>
<script>
import DateFilter from '../../components/DatePicker/DateFilter.vue';
export default {
components: { DateFilter },
data() {
return {
tabList: [{
name: "全部",
value: "all"
},
{
name: "待签署",
value: "pending"
},
{
name: "已签署",
value: "signed"
},
{
name: "已过期",
value: "expired"
},
tabList: [
{ name: "全部", value: "all" },
{ name: "待签署", value: "pending" },
{ name: "已签署", value: "signed" },
{ name: "已过期", value: "expired" },
],
currentTab: 0,
statusFilter: "all",
// --- 时间筛选 ---
startDate: "",
endDate: "",
// 可选:限制日期范围
minDate: "2000-01-01",
maxDate: "2099-12-31",
maxDate: "2199-12-31",
contracts: [],
pageNo: 1,
pageSize: 10,
total: 0,
loadStatus: "loadmore",
loadStatus: "more", // ✅ 修复为官方正确值
isRefreshing: false,
defaultCover: "/public/static/assets.jpg",
defaultCover: "/public/static/index/assets.jpg",
};
},
onLoad(options) {
this.loadContracts();
},
onShow() {
this.$checkToken(this.$getToken())
},
onShow() {
this.$checkToken(this.$getToken())
},
// ✅ 删除和 scroll-view 冲突的 onReachBottom
computed: {
staticHost() {
return this.$config.staticUrl
}
staticHost() {
return this.$config.staticUrl
}
},
methods: {
onTabChange(index) {
@@ -110,89 +90,74 @@ export default {
onDateFilterChange({ start, end }) {
this.resetAndLoad();
},
formatDate(time) {
const d = new Date(time);
const m = String(d.getMonth() + 1).padStart(2, "0");
const day = String(d.getDate()).padStart(2, "0");
return `${d.getFullYear()}-${m}-${day}`;
},
resetAndLoad() {
this.pageNo = 1;
this.contracts = [];
this.loadStatus = "loadmore";
this.loadStatus = "more"; // ✅ 修复
this.loadContracts();
},
/** 你的 loadContracts() 保持不变,只需加:按时间筛选 */
loadContracts() {
if (this.loadStatus !== 'loadmore') return;
this.loadStatus = 'loading';
this.$u.post('/contract/queryPage', {
pageNo: this.pageNo,
pageSize: this.pageSize,
startDate: this.startDate,
endDate: this.endDate,
signStatus: this.statusFilter
}, {
WT: this.$getToken()
}).then(result => {
const rows = result.data.result || [];
// 第一页 & 无数据
if (this.pageNo === 1 && rows.length === 0) {
this.contracts = [];
this.loadStatus = 'nomore';
return;
}
// 追加数据
this.contracts = this.contracts.concat(rows);
// 是否还有下一页(核心判断)
if (rows.length < this.pageSize) {
this.loadStatus = 'nomore';
} else {
this.pageNo++; // ✅ 只有这里才能 +1
this.loadStatus = 'loadmore';
}
}).catch(err => {
console.log("获取合同信息失败:", err);
this.loadStatus = 'loadmore';
}).finally(() => {
this.isRefreshing = false;
});
},
// ✅ 正确判断加载状态
if (this.loadStatus !== 'more') return;
this.loadStatus = 'loading';
this.$u.post('/contract/queryPage', {
pageNo: this.pageNo,
pageSize: this.pageSize,
startDate: this.startDate,
endDate: this.endDate,
signStatus: this.statusFilter
}, {
WT: this.$getToken()
}).then(result => {
const rows = result.data.result || [];
if (this.pageNo === 1 && rows.length === 0) {
this.contracts = [];
this.loadStatus = 'nomore';
return;
}
this.contracts = this.contracts.concat(rows);
if (rows.length < this.pageSize) {
this.loadStatus = 'nomore';
} else {
this.pageNo++;
this.loadStatus = 'more'; // ✅ 修复
}
}).catch(err => {
console.log("获取合同信息失败:", err);
this.loadStatus = 'more'; // ✅ 异常恢复
}).finally(() => {
this.isRefreshing = false;
});
},
refresh() {
this.isRefreshing = true;
this.resetAndLoad();
},
loadMore() {
if (this.loadStatus !== "loadmore") return;
this.loadContracts();
if (this.loadStatus !== "more") return; // ✅ 修复
this.loadContracts();
},
goDetail(item) {
uni.navigateTo({
url: `/pages-biz/contract/contractDetail?contractNo=${item.contractNo}`,
});
},
getStatusText(status) {
switch (status) {
case "pending":
return "签署";
case "signed":
return "已签署";
case "expired":
return "已过期";
case "pending": return "待签署";
case "signed": return "签署";
case "expired": return "已过期";
default: return "未知";
}
},
},
@@ -203,12 +168,14 @@ export default {
.contract-page {
background-color: #f8f8f8;
padding-top: 170rpx;
/* 给导航栏留空间 */
min-height: 100vh;
box-sizing: border-box;
}
/* ✅ 核心修复:正确的滚动高度 */
.scroll-content {
height: calc(100vh - 100rpx);
height: calc(100vh - 170rpx - 100rpx);
box-sizing: border-box;
}
.contract-list {

View File

@@ -19,7 +19,7 @@
<!-- 登录按钮 -->
<button class="login-btn" open-type="getPhoneNumber" @getphonenumber="onGetPhone">
使用微信授权登录
手机号快捷登录
</button>
<!-- 用户类型选择 -->

View File

@@ -39,14 +39,20 @@ export default {
pageNo:1,
pageSize:10,
isRefreshing: false,
loadStatus: 'loadmore'
loadStatus: 'more', // ✅ 修复为官方正确值
}
},
onLoad() { // ✅ 修复生命周期拼写
this.fetchMessageList();
},
onShow() {
this.$checkToken(this.$getToken())
},
onload(){
this.loadMore();
// ✅ 删除和 scroll-view 冲突的 onReachBottom
computed: {
staticHost() {
return this.$config.staticUrl;
}
},
methods: {
goBack() {
@@ -68,8 +74,10 @@ export default {
}
},
fetchMessageList(){
if (this.loadStatus !== 'loadmore') return;
// ✅ 正确判断加载状态
if (this.loadStatus !== 'more') return;
this.loadStatus = 'loading';
let url = '/message/queryPage'
this.$u.post(url, {
pageNo: this.pageNo,
@@ -78,36 +86,44 @@ export default {
WT: this.$getToken()
}).then(res => {
const rows = res.data.result || [];
console.log(rows)
if (this.pageNo === 1) this.flowList = [];
this.flowList = this.flowList.concat(rows);
// ✅ 判断是否还有更多
if (rows.length < this.pageSize) {
this.loadStatus = 'nomore';
} else {
this.pageNo++;
this.loadStatus = 'loadmore';
this.loadStatus = 'more';
}
}).catch(err => {
console.log("获取消息列表失败:", err)
this.loadStatus = 'loadmore';
this.loadStatus = 'more'; // ✅ 异常恢复
})
},
loadMore() {
// 只有在 loadStatus 为 'loadmore' 时才触发
if (this.loadStatus !== 'loadmore') return;
this.fetchMessageList()
},
viewMessage(msg) {
this.$u.route({url:'/pages-biz/message/messageDetail',params:{
id: msg.id,
read: msg.read
}});
this.$u.route({
url:'/pages-biz/message/messageDetail',
params:{
id: msg.id,
read: msg.read
}
});
},
// ✅ 修复下拉刷新(重置数据)
refresh() {
this.isRefreshing = true;
this.pageNo = 1;
this.flowList = [];
this.loadStatus = 'more';
this.fetchMessageList();
setTimeout(() => {
this.isRefreshing = false;
}, 1000);
}, 800);
}
}
}
@@ -119,7 +135,9 @@ export default {
min-height: 100vh;
}
/* ✅ 修复滚动区域高度 */
.message-list {
height: calc(100vh - var(--window-top));
padding: 20rpx;
box-sizing: border-box;
}

View File

@@ -3,9 +3,6 @@
<!-- 顶部自定义导航栏 -->
<customNavbar title="我的租赁资产" />
<!-- 筛选栏 -->
<!-- 租赁资产列表组件 -->
<scroll-view
scroll-y
@@ -16,6 +13,9 @@
:list="assetList"
@click="goDetail"
/>
<!-- 加载更多 -->
<u-loadmore :status="loadStatus" />
</scroll-view>
</view>
</template>
@@ -24,60 +24,57 @@
import AssetList from '@/components/asset/assetList.vue'
export default {
name: 'MyLease',
components: { AssetList},
components: { AssetList },
data() {
return {
assetList: [],
pageNo: 1,
pageSize: 10,
loadStatus: 'loadmore',
loadStatus: 'more', // ✅ 修复为官方正确值
cusNo: ''
};
},
onLoad(options) {
this.cusNo = options.cusNo;
this.cusNo = options.cusNo;
this.loadAssets();
},
onShow() {
this.$checkToken(this.$getToken())
this.$checkToken(this.$getToken())
},
staticHost() {
return this.$config.staticUrl
// ✅ 删除和 scroll-view 冲突的 onReachBottom
computed: {
staticHost() {
return this.$config.staticUrl
}
},
methods: {
changeFilter(value) {
if (this.currentFilter === value) return;
this.currentFilter = value;
this.pageNo = 1;
this.assetList = [];
this.loadAssets();
},
loadAssets() {
if (this.loadStatus !== 'loadmore') return;
this.loadStatus = 'loading';
this.$u.post('/assets/getMyAssetsList', {
pageNo: this.pageNo,
pageSize: this.pageSize
},{
WT: this.$getToken()
}).then(res => {
const rows = res.data.result || [];
if (this.pageNo === 1) this.assetList = [];
this.assetList = this.assetList.concat(rows);
if (rows.length < this.pageSize) {
this.loadStatus = 'nomore';
} else {
this.pageNo++;
this.loadStatus = 'loadmore';
}
}).catch(err => {
console.error(err);
this.loadStatus = 'loadmore';
});
// ✅ 正确判断加载状态
if (this.loadStatus !== 'more') return;
this.loadStatus = 'loading';
this.$u.post('/assets/getMyAssetsList', {
pageNo: this.pageNo,
pageSize: this.pageSize
}, {
WT: this.$getToken()
}).then(res => {
const rows = res.data.result || [];
if (this.pageNo === 1) this.assetList = [];
this.assetList = this.assetList.concat(rows);
// ✅ 判断是否还有更多数据
if (rows.length < this.pageSize) {
this.loadStatus = 'nomore';
} else {
this.pageNo++;
this.loadStatus = 'more';
}
}).catch(err => {
console.error(err);
this.loadStatus = 'more'; // ✅ 异常恢复
});
},
loadMore() {
@@ -97,33 +94,15 @@ export default {
.page {
display: flex;
flex-direction: column;
height: 100vh;
min-height: 100vh;
background: #f7f8fa;
padding-top: 175rpx;
}
.filter-bar {
display: flex;
justify-content: space-around;
align-items: center;
background-color: #fff;
padding: 20rpx 0;
margin-top: var(--custom-navbar-height);
border-bottom: 1rpx solid #f0f0f0;
.filter-btn {
min-width: 150rpx;
text-align: center;
font-size: 26rpx;
height: 60rpx;
line-height: 60rpx;
border-radius: 40rpx;
margin: 0 8rpx;
}
box-sizing: border-box;
}
.scroll-content {
flex: 1;
height: calc(100vh - 200rpx);
height: calc(100vh - 175rpx); /* ✅ 正确高度,不超出屏幕 */
box-sizing: border-box;
}
</style>

View File

@@ -17,6 +17,9 @@
</view>
<u-icon name="arrow-right" color="rgb(203,203,203)" :size="26" class="arrow-icon"></u-icon>
</view>
<!-- 加载更多 -->
<u-loadmore :status="loadStatus" />
</view>
</scroll-view>
</view>
@@ -26,20 +29,18 @@
<script>
export default {
data() {
// 静态公告数据
const staticNoticeList = [];
return {
pageNo: 1,
pageSize: 20,
flowList: [],
loadStatus: 'loadmore',
loadStatus: 'more', // ✅ 修复为官方正确值
isRefreshing: false
};
},
onLoad() {
// 静态数据已在data中初始化无需调用接口
this.getNoticecList();
},
// ✅ 删除和 scroll-view 冲突的 onReachBottom
methods: {
clickContent(item) {
if (item.noticeId) {
@@ -52,30 +53,39 @@ export default {
}
},
getNoticecList() {
if (this.loadStatus !== 'loadmore') return;
this.loadStatus = 'loading';
// ✅ 正确判断加载状态
if (this.loadStatus !== 'more') return;
this.loadStatus = 'loading';
let url = "/notice/pageQuery";
this.$u.post(url, {
pageNo: this.pageNo,
pageSize: this.pageSize
}).then(res => {
const rows = res.data.result || [];
console.log(rows)
if (this.pageNo === 1) this.flowList = [];
this.flowList = this.flowList.concat(rows)
// ✅ 判断是否还有更多
if (rows.length < this.pageSize) {
this.loadStatus = 'nomore';
} else {
this.pageNo++;
this.loadStatus = 'loadmore';
this.loadStatus = 'more';
}
}).catch(err => {
console.log("获取招商公告失败:", err)
this.loadStatus = 'more'; // ✅ 异常恢复
});
},
// 上拉加载
loadMore() {
this.getNoticecList();
}
}
};
</script>
<style lang="scss" scoped>
.tabSwiper {
width: 95%;
@@ -158,4 +168,4 @@ export default {
.page-box {
padding: 16rpx 0 40rpx 0;
}
</style>
</style>

View File

@@ -29,11 +29,33 @@
this.id = option.id
this.getDetail()
},
onShow(){
this.recordView(this.id)
},
methods:{
recordView(assetId) {
let token = this.$getToken()
let userInfo = uni.getStorageSync('userInfo')
if(token){
return
}
if (token) {
let url = "/potential/add";
this.$u.get(url, {
assetId: this.id,
assetsName: '查看公告' + this.title,
userType: userInfo.userType
}, {
'WT': this.$getToken()
}).then(obj => {
}).catch(err => {
console.log("记录客户浏览记录失败", err)
})
}
},
getDetail(){
this.$u.get(`/notice/detail?id=${this.id}`,{},{
WT: this.$getToken()
}).then(res=>{
this.$u.get(`/notice/detail?id=${this.id}`,{},{}).then(res=>{
if(res.flag) {
this.title = res.data.noticeTitle;
this.content = res.data.noticeContent;
@@ -44,12 +66,13 @@
})
}
this.attachments = res.data.attachments;
this.recordView(this.id)
}
})
},
download(item){
uni.downloadFile({
url: this.$config.staticUrl + item.url,
url: this.$config.staticUrl + item.fileUrl,
success(res) {
uni.openDocument({
filePath: res.tempFilePath

View File

@@ -2,16 +2,6 @@
<view class="u-m-20">
<u-navbar :is-back="true" title="账号实名信息" :border-bottom="false"></u-navbar>
<view>
<!-- <u-cell-group>
<u-cell-item title="头像" :arrow="false" hover-class="none" @click="updateAvatar">
<u-avatar :src="pic" size="100"></u-avatar>
</u-cell-item>
</u-cell-group> -->
<!-- <u-cell-group>
<u-cell-item title="昵称" :arrow="false" hover-class="none" @click="updateName">
{{vuex_user.user.nickName}}
</u-cell-item>
</u-cell-group> -->
<u-cell-group>
<u-cell-item :title="getTitle" :arrow="false" hover-class="none" @click="updateName">
{{(cardNo == null ? orgNo : cardNo) || ''}}
@@ -19,29 +9,28 @@
</u-cell-group>
</view>
<u-modal v-model="showModel" @confirm="confirmAuthCode" ref="uModal" :async-close="true"
:title="'设置' + getTitle">
<u-modal
v-model="showModel"
@confirm="confirmAuthCode"
ref="uModal"
:async-close="true"
:title="'设置' + getTitle"
>
<view class="slot-content">
<u-input v-model="authCode" type="text" :border="false" :placeholder="'请输入' + getTitle" />
<u-input
v-model="authCode"
type="text"
:border="false"
:placeholder="'请输入' + getTitle"
/>
</view>
</u-modal>
<!-- <view class="u-m-t-20">
<u-button type="primary" @click="subProfile">提交</u-button>
</view> -->
<!-- 如果是微信登录小程序则获取用户的昵称与头像 -->
<!-- #ifdef MP-WEIXIN -->
<!-- <u-button type="default">使用微信头像与昵称</u-button> -->
<!-- #endif -->
</view>
</template>
<script>
import config from "@/common/config.js" // 全局配置文件
import {
rsaEncrypt
} from "@/common/utils/ras.js"
import config from "@/common/config.js"
import { rsaEncrypt } from "@/common/utils/ras.js"
export default {
data() {
return {
@@ -60,49 +49,46 @@
}
},
onLoad(options) {
let userVo = uni.getStorageSync('userInfo');
this.user = userVo;
// 页面加载时同步最新用户信息
this.getUserProfile();
},
methods: {
updateName() {
this.showModel = true;
},
// 简单身份证校验18 位)
// 身份证校验
checkIdCard(code) {
return /^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/.test(
code
);
return /^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/.test(code);
},
// 统一社会信用代码校验18 位)
// 统一社会信用代码校验
checkCreditCode(code) {
return /^[0-9A-Z]{18}$/.test(code);
},
confirmAuthCode() {
let loginType = this.user.userType
// 修复:统一使用 loginType 变量
const loginType = this.user.userType;
if (!this.authCode) {
this.showModel = false;
return this.$mytip.toast(loginType === '0' ? '请输入身份证号' : '请输入组织社会信用代码')
}
// 身份证校验
if (this.loginType === '0' && !this.checkIdCard(this.authCode)) {
uni.showToast({
title: '身份证号格式不正确',
icon: 'none'
});
// 校验身份证
if (loginType === '0' && !this.checkIdCard(this.authCode)) {
uni.showToast({ title: '身份证号格式不正确', icon: 'none' });
return;
}
// 企业社会信用代码校验
if (this.loginType === '1' && !this.checkCreditCode(this.authCode)) {
uni.showToast({
title: '社会信用代码格式不正确',
icon: 'none'
});
// 校验信用代码
if (loginType === '1' && !this.checkCreditCode(this.authCode)) {
uni.showToast({ title: '社会信用代码格式不正确', icon: 'none' });
return;
}
let token = this.$getToken()
let url = "/login/updateVerifyCode";
let encryptCode = rsaEncrypt(this.authCode);
const token = this.$getToken();
const url = "/login/updateVerifyCode";
const encryptCode = rsaEncrypt(this.authCode);
this.$u.post(url, {
userType: loginType,
code: loginType === '0' ? encryptCode : this.authCode
@@ -110,64 +96,74 @@
'WT': token
}).then(obj => {
if (obj.flag) {
// 赋值展示
if (loginType === '0') {
this.cardNo = encryptCode
this.cardNo = this.applyMask(this.authCode)
this.cardNo = this.applyMask(this.authCode);
} else {
this.orgNo = this.authCode
this.orgNo = this.authCode;
}
this.showModel = false;
this.$mytip.toast('修改成功');
this.getUserProfile();
uni.switchTab({
url: '/pages/center/center'
})
// 关键:先更新用户信息,成功后再跳转
this.getUserProfile().then(() => {
setTimeout(() => {
uni.switchTab({ url: '/pages/center/center' });
}, 1000);
});
} else {
this.$mytip.toast('修改失败');
}
});
},
// 身份证脱敏修复
applyMask(idCard) {
if (idCard.length !== 18) return idCard; // 非18位直接返回
return idCard.replace(/(\d{6})(\d{8})(\d{4})/, '$1********$2****');
if (!idCard || idCard.length !== 18) return idCard;
// 前6位 + 8个* + 后4位
return idCard.replace(/^(\d{6})\d{8}(\d{4})$/, '$1********$2');
},
updateAvatar() {
this.$u.route('/pages-biz/profile/avatar')
},
subProfile() {
// 1.更新vuex中的用户信息
this.$mytip.toast('修改成功')
// 2.页面跳转
},
getUserProfile() {
// 如果是微信登录小程序,则获取用户的昵称与头像
// #ifdef MP-WEIXIN
// 此处执行微信才执行
// #endif
uni.removeStorageSync('userInfo');
let token = this.$getToken();
let url = `/login/userInfo`;
this.$u.get(url, {}, {
'WT': token
}).then(obj => {
uni.setStorageSync('userInfo', {
// 关键修复:获取用户信息并同步到当前页面 data
async getUserProfile() {
try {
const token = this.$getToken();
const url = `/login/userInfo`;
const obj = await this.$u.get(url, {}, { 'WT': token });
const userInfo = {
userType: obj.data.userType,
oaAuth: obj.data.oaAuth,
cusNo: obj.data.cusNo,
userName: obj.data.userName,
openId: obj.data.openId,
subscribe: obj.data.subscribeMsg
})
});
};
// 同步缓存 + 当前页面数据
uni.setStorageSync('userInfo', userInfo);
this.user = userInfo;
// 同步展示实名信息
if (userInfo.userType === '0') {
this.cardNo = obj.data.cardNo ? this.applyMask(obj.data.cardNo) : null;
this.orgNo = null;
} else {
this.orgNo = obj.data.orgNo || null;
this.cardNo = null;
}
return userInfo;
} catch (e) {
console.error('获取用户信息失败', e);
}
}
},
computed: {
getTitle() {
return this.user.userType === '0' ?
'身份证号' :
'企业社会信用代码'
return this.user.userType === '0' ? '身份证号' : '企业社会信用代码';
}
}
}

View File

@@ -5,11 +5,11 @@
<view class="setting-content">
<u-cell-group>
<u-cell-item title="账号实名信息" @click="profile"></u-cell-item>
<u-cell-item title="订阅系统消息" :arrow="false">
<!-- <u-cell-item title="订阅系统消息" :arrow="false">
<u-switch v-model="longSubscribe" @change="toggleLongSubscribe" />
</u-cell-item>
</u-cell-item> -->
</u-cell-group>
</view>
@@ -53,32 +53,30 @@
// 微信小程序专用
// #ifdef MP-WEIXIN
if (this.longSubscribe) {
const tmplIds = ['ZVl9bkFv8Nzha2n_6wO36IBqe0H5VwJBvV-7OkVT5jo'] // 在小程序后台配置的长期订阅模板
wx.requestSubscribeMessage({
tmplIds,
success: (res) => {
// 用户同意才生效
console.log('长期订阅授权结果', res)
if (Object.values(res).some((v) => v === 'accept')) {
uni.showToast({
title: '长期订阅开启成功',
icon: 'success'
})
// 可以把状态保存到后端
this.saveLongSubscribeStatus(true)
} else {
uni.showToast({
title: '未授权订阅',
icon: 'none'
})
this.longSubscribe = false
}
},
fail: (err) => {
console.error(err)
this.longSubscribe = false
},
})
// const tmplIds = ['9QlNxNONJBICzw3Vcetqbf9yv4lI9q9cR_px8ujlOu8']
// wx.requestSubscribeMessage({
// tmplIds,
// success: (res) => {
// if (Object.values(res).some((v) => v === 'accept')) {
// uni.showToast({
// title: '长期订阅开启成功',
// icon: 'success'
// })
// this.saveLongSubscribeStatus(true)
// } else {
// uni.showToast({
// title: '未授权订阅',
// icon: 'none'
// })
// this.longSubscribe = false
// }
// },
// fail: (err) => {
// console.error(err)
// this.longSubscribe = false
// },
// })
this.saveLongSubscribeStatus(true)
} else {
// 取消订阅
uni.showToast({

View File

@@ -85,8 +85,14 @@ export default {
pageNo: 1,
pageSize:10,
flowList: [],
loadStatus: 'loadmore',
isRefreshing: false
loadStatus: 'more', // ✅ 修复为官方正确值
isRefreshing: false,
navbarStyle: {
isTransparent: false,
bgColor: '#fff',
textColor: '#2D2B2C',
opacity: 1
}
}
},
onLoad(options){
@@ -95,6 +101,7 @@ export default {
onShow() {
this.$checkToken(this.$getToken())
},
// ✅ 删除 scroll-view 冲突的 onReachBottom
methods: {
statusText(status) {
switch (status) {
@@ -107,7 +114,6 @@ export default {
}
},
formatDate(dateStr) {
// 格式化日期例如2025-11-10 周五 09:00
if(!dateStr){return '-'}
const date = new Date(dateStr);
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
@@ -121,8 +127,9 @@ export default {
return `${year}-${month}-${day} ${weekday} ${hours}:${minutes}`;
},
fetchReserve(){
if (this.loadStatus !== 'loadmore') return;
this.loadStatus = 'loading';
// ✅ 正确判断加载状态
if (this.loadStatus !== 'more') return;
this.loadStatus = 'loading';
let url = '/reservate/queryPage'
this.$u.post(url, {
pageNo: this.pageNo,
@@ -131,18 +138,19 @@ export default {
WT: this.$getToken()
}).then(res => {
const rows = res.data.result || [];
console.log(rows)
if (this.pageNo === 1) this.flowList = [];
this.flowList = this.flowList.concat(rows);
// ✅ 判断是否还有更多数据
if (rows.length < this.pageSize) {
this.loadStatus = 'nomore';
} else {
this.pageNo++;
this.loadStatus = 'loadmore';
this.loadStatus = 'more';
}
}).catch(err => {
console.log("获取预约记录失败:", err)
this.loadStatus = 'loadmore';
this.loadStatus = 'more'; // ✅ 异常恢复
})
},
viewLocation(item) {
@@ -166,11 +174,16 @@ export default {
loadMore() {
this.fetchReserve()
},
// ✅ 修复下拉刷新(重置数据)
refresh() {
this.isRefreshing = true;
this.pageNo = 1;
this.flowList = [];
this.loadStatus = 'more';
this.fetchReserve();
setTimeout(() => {
this.isRefreshing = false;
}, 1000);
}, 800);
}
}
};
@@ -179,12 +192,15 @@ export default {
<style lang="scss" scoped>
.reserve-records {
min-height: 100vh;
padding-top: 175rpx; /* 给导航栏留空间 */
padding-top: 175rpx;
background: linear-gradient(0deg, #F3F1ED 43%, #F5E9DB 100%);
box-sizing: border-box;
}
/* ✅ 核心修复:正确的滚动区域高度 */
.scroll-content {
height: calc(100vh - -120rpx - 120rpx);
height: calc(100vh - 175rpx);
box-sizing: border-box;
}
.record-list {

View File

@@ -1,7 +1,7 @@
<template>
<view class="u-margin-left-20 u-margin-right-20">
<u-navbar :is-back="true" title="搜索" :border-bottom="false"></u-navbar>
<u-search placeholder="请输入资产名称/位置等信息" v-model="keyword" @search="clickSearch(value)"
<u-search placeholder="请输入品牌名称/位置等信息" v-model="keyword" @search="clickSearch(value)"
:focus="true" action-text="取消" @custom="cancelSearch"></u-search>
<!-- 搜索记录 -->
<template v-if="historyList.length > 0">

View File

@@ -1,12 +1,9 @@
<template>
<view class="search-list-page">
<!-- 顶部导航栏 -->
<!-- <customNavbar title="搜索资产" /> -->
<u-navbar title="搜索资产" :autoBack="true" :background="background" title-color="#2D2B2C"
back-icon-color="#2D2B2C">
</u-navbar>
<view class="search-list-content">
<!-- 筛选标签栏 -->
<view class="filter-dropdown-wrapper">
<u-sticky offset-top="0">
<view class="sticky" style="width: 100vw;">
@@ -15,7 +12,6 @@
</view>
</u-sticky>
</view>
<!-- 搜索栏 -->
<view class="search-bar-wrapper">
<view class="search-bar">
<view class="city-select" @click="location()">{{ city ||'宜昌市'}} <text class="icon-down"></text>
@@ -26,7 +22,6 @@
</view>
</view>
</view>
<!-- 标签组 -->
<view class="tag-group">
<view class="tag-item" :class="{ active: selectedTags.includes(tag) }"
v-for="(tag, index) in tagGroupList" :key="index" @click="onTagClick(tag)">
@@ -39,32 +34,35 @@
<u-waterfall v-model="flowList" ref="uWaterfall">
<template v-slot:left="{ leftList }">
<view class="demo-warter" v-for="(item, index) in leftList" :key="index">
<u-lazy-load threshold="750" border-radius="8" :image="item.coverImgUrl" :index="index"
@click="clickImage(item.assetsNo)" mode="aspectFill"></u-lazy-load>
<view class="img-box" @click="clickImage(item.assetsNo)">
<img class="img" :src="item.coverImgUrl" alt="" />
</view>
<view class="item-title">{{ item.assetsName }}</view>
<view class="item-desc">{{ item.assetsType }} {{ item.footPrint }} {{ item.orientation ||'未知'}}
</view>
<view class="item-tags">
<view class="tag" v-for="(tag, tagIndex) in item.tags" :key="tagIndex">{{ tag }}</view>
</view>
<view class="item-price">¥{{ item.rentFee || '未知'}}/<text></text></view>
</view>
</template>
<template v-slot:right="{ rightList }">
<view class="demo-warter" v-for="(item, index) in rightList" :key="index">
<u-lazy-load threshold="750" border-radius="8" :image="item.coverImgUrl" :index="index"
@click="clickImage(item.assetsNo)" mode="aspectFill"></u-lazy-load>
<view class="img-box" @click="clickImage(item.assetsNo)">
<img class="img" :src="item.coverImgUrl" alt="" />
</view>
<view class="item-title">{{ item.assetsName }}</view>
<view class="item-desc">{{ item.assetsType}} {{ item.footPrint }} {{ item.orientation ||'未知'}}</view>
<view class="item-tags">
<view class="tag" v-for="(tag, tagIndex) in item.tags" :key="tagIndex">{{ tag }}</view>
</view>
<view class="item-price">¥{{ item.rentFee || '未知'}}/<text></text></view>
</view>
</template>
</u-waterfall>
<u-loadmore bg-color="rgb(240, 240, 240)" :status="loadStatus" @loadmore="loadMore"
<!-- 修复状态 + 去掉自带loadmore -->
<u-loadmore bg-color="rgb(240, 240, 240)" :status="loadStatus"
style="height: 80rpx;line-height: 80rpx;"></u-loadmore>
<u-back-top :scroll-top="scrollTop" top="1000"></u-back-top>
<u-no-network></u-no-network>
</view>
@@ -72,8 +70,8 @@
</template>
<script>
import config from "@/common/config.js" // 全局配置文件
import searchData from '@/common/utils/searchData.js'; //筛选菜单数据
import config from "@/common/config.js"
import searchData from '@/common/utils/searchData.js';
import filterDropdown from '@/components/zy/filterDropdown.vue';
export default {
components: {
@@ -82,26 +80,22 @@
data() {
return {
city: null,
selectedBizZone: null,
selectedLayout: null,
selectedDecorationStatus: null,
selectedFeatures:[],
indexArr: [],
valueArr: [],
defaultSelected: [],
filterData: [],
searchData: {},
pageNum: 1,
pageNo: 1, // ✅ 统一页码
pageSize: 20,
scrollTop: 0,
houseList: [],
loadStatus: 'loadmore',
loadStatus: 'more', // ✅ 修复为正确状态
flowList: [],
// 标签组数据和选中状态
tagGroupList: ['全套家具', '配套齐全', '优选好房', '生活便利'],
imageModeMap: {},
defaultImgUrl: '/public/static/index/assets.jpg',
tagGroupList: [],
selectedTags: [],
background: {
// 渐变色
backgroundImage: 'linear-gradient(-90deg, #F9DED9 0%, #F8DFC0 99%);'
},
}
@@ -119,18 +113,21 @@
if (villageName) {
this.searchData.villageName = villageName
}
// 获取街道数据
this.findFilterTabData()
this.findHouseList(null,option.keyword)
},
onShow() {
},
onPageScroll(e) {
this.scrollTop = e.scrollTop;
},
// 下拉刷新
// ✅ 保留页面触底(瀑布流必须用这个)
onReachBottom() {
this.loadMore()
},
onPullDownRefresh() {
this.resetAndLoad();
// 关闭刷新
uni.stopPullDownRefresh();
},
computed: {
staticHost() {
@@ -138,20 +135,13 @@
}
},
methods: {
// 标签点击事件
onTagClick(tag) {
// 检查标签是否已选中
const isSelected = this.selectedTags.includes(tag);
if (isSelected) {
// 如果已选中,则移除
this.selectedTags = this.selectedTags.filter(item => item !== tag);
} else {
// 如果未选中,则添加
this.selectedTags.push(tag);
}
// 这里可以添加根据标签筛选数据的逻辑
console.log('标签点击:', tag);
console.log('当前选中的标签:', this.selectedTags);
this.resetAndLoad()
},
location() {
@@ -165,14 +155,15 @@
resetAndLoad() {
this.pageNo = 1;
this.flowList = [];
this.loadStatus = 'loadmore';
this.loadStatus = 'more'; // ✅ 修复
this.$nextTick(() => {
this.$refs.uWaterfall && this.$refs.uWaterfall.clear();
this.findHouseList();
});
},
findHouseList(type = null,keyWord = null) {
if (this.loadStatus !== 'loadmore') return;
findHouseList(type = null,keyword = null) {
// ✅ 正确判断
if (this.loadStatus !== 'more') return;
this.loadStatus = 'loading';
@@ -181,16 +172,20 @@
assetsType: type,
pageNo: this.pageNo,
pageSize: this.pageSize,
keyWord: this.keyWord,
bizZone: this.searchData.bizZone
keyWord: keyword,
bizZone: this.searchData.bizZone,
layout: this.searchData.layout,
renovationStatus: this.searchData.decoration,
features: this.searchData.feature
}).then(result => {
const rows = result.data.result || [];
// 第一页无数据
if (this.pageNo === 1 && rows.length === 0) {
this.flowList = [];
this.loadStatus = 'nomore';
return;
}
rows.forEach(row => {
if (row.coverImgUrl) {
row.coverImgUrl = this.$config.staticUrl + row.coverImgUrl
@@ -198,32 +193,29 @@
row.coverImgUrl = this.$config.staticUrl + this.defaultImgUrl
}
})
// 追加数据
this.flowList = this.flowList.concat(rows);
// 判断是否还有下一页(核心)
if (rows.length < this.pageSize) {
this.loadStatus = 'nomore';
} else {
this.pageNo++; // ✅ 只有这里能 +1
this.loadStatus = 'loadmore';
this.pageNo++;
this.loadStatus = 'more'; // ✅ 恢复
}
this.keyWord = null
}).catch(err => {
console.log("获取资产信息失败:", err);
this.loadStatus = 'loadmore';
this.loadStatus = 'more'; // ✅ 恢复
}).finally(() => {
uni.stopPullDownRefresh();
});
},
loadMore() {
// 只有在 loadStatus 为 'loadmore' 时才触发
if (this.loadStatus !== 'loadmore') return;
// 调用接口获取下一页
if (this.loadStatus !== 'more') return;
this.findHouseList();
},
async findFilterTabData() {
// 填充商圈数据到筛选菜单
const bizZones = await this.getBizZone();
const features = await this.getFeatures();
let featureSubMenu = [];
@@ -232,7 +224,6 @@
name: bizZones[i],
value: bizZones[i]
});
}
for (let i = 0; i < features.length; i++) {
featureSubMenu.push({
@@ -240,7 +231,7 @@
value: features[i]
})
}
searchData[2].submenu.push({
searchData[1].submenu.push({
name:"基础配套",
type:"radio-multi",
submenu: featureSubMenu
@@ -261,6 +252,18 @@
}
return [];
},
getImageSize(url, index) {
uni.getImageInfo({
src: url,
success: (res) => {
const { width, height } = res;
this.$set(this.imageModeMap, index, width >= height ? 'widthFix' : 'aspectFit');
},
fail: () => {
this.$set(this.imageModeMap, index, 'aspectFit');
}
});
},
clickImage(houseId) {
this.$u.route({
url: '/pages-assets/assets/assetsDetail',
@@ -269,11 +272,9 @@
}
})
},
//接收菜单结果
confirm(e) {
let bizZone = e.value[0][0]
let price = e.value[1][0]
let combo = e.value[2]
let combo = e.value[1]
let layout = combo[0]
let decoration = combo[1]
let feature = combo[2]
@@ -281,9 +282,6 @@
if (bizZone) {
this.searchData.bizZone = bizZone
}
if (price) {
this.searchData.price = price
}
if (layout && layout.length > 0) {
this.searchData.layout = layout.toString()
}
@@ -308,13 +306,11 @@
}
.search-list-content {
// padding-top: 20rpx;
background: linear-gradient(-90deg, #F9DED9 0%, #F8DFC0 99%);
border-radius: 0rpx;
padding-bottom: 20rpx;
}
// 搜索栏样式
.search-bar-wrapper {
padding: 10rpx 20rpx;
}
@@ -365,12 +361,9 @@
}
.filter-dropdown-wrapper {
// padding: 0 20rpx;
border-radius: 10rpx;
margin-bottom: 20rpx;
}
// 标签组样式
.tag-group {
padding: 15rpx 20rpx;
display: flex;
@@ -444,15 +437,8 @@
right: 20rpx;
}
// 图片样式
.u-lazy-load {
width: 100%;
height: 300rpx;
}
.item-cover {
font-size: 55rpx;
color: $u-type-warning;
}
.item-title {
@@ -485,7 +471,6 @@
padding: 0 15rpx 8rpx 15rpx;
}
// 标签样式
.item-tags {
display: flex;
flex-wrap: wrap;
@@ -506,4 +491,15 @@
color: $u-tips-color;
margin-top: 3px;
}
.img{
width: 100%;
height: 230rpx;
display: block;
}
.img-box {
border-radius: 10rpx;
width: 100%;
height: 230rpx;
overflow: hidden;
}
</style>

View File

@@ -3,8 +3,19 @@
<!-- 自定义导航栏 -->
<custom-navbar title="租金待付" />
<scroll-view scroll-y class="scroll-content" :refresher-enabled="true" :refresher-triggered="isRefreshing"
@refresherrefresh="refresh" @scrolltolower="loadMore">
<!-- 筛选栏 -->
<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="flowList.length > 0">
<view class="bill-item" v-for="item in flowList" :key="item.billNo">
<!-- 左侧勾选 + 信息 -->
@@ -20,7 +31,8 @@
<!-- 右侧金额 + 支付按钮 -->
<view class="bill-right">
<text class="amount">{{ formatMoney(item.billAmount) }}</text>
<button class="pay-btn" @click="goPayTest([item])">去支付
<button class="pay-btn" @click="goPay([item])" :disabled="isPaying">
去支付
</button>
</view>
</view>
@@ -40,8 +52,8 @@
合计<text class="sumAmount">{{ formatMoney(sumAmount) }}</text>
</view>
<view class="batch-pay-bar-right">
<button class="bottomPayBtn" color="linear-gradient(90deg, #007aff, #00aaff)" type="primary"
size="small" @click="goPayTest(selectedBills)">
<button class="bottomPayBtn" type="primary" size="small"
@click="goPay(selectedBills)" :disabled="isPaying">
批量支付
</button>
</view>
@@ -50,16 +62,23 @@
</template>
<script>
import DateFilter from '../../components/DatePicker/DateFilter.vue';
export default {
components: { DateFilter },
data() {
return {
pageNo: 1,
pageSize: 10,
flowList: [],
isRefreshing: false,
loadStatus: 'loadmore',
loadStatus: 'more',
sumAmount: 0,
selectedBills: [], // 勾选的账单集合
selectedBills: [],
startDate: "",
endDate: "",
minDate: "2000-01-01",
maxDate: "2199-12-31",
isPaying: false
};
},
onLoad(options) {
@@ -70,167 +89,190 @@
},
methods: {
loadBills() {
if (this.loadStatus !== 'loadmore') return;
if (this.loadStatus !== 'more') return;
this.loadStatus = 'loading';
const token = this.$getToken()
let url = '/bill/pageQueryContractBill'
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 || [];
console.log(rows)
rows.forEach(item => {
item.checked = false;
});
if (this.pageNo === 1) this.flowList = [];
this.flowList = this.flowList.concat(rows);
if (rows.length < this.pageSize) {
this.loadStatus = 'nomore';
} else {
this.pageNo++;
this.loadStatus = 'loadmore';
this.loadStatus = 'more';
}
}).catch(err => {
console.log("获取待付合同账单记录失败:", err)
this.loadStatus = 'loadmore';
this.loadStatus = 'more';
})
this.updateSelected();
},
onDateFilterChange({ start, end }) {
this.loadStatus = 'more'
this.refresh();
},
refresh() {
this.isRefreshing = true;
this.pageNo = 1;
this.selectedBills = [];
this.sumAmount = 0;
setTimeout(() => {
this.loadBills();
this.isRefreshing = false;
}, 1000);
}, 500);
},
loadMore() {
this.loadBills();
},
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 && !this.selectedBills.some(b => b.id === item.id)) {
this.selectedBills.push(item);
if (item.checked) {
if (!this.selectedBills.some(b => b.billNo === item.billNo)) {
this.selectedBills.push(item);
}
} else {
// 取消勾选时从已选数组移除
this.selectedBills = this.selectedBills.filter(b => b.id !== item.id);
this.selectedBills = this.selectedBills.filter(b => b.billNo !== item.billNo);
}
let sumFee = 0;
this.selectedBills.forEach(b => sumFee += b.billAmount);
this.sumAmount = sumFee;
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.selectedBills = this.flowList.filter(b => b.checked);
this.calcTotalAmount();
},
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
timeStamp: String(Date.now()),
nonceStr: Math.random().toString(36).substr(2, 15),
package: 'prepay_id=TEST1234567890',
signType: 'MD5',
paySign: 'TEST_SIGN', // 模拟签名
paySign: 'TEST_SIGN',
};
// 调用微信支付接口(测试)
uni.requestPayment({
...order,
success: () => {
uni.showToast({
title: '支付成功(测试)',
icon: 'success'
});
// 清空勾选状态
uni.showToast({ title: '支付成功(测试)', icon: 'success' });
billList.forEach(b => b.checked = false);
this.updateSelected();
// 刷新列表(可选)
this.loadBills();
this.refresh();
},
fail: () => {
uni.showToast({
title: '支付失败(测试)',
icon: 'none'
});
uni.showToast({ title: '支付失败(测试)', icon: 'none' });
}
});
},
updateBillStatus(billIds) {
const token = this.$getToken()
this.$u.post('/bill/updateRentBillStatus', { billIds }, { WT: token })
},
async goPay(billList) {
if (this.isPaying) return;
if (!billList || billList.length === 0) return;
this.isPaying = true;
const token = this.$getToken()
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),
}
});
let unpaidBillVos = []
let tempSumAmount = 0
billList.forEach(bill => {
unpaidBillVos.push({
billNo: bill.billNo,
bizType: 'rent',
amount: bill.billAmount
})
tempSumAmount += Number(bill.billAmount)
})
const res = await this.$u.post('/bill/pay', {
amount: tempSumAmount,
billVoList: unpaidBillVos
}, { WT: token });
if (res[1].data.code !== 0) {
uni.showToast({
title: res[1].data.msg,
icon: 'none'
});
if (res.code !== 200) {
uni.showToast({ title: res.msg, icon: 'none' });
this.isPaying = false;
return;
}
const order = res[1].data.data; // 后台返回的支付参数
// 2. 调用微信支付
const order = res.data;
let orderId = order.mainOrderId
uni.requestPayment({
timeStamp: order.timeStamp,
nonceStr: order.nonceStr,
package: order.package,
signType: order.signType,
paySign: order.paySign,
timeStamp: order.miniPayRequest.timeStamp,
nonceStr: order.miniPayRequest.nonceStr,
package: order.miniPayRequest.packageStr,
signType: order.miniPayRequest.signType,
paySign: order.miniPayRequest.paySign,
success: () => {
uni.showToast({
title: '支付成功',
icon: 'success'
});
// 更新勾选状态
billList.forEach(b => b.checked = false);
this.updateSelected();
// 刷新列表
this.loadBills();
this.refresh();
this.isPaying = false;
},
fail: () => {
uni.showToast({
title: '支付失败',
icon: 'none'
});
fail: (err) => {
this.payFailCallback(err, orderId);
this.isPaying = false;
}
});
} catch (error) {
console.error('支付请求失败', error);
uni.showToast({
title: '支付请求失败',
icon: 'none'
});
console.error('支付请求异常', error);
uni.showToast({ title: '支付请求失败', icon: 'none' });
this.isPaying = false;
}
},
payFailCallback(err, orderId) {
console.log("触发支付失败回调")
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("回调成功", res)
}).catch(err => {
console.log("回调失败", err)
})
uni.showToast({ title: reason, icon: 'none' });
}
}
};
}
</script>
<style lang="scss" scoped>
@@ -238,10 +280,11 @@
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;
}
@@ -263,6 +306,7 @@
.bill-info {
display: flex;
flex-direction: column;
margin-left: 12rpx;
.bill-name {
font-size: 30rpx;
@@ -301,16 +345,12 @@
padding: 0 40rpx;
height: 60rpx;
line-height: 60rpx;
border-radius: 6rpx; // 圆角
border-radius: 6rpx;
font-size: 30rpx;
color: #fff;
background-color: #F34038;
text-align: center;
}
.btn-text {
padding-top: 13rpx;
}
}
.batch-pay-bar {
@@ -318,7 +358,7 @@
bottom: 0;
left: 0;
right: 0;
height: 170rpx;
height: 110rpx;
padding: 0 30rpx;
background-color: #fff;
display: flex;
@@ -359,6 +399,11 @@
}
}
button[disabled] {
opacity: 0.5 !important;
background-color: #ccc !important;
color: #fff !important;
}
.empty {
margin-top: 200rpx;

View File

@@ -0,0 +1,415 @@
<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="flowList.length > 0">
<view class="bill-item" v-for="item in flowList" :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">{{ $ellipsis(item.billName + item.billStartDate+'-'+item.billEndDate,27) }}) </text>
<text class="bill-date">缴费截止<text class="date">{{ item.billPayEndDate }}</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,
flowList: [],
isRefreshing: false,
loadStatus: 'more', // ✅ 修复为正确状态
sumAmount: 0,
selectedBills: [],
startDate: "",
endDate: "",
minDate: "2000-01-01",
maxDate: "2199-12-31",
isPaying: false
};
},
onLoad(options) {
this.loadBills();
},
onShow() {
this.$checkToken(this.$getToken())
},
// ❌ 已删除冲突的 onReachBottom
methods: {
loadBills() {
// ✅ 正确判断状态
if (this.loadStatus !== 'more') return;
this.loadStatus = 'loading';
const token = this.$getToken()
let url = '/bill/pageQueryUnpaidMargin'
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.flowList = [];
this.flowList = this.flowList.concat(rows);
if (rows.length < this.pageSize) {
this.loadStatus = 'nomore';
} else {
this.pageNo++;
this.loadStatus = 'more'; // ✅ 恢复可加载
}
}).catch(err => {
console.log("获取待付保证金账单记录失败:", err)
this.loadStatus = 'more'; // ✅ 异常恢复
})
},
onDateFilterChange({ start, end }) {
this.loadStatus = 'more'
this.refresh();
},
refresh() {
this.isRefreshing = true;
this.pageNo = 1;
this.selectedBills = [];
this.sumAmount = 0;
setTimeout(() => {
this.loadBills();
this.isRefreshing = false;
}, 500);
},
loadMore() {
this.loadBills();
},
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() {
this.selectedBills = this.flowList.filter(b => b.checked);
this.calcTotalAmount();
},
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',
signType: 'MD5',
paySign: 'TEST_SIGN',
};
uni.requestPayment({
...order,
success: () => {
uni.showToast({ title: '支付成功(测试)', icon: 'success' });
billList.forEach(b => b.checked = false);
this.updateSelected();
this.refresh();
},
fail: () => {
uni.showToast({ title: '支付失败(测试)', icon: 'none' });
}
});
},
updateBillStatus(billIds) {
const token = this.$getToken()
this.$u.post('/bill/updateRentBillStatus', { billIds }, { WT: token })
},
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 => {
unpaidBillVos.push({
billNo: bill.billNo,
bizType: 'margin',
amount: bill.billAmount
})
tempSumAmount += Number(bill.billAmount)
})
const res = await this.$u.post('/bill/pay', {
amount: tempSumAmount,
billVoList: unpaidBillVos
}, { 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) {
console.log("触发支付失败回调")
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("回调成功", res)
}).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: 26rpx;
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;
font-size: 30rpx;
height: 28rpx;
line-height: 28rpx;
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>

View File

@@ -1,13 +1,20 @@
<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">
<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" />
@@ -17,10 +24,10 @@
</view>
</view>
<!-- 右侧金额 + 支付按钮 -->
<view class="bill-right">
<text class="amount">{{ formatMoney(item.billAmount) }}</text>
<button class="pay-btn" @click="goPayTest([item])">去支付
<button class="pay-btn" @click="goPay([item])" :disabled="isPaying">
去支付
</button>
</view>
</view>
@@ -33,15 +40,15 @@
<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" color="linear-gradient(90deg, #007aff, #00aaff)" type="primary"
size="small" @click="goPayTest(selectedBills)">
<button class="bottomPayBtn" type="primary" size="small"
@click="goPay(selectedBills)"
:disabled="isPaying">
批量缴费
</button>
</view>
@@ -50,16 +57,23 @@
</template>
<script>
import DateFilter from '../../components/DatePicker/DateFilter.vue';
export default {
components: { DateFilter },
data() {
return {
pageNo: 1,
pageSize: 10,
bills: [],
isRefreshing: false,
loadStatus: 'loadmore',
loadStatus: 'more', // ✅ 修复为正确状态
sumAmount: 0,
selectedBills: [], // 勾选的账单集合
selectedBills: [],
startDate: "",
endDate: "",
minDate: "2000-01-01",
maxDate: "2199-12-31",
isPaying: false
};
},
onLoad(options) {
@@ -68,166 +82,174 @@
onShow() {
this.$checkToken(this.$getToken())
},
// ❌ 已删除冲突的 onReachBottom
methods: {
loadBills() {
if (this.loadStatus !== 'loadmore') return;
// ✅ 正确判断状态
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(
result => {
const rows = result.data.result || [];
}).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 (this.pageNo === 1) this.bills = [];
this.bills = this.bills.concat(rows);
if (rows.length < this.pageSize) {
this.loadStatus = 'nomore';
} else {
this.pageNo++;
this.loadStatus = 'loadmore';
}
})
this.updateSelected();
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;
}, 1000);
}, 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 && !this.selectedBills.some(b => b.id === item.id)) {
this.selectedBills.push(item);
if (item.checked) {
if (!this.selectedBills.some(b => b.billNo === item.billNo)) {
this.selectedBills.push(item);
}
} else {
// 取消勾选时从已选数组移除
this.selectedBills = this.selectedBills.filter(b => b.id !== item.id);
this.selectedBills = this.selectedBills.filter(b => b.billNo !== item.billNo);
}
let sumFee = 0;
this.selectedBills.forEach(b => sumFee += b.billAmount);
this.sumAmount = sumFee;
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);
},
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'
});
}
});
this.calcTotalAmount();
},
async goPay(billList) {
if (this.isPaying) return;
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),
}
});
this.isPaying = true;
const token = this.$getToken()
if (res[1].data.code !== 0) {
uni.showToast({
title: res[1].data.msg,
icon: 'none'
});
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[1].data.data; // 后台返回的支付参数
const order = res.data;
let orderId = order.mainOrderId
// 2. 调用微信支付
uni.requestPayment({
timeStamp: order.timeStamp,
nonceStr: order.nonceStr,
package: order.package,
signType: order.signType,
paySign: order.paySign,
timeStamp: order.miniPayRequest.timeStamp,
nonceStr: order.miniPayRequest.nonceStr,
package: order.miniPayRequest.packageStr,
signType: order.miniPayRequest.signType,
paySign: order.miniPayRequest.paySign,
success: () => {
uni.showToast({
title: '支付成功',
icon: 'success'
});
// 更新勾选状态
billList.forEach(b => b.checked = false);
this.updateSelected();
// 刷新列表
this.loadBills();
this.refresh();
this.isPaying = false;
},
fail: () => {
uni.showToast({
title: '支付失败',
icon: 'none'
});
fail: (err) => {
this.payFailCallback(err, orderId);
this.isPaying = false;
}
});
} catch (error) {
console.error('支付请求失败', error);
uni.showToast({
title: '支付请求失败',
icon: 'none'
});
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>
@@ -237,10 +259,12 @@
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;
}
@@ -262,6 +286,7 @@
.bill-info {
display: flex;
flex-direction: column;
margin-left: 12rpx;
.bill-name {
font-size: 30rpx;
@@ -300,16 +325,12 @@
padding: 0 40rpx;
height: 60rpx;
line-height: 60rpx;
border-radius: 6rpx; // 圆角
border-radius: 6rpx;
font-size: 30rpx;
color: #fff;
background-color: #F34038;
text-align: center;
}
.btn-text {
padding-top: 13rpx;
}
}
.batch-pay-bar {
@@ -317,7 +338,7 @@
bottom: 0;
left: 0;
right: 0;
height: 170rpx;
height: 110rpx;
padding: 0 30rpx;
background-color: #fff;
display: flex;
@@ -358,6 +379,11 @@
}
}
button[disabled] {
opacity: 0.5 !important;
background-color: #ccc !important;
color: #fff !important;
}
.empty {
margin-top: 200rpx;