This commit is contained in:
Pengxiansen
2025-02-24 11:31:14 +08:00
parent e09c64cbd3
commit b7345838a2
6 changed files with 525 additions and 33 deletions

View File

@@ -0,0 +1,382 @@
<template>
<div
style="transform-origin: top left; width: 1920px; height: 1122px"
class="roadmap"
>
<div class="path-container">
<div
:class="
(!((item.position + 1) % 2) || item.position === 0) &&
item.position !== 1
? 'path-item-top'
: 'path-item-bottom'
"
@click="toFinish(item)"
:style="point[item.position]"
v-for="(item, index) of stageProcessList"
>
<template v-if="item.position + 1 == 1">
<div style="display: flex">
<div>
<div>
<div class="item-name" style="width: 210px">
{{ item.taskName }}
</div>
<div class="triangle"></div>
</div>
<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>
<div class="item-link1" style="display: flex; align-items: center">
<div class="line1"></div>
<div class="circle1"></div>
</div>
</div>
</template>
<template v-else-if="(item.position + 1) % 2 || item.position === 1">
<div class="item-link">
<div class="circle"></div>
<div class="line"></div>
</div>
<div>
<div class="triangle"></div>
<div class="item-name">{{ item.taskName }}</div>
</div>
<div class="f-a-c" style="margin-top: 9px">
<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>
</template>
<template v-else>
<div>
<div class="item-name">{{ item.taskName }}</div>
<div class="triangle"></div>
</div>
<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 class="line"></div>
<div class="circle"></div>
</div>
</template>
</div>
</div>
</div>
</template>
<script setup>
import { computed } from "vue";
const emit = defineEmits("toFinish");
const propas = defineProps({
stageProcessList: Array,
});
const point = [
{
top: "-13px",
right: "258px",
},
{
top: "226px",
right: "128px",
},
{
top: "347px",
right: "341px",
},
{
top: "92px",
right: "455px",
},
{
top: "443px",
right: "561px",
},
{
top: "155px",
right: "673px",
},
{
top: "512px",
right: "780px",
},
{
top: "200px",
right: "893px",
},
{
top: "565px",
right: "1000px",
},
{
top: "232px",
right: "1111px",
},
{
top: "602px",
right: "1220px",
},
{
top: "254px",
right: "1331px",
},
{
top: "630px",
right: "1440px",
},
{
top: "267px",
right: "1551px",
},
{
top: "650px",
right: "1660px",
},
];
const toFinish = (item) => {
emit("toFinish", item);
};
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",
};
} else if (item.completionStatus === "3") {
return {
text: "已结束",
color: "#666666",
bgColor: "rgba(102, 102, 102, 0.2)",
progressColor: "#AEB3B8",
};
}
};
});
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="scss" scoped>
.f-a-c {
display: flex;
align-items: center;
}
.roadmap {
background-image: url(@/assets/image/growth/path-bg.png);
background-size: 100%;
background-repeat: no-repeat;
}
.path-container {
position: relative;
width: 100%;
height: 659px;
margin-top: 53px;
background-image: url(@/assets/image/growth/path.png);
.path-item-bottom {
position: absolute;
width: 210px;
cursor: pointer;
.item-progress {
flex: 1;
}
.item-state {
width: 64px;
height: 24px;
border-radius: 6px;
text-align: center;
line-height: 24px;
margin-left: 5px;
}
.item-name {
display: inline-block;
max-width: 210px;
min-width: 80px;
background: linear-gradient(268deg, #3c65f5 0%, #4395f9 100%);
border-radius: 7px;
font-size: 16px;
color: #ffffff;
padding: 14px 10px 14px 15px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.triangle {
width: 0px;
height: 0px;
border: 7px solid transparent;
border-bottom-color: #4391f8;
margin-left: 32px;
padding-top: 10px;
}
.item-link {
position: relative;
.line {
width: 2px;
height: 138px;
margin-left: 39px;
background: linear-gradient(180deg, #ffffff 0%, #0077ec 65%);
border-image: linear-gradient(180deg, #ffffff, #0077ec) 10 10;
}
.circle {
width: 14px;
height: 14px;
background: #ffffff;
border-radius: 50%;
border: 3px solid #0077ec;
position: absolute;
top: 0;
left: 30px;
}
}
}
.path-item-top {
position: absolute;
width: 210px;
cursor: pointer;
.item-progress {
flex: 1;
}
.item-state {
width: 64px;
height: 24px;
border-radius: 6px;
text-align: center;
line-height: 24px;
margin-left: 5px;
}
.item-name {
max-width: 210px;
min-width: 80px;
display: inline-block;
background: linear-gradient(268deg, #3c65f5 0%, #4395f9 100%);
border-radius: 7px;
font-size: 16px;
color: #ffffff;
padding: 14px 10px 14px 15px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.triangle {
width: 0px;
height: 0px;
border: 7px solid transparent;
border-top-color: #4391f8;
margin-left: 32px;
}
.item-link1 {
margin-top: 14px;
height: 20px;
.line1 {
width: 135px;
height: 2px;
background: linear-gradient(-90deg, #ffffff 0%, #0077ec 65%);
border-image: linear-gradient(-90deg, #ffffff, #0077ec) 10 10;
}
.circle1 {
width: 14px;
height: 14px;
background: #ffffff;
border-radius: 50%;
border: 3px solid #0077ec;
}
}
.item-link {
position: relative;
.line {
margin-left: 39px;
width: 2px;
height: 210px;
background: linear-gradient(0deg, #ffffff 0%, #0077ec 65%);
border-image: linear-gradient(0deg, #ffffff, #0077ec) 10 10;
}
.circle {
width: 14px;
height: 14px;
background: #ffffff;
border-radius: 50%;
border: 3px solid #0077ec;
position: absolute;
bottom: 0;
left: 30px;
}
}
}
}
</style>

View File

@@ -6,18 +6,58 @@
<div class="path-container"> <div class="path-container">
<div <div
:class=" :class="
(item.position + 1) % 2 || item.position + 1 == 15 (!((item.position + 1) % 2) || item.position === 0) &&
? 'path-item-bottom' item.position !== 1
: 'path-item-top' ? 'path-item-top'
: 'path-item-bottom'
" "
@click="toFinish(item)" @click="toFinish(item)"
:style="point[item.position]" :style="point[item.position]"
v-for="(item, index) of stageProcessList" v-for="(item, index) of stageProcessList"
> >
<template v-if="(item.position + 1) % 2 || item.position + 1 == 15"> <template v-if="item.position + 1 == 1">
<div style="display: flex">
<div>
<div>
<div class="item-name" style="width: 210px">
{{ item.taskName }}
</div>
<div class="triangle"></div>
</div>
<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>
<div class="item-link1" style="display: flex; align-items: center">
<div class="line1"></div>
<div class="circle1"></div>
</div>
</div>
</template>
<template v-else-if="(item.position + 1) % 2 || item.position === 1">
<div class="item-link"> <div class="item-link">
<div class="circle"></div> <div class="circle"></div>
<div class="line"></div> <div
class="line"
:style="{ height: point[item.position].height }"
></div>
</div> </div>
<div> <div>
<div class="triangle"></div> <div class="triangle"></div>
@@ -44,6 +84,7 @@
</div> </div>
</div> </div>
</template> </template>
<template v-else> <template v-else>
<div> <div>
<div class="item-name">{{ item.taskName }}</div> <div class="item-name">{{ item.taskName }}</div>
@@ -70,7 +111,10 @@
</div> </div>
</div> </div>
<div class="item-link"> <div class="item-link">
<div class="line"></div> <div
class="line"
:style="{ height: point[item.position].height }"
></div>
<div class="circle"></div> <div class="circle"></div>
</div> </div>
</template> </template>
@@ -80,75 +124,90 @@
</template> </template>
<script setup> <script setup>
import { computed } from "vue"; import { computed } from "vue";
const emit = defineEmits("click"); const emit = defineEmits("toFinish");
const propas = defineProps({ const propas = defineProps({
stageProcessList: Array, stageProcessList: Array,
}); });
const point = [ const point = [
{ {
top: "226px", top: "-13px",
right: "128px", right: "258px",
height: "210px",
}, },
{ {
top: 0, top: "226px",
right: "234px", right: "128px",
height: "210px",
}, },
{ {
top: "347px", top: "347px",
right: "341px", right: "341px",
height: "210px",
}, },
{ {
top: "92px", top: "92px",
right: "455px", right: "455px",
height: "210px",
}, },
{ {
top: "443px", top: "443px",
right: "561px", right: "561px",
height: "210px",
}, },
{ {
top: "155px", top: "218px",
right: "673px", right: "673px",
height: "147px",
}, },
{ {
top: "512px", top: "512px",
right: "780px", right: "780px",
height: "234px",
}, },
{ {
top: "200px", top: "113px",
right: "893px", right: "893px",
height: "295px",
}, },
{ {
top: "565px", top: "565px",
right: "1000px", right: "1000px",
height: "281px",
}, },
{ {
top: "232px", top: "232px",
right: "1111px", right: "1111px",
height: "210px",
}, },
{ {
top: "602px", top: "602px",
right: "1220px", right: "1220px",
height: "135px",
}, },
{ {
top: "254px", top: "125px",
right: "1331px", right: "1331px",
height: "334px",
}, },
{ {
top: "630px", top: "630px",
right: "1440px", right: "1440px",
height: "226px",
}, },
{ {
top: "267px", top: "267px",
right: "1551px", right: "1551px",
height: "210px",
}, },
{ {
top: "650px", top: "650px",
right: "1660px", right: "1660px",
height: "90px",
}, },
]; ];
const toFinish = (item) => { const toFinish = (item) => {
emit("click", item); emit("toFinish", item);
}; };
const stateData = computed(() => { const stateData = computed(() => {
return (item) => { return (item) => {
@@ -180,6 +239,13 @@ const stateData = computed(() => {
bgColor: "rgba(242, 144, 61, 0.2)", bgColor: "rgba(242, 144, 61, 0.2)",
progressColor: "#F2903D", progressColor: "#F2903D",
}; };
} else if (item.completionStatus === "3") {
return {
text: "已结束",
color: "#666666",
bgColor: "rgba(102, 102, 102, 0.2)",
progressColor: "#AEB3B8",
};
} }
}; };
}); });
@@ -237,11 +303,11 @@ const stateData = computed(() => {
margin-left: 32px; margin-left: 32px;
padding-top: 10px; padding-top: 10px;
} }
.item-link { .item-link {
position: relative; position: relative;
.line { .line {
width: 2px; width: 2px;
height: 138px;
margin-left: 39px; margin-left: 39px;
background: linear-gradient(180deg, #ffffff 0%, #0077ec 65%); background: linear-gradient(180deg, #ffffff 0%, #0077ec 65%);
border-image: linear-gradient(180deg, #ffffff, #0077ec) 10 10; border-image: linear-gradient(180deg, #ffffff, #0077ec) 10 10;
@@ -293,12 +359,29 @@ const stateData = computed(() => {
border-top-color: #4391f8; border-top-color: #4391f8;
margin-left: 32px; margin-left: 32px;
} }
.item-link1 {
margin-top: 14px;
height: 20px;
.line1 {
width: 135px;
height: 2px;
background: linear-gradient(-90deg, #ffffff 0%, #0077ec 65%);
border-image: linear-gradient(-90deg, #ffffff, #0077ec) 10 10;
}
.circle1 {
width: 14px;
height: 14px;
background: #ffffff;
border-radius: 50%;
border: 3px solid #0077ec;
}
}
.item-link { .item-link {
position: relative; position: relative;
.line { .line {
margin-left: 39px; margin-left: 39px;
width: 2px; width: 2px;
height: 210px;
background: linear-gradient(0deg, #ffffff 0%, #0077ec 65%); background: linear-gradient(0deg, #ffffff 0%, #0077ec 65%);
border-image: linear-gradient(0deg, #ffffff, #0077ec) 10 10; border-image: linear-gradient(0deg, #ffffff, #0077ec) 10 10;
} }

View File

@@ -7,7 +7,7 @@
<div <div
class="path-container" class="path-container"
:style="{ :style="{
height: `${Number(position(stageProcessList.length - 1).topNum) + 100}px`, height: `${Number(position(stageProcessList.length - 1).topNum) + 65}px`,
}" }"
> >
<div <div

View File

@@ -133,12 +133,17 @@
未解锁 未解锁
</div> </div>
</template> </template>
<template <template v-if="value.completionStatus === '0'">
v-if=" <div
value.completionStatus === '0' || @click="toFinish(value)"
value.completionStatus === '2' :style="{
" background: value.canLearn ? '#f2903d' : '#999',
> }"
>
未开始
</div>
</template>
<template v-if="value.completionStatus === '2'">
<div @click="toFinish(value)" style="background: #f2903d"> <div @click="toFinish(value)" style="background: #f2903d">
{{ TASK_TYPES.toName[value.courseType] }} {{ TASK_TYPES.toName[value.courseType] }}
</div> </div>
@@ -148,6 +153,11 @@
已完成 已完成
</div> </div>
</template> </template>
<template v-if="value.completionStatus === '3'">
<div @click="toFinish(value)" style="background: #999">
已结束
</div>
</template>
</div> </div>
</div> </div>
</el-col> </el-col>
@@ -210,7 +220,7 @@
<div class="progressBox"> <div class="progressBox">
<div>总进度</div> <div>总进度</div>
<div class="progress"> <div class="progress">
<div style="flex: 1;"> <div style="flex: 1">
<el-progress <el-progress
:percentage="totalProgress" :percentage="totalProgress"
:show-text="false" :show-text="false"
@@ -235,7 +245,7 @@
<div class="progressBox"> <div class="progressBox">
<div>必修进度</div> <div>必修进度</div>
<div class="progress"> <div class="progress">
<div style="flex: 1;"> <div style="flex: 1">
<el-progress <el-progress
:percentage="requiredProgress" :percentage="requiredProgress"
:show-text="false" :show-text="false"
@@ -263,7 +273,7 @@
<div class="progressBox"> <div class="progressBox">
<div>选修进度</div> <div>选修进度</div>
<div class="progress"> <div class="progress">
<div style="flex: 1;"> <div style="flex: 1">
<el-progress <el-progress
:percentage="electiveProgress" :percentage="electiveProgress"
:show-text="false" :show-text="false"
@@ -598,6 +608,14 @@ const dialogVisible = ref(false);
const dialogVisibleTip = ref("该任务无法学习,请联系管理员进行替换!"); const dialogVisibleTip = ref("该任务无法学习,请联系管理员进行替换!");
async function toFinish(d) { async function toFinish(d) {
if (d.completionStatus == 0 || !d.canLearn) {
ElMessage.warning(`学习任务暂未开始`);
return;
}
if (d.completionStatus == 3) {
ElMessage.warning(`学习任务已结束无法学习`);
return;
}
if (d.completionStatus == 10) { if (d.completionStatus == 10) {
ElMessage.warning(`请先完成“${d.superTaskName}”的学习任务`); ElMessage.warning(`请先完成“${d.superTaskName}”的学习任务`);
return; return;

View File

@@ -98,7 +98,7 @@
</template> </template>
<template v-else> <template v-else>
<Roadmap1 <Roadmap1
@click="toFinish" @toFinish="toFinish"
:stageProcessList="stageProcessList" :stageProcessList="stageProcessList"
></Roadmap1> ></Roadmap1>
</template> </template>
@@ -182,7 +182,7 @@
</template> </template>
<template v-else> <template v-else>
<Roadmap1 <Roadmap1
@click="toFinish" @toFinish="toFinish"
:stageProcessList="stageProcessList" :stageProcessList="stageProcessList"
></Roadmap1> ></Roadmap1>
</template> </template>
@@ -399,21 +399,22 @@ const getList = () => {
loading.value = true; loading.value = true;
growthRequest(PROFESSIONAL_STUDENT_TASKLIST, params).then((res) => { growthRequest(PROFESSIONAL_STUDENT_TASKLIST, params).then((res) => {
if (selectGrowth.value.template === "1") { if (selectGrowth.value.template === "1") {
stageProcessList.value = res.data; stageProcessList.value = res.data.reverse();
} else { } else {
let newData = res.data.slice(0, 15).reverse(); let newData = res.data.slice(0, 15).reverse();
// 默认第一个在第一点位 // 默认第一个在第一点位
// let num = Number((15 / newData.length).toFixed(0));
// // 默认第一个在第一点位
let num = 15 / newData.length; let num = 15 / newData.length;
stageProcessList.value = newData.map((item, index) => { stageProcessList.value = newData.map((item, index) => {
// 默认第一个在第一点位 // 默认第一个在第一点位
if (index === 0) { if (index === 0) {
item.position = 0; item.position = 0;
} }
item.position = Number((index * num).toFixed()); item.position = Number(Math.round(index * num));
return item; return item;
}); });
} }
loading.value = false; loading.value = false;
}); });
}; };
@@ -468,6 +469,14 @@ const dialogVisible = ref(false);
const dialogVisibleTip = ref("该任务无法学习,请联系管理员进行替换!"); const dialogVisibleTip = ref("该任务无法学习,请联系管理员进行替换!");
async function toFinish(d) { async function toFinish(d) {
if (d.completionStatus == 0 || !d.canLearn) {
ElMessage.warning(`学习任务暂未开始`);
return;
}
if (d.completionStatus == 3) {
ElMessage.warning(`学习任务已结束无法学习`);
return;
}
if (d.completionStatus == 10) { if (d.completionStatus == 10) {
ElMessage.warning(`请先完成“${d.superTaskName}”的学习任务`); ElMessage.warning(`请先完成“${d.superTaskName}”的学习任务`);
return; return;

View File

@@ -41,7 +41,7 @@ export default defineConfig(({ command, mode }) =>
// "/professional": { // "/professional": {
// // target: 'http://192.168.16.195:32002', // // target: 'http://192.168.16.195:32002',
// // target: 'http://192.168.150.97:32002', // // target: 'http://192.168.150.97:32002',
// target: 'http://192.168.68.211:32002', // target: 'http://192.168.66.211:32002',
// changeOrigin: true, // changeOrigin: true,
// }, // },
'/growth': { '/growth': {