This commit is contained in:
Pengxiansen
2025-02-17 10:31:26 +08:00
parent 1904d07014
commit f83820965d
30 changed files with 822 additions and 540 deletions

View File

@@ -10,6 +10,7 @@ export const PROJECT = 1;
export const ROUTER = 2; export const ROUTER = 2;
export const COURSE = 3; export const COURSE = 3;
export const GROWTH = 4 export const GROWTH = 4
export const TASK_TYPES = { export const TASK_TYPES = {
typeName: { typeName: {
1: "在线", 1: "在线",
@@ -41,6 +42,7 @@ export const TASK_TYPES = {
12: "去投票", 12: "去投票",
13: "去完成", 13: "去完成",
}, },
path: { path: {
1: ({ courseId }) => window.open(window.location.protocol + import.meta.env.VITE_BOE_ONLINE_CLASS_URL + courseId), //在线 1: ({ courseId }) => window.open(window.location.protocol + import.meta.env.VITE_BOE_ONLINE_CLASS_URL + courseId), //在线
2: ({ targetId }) => window.open(`${location.protocol}//${location.host}${import.meta.env.VITE_BASE_API}/stu/project/redirectDetail?courseId=${targetId}`, '_top'), 2: ({ targetId }) => window.open(`${location.protocol}//${location.host}${import.meta.env.VITE_BASE_API}/stu/project/redirectDetail?courseId=${targetId}`, '_top'),
@@ -56,4 +58,6 @@ export const TASK_TYPES = {
12: "/ballotpage", 12: "/ballotpage",
13: "/projectdetails", 13: "/projectdetails",
}, },
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 996 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 678 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1003 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -9,6 +9,7 @@
import { createStore } from 'vuex' import { createStore } from 'vuex'
import { PROJECT_PROCESS, ROUTER_PROCESS,PROFESSIONAL_STUDENT_DETAIL } from "@/api/api"; import { PROJECT_PROCESS, ROUTER_PROCESS,PROFESSIONAL_STUDENT_DETAIL } from "@/api/api";
import { request } from "@/api/request"; import { request } from "@/api/request";
import { growthRequest } from "@/api/growthRequest";
import { TASK_TYPES } from "@/api/CONST"; import { TASK_TYPES } from "@/api/CONST";
export default createStore({ export default createStore({

View File

@@ -1,217 +1,139 @@
<template> <template>
<div class="growth-details"> <div class="growth-details">
<ReturnHead text="专业力必修" :gohome="true"></ReturnHead> <div class="navbar">
<div class="main"> <div class="nav-left">
<div class="tabs"> <el-icon color="#fff" size="20"><ArrowLeft /></el-icon>
<div
class="tabs-item"
:class="queryParams.type == 1 ? 'active' : ''"
@click="tabClick(1)"
>
<div class="tabs-text">必修</div>
<div class="tabs-line"></div>
</div>
<div
class="tabs-item"
:class="queryParams.type == 2 ? 'active' : ''"
@click="tabClick(2)"
>
<div class="tabs-text">选修</div>
<div class="tabs-line"></div>
</div>
</div> </div>
<div class="search"> <div class="nav-title">专业力必修</div>
<div class="search-input"> </div>
<el-input <div class="tabs">
v-model="queryParams.taskName" <div
border-radius: class="tabs-item"
:input-style="{ :class="queryParams.type == 1 ? 'active' : ''"
width: '100%', @click="tabClick(1)"
height: '34px', >
}" <div class="tabs-text">必修</div>
@change="getList" <div class="tabs-line"></div>
style="width: 240px" </div>
placeholder="搜索关键字" <div
class="tabs-item"
:class="queryParams.type == 2 ? 'active' : ''"
@click="tabClick(2)"
>
<div class="tabs-text">选修</div>
<div class="tabs-line"></div>
</div>
</div>
<div class="search">
<div class="search-input">
<el-input
v-model="queryParams.taskName"
:input-style="{
width: '100%',
height: '40px',
color: '#fff',
}"
@change="getList"
placeholder="搜索关键字"
>
<template #prefix>
<el-icon color="#fff" class="el-input__icon"><search /></el-icon>
</template>
</el-input>
</div>
<el-dropdown>
<img class="icon" src="@/assets/image/growth/qiehuan.png" />
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="tabClick(null, '0')"
>未开始</el-dropdown-item
>
<el-dropdown-item @click="tabClick(null, '1')"
>已完成</el-dropdown-item
>
<el-dropdown-item @click="tabClick(null, '2')"
>进行中</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
<!-- <img class="icon" src="@/assets/image/growth/list.png" /> -->
<img class="icon" @click="toPath" src="@/assets/image/growth/path.png" />
</div>
<div
class="container"
v-loading="loading"
:style="stageProcessList.length ? '' : 'height:400px'"
>
<div
@click="toFinish(item)"
:id="item.id"
v-for="(item, key) in stageProcessList"
:key="key"
class="task-item"
>
<div class="task-img">
<img
style="width: 100%; height: 100%"
:src="getAssetsFile(item.courseType)"
/> />
</div> </div>
<el-dropdown> <div>
<el-icon color="#00000" :size="24"> <div style="display: flex; align-items: center">
<Filter /> <div class="task-type">
</el-icon> {{ TASK_TYPES.typeName[item.courseType] }}
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="tabClick(null, 0)"
>未开始</el-dropdown-item
>
<el-dropdown-item @click="tabClick(null, 1)"
>已完成</el-dropdown-item
>
<el-dropdown-item @click="tabClick(null, 2)"
>进行中</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<div
class="down"
v-loading="loading"
:style="stageProcessList.length ? '' : 'height:400px'"
>
<template v-if="stageProcessList && stageProcessList.length">
<div
class="project_second"
v-for="(item, key) in stageProcessList"
:key="key"
>
<div
style="
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
"
>
<div class="secondcontent">
<div class="question">
<div style="width: calc(100% - 80px)">
<div class="issue" :title="item.taskName">
{{ TASK_TYPES.typeName[item.courseType] || "" }}
{{ item.taskName }}
</div>
<div v-if="item.courseType === '1'" class="progressBox">
<!-- <div>当前进度</div> -->
<div
class="progress"
style="
display: flex;
align-items: center;
margin-bottom: 3px;
"
>
<div style="width: 200px">
<el-progress
:percentage="item.progress"
:show-text="false"
:stroke-width="8"
:color="
{
0: 'rgba(238, 112, 108, 1)',
1: 'rgba(255, 151, 38, 1)',
2: 'rgba(39, 122, 255, 1)',
3: 'rgba(59, 94, 251, 1)',
4: 'rgba(57, 219, 183, 1)',
5: 'rgba(57, 219, 183, 1)',
}[item.progress / 20]
"
/>
</div>
<div
style="
font-size: 12px;
font-weight: 500;
color: #277aff;
margin-left: 10px;
"
:style="{
color: {
0: 'rgba(238, 112, 108, 1)',
1: 'rgba(255, 151, 38, 1)',
2: 'rgba(39, 122, 255, 1)',
3: 'rgba(59, 94, 251, 1)',
4: 'rgba(57, 219, 183, 1)',
5: 'rgba(57, 219, 183, 1)',
}[item.progress / 20],
}"
>
{{ item.progress }}%
</div>
</div>
</div>
<!-- <div class="coursetag">
<div
class="tag3"
style="margin-right: 11px; margin-top: 3px"
>
{{ TASK_TYPES.typeName[item.courseType] || "" }}
</div>
</div> -->
</div>
<el-dropdown trigger="click">
<template v-if="item.completionStatus === '0'">
<div
class="goclass"
@click="toFinish(item)"
style="background: #2478ff"
>
{{ TASK_TYPES.toName[item.courseType] }}
</div>
</template>
<template v-if="item.completionStatus === '1'">
<div
class="goclass"
@click="toFinish(item)"
style="background: #2478ff"
>
已完成
</div>
</template>
<template v-if="item.completionStatus === '2'">
<div
class="goclass"
@click="toFinish(item)"
style="background: #2478ff"
>
进行中
</div>
</template>
<template v-if="item.lastStudy">
<div
class="goclass"
@click="toFinish(item)"
style="background: #999"
>
继续学习
</div>
</template>
<template v-if="item.completionStatus === '10'">
<div
class="goclass"
@click="toFinish(item)"
style="background: #999"
>
未解锁
</div>
</template>
<!-- <template #dropdown v-if="el.type===2 && el.targetId?.split(',')?.length > 1">
<el-dropdown-menu>
<el-dropdown-item v-for="(name,key) in el.targetName?.split(',')" :key="key" @click="toOffcoursePlanPage(el.targetId?.split(',')[key])">{{ name }}</el-dropdown-item>
</el-dropdown-menu>
</template> -->
</el-dropdown>
</div>
</div>
</div> </div>
<div class="task-name">{{ item.taskName }}</div>
</div> </div>
</template> <div
<template v-else> class="task-state"
<el-empty description="暂无数据" /> :style="{
</template> color:
item.completionStatus === '0'
? '#C4C2C2'
: item.completionStatus === '1'
? '#0077EC'
: '#FF8726',
}"
>
{{
item.completionStatus === "0"
? "未开始"
: item.completionStatus === "1"
? "已完成"
: "进行中"
}}
</div>
<div style="display: flex; align-items: center">
<div style="flex: 1">
<el-progress
:percentage="item.progress"
:show-text="false"
:stroke-width="3"
:color="
item.completionStatus === '0'
? '#C4C2C2'
: item.completionStatus === '1'
? '#0077EC'
: '#FF8726'
"
/>
</div>
<div class="progress-text">{{ item.progress }}%</div>
</div>
</div>
</div> </div>
<template v-if="stageProcessList && stageProcessList.length"> </template>
<template v-else>
<el-empty description="暂无数据" />
</template>
</div> </div>
<!-- 开课列表弹框 --> <!-- 开课列表弹框 -->
<el-dialog <el-dialog
top="120px" top="120px"
title="开课列表" title="开课列表"
v-model="openCourseVisible" v-model="openCourseVisible"
style=" style="min-height: 320px; padding: 0; border-radius: 4px"
min-height: 320px;
padding: 0;
border-radius: 4px;
"
width="80%" width="80%"
> >
<div style="width: 100%; min-height: 210px; margin-top: 12px"> <div style="width: 100%; min-height: 210px; margin-top: 12px">
@@ -314,6 +236,8 @@ watch(data, () => {
}); });
// 学习任务列表 // 学习任务列表
const stageProcessList = ref([]); const stageProcessList = ref([]);
// 锚点跳转的次数
const anchorNum = ref(0);
onMounted(() => { onMounted(() => {
dispatch("getGrowthInfo", { routerId, type }); dispatch("getGrowthInfo", { routerId, type });
getList(); getList();
@@ -330,6 +254,16 @@ const getList = () => {
console.log(res); console.log(res);
stageProcessList.value = res.data; stageProcessList.value = res.data;
loading.value = false; loading.value = false;
if (anchorNum.value === 0) {
let find = stageProcessList.value.find((item) => item.lastStudy);
if (find) {
// var aLink = document.createElement("a");
// aLink.href = `#${find.id}`; // 设置链接地址
// aLink.click();
// document.body.removeChild(aLink);
}
}
}); });
}; };
const openCourseVisible = ref(false); const openCourseVisible = ref(false);
@@ -544,7 +478,7 @@ async function toFinish(d) {
pName: data.value.growthName, pName: data.value.growthName,
sName: d.taskName, sName: d.taskName,
chapterOrStageId: 0, chapterOrStageId: 0,
// id: d.id, // id: d.id,
// type: PROJECT, // type: PROJECT,
// infoId: data.value.projectId, // infoId: data.value.projectId,
@@ -578,6 +512,9 @@ async function toFinish(d) {
} }
} }
} }
const getAssetsFile = (url) => {
return new URL(`../../assets/image/growth/type${url}.png`, import.meta.url).href
}
function toOffcoursePlanPage(id) { function toOffcoursePlanPage(id) {
window.open( window.open(
`${location.protocol}//${location.host}${ `${location.protocol}//${location.host}${
@@ -586,177 +523,155 @@ function toOffcoursePlanPage(id) {
"_top" "_top"
); );
} }
const toPath = () => {
router.push({
path: "/growthPath",
query: {
routerId,
},
});
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.growth-details { .growth-details {
padding: 0 15px 0 10px; background-image: url(@/assets/image/growth/bg.png);
background-size: 100%;
background-repeat: no-repeat;
height: 100vh; height: 100vh;
box-sizing: border-box; box-sizing: border-box;
background-color: #ffffff; background-color: #ffffff;
position: relative;
.container {
position: absolute;
background-color: #ffffff;
top: 165px;
left: 0;
right: 0;
border-radius: 15px 15px 0 0;
padding: 5px 15px;
.task-item {
display: flex;
padding: 20px 0;
border-bottom: 1px solid #f5f5f5;
.progress-text {
font-weight: bold;
font-size: 15px;
color: #333333;
margin-left: 9px;
}
.task-img {
width: 110px;
height: 70px;
margin-right: 11px;
border-radius: 4px;
overflow: hidden;
}
.task-state {
font-size: 13px;
margin-top: 11px;
margin-bottom: 13px;
}
.task-name {
font-size: 14px;
color: #000000;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 200px;
}
.task-type {
background-image: url(@/assets/image/growth/task-type.png);
width: 41px;
height: 17px;
background-size: 100% 100%;
font-weight: 400;
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
color: #ffffff;
margin-right: 5px;
}
}
}
.search {
display: flex;
align-items: center;
padding: 0 15px;
.search-input {
flex: 1;
}
.icon {
width: 18px;
height: 18px;
margin-left: 8px;
}
:deep(.el-input__wrapper) {
box-shadow: none;
padding-left: 18px;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 20px;
}
:deep(.el-input__inner) {
background-color: rgba(255, 255, 255, 0);
padding-left: 0;
}
}
.navbar {
position: relative;
display: flex;
justify-content: center;
align-items: center;
height: 44px;
.nav-title {
font-weight: 500;
font-size: 18px;
color: #ffffff;
}
.nav-left {
position: absolute;
left: 10px;
top: calc(50% - 10px);
}
}
.el-dialog__body { .el-dialog__body {
width: 80%; width: 80%;
} }
:deep(.el-dialog__body){ :deep(.el-dialog__body) {
padding-top: 0px; padding-top: 0px;
} }
.el-dialog__header { .el-dialog__header {
display: none; display: none;
} }
width: 100%;
.tabs { .tabs {
padding: 12px 0 9px 0; padding: 12px 0 14px 0;
background-color: #ffffff;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
.tabs-item { .tabs-item {
width: 135px; color: #ffffff;
margin: 0 33px;
display: flex; display: flex;
align-items: center; align-items: center;
flex-direction: column; flex-direction: column;
font-size: 18px; font-size: 15px;
opacity: 0.7;
font-weight: 700; font-weight: 700;
} }
.tabs-line { .tabs-line {
width: 135px; width: 39px;
height: 1px; height: 3px;
margin-top: 2px; margin-top: 6px;
} }
.active { .active {
color: #2478ff; font-size: 17px;
font-weight: 700;
opacity: 1;
.tabs-line { .tabs-line {
background-color: #61a4f9; background: #ffffff;
} border-radius: 2px;
}
}
.main {
width: 100%;
display: flex;
flex-direction: column;
//justify-content: center;
.up {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
//justify-content: center;
background-color: rgba(255, 255, 255, 1);
.content {
width: 90%;
display: flex;
flex-direction: column;
.title {
margin-top: 15.5px;
font-size: 14px;
font-weight: 700;
line-height: 21.6px;
color: rgba(4, 36, 60, 1);
}
.text2 {
display: flex;
margin-top: 10px;
margin-bottom: 22.5px;
font-size: 13px;
color: rgba(51, 51, 48, 1);
line-height: 24px;
text-overflow: ellipsis;
overflow: hidden;
}
}
}
.search {
display: flex;
align-items: center;
.search-input {
flex: 1;
}
:deep(.el-input__wrapper) {
box-shadow: none;
padding-left: 0;
}
:deep(.el-input__inner) {
padding-left: 40px;
background-color: #eee;
border-radius: 10px;
}
}
.down {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
//justify-content: center;
background-color: rgba(255, 255, 255, 1);
.project_title {
width: calc(100% - 36.5px);
display: flex;
font-size: 16px;
font-weight: 500;
line-height: 12px;
color: rgba(13, 35, 58, 1);
padding: 17px 0 17px 36.5px;
border-bottom: 0.5px solid rgba(241, 242, 243, 1);
}
.project_second {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 10.5px;
.secondcontent {
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
margin-top: 10px;
.question {
width: 100%;
display: flex;
padding-left: 6px;
box-sizing: border-box;
position: relative;
height: 72px;
border-bottom: 0.5px solid rgba(241, 242, 243, 1);
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
.issue {
width: 100%;
font-size: 13px;
line-height: 30.29px;
color: rgba(110, 123, 132, 1);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.coursetag {
display: flex;
flex-wrap: wrap;
}
.goclass {
width: 63px;
height: 23px;
background: #2478ff;
// box-shadow: 0px 1px 8px 0px rgba(56, 125, 247, 0.7);
border-radius: 4px;
font-size: 14px;
font-weight: 800;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
// margin-right: 37px;
cursor: pointer;
}
}
}
} }
} }
} }

View File

@@ -1,128 +1,169 @@
<template> <template>
<div class="growth-path"> <div class="growth-details">
<div class="nav"> <div class="navbar">
<ReturnHead text="专业力必修" :gohome="true"></ReturnHead> <div class="nav-left">
<div class="tabs"> <el-icon color="#fff" size="20"><ArrowLeft /></el-icon>
<div </div>
class="tabs-item" <div class="nav-title">专业力必修</div>
:class="queryParams.type == 1 ? 'active' : ''" </div>
@click="tabClick(1)" <div class="tabs">
> <div
<div class="tabs-text">必修</div> class="tabs-item"
<div class="tabs-line"></div> :class="queryParams.type == 1 ? 'active' : ''"
</div> @click="tabClick(1)"
<div >
class="tabs-item" <div class="tabs-text">必修</div>
:class="queryParams.type == 2 ? 'active' : ''" <div class="tabs-line"></div>
@click="tabClick(2)" </div>
> <div
<div class="tabs-text">选修</div> class="tabs-item"
<div class="tabs-line"></div> :class="queryParams.type == 2 ? 'active' : ''"
</div> @click="tabClick(2)"
>
<div class="tabs-text">选修</div>
<div class="tabs-line"></div>
</div> </div>
</div> </div>
<div class="search">
<!-- 占位容器防止塌陷 --> <div class="search-input">
<div class="placeholder"></div> <el-input
v-model="queryParams.taskName"
<div :input-style="{
class="path-container" width: '100%',
v-loading="loading" height: '40px',
:style="stageProcessList.length ? '' : 'height:400px'" color: '#fff',
> }"
<template v-if="stageProcessList && stageProcessList.length"> @change="getList"
<div placeholder="搜索关键字"
class="path-item"
@click="toFinish(item)"
v-for="(item, index) of stageProcessList"
:key="item.id"
> >
<div class="item-content"> <template #prefix>
<div class="icon"> <el-icon color="#fff" class="el-input__icon"><search /></el-icon>
<template v-if="item.lastStudy"> </template>
<img </el-input>
style="width: 100%; height: 100%" </div>
src="@/assets/image/growth/growth-icon4.png" <el-dropdown>
/> <img class="icon" src="@/assets/image/growth/qiehuan.png" />
</template> <template #dropdown>
<template v-else-if="item.completionStatus === '1'"> <el-dropdown-menu>
<img <el-dropdown-item @click="tabClick(null, '0')"
style="width: 100%; height: 100%" >未开始</el-dropdown-item
src="@/assets/image/growth/growth-icon1.png" >
/> <el-dropdown-item @click="tabClick(null, '1')"
</template> >已完成</el-dropdown-item
<template v-else-if="item.completionStatus === '2'"> >
<img <el-dropdown-item @click="tabClick(null, '2')"
style="width: 100%; height: 100%" >进行中</el-dropdown-item
src="@/assets/image/growth/growth-icon2.png" >
/> </el-dropdown-menu>
</template> </template>
<template </el-dropdown>
v-else-if=" <!-- <img class="icon" src="@/assets/image/growth/list.png" /> -->
item.completionStatus === '0' || <img class="icon" @click="toPath" src="@/assets/image/growth/list.png" />
item.completionStatus === '10' </div>
" <div class="container" v-loading="loading">
> <div :style="{ transform: 'scale(' + transformSize + ')' }">
<img <div class="path-container">
style="width: 100%; height: 100%" <div
src="@/assets/image/growth/growth-icon3.png" :class="
/> item.position + 1 < 3 || item.position + 1 == 4 || item.position + 1 == 6
</template> ? 'path-item-left'
</div> : 'path-item-right'
<template v-if="item.completionStatus !== '2'"> "
<div class="item-text"> @click="toFinish(item)"
{{ :style="point[item.position]"
`${item.taskName}${ v-for="(item, index) of stageProcessList"
item.completionStatus === "10" ? "(未解锁)" : "" >
}` <template v-if="item.position + 1 < 3 || item.position + 1 == 4 || item.position + 1 == 6">
}} <div>
<div class="item-name">{{ item.taskName }}</div>
<div class="triangle"></div>
</div>
<div class="f-a-c">
<div class="f-a-c">
<div class="item-progress">
<el-progress
:percentage="parseInt(item.progress)"
:show-text="false"
:stroke-width="6"
:color="stateData(item).progressColor"
/>
</div>
<div
class="item-state"
:style="{
color: stateData(item).color,
background: stateData(item).bgColor,
}"
>
{{ stateData(item).text }}
</div>
</div>
<div class="item-link">
<div
:style="{
width: widthConfig(item.position).width,
marginLeft: widthConfig(item.position).margin,
}"
class="line"
></div>
<div class="circle"></div>
</div>
</div> </div>
</template> </template>
<template v-else> <template v-else>
<div class="item-progress"> <div class="item-link">
<div class="circle"></div>
<div <div
:style="{ :style="{
width: `${item.progress}%`, width: widthConfig(item.position).width,
marginRight: widthConfig(item.position).margin,
}" }"
class="progress-content" class="line"
> ></div>
<div class="rocket"> </div>
<img <div>
style="width: 100%; height: 100%" <div>
src="@/assets/image/growth/rocket.png" <div class="item-name">{{ item.taskName }}</div>
<div class="triangle"></div>
</div>
<div class="f-a-c" style="justify-content: flex-end">
<div class="item-progress">
<el-progress
:percentage="parseInt(item.progress)"
:show-text="false"
:stroke-width="6"
:color="stateData(item).progressColor"
/> />
</div> </div>
<div
class="item-state"
:style="{
color: stateData(item).color,
background: stateData(item).bgColor,
}"
>
{{ stateData(item).text }}
</div>
</div> </div>
<div class="progress-text">{{ item.taskName }}</div>
</div> </div>
</template> </template>
</div> </div>
<template v-if="index != stageProcessList.length - 1">
<div
class="gap"
:style="{
height: item.completionStatus !== '2' ? '48px' : '70px',
}"
>
<!-- 虚线不可删除 -->
<div></div>
</div>
</template>
</div> </div>
</template> </div>
<template v-if="stageProcessList && stageProcessList.length"> </template>
<template v-else> <template v-else>
<el-empty description="暂无数据" /> <el-empty description="暂无数据" />
</template> </template>
</div> </div>
<!-- 开课列表弹框 -->
<el-dialog <el-dialog
top="120px" top="120px"
title="开课列表" title="开课列表"
v-model="openCourseVisible" v-model="openCourseVisible"
style=" style="min-height: 320px; padding: 0; border-radius: 4px"
min-height: 320px;
padding: 0;
border-radius: 4px;
"
width="80%" width="80%"
> >
<div style="width: 100%; min-height: 210px; margin-top: 12px"> <div style="width: 100%; min-height: 210px; margin-top: 12px">
@@ -172,13 +213,10 @@
</template> </template>
<script setup> <script setup>
import ReturnHead from "@/components/ReturnHead.vue"; import { computed, reactive, ref, watch, onMounted } from "vue";
import { computed, reactive, onMounted, onUnmounted, ref } from "vue"; import { ElLoading } from "element-plus";
import { useRoute, useRouter } from "vue-router";
import { useRequest, request } from "@/api/request"; import { useRequest, request } from "@/api/request";
import { growthRequest } from "@/api/growthRequest"; import { growthRequest } from "@/api/growthRequest";
import { GROWTH, TASK_TYPES } from "@/api/CONST";
import { ElMessage } from "element-plus";
import { import {
EvaluationToLearn, EvaluationToLearn,
QueryEvaluationTaskStatusOne, QueryEvaluationTaskStatusOne,
@@ -187,16 +225,21 @@ import {
PROFESSIONAL_STUDENT_TASKLIST, PROFESSIONAL_STUDENT_TASKLIST,
PROFESSIONAL_STUDENT_LEARN, PROFESSIONAL_STUDENT_LEARN,
} from "@/api/api"; } from "@/api/api";
import { useStore } from "vuex"; import { useRoute, useRouter } from "vue-router";
import store from "@/store"; import store from "@/store";
const { commit, dispatch, state } = useStore(); import { ElMessage } from "element-plus";
import ReturnHead from "@/components/ReturnHead.vue";
import { GROWTH, TASK_TYPES } from "@/api/CONST";
import dayjs from "dayjs";
import { useStore } from "vuex";
import { changeTime } from "@/api/method";
const { const {
query: { courseId, routerId, type, infoId, chapterOrStageId, id }, query: { courseId, routerId, type, infoId, chapterOrStageId, id },
} = useRoute(); } = useRoute();
const router = useRouter(); const router = useRouter();
const { commit, dispatch, state } = useStore();
// 专业力必修详情 // 专业力必修详情
const data = computed(() => state.growthInfo); const data = computed(() => state.growthInfo);
const userInfo = computed(() => store.state.userInfo);
// 查询条件 // 查询条件
const queryParams = reactive({ const queryParams = reactive({
type: 1, type: 1,
@@ -213,6 +256,31 @@ const tabClick = (type, status) => {
getList(); getList();
}; };
watch(data, () => {
if (data.value.code === 6) {
router.push({
path: "/notpath",
});
}
});
// 学习任务列表
const stageProcessList = ref([]);
// 锚点跳转的次数
const anchorNum = ref(0);
onMounted(() => {
updateWindowWidth(); // 初始化宽度
window.addEventListener("resize", updateWindowWidth);
dispatch("getGrowthInfo", { routerId, type });
getList();
});
// 储存屏幕宽
const windowWidth = ref(0);
const transformSize = ref(1);
const updateWindowWidth = () => {
windowWidth.value = window.innerWidth;
transformSize.value = windowWidth.value / 414;
};
// 是否加载数据中 // 是否加载数据中
const loading = ref(false); const loading = ref(false);
const getList = () => { const getList = () => {
@@ -221,21 +289,183 @@ const getList = () => {
growthId: routerId, growthId: routerId,
...queryParams, ...queryParams,
}).then((res) => { }).then((res) => {
console.log(res); let newData = res.data.slice(0, 15);
stageProcessList.value = res.data; // 默认第一个在第一点位
let num = 15 / newData.length;
stageProcessList.value = newData.map((item, index) => {
// 默认第一个在第一点位
if (index === 0) {
item.position = 0;
}
item.position = Number((index * num).toFixed());
return item;
});
if (anchorNum.value === 0) {
let find = stageProcessList.value.find((item) => item.lastStudy);
if (find) {
// var aLink = document.createElement("a");
// aLink.href = `#${find.id}`; // 设置链接地址
// aLink.click();
// document.body.removeChild(aLink);
}
}
loading.value = false; loading.value = false;
}); });
}; };
// 学习任务列表
const stageProcessList = ref([]);
onMounted(() => {
dispatch("getGrowthInfo", { routerId, type });
getList();
});
const openCourseVisible = ref(false); const openCourseVisible = ref(false);
const openCourseList = ref([]); const openCourseList = ref([]);
const openCourseIdList = ref([]); const openCourseIdList = ref([]);
const userInfo = computed(() => store.state.userInfo);
const point = [
{
top: "-15px",
right: "57px",
},
{
top: "51px",
right: "106px",
},
{
top: "132px",
right: "-26px",
},
{
top: "124px",
right: "146px",
},
{
top: "207px",
right: "10px",
},
{
top: "204px",
right: "181px",
},
{
top: "288px",
left: "109px",
},
{
top: "356px",
left: "91px",
},
{
top: "435px",
left: "76px",
},
{
top: "503px",
left: "66px",
},
{
top: "580px",
left: "57px",
},
{
top: "649px",
left: "51px",
},
{
top: "720px",
left: "51px",
},
{
top: "790px",
left: "45px",
},
{
top: "860px",
left: "45px",
},
];
// 基础配置项
const widthConfig = computed(() => {
return (index) => {
if (index === 0) {
return {
width: "60px",
margin: "19px",
};
} else if (index === 1) {
return {
width: "60px",
margin: "19px",
};
} else if (index === 2) {
return {
width: "25px",
margin: "0",
};
} else if (index === 3) {
return {
width: "30px",
margin: "0px",
};
} else if (index === 4) {
return {
width: "25px",
margin: "0",
};
} else if (index === 5) {
return {
width: "10px",
margin: "0",
};
} else if (index === 6) {
return {
width: "50px",
margin: "0",
};
} else if (index === 7) {
return {
width: "60px",
margin: "0px",
};
} else {
return {
width: "70px",
margin: "0px",
};
}
};
});
// 基础配置项
const stateData = computed(() => {
return (item) => {
if (item.completionStatus === "10") {
return {
text: "未解锁",
color: "#666666",
bgColor: "rgba(102, 102, 102, 0.2)",
progressColor: "#AEB3B8",
};
} else if (item.completionStatus === "0") {
return {
text: "未开始",
color: "#666666",
bgColor: "rgba(102, 102, 102, 0.2)",
progressColor: "#AEB3B8",
};
} else if (item.completionStatus === "1") {
return {
text: "已完成",
color: "#0077EC",
bgColor: "rgba(0, 119, 236, 0.2)",
progressColor: "#0077EC",
};
} else if (item.completionStatus === "2") {
return {
text: "进行中",
color: "#F2903D",
bgColor: "rgba(242, 144, 61, 0.2)",
progressColor: "#F2903D",
};
}
};
});
async function toFinish(d) { async function toFinish(d) {
if (d.completionStatus == 10) { if (d.completionStatus == 10) {
ElMessage.warning("当前未解锁"); ElMessage.warning("当前未解锁");
@@ -484,104 +714,232 @@ function toOffcoursePlanPage(id) {
"_top" "_top"
); );
} }
const toPath = () => {
router.push({
path: "/growthDetails",
query: {
routerId,
},
});
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.growth-path { .f-a-c {
min-height: 100vh; display: flex;
align-items: center;
}
.growth-details {
background-image: url(@/assets/image/growth/bg.png);
background-size: 100%;
background-repeat: no-repeat;
height: 100vh;
box-sizing: border-box;
background-color: #ffffff; background-color: #ffffff;
position: relative;
:deep(.el-dialog__body){ .container {
padding-top: 0px; position: absolute;
} background-color: #ffffff;
.path-item { background-image: url(@/assets/image/growth/path-bg.png);
.item-content { background-size: 100% 100%;
display: flex; top: 165px;
align-items: center;
.progress-content {
position: relative;
height: 15px;
border-radius: 16px;
height: 15px;
background: linear-gradient(90deg, #fecd49 0%, #e13915 100%);
.rocket {
position: absolute;
width: 36px;
height: 36px;
right: -18px;
top: -11px;
}
}
.item-progress {
position: relative;
height: 15px;
border-radius: 16px;
flex: 1;
background: #ededed;
margin-left: 6px;
.progress-text {
position: absolute;
top: 22px;
}
}
.icon {
width: 20px;
height: 20px;
}
.item-text {
margin-left: 10px;
}
}
.gap {
display: flex;
justify-content: center;
width: 20px;
div {
height: 100%;
border-left: 1px dashed #c5c6ca;
width: 1px;
}
}
}
.path-container {
padding: 28px;
}
.placeholder {
height: 98px;
}
.nav {
position: fixed;
left: 0; left: 0;
right: 0; right: 0;
background-color: #f6f6f6; border-radius: 15px 15px 0 0;
.path-container {
position: relative;
height: 935px;
margin: 53px 45px 31px 63px;
box-sizing: border-box;
background-image: url(@/assets/image/growth/path-arrow.png);
background-size: 100%;
.path-item-left {
position: absolute;
// width: 125px;
.item-link {
display: flex;
align-items: center;
.line {
height: 2px;
background: linear-gradient(-90deg, #ffffff 0%, #0077ec 65%);
border-image: linear-gradient(-90deg, #ffffff, #0077ec) 10 10;
}
.circle {
width: 10px;
height: 10px;
background: #ffffff;
border-radius: 50%;
border: 2px solid #0077ec;
}
}
.item-progress {
width: 71px;
}
.item-state {
width: 48px;
height: 16px;
border-radius: 3px;
text-align: center;
line-height: 16px;
margin-left: 4px;
font-size: 12px;
}
.item-name {
max-width: 125px;
min-width: 40px;
display: inline-block;
background: linear-gradient(268deg, #3c65f5 0%, #4395f9 100%);
border-radius: 4px;
font-size: 12px;
color: #ffffff;
padding: 8px 5px 9px 10px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.triangle {
width: 0px;
height: 0px;
border: 5px solid transparent;
border-top-color: #4391f8;
margin-left: 22px;
}
}
.path-item-right {
position: absolute;
// width: 125px;
display: flex;
.item-link {
height: 28px;
display: flex;
align-items: center;
.line {
height: 2px;
background: linear-gradient(90deg, #ffffff 0%, #0077ec 65%);
border-image: linear-gradient(0deg, #ffffff, #0077ec) 10 10;
}
.circle {
width: 10px;
height: 10px;
background: #ffffff;
border-radius: 50%;
border: 2px solid #0077ec;
}
}
.item-progress {
width: 71px;
}
.item-state {
width: 48px;
height: 16px;
border-radius: 3px;
text-align: center;
line-height: 16px;
margin-left: 4px;
font-size: 12px;
}
.item-name {
max-width: 125px;
min-width: 40px;
display: inline-block;
background: linear-gradient(268deg, #3c65f5 0%, #4395f9 100%);
border-radius: 4px;
font-size: 12px;
color: #ffffff;
padding: 8px 5px 9px 10px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.triangle {
width: 0px;
height: 0px;
border: 5px solid transparent;
border-top-color: #4391f8;
margin-left: 22px;
}
}
}
} }
.tabs { .search {
display: flex;
align-items: center;
padding: 0 15px;
.search-input {
flex: 1;
}
.icon {
width: 18px;
height: 18px;
margin-left: 8px;
}
:deep(.el-input__wrapper) {
box-shadow: none;
padding-left: 18px;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 20px;
}
:deep(.el-input__inner) {
background-color: rgba(255, 255, 255, 0);
padding-left: 0;
}
}
.navbar {
position: relative;
display: flex;
justify-content: center;
align-items: center;
height: 44px; height: 44px;
padding: 12px 0 9px 0; .nav-title {
margin-top: 10px; font-weight: 500;
box-sizing: border-box; font-size: 18px;
background-color: #ffffff; color: #ffffff;
}
.nav-left {
position: absolute;
left: 10px;
top: calc(50% - 10px);
}
}
.el-dialog__body {
width: 80%;
}
:deep(.el-dialog__body) {
padding-top: 0px;
}
.el-dialog__header {
display: none;
}
.tabs {
padding: 12px 0 14px 0;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
.tabs-item { .tabs-item {
width: 135px; color: #ffffff;
margin: 0 33px;
display: flex; display: flex;
align-items: center; align-items: center;
flex-direction: column; flex-direction: column;
font-size: 18px; font-size: 15px;
opacity: 0.7;
font-weight: 700; font-weight: 700;
} }
.tabs-line { .tabs-line {
width: 135px; width: 39px;
height: 1px; height: 3px;
margin-top: 2px; margin-top: 6px;
} }
.active { .active {
color: #2478ff; font-size: 17px;
font-weight: 700;
opacity: 1;
.tabs-line { .tabs-line {
background-color: #61a4f9; background: #ffffff;
border-radius: 2px;
} }
} }
} }

View File

@@ -43,10 +43,14 @@ export default defineConfig(({ command, mode }) =>
server: { server: {
// host: "192.168.3.51", // host: "192.168.3.51",
proxy: { proxy: {
"/professional": { // "/professional": {
// target: 'http://192.168.237.141:32002', // // target: 'http://192.168.237.141:32002',
target: 'http://192.168.150.97:32002', // target: 'http://192.168.150.97:32002',
changeOrigin: true, // changeOrigin: true,
// },
"/growth": {
target: 'https://u-pre.boe.com',
changeOrigin: true,
}, },
"/file/upload": { "/file/upload": {
target: loadEnv(mode, process.cwd()).VITE_PROXY_URL, target: loadEnv(mode, process.cwd()).VITE_PROXY_URL,