提交代码

This commit is contained in:
zlwu committed 2025-08-17 23:05:57 +08:00
1 parent 27c2a307e6
commit 2069e09659
11 files changed
+5347

No files matched your search

+16
View File
@@ -199,6 +199,22 @@
"navigationBarBackgroundColor": "#0051d9",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/xgss/xssswsjc/xssswsjc",
"style": {
"navigationBarTitleText": "宿舍卫生检查",
"navigationBarBackgroundColor": "#0051d9",
"navigationBarTextStyle": "white"
}
},
{
"path": "pages/xgss/xssswsjc/xssswsjcDetail",
"style": {
"navigationBarTitleText": "宿舍卫生检查详情",
"navigationBarBackgroundColor": "#0051d9",
"navigationBarTextStyle": "white"
}
}
],
"globalStyle": {
+20
View File
@@ -207,6 +207,19 @@
/>
</template>
</ServiceItem>
<ServiceItem
v-if="hasPermi(['student:dormhygiene:studentlist'])"
title="宿舍卫生检查(学生)"
@click="gotoStudentDormHygiene"
>
<template #icon>
<image
src="/static/00135.png"
mode="aspectFit"
style="width: 24px; height: 24px"
/>
</template>
</ServiceItem>
</GridLayout>
</Card>
@@ -860,6 +873,13 @@ export default {
});
},
// 跳转到宿舍卫生检查(学生)页面
gotoStudentDormHygiene() {
uni.navigateTo({
url: '/pages/xgss/xssswsjc/xssswsjc',
});
},
// 图片加载成功处理
handleImageLoad(event) {
console.log('✅ 轮播图片加载成功:', event.detail);
+880
View File
@@ -0,0 +1,880 @@
<template>
<view class="page-container">
<!-- 顶部导航 -->
<u-navbar title="宿舍卫生检查" :border-bottom="false" bg-color="#3c9cff" title-color="#fff">
<view slot="left" @click="goBack">
<u-icon name="arrow-left" color="#fff" size="22"></u-icon>
</view>
</u-navbar>
<!-- 搜索区域 -->
<view class="search-container">
<view class="search-row">
<view class="search-item">
<text class="search-label">检查标题:</text>
<u-input
v-model="queryParams.checkTitle"
placeholder="请输入检查标题"
clearable
border="none"
style="width: 100%"
/>
</view>
</view>
<view class="search-actions">
<u-button type="primary" size="small" class="search-btn" @click="handleQuery">
搜索
</u-button>
<u-button type="info" size="small" @click="resetQuery" style="margin-left: 10px">
重置
</u-button>
</view>
</view>
<!-- 加载状态 -->
<u-loading-page :loading="loading" loading-text="加载中..."></u-loading-page>
<!-- 卫生检查记录列表 -->
<view v-if="!loading" class="content-wrapper">
<!-- 空状态 -->
<view v-if="checkList.length === 0" class="empty-container">
<u-empty text="暂无检查记录" mode="data"></u-empty>
</view>
<!-- 检查记录卡片列表 -->
<view v-else class="check-list">
<view v-for="(item, index) in checkList" :key="item.id || index" class="check-card">
<!-- 卡片头部 -->
<view class="card-header">
<!-- 第一行:标题和卫生等级 -->
<view class="header-row">
<view class="check-title">{{ item.checkTitle || '-' }}</view>
<view class="grade-section">
<u-tag
:text="$getDictLabel(xg_dorm_hygiene_grade, item.hygieneGrade)"
:type="getHygieneGradeType(item.hygieneGrade)"
size="mini"
></u-tag>
</view>
</view>
<!-- 第二行:检查类型、检查级别和总分 -->
<view class="header-row second-row">
<view class="left-section">
<view class="check-type">
<!-- {{
$getDictLabel(xg_dorm_hygiene_check_type, item.checkType) ||
'-'
}} -->
<u-tag
:text="
$getDictLabel(
xg_dorm_hygiene_check_type,
item.checkType,
)
"
:type="getCheckLevelType(item.checkType)"
size="mini"
></u-tag>
</view>
<view class="check-level">
<u-tag
:text="
$getDictLabel(
xg_dorm_hygiene_check_level,
item.checkLevel,
)
"
:type="getCheckLevelType(item.checkLevel)"
size="mini"
></u-tag>
</view>
</view>
<view class="score-section">
<text class="total-score">{{ item.totalScore || '-' }}分</text>
</view>
</view>
</view>
<!-- 卡片内容 -->
<view class="card-content">
<!-- 宿舍信息 -->
<view class="info-section">
<text class="section-title">宿舍信息</text>
<view class="dorm-info-grid">
<!-- 第一行:校区和宿舍区 -->
<view class="dorm-row">
<view class="info-item-half">
<text class="label">校区:</text>
<text class="value">{{ item.campusName || '-' }}</text>
</view>
<view class="info-item-half">
<text class="label">宿舍区:</text>
<text class="value">{{ item.areaName || '-' }}</text>
</view>
</view>
<!-- 第二行:宿舍楼和房间 -->
<view class="dorm-row">
<view class="info-item-half">
<text class="label">宿舍楼:</text>
<text class="value">{{ item.buildingName || '-' }}</text>
</view>
<view class="info-item-half">
<text class="label">房间:</text>
<text class="value">{{ item.roomName || '-' }}</text>
</view>
</view>
</view>
</view>
<!-- 检查信息 -->
<view class="info-section">
<text class="section-title">检查信息</text>
<!-- 检查员和检查时间一行 -->
<view class="check-details-row">
<view class="info-item-half">
<text class="label">检查员:</text>
<text class="value">{{ item.checkerName || '-' }}</text>
</view>
<view class="check-time">
{{ formatTime(item.checkDate) }}
</view>
</view>
<!-- 检查总结单独一行 -->
<view class="info-item" v-if="item.checkSummary">
<text class="label">检查总结:</text>
<text class="value summary">{{ item.checkSummary }}</text>
</view>
</view>
</view>
<!-- 操作按钮 -->
<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>
<!-- 修改按钮 -->
<!-- <view class="action-btn info-btn" @click="handleUpdate(item)">
<u-icon name="edit-pen" size="16" color="#3c9cff"></u-icon>
<text class="btn-text">修改</text>
</view> -->
<!-- 删除按钮 -->
<!-- <view class="action-btn danger-btn" @click="handleDelete(item)">
<u-icon name="trash" size="16" color="#f56c6c"></u-icon>
<text class="btn-text">删除</text>
</view> -->
</view>
</view>
</view>
</view>
<!-- 分页加载(已废弃,因为接口返回完整列表) -->
<!-- <view v-if="checkList.length > 0" class="pagination-container">
<u-loadmore
:status="loadStatus"
@loadmore="loadMore"
load-text="上拉加载更多"
loading-text="正在加载..."
no-more-text="没有更多数据了"
/>
</view> -->
<!-- 悬浮添加按钮 -->
<!-- <view class="fab-button" @click="handleAdd">
<u-icon name="plus" size="24" color="#ffffff" />
</view> -->
</view>
</template>
<script>
import { request } from '@/common/request.js';
import { getDict, getDictLabel, getDictTagType } from '@/common/dict.js';
import { userManager } from '@/utils/user.js';
export default {
name: 'DormHygieneCheck',
data() {
return {
loading: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
checkTitle: '',
},
// 检查记录列表
checkList: [],
originalCheckList: [], // 原始数据,用于前端过滤
total: 0,
// 分页加载状态
loadStatus: 'loadmore', // loadmore, loading, nomore
// 字典数据
xg_dorm_hygiene_check_type: [],
xg_dorm_hygiene_check_level: [],
xg_dorm_hygiene_grade: [],
};
},
async created() {
// 绑定 getDictLabel 函数到组件实例
this.$getDictLabel = getDictLabel;
// 加载字典数据
await this.loadDictionaries();
// 加载列表数据
await this.loadCheckList();
},
mounted() {
// 监听刷新事件
uni.$on('refreshCheckList', this.handleRefreshEvent);
},
beforeDestroy() {
// 移除事件监听
uni.$off('refreshCheckList', this.handleRefreshEvent);
},
// 页面滚动到底部事件(已废弃,因为接口返回完整列表)
// onReachBottom() {
// console.log('🔄 触发滚动到底部事件,开始加载更多...');
// this.loadMore();
// },
methods: {
// 处理刷新事件
handleRefreshEvent() {
console.log('🔄 收到刷新事件,正在刷新检查列表...');
this.loadCheckList();
},
// 返回上一页
goBack() {
uni.navigateBack();
},
// 加载字典数据
async loadDictionaries() {
try {
console.log('🔍 开始加载字典数据...');
const dictTypes = [
'xg_dorm_hygiene_check_type',
'xg_dorm_hygiene_check_level',
'xg_dorm_hygiene_grade',
];
// 使用 getDict 函数获取已转换格式的字典数据
const dictPromises = dictTypes.map((dictType) => getDict(dictType));
const results = await Promise.all(dictPromises);
this.xg_dorm_hygiene_check_type = results[0] || [];
this.xg_dorm_hygiene_check_level = results[1] || [];
this.xg_dorm_hygiene_grade = results[2] || [];
console.log('✅ 字典数据加载完成:', {
xg_dorm_hygiene_check_type: this.xg_dorm_hygiene_check_type.length,
xg_dorm_hygiene_check_level: this.xg_dorm_hygiene_check_level.length,
xg_dorm_hygiene_grade: this.xg_dorm_hygiene_grade.length,
});
} catch (error) {
console.error('❌ 加载字典数据失败:', error);
}
},
// 加载检查记录列表
async loadCheckList(isRefresh = true) {
if (isRefresh) {
this.loading = true;
this.queryParams.pageNum = 1;
this.checkList = [];
} else {
this.loadStatus = 'loading';
}
try {
// 获取当前登录用户信息
const currentUser = userManager.getCurrentUser();
if (!currentUser || !currentUser.userId) {
uni.showToast({
title: '请先登录',
icon: 'none',
});
return;
}
console.log('📋 开始加载当前学生的宿舍卫生检查记录...', {
学生ID: currentUser.userId,
查询参数: this.queryParams,
});
// 调用根据学生ID查询卫生检查记录的接口
const res = await request({
url: `/dormHygieneCheck/dormHygieneCheck/student/${currentUser.userId}`,
method: 'GET',
});
if (res && res.code === 200) {
const newData = res.data || [];
if (isRefresh) {
this.originalCheckList = newData; // 保存原始数据
this.checkList = newData;
} else {
this.originalCheckList = [...this.originalCheckList, ...newData];
this.checkList = [...this.checkList, ...newData];
}
this.total = newData.length;
// 由于getHygieneChecksByStudentId返回的是完整列表,不需要分页加载
this.loadStatus = 'nomore';
console.log('✅ 学生宿舍卫生检查记录加载成功:', {
学生ID: currentUser.userId,
本次加载: newData.length,
总数: this.total,
列表长度: this.checkList.length,
});
} else {
console.warn('获取学生宿舍卫生检查记录失败:', res?.msg);
uni.showToast({
title: res?.msg || '获取数据失败',
icon: 'none',
});
if (!isRefresh) {
this.loadStatus = 'loadmore';
}
}
} catch (error) {
console.error('❌ 加载学生宿舍卫生检查记录失败:', error);
uni.showToast({
title: '获取数据失败',
icon: 'none',
});
if (!isRefresh) {
this.loadStatus = 'loadmore';
}
} finally {
if (isRefresh) {
this.loading = false;
}
}
},
// 加载更多(已废弃,因为getHygieneChecksByStudentId返回完整列表)
async loadMore() {
console.log('📄 当前接口返回完整列表,无需分页加载');
// 由于getHygieneChecksByStudentId返回的是完整列表,不需要分页加载
this.loadStatus = 'nomore';
},
// 搜索操作(前端过滤)
handleQuery() {
console.log('🔍 执行前端搜索过滤:', this.queryParams);
// 由于接口返回完整列表,在前端进行过滤
this.filterCheckList();
},
// 重置搜索
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,
});
},
// 获取检查级别类型
getCheckLevelType(level) {
const fallbackMap = {
1: 'info', // 宿管员检查
2: 'warning', // 学院检查
3: 'success', // 学校检查
};
return getDictTagType(this.xg_dorm_hygiene_check_level, level, fallbackMap);
},
// 获取检查类型类型
getCheckTypeType(type) {
const fallbackMap = {
1: 'info', // 日常检查
2: 'warning', // 专项检查
3: 'error', // 突击检查
};
return getDictTagType(this.xg_dorm_hygiene_check_type, type, fallbackMap);
},
// 获取卫生等级类型
getHygieneGradeType(grade) {
const fallbackMap = {
A: 'success', // 优秀
B: 'warning', // 良好
C: 'info', // 一般
D: 'error', // 较差
};
return getDictTagType(this.xg_dorm_hygiene_grade, grade, fallbackMap);
},
// 格式化时间
formatTime(time) {
if (!time) return '-';
try {
// 处理时间字符串,保持完整格式 YYYY-MM-DD HH:mm:ss
return time.replace('T', ' ').substring(0, 19);
} catch (error) {
return time;
}
},
// 新增检查
handleAdd() {
uni.navigateTo({
url: '/pages/xgss/xssswsjc/xssswsjcDetail?type=add',
});
},
// 查看检查
handleView(item) {
uni.navigateTo({
url: `/pages/xgss/xssswsjc/xssswsjcDetail?id=${item.id}&type=view`,
});
},
// 修改检查
handleUpdate(item) {
uni.navigateTo({
url: `/pages/xgss/xssswsjc/xssswsjcDetail?id=${item.id}&type=update`,
});
},
// 删除检查
async handleDelete(item) {
try {
const confirm = await new Promise((resolve) => {
uni.showModal({
title: '确认删除',
content: '是否确认删除这条检查记录?',
success: (res) => resolve(res.confirm),
fail: () => resolve(false),
});
});
if (!confirm) return;
uni.showLoading({ title: '删除中...' });
const res = await request({
url: `/dormHygieneCheck/dormHygieneCheck/${item.id}`,
method: 'DELETE',
});
uni.hideLoading();
if (res && res.code === 200) {
uni.showToast({
title: '删除成功',
icon: 'success',
});
// 刷新列表
this.loadCheckList();
} else {
uni.showToast({
title: res?.msg || '删除失败',
icon: 'none',
});
}
} catch (error) {
uni.hideLoading();
console.error('❌ 删除检查记录失败:', error);
uni.showToast({
title: '删除失败',
icon: 'none',
});
}
},
},
};
</script>
<style lang="scss" scoped>
.page-container {
min-height: 100vh;
background-color: #f5f6fa;
padding-bottom: 80px;
}
// 搜索区域
.search-container {
background-color: #ffffff;
padding: 20rpx;
margin-bottom: 8px;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.search-row {
display: flex;
flex-direction: row;
gap: 20rpx;
}
.search-item {
display: flex;
flex-direction: column;
flex: 1;
.search-label {
font-size: 28rpx;
color: #606266;
margin-bottom: 8rpx;
}
}
.search-actions {
display: flex;
justify-content: center;
margin-top: 20rpx;
gap: 20rpx;
}
// 内容区域
.content-wrapper {
padding: 20rpx;
}
.empty-container {
padding: 100rpx 20rpx;
}
// 检查列表
.check-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.check-card {
background-color: #ffffff;
border-radius: 16rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
overflow: hidden;
}
// 卡片头部
.card-header {
display: flex;
flex-direction: column;
padding: 24rpx;
border-bottom: 1px solid #f0f0f0;
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
}
.header-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8rpx;
}
.second-row {
margin-bottom: 0;
}
.left-section {
display: flex;
align-items: center;
gap: 16rpx;
}
.score-section {
display: flex;
align-items: center;
gap: 8rpx;
}
.total-score {
font-size: 28rpx;
font-weight: bold;
color: #007aff;
}
.check-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
flex: 1;
}
.check-level {
flex-shrink: 0;
}
.check-type {
font-size: 28rpx;
color: #606266;
font-weight: 500;
}
.grade-section {
display: flex;
justify-content: flex-end;
}
.check-details-row {
display: flex;
justify-content: space-between;
gap: 20rpx;
margin-top: 8rpx;
}
.check-time {
font-size: 24rpx;
color: #999999;
text-align: right;
}
// 卡片内容
.card-content {
padding: 24rpx;
}
.info-section {
margin-bottom: 24rpx;
&:last-child {
margin-bottom: 0;
}
}
.section-title {
font-size: 28rpx;
font-weight: bold;
color: #303133;
margin-bottom: 16rpx;
padding-bottom: 8rpx;
// border-bottom: 2rpx solid #e4e7ed;
display: block;
}
.info-item {
display: flex;
align-items: flex-start;
margin-bottom: 12rpx;
line-height: 1.5;
&:last-child {
margin-bottom: 0;
}
}
.dorm-info-grid {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.dorm-row {
display: flex;
justify-content: space-between;
gap: 20rpx;
}
.info-item-half {
flex: 1;
display: flex;
align-items: flex-start;
.label {
font-size: 26rpx;
color: #606266;
min-width: 100rpx;
margin-right: 8rpx;
flex-shrink: 0;
}
.value {
font-size: 26rpx;
color: #303133;
flex: 1;
word-break: break-all;
}
}
.label {
font-size: 26rpx;
color: #606266;
min-width: 120rpx;
margin-right: 16rpx;
flex-shrink: 0;
}
.value {
font-size: 26rpx;
color: #303133;
flex: 1;
word-break: break-all;
&.summary {
line-height: 1.6;
}
}
// 操作按钮
.card-actions {
display: flex;
justify-content: flex-end;
padding: 20rpx;
border-top: 1px solid #f0f0f0;
gap: 16rpx;
}
.action-btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 16rpx 20rpx;
border-radius: 12rpx;
min-width: 120rpx;
transition: all 0.3s ease;
background-color: transparent;
&:active {
transform: scale(0.95);
opacity: 0.8;
}
}
.btn-text {
font-size: 24rpx;
margin-top: 8rpx;
font-weight: 500;
}
.primary-btn .btn-text {
color: #19be6b;
}
.info-btn .btn-text {
color: #3c9cff;
}
.danger-btn .btn-text {
color: #f56c6c;
}
// 分页容器(已废弃)
// .pagination-container {
// padding: 20rpx;
// }
// 搜索按钮样式
::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;
&:active {
transform: scale(0.95) !important;
box-shadow: 0 2px 8px rgba(0, 122, 255, 0.4) !important;
}
}
// 悬浮按钮
.fab-button {
position: fixed;
right: 20px;
bottom: 30px;
width: 56px;
height: 56px;
border-radius: 50%;
background: linear-gradient(135deg, #007aff, #0051d9);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 16px rgba(0, 122, 255, 0.3);
transition: all 0.3s ease;
z-index: 999;
&:active {
transform: scale(0.95);
box-shadow: 0 2px 8px rgba(0, 122, 255, 0.4);
}
}
// 响应式设计
@media (max-width: 375px) {
.search-container {
padding: 16rpx;
}
.content-wrapper {
padding: 16rpx;
}
.check-card {
margin-bottom: 16rpx;
}
.card-header,
.card-content {
padding: 20rpx;
}
.fab-button {
right: 16px;
bottom: 24px;
width: 48px;
height: 48px;
}
}
// uview组件样式调整
::v-deep .u-tag {
margin: 0;
}
::v-deep .u-input {
font-size: 26rpx;
}
::v-deep .u-button {
border-radius: 8rpx;
}
</style>
File diff suppressed because it is too large. Load diff