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. 239
      src/views/knowledge/index.vue
  9. 9
      src/views/professionalListProfile/index.vue
  10. 382
      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) => { export const getCourseFiles = (params: any) => {
return request({ return request({
url: '/api/resource/queryByCourseId', url: '/api/resource/graph/queryByCourseId',
params, params,
}) })
} }
@ -45,18 +45,24 @@ export const getFileStreams = (params: any) => {
// 查询课程资源 // 查询课程资源
export const getCourseOneFiles = (params: any) => { export const getCourseOneFiles = (params: any) => {
return request({ return request({
url: '/api/resource/queryBesidesKnow', url: '/api/resource/graph/queryBesidesKnow',
params, params,
}) })
} }
// 获取二级图谱 // 获取二级图谱
export const getCourseAtlasTow = (params: object) => { export const getCourseAtlasTow = (params: object) => {
return request({ return request({
url: '/api/knowNeo/getsecondKnowsById', url: '/api/knowNeo/getNodeByDepth',
params,
})
}
// 获取知识点资源
export const getCourseTowFiles = (params: any) => {
return request({
url: '/api/resource/graph/queryBesidesKnow',
params, params,
}) })
} }
// 获取课程目标 // 获取课程目标
export const getCourseObjectivesList = (params:GetCourseObjectivesList) => { export const getCourseObjectivesList = (params:GetCourseObjectivesList) => {
return request({ return request({
@ -64,3 +70,34 @@ export const getCourseObjectivesList = (params:GetCourseObjectivesList) => {
}) })
} }
// 获取知识点学习路径
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' import { constRouter } from './module/constRouter'
const router = createRouter({ const router = createRouter({
history: createWebHashHistory(), history: createWebHashHistory(),

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

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

@ -15,7 +15,7 @@ import {
import SpriteText from '../../professionalProfile/spritetext' import SpriteText from '../../professionalProfile/spritetext'
// const $router = useRouter() // const $router = useRouter()
// const jsonData = ref(null) // const jsonData = ref(null)
import { getCourseAtlas } from '@/api/course' import { getCourseAtlas ,getCourseDepth,getCourseType} from '@/api/course'
let Graph = reactive({}) let Graph = reactive({})
const props = defineProps({ const props = defineProps({
width: { width: {
@ -40,28 +40,9 @@ const props = defineProps({
type: String || Number, type: String || Number,
required: true, 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 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) const dom = ref(null)
onMounted(async () => { onMounted(async () => {
const res: any = await getCourseAtlas({ id: '719f91586a64413898253c5b7d046fd8' }) 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() // getCourseAtlasTowEvent()
const dom = ref(null) const dom = ref(null)
onMounted(async () => { 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') // console.log(res,'res')
const gData:any = { const gData:any = {
nodes: [...res.data.knowList], nodes: [...res.data.knowList],

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

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

@ -3,12 +3,36 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted } from 'vue' import { onMounted, ref } from 'vue'
onMounted(() => { import { getCoursePath } from '@/api/course'
/** import {useRouter} from 'vue-router'
* 该示例演示自定义边和节点实现资金流转图效果 const Router = useRouter()
* by 十吾 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 = { var colorMap = {
凭证开立: '#72CC4A', 凭证开立: '#72CC4A',
凭证转让: '#1A91FF', 凭证转让: '#1A91FF',
@ -17,146 +41,146 @@ onMounted(() => {
第二阶段: '#1A91FF', 第二阶段: '#1A91FF',
第三阶段: '#FFAA15', 第三阶段: '#FFAA15',
} }
var data = { // var data = {
nodes: [ // nodes: [
{ // {
id: '1', // id: '1',
label: '前端', // label: '',
}, // },
{ // {
id: '2', // id: '2',
label: 'HTML&CSS&Javascript', // label: 'HTML&CSS&Javascript',
}, // },
{ // {
id: '3', // id: '3',
label: 'HTML&CSS&Javascript', // label: 'HTML&CSS&Javascript',
}, // },
{ // {
id: '4', // id: '4',
label: 'React.js', // label: 'React.js',
}, // },
{ // {
id: '5', // id: '5',
label: 'Vue.js', // label: 'Vue.js',
}, // },
{ // {
id: '6', // id: '6',
label: '工程化脚手架', // label: '',
}, // },
{ // {
id: '7', // id: '7',
label: '工程化脚手架', // label: '',
}, // },
{ // {
id: '8', // id: '8',
label: 'HTML&CSS&Javascript', // label: 'HTML&CSS&Javascript',
}, // },
{ // {
id: '9', // id: '9',
label: 'HTML&CSS&Javascript', // label: 'HTML&CSS&Javascript',
}, // },
{ // {
id: '10', // id: '10',
label: 'test', // label: 'test',
}, // },
{ // {
id: '11', // id: '11',
label: 'text2', // label: 'text2',
}, // },
], // ],
edges: [ // edges: [
{ // {
source: '1', // source: '1',
target: '2', // target: '2',
data: { // data: {
type: '第一阶段', // type: '',
amount: '10学时', // amount: '10',
date: '学习基础知识', // date: '',
}, // },
}, // },
{ // {
source: '1', // source: '1',
target: '3', // target: '3',
data: { // data: {
type: '第一阶段', // type: '',
amount: '10学时', // amount: '10',
date: '学习基础知识', // date: '',
}, // },
}, // },
{ // {
source: '2', // source: '2',
target: '5', // target: '5',
data: { // data: {
type: '第二阶段', // type: '',
amount: '15学时', // amount: '15',
date: '学习Vue框架', // date: 'Vue',
}, // },
}, // },
{ // {
source: '5', // source: '5',
target: '6', // target: '6',
data: { // data: {
type: '第三阶段', // type: '',
amount: '8学时', // amount: '8',
date: '学习前端开发工程化', // date: '',
}, // },
}, // },
{ // {
source: '3', // source: '3',
target: '4', // target: '4',
data: { // data: {
type: '第二阶段', // type: '',
amount: '18学时', // amount: '18',
date: '学习React.js', // date: 'React.js',
}, // },
}, // },
{ // {
source: '4', // source: '4',
target: '7', // target: '7',
data: { // data: {
type: '第三阶段', // type: '',
amount: '8学时', // amount: '8',
date: '学习前端开发工程化', // date: '',
}, // },
}, // },
{ // {
source: '1', // source: '1',
target: '8', // target: '8',
data: { // data: {
type: '第一阶段', // type: '',
amount: '10学时', // amount: '10',
date: '学习基础知识', // date: '',
}, // },
}, // },
{ // {
source: '1', // source: '1',
target: '9', // target: '9',
data: { // data: {
type: '第一阶段', // type: '',
amount: '10学时', // amount: '10',
date: '学习基础知识', // date: '',
}, // },
}, // },
{ // {
source: '6', // source: '6',
target: '10', // target: '10',
data: { // data: {
type: '第一阶段', // type: '',
amount: '10学时', // amount: '10',
date: '学习基础知识', // date: '',
}, // },
}, // },
{ // {
source: '6', // source: '6',
target: '11', // target: '11',
data: { // data: {
type: '第一阶段', // type: '',
amount: '10学时', // amount: '10',
date: '学习基础知识', // date: '',
}, // },
}, // },
], // ],
} // }
G6.registerNode( G6.registerNode(
'round-rect', 'round-rect',
@ -223,6 +247,7 @@ onMounted(() => {
G6.registerEdge('polyline', { G6.registerEdge('polyline', {
itemType: 'edge', itemType: 'edge',
draw: function draw(cfg, group) { draw: function draw(cfg, group) {
var startPoint = cfg.startPoint var startPoint = cfg.startPoint
var endPoint = cfg.endPoint var endPoint = cfg.endPoint
var centerPoint = { var centerPoint = {
@ -287,33 +312,33 @@ onMounted(() => {
var labelLeftOffset = 8 var labelLeftOffset = 8
var labelTopOffset = 8 var labelTopOffset = 8
// amount // amount
var amount = group.addShape('text', { // var amount = group.addShape('text', {
attrs: { // attrs: {
text: cfg.data.amount, // text: cfg.data.amount,
x: line2StartPoint.x + labelLeftOffset, // x: line2StartPoint.x + labelLeftOffset,
y: endPoint.y - labelTopOffset - 2, // y: endPoint.y - labelTopOffset - 2,
fontSize: 14, // fontSize: 14,
textAlign: 'left', // textAlign: 'left',
textBaseline: 'middle', // textBaseline: 'middle',
fill: '#000000D9', // fill: '#000000D9',
}, // },
}) // })
// type // // type
var type = group.addShape('text', { // var type = group.addShape('text', {
attrs: { // attrs: {
text: cfg.data.type, // text: cfg.data.type,
x: line2StartPoint.x + labelLeftOffset, // x: line2StartPoint.x + labelLeftOffset,
y: endPoint.y - labelTopOffset - amount.getBBox().height - 2, // y: endPoint.y - labelTopOffset - amount.getBBox().height - 2,
fontSize: 10, // fontSize: 10,
textAlign: 'left', // textAlign: 'left',
textBaseline: 'middle', // textBaseline: 'middle',
fill: '#000000D9', // fill: '#000000D9',
}, // },
}) // })
// date // date
var date = group.addShape('text', { var date = group.addShape('text', {
attrs: { attrs: {
text: cfg.data.date, text: cfg.label,
x: line2StartPoint.x + labelLeftOffset, x: line2StartPoint.x + labelLeftOffset,
y: endPoint.y + labelTopOffset + 4, y: endPoint.y + labelTopOffset + 4,
fontSize: 12, fontSize: 12,
@ -358,9 +383,16 @@ onMounted(() => {
}, },
}) })
graph.data(data) graph.data( nodeList.value)
graph.render() 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() var edges = graph.getEdges()
edges.forEach(function (edge: any) { edges.forEach(function (edge: any) {
var line = edge.getKeyShape() var line = edge.getKeyShape()
@ -373,6 +405,14 @@ onMounted(() => {
}) })
}) })
graph.paint() graph.paint()
}
onMounted(() => {
getCoursePathEvent()
/**
* 该示例演示自定义边和节点实现资金流转图效果
* by 十吾
*/
}) })
</script> </script>

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

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

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

Loading…
Cancel
Save