perf: 优化文件历史查看

This commit is contained in:
kuaifan 2022-04-26 08:47:58 +08:00
parent 00f80e8db8
commit 41e60ee990
14 changed files with 397 additions and 203 deletions

View File

@ -804,6 +804,46 @@ class FileController extends AbstractController
return Base::retSuccess('success', $data); return Base::retSuccess('success', $data);
} }
/**
* @api {get} api/file/content/restore 13. 恢复文件历史
*
* @apiDescription 需要token身份
* @apiVersion 1.0.0
* @apiGroup file
* @apiName content__restore
*
* @apiParam {Number} id 文件ID
* @apiParam {Number} history_id 历史数据ID
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
* @apiSuccess {Object} data 返回数据
*/
public function content__restore()
{
$user = User::auth();
//
$id = intval(Request::input('id'));
$history_id = intval(Request::input('history_id'));
//
$file = File::permissionFind($id);
//
$history = FileContent::whereFid($file->id)->whereId($history_id)->first();
if (empty($history)) {
return Base::retError('历史数据不存在或已被删除');
}
//
$content = $history->replicate();
$content->userid = $user->userid;
$content->save();
//
$file->size = $content->size;
$file->save();
$file->pushMsg('content');
//
return Base::retSuccess('还原成功');
}
/** /**
* @api {get} api/file/share 13. 获取共享信息 * @api {get} api/file/share 13. 获取共享信息
* *

View File

@ -73,6 +73,10 @@ export default {
type: String, type: String,
default: '' default: ''
}, },
historyId: {
type: Number,
default: 0
},
value: { value: {
type: [Object, Array], type: [Object, Array],
default: function () { default: function () {
@ -178,14 +182,20 @@ export default {
break; break;
} }
// //
let fileKey = this.code || this.value.id; let codeId = this.code || this.value.id;
let fileName = $A.strExists(this.fileName, '.') ? this.fileName : (this.fileName + '.' + this.fileType); let fileName = $A.strExists(this.fileName, '.') ? this.fileName : (this.fileName + '.' + this.fileType);
let fileKey = `${this.fileType}-${fileKey}-${keyAppend}`;
let fileUrl = `http://nginx/api/file/content/?id=${codeId}&token=${this.userToken}`;
if (this.historyId > 0) {
fileKey += `-${this.historyId}`
fileUrl += `&history_id=${this.historyId}`
}
const config = { const config = {
"document": { "document": {
"fileType": this.fileType, "fileType": this.fileType,
"key": `${this.fileType}-${fileKey}-${keyAppend}`,
"title": fileName, "title": fileName,
"url": `http://nginx/api/file/content/?id=${fileKey}&token=${this.userToken}`, "key": fileKey,
"url": fileUrl,
}, },
"editorConfig": { "editorConfig": {
"mode": "edit", "mode": "edit",
@ -199,18 +209,21 @@ export default {
"forcesave": true, "forcesave": true,
"help": false, "help": false,
}, },
"callbackUrl": `http://nginx/api/file/content/office?id=${fileKey}&token=${this.userToken}`, "callbackUrl": `http://nginx/api/file/content/office?id=${codeId}&token=${this.userToken}`,
} },
"events": {
"onDocumentReady": this.onDocumentReady,
},
}; };
if (/\/hideenOfficeTitle\//.test(window.navigator.userAgent)) { if (/\/hideenOfficeTitle\//.test(window.navigator.userAgent)) {
config.document.title = " "; config.document.title = " ";
} }
if ($A.leftExists(fileKey, "msgFile_")) { if ($A.leftExists(codeId, "msgFile_")) {
config.document.url = `http://nginx/api/dialog/msg/download/?msg_id=${$A.leftDelete(fileKey, "msgFile_")}&token=${this.userToken}`; config.document.url = `http://nginx/api/dialog/msg/download/?msg_id=${$A.leftDelete(codeId, "msgFile_")}&token=${this.userToken}`;
} else if ($A.leftExists(fileKey, "taskFile_")) { } else if ($A.leftExists(codeId, "taskFile_")) {
config.document.url = `http://nginx/api/project/task/filedown/?file_id=${$A.leftDelete(fileKey, "taskFile_")}&token=${this.userToken}`; config.document.url = `http://nginx/api/project/task/filedown/?file_id=${$A.leftDelete(codeId, "taskFile_")}&token=${this.userToken}`;
} }
if (this.readOnly) { if (this.readOnly || this.historyId > 0) {
config.editorConfig.mode = "view"; config.editorConfig.mode = "view";
config.editorConfig.callbackUrl = null; config.editorConfig.callbackUrl = null;
if (!config.editorConfig.user.id) { if (!config.editorConfig.user.id) {
@ -226,6 +239,10 @@ export default {
this.$nextTick(() => { this.$nextTick(() => {
this.docEditor = new DocsAPI.DocEditor(this.id, config); this.docEditor = new DocsAPI.DocEditor(this.id, config);
}) })
},
onDocumentReady() {
this.$emit("on-document-ready", this.docEditor)
} }
} }
} }

View File

@ -9,6 +9,7 @@
<slot></slot> <slot></slot>
<ETooltip <ETooltip
v-for="(item, key) in menu" v-for="(item, key) in menu"
v-if="item.hidden !== true"
placement="top" placement="top"
:key="key" :key="key"
:disabled="!item.title" :disabled="!item.title"
@ -21,8 +22,13 @@
trigger="click" trigger="click"
class="menu-dropdown" class="menu-dropdown"
@command="onClick"> @command="onClick">
<a
v-if="item.label"
:href="item.href || 'javascript:void(0)'"
:target="item.target || '_self'"
:style="item.style || {}">{{item.label}}</a>
<i <i
v-if="isAliIcon(item.icon)" v-else-if="isAliIcon(item.icon)"
class="taskfont menu-icon" class="taskfont menu-icon"
v-html="item.icon" v-html="item.icon"
:style="item.style || {}"/> :style="item.style || {}"/>
@ -34,14 +40,22 @@
<EDropdownMenu slot="dropdown"> <EDropdownMenu slot="dropdown">
<EDropdownItem <EDropdownItem
v-for="(d, k) in item.children" v-for="(d, k) in item.children"
v-if="d.hidden !== true"
:key="k" :key="k"
:command="d.action" :command="d.action"
:disabled="!!d.disabled"
:divided="!!d.divided" :divided="!!d.divided"
:style="d.style || {}"> :style="d.style || {}">
<div>{{d.title}}</div> <div>{{d.title}}</div>
</EDropdownItem> </EDropdownItem>
</EDropdownMenu> </EDropdownMenu>
</EDropdown> </EDropdown>
<a
v-else-if="item.label"
:href="item.href || 'javascript:void(0)'"
:target="item.target || '_self'"
:style="item.style || {}"
@click="onClick(item.action)">{{item.label}}</a>
<i <i
v-else-if="isAliIcon(item.icon)" v-else-if="isAliIcon(item.icon)"
class="taskfont menu-icon" class="taskfont menu-icon"
@ -64,7 +78,7 @@ import VueResizeObserver from "vue-resize-observer";
import Vue from 'vue' import Vue from 'vue'
Vue.use(VueResizeObserver); Vue.use(VueResizeObserver);
export default { export default {
name: 'TableAction', name: 'TableAction',
props: { props: {
column: { column: {
@ -170,5 +184,5 @@ Vue.use(VueResizeObserver);
this.$emit("action", action) this.$emit("action", action)
} }
} }
} }
</script> </script>

View File

@ -388,6 +388,19 @@
text = text.replace(/<img\s+class="emoticon"[^>]*?>/g, `[${$A.L('表情')}]`) text = text.replace(/<img\s+class="emoticon"[^>]*?>/g, `[${$A.L('表情')}]`)
text = text.replace(/<img\s+class="browse"[^>]*?>/g, `[${$A.L('图片')}]`) text = text.replace(/<img\s+class="browse"[^>]*?>/g, `[${$A.L('图片')}]`)
return text.replace(/<[^>]+>/g,"") return text.replace(/<[^>]+>/g,"")
},
/**
* 获取文件标题
* @param file
* @returns {*}
*/
getFileName(file) {
let {name, ext} = file;
if (ext != '') {
name += "." + ext;
}
return name;
} }
}); });

