| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696 |
- <template>
- <div style="position: relative">
- <div class="left-containe hiddenScroll" :class="[notFixed?'':'notFixed']">
- <div class="catalogue">
- <template v-if="!search_show">
- <span>目录</span>
- <div>
- <span><i class="add-document el-icon-search" style="cursor: pointer;margin-right: 10px;" @click.stop="showSearch"></i></span>
- <span><i class="add-document el-icon-s-unfold" style="cursor: pointer;margin-right: 10px;" @click.stop="foldArticle()"></i></span>
- <span v-if="isMember || isManager"><i class="add-document el-icon-plus" style="cursor: pointer;" @click.stop="newArticle"></i></span>
- </div>
- </template>
- <template v-if="search_show">
- <el-input ref="searchInput" v-model="inputKeyword" :clearable="true" placeholder="搜索文章" @blur="blurSearch" @keyup.enter.native="toSearchArticle" size="small">
- </el-input>
- </template>
- </div>
- <div class="catalogue-tree">
- <el-tree ref=slotTree
- highlight-current
- draggable
- :filter-node-method="filterNode"
- :node-key="NODE_KEY"
- :data="catalogueTree"
- :props="catalogueProps"
- :default-expand-all="expand_all"
- :expand-on-click-node="false"
- :current-node-key="article_id"
- :allow-drag="allowDrag"
- :allow-drop="allowDrop"
- @node-drop="handledropNode"
- @node-click="handleNodeClick"
- >
- <div class="catalogue-tree-node" slot-scope="{ node, data }">
- <el-input
- v-if="node.isEdit"
- v-model="data.article_name"
- autofocus
- size="mini"
- :ref="'slotTreeInput'+data[NODE_KEY]"
- @blur.stop="handleBlur(node, data)"
- @keyup.enter.native="handleInput(node, data)"
- ></el-input>
- <div v-else class="node-containe">
- <span class="node-text text-over">
- {{data.article_name}}
- </span>
- <div class="option-node" v-if="isMember || isManager">
- <i class="add-document el-icon-plus" @click.stop="handleEdit(node, data)"></i>
- <el-popover
- :value="node.isShowOptPop"
- trigger="click"
- placement="bottom"
- width="200"
- >
- <!--<div style="cursor: pointer;margin-bottom:10px" @click.stop="handleEdit(node, data)">新建</div>-->
- <div style="cursor: pointer;margin-bottom:10px" @click.stop="handleRename(node, data)">重命名</div>
- <div style="cursor: pointer;margin-bottom:10px" @click.stop="showDialog(node, data)">移动到</div>
- <div style="cursor: pointer;margin-bottom:10px" @click.stop="toArticleEditor(node, data)">编辑</div>
- <div style="cursor: pointer;margin-bottom:10px" v-if="isManager" @click="handleDelete(node, data)">
- 删除
- </div>
- <i slot="reference" class="set-node el-icon-setting" @click.stop></i>
- </el-popover>
- </div>
- </div>
- </div>
- </el-tree>
- </div>
- </div>
- <el-dialog title="移动到..."
- :visible.sync="dialogTableVisible"
- :lock-scroll="true"
- >
- <div class="scroll-box">
- <div>
- <el-select v-model="select_base" @change="changeBase" placeholder="请选择知识库">
- <el-option
- v-for="item in base_options"
- :key="item.id"
- :label="item.name"
- :value="item.id">
- </el-option>
- </el-select>
- <el-input style="width: 350px;" v-model="article_sort" placeholder="请输入文章排序(数字越大排序越前,默认0)">
- </el-input>
- </div>
- <el-tree
- highlight-current
- :node-key="NODE_KEY"
- :data="selectTree"
- :props="catalogueProps"
- :default-expand-all="true"
- :expand-on-click-node="false"
- :current-node-key="article_id"
- @node-click="clickDialogNode"
- >
- <div class="catalogue-tree-node" slot-scope="{ node, data }">
- <div class="node-containe">
- <span class="node-text text-over">
- {{node.label}}
- </span>
- <div class="hidden radio-box">
- <span style="color:#bfbfbf">移动为</span>
- <el-radio-group v-model="radio">
- <el-radio :label="0">同级</el-radio>
- <el-radio :label="1">子级</el-radio>
- </el-radio-group>
- </div>
- <div class="hidden selector-tree-placeholder"
- :style="{left: radio==1?'25px':'',width: radio==1?'96%':''}"></div>
- </div>
- </div>
- </el-tree>
- </div>
- <span slot="footer" class="dialog-footer">
- <el-button @click="dialogTableVisible = false">取 消</el-button>
- <el-button type="primary" @click="confirmMove">确 定</el-button>
- </span>
- </el-dialog>
- </div>
- </template>
- <script>
- import {mapState} from "vuex";
- export default {
- data() {
- return {
- expand_all: false,
- search_show: false,
- inputKeyword: '',
- article_id: '', // 文章id
- article_sort: "", //文章排序
- // base_id: '', // 知识库id
- show_type: 1, // 1 PC端 2 移动端
- isManager: false,
- isMember: false,
- // 目录
- catalogueTree: [],
- catalogueProps: {
- label: "article_name",
- children: "child",
- },
- parentData: "",
- // 树节点参数
- NODE_KEY: 'id',
- MAX_LEVEL: 4,
- moveNode: '', // 需要弹框移动的节点
- notFixed: true,
- dialogTableVisible: false,
- radio: 0,
- selectTree: [],
- base_options: [],
- select_base: ''
- };
- },
- watch: {
- base_id() {
- this.select_base = Number(this.base_id);
- this.getTreeData();
- },
- },
- computed: {
- ...mapState(["basic_info", "basicSet"]),
- base_id() {
- return this.$route.query.base_id;
- },
- },
- mounted() {
- this.select_base = Number(this.base_id);
- this.getTreeData();
- //监听滚动条
- // window.addEventListener('scroll', this.handleScroll);
- },
- destroyed() {
- // window.removeEventListener('scroll', this.handleScroll);
- },
- methods: {
- showSearch() {
- this.search_show = true;
- setTimeout(()=>{
- this.$refs.searchInput.focus();
- },300);
- },
- filterNode(value, data) {
- if (!value) return true
- return data.article_name.indexOf(value) !== -1
- },
- blurSearch() {
- this.search_show = false;
- if(!this.inputKeyword.trim()) {
- this.$refs.slotTree.filter('')
- }
- },
- toSearchArticle() {
- this.$refs.slotTree.filter(this.inputKeyword.trim())
- },
- foldArticle(id) {
- let nodes= this.$refs.slotTree.store.nodesMap;
- if(id) {
- // 通过循环展开树形
- for(let i in nodes){
- if(nodes[i].data.id == id) {
- nodes[i].expanded = true;
- if(nodes[i].data.parent_id != 0) {
- this.foldArticle(nodes[i].data.parent_id)
- }
- }
- }
- }else {
- this.expand_all = !this.expand_all;
- for(let i in nodes){
- nodes[i].expanded = this.expand_all;
- }
- }
- },
- newArticle() {
- this.$router.push(this.fun.getUrl("knowledge-knowledge_editor", {}, {base_id: this.base_id, articleId: -1}));
- },
- // 目录树结构
- getTreeData(base_id = this.base_id, type) {
- this.fun.$get("plugin.message-base.frontend.article.baseArticle", {base_id: base_id})
- .then((response) => {
- // console.log("知识库结构列表:::", response);
- if (response.result !== 1) {
- console.log(response.msg);
- return;
- }
- this.isMember = response.data.is_member;
- this.isManager = response.data.is_manager;
- if (response.data.article_list.length <= 0) {
- this.$store.commit("setBreadcrumbs", {
- base: {
- id: response.data.base.id,
- name: response.data.base.name
- },
- });
- this.$store.commit("setBaseAuths", {
- isMember: this.isMember,
- isManager: this.isManager,
- isNoList: true,
- });
- return;
- }
- this.$store.commit("setBaseAuths", {
- isMember: this.isMember,
- isManager: this.isManager,
- });
- this.selectTree = response.data.article_list;
- if(type !== 'change') {
- this.$store.commit("setArticleTree", response.data.article_list);
- this.catalogueTree = response.data.article_list;
- }
- if(type !== 'move') {
- if (!this.$route.params.articleId || this.$route.params.articleId == -1) {
- this.article_id = this.catalogueTree[0].id;
- // this.getArticleDetail(this.article_id);
- } else {
- this.article_id = this.$route.params.articleId;
- // this.getArticleDetail(this.article_id);
- }
- }
- this.$nextTick(() => {
- //默认选中
- if (this.$refs.slotTree) this.$refs.slotTree.setCurrentKey(this.article_id);
- this.foldArticle(this.$route.params.articleId);
- })
- })
- },
- // 是否具有拖拽权限
- allowDrag() {
- return this.isManager || this.isMember;
- },
- // 放置校验
- allowDrop(draggingNode, dropNode, type) {
- // if (draggingNode.data.parent_id === dropNode.data.parent_id) {
- // return;
- // } else {
- return true;
- // }
- },
- // 点击
- handleNodeClick(e) {
- if(this.article_id!=e.id) {
- if(e.child && e.child.length > 0) {
- this.foldArticle(e.id);
- }
- this.article_id = e.id;
- this.$store.commit('setKnowledgeLoading', true);
- this.$router.push(this.fun.getUrl("knowledge-knowledge_detail-articleId", {articleId: this.article_id}, {base_id: this.base_id}));
- }
- },
- // 修改
- handleInput(_node, _data) {
- if (!this.isMember && !this.isManager) {
- this.$message.error("暂无权限操作");
- return;
- }
- if (_node.isEdit) {
- this.$set(_node, 'isEdit', false)
- }
- if (_data.article_name === '') {
- this.$set(_data, "article_name", "新增文章")
- }
- },
- // 失去焦点
- handleBlur(_node, _data) {
- // 新增-请求
- // let addNodeRequset = () => {
- // this.fun.$get("plugin.message-base.frontend.article.changeArticle", {
- // base_id: this.base_id,
- // parent_id: _data.parent_id,
- // article_name: _data.article_name,
- // article: '',
- // })
- // .then((response) => {
- // if (response.result !== 1) {
- // this.$refs.slotTree.remove(_data);
- // this.$message.error(response.msg);
- // return;
- // }
- // this.$set(_data, 'id', response.data.id);
- // this.$message.success(response.msg);
- // });
- // };
- // 修改-请求
- let editNodeRequest = () => {
- this.fun.$get("plugin.message-base.frontend.article.changeArticle", {
- article_id: _data.id,
- article_name: _data.article_name
- })
- .then((response) => {
- if (response.result !== 1) {
- this.$message.error(response.msg);
- }else {
- if(this.article_id == _data.id) {
- location.reload();
- }
- }
- });
- }
- // this.isCreate ? addNodeRequset() : editNodeRequest();
- editNodeRequest()
- this.$set(_node, 'isEdit', false);
- },
- // 新增
- handleEdit(_node, _data) {
- if (!this.isMember && !this.isManager) {
- this.$message.error("暂无权限操作");
- return;
- }
- if (_node.level >= this.MAX_LEVEL) {
- this.$message.warning("当前已达到" + this.MAX_LEVEL + "级,无法新增!")
- return;
- }
- this.$router.push(this.fun.getUrl("knowledge-knowledge_editor", {}, {
- base_id: this.base_id,
- parent_id: _data.id
- }));
- },
- // 编辑
- handleRename(_node, _data) {
- if (!this.isMember && !this.isManager) {
- this.$message.error("暂无权限操作");
- return;
- }
- if (!_node.isEdit) {
- this.$set(_node, 'isEdit', true)
- }
- this.$nextTick(() => {
- if (this.$refs['slotTreeInput' + _data[this.NODE_KEY]]) {
- this.$refs['slotTreeInput' + _data[this.NODE_KEY]].$refs.input.focus()
- }
- })
- },
- // 跳转编辑页
- toArticleEditor(node, data) {
- if (!this.isMember && !this.isManager) {
- this.$message.error("暂无权限操作");
- return;
- }
- let artId = data.id;
- let base_id = this.fun.getKey("base_id");
- this.$router.push(this.fun.getUrl("knowledge-knowledge_editor", {}, {base_id: base_id, articleId: artId}));
- },
- // 删除
- handleDelete(_node, _data) {
- if (!this.isManager) {
- this.$message.error("您不是管理员,暂无权限删除");
- return;
- }
- this.$confirm("是否删除?", "提示", {
- confirmButtonText: "确认",
- cancelButtonText: "取消",
- type: "warning"
- }).then((res) => {
- removeQuery();
- }).catch(() => {
- });
- let removeQuery = () => {// 发送删除请求
- this.fun.$get("plugin.message-base.frontend.article.deleteArticle", {article_id: _data.id}, "loading")
- .then((response) => {
- if (response.result !== 1) {
- this.$message.error(response.msg);
- return;
- }
- this.$refs.slotTree.remove(_data)
- this.$message.success("删除成功");
- });
- }
- },
- // 完成拖拽
- handledropNode(before, after, inner, event) {
- this.moveRequest(before, after.data.parent_id, after.data, inner);
- },
- // 接口请求
- moveRequest(moveNode, parentId, parentData, inner) {
- let json = {
- article_id: moveNode.data.id,
- parent_id: "",
- last_id: "",
- base_id: this.select_base
- };
- if (inner === 'after') {
- json = {
- article_id: moveNode.data.id,
- parent_id: parentId,
- last_id: parentData.id,
- move_type: '1',
- base_id: this.select_base
- };
- }else if(inner === 'inner'){
- json = {
- article_id: moveNode.data.id,
- parent_id: parentData.id,
- last_id: 0,
- move_type: '1',
- base_id: this.select_base
- };
- } else if(inner === 'before'){
- json = {
- article_id: moveNode.data.id,
- parent_id: parentId,
- last_id: parentData.id,
- move_type: '2',
- base_id: this.select_base
- };
- }
- console.log(json)
- this.fun.$get("plugin.message-base.frontend.article.moveArticle", json, "loading")
- .then((response) => {
- if (response.result !== 1) {
- this.getTreeData(this.base_id, 'move');
- this.$message.error(response.msg);
- return;
- }
- if(moveNode.data.id == this.$route.params.articleId) {
- this.handleNodeClick({id: this.catalogueTree[0].id})
- }
- this.dialogTableVisible = false;
- this.getTreeData(this.base_id, 'move');
- this.$message.success("移动成功");
- })
- },
- // 显示移动弹框
- showDialog(_node, _data) {
- if (!this.isMember && !this.isManager) {
- this.$message.error("暂无权限操作");
- return;
- }
- this.getCanMoveBase(_node, _data)
- },
- getCanMoveBase(_node, _data) {
- this.fun.$get("plugin.message-base.frontend.article.getAllAuthBase", {}, "loading")
- .then((response) => {
- if (response.result !== 1) {
- this.$message.error(response.msg);
- return;
- }
- this.base_options = response.data;
- this.dialogTableVisible = true;
- this.moveNode = _node;
- })
- },
- changeBase() {
- this.getTreeData(this.select_base, 'change')
- },
- // 弹框点击
- clickDialogNode(_data, _node) {
- this.parentData = _data;
- // this.radio ==0同级添加
- // this.radio ==1子级添加
- },
- // 确定按钮
- confirmMove() {
- this.moveRequest(this.moveNode, this.radio==1 ? this.parentData.id : this.parentData.parent_id, this.parentData, this.radio?'inner':'after');
- },
- handleScroll() {
- let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
- let boxHeight = document.getElementById("knowledge-article").offsetHeight + 70;
- let clientHeight = -(document.documentElement.clientHeight - boxHeight);
- if (scrollTop < clientHeight) {
- this.notFixed = true;
- } else {
- this.notFixed = false;
- }
- },
- }
- };
- </script>
- <style lang="scss" rel="stylesheet/scss" scoped>
- .text-over {
- overflow: hidden;
- white-space: nowrap;
- width: 100%;
- text-overflow: ellipsis;
- }
- .left-containe {
- background-color: #fafafa;
- left: 0;
- }
- // 滚动条隐藏
- .hiddenScroll {
- scrollbar-width: none; /* firefox */
- -ms-overflow-style: none; /* IE 10+ */
- overflow-x: hidden;
- overflow-y: scroll;
- }
- .hiddenScroll::-webkit-scrollbar {
- display: none; /* Chrome Safari */
- }
- .left-containe {
- z-index: 2;
- position: fixed;
- top: 70px;
- width: 20vw;
- height: calc(100vh - 75px);
- border-right: solid 1px #efefef;
- overflow-y: scroll;
- background-color: #fafafa;
- .catalogue {
- display: flex;
- align-items: center;
- justify-content: space-between;
- letter-spacing: 1px;
- color: #595959;
- font-size: 14px;
- font-weight: bold;
- padding: 15px 25px;
- border-bottom: solid 1px #e2e2e2;
- margin-bottom: 25px;
- }
- .catalogue-tree, .synopsis-tree {
- padding-left: 15px;
- .catalogue-tree-node {
- width: 100%;
- .node-containe {
- display: flex;
- width: 100%;
- flex-wrap: nowrap;
- white-space: nowrap;
- padding-right: 10px;
- }
- .node-text {
- flex: 1;
- width: 0; // 元素自适应超出隐藏
- }
- .option-node {
- margin-right: 5px;
- display: none;
- font-size: 15px;
- }
- }
- .catalogue-tree-node:hover .option-node {
- display: inline-block;
- }
- :deep(.el-tree) {
- background: transparent;
- .el-tree-node__content {
- padding: 8px 0;
- }
- .el-tree-node__label {
- font-size: 14px;
- letter-spacing: 1px;
- color: #595959;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .el-tree__drop-indicator {
- height: 2px;
- }
- .is-current > .el-tree-node__content .node-text {
- color: #66B1FF;
- }
- .is-current > .el-tree-node__content .el-tree-node__label {
- // color: var(--color);
- }
- }
- }
- .synopsis-tree {
- margin-top: 20px;
- border-left: 2px solid #e8e8e8;
- }
- }
- .left-containe.notFixed {
- display: none;
- /*position: absolute;*/
- /*top: 60px;*/
- /*height: 100%;*/
- }
- .scroll-box {
- height: 50vh;
- overflow-y: scroll;
- :deep(.el-tree) {
- background: transparent;
- .el-tree-node__content {
- margin: 6px 0;
- .hidden {
- display: none;
- }
- .catalogue-tree-node {
- position: relative;
- flex: 1;
- .node-containe {
- display: flex;
- width: 100%;
- flex-wrap: nowrap;
- white-space: nowrap;
- .node-text {
- flex: 1;
- width: 0; // 元素自适应超出隐藏
- }
- }
- }
- }
- .is-current > .el-tree-node__content {
- .catalogue-tree-node {
- position: relative;
- flex: 1;
- .radio-box {
- display: block;
- }
- .el-radio {
- font-size: 12px;
- margin-right: 0;
- margin-left: 10px;
- }
- .selector-tree-placeholder {
- display: block;
- position: absolute;
- bottom: -5px;
- left: 0;
- width: 100%;
- height: 2px;
- background-color: #66B1FF;
- }
- }
- }
- .el-tree-node__label {
- font-size: 14px;
- letter-spacing: 1px;
- color: #595959;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- }
- }
- .dialog-footer {
- display: flex;
- justify-content: center;
- }
- </style>
|