Compare commits

...

3 Commits

  1. 45
      src/api/course.ts
  2. 2
      src/router/index.ts
  3. 18
      src/router/module/constRouter/index.ts
  4. 8
      src/views/course/index.vue
  5. 21
      src/views/home/components/Graph.vue
  6. 411
      src/views/home/components/Graph1.vue
  7. 2
      src/views/knowledge/components/towGraph.vue
  8. 241
      src/views/knowledge/index.vue
  9. 9
      src/views/professionalListProfile/index.vue
  10. 386
      src/views/roadbedRecommendation/components/mountNode.vue
  11. 101
      src/views/roadbedRecommendation/index.vue
  12. 11
      src/views/scientificResearch/index.vue
  13. 1
      vite.config.ts

@ -31,7 +31,7 @@ export const getCourseChapter = (params: any) => {
// 获取所有课程资源
export const getCourseFiles = (params: any) => {
return request({
url: '/api/resource/queryByCourseId',
url: '/api/resource/graph/queryByCourseId',
params,
})
}
@ -45,22 +45,59 @@ export const getFileStreams = (params: any) => {
// 查询课程资源
export const getCourseOneFiles = (params: any) => {
return request({
url: '/api/resource/queryBesidesKnow',
url: '/api/resource/graph/queryBesidesKnow',
params,
})
}
// 获取二级图谱
export const getCourseAtlasTow = (params: object) => {
return request({
url: '/api/knowNeo/getsecondKnowsById',
url: '/api/knowNeo/getNodeByDepth',
params,
})
}
// 获取知识点资源
export const getCourseTowFiles = (params: any) => {
return request({
url: '/api/resource/graph/queryBesidesKnow',
params,
})
}
// 获取课程目标
export const getCourseObjectivesList = (params:GetCourseObjectivesList) => {
return request({
url:'/api/course_objectives/list/' + params.id,
})
}
// 获取知识点学习路径
export const getCoursePath = (params:any) => {
return request({
url:'/api/knowNeo/knowLearnPathGraph',
params
})
}
export const getknowLearnPath = (params:any) => {
return request({
url:'/api/knowNeo/knowLearnPath',
params
})
}
// 通过课程id查层级知识点
export const getCourseDepth = (params:any) => {
return request({
url:'/api/knowNeo/getDepthNodeByCourseId',
params
})
}
// 查看关系类型的节点
export const getCourseType = (params:any) => {
return request({
url:'/api/knowNeo/getRelsNodesByCourseId',
params
})
}

@ -1,4 +1,4 @@
import { createRouter, createWebHashHistory } from 'vue-router'
import { createRouter, createWebHashHistory,createWebHistory } from 'vue-router'
import { constRouter } from './module/constRouter'
const router = createRouter({
history: createWebHashHistory(),

@ -203,13 +203,13 @@ export const constRouter: any = [
hidden: true,
},
},
{
path: '/:pathMatch(.*)*',
redirect: '/404',
name: 'Any',
meta: {
title: '任意',
hidden: true,
},
},
// {
// path: '/:pathMatch(.*)*',
// redirect: '/404',
// name: 'Any',
// meta: {
// title: '任意',
// hidden: true,
// },
// },
]

@ -48,9 +48,9 @@
<el-radio value="4" size="mini">四层</el-radio>
</el-radio-group>
<el-checkbox-group v-model="checkList" @change="checkListChange">
<el-checkbox label="包含" value="Value A" style="margin: 0" />
<el-checkbox label="依赖" value="Value B" style="margin: 0" />
<el-checkbox label="顺序" value="Value C" />
<el-checkbox label="包含" value="contain" style="margin: 0" />
<el-checkbox label="依赖" value="depend" style="margin: 0" />
<el-checkbox label="顺序" value="order" />
</el-checkbox-group>
<div class="reset" @click="reset">重置</div>
</div>
@ -185,7 +185,7 @@
<script lang="ts" setup>
import StuList from './components/StuList.vue'
import { ref, nextTick } from 'vue'
import Graph from '../home/components/Graph.vue'
import Graph from '../home/components/Graph1.vue'
import courseTree from './components/courseTree.vue'
import { useRoute, useRouter } from 'vue-router'
import {

@ -15,7 +15,7 @@ import {
import SpriteText from '../../professionalProfile/spritetext'
// const $router = useRouter()
// const jsonData = ref(null)
import { getCourseAtlas } from '@/api/course'
import { getCourseAtlas ,getCourseDepth,getCourseType} from '@/api/course'
let Graph = reactive({})
const props = defineProps({
width: {
@ -40,28 +40,9 @@ const props = defineProps({
type: String || Number,
required: true,
},
checkList:{
},
radio1:{}
})
watch(() => props.radio1,(newVal:any) => {
console.log(newVal);
} )
watch(() => props.checkList,(newVal:any) => {
console.log(newVal);
} )
const emits = defineEmits(['clickGraph'])
// const nodeData = ref({})
// const getCourseAtlasEvent = async() => {
// const res = await getCourseAtlas({id:props.id})
// nodeData.value = res
// // console.log(res);
// }
// getCourseAtlasEvent()
const dom = ref(null)
onMounted(async () => {
const res: any = await getCourseAtlas({ id: '719f91586a64413898253c5b7d046fd8' })

@ -0,0 +1,411 @@
<template>
<div :id="'3d-graph' + props.index"></div>
</template>
<script lang="ts" setup>
// import { useRouter } from 'vue-router'
import { onMounted, ref, reactive ,watch} from 'vue'
import ForceGraph3D from '3d-force-graph'
//@ts-ignore
import {
CSS2DRenderer,
CSS2DObject,
} from 'three/examples/jsm/renderers/CSS2DRenderer.js'
//@ts-ignore
import SpriteText from '../../professionalProfile/spritetext'
// const $router = useRouter()
// const jsonData = ref(null)
import { getCourseAtlas ,getCourseDepth,getCourseType} from '@/api/course'
let Graph = reactive({})
const props = defineProps({
width: {
type: Number,
default:
window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth,
},
height: {
type: Number,
default:
window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight,
},
index: {
type: String,
required: true,
},
id: {
type: String || Number,
required: true,
},
checkList:{
},
radio1:{}
})
watch(() => props.radio1,(newVal:any) => {
console.log(newVal);
getCourseDepthEvent(newVal)
} )
watch(() => props.checkList,(newVal:any) => {
console.log(newVal);
getCourseTypeEvent(newVal)
} )
const emits = defineEmits(['clickGraph'])
const data = ref({})
const dom = ref(null)
const getCourseDepthEvent = async(depth:any) => {
const res = await getCourseDepth({courseId:'719f91586a64413898253c5b7d046fd8',depth})
data.value = res.data
const gData:any = {
nodes: [... data.value.knowList],
links: [... data.value.linksList],
}
gData.links.forEach((link:any) => {
const a = gData.nodes.find((item:any) => item.id === link.source)
const b = gData.nodes.find((item:any) => item.id === link.target)
// console.log(a, b)
!a.neighbors && (a.neighbors = [])
!b.neighbors && (b.neighbors = [])
a.neighbors.push(b)
b.neighbors.push(a)
!a.links && (a.links = [])
!b.links && (b.links = [])
a.links.push(link)
b.links.push(link)
})
const highlightNodes = new Set()
const highlightLinks = new Set()
let hoverNode:any = null
Graph = ForceGraph3D({
extraRenderers: [new CSS2DRenderer()],
})(document.getElementById('3d-graph' + props.index) as HTMLElement)
.graphData(gData)
// .nodeAutoColorBy('group')
.nodeThreeObject((node: any) => {
const nodeEl = document.createElement('div')
nodeEl.textContent = node.label
nodeEl.style.color = '#333333'
nodeEl.style.borderRadius = '50%'
// console.log(node, 111, Graph.graphData().nodes)
return new CSS2DObject(nodeEl)
})
.linkLabel((link: any) => link.label) //
.linkWidth(0.8)
.linkHoverPrecision(0.5) //
.linkColor(() => '#dd92fd') // 线
.backgroundColor('#f5f6fd')
.width(props.width)
.height(props.height)
.linkThreeObjectExtend(true)
.nodeRelSize(7) // 4
.nodeResolution(20)
.linkDirectionalArrowLength(3) // 线3
.linkDirectionalArrowRelPos(1) // 线线
.nodeThreeObjectExtend(true)
.nodeColor((node:any) =>
highlightNodes.has(node)
? node === hoverNode
? 'rgb(255,0,0,1)'
: node.color
: node.color,
)
.linkWidth((link) => (highlightLinks.has(link) ? 4 : 1))
.linkDirectionalParticles((link) => (highlightLinks.has(link) ? 4 : 0))
.linkDirectionalParticleWidth(4)
.onNodeClick((node: any) => {
console.log(node);
emits('clickGraph',node.id)
// Aim at node from outside it
//
const targetDistance = 200 //
//
const distRatio = 1 + targetDistance / Math.hypot(node.x, node.y, node.z)
const newPos = {
x: node.x * distRatio,
y: node.y * distRatio,
z: node.z * distRatio,
}
//
if (node.x === 0 && node.y === 0 && node.z === 0) {
newPos.z = targetDistance // z
}
//
//@ts-ignore
Graph.cameraPosition(
newPos, //
node, //
3000, //
)
//
//@ts-ignore
const graphData = Graph.graphData()
// 线线
graphData.links.forEach((link: any) => {
// console.log(link);
if (link.source.id === node.id || link.target.id === node.id) {
setLabel()
// 线
// link.color = '#FF0000' // 线
//@ts-ignore
Graph.linkColor((item: any): any => {
if (item.source.id === node.id || item.target.id === node.id) {
return 'red'
} else {
return '#dd92fd'
}
})
} else {
// Graph.linkColor(() => '#a4c7fe') // 线
}
})
//
//@ts-ignore
Graph.graphData(graphData)
})
.onNodeHover((node:any) => {
// no state change
if ((!node && !highlightNodes.size) || (node && hoverNode === node))
return
highlightNodes.clear()
highlightLinks.clear()
if (node && node.neighbors ) {
highlightNodes.add(node)
node.neighbors.forEach((neighbor:any) => highlightNodes.add(neighbor))
node.links.forEach((link :any) => highlightLinks.add(link))
}
hoverNode = node || null
updateHighlight()
})
.onLinkHover((link :any) => {
highlightNodes.clear()
highlightLinks.clear()
if (link) {
highlightLinks.add(link)
highlightNodes.add(link.source)
highlightNodes.add(link.target)
}
updateHighlight()
})
dom.value = document.querySelector('canvas') as any
}
const getCourseTypeEvent = async(type:any) => {
const res = await getCourseType({courseId:'719f91586a64413898253c5b7d046fd8',type})
console.log(res);
}
onMounted(async () => {
const res: any = await getCourseAtlas({ id: '719f91586a64413898253c5b7d046fd8' })
data.value = res.data
// console.log(res,'res')
const gData:any = {
nodes: [... data.value.knowList],
links: [... data.value.linksList],
}
gData.links.forEach((link:any) => {
const a = gData.nodes.find((item:any) => item.id === link.source)
const b = gData.nodes.find((item:any) => item.id === link.target)
// console.log(a, b)
!a.neighbors && (a.neighbors = [])
!b.neighbors && (b.neighbors = [])
a.neighbors.push(b)
b.neighbors.push(a)
!a.links && (a.links = [])
!b.links && (b.links = [])
a.links.push(link)
b.links.push(link)
})
const highlightNodes = new Set()
const highlightLinks = new Set()
let hoverNode:any = null
Graph = ForceGraph3D({
extraRenderers: [new CSS2DRenderer()],
})(document.getElementById('3d-graph' + props.index) as HTMLElement)
.graphData(gData)
// .nodeAutoColorBy('group')
.nodeThreeObject((node: any) => {
const nodeEl = document.createElement('div')
nodeEl.textContent = node.label
nodeEl.style.color = '#333333'
nodeEl.style.borderRadius = '50%'
// console.log(node, 111, Graph.graphData().nodes)
return new CSS2DObject(nodeEl)
})
.linkLabel((link: any) => link.label) //
.linkWidth(0.8)
.linkHoverPrecision(0.5) //
.linkColor(() => '#dd92fd') // 线
.backgroundColor('#f5f6fd')
.width(props.width)
.height(props.height)
.linkThreeObjectExtend(true)
.nodeRelSize(7) // 4
.nodeResolution(20)
.linkDirectionalArrowLength(3) // 线3
.linkDirectionalArrowRelPos(1) // 线线
.nodeThreeObjectExtend(true)
.nodeColor((node:any) =>
highlightNodes.has(node)
? node === hoverNode
? 'rgb(255,0,0,1)'
: node.color
: node.color,
)
.linkWidth((link) => (highlightLinks.has(link) ? 4 : 1))
.linkDirectionalParticles((link) => (highlightLinks.has(link) ? 4 : 0))
.linkDirectionalParticleWidth(4)
.onNodeClick((node: any) => {
console.log(node);
emits('clickGraph',node.id)
// Aim at node from outside it
//
const targetDistance = 200 //
//
const distRatio = 1 + targetDistance / Math.hypot(node.x, node.y, node.z)
const newPos = {
x: node.x * distRatio,
y: node.y * distRatio,
z: node.z * distRatio,
}
//
if (node.x === 0 && node.y === 0 && node.z === 0) {
newPos.z = targetDistance // z
}
//
//@ts-ignore
Graph.cameraPosition(
newPos, //
node, //
3000, //
)
//
//@ts-ignore
const graphData = Graph.graphData()
// 线线
graphData.links.forEach((link: any) => {
// console.log(link);
if (link.source.id === node.id || link.target.id === node.id) {
setLabel()
// 线
// link.color = '#FF0000' // 线
//@ts-ignore
Graph.linkColor((item: any): any => {
if (item.source.id === node.id || item.target.id === node.id) {
return 'red'
} else {
return '#dd92fd'
}
})
} else {
// Graph.linkColor(() => '#a4c7fe') // 线
}
})
//
//@ts-ignore
Graph.graphData(graphData)
})
.onNodeHover((node:any) => {
// no state change
if ((!node && !highlightNodes.size) || (node && hoverNode === node))
return
highlightNodes.clear()
highlightLinks.clear()
if (node && node.neighbors ) {
highlightNodes.add(node)
node.neighbors.forEach((neighbor:any) => highlightNodes.add(neighbor))
node.links.forEach((link :any) => highlightLinks.add(link))
}
hoverNode = node || null
updateHighlight()
})
.onLinkHover((link :any) => {
highlightNodes.clear()
highlightLinks.clear()
if (link) {
highlightLinks.add(link)
highlightNodes.add(link.source)
highlightNodes.add(link.target)
}
updateHighlight()
})
dom.value = document.querySelector('canvas') as any
})
const updateHighlight = () => {
// console.log(1111)
// trigger update of highlighted objects in scene
Graph.nodeColor(Graph.nodeColor())
.linkWidth(Graph.linkWidth())
.linkDirectionalParticles(Graph.linkDirectionalParticles())
}
const setLabel = () => {
//@ts-ignore
Graph.linkThreeObject((link: any) => {
// extend link with text sprite
const sprite = new SpriteText(`${link.label}`)
sprite.color = '#ccc'
sprite.textHeight = 1.5
return sprite
})
//@ts-ignore
Graph.linkPositionUpdate((sprite, { start, end }) => {
//@ts-ignore
const middlePos = Object.assign(
...['x', 'y', 'z'].map((c) => ({
//@ts-ignore
[c]: start[c] + (end[c] - start[c]) / 2, // calc middle point
})),
)
// Position sprite
Object.assign(sprite.position, middlePos)
})
//@ts-ignore
Graph.d3Force('charge').strength(-120)
}
// const goToEditAtlas = () => {
// console.log(jsonData.value)
// $router.push({ name: 'EditAtlas', params: { id: 123 } })
// }
</script>
<style lang="scss" scoped></style>

@ -46,7 +46,7 @@
// getCourseAtlasTowEvent()
const dom = ref(null)
onMounted(async () => {
const res: any = await getCourseAtlasTow({ id:Route.query.id })
const res: any = await getCourseAtlasTow({ id:Route.query.id,depth:2 })
// console.log(res,'res')
const gData:any = {
nodes: [...res.data.knowList],

@ -1,9 +1,12 @@
<template>
<div class="title">xxx知识点
<div class="back" @click="router.go(-1)">返回</div>
</div>
<div class="container" v-if="loading">
<div class="left" v-loading="tabLoading">
<div class="gruop">
<div class="no" v-if="flag === 1">当前无播放资源</div>
<!-- <Graph
<div class="left" v-loading="tabLoading">
<div class="gruop">
<div class="no" v-if="flag === 1">当前无播放资源</div>
<!-- <Graph
:width="1195"
:height="800"
:index="courseId"
@ -11,112 +14,109 @@
v-show="flag === 1"
@clickGraph="clickGraphChange"
/> -->
<div class="video" v-if="flag === 2">
<video id="video" width="100%" height="100%" controls>
<source :src="videoUrl" type="video/mp4" />
您的浏览器不支持视频播放
</video>
</div>
<div class="pdf" v-if="flag === 3">
<!-- <vuePdf /> -->
<VuePdf
v-for="page in numOfPages"
:key="page"
:src="pdfUrl"
:page="page"
/>
</div>
<div class="docx" v-if="flag === 4">
<vue-office-docx :src="docx" style="width: 100%; height: 100%" />
</div>
<div v-show="flag != 1" class="back" @click="router.go(-1)">
<el-icon><Back /></el-icon>
</div>
<div class="video" v-if="flag === 2">
<video id="video" width="100%" height="100%" controls>
<source :src="videoUrl" type="video/mp4" />
您的浏览器不支持视频播放
</video>
</div>
<div class="pdf" v-if="flag === 3">
<!-- <vuePdf /> -->
<VuePdf
v-for="page in numOfPages"
:key="page"
:src="pdfUrl"
:page="page"
/>
</div>
<div class="docx" v-if="flag === 4">
<vue-office-docx :src="docx" style="width: 100%; height: 100%" />
</div>
<div v-show="flag != 1" class="back" @click="router.go(-1)">
<el-icon><Back /></el-icon>
</div>
</div>
<div class="resource">
<el-tabs
v-model="activeName"
class="demo-tabs"
@tab-click="handleClick"
v-loading="isTabsLoading"
>
<el-tab-pane label="视频" name="1">
<div class="files-box">
<div
class="item"
v-for="item in courseFilesList.video"
:key="item.id"
@click="clickFile(item, 2)"
>
{{ item.name }}
</div>
<div class="resource">
<el-tabs
v-model="activeName"
class="demo-tabs"
@tab-click="handleClick"
v-loading="isTabsLoading"
>
<el-tab-pane label="视频" name="1">
<div class="files-box">
<div
class="item"
v-for="item in courseFilesList.video"
:key="item.id"
@click="clickFile(item, 2)"
>
{{ item.name }}
</div>
</el-tab-pane>
<el-tab-pane label="PPT" name="2">
<div class="files-box">
<div
class="item"
v-for="item in courseFilesList.PPT"
:key="item.id"
@click="clickFile(item, 3)"
>
{{ item.name }}
</div>
</div>
</el-tab-pane>
<el-tab-pane label="PPT" name="2">
<div class="files-box">
<div
class="item"
v-for="item in courseFilesList.PPT"
:key="item.id"
@click="clickFile(item, 3)"
>
{{ item.name }}
</div>
</el-tab-pane>
<el-tab-pane label="试题" name="3">Role</el-tab-pane>
<el-tab-pane label="文档" name="4">
<div class="files-box">
<div
class="item"
v-for="item in courseFilesList.word"
:key="item.id"
@click="clickFile(item, 4)"
>
{{ item.name }}
</div>
</div>
</el-tab-pane>
<el-tab-pane label="试题" name="3">Role</el-tab-pane>
<el-tab-pane label="文档" name="4">
<div class="files-box">
<div
class="item"
v-for="item in courseFilesList.word"
:key="item.id"
@click="clickFile(item, 4)"
>
{{ item.name }}
</div>
</el-tab-pane>
<el-tab-pane label="其他" name="5">
<div class="files-box">
<div
class="item"
v-for="item in courseFilesList.other"
:key="item.id"
@click="download(item)"
>
{{ item.name }}
</div>
</div>
</el-tab-pane>
<el-tab-pane label="其他" name="5">
<div class="files-box">
<div
class="item"
v-for="item in courseFilesList.other"
:key="item.id"
@click="download(item)"
>
{{ item.name }}
</div>
</el-tab-pane>
</el-tabs>
</div>
</div>
</el-tab-pane>
</el-tabs>
</div>
<div class="right">
<div class="course-info">
<div class="item">
<towGraph
:width="398"
:height="252"
/>
</div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="chapter">
<!-- <courseTree :chapterList="chapterList" /> -->
</div>
<div class="right">
<div class="course-info">
<div class="item">
<towGraph :width="398" :height="252" />
</div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="chapter">
<!-- <courseTree :chapterList="chapterList" /> -->
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import towGraph from './components/towGraph.vue'
// import courseTree from './components/courseTree.vue'
import { useRoute,useRouter } from 'vue-router'
import { getCourseOneFiles } from '@/api/course'
import { useRoute, useRouter } from 'vue-router'
import { getCourseTowFiles } from '@/api/course'
import { ElLoading } from 'element-plus'
import { filterFilesType } from '@/utils/filters'
// @ts-ignore
@ -150,40 +150,39 @@ const getCourseFilesEvent = async () => {
// })
// // console.log(filterFilesType(res));
// courseFilesList.value = filterFilesType(res.data)
const res = await getCourseOneFiles({ KnowId: 227 })
const res = await getCourseTowFiles({ knowId: Route.query.id })
console.log(res)
courseFilesList.value = filterFilesType(res.data)
isTabsLoading.value = false
// console.log(courseFilesList.value)
let arr = []
if(res.data) return loadingInstance.close()
if (res.data) return loadingInstance.close()
for (const key in courseFilesList.value) {
if(courseFilesList.value[key]){
arr.push({[key]:courseFilesList.value[key]})
if (courseFilesList.value[key]) {
arr.push({ [key]: courseFilesList.value[key] })
}
}
let key = Object.keys(arr[0])[0]
if(key === 'video'){
if (key === 'video') {
flag.value = 2
console.log(courseFilesList.value[key][0]);
console.log(courseFilesList.value[key][0])
videoUrl.value = courseFilesList.value[key][0].url
}else if(key === 'PPT'){
} else if (key === 'PPT') {
flag.value = 3
pdfUrl.value = `http://39.106.16.162:8080/api/resource/read?filename=${courseFilesList.value[key][0].name}`
const loadingTask = createLoadingTask(pdfUrl.value)
loadingTask.promise.then((pdf: any) => {
numOfPages.value = pdf.numPages
})
}else if(key === 'word'){
docx.value = `http://39.106.16.162:8080/api/resource/read?filename=${courseFilesList.value[key][0].name}`
} else if (key === 'word') {
docx.value = `http://39.106.16.162:8080/api/resource/read?filename=${courseFilesList.value[key][0].name}`
flag.value = 4
}else{
} else {
flag.value = 1
}
console.log(courseFilesList.value[key]);
console.log(courseFilesList.value[key])
loadingInstance.close()
}
getCourseFilesEvent()
@ -245,6 +244,34 @@ function downloadImage(imageUrl: any, filename: any) {
</script>
<style lang="scss" scoped>
.title {
position: relative;
width: $base-container-width;
height: 50px;
margin: 10px auto;
text-align: center;
font-size: 22px;
font-weight: 600;
line-height: 50px;
// padding: 20px 0;
background-color: #fff;
.back{
position: absolute;
top: 50%;
transform: translateY(-50%);
right: 30px;
width: 60px;
height: 30px;
text-align: center;
line-height: 30px;
color: #fff;
border-radius: 5px;
cursor: pointer;
background-color: #6da0ff;
font-size: 14px;
font-weight: normal;
}
}
.view-container {
// height: 100vh;
.container {

@ -73,7 +73,14 @@ const onGetCourseObject = async (id: any) => {
}
function toPath(item: any) {
$router.push('/roadbedRecommendation?isCourse=true')
$router.push({
path:'/roadbedRecommendation',
query:{
isCourse:'true',
id:item.id
}
})
learnPathStore.setCourseData(item)
}
</script>

@ -3,12 +3,36 @@
</template>
<script lang="ts" setup>
import { onMounted } from 'vue'
onMounted(() => {
/**
* 该示例演示自定义边和节点实现资金流转图效果
* by 十吾
*/
import { onMounted, ref } from 'vue'
import { getCoursePath } from '@/api/course'
import {useRouter} from 'vue-router'
const Router = useRouter()
const nodeList = ref({nodes:[],edges:[]})
const getCoursePathEvent = async () => {
const res = await getCoursePath({
corseId: '719f91586a64413898253c5b7d046fd8',
})
nodeList.value = { nodes: res.data.knowList, edges: res.data.linksList }
nodeList.value.edges.forEach((item:any) => {
let target = item.target
let source = item.source
item.target = target.toString()
item.source = source.toString()
item.data = {
type: '第一阶段',
amount: '10学时',
date: '学习基础知识',
}
})
nodeList.value.nodes.forEach((item:any) => {
item.id = item.id.toString()
})
console.log(nodeList.value)
init()
}
const init = () => {
var colorMap = {
凭证开立: '#72CC4A',
凭证转让: '#1A91FF',
@ -17,146 +41,146 @@ onMounted(() => {
第二阶段: '#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',
},
{
id: '10',
label: 'test',
},
{
id: '11',
label: 'text2',
},
],
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: '学习基础知识',
},
},
{
source: '6',
target: '10',
data: {
type: '第一阶段',
amount: '10学时',
date: '学习基础知识',
},
},
{
source: '6',
target: '11',
data: {
type: '第一阶段',
amount: '10学时',
date: '学习基础知识',
},
},
],
}
// 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',
// },
// {
// id: '10',
// label: 'test',
// },
// {
// id: '11',
// label: 'text2',
// },
// ],
// 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: '',
// },
// },
// {
// source: '6',
// target: '10',
// data: {
// type: '',
// amount: '10',
// date: '',
// },
// },
// {
// source: '6',
// target: '11',
// data: {
// type: '',
// amount: '10',
// date: '',
// },
// },
// ],
// }
G6.registerNode(
'round-rect',
@ -223,6 +247,7 @@ onMounted(() => {
G6.registerEdge('polyline', {
itemType: 'edge',
draw: function draw(cfg, group) {
var startPoint = cfg.startPoint
var endPoint = cfg.endPoint
var centerPoint = {
@ -287,33 +312,33 @@ onMounted(() => {
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',
},
})
// 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,
text: cfg.label,
x: line2StartPoint.x + labelLeftOffset,
y: endPoint.y + labelTopOffset + 4,
fontSize: 12,
@ -326,7 +351,7 @@ onMounted(() => {
return line
},
})
var graph = new G6.Graph({
container: 'mountNode',
width: window.innerWidth - 19,
@ -358,9 +383,16 @@ onMounted(() => {
},
})
graph.data(data)
graph.data( nodeList.value)
graph.render()
graph.on('node:click', ev => {
console.log(ev.item._cfg.id);
Router.push({
path:'/knowledge',
query:{id:ev.item._cfg.id}
})
});
var edges = graph.getEdges()
edges.forEach(function (edge: any) {
var line = edge.getKeyShape()
@ -373,6 +405,14 @@ onMounted(() => {
})
})
graph.paint()
}
onMounted(() => {
getCoursePathEvent()
/**
* 该示例演示自定义边和节点实现资金流转图效果
* by 十吾
*/
})
</script>

@ -2,11 +2,21 @@
<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
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 type="primary" style="margin-left: 20px" @click="goCourse">
返回课程首页
</el-button>
</div>
@ -18,45 +28,60 @@
<div class="title">学习路径</div>
<el-card style="margin-top: 50px">
<el-table :data="tableData" border style="width: 100%">
<el-table :data="knowLearnPathList" 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">
<el-tag
style="margin-right: 10px"
type="primary"
v-for="(item, index) in row.nodeList"
: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-column
prop="weight"
label="数量"
width="100px"
/>
<el-table-column prop="weight" label="学时" width="100px" />
</el-table>
<div class="path-description">
前端课程主要分为四个分支每个分支包含很多知识点其中分为三个阶段在每个阶段有不同的知识点在学习后继知识点需要学习前置知识点
</div>
</el-card>
<el-card v-if="$route.query.isCourse === 'true'" style="margin-top: 20px;">
<h1 style="text-align: center;font-size: 20px;font-weight: bolder;">相关信息</h1>
<div style="color: #ccc;">{{ learnPathStore.courseData.name }}</div>
<div style="font-size: 16px;line-height: 1.5;">{{ learnPathStore.courseData.description }}</div>
<el-card v-if="$route.query.isCourse === 'true'" style="margin-top: 20px">
<h1 style="text-align: center; font-size: 20px; font-weight: bolder">
相关信息
</h1>
<div style="color: #ccc">{{ learnPathStore.courseData.name }}</div>
<div style="font-size: 16px; line-height: 1.5">
{{ learnPathStore.courseData.description }}
</div>
</el-card>
<el-card v-else style="margin-top: 20px;" >
<h1 style="text-align: center;font-size: 20px;font-weight: bolder;">最新的课程</h1>
<el-card v-else style="margin-top: 20px">
<h1 style="text-align: center; font-size: 20px; font-weight: bolder">
最新的课程
</h1>
</el-card>
</div>
</template>
<script lang="ts" setup>
import useLearnPathStore from '@/store/module/learnPath';
const learnPathStore = useLearnPathStore()
import useLearnPathStore from '@/store/module/learnPath'
import { ref } from 'vue'
import { getknowLearnPath } from '@/api/course'
import mountNode from './components/mountNode.vue'
import { useRouter } from 'vue-router'
const Router = useRouter()
const courseName = ref('')
const learnPathStore = useLearnPathStore()
const options = [
{
@ -64,33 +89,21 @@ const options = [
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,
},
]
const goCourse = () => {
Router.push({
path: '/course',
query: { id: 'b7b169b7f9dd4ff2ae9639399206fda1' },
})
}
const knowLearnPathList = ref([])
const getknowLearnPathEvent = async () => {
const res = await getknowLearnPath({
corseId: '719f91586a64413898253c5b7d046fd8',
})
knowLearnPathList.value = res.data
console.log(res)
}
getknowLearnPathEvent()
</script>
<style lang="scss" scoped>

@ -1,11 +1,14 @@
<template>
<div>111</div>
<div>
111
</div>
</template>
<script lang="ts" setup>
import {} from 'vue'
<script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue'
</script>
<style lang="scss" scoped>
<style lang='scss' scoped>
</style>

@ -38,6 +38,7 @@ export default defineConfig({
resolve: {
alias: {
'@': path.resolve('./src'), // 相对路径别名配置,使用 @ 代替 src
// 'vue': 'vue/dist/vue.esm-bundler.js',
},
},
css: {

Loading…
Cancel
Save