提交代码

This commit is contained in:
zlwu committed 2025-08-22 22:24:06 +08:00
1 parent eb51f1645c
commit c164d1feb4
21 files changed
+1721 -381

No files matched your search

+8 -1
View File
@@ -50,7 +50,7 @@
<!-- 流程列表 -->
<view v-else class="process-list">
<view
v-for="item in processInstanceList"
v-for="(item, index) in processInstanceList"
:key="item.id"
class="process-item"
@click="handleView(item)"
@@ -58,6 +58,7 @@
<!-- 流程信息 -->
<view class="process-header">
<view class="process-title-row">
<text class="title-index">{{ index + 1 }}.</text>
<text class="process-name">{{ item.flowName }}</text>
<u-tag
:text="getStatusText(item.flowStatus)"
@@ -751,6 +752,12 @@ export default {
margin-bottom: 8px;
}
.title-index {
color: #000000;
font-weight: bold;
margin-right: 8px;
}
.process-name {
font-size: 16px;
font-weight: 500;
+10 -1
View File
@@ -43,7 +43,10 @@
<view v-for="(item, index) in taskList" :key="item.id || index" class="task-card">
<!-- 卡片头部 -->
<view class="card-header">
<view class="flow-name">{{ item.flowName || '-' }}</view>
<view class="flow-name">
<text class="title-index">{{ index + 1 }}.</text>
{{ item.flowName || '-' }}
</view>
<view class="flow-status">
<u-tag
:text="getFlowStatusText(item.flowStatus)"
@@ -458,6 +461,12 @@ export default {
border-bottom: 1px solid #f0f0f0;
}
.title-index {
color: #000000;
font-weight: bold;
margin-right: 8rpx;
}
.flow-name {
font-size: 32rpx;
font-weight: bold;
+10 -1
View File
@@ -73,7 +73,10 @@
>
<!-- 卡片头部 -->
<view class="card-header">
<view class="task-title">{{ item.flowName || '-' }}</view>
<view class="task-title">
<text class="title-index">{{ index + 1 }}.</text>
{{ item.flowName || '-' }}
</view>
<view class="task-status">
<u-tag
:text="getFlowStatusText(item.flowStatus)"
@@ -842,6 +845,12 @@ export default {
border-bottom: 1px solid #f0f0f0;
}
.title-index {
color: #000000;
font-weight: bold;
margin-right: 8rpx;
}
.task-title {
font-size: 32rpx;
font-weight: bold;
+156 -80
View File
@@ -53,92 +53,110 @@
<u-empty text="暂无待办任务" mode="data"></u-empty>
</view>
<!-- 任务卡片列表 -->
<view v-else class="task-list">
<view v-for="(item, index) in taskList" :key="item.id || index" class="task-card">
<!-- 卡片头部 -->
<view class="card-header">
<view class="task-title">{{ item.flowName || '-' }}</view>
<view class="task-status">
<u-tag
:text="getFlowStatusText(item.flowStatus)"
:type="getFlowStatusType(item.flowStatus)"
size="mini"
></u-tag>
</view>
</view>
<!-- 卡片内容 -->
<view class="card-content">
<view class="info-item">
<text class="label">流程名称:</text>
<text class="value">{{ item.flowName || '-' }}</text>
</view>
<view class="info-item">
<text class="label">流程分类:</text>
<text class="value">{{ item.categoryName || '-' }}</text>
</view>
<view class="info-item">
<text class="label">任务名称:</text>
<text class="value">{{ item.nodeName || '-' }}</text>
</view>
<view class="info-item">
<text class="label">申请人:</text>
<text class="value">{{ item.createByName || '-' }}</text>
</view>
<view class="info-item">
<text class="label">办理人:</text>
<view class="assignee-tags">
<template v-if="item.assigneeNames">
<u-tag
v-for="(name, idx) in item.assigneeNames.split(',')"
:key="idx"
:text="name"
type="success"
size="mini"
style="margin-right: 8rpx; margin-bottom: 8rpx"
></u-tag>
</template>
<u-tag v-else text="无" type="info" size="mini"></u-tag>
<!-- 任务卡片列表 - 滚动加载 -->
<scroll-view
v-else
scroll-y
class="task-scroll-list"
@scrolltolower="loadMore"
:scroll-top="scrollTop"
refresher-enabled="true"
:refresher-triggered="refreshing"
@refresherrefresh="onRefresh"
>
<view class="task-list">
<view
v-for="(item, index) in taskList"
:key="item.id || index"
class="task-card"
>
<!-- 卡片头部 -->
<view class="card-header">
<view class="task-title">
<text class="title-index">{{ index + 1 }}.</text>
{{ item.flowName || '-' }}
</view>
<view class="task-status">
<u-tag
:text="getFlowStatusText(item.flowStatus)"
:type="getFlowStatusType(item.flowStatus)"
size="mini"
></u-tag>
</view>
</view>
<view class="info-item">
<text class="label">创建时间:</text>
<text class="value">{{ formatTime(item.createTime) }}</text>
<!-- 卡片内容 -->
<view class="card-content">
<view class="info-item">
<text class="label">流程名称:</text>
<text class="value">{{ item.flowName || '-' }}</text>
</view>
<view class="info-item">
<text class="label">流程分类:</text>
<text class="value">{{ item.categoryName || '-' }}</text>
</view>
<view class="info-item">
<text class="label">任务名称:</text>
<text class="value">{{ item.nodeName || '-' }}</text>
</view>
<view class="info-item">
<text class="label">申请人:</text>
<text class="value">{{ item.createByName || '-' }}</text>
</view>
<view class="info-item">
<text class="label">办理人:</text>
<view class="assignee-tags">
<template v-if="item.assigneeNames">
<u-tag
v-for="(name, idx) in item.assigneeNames.split(',')"
:key="idx"
:text="name"
type="success"
size="mini"
style="margin-right: 8rpx; margin-bottom: 8rpx"
></u-tag>
</template>
<u-tag v-else text="无" type="info" size="mini"></u-tag>
</view>
</view>
<view class="info-item">
<text class="label">创建时间:</text>
<text class="value">{{ formatTime(item.createTime) }}</text>
</view>
</view>
<!-- 操作按钮 -->
<view class="card-actions">
<u-button
@click="handleApproval(item)"
type="primary"
size="small"
shape="circle"
>
<u-icon
name="edit-pen"
size="16"
color="#fff"
style="margin-right: 8rpx"
></u-icon>
办理
</u-button>
</view>
</view>
<!-- 操作按钮 -->
<view class="card-actions">
<u-button
@click="handleApproval(item)"
type="primary"
size="small"
shape="circle"
>
<u-icon
name="edit-pen"
size="16"
color="#fff"
style="margin-right: 8rpx"
></u-icon>
办理
</u-button>
</view>
</view>
</view>
<!-- 滚动加载更多 -->
<u-loadmore
v-if="taskList.length > 0"
:status="loadmoreStatus"
:load-text="{
loadmore: '轻轻上拉',
loading: '努力加载中',
nomore: '没有更多了',
}"
@loadmore="loadMore"
></u-loadmore>
<!-- 滚动加载更多状态 -->
<view v-if="taskList.length > 0" class="loadmore-status">
<u-loadmore
:status="loadmoreStatus"
:load-text="{
loadmore: '轻轻上拉加载更多',
loading: '努力加载中...',
nomore: '没有更多数据了',
}"
></u-loadmore>
</view>
</scroll-view>
</view>
<!-- 申请人选择弹窗 -->
@@ -229,6 +247,10 @@ export default {
total: 0,
loadmoreStatus: 'loadmore', // loadmore, loading, nomore
// 滚动相关
scrollTop: 0,
refreshing: false,
// 查询参数
queryParams: {
pageNum: 1,
@@ -262,6 +284,8 @@ export default {
async created() {
await this.loadFlowStatusDict();
// 重置滚动位置
this.scrollTop = 0;
await this.getList();
},
@@ -320,6 +344,8 @@ export default {
if (!isLoadMore) {
this.loading = true;
this.queryParams.pageNum = 1;
// 非加载更多时重置滚动位置
this.scrollTop = 0;
} else {
this.loadmoreStatus = 'loading';
}
@@ -400,6 +426,8 @@ export default {
// 搜索操作
handleQuery() {
// 重置滚动位置
this.scrollTop = 0;
this.getList();
},
@@ -413,6 +441,35 @@ export default {
this.getList(true);
},
// 下拉刷新
async onRefresh() {
this.refreshing = true;
try {
// 重置分页参数
this.queryParams.pageNum = 1;
this.loadmoreStatus = 'loadmore';
// 重新加载数据
await this.getList();
// 显示刷新成功提示
uni.showToast({
title: '刷新成功',
icon: 'success',
duration: 1500,
});
} catch (error) {
console.error('下拉刷新失败:', error);
uni.showToast({
title: '刷新失败',
icon: 'none',
duration: 1500,
});
} finally {
this.refreshing = false;
}
},
// 格式化时间
formatTime(timeStr) {
if (!timeStr) return '-';
@@ -536,6 +593,8 @@ export default {
}
this.userSelectDialog.visible = false;
// 重置滚动位置并查询
this.scrollTop = 0;
this.handleQuery();
},
@@ -717,6 +776,12 @@ export default {
.content-wrapper {
padding: 20rpx;
height: calc(100vh - 200rpx); /* 减去导航栏和搜索区域的高度 */
}
.task-scroll-list {
height: 100%;
padding: 0 20rpx;
}
.empty-container {
@@ -744,6 +809,12 @@ export default {
border-bottom: 1px solid #f0f0f0;
}
.title-index {
color: #000000;
font-weight: bold;
margin-right: 8rpx;
}
.task-title {
font-size: 32rpx;
font-weight: bold;
@@ -923,4 +994,9 @@ export default {
::v-deep .u-loadmore {
padding: 40rpx 0;
}
.loadmore-status {
padding: 20rpx 0;
text-align: center;
}
</style>
+119 -2
View File
@@ -92,6 +92,12 @@
<!-- 请假记录卡片列表 -->
<view v-else class="leave-list">
<view v-for="(item, index) in leaveList" :key="item.id || index" class="leave-card">
<!-- 序号标识 -->
<view class="card-index">
<text class="index-text">
{{ getItemIndex(index) }}
</text>
</view>
<!-- 卡片头部 -->
<view class="card-header">
<view class="leave-info">
@@ -478,7 +484,11 @@ export default {
本次加载: newData.length,
总数: this.total,
列表长度: this.leaveList.length,
分页状态: this.loadStatus,
});
// 验证序号连续性
this.validateIndexContinuity();
} else {
console.warn('获取请假记录失败:', res?.msg);
uni.showToast({
@@ -518,7 +528,12 @@ export default {
return;
}
console.log('📄 开始加载更多数据...');
console.log('📄 开始加载更多数据...', {
当前页码: this.queryParams.pageNum,
当前列表长度: this.leaveList.length,
总数: this.total,
});
this.queryParams.pageNum += 1;
await this.loadLeaveList(false);
},
@@ -604,11 +619,17 @@ export default {
// 搜索操作
handleQuery() {
console.log('🔍 执行搜索:', this.queryParams);
// 搜索时重置分页状态
this.queryParams.pageNum = 1;
this.loadStatus = 'loadmore';
this.loadLeaveList();
},
// 重置搜索
resetQuery() {
console.log('🔄 重置搜索条件...');
this.queryParams.startTime = '';
this.queryParams.endTime = '';
this.queryParams.approvalStatus = '';
@@ -616,6 +637,12 @@ export default {
this.endTimeDisplay = '';
this.startTimeValue = '';
this.endTimeValue = '';
// 重置分页状态
this.queryParams.pageNum = 1;
this.loadStatus = 'loadmore';
console.log('🔄 重置完成,开始加载数据...');
this.loadLeaveList();
},
@@ -703,6 +730,60 @@ export default {
}
},
// 计算列表项序号
getItemIndex(index) {
// 序号应该基于数据在列表中的实际位置,而不是基于当前请求的页码
// 直接使用 index + 1,因为数据已经按顺序合并到 leaveList 中
const finalIndex = index + 1;
// 调试信息
console.log('🔢 序号计算:', {
当前项索引: index,
最终序号: finalIndex,
列表总长度: this.leaveList.length,
});
return finalIndex;
},
// 验证序号连续性
validateIndexContinuity() {
if (this.leaveList.length === 0) return;
console.log('🔍 验证序号连续性...');
const expectedIndices = [];
for (let i = 0; i < this.leaveList.length; i++) {
const expectedIndex = i + 1;
const actualIndex = this.getItemIndex(i);
expectedIndices.push({ position: i, expected: expectedIndex, actual: actualIndex });
}
console.log('🔍 序号验证结果:', expectedIndices);
// 检查是否有不连续的序号
const hasDiscontinuity = expectedIndices.some((item, index) => {
if (index === 0) return false;
return item.expected !== expectedIndices[index - 1].expected + 1;
});
if (hasDiscontinuity) {
console.warn('⚠️ 发现序号不连续:', expectedIndices);
} else {
console.log('✅ 序号连续性验证通过');
}
// 额外验证:检查序号范围
const minIndex = Math.min(...expectedIndices.map((item) => item.actual));
const maxIndex = Math.max(...expectedIndices.map((item) => item.actual));
console.log('🔍 序号范围验证:', {
最小序号: minIndex,
最大序号: maxIndex,
期望范围: `1-${this.leaveList.length}`,
是否正常: minIndex === 1 && maxIndex === this.leaveList.length,
});
},
// 查看详情
handleViewDetail(item) {
const detailInfo = [
@@ -863,6 +944,26 @@ export default {
border-radius: 16rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
overflow: hidden;
position: relative;
}
// 序号标识
.card-index {
position: absolute;
top: 8rpx;
left: 8rpx;
background-color: #f5f6fa;
padding: 6rpx 12rpx;
border-radius: 8rpx;
z-index: 1;
min-width: 32rpx;
text-align: center;
}
.index-text {
font-size: 24rpx;
color: #909399;
font-weight: 500;
}
// 卡片头部
@@ -871,6 +972,7 @@ export default {
justify-content: space-between;
align-items: flex-start;
padding: 24rpx;
padding-left: 80rpx; // 为序号预留左边空间
border-bottom: 1px solid #f0f0f0;
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
}
@@ -928,6 +1030,7 @@ export default {
// 卡片内容
.card-content {
padding: 24rpx;
padding-left: 80rpx; // 与头部对齐
}
.info-section {
@@ -1021,6 +1124,7 @@ export default {
display: flex;
justify-content: flex-end;
padding: 20rpx;
padding-left: 80rpx; // 与头部对齐
border-top: 1px solid #f0f0f0;
gap: 16rpx;
}
@@ -1080,8 +1184,21 @@ export default {
}
.card-header,
.card-content {
.card-content,
.card-actions {
padding: 20rpx;
padding-left: 70rpx; // 小屏幕下为序号预留左边空间
}
.card-index {
top: 6rpx;
left: 6rpx;
padding: 4rpx 8rpx;
min-width: 28rpx;
}
.index-text {
font-size: 22rpx;
}
.fab-button {
+17 -2
View File
@@ -39,7 +39,10 @@
>
<!-- 卡片头部 -->
<view class="card-header">
<view class="batch-title">{{ item.batchName || '-' }}</view>
<view class="batch-title">
<text class="batch-number">{{ index + 1 }}.</text>
<text>{{ item.batchName || '-' }}</text>
</view>
<view class="batch-status">
<u-tag
:text="item.status === '0' ? '正常' : '停用'"
@@ -90,7 +93,12 @@
></u-icon>
信息完善
</u-button>
<u-button type="info" shape="round" size="small" @click="handleViewHistory(item)">
<u-button
type="info"
shape="round"
size="small"
@click="handleViewHistory(item)"
>
<u-icon
name="clock"
size="14"
@@ -450,6 +458,13 @@ export default {
font-weight: bold;
color: #303133;
flex: 1;
display: flex;
align-items: center;
}
.batch-number {
color: #000000;
margin-right: 8rpx;
}
.batch-status {
+147 -27
View File
@@ -50,12 +50,15 @@
</view>
<!-- 加载状态 -->
<u-loading-page :loading="loading" loading-text="加载中..."></u-loading-page>
<u-loading-page
:loading="loading && queryParams.pageNum === 1"
loading-text="加载中..."
></u-loading-page>
<!-- 列表内容 -->
<view v-if="!loading" class="content-wrapper">
<view v-if="!loading || queryParams.pageNum > 1" class="content-wrapper">
<!-- 空状态 -->
<view v-if="dormViolationList.length === 0" class="empty-container">
<view v-if="dormViolationList.length === 0 && !loading" class="empty-container">
<u-empty text="暂无违纪记录" mode="data"></u-empty>
</view>
@@ -66,6 +69,13 @@
:key="item.id || index"
class="violation-card"
>
<!-- 序号标识 -->
<view class="card-index">
<text class="index-text">
{{ index + 1 }}
</text>
</view>
<!-- 卡片头部 -->
<view class="card-header">
<view class="student-info">
@@ -178,15 +188,18 @@
</view>
</view>
<!-- 加载更多 -->
<view v-if="hasMore" class="load-more">
<u-loadmore
:status="loadMoreStatus"
@loadmore="loadMore"
:loading-text="loadingText"
:loadmore-text="loadMoreText"
:nomore-text="noMoreText"
></u-loadmore>
<!-- 底部加载状态提示 -->
<view v-if="dormViolationList.length > 0" class="load-status">
<view v-if="loading && queryParams.pageNum > 1" class="loading-tip">
<u-loading-icon mode="circle" size="32"></u-loading-icon>
<text class="loading-text">加载中...</text>
</view>
<view v-else-if="!hasMore" class="no-more-tip">
<text class="no-more-text">没有更多数据了</text>
</view>
<view v-else-if="dormViolationList.length >= 10" class="pull-tip">
<text class="pull-text">上拉加载更多</text>
</view>
</view>
</view>
</view>
@@ -205,10 +218,6 @@ export default {
dormViolationList: [],
total: 0,
hasMore: true,
loadMoreStatus: 'loadmore',
loadingText: '努力加载中...',
loadMoreText: '点击或上拉加载更多',
noMoreText: '没有更多了',
// 查询参数
queryParams: {
@@ -253,6 +262,16 @@ export default {
await this.initData();
},
// 监听页面触底事件
onReachBottom() {
this.loadMore();
},
// 监听下拉刷新事件
onPullDownRefresh() {
this.refreshData();
},
methods: {
// 返回上一页
goBack() {
@@ -296,10 +315,19 @@ export default {
// 获取违纪记录列表
async getList(isLoadMore = false) {
if (this.loading) return;
// 防止重复加载
if (this.loading) {
console.log('正在加载中,跳过本次请求');
return;
}
// 如果没有更多数据且是加载更多操作,直接返回
if (isLoadMore && !this.hasMore) {
console.log('没有更多数据,跳过加载更多');
return;
}
this.loading = true;
this.loadMoreStatus = 'loading';
try {
// 获取当前登录用户信息
@@ -326,24 +354,52 @@ export default {
if (res && res.code === 200) {
const { rows, total } = res;
// 确保 rows 是数组
const newData = Array.isArray(rows) ? rows : [];
console.log('API返回数据:', {
isLoadMore: isLoadMore,
pageNum: this.queryParams.pageNum,
apiReturnedCount: newData.length,
currentListLength: this.dormViolationList.length,
total: total,
});
if (isLoadMore) {
this.dormViolationList = [...this.dormViolationList, ...rows];
// 加载更多时,追加数据(去重处理)
const existingIds = new Set(this.dormViolationList.map((item) => item.id));
const uniqueNewData = newData.filter((item) => !existingIds.has(item.id));
console.log('加载更多去重处理:', {
existingCount: this.dormViolationList.length,
newDataCount: newData.length,
uniqueNewDataCount: uniqueNewData.length,
duplicateCount: newData.length - uniqueNewData.length,
});
this.dormViolationList = [...this.dormViolationList, ...uniqueNewData];
} else {
this.dormViolationList = rows;
// 首次加载或搜索时,替换数据
this.dormViolationList = newData;
}
this.total = total;
// 更新是否还有更多数据的状态
this.hasMore = this.dormViolationList.length < total;
console.log('获取违纪记录成功:', {
current: this.dormViolationList.length,
finalListLength: this.dormViolationList.length,
total: total,
hasMore: this.hasMore,
isLoadMore: isLoadMore,
pageNum: this.queryParams.pageNum,
});
} else {
if (!isLoadMore) {
this.dormViolationList = [];
this.total = 0;
this.hasMore = false;
}
uni.showToast({
title: res?.msg || '获取数据失败',
@@ -355,6 +411,7 @@ export default {
if (!isLoadMore) {
this.dormViolationList = [];
this.total = 0;
this.hasMore = false;
}
uni.showToast({
title: '获取数据失败',
@@ -362,13 +419,17 @@ export default {
});
} finally {
this.loading = false;
this.loadMoreStatus = this.hasMore ? 'loadmore' : 'nomore';
// 结束下拉刷新
if (!isLoadMore) {
uni.stopPullDownRefresh();
}
}
},
// 搜索操作
handleQuery() {
this.queryParams.pageNum = 1;
this.hasMore = true;
this.getList();
},
@@ -379,10 +440,18 @@ export default {
pageSize: 10,
violationTime: '',
};
this.hasMore = true;
this.getList();
},
// 加载更多
// 下拉刷新
refreshData() {
this.queryParams.pageNum = 1;
this.hasMore = true;
this.getList();
},
// 加载更多(滚动到底部触发)
loadMore() {
if (this.hasMore && !this.loading) {
this.queryParams.pageNum++;
@@ -554,13 +623,34 @@ export default {
border-radius: 16rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
overflow: hidden;
position: relative;
}
.card-index {
position: absolute;
top: 12rpx;
left: 12rpx;
width: 40rpx;
height: 40rpx;
background-color: rgba(162, 161, 161, 0.8);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
}
.index-text {
font-size: 22rpx;
font-weight: bold;
color: #fff;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx;
padding: 24rpx 24rpx 24rpx 70rpx;
border-bottom: 1px solid #f0f0f0;
background-color: #f8f9fa;
}
@@ -673,10 +763,42 @@ export default {
border-top: 1px solid #f0f0f0;
}
.load-more {
// 底部加载状态样式
.load-status {
padding: 30rpx 0;
text-align: center;
}
.loading-tip {
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
}
.loading-text {
font-size: 26rpx;
color: #909399;
}
.no-more-tip {
padding: 20rpx 0;
}
.no-more-text {
font-size: 26rpx;
color: #c0c4cc;
}
.pull-tip {
padding: 20rpx 0;
}
.pull-text {
font-size: 26rpx;
color: #909399;
}
// uview组件样式调整
::v-deep .u-tag {
margin: 0;
@@ -684,13 +806,11 @@ export default {
::v-deep .u-button {
flex: 1;
// max-width: 200rpx;
border-radius: 8rpx;
}
// 搜索按钮样式
::v-deep .search-btn {
// background: linear-gradient(135deg, #007aff, #0051d9) !important;
border: none !important;
box-shadow: 0 4px 16px rgba(0, 122, 255, 0.3) !important;
transition: all 0.3s ease !important;
+45 -32
View File
@@ -48,7 +48,10 @@
<view class="card-header">
<!-- 第一行:标题和卫生等级 -->
<view class="header-row">
<view class="check-title">{{ item.checkTitle || '-' }}</view>
<view class="check-title">
<text class="title-index">{{ index + 1 }}.</text>
{{ item.checkTitle || '-' }}
</view>
<view class="grade-section">
<u-tag
:text="$getDictLabel(xg_dorm_hygiene_grade, item.hygieneGrade)"
@@ -151,22 +154,37 @@
<!-- 操作按钮 -->
<view class="card-actions">
<!-- 查看按钮 -->
<view class="action-btn primary-btn" @click="handleView(item)">
<u-icon name="eye" size="16" color="#19be6b"></u-icon>
<text class="btn-text">查看</text>
</view>
<u-button
type="info"
size="small"
class="action-btn"
@click="handleView(item)"
>
<u-icon name="eye" size="16" color="#323233"></u-icon>
<text>查看</text>
</u-button>
<!-- 修改按钮 -->
<view class="action-btn info-btn" @click="handleUpdate(item)">
<u-icon name="edit-pen" size="16" color="#3c9cff"></u-icon>
<u-button
type="primary"
size="small"
class="action-btn"
@click="handleUpdate(item)"
>
<u-icon name="edit-pen" size="16" color="#ffffff"></u-icon>
<text class="btn-text">修改</text>
</view>
</u-button>
<!-- 删除按钮 -->
<view class="action-btn danger-btn" @click="handleDelete(item)">
<u-icon name="trash" size="16" color="#f56c6c"></u-icon>
<u-button
type="error"
size="small"
class="action-btn"
@click="handleDelete(item)"
>
<u-icon name="trash" size="16" color="#ffffff"></u-icon>
<text class="btn-text">删除</text>
</view>
</u-button>
</view>
</view>
</view>
@@ -608,6 +626,12 @@ export default {
flex: 1;
}
.title-index {
color: #000000;
font-weight: bold;
margin-right: 8rpx;
}
.check-level {
flex-shrink: 0;
}
@@ -733,37 +757,26 @@ export default {
.action-btn {
display: flex;
flex-direction: column;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 16rpx 20rpx;
border-radius: 12rpx;
min-width: 120rpx;
transition: all 0.3s ease;
background-color: transparent;
border-radius: 20rpx;
&:active {
transform: scale(0.95);
opacity: 0.8;
::v-deep .u-button {
border-radius: 20rpx;
padding: 16rpx 20rpx;
min-width: 120rpx;
height: auto;
line-height: 1.2;
}
}
.btn-text {
font-size: 24rpx;
margin-top: 8rpx;
margin-left: 8rpx;
font-weight: 500;
}
.primary-btn .btn-text {
color: #19be6b;
}
.info-btn .btn-text {
color: #3c9cff;
}
.danger-btn .btn-text {
color: #f56c6c;
color: #ffffff;
}
// 分页容器
+74 -65
View File
@@ -60,7 +60,10 @@
<view class="card-header">
<!-- 第一行:标题和卫生等级 -->
<view class="header-row">
<view class="check-title">{{ item.checkTitle || '-' }}</view>
<view class="check-title">
<text class="check-index">{{ index + 1 }}.</text>
<text>{{ item.checkTitle || '-' }}</text>
</view>
<view class="grade-section">
<u-tag
:text="$getDictLabel(xg_dorm_hygiene_grade, item.hygieneGrade)"
@@ -189,8 +192,8 @@
</view>
</view>
<!-- 分页加载(已废弃,因为接口返回完整列表) -->
<!-- <view v-if="checkList.length > 0" class="pagination-container">
<!-- 分页加载 -->
<view v-if="checkList.length > 0" class="pagination-container">
<u-loadmore
:status="loadStatus"
@loadmore="loadMore"
@@ -198,7 +201,7 @@
loading-text="正在加载..."
no-more-text="没有更多数据了"
/>
</view> -->
</view>
<!-- 悬浮添加按钮 -->
<!-- <view class="fab-button" @click="handleAdd">
@@ -227,7 +230,6 @@ export default {
// 检查记录列表
checkList: [],
originalCheckList: [], // 原始数据,用于前端过滤
total: 0,
// 分页加载状态
@@ -260,11 +262,11 @@ export default {
uni.$off('refreshCheckList', this.handleRefreshEvent);
},
// 页面滚动到底部事件(已废弃,因为接口返回完整列表)
// onReachBottom() {
// console.log('🔄 触发滚动到底部事件,开始加载更多...');
// this.loadMore();
// },
// 页面滚动到底部事件
onReachBottom() {
console.log('🔄 触发滚动到底部事件,开始加载更多...');
this.loadMore();
},
methods: {
// 处理刷新事件
@@ -313,7 +315,11 @@ export default {
this.loading = true;
this.queryParams.pageNum = 1;
this.checkList = [];
this.loadStatus = 'loadmore';
} else {
if (this.loadStatus === 'loading' || this.loadStatus === 'nomore') {
return;
}
this.loadStatus = 'loading';
}
@@ -331,35 +337,50 @@ export default {
console.log('📋 开始加载当前学生的宿舍卫生检查记录...', {
学生ID: currentUser.userId,
查询参数: this.queryParams,
是否刷新: isRefresh,
});
// 调用根据学生ID查询卫生检查记录的接口
// 构建请求参数
const params = {
pageNum: this.queryParams.pageNum,
pageSize: this.queryParams.pageSize,
};
// 添加搜索条件
if (this.queryParams.checkTitle && this.queryParams.checkTitle.trim()) {
params.checkTitle = this.queryParams.checkTitle.trim();
}
// 调用分页接口
const res = await request({
url: `/dormHygieneCheck/dormHygieneCheck/student/${currentUser.userId}`,
url: `/dormHygieneCheck/dormHygieneCheck/student/${currentUser.userId}/page`,
method: 'GET',
params: params,
});
if (res && res.code === 200) {
const newData = res.data || [];
const newData = res.rows || [];
const total = res.total || 0;
if (isRefresh) {
this.originalCheckList = newData; // 保存原始数据
this.checkList = newData;
} else {
this.originalCheckList = [...this.originalCheckList, ...newData];
this.checkList = [...this.checkList, ...newData];
}
this.total = newData.length;
this.total = total;
// 由于getHygieneChecksByStudentId返回的是完整列表,不需要分页加载
this.loadStatus = 'nomore';
// 判断是否还有更多数据
const hasMore = this.queryParams.pageNum * this.queryParams.pageSize < total;
this.loadStatus = hasMore ? 'loadmore' : 'nomore';
console.log('✅ 学生宿舍卫生检查记录加载成功:', {
学生ID: currentUser.userId,
当前页码: this.queryParams.pageNum,
本次加载: newData.length,
总数: this.total,
总数: total,
列表长度: this.checkList.length,
是否还有更多: hasMore,
});
} else {
console.warn('获取学生宿舍卫生检查记录失败:', res?.msg);
@@ -368,9 +389,7 @@ export default {
icon: 'none',
});
if (!isRefresh) {
this.loadStatus = 'loadmore';
}
this.loadStatus = isRefresh ? 'loadmore' : 'loadmore';
}
} catch (error) {
console.error('❌ 加载学生宿舍卫生检查记录失败:', error);
@@ -379,9 +398,7 @@ export default {
icon: 'none',
});
if (!isRefresh) {
this.loadStatus = 'loadmore';
}
this.loadStatus = isRefresh ? 'loadmore' : 'loadmore';
} finally {
if (isRefresh) {
this.loading = false;
@@ -389,51 +406,35 @@ export default {
}
},
// 加载更多(已废弃,因为getHygieneChecksByStudentId返回完整列表)
// 加载更多
async loadMore() {
console.log('📄 当前接口返回完整列表,无需分页加载');
// 由于getHygieneChecksByStudentId返回的是完整列表,不需要分页加载
this.loadStatus = 'nomore';
console.log('📄 触发加载更多,当前状态:', this.loadStatus);
if (this.loadStatus !== 'loadmore') {
console.log('📄 当前状态不允许加载更多:', this.loadStatus);
return;
}
// 增加页码,加载下一页数据
this.queryParams.pageNum += 1;
console.log('📄 加载第', this.queryParams.pageNum, '页数据');
await this.loadCheckList(false);
},
// 搜索操作(前端过滤)
// 搜索操作(后端过滤)
handleQuery() {
console.log('🔍 执行前端搜索过滤:', this.queryParams);
// 由于接口返回完整列表,在前端进行过滤
this.filterCheckList();
console.log('🔍 执行搜索查询:', this.queryParams);
// 重新从第一页开始搜索
this.loadCheckList(true);
},
// 重置搜索
resetQuery() {
this.queryParams.checkTitle = '';
this.filterCheckList();
},
// 前端过滤检查记录列表
filterCheckList() {
if (!this.originalCheckList || this.originalCheckList.length === 0) {
this.checkList = [];
return;
}
let filteredList = [...this.originalCheckList];
// 按检查标题过滤
if (this.queryParams.checkTitle && this.queryParams.checkTitle.trim()) {
const searchTerm = this.queryParams.checkTitle.trim().toLowerCase();
filteredList = filteredList.filter(
(item) => item.checkTitle && item.checkTitle.toLowerCase().includes(searchTerm),
);
}
this.checkList = filteredList;
this.total = filteredList.length;
console.log('✅ 前端过滤完成:', {
原始数据: this.originalCheckList.length,
过滤后: this.checkList.length,
搜索条件: this.queryParams.checkTitle,
});
console.log('🔄 重置搜索条件');
// 重新加载数据
this.loadCheckList(true);
},
// 获取检查级别类型
@@ -655,6 +656,14 @@ export default {
font-weight: bold;
color: #303133;
flex: 1;
display: flex;
align-items: baseline;
}
.check-index {
color: #000000;
font-weight: bold;
margin-right: 8rpx;
}
.check-level {
@@ -815,10 +824,10 @@ export default {
color: #f56c6c;
}
// 分页容器(已废弃)
// .pagination-container {
// padding: 20rpx;
// }
// 分页容器
.pagination-container {
padding: 20rpx;
}
// 搜索按钮样式
::v-deep .search-btn {
+206 -119
View File
@@ -17,101 +17,126 @@
<u-empty text="暂无可申请的考核计划" mode="data"></u-empty>
</view>
<!-- 考核计划列表 -->
<view v-else class="schedule-list">
<view
v-for="(item, index) in assessmentScheduleList"
:key="item.id || index"
class="schedule-card"
>
<!-- 卡片头部 -->
<view class="card-header">
<view class="schedule-info">
<text class="schedule-name">{{ item.scheduleName || '暂无' }}</text>
<view class="schedule-meta">
<text class="academic-info">
{{ item.academicYear || '暂无' }}
{{ getSemesterText(item.semester) }}
<!-- 考核计划列表 - 滚动加载 -->
<scroll-view
v-else
class="schedule-scroll-view"
scroll-y
@scrolltolower="handleScrollToLower"
:lower-threshold="100"
>
<view class="schedule-list">
<view
v-for="(item, index) in assessmentScheduleList"
:key="item.id || index"
class="schedule-card"
>
<!-- 卡片头部 -->
<view class="card-header">
<view class="schedule-info">
<view class="schedule-name-wrapper">
<text class="schedule-index">{{ index + 1 }}.</text>
<text class="schedule-name">
{{ item.scheduleName || '暂无' }}
</text>
</view>
<view class="schedule-meta">
<text class="academic-info">
{{ item.academicYear || '暂无' }}
{{ getSemesterText(item.semester) }}
</text>
</view>
</view>
<view class="status-info">
<u-tag
:text="getStatusText(item.status)"
:type="getStatusTagType(item.status)"
size="mini"
></u-tag>
</view>
</view>
<!-- 卡片内容 -->
<view class="card-content">
<view class="schedule-description">
<text class="description-text">
{{ item.description || '暂无说明' }}
</text>
</view>
<view class="time-info">
<view class="time-item">
<text class="time-label">开始时间:</text>
<text class="time-value">{{ formatTime(item.startTime) }}</text>
</view>
<view class="time-item">
<text class="time-label">结束时间:</text>
<text class="time-value">{{ formatTime(item.endTime) }}</text>
</view>
<view class="time-item">
<text class="time-label">数据统计开始时间:</text>
<text class="time-value">
{{ formatTime(item.dataStartTime) }}
</text>
</view>
<view class="time-item">
<text class="time-label">数据统计结束时间:</text>
<text class="time-value">
{{ formatTime(item.dataEndTime) }}
</text>
</view>
</view>
<view class="plan-info">
<text class="plan-name">
考核方案: {{ item.planName || '暂无' }}
</text>
</view>
</view>
<view class="status-info">
<u-tag
:text="getStatusText(item.status)"
:type="getStatusTagType(item.status)"
size="mini"
></u-tag>
<!-- 卡片操作按钮 -->
<view class="card-actions">
<u-button
type="info"
size="small"
icon="eye"
shape="round"
@click="handleViewSchedule(item)"
>
查看计划
</u-button>
<u-button
v-if="canSubmitApplication(item)"
type="primary"
size="small"
icon="edit-pen"
shape="round"
@click="handleSubmitApplication(item)"
>
提交申请
</u-button>
<u-button
type="warning"
size="small"
icon="file-text"
shape="round"
@click="handleViewApplication(item)"
>
查看申请
</u-button>
</view>
</view>
<!-- 卡片内容 -->
<view class="card-content">
<view class="schedule-description">
<text class="description-text">
{{ item.description || '暂无说明' }}
</text>
<!-- 加载更多状态提示 -->
<view v-if="assessmentScheduleList.length > 0" class="load-more">
<view v-if="loadingMore" class="loading-more">
<u-loading-icon mode="circle" size="16"></u-loading-icon>
<text class="loading-text">正在加载更多...</text>
</view>
<view class="time-info">
<view class="time-item">
<text class="time-label">开始时间:</text>
<text class="time-value">{{ formatTime(item.startTime) }}</text>
</view>
<view class="time-item">
<text class="time-label">结束时间:</text>
<text class="time-value">{{ formatTime(item.endTime) }}</text>
</view>
<view class="time-item">
<text class="time-label">数据统计开始时间:</text>
<text class="time-value">{{ formatTime(item.dataStartTime) }}</text>
</view>
<view class="time-item">
<text class="time-label">数据统计结束时间:</text>
<text class="time-value">{{ formatTime(item.dataEndTime) }}</text>
</view>
<view v-else class="load-complete-text">
{{ getNoMoreText() }}
</view>
<view class="plan-info">
<text class="plan-name">考核方案: {{ item.planName || '暂无' }}</text>
</view>
</view>
<!-- 卡片操作按钮 -->
<view class="card-actions">
<u-button
type="info"
size="small"
icon="eye"
shape="round"
@click="handleViewSchedule(item)"
>
查看计划
</u-button>
<u-button
v-if="canSubmitApplication(item)"
type="primary"
size="small"
icon="edit-pen"
shape="round"
@click="handleSubmitApplication(item)"
>
提交申请
</u-button>
<u-button
type="warning"
size="small"
icon="file-text"
shape="round"
@click="handleViewApplication(item)"
>
查看申请
</u-button>
</view>
</view>
</view>
<!-- 分页加载 -->
<view v-if="hasMore && assessmentScheduleList.length > 0" class="load-more">
<u-loadmore :status="loadStatus" @loadmore="loadMore"></u-loadmore>
</view>
</scroll-view>
</view>
<!-- 查看计划详情弹窗 -->
@@ -231,6 +256,7 @@ export default {
total: 0,
hasMore: true,
loadStatus: 'loadmore',
loadingMore: false,
// 查询参数
queryParams: {
@@ -276,9 +302,14 @@ export default {
},
// 获取考核计划列表
async getList(loadMore = false) {
if (!loadMore) {
async getList(isLoadMore = false) {
if (isLoadMore) {
this.loadingMore = true;
} else {
this.loading = true;
// 重置分页参数
this.queryParams.pageNum = 1;
this.assessmentScheduleList = [];
}
try {
@@ -290,38 +321,49 @@ export default {
if (res && res.code === 200) {
const rows = res.rows || [];
const total = res.total || 0;
if (loadMore) {
this.assessmentScheduleList = this.assessmentScheduleList.concat(rows);
if (isLoadMore) {
// 加载更多时追加数据
this.assessmentScheduleList = [...this.assessmentScheduleList, ...rows];
} else {
// 首次加载时直接设置数据
this.assessmentScheduleList = rows;
}
this.total = res.total || 0;
this.total = total;
if (rows.length < this.queryParams.pageSize) {
this.hasMore = false;
this.loadStatus = 'nomore';
} else {
this.hasMore = true;
this.loadStatus = 'loadmore';
}
// 判断是否还有更多数据
const currentTotal = this.assessmentScheduleList.length;
this.hasMore = currentTotal < total;
this.loadStatus = this.hasMore ? 'loadmore' : 'nomore';
console.log('获取考核计划数据成功:', {
当前页: this.queryParams.pageNum,
返回条数: rows.length,
累计条数: currentTotal,
总数量: total,
是否还有更多: this.hasMore,
});
} else {
this.handleRequestError(res?.msg || '获取数据失败', loadMore);
this.handleRequestError(res?.msg || '获取数据失败');
}
} catch (error) {
console.error('获取数据失败:', error);
this.handleRequestError('获取数据失败', loadMore);
this.handleRequestError('获取数据失败');
} finally {
if (!loadMore) {
if (isLoadMore) {
this.loadingMore = false;
} else {
this.loading = false;
}
}
},
// 错误处理
handleRequestError(message, isLoadMore = false) {
if (!isLoadMore) {
handleRequestError(message) {
if (this.queryParams.pageNum === 1) {
// 首次加载失败,清空数据
this.assessmentScheduleList = [];
this.total = 0;
}
@@ -334,22 +376,22 @@ export default {
});
},
// 加载更多
async loadMore() {
if (!this.hasMore || this.loadStatus !== 'loadmore') {
// 滚动到底部触发加载更多
async handleScrollToLower() {
if (!this.hasMore || this.loadingMore || this.loading) {
console.log('无需加载更多数据:', {
hasMore: this.hasMore,
loadingMore: this.loadingMore,
loading: this.loading,
});
return;
}
this.loadStatus = 'loading';
this.queryParams.pageNum += 1;
console.log('滚动到底部,开始加载更多数据');
try {
await this.getList(true);
} catch (error) {
console.error('加载更多数据失败:', error);
this.queryParams.pageNum -= 1;
this.loadStatus = 'loadmore';
}
// 页码加1,加载下一页
this.queryParams.pageNum += 1;
await this.getList(true);
},
// 查看考核计划信息
@@ -466,9 +508,6 @@ export default {
// 提交成功回调
handleSuccess() {
this.queryParams.pageNum = 1;
this.hasMore = true;
this.loadStatus = 'loadmore';
this.getList();
},
@@ -514,6 +553,16 @@ export default {
};
return getDictTagType(this.assessmentScheduleStatus, status, fallbackMap);
},
// 获取没有更多数据文本
getNoMoreText() {
if (this.hasMore) {
return `已加载${this.assessmentScheduleList.length}条,共${this.total}条`;
} else if (this.total > 0) {
return `已全部加载完毕,共${this.total}条考核计划`;
}
return '暂无数据';
},
},
};
</script>
@@ -526,6 +575,11 @@ export default {
.content-wrapper {
padding: 20rpx;
height: calc(100vh - 88rpx); /* 减去导航栏高度 */
}
.schedule-scroll-view {
height: 100%;
}
.empty-container {
@@ -558,12 +612,25 @@ export default {
flex: 1;
}
.schedule-name-wrapper {
display: flex;
align-items: center;
margin-bottom: 12rpx;
}
.schedule-index {
font-size: 32rpx;
font-weight: bold;
color: #000000;
margin-right: 8rpx;
min-width: 40rpx;
}
.schedule-name {
font-size: 32rpx;
font-weight: bold;
color: #303133;
display: block;
margin-bottom: 12rpx;
flex: 1;
}
.schedule-meta {
@@ -640,6 +707,26 @@ export default {
padding: 20rpx 0;
}
.loading-more {
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx 0;
gap: 12rpx;
}
.loading-text {
font-size: 24rpx;
color: #909399;
}
.load-complete-text {
text-align: center;
font-size: 24rpx;
color: #909399;
padding: 20rpx 0;
}
/* 弹窗样式 */
.schedule-detail-popup {
background-color: #fff;
+90 -14
View File
@@ -26,7 +26,10 @@
>
<!-- 卡片头部 -->
<view class="card-header">
<view class="record-title">{{ item.disciplineTypeName || '-' }}</view>
<view class="record-title">
<text class="record-number">{{ index + 1 }}.</text>
{{ item.disciplineTypeName || '-' }}
</view>
<view class="record-status">
<u-tag
:text="getDictLabel(studentDisciplineStatus, item.status)"
@@ -114,9 +117,15 @@
</view>
</view>
<!-- 滚动加载提示 -->
<view v-if="hasMore && disciplineRecordList.length > 0" class="load-more">
<u-loadmore :status="loadStatus" @loadmore="loadMore"></u-loadmore>
<!-- 底部加载状态提示 -->
<view v-if="disciplineRecordList.length > 0" class="load-status">
<view v-if="loadingMore" class="loading-tip">
<u-loading-icon></u-loading-icon>
<text class="loading-text">加载中...</text>
</view>
<view v-else-if="!hasMore" class="no-more-tip">
<text>已加载全部数据</text>
</view>
</view>
</view>
@@ -143,10 +152,10 @@ export default {
data() {
return {
loading: false,
loadingMore: false, // 加载更多状态
disciplineRecordList: [],
total: 0,
hasMore: true,
loadStatus: 'loadmore',
// 查询参数
queryParams: {
@@ -172,6 +181,16 @@ export default {
}
},
// 滚动到底部时自动加载更多
onReachBottom() {
this.loadMore();
},
// 下拉刷新
onPullDownRefresh() {
this.handleRefresh();
},
methods: {
// 返回上一页
goBack() {
@@ -205,6 +224,8 @@ export default {
async getList(loadMore = false) {
if (!loadMore) {
this.loading = true;
} else {
this.loadingMore = true;
}
try {
@@ -230,10 +251,8 @@ export default {
// 判断是否还有更多数据
if (rows.length < this.queryParams.pageSize) {
this.hasMore = false;
this.loadStatus = 'nomore';
} else {
this.hasMore = true;
this.loadStatus = 'loadmore';
}
} else {
if (!loadMore) {
@@ -241,7 +260,6 @@ export default {
this.total = 0;
}
this.hasMore = false;
this.loadStatus = 'nomore';
uni.showToast({
title: res?.msg || '获取数据失败',
@@ -256,7 +274,6 @@ export default {
this.total = 0;
}
this.hasMore = false;
this.loadStatus = 'nomore';
uni.showToast({
title: '获取数据失败',
@@ -265,17 +282,19 @@ export default {
} finally {
if (!loadMore) {
this.loading = false;
} else {
this.loadingMore = false;
}
}
},
// 加载更多数据
async loadMore() {
if (!this.hasMore || this.loadStatus !== 'loadmore') {
// 防止重复加载
if (!this.hasMore || this.loadingMore || this.loading) {
return;
}
this.loadStatus = 'loading';
this.queryParams.pageNum += 1;
try {
@@ -283,7 +302,25 @@ export default {
} catch (error) {
console.error('加载更多数据失败:', error);
this.queryParams.pageNum -= 1; // 回退页码
this.loadStatus = 'loadmore';
uni.showToast({
title: '加载失败,请重试',
icon: 'none',
});
}
},
// 下拉刷新处理
async handleRefresh() {
this.queryParams.pageNum = 1;
this.hasMore = true;
try {
await this.getList();
} catch (error) {
console.error('刷新数据失败:', error);
} finally {
uni.stopPullDownRefresh();
}
},
@@ -318,7 +355,6 @@ export default {
// 重新加载列表
this.queryParams.pageNum = 1;
this.hasMore = true;
this.loadStatus = 'loadmore';
this.getList();
},
@@ -354,6 +390,7 @@ export default {
.content-wrapper {
padding: 20rpx;
padding-bottom: 40rpx; // 增加底部间距
}
.empty-container {
@@ -386,6 +423,15 @@ export default {
font-weight: bold;
color: #303133;
flex: 1;
display: flex;
align-items: center;
}
.record-number {
font-size: 28rpx;
font-weight: 600;
margin-right: 8rpx;
min-width: 40rpx;
}
.record-status {
@@ -434,12 +480,42 @@ export default {
gap: 16rpx;
}
.load-more {
// 底部加载状态样式
.load-status {
display: flex;
justify-content: center;
align-items: center;
padding: 40rpx 20rpx;
margin-top: 20rpx;
}
.loading-tip {
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
.loading-text {
font-size: 28rpx;
color: #999;
}
}
.no-more-tip {
text {
font-size: 28rpx;
color: #999;
}
}
// uview组件样式调整
::v-deep .u-tag {
margin: 0;
}
// 加载图标样式调整
::v-deep .u-loading-icon {
width: 32rpx;
height: 32rpx;
}
</style>