Selaa lähdekoodia

feat: 课程详情-新增提示悬浮窗和答题弹窗页面

wenxingxing 1 päivä sitten
vanhempi
commit
baa7d2042a

+ 111 - 0
pages/course/components/answerFloatBox.vue

@@ -0,0 +1,111 @@
+<template>
+	<view class="complaintViewClass">
+		<image src="/static/image/hall/baoxiang_icon.png" mode="aspectFill"></image>
+		<view class="complaintViewTextClass">
+			<view v-if="~~typeNum === 1" class="pointsOkTextClass">
+				已得<text class="pointsNumTextClass">{{pointsNum}}</text>积分
+			</view>
+			<view v-if="~~typeNum === 2" class="pointsOkTowTextClass">
+				<text>未答对\n明天再来</text>
+			</view>
+			<view v-if="~~typeNum === 3" class="pointsOkTowTextClass">
+				<text>未答对\n继续答题</text>
+				<view class="answerBtnClass" @tap="handleShowAnswerMethods">答题</view>
+			</view>
+			<view v-if="~~typeNum === 4" class="pointsOkTowTextClass">
+				<text>
+					<text>再观看2:20</text>\n答题得奖励
+				</text>
+				<view class="answerBtnClass" @tap="handleShowAnswerMethods">答题</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			typeNum: {
+				type: Number,
+				default: 1, //悬浮框类型:1、已得积分,2、未答对明天再来,3、未答对继续答题,4、答题得奖励
+			},
+			pointsNum: {
+				type: Number,
+				default: 20, //已得积分数量
+			}
+		},
+		methods: {
+			handleShowAnswerMethods() {
+				this.$emit('handleShowAnswer')
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	@mixin u-flex($flexD, $alignI, $justifyC) {
+		display: flex;
+		flex-direction: $flexD;
+		align-items: $alignI;
+		justify-content: $justifyC;
+	}
+
+	.complaintViewClass {
+		@include u-flex(column, center, center);
+		position: fixed;
+		right: 34rpx;
+		bottom: 400rpx;
+
+		image {
+			width: 210rpx;
+			height: 90rpx;
+		}
+
+		.complaintViewTextClass {
+			@include u-flex(column, center, center);
+			margin-top: -15rpx;
+			z-index: 10;
+			width: 210rpx;
+			min-height: 120rpx;
+			background: linear-gradient(180deg, #FFF9DC 0%, #FFDC97 100%);
+			border-radius: 20rpx;
+			border: 2rpx solid linear-gradient(180deg, rgba(255, 228, 105, 1), rgba(255, 178, 30, 1));
+			padding: 10rpx 10rpx 20rpx;
+			box-sizing: border-box;
+			text-align: center;
+			overflow: hidden;
+		}
+	}
+
+	.pointsOkTextClass {
+		font-weight: 400;
+		font-size: 28rpx;
+		color: #FF2E3F;
+		line-height: 40rpx;
+	}
+
+	.pointsNumTextClass {
+		font-weight: 600;
+		font-size: 56rpx;
+		color: #FF2E3F;
+	}
+
+	.pointsOkTowTextClass {
+		font-weight: 600;
+		font-size: 32rpx;
+		color: #FF2E3F;
+	}
+
+	.answerBtnClass {
+		width: 150rpx;
+		height: 60rpx;
+		background: linear-gradient(135deg, #FF515F 0%, #F72234 100%);
+		border-radius: 30rpx;
+		margin-top: 10rpx;
+		font-weight: 600;
+		font-size: 32rpx;
+		color: #FFF2C3;
+		line-height: 55rpx;
+		text-align: center;
+	}
+</style>

+ 272 - 0
pages/course/components/questionsPopup.vue

@@ -0,0 +1,272 @@
+<template>
+	<u-popup :show="showPopup" mode="bottom" round="30" @close="close">
+		<view class="ques-content">
+			<view class="quesTitleViewClass">
+				<view class="quesTitleLeftClass">
+					<image src="/static/image/hall/ques_icon.png" mode="aspectFill"></image>
+					<text class="quesTitleTextClass">问答题</text>
+				</view>
+				<view @tap="close">
+					<u-icon name="close-circle-fill" color="#D8D8D8FF" size="32"></u-icon>
+				</view>
+			</view>
+			<scroll-view class="scroll-y" scroll-y>
+				<view class="dataItemViewClass" v-for="(item,index) in quesList" :key="index">
+					<view class="ques-title">
+						<text>{{index + 1}}.</text>
+						<!-- <view class="ques-type" v-show="item.type == 1 || item.type == 2">
+						{{item.type == 1 ? '单选' : item.type == 2 ? '多选' : ''}}
+					</view> -->
+						<text>{{item.title}}</text>
+					</view>
+					<view :class="isAnswer(item,option.name) ?'ques-option ques-option-active':'ques-option'"
+						v-for="(option,idx) in item.questionOption" :key="idx" @tap="handleSelectAnswer(item,option)">
+						<view>
+							{{numberToLetter(idx)}}.
+						</view>
+						<view>{{option.name}}</view>
+					</view>
+				</view>
+				<view class="empty" v-if="quesList.length==0">暂未设置题目~</view>
+			</scroll-view>
+			<view class="bottomBtnViewClass">
+				<view v-if="~~typeStatus === 1" :class="isOkAnswer ?'btnViewClass btnViewClass-active':'btnViewClass'"
+					@tap="isOkAnswer ? confirmAnswer():null">
+					提交答案</view>
+				<view v-if="~~typeStatus === 2" class="btnViewClass">再观看1分30秒可答题</view>
+			</view>
+		</view>
+	</u-popup>
+</template>
+
+<script>
+	export default {
+		props: {
+			isShow: {
+				type: Boolean,
+				default: false
+			},
+			typeStatus: {
+				type: Number,
+				default: 1, //提交类型:1、可以提交答案,2、需再观看视频
+			}
+		},
+		data() {
+			return {
+				showPopup: false,
+				quesList: [{
+					type: 1,
+					title: '《大美国医》药王级鹿茸粉单选特价供应货源还剩下不足多少盒?',
+					answer: '',
+					questionOption: [{
+							name: '800 盒'
+						},
+						{
+							name: '500 盒'
+						},
+						{
+							name: '1000 盒'
+						},
+						{
+							name: '1500 盒'
+						}
+					]
+				}],
+			}
+		},
+		computed: {
+			isOkAnswer() {
+				let newData = false
+				newData = !(this.quesList.map(item => item.answer).some(itemOne => itemOne == null || itemOne === ''))
+				return newData
+			},
+			isAnswer() {
+				return (item, name) => {
+					if (item.type == 1) {
+						return item.answer == name
+					} else if (item.type == 2) {
+						const array = item.answer.split(',')
+						return array.some(i => i == name)
+					} else {
+						return false
+					}
+				}
+			}
+		},
+		watch: {
+			isShow(newVal) {
+				this.showPopup = newVal
+			}
+		},
+
+		methods: {
+			numberToLetter(num) {
+				// 将数字转换为字母的 ASCII 码
+				let letterCode = num + 65;
+				// 将 ASCII 码转换为大写字母
+				let letter = String.fromCharCode(letterCode);
+				return letter;
+			},
+			// 点击选择答案
+			handleSelectAnswer(item, option) {
+				if (item.type == 1) {
+					// 单选option
+					if (item.answer === option.name) {
+						item.answer = ''
+					} else {
+						item.answer = option.name
+					}
+				} else if (item.type == 2) {
+					// 多选
+					let answer = item.answer ? item.answer.split(',') : []
+					if (answer.indexOf(option.name) === -1) {
+						answer.push(option.name)
+						item.answer = answer.join(',')
+					} else {
+						answer.splice(answer.indexOf(option.name), 1)
+						item.answer = answer.join(',')
+					}
+				}
+			},
+
+			// 提交答案
+			confirmAnswer() {
+				this.$emit('submitAnswer', this.quesList)
+				this.close()
+			},
+			// 关闭弹框
+			close() {
+				this.$emit('closeMethod')
+			},
+		},
+	}
+</script>
+
+<style lang="scss" scoped>
+	@mixin u-flex($flexD, $alignI, $justifyC) {
+		display: flex;
+		flex-direction: $flexD;
+		align-items: $alignI;
+		justify-content: $justifyC;
+	}
+
+	.empty {
+		@include u-flex(row, center, center);
+		padding: 24rpx 50rpx;
+		color: #999999;
+	}
+
+	.scroll-y {
+		width: 100%;
+		height: calc(60vh - 300rpx)
+	}
+
+	.quesTitleViewClass {
+		@include u-flex(row, center, space-between);
+		padding-bottom: 26rpx;
+		border-bottom: 2rpx solid #D8D8D8;
+		margin-bottom: 24rpx;
+
+		.quesTitleLeftClass {
+			@include u-flex(row, center, center);
+
+			image {
+				width: 28rpx;
+				height: 28rpx;
+				margin-right: 10rpx;
+			}
+
+			.quesTitleTextClass {
+				font-weight: 600;
+				font-size: 36rpx;
+				color: #222222;
+			}
+		}
+	}
+
+	.ques-content {
+		width: 100vw;
+		height: 60vh;
+		background-color: #fff;
+		padding: 24rpx 24rpx 20rpx 32rpx;
+		box-sizing: border-box;
+		background: #FFFFFF;
+		border-radius: 30rpx 30rpx 0rpx 0rpx;
+		font-weight: 400;
+		font-size: 28rpx;
+		color: #222222;
+	}
+
+	.dataItemViewClass {
+		width: 100%;
+		margin-bottom: 25rpx;
+	}
+
+	.ques-title {
+		font-weight: 600;
+		font-size: 40rpx;
+		margin-bottom: 24rpx;
+		color: rgba(0, 0, 0, 0.85);
+		white-space: normal;
+	}
+
+	.ques-type {
+		flex-shrink: 0;
+		min-width: 72rpx;
+		min-height: 40rpx;
+		padding: 0 12rpx;
+		margin: 0 12rpx;
+		box-sizing: border-box;
+		background: #FF5C03;
+		border-radius: 8rpx 8rpx 8rpx 8rpx;
+		line-height: 40rpx;
+		text-align: center;
+		font-family: PingFang SC, PingFang SC;
+		font-weight: 400;
+		font-size: 24rpx;
+		color: #FFFFFF;
+		display: inline-block;
+	}
+
+	.ques-option {
+		min-height: 104rpx;
+		padding: 24rpx;
+		box-sizing: border-box;
+		margin-bottom: 24rpx;
+		background: #F5F7FAFF;
+		border-radius: 20rpx;
+		display: flex;
+		align-items: center;
+		font-weight: 400;
+		font-size: 40rpx;
+		color: rgba(0, 0, 0, 0.85);
+
+		&-active {
+			color: #FF233CFF !important;
+			background: #FFF0F1FF !important;
+		}
+	}
+
+	.bottomBtnViewClass {
+		width: 100%;
+		height: 160rpx;
+		@include u-flex(row, center, center);
+
+		.btnViewClass {
+			width: 630rpx;
+			height: 96rpx;
+			background: #00000040;
+			border-radius: 48rpx;
+			font-family: PingFangSC, PingFang SC;
+			font-weight: 600;
+			font-size: 40rpx;
+			color: #FFFFFF;
+			line-height: 90rpx;
+			text-align: center;
+
+			&-active {
+				background: linear-gradient(135deg, #FF5267 0%, #FF233C 100%);
+			}
+		}
+	}
+</style>

+ 21 - 31
pages/course/info.vue

@@ -409,10 +409,10 @@
 			:smsNum="data.commentNum" :title="data.commentNum+'条评论'" :type="1" radius="32" maxHeight="1200">
 		</popupBottom>
 
-		<view class="complaintViewClass">
-			<image src="/static/image/my/complaint_icon.png" mode="aspectFill"></image>
-			<view class="complaintViewTextClass">答题</view>
-		</view>
+		<answerFloatBox :typeNum="4" @handleShowAnswer="handleAnswerMethods" />
+
+		<questionsPopup :isShow="isShowQuestions" :typeStatus="1" @closeMethod="questionsCloseMethod"
+			@submitAnswer="handleSubmitAnswer" />
 	</view>
 </template>
 
@@ -447,6 +447,8 @@
 	import popupBottom from '@/components/popupBottom/popupBottom.vue'
 	import MescrollCompMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mixins/mescroll-comp.js";
 	import adMask from "@/components/adMask/adMask.vue"
+	import answerFloatBox from "./components/answerFloatBox.vue"
+	import questionsPopup from "./components/questionsPopup.vue"
 
 	export default {
 		mixins: [MescrollCompMixin],
@@ -455,7 +457,9 @@
 			commentList,
 			newCommentList,
 			hallItem,
-			adMask
+			adMask,
+			answerFloatBox,
+			questionsPopup
 		},
 		data() {
 			return {
@@ -470,6 +474,8 @@
 				isShare: false,
 				videoId: null,
 				isLearning: false,
+				isShowQuestions: false,
+				inputContent: '',
 				newCommentList: [{
 						avatar: "",
 						content: "讲的真好,循序渐进,让小白也很容易能入门学习!让小白也很容易能入门学习让小白也很容易能入门学习让小白也很容易能入门学习让小白也很容易能入门学习让小白也很容易能入门学习",
@@ -747,6 +753,16 @@
 			uni.$off("refreshCatalog");
 		},
 		methods: {
+			// 点击答题
+			handleAnswerMethods() {
+				this.isShowQuestions = true
+			},
+			// 点击关闭答题弹窗
+			questionsCloseMethod() {
+				this.isShowQuestions = false
+			},
+			// 点击提交答案后
+			handleSubmitAnswer() {},
 			sendCommentMsg() {},
 			endCountsTime() {
 				if (this.timer) {
@@ -3279,30 +3295,4 @@
 			}
 		}
 	}
-
-	.complaintViewClass {
-		@include u-flex(column, center, center);
-		position: fixed;
-		right: 34rpx;
-		bottom: 400rpx;
-
-		image {
-			width: 132rpx;
-			height: 112rpx;
-		}
-
-		.complaintViewTextClass {
-			@include u-flex(row, center, center);
-			width: 152rpx;
-			height: 52rpx;
-			background: linear-gradient(135deg, #FF5B6E 1.51%, #FC1D37 100%);
-			border-radius: 26rpx;
-			font-family: DOUYINSANSBOLD, DOUYINSANSBOLD;
-			font-weight: normal;
-			font-size: 30rpx;
-			color: #FFFFFF;
-			margin-top: -13rpx;
-			z-index: 10;
-		}
-	}
 </style>

BIN
static/image/hall/ques_icon.png