wiki增加导航和拖动改变左侧菜单宽度功能,编辑器默认改为markdown模式

This commit is contained in:
暮光:城中城
2021-12-02 23:18:31 +08:00
parent af645464e4
commit 22a73b445a
28 changed files with 502 additions and 353 deletions

View File

@@ -0,0 +1,115 @@
export default {
/**
* 生成目录树
* ========================================================
* 说明:代码修改至 yaohaixiao 的 autoc.js
* 项目 gitee 地址https://gitee.com/yaohaixiao/AutocJS
* ========================================================
*/
createNavigationHeading() {
let headArr = [];
let headNodeArr = document.querySelector('.wiki-page-content').querySelectorAll('h1,h2,h3,h4,h5,h6');
if (headNodeArr.length <= 0) {
return [];
}
headNodeArr.forEach(node => {
headArr.push({
node: node,
level: parseInt(node.tagName.replace(/[h]/i, ''), 10)
});
});
let chapters = []
let previous = 1
let level = 0
headArr.forEach((heading, i) => {
let current = heading.level
let pid = -1
// 当前标题的(标题标签)序号 > 前一个标题的序号:两个相连的标题是父标题 -> 子标题关系;
// h2 (前一个标题)
// h3 (当前标题)
if (current > previous) {
level += 1
// 第一层级的 pid 是 -1
if (level === 1) {
pid = -1
} else {
pid = i - 1
}
}
// 当前标题的(标题标签)序号 = 前一个标题的序号
// h2 (前一个标题)
// h2 (当前标题)
// 当前标题的(标题标签)序号 < 前一个标题的序号,并且当前标题序号 > 当前的级别
// h2
// h4 (前一个标题)
// h3 (当前标题:这种情况我们还是任务 h3 是 h2 的下一级章节)
else if (current === previous || (current < previous && current > level)) {
// H1 的层级肯定是 1
if (current === 1) {
level = 1
pid = -1
} else {
pid = chapters[i - 1].pid
}
} else if (current <= level) {
// H1 的层级肯定是 1
if (current === 1) {
level = 1
} else {
level = level - (previous - current)
if (level <= 1) {
level = 1
}
}
// 第一级的标题
if (level === 1) {
pid = -1
} else {
// 虽然看上去差点,不过能工作啊
pid = this.generatePid(chapters, previous - current, i)
}
}
previous = current
chapters.push({
id: i,
pid: pid,
level: level,
node: heading.node,
text: this.stripTags(this.trim(heading.node.innerHTML))
});
})
console.log(chapters);
return chapters;
},
trim: (str) => {
return str.replace(/^\s+/g, '').replace(/\s+$/g, '')
},
stripTags: (str) => {
return str.replace(/<\/?[^>]+(>|$)/g, '')
},
generatePid(chapters, differ, index) {
let pid
// 最大只有 5 级的差距
switch (differ) {
case 2:
pid = chapters[chapters[chapters[index - 1].pid].pid].pid
break
case 3:
pid = chapters[chapters[chapters[chapters[index - 1].pid].pid].pid].pid
break
case 4:
pid = chapters[chapters[chapters[chapters[chapters[index - 1].pid].pid].pid].pid].pid
break
case 5:
pid = chapters[chapters[chapters[chapters[chapters[chapters[index - 1].pid].pid].pid].pid].pid].pid
break
default:
pid = chapters[chapters[index - 1].pid].pid
break
}
return pid
},
}

View File

@@ -0,0 +1,26 @@
export default {
computeFileSize(fileSize) {
if (!fileSize) {
return '-';
}
let size = "";
if (fileSize < 0.1 * 1024) {
size = fileSize.toFixed(2) + "B"
} else if (fileSize < 0.1 * 1024 * 1024) {
size = (fileSize / 1024).toFixed(2) + "KB"
} else if (fileSize < 0.1 * 1024 * 1024 * 1024) {
size = (fileSize / (1024 * 1024)).toFixed(2) + "MB"
} else {
size = (fileSize / (1024 * 1024 * 1024)).toFixed(2) + "GB"
}
let sizeStr = size + "";
let index = sizeStr.indexOf(".");
let dou = sizeStr.substr(index + 1, 2);
if (dou == "00") {
return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2)
}
return size;
},
}

View File

