626 lines
14 KiB
Vue
626 lines
14 KiB
Vue
<template>
|
|
<view class="max_page" @click="hideKeyboradNow">
|
|
<nav-bar :is_seat="false" :backgroundColor="bgOpacity"></nav-bar>
|
|
<scroll-view :scroll-y="true" class="scroll detail-main" @scroll="scroll_fun" @scrolltolower="scrolltolower"
|
|
:show-scrollbar="false">
|
|
<view class="bg_div">
|
|
<image-preview class="img_100" :imgId="form.imgId" mode="widthFix"></image-preview>
|
|
</view>
|
|
<view class="back_div" @click="common.navigateBack()">
|
|
<view class="back-icon"></view>
|
|
</view>
|
|
<view class="detail-body">
|
|
<view class="head-title font_pf">
|
|
<view class="title-text">
|
|
{{ form.crsName }}
|
|
</view>
|
|
<view class="title-num">
|
|
<view class="num-item">
|
|
<image class="title-icon" src="/src/static/images/courseDetail/zhishidian.png" mode="widthFix"></image>
|
|
<view class="text-1">当前进度</view>
|
|
</view>
|
|
<view class="line-progress-div">
|
|
<text class="text-2">(<text
|
|
class="text-1">{{ form.styParaGraphNum || 0 }}</text>/{{ form.pgrphNum || 0 }})</text>
|
|
<view class="progress-div">
|
|
<view class="progress-line"></view>
|
|
</view>
|
|
</view>
|
|
<view class="num-item examination" @click="common.navigateTo(`/pages/examRanking/index?crsId=${crsId}`)">
|
|
<image class="ranking-icon" src="/src/static/images/courseDetail/charts.png" mode="aspectFill"></image>
|
|
<view>考试排行榜</view>
|
|
<view class="back-icon"></view>
|
|
</view>
|
|
|
|
<view class="num-item" @click="collect_click(form.collectId)">
|
|
<image class="collect-icon" :src="form.collectId ? collectedImg : notCollectedImg" mode="widthFix">
|
|
</image>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="body-box">
|
|
<uv-sticky :customNavHeight="statusBarHeight" class="sticky">
|
|
<view class="body-tab">
|
|
<uv-tabs class="font_pf my_tabs" :current="tabAct" :list="tabList" @change="tabSwitch" :scrollable="false"
|
|
line-color="#0066FF" :inactive-style="{ color: '#333333', fontSize: '30rpx', fontWeight: '500' }"
|
|
:activeStyle="{ color: '#0066FF', fontSize: '30rpx', fontWeight: '600' }"
|
|
:lineColor="`url(${LineBg}) 10% 10%`"></uv-tabs>
|
|
</view>
|
|
</uv-sticky>
|
|
<view class="course-info" v-if="tabAct === 0">
|
|
<introduceVue v-model="form"></introduceVue>
|
|
</view>
|
|
<view class="point" v-if="tabAct === 1">
|
|
<knowledge v-model="form" @toStudyPrgh="toStudyPrgh"></knowledge>
|
|
</view>
|
|
<view class="evaluate" v-if="tabAct === 2 && form">
|
|
<comment ref="commentRef" :crsId="crsId" :imgId="form.imgId" @replayInput="replayInput"></comment>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
<view class="btn-box btn-box-height font_pf" v-if="[0, 1].includes(tabAct)">
|
|
<view class="fl1">
|
|
<uv-button type="primary" @click="goto_study()">去学习</uv-button>
|
|
</view>
|
|
<view class="fl1" @click="goto_practice()">
|
|
<uv-button type="success" :disabled="practiceButtonDisabled">去练习</uv-button>
|
|
</view>
|
|
<view class="fl1" @click="goto_examination()">
|
|
<uv-button type="success" :disabled="examinationButtonDisabled">去考试</uv-button>
|
|
<!-- <uv-button type="success" :disabled="true">去考试</uv-button> -->
|
|
</view>
|
|
<!-- <template v-if="tabAct === 2"> -->
|
|
<!-- <view class="fl1" @click="goto_submit()"> -->
|
|
|
|
<!-- <uv-button type="primary" class="send_evaluate" :disabled="isPreview === 'preview'">发布评价</uv-button> -->
|
|
<!-- </view> -->
|
|
<!-- </template> -->
|
|
</view>
|
|
<comment-input v-if="tabAct === 2" ref="commentInputRef" :crsId="crsId" @sendReply="sendReply"></comment-input>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import {
|
|
LineBg
|
|
} from '@/enum.js';
|
|
import {
|
|
ref,
|
|
computed,
|
|
onMounted
|
|
} from 'vue';
|
|
import {
|
|
onShow,
|
|
onLoad,
|
|
onUnload
|
|
} from '@dcloudio/uni-app';
|
|
import {
|
|
getCourseDetailApi
|
|
} from '@/api/courseDetail.js';
|
|
import {
|
|
startExamByCrs
|
|
} from '@/api/examination.js';
|
|
import {
|
|
insertTraPersonalCollectionTask,
|
|
deleteTraPersonalCollectionById
|
|
} from '@/api/favorites.js';
|
|
import {
|
|
startPracticeByCrs
|
|
} from '@/api/practice.js';
|
|
import common from '@/common/common';
|
|
import {
|
|
setPageCache
|
|
} from '@/common/common';
|
|
import introduceVue from './components/introduce.vue';
|
|
import knowledge from './components/knowledge.vue';
|
|
import comment from './components/comment.vue';
|
|
import collectedImg from '@/static/images/courseDetail/out_collect.png';
|
|
import notCollectedImg from '@/static/images/courseDetail/in_collect.png';
|
|
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight;
|
|
// tab栏
|
|
const tabList = ref([{
|
|
name: '课程介绍'
|
|
}, {
|
|
name: '知识点'
|
|
}, {
|
|
name: '评价'
|
|
}]);
|
|
const commentRef = ref(null);
|
|
const commentInputRef = ref(null)
|
|
const form = ref({});
|
|
const crsId = ref('');
|
|
const collectId = ref(''); // 记录初始的收藏id
|
|
const isPreview = ref(''); // 记录是否是预览
|
|
const tabAct = ref(0);
|
|
const scrollTop = ref(0);
|
|
const practiceButtonDisabled = computed(() => isPreview.value === 'preview' || form.value.examStat === '01');
|
|
const examinationButtonDisabled = computed(() => isPreview.value === 'preview' || form.value.examStat !== '00');
|
|
const progress = computed(() => {
|
|
// 计算进度百分比(保留两位小数)
|
|
const total = form.value.pgrphNum;
|
|
if (total === 0) return '0%';
|
|
const completed = form.value.styParaGraphNum;
|
|
return Math.min(Math.round((completed / total) * 10000) / 100, 100) + '%';
|
|
});
|
|
const tabSwitch = (item) => {
|
|
tabAct.value = item.index;
|
|
};
|
|
// 上拉加载
|
|
const scrolltolower = (item) => {
|
|
if (tabAct.value == 2) {
|
|
commentRef.value?.getData();
|
|
}
|
|
};
|
|
const isShowing = ref(false)
|
|
const replayInput = (data) => {
|
|
isShowing.value = true
|
|
commentInputRef.value.resetVal(data, true)
|
|
setTimeout(() => {
|
|
isShowing.value = false
|
|
}, 800)
|
|
}
|
|
const sendReply = (data) => {
|
|
console.log(data,'111111111111')
|
|
commentRef.value?.setReplyData(data, ()=>{
|
|
commentInputRef.value.hideAll(true)
|
|
});
|
|
}
|
|
const hideKeyboradNow = () => {
|
|
if (isShowing.value) return
|
|
commentInputRef.value.hideAll()
|
|
}
|
|
const getData = async () => {
|
|
common.loading();
|
|
try {
|
|
const {
|
|
body
|
|
} = await getCourseDetailApi({
|
|
crsId: crsId.value
|
|
});
|
|
form.value = body;
|
|
} catch (e) {}
|
|
common.hideLoading();
|
|
};
|
|
const toStudyPrgh = (info) => {
|
|
common.navigateTo(
|
|
'/pages/course/study?crsId=' +
|
|
crsId.value +
|
|
'&pgrphId=' +
|
|
info.pgrphId +
|
|
'&imgId=' +
|
|
form.imgId +
|
|
'&isPreview=' +
|
|
isPreview.value
|
|
);
|
|
};
|
|
|
|
const bgOpacity = computed(() => {
|
|
if (scrollTop.value <= 20) return `rgba(255,255,255,0)`;
|
|
const opacity = Math.min(1, (scrollTop.value - 20) / 80);
|
|
return `rgba(255,255,255,${opacity})`;
|
|
});
|
|
|
|
const scroll_fun = (e) => {
|
|
scrollTop.value = e.detail.scrollTop;
|
|
};
|
|
|
|
// 去评论
|
|
const goto_submit = async () => {
|
|
if (isPreview.value === 'preview') return common.msg('预览课程不可以评价。');
|
|
common.navigateTo('/pages/courseDetail/submit?crsId=' + crsId.value + '&imgId=' + form.value.imgId);
|
|
};
|
|
// 去考试
|
|
const goto_examination = async () => {
|
|
if (isPreview.value === 'preview') return common.msg('预览课程不允许考试');
|
|
if (form.value.examStat === '01') return common.msg('该课程下暂无试题');
|
|
if (form.value.examStat === '02') return common.msg('该课程下的试题未设置考试规则');
|
|
common.loading();
|
|
startExamByCrs({
|
|
crsId: crsId.value
|
|
})
|
|
.then((res) => {
|
|
setPageCache('examination', {
|
|
...res.body,
|
|
name: form.value.crsName,
|
|
crsId: crsId.value
|
|
});
|
|
common.navigateTo('/pages/examination/index');
|
|
})
|
|
.finally(() => {
|
|
common.hideLoading();
|
|
});
|
|
};
|
|
// 去学习
|
|
const goto_study = async () => {
|
|
common.navigateTo(
|
|
'/pages/course/study?crsId=' + crsId.value + '&isPreview=' + isPreview.value + '&imgId=' + form.value.imgId
|
|
);
|
|
};
|
|
// 去练习
|
|
const goto_practice = async () => {
|
|
if (isPreview.value === 'preview') return common.msg('预览课程不允许练习');
|
|
if (form.value.examStat === '01') return common.msg('该课程下暂无试题');
|
|
common.loading();
|
|
startPracticeByCrs({
|
|
crsId: crsId.value
|
|
})
|
|
.then((res) => {
|
|
console.log('res', res);
|
|
setPageCache('practice', {
|
|
...res.body,
|
|
name: form.value.crsName,
|
|
crsId: crsId.value
|
|
});
|
|
common.navigateTo('/pages/practice/index?examStat=' + form.value.examStat);
|
|
})
|
|
.finally(() => {
|
|
common.hideLoading();
|
|
});
|
|
};
|
|
const collect_click = async (id) => {
|
|
try {
|
|
if (!id) {
|
|
common.loading('收藏中');
|
|
insertTraPersonalCollectionTask({
|
|
collectTyp: '01',
|
|
collectBusId: crsId.value
|
|
})
|
|
.then((result) => {
|
|
form.value.collectId = result.body;
|
|
common.msg('收藏成功');
|
|
})
|
|
.catch(() => {
|
|
common.hideLoading();
|
|
});
|
|
} else {
|
|
common.loading('取消收藏中');
|
|
deleteTraPersonalCollectionById({
|
|
collectId: id
|
|
})
|
|
.then(() => {
|
|
form.value.collectId = null;
|
|
common.msg('取消成功');
|
|
})
|
|
.catch(() => {
|
|
common.hideLoading();
|
|
});
|
|
}
|
|
} catch (e) {
|
|
common.hideLoading();
|
|
}
|
|
};
|
|
onMounted(async () => {
|
|
// 监听评论列表更新
|
|
uni.$on('refresh_comment_data', () => {
|
|
commentRef.value?.getData('submit');
|
|
tabAct.value = 2;
|
|
});
|
|
});
|
|
onLoad((params) => {
|
|
crsId.value = params.crsId;
|
|
collectId.value = params.collectId || null;
|
|
isPreview.value = params.isPreview || '';
|
|
tabAct.value = Number(params.tabAct || 0)
|
|
});
|
|
onShow(() => {
|
|
getData();
|
|
});
|
|
onUnload(() => {
|
|
uni.$off('refresh_comment_data');
|
|
// 如果收藏变了,并且上一页是收藏页,更新收藏列表
|
|
if (form.value.collectId !== collectId.value) {
|
|
const pages = getCurrentPages();
|
|
if (pages.length >= 2) {
|
|
const prevPage = pages[pages.length - 2];
|
|
if (prevPage.route === 'pages/favorites/index') {
|
|
// if (prevPage.$vm && typeof prevPage.$vm.$?.exposed?.reload === 'function') {
|
|
// prevPage.$vm.$?.exposed?.reload('course', form.value);
|
|
// }
|
|
uni.$emit('update_course_item', form.value);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.my_tabs {
|
|
|
|
// 解决这个圆角的图片,开穿透
|
|
:deep(.uv-tabs__wrapper__nav__line) {
|
|
height: 20rpx !important;
|
|
left: 60rpx;
|
|
background-size: 26rpx !important;
|
|
background-repeat: no-repeat !important;
|
|
}
|
|
}
|
|
|
|
// 1124新改样式 ↓ ↓ ↓ ↓ ↓ ↓
|
|
.btn-box {
|
|
:deep(.uv-button--disabled) {
|
|
background-color: #ededed;
|
|
color: #999999;
|
|
opacity: 1;
|
|
border-color: #ededed;
|
|
}
|
|
|
|
:deep(.uv-button--success:not(.uv-button--disabled)) {
|
|
background-color: #dcedff;
|
|
color: #0066ff;
|
|
border-color: #dcedff;
|
|
}
|
|
}
|
|
|
|
// 1124新改样式 ↑↑↑↑↑
|
|
.back_div {
|
|
margin-right: 10rpx;
|
|
position: fixed;
|
|
left: 25rpx;
|
|
top: var(--status-bar-height);
|
|
// background-color: red;
|
|
// width: 60rpx;
|
|
// height: 60rpx;
|
|
padding: 20rpx;
|
|
|
|
.back-icon {
|
|
position: relative;
|
|
width: 40rpx;
|
|
height: 40rpx;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.back-icon::before,
|
|
.back-icon::after {
|
|
content: '';
|
|
position: absolute;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.back-icon::after {
|
|
top: 25%;
|
|
left: 25%;
|
|
width: 40%;
|
|
height: 40%;
|
|
border-top: 4rpx solid #ffffff;
|
|
border-left: 4rpx solid #ffffff;
|
|
transform: rotate(-45deg);
|
|
}
|
|
}
|
|
|
|
.detail-main {
|
|
background-color: #f5f5f5;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.scroll {
|
|
height: 100vh;
|
|
}
|
|
|
|
.detail-body {
|
|
position: absolute;
|
|
top: 256rpx;
|
|
border-radius: 23rpx 23rpx 0rpx 0rpx;
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.body-head {
|
|
height: 460rpx;
|
|
background-color: red;
|
|
}
|
|
|
|
.bg_div {
|
|
position: fixed;
|
|
width: calc(100% + 4rpx);
|
|
left: -4rpx;
|
|
|
|
.back-image {
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
.head-title {
|
|
border-radius: 24rpx 24rpx 0rpx 0rpx;
|
|
// height: 162rpx;
|
|
background-color: #ffffff;
|
|
// display: flex;
|
|
// flex-direction: column;
|
|
padding-top: 36rpx;
|
|
padding-left: 42rpx;
|
|
padding-bottom: 24rpx;
|
|
|
|
// overflow: hidden;
|
|
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.title-text {
|
|
font-size: 34rpx;
|
|
color: #333333;
|
|
font-weight: 600;
|
|
margin-bottom: 20rpx;
|
|
min-height: 36rpx;
|
|
}
|
|
|
|
.title-icon {
|
|
height: 30rpx;
|
|
width: 30rpx;
|
|
margin-right: 10rpx;
|
|
}
|
|
|
|
.ranking-icon {
|
|
height: 40rpx;
|
|
width: 40rpx;
|
|
margin-right: 6rpx;
|
|
}
|
|
|
|
.collect-icon {
|
|
width: 40rpx;
|
|
height: 40rpx;
|
|
margin-right: 10rpx;
|
|
}
|
|
|
|
.title-num {
|
|
display: flex;
|
|
flex-wrap: nowrap;
|
|
align-items: center;
|
|
|
|
.examination {
|
|
color: #0066ff;
|
|
margin: 0 14rpx;
|
|
|
|
.back-icon {
|
|
position: relative;
|
|
width: 40rpx;
|
|
height: 40rpx;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.back-icon::before,
|
|
.back-icon::after {
|
|
content: '';
|
|
position: absolute;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.back-icon::after {
|
|
top: 25%;
|
|
left: 25%;
|
|
width: 40%;
|
|
height: 40%;
|
|
border-top: 4rpx solid #0066ff;
|
|
border-left: 4rpx solid #0066ff;
|
|
transform: rotate(135deg);
|
|
}
|
|
}
|
|
}
|
|
|
|
.body-box {
|
|
background-color: #f5f5f5;
|
|
flex: 1;
|
|
padding-left: 16rpx;
|
|
padding-right: 16rpx;
|
|
padding-top: 20rpx;
|
|
padding-bottom: 245rpx;
|
|
}
|
|
|
|
.body-tab {
|
|
background-color: #ffffff;
|
|
border-radius: 22rpx;
|
|
height: 92rpx;
|
|
padding-bottom: 22rpx;
|
|
margin-bottom: 24rpx;
|
|
}
|
|
|
|
.course-info,
|
|
.point,
|
|
.evaluate {
|
|
min-height: calc(100vh - 92rpx - 22rpx - 245rpx - var(--status-bar-height));
|
|
}
|
|
|
|
.btn-box-height {
|
|
height: 187rpx;
|
|
}
|
|
|
|
.btn-box {
|
|
position: fixed;
|
|
bottom: 0;
|
|
width: 100%;
|
|
display: flex;
|
|
padding-top: 37rpx;
|
|
justify-content: space-around;
|
|
background-color: #ffffff;
|
|
border: 2rpx solid #e5e5e5;
|
|
z-index: 1000;
|
|
|
|
:deep(.uv-button-wrapper) {
|
|
flex: 1;
|
|
|
|
&.send_evaluate {
|
|
margin: 0 60rpx;
|
|
}
|
|
|
|
&:not(.send_evaluate) {
|
|
margin: 0 30rpx;
|
|
}
|
|
|
|
.uv-button {
|
|
border-radius: 14rpx;
|
|
width: 100%;
|
|
height: 92rpx;
|
|
}
|
|
}
|
|
}
|
|
|
|
.num-item {
|
|
display: flex;
|
|
align-items: center;
|
|
font-size: 30rpx;
|
|
height: 30rpx;
|
|
|
|
}
|
|
|
|
.line-progress-div {
|
|
display: flex;
|
|
align-items: center;
|
|
flex: 1;
|
|
margin-right: 20rpx;
|
|
|
|
.text-1 {
|
|
color: #333333;
|
|
font-size: 30rpx;
|
|
}
|
|
|
|
.text-2 {
|
|
color: #999999;
|
|
font-size: 30rpx;
|
|
margin: 0 8rpx;
|
|
}
|
|
|
|
.progress-div {
|
|
position: relative;
|
|
background-color: #D9DEE8;
|
|
width: 100%;
|
|
height: 16rpx;
|
|
border-radius: 10rpx;
|
|
overflow: hidden;
|
|
|
|
.progress-line {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
background-color: #0066FF;
|
|
// width: 100%;
|
|
width: v-bind(progress);
|
|
height: 100%;
|
|
border-radius: 10rpx;
|
|
}
|
|
}
|
|
}
|
|
|
|
.learn {
|
|
color: #1dd17a;
|
|
}
|
|
|
|
.unlearn {
|
|
color: #666666;
|
|
}
|
|
|
|
.c-000 {
|
|
font-weight: 600;
|
|
color: #000000;
|
|
}
|
|
|
|
.c-000 {
|
|
font-weight: 600;
|
|
color: #000000;
|
|
}
|
|
|
|
.c-0066FF {
|
|
color: #0066ff;
|
|
}
|
|
</style> |