Files
tra-app/src/pages/learningTasks/details.vue
T
2025-09-04 09:41:33 +08:00

638 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="main_div max_page">
<view class="my-nav-bar"></view>
<view class="body-title">
<view class="back_div" @click="common.navigateBack()">
<view class="back-icon"></view>
</view>
<view>任务详情</view>
</view>
<view class="detail_div">
<view class="left">
<image-preview class="img" :src="detailData.ossAddr" mode="scaleToFill"></image-preview>
</view>
<view class="right">
<view class="title_div">
<view class="title">
{{ detailData.taskName }}
</view>
</view>
<view class="time">
<text class="color_3">起止时间</text>
<text class="color_class">
{{ detailData.startTm?.substr(0, 10) }}{{ detailData.endTm?.substr(0, 10) }}
</text>
<view class="fl1"></view>
<view class="num-item" @click="collect_click(detailData.collectionId)">
<image
v-if="detailData.collectionId"
class="collect-icon"
src="@/static/images/courseDetail/out_collect.png"
mode="widthFix"
></image>
<image
v-else
class="collect-icon"
src="@/static/images/courseDetail/in_collect.png"
mode="widthFix"
></image>
</view>
</view>
<view class="num_div">
<view class="num_div_item">
<text class="color_3">完成人数</text>
<text class="color_2">{{ detailData.taskFinishSums ?? 0 }}/{{ detailData.taskSums ?? 0 }}</text>
</view>
<view class="num_div_item">
<text class="color_3">进度</text>
<text class="color_2">{{ detailData.finishCrs ?? 0 }}/{{ detailData.sumCrs ?? 0 }}门课程</text>
</view>
</view>
</view>
</view>
<view class="scroll-div">
<view class="paper_title_div">
<image src="@/static/images/testingHall/testing.png" class="img" mode="aspectFit"></image>
<view class="title">任务历程</view>
</view>
<scroll-view
ref="scrollRef"
:scroll-y="true"
class="scroll-Y"
:show-scrollbar="false"
@scrolltolower="scrolltolower"
>
<view class="item" v-for="item in data_list" @click="item_click(item)" :class="getStatusClass(item.status)">
<view class="progress_div">
<view class="circle_div"></view>
<view class="line_div"></view>
<view class="plug"></view>
</view>
<view class="content_div">
<view class="status_div">
<text v-if="item.status === '01'">进行中</text>
<text v-if="item.status === '02'">已完成</text>
<text v-if="item.status === '03'">未解锁</text>
</view>
<view class="main_body_div">
<view class="title">
{{ item.crsName }}
</view>
<view class="button_div">
<template
v-if="item.isFinishStudy === '01' && item.isFinishExam === '01' && item.status !== '02'"
>
<image class="img" :src="lockIcon('#999999')"></image>
<view class="button_text error">暂无通过条件可自动解锁</view>
</template>
<template
v-if="item.isFinishStudy === '01' && item.isFinishExam === '01' && item.status === '02'"
>
<image class="img" :src="lockIcon('#0066FF')"></image>
<view class="button_text success">已自动解锁</view>
</template>
<template v-if="item.isFinishStudy !== '01'">
<image
class="img"
:src="passTheExamIcon(item.isFinishStudy === '02' ? '#0066FF' : '#999999')"
></image>
<view class="button_text" :class="item.isFinishStudy === '02' ? 'success' : 'error'">
完成学习
</view>
</template>
<template v-if="item.isFinishExam !== '01'">
<image
class="img"
:src="completeTheExercisesIcon(item.isFinishExam === '02' ? '#0066FF' : '#999999')"
></image>
<view class="button_text" :class="item.isFinishExam === '02' ? 'success' : 'error'">
通过考试
</view>
</template>
</view>
</view>
</view>
</view>
<list-no-data v-if="total === 0 && status === 'nomore'">暂无数据</list-no-data>
<uv-load-more
v-if="status === 'loading'"
:status="status"
loadmore-text="轻轻上拉加载"
:height="30"
></uv-load-more>
</scroll-view>
</view>
</view>
</template>
<script setup>
import { onLoad, onUnload } from '@dcloudio/uni-app';
import { ref, reactive, computed, nextTick } from 'vue';
import { queryAllTraTaskCrsInfo, queryTraTaskInfoByTaskId } from '@/api/learningTasks.js';
import { passTheExamIcon, completeTheExercisesIcon, lockIcon } from '@/common/imgSvg';
import { insertTraPersonalCollectionTask, deleteTraPersonalCollectionById } from '@/api/favorites.js';
import common from '@/common/common';
import { setPageCache, getPageCache } from '@/common/common';
const collectId = ref(''); // 记录初始的收藏id
const detailData = reactive({
taskId: '',
taskName: '',
collectionId: '',
taskFinishSums: '',
taskSums: '',
finishCrs: '',
sumCrs: ''
});
const total = ref(-1);
const status = ref('loading'); // loadmore - 加载前,loading - 加载中,nomore - 没有数据
const data_list = reactive([]);
const getStatusClass = (isFinish) => {
// 00进行中、01已完成、02已超时
if (isFinish === '01') return 'unfinished';
if (isFinish === '02') return 'completed';
return 'not_unlocked';
};
const getData = () => {
status.value = 'loading';
queryAllTraTaskCrsInfo({
taskId: detailData.taskId
})
.then((res) => {
data_list.length = 0
data_list.push(...res.body);
})
.finally(() => {
total.value = data_list.length;
if (total.value === 0) {
status.value = 'nomore';
} else {
status.value = 'loadmore';
}
});
};
const scrolltolower = () => {};
const item_click = (item) => {
if (item.status === '03') {
common.msg('任务未解锁');
return;
}
common.navigateTo('/pages/courseDetail/index?crsId=' + item.crsId);
};
const collect_click = async (id) => {
try {
if (!id) {
common.loading('收藏中');
const res = await insertTraPersonalCollectionTask({
collectTyp: '02',
collectBusId: detailData.taskId
});
detailData.collectionId = res.body;
common.msg('收藏成功');
} else {
common.loading('取消收藏中');
await deleteTraPersonalCollectionById({
collectId: id
});
detailData.collectionId = null;
common.msg('取消成功');
}
} catch (e) {
common.hideLoading();
}
};
onLoad((e) => {
collectId.value = e.collectId || '';
const learning_tasks_details = getPageCache('learning_tasks_details');
Object.assign(detailData, {
...learning_tasks_details
});
getData();
const updateFun = () => {
console.log('详情监听里面学习完成后更新任务历程');
queryTraTaskInfoByTaskId({taskId:detailData.taskId}).then(({body}) => {
uni.$emit('refresh_favorites_data', body)
Object.assign(detailData, {
...body
});
})
getData();
}
// 监听里面学习完成后更新任务历程,执行更新函数
uni.$on('refresh_course_list', () => updateFun())
// 监听考试完成事件,执行更新函数
uni.$on('exam_completed', () => updateFun())
});
onUnload(() => {
uni.$off('refresh_course_list');
uni.$off('exam_completed');
// 如果收藏变了,并且上一页是收藏页,更新收藏列表
if (detailData.collectionId !== collectId.value) {
const pages = getCurrentPages();
if (pages.length >= 2) {
const prevPage = pages[pages.length - 2];
if (prevPage.route === 'pages/favorites/index') {
uni.$emit('refresh_favorites_list', {
type: 'task',
state: !!detailData.collectionId, // 最终是收藏了还是取消了
old: collectId.value, // 进入时候的收藏id
new: detailData.collectionId // 新的收藏id
});
}
}
}
});
</script>
<style scoped lang="scss">
$bg-margin-left: 30rpx;
.scroll-Y .item {
margin: 0 $bg-margin-left 0 $bg-margin-left;
display: flex;
justify-content: space-between;
// 已完成
&.completed {
.circle_div {
border: 4rpx solid #bdc7e6;
background-color: #bdc7e6;
}
.line_div {
border-left: 4rpx solid #e1e8f0;
}
.status_div {
color: #adb4c3;
background-color: #f3f5f5;
}
.plug {
border-top: 4rpx solid #e1e8f0;
}
}
//未完成
&.unfinished {
.circle_div {
border: 4rpx solid #0066ff;
// background-color: #bdc7e6;
}
.line_div {
border-left: 4rpx solid #0066ff;
}
.status_div {
color: #ffffff;
background-color: #4c93ff;
}
.plug {
border-top: 4rpx solid #0066ff;
}
}
// 未解锁
&.not_unlocked {
.circle_div {
border: 4rpx solid #adb4c3;
}
.line_div {
border-left: 4rpx dashed #adb4c3;
}
.status_div {
color: #6c9ce4;
background-color: #eff6ff;
}
.plug {
border-top: 4rpx solid #adb4c3;
}
}
// 最后一项
&:last-child .plug {
width: 80%;
height: 40rpx;
margin-top: -6rpx;
}
.progress_div {
width: 30rpx;
display: flex;
align-items: center;
flex-direction: column;
.circle_div {
width: 20rpx;
height: 20rpx;
border-radius: 50%;
overflow: hidden;
box-sizing: border-box;
}
.line_div {
height: calc(100% - 20rpx);
width: 4rpx;
margin: 6rpx 0;
}
}
.content_div {
flex: 1;
display: flex;
min-height: 140rpx;
background-color: #fff;
margin-bottom: 34rpx;
padding: 4rpx 4rpx 4rpx 4rpx;
// background-color: red;
border-radius: 16rpx;
overflow: hidden;
.status_div {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 30rpx;
writing-mode: vertical-rl;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
padding: 4rpx 4rpx;
}
.main_body_div {
margin-left: 34rpx;
flex: 1;
display: flex;
flex-direction: column;
padding-right: 10rpx;
.title {
// background-color: red;
margin-top: 10rpx;
min-height: 30rpx;
flex: 1;
font-weight: 500;
font-size: 30rpx;
color: #333333;
line-height: 40rpx;
text-align: left;
font-style: normal;
}
.button_div {
// background-color: red;
height: 60rpx;
display: flex;
align-items: center;
flex-wrap: nowrap;
.img {
width: 30rpx;
height: 30rpx;
}
.button_text {
font-weight: 400;
font-size: 24rpx;
text-align: left;
margin-right: 50rpx;
&.success {
color: #0066ff;
}
&.error {
color: #999999;
}
}
}
}
}
}
.paper_title_div {
display: flex;
align-items: center;
margin: 20rpx 0 20rpx $bg-margin-left;
height: 42rpx;
.img {
width: 32rpx;
height: 28rpx;
}
.title {
font-weight: 600;
font-family: PingFangTC;
font-weight: 600;
font-size: 30rpx;
color: #333333;
font-style: normal;
margin-left: 12rpx;
}
}
.scroll-div {
background: linear-gradient(180deg, #ebf2fe 0%, #f3f7fe 6%, #f9fbff 12%, #f4f6f8 100%);
// background: linear-gradient(180deg, #ebf2fe 0%, #f3f7fe 6%, #fafbfc 12%, #fafbfc 100%);
border-radius: 16rpx;
margin-top: -20rpx;
z-index: 2;
box-shadow: 0 0 10rpx #f9fbff;
border: 2rpx solid #f9f9fa;
margin: 0 auto;
width: calc(100% - 52rpx);
}
.scroll-Y {
position: relative;
overflow: hidden;
height: calc(100vh - var(--status-bar-height) - 120rpx - 250rpx + 20rpx + 20rpx - 20rpx - 42rpx - 50rpx);
}
.main_div {
background-image: url('@/static/images/learningTasks/learningTasksBg.png');
background-repeat: no-repeat;
background-size: 100% calc(420rpx + var(--status-bar-height)); /* 宽度充满,高度自适应比例 */
background-position: top;
background-color: #fff;
}
.my-nav-bar {
width: 100%;
height: calc(var(--status-bar-height) - 10rpx);
}
.body-title {
width: 100%;
position: relative;
text-align: center;
height: 120rpx;
line-height: 60rpx;
font-family: PingFangSC;
font-weight: 600;
font-size: 32rpx;
color: #000000;
font-style: normal;
}
.detail_div {
margin-top: -20rpx;
height: 250rpx;
z-index: 2;
width: 100%;
padding: 36rpx 26rpx 20rpx 26rpx;
background-color: #ffffff;
border-radius: 16rpx 16rpx 0 0;
position: relative;
overflow: hidden;
display: flex;
.subscript {
position: absolute;
top: 0;
right: 0;
width: 102rpx;
height: 42rpx;
font-family: PingFangSC;
font-weight: 400;
font-size: 24rpx;
line-height: 42rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 0 0 0 28rpx;
}
.left > .img {
width: 225rpx;
height: 169rpx;
border-radius: 16rpx;
overflow: hidden;
}
.right {
overflow: hidden;
margin-left: 24rpx;
width: 100%;
.title_div {
display: flex;
justify-content: space-between;
flex: 1;
.title {
font-family: PingFangSC;
font-weight: 600;
color: #000000;
text-align: left;
font-style: normal;
font-size: 28rpx; /* 字体大小30rpx */
display: -webkit-box; /* 启用弹性盒模型 */
-webkit-box-orient: vertical; /* 设置盒子内子元素的排列方向为垂直 */
-webkit-line-clamp: 2; /* 限制最多显示2行 */
overflow: hidden; /* 超出部分隐藏 */
text-overflow: ellipsis; /* 超出部分显示省略号(多行时可能不显示,但建议保留) */
line-height: 1.5; /* 可选:设置行高,优化多行显示效果 */
}
}
.time {
font-size: 22rpx;
color: #999999;
line-height: 30rpx;
font-family: Arial;
font-weight: 400;
color: #666666;
height: 54rpx;
display: flex;
align-items: center;
.num-item {
display: flex;
align-items: center;
font-size: 30rpx;
color: #666666;
.collect-icon {
width: 36rpx;
height: 36rpx;
}
}
}
.num_div {
font-family: PingFangSC;
font-weight: 400;
font-size: 22rpx;
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: nowrap;
overflow: hidden;
height: 28rpx;
.num_div_item {
display: flex;
flex-wrap: nowrap;
line-height: 28rpx;
height: 28rpx;
}
}
.color_1 {
color: #d70c18;
}
.color_2 {
color: #111111;
}
.color_3 {
color: #666666;
}
}
}
.incomplete {
// 进行中
.subscript {
color: #ffffff;
background-color: #ef5705;
}
.color_class {
color: #d70c18;
}
}
.completed {
// 已完成
.subscript {
color: #ffffff;
background-color: #33c583;
}
.color_class {
color: #0066ff;
}
}
.back_div {
position: absolute;
left: 26rpx;
height: 100%;
top: -30rpx;
display: flex;
align-items: center;
.back-icon {
position: relative;
width: 50rpx;
height: 50rpx;
cursor: pointer;
display: flex;
align-items: center;
}
.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 #000000;
border-left: 4rpx solid #000000;
transform: rotate(-45deg);
}
}
</style>