View File

@ -302,8 +302,8 @@ export default {
} }
if (this.$Electron) { if (this.$Electron) {
this.$Electron.sendMessage('windowRouter', { this.$Electron.sendMessage('windowRouter', {
name: 'file-msg-' + this.msgData.id, name: `file-msg-${this.msgData.id}`,
path: "/single/file/msg/" + this.msgData.id, path: `/single/file/msg/${this.msgData.id}`,
userAgent: "/hideenOfficeTitle/", userAgent: "/hideenOfficeTitle/",
force: false, force: false,
config: { config: {

View File

@ -2,7 +2,18 @@
<div v-if="ready" class="file-content"> <div v-if="ready" class="file-content">
<iframe v-if="isPreview" ref="myPreview" class="preview-iframe" :src="previewUrl"></iframe> <iframe v-if="isPreview" ref="myPreview" class="preview-iframe" :src="previewUrl"></iframe>
<template v-else> <template v-else>
<div v-show="!['word', 'excel', 'ppt'].includes(file.type)" class="edit-header"> <div v-if="['word', 'excel', 'ppt'].includes(file.type)" class="office-header">
<div v-if="!file.only_view && officeReady" class="header-icons">
<div class="header-icon" @click="handleClick('link')"><i class="taskfont">&#xe785;</i></div>
<EPopover v-model="historyShow" trigger="click">
<div class="file-content-history">
<FileHistory :value="historyShow" :file="file" @on-restore="onRestoreHistory"/>
</div>
<div slot="reference" class="header-icon"><i class="taskfont">&#xe71d;</i></div>
</EPopover>
</div>
</div>
<div v-else class="edit-header">
<div class="header-title"> <div class="header-title">
<EPopover v-if="!equalContent" v-model="unsaveTip" class="file-unsave-tip"> <EPopover v-if="!equalContent" v-model="unsaveTip" class="file-unsave-tip">
<div class="task-detail-delete-file-popover"> <div class="task-detail-delete-file-popover">
@ -14,7 +25,7 @@
</div> </div>
<span slot="reference">[{{$L('未保存')}}*]</span> <span slot="reference">[{{$L('未保存')}}*]</span>
</EPopover> </EPopover>
{{formatName(file)}} {{$A.getFileName(file)}}
</div> </div>
<div class="header-user"> <div class="header-user">
<ul> <ul>
@ -50,7 +61,7 @@
</ETooltip> </ETooltip>
<EPopover v-model="historyShow" trigger="click"> <EPopover v-model="historyShow" trigger="click">
<div class="file-content-history"> <div class="file-content-history">
<FileHistory :value="historyShow" :fileId="fileId" @on-select="handleHistory"/> <FileHistory :value="historyShow" :file="file" @on-restore="onRestoreHistory"/>
</div> </div>
<ETooltip slot="reference" :disabled="historyShow" :content="$L('历史版本')"> <ETooltip slot="reference" :disabled="historyShow" :content="$L('历史版本')">
<div class="header-icon"><i class="taskfont">&#xe71d;</i></div> <div class="header-icon"><i class="taskfont">&#xe71d;</i></div>
@ -61,6 +72,7 @@
</template> </template>
</div> </div>
<div v-if="contentDetail" class="content-body"> <div v-if="contentDetail" class="content-body">
<div v-if="historyShow" class="content-mask"></div>
<template v-if="file.type=='document'"> <template v-if="file.type=='document'">
<MDEditor v-if="contentDetail.type=='md'" v-model="contentDetail.content" height="100%"/> <MDEditor v-if="contentDetail.type=='md'" v-model="contentDetail.content" height="100%"/>
<TEditor v-else v-model="contentDetail.content" height="100%" @editorSave="handleClick('saveBefore')"/> <TEditor v-else v-model="contentDetail.content" height="100%" @editorSave="handleClick('saveBefore')"/>
@ -68,8 +80,7 @@
<Drawio v-else-if="file.type=='drawio'" ref="myFlow" v-model="contentDetail" :title="file.name" @saveData="handleClick('saveBefore')"/> <Drawio v-else-if="file.type=='drawio'" ref="myFlow" v-model="contentDetail" :title="file.name" @saveData="handleClick('saveBefore')"/>
<Minder v-else-if="file.type=='mind'" ref="myMind" v-model="contentDetail" @saveData="handleClick('saveBefore')"/> <Minder v-else-if="file.type=='mind'" ref="myMind" v-model="contentDetail" @saveData="handleClick('saveBefore')"/>
<AceEditor v-else-if="['code', 'txt'].includes(file.type)" v-model="contentDetail.content" :ext="file.ext" @saveData="handleClick('saveBefore')"/> <AceEditor v-else-if="['code', 'txt'].includes(file.type)" v-model="contentDetail.content" :ext="file.ext" @saveData="handleClick('saveBefore')"/>
<OnlyOffice v-else-if="['word', 'excel', 'ppt'].includes(file.type)" v-model="contentDetail" :documentKey="documentKey"/> <OnlyOffice v-else-if="['word', 'excel', 'ppt'].includes(file.type)" v-model="contentDetail" :documentKey="documentKey" @on-document-ready="handleClick('officeReady')"/>
<div v-if="historyShow" class="content-mask"></div>
</div> </div>
</template> </template>
<div v-if="contentLoad" class="content-load"><Loading/></div> <div v-if="contentLoad" class="content-load"><Loading/></div>
@ -151,6 +162,7 @@ export default {
linkLoad: 0, linkLoad: 0,
historyShow: false, historyShow: false,
officeReady: false,
} }
}, },
@ -190,6 +202,7 @@ export default {
} else { } else {
this.linkShow = false; this.linkShow = false;
this.historyShow = false; this.historyShow = false;
this.officeReady = false;
} }
}, },
immediate: true, immediate: true,
@ -275,7 +288,7 @@ export default {
} }
}, },
getContent(history_id = 0) { getContent() {
if (this.fileId === 0) { if (this.fileId === 0) {
this.contentDetail = {}; this.contentDetail = {};
this.updateBak(); this.updateBak();
@ -292,13 +305,10 @@ export default {
url: 'file/content', url: 'file/content',
data: { data: {
id: this.fileId, id: this.fileId,
history_id: history_id
}, },
}).then(({data}) => { }).then(({data}) => {
this.contentDetail = data.content; this.contentDetail = data.content;
if (!history_id) {
this.updateBak(); this.updateBak();
}
}).catch(({msg}) => { }).catch(({msg}) => {
$A.modalError(msg); $A.modalError(msg);
}).finally(_ => { }).finally(_ => {
@ -355,23 +365,38 @@ export default {
this.loadSave--; this.loadSave--;
}) })
break; break;
case "officeReady":
this.officeReady = true
break;
} }
}, },
handleHistory(item) { onRestoreHistory(item) {
this.historyShow = false; this.historyShow = false;
if (!this.equalContent) {
$A.modalConfirm({ $A.modalConfirm({
content: '修改的内容尚未保存,确定要读取历史记录吗?', content: `你确定文件还原至【${item.created_at}】吗?`,
cancelText: '取消', cancelText: '取消',
okText: '确定', okText: '确定',
loading: true,
onOk: () => { onOk: () => {
this.getContent(item.id) this.$store.dispatch("call", {
url: 'file/content/restore',
data: {
id: this.fileId,
history_id: item.id,
}
}).then(({msg}) => {
$A.messageSuccess(msg);
this.contentDetail = null;
this.getContent();
}).catch(({msg}) => {
$A.modalError(msg, 301);
}).finally(_ => {
this.$Modal.remove();
});
} }
}); });
} else {
this.getContent(item.id)
}
}, },
linkGet(refresh) { linkGet(refresh) {
@ -443,14 +468,6 @@ export default {
}); });
}) })
}, },
formatName(file) {
let {name, ext} = file;
if (ext != '') {
name += "." + ext;
}
return name;
},
} }
} }
</script> </script>

