diff --git a/package.json b/package.json index 203fa8e..3510488 100644 --- a/package.json +++ b/package.json @@ -88,8 +88,7 @@ "vue-template-compiler": "^2.6.13" }, "engines": { - "node": ">=8.9", - "npm": ">= 3.0.0" + "node": "^16" }, "browserslist": [ "> 1%", diff --git a/src/api/file-history.js b/src/api/file-history.js new file mode 100644 index 0000000..4b46bf0 --- /dev/null +++ b/src/api/file-history.js @@ -0,0 +1,64 @@ +import request from '@/utils/request' + +export default { + /** + * 查询历史文件列表 + * @param params + * @returns {*} + */ + fileHistoryList: function(params) { + return request({ + url: '/history/list', + method: 'get', + params + }) + }, + /** + * 查询历史文件列表(根据path) + * @param params + * @returns {*} + */ + fileHistoryPathList: function(params) { + return request({ + url: '/history/path/list', + method: 'get', + params + }) + }, + /** + * 预览某版本的历史文件 + * @param params + * @returns {*} + */ + previewHistoryText: function(params) { + return request({ + url: '/history/preview/text', + method: 'get', + params + }) + }, + /** + * 恢复该历史版本 + * @param params + * @returns {*} + */ + recoveryHistory: function(params) { + return request({ + url: '/history/recovery', + method: 'put', + params + }) + }, + /** + * 删除该历史版本 + * @param params + * @returns {*} + */ + deleteHistory: function(params) { + return request({ + url: '/history/delete', + method: 'delete', + params + }) + }, +} diff --git a/src/assets/img/history.svg b/src/assets/img/history.svg new file mode 100644 index 0000000..6c65697 --- /dev/null +++ b/src/assets/img/history.svg @@ -0,0 +1,11 @@ + + + + + diff --git a/src/components/HistoryPopover/index.vue b/src/components/HistoryPopover/index.vue new file mode 100644 index 0000000..1b6921a --- /dev/null +++ b/src/components/HistoryPopover/index.vue @@ -0,0 +1,217 @@ + + + + + + + + + + 预览 + + + + {{'确定要恢复到'+ scope.row.metadata.time +'吗?当前内容将被覆盖!'}} + + + 取消 + 确定 + + 恢复 + + + + + {{'确定要删除'+ scope.row.metadata.time +'吗?这将永久删除该历史版本!'}} + + + 取消 + 确定 + + 删除 + + + + + + + 历史版本 + + + + + + + diff --git a/src/components/Minder/minder.vue b/src/components/Minder/minder.vue index 723c0e0..577b8bc 100644 --- a/src/components/Minder/minder.vue +++ b/src/components/Minder/minder.vue @@ -1,8 +1,25 @@ - {{title}} - 保存 + {{title}} + + + 取消预览 + + + + + 保存 + + @@ -13,7 +30,7 @@ - + @@ -21,16 +38,16 @@ - - - - - - + + + + + + - + @@ -94,10 +111,13 @@ import JSPDF from 'jspdf'; import api from "@/api/file-api"; import txtApi from "@/api/markdown-api"; import Bus from "@/assets/js/bus"; +import historyApi from "@/api/file-history"; +import HistoryPopover from "@/components/HistoryPopover/index.vue"; export default { name: 'my-mind-editor', + components: {HistoryPopover}, props: { file: { type: Object, @@ -118,6 +138,17 @@ export default { default: 'minder-component-' + generateMixed(12) }, }, + computed: { + hasReadOnly() { + return this.readOnly || this.viewHistory + }, + titleColor() { + if (!this.saved) { + return '#ff8200' + } + return '' + } + }, data() { return { minder: null, @@ -129,7 +160,16 @@ export default { zoom: 100, saved: true, titleShow: false, - }; + currentContext: undefined, + currentTitle: undefined, + historyVersion: {metadata: {}}, + hasHistoryVersion: false, + historyListPopoverVisible: false, + viewHistory: false, + loading: { + closed: true + }, + } }, watch: { 'file.id': { @@ -138,7 +178,7 @@ export default { return } let request = 'previewText' - if (this.readOnly) { + if (this.hasReadOnly) { request = 'sharePreviewText' } this.content = null @@ -158,6 +198,9 @@ export default { this.init(this.content) this.$emit('onReady') }) + this.$nextTick(()=> { + this.$refs.historyPopover.loadHistoryList(this.file.id) + }) }, deep: true, immediate: true @@ -175,9 +218,70 @@ export default { document.removeEventListener('keydown', this.ctrlAndS) }, methods: { - /** - * 保存并关闭 - */ + viewHistoryFile({historyInfo, recovery}) { + if (!this.saved) { + this.$message({type: 'info', message: "请先保存当前修改的内容"}) + return + } + let loadingInfo = recovery ? '恢复中...' : '加载中...' + this.loading = this.$message({ + iconClass: 'el-icon-loading', + type: 'info', + duration: 0, + dangerouslyUseHTMLString: true, + message: ` ${loadingInfo}` + }) + historyApi.previewHistoryText({id: historyInfo.id}).then((res) => { + this.loading.close() + + if (this.historyListPopoverVisible) { + this.historyListPopoverVisible = false + } + if (recovery) { + this.cancelPreview(null, res.data.contentText) + this.$message({message: '恢复成功',type: 'success'}) + } else { + this.currentContext = JSON.stringify(this.content) + this.currentTitle = this.title + this.content = JSON.parse(res.data.contentText) + this.bakValue = res.data.contentText + this.minder.importJson(this.content) + this.historyVersion = historyInfo + this.title = `历史版本:${historyInfo.metadata.time}` + this.viewHistory = true + this.setReadOnly() + } + }).catch(() => { + this.loading.close() + }) + }, + recoverySuccess({historyInfo}) { + this.viewHistoryFile({historyInfo: historyInfo, recovery: true}) + }, + cancelPreview(event, currentContext) { + if (!currentContext) { + currentContext = this.currentContext + } + this.historyVersion = {metadata: {}} + this.content = JSON.parse(currentContext) + this.bakValue = currentContext + this.minder.importJson(this.content) + if (this.currentTitle) { + this.title = this.currentTitle + } + this.viewHistory = false + this.setReadOnly() + }, + setReadOnly() { + window.__minderReadOnly = this.hasReadOnly + if (this.hasReadOnly === true) { + this.minder.disable() + this.minder.execCommand('Hand') + this.isHand = true + } else { + this.minder.enable() + } + }, saveAndClose() { this.save() this.$emit('onClose') @@ -247,31 +351,30 @@ export default { this.minder.importJson(this.content) return } - window.__minderReadOnly = this.readOnly const Editor = require('./editor') this.minder = window.editor = new Editor(document.getElementById(this.id)).minder this.bakValue = JSON.stringify(this.content) this.titleShow = true this.minder.importJson(this.content) - if (this.readOnly === true) { - this.minder.disable() - this.minder.execCommand('Hand') - this.isHand = true - } - this.minder.on('contentchange', () => { - const newJson = this.minder.exportJson() - if (this.bakValue === JSON.stringify(newJson)) { - return - } - this.bakValue = JSON.stringify(newJson) - this.content = newJson - this.saved = false - this.title = `*${this.file.name}` - this.$emit('onEdit', this.saved) - }) + this.setReadOnly() + this.minder.on('contentchange', () => this.onContentChange()) }, 300) }) }, + onContentChange() { + const newJson = this.minder.exportJson() + if (this.bakValue === JSON.stringify(newJson)) { + this.saved = true + if (this.title === `*${this.file.name}`) { + this.title = this.file.name + } + } else { + this.content = newJson + this.saved = false + this.title = `*${this.file.name}` + } + this.$emit('onEdit', this.saved) + }, init(newObj) { if (typeof newObj !== "object" || newObj === null) { newObj = { @@ -314,6 +417,7 @@ export default { this.saved = true this.title = this.file.name this.$emit('onEdit', this.saved) + this.$refs.historyPopover.loadHistoryList(this.file.id) }).catch(() => { this.saveBtnUpdating = false }) @@ -466,7 +570,8 @@ export default { line-height: 40px; } - .minder-save { + .minder-operation { + display: flex; float: right; margin-top: -40px; margin-right: 30px; diff --git a/src/components/MonacoEditorVue/index.js b/src/components/MonacoEditorVue/index.js index 7322a61..e85518b 100644 --- a/src/components/MonacoEditorVue/index.js +++ b/src/components/MonacoEditorVue/index.js @@ -162,7 +162,13 @@ export default { _getValue() { let editor = this._getEditor(); - if(!editor) return ''; + if(!editor) { + if (this.diffEditor) { + return this.editor.getModel().modified.getValue() + } else { + return '' + } + } return editor.getValue(); }, @@ -175,8 +181,8 @@ export default { this.editorMounted(editor, monaco); if(this.diffEditor){ editor.onDidUpdateDiff((event) => { - const value = this._getValue(); - this._emitChange(value, event); + const value = this._getValue() + this._emitChange(value, event) }); }else{ editor.onDidChangeModelContent(event => { diff --git a/src/components/ShowFile/ShowFile.vue b/src/components/ShowFile/ShowFile.vue index 84a6b50..606f31e 100644 --- a/src/components/ShowFile/ShowFile.vue +++ b/src/components/ShowFile/ShowFile.vue @@ -3222,6 +3222,12 @@ export default { this.officePreviewRow = row return } + if (row.contentType.indexOf('utf-8') > -1) { + // 文本文件 + this.textPreviewRow = row + this.textPreviewVisible = true + return + } this.notPreviewDialogVisible = true } }, diff --git a/src/components/office/Drawio.vue b/src/components/office/Drawio.vue index 7df6e31..3d164c1 100644 --- a/src/components/office/Drawio.vue +++ b/src/components/office/Drawio.vue @@ -2,7 +2,23 @@ {{title}} - 保存 + + + 取消预览 + + + + + 保存 + @@ -13,9 +29,12 @@ import api from '@/api/file-api' import txtApi from "@/api/markdown-api" import Bus from "@/assets/js/bus"; +import HistoryPopover from "@/components/HistoryPopover/index.vue"; +import historyApi from "@/api/file-history"; export default { name: "Drawio", + components: {HistoryPopover}, props: { file: { type: Object, @@ -40,7 +59,16 @@ export default { saveBtnUpdating: false, title: this.file.name, saved: true, - reday: false + ready: false, + currentContext: undefined, + currentTitle: undefined, + historyVersion: {metadata: {}}, + hasHistoryVersion: false, + historyListPopoverVisible: false, + viewHistory: false, + loading: { + closed: true + }, } }, created() { @@ -90,15 +118,67 @@ export default { this.bakData = res.data.contentText this.updateContent() }) + this.$nextTick(()=> { + this.$refs.historyPopover.loadHistoryList(this.file.id) + }) }, immediate: true, deep: true, }, }, methods: { - /** - * 保存并关闭 - */ + viewHistoryFile({historyInfo, recovery}) { + if (!this.saved) { + this.$message({type: 'info', message: "请先保存当前修改的内容"}) + return + } + let loadingInfo = recovery ? '恢复中...' : '加载中...' + this.loading = this.$message({ + iconClass: 'el-icon-loading', + type: 'info', + duration: 0, + dangerouslyUseHTMLString: true, + message: ` ${loadingInfo}` + }) + historyApi.previewHistoryText({id: historyInfo.id}).then((res) => { + this.loading.close() + + if (this.historyListPopoverVisible) { + this.historyListPopoverVisible = false + } + if (recovery) { + this.cancelPreview(null, res.data.contentText) + this.$message({message: '恢复成功',type: 'success'}) + } else { + this.currentContext = this.xml + this.currentTitle = this.title + this.bakData = res.data.contentText + this.xml = res.data.contentText + this.updateContent() + this.historyVersion = historyInfo + this.title = `历史版本:${historyInfo.metadata.time}` + this.viewHistory = true + } + }).catch(() => { + this.loading.close() + }) + }, + recoverySuccess({historyInfo}) { + this.viewHistoryFile({historyInfo: historyInfo, recovery: true}) + }, + cancelPreview(event, currentContext) { + if (!currentContext) { + currentContext = this.currentContext + } + this.historyVersion = {metadata: {}} + this.xml = currentContext + this.bakData = currentContext + this.updateContent() + if (this.currentTitle) { + this.title = this.currentTitle + } + this.viewHistory = false + }, saveAndClose() { this.save() this.$emit('onClose') @@ -127,6 +207,7 @@ export default { this.saved = true this.title = this.file.name this.$emit('onEdit', this.saved) + this.$refs.historyPopover.loadHistoryList(this.file.id) }).catch(() => { this.saveBtnUpdating = false }) @@ -136,13 +217,13 @@ export default { if (event.source !== editWindow) { return } + let doc = this.$refs.myFlow.contentWindow.document const payload = $J.jsonParse(event.data) switch (payload.event) { case "init": - this.reday = true + this.ready = true this.$emit('onReady') this.updateContent() - let doc = this.$refs.myFlow.contentWindow.document let helpMenu = doc.querySelector('.geMenubarContainer .geMenubar').childNodes[5] helpMenu.style.display = 'none' break @@ -155,15 +236,24 @@ export default { break case "autosave": - this.bakData = payload.xml - this.xml = payload.xml - this.saved = false - this.title = `*${this.file.name}` - this.$emit('onEdit', this.saved) + let undo = doc.querySelector('.geSprite.geSprite-undo') + if (undo && !this.viewHistory) { + let undoClass = undo.parentElement.getAttribute('class') + if (undoClass && undoClass.indexOf('mxDisabled') > -1) { + this.saved = true + if (this.title === `*${this.file.name}`) { + this.title = this.file.name + } + } else { + this.xml = payload.xml + this.saved = false + this.title = `*${this.file.name}` + } + this.$emit('onEdit', this.saved) + } break case "save": - // save this.save() break } @@ -187,18 +277,19 @@ export default { z-index: 2001; position: absolute; top: 0; - width: 50%; - margin-left: 50%; + width: calc(50% + 121px); + margin-left: calc(50% - 121px); height: 0; .drawio-title-name { line-height: 32px; } - .drawio-save { + .drawio-operation { + display: flex; float: right; margin-top: -32px; - margin-right: 32px; + margin-right: 15px; line-height: 32px; } } diff --git a/src/components/office/OnlyOfficeEditor.vue b/src/components/office/OnlyOfficeEditor.vue index f26db6e..85f926e 100644 --- a/src/components/office/OnlyOfficeEditor.vue +++ b/src/components/office/OnlyOfficeEditor.vue @@ -1,9 +1,22 @@ - + + + + - + diff --git a/src/components/preview/OfficePreview.vue b/src/components/preview/OfficePreview.vue index c0b98e4..3361a4e 100644 --- a/src/components/preview/OfficePreview.vue +++ b/src/components/preview/OfficePreview.vue @@ -94,13 +94,13 @@ export default { this.previewDocument = document.querySelector('.preview-block') }) this.checkReadOnly(this.file.userId) - // 6秒后还没加载出来视为加载失败 + // 12秒后还没加载出来视为加载失败 let that = this this.delayClosing = setTimeout(function () { if (!that.readyShow) { that.loadFileFaild() } - },6000) + },12000) } } }, diff --git a/src/components/preview/SimTextPreview.vue b/src/components/preview/SimTextPreview.vue index a29b6f0..8169f3e 100644 --- a/src/components/preview/SimTextPreview.vue +++ b/src/components/preview/SimTextPreview.vue @@ -38,17 +38,33 @@ - 保存所有 - - - + + + 保存所有 + + + + + + + + + + + - + @@ -111,7 +127,7 @@ :height="editorHieght" :theme="lightTheme?'vs':'vs-dark'" :language="item.language" - :diffEditor="diffEditor" + :diffEditor="item.hasHistoryVersion" original="..." :options="options" @change="change($event,index)" @@ -132,6 +148,7 @@ import _ from "lodash" import '@/utils/directives.js' import api from '@/api/file-api' + import historyApi from '@/api/file-history' import markdownApi from '@/api/markdown-api' import { iconClass,lineWrapping,suffix } from '@/utils/file-type' @@ -146,10 +163,12 @@ import Icon from '@/components/Icon/Icon.vue' import VditorPreview from "@/components/preview/VditorPreview"; + import HistoryPopover from "@/components/HistoryPopover/index.vue"; export default { name: "SimTextPreview", components: { + HistoryPopover, Icon,MonacoEditor,FileTree,FancyTree,MessageDialog,FilePathNav,VditorPreview }, props: { @@ -174,6 +193,8 @@ } } }, + computed: { + }, data(){ return{ lightTheme: true, @@ -194,19 +215,20 @@ // 换行 wordWrap: this.lineWrapping ? 'wordWrapColumn':'', wordWrapMinified: true, - wrappingIndent: "indent" + wrappingIndent: "indent", + preview: true, + previewMode: 'subwordSmart' }, - diffEditor: false, textPreviewVisible: false, fullscreen: false, - dialogWidth: 0, + dialogWidth: 650, + minDialogWidth: 650, dialogWidthPercent: 0.7, lastTransform: undefined, contentsWidth: 273, editorWidth: 1035, editorHieght: 640, transition: 'all 500ms ease 0s', - content: '', newContent: '', previewMode: true, isShowUpdateBtn: false, @@ -227,16 +249,20 @@ editableTabs: [], editableValueMap: new Map(), abortControllerMap: new Map(), + editableVersionMap: new Map(), + hasHistoryVersion: false, + historyListPopoverVisible: false, + historyVersion: {metadata: {}}, filePathNav: '', toolbars: { readmodel: true, // 沉浸式阅读 navigation: true, // 导航目录 - } + }, } }, mounted() { this.$nextTick(()=>{ - this.dialogWidth = document.body.clientWidth * this.dialogWidthPercent + this.setDialogWidth() }) }, directives: { @@ -311,13 +337,10 @@ } this.textPreviewVisible = true - this.requestStream(request, params, 0) - let pathname = res.data.path.substring(1, res.data.path.length) + res.data.name if ('previewTextByPath' === request) { pathname = `/${res.data.path}/${res.data.name}` } - // 加载tabs this.editableTabs.push({ title: res.data.name, @@ -326,11 +349,16 @@ status: undefined,//标签状态 name: pathname }) + + this.requestStream(request, params, 0) + this.editableTabsValue = pathname + // 加载历史版本 + this.$refs.historyPopover.loadHistoryPathList(pathname) // 界面的渲染后的初始化工作 this.$nextTick(() => { this.onDialogDblClick() - this.dargDialogSize() + this.dragDialogSize() this.dragControllerDiv() this.setTheme() }) @@ -347,9 +375,90 @@ if(value.endsWith('.md')){ this.previewMode = false } + this.hasHistoryVersion = this.editableVersionMap.get(value) + if (this.hasHistoryVersion) { + let currentIndex = this.editableTabs.findIndex(editable => editable.name === value) + const tab = this.editableTabs[currentIndex] + this.historyVersion = tab.historyVersion || {metadata: {}} + } else { + this.historyVersion = {metadata: {}} + } } }, methods:{ + setDialogWidth() { + this.dialogWidth = document.body.clientWidth * this.dialogWidthPercent + }, + loadHistoryPathListSuccess({res, pathname}) { + if (res.count && res.count > 0) { + this.editableVersionMap.set(pathname, true) + } else { + this.editableVersionMap.set(pathname, false) + } + this.hasHistoryVersion = this.editableVersionMap.get(pathname) + }, + // loading + viewHistoryFile({historyInfo, diff, recovery}) { + const pathname = this.editableTabsValue + let currentIndex = this.editableTabs.findIndex(editable => editable.name === pathname) + const tab = this.editableTabs[currentIndex] + + if (this.isShowUpdateBtn) { + this.$message({type: 'info', message: "请先保存当前修改的内容"}) + return + } + + const currentContentText = this.getContentText(currentIndex) + + let loadingInfo = recovery ? '恢复中...' : '加载中...' + this.loading = this.$message({ + iconClass: 'el-icon-loading', + type: 'info', + duration: 0, + dangerouslyUseHTMLString: true, + message: ` ${loadingInfo}` + }) + historyApi.previewHistoryText({id: historyInfo.id}).then((res) => { + // add new tab + let newTab = { + title: tab.title, + copyTitle: tab.copyTitle, + status: undefined, + language: tab.language, + name: pathname, + hasHistoryVersion: !recovery || diff, + historyVersion: historyInfo + } + // remove + this.removeTab(pathname) + this.$nextTick(() => { + this.loading.close() + this.editableTabs.splice(currentIndex, 0, newTab) + if (diff) { + this.setEditMap(currentIndex, currentContentText, res.data.contentText, historyInfo.metadata.time) + } else { + this.setEditMap(currentIndex, res.data.contentText) + } + this.editableTabsValue = pathname + if (this.historyListPopoverVisible) { + this.historyListPopoverVisible = false + } + if (recovery) { + this.historyVersion = {metadata: {}} + } else { + this.historyVersion = newTab.historyVersion + } + if (recovery) { + this.$message({message: '恢复成功',type: 'success'}) + } + }) + }).catch(() => { + this.loading.close() + }) + }, + recoverySuccess({historyInfo}) { + this.viewHistoryFile({historyInfo: historyInfo, diff: false, recovery: true}) + }, abortControllerAbort(index) { const map = this.abortControllerMap.get(index) if (map !== undefined && map.abort !== undefined) { @@ -362,7 +471,7 @@ const readOnly = this.panelReadOnly this.options.readOnly = true this.abortControllerAbort(index) - const queryString = this.buildQueryString(params); + const queryString = this.buildQueryString(params) let url = "/api/preview/text/stream" if (request === 'previewTextByPath') { url = "/api/preview/path/text/stream" @@ -374,8 +483,7 @@ let result = ""; // 创建一个节流函数,限制更新频率为每 1500 毫秒一次 const throttledUpdateContent = _.throttle(text => { - this.content = text; - this.setEditMap(index, this.content) + this.setEditMap(index, text) }, 1500); this.abortControllerMap.set(index, {abort: abortController, throttle: throttledUpdateContent}) @@ -387,8 +495,7 @@ if (done) { // 确保在流结束时取消节流 throttledUpdateContent.cancel(); - this.content = result; - this.setEditMap(index, this.content) + this.setEditMap(index, result) this.options.readOnly = readOnly return; } @@ -454,7 +561,7 @@ } }, // 拖动调整窗口大小 - dargDialogSize(){ + dragDialogSize(){ // 右下角 let nwse = document.querySelector('.el-dialog__body .nwse-resize') if(nwse){ @@ -567,7 +674,7 @@ if(row.isFolder){ return } - if(!suffix.simText.includes(row.suffix)){ + if(!suffix.simText.includes(row.suffix) && row.contentType.indexOf('utf-8') < 0){ return } let languages = monaco.languages.getLanguages(); @@ -621,6 +728,9 @@ } } this.editableTabsValue = row.path + + // 加载历史版本 + this.$refs.historyPopover.loadHistoryPathList(row.path) }).catch(() => { this.loading.close() }) @@ -629,15 +739,50 @@ this.clickTab() } }, - setEditMap(index, text) { + getContentText(index) { + let ref = 'monacoEditor' + index + return this.$refs[ref][0]._getValue() + }, + setEditMap(index, text, historyText, historyVersion) { this.editableValueMap.set(index, text) this.$nextTick(()=> { let ref = 'monacoEditor' + index - this.$refs[ref][0]._setValue(text) + if (historyText) { + this.$refs[ref][0]._setModel(text, historyText) + } else { + this.$refs[ref][0]._setValue(text) + } if (!this.$pc && this.dialogWidthPercent < 1) { this.fullScreen() } }) + + this.$nextTick(() => { + const pathname = this.editableTabs[index].name + let monacoDiffEditor = document.getElementById(`pane-${pathname}`) + let original = monacoDiffEditor.querySelector(".editor.original") + let current = monacoDiffEditor.querySelector(".editor.modified") + if (original !== null && current !== null) { + this.setVersionInfo(original, historyVersion) + this.setVersionInfo(current, "当前版本") + } + }) + + }, + setVersionInfo(editor, versionInfo) { + const existingDiv = editor.querySelector('.version-info'); + if (!existingDiv) { + const div = document.createElement('div'); + div.className = 'version-info'; + div.textContent = versionInfo; + if (editor.firstChild) { + editor.insertBefore(div, editor.firstChild); + } else { + editor.appendChild(div); + } + } else { + existingDiv.textContent = versionInfo + } }, containerResize() { this.loadEditorSize() @@ -666,7 +811,7 @@ } }, loadEditorSize(){ - this.dialogWidth = document.body.clientWidth * this.dialogWidthPercent + this.setDialogWidth() if(this.contentsHide){ this.editorWidth = this.dialogWidth }else{ @@ -701,7 +846,7 @@ this.isSaveDialogVisible = false this.isShowUpdateBtn = false }, - // 放弃修改 + // Abandon Modification closeTabDialog(){ this.isTabSaveDialogVisible = false this.editableTabsValue = this.nextActiveName @@ -716,24 +861,26 @@ this.$emit('update:status', this.textPreviewVisible) this.isSaveDialogVisible = false this.isShowUpdateBtn = false + this.historyVersion = {metadata: {}} this.closeAllTabs() }, change(value,index) { + let editableTabValue = this.editableTabs[index] if(value === this.editableValueMap.get(index)){ - if(this.editableTabs[index].copyTitle !== this.editableTabs[index].title){ - this.editableTabs[index].title = this.editableTabs[index].copyTitle - this.editableTabs[index].status = 'Modified' - // 没有任何改变 + if(editableTabValue.copyTitle !== editableTabValue.title){ + editableTabValue.title = editableTabValue.copyTitle + editableTabValue.status = 'Modified' + // without any change if(this.editableTabs.findIndex(tab=>tab.title !== tab.copyTitle) < 0){ this.isShowUpdateBtn = false } } }else{ - if(this.editableTabs[index].copyTitle === this.editableTabs[index].title){ - this.editableTabs[index].title += '*' - this.editableTabs[index].status = 'Modifying' + if(editableTabValue.copyTitle === editableTabValue.title){ + editableTabValue.title += '*' + editableTabValue.status = 'Modifying' this.isShowUpdateBtn = true - this.editableTabs[index].change = value + editableTabValue.change = value } } }, @@ -758,7 +905,7 @@ this.abortControllerAbort(key) } }, - save(value,index) { + save(value, index) { if(value !== this.editableTabs[index].content && this.isShowUpdateBtn){ this.update(value,this.editableTabs[index].name,index) } @@ -794,6 +941,7 @@ } } if(!this.modifyMsg){ + this.$refs.historyPopover.loadHistoryPathList(this.editableTabsValue) this.modifyMsg = this.$message({ message: "更新成功", type: 'success', @@ -815,11 +963,11 @@ if(this.fullscreen){ this.lastTransform = dragDom.style.transform this.dialogWidthPercent = 1 - this.dialogWidth = document.body.clientWidth * this.dialogWidthPercent + this.setDialogWidth() dragDom.style.transform="translate("+0+"px,"+0+"px)"; }else{ this.dialogWidthPercent = 0.7 - this.dialogWidth = document.body.clientWidth * this.dialogWidthPercent + this.setDialogWidth() let x = (document.body.clientWidth - this.dialogWidth)/2 let y = (document.body.clientHeight - this.dialogWidth)/2 if(this.lastTransform){ @@ -880,8 +1028,8 @@ this.clickTab() }, clickTab() { - this.editorWidth += 0.001 - this.editorHieght += 0.001 + // this.editorWidth += 0.001 + // this.editorHieght += 0.001 }, removeTab(targetName) { let tabs = this.editableTabs; @@ -900,13 +1048,19 @@ } this.nextActiveName = activeName if(this.editableTabs[removeIndex].status !== 'Modifying'){ - this.editableTabsValue = activeName this.editableTabs = tabs.filter(tab => tab.name !== targetName) }else{ this.removeIndex = removeIndex this.isTabSaveDialogVisible = true } + this.editableTabsValue = activeName this.abortControllerAbort(removeIndex) + setTimeout(()=> { + if (this.editableTabs.length < 1) { + this.hasHistoryVersion = false + this.historyVersion = {metadata: {}} + } + }, 100) }, } } @@ -983,15 +1137,14 @@ background: #ececec; border: 1px solid #ececec; } - + .light-button:hover { + background: #DCDFE6; + } .dark-button { background: #3e3e3e; border: 1px solid #3e3e3e; color: #ffffff; } - .light-button:hover { - background: #DCDFE6; - } .dark-button:hover { color: #409EFF; background-color: #181818; @@ -1407,4 +1560,5 @@ padding: 20px 30px; background-color: #ffffff; } + diff --git a/src/styles/index.scss b/src/styles/index.scss index 2454428..c4e7c0c 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -183,3 +183,46 @@ input { background-color:transparent; } + +.file-history-popover { + .el-popconfirm { + width: 310px; + } +} +.dark-file-history-popover { + background-color: #202021; + color: #b7b7b7; + border: 1px solid #2e2e30; + .el-popconfirm { + width: 310px; + } +} + +.dark-file-history-list.el-table--enable-row-hover { + .el-table__body tr:hover>td { + background-color: #2e2e30; + color: #fff; + } +} + +.dark-file-history-list.el-table { + background-color: #202021; + tr,th,td { + background-color: #202021; + color: #b7b7b7; + border-bottom: 1px solid #3e3e3e; + } + + .dark-button { + background: #3e3e3e; + border: 1px solid #3e3e3e; + color: #ffffff; + } + .dark-button:hover { + color: #409EFF; + background-color: #181818; + } +} +.dark-file-history-list.el-table::before { + background-color: #3e3e3e; +} diff --git a/src/utils/file-config.js b/src/utils/file-config.js index 1fed9ab..86cc4f8 100644 --- a/src/utils/file-config.js +++ b/src/utils/file-config.js @@ -30,6 +30,10 @@ export default { } return fileUrl }, + // 预览历史文件 + previewHistoryUrl: function(historyId, name, token) { + return `${this.baseUrl}/history/preview/file?id=${historyId}&name=${name}&jmal-token=${token}` + }, // markdown里上传图片后的图片预览地址 markdownPreviewUrl: function (path){ return window.location.origin + `${this.baseUrl}${path}`
+ + {{'确定要恢复到'+ scope.row.metadata.time +'吗?当前内容将被覆盖!'}} +
+ + {{'确定要删除'+ scope.row.metadata.time +'吗?这将永久删除该历史版本!'}} +