mirror of
https://github.com/kuaifan/dootask.git
synced 2026-01-12 17:08:11 +00:00
feat: 新增查看文件历史版本
This commit is contained in:
parent
ab66b70485
commit
ebb3ec6784
@ -439,6 +439,7 @@ class FileController extends AbstractController
|
||||
* @apiParam {String} down 直接下载
|
||||
* - no: 浏览(默认)
|
||||
* - yes: 下载(office文件直接下载)
|
||||
* @apiParam {Number} [history_id] 读取历史记录ID
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
@ -449,6 +450,7 @@ class FileController extends AbstractController
|
||||
$id = Request::input('id');
|
||||
$down = Request::input('down', 'no');
|
||||
$only_update_at = Request::input('only_update_at', 'no');
|
||||
$history_id = intval(Request::input('history_id'));
|
||||
//
|
||||
if (Base::isNumber($id)) {
|
||||
User::auth();
|
||||
@ -470,7 +472,11 @@ class FileController extends AbstractController
|
||||
]);
|
||||
}
|
||||
//
|
||||
$content = FileContent::whereFid($file->id)->orderByDesc('id')->first();
|
||||
$builder = FileContent::whereFid($file->id);
|
||||
if ($history_id > 0) {
|
||||
$builder->whereId($history_id);
|
||||
}
|
||||
$content = $builder->orderByDesc('id')->first();
|
||||
return FileContent::formatContent($file, $content?->content, $down == 'yes');
|
||||
}
|
||||
|
||||
@ -767,6 +773,36 @@ class FileController extends AbstractController
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/file/content/history 08. 获取内容历史
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup file
|
||||
* @apiName content__history
|
||||
*
|
||||
* @apiParam {Number} id 文件ID
|
||||
*
|
||||
* @apiParam {Number} [page] 当前页,默认:1
|
||||
* @apiParam {Number} [pagesize] 每页显示数量,默认:20,最大:100
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function content__history()
|
||||
{
|
||||
$id = Request::input('id');
|
||||
//
|
||||
$file = File::permissionFind(intval($id));
|
||||
//
|
||||
$data = FileContent::select(['id', 'size', 'userid', 'created_at'])
|
||||
->whereFid($file->id)
|
||||
->orderByDesc('id')
|
||||
->paginate(Base::getPaginate(100, 20));
|
||||
return Base::retSuccess('success', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/file/share 12. 获取共享信息
|
||||
*
|
||||
|
||||
@ -43,7 +43,22 @@
|
||||
<DropdownItem name="pdf">{{$L('导出PDF文件')}}</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
<Button v-if="!file.only_view" :disabled="equalContent" :loading="loadSave > 0" class="header-button" size="small" type="primary" @click="handleClick('save')">{{$L('保存')}}</Button>
|
||||
<template v-if="!file.only_view">
|
||||
<div class="header-icons">
|
||||
<ETooltip :content="$L('文件链接')">
|
||||
<div class="header-icon" @click="handleClick('link')"><i class="taskfont"></i></div>
|
||||
</ETooltip>
|
||||
<EPopover v-model="historyShow" trigger="click">
|
||||
<div class="file-content-history">
|
||||
<FileHistory :value="historyShow" :fileId="fileId" @on-select="handleHistory"/>
|
||||
</div>
|
||||
<ETooltip slot="reference" :disabled="historyShow" :content="$L('历史版本')">
|
||||
<div class="header-icon"><i class="taskfont"></i></div>
|
||||
</ETooltip>
|
||||
</EPopover>
|
||||
</div>
|
||||
<Button :disabled="equalContent" :loading="loadSave > 0" class="header-button" size="small" type="primary" @click="handleClick('save')">{{$L('保存')}}</Button>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="contentDetail" class="content-body">
|
||||
<template v-if="file.type=='document'">
|
||||
@ -57,6 +72,31 @@
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="contentLoad" class="content-load"><Loading/></div>
|
||||
|
||||
<!--文件链接-->
|
||||
<Modal
|
||||
v-model="linkShow"
|
||||
:title="$L('文件链接')"
|
||||
:mask-closable="false">
|
||||
<div>
|
||||
<Input ref="linkInput" v-model="linkData.url" type="textarea" :rows="3" @on-focus="linkFocus" readonly/>
|
||||
<div class="form-tip" style="padding-top:6px">{{$L('可通过此链接浏览文件。')}}</div>
|
||||
</div>
|
||||
<div slot="footer" class="adaption">
|
||||
<Button type="default" @click="linkShow=false">{{$L('取消')}}</Button>
|
||||
<Poptip
|
||||
confirm
|
||||
placement="bottom"
|
||||
style="margin-left:8px"
|
||||
@on-ok="linkGet(true)"
|
||||
transfer>
|
||||
<div slot="title">
|
||||
<p><strong>{{$L('注意:刷新将导致原来的链接失效!')}}</strong></p>
|
||||
</div>
|
||||
<Button type="primary" :loading="linkLoad > 0">{{$L('刷新')}}</Button>
|
||||
</Poptip>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -64,6 +104,7 @@
|
||||
import Vue from 'vue'
|
||||
import Minder from '../../../components/Minder'
|
||||
import {mapState} from "vuex";
|
||||
import FileHistory from "./FileHistory";
|
||||
Vue.use(Minder)
|
||||
|
||||
const MDEditor = () => import('../../../components/MDEditor/index');
|
||||
@ -74,7 +115,7 @@ const Drawio = () => import('../../../components/Drawio');
|
||||
|
||||
export default {
|
||||
name: "FileContent",
|
||||
components: {AceEditor, TEditor, MDEditor, OnlyOffice, Drawio},
|
||||
components: {FileHistory, AceEditor, TEditor, MDEditor, OnlyOffice, Drawio},
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
@ -103,6 +144,12 @@ export default {
|
||||
editUser: [],
|
||||
|
||||
loadPreview: true,
|
||||
|
||||
linkShow: false,
|
||||
linkData: {},
|
||||
linkLoad: 0,
|
||||
|
||||
historyShow: false,
|
||||
}
|
||||
},
|
||||
|
||||
@ -114,7 +161,7 @@ export default {
|
||||
window.__onBeforeUnload = () => {
|
||||
if (!this.equalContent) {
|
||||
$A.modalConfirm({
|
||||
content: '修改的内容尚未保存,真的要放弃修改吗?',
|
||||
content: '修改的内容尚未保存,确定要放弃修改吗?',
|
||||
cancelText: '取消',
|
||||
okText: '放弃',
|
||||
onOk: () => {
|
||||
@ -139,6 +186,9 @@ export default {
|
||||
this.ready = true;
|
||||
this.editUser = [this.userId];
|
||||
this.getContent();
|
||||
} else {
|
||||
this.linkShow = false;
|
||||
this.historyShow = false;
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
@ -224,7 +274,7 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
getContent() {
|
||||
getContent(history_id = 0) {
|
||||
if (this.fileId === 0) {
|
||||
this.contentDetail = {};
|
||||
this.updateBak();
|
||||
@ -241,10 +291,13 @@ export default {
|
||||
url: 'file/content',
|
||||
data: {
|
||||
id: this.fileId,
|
||||
history_id: history_id
|
||||
},
|
||||
}).then(({data}) => {
|
||||
this.contentDetail = data.content;
|
||||
this.updateBak();
|
||||
if (!history_id) {
|
||||
this.updateBak();
|
||||
}
|
||||
}).catch(({msg}) => {
|
||||
$A.modalError(msg);
|
||||
}).finally(_ => {
|
||||
@ -259,13 +312,21 @@ export default {
|
||||
|
||||
handleClick(act) {
|
||||
switch (act) {
|
||||
case "link":
|
||||
this.linkData = {
|
||||
id: this.fileId
|
||||
};
|
||||
this.linkShow = true;
|
||||
this.linkGet()
|
||||
break;
|
||||
|
||||
case "saveBefore":
|
||||
if (!this.equalContent && this.loadSave == 0) {
|
||||
this.handleClick('save');
|
||||
} else {
|
||||
$A.messageWarning('没有任何修改!');
|
||||
}
|
||||
return;
|
||||
break;
|
||||
|
||||
case "save":
|
||||
if (this.file.only_view) {
|
||||
@ -296,6 +357,58 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
handleHistory(item) {
|
||||
this.historyShow = false;
|
||||
if (!this.equalContent) {
|
||||
$A.modalConfirm({
|
||||
content: '修改的内容尚未保存,确定要读取历史记录吗?',
|
||||
cancelText: '取消',
|
||||
okText: '确定',
|
||||
onOk: () => {
|
||||
this.getContent(item.id)
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.getContent(item.id)
|
||||
}
|
||||
},
|
||||
|
||||
linkGet(refresh) {
|
||||
this.linkLoad++;
|
||||
this.$store.dispatch("call", {
|
||||
url: 'file/link',
|
||||
data: {
|
||||
id: this.linkData.id,
|
||||
refresh: refresh === true ? 'yes' : 'no'
|
||||
},
|
||||
}).then(({data}) => {
|
||||
this.linkData = Object.assign(data, {
|
||||
id: this.linkData.id
|
||||
});
|
||||
this.linkCopy();
|
||||
}).catch(({msg}) => {
|
||||
this.linkShow = false
|
||||
$A.modalError(msg);
|
||||
}).finally(_ => {
|
||||
this.linkLoad--;
|
||||
});
|
||||
},
|
||||
|
||||
linkCopy() {
|
||||
if (!this.linkData.url) {
|
||||
return;
|
||||
}
|
||||
this.$copyText(this.linkData.url).then(() => {
|
||||
$A.messageSuccess(this.$L('复制成功!'));
|
||||
}, () => {
|
||||
$A.messageError(this.$L('复制失败!'));
|
||||
});
|
||||
},
|
||||
|
||||
linkFocus() {
|
||||
this.$refs.linkInput.focus({cursor:'all'});
|
||||
},
|
||||
|
||||
exportMenu(act) {
|
||||
switch (this.file.type) {
|
||||
case 'mind':
|
||||
|
||||
169
resources/assets/js/pages/manage/components/FileHistory.vue
Normal file
169
resources/assets/js/pages/manage/components/FileHistory.vue
Normal file
@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<div class="file-history">
|
||||
<Table
|
||||
:width="460"
|
||||
:max-height="windowHeight - 180"
|
||||
:columns="columns"
|
||||
:data="list"
|
||||
:loading="loadIng > 0"
|
||||
:no-data-text="$L(noText)"
|
||||
stripe/>
|
||||
<Page
|
||||
v-if="total > pageSize"
|
||||
:total="total"
|
||||
:current="page"
|
||||
:page-size="pageSize"
|
||||
:disabled="loadIng > 0"
|
||||
:simple="true"
|
||||
@on-change="setPage"
|
||||
@on-page-size-change="setPageSize"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.file-history {
|
||||
.ivu-page {
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
name: "FileHistory",
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
fileId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
loadIng: 0,
|
||||
|
||||
columns: [
|
||||
{
|
||||
title: this.$L('日期'),
|
||||
key: 'created_at',
|
||||
width: 168,
|
||||
}, {
|
||||
title: this.$L('创建人'),
|
||||
width: 120,
|
||||
render: (h, {row}) => {
|
||||
return h('UserAvatar', {
|
||||
props: {
|
||||
showName: true,
|
||||
size: 22,
|
||||
userid: row.userid,
|
||||
}
|
||||
})
|
||||
}
|
||||
}, {
|
||||
title: this.$L('大小'),
|
||||
key: 'size',
|
||||
width: 80,
|
||||
render: (h, {row}) => {
|
||||
return h('AutoTip', $A.bytesToSize(row.size));
|
||||
}
|
||||
}, {
|
||||
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('读取')),
|
||||
];
|
||||
return h('TableAction', {
|
||||
props: {
|
||||
column: column
|
||||
}
|
||||
}, vNodes);
|
||||
}
|
||||
}
|
||||
],
|
||||
list: [],
|
||||
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
noText: ''
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
|
||||
},
|
||||
|
||||
watch: {
|
||||
value: {
|
||||
handler(val) {
|
||||
if (val) {
|
||||
this.setPage(1);
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['windowHeight'])
|
||||
},
|
||||
|
||||
methods: {
|
||||
getLists() {
|
||||
if (this.fileId === 0) {
|
||||
return;
|
||||
}
|
||||
this.loadIng++;
|
||||
this.$store.dispatch("call", {
|
||||
url: 'file/content/history',
|
||||
data: {
|
||||
id: this.fileId,
|
||||
page: Math.max(this.page, 1),
|
||||
pagesize: Math.max($A.runNum(this.pageSize), 10),
|
||||
},
|
||||
}).then(({data}) => {
|
||||
this.page = data.current_page;
|
||||
this.total = data.total;
|
||||
this.list = data.data;
|
||||
this.noText = '没有相关的数据';
|
||||
}).catch(() => {
|
||||
this.noText = '数据加载失败';
|
||||
}).finally(_ => {
|
||||
this.loadIng--;
|
||||
})
|
||||
},
|
||||
|
||||
setPage(page) {
|
||||
this.page = page;
|
||||
this.getLists();
|
||||
},
|
||||
|
||||
setPageSize(pageSize) {
|
||||
this.page = 1;
|
||||
this.pageSize = pageSize;
|
||||
this.getLists();
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -1529,7 +1529,7 @@ export default {
|
||||
return
|
||||
}
|
||||
$A.modalConfirm({
|
||||
content: '文件尚未保存,是否放弃修改?',
|
||||
content: '修改的内容尚未保存,确定要放弃修改吗?',
|
||||
cancelText: '取消',
|
||||
okText: '放弃',
|
||||
onOk: () => {
|
||||
|
||||
@ -92,6 +92,25 @@
|
||||
font-size: 12px !important;
|
||||
}
|
||||
}
|
||||
.header-icons {
|
||||
margin-left: -4px;
|
||||
margin-right: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.header-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 44px;
|
||||
height: 100%;
|
||||
color: #777777;
|
||||
> i {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-button {
|
||||
font-size: 12px;
|
||||
margin-right: 24px;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user