437 lines
11 KiB
Vue
437 lines
11 KiB
Vue
<template>
|
||
<view class="noise-bg">
|
||
<view class="is-bg"></view>
|
||
<view class="div-max">
|
||
<z-paging
|
||
ref="pagingRef"
|
||
@query="queryList"
|
||
v-model="data_list"
|
||
:loading-more-enabled="false"
|
||
:refresher-only="true"
|
||
:aoto="false"
|
||
>
|
||
<template #top>
|
||
<view class="body-title">
|
||
<view class="back_div" @click="common.navigateBack()">
|
||
<view class="back-icon"></view>
|
||
</view>
|
||
<view>任务详情</view>
|
||
</view>
|
||
</template>
|
||
<view class="interior">
|
||
<!-- 详情盒子 -->
|
||
<view class="details-div">
|
||
<view class="img-div">
|
||
<image-preview class="img_100" :src="detailData.ossAddr"></image-preview>
|
||
</view>
|
||
<view class="right-div">
|
||
<view class="title-div">{{ detailData.taskName }}</view>
|
||
<view class="other-div-1">
|
||
<!-- 时间盒子 -->
|
||
<view class="time-div">
|
||
起止时间:{{ detailData.startTm?.substr(0, 10) }}至{{ detailData.endTm?.substr(0, 10) }}
|
||
</view>
|
||
<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="other-div-2">
|
||
<!-- 完成人数盒子 -->
|
||
<view class="progress-text-div">
|
||
<text class="color_3">
|
||
完成人数
|
||
<text class="maoh">:</text>
|
||
</text>
|
||
<text class="color_2">
|
||
{{ detailData.taskFinishSums ?? 0 }}/{{ detailData.taskSums ?? 0 }}
|
||
</text>
|
||
</view>
|
||
<!-- 进度条 -->
|
||
<view class="line-progress-div">
|
||
<view class="progress-div">
|
||
<view class="progress-line"></view>
|
||
</view>
|
||
<view class="progress-text">{{progress}}</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 步骤 -->
|
||
<view class="step-list-div">
|
||
<detailsItem v-for="(item, index) in data_list" :item="item" :index="index" @item_click="item_click"></detailsItem>
|
||
</view>
|
||
</z-paging>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { onLoad, onUnload, onShow } from '@dcloudio/uni-app';
|
||
import { ref, reactive, computed, nextTick, onMounted } from 'vue';
|
||
import { queryAllTraTaskCrsInfo, queryTraTaskInfoByTaskId } from '@/api/learningTasks.js';
|
||
import { passTheExamIcon, completeTheExercisesIcon, lockIcon } from '@/common/imgSvg';
|
||
import { insertTraPersonalCollectionTask, deleteTraPersonalCollectionById } from '@/api/favorites.js';
|
||
import detailsItem from './components/details-item';
|
||
import common from '@/common/common';
|
||
import { getPageCache } from '@/common/common';
|
||
|
||
const status = ref('loading'); // loadmore - 加载前,loading - 加载中,nomore - 没有数据
|
||
const pagingRef = ref(null);
|
||
const data_list = ref([]);
|
||
const total = ref(-1);
|
||
const taskId = ref('');
|
||
// const progress = computed(() => '30%');
|
||
const progress = computed(() => {
|
||
// 计算进度百分比(保留两位小数)
|
||
const total = detailData.sumCrs ?? detailData.taskNumber ?? 0;
|
||
if (total === 0) return '0%';
|
||
const completed = detailData.finishCrs ?? detailData.learnedNumber ?? 0;
|
||
return Math.min(Math.round((completed / total) * 10000) / 100, 100) + '%';
|
||
});
|
||
const queryList = async (pageNo, pageSize, from) => {
|
||
const requests = [queryAllTraTaskCrsInfo({ taskId: taskId.value })];
|
||
// 如果不是第一次请求,才添加第二个请求
|
||
if (total.value === -1 && detailData.taskName !== '') {
|
||
status.value = 'loading';
|
||
} else {
|
||
requests.push(queryTraTaskInfoByTaskId({ taskId: taskId.value }));
|
||
}
|
||
Promise.all(requests)
|
||
.then((res) => {
|
||
if (res.length === 2) {
|
||
const TaskDetailsData = res[1].body;
|
||
// 需要比较的属性列表
|
||
const compareKeys = [
|
||
'taskId',
|
||
'taskName',
|
||
'collectionId',
|
||
'taskFinishSums',
|
||
'taskSums',
|
||
'finishCrs',
|
||
'sumCrs',
|
||
'isFinish'
|
||
];
|
||
// 检查是否需要更新
|
||
const needUpdate = compareKeys.some((key) => {
|
||
return detailData[key] !== TaskDetailsData[key];
|
||
});
|
||
console.log('检查是否需要更新', needUpdate);
|
||
if (needUpdate) {
|
||
Object.assign(detailData, {
|
||
...TaskDetailsData
|
||
});
|
||
uni.$emit('update_tasks_item', detailData);
|
||
}
|
||
}
|
||
const list = res[0].body;
|
||
pagingRef.value.complete(list);
|
||
total.value = list.length;
|
||
if (total.value === 0) {
|
||
status.value = 'nomore';
|
||
} else {
|
||
status.value = 'loadmore';
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
pagingRef.value?.complete(false);
|
||
total.value = data_list.value.length;
|
||
if (total.value === 0) {
|
||
status.value = 'nomore';
|
||
} else {
|
||
status.value = 'loadmore';
|
||
}
|
||
})
|
||
.finally(() => {});
|
||
};
|
||
const collectId = ref(''); // 记录初始的收藏id
|
||
const detailData = reactive({
|
||
taskId: '',
|
||
taskName: '',
|
||
collectionId: '',
|
||
taskFinishSums: '',
|
||
taskSums: '',
|
||
finishCrs: '',
|
||
isFinish: '',
|
||
sumCrs: ''
|
||
});
|
||
|
||
const getStatusClass = (isFinish) => {
|
||
// 00进行中、01已完成、02已超时
|
||
if (isFinish === '01') return 'unfinished';
|
||
if (isFinish === '02') return 'completed';
|
||
return 'not_unlocked';
|
||
};
|
||
|
||
const item_click = (item) => {
|
||
if (item.status === '03') {
|
||
common.msg('任务未解锁');
|
||
return;
|
||
}
|
||
common.navigateTo('/pages/courseDetail/index?crsId=' + item.crsId);
|
||
};
|
||
|
||
const collect_click = async (id) => {
|
||
const loadingText = id ? '取消收藏中' : '收藏中';
|
||
try {
|
||
common.loading(loadingText);
|
||
if (!id) {
|
||
// 收藏操作
|
||
const res = await insertTraPersonalCollectionTask({
|
||
collectTyp: '02',
|
||
collectBusId: detailData.taskId
|
||
});
|
||
detailData.collectionId = res.body;
|
||
common.msg('收藏成功');
|
||
} else {
|
||
// 取消收藏操作
|
||
await deleteTraPersonalCollectionById({
|
||
collectId: id
|
||
});
|
||
detailData.collectionId = null;
|
||
common.msg('取消成功');
|
||
}
|
||
} catch (error) {
|
||
// 错误提示可以更具体
|
||
common.msg(id ? '取消收藏失败' : '收藏失败');
|
||
console.error('收藏操作失败:', error);
|
||
} finally {
|
||
// 无论成功失败,最终都关闭加载提示
|
||
// common.hideLoading();
|
||
}
|
||
};
|
||
|
||
onMounted(() => {
|
||
pagingRef.value.reload();
|
||
});
|
||
onShow(() => {});
|
||
onLoad((e) => {
|
||
taskId.value = e.taskId;
|
||
const learning_tasks_details = getPageCache('learning_tasks_details');
|
||
Object.assign(detailData, {
|
||
...learning_tasks_details
|
||
});
|
||
collectId.value = learning_tasks_details.collectionId || null;
|
||
const updateFun = () => {
|
||
setTimeout(() => {
|
||
console.log('监听考试获取结果事件,执行更新函数');
|
||
pagingRef.value?.reload();
|
||
}, 1000);
|
||
};
|
||
// 监听里面学习完成后更新任务历程,执行更新函数
|
||
uni.$on('refresh_course_list', () => updateFun());
|
||
// 监听考试获取结果事件,执行更新函数
|
||
uni.$on('get_result_completed', () => updateFun());
|
||
});
|
||
|
||
onUnload(() => {
|
||
uni.$off('refresh_course_list');
|
||
uni.$off('get_result_completed');
|
||
// 如果收藏变了,并且上一页是收藏页,更新收藏列表
|
||
console.log('detailData.collectionId', detailData.collectionId);
|
||
console.log('collectId', collectId.value);
|
||
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('update_tasks_item', detailData);
|
||
} else if (prevPage.route === 'pages/learningTasks/index') {
|
||
// 学习任务页跳入,更新外部列表否则下次列表数据还是老的
|
||
console.log('学习任务页跳入,更新外部列表否则下次列表数据还是老的(作废)');
|
||
// uni.$emit('update_tasks_item', detailData);
|
||
}
|
||
}
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
// 步骤
|
||
.step-list-div {
|
||
margin: 50rpx 0;
|
||
}
|
||
// 详情
|
||
.details-div {
|
||
display: flex;
|
||
margin: 50rpx auto 30rpx auto;
|
||
width: calc(100% - 60rpx);
|
||
.img-div {
|
||
width: 224rpx;
|
||
height: 126rpx;
|
||
border-radius: 18rpx;
|
||
overflow: hidden;
|
||
}
|
||
.right-div {
|
||
flex: 1;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
margin-left: 24rpx;
|
||
|
||
.title-div {
|
||
font-family: PingFangSC, PingFang SC;
|
||
font-weight: 500;
|
||
font-size: 30rpx;
|
||
color: #ffffff;
|
||
line-height: 43rpx;
|
||
text-align: left;
|
||
font-style: normal;
|
||
max-height: 86rpx;
|
||
}
|
||
.other-div-1 {
|
||
margin-top: 6rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
.time-div {
|
||
font-weight: 400;
|
||
font-size: 22rpx;
|
||
color: #f2f5fa;
|
||
line-height: 33rpx;
|
||
font-family: Arial, Helvetica, sans-serif;
|
||
}
|
||
.num-item {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 30rpx;
|
||
color: #666666;
|
||
|
||
.collect-icon {
|
||
width: 36rpx;
|
||
height: 36rpx;
|
||
}
|
||
}
|
||
}
|
||
.other-div-2 {
|
||
width: 100%;
|
||
margin-top: 6rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
.progress-text-div {
|
||
font-weight: 400;
|
||
font-size: 22rpx;
|
||
color: #f2f5fa;
|
||
line-height: 33rpx;
|
||
text-align: left;
|
||
font-style: normal;
|
||
}
|
||
|
||
.line-progress-div {
|
||
margin-left: 20rpx;
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
.progress-div {
|
||
position: relative;
|
||
background-color: rgba(255, 255, 255, 0.5);
|
||
width: 100%;
|
||
height: 16rpx;
|
||
border-radius: 10rpx;
|
||
overflow: hidden;
|
||
.progress-line {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
border-radius: 10rpx;
|
||
background-color: #ffffff;
|
||
width: v-bind(progress);
|
||
height: 100%;
|
||
}
|
||
}
|
||
.progress-text {
|
||
color: #ffffff;
|
||
font-size: 22rpx;
|
||
margin-left: 10rpx;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.div-max {
|
||
width: 100vw;
|
||
height: 100vh;
|
||
z-index: 10;
|
||
opacity: 1;
|
||
// background-color: red;
|
||
}
|
||
.interior {
|
||
z-index: 1;
|
||
}
|
||
|
||
.noise-bg {
|
||
width: 100vw;
|
||
height: 100vh;
|
||
position: relative;
|
||
overflow: hidden;
|
||
background: linear-gradient(358deg, #1848a1 0%, #3772e1 100%);
|
||
// opacity: .4;
|
||
}
|
||
|
||
.is-bg {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
/* 噪点图配置 */
|
||
background-image: url('@/static/images/learningTasks/bg.png');
|
||
background-repeat: repeat;
|
||
background-size: 200px; /* 控制噪点大小,可按需改 */
|
||
/* 核心:模糊噪点(1px=轻微,2px=中度,3px=更糊) */
|
||
// filter: blur(1px);
|
||
opacity: 0.3;
|
||
/* 混合模式:让噪点和渐变自然融合(multiply/overlay二选一) */
|
||
background-blend-mode: multiply;
|
||
/* 不影响容器内元素点击 */
|
||
pointer-events: none;
|
||
/* 确保噪点在内容之下,渐变之上 */
|
||
z-index: 0;
|
||
}
|
||
.body-title {
|
||
width: 100%;
|
||
position: relative;
|
||
padding-top: var(--status-bar-height);
|
||
font-weight: 500;
|
||
font-size: 38rpx;
|
||
color: #ffffff;
|
||
text-align: center;
|
||
margin: 34rpx 0;
|
||
}
|
||
.back_div {
|
||
position: absolute;
|
||
left: 26rpx;
|
||
.back-icon {
|
||
position: relative;
|
||
width: 50rpx;
|
||
height: 50rpx;
|
||
}
|
||
.back-icon::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: 25%;
|
||
left: 25%;
|
||
width: 40%;
|
||
height: 40%;
|
||
border-top: 4rpx solid #ffffff;
|
||
border-left: 4rpx solid #ffffff;
|
||
transform: rotate(-45deg);
|
||
}
|
||
}
|
||
</style>
|