View File

@ -1,12 +1,13 @@
<template> <template>
<div class="file-history"> <div class="file-history">
<Table <Table
:width="460" :width="480"
:max-height="windowHeight - 180" :max-height="windowHeight - 180"
:columns="columns" :columns="columns"
:data="list" :data="list"
:loading="loadIng > 0" :loading="loadIng > 0"
:no-data-text="$L(noText)" :no-data-text="$L(noText)"
highlight-row
stripe/> stripe/>
<Page <Page
v-if="total > pageSize" v-if="total > pageSize"
@ -40,9 +41,11 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
}, },
fileId: { file: {
type: Number, type: Object,
default: 0 default: () => {
return {};
}
}, },
}, },
@ -70,7 +73,7 @@ export default {
}, { }, {
title: this.$L('大小'), title: this.$L('大小'),
key: 'size', key: 'size',
width: 80, width: 90,
render: (h, {row}) => { render: (h, {row}) => {
return h('AutoTip', $A.bytesToSize(row.size)); return h('AutoTip', $A.bytesToSize(row.size));
} }
@ -78,26 +81,29 @@ export default {
title: this.$L('操作'), title: this.$L('操作'),
align: 'center', align: 'center',
width: 100, width: 100,
render: (h, {row, column}) => { render: (h, {index, row, column}) => {
const vNodes = [ if (index === 0) {
h('div', { return h('div', '-');
style: {
fontSize: '13px',
cursor: 'pointer',
color: '#8bcf70',
},
on: {
'click': () => {
this.$emit('on-select', row)
} }
},
}, this.$L('读取')),
];
return h('TableAction', { return h('TableAction', {
props: { props: {
column: column column: column,
menu: [
{
label: this.$L('查看'),
action: "preview",
}, {
label: this.$L('还原'),
action: "restore",
} }
}, vNodes); ]
},
on: {
action: (name) => {
this.onAction(name, row)
}
}
});
} }
} }
], ],
@ -126,7 +132,11 @@ export default {
}, },
computed: { computed: {
...mapState(['windowHeight']) ...mapState(['windowHeight']),
fileId() {
return this.file.id || 0
},
}, },
methods: { methods: {
@ -164,6 +174,37 @@ export default {
this.pageSize = pageSize; this.pageSize = pageSize;
this.getLists(); this.getLists();
}, },
onAction(name, row) {
switch (name) {
case 'restore':
this.$emit('on-restore', row)
break;
case 'preview':
if (this.$Electron) {
this.$Electron.sendMessage('windowRouter', {
name: `file-${this.fileId}-${row.id}`,
path: `/single/file/${this.fileId}?history_id=${row.id}&history_at=${row.created_at}`,
userAgent: "/hideenOfficeTitle/",
force: false,
config: {
title: $A.getFileName(this.file) + ` [${row.created_at}]`,
titleFixed: true,
parent: null,
width: Math.min(window.screen.availWidth, 1440),
height: Math.min(window.screen.availHeight, 900),
},
webPreferences: {
nodeIntegrationInSubFrames: this.file.type === 'drawio'
},
});
} else {
window.open($A.apiUrl(`../single/file/${this.fileId}?history_id=${row.id}&history_at=${row.created_at}`))
}
break;
}
},
} }
} }
</script> </script>

