需求
- 整体宽高占一屏,超出滚动条
- tree组件点击懒加载每一级数据,一共三级
- 三级节点前加icon,标识是否已学习
- 点击高亮显示背景图
- 横向超出省略显示或者横向滚动条
- 纵向超出纵向滚动条
- 修改其字体和间距
- ☆☆☆☆☆从别的页面跳入回显三级点击状态
tree组件
<el-card
shadow="hover"
class="solo mr-10"
style="height: calc(100vh - 85px); width: 330px"
>
<div slot="header" class="clearfix">
<span>问题分类</span>
</div>
<div class="scroll-tree">
<el-scrollbar style="height: 100%">
<!--accordion -->
<el-tree
ref="popularTree"
highlight-current
:props="defaultProps"
lazy
:default-expanded-keys="treeExpandedKeys"
:load="loadNode"
@node-click="handleNodeClick"
node-key="knowledgeBaseTypeId"
>
<span class="custom-tree-node" slot-scope="{ node, data }">
<div class="flex_l">
<i
v-if="node.level == 3 && data.whetherLearn == 1"
class="el-icon-success blue size-10 mr-4"
></i>
<span
style="max-width: 270px"
class="line-1"
:class="
node.level == 1
? 'bold gray-1'
: node.level == 2
? 'gray-1'
: ''
"
>{{ data.knowledgeBaseTypeId }}{{ data.typeName }}</span
>
</div>
</span>
</el-tree>
</el-scrollbar>
</div>
</el-card>
nodeIdArr: [], // 首页跳转过来携带的三级id [2,3,4]
isFirst: false, // 是否从首页来
treeExpandedKeys: [], // 默认展开的节点id
defaultProps: {
children: "children",
label: "typeName",
isLeaf: "leaf",
},
modelId: null, // 模型id
info: {}, //详情
mounted() {
this.nodeIdArr = this.$route.query.id.split(",").map((item) => item * 1);
if (this.nodeIdArr.length > 0) {
this.isFirst = true;
}
},
methods: {
async loadNode(node, resolve) {
console.log("loadNode", 1111, node);
// 根据 node.level 获取相应层级的数据
const level = node.level;
const { data } = await this.$axios.get(
"/qualityTrain/knowledgeBase/type/tree?parentId=" +
(level == 0 ? 0 : node.data.knowledgeBaseTypeId)
);
// 从首页跳入的时候,默认选中知识点高亮
this.highlight(node, data);
if (node.level == 2) {
data.forEach((item) => {
item.leaf = true;
});
}
resolve(data);
},
// 从首页跳入的时候,默认选中知识点高亮
highlight(node, data) {
if (this.nodeIdArr.length > 0 && this.isFirst) {
// 默认展开1级和2级
this.treeExpandedKeys.push(this.nodeIdArr[0]);
this.treeExpandedKeys.push(this.nodeIdArr[1]);
if (node.level == 2) {
console.log("loadNode", 6666, data);
let currentNode = data.filter(
(item) => item.knowledgeBaseTypeId == this.nodeIdArr[2]
);
if (currentNode.length > 0) {
// 设置高亮
this.$nextTick(function () {
this.$refs.popularTree.setCurrentKey(currentNode[0].knowledgeBaseTypeId);
});
// 模拟自动点击
this.handleNodeClick(currentNode[0]);
} else {
this.$message.error("知识点已下架");
}
this.isFirst = false;
}
}
},
handleNodeClick(data) {
console.log("Clicked node:", data);
this.info = {};
this.$refs.modelRef.changeCom([]);
if (data.modelId != this.modelId) {
this.modelId = data.modelId;
if (this.modelId) {
this.$refs.modelRef.init(this.modelId);
}
}
if (data.level == 3) {
// 获取知识点详情
this.$axios
.get("/qualityTrain/knowledgeBase/type/" + data.knowledgeBaseTypeId)
.then((res) => {
this.info = res.data;
// 获取构件信息
this.$refs.modelRef.changeCom(
res.data.componentJsonStr
? JSON.parse(res.data.componentJsonStr)
: []
);
});
// 更新学习状态
if (data.whetherLearn == 0) {
this.$axios
.post("/qualityTrain/knowledgeBase/updateLearnStatus", {
knowledgeBaseTypeId: data.knowledgeBaseTypeId,
})
.then((res) => {
data.whetherLearn = 1;
});
}
}
},
},
/deep/.el-card__header {
font-weight: 700;
padding: 0.17rem;
border-bottom: 0px solid #000;
font-size: 16px;
}
/deep/ .el-tree-node__content {
height: 33px;
/* box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.03); */
}
/deep/.el-tree--highlight-current
.el-tree-node.is-current
> .el-tree-node__content {
/* background: rgba(238, 243, 254, 1);
border-left: 5px solid rgba(64, 158, 255, 1); */
background: url("../../assets/img/tree-bg.png") no-repeat center center;
background-size: 100% 100%;
color: rgba(64, 158, 255, 1);
font-weight: 700;
border-radius: 3px;
/* padding-left: 31px !important; */
}
/* /deep/.el-tree--highlight-current
.el-tree-node.is-current
> .el-tree-node__content
.el-tree-node__expand-icon {
color: rgba(64, 158, 255, 1);
} */
/deep/.el-tree--highlight-current
.el-tree-node.is-current
> .el-tree-node__content
.el-tree-node__expand-icon.is-leaf {
color: transparent;
font-size: 0px;
}
/deep/.el-tree-node__expand-icon {
color: #333;
}
/deep/.el-tree-node__expand-icon.is-leaf {
color: transparent;
font-size: 0px;
}
/* 添加水平滚动条和纵向滚动条 */
.scroll-tree {
overflow: auto;
height: calc(100vh - 140px);
}
.scroll-tree ::-webkit-scrollbar {
width: 10px;
height: 10px;
}
.el-tree {
display: inline-block;
min-width: 100%;
}
/deep/.solo .el-card__body {
padding: 0px;
}
/deep/.solo1 .el-card__body {
padding-top: 4px;
}
整个组件
<template>
<div id="index" class="bg w100 vh100">
<div class="">
<div class="flex pl-20" style="height: 70px">
<el-page-header @back="goBack" content="知识库"> </el-page-header>
<!-- <div class="flex_r">
已学习<span class="size-26 green bold ml-10">{{
formattedTime
}}</span>
</div> -->
</div>
<div class="flex_l flex-top plr-20">
<el-card
shadow="hover"
class="solo mr-10"
style="height: calc(100vh - 85px); width: 330px"
>
<div slot="header" class="clearfix">
<span>问题分类</span>
</div>
<div class="scroll-tree">
<el-scrollbar style="height: 100%">
<!--accordion -->
<el-tree
ref="popularTree"
highlight-current
:props="defaultProps"
lazy
:default-expanded-keys="treeExpandedKeys"
:load="loadNode"
@node-click="handleNodeClick"
node-key="knowledgeBaseTypeId"
>
<span class="custom-tree-node" slot-scope="{ node, data }">
<div class="flex_l">
<i
v-if="node.level == 3 && data.whetherLearn == 1"
class="el-icon-success blue size-10 mr-4"
></i>
<span
style="max-width: 270px"
class="line-1"
:class="
node.level == 1
? 'bold gray-1'
: node.level == 2
? 'gray-1'
: ''
"
>{{ data.knowledgeBaseTypeId }}{{ data.typeName }}</span
>
</div>
</span>
</el-tree>
</el-scrollbar>
</div>
</el-card>
<div
v-show="modelId"
class="border"
style="height: calc(100vh - 85px); width: 48%"
>
<ZhipeiModel ref="modelRef"></ZhipeiModel>
</div>
<div
class="scroll ml-10"
:style="`height: calc(100vh - 85px); width: calc(${
modelId ? '52%' : '100%'
} - 350px)`"
>
<el-card shadow="never">
<div class="title">知识点</div>
<div class="text">
{{ info.typeName }}
</div>
</el-card>
<el-card shadow="never" class="mtb-10">
<div class="title">详细描述</div>
<div v-html="info.detailedDescription"></div>
</el-card>
<el-card
shadow="never"
class="mtb-10"
v-if="
info.knowledgeBasePictureList?.length > 0 ||
info.knowledgeBaseVideoList?.length > 0
"
>
<div v-if="info.knowledgeBasePictureList?.length > 0">
<div class="title">图片</div>
<div>
<el-image
v-for="(item, i) in info.knowledgeBasePictureList"
:key="i"
style="width: 1.14rem; height: 1.14rem; border-radius: 6px"
:src="item.pictureUrl"
:preview-src-list="
info.knowledgeBasePictureList.map((item) => item.pictureUrl)
"
class="mr-6"
>
</el-image>
</div>
</div>
<div v-if="info.knowledgeBaseVideoList?.length > 0">
<div class="title">视频</div>
<div class="flex_l flex-wrap">
<video
v-for="(item, i) in info.knowledgeBaseVideoList"
:key="i"
:style="`width: ${
modelId ? '48%' : '3rem'
}; height: 2rem; background: #000`"
controls
:src="item.videoUrl"
class="w100 h100 mr-6"
></video>
</div>
</div>
</el-card>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
layout: "layout1",
data() {
return {
nodeIdArr: [], //首页跳转过来携带的三级id
isFirst: false,
treeExpandedKeys: [], // 展开的节点id
defaultProps: {
children: "children",
label: "typeName",
isLeaf: "leaf",
},
modelId: null, // 模型id
info: {}, //题目详情
itemList: [], //题目列表
id: null, //选中题目id
};
},
computed: {
...mapState(["userInfo"]),
},
mounted() {
this.nodeIdArr = this.$route.query.id.split(",").map((item) => item * 1);
if (this.nodeIdArr.length > 0) {
this.isFirst = true;
}
},
methods: {
async loadNode(node, resolve) {
console.log("loadNode", 1111, node);
// 根据 node.level 获取相应层级的数据
const level = node.level;
const { data } = await this.$axios.get(
"/qualityTrain/knowledgeBase/type/tree?parentId=" +
(level == 0 ? 0 : node.data.knowledgeBaseTypeId)
);
// 从首页跳入的时候,默认选中知识点高亮
this.highlight(node, data);
if (node.level == 2) {
data.forEach((item) => {
item.leaf = true;
});
}
resolve(data);
},
// 从首页跳入的时候,默认选中知识点高亮
highlight(node, data) {
if (this.nodeIdArr.length > 0 && this.isFirst) {
// 默认展开1级和2级
this.treeExpandedKeys.push(this.nodeIdArr[0]);
this.treeExpandedKeys.push(this.nodeIdArr[1]);
if (node.level == 2) {
console.log("loadNode", 6666, data);
let currentNode = data.filter(
(item) => item.knowledgeBaseTypeId == this.nodeIdArr[2]
);
if (currentNode.length > 0) {
// 设置高亮
this.$nextTick(function () {
this.$refs.popularTree.setCurrentKey(currentNode[0].knowledgeBaseTypeId);
});
// 模拟自动点击
this.handleNodeClick(currentNode[0]);
} else {
this.$message.error("知识点已下架");
}
this.isFirst = false;
}
}
},
handleNodeClick(data) {
console.log("Clicked node:", data);
this.info = {};
this.$refs.modelRef.changeCom([]);
if (data.modelId != this.modelId) {
this.modelId = data.modelId;
if (this.modelId) {
this.$refs.modelRef.init(this.modelId);
}
}
if (data.level == 3) {
// 获取知识点详情
this.$axios
.get("/qualityTrain/knowledgeBase/type/" + data.knowledgeBaseTypeId)
.then((res) => {
this.info = res.data;
// 获取构件信息
this.$refs.modelRef.changeCom(
res.data.componentJsonStr
? JSON.parse(res.data.componentJsonStr)
: []
);
});
// 更新学习状态
if (data.whetherLearn == 0) {
this.$axios
.post("/qualityTrain/knowledgeBase/updateLearnStatus", {
knowledgeBaseTypeId: data.knowledgeBaseTypeId,
})
.then((res) => {
data.whetherLearn = 1;
});
}
}
},
goBack() {
this.$router.go(-1);
},
},
};
</script>
<style scoped lang="css">
/deep/.el-card__header {
font-weight: 700;
padding: 0.17rem;
border-bottom: 0px solid #000;
font-size: 16px;
}
/deep/ .el-tree-node__content {
height: 33px;
/* box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.03); */
}
/deep/.el-tree--highlight-current
.el-tree-node.is-current
> .el-tree-node__content {
/* background: rgba(238, 243, 254, 1);
border-left: 5px solid rgba(64, 158, 255, 1); */
background: url("../../assets/img/tree-bg.png") no-repeat center center;
background-size: 100% 100%;
color: rgba(64, 158, 255, 1);
font-weight: 700;
border-radius: 3px;
/* padding-left: 31px !important; */
}
/* /deep/.el-tree--highlight-current
.el-tree-node.is-current
> .el-tree-node__content
.el-tree-node__expand-icon {
color: rgba(64, 158, 255, 1);
} */
/deep/.el-tree--highlight-current
.el-tree-node.is-current
> .el-tree-node__content
.el-tree-node__expand-icon.is-leaf {
color: transparent;
font-size: 0px;
}
/deep/.el-tree-node__expand-icon {
color: #333;
}
/deep/.el-tree-node__expand-icon.is-leaf {
color: transparent;
font-size: 0px;
}
/* 添加水平滚动条和纵向滚动条 */
.scroll-tree {
overflow: auto;
height: calc(100vh - 140px);
}
.scroll-tree ::-webkit-scrollbar {
width: 10px;
height: 10px;
}
.el-tree {
display: inline-block;
min-width: 100%;
}
/deep/.solo .el-card__body {
padding: 0px;
}
/deep/.solo1 .el-card__body {
padding-top: 4px;
}
.title {
font-weight: bold;
margin: 15px 0;
/* border-left: 4px solid #00cdba; */
line-height: 15px;
padding-left: 6px;
font-size: 16px;
}
.active {
background: rgba(0, 205, 186, 0.1);
color: #00cdba;
font-weight: 700;
}
.text {
text-align: justify;
padding: 0 10px;
}
</style>