mirror of
https://github.com/kuaifan/dootask.git
synced 2026-03-03 07:37:05 +00:00
perf: 优化文件历史查看
This commit is contained in:
parent
00f80e8db8
commit
41e60ee990
@ -804,6 +804,46 @@ class FileController extends AbstractController
|
||||
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. 获取共享信息
|
||||
*
|
||||
|
||||
@ -73,6 +73,10 @@ export default {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
historyId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
value: {
|
||||
type: [Object, Array],
|
||||
default: function () {
|
||||
@ -178,14 +182,20 @@ export default {
|
||||
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 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 = {
|
||||
"document": {
|
||||
"fileType": this.fileType,
|
||||
"key": `${this.fileType}-${fileKey}-${keyAppend}`,
|
||||
"title": fileName,
|
||||
"url": `http://nginx/api/file/content/?id=${fileKey}&token=${this.userToken}`,
|
||||
"key": fileKey,
|
||||
"url": fileUrl,
|
||||
},
|
||||
"editorConfig": {
|
||||
"mode": "edit",
|
||||
@ -199,18 +209,21 @@ export default {
|
||||
"forcesave": true,
|
||||
"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)) {
|
||||
config.document.title = " ";
|
||||
}
|
||||
if ($A.leftExists(fileKey, "msgFile_")) {
|
||||
config.document.url = `http://nginx/api/dialog/msg/download/?msg_id=${$A.leftDelete(fileKey, "msgFile_")}&token=${this.userToken}`;
|
||||
} else if ($A.leftExists(fileKey, "taskFile_")) {
|
||||
config.document.url = `http://nginx/api/project/task/filedown/?file_id=${$A.leftDelete(fileKey, "taskFile_")}&token=${this.userToken}`;
|
||||
if ($A.leftExists(codeId, "msgFile_")) {
|
||||
config.document.url = `http://nginx/api/dialog/msg/download/?msg_id=${$A.leftDelete(codeId, "msgFile_")}&token=${this.userToken}`;
|
||||
} else if ($A.leftExists(codeId, "taskFile_")) {
|
||||
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.callbackUrl = null;
|
||||
if (!config.editorConfig.user.id) {
|
||||
@ -226,6 +239,10 @@ export default {
|
||||
this.$nextTick(() => {
|
||||
this.docEditor = new DocsAPI.DocEditor(this.id, config);
|
||||
})
|
||||
},
|
||||
|
||||
onDocumentReady() {
|
||||
this.$emit("on-document-ready", this.docEditor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
<slot></slot>
|
||||
<ETooltip
|
||||
v-for="(item, key) in menu"
|
||||
v-if="item.hidden !== true"
|
||||
placement="top"
|
||||
:key="key"
|
||||
:disabled="!item.title"
|
||||
@ -21,8 +22,13 @@
|
||||
trigger="click"
|
||||
class="menu-dropdown"
|
||||
@command="onClick">
|
||||
<a
|
||||
v-if="item.label"
|
||||
:href="item.href || 'javascript:void(0)'"
|
||||
:target="item.target || '_self'"
|
||||
:style="item.style || {}">{{item.label}}</a>
|
||||
<i
|
||||
v-if="isAliIcon(item.icon)"
|
||||
v-else-if="isAliIcon(item.icon)"
|
||||
class="taskfont menu-icon"
|
||||
v-html="item.icon"
|
||||
:style="item.style || {}"/>
|
||||
@ -34,14 +40,22 @@
|
||||
<EDropdownMenu slot="dropdown">
|
||||
<EDropdownItem
|
||||
v-for="(d, k) in item.children"
|
||||
v-if="d.hidden !== true"
|
||||
:key="k"
|
||||
:command="d.action"
|
||||
:disabled="!!d.disabled"
|
||||
:divided="!!d.divided"
|
||||
:style="d.style || {}">
|
||||
<div>{{d.title}}</div>
|
||||
</EDropdownItem>
|
||||
</EDropdownMenu>
|
||||
</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
|
||||
v-else-if="isAliIcon(item.icon)"
|
||||
class="taskfont menu-icon"
|
||||
@ -64,111 +78,111 @@ import VueResizeObserver from "vue-resize-observer";
|
||||
import Vue from 'vue'
|
||||
Vue.use(VueResizeObserver);
|
||||
|
||||
export default {
|
||||
name: 'TableAction',
|
||||
props: {
|
||||
column: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
autoWidth: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
minWidth: {
|
||||
type: Number,
|
||||
default: 80
|
||||
},
|
||||
align: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
menu: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
width: 0,
|
||||
height: 0,
|
||||
export default {
|
||||
name: 'TableAction',
|
||||
props: {
|
||||
column: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.onUpdate();
|
||||
autoWidth: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
activated() {
|
||||
this.onUpdate();
|
||||
minWidth: {
|
||||
type: Number,
|
||||
default: 80
|
||||
},
|
||||
beforeUpdate() {
|
||||
this.onUpdate();
|
||||
align: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
computed: {
|
||||
tdStyle() {
|
||||
const style = {};
|
||||
const {align} = this;
|
||||
switch (align.toLowerCase()) {
|
||||
case 'left':
|
||||
style.justifyContent = 'flex-start';
|
||||
break;
|
||||
case 'center':
|
||||
style.justifyContent = 'center';
|
||||
break;
|
||||
case 'right':
|
||||
style.justifyContent = 'flex-end';
|
||||
break;
|
||||
}
|
||||
return style;
|
||||
menu: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isAliIcon(icon) {
|
||||
return $A.leftExists(icon, '&#')
|
||||
},
|
||||
handleIn() {
|
||||
if (this.$refs.action.offsetWidth != this.width) {
|
||||
this.onUpdate();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
width: 0,
|
||||
height: 0,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.onUpdate();
|
||||
},
|
||||
activated() {
|
||||
this.onUpdate();
|
||||
},
|
||||
beforeUpdate() {
|
||||
this.onUpdate();
|
||||
},
|
||||
computed: {
|
||||
tdStyle() {
|
||||
const style = {};
|
||||
const {align} = this;
|
||||
switch (align.toLowerCase()) {
|
||||
case 'left':
|
||||
style.justifyContent = 'flex-start';
|
||||
break;
|
||||
case 'center':
|
||||
style.justifyContent = 'center';
|
||||
break;
|
||||
case 'right':
|
||||
style.justifyContent = 'flex-end';
|
||||
break;
|
||||
}
|
||||
return style;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isAliIcon(icon) {
|
||||
return $A.leftExists(icon, '&#')
|
||||
},
|
||||
handleIn() {
|
||||
if (this.$refs.action.offsetWidth != this.width) {
|
||||
this.onUpdate();
|
||||
}
|
||||
},
|
||||
onUpdate() {
|
||||
this.onResize({
|
||||
width: this.$refs.action.offsetWidth,
|
||||
height: this.$refs.action.offsetHeight,
|
||||
})
|
||||
},
|
||||
onResize({ width, height }) {
|
||||
if (!this.autoWidth) {
|
||||
return;
|
||||
}
|
||||
$A(".ivu-table-column-" + this.column.__id).each((index, el) => {
|
||||
let action = $A(el).find(".td-action-container")
|
||||
if (action.length > 0) {
|
||||
width = Math.max(width, action[0].offsetWidth)
|
||||
height = Math.max(height, action[0].offsetHeight)
|
||||
}
|
||||
},
|
||||
onUpdate() {
|
||||
this.onResize({
|
||||
width: this.$refs.action.offsetWidth,
|
||||
height: this.$refs.action.offsetHeight,
|
||||
});
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
let newWidth = Math.max(this.minWidth, this.width + 26);
|
||||
if (this.column.minWidth) {
|
||||
newWidth = Math.max(this.column.minWidth, newWidth);
|
||||
}
|
||||
if (this.column.maxWidth) {
|
||||
newWidth = Math.min(this.column.maxWidth, newWidth);
|
||||
}
|
||||
if (newWidth != this.column.width) {
|
||||
this.$nextTick(() => {
|
||||
this.$set(this.column, 'width', newWidth);
|
||||
})
|
||||
},
|
||||
onResize({ width, height }) {
|
||||
if (!this.autoWidth) {
|
||||
return;
|
||||
}
|
||||
$A(".ivu-table-column-" + this.column.__id).each((index, el) => {
|
||||
let action = $A(el).find(".td-action-container")
|
||||
if (action.length > 0) {
|
||||
width = Math.max(width, action[0].offsetWidth)
|
||||
height = Math.max(height, action[0].offsetHeight)
|
||||
}
|
||||
});
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
let newWidth = Math.max(this.minWidth, this.width + 26);
|
||||
if (this.column.minWidth) {
|
||||
newWidth = Math.max(this.column.minWidth, newWidth);
|
||||
}
|
||||
if (this.column.maxWidth) {
|
||||
newWidth = Math.min(this.column.maxWidth, newWidth);
|
||||
}
|
||||
if (newWidth != this.column.width) {
|
||||
this.$nextTick(() => {
|
||||
this.$set(this.column, 'width', newWidth);
|
||||
})
|
||||
}
|
||||
},
|
||||
onClick(action) {
|
||||
this.$emit("action", action)
|
||||
}
|
||||
},
|
||||
onClick(action) {
|
||||
this.$emit("action", action)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
13
resources/assets/js/functions/web.js
vendored
13
resources/assets/js/functions/web.js
vendored
@ -388,6 +388,19 @@
|
||||
text = text.replace(/<img\s+class="emoticon"[^>]*?>/g, `[${$A.L('表情')}]`)
|
||||
text = text.replace(/<img\s+class="browse"[^>]*?>/g, `[${$A.L('图片')}]`)
|
||||
return text.replace(/<[^>]+>/g,"")
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取文件标题
|
||||
* @param file
|
||||
* @returns {*}
|
||||
*/
|
||||
getFileName(file) {
|
||||
let {name, ext} = file;
|
||||
if (ext != '') {
|
||||
name += "." + ext;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -302,8 +302,8 @@ export default {
|
||||
}
|
||||
if (this.$Electron) {
|
||||
this.$Electron.sendMessage('windowRouter', {
|
||||
name: 'file-msg-' + this.msgData.id,
|
||||
path: "/single/file/msg/" + this.msgData.id,
|
||||
name: `file-msg-${this.msgData.id}`,
|
||||
path: `/single/file/msg/${this.msgData.id}`,
|
||||
userAgent: "/hideenOfficeTitle/",
|
||||
force: false,
|
||||
config: {
|
||||
|
||||
@ -2,7 +2,18 @@
|
||||
<div v-if="ready" class="file-content">
|
||||
<iframe v-if="isPreview" ref="myPreview" class="preview-iframe" :src="previewUrl"></iframe>
|
||||
<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"></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"></i></div>
|
||||
</EPopover>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="edit-header">
|
||||
<div class="header-title">
|
||||
<EPopover v-if="!equalContent" v-model="unsaveTip" class="file-unsave-tip">
|
||||
<div class="task-detail-delete-file-popover">
|
||||
@ -14,7 +25,7 @@
|
||||
</div>
|
||||
<span slot="reference">[{{$L('未保存')}}*]</span>
|
||||
</EPopover>
|
||||
{{formatName(file)}}
|
||||
{{$A.getFileName(file)}}
|
||||
</div>
|
||||
<div class="header-user">
|
||||
<ul>
|
||||
@ -50,7 +61,7 @@
|
||||
</ETooltip>
|
||||
<EPopover v-model="historyShow" trigger="click">
|
||||
<div class="file-content-history">
|
||||
<FileHistory :value="historyShow" :fileId="fileId" @on-select="handleHistory"/>
|
||||
<FileHistory :value="historyShow" :file="file" @on-restore="onRestoreHistory"/>
|
||||
</div>
|
||||
<ETooltip slot="reference" :disabled="historyShow" :content="$L('历史版本')">
|
||||
<div class="header-icon"><i class="taskfont"></i></div>
|
||||
@ -61,6 +72,7 @@
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="contentDetail" class="content-body">
|
||||
<div v-if="historyShow" class="content-mask"></div>
|
||||
<template v-if="file.type=='document'">
|
||||
<MDEditor v-if="contentDetail.type=='md'" v-model="contentDetail.content" height="100%"/>
|
||||
<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')"/>
|
||||
<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')"/>
|
||||
<OnlyOffice v-else-if="['word', 'excel', 'ppt'].includes(file.type)" v-model="contentDetail" :documentKey="documentKey"/>
|
||||
<div v-if="historyShow" class="content-mask"></div>
|
||||
<OnlyOffice v-else-if="['word', 'excel', 'ppt'].includes(file.type)" v-model="contentDetail" :documentKey="documentKey" @on-document-ready="handleClick('officeReady')"/>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="contentLoad" class="content-load"><Loading/></div>
|
||||
@ -151,6 +162,7 @@ export default {
|
||||
linkLoad: 0,
|
||||
|
||||
historyShow: false,
|
||||
officeReady: false,
|
||||
}
|
||||
},
|
||||
|
||||
@ -190,6 +202,7 @@ export default {
|
||||
} else {
|
||||
this.linkShow = false;
|
||||
this.historyShow = false;
|
||||
this.officeReady = false;
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
@ -275,7 +288,7 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
getContent(history_id = 0) {
|
||||
getContent() {
|
||||
if (this.fileId === 0) {
|
||||
this.contentDetail = {};
|
||||
this.updateBak();
|
||||
@ -292,13 +305,10 @@ export default {
|
||||
url: 'file/content',
|
||||
data: {
|
||||
id: this.fileId,
|
||||
history_id: history_id
|
||||
},
|
||||
}).then(({data}) => {
|
||||
this.contentDetail = data.content;
|
||||
if (!history_id) {
|
||||
this.updateBak();
|
||||
}
|
||||
this.updateBak();
|
||||
}).catch(({msg}) => {
|
||||
$A.modalError(msg);
|
||||
}).finally(_ => {
|
||||
@ -355,23 +365,38 @@ export default {
|
||||
this.loadSave--;
|
||||
})
|
||||
break;
|
||||
|
||||
case "officeReady":
|
||||
this.officeReady = true
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleHistory(item) {
|
||||
onRestoreHistory(item) {
|
||||
this.historyShow = false;
|
||||
if (!this.equalContent) {
|
||||
$A.modalConfirm({
|
||||
content: '修改的内容尚未保存,确定要读取历史记录吗?',
|
||||
cancelText: '取消',
|
||||
okText: '确定',
|
||||
onOk: () => {
|
||||
this.getContent(item.id)
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.getContent(item.id)
|
||||
}
|
||||
$A.modalConfirm({
|
||||
content: `你确定文件还原至【${item.created_at}】吗?`,
|
||||
cancelText: '取消',
|
||||
okText: '确定',
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
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();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
linkGet(refresh) {
|
||||
@ -443,14 +468,6 @@ export default {
|
||||
});
|
||||
})
|
||||
},
|
||||
|
||||
formatName(file) {
|
||||
let {name, ext} = file;
|
||||
if (ext != '') {
|
||||
name += "." + ext;
|
||||
}
|
||||
return name;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
<template>
|
||||
<div class="file-history">
|
||||
<Table
|
||||
:width="460"
|
||||
:width="480"
|
||||
:max-height="windowHeight - 180"
|
||||
:columns="columns"
|
||||
:data="list"
|
||||
:loading="loadIng > 0"
|
||||
:no-data-text="$L(noText)"
|
||||
highlight-row
|
||||
stripe/>
|
||||
<Page
|
||||
v-if="total > pageSize"
|
||||
@ -40,9 +41,11 @@ export default {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
fileId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
file: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@ -70,7 +73,7 @@ export default {
|
||||
}, {
|
||||
title: this.$L('大小'),
|
||||
key: 'size',
|
||||
width: 80,
|
||||
width: 90,
|
||||
render: (h, {row}) => {
|
||||
return h('AutoTip', $A.bytesToSize(row.size));
|
||||
}
|
||||
@ -78,26 +81,29 @@ export default {
|
||||
title: this.$L('操作'),
|
||||
align: 'center',
|
||||
width: 100,
|
||||
render: (h, {row, column}) => {
|
||||
const vNodes = [
|
||||
h('div', {
|
||||
style: {
|
||||
fontSize: '13px',
|
||||
cursor: 'pointer',
|
||||
color: '#8bcf70',
|
||||
},
|
||||
on: {
|
||||
'click': () => {
|
||||
this.$emit('on-select', row)
|
||||
}
|
||||
},
|
||||
}, this.$L('读取')),
|
||||
];
|
||||
render: (h, {index, row, column}) => {
|
||||
if (index === 0) {
|
||||
return h('div', '-');
|
||||
}
|
||||
return h('TableAction', {
|
||||
props: {
|
||||
column: column
|
||||
column: column,
|
||||
menu: [
|
||||
{
|
||||
label: this.$L('查看'),
|
||||
action: "preview",
|
||||
}, {
|
||||
label: this.$L('还原'),
|
||||
action: "restore",
|
||||
}
|
||||
]
|
||||
},
|
||||
on: {
|
||||
action: (name) => {
|
||||
this.onAction(name, row)
|
||||
}
|
||||
}
|
||||
}, vNodes);
|
||||
});
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -126,7 +132,11 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['windowHeight'])
|
||||
...mapState(['windowHeight']),
|
||||
|
||||
fileId() {
|
||||
return this.file.id || 0
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
@ -164,6 +174,37 @@ export default {
|
||||
this.pageSize = pageSize;
|
||||
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>
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<template v-else>
|
||||
<div v-show="!['word', 'excel', 'ppt'].includes(file.type)" class="edit-header">
|
||||
<div class="header-title">
|
||||
{{formatName(file)}}
|
||||
{{$A.getFileName(file)}}
|
||||
<Tag color="default">{{$L('只读')}}</Tag>
|
||||
<div class="refresh">
|
||||
<Loading v-if="contentLoad"/>
|
||||
@ -30,7 +30,7 @@
|
||||
<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/>
|
||||
<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>
|
||||
</template>
|
||||
<div v-if="contentLoad" class="content-load"><Loading/></div>
|
||||
@ -56,6 +56,10 @@ export default {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
historyId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
file: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
@ -134,6 +138,7 @@ export default {
|
||||
url: 'file/content',
|
||||
data: {
|
||||
id: this.code || this.file.id,
|
||||
history_id: this.historyId
|
||||
},
|
||||
}).then(({data}) => {
|
||||
this.contentDetail = data.content;
|
||||
@ -167,14 +172,6 @@ export default {
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
formatName(file) {
|
||||
let {name, ext} = file;
|
||||
if (ext != '') {
|
||||
name += "." + ext;
|
||||
}
|
||||
return name;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -103,8 +103,8 @@ export default {
|
||||
height: Math.min(window.screen.availHeight, 900),
|
||||
}
|
||||
this.$Electron.sendMessage('windowRouter', {
|
||||
name: 'report-' + row.id,
|
||||
path: "/single/report/detail/" + row.id,
|
||||
name: `report-detail-${row.id}`,
|
||||
path: `/single/report/detail/${row.id}`,
|
||||
force: false,
|
||||
config
|
||||
});
|
||||
@ -122,8 +122,8 @@ export default {
|
||||
height: Math.min(window.screen.availHeight, 900),
|
||||
}
|
||||
this.$Electron.sendMessage('windowRouter', {
|
||||
name: 'report-' + id,
|
||||
path: "/single/report/edit/" + id,
|
||||
name: `report-edit-${id}`,
|
||||
path: `/single/report/edit/${id}`,
|
||||
force: false,
|
||||
config
|
||||
});
|
||||
|
||||
@ -1206,8 +1206,8 @@ export default {
|
||||
config.minHeight = 600;
|
||||
}
|
||||
this.$Electron.sendMessage('windowRouter', {
|
||||
name: 'task-' + this.taskDetail.id,
|
||||
path: "/single/task/" + this.taskDetail.id,
|
||||
name: `task-${this.taskDetail.id}`,
|
||||
path: `/single/task/${this.taskDetail.id}`,
|
||||
force: false,
|
||||
config
|
||||
});
|
||||
@ -1251,8 +1251,8 @@ export default {
|
||||
}
|
||||
if (this.$Electron) {
|
||||
this.$Electron.sendMessage('windowRouter', {
|
||||
name: 'file-task-' + file.id,
|
||||
path: "/single/file/task/" + file.id,
|
||||
name: `file-task-${file.id}`,
|
||||
path: `/single/file/task/${file.id}`,
|
||||
userAgent: "/hideenOfficeTitle/",
|
||||
force: false,
|
||||
config: {
|
||||
|
||||
@ -114,7 +114,7 @@
|
||||
@on-keyup="onKeyup($event, item)"/>
|
||||
<div v-if="item._load" class="file-load"><Loading/></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>
|
||||
</ul>
|
||||
</div>
|
||||
@ -364,10 +364,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import VueClipboard from 'vue-clipboard2'
|
||||
Vue.use(VueClipboard)
|
||||
|
||||
import {mapState} from "vuex";
|
||||
import {sortBy} from "lodash";
|
||||
import UserInput from "../../components/UserInput";
|
||||
@ -377,7 +373,6 @@ import PreviewImage from "../../components/PreviewImage";
|
||||
const FilePreview = () => import('./components/FilePreview');
|
||||
const FileContent = () => import('./components/FileContent');
|
||||
|
||||
|
||||
export default {
|
||||
components: {PreviewImage, FilePreview, DrawerOverlay, UserInput, FileContent},
|
||||
data() {
|
||||
@ -749,7 +744,7 @@ export default {
|
||||
}
|
||||
}
|
||||
}, [
|
||||
h('AutoTip', this.formatName(row))
|
||||
h('AutoTip', $A.getFileName(row))
|
||||
]));
|
||||
//
|
||||
const iconArray = [];
|
||||
@ -852,14 +847,6 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
formatName(file) {
|
||||
let {name, ext} = file;
|
||||
if (ext != '') {
|
||||
name += "." + ext;
|
||||
}
|
||||
return name;
|
||||
},
|
||||
|
||||
getFileList() {
|
||||
if (this.$route.name !== 'manage-file') {
|
||||
return;
|
||||
@ -976,12 +963,12 @@ export default {
|
||||
|
||||
openFileSingle(item) {
|
||||
this.$Electron.sendMessage('windowRouter', {
|
||||
name: 'file-' + item.id,
|
||||
path: "/single/file/" + item.id,
|
||||
name: `file-${item.id}`,
|
||||
path: `/single/file/${item.id}`,
|
||||
userAgent: "/hideenOfficeTitle/",
|
||||
force: false, // 如果窗口已存在不重新加载
|
||||
config: {
|
||||
title: this.formatName(item),
|
||||
title: $A.getFileName(item),
|
||||
titleFixed: true,
|
||||
parent: null,
|
||||
width: Math.min(window.screen.availWidth, 1440),
|
||||
@ -1103,11 +1090,11 @@ export default {
|
||||
},
|
||||
}).then(({msg}) => {
|
||||
$A.messageSuccess(msg);
|
||||
this.$Modal.remove();
|
||||
this.$store.dispatch("forgetFile", item.id);
|
||||
}).catch(({msg}) => {
|
||||
this.$Modal.remove();
|
||||
$A.modalError(msg, 301);
|
||||
}).finally(_ => {
|
||||
this.$Modal.remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -1221,11 +1208,11 @@ export default {
|
||||
},
|
||||
}).then(({msg}) => {
|
||||
$A.messageSuccess(msg);
|
||||
this.$Modal.remove();
|
||||
this.$store.dispatch("forgetFile", ids);
|
||||
this.selectIds = this.selectIds.filter(id => !ids.includes(id))
|
||||
}).catch(({msg}) => {
|
||||
$A.modalError(msg, 301);
|
||||
}).finally(_ => {
|
||||
this.$Modal.remove();
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="single-file">
|
||||
<PageTitle :title="fileInfo.name"/>
|
||||
<PageTitle :title="pageName"/>
|
||||
<Loading v-if="loadIng > 0"/>
|
||||
<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"/>
|
||||
</template>
|
||||
</div>
|
||||
@ -38,6 +38,21 @@ export default {
|
||||
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: {
|
||||
'$route': {
|
||||
handler() {
|
||||
|
||||
10
resources/assets/sass/dark.scss
vendored
10
resources/assets/sass/dark.scss
vendored
@ -64,6 +64,16 @@ body.dark-mode-reverse {
|
||||
|
||||
.file-content,
|
||||
.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 {
|
||||
.tox {
|
||||
.tox-edit-area__iframe {
|
||||
|
||||
@ -25,6 +25,40 @@
|
||||
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 {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@ -105,6 +139,7 @@
|
||||
width: 44px;
|
||||
height: 100%;
|
||||
color: #777777;
|
||||
cursor: pointer;
|
||||
> i {
|
||||
font-size: 20px;
|
||||
}
|
||||
@ -273,6 +308,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.file-content {
|
||||
.office-header {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.file-content {
|
||||
overflow: auto;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user