View File

@ -4,7 +4,7 @@
<template v-else> <template v-else>
<div v-show="!['word', 'excel', 'ppt'].includes(file.type)" class="edit-header"> <div v-show="!['word', 'excel', 'ppt'].includes(file.type)" class="edit-header">
<div class="header-title"> <div class="header-title">
{{formatName(file)}} {{$A.getFileName(file)}}
<Tag color="default">{{$L('只读')}}</Tag> <Tag color="default">{{$L('只读')}}</Tag>
<div class="refresh"> <div class="refresh">
<Loading v-if="contentLoad"/> <Loading v-if="contentLoad"/>
@ -30,7 +30,7 @@
<Drawio v-else-if="file.type=='drawio'" ref="myFlow" :value="contentDetail" :title="file.name" readOnly/> <Drawio v-else-if="file.type=='drawio'" ref="myFlow" :value="contentDetail" :title="file.name" readOnly/>
<Minder v-else-if="file.type=='mind'" ref="myMind" :value="contentDetail" readOnly/> <Minder v-else-if="file.type=='mind'" ref="myMind" :value="contentDetail" readOnly/>
<AceEditor v-else-if="['code', 'txt'].includes(file.type)" :value="contentDetail.content" :ext="file.ext" readOnly/> <AceEditor v-else-if="['code', 'txt'].includes(file.type)" :value="contentDetail.content" :ext="file.ext" readOnly/>
<OnlyOffice v-else-if="['word', 'excel', 'ppt'].includes(file.type)" :value="contentDetail" :code="code" :documentKey="documentKey" readOnly/> <OnlyOffice v-else-if="['word', 'excel', 'ppt'].includes(file.type)" :value="contentDetail" :code="code" :historyId="historyId" :documentKey="documentKey" readOnly/>
</div> </div>
</template> </template>
<div v-if="contentLoad" class="content-load"><Loading/></div> <div v-if="contentLoad" class="content-load"><Loading/></div>
@ -56,6 +56,10 @@ export default {
type: String, type: String,
default: '' default: ''
}, },
historyId: {
type: Number,
default: 0
},
file: { file: {
type: Object, type: Object,
default: () => { default: () => {
@ -134,6 +138,7 @@ export default {
url: 'file/content', url: 'file/content',
data: { data: {
id: this.code || this.file.id, id: this.code || this.file.id,
history_id: this.historyId
}, },
}).then(({data}) => { }).then(({data}) => {
this.contentDetail = data.content; this.contentDetail = data.content;
@ -167,14 +172,6 @@ export default {
break; break;
} }
}, },
formatName(file) {
let {name, ext} = file;
if (ext != '') {
name += "." + ext;
}
return name;
},
} }
} }
</script> </script>