@@ -1,90 +0,0 @@
import vue from '../../main'
export default {
data: {
accessToken: '',
},
setAccessToken: function (token) {
this.data.accessToken = token;
},
getAccessToken: function () {
if (!this.data.accessToken) {
var arr, reg = new RegExp("(^| )accessToken=([^;]*)(;|$)");
if (arr = document.cookie.match(reg)) {
this.data.accessToken = unescape(arr[2]);
}
}
return this.data.accessToken;
},
validateResult: function (res) {
return new Promise(function (resolve, reject) {
if (!!res.message) {
vue.$message('请求错误:' + res.message);
} else if (res.data.errCode == 400) {
vue.$message('请先登录');
var href = encodeURIComponent(window.location.href);
window.location = process.env.VUE_APP_BASE_API + "#/user/login?redirect=" + href;
} else if (res.data.errCode == 402) {
vue.$router.push("/common/noAuth");
} else if (res.data.errCode !== 200) {
vue.$message(res.data.errMsg || "未知错误");
} else {
resolve(res.data);
}
});
},
/**
* 返回不为空的字符串为空返回def
*/
getNotEmptyStr(str, def) {
if (isEmpty(str)) {
return isEmpty(def) ? "" : def;
}
return str;
},
/**
* 是否是空对象
* @param obj
* @returns
*/
isEmptyObject(obj) {
return isEmpty(obj) || $.isEmptyObject(obj);
},
/**
* 是否是空字符串
* @param str
* @returns
*/
isEmpty(str) {
return (str == "" || str == null || str == undefined);
},
/**
* 是否不是空字符串
* @param str
* @returns
*/
isNotEmpty(str) {
return !isEmpty(str);
},
/**
* param 将要转为URL参数字符串的对象
* key URL参数字符串的前缀
* encode true/false 是否进行URL编码,默认为true
* return URL参数字符串
*/
objUrlEncode(param, key, encode) {
if (param == null) return '';
var paramStr = '';
var t = typeof (param);
if (t == 'string' || t == 'number' || t == 'boolean') {
paramStr += '&' + key + '=' + ((encode == null || encode) ? encodeURIComponent(param) : param);
} else {
for (var i in param) {
var k = key == null ? i : key + (param instanceof Array ? '[' + i + ']' : '.' + i);
paramStr += urlEncode(param[i], k, encode);
}
}
return paramStr;
}
}

View File

