dedsudiyu 1 week ago
parent
commit
e1e7f2c81a

+ 33 - 2
pages_safetyEducationExamination/api/index.js

@@ -35,7 +35,14 @@ export const examUserCourseLearningList = (data) => {
 		data: { ...data }
 		data: { ...data }
 	})
 	})
 };
 };
-
+//在线考试列表
+export const examUserExamList = (data) => {
+	return apiResquest({
+		url: `/exam/user/exam/list`,
+		method: 'POST',
+		data: { ...data }
+	})
+};
 //模拟考试列表
 //模拟考试列表
 export const examUserExamMockList = (data) => {
 export const examUserExamMockList = (data) => {
 	return apiResquest({
 	return apiResquest({
@@ -44,6 +51,22 @@ export const examUserExamMockList = (data) => {
 		data: { ...data }
 		data: { ...data }
 	})
 	})
 };
 };
+//我的成绩列表
+export const examElExamUserResultMyScoreListPage = (data) => {
+	return apiResquest({
+		url: `/exam/elExamUserResult/myScoreListPage`,
+		method: 'POST',
+		data: { ...data }
+	})
+};
+//考试/类型数量列表
+export const examUserExamTypeSelectExamType = (data) => {
+	return apiResquest({
+		url: `/exam/user/examType/selectExamType`,
+		method: 'POST',
+		data: { ...data }
+	})
+};
 //模拟练习正确率
 //模拟练习正确率
 export const examUserPracticeSummary = (data) => {
 export const examUserPracticeSummary = (data) => {
 	return apiResquest({
 	return apiResquest({
@@ -93,4 +116,12 @@ export const examElQuestionBankGroupByKnowledgePoint = (data) => {
 		method: 'POST',
 		method: 'POST',
 		data: { ...data }
 		data: { ...data }
 	})
 	})
-};
+};
+//查询毕业报告
+export const examElLabEduRelationGraduationReport = (data) => {
+  return apiResquest({
+    url: `/exam/elLabEduRelation/graduationReport`,
+		method: 'get',
+		data: { ...data }
+  })
+}

+ 608 - 23
pages_safetyEducationExamination/views/exam/index.vue

@@ -1,45 +1,630 @@
 <!-- 在线考试列表 -->
 <!-- 在线考试列表 -->
 <template>
 <template>
 	<view class="safetyEducationExamination-exam">
 	<view class="safetyEducationExamination-exam">
-		
+		<!-- 顶部 Tab -->
+		<view class="tab-bar">
+			<view
+				v-for="(tab, index) in tabs"
+				:key="index"
+				class="tab-item"
+				:class="{ active: activeTab === index }"
+				@click="switchTab(index)"
+			>
+				{{ tab }}
+			</view>
+		</view>
+
+		<!-- 内容区 -->
+		<scroll-view scroll-y class="scroll-content" @scrolltolower="onScrollToLower">
+			<!-- 考试任务 -->
+			<view v-if="activeTab === 0" class="panel">
+				<view
+					v-for="(item, index) in examTaskList"
+					:key="index"
+					class="exam-card"
+					@click="goToExamDetail(item)"
+				>
+					<view class="card-top">
+						<view class="card-top-left">
+							<text class="tag tag-blue">{{ item.examTypeName }}</text>
+							<view class="status-dot" :class="item.examStatus == 1 ? 'dot-green' : 'dot-orange'"></view>
+							<text class="status-text" :class="item.examStatus == 1 ? 'text-gray' : 'text-orange'">
+								{{ item.examStatus == 1 ? '未开始' : '进行中' }}
+							</text>
+						</view>
+						<text class="arrow-icon">›</text>
+					</view>
+					<text class="exam-name">{{ item.examName }}</text>
+					<!-- 有学时要求:三列 -->
+					<view v-if="item.needStudy || item.examStudy || item.mockExam" class="info-grid col3">
+						<view class="info-item">
+							<text class="info-label">学时要求</text>
+							<text class="info-value" :class="item.needStudy ? 'text-orange' : 'text-green'">
+								{{ item.completedStudyHours }}/{{ item.studyHoursRequirement }}
+								<text v-if="item.needStudy"> 未达标</text>
+								<text v-else> 已达标</text>
+							</text>
+						</view>
+						<view class="info-item">
+							<text class="info-label">学习任务</text>
+							<text class="info-value" :class="item.examStudy ? 'text-orange' : 'text-green'">
+								{{ item.examStudy ? '待完成' : '已完成' }}
+							</text>
+						</view>
+						<view class="info-item">
+							<text class="info-label">模拟考试</text>
+							<text class="info-value" :class="item.mockExam ? 'text-orange' : 'text-green'">
+								{{ item.mockExam ? '待完成' : '已完成' }}
+							</text>
+						</view>
+					</view>
+					<!-- 无前置条件:两列 -->
+					<view v-else class="info-grid col2">
+						<view class="info-item">
+							<text class="info-label">满分/及格</text>
+							<text class="info-value">{{ item.totalScore }} / {{ item.passScore }} 分</text>
+						</view>
+						<view class="info-item">
+							<text class="info-label">可考次数</text>
+							<text class="info-value text-gray">{{ item.attemptLimit === 0 ? '不限' : item.attemptLimit + ' 次' }}</text>
+						</view>
+					</view>
+				</view>
+				<view v-if="!examTaskList[0] && !examTaskLoading" class="empty-tip">暂无考试任务</view>
+				<view v-if="examTaskLoading" class="loading-tip">加载中...</view>
+			</view>
+
+			<!-- 模拟考试 -->
+			<view v-if="activeTab === 1" class="panel">
+				<view
+					v-for="(item, index) in mockExamList"
+					:key="index"
+					class="exam-card"
+					@click="goToMockDetail(item)"
+				>
+					<view class="card-top">
+						<view class="card-top-left">
+							<text class="tag tag-blue">{{ item.examTypeName }}</text>
+							<text class="tag tag-orange" style="margin-left:8rpx;">模拟卷</text>
+						</view>
+						<text class="arrow-icon">›</text>
+					</view>
+					<text class="exam-name">{{ item.examName }}</text>
+					<view class="info-grid col2">
+						<view class="info-item-2">
+							<span class="info-value" style="color:#8896a7;">最高成绩:
+							<span class="info-value" :class="item.maxScore >= item.passScore ? 'text-green' : 'text-orange'">
+							{{ item.maxScore > 0 ? item.maxScore + ' 分' : '未参加' }}
+							</span></span>
+						</view>
+						<view class="info-item-2">
+							<text class="info-value" style="text-align:right;color:#8896a7;">及格线:{{ item.passScore }} 分</text>
+						</view>
+					</view>
+				</view>
+				<view v-if="!mockExamList[0] && !mockExamLoading" class="empty-tip">暂无模拟考试</view>
+				<view v-if="mockExamLoading" class="loading-tip">加载中...</view>
+			</view>
+
+			<!-- 我的成绩 -->
+			<view v-if="activeTab === 2" class="panel">
+				<!-- 筛选区 -->
+				<view class="filter-row">
+					<picker :range="resultOptions" :range-key="'label'" @change="onResultChange">
+						<view class="picker-input" style="width:100rpx;">{{ resultOptions[resultIndex].label }} ▾</view>
+					</picker>
+					<picker mode="date" :value="startDate" @change="onStartDateChange">
+						<view class="picker-input top-picker-input-box" :style="!startDate?'color:#999;font-size:22rpx;':''">{{ startDate?startDate:'请选择' }}</view>
+					</picker>
+					<text class="filter-sep">至</text>
+					<picker mode="date" :value="endDate" @change="onEndDateChange" >
+						<view class="picker-input top-picker-input-box" :style="!endDate?'color:#999;font-size:22rpx;':''">{{ endDate?endDate:'请选择' }}</view>
+					</picker>
+					<view class="top-right-box-button" @click="resetScoreList()">重置</view>
+				</view>
+				<!-- 考试类型标签 -->
+				<scroll-view scroll-x class="tag-scroll">
+					<view class="tag-scroll-inner">
+						<text
+							v-for="(tag, index) in examTypeTags"
+							:key="index"
+							class="filter-tag"
+							:class="{ 'filter-tag-active': activeTagIndex === index }"
+							@click="onTagChange(index)"
+						>{{ tag.label }}</text>
+					</view>
+				</scroll-view>
+				<!-- 成绩卡片 -->
+				<view
+					v-for="(item, index) in scoreList"
+					:key="index"
+					class="score-card"
+					@click="goToScoreDetail(item)"
+				>
+					<view class="card-top">
+						<text class="tag tag-blue">{{ item.examTypeName }}</text>
+						<text class="score-result" :class="item.resultStatus == 2 ? 'result-pass' : 'result-fail'">
+							{{ item.resultStatus == 2 ? '通过' : '未通过' }}
+						</text>
+					</view>
+					<text class="score-exam-name">{{ item.examName }}</text>
+					<view class="score-info-grid">
+						<view><text class="text-gray">考试时间:</text>{{ item.startTime }}</view>
+						<view><text class="text-gray">时长:</text>{{ item.answerDuration }} 分钟</view>
+						<view><text class="text-gray">满分/及格:</text>{{ item.totalScore }} / {{ item.passScore }}</view>
+						<view><text class="text-gray">考次:</text>{{ item.attemptCount }} / {{ item.attemptLimit === 0 ? '不限' : item.attemptLimit }}</view>
+						<view><text class="text-gray">用时:</text>{{ item.myDuration || '-' }}</view>
+						<view>
+							<text class="text-gray">最高成绩:</text>
+							<text :class="item.bestScore >= item.passScore ? 'text-green' : 'text-red'">{{ item.bestScore }} 分</text>
+						</view>
+						<view>
+							<text class="text-gray">获得积分:</text>
+							<text :class="item.myScore > 0 ? 'text-orange' : 'text-gray'">
+								{{ item.myScore > 0 ? '+' + item.myScore + '分' : '无' }}
+							</text>
+						</view>
+						<view>
+							<text class="text-gray">考试结果:</text>
+							<text :class="item.resultStatus === 1 ? 'text-green' : 'text-red'">
+								{{ item.resultStatus === 1 ? '通过' : '未通过' }}
+							</text>
+						</view>
+					</view>
+				</view>
+				<view v-if="!scoreList[0] && !scoreLoading" class="empty-tip">暂无成绩记录</view>
+				<view v-if="scoreLoading" class="loading-tip">加载中...</view>
+				<view v-if="scoreNoMore && scoreList[0]" class="loading-tip">没有更多了</view>
+			</view>
+		</scroll-view>
 	</view>
 	</view>
 </template>
 </template>
 
 
 <script>
 <script>
-	// import {
-	// 	systemMineUserEdit
-	// } from '@/pages_safetyEducationExamination/api/index.js'
-	// import {
-	// 	workbench
-	// } from '@/pages_safetyEducationExamination/component/workbench/index'
+	import {
+		parseTime
+	} from '@/component/public.js'
+	import {
+		examUserExamList,
+		examUserExamMockList,
+		examElExamUserResultMyScoreListPage,
+		examUserExamTypeSelectExamType,
+	} from '@/pages_safetyEducationExamination/api/index.js'
+
 	export default {
 	export default {
-		// components: {
-		// 	workbench,
-		// },
 		data() {
 		data() {
 			return {
 			return {
-				
+				tabs: ['考试任务', '模拟考试', '我的成绩'],
+				activeTab: 0,
+				// 考试任务
+				examTaskList: [],
+				examTaskLoading: false,
+				// 模拟考试
+				mockExamList: [],
+				mockExamLoading: false,
+				// 我的成绩
+				scoreList: [],
+				scoreLoading: false,
+				scorePage: 1,
+				scorePageSize: 10,
+				scoreTotal: 0,
+				scoreNoMore: false,
+				// 筛选
+				resultOptions: [
+					{ label: '全部', value: null },
+					{ label: '通过', value: 1 },
+					{ label: '未通过', value: 2 },
+				],
+				resultIndex: 0,
+				startDate: '',
+				endDate: '',
+				examTypeTags: [{ label: '全部', value: null }],
+				activeTagIndex: 0,
 			}
 			}
 		},
 		},
 		created() {
 		created() {
-			
+			this.loadExamTypeTags();
 		},
 		},
 		onShow() {
 		onShow() {
-			
+			this.refreshCurrentTab();
 		},
 		},
 		methods: {
 		methods: {
-
+			switchTab(index) {
+				this.activeTab = index;
+				this.refreshCurrentTab();
+			},
+			refreshCurrentTab() {
+				if (this.activeTab === 0) {
+					this.loadExamTaskList();
+				} else if (this.activeTab === 1) {
+					this.loadMockExamList();
+				} else if (this.activeTab === 2) {
+					this.resetScoreList();
+				}
+			},
+			// 考试类型标签(用于我的成绩筛选)
+			async loadExamTypeTags() {
+				try {
+					const { data } = await examUserExamTypeSelectExamType({});
+					if (data.code === 200 && data.data) {
+						const tags = (data.data || []).map(item => ({
+							label: item.examTypeName,
+							value: item.examTypeId,
+						}));
+						this.$set(this, 'examTypeTags', [{ label: '全部', value: null }, ...tags]);
+					}
+				} catch (e) {
+					console.error('获取考试类型失败', e);
+				}
+			},
+			// 考试任务列表
+			async loadExamTaskList() {
+				if (this.examTaskLoading) return;
+				this.examTaskLoading = true;
+				try {
+					const { data } = await examUserExamList({ page: 1, pageSize: 50 });
+					if (data.code === 200) {
+						this.$set(this, 'examTaskList', data.data.records || []);
+					}
+				} catch (e) {
+					console.error('获取考试任务失败', e);
+				} finally {
+					this.examTaskLoading = false;
+				}
+			},
+			// 模拟考试列表
+			async loadMockExamList() {
+				if (this.mockExamLoading) return;
+				this.mockExamLoading = true;
+				try {
+					const { data } = await examUserExamMockList({ page: 1, pageSize: 50 });
+					if (data.code === 200) {
+						this.$set(this, 'mockExamList', data.data.records || []);
+					}
+				} catch (e) {
+					console.error('获取模拟考试失败', e);
+				} finally {
+					this.mockExamLoading = false;
+				}
+			},
+			// 重置成绩列表(筛选条件变更时调用)
+			resetScoreList() {
+				this.scorePage = 1;
+				this.scoreNoMore = false;
+				this.startTime = '';
+				this.endTime = '';
+				this.$set(this, 'scoreList', []);
+				this.loadScoreList();
+			},
+			// 我的成绩列表(支持分页)
+			async loadScoreList() {
+				if (this.scoreLoading || this.scoreNoMore) return;
+				this.scoreLoading = true;
+				try {
+					const tag = this.examTypeTags[this.activeTagIndex];
+					const result = this.resultOptions[this.resultIndex];
+					const obj = {
+						page: this.scorePage,
+						pageSize: this.scorePageSize,
+						examTypeId: tag.value || '',
+						resultStatus: result.value || '',
+						startTime: this.startDate?this.startDate + 'T00:00:00':'',
+						endTime: this.endDate?this.endDate + 'T23:59:59':'',
+						examScene:null
+					};
+					const { data } = await examElExamUserResultMyScoreListPage(obj);
+					if (data.code === 200) {
+						for(let i=0;i<data.data.records.length;i++){
+							data.data.records[i].startTime = parseTime(data.data.records[i].startTime, "{y}-{m}-{d}")
+						}
+						const records = data.data.records || [];
+						const newList = this.scorePage === 1 ? records : [...this.scoreList, ...records];
+						this.$set(this, 'scoreList', newList);
+						this.scoreTotal = data.data.total;
+						if (newList.length >= this.scoreTotal) {
+							this.scoreNoMore = true;
+						} else {
+							this.scorePage++;
+						}
+					}
+				} catch (e) {
+					console.error('获取成绩列表失败', e);
+				} finally {
+					this.scoreLoading = false;
+				}
+			},
+			// 滚动到底部加载更多(我的成绩)
+			onScrollToLower() {
+				if (this.activeTab === 2) {
+					this.loadScoreList();
+				}
+			},
+			onResultChange(e) {
+				this.resultIndex = e.detail.value;
+				this.resetScoreList();
+			},
+			onStartDateChange(e) {
+				this.startDate = e.detail.value;
+				this.resetScoreList();
+			},
+			onEndDateChange(e) {
+				this.endDate = e.detail.value;
+				this.resetScoreList();
+			},
+			onTagChange(index) {
+				this.activeTagIndex = index;
+				this.resetScoreList();
+			},
+			goToExamDetail(item) {
+				// 跳转考试详情,传递 examId / attemptId
+			},
+			goToMockDetail(item) {
+				// 跳转模拟考试详情,传递 mockExamId
+			},
+			goToScoreDetail(item) {
+				// 跳转成绩详情,传递 examId
+			},
 		},
 		},
-		
 	}
 	}
 </script>
 </script>
 
 
 <style lang="stylus" scoped>
 <style lang="stylus" scoped>
-	.safetyEducationExamination-exam {
-		height: 100%;
-		display: flex;
-		flex-direction: column;
-		overflow: hidden;
-		background-color: #f0f4fb;
-	}
-</style>
+	.safetyEducationExamination-exam
+		height 100%
+		display flex
+		flex-direction column
+		overflow hidden
+		background-color #f0f4fb
+
+	// 顶部 Tab
+	.tab-bar
+		background #fff
+		border-bottom 1rpx solid #e8edf3
+		display flex
+		flex-shrink 0
+
+		.tab-item
+			flex 1
+			text-align center
+			padding 18rpx 8rpx 16rpx
+			font-size 26rpx
+			color #888
+			border-bottom 4rpx solid transparent
+
+		.tab-item.active
+			color #1677ff
+			font-weight 600
+			border-bottom-color #1677ff
+
+	// 滚动区
+	.scroll-content
+		flex 1
+		overflow hidden
+
+	.panel
+		padding 24rpx
+
+	// 考试卡片
+	.exam-card
+		background #fff
+		border-radius 20rpx
+		padding 24rpx 28rpx
+		margin-bottom 20rpx
+		box-shadow 0 2rpx 12rpx rgba(0,0,0,0.04)
+		border 1rpx solid #dde3ed
+
+	.card-top
+		display flex
+		justify-content space-between
+		align-items center
+		margin-bottom 16rpx
+
+	.card-top-left
+		display flex
+		align-items center
+
+	.arrow-icon
+		font-size 32rpx
+		color #bbb
+
+	// 标签
+	.tag
+		font-size 20rpx
+		padding 4rpx 12rpx
+		border-radius 8rpx
+		border 1rpx solid transparent
+
+	.tag-blue
+		background #e6f4ff
+		color #1677ff
+		border-color #91caff
+
+	.tag-orange
+		background #fff7e6
+		color #d46b08
+		border-color #ffd591
+
+	// 状态点
+	.status-dot
+		width 12rpx
+		height 12rpx
+		border-radius 50%
+		margin-left 24rpx
+		margin-right:10rpx;
+
+	.dot-orange
+		background #fa8c16
+
+	.dot-green
+		background #999
+
+	.status-text
+		font-size 22rpx
+		margin-left 6rpx
+
+	.text-orange
+		color #fa8c16
+
+	.text-gray
+		color #999
+
+	.text-green
+		color #52c41a
+
+	.text-blue
+		color #1677ff
+
+	.text-red
+		color #f5222d
+
+	// 考试名称
+	.exam-name
+		display block
+		font-size 28rpx
+		font-weight 600
+		color #222
+		margin-bottom 16rpx
+
+	// 信息格
+	.info-grid
+		display grid
+		gap 12rpx
+
+	.col3
+		grid-template-columns 1fr 1fr 1fr
+
+	.col2
+		grid-template-columns 1fr 1fr
+
+	.info-item
+		background #f4f6fa
+		border-radius 12rpx
+		padding 12rpx 16rpx
+		display flex
+		flex-direction column
+
+	.info-item-2
+		display flex
+		flex-direction column
+
+	.info-label
+		font-size 20rpx
+		color #999
+		margin-bottom 8rpx
+
+	.info-value
+		font-size 22rpx
+
+	// 筛选
+	.filter-row
+		display flex
+		align-items center
+		gap 12rpx
+		padding 16rpx 0 8rpx
+		flex-wrap nowrap
+		.top-picker-input-box{
+			width:190rpx;
+			height:54rpx;
+			padding:0;
+			text-align: center;
+			line-height:54rpx;
+		}
+		.top-right-box-button{
+			border: 1rpx solid #dde3ed;
+			border-radius:10rpx
+			background:#fff;
+			font-size:24rpx;
+			width:100rpx;
+			height:54rpx;
+			padding:0;
+			text-align: center;
+			line-height:54rpx;
+		}
+	.picker-input
+		font-size 24rpx
+		color #333
+		background #fff
+		border 1rpx solid #dde3ed
+		border-radius 10rpx
+		padding 10rpx 16rpx
+
+	.filter-sep
+		font-size 22rpx
+		color #999
+		flex-shrink 0
+
+	// 类型标签滚动
+	.tag-scroll
+		white-space nowrap
+		padding 8rpx 0 16rpx
+
+	.tag-scroll-inner
+		display inline-flex
+		gap 12rpx
+
+	.filter-tag
+		display inline-block
+		font-size 22rpx
+		padding 8rpx 20rpx
+		border-radius 30rpx
+		background #eef1f6
+		color #666
+		border 1rpx solid transparent
+
+	.filter-tag-active
+		background #e6f0ff
+		color #1677ff
+		border-color #91caff
+
+	// 成绩卡片
+	.score-card
+		background #fff
+		border-radius 20rpx
+		padding 24rpx 28rpx
+		margin-bottom 20rpx
+		box-shadow 0 2rpx 12rpx rgba(0,0,0,0.04)
+		border 1rpx solid #dde3ed
+
+	.score-result
+		font-size 22rpx
+		font-weight 600
+		padding 4rpx 16rpx
+		border-radius 20rpx
+
+	.result-pass
+		background #f6ffed
+		color #52c41a
+		border 1rpx solid #b7eb8f
+
+	.result-fail
+		background #fff2f0
+		color #f5222d
+		border 1rpx solid #ffccc7
+
+	.score-exam-name
+		display block
+		font-size 30rpx
+		font-weight 700
+		color #222
+		margin 16rpx 0
+
+	.score-info-grid
+		display grid
+		grid-template-columns 1fr 1fr
+		gap 12rpx
+		margin-bottom 20rpx
+		font-size 26rpx
+		color #333
+
+	.empty-tip
+		text-align center
+		line-height 80rpx
+		color #aaa
+		font-size 24rpx
+
+	.loading-tip
+		text-align center
+		line-height 60rpx
+		color #aaa
+		font-size 22rpx
+</style>

+ 34 - 5
pages_safetyEducationExamination/views/home/component/academicYearStats.vue

@@ -4,7 +4,7 @@
 		<view class="card">
 		<view class="card">
 			<view class="card-header">
 			<view class="card-header">
 				<text class="card-title">📊 学年数据统计</text>
 				<text class="card-title">📊 学年数据统计</text>
-				<view class="btn-outline" @click="handleShowReport">成绩报告</view>
+				<view class="btn-outline" @click="examElLabEduRelationGraduationReport">成绩报告</view>
 			</view>
 			</view>
 			<view class="card-body">
 			<view class="card-body">
 				<view class="year-row" v-for="(item, index) in yearStatsList" :key="index">
 				<view class="year-row" v-for="(item, index) in yearStatsList" :key="index">
@@ -14,21 +14,25 @@
 				<view v-if="!yearStatsList.length" class="empty-tip">暂无统计数据</view>
 				<view v-if="!yearStatsList.length" class="empty-tip">暂无统计数据</view>
 			</view>
 			</view>
 		</view>
 		</view>
+		<dataStatisticsReport v-if="dialogType" :dataStatisticsReportPropsData="dataStatisticsReportPropsData"></dataStatisticsReport>
 	</view>
 	</view>
 </template>
 </template>
 
 
 <script>
 <script>
 	import { 
 	import { 
 		examElLabEduRelationAcademicYearProgress, 
 		examElLabEduRelationAcademicYearProgress, 
+		examElLabEduRelationGraduationReport,
 	} from '@/pages_safetyEducationExamination/api/index.js'
 	} from '@/pages_safetyEducationExamination/api/index.js'
+	import { dataStatisticsReport } from './dataStatisticsReport'
 	export default {
 	export default {
-		// components: {
-		// 	workbench,
-		// },
+		components: {
+			dataStatisticsReport,
+		},
 		data() {
 		data() {
 			return {
 			return {
 				yearStatsList: [],
 				yearStatsList: [],
-
+				dataStatisticsReportPropsData:{},
+				dialogType:false,
 			}
 			}
 		},
 		},
 		created() {
 		created() {
@@ -51,6 +55,22 @@
 					}
 					}
 				} catch (e) { console.error('获取学年统计失败', e); }
 				} catch (e) { console.error('获取学年统计失败', e); }
 			},
 			},