View File

@ -103,8 +103,8 @@ export default {
height: Math.min(window.screen.availHeight, 900), height: Math.min(window.screen.availHeight, 900),
} }
this.$Electron.sendMessage('windowRouter', { this.$Electron.sendMessage('windowRouter', {
name: 'report-' + row.id, name: `report-detail-${row.id}`,
path: "/single/report/detail/" + row.id, path: `/single/report/detail/${row.id}`,
force: false, force: false,
config config
}); });
@ -122,8 +122,8 @@ export default {
height: Math.min(window.screen.availHeight, 900), height: Math.min(window.screen.availHeight, 900),
} }
this.$Electron.sendMessage('windowRouter', { this.$Electron.sendMessage('windowRouter', {
name: 'report-' + id, name: `report-edit-${id}`,
path: "/single/report/edit/" + id, path: `/single/report/edit/${id}`,
force: false, force: false,
config config
}); });

View File

@ -1206,8 +1206,8 @@ export default {
config.minHeight = 600; config.minHeight = 600;
} }
this.$Electron.sendMessage('windowRouter', { this.$Electron.sendMessage('windowRouter', {
name: 'task-' + this.taskDetail.id, name: `task-${this.taskDetail.id}`,
path: "/single/task/" + this.taskDetail.id, path: `/single/task/${this.taskDetail.id}`,
force: false, force: false,
config config
}); });
@ -1251,8 +1251,8 @@ export default {
} }
if (this.$Electron) { if (this.$Electron) {
this.$Electron.sendMessage('windowRouter', { this.$Electron.sendMessage('windowRouter', {
name: 'file-task-' + file.id, name: `file-task-${file.id}`,
path: "/single/file/task/" + file.id, path: `/single/file/task/${file.id}`,
userAgent: "/hideenOfficeTitle/", userAgent: "/hideenOfficeTitle/",
force: false, force: false,
config: { config: {

View File

@ -114,7 +114,7 @@
@on-keyup="onKeyup($event, item)"/> @on-keyup="onKeyup($event, item)"/>
<div v-if="item._load" class="file-load"><Loading/></div> <div v-if="item._load" class="file-load"><Loading/></div>
</div> </div>
<div v-else class="file-name" :title="item.name">{{formatName(item)}}</div> <div v-else class="file-name" :title="item.name">{{$A.getFileName(item)}}</div>
</li> </li>
</ul> </ul>
</div> </div>
@ -364,10 +364,6 @@
</template> </template>
<script> <script>
import Vue from 'vue'
import VueClipboard from 'vue-clipboard2'
Vue.use(VueClipboard)
import {mapState} from "vuex"; import {mapState} from "vuex";
import {sortBy} from "lodash"; import {sortBy} from "lodash";
import UserInput from "../../components/UserInput"; import UserInput from "../../components/UserInput";
@ -377,7 +373,6 @@ import PreviewImage from "../../components/PreviewImage";
const FilePreview = () => import('./components/FilePreview'); const FilePreview = () => import('./components/FilePreview');
const FileContent = () => import('./components/FileContent'); const FileContent = () => import('./components/FileContent');
export default { export default {
components: {PreviewImage, FilePreview, DrawerOverlay, UserInput, FileContent}, components: {PreviewImage, FilePreview, DrawerOverlay, UserInput, FileContent},
data() { data() {
@ -749,7 +744,7 @@ export default {
} }
} }
}, [ }, [
h('AutoTip', this.formatName(row)) h('AutoTip', $A.getFileName(row))
])); ]));
// //
const iconArray = []; const iconArray = [];
@ -852,14 +847,6 @@ export default {
}); });
}, },
formatName(file) {
let {name, ext} = file;
if (ext != '') {
name += "." + ext;
}
return name;
},
getFileList() { getFileList() {
if (this.$route.name !== 'manage-file') { if (this.$route.name !== 'manage-file') {
return; return;
@ -976,12 +963,12 @@ export default {
openFileSingle(item) { openFileSingle(item) {
this.$Electron.sendMessage('windowRouter', { this.$Electron.sendMessage('windowRouter', {
name: 'file-' + item.id, name: `file-${item.id}`,
path: "/single/file/" + item.id, path: `/single/file/${item.id}`,
userAgent: "/hideenOfficeTitle/", userAgent: "/hideenOfficeTitle/",
force: false, // force: false, //
config: { config: {
title: this.formatName(item), title: $A.getFileName(item),
titleFixed: true, titleFixed: true,
parent: null, parent: null,
width: Math.min(window.screen.availWidth, 1440), width: Math.min(window.screen.availWidth, 1440),
@ -1103,11 +1090,11 @@ export default {
}, },
}).then(({msg}) => { }).then(({msg}) => {
$A.messageSuccess(msg); $A.messageSuccess(msg);
this.$Modal.remove();
this.$store.dispatch("forgetFile", item.id); this.$store.dispatch("forgetFile", item.id);
}).catch(({msg}) => { }).catch(({msg}) => {
this.$Modal.remove();
$A.modalError(msg, 301); $A.modalError(msg, 301);
}).finally(_ => {
this.$Modal.remove();
}); });
} }
}); });
@ -1221,11 +1208,11 @@ export default {
}, },
}).then(({msg}) => { }).then(({msg}) => {
$A.messageSuccess(msg); $A.messageSuccess(msg);
this.$Modal.remove();
this.$store.dispatch("forgetFile", ids); this.$store.dispatch("forgetFile", ids);
this.selectIds = this.selectIds.filter(id => !ids.includes(id)) this.selectIds = this.selectIds.filter(id => !ids.includes(id))
}).catch(({msg}) => { }).catch(({msg}) => {
$A.modalError(msg, 301); $A.modalError(msg, 301);
}).finally(_ => {
this.$Modal.remove(); this.$Modal.remove();
}); });
} }

