Files
RentWeAppFront/pages-biz/contract/contract.vue
2026-07-24 10:46:00 +08:00

368 lines
8.3 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="contract-page">
<!-- 顶部导航栏 -->
<customNavbar title="我的合同" :showHome="true"/>
<!-- Tabs -->
<view class="tab-wrapper">
<u-tabs :list="tabList" :current="currentTab" @change="onTabChange" lineColor="#0088FE" activeColor="#0088FE"
itemStyle="padding: 0 30rpx;"></u-tabs>
</view>
<DateFilter :start="startDate" :end="endDate" @update:start="startDate = $event" @update:end="endDate = $event"
@change="onDateFilterChange" />
<!-- 合同列表 -->
<scroll-view scroll-y class="scroll-content" @scrolltolower="loadMore" :refresher-enabled="true"
:refresher-triggered="isRefreshing" @refresherrefresh="refresh">
<view v-if="contracts.length > 0" class="contract-list">
<view :class="['contract-card', { 'is-expired': item.signStatus === 'expired' }]" v-for="item in contracts" :key="item.contractNo" @click="goDetail(item)">
<view class="card-header">
<text class="contract-name">{{ $ellipsis(item.contractName, 12) }}</text>
<view :class="['status-tag', item.signStatus]">
{{ getStatusText(item.signStatus) }}
</view>
</view>
<view class="card-divider"></view>
<view class="card-body">
<view class="info-row">
<view class="info-item">
<text class="info-label">合同类型</text>
<text class="info-value">电子合同</text>
</view>
<view class="info-item">
<text class="info-label">租金</text>
<text class="info-value">{{ item.contractNo }}</text>
</view>
</view>
<view class="info-row">
<view class="info-item">
<text class="info-label">开始日期</text>
<text class="info-value">{{ item.startDate }}</text>
</view>
<view class="info-item">
<text class="info-label">结束日期</text>
<text class="info-value">{{ item.endDate }}</text>
</view>
</view>
</view>
</view>
<u-loadmore :status="loadStatus" />
</view>
<view v-else class="empty">
<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" },
],
currentTab: 0,
statusFilter: "all",
startDate: "",
endDate: "",
minDate: "2000-01-01",
maxDate: "2199-12-31",
contracts: [],
pageNo: 1,
pageSize: 10,
total: 0,
loadStatus: "more", // ✅ 修复为官方正确值
isRefreshing: false,
defaultCover: "/public/static/index/assets.jpg",
};
},
onLoad(options) {
// loadContracts 移到 onShow 中,等 token 校验通过后再加载
},
async onShow() {
try {
// await this.$checkToken(this.$getToken())
// token 有效,继续执行
// this.checkOaAuth()
this.loadContracts()
} catch (e) {
// token 无效,$checkToken 内部已处理跳转登录页
return
}
},
// ✅ 删除和 scroll-view 冲突的 onReachBottom
computed: {
staticHost() {
return this.$config.staticUrl
}
},
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' })
}
})
}
},
onTabChange(index) {
this.currentTab = index;
this.statusFilter = this.tabList[index].value;
this.resetAndLoad();
},
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 = "more"; // ✅ 修复
this.loadContracts();
},
loadContracts() {
if (this.loadStatus !== 'more') return;
this.loadStatus = 'loading';
// TODO: 接口联调时取消注释,删除 mock 数据
// 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;
// });
// Mock 静态数据
const mockData = [
{
contractNo: 'HT-2026-001',
contractName: '东山大道435-2-1-104号房屋租赁合同',
startDate: '2026-01-01',
endDate: '2026-12-31',
signStatus: 'signed'
},
{
contractNo: 'HT-2026-002',
contractName: '夷陵大道418号房屋租赁合同',
startDate: '2026-03-01',
endDate: '2027-02-28',
signStatus: 'pending'
},
{
contractNo: 'HT-2025-003',
contractName: '解放路88-1-502号房屋租赁合同',
startDate: '2025-01-01',
endDate: '2025-12-31',
signStatus: 'expired'
}
];
if (this.pageNo === 1) this.contracts = [];
this.contracts = this.contracts.concat(mockData);
this.loadStatus = 'nomore';
this.isRefreshing = false;
},
refresh() {
this.isRefreshing = true;
this.resetAndLoad();
},
loadMore() {
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 "已过期";
default: return "未知";
}
},
},
};
</script>
<style lang="scss" scoped>
.contract-page {
background-color: #f8f8f8;
padding-top: 170rpx;
min-height: 100vh;
box-sizing: border-box;
}
/* ✅ 核心修复:正确的滚动高度 */
.scroll-content {
height: calc(100vh - 170rpx - 100rpx);
box-sizing: border-box;
}
.contract-list {
padding: 20rpx;
}
.card-info {
flex: 1;
margin-left: 20rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 20rpx;
}
.card-divider {
height: 1rpx;
background-color: #f0f0f0;
}
.contract-card {
background: #fff;
border-radius: 16rpx;
margin-bottom: 24rpx;
padding: 24rpx;
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.05);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 20rpx;
}
.contract-name {
font-size: 30rpx;
font-weight: 600;
color: #333;
flex: 1;
}
.status-tag {
font-size: 24rpx;
padding: 6rpx 16rpx;
border-radius: 8rpx;
flex-shrink: 0;
&.pending {
background: #FF8D1A;
color: #fff;
}
&.signed {
background: #0088FE;
color: #fff;
}
&.expired {
background: #A6A6A6;
color: #fff;
}
}
.card-divider {
height: 1rpx;
background-color: #f0f0f0;
}
.card-body {
padding-top: 20rpx;
}
.info-row {
display: flex;
margin-bottom: 16rpx;
padding: 20rpx 0;
&:last-child {
margin-bottom: 0;
}
}
.info-item {
flex: 1;
display: flex;
}
.info-label {
font-size: 24rpx;
color: #999;
margin-right: 8rpx;
flex-shrink: 0;
}
.info-value {
font-size: 24rpx;
color: #333;
}
.is-expired {
.contract-name,
.info-label,
.info-value {
color: #A6A6A6 !important;
}
}
.empty {
margin-top: 200rpx;
}
.tab-wrapper {
background-color: #ffffff;
padding: 10rpx 0;
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.06);
position: sticky;
top: 0;
z-index: 10;
}
</style>