dedsudiyu 1 week ago
parent
commit
2c1851b4dd

+ 32 - 1
.claude/claude.md

@@ -7,4 +7,35 @@ id="screen-approval" 的内容重构至E:\git\2021项目\v3-小程序\pages_safe
 列表使用examElLabEduRelationAuditList接口
 列表使用examElLabEduRelationAuditList接口
 审批使用examElLabEduRelationAudit接口
 审批使用examElLabEduRelationAudit接口
 
 
-要求符合uni-app 微信小程序
+要求符合uni-app 微信小程序
+
+exam/elLabEduRelation/auditList 接口文档
+exam/elLabEduRelation/audit 接口文档
+
+
+E:\git\2021项目\v3-小程序\.claude\mobile_exam.html内的
+id="screen-approval" 的内容重构至E:\git\2021项目\v3-小程序\pages_safetyEducationExamination\views\approval\index.vue页面样式与需求原型不服 检查代码不要修改样式
+
+
+
+1. 把richTextPdf.vue内容重构至E:\git\2021项目\v3-小程序\pages_safetyEducationExamination\component\richTextPdf.vue内 要求完全符合uni-app 微信小程序 并且使用前端方式生成下载PDF
+2. class为preExam-dialog的部分页面与操作逻辑 重构至E:\git\2021项目\v3-小程序\pages_safetyEducationExamination\views\home\component\examTask.vue内要求完全符合uni-app 微信小程序触发方法在setRichExamData()方法内 判定方式是if(item.commitmentEnabled == 1 && !item.commitmentConfirmed)已经写好了
+
+
+
+1. E:\git\2021项目\v3-小程序\pages_safetyEducationExamination\views\studyHourTask\index.vue页面顶部tag-scroll使用examElKnowledgePointTreeList接口数据并且该页面跳转进入时会携带一个入参knowledgePointIds这个参数是通过上个页面
+								uni.navigateTo({
+									url: `/pages_safetyEducationExamination/views/studyHourTask/index?knowledgePointId=${item.knowledgePointIds}`,
+								});
+过来的 本身是个数组
+需要根据这个入参来匹配tag-scroll展示内容 去掉 全部选项只展示匹配的选项内容
+列表借口替换为exam/user/courseware/learning/list 入参字段materialType为空字符串 查询全部类型
+页面依旧需要分页滚动加载
+
+1. E:\git\2021项目\v3-小程序\pages_safetyEducationExamination\views\studyHourTask\index.vue页面的入参的knowledgePointId字段 需要与examElKnowledgePointTreeList接口返回数据所有数据id和所有children子级id进行匹配 children可能有多级
+
+
+
+1. 重构E:\git\2021项目\v3-小程序\.claude\mobile_exam.html文件内 ID为screen-exam-detail的内容 至E:\git\2021项目\v3-小程序\pages_safetyEducationExamination\views\exam\onlineExamInfo.vue内 要求符合uni-app 微信小程序 并且还原完整样式与原型不要擅自更改样式与原型
+页面数据将会从上级列表页面的exam/user/exam/list接口中取值并且传入本页面 写好接参
+同时写好在pages_safetyEducationExamination/views/exam/index页面考试任务状态时点击列表内容跳转到此页面的方法与传参 

+ 5 - 1
pages_safetyEducationExamination/views/exam/index.vue