@@ -1,7 +1,7 @@
<template>
<div class="global-layout-vue">
<el-container>
<el-aside v-show="leftCollapse">
<el-aside v-show="leftCollapse" :style="{ width: rightAsideWidth + 'px' }">
<div style="padding: 10px;height: 100%;box-sizing: border-box;background: #fafafa;">
<div style="margin-bottom: 10px;">
<el-select :value="choiceSpace" @change="spaceChangeEvents" filterable placeholder="选择空间" style="width: 100%;">
@@ -31,10 +31,11 @@
</div>
</div>
</el-aside>
<RightResize v-model="rightAsideWidth" v-show="leftCollapse"></RightResize>
<el-container>
<el-header>
<i class="el-icon-upload2" v-if="leftCollapse" @click="turnLeftCollapse"></i>
<i class="el-icon-download" v-else @click="turnLeftCollapse"></i>
<i class="el-icon-fold el-icon-s-fold" v-if="leftCollapse" @click="turnLeftCollapse"></i>
<i class="el-icon-fold el-icon-s-unfold" v-else @click="turnLeftCollapse"></i>
<span class="header-right-user-name">{{userSelfInfo.userName}}</span>
<el-popover placement="bottom" width="600" trigger="click" v-model="userMessagePopVisible">
<el-badge :is-dot="haveNotReadUserMessage" slot="reference" style="line-height: 20px;margin: 0 15px;">
@@ -98,6 +99,7 @@
import userApi from '../../common/api/user'
import pageApi from '../../common/api/page'
import CreateSpace from '../space/CreateSpace'
import RightResize from './RightResize.vue'
import aboutDialog from "../../views/common/AboutDialog";
export default {
@@ -134,9 +136,11 @@
pageNum: 1,
pageSize: 20,
},
rightAsideWidth: 300,
}
},
components: {
RightResize,
"create-space": CreateSpace,
'about-dialog': aboutDialog
},
@@ -376,8 +380,8 @@
}
.header-right-user-name{color: #fff;padding-right: 5px;}
.el-header {color: #333; line-height: 40px; text-align: right;height: 40px !important;}
.el-icon-download,.el-icon-upload2{transform: rotate(-90deg);float: left;font-size: 25px;color: #aaa;margin-top: 8px;cursor: pointer;}
.el-icon-download:hover,.el-icon-upload2:hover{color: #eee;}
.el-icon-fold{float: left;font-size: 25px;color: #aaa;margin-top: 8px;cursor: pointer;}
.el-icon-fold:hover{color: #eee;}
.head-icon{margin-right: 15px; font-size: 16px;cursor: pointer;color: #fff;}
.header-user-message .page-info-box{text-align: right;margin-top: 10px;}
.upgrade-info{max-height: 150px;overflow-y: auto;word-break: break-all; white-space: pre-wrap; line-height: 26px;}

View File

@@ -0,0 +1,76 @@
<template>
<div ref="rightResize" class="right-resize">
<i ref="rightResizeBar">...</i>
</div>
</template>
<script>
export default {
data() {
return {
rightAsideWidth: 300,
}
},
mounted() {
this.dragChangeRightAsideWidth();
},
methods: {
dragChangeRightAsideWidth() {
// 保留this引用
let resize = this.$refs.rightResize;
let resizeBar = this.$refs.rightResizeBar;
resize.onmousedown = e => {
let startX = e.clientX;
// 颜色改变提醒
resize.style.background = "#ccc";
resizeBar.style.background = "#aaa";
resize.left = resize.offsetLeft;
document.onmousemove = e2 => {
// 计算并应用位移量
let endX = e2.clientX;
let moveLen = startX - endX;
if ((moveLen < 0 && this.rightAsideWidth < 600) || (moveLen > 0 && this.rightAsideWidth > 300)) {
startX = endX;
this.rightAsideWidth -= moveLen;
if (this.rightAsideWidth < 300) {
this.rightAsideWidth = 300;
}
this.$emit('input', this.rightAsideWidth);
}
};
document.onmouseup = () => {
// 颜色恢复
resize.style.background = "#fafafa";
resizeBar.style.background = "#ccc";
document.onmousemove = null;
document.onmouseup = null;
};
return false;
};
}
}
};
</script>
<style scoped>
.right-resize {
width: 5px;
height: 100%;
cursor: w-resize;
background: #fafafa;
}
.right-resize i {
margin-top: 300px;
width: 5px;
height: 35px;
display: inline-block;
word-wrap: break-word;
word-break: break-all;
line-height: 8px;
border-radius: 5px;
background: #ccc;
color: #888;
}
</style>

View File

@@ -1,7 +1,7 @@
<template>
<div style="height: 100%;">
<el-container>
<el-aside width="300px" style="background-color: #fafafa;" v-show="leftCollapse">
<el-aside width="300px" style="background-color: #fafafa;" :style="{ width: rightAsideWidth + 'px' }" v-show="leftCollapse">
<div class="logo">{{nowSpaceShow.name}}</div>
<div style="padding: 10px;box-sizing: border-box;background: #fafafa;">
<el-input v-model="searchKeywords" @keyup.enter.native="searchByKeywords" placeholder="搜索文档" style="margin: 10px 0;">
@@ -17,6 +17,7 @@
<div class="build-info">本文档使用<a target="_blank" href="https://gitee.com/zyplayer/zyplayer-doc">zyplayer-doc</a>构建</div>
</div>
</el-aside>
<RightResize v-model="rightAsideWidth" v-show="leftCollapse"></RightResize>
<el-container>
<el-main class="doc-body-box">
<router-view></router-view>
@@ -28,6 +29,7 @@
<script>
import pageApi from '../../common/api/page'
import RightResize from './RightResize.vue'
export default {
data() {
@@ -46,8 +48,10 @@
// 页面展示相关
wikiPageList:[],
wikiPageExpandedKeys: [],
rightAsideWidth: 300,
}
},
components: {RightResize},
mounted: function () {
this.spaceUuid = this.$route.query.space || '';
this.getSpaceInfo();

View File

@@ -6,8 +6,8 @@
<template v-if="pageId">
<span>编辑方式</span>
<el-select v-model="wikiPageEdit.editorType" v-on:change="editorTypeChange" :disabled="!!pageId">
<el-option label="HTML" :value="1"></el-option>
<el-option label="Markdown" :value="2"></el-option>
<el-option label="HTML" :value="1"></el-option>
</el-select>
</template>
<template v-else>
@@ -17,8 +17,8 @@
</el-tooltip>
<span style="margin-left: 50px;">编辑方式</span>
<el-select v-model="wikiPageEdit.editorType" v-on:change="editorTypeChange" :disabled="!!pageId">
<el-option label="HTML" :value="1"></el-option>
<el-option label="Markdown" :value="2"></el-option>
<el-option label="HTML" :value="1"></el-option>
</el-select>
</template>
</el-col>
@@ -54,7 +54,7 @@
editor: {},
// 编辑相关
wikiPageEdit: {
editorType: 1,
editorType: 2,
pageTitle: "",
},
wikiPage: {},

View File

@@ -2,85 +2,89 @@
<div class="page-show-vue">
<el-row type="border-card" style="height: 100%;">
<el-col :span="actionTabVisible?18:24" style="padding: 20px;border-right: 1px solid #f1f1f1;height: 100%;overflow: auto;">
<div style="max-width: 1000px;margin: 0 auto;">
<div class="wiki-title">{{wikiPage.name}}</div>
<div class="wiki-author">
<div>
<span v-if="wikiPage.updateUserName">{{wikiPage.updateUserName}}  {{wikiPage.updateTime}} 修改</span>
<span v-else class="create-user-time">{{wikiPage.createUserName}}  {{wikiPage.createTime}} 创建</span>
<div style="float: right;">
<el-button type="text" icon="el-icon-chat-line-round" @click="showCommentWiki" style="margin-right: 10px;">评论</el-button>
<el-upload v-if="wikiPageAuth.canUploadFile==1"
class="upload-page-file" :action="uploadFileUrl"
:with-credentials="true"
:on-success="uploadFileSuccess" :on-error="uploadFileError"
name="files" show-file-list multiple :data="uploadFormData" :limit="999"
style="display: inline;margin-right: 10px;">
<el-button type="text" icon="el-icon-upload">上传附件</el-button>
</el-upload>
<el-button v-if="wikiPageAuth.canEdit==1" type="text" icon="el-icon-edit" @click="editWiki">编辑</el-button>
<el-dropdown style="margin-left: 10px;" @command="handleMoreCommand">
<el-button type="text">
更多<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="showPageHistory" icon="el-icon-time">查看历史版本</el-dropdown-item>
<el-dropdown-item command="deletePage" v-if="wikiPageAuth.canDelete==1" icon="el-icon-delete">删除</el-dropdown-item>
<el-dropdown-item command="editAuth" v-if="wikiPageAuth.canConfigAuth==1" icon="el-icon-s-check">权限设置</el-dropdown-item>
<el-dropdown-item command="showOpenPage" v-if="spaceInfo.openDoc == 1" icon="el-icon-share">查看开放文档</el-dropdown-item>
<el-dropdown-item command="showMobileView" v-if="spaceInfo.openDoc == 1" icon="el-icon-mobile-phone">手机端查看</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-row>
<el-col :xs="0" :sm="4" :md="4" :lg="6" :xl="6" v-if="navigationList.length > 0">
<Navigation :heading="navigationList"></Navigation>
</el-col>
<el-col :xs="24" :sm="navigationList.length > 0?20:24" :md="navigationList.length > 0?20:24" :lg="navigationList.length > 0?18:24" :xl="navigationList.length > 0?18:24">
<div style="max-width: 1000px;margin: 0 auto;padding-left: 10px;">
<div class="wiki-title" ref="wikiTitle">{{wikiPage.name}}</div>
<div class="wiki-author">
<div>
<span v-if="wikiPage.updateUserName">{{wikiPage.updateUserName}}  {{wikiPage.updateTime}} 修改</span>
<span v-else class="create-user-time">{{wikiPage.createUserName}}  {{wikiPage.createTime}} 创建</span>
<div style="float: right;">
<el-button type="text" icon="el-icon-chat-line-round" @click="showCommentWiki" style="margin-right: 10px;">评论</el-button>
<el-upload v-if="wikiPageAuth.canUploadFile==1"
class="upload-page-file" :action="uploadFileUrl"
:with-credentials="true"
:on-success="uploadFileSuccess" :on-error="uploadFileError"
name="files" show-file-list multiple :data="uploadFormData" :limit="999"
style="display: inline;margin-right: 10px;">
<el-button type="text" icon="el-icon-upload">上传附件</el-button>
</el-upload>
<el-button v-if="wikiPageAuth.canEdit==1" type="text" icon="el-icon-edit" @click="editWiki">编辑</el-button>
<el-dropdown style="margin-left: 10px;" @command="handleMoreCommand">
<el-button type="text">
更多<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="showPageHistory" icon="el-icon-time">查看历史版本</el-dropdown-item>
<el-dropdown-item command="deletePage" v-if="wikiPageAuth.canDelete==1" icon="el-icon-delete">删除</el-dropdown-item>
<el-dropdown-item command="editAuth" v-if="wikiPageAuth.canConfigAuth==1" icon="el-icon-s-check">权限设置</el-dropdown-item>
<el-dropdown-item command="showOpenPage" v-if="spaceInfo.openDoc == 1" icon="el-icon-share">查看开放文档</el-dropdown-item>
<el-dropdown-item command="showMobileView" v-if="spaceInfo.openDoc == 1" icon="el-icon-mobile-phone">手机端查看</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</div>
<div class="wiki-files">
<el-table v-show="pageFileList.length > 0" :data="pageFileList" border style="width: 100%; margin-bottom: 5px;">
<el-table-column label="文件名">
<template slot-scope="scope">
<a target="_blank" :href="scope.row.fileUrl">{{scope.row.fileName}}</a>
</template>
</el-table-column>
<el-table-column prop="createUserName" label="创建人"></el-table-column>
<el-table-column label="文件大小">
<template slot-scope="scope">{{computeFileSize(scope.row.fileSize)}}</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="180px"></el-table-column>
<el-table-column prop="downloadNum" label="下载次数" width="80px"></el-table-column>
<el-table-column label="操作" width="100px" v-if="wikiPageAuth.canDeleteFile==1">
<template slot-scope="scope">
<el-button size="small" v-on:click="deletePageFile(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div ref="pageContent" class="wiki-page-content">
<div v-html="pageShowDetail" class="markdown-body" v-if="wikiPage.editorType == 2" v-highlight></div>
<div v-html="pageShowDetail" class="wang-editor-body" v-else></div>
</div>
<div style="margin-top: 40px; font-size: 14px;">
<span style="vertical-align: top;" class="is-link">
<span v-show="wikiPage.selfZan == 0" v-on:click="zanPage(1)"><img src="../../assets/img/zan.png" style="vertical-align: middle;"> </span>
<span v-show="wikiPage.selfZan == 1" v-on:click="zanPage(0)"><img src="../../assets/img/zan.png" style="vertical-align: middle;transform: rotateX(180deg);"> </span>
</span>
<span style="margin-left: 10px;vertical-align: top;">
<span v-if="wikiPage.selfZan == 0 && wikiPage.zanNum <= 0">成为第一个赞同者</span>
<span v-else-if="wikiPage.selfZan == 0 && wikiPage.zanNum > 0">
<span class="is-link" v-on:click="showZanPageUser">{{wikiPage.zanNum}}</span>赞了它
</span>
<span v-else-if="wikiPage.selfZan == 1 && wikiPage.zanNum <= 1">我赞了它</span>
<span v-else-if="wikiPage.selfZan == 1 && wikiPage.zanNum > 1">
<span class="is-link" v-on:click="showZanPageUser">我和{{wikiPage.zanNum-1}}个其他人</span>赞了它
</span>
</span>
<span style="margin-left: 10px;">
<i class="el-icon-view" style="font-size: 16px;color: #666;"></i> {{wikiPage.viewNum}}次阅读
</span>
</div>
</div>
</div>
<div class="wiki-files">
<el-table v-show="pageFileList.length > 0" :data="pageFileList" border style="width: 100%; margin-bottom: 5px;">
<el-table-column label="文件名">
<template slot-scope="scope">
<a target="_blank" :href="scope.row.fileUrl">{{scope.row.fileName}}</a>
</template>
</el-table-column>
<el-table-column prop="createUserName" label="创建人"></el-table-column>
<el-table-column label="文件大小">
<template slot-scope="scope">{{computeFileSize(scope.row.fileSize)}}</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="180px"></el-table-column>
<el-table-column prop="downloadNum" label="下载次数" width="80px"></el-table-column>
<el-table-column label="操作" width="100px" v-if="wikiPageAuth.canDeleteFile==1">
<template slot-scope="scope">
<el-button size="small" v-on:click="deletePageFile(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div ref="pageContent" class="wiki-page-content">
<!-- <mavon-editor v-if="wikiPage.editorType == 2" ref="mavonEditor" :editable="false"-->
<!-- :subfield="false" defaultOpen="preview" v-model="pageShowDetail"-->
<!-- :toolbars="markdownToolbars"-->
<!-- :externalLink="false" v-highlight-->
<!-- :boxShadow="false"-->
<!-- class="page-content-editor wang-editor-body"-->
<!-- />-->
<div v-html="pageShowDetail" class="markdown-body" v-if="wikiPage.editorType == 2" v-highlight></div>
<div v-html="pageShowDetail" class="wang-editor-body" v-else></div>
</div>
<div style="margin-top: 40px; font-size: 14px;">
<span style="vertical-align: top;" class="is-link">
<span v-show="wikiPage.selfZan == 0" v-on:click="zanPage(1)"><img src="../../assets/img/zan.png" style="vertical-align: middle;"> </span>
<span v-show="wikiPage.selfZan == 1" v-on:click="zanPage(0)"><img src="../../assets/img/zan.png" style="vertical-align: middle;transform: rotateX(180deg);"> </span>
</span>
<span style="margin-left: 10px;vertical-align: top;">
<span v-if="wikiPage.selfZan == 0 && wikiPage.zanNum <= 0">成为第一个赞同者</span>
<span v-else-if="wikiPage.selfZan == 0 && wikiPage.zanNum > 0"><span class="is-link" v-on:click="showZanPageUser">{{wikiPage.zanNum}}</span>赞了它</span>
<span v-else-if="wikiPage.selfZan == 1 && wikiPage.zanNum <= 1">我赞了它</span>
<span v-else-if="wikiPage.selfZan == 1 && wikiPage.zanNum > 1"><span class="is-link" v-on:click="showZanPageUser">我和{{wikiPage.zanNum-1}}个其他人</span>赞了它</span>
</span>
<span style="margin-left: 10px;">
<i class="el-icon-view" style="font-size: 16px;color: #666;"></i> {{wikiPage.viewNum}}次阅读
</span>
</div>
</div>
</el-col>
</el-row>
</el-col>
<el-col :span="6" style="height: 100%;" v-show="actionTabVisible">
<i class="el-icon-close close-action-tab" @click="closeActionTab"></i>
@@ -187,13 +191,16 @@
<script>
import QRCode from 'qrcodejs2'
import common from '../../common/lib/common'
import unitUtil from '../../common/lib/UnitUtil.js'
import htmlUtil from '../../common/lib/HtmlUtil.js'
import pageApi from '../../common/api/page'
import userApi from '../../common/api/user'
import Navigation from './components/Navigation.vue'
import {mavonEditor, markdownIt} from 'mavon-editor'
import ElImageViewer from 'element-ui/packages/image/src/image-viewer'
import 'mavon-editor/dist/markdown/github-markdown.min.css'
import 'mavon-editor/dist/css/index.css'
import vue from "../../main";
var page = {
colorArr: ["#67C23A", "#409EFF", "#E6A23C", "#F56C6C", "#909399", "#303133"],
@@ -201,7 +208,7 @@
};
export default {
props: ['spaceInfo'],
components: {'el-image-viewer': ElImageViewer, mavonEditor},
components: {'el-image-viewer': ElImageViewer, mavonEditor, Navigation},
data() {
return {
// 页面展示相关
@@ -236,6 +243,8 @@
pageHistoryChoice: {},
pageHistoryList: [],
pageHistoryPageNum: 1,
// 左侧导航菜单
navigationList: [],
// 大图预览
previewInitialIndex: 0,
showImagePreview: false,
@@ -459,26 +468,7 @@
this.pageShowDetail = this.pageContent.content;
},
computeFileSize(fileSize) {
if (!fileSize) {
return '-';
}
let size = "";
if (fileSize < 0.1 * 1024) {
size = fileSize.toFixed(2) + "B"
} else if (fileSize < 0.1 * 1024 * 1024) {
size = (fileSize / 1024).toFixed(2) + "KB"
} else if (fileSize < 0.1 * 1024 * 1024 * 1024) {
size = (fileSize / (1024 * 1024)).toFixed(2) + "MB"
} else {
size = (fileSize / (1024 * 1024 * 1024)).toFixed(2) + "GB"
}
let sizeStr = size + "";
let index = sizeStr.indexOf(".");
let dou = sizeStr.substr(index + 1, 2);
if (dou == "00") {
return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2)
}
return size;
return unitUtil.computeFileSize(fileSize);
},
loadPageDetail(pageId) {
this.clearHistory();
@@ -500,16 +490,11 @@
};
if (this.wikiPage.editorType === 2) {
this.pageContent.content = markdownIt.render(this.pageContent.content);
// setTimeout(() => {
// // if (this.$refs.mavonEditor) {
// // this.$refs.mavonEditor.toolbar_right_click('read');
// // }
// this.createHeading();
// }, 0);
}
this.pageShowDetail = this.pageContent.content;
// 修改标题
document.title = wikiPage.name || 'WIKI-内容展示';
let wikiTile = wikiPage.name || 'WIKI-内容展示';
document.title = wikiTile;
// 修改最后点击的项,保证刷新后点击编辑能展示编辑的项
// if (!this.lastClickNode.id) {
// this.lastClickNode = {id: wikiPage.id, nodePath: wikiPage.name};
@@ -518,7 +503,19 @@
this.$emit('switchSpace', this.wikiPage.spaceId);
// 调用父方法展开目录树
this.$emit('changeExpandedKeys', pageId);
setTimeout(() => this.previewPageImage(), 500);
setTimeout(() => {
this.previewPageImage();
let navigationList = htmlUtil.createNavigationHeading();
// 标题加到导航里面去
if (navigationList.length > 0) {
navigationList.unshift({
level: 1,
node: this.$refs.wikiTitle,
text: wikiTile
});
}
this.navigationList = navigationList;
}, 500);
});
this.loadCommentList(pageId);
this.getPageHistory(pageId, 1);
@@ -526,112 +523,6 @@
closeImagePreview() {
this.showImagePreview = false;
},
/**
* 生成目录树
* ========================================================
* 说明:代码修改至 yaohaixiao 的 autoc.js
* 项目 gitee 地址https://gitee.com/yaohaixiao/AutocJS
* ========================================================
*/
createHeading() {
let headArr = [];
let headNodeArr = document.querySelector('.wiki-page-content').querySelectorAll('h1,h2,h3,h4,h5,h6,h7,h8,h9');
headNodeArr.forEach(node => {
headArr.push({
node: node,
level: parseInt(node.tagName.replace(/[h]/i, ''), 10)
});
});
let chapters = []
let previous = 1
let level = 0
headArr.forEach((heading, i) => {
let current = heading.level
let pid = -1
// 当前标题的(标题标签)序号 > 前一个标题的序号:两个相连的标题是父标题 -> 子标题关系;
// h2 (前一个标题)
// h3 (当前标题)
if (current > previous) {
level += 1
// 第一层级的 pid 是 -1
if (level === 1) {
pid = -1
} else {
pid = i - 1
}
}
// 当前标题的(标题标签)序号 = 前一个标题的序号
// h2 (前一个标题)
// h2 (当前标题)
// 当前标题的(标题标签)序号 < 前一个标题的序号,并且当前标题序号 > 当前的级别
// h2
// h4 (前一个标题)
// h3 (当前标题:这种情况我们还是任务 h3 是 h2 的下一级章节)
else if (current === previous || (current < previous && current > level)) {
// H1 的层级肯定是 1
if (current === 1) {
level = 1
pid = -1
} else {
pid = chapters[i - 1].pid
}
} else if (current <= level) {
// H1 的层级肯定是 1
if (current === 1) {
level = 1
} else {
level = level - (previous - current)
if (level <= 1) {
level = 1
}
}
// 第一级的标题
if (level === 1) {
pid = -1
} else {
// 虽然看上去差点,不过能工作啊
pid = this.generatePid(chapters, previous - current, i)
}
}
previous = current
chapters.push({
id: i,
pid: pid,
level: level,
text: this.stripTags(this.trim(heading.node.innerHTML))
});
})
console.log(chapters)
},
trim: (str) => {
return str.replace(/^\s+/g, '').replace(/\s+$/g, '')
},
stripTags: (str) => {
return str.replace(/<\/?[^>]+(>|$)/g, '')
},
generatePid(chapters, differ, index) {
let pid
// 最大只有 5 级的差距
switch (differ) {
case 2:
pid = chapters[chapters[chapters[index - 1].pid].pid].pid
break
case 3:
pid = chapters[chapters[chapters[chapters[index - 1].pid].pid].pid].pid
break
case 4:
pid = chapters[chapters[chapters[chapters[chapters[index - 1].pid].pid].pid].pid].pid
break
case 5:
pid = chapters[chapters[chapters[chapters[chapters[chapters[index - 1].pid].pid].pid].pid].pid].pid
break
default:
pid = chapters[chapters[index - 1].pid].pid
break
}
return pid
},
previewPageImage() {
const imgArr = [];
const imgSelector = this.$refs.pageContent.querySelectorAll('img');
@@ -728,10 +619,12 @@
this.$message.error("上传失败," + err);
},
uploadFileSuccess(response) {
common.validateResult({data: response}).then(() => {
if (response.errCode == 200) {
this.pageFileList.push(response.data);
this.$message.success("上传成功!");
});
} else {
vue.$message('上传失败:' + (response.errMsg || "未知错误"));
}
},
deletePageFile(row) {
this.$confirm('确定要删除此文件吗?', '提示', {

View File

@@ -0,0 +1,97 @@
<template>
<div class="navigation">
<div ref="navigation" style="display: inline-block;width: 100%;"></div>
<div class="navigation-heading" :style="{width: navigationWidth}">
<div v-for="item in heading" :class="'heading-item heading-'+item.level" @click="headingItemClick(item)">
{{item.text}}
</div>
</div>
</div>
</template>
<script>
export default {
props: {
heading: {
type: Array,
default: []
},
},
data() {
return {
navigationWidth: '100px'
};
},
mounted() {
window.onresize = () => {
this.computeNavigationWidth();
}
setTimeout(() => this.computeNavigationWidth(), 100);
},
methods: {
computeNavigationWidth() {
this.navigationWidth = window.getComputedStyle(this.$refs.navigation, null).width;
},
headingItemClick(item) {
// 滚动到指定节点
item.node.scrollIntoView({behavior: "smooth", block: "start", inline: "nearest"});
// 距离顶部高度
//console.log(item.node.offsetTop - item.node.scrollHeight)
},
}
}
</script>
<style>
.navigation {
width: 100%;
}
.navigation-heading {
position: fixed;
z-index: 4;
top: 150px;
height: calc(100vh - 250px);
width: 100%;
overflow-y: auto;
padding-left: 16px;
box-sizing: border-box;
}
.navigation-heading .heading-item {
padding: 5px 0;
cursor: pointer;
color: #646a73;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.navigation-heading .heading-item:hover {
color: #3370ff;
}
.navigation-heading .heading-1 {
padding-left: 0;
}
.navigation-heading .heading-2 {
padding-left: 16px;
}
.navigation-heading .heading-3 {
padding-left: 32px;
}
.navigation-heading .heading-4 {
padding-left: 48px;
}
.navigation-heading .heading-5 {
padding-left: 64px;
}
.navigation-heading .heading-6 {
padding-left: 80px;
}
</style>

View File

@@ -1,31 +1,38 @@
<template>
<div class="page-share-view-vue">
<el-row type="border-card">
<div style="max-width: 950px;margin: 0 auto;">
<div class="wiki-title">{{wikiPage.name}}</div>
<div class="wiki-author">
<span v-if="wikiPage.updateTime">最后修改{{wikiPage.updateTime}}</span>
<span v-else>创建时间{{wikiPage.createTime}}</span>
</div>
<div class="wiki-files">
<el-table v-show="pageFileList.length > 0" :data="pageFileList" border style="width: 100%; margin-bottom: 5px;">
<el-table-column label="文件名">
<template slot-scope="scope">
<a target="_blank" :href="scope.row.fileUrl">{{scope.row.fileName}}</a>
</template>
</el-table-column>
<el-table-column label="文件大小">
<template slot-scope="scope">{{computeFileSize(scope.row.fileSize)}}</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="180px"></el-table-column>
<el-table-column prop="downloadNum" label="下载次数" width="80px"></el-table-column>
</el-table>
</div>
<div ref="pageContent" class="wiki-page-content">
<div v-html="pageShowDetail" class="markdown-body" v-if="wikiPage.editorType == 2"></div>
<div v-html="pageShowDetail" class="wang-editor-body" v-else></div>
</div>
</div>
<el-row>
<el-col :xs="0" :sm="4" :md="4" :lg="6" :xl="6" v-if="navigationList.length > 0">
<Navigation :heading="navigationList"></Navigation>
</el-col>
<el-col :xs="24" :sm="navigationList.length > 0?20:24" :md="navigationList.length > 0?20:24" :lg="navigationList.length > 0?18:24" :xl="navigationList.length > 0?18:24">
<div style="max-width: 1000px;padding-left: 10px;margin: 0 auto;">
<div class="wiki-title" ref="wikiTitle">{{wikiPage.name}}</div>
<div class="wiki-author">
<span v-if="wikiPage.updateTime">最后修改{{wikiPage.updateTime}}</span>
<span v-else>创建时间{{wikiPage.createTime}}</span>
</div>
<div class="wiki-files">
<el-table v-show="pageFileList.length > 0" :data="pageFileList" border style="width: 100%; margin-bottom: 5px;">
<el-table-column label="文件">
<template slot-scope="scope">
<a target="_blank" :href="scope.row.fileUrl">{{scope.row.fileName}}</a>
</template>
</el-table-column>
<el-table-column label="文件大小">
<template slot-scope="scope">{{computeFileSize(scope.row.fileSize)}}</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="180px"></el-table-column>
<el-table-column prop="downloadNum" label="下载次数" width="80px"></el-table-column>
</el-table>
</div>
<div ref="pageContent" class="wiki-page-content">
<div v-html="pageShowDetail" class="markdown-body" v-if="wikiPage.editorType == 2"></div>
<div v-html="pageShowDetail" class="wang-editor-body" v-else></div>
</div>
</div>
</el-col>
</el-row>
</el-row>
<div ref="imagePreview">
<el-image-viewer v-if="showImagePreview" :url-list="showImagePreviewList" :on-close="closeImagePreview" :initial-index="previewInitialIndex"></el-image-viewer>
@@ -36,6 +43,9 @@
<script>
import pageApi from '../../../../common/api/page'
import {mavonEditor, markdownIt} from 'mavon-editor'
import unitUtil from '../../../../common/lib/UnitUtil.js'
import htmlUtil from '../../../../common/lib/HtmlUtil.js'
import Navigation from '../../components/Navigation.vue'
import ElImageViewer from 'element-ui/packages/image/src/image-viewer'
import 'mavon-editor/dist/markdown/github-markdown.min.css'
import 'mavon-editor/dist/css/index.css'
@@ -53,9 +63,10 @@
previewInitialIndex: 0,
showImagePreview: false,
showImagePreviewList: [],
navigationList: [],
};
},
components: {'el-image-viewer': ElImageViewer},
components: {'el-image-viewer': ElImageViewer, Navigation},
beforeRouteUpdate(to, from, next) {
this.initQueryParam(to);
next();
@@ -76,8 +87,21 @@
pageContent.content = markdownIt.render(pageContent.content);
}
this.pageShowDetail = pageContent.content;
document.title = wikiPage.name || 'WIKI-内容展示';
setTimeout(() => this.previewPageImage(), 500);
let wikiTile = wikiPage.name || 'WIKI-内容展示';
document.title = wikiTile;
setTimeout(() => {
this.previewPageImage();
let navigationList = htmlUtil.createNavigationHeading();
// 标题加到导航里面去
if (navigationList.length > 0) {
navigationList.unshift({
level: 1,
node: this.$refs.wikiTitle,
text: wikiTile
});
}
this.navigationList = navigationList;
}, 500);
});
},
initQueryParam(to) {