View File

@ -1,9 +1,9 @@
<template> <template>
<div class="single-file"> <div class="single-file">
<PageTitle :title="fileInfo.name"/> <PageTitle :title="pageName"/>
<Loading v-if="loadIng > 0"/> <Loading v-if="loadIng > 0"/>
<template v-else> <template v-else>
<FilePreview v-if="code || fileInfo.permission === 0" :code="code" :file="fileInfo"/> <FilePreview v-if="isPreview" :code="code" :file="fileInfo" :historyId="historyId"/>
<FileContent v-else v-model="fileShow" :file="fileInfo"/> <FileContent v-else v-model="fileShow" :file="fileInfo"/>
</template> </template>
</div> </div>
@ -38,6 +38,21 @@ export default {
mounted() { mounted() {
// //
}, },
computed: {
historyId() {
return this.$route.query ? $A.runNum(this.$route.query.history_id) : 0;
},
isPreview() {
return this.code || this.fileInfo.permission === 0 || this.historyId > 0
},
pageName() {
let name = this.fileInfo.name;
if (this.$route.query && this.$route.query.history_at) {
name += ` [${this.$route.query.history_at}]`
}
return name;
}
},
watch: { watch: {
'$route': { '$route': {
handler() { handler() {

View File

@ -64,6 +64,16 @@ body.dark-mode-reverse {
.file-content, .file-content,
.file-preview { .file-preview {
.office-header {
.header-icons {
.header-icon {
color: rgba(0, 0, 0, 0.8);
&:hover {
background-color: rgba(0, 0, 0, 0.05);
}
}
}
}
.content-body { .content-body {
.tox { .tox {
.tox-edit-area__iframe { .tox-edit-area__iframe {

View File

@ -25,6 +25,40 @@
padding: 0; padding: 0;
} }
.office-header {
display: flex;
align-items: center;
position: absolute;
right: 40px;
top: 28px;
z-index: 1;
.header-icons {
display: flex;
align-items: center;
justify-content: center;
.header-icon {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 28px;
line-height: 28px;
cursor: pointer;
color: rgba(255, 255, 255, 0.9);
&:hover {
background-color: rgba(255, 255, 255, 0.2);
}
> i {
font-size: 16px;
}
}
}
}
.edit-header { .edit-header {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -105,6 +139,7 @@
width: 44px; width: 44px;
height: 100%; height: 100%;
color: #777777; color: #777777;
cursor: pointer;
> i { > i {
font-size: 20px; font-size: 20px;
} }
@ -273,6 +308,14 @@
} }
} }
@media (max-width: 768px) {
.file-content {
.office-header {
display: none;
}
}
}
@media (max-width: 1200px) { @media (max-width: 1200px) {
.file-content { .file-content {
overflow: auto; overflow: auto;