parent
d8550d2564
commit
68af92d3a8
9 changed files with 771 additions and 41 deletions
@ -0,0 +1,3 @@ |
||||
export interface GetCourseObjectivesList { |
||||
id:string | number |
||||
} |
@ -0,0 +1,358 @@ |
||||
<template> |
||||
<div id="mountNode"></div> |
||||
</template> |
||||
|
||||
<script lang="ts" setup> |
||||
import { onMounted } from 'vue' |
||||
onMounted(() => { |
||||
/** |
||||
* 该示例演示自定义边和节点实现资金流转图效果 |
||||
* by 十吾 |
||||
*/ |
||||
var colorMap = { |
||||
凭证开立: '#72CC4A', |
||||
凭证转让: '#1A91FF', |
||||
凭证融资: '#FFAA15', |
||||
第一阶段: '#72CC4A', |
||||
第二阶段: '#1A91FF', |
||||
第三阶段: '#FFAA15', |
||||
} |
||||
var data = { |
||||
nodes: [ |
||||
{ |
||||
id: '1', |
||||
label: '前端', |
||||
}, |
||||
{ |
||||
id: '2', |
||||
label: 'HTML&CSS&Javascript', |
||||
}, |
||||
{ |
||||
id: '3', |
||||
label: 'HTML&CSS&Javascript', |
||||
}, |
||||
{ |
||||
id: '4', |
||||
label: 'React.js', |
||||
}, |
||||
{ |
||||
id: '5', |
||||
label: 'Vue.js', |
||||
}, |
||||
{ |
||||
id: '6', |
||||
label: '工程化脚手架', |
||||
}, |
||||
{ |
||||
id: '7', |
||||
label: '工程化脚手架', |
||||
}, |
||||
{ |
||||
id: '8', |
||||
label: 'HTML&CSS&Javascript', |
||||
}, |
||||
{ |
||||
id: '9', |
||||
label: 'HTML&CSS&Javascript', |
||||
}, |
||||
], |
||||
edges: [ |
||||
{ |
||||
source: '1', |
||||
target: '2', |
||||
data: { |
||||
type: '第一阶段', |
||||
amount: '10学时', |
||||
date: '学习基础知识', |
||||
}, |
||||
}, |
||||
{ |
||||
source: '1', |
||||
target: '3', |
||||
data: { |
||||
type: '第一阶段', |
||||
amount: '10学时', |
||||
date: '学习基础知识', |
||||
}, |
||||
}, |
||||
{ |
||||
source: '2', |
||||
target: '5', |
||||
data: { |
||||
type: '第二阶段', |
||||
amount: '15学时', |
||||
date: '学习Vue框架', |
||||
}, |
||||
}, |
||||
{ |
||||
source: '5', |
||||
target: '6', |
||||
data: { |
||||
type: '第三阶段', |
||||
amount: '8学时', |
||||
date: '学习前端开发工程化', |
||||
}, |
||||
}, |
||||
{ |
||||
source: '3', |
||||
target: '4', |
||||
data: { |
||||
type: '第二阶段', |
||||
amount: '18学时', |
||||
date: '学习React.js', |
||||
}, |
||||
}, |
||||
{ |
||||
source: '4', |
||||
target: '7', |
||||
data: { |
||||
type: '第三阶段', |
||||
amount: '8学时', |
||||
date: '学习前端开发工程化', |
||||
}, |
||||
}, |
||||
{ |
||||
source: '1', |
||||
target: '8', |
||||
data: { |
||||
type: '第一阶段', |
||||
amount: '10学时', |
||||
date: '学习基础知识', |
||||
}, |
||||
}, |
||||
{ |
||||
source: '1', |
||||
target: '9', |
||||
data: { |
||||
type: '第一阶段', |
||||
amount: '10学时', |
||||
date: '学习基础知识', |
||||
}, |
||||
}, |
||||
], |
||||
} |
||||
|
||||
G6.registerNode( |
||||
'round-rect', |
||||
{ |
||||
drawShape: function drawShape(cfg, group) { |
||||
var width = cfg.style.width |
||||
var stroke = cfg.style.stroke |
||||
var rect = group.addShape('rect', { |
||||
attrs: { |
||||
x: -width / 2, |
||||
y: -15, |
||||
width: width, |
||||
height: 30, |
||||
radius: 15, |
||||
stroke: stroke, |
||||
lineWidth: 1.2, |
||||
fillOpacity: 1, |
||||
}, |
||||
}) |
||||
var circleLeft = group.addShape('circle', { |
||||
attrs: { |
||||
x: -width / 2, |
||||
y: 0, |
||||
r: 3, |
||||
fill: stroke, |
||||
}, |
||||
}) |
||||
var circleRight = group.addShape('circle', { |
||||
attrs: { |
||||
x: width / 2, |
||||
y: 0, |
||||
r: 3, |
||||
fill: stroke, |
||||
}, |
||||
}) |
||||
return rect |
||||
}, |
||||
getAnchorPoints: function getAnchorPoints() { |
||||
return [ |
||||
[0, 0.5], |
||||
[1, 0.5], |
||||
] |
||||
}, |
||||
update: function update(cfg, item) { |
||||
var group = item.getContainer() |
||||
var children = group.get('children') |
||||
var node = children[0] |
||||
var circleLeft = children[1] |
||||
var circleRight = children[2] |
||||
|
||||
var stroke = cfg.style.stroke, |
||||
labelStyle = cfg.labelStyle |
||||
|
||||
if (stroke) { |
||||
node.attr('stroke', stroke) |
||||
circleLeft.attr('fill', stroke) |
||||
circleRight.attr('fill', stroke) |
||||
} |
||||
}, |
||||
}, |
||||
'single-shape', |
||||
) |
||||
|
||||
G6.registerEdge('polyline', { |
||||
itemType: 'edge', |
||||
draw: function draw(cfg, group) { |
||||
var startPoint = cfg.startPoint |
||||
var endPoint = cfg.endPoint |
||||
var centerPoint = { |
||||
x: (startPoint.x + endPoint.x) / 2, |
||||
y: (startPoint.y + endPoint.y) / 2, |
||||
} |
||||
|
||||
var Ydiff = endPoint.y - startPoint.y |
||||
|
||||
var slope = Ydiff !== 0 ? 500 / Math.abs(Ydiff) : 0 |
||||
|
||||
var cpOffset = 16 |
||||
var offset = Ydiff < 0 ? cpOffset : -cpOffset |
||||
|
||||
var line1EndPoint = { |
||||
x: startPoint.x + slope, |
||||
y: endPoint.y + offset, |
||||
} |
||||
var line2StartPoint = { |
||||
x: line1EndPoint.x + cpOffset, |
||||
y: endPoint.y, |
||||
} |
||||
|
||||
// 控制点坐标 |
||||
var controlPoint = { |
||||
x: |
||||
((line1EndPoint.x - startPoint.x) * (endPoint.y - startPoint.y)) / |
||||
(line1EndPoint.y - startPoint.y) + |
||||
startPoint.x, |
||||
y: endPoint.y, |
||||
} |
||||
|
||||
var path = [ |
||||
['M', startPoint.x, startPoint.y], |
||||
['L', line1EndPoint.x, line1EndPoint.y], |
||||
[ |
||||
'Q', |
||||
controlPoint.x, |
||||
controlPoint.y, |
||||
line2StartPoint.x, |
||||
line2StartPoint.y, |
||||
], |
||||
['L', endPoint.x, endPoint.y], |
||||
] |
||||
|
||||
if (Ydiff === 0) { |
||||
path = [ |
||||
['M', startPoint.x, startPoint.y], |
||||
['L', endPoint.x, endPoint.y], |
||||
] |
||||
} |
||||
|
||||
var line = group.addShape('path', { |
||||
attrs: { |
||||
path: path, |
||||
stroke: colorMap[cfg.data.type], |
||||
lineWidth: 1.2, |
||||
endArrow: false, |
||||
}, |
||||
}) |
||||
|
||||
var labelLeftOffset = 8 |
||||
var labelTopOffset = 8 |
||||
// amount |
||||
var amount = group.addShape('text', { |
||||
attrs: { |
||||
text: cfg.data.amount, |
||||
x: line2StartPoint.x + labelLeftOffset, |
||||
y: endPoint.y - labelTopOffset - 2, |
||||
fontSize: 14, |
||||
textAlign: 'left', |
||||
textBaseline: 'middle', |
||||
fill: '#000000D9', |
||||
}, |
||||
}) |
||||
// type |
||||
var type = group.addShape('text', { |
||||
attrs: { |
||||
text: cfg.data.type, |
||||
x: line2StartPoint.x + labelLeftOffset, |
||||
y: endPoint.y - labelTopOffset - amount.getBBox().height - 2, |
||||
fontSize: 10, |
||||
textAlign: 'left', |
||||
textBaseline: 'middle', |
||||
fill: '#000000D9', |
||||
}, |
||||
}) |
||||
// date |
||||
var date = group.addShape('text', { |
||||
attrs: { |
||||
text: cfg.data.date, |
||||
x: line2StartPoint.x + labelLeftOffset, |
||||
y: endPoint.y + labelTopOffset + 4, |
||||
fontSize: 12, |
||||
fontWeight: 300, |
||||
textAlign: 'left', |
||||
textBaseline: 'middle', |
||||
fill: '#000000D9', |
||||
}, |
||||
}) |
||||
return line |
||||
}, |
||||
}) |
||||
|
||||
var graph = new G6.Graph({ |
||||
container: 'mountNode', |
||||
width: window.innerWidth - 19, |
||||
height: 600, |
||||
layout: { |
||||
type: 'dagre', |
||||
rankdir: 'LR', |
||||
nodesep: 30, |
||||
ranksep: 100, |
||||
}, |
||||
modes: { |
||||
default: ['drag-canvas'], |
||||
}, |
||||
defaultNode: { |
||||
shape: 'round-rect', |
||||
labelCfg: { |
||||
style: { |
||||
fill: '#000000A6', |
||||
fontSize: 10, |
||||
}, |
||||
}, |
||||
style: { |
||||
stroke: '#72CC4A', |
||||
width: 150, |
||||
}, |
||||
}, |
||||
defaultEdge: { |
||||
shape: 'polyline', |
||||
}, |
||||
}) |
||||
|
||||
graph.data(data) |
||||
graph.render() |
||||
|
||||
var edges = graph.getEdges() |
||||
edges.forEach(function (edge:any) { |
||||
var line = edge.getKeyShape() |
||||
var stroke = line.attr('stroke') |
||||
var targetNode = edge.getTarget() |
||||
targetNode.update({ |
||||
style: { |
||||
stroke: stroke, |
||||
}, |
||||
}) |
||||
}) |
||||
graph.paint() |
||||
}) |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
#mountNode { |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
</style> |
@ -0,0 +1,149 @@ |
||||
<template> |
||||
<div class="path-title"> |
||||
<div class="title">前端课程学习路径推荐</div> |
||||
<div class="setting"> |
||||
<el-select |
||||
v-model="courseName" |
||||
placeholder="请选择课程" |
||||
size="large" |
||||
style="width: 200px" |
||||
> |
||||
<el-option |
||||
v-for="item in options" |
||||
:key="item.id" |
||||
:label="item.label" |
||||
:value="item.id" |
||||
/> |
||||
</el-select> |
||||
<el-button type="primary" style="margin-left: 20px">切换</el-button> |
||||
<el-button |
||||
type="primary" |
||||
style="margin-left: 20px" |
||||
@click="Router.push('/')" |
||||
> |
||||
返回课程首页 |
||||
</el-button> |
||||
</div> |
||||
</div> |
||||
<div class="path-container"> |
||||
<mountNode /> |
||||
</div> |
||||
<div class="statistics"> |
||||
<div class="title">学习路径</div> |
||||
|
||||
<el-card style="margin-top: 50px"> |
||||
<el-table :data="tableData" border style="width: 100%"> |
||||
<el-table-column type="index" label="序号" width="100px" /> |
||||
<el-table-column prop="content" label="学习路径"> |
||||
<template v-slot="{ row }"> |
||||
<div> |
||||
<el-tag |
||||
style="margin-right: 10px" |
||||
type="primary" |
||||
v-for="(item, index) in row.content" |
||||
:key="index" |
||||
> |
||||
{{ item }} |
||||
</el-tag> |
||||
</div> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column prop="num" label="数量" width="100px" /> |
||||
<el-table-column prop="hours" label="学时" width="100px" /> |
||||
</el-table> |
||||
<div class="path-description"> |
||||
前端课程主要分为四个分支,每个分支包含很多知识点,其中分为三个阶段在每个阶段有不同的知识点,在学习后继知识点需要学习前置知识点 |
||||
</div> |
||||
</el-card> |
||||
|
||||
</div> |
||||
|
||||
</template> |
||||
|
||||
<script lang="ts" setup> |
||||
import { ref } from 'vue' |
||||
import mountNode from './components/mountNode.vue' |
||||
import { useRouter } from 'vue-router' |
||||
const Router = useRouter() |
||||
const courseName = ref('') |
||||
const options = [ |
||||
{ |
||||
id: 1, |
||||
label: 'Vue.js', |
||||
}, |
||||
] |
||||
const tableData = [ |
||||
{ |
||||
content: ['HTML', ' CSS', 'JavaScript', 'Node.js', 'Vue.js', 'React.js'], |
||||
num: 10, |
||||
hours: 7.5, |
||||
}, |
||||
{ |
||||
content: ['HTML', ' CSS', 'JavaScript', 'Node.js', 'Vue.js', 'React.js'], |
||||
num: 10, |
||||
hours: 7.5, |
||||
}, |
||||
{ |
||||
content: ['HTML', ' CSS', 'JavaScript', 'Node.js', 'Vue.js', 'React.js'], |
||||
num: 10, |
||||
hours: 7.5, |
||||
}, |
||||
{ |
||||
content: ['HTML', ' CSS', 'JavaScript', 'Node.js', 'Vue.js', 'React.js'], |
||||
num: 10, |
||||
hours: 7.5, |
||||
}, |
||||
{ |
||||
content: ['HTML', ' CSS', 'JavaScript', 'Node.js', 'Vue.js', 'React.js'], |
||||
num: 10, |
||||
hours: 7.5, |
||||
}, |
||||
] |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.path-container { |
||||
width: 100%; |
||||
height: 600px; |
||||
background-color: #f5f6fd; |
||||
} |
||||
.path-title { |
||||
position: relative; |
||||
width: 100%; |
||||
height: 50px; |
||||
// background-color: skyblue; |
||||
display: flex; |
||||
justify-content: center; |
||||
.title { |
||||
font-size: 18px; |
||||
height: 100%; |
||||
line-height: 50px; |
||||
font-weight: 600; |
||||
} |
||||
.setting { |
||||
position: absolute; |
||||
left: 50%; |
||||
top: 50%; |
||||
|
||||
transform: translate(50%, -50%); |
||||
display: flex; |
||||
align-items: center; |
||||
} |
||||
} |
||||
.statistics { |
||||
width: 100%; |
||||
margin-top: 50px; |
||||
padding: 0 30px 30px 30px; |
||||
.title { |
||||
font-size: 32px; |
||||
font-weight: 600; |
||||
text-align: center; |
||||
// margin: 30px 0; |
||||
} |
||||
} |
||||
.path-description{ |
||||
// padding: 20px 30px; |
||||
margin: 30px 0; |
||||
font-size: 14px; |
||||
} |
||||
</style> |
Loading…
Reference in new issue