+			async examElLabEduRelationGraduationReport() {
+				try {
+					const { data } = await examElLabEduRelationGraduationReport({});
+					if(data.data.studyHoursList[0]&&data.data.examPassRecords[0]){
+						this.$set(this, 'dataStatisticsReportPropsData', data.data);
+						this.$set(this,'dialogType',true);
+					}else{
+						uni.showToast({
+							title: '请完成至少一次课程学习与考试',
+							icon:"none",
+							mask:true,
+							duration: 2000
+						});
+					}
+				} catch (e) { console.error('获取成绩报表失败', e); }
+			},
 		},
 		},
 
 
 	}
 	}
@@ -80,6 +100,15 @@
 				font-weight: 700;
 				font-weight: 700;
 				color: #333;
 				color: #333;
 			}
 			}
+			.btn-outline{
+				height: 56rpx;
+				line-height:56rpx;
+				font-size: 24rpx;
+				padding: 0 20rpx;
+				border-radius: 12rpx;
+				color: #1857d4;
+				border: 1px solid rgba(24, 87, 212, .3);
+			}
 
 
 			.header-link {
 			.header-link {
 				font-size: 24rpx;
 				font-size: 24rpx;

+ 384 - 0
pages_safetyEducationExamination/views/home/component/dataStatisticsReport.vue

@@ -0,0 +1,384 @@
+<!-- 毕业教育考试数据统计报告 -->
+<template>
+  <view class="dataStatisticsReport-addPage">
+    <!-- 报告主体 -->
+    <view class="report-wrap" v-if="showType">
+      <view class="report-wrap-big-box">
+        <view class="report-wrap-min-box">
+          <!-- logo -->
+          <view class="logo-box">
+            <image :src="logUrl" mode="widthFix" />
+          </view>
+          <!-- 标题 -->
+          <text class="title-p">实验室安全教育成绩报告</text>
+          <!-- 用户信息 -->
+          <view class="user-box">
+            <view class="user-min-box">
+              <view>
+                <text class="label">姓名:</text>
+                <text>{{newData.userName}}</text>
+              </view>
+              <view>
+                <text class="label">学号:</text>
+                <text>{{newData.account}}</text>
+              </view>
+            </view>
+            <view class="user-min-box">
+              <view>
+                <text class="label">学院:</text>
+                <text>{{newData.deptName}}</text>
+              </view>
+              <view>
+                <text class="label">年级:</text>
+                <text>{{newData.grade}}</text>
+              </view>
+            </view>
+            <view class="user-min-box">
+              <view>
+                <text class="label">用户类型:</text>
+                <text>{{newData.educationTypeName}}</text>
+              </view>
+            </view>
+          </view>
+          <!-- 学年学时 -->
+          <view class="study-hours-max-big-box" v-if="newData.studyHoursList && newData.studyHoursList[0]">
+            <view class="study-hours-title-box">
+              <view class="title-bar"></view>
+              <text class="title-text">学年学时完成情况</text>
+            </view>
+            <view class="study-hours-text-title-box">
+              <text>学年</text>
+              <text>完成学时</text>
+              <text>要求学时</text>
+            </view>
+            <view class="study-hours-for-box" v-for="(item, index) in newData.studyHoursList" :key="index">
+              <text>{{item.academicYear}}</text>
+              <text>{{item.completedStudyHours}}</text>
+              <text>{{item.studyHoursRequirement}}</text>
+            </view>
+            <view class="study-hours-bottom-box">
+              <text class="sum-label">累计</text>
+              <text class="sum-value">{{newData.totalStudyHours}} 学时</text>
+            </view>
+          </view>
+          <!-- 考试通过记录 -->
+          <view class="study-hours-max-big-box-2" v-if="newData.examPassRecords && newData.examPassRecords[0]">
+            <view class="study-hours-title-box">
+              <view class="title-bar"></view>
+              <text class="title-text">考试通过记录</text>
+            </view>
+            <view class="study-hours-text-title-box">
+              <text>学年</text>
+              <text>考试类型</text>
+              <text>成绩</text>
+            </view>
+            <view class="study-hours-for-box" v-for="(item, index) in newData.examPassRecords" :key="index">
+              <text>{{item.academicYear}}</text>
+              <text>{{item.examTypeName}}</text>
+              <text>{{item.score}}</text>
+            </view>
+          </view>
+          <!-- 描述信息 -->
+          <text class="study-text-p">  该同学在校期间认真完成实验室安全教育各项学习任务,累计完成 <text class="bold-text">{{newData.totalStudyHours}}</text> 学时安全培训,通过全部年度安全考核,具备良好的实验室安全意识和规范操作能力,特此证明。</text>
+          <!-- 落款 -->
+          <view class="signature-box">
+            <text>{{newData.issuingUnit}}</text>
+            <text>{{newData.issuingTime}}</text>
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script>
+  export default {
+    name: 'dataStatisticsReport',
+    props: {
+      dataStatisticsReportPropsData: {
+        type: Object,
+        default: () => ({})
+      }
+    },
+    data() {
+      return {
+        logUrl: 'https://labcontrol.nwafu.edu.cn/statics/2024/07/22/d1a9d129-ced7-49ac-b258-e5167d85232d.png',
+        newData: {
+          userName: '',
+          account: '',
+          deptName: '',
+          grade: '',
+          educationTypeName: '',
+          totalStudyHours: '',
+          studyHoursList: [],
+          examPassRecords: [],
+          issuingUnit: '',
+          issuingTime: '',
+        },
+        showType: false,
+      }
+    },
+    mounted() {
+      this.initialize()
+    },
+    methods: {
+      initialize() {
+        this.$set(this, 'newData', this.dataStatisticsReportPropsData)
+        this.$set(this, 'showType', true)
+      },
+    }
+  }
+</script>
+
+<style scoped lang="scss">
+.dataStatisticsReport-addPage {
+  background: #f5f7fa;
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+
+  .report-wrap {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+
+    .report-wrap-big-box {
+      margin: 20rpx;
+      border: 1rpx solid #c9a84c;
+      border-radius: 4rpx;
+      position: relative;
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+      background-color: #fffdf5;
+
+      .report-wrap-min-box {
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        border: 1rpx solid #c9a84c;
+        border-radius: 4rpx;
+        margin: 1rpx;
+
+        // logo
+        .logo-box {
+          width: 578rpx;
+          height: 88rpx;
+          border-radius: 6rpx;
+          background-color: #1a6e3a;
+          margin: 40rpx 0 0 48rpx;
+          overflow: hidden;
+
+          image {
+            width: 350rpx;
+            margin: 6rpx auto;
+            display: block;
+          }
+        }
+
+        // 标题
+        .title-p {
+          line-height: 56rpx;
+          color: #8b452f;
+          text-align: center;
+          font-size: 20rpx;
+          letter-spacing: 6rpx;
+          display: block;
+        }
+
+        // 用户信息
+        .user-box {
+          width: 578rpx;
+          background-color: #faf6ec;
+          border: 1rpx solid #e8dcc8;
+          margin: 9rpx 0 0 48rpx;
+          border-radius: 4rpx;
+          padding: 10rpx 20rpx;
+          box-sizing: border-box;
+
+          .user-min-box {
+            display: flex;
+
+            view {
+              flex: 1;
+              display: flex;
+
+              .label {
+                line-height: 26rpx;
+                font-size: 14rpx;
+                color: #4a3c2a;
+                font-weight: 700;
+              }
+
+              text:not(.label) {
+                line-height: 26rpx;
+                font-size: 14rpx;
+                color: #4a3c2a;
+              }
+            }
+          }
+        }
+
+        // 学年学时列表
+        .study-hours-max-big-box {
+          margin: 20rpx 48rpx 0 48rpx;
+
+          .study-hours-title-box {
+            display: flex;
+            align-items: center;
+
+            .title-bar {
+              height: 20rpx;
+              width: 3rpx;
+              background-color: #c9a84c;
+            }
+
+            .title-text {
+              line-height: 20rpx;
+              font-size: 12rpx;
+              flex: 1;
+              color: #8b4513;
+              margin-left: 8rpx;
+              font-weight: 700;
+            }
+          }
+
+          .study-hours-text-title-box {
+            display: flex;
+            background-color: #f5edd8;
+            border-bottom: 1rpx solid #d4c5a0;
+            margin-top: 10rpx;
+
+            text {
+              line-height: 34rpx;
+              font-size: 12rpx;
+              color: #5a4320;
+              flex: 1;
+              text-align: center;
+              font-weight: 700;
+            }
+          }
+
+          .study-hours-for-box {
+            display: flex;
+            border-bottom: 1rpx solid #ebe3d0;
+
+            text {
+              line-height: 32rpx;
+              font-size: 12rpx;
+              color: #4a3c2a;
+              flex: 1;
+              text-align: center;
+            }
+          }
+
+          .study-hours-bottom-box {
+            display: flex;
+            background-color: #faf6ec;
+            border-bottom: 1rpx solid #ebe3d0;
+
+            .sum-label {
+              width: 216rpx;
+              line-height: 32rpx;
+              font-size: 12rpx;
+              color: #4a3c2a;
+              font-weight: 700;
+              text-align: center;
+            }
+
+            .sum-value {
+              flex: 1;
+              line-height: 32rpx;
+              font-size: 12rpx;
+              color: #4a3c2a;
+              font-weight: 700;
+              text-align: center;
+            }
+          }
+        }
+
+        // 考试通过记录列表
+        .study-hours-max-big-box-2 {
+          margin: 20rpx 48rpx 0 48rpx;
+
+          .study-hours-title-box {
+            display: flex;
+            align-items: center;
+
+            .title-bar {
+              height: 20rpx;
+              width: 3rpx;
+              background-color: #c9a84c;
+            }
+
+            .title-text {
+              line-height: 20rpx;
+              font-size: 12rpx;
+              flex: 1;
+              color: #8b4513;
+              margin-left: 8rpx;
+              font-weight: 700;
+            }
+          }
+
+          .study-hours-text-title-box {
+            display: flex;
+            background-color: #f5edd8;
+            border-bottom: 1rpx solid #d4c5a0;
+            margin-top: 10rpx;
+
+            text {
+              line-height: 34rpx;
+              font-size: 12rpx;
+              color: #5a4320;
+              flex: 1;
+              text-align: center;
+              font-weight: 700;
+            }
+          }
+
+          .study-hours-for-box {
+            display: flex;
+            border-bottom: 1rpx solid #ebe3d0;
+
+            text {
+              line-height: 32rpx;
+              font-size: 12rpx;
+              color: #4a3c2a;
+              flex: 1;
+              text-align: center;
+            }
+          }
+        }
+
+        // 描述信息
+        .study-text-p {
+          margin: 25rpx 48rpx 0 48rpx;
+          line-height: 24rpx;
+          font-size: 14rpx;
+          color: #4a3c2a;
+          display: block;
+
+          .bold-text {
+            font-weight: 700;
+          }
+        }
+
+        // 落款
+        .signature-box {
+          margin: 103rpx 180rpx 80rpx 48rpx;
+
+          text {
+            height: 24rpx;
+            display: block;
+            text-align: right;
+            font-size: 14rpx;
+            color: #4a3c2a;
+            line-height: 24rpx;
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 4 - 0
pages_safetyEducationExamination/views/home/component/examTask.vue

@@ -44,6 +44,10 @@
 			goToPage(type,item){
 			goToPage(type,item){
 				if(type == 1){
 				if(type == 1){
 					//考试列表
 					//考试列表
+					uni.navigateTo({
+						url: '/pages_safetyEducationExamination/views/exam/index',
+					});
+					
 				}else if(type == 2){
 				}else if(type == 2){
 					//开始考试相关业务
 					//开始考试相关业务
 				}
 				}