提交 c0bc635c authored 作者: lhh's avatar lhh

对接知识图谱的接口

上级 e5513e29
...@@ -254,3 +254,14 @@ export function getBookDetail(data: { id: string; }) { ...@@ -254,3 +254,14 @@ export function getBookDetail(data: { id: string; }) {
export function getChapter(data: { book_id: string; }) { export function getChapter(data: { book_id: string; }) {
return httpRequest.post('/api/ebook/open/teacher/chapter/getAllList', data) return httpRequest.post('/api/ebook/open/teacher/chapter/getAllList', data)
} }
// 获取知识图谱
export function getTagList(params: { type: string; parent_id: string; chapter_id?: string }) {
return httpRequest.get('/api/resource/v1/course/course/tag-list', { params })
}
// 关联知识图谱
export function addTagCourse(data: { tag_id: string; course_id: string; chapter_id: string; }) {
return httpRequest.post('/api/resource/v1/course/course/tag-add-course', data)
}
// /v1/course/course/tag-add-course
<script setup lang="ts"> <script setup lang="ts">
import { getChapter, createCharacter } from '../../api' import { getTagList, addTagCourse } from '../../api'
import { Plus } from '@element-plus/icons-vue' import { Plus } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
...@@ -35,7 +35,7 @@ const handleCancel = () => { ...@@ -35,7 +35,7 @@ const handleCancel = () => {
const chapterList = ref([]) const chapterList = ref([])
onMounted(() => { onMounted(() => {
getChapter({ book_id: route.query?.bid as string }).then(res => { getTagList({ type: '1', parent_id: route.query.id as string }).then(res => {
chapterList.value = res.data.reduce((a: any, b: any) => { chapterList.value = res.data.reduce((a: any, b: any) => {
b.index = '0' b.index = '0'
if (b.children) { if (b.children) {
...@@ -57,13 +57,11 @@ const handleView = function (id: any) { ...@@ -57,13 +57,11 @@ const handleView = function (id: any) {
const handleGl = function (val: any) { const handleGl = function (val: any) {
const params: any = { const params: any = {
name: val.name, tag_id: val.id,
course_id: props.course_id, course_id: props.course_id,
resource_type: '13', chapter_id: props.chapterID
parent_id: props.chapterID,
resource_id: val.id
} }
createCharacter(params).then(() => { addTagCourse(params).then(() => {
emit('update:isShowTextbookDialog2', false) emit('update:isShowTextbookDialog2', false)
emit('create', val) emit('create', val)
ElMessage.success('添加成功') ElMessage.success('添加成功')
......
...@@ -13,7 +13,7 @@ import AddExamDialog from '../components/stepTwoComponents/AddExamDialog.vue' ...@@ -13,7 +13,7 @@ import AddExamDialog from '../components/stepTwoComponents/AddExamDialog.vue'
import VideoPlayDialog from '../components/stepTwoComponents/VideoPlayDialog.vue' import VideoPlayDialog from '../components/stepTwoComponents/VideoPlayDialog.vue'
import AddChapterDialog from '../components/stepTwoComponents/AddChapterDialog.vue' import AddChapterDialog from '../components/stepTwoComponents/AddChapterDialog.vue'
import AddTextbookDialog from '../components/stepTwoComponents/AddTextbookDialog.vue' import AddTextbookDialog from '../components/stepTwoComponents/AddTextbookDialog.vue'
import AddTextbookDialog2 from '../components/stepTwoComponents/AddTextbookDialog2.vue' import AddGraphbookDialog from '../components/stepTwoComponents/AddGraphbookDialog.vue'
import OpenRules from '../components/stepTwoComponents/OpenRules.vue' import OpenRules from '../components/stepTwoComponents/OpenRules.vue'
const route = useRoute() const route = useRoute()
...@@ -600,7 +600,7 @@ const handleChangeStatus = (node: any, data: any) => { ...@@ -600,7 +600,7 @@ const handleChangeStatus = (node: any, data: any) => {
:chapterID="chapterID" :chapterID="chapterID"
:course_id="id" :course_id="id"
/> />
<AddTextbookDialog2 <AddGraphbookDialog
v-if="isShowTextbookDialog2 === true" v-if="isShowTextbookDialog2 === true"
v-model:isShowTextbookDialog2="isShowTextbookDialog2" v-model:isShowTextbookDialog2="isShowTextbookDialog2"
@create="handleFresh" @create="handleFresh"
......
...@@ -92,3 +92,34 @@ export function courseCopy(data: { id: string }) { ...@@ -92,3 +92,34 @@ export function courseCopy(data: { id: string }) {
export function setDownload(data: { course_id: string; information_id: string; can_download: string }) { export function setDownload(data: { course_id: string; information_id: string; can_download: string }) {
return httpRequest.post('/api/resource/v1/course/course/set-course-information-can-download ', data) return httpRequest.post('/api/resource/v1/course/course/set-course-information-can-download ', data)
} }
// 获取知识图谱
export function getTagList(params: { type: string; parent_id: string; chapter_id?: string }) {
return httpRequest.get('/api/resource/v1/course/course/tag-list', { params })
}
// 新增知识图谱
export function addTag(data: { name: string; course_id: string; status: string; parent_id?: string }) {
return httpRequest.post('/api/resource/v1/course/course/tag-add', data)
}
// 更新知识图谱
export function updateTag(data: { id: string; name: string; course_id: string; status: string; }) {
return httpRequest.post('/api/resource/v1/course/course/tag-update', data)
}
// 删除知识图谱
export function deleteTag(data: { id: string; course_id: string }) {
return httpRequest.post('/api/resource/v1/course/course/tag-delete', data)
}
// 查看关联的课程章节
export function viewTagCourse(params: { tag_id: string; course_id: string }) {
return httpRequest.get('/api/resource/v1/course/course/tag-course', { params })
}
// 查看关联的书籍章节
export function viewTagBook(params: { tag_id: string; course_id: string }) {
return httpRequest.get('/api/resource/v1/course/course/tag-book', { params })
}
...@@ -126,7 +126,7 @@ const handleMembers = () => { ...@@ -126,7 +126,7 @@ const handleMembers = () => {
// 点击知识图谱 // 点击知识图谱
const handleChart = () => { const handleChart = () => {
router.push({ path: '/course/my/graph', query: { n: props.data?.name, bid: 19 } }) router.push({ path: '/course/my/graph', query: { n: props.data?.name, bid: 19, cid: route.query.id } })
} }
// 更改负责人确定 // 更改负责人确定
......
<script setup lang="ts">
import { viewTagBook } from '../api'
const route = useRoute()
const emit = defineEmits<Emits>()
const props = defineProps({
isShowGraphBookDialog: {
type: Boolean,
required: true
},
id: {
type: String,
required: false
}
})
interface Emits {
(e: 'update:isShowGraphBookDialog', isShowVideoDialog: boolean): void
(e: 'create', val: any): void
}
// 取消
const handleCancel = () => {
emit('update:isShowGraphBookDialog', false)
}
const chapterList = ref([])
onMounted(() => {
viewTagBook({ tag_id: props.id as string, course_id: route.query.cid as string }).then(res => {
chapterList.value = res.data.reduce((a: any, b: any) => {
b.index = '0'
if (b.children) {
b.children.map((m: any) => {
m.index = '1'
})
}
a.push(b)
return a
}, [])
console.log(chapterList.value, 'chapterList.value')
})
})
</script>
<template>
<el-drawer
:model-value="isShowGraphBookDialog"
draggable
:before-close="handleCancel"
size="60%"
title="关联数字教材章节"
>
<el-tree :data="chapterList" node-key="id" :accordion="true" :expand-on-click-node="false" style="min-width: 100%">
<template #default="{ data }">
<span class="custom-tree-node">
<span class="node_title">{{ data.name }}</span>
</span>
</template>
</el-tree>
</el-drawer>
</template>
<style lang="scss" scoped>
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
.btn_operate {
background-color: rgba(248, 241, 229, 0.39);
font-weight: 400;
color: #b2833d;
border: none;
border-radius: 16px;
margin: 3px;
}
.card-list {
display: flex;
flex-direction: column;
}
.card-list-con {
background: #fafafa;
padding: 20px;
display: flex;
flex-wrap: wrap;
}
.video-head {
position: relative;
.video-head-icon {
position: absolute;
top: 0;
right: 0;
font-size: 30px;
color: #666;
cursor: pointer;
}
}
.video-tool-btn {
padding: 10px 0 30px 0;
}
.video-head-icon {
position: absolute;
top: 0;
right: 0;
font-size: 30px;
color: #666;
cursor: pointer;
}
</style>
<script setup lang="ts">
import { viewTagCourse } from '../api'
const route = useRoute()
const emit = defineEmits<Emits>()
const props = defineProps({
isShowGraphCourseDialog: {
type: Boolean,
required: true
},
id: {
type: String,
required: false
}
})
interface Emits {
(e: 'update:isShowGraphCourseDialog', isShowVideoDialog: boolean): void
(e: 'create', val: any): void
}
// 取消
const handleCancel = () => {
emit('update:isShowGraphCourseDialog', false)
}
const chapterList = ref([])
onMounted(() => {
viewTagCourse({ tag_id: props.id as string, course_id: route.query.cid as string }).then(res => {
chapterList.value = res.data.reduce((a: any, b: any) => {
b.index = '0'
if (b.children) {
b.children.map((m: any) => {
m.index = '1'
})
}
a.push(b)
return a
}, [])
console.log(chapterList.value, 'chapterList.value')
})
})
</script>
<template>
<el-drawer
:model-value="isShowGraphCourseDialog"
draggable
:before-close="handleCancel"
size="60%"
title="关联课程章节"
>
<el-tree :data="chapterList" node-key="id" :accordion="true" :expand-on-click-node="false" style="min-width: 100%">
<template #default="{ data }">
<span class="custom-tree-node">
<span class="node_title">{{ data.name }}</span>
</span>
</template>
</el-tree>
</el-drawer>
</template>
<style lang="scss" scoped>
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
.btn_operate {
background-color: rgba(248, 241, 229, 0.39);
font-weight: 400;
color: #b2833d;
border: none;
border-radius: 16px;
margin: 3px;
}
.card-list {
display: flex;
flex-direction: column;
}
.card-list-con {
background: #fafafa;
padding: 20px;
display: flex;
flex-wrap: wrap;
}
.video-head {
position: relative;
.video-head-icon {
position: absolute;
top: 0;
right: 0;
font-size: 30px;
color: #666;
cursor: pointer;
}
}
.video-tool-btn {
padding: 10px 0 30px 0;
}
.video-head-icon {
position: absolute;
top: 0;
right: 0;
font-size: 30px;
color: #666;
cursor: pointer;
}
</style>
<script setup lang="ts"> <script setup lang="ts">
import AddTextbookDialog from '../../create/components/stepTwoComponents/AddTextbookDialog.vue' import { getTagList, addTag, updateTag, deleteTag } from '../api'
import ViewGraphCourse from '../components/ViewGraphCourse.vue'
import ViewGraphBook from '../components/ViewGraphBook.vue'
import { ElMessage } from 'element-plus'
const route = useRoute() const route = useRoute()
const tableData = ref([ // 获取列表
{ const tableData = ref([])
id: 1, const updateTagList = () => {
points: '项目一:初识商务数据分析', getTagList({ type: '1', parent_id: route.query.cid as string }).then(res => {
update: '管理员', tableData.value = res.data
time: '2024-09-12 12:00:23', })
children: [ }
{ updateTagList()
id: 2,
points: '任务一:人人都需要商务数据分析', // 新增
update: '管理员', const addTagRequest = () => {
time: '2024-09-12 12:00:23', addTag({ name: pName.value, course_id: route.query?.cid as string, status: '1', parent_id: addTagId.value }).then(
children: [ res => {
{ updateTagList()
id: 3, ElMessage({
points: '商务数据分析就业情况', message: '添加成功',
update: '管理员', type: 'success'
time: '2024-09-12 12:00:23', })
children: [
{
id: 4,
points: '商务数据分析师岗位',
update: '管理员',
time: '2024-09-12 12:00:23'
},
{
id: 5,
points: '商务数据分析师的市场优势',
update: '管理员',
time: '2024-09-12 12:00:23'
},
{
id: 6,
points: '商务数据分析师的工作职责',
update: '管理员',
time: '2024-09-12 12:00:23'
} }
] )
}
// 更新
const updateTagRequest = () => {
updateTag({ id: addTagId.value, name: pName.value, course_id: route.query?.cid as string, status: '1' }).then(res => {
updateTagList()
ElMessage({
message: '修改成功',
type: 'success'
})
})
}
const findParentIdById = (items: any, targetId: any) => {
// 使用栈来模拟递归过程,存储当前遍历元素和父级id
const stack = [...items] // 初始化栈为顶层元素
// 使用栈遍历
while (stack.length > 0) {
const currentItem = stack.pop() // 取出栈顶元素
// 检查当前元素是否是目标元素
if (currentItem.id === targetId) {
return currentItem.parentId // 找到目标元素,返回父级id
} }
] // 如果当前元素有children,继续遍历子元素
if (currentItem.children) {
for (const child of currentItem.children) {
child.parentId = currentItem.id // 为子元素添加父级id
stack.push(child) // 将子元素压入栈中
} }
]
} }
]) }
return undefined // 如果没有找到目标id,返回undefined
}
// 弹窗输入框 // 弹窗输入框
const pName: any = ref('') const pName: any = ref('')
const dialogVisible = ref(false) const dialogVisible = ref(false)
const isUpdate = ref(false)
// 点击添加同级的id // 点击添加同级 子级的id
const addSameId = ref<any>('') const addTagId = ref<any>('')
const stu = ref<number>(0) const handleAddTagSame = (scope: any) => {
const addChild = function (scope: any, n: number) { const id = findParentIdById(tableData.value, scope?.row?.id)
if (scope !== 1) { addTagId.value = id || ''
addSameId.value = scope?.row.id isUpdate.value = false
} else {
addSameId.value = 1
}
stu.value = n
dialogVisible.value = true dialogVisible.value = true
} }
const handleAddTagChild = (scope: any) => {
const handleConfirm = () => { addTagId.value = scope?.row.id
// 查找 ID 为 4 的所有层级下标 isUpdate.value = false
// 同级增加 dialogVisible.value = true
// for (let i = 0; i < fIndex.length - 1; i++){ }
// // tableData[] const handleUpdateTag = (scope: any) => {
// tableData.value[fIndex[i]] addTagId.value = scope?.row?.id
// } pName.value = scope?.row?.name
const getRandomInt = function (min: any, max: any) { isUpdate.value = true
return Math.floor(Math.random() * (max - min + 1)) + min dialogVisible.value = true
}
const data: any = {
id: getRandomInt(100, 100000),
points: pName.value,
update: '管理员',
time: '2024-09-12 12:00:23'
}
if (stu.value === 0) {
manageById(tableData.value, addSameId.value, data)
}
if (stu.value === 1) {
manageById(tableData.value, addSameId.value, data, true)
}
if (stu.value === 2) {
manageById(tableData.value, addSameId.value, null, false, pName.value)
}
// if (stu.value === 3) {
// manageById(tableData.value, addSameId.value, null, false, null, true)
// }
pName.value = ''
dialogVisible.value = false
} }
function manageById( // 输入完名称点击输入框
array: any, const handleConfirm = () => {
targetId: any, if (isUpdate) {
newElement = null, updateTagRequest()
insertAsChild = false,
newPoints = null,
deleteTarget = false
) {
for (let i = 0; i < array.length; i++) {
const item = array[i]
// 检查当前项的 ID 是否匹配目标 ID
if (item.id === targetId) {
if (deleteTarget) {
// 删除目标对象
array.splice(i, 1)
return true // 删除成功
}
// 如果需要更新 points,则修改
if (newPoints !== null) {
item.points = newPoints
return false
}
if (insertAsChild) {
// 如果插入为子级,初始化 children 如果不存在
if (!item.children) {
item.children = []
}
// 在 children 中插入新元素
item.children.push(newElement)
} else { } else {
// 如果不作为子级,插入在当前项后面 addTagRequest()
array.splice(i + 1, 0, newElement)
}
return true // 插入或更新成功
}
// 如果当前项有 children,递归查找
if (Array.isArray(item.children)) {
const result = manageById(item.children, targetId, newElement, insertAsChild, newPoints, deleteTarget)
if (result) {
return true // 插入、更新或删除成功
}
}
} }
return false // 未找到目标 ID dialogVisible.value = false
} }
const handleDelete = (scope: any) => { const handleDelete = (scope: any) => {
addSameId.value = scope?.row.id deleteTag({ id: scope.row?.id, course_id: route.query.cid as string }).then(res => {
manageById(tableData.value, addSameId.value, null, false, null, true) updateTagList()
ElMessage({
message: '删除成功',
type: 'success'
})
})
} }
const isShowTextbookDialog = ref(false) const isShowGraphCourseDialog = ref(false)
const bookName = ref('关联课程章节') const isShowGraphBookDialog = ref(false)
const handleCourseView = function (scope: any) {
addTagId.value = scope.row?.id
isShowGraphCourseDialog.value = true
}
const handleView = function (n: any) { const handleBookView = function (scope: any) {
bookName.value = n addTagId.value = scope.row?.id
isShowTextbookDialog.value = true isShowGraphBookDialog.value = true
} }
const formInline = reactive({ const formInline = reactive({
...@@ -167,7 +124,7 @@ const formInline = reactive({ ...@@ -167,7 +124,7 @@ const formInline = reactive({
<template> <template>
<AppCard title="知识图库"> <AppCard title="知识图库">
<div style="margin-bottom: 15px">课程名称:{{ route.query?.n }}</div> <div style="margin-bottom: 15px">课程名称:{{ route.query?.n }}</div>
<div> <!-- <div>
<el-form :inline="true" :model="formInline" class="demo-form-inline"> <el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item label="知识点"> <el-form-item label="知识点">
<el-input v-model="formInline.user" placeholder="请输入" clearable /> <el-input v-model="formInline.user" placeholder="请输入" clearable />
...@@ -177,8 +134,8 @@ const formInline = reactive({ ...@@ -177,8 +134,8 @@ const formInline = reactive({
<el-button type="primary">重置</el-button> <el-button type="primary">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div> </div> -->
<el-button type="primary" @click="addChild(1, 1)">添加知识点</el-button> <el-button type="primary" @click="handleAddTagSame">添加知识点</el-button>
<el-button type="primary">批量导入</el-button> <el-button type="primary">批量导入</el-button>
<el-button type="primary">导出</el-button> <el-button type="primary">导出</el-button>
<el-table <el-table
...@@ -190,19 +147,17 @@ const formInline = reactive({ ...@@ -190,19 +147,17 @@ const formInline = reactive({
align="center" align="center"
> >
<!-- <el-table-column type="index"></el-table-column> --> <!-- <el-table-column type="index"></el-table-column> -->
<el-table-column prop="points" label="知识点"> </el-table-column> <el-table-column prop="name" label="知识点"> </el-table-column>
<el-table-column prop="update" label="更新人" width="180"> </el-table-column> <!-- <el-table-column prop="update" label="更新人" width="180"> </el-table-column>
<el-table-column prop="time" label="更新时间" width="180"> </el-table-column> <el-table-column prop="time" label="更新时间" width="180"> </el-table-column> -->
<el-table-column fixed="right" label="操作"> <el-table-column fixed="right" label="操作">
<template #default="scope"> <template #default="scope">
<el-button link type="primary" size="small" @click="addChild(scope, 0)"> 添加同级 </el-button> <el-button link type="primary" size="small" @click="handleAddTagSame(scope)"> 添加同级 </el-button>
<el-button link type="primary" size="small" @click="addChild(scope, 1)">添加子级</el-button> <el-button link type="primary" size="small" @click="handleAddTagChild(scope)">添加子级</el-button>
<el-button link type="primary" size="small" @click="addChild(scope, 2)">编辑知识点</el-button> <el-button link type="primary" size="small" @click="handleUpdateTag(scope)">编辑知识点</el-button>
<el-button link type="primary" size="small" @click="handleDelete(scope)">删除</el-button> <el-button link type="primary" size="small" @click="handleDelete(scope)">删除</el-button>
<el-button link type="primary" size="small" @click="handleView('关联课程章节')">查看关联章节</el-button> <el-button link type="primary" size="small" @click="handleCourseView(scope)">查看关联章节</el-button>
<el-button link type="primary" size="small" @click="handleView('关联数字教材章节')" <el-button link type="primary" size="small" @click="handleBookView(scope)">查看关联数字教材</el-button>
>查看关联数字教材</el-button
>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
...@@ -230,10 +185,15 @@ const formInline = reactive({ ...@@ -230,10 +185,15 @@ const formInline = reactive({
</div> </div>
</div> --> </div> -->
</AppCard> </AppCard>
<AddTextbookDialog <ViewGraphCourse
:drawerName="bookName" :id="addTagId"
v-if="isShowTextbookDialog === true" v-if="isShowGraphCourseDialog === true"
v-model:isShowTextbookDialog="isShowTextbookDialog" v-model:isShowGraphCourseDialog="isShowGraphCourseDialog"
/>
<ViewGraphBook
:id="addTagId"
v-if="isShowGraphBookDialog === true"
v-model:isShowGraphBookDialog="isShowGraphBookDialog"
/> />
</template> </template>
<style lang="scss"> <style lang="scss">
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论