@@ -359,7 +359,11 @@
 				this.resetScoreList();
 				this.resetScoreList();
 			},
 			},
 			goToExamDetail(item) {
 			goToExamDetail(item) {
-				// 跳转考试详情,传递 examId / attemptId
+				// 跳转考试详情,传递完整考试数据
+				const examData = encodeURIComponent(JSON.stringify(item));
+				uni.navigateTo({
+					url: `/pages_safetyEducationExamination/views/exam/onlineExamInfo?examData=${examData}`
+				});
 			},
 			},
 			goToMockDetail(item) {
 			goToMockDetail(item) {
 				// 跳转模拟考试详情,传递 mockExamId
 				// 跳转模拟考试详情,传递 mockExamId

+ 328 - 2
pages_safetyEducationExamination/views/exam/onlineExamInfo.vue

@@ -1,8 +1,334 @@
+<!-- 考试详情 -->
 <template>
 <template>
+	<view class="exam-detail-page">
+		<scroll-view scroll-y class="scroll-content">
+			<view class="card">
+				<view class="chip-row mb8">
+					<text class="tag tag-orange text-xs">{{ examData.examTypeName }}</text>
+					<text class="tag tag-orange text-xs">{{ getExamStatusText() }}</text>
+				</view>
+				<view class="exam-title">{{ examData.examName }}</view>
+				<view class="info-grid mb14">
+					<view class="info-item">
+						<view class="text-xs text-gray mb4">总题目数</view>
+						<view class="text-blue fw500">{{ examData.totalQuestionNum }}</view>
+					</view>
+					<view class="info-item">
+						<view class="text-xs text-gray mb4">考试时长</view>
+						<view class="text-333 fw500">{{ examData.answerDuration }} 分钟</view>
+					</view>
+					<view class="info-item">
+						<view class="text-xs text-gray mb4">总分/及格</view>
+						<view class="text-333 fw500">{{ examData.totalScore }} / {{ examData.passScore }} 分</view>
+					</view>
+					<view class="info-item">
+						<view class="text-xs text-gray mb4">考试次数</view>
+						<view class="text-333 fw500">{{ examData.attemptLimit === 0 ? '不限' : examData.attemptLimit+' 次' }}</view>
+					</view>
+				</view>
+				<!-- 考前任务要求 -->
+				<view class="exam-type-max-box" v-if="examData.needStudy||examData.examStudy||examData.mockExam">
+					<view class="exam-title-p">考前任务状态</view>
+					<view class="exam-type-box">
+						<view class="exam-min-box" v-if="examData.needStudy">
+							<view>学时要求</view>
+							<view>{{ examData.completedStudyHours }}/{{ examData.studyHoursRequirement }}</view>
+						</view>
+						<view class="exam-min-box" v-if="examData.examStudy">
+							<view>学习任务</view>
+							<view>待完成</view>
+						</view>
+						<view class="exam-min-box" v-if="examData.mockExam">
+							<view>模拟考试</view>
+							<view>待完成</view>
+						</view>
+					</view>
+				</view>
+				<!-- 考试说明 -->
+				<view v-if="examData.unavailableDesc" class="exam-desc-box" style="background-color:#f4f6fa;">
+					<view class="exam-desc">{{ examData.unavailableDesc }}</view>
+				</view>
+			</view>
+		</scroll-view>
+
+		<!-- 底部按钮 -->
+		<view class="bottom-bar">
+			<view class="btn-primary" @click="startExam">
+				{{examData.needStudy||examData.examStudy?'开始学习':(examData.mockExam?'模拟考试':'开始考试')}}
+				</view>
+		</view>
+	</view>
 </template>
 </template>
 
 
 <script>
 <script>
+	import {
+		parseTime
+	} from '@/component/public.js'
+
+	export default {
+		data() {
+			return {
+				examData: {},
+			}
+		},
+		computed: {
+			showConditions() {
+				return this.examData.needStudy || this.examData.examStudy || this.examData.mockExam;
+			}
+		},
+		onLoad(options) {
+			// 接收从上个页面传递的考试数据
+			if (options.examData) {
+				try {
+					this.examData = JSON.parse(decodeURIComponent(options.examData));
+					this.formatExamData();
+				} catch (e) {
+					console.error('解析考试数据失败', e);
+				}
+			}
+		},
+		methods: {
+			formatExamData() {
+				// 格式化时间
+				if (this.examData.startTime) {
+					this.examData.startTime = parseTime(this.examData.startTime, '{y}-{m}-{d} {h}:{i}');
+				}
+				if (this.examData.endTime) {
+					this.examData.endTime = parseTime(this.examData.endTime, '{y}-{m}-{d} {h}:{i}');
+				}
+			},
+			getExamStatusText() {
+				// 根据时间判断考试状态
+				const now = new Date().getTime();
+				const start = new Date(this.examData.startTime).getTime();
+				const end = new Date(this.examData.endTime).getTime();
+
+				if (now < start) return '未开始';
+				if (now > end) return '已结束';
+				return '进行中';
+			},
+			goToStudyHour() {
+				// 跳转到学时任务页面
+				if (this.examData.knowledgePointIds && this.examData.knowledgePointIds.length > 0) {
+					uni.navigateTo({
+						url: `/pages_safetyEducationExamination/views/studyHourTask/index?knowledgePointId=${this.examData.knowledgePointIds.join(',')}`
+					});
+				} else {
+					uni.navigateTo({
+						url: '/pages_safetyEducationExamination/views/study/index'
+					});
+				}
+			},
+			goToCourse() {
+				// 跳转到课程学习页面
+				uni.showToast({
+					title: '跳转到课程学习',
+					icon: 'none'
+				});
+			},
+			goToMockExam() {
+				// 跳转到模拟考试页面
+				uni.showToast({
+					title: '跳转到模拟考试',
+					icon: 'none'
+				});
+			},
+			startExam() {
+				
+			},
+		},
+	}
 </script>
 </script>
 
 
-<style>
-</style>
+<style lang="stylus" scoped>
+	.exam-detail-page {
+		height: 100%;
+		display: flex;
+		flex-direction: column;
+		background-color: #f0f4fb;
+	}
+
+	.scroll-content {
+		flex: 1;
+		overflow: hidden;
+		padding-bottom: 160rpx;
+	}
+
+	.card {
+		background: #fff;
+		border-radius: 20rpx;
+		padding: 28rpx;
+		margin: 24rpx 24rpx 0;
+		border: 1px solid #dde3ed;
+	}
+
+	.chip-row {
+		display: flex;
+		gap: 12rpx;
+	}
+
+	.tag {
+		display: inline-block;
+		padding: 6rpx 16rpx;
+		border-radius: 20rpx;
+		font-size: 20rpx;
+	}
+
+	.tag-orange {
+		background: #fff7e6;
+		color: #d46b08;
+	}
+
+	.text-xs {
+		font-size: 22rpx;
+	}
+
+	.mb8 {
+		margin-bottom: 16rpx;
+	}
+
+	.mb4 {
+		margin-bottom: 8rpx;
+	}
+
+	.mb12 {
+		margin-bottom: 24rpx;
+	}
+
+	.mb14 {
+		margin-bottom: 28rpx;
+	}
+
+	.exam-title {
+		font-size: 34rpx;
+		font-weight: 700;
+		margin-bottom: 24rpx;
+	}
+
+	.info-grid {
+		display: grid;
+		grid-template-columns: 1fr 1fr;
+		gap: 16rpx;
+	}
+
+	.info-item {
+		border: 1px solid #dde3ed;
+		border-radius: 16rpx;
+		padding: 20rpx;
+	}
+
+	.text-gray {
+		color: #999;
+	}
+
+	.text-333 {
+		color: #333;
+	}
+	
+	.text-blue {
+		color: #1857d4;
+	}
+
+	.text-green {
+		color: #52c41a;
+	}
+
+	.text-red {
+		color: #ff4d4f;
+	}
+
+	.fw500 {
+		font-weight: 500;
+	}
+
+	.time-row {
+		font-size: 24rpx;
+	}
+
+	.card-title {
+		font-size: 28rpx;
+		font-weight: 600;
+	}
+
+	.condition-row {
+		display: flex;
+		align-items: center;
+		padding: 16rpx 0;
+		border-bottom: 1rpx solid #f0f0f0;
+
+		&:last-child {
+			border-bottom: none;
+		}
+	}
+
+	.condition-icon {
+		font-size: 32rpx;
+		margin-right: 16rpx;
+	}
+
+	.condition-text {
+		flex: 1;
+		font-size: 26rpx;
+	}
+	.exam-desc-box{
+		padding:28rpx;
+		border-radius:10rpx;
+	}
+	.exam-desc {
+		font-size: 26rpx;
+		line-height: 1.8;
+		color: #666;
+	}
+	.exam-type-max-box{
+		margin-bottom:30rpx;
+		.exam-title-p{
+			font-size:24rpx;
+			line-height:70rpx;
+		}
+		.exam-type-box{
+			border:1px solid #dde3ed;
+			border-radius:20rpx;
+			.exam-min-box:nth-child(1){
+				border-top:none;
+			}
+			.exam-min-box{
+				display:flex;
+				border-top:1px solid #dde3ed;
+				padding:30rpx 28rpx;
+				view{
+					height:30rpx;
+					line-height:30rpx;
+					font-size:24rpx;
+				}
+				view:nth-child(1){
+					flex:1;
+				}
+				view:nth-child(2){
+					color:#e67e22;
+				}
+			}
+		}
+	}
+
+	.bottom-bar {
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		right: 0;
+		background: #fff;
+		padding: 20rpx 24rpx;
+		border-top: 1rpx solid #eee;
+		padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
+	}
+
+	.btn-primary {
+		height: 88rpx;
+		line-height: 88rpx;
+		text-align: center;
+		background: #1857d4;
+		color: #fff;
+		border-radius: 16rpx;
+		font-size: 32rpx;
+		font-weight: 600;
+	}
+</style>