提交代码

This commit is contained in:
zlwu committed 2025-08-22 08:18:02 +08:00
1 parent 6d2a23942a
commit 9e617c3311
3 files changed
+2270 -12

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -0,0 +1,434 @@
<template>
<view class="full-page">
<!-- 顶部导航 -->
<u-navbar :title="pageTitle" :border-bottom="false" bg-color="#0051d9" title-color="#fff">
<view slot="left" @click="goBack">
<u-icon name="arrow-left" color="#fff" size="22"></u-icon>
</view>
</u-navbar>
<!-- 页面内容 -->
<view class="page-content" v-loading="loading">
<!-- 违纪处分记录区域 -->
<view class="record-section">
<view class="section-header">
<text class="section-title">违纪处分记录</text>
<u-tag type="error" size="mini">{{ disciplineRecords.length }} 条记录</u-tag>
</view>
<view v-if="disciplineRecords.length > 0" class="record-list">
<view
v-for="(item, index) in disciplineRecords"
:key="index"
class="record-card"
>
<view class="record-header">
<text class="record-type">{{ item.disciplineTypeName }}</text>
<view class="record-score">
<u-tag type="error" size="mini">
-{{ item.scoreDeduction || 0 }}
</u-tag>
</view>
</view>
<view class="record-content">
<view class="record-item">
<text class="record-label">违纪日期:</text>
<text class="record-value">
{{ formatDate(item.disciplineDate) }}
</text>
</view>
<view class="record-item">
<text class="record-label">违纪原因:</text>
<text class="record-value">
{{ item.disciplineReason || '暂无' }}
</text>
</view>
<view class="record-item-full">
<text class="record-label">违纪内容:</text>
<view class="record-content-text">
{{ item.disciplineContent || '暂无' }}
</view>
</view>
</view>
</view>
</view>
<view v-else class="empty-container">
<u-empty text="暂无违纪处分记录" mode="data"></u-empty>
</view>
</view>
<!-- 奖励记录区域 -->
<view class="record-section">
<view class="section-header">
<text class="section-title">奖励记录</text>
<u-tag type="success" size="mini">{{ rewardRecords.length }} 条记录</u-tag>
</view>
<view v-if="rewardRecords.length > 0" class="record-list">
<view v-for="(item, index) in rewardRecords" :key="index" class="record-card">
<view class="record-header">
<text class="record-type">{{ item.rewardTypeName }}</text>
<view class="record-score">
<u-tag type="success" size="mini">
+{{ item.scoreAddition || 0 }}
</u-tag>
</view>
</view>
<view class="record-content">
<view class="record-item">
<text class="record-label">奖励日期:</text>
<text class="record-value">{{ formatDate(item.rewardDate) }}</text>
</view>
<view class="record-item-full">
<text class="record-label">奖励内容:</text>
<view class="record-content-text">
{{ item.rewardContent || '暂无' }}
</view>
</view>
</view>
</view>
</view>
<view v-else class="empty-container">
<u-empty text="暂无奖励记录" mode="data"></u-empty>
</view>
</view>
</view>
</view>
</template>
<script>
import { request } from '@/common/request.js';
export default {
name: 'IndicatorDataDialog',
data() {
return {
loading: false,
pageTitle: '学生数据详情',
// 页面参数
indicatorId: null,
indicatorName: '',
studentId: null,
scheduleId: null,
dataStartTime: '',
dataEndTime: '',
// 数据列表
disciplineRecords: [],
rewardRecords: [],
};
},
async onLoad(options) {
console.log('学生数据详情页面加载', options);
// 获取参数
this.indicatorId = options.indicatorId;
this.indicatorName = decodeURIComponent(options.indicatorName || '');
this.studentId = options.studentId;
this.scheduleId = options.scheduleId;
this.dataStartTime = options.dataStartTime;
this.dataEndTime = options.dataEndTime;
// 设置页面标题
this.pageTitle = `${this.indicatorName} - 学生数据详情`;
uni.setNavigationBarTitle({
title: this.pageTitle,
});
// 加载数据
await this.loadData();
},
methods: {
// 返回上一页
goBack() {
uni.navigateBack();
},
// 加载数据
async loadData() {
if (!this.indicatorId) {
console.log('无indicatorId,跳过数据加载');
return;
}
this.loading = true;
try {
console.log('开始加载指标数据,indicatorId:', this.indicatorId);
// 获取指标关联的违纪处分类型和奖励类型
const indicatorTypesResponse = await request({
url: `/disciplineRecord/disciplineRecord/getIndicatorTypes/${this.indicatorId}`,
method: 'get',
});
if (indicatorTypesResponse.code === 200 && indicatorTypesResponse.data) {
// 修复字段名映射:后端返回下划线格式,前端使用驼峰格式
const disciplineTypeIds =
indicatorTypesResponse.data.discipline_type_ids ||
indicatorTypesResponse.data.disciplineTypeIds;
const rewardTypeIds =
indicatorTypesResponse.data.reward_type_ids ||
indicatorTypesResponse.data.rewardTypeIds;
// 并行加载违纪处分记录和奖励记录
await Promise.all([
this.loadDisciplineRecords(disciplineTypeIds),
this.loadRewardRecords(rewardTypeIds),
]);
} else {
uni.showToast({
title: '获取指标类型信息失败',
icon: 'none',
});
}
} catch (error) {
console.error('加载数据失败:', error);
uni.showToast({
title: '加载数据失败,请稍后重试',
icon: 'none',
});
} finally {
this.loading = false;
}
},
// 加载违纪处分记录
async loadDisciplineRecords(disciplineTypeIds) {
if (!disciplineTypeIds) {
this.disciplineRecords = [];
return;
}
console.log('加载违纪处分记录,disciplineTypeIds:', disciplineTypeIds);
console.log('加载违纪处分记录,dataStartTime:', this.dataStartTime);
console.log('加载违纪处分记录,dataEndTime:', this.dataEndTime);
console.log('加载违纪处分记录,studentId:', this.studentId);
try {
const response = await request({
url: '/disciplineRecord/disciplineRecord/getStudentDisciplineRecords',
method: 'get',
params: {
studentId: this.studentId,
disciplineTypeIds: disciplineTypeIds,
startTime: this.dataStartTime,
endTime: this.dataEndTime,
status: 1, // 只查询状态为1的记录
},
});
if (response.code === 200) {
this.disciplineRecords = response.data || [];
} else {
uni.showToast({
title: '获取违纪处分记录失败',
icon: 'none',
});
this.disciplineRecords = [];
}
} catch (error) {
console.error('获取违纪处分记录失败:', error);
this.disciplineRecords = [];
}
},
// 加载奖励记录
async loadRewardRecords(rewardTypeIds) {
if (!rewardTypeIds) {
this.rewardRecords = [];
return;
}
try {
const response = await request({
url: '/rewardRecord/rewardRecord/getStudentRewardRecords',
method: 'get',
params: {
studentId: this.studentId,
rewardTypeIds: rewardTypeIds,
startTime: this.dataStartTime,
endTime: this.dataEndTime,
status: 1, // 只查询状态为1的记录
},
});
if (response.code === 200) {
this.rewardRecords = response.data || [];
} else {
uni.showToast({
title: '获取奖励记录失败',
icon: 'none',
});
this.rewardRecords = [];
}
} catch (error) {
console.error('获取奖励记录失败:', error);
this.rewardRecords = [];
}
},
// 格式化日期
formatDate(dateStr) {
if (!dateStr) return '-';
try {
const date = new Date(dateStr);
if (isNaN(date.getTime())) return dateStr;
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
} catch (error) {
console.error('日期格式化失败:', error);
return dateStr;
}
},
},
};
</script>
<style lang="scss" scoped>
// 参考移动端违纪记录模块开发规范的样式系统
$primary-color: #3c9cff;
$success-color: #19be6b;
$warning-color: #ff9900;
$error-color: #fa3534;
$info-color: #909399;
$text-primary: #303133;
$text-secondary: #606266;
$text-placeholder: #909399;
$border-color: #f0f0f0;
$background-color: #f8f9fa;
$spacing-xs: 8rpx;
$spacing-sm: 12rpx;
$spacing-md: 16rpx;
$spacing-lg: 20rpx;
$spacing-xl: 24rpx;
$radius-sm: 8rpx;
$radius-md: 12rpx;
$radius-lg: 16rpx;
.full-page {
min-height: 100vh;
background-color: #f5f6fa;
}
.page-content {
padding: $spacing-lg;
}
.record-section {
margin-bottom: 32rpx;
&:last-child {
margin-bottom: 0;
}
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: $spacing-lg;
padding-bottom: 10rpx;
border-bottom: 2rpx solid $border-color;
}
.section-title {
font-size: 30rpx;
font-weight: bold;
color: $text-primary;
}
.record-list {
display: flex;
flex-direction: column;
gap: $spacing-md;
}
.record-card {
background-color: #fff;
border-radius: $radius-lg;
padding: $spacing-xl;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
border-left: 4rpx solid $primary-color;
}
.record-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: $spacing-md;
}
.record-type {
font-size: 28rpx;
font-weight: bold;
color: $text-primary;
}
.record-score {
display: flex;
align-items: center;
}
.record-content {
display: flex;
flex-direction: column;
gap: $spacing-sm;
}
.record-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: $spacing-xs 0;
}
.record-item-full {
display: flex;
flex-direction: column;
gap: $spacing-xs;
padding: $spacing-sm 0;
}
.record-label {
font-size: 26rpx;
color: $text-secondary;
min-width: 120rpx;
flex-shrink: 0;
}
.record-value {
font-size: 26rpx;
color: $text-primary;
text-align: right;
word-break: break-all;
}
.record-content-text {
font-size: 26rpx;
color: $text-primary;
line-height: 1.5;
padding: $spacing-sm;
background-color: $background-color;
border-radius: $radius-sm;
word-break: break-word;
white-space: pre-wrap;
}
.empty-container {
padding: 60rpx 0;
background-color: #fff;
border-radius: $radius-lg;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
}
</style>
+206 -12
View File
@@ -33,13 +33,15 @@
{{ item.academicYear || '暂无' }} {{ item.academicYear || '暂无' }}
{{ getSemesterText(item.semester) }} {{ getSemesterText(item.semester) }}
</text> </text>
<u-tag
:text="getStatusText(item.status)"
:type="getStatusTagType(item.status)"
size="mini"
></u-tag>
</view> </view>
</view> </view>
<view class="status-info">
<u-tag
:text="getStatusText(item.status)"
:type="getStatusTagType(item.status)"
size="mini"
></u-tag>
</view>
</view> </view>
<!-- 卡片内容 --> <!-- 卡片内容 -->
@@ -58,6 +60,14 @@
<text class="time-label">结束时间:</text> <text class="time-label">结束时间:</text>
<text class="time-value">{{ formatTime(item.endTime) }}</text> <text class="time-value">{{ formatTime(item.endTime) }}</text>
</view> </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>
<view class="plan-info"> <view class="plan-info">
<text class="plan-name">考核方案: {{ item.planName || '暂无' }}</text> <text class="plan-name">考核方案: {{ item.planName || '暂无' }}</text>
@@ -91,6 +101,103 @@
<u-loadmore :status="loadStatus" @loadmore="loadMore"></u-loadmore> <u-loadmore :status="loadStatus" @loadmore="loadMore"></u-loadmore>
</view> </view>
</view> </view>
<!-- 查看计划详情弹窗 -->
<u-popup
:show="showScheduleDetail"
@close="closeScheduleDetail"
mode="center"
border-radius="20"
width="90%"
close-on-click-overlay
>
<view class="schedule-detail-popup">
<view class="popup-header">
<text class="popup-title">考核计划信息</text>
<u-icon
name="close"
size="20"
color="#909399"
@click="closeScheduleDetail"
></u-icon>
</view>
<view class="popup-content">
<view class="detail-item">
<text class="detail-label">考核计划:</text>
<text class="detail-value">
{{ selectedSchedule.scheduleName || '暂无' }}
</text>
</view>
<view class="detail-item">
<text class="detail-label">学年学期:</text>
<text class="detail-value">
{{
(selectedSchedule.academicYear || '暂无') +
' ' +
getSemesterText(selectedSchedule.semester)
}}
</text>
</view>
<view class="detail-item">
<text class="detail-label">考核方案:</text>
<text class="detail-value">{{ selectedSchedule.planName || '暂无' }}</text>
</view>
<view class="detail-item">
<text class="detail-label">状态:</text>
<view class="detail-value">
<u-tag
:text="getStatusText(selectedSchedule.status)"
:type="getStatusTagType(selectedSchedule.status)"
size="mini"
></u-tag>
</view>
</view>
<view class="detail-item">
<text class="detail-label">说明:</text>
<text class="detail-value description">
{{ selectedSchedule.description || '暂无说明' }}
</text>
</view>
<view class="detail-item">
<text class="detail-label">开始时间:</text>
<text class="detail-value">
{{ formatTime(selectedSchedule.startTime) }}
</text>
</view>
<view class="detail-item">
<text class="detail-label">结束时间:</text>
<text class="detail-value">{{ formatTime(selectedSchedule.endTime) }}</text>
</view>
<view class="detail-item">
<text class="detail-label">数据统计开始时间:</text>
<text class="detail-value">
{{ formatTime(selectedSchedule.dataStartTime) }}
</text>
</view>
<view class="detail-item">
<text class="detail-label">数据统计结束时间:</text>
<text class="detail-value">
{{ formatTime(selectedSchedule.dataEndTime) }}
</text>
</view>
</view>
<view class="popup-footer">
<u-button type="primary" size="medium" @click="closeScheduleDetail">
确定
</u-button>
</view>
</view>
</u-popup>
</view> </view>
</template> </template>
@@ -118,6 +225,10 @@ export default {
// 字典数据 // 字典数据
assessmentScheduleStatus: [], assessmentScheduleStatus: [],
studentSemester: [], studentSemester: [],
// 弹窗相关
showScheduleDetail: false,
selectedSchedule: {},
}; };
}, },
async onLoad(options) { async onLoad(options) {
@@ -226,12 +337,16 @@ export default {
// 查看考核计划信息 // 查看考核计划信息
handleViewSchedule(row) { handleViewSchedule(row) {
const message = `考核计划:${row.scheduleName}\n说明:${row.description}\n时间:${row.startTime} 至 ${row.endTime}`; console.log('点击查看计划按钮', row);
uni.showModal({ this.selectedSchedule = row;
title: '考核计划信息', this.showScheduleDetail = true;
content: message, console.log('弹窗状态已设置为true:', this.showScheduleDetail);
showCancel: false, },
});
// 关闭计划详情弹窗
closeScheduleDetail() {
this.showScheduleDetail = false;
this.selectedSchedule = {};
}, },
// 判断是否可以提交申请 // 判断是否可以提交申请
@@ -351,8 +466,11 @@ export default {
const year = date.getFullYear(); const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day}`; return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
} catch (error) { } catch (error) {
console.error('时间格式化失败:', error); console.error('时间格式化失败:', error);
return timeStr; return timeStr;
@@ -437,6 +555,11 @@ export default {
gap: 16rpx; gap: 16rpx;
} }
.status-info {
display: flex;
align-items: center;
}
.academic-info { .academic-info {
font-size: 26rpx; font-size: 26rpx;
color: #606266; color: #606266;
@@ -533,4 +656,75 @@ export default {
.load-more { .load-more {
padding: 20rpx 0; padding: 20rpx 0;
} }
/* 弹窗样式 */
.schedule-detail-popup {
background-color: #fff;
border-radius: 20rpx;
overflow: hidden;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx 30rpx 20rpx;
border-bottom: 1px solid #f0f0f0;
}
.popup-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.popup-content {
padding: 30rpx;
max-height: 60vh;
overflow-y: auto;
}
.detail-item {
display: flex;
align-items: flex-start;
margin-bottom: 24rpx;
text-align: left;
&:last-child {
margin-bottom: 0;
}
}
.detail-label {
font-size: 28rpx;
color: #606266;
min-width: 200rpx;
flex-shrink: 0;
text-align: left;
}
.detail-value {
font-size: 28rpx;
color: #303133;
flex: 1;
text-align: right;
word-break: break-all;
display: flex;
justify-content: flex-end;
align-items: center;
&.description {
line-height: 1.6;
text-align: left;
display: block;
justify-content: initial;
}
}
.popup-footer {
padding: 20rpx 30rpx 30rpx;
border-top: 1px solid #f0f0f0;
display: flex;
justify-content: center;
}
</style> </style>