背景
最近在做一個部門內部簡單的知識庫系統,便於新人入職了解與一些常見問題的解答,知識庫的形式是以文檔為主,為了快速實現文檔功能,決定采用markdown形式錄入,生成本地文件后以html方式展現,層次清晰便於查看
表結構設計
文檔信息表
DROP TABLE IF EXISTS `knowledge_documentinfo`;
CREATE TABLE `knowledge_documentinfo` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`UnitGuid` varchar(50) DEFAULT NULL,
`AddDate` datetime DEFAULT NULL,
`DocName` varchar(50) DEFAULT NULL,
`DocType` int(11) DEFAULT NULL,
`DocRemark` varchar(500) DEFAULT NULL,
`DocTag` varchar(100) DEFAULT NULL,
`DocClass` int(11) DEFAULT NULL,
`GroupGuid` varchar(50) DEFAULT NULL,
`SortNum` int(11) DEFAULT NULL,
KEY `ID` (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4;
文檔內容表
DROP TABLE IF EXISTS `knowledge_documentcontentinfo`;
CREATE TABLE `knowledge_documentcontentinfo` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`UnitGuid` varchar(50) DEFAULT NULL,
`DocGuid` varchar(50) DEFAULT NULL,
`DocClass` int(11) DEFAULT NULL,
`DocContent` longtext,
KEY `ID` (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4;
前端集成
前端為了markdown編輯操作便捷,集成了toastui-edit編輯器,具有所見即所得模式,和typora一樣的效果。因為我們前端是自己開發,基於vue+html本地化方式開發,就簡單封裝了控件使用,同時需要引用zh-cn.js漢化,指定initialEditType模式為wysiwyg
template
<div v-if="!readonly" id="markdownedit"></div>
<div v-else id="markdownedit_viewer"> </div>
index.js
var mdeditortemplatepath = GetRootPath() + 'component/commonmdeditor/template.html';
Vue.component('common-markdowneditor', function(resolve, reject) {
$.get(mdeditortemplatepath).then(function(res) {
resolve({
template: res,
model: {
prop: 'value', //要存在於props
event: 'change' //當組件的值發生改變時要emit的事件名
},
props: {
value: {},
height: {
default: '300px'
},
readonly: {
default: false
}
},
data() {
return {
editorID: getNewGuid(),
editorImageStoreGroupType: "edtior",
editContent: this.value,
editorOption: {},
editorEntity: null,
editorViewEntity: null
}
},
watch: {
//組件輸入同步到頁面綁定的變量
editContent: function(newVal, oldVal) {
this.$emit('change', newVal)
},
//頁面變量同步到組件顯示
value: function(newVal, oldVal) {
//從頁面向組件更新時
if (this.editContent != newVal) {
this.editContent = newVal;
if (this.editorEntity != null) {
this.editorEntity.setMarkdown(newVal, false)
}
if (this.editorViewEntity != null) {
this.editorViewEntity.setMarkdown(newVal, false)
}
}
},
},
created() {
var page = this;
},
mounted() {
var page = this;
this.$nextTick(function() {
if (!page.readonly) {
page.editorEntity = new toastui.Editor({
el: document.querySelector('#markdownedit'),
height: this.height,
initialValue: '',
initialEditType: 'wysiwyg',
hideModeSwitch: true,
language: "zh-CN",
events: {
change: function() {
page.editContent = page.editorEntity.getMarkdown();
}
}
})
page.editorEntity.setMarkdown(page.editContent, true)
} else {
page.editorViewEntity = toastui.Editor.factory({
el: document.querySelector('#markdownedit_viewer'),
viewer: true,
initialValue: page.editContent
});
}
});
},
methods: {
},
})
});
});
實際使用
<common-markdowneditor v-model="form.docContent" ></common-markdowneditor>
后端集成
在把markdonw的內容保存到數據庫后,同時同步生成本地markdown文件,為后續html展示做准備
public void creatMarkdownFile(DocumentContentInfoDO entity) {
if (entity.getDocClass() == DocEnum.DocClass.Markdown.get_value()) {
try {
//生成markdown文件
String dicPath = "tempfiles/markdown/";
String filePath = dicPath + entity.getDocGuid() + ".md";
File dicInfo = new File(dicPath);
if (!dicInfo.exists()) {
dicInfo.mkdirs();
}
File file = new File(filePath);
if (file.exists()) {
file.delete();
}
file.createNewFile();
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(filePath)),"utf-8"));
out.write(entity.getDocContent());
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
文檔顯示
前端顯示集成了docsify@4.js,通過動態的指定homepage主頁markdown文件地址達到一個index.html頁面根據文檔標識顯示不同內容的效果
<script>
var showDocUrl = apiFrameUrl + "/foundation/documentinfo/getMarkdownUrl";
var docTag = getUrlParam("docTag")
$(function() {
var data = {
docTag: docTag,
};
JsonAjax_Sync(JSON.stringify(data), showDocUrl, function(result, status) {
var mdFileUrl = GetRootPath() + result.data.obj;
window.$docsify = {
homepage: mdFileUrl
}
})
})
</script>