mirror of https://gitee.com/xiaonuobase/snowy
【升级】新增在线文档示例功能
parent
178fb8e23b
commit
47121ebcd0
|
@ -579,6 +579,7 @@ INSERT INTO `sys_menu` VALUES (1264622039642256571, 1264622039642256531, '[0],[1
|
||||||
INSERT INTO `sys_menu` VALUES (1264622039642256581, 1264622039642256531, '[0],[1264622039642256521],[1264622039642256531],', '文件上传', 'sys_file_mgr_sys_file_upload', 2, NULL, NULL, NULL, 'sysFileInfo:upload', 'system', 0, 'Y', NULL, NULL, 1, 100, NULL, 0, '2020-06-24 17:34:29', 1265476890672672808, NULL, NULL);
|
INSERT INTO `sys_menu` VALUES (1264622039642256581, 1264622039642256531, '[0],[1264622039642256521],[1264622039642256531],', '文件上传', 'sys_file_mgr_sys_file_upload', 2, NULL, NULL, NULL, 'sysFileInfo:upload', 'system', 0, 'Y', NULL, NULL, 1, 100, NULL, 0, '2020-06-24 17:34:29', 1265476890672672808, NULL, NULL);
|
||||||
INSERT INTO `sys_menu` VALUES (1264622039642256591, 1264622039642256531, '[0],[1264622039642256521],[1264622039642256531],', '文件下载', 'sys_file_mgr_sys_file_download', 2, NULL, NULL, NULL, 'sysFileInfo:download', 'system', 0, 'Y', NULL, NULL, 1, 100, NULL, 0, '2020-06-24 17:34:55', 1265476890672672808, NULL, NULL);
|
INSERT INTO `sys_menu` VALUES (1264622039642256591, 1264622039642256531, '[0],[1264622039642256521],[1264622039642256531],', '文件下载', 'sys_file_mgr_sys_file_download', 2, NULL, NULL, NULL, 'sysFileInfo:download', 'system', 0, 'Y', NULL, NULL, 1, 100, NULL, 0, '2020-06-24 17:34:55', 1265476890672672808, NULL, NULL);
|
||||||
INSERT INTO `sys_menu` VALUES (1264622039642256601, 1264622039642256531, '[0],[1264622039642256521],[1264622039642256531],', '图片预览', 'sys_file_mgr_sys_file_preview', 2, NULL, NULL, NULL, 'sysFileInfo:preview', 'system', 0, 'Y', NULL, NULL, 1, 100, NULL, 0, '2020-06-24 17:35:19', 1265476890672672808, NULL, NULL);
|
INSERT INTO `sys_menu` VALUES (1264622039642256601, 1264622039642256531, '[0],[1264622039642256521],[1264622039642256531],', '图片预览', 'sys_file_mgr_sys_file_preview', 2, NULL, NULL, NULL, 'sysFileInfo:preview', 'system', 0, 'Y', NULL, NULL, 1, 100, NULL, 0, '2020-06-24 17:35:19', 1265476890672672808, NULL, NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (1264622039642256602, 1264622039642256521, '[0],[1264622039642256521],', '在线文档', 'sys_file_mgr_sys_online_file', 1, NULL, '/fileOnline', '/system/file/onlineIndex', NULL, 'system', 1, 'Y', NULL, NULL, 1, 21, NULL, 0, '2020-06-24 17:32:57', 1265476890672672808, NULL, NULL);
|
||||||
INSERT INTO `sys_menu` VALUES (1264622039642256611, 0, '[0],', '定时任务', 'sys_timers', 0, 'dashboard', '/timers', 'PageView', NULL, 'system', 1, 'Y', NULL, NULL, 1, 100, NULL, 0, '2020-07-01 17:17:20', 1265476890672672808, NULL, NULL);
|
INSERT INTO `sys_menu` VALUES (1264622039642256611, 0, '[0],', '定时任务', 'sys_timers', 0, 'dashboard', '/timers', 'PageView', NULL, 'system', 1, 'Y', NULL, NULL, 1, 100, NULL, 0, '2020-07-01 17:17:20', 1265476890672672808, NULL, NULL);
|
||||||
INSERT INTO `sys_menu` VALUES (1264622039642256621, 1264622039642256611, '[0],[1264622039642256611],', '任务管理', 'sys_timers_mgr', 1, NULL, '/timers', 'system/timers/index', NULL, 'system', 1, 'Y', NULL, NULL, 1, 22, NULL, 0, '2020-07-01 17:18:53', 1265476890672672808, NULL, NULL);
|
INSERT INTO `sys_menu` VALUES (1264622039642256621, 1264622039642256611, '[0],[1264622039642256611],', '任务管理', 'sys_timers_mgr', 1, NULL, '/timers', 'system/timers/index', NULL, 'system', 1, 'Y', NULL, NULL, 1, 22, NULL, 0, '2020-07-01 17:18:53', 1265476890672672808, NULL, NULL);
|
||||||
INSERT INTO `sys_menu` VALUES (1264622039642256631, 1264622039642256621, '[0],[1264622039642256611],[1264622039642256621],', '定时任务查询', 'sys_timers_mgr_page', 2, NULL, NULL, NULL, 'sysTimers:page', 'system', 0, 'Y', NULL, NULL, 1, 100, NULL, 0, '2020-07-01 17:19:43', 1265476890672672808, NULL, NULL);
|
INSERT INTO `sys_menu` VALUES (1264622039642256631, 1264622039642256621, '[0],[1264622039642256611],[1264622039642256621],', '定时任务查询', 'sys_timers_mgr_page', 2, NULL, NULL, NULL, 'sysTimers:page', 'system', 0, 'Y', NULL, NULL, 1, 100, NULL, 0, '2020-07-01 17:19:43', 1265476890672672808, NULL, NULL);
|
||||||
|
|
|
@ -6,11 +6,14 @@
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<link rel="icon" href="<%= BASE_URL %>logo.png">
|
<link rel="icon" href="<%= BASE_URL %>logo.png">
|
||||||
<title>Snowy快速开发平台</title>
|
<title>Snowy快速开发平台</title>
|
||||||
|
|
||||||
<style>.first-loading-wrp{display:flex;justify-content:center;align-items:center;flex-direction:column;min-height:420px;height:100%}.first-loading-wrp>h1{font-size:128px}.first-loading-wrp .loading-wrp{padding:98px;display:flex;justify-content:center;align-items:center}.dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:32px;width:32px;height:32px;box-sizing:border-box}.dot i{width:14px;height:14px;position:absolute;display:block;background-color:#1890ff;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.dot i:nth-child(1){top:0;left:0}.dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}}</style>
|
<style>.first-loading-wrp{display:flex;justify-content:center;align-items:center;flex-direction:column;min-height:420px;height:100%}.first-loading-wrp>h1{font-size:128px}.first-loading-wrp .loading-wrp{padding:98px;display:flex;justify-content:center;align-items:center}.dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:32px;width:32px;height:32px;box-sizing:border-box}.dot i{width:14px;height:14px;position:absolute;display:block;background-color:#1890ff;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.dot i:nth-child(1){top:0;left:0}.dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}}</style>
|
||||||
|
<script type="text/javascript" src="https://onlyoffice.xiaonuo.vip/web-apps/apps/api/documents/api.js"></script>
|
||||||
<!-- require cdn assets css -->
|
<!-- require cdn assets css -->
|
||||||
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
|
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
|
||||||
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" />
|
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" />
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
|
|
|
@ -99,3 +99,17 @@ export function sysFileInfoDelete (parameter) {
|
||||||
data: parameter
|
data: parameter
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取在线文档配置
|
||||||
|
*
|
||||||
|
* @author yubaoshan
|
||||||
|
* @date 2020/6/30 00:20
|
||||||
|
*/
|
||||||
|
export function sysFileInfoGetOnlineConfig (parameter) {
|
||||||
|
return axios({
|
||||||
|
url: '/sysFileInfo/getOnlineFileConfig',
|
||||||
|
method: 'get',
|
||||||
|
params: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
/* eslint-disable no-undef */
|
||||||
|
<!--onlyoffice 编辑器-->
|
||||||
|
<template>
|
||||||
|
<div id="editorDiv"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { handleDocType } from '@/utils/onlyofficeUtil'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Editor',
|
||||||
|
props: {
|
||||||
|
option: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
doctype: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.option.url) {
|
||||||
|
this.setEditor(this.option)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setEditor(option) {
|
||||||
|
this.doctype = handleDocType(option.fileType)
|
||||||
|
const config = {
|
||||||
|
document: {
|
||||||
|
fileType: option.fileType,
|
||||||
|
key: option.key,
|
||||||
|
title: option.title,
|
||||||
|
permissions: {
|
||||||
|
comment: true,
|
||||||
|
download: true,
|
||||||
|
modifyContentControl: true,
|
||||||
|
modifyFilter: true,
|
||||||
|
print: false,
|
||||||
|
edit: option.isEdit,
|
||||||
|
fillForms: true
|
||||||
|
// review: false
|
||||||
|
},
|
||||||
|
url: option.url
|
||||||
|
|
||||||
|
},
|
||||||
|
type: option.type,
|
||||||
|
documentType: this.doctype,
|
||||||
|
editorConfig: {
|
||||||
|
callbackUrl: option.callbackUrl,
|
||||||
|
lang: 'zh',
|
||||||
|
customization: {
|
||||||
|
commentAuthorOnly: false,
|
||||||
|
comments: true,
|
||||||
|
compactHeader: false,
|
||||||
|
compactToolbar: true,
|
||||||
|
feedback: false,
|
||||||
|
plugins: true
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
id: option.user.id,
|
||||||
|
name: option.user.name
|
||||||
|
}
|
||||||
|
// mode: option.mode
|
||||||
|
},
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
position: 'absolute',
|
||||||
|
token: option.token
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
let docEditor = null
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
docEditor = new DocsAPI.DocEditor('editorDiv', config)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
option: {
|
||||||
|
handler: function (n, o) {
|
||||||
|
this.setEditor(n)
|
||||||
|
this.doctype = handleDocType(n.fileType)
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,22 @@
|
||||||
|
export function handleDocType(fileType) {
|
||||||
|
let docType = ''
|
||||||
|
const fileTypesDoc = [
|
||||||
|
'doc', 'docm', 'docx', 'dot', 'dotm', 'dotx', 'epub', 'fodt', 'htm', 'html', 'mht', 'odt', 'ott', 'pdf', 'rtf', 'txt', 'djvu', 'xps'
|
||||||
|
]
|
||||||
|
const fileTypesCsv = [
|
||||||
|
'csv', 'fods', 'ods', 'ots', 'xls', 'xlsm', 'xlsx', 'xlt', 'xltm', 'xltx'
|
||||||
|
]
|
||||||
|
const fileTypesPPt = [
|
||||||
|
'fodp', 'odp', 'otp', 'pot', 'potm', 'potx', 'pps', 'ppsm', 'ppsx', 'ppt', 'pptm', 'pptx'
|
||||||
|
]
|
||||||
|
if (fileTypesDoc.includes(fileType)) {
|
||||||
|
docType = 'text'
|
||||||
|
}
|
||||||
|
if (fileTypesCsv.includes(fileType)) {
|
||||||
|
docType = 'spreadsheet'
|
||||||
|
}
|
||||||
|
if (fileTypesPPt.includes(fileType)) {
|
||||||
|
docType = 'presentation'
|
||||||
|
}
|
||||||
|
return docType
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
title="文件信息详情"
|
||||||
|
:footer="null"
|
||||||
|
:width="900"
|
||||||
|
:visible="visible"
|
||||||
|
:confirmLoading="confirmLoading"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
>
|
||||||
|
<a-spin :spinning="confirmLoading">
|
||||||
|
<a-form :form="form">
|
||||||
|
<a-form-item v-show="false">
|
||||||
|
<a-input v-decorator="['id']" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
label="文件存储位置"
|
||||||
|
:labelCol="labelCol"
|
||||||
|
:wrapperCol="wrapperCol"
|
||||||
|
>
|
||||||
|
{{ fileDetail.fileLocation }}
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
label="文件仓库"
|
||||||
|
:labelCol="labelCol"
|
||||||
|
:wrapperCol="wrapperCol"
|
||||||
|
>
|
||||||
|
{{ fileDetail.fileBucket }}
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
:labelCol="labelCol"
|
||||||
|
:wrapperCol="wrapperCol"
|
||||||
|
label="文件名称"
|
||||||
|
>
|
||||||
|
{{ fileDetail.fileOriginName }}
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
:labelCol="labelCol"
|
||||||
|
:wrapperCol="wrapperCol"
|
||||||
|
label="文件后缀"
|
||||||
|
>
|
||||||
|
{{ fileDetail.fileSuffix }}
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
:labelCol="labelCol"
|
||||||
|
:wrapperCol="wrapperCol"
|
||||||
|
label="文件大小"
|
||||||
|
>
|
||||||
|
{{ fileDetail.fileSizeKb }}
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
:labelCol="labelCol"
|
||||||
|
:wrapperCol="wrapperCol"
|
||||||
|
label="唯一标识"
|
||||||
|
>
|
||||||
|
{{ fileDetail.fileObjectName }}
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item
|
||||||
|
label="存储路径"
|
||||||
|
:labelCol="labelCol"
|
||||||
|
:wrapperCol="wrapperCol"
|
||||||
|
>
|
||||||
|
{{ fileDetail.filePath }}
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-spin>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
labelCol: {
|
||||||
|
xs: { span: 24 },
|
||||||
|
sm: { span: 8 }
|
||||||
|
},
|
||||||
|
wrapperCol: {
|
||||||
|
xs: { span: 24 },
|
||||||
|
sm: { span: 15 }
|
||||||
|
},
|
||||||
|
fileDetail: [],
|
||||||
|
visible: false,
|
||||||
|
confirmLoading: false,
|
||||||
|
form: this.$form.createForm(this)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 初始化方法
|
||||||
|
detail (record) {
|
||||||
|
this.fileDetail = record
|
||||||
|
this.visible = true
|
||||||
|
},
|
||||||
|
handleCancel () {
|
||||||
|
this.form.resetFields()
|
||||||
|
this.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,251 @@
|
||||||
|
<template>
|
||||||
|
<a-spin :spinning="cardLoading">
|
||||||
|
<x-card v-if="hasPerm('sysFileInfo:page')">
|
||||||
|
<div slot="content" class="table-page-search-wrapper">
|
||||||
|
<a-form layout="inline">
|
||||||
|
<a-row :gutter="48">
|
||||||
|
<a-col :md="8" :sm="24">
|
||||||
|
<a-form-item label="存储位置">
|
||||||
|
<a-select v-model="queryParam.fileLocation" placeholder="请选择存储位置" >
|
||||||
|
<a-select-option v-for="(item,index) in fileLocationDictTypeDropDown" :key="index" :value="item.code" >{{ item.name }}</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :md="8" :sm="24">
|
||||||
|
<a-form-item label="文件仓库">
|
||||||
|
<a-input v-model="queryParam.fileBucket" placeholder="请输入文件仓库"/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<template v-if="advanced">
|
||||||
|
<a-col :md="8" :sm="24">
|
||||||
|
<a-form-item label="文件名称">
|
||||||
|
<a-input v-model="queryParam.fileOriginName" placeholder="请输入文件名称(上传时候的文件名)"/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</template>
|
||||||
|
<a-col :md="!advanced && 8 || 24" :sm="24">
|
||||||
|
<span class="table-page-search-submitButtons" :style="advanced && { float: 'right', overflow: 'hidden' } || {} ">
|
||||||
|
<a-button type="primary" @click="$refs.table.refresh(true)" >查询</a-button>
|
||||||
|
<a-button style="margin-left: 8px" @click="() => queryParam = { fileSuffix: 'doc,docx,xls,xlsx,ppt,pptx' }">重置</a-button>
|
||||||
|
<a @click="toggleAdvanced" style="margin-left: 8px">
|
||||||
|
{{ advanced ? '收起' : '展开' }}
|
||||||
|
<a-icon :type="advanced ? 'up' : 'down'"/>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
</x-card>
|
||||||
|
<a-card :bordered="false">
|
||||||
|
<s-table
|
||||||
|
ref="table"
|
||||||
|
:columns="columns"
|
||||||
|
:data="loadData"
|
||||||
|
:alert="false"
|
||||||
|
:rowKey="(record) => record.id"
|
||||||
|
:rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
|
||||||
|
>
|
||||||
|
<span slot="fileOriginName" slot-scope="text">
|
||||||
|
<ellipsis :length="10" tooltip>{{ text }}</ellipsis>
|
||||||
|
</span>
|
||||||
|
<span slot="fileObjectName" slot-scope="text">
|
||||||
|
<ellipsis :length="10" tooltip>{{ text }}</ellipsis>
|
||||||
|
</span>
|
||||||
|
<span slot="fileLocation" slot-scope="text">
|
||||||
|
{{ 'file_storage_location' | dictType(text) }}
|
||||||
|
</span>
|
||||||
|
<span slot="fileSuffix" slot-scope="text">
|
||||||
|
<a-tag color="blue">{{ text }}</a-tag>
|
||||||
|
</span>
|
||||||
|
<span slot="action" slot-scope="text, record">
|
||||||
|
<a @click="onlineEdit(record)">在线编辑</a>
|
||||||
|
<a-divider type="vertical"/>
|
||||||
|
<a v-if="hasPerm('sysFileInfo:download')" @click="sysFileInfoDownload(record)">下载</a>
|
||||||
|
<a-divider type="vertical" v-if="hasPerm('sysFileInfo:download') & hasPerm('sysFileInfo:preview')"/>
|
||||||
|
<a v-if="hasPerm('sysFileInfo:preview')" @click="onlinePreview(record, 'desktop')">桌面预览</a>
|
||||||
|
<a-divider type="vertical" v-if="hasPerm('sysFileInfo:preview')"/>
|
||||||
|
<a v-if="hasPerm('sysFileInfo:preview')" @click="onlinePreview(record, 'mobile')">手机预览</a>
|
||||||
|
<a-divider type="vertical" v-if="hasPerm('sysFileInfo:preview') & hasPerm('sysFileInfo:delete')"/>
|
||||||
|
<a-popconfirm v-if="hasPerm('sysFileInfo:delete')" placement="topRight" title="确认删除?" @confirm="() => sysFileInfoDelete(record)">
|
||||||
|
<a>删除</a>
|
||||||
|
</a-popconfirm>
|
||||||
|
</span>
|
||||||
|
</s-table>
|
||||||
|
<preview-form ref="previewForm"/>
|
||||||
|
<online-edit-form ref="onlineEditForm"/>
|
||||||
|
</a-card>
|
||||||
|
</a-spin>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { STable, Ellipsis, XCard } from '@/components'
|
||||||
|
import { sysFileInfoPage, sysFileInfoDelete, sysFileInfoDownload, sysFileInfoGetOnlineConfig } from '@/api/modular/system/fileManage'
|
||||||
|
import previewForm from './previewForm'
|
||||||
|
import onlineEditForm from './onlineEditForm'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
XCard,
|
||||||
|
STable,
|
||||||
|
Ellipsis,
|
||||||
|
previewForm,
|
||||||
|
onlineEditForm
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
// 高级搜索 展开/关闭
|
||||||
|
advanced: false,
|
||||||
|
// 查询参数
|
||||||
|
queryParam: { fileSuffix: 'doc,docx,xls,xlsx,ppt,pptx' },
|
||||||
|
// 表头
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
title: '存储位置',
|
||||||
|
dataIndex: 'fileLocation',
|
||||||
|
scopedSlots: { customRender: 'fileLocation' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '文件仓库',
|
||||||
|
dataIndex: 'fileBucket'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '文件名称',
|
||||||
|
dataIndex: 'fileOriginName',
|
||||||
|
scopedSlots: { customRender: 'fileOriginName' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '文件后缀',
|
||||||
|
dataIndex: 'fileSuffix',
|
||||||
|
scopedSlots: { customRender: 'fileSuffix' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '文件大小',
|
||||||
|
dataIndex: 'fileSizeInfo'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '唯一标识id',
|
||||||
|
dataIndex: 'fileObjectName',
|
||||||
|
scopedSlots: { customRender: 'fileObjectName' }
|
||||||
|
}
|
||||||
|
|
||||||
|
],
|
||||||
|
// 加载数据方法 必须为 Promise 对象
|
||||||
|
loadData: parameter => {
|
||||||
|
return sysFileInfoPage(Object.assign(parameter, this.queryParam)).then((res) => {
|
||||||
|
return res.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
cardLoading: false,
|
||||||
|
fileLocationDictTypeDropDown: [],
|
||||||
|
selectedRowKeys: [],
|
||||||
|
selectedRows: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.sysDictTypeDropDown()
|
||||||
|
if (this.hasPerm('sysPos:edit') || this.hasPerm('sysPos:delete')) {
|
||||||
|
this.columns.push({
|
||||||
|
title: '操作',
|
||||||
|
width: '350px',
|
||||||
|
dataIndex: 'action',
|
||||||
|
scopedSlots: { customRender: 'action' }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* 在线编辑
|
||||||
|
*/
|
||||||
|
onlineEdit (record) {
|
||||||
|
this.cardLoading = true
|
||||||
|
sysFileInfoGetOnlineConfig({ id: record.id }).then((res) => {
|
||||||
|
this.cardLoading = false
|
||||||
|
this.$refs.onlineEditForm.onlineEdit(res, 'desktop')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 在线预览
|
||||||
|
*/
|
||||||
|
onlinePreview (record, type) {
|
||||||
|
this.cardLoading = true
|
||||||
|
sysFileInfoGetOnlineConfig({ id: record.id }).then((res) => {
|
||||||
|
this.cardLoading = false
|
||||||
|
this.$refs.previewForm.preview(res, type)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 预览文件(微软插件)
|
||||||
|
*/
|
||||||
|
previewMicrosoft (record) {
|
||||||
|
window.open('https://view.officeapps.live.com/op/view.aspx?src=' + process.env.VUE_APP_API_BASE_URL + '/sysFileInfo/download?id=' + record.id)
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 获取字典数据
|
||||||
|
*/
|
||||||
|
sysDictTypeDropDown () {
|
||||||
|
this.fileLocationDictTypeDropDown = this.$options.filters['dictData']('file_storage_location')
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 下载文件(所有文件)
|
||||||
|
*/
|
||||||
|
sysFileInfoDownload (record) {
|
||||||
|
this.cardLoading = true
|
||||||
|
sysFileInfoDownload({ id: record.id }).then((res) => {
|
||||||
|
this.cardLoading = false
|
||||||
|
this.downloadfile(res)
|
||||||
|
// eslint-disable-next-line handle-callback-err
|
||||||
|
}).catch((err) => {
|
||||||
|
this.cardLoading = false
|
||||||
|
this.$message.error('下载错误:获取文件流错误')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
downloadfile (res) {
|
||||||
|
var blob = new Blob([res.data], { type: 'application/octet-stream;charset=UTF-8' })
|
||||||
|
var contentDisposition = res.headers['content-disposition']
|
||||||
|
var patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
|
||||||
|
var result = patt.exec(contentDisposition)
|
||||||
|
var filename = result[1]
|
||||||
|
var downloadElement = document.createElement('a')
|
||||||
|
var href = window.URL.createObjectURL(blob) // 创建下载的链接
|
||||||
|
var reg = /^["](.*)["]$/g
|
||||||
|
downloadElement.style.display = 'none'
|
||||||
|
downloadElement.href = href
|
||||||
|
downloadElement.download = decodeURI(filename.replace(reg, '$1')) // 下载后文件名
|
||||||
|
document.body.appendChild(downloadElement)
|
||||||
|
downloadElement.click() // 点击下载
|
||||||
|
document.body.removeChild(downloadElement) // 下载完成移除元素
|
||||||
|
window.URL.revokeObjectURL(href)
|
||||||
|
},
|
||||||
|
sysFileInfoDelete (record) {
|
||||||
|
sysFileInfoDelete(record).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
this.$message.success('删除成功')
|
||||||
|
this.$refs.table.refresh()
|
||||||
|
} else {
|
||||||
|
this.$message.error('删除失败:' + res.message)
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
this.$message.error('删除错误:' + err.message)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
toggleAdvanced () {
|
||||||
|
this.advanced = !this.advanced
|
||||||
|
},
|
||||||
|
handleOk () {
|
||||||
|
this.$refs.table.refresh()
|
||||||
|
},
|
||||||
|
onSelectChange (selectedRowKeys, selectedRows) {
|
||||||
|
this.selectedRowKeys = selectedRowKeys
|
||||||
|
this.selectedRows = selectedRows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="less">
|
||||||
|
.table-operator {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,91 @@
|
||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
title="在线编辑"
|
||||||
|
:footer="null"
|
||||||
|
:width="1500"
|
||||||
|
:visible="visible"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
:destroyOnClose="true"
|
||||||
|
>
|
||||||
|
<a-spin :spinning="divLoading">
|
||||||
|
<div class="editorview" style="height: 800px;">
|
||||||
|
<Editor :option="option"/>
|
||||||
|
</div>
|
||||||
|
</a-spin>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import Editor from '../../../components/xnComponents/EditorDiv'
|
||||||
|
import Vue from 'vue'
|
||||||
|
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Editor
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
divLoading: false,
|
||||||
|
sysOnlineFileInfoResult: {},
|
||||||
|
option: {
|
||||||
|
url: '',
|
||||||
|
isEdit: true,
|
||||||
|
fileType: '',
|
||||||
|
title: '',
|
||||||
|
token: Vue.ls.get(ACCESS_TOKEN),
|
||||||
|
user: {
|
||||||
|
id: '',
|
||||||
|
name: ''
|
||||||
|
},
|
||||||
|
mode: '',
|
||||||
|
callbackUrl: '',
|
||||||
|
key: '',
|
||||||
|
review: false,
|
||||||
|
type: 'desktop'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
*/
|
||||||
|
onlineEdit(record) {
|
||||||
|
this.visible = true
|
||||||
|
const data = record.data.sysOnlineFileInfoResult
|
||||||
|
this.option.user.id = data.editorConfig.user.id
|
||||||
|
this.option.user.name = data.editorConfig.user.name
|
||||||
|
this.option.fileType = data.document.fileType
|
||||||
|
this.option.title = data.document.title
|
||||||
|
this.option.key = data.document.key
|
||||||
|
this.option.url = process.env.VUE_APP_API_BASE_URL + data.document.url // res.data.docServiceApiUrl
|
||||||
|
this.callbackUrl = process.env.VUE_APP_API_BASE_URL + data.editorConfig.callbackUrl
|
||||||
|
// this.option.type = type
|
||||||
|
this.option.review = false
|
||||||
|
},
|
||||||
|
handleCancel () {
|
||||||
|
this.visible = false
|
||||||
|
this.option = {
|
||||||
|
url: '',
|
||||||
|
isEdit: false,
|
||||||
|
fileType: '',
|
||||||
|
title: '',
|
||||||
|
token: Vue.ls.get(ACCESS_TOKEN),
|
||||||
|
user: {
|
||||||
|
id: '',
|
||||||
|
name: ''
|
||||||
|
},
|
||||||
|
mode: '',
|
||||||
|
callbackUrl: '',
|
||||||
|
key: '',
|
||||||
|
review: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.editorview iframe{
|
||||||
|
position: absolute !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,96 @@
|
||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
title="在线预览"
|
||||||
|
:footer="null"
|
||||||
|
:width="1500"
|
||||||
|
:visible="visible"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
:destroyOnClose="true"
|
||||||
|
>
|
||||||
|
<a-spin :spinning="divLoading">
|
||||||
|
<div class="editorview" style="height: 800px;">
|
||||||
|
<Editor :option="option"/>
|
||||||
|
</div>
|
||||||
|
</a-spin>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import Editor from '../../../components/xnComponents/EditorDiv'
|
||||||
|
import Vue from 'vue'
|
||||||
|
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Editor
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
divLoading: false,
|
||||||
|
sysOnlineFileInfoResult: {},
|
||||||
|
option: {
|
||||||
|
url: '',
|
||||||
|
isEdit: false,
|
||||||
|
fileType: '',
|
||||||
|
title: '',
|
||||||
|
token: Vue.ls.get(ACCESS_TOKEN),
|
||||||
|
user: {
|
||||||
|
id: '',
|
||||||
|
name: ''
|
||||||
|
},
|
||||||
|
mode: '',
|
||||||
|
callbackUrl: '',
|
||||||
|
key: '',
|
||||||
|
review: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
*/
|
||||||
|
preview(record, type) {
|
||||||
|
this.visible = true
|
||||||
|
const data = record.data.sysOnlineFileInfoResult
|
||||||
|
this.option.user.id = '1265476890672672808' // data.editorConfig.user.id
|
||||||
|
this.option.user.name = '超级管理员' // data.editorConfig.user.name
|
||||||
|
this.option.fileType = data.document.fileType
|
||||||
|
this.option.title = data.document.title
|
||||||
|
this.option.key = data.document.key
|
||||||
|
this.option.url = process.env.VUE_APP_API_BASE_URL + data.document.url // res.data.docServiceApiUrl
|
||||||
|
this.callbackUrl = process.env.VUE_APP_API_BASE_URL + data.editorConfig.callbackUrl
|
||||||
|
this.option.type = type
|
||||||
|
},
|
||||||
|
handleCancel () {
|
||||||
|
this.visible = false
|
||||||
|
this.option = {
|
||||||
|
url: '',
|
||||||
|
isEdit: false,
|
||||||
|
fileType: '',
|
||||||
|
title: '',
|
||||||
|
token: Vue.ls.get(ACCESS_TOKEN),
|
||||||
|
user: {
|
||||||
|
id: '',
|
||||||
|
name: ''
|
||||||
|
},
|
||||||
|
mode: '',
|
||||||
|
callbackUrl: '',
|
||||||
|
key: '',
|
||||||
|
review: false
|
||||||
|
}
|
||||||
|
const oScript = document.createElement('script')
|
||||||
|
oScript.type = 'text/javascript'
|
||||||
|
oScript.src = ''
|
||||||
|
document.body.appendChild(oScript)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.editorview iframe{
|
||||||
|
position: absolute !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -311,6 +311,16 @@ public class ConstantContextHolder {
|
||||||
return getSysConfig("SNOWY_ALIPAY_RETURN_URL", String.class, true);
|
return getSysConfig("SNOWY_ALIPAY_RETURN_URL", String.class, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取OnlyOffice地址
|
||||||
|
*
|
||||||
|
* @author xuyuxiang
|
||||||
|
* @date 2020/7/29 14:08
|
||||||
|
**/
|
||||||
|
public static String getOnlyOfficeUrl() {
|
||||||
|
return getSysConfig("SNOWY_ONLY_OFFICE_SERVICE_URL", String.class, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取config表中的配置,如果为空返回默认值
|
* 获取config表中的配置,如果为空返回默认值
|
||||||
*
|
*
|
||||||
|
|
|
@ -25,6 +25,7 @@ Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意
|
||||||
package vip.xiaonuo.core.file.modular.local;
|
package vip.xiaonuo.core.file.modular.local;
|
||||||
|
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.core.lang.Dict;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.system.SystemUtil;
|
import cn.hutool.system.SystemUtil;
|
||||||
import vip.xiaonuo.core.file.FileOperator;
|
import vip.xiaonuo.core.file.FileOperator;
|
||||||
|
@ -47,6 +48,8 @@ public class LocalFileOperator implements FileOperator {
|
||||||
|
|
||||||
private String currentSavePath = "";
|
private String currentSavePath = "";
|
||||||
|
|
||||||
|
private Dict localClient;
|
||||||
|
|
||||||
public LocalFileOperator(LocalFileProperties localFileProperties) {
|
public LocalFileOperator(LocalFileProperties localFileProperties) {
|
||||||
this.localFileProperties = localFileProperties;
|
this.localFileProperties = localFileProperties;
|
||||||
initClient();
|
initClient();
|
||||||
|
@ -67,6 +70,9 @@ public class LocalFileOperator implements FileOperator {
|
||||||
}
|
}
|
||||||
currentSavePath = savePathLinux;
|
currentSavePath = savePathLinux;
|
||||||
}
|
}
|
||||||
|
localClient = Dict.create();
|
||||||
|
localClient.put("currentSavePath", currentSavePath);
|
||||||
|
localClient.put("localFileProperties", localFileProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -77,7 +83,7 @@ public class LocalFileOperator implements FileOperator {
|
||||||
@Override
|
@Override
|
||||||
public Object getClient() {
|
public Object getClient() {
|
||||||
// empty
|
// empty
|
||||||
return null;
|
return localClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -24,15 +24,21 @@ Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意
|
||||||
*/
|
*/
|
||||||
package vip.xiaonuo.sys.modular.file.controller;
|
package vip.xiaonuo.sys.modular.file.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Dict;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import vip.xiaonuo.core.annotion.BusinessLog;
|
import vip.xiaonuo.core.annotion.BusinessLog;
|
||||||
import vip.xiaonuo.core.annotion.Permission;
|
import vip.xiaonuo.core.annotion.Permission;
|
||||||
|
import vip.xiaonuo.core.context.constant.ConstantContextHolder;
|
||||||
import vip.xiaonuo.core.enums.LogAnnotionOpTypeEnum;
|
import vip.xiaonuo.core.enums.LogAnnotionOpTypeEnum;
|
||||||
import vip.xiaonuo.core.pojo.response.ResponseData;
|
import vip.xiaonuo.core.pojo.response.ResponseData;
|
||||||
import vip.xiaonuo.core.pojo.response.SuccessResponseData;
|
import vip.xiaonuo.core.pojo.response.SuccessResponseData;
|
||||||
import vip.xiaonuo.sys.modular.file.param.SysFileInfoParam;
|
import vip.xiaonuo.sys.modular.file.param.SysFileInfoParam;
|
||||||
|
import vip.xiaonuo.sys.modular.file.result.SysOnlineFileInfoResult;
|
||||||
import vip.xiaonuo.sys.modular.file.service.SysFileInfoService;
|
import vip.xiaonuo.sys.modular.file.service.SysFileInfoService;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
@ -50,6 +56,27 @@ public class SysFileInfoController {
|
||||||
@Resource
|
@Resource
|
||||||
private SysFileInfoService sysFileInfoService;
|
private SysFileInfoService sysFileInfoService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onlyoffice资源文件路径
|
||||||
|
*/
|
||||||
|
public static final String ONLY_OFFICE_APP_JS_SUFFIX = "/web-apps/apps/api/documents/api.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线文档配置
|
||||||
|
*
|
||||||
|
* @author xuyuxiang
|
||||||
|
* @date 2020/11/17 16:40
|
||||||
|
*/
|
||||||
|
@GetMapping("/sysFileInfo/getOnlineFileConfig")
|
||||||
|
public ResponseData getOnlineFileConfig(SysFileInfoParam sysFileInfoParam) {
|
||||||
|
//生成在线文档的model
|
||||||
|
SysOnlineFileInfoResult sysOnlineFileInfoResult = sysFileInfoService.onlineAddOrUpdate(sysFileInfoParam);
|
||||||
|
Dict dict = Dict.create();
|
||||||
|
dict.put("docServiceApiUrl", ConstantContextHolder.getOnlyOfficeUrl() + ONLY_OFFICE_APP_JS_SUFFIX);
|
||||||
|
dict.put("sysOnlineFileInfoResult", sysOnlineFileInfoResult);
|
||||||
|
return new SuccessResponseData(dict);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传文件
|
* 上传文件
|
||||||
*
|
*
|
||||||
|
@ -139,4 +166,15 @@ public class SysFileInfoController {
|
||||||
return new SuccessResponseData();
|
return new SuccessResponseData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线文档编辑回调
|
||||||
|
*
|
||||||
|
* @author xuyuxiang
|
||||||
|
* @date 2021/3/25 16:06
|
||||||
|
*/
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping("/sysFileInfo/track")
|
||||||
|
public void track() {
|
||||||
|
sysFileInfoService.track();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,22 @@ public enum SysFileInfoExceptionEnum implements AbstractBaseExceptionEnum {
|
||||||
/**
|
/**
|
||||||
* 预览文件异常
|
* 预览文件异常
|
||||||
*/
|
*/
|
||||||
PREVIEW_ERROR_LIBREOFFICE(7, "预览文件异常,请检查LibreOffice是否启动");
|
PREVIEW_ERROR_LIBREOFFICE(7, "预览文件异常,请检查LibreOffice是否启动"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件操作客户端初始化异常
|
||||||
|
*/
|
||||||
|
CLIENT_INIT_ERROR(8, "文件操作客户端初始化异常"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线文档暂时只支持本地文件
|
||||||
|
*/
|
||||||
|
ONLINE_EDIT_SUPPORT_LOCAL_ONLY(9, "在线文档暂时只支持本地文件"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线文档参数错误
|
||||||
|
*/
|
||||||
|
ONLINE_EDIT_PARAM_ERROR(10, "在线文档参数错误");
|
||||||
|
|
||||||
private final Integer code;
|
private final Integer code;
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ import lombok.Getter;
|
||||||
* @date 2020/6/7 22:24
|
* @date 2020/6/7 22:24
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum FileLocationEnum {
|
public enum SysFileLocationEnum {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 阿里云
|
* 阿里云
|
||||||
|
@ -57,7 +57,7 @@ public enum FileLocationEnum {
|
||||||
|
|
||||||
private final Integer code;
|
private final Integer code;
|
||||||
|
|
||||||
FileLocationEnum(int code) {
|
SysFileLocationEnum(int code) {
|
||||||
this.code = code;
|
this.code = code;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import vip.xiaonuo.core.pojo.base.param.BaseParam;
|
import vip.xiaonuo.core.pojo.base.param.BaseParam;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,6 +77,7 @@ public class SysFileInfoParam extends BaseParam {
|
||||||
/**
|
/**
|
||||||
* 存储到bucket的名称(文件唯一标识id)
|
* 存储到bucket的名称(文件唯一标识id)
|
||||||
*/
|
*/
|
||||||
|
@NotEmpty(message = "存储到bucket的名称不能为空,请检查fileObjectName参数", groups = {trace.class})
|
||||||
private String fileObjectName;
|
private String fileObjectName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,4 +85,19 @@ public class SysFileInfoParam extends BaseParam {
|
||||||
*/
|
*/
|
||||||
private String filePath;
|
private String filePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文档创建时是否创建相同文件内容的模板文件
|
||||||
|
*/
|
||||||
|
private Boolean sample = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模式:编辑edit 查看view
|
||||||
|
*/
|
||||||
|
private String mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型:桌面desktop 手机mobile
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,187 @@
|
||||||
|
/*
|
||||||
|
Copyright [2020] [https://www.xiaonuo.vip]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||||
|
|
||||||
|
1.请不要删除和修改根目录下的LICENSE文件。
|
||||||
|
2.请不要删除和修改Snowy源码头部的版权声明。
|
||||||
|
3.请保留源码和相关描述文件的项目出处,作者声明等。
|
||||||
|
4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuobase/snowy-layui
|
||||||
|
5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuobase/snowy-layui
|
||||||
|
6.若您的项目无法满足以上几点,可申请商业授权,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
|
||||||
|
*/
|
||||||
|
package vip.xiaonuo.sys.modular.file.result;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import lombok.Data;
|
||||||
|
import vip.xiaonuo.core.consts.CommonConstant;
|
||||||
|
import vip.xiaonuo.core.consts.SymbolConstant;
|
||||||
|
import vip.xiaonuo.sys.modular.file.util.OnlineDocumentUtil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线文件信息结果集
|
||||||
|
*
|
||||||
|
* @author yubaoshan
|
||||||
|
* @date 2020/6/7 22:15
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SysOnlineFileInfoResult {
|
||||||
|
|
||||||
|
public String fileId;
|
||||||
|
public String[] history;
|
||||||
|
public String type = "desktop";
|
||||||
|
public String mode = "edit";
|
||||||
|
public String documentType;
|
||||||
|
public Document document;
|
||||||
|
public EditorConfig editorConfig;
|
||||||
|
public String token;
|
||||||
|
|
||||||
|
public static class Document {
|
||||||
|
public String title;
|
||||||
|
public String url;
|
||||||
|
public String fileType;
|
||||||
|
public String key;
|
||||||
|
public Permissions permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Permissions {
|
||||||
|
public Boolean comment;
|
||||||
|
public Boolean download;
|
||||||
|
public Boolean edit;
|
||||||
|
public Boolean fillForms;
|
||||||
|
public Boolean modifyFilter;
|
||||||
|
public Boolean modifyContentControl;
|
||||||
|
public Boolean review;
|
||||||
|
|
||||||
|
public Permissions(String mode, String type, Boolean canEdit) {
|
||||||
|
comment = !mode.equals("view") && !mode.equals("fillForms") && !mode.equals("embedded") && !mode.equals("blockcontent");
|
||||||
|
download = true;
|
||||||
|
edit = canEdit && (mode.equals("edit") || mode.equals("filter") || mode.equals("blockcontent"));
|
||||||
|
fillForms = !mode.equals("view") && !mode.equals("comment") && !mode.equals("embedded") && !mode.equals("blockcontent");
|
||||||
|
modifyFilter = !mode.equals("filter");
|
||||||
|
modifyContentControl = !mode.equals("blockcontent");
|
||||||
|
review = mode.equals("edit") || mode.equals("review");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EditorConfig {
|
||||||
|
public HashMap<String, Object> actionLink = null;
|
||||||
|
public String mode = "edit";
|
||||||
|
public String callbackUrl;
|
||||||
|
public String lang = "en";
|
||||||
|
public Integer forcesavetype = 1;
|
||||||
|
public User user;
|
||||||
|
public Customization customization;
|
||||||
|
public Embedded embedded;
|
||||||
|
|
||||||
|
public EditorConfig(String actionData) {
|
||||||
|
if (actionData != null) {
|
||||||
|
Gson gson = new Gson();
|
||||||
|
actionLink = gson.fromJson(actionData, new TypeToken<HashMap<String, Object>>() { }.getType());
|
||||||
|
}
|
||||||
|
user = new User();
|
||||||
|
customization = new Customization();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitDesktop(String url) {
|
||||||
|
embedded = new Embedded();
|
||||||
|
embedded.saveUrl = url;
|
||||||
|
embedded.embedUrl = url;
|
||||||
|
embedded.shareUrl = url;
|
||||||
|
embedded.toolbarDocked = "top";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class User {
|
||||||
|
public String id = "-1";
|
||||||
|
public String name = CommonConstant.UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Customization {
|
||||||
|
public GoBack goback;
|
||||||
|
public Boolean forcesave = true;
|
||||||
|
public Customization()
|
||||||
|
{
|
||||||
|
goback = new GoBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GoBack {
|
||||||
|
public String url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Embedded {
|
||||||
|
public String saveUrl;
|
||||||
|
public String embedUrl;
|
||||||
|
public String shareUrl;
|
||||||
|
public String toolbarDocked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SysOnlineFileInfoResult(String fileId, String fileOriginName, String userId, String userName) {
|
||||||
|
if (fileOriginName == null) fileOriginName = "";
|
||||||
|
fileOriginName = fileOriginName.trim();
|
||||||
|
documentType = OnlineDocumentUtil.getFileType(fileOriginName).toLowerCase();
|
||||||
|
this.fileId = fileId;
|
||||||
|
document = new Document();
|
||||||
|
document.title = fileOriginName;
|
||||||
|
document.url = OnlineDocumentUtil.getFileUri(fileId, fileOriginName);
|
||||||
|
document.fileType = FileUtil.getSuffix(fileOriginName);
|
||||||
|
document.key = GenerateRevisionId(fileOriginName + SymbolConstant.PERIOD + new File(OnlineDocumentUtil.getStoragePath(fileId + SymbolConstant.PERIOD + FileUtil.getSuffix(fileOriginName))).lastModified());
|
||||||
|
|
||||||
|
editorConfig = new EditorConfig(null);
|
||||||
|
editorConfig.callbackUrl = OnlineDocumentUtil.getCallback(fileId, document.fileType);
|
||||||
|
editorConfig.lang = "zh";
|
||||||
|
|
||||||
|
if (userId != null) editorConfig.user.id = userId;
|
||||||
|
if (userName != null) editorConfig.user.name = userName;
|
||||||
|
|
||||||
|
editorConfig.customization.goback.url = "";
|
||||||
|
|
||||||
|
changeType(mode, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeType(String _mode, String _type) {
|
||||||
|
if (_mode != null) mode = _mode;
|
||||||
|
if (_type != null) type = _type;
|
||||||
|
|
||||||
|
Boolean canEdit = OnlineDocumentUtil.getEditedSuffix().contains(SymbolConstant.PERIOD + FileUtil.getSuffix(document.title));
|
||||||
|
|
||||||
|
editorConfig.mode = canEdit && !mode.equals("view") ? "edit" : "view";
|
||||||
|
|
||||||
|
document.permissions = new Permissions(mode, type, canEdit);
|
||||||
|
|
||||||
|
if (type.equals("embedded")) InitDesktop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String GenerateRevisionId(String expectedKey) {
|
||||||
|
if (expectedKey.length() > 20)
|
||||||
|
expectedKey = Integer.toString(expectedKey.hashCode());
|
||||||
|
|
||||||
|
String key = expectedKey.replace("[^0-9-.a-zA-Z_=]", "_");
|
||||||
|
|
||||||
|
return key.substring(0, Math.min(key.length(), 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitDesktop() {
|
||||||
|
editorConfig.InitDesktop(document.url);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -30,6 +30,7 @@ import vip.xiaonuo.core.pojo.page.PageResult;
|
||||||
import vip.xiaonuo.sys.modular.file.entity.SysFileInfo;
|
import vip.xiaonuo.sys.modular.file.entity.SysFileInfo;
|
||||||
import vip.xiaonuo.sys.modular.file.param.SysFileInfoParam;
|
import vip.xiaonuo.sys.modular.file.param.SysFileInfoParam;
|
||||||
import vip.xiaonuo.sys.modular.file.result.SysFileInfoResult;
|
import vip.xiaonuo.sys.modular.file.result.SysFileInfoResult;
|
||||||
|
import vip.xiaonuo.sys.modular.file.result.SysOnlineFileInfoResult;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -147,4 +148,21 @@ public interface SysFileInfoService extends IService<SysFileInfo> {
|
||||||
* @date 2020/7/7 12:09
|
* @date 2020/7/7 12:09
|
||||||
*/
|
*/
|
||||||
void download(SysFileInfoParam sysFileInfoParam, HttpServletResponse response);
|
void download(SysFileInfoParam sysFileInfoParam, HttpServletResponse response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增或编辑在线文档
|
||||||
|
*
|
||||||
|
* @param sysFileInfoParam 新增或编辑参数
|
||||||
|
* @author xuyuxiang
|
||||||
|
* @date 2021/3/24 10:02
|
||||||
|
*/
|
||||||
|
SysOnlineFileInfoResult onlineAddOrUpdate(SysFileInfoParam sysFileInfoParam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线文档编辑回调
|
||||||
|
*
|
||||||
|
* @author xuyuxiang
|
||||||
|
* @date 2021/3/25 15:48
|
||||||
|
*/
|
||||||
|
void track();
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,12 +26,16 @@ package vip.xiaonuo.sys.modular.file.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.core.lang.Dict;
|
||||||
import cn.hutool.core.util.NumberUtil;
|
import cn.hutool.core.util.NumberUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
import cn.hutool.log.Log;
|
import cn.hutool.log.Log;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
@ -39,30 +43,43 @@ import org.springframework.http.MediaType;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import vip.xiaonuo.core.consts.CommonConstant;
|
||||||
import vip.xiaonuo.core.consts.SymbolConstant;
|
import vip.xiaonuo.core.consts.SymbolConstant;
|
||||||
|
import vip.xiaonuo.core.context.login.LoginContextHolder;
|
||||||
import vip.xiaonuo.core.context.requestno.RequestNoContext;
|
import vip.xiaonuo.core.context.requestno.RequestNoContext;
|
||||||
import vip.xiaonuo.core.exception.LibreOfficeException;
|
import vip.xiaonuo.core.exception.LibreOfficeException;
|
||||||
import vip.xiaonuo.core.exception.ServiceException;
|
import vip.xiaonuo.core.exception.ServiceException;
|
||||||
import vip.xiaonuo.core.factory.PageFactory;
|
import vip.xiaonuo.core.factory.PageFactory;
|
||||||
import vip.xiaonuo.core.file.FileOperator;
|
import vip.xiaonuo.core.file.FileOperator;
|
||||||
|
import vip.xiaonuo.core.file.modular.local.LocalFileOperator;
|
||||||
|
import vip.xiaonuo.core.pojo.login.SysLoginUser;
|
||||||
import vip.xiaonuo.core.pojo.page.PageResult;
|
import vip.xiaonuo.core.pojo.page.PageResult;
|
||||||
|
import vip.xiaonuo.core.util.HttpServletUtil;
|
||||||
import vip.xiaonuo.core.util.LibreOfficeUtil;
|
import vip.xiaonuo.core.util.LibreOfficeUtil;
|
||||||
import vip.xiaonuo.sys.modular.file.entity.SysFileInfo;
|
import vip.xiaonuo.sys.modular.file.entity.SysFileInfo;
|
||||||
import vip.xiaonuo.sys.modular.file.enums.FileLocationEnum;
|
import vip.xiaonuo.sys.modular.file.enums.SysFileLocationEnum;
|
||||||
import vip.xiaonuo.sys.modular.file.enums.SysFileInfoExceptionEnum;
|
import vip.xiaonuo.sys.modular.file.enums.SysFileInfoExceptionEnum;
|
||||||
import vip.xiaonuo.sys.modular.file.mapper.SysFileInfoMapper;
|
import vip.xiaonuo.sys.modular.file.mapper.SysFileInfoMapper;
|
||||||
import vip.xiaonuo.sys.modular.file.param.SysFileInfoParam;
|
import vip.xiaonuo.sys.modular.file.param.SysFileInfoParam;
|
||||||
import vip.xiaonuo.sys.modular.file.result.SysFileInfoResult;
|
import vip.xiaonuo.sys.modular.file.result.SysFileInfoResult;
|
||||||
|
import vip.xiaonuo.sys.modular.file.result.SysOnlineFileInfoResult;
|
||||||
import vip.xiaonuo.sys.modular.file.service.SysFileInfoService;
|
import vip.xiaonuo.sys.modular.file.service.SysFileInfoService;
|
||||||
import vip.xiaonuo.sys.modular.file.util.DownloadUtil;
|
import vip.xiaonuo.sys.modular.file.util.DownloadUtil;
|
||||||
|
import vip.xiaonuo.sys.modular.file.util.OnlineDocumentUtil;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.ServletOutputStream;
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
import static vip.xiaonuo.sys.config.FileConfig.DEFAULT_BUCKET;
|
import static vip.xiaonuo.sys.config.FileConfig.DEFAULT_BUCKET;
|
||||||
|
|
||||||
|
@ -80,6 +97,46 @@ public class SysFileInfoServiceImpl extends ServiceImpl<SysFileInfoMapper, SysFi
|
||||||
@Resource
|
@Resource
|
||||||
private FileOperator fileOperator;
|
private FileOperator fileOperator;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SysOnlineFileInfoResult onlineAddOrUpdate(SysFileInfoParam sysFileInfoParam) {
|
||||||
|
if(fileOperator instanceof LocalFileOperator) {
|
||||||
|
//文件后缀
|
||||||
|
String fileSuffix = sysFileInfoParam.getFileSuffix();
|
||||||
|
//文件名称
|
||||||
|
String fileOriginName = sysFileInfoParam.getFileOriginName();
|
||||||
|
//文件id
|
||||||
|
Long id = sysFileInfoParam.getId();
|
||||||
|
//参数错误
|
||||||
|
if(ObjectUtil.isAllEmpty(fileSuffix, fileOriginName, id)) {
|
||||||
|
throw new ServiceException(SysFileInfoExceptionEnum.ONLINE_EDIT_PARAM_ERROR);
|
||||||
|
}
|
||||||
|
//获取登录用户
|
||||||
|
SysLoginUser sysLoginUser = LoginContextHolder.me().getSysLoginUser();
|
||||||
|
SysFileInfo sysFileInfo;
|
||||||
|
SysOnlineFileInfoResult sysOnlineFileInfoResult;
|
||||||
|
//文件id不为空则表示编辑
|
||||||
|
if(ObjectUtil.isNotEmpty(id)) {
|
||||||
|
sysFileInfo = this.getById(id);
|
||||||
|
sysOnlineFileInfoResult= new SysOnlineFileInfoResult(Convert.toStr(sysFileInfo.getId()), sysFileInfo.getFileOriginName(), Convert.toStr(sysLoginUser.getId()), sysLoginUser.getName());
|
||||||
|
} else {
|
||||||
|
//否则表示新增
|
||||||
|
Boolean sample = sysFileInfoParam.getSample();
|
||||||
|
sysFileInfo = createDemo(fileSuffix, fileOriginName, sample, Convert.toStr(sysLoginUser.getId()), sysLoginUser.getName());
|
||||||
|
sysOnlineFileInfoResult= new SysOnlineFileInfoResult(Convert.toStr(sysFileInfo.getId()), fileOriginName + SymbolConstant.PERIOD + fileSuffix, Convert.toStr(sysLoginUser.getId()), sysLoginUser.getName());
|
||||||
|
|
||||||
|
}
|
||||||
|
//设置history
|
||||||
|
sysOnlineFileInfoResult.history = OnlineDocumentUtil.getHistory(sysOnlineFileInfoResult);
|
||||||
|
if(ObjectUtil.isAllNotEmpty(sysFileInfoParam.getMode(), sysFileInfoParam.getType())) {
|
||||||
|
sysOnlineFileInfoResult.changeType(sysFileInfoParam.getMode(), sysFileInfoParam.getType());
|
||||||
|
}
|
||||||
|
return sysOnlineFileInfoResult;
|
||||||
|
} else {
|
||||||
|
//暂时只支持本地文件
|
||||||
|
throw new ServiceException(SysFileInfoExceptionEnum.ONLINE_EDIT_SUPPORT_LOCAL_ONLY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<SysFileInfo> page(SysFileInfoParam sysFileInfoParam) {
|
public PageResult<SysFileInfo> page(SysFileInfoParam sysFileInfoParam) {
|
||||||
|
|
||||||
|
@ -101,6 +158,15 @@ public class SysFileInfoServiceImpl extends ServiceImpl<SysFileInfoMapper, SysFi
|
||||||
if (ObjectUtil.isNotEmpty(sysFileInfoParam.getFileOriginName())) {
|
if (ObjectUtil.isNotEmpty(sysFileInfoParam.getFileOriginName())) {
|
||||||
queryWrapper.like(SysFileInfo::getFileOriginName, sysFileInfoParam.getFileOriginName());
|
queryWrapper.like(SysFileInfo::getFileOriginName, sysFileInfoParam.getFileOriginName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 根据后缀查询
|
||||||
|
if(ObjectUtil.isNotEmpty(sysFileInfoParam.getFileSuffix())) {
|
||||||
|
if(sysFileInfoParam.getFileSuffix().contains(SymbolConstant.COMMA)) {
|
||||||
|
queryWrapper.in(SysFileInfo::getFileSuffix, Arrays.asList(sysFileInfoParam.getFileSuffix().split(SymbolConstant.COMMA)));
|
||||||
|
} else {
|
||||||
|
queryWrapper.eq(SysFileInfo::getFileSuffix, sysFileInfoParam.getFileSuffix());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询分页结果
|
// 查询分页结果
|
||||||
|
@ -194,7 +260,7 @@ public class SysFileInfoServiceImpl extends ServiceImpl<SysFileInfoMapper, SysFi
|
||||||
// 存储文件信息
|
// 存储文件信息
|
||||||
SysFileInfo sysFileInfo = new SysFileInfo();
|
SysFileInfo sysFileInfo = new SysFileInfo();
|
||||||
sysFileInfo.setId(fileId);
|
sysFileInfo.setId(fileId);
|
||||||
sysFileInfo.setFileLocation(FileLocationEnum.LOCAL.getCode());
|
sysFileInfo.setFileLocation(SysFileLocationEnum.LOCAL.getCode());
|
||||||
sysFileInfo.setFileBucket(DEFAULT_BUCKET);
|
sysFileInfo.setFileBucket(DEFAULT_BUCKET);
|
||||||
sysFileInfo.setFileObjectName(finalName);
|
sysFileInfo.setFileObjectName(finalName);
|
||||||
sysFileInfo.setFileOriginName(originalFilename);
|
sysFileInfo.setFileOriginName(originalFilename);
|
||||||
|
@ -318,4 +384,157 @@ public class SysFileInfoServiceImpl extends ServiceImpl<SysFileInfoMapper, SysFi
|
||||||
return sysFileInfo;
|
return sysFileInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void track() {
|
||||||
|
HttpServletRequest request = HttpServletUtil.getRequest();
|
||||||
|
HttpServletResponse response = HttpServletUtil.getResponse();
|
||||||
|
String fileObjectName = request.getParameter("fileObjectName");
|
||||||
|
String id = request.getParameter("id");
|
||||||
|
String storagePath = OnlineDocumentUtil.getStoragePath(id + SymbolConstant.PERIOD + FileUtil.getSuffix(fileObjectName));
|
||||||
|
String body = "";
|
||||||
|
Scanner scanner;
|
||||||
|
|
||||||
|
try {
|
||||||
|
scanner = new Scanner(request.getInputStream());
|
||||||
|
scanner.useDelimiter("\\A");
|
||||||
|
body = scanner.hasNext() ? scanner.next() : "";
|
||||||
|
scanner.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject jsonObj;
|
||||||
|
|
||||||
|
if (body.isEmpty()) {
|
||||||
|
log.error(">>> 读取文件request输入流为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
jsonObj = JSONObject.parseObject(body);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.error(">>> 文件信息body格式化错误");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = (int) jsonObj.get("status");
|
||||||
|
String downloadUri = (String) jsonObj.get("url");
|
||||||
|
String changesUri = (String) jsonObj.get("changesurl");
|
||||||
|
String key = (String) jsonObj.get("key");
|
||||||
|
|
||||||
|
int saved = 0;
|
||||||
|
if (status == 2 || status == 3) {
|
||||||
|
//MustSave, Corrupted
|
||||||
|
try {
|
||||||
|
String histDir = OnlineDocumentUtil.getHistoryDir(OnlineDocumentUtil.getStoragePath(id));
|
||||||
|
String versionDir = OnlineDocumentUtil.getVersionDir(histDir, OnlineDocumentUtil.getFileVersion(histDir) + 1);
|
||||||
|
File ver = new File(versionDir);
|
||||||
|
File toSave = new File(storagePath);
|
||||||
|
if (!ver.exists()) ver.mkdirs();
|
||||||
|
toSave.renameTo(new File(versionDir + File.separator + "prev" + SymbolConstant.PERIOD + FileUtil.getSuffix(fileObjectName)));
|
||||||
|
DownloadUtil.downloadToFile(downloadUri, toSave);
|
||||||
|
DownloadUtil.downloadToFile(changesUri, new File(versionDir + File.separator + "diff.zip"));
|
||||||
|
|
||||||
|
String history = (String) jsonObj.get("changeshistory");
|
||||||
|
if (history == null && jsonObj.containsKey("history")) {
|
||||||
|
history = ((JSONObject) jsonObj.get("history")).toJSONString();
|
||||||
|
}
|
||||||
|
if (history != null && !history.isEmpty()) {
|
||||||
|
FileWriter fw = new FileWriter(new File(versionDir + File.separator + "changes.json"));
|
||||||
|
fw.write(history);
|
||||||
|
fw.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileWriter fw = new FileWriter(new File(versionDir + File.separator + "key.txt"));
|
||||||
|
fw.write(key);
|
||||||
|
fw.close();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
saved = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
response.getWriter().write("{\"error\":" + saved + "}");
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建模板文件
|
||||||
|
*
|
||||||
|
* @param fileSuffix 文件后缀
|
||||||
|
* @param originalFilename 文件原始名称
|
||||||
|
* @param sample 是否创建相同文件内容的模板文件
|
||||||
|
* @param userId 用户id
|
||||||
|
* @param userName 用户名称
|
||||||
|
* @author xuyuxiang
|
||||||
|
* @date 2021/3/24 11:01
|
||||||
|
*/
|
||||||
|
public SysFileInfo createDemo(String fileSuffix, String originalFilename, Boolean sample, String userId, String userName) {
|
||||||
|
// 文件名称拼接
|
||||||
|
originalFilename = originalFilename + SymbolConstant.PERIOD + fileSuffix;
|
||||||
|
// 模板名称
|
||||||
|
String demoName = (sample ? "sample." : "new.") + fileSuffix;
|
||||||
|
InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("assets/" + demoName);
|
||||||
|
// 生成文件的唯一id
|
||||||
|
Long fileId = IdWorker.getId();
|
||||||
|
// 生成文件的最终名称
|
||||||
|
String finalName = fileId + SymbolConstant.PERIOD + fileSuffix;
|
||||||
|
// 读取流
|
||||||
|
byte[] bytes = IoUtil.readBytes(stream);
|
||||||
|
// 将该模板文件存到存储桶
|
||||||
|
fileOperator.storageFile(DEFAULT_BUCKET, finalName, bytes);
|
||||||
|
// 创建元数据信息
|
||||||
|
createMeta(Convert.toStr(fileId), userId, userName);
|
||||||
|
// 计算文件大小kb
|
||||||
|
long fileSizeKb = Convert.toLong(NumberUtil.div(new BigDecimal(bytes.length), BigDecimal.valueOf(1024))
|
||||||
|
.setScale(0, BigDecimal.ROUND_HALF_UP));
|
||||||
|
// 计算文件大小信息
|
||||||
|
String fileSizeInfo = FileUtil.readableFileSize(bytes.length);
|
||||||
|
// 存储文件信息
|
||||||
|
SysFileInfo sysFileInfo = new SysFileInfo();
|
||||||
|
sysFileInfo.setId(fileId);
|
||||||
|
sysFileInfo.setFileLocation(SysFileLocationEnum.LOCAL.getCode());
|
||||||
|
sysFileInfo.setFileBucket(DEFAULT_BUCKET);
|
||||||
|
sysFileInfo.setFileObjectName(finalName);
|
||||||
|
sysFileInfo.setFileOriginName(originalFilename);
|
||||||
|
sysFileInfo.setFileSuffix(fileSuffix);
|
||||||
|
sysFileInfo.setFileSizeKb(fileSizeKb);
|
||||||
|
sysFileInfo.setFileSizeInfo(fileSizeInfo);
|
||||||
|
// 将新创建的文件保存到数据库
|
||||||
|
this.save(sysFileInfo);
|
||||||
|
return sysFileInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建元数据信息
|
||||||
|
*
|
||||||
|
* @param fileId 文件id
|
||||||
|
* @param userId 用户id
|
||||||
|
* @param userName 用户名称
|
||||||
|
* @author xuyuxiang
|
||||||
|
* @date 2021/3/24 11:19
|
||||||
|
*/
|
||||||
|
public void createMeta(String fileId, String userId, String userName) {
|
||||||
|
// 仅限本地文件
|
||||||
|
Object localClient = fileOperator.getClient();
|
||||||
|
if(ObjectUtil.isNull(localClient)) {
|
||||||
|
throw new ServiceException(SysFileInfoExceptionEnum.CLIENT_INIT_ERROR);
|
||||||
|
}
|
||||||
|
Dict localClientDict = (Dict) localClient;
|
||||||
|
// 拼接获取文档历史路径
|
||||||
|
String histDir = localClientDict.getStr("currentSavePath") + File.separator + DEFAULT_BUCKET + File.separator + fileId + "-hist";
|
||||||
|
if(!FileUtil.exist(histDir)) {
|
||||||
|
// 历史路径不存在则创建
|
||||||
|
File dir = new File(histDir);
|
||||||
|
dir.mkdir();
|
||||||
|
}
|
||||||
|
Dict dict = new Dict();
|
||||||
|
dict.put("created", DateUtil.now());
|
||||||
|
dict.put("id", (userId == null || userId.isEmpty()) ? -1 : userId);
|
||||||
|
dict.put("name", (userName == null || userName.isEmpty()) ? CommonConstant.UNKNOWN : userName);
|
||||||
|
File metaFile = new File(histDir + File.separator + "createdInfo.json");
|
||||||
|
FileUtil.writeString(JSONUtil.toJsonStr(dict), metaFile, Charset.defaultCharset());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,9 @@ import vip.xiaonuo.sys.modular.file.enums.SysFileInfoExceptionEnum;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URL;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,4 +88,33 @@ public class DownloadUtil {
|
||||||
//下载文件
|
//下载文件
|
||||||
download(fileName, fileBytes, response);
|
download(fileName, fileBytes, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将url的文件下载到目标文件
|
||||||
|
*
|
||||||
|
* @param url 下载url
|
||||||
|
* @param file 目标文件
|
||||||
|
* @author xuyuxiang
|
||||||
|
* @date 2021/3/25 16:51
|
||||||
|
*/
|
||||||
|
public static void downloadToFile(String url, File file) {
|
||||||
|
if (url == null || url.isEmpty()) throw new ServiceException(SysFileInfoExceptionEnum.DOWNLOAD_FILE_ERROR);
|
||||||
|
|
||||||
|
if (file == null) throw new ServiceException(SysFileInfoExceptionEnum.NOT_EXISTED_FILE);
|
||||||
|
|
||||||
|
try {
|
||||||
|
URL uri = new URL(url);
|
||||||
|
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) uri.openConnection();
|
||||||
|
InputStream stream = connection.getInputStream();
|
||||||
|
|
||||||
|
if (stream == null) {
|
||||||
|
throw new ServiceException(SysFileInfoExceptionEnum.FILE_STREAM_ERROR);
|
||||||
|
}
|
||||||
|
FileUtil.writeFromStream(stream, file);
|
||||||
|
connection.disconnect();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(">>> 下载文件异常,请求号为:{},具体信息为:{}", RequestNoContext.get(), e.getMessage());
|
||||||
|
throw new ServiceException(SysFileInfoExceptionEnum.DOWNLOAD_FILE_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,246 @@
|
||||||
|
/*
|
||||||
|
Copyright [2020] [https://www.xiaonuo.vip]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||||
|
|
||||||
|
1.请不要删除和修改根目录下的LICENSE文件。
|
||||||
|
2.请不要删除和修改Snowy源码头部的版权声明。
|
||||||
|
3.请保留源码和相关描述文件的项目出处,作者声明等。
|
||||||
|
4.分发源码时候,请注明软件出处 https://gitee.com/xiaonuobase/snowy-layui
|
||||||
|
5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/xiaonuobase/snowy-layui
|
||||||
|
6.若您的项目无法满足以上几点,可申请商业授权,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
|
||||||
|
*/
|
||||||
|
package vip.xiaonuo.sys.modular.file.util;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.core.lang.Dict;
|
||||||
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import vip.xiaonuo.core.consts.SymbolConstant;
|
||||||
|
import vip.xiaonuo.core.file.FileOperator;
|
||||||
|
import vip.xiaonuo.core.file.modular.local.LocalFileOperator;
|
||||||
|
import vip.xiaonuo.sys.config.FileConfig;
|
||||||
|
import vip.xiaonuo.sys.modular.file.result.SysOnlineFileInfoResult;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线文档相关工具类
|
||||||
|
*
|
||||||
|
* @author xuyuxiang
|
||||||
|
* @date 2021/3/24 16:12
|
||||||
|
*/
|
||||||
|
public class OnlineDocumentUtil {
|
||||||
|
|
||||||
|
private static final String VIEWED_SUFFIX = ".pdf|.djvu|.xps";
|
||||||
|
private static final String EDITED_SUFFIX = ".docx|.xlsx|.csv|.pptx|.txt";
|
||||||
|
private static final String CONVERT_SUFFIX = ".docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.epub";
|
||||||
|
|
||||||
|
public static final List<String> DOCUMENT_SUFFIX = Arrays.asList(".doc", ".docx", ".docm", ".dot", ".dotx", ".dotm", ".odt", ".fodt", ".ott", ".rtf", ".txt", ".html", ".htm",
|
||||||
|
".mht", ".pdf", ".djvu", ".fb2", ".epub", ".xps");
|
||||||
|
|
||||||
|
public static final List<String> SPREADSHEET_SUFFIX = Arrays.asList(".xls", ".xlsx", ".xlsm", ".xlt", ".xltx", ".xltm", ".ods", ".fods", ".ots", ".csv");
|
||||||
|
|
||||||
|
public static final List<String> Presentation_SUFFIX = Arrays.asList(".pps", ".ppsx", ".ppsm",".ppt", ".pptx", ".pptm", ".pot", ".potx", ".potm", ".odp", ".fodp", ".otp");
|
||||||
|
|
||||||
|
|
||||||
|
public static List<String> getFileSuffix() {
|
||||||
|
List<String> res = new ArrayList<>();
|
||||||
|
res.addAll(getViewedSuffix());
|
||||||
|
res.addAll(getEditedSuffix());
|
||||||
|
res.addAll(getConvertSuffix());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> getViewedSuffix() {
|
||||||
|
return Arrays.asList(VIEWED_SUFFIX.split("\\|"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> getEditedSuffix() {
|
||||||
|
return Arrays.asList(EDITED_SUFFIX.split("\\|"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> getConvertSuffix() {
|
||||||
|
return Arrays.asList(CONVERT_SUFFIX.split("\\|"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getFileType(String fileOriginName) {
|
||||||
|
String suffix = SymbolConstant.PERIOD + FileUtil.getSuffix(fileOriginName);
|
||||||
|
if (DOCUMENT_SUFFIX.contains(suffix)) return "Text";
|
||||||
|
if (SPREADSHEET_SUFFIX.contains(suffix)) return "Spreadsheet";
|
||||||
|
if (Presentation_SUFFIX.contains(suffix)) return "Presentation";
|
||||||
|
return "Text";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getFileUri(String fileId, String fileName) {
|
||||||
|
try {
|
||||||
|
String filePath = "sysFileInfo/download?id="+ fileId +"&name=" + URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString()).replace("+", "%20");
|
||||||
|
|
||||||
|
return filePath;
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getCallback(String fileId, String fileSuffix) {
|
||||||
|
return "sysFileInfo/track?fileObjectName=" + fileId + SymbolConstant.PERIOD + fileSuffix + "&id=" + fileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getStoragePath(String fileIdOrObjectName) {
|
||||||
|
String directory = FilesRootPath();
|
||||||
|
return directory + File.separator + FileConfig.DEFAULT_BUCKET + File.separator + fileIdOrObjectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String FilesRootPath() {
|
||||||
|
LocalFileOperator localFileOperator = (LocalFileOperator) SpringUtil.getBean(FileOperator.class);
|
||||||
|
Dict localClientDict = (Dict) localFileOperator.getClient();
|
||||||
|
String currentSavePath = localClientDict.getStr("currentSavePath");
|
||||||
|
File file = new File(currentSavePath);
|
||||||
|
|
||||||
|
if (!file.exists()) {
|
||||||
|
file.mkdirs();
|
||||||
|
}
|
||||||
|
return currentSavePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getHistory(SysOnlineFileInfoResult sysOnlineFileInfoResult) {
|
||||||
|
String histDir = OnlineDocumentUtil.getHistoryDir(OnlineDocumentUtil.getStoragePath(sysOnlineFileInfoResult.getFileId()));
|
||||||
|
if (getFileVersion(histDir) > 0) {
|
||||||
|
Integer curVer = getFileVersion(histDir);
|
||||||
|
|
||||||
|
Set<Object> hist = new HashSet<Object>();
|
||||||
|
Map<String, Object> histData = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
for (Integer i = 0; i <= curVer; i++) {
|
||||||
|
Map<String, Object> obj = new HashMap<String, Object>();
|
||||||
|
Map<String, Object> dataObj = new HashMap<String, Object>();
|
||||||
|
String verDir = getVersionDir(histDir, i + 1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
String key = null;
|
||||||
|
|
||||||
|
key = i == curVer ? sysOnlineFileInfoResult.document.key : readFileToEnd(new File(verDir + File.separator + "key.txt"));
|
||||||
|
|
||||||
|
obj.put("key", key);
|
||||||
|
obj.put("version", i);
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
String createdInfo = readFileToEnd(new File(histDir + File.separator + "createdInfo.json"));
|
||||||
|
JSONObject json = (JSONObject) JSONUtil.parse(createdInfo);
|
||||||
|
|
||||||
|
obj.put("created", json.get("created"));
|
||||||
|
Map<String, Object> user = new HashMap<String, Object>();
|
||||||
|
user.put("id", json.get("id"));
|
||||||
|
user.put("name", json.get("name"));
|
||||||
|
obj.put("user", user);
|
||||||
|
}
|
||||||
|
|
||||||
|
dataObj.put("key", key);
|
||||||
|
dataObj.put("url", i == curVer ? sysOnlineFileInfoResult.document.url : getStoragePath(verDir + File.separator + "prev" + FileUtil.getSuffix(sysOnlineFileInfoResult.getDocument().title)));
|
||||||
|
dataObj.put("version", i);
|
||||||
|
|
||||||
|
if (i > 0) {
|
||||||
|
JSONObject changes = (JSONObject) JSONUtil.parse(readFileToEnd(new File(getVersionDir(histDir, i) + File.separator + "changes.json")));
|
||||||
|
JSONObject change = (JSONObject) ((JSONArray) changes.get("changes")).get(0);
|
||||||
|
|
||||||
|
obj.put("changes", changes.get("changes"));
|
||||||
|
obj.put("serverVersion", changes.get("serverVersion"));
|
||||||
|
obj.put("created", change.get("created"));
|
||||||
|
obj.put("user", change.get("user"));
|
||||||
|
|
||||||
|
Map<String, Object> prev = (Map<String, Object>) histData.get(Integer.toString(i - 1));
|
||||||
|
Map<String, Object> prevInfo = new HashMap<String, Object>();
|
||||||
|
prevInfo.put("key", prev.get("key"));
|
||||||
|
prevInfo.put("url", prev.get("url"));
|
||||||
|
dataObj.put("previous", prevInfo);
|
||||||
|
dataObj.put("changesUrl", getStoragePath(getVersionDir(histDir, i) + File.separator + "diff.zip"));
|
||||||
|
}
|
||||||
|
|
||||||
|
hist.add(obj);
|
||||||
|
histData.put(Integer.toString(i), dataObj);
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> histObj = new HashMap<String, Object>();
|
||||||
|
histObj.put("currentVersion", curVer);
|
||||||
|
histObj.put("history", hist);
|
||||||
|
|
||||||
|
Gson gson = new Gson();
|
||||||
|
return new String[]{gson.toJson(histObj), gson.toJson(histData)};
|
||||||
|
}
|
||||||
|
return new String[]{"", ""};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getHistoryDir(String storagePath) {
|
||||||
|
return storagePath += "-hist";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getVersionDir(String histPath, Integer version) {
|
||||||
|
return histPath + File.separator + Integer.toString(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer getFileVersion(String historyPath) {
|
||||||
|
File dir = new File(historyPath);
|
||||||
|
|
||||||
|
if (!dir.exists()) return 0;
|
||||||
|
|
||||||
|
File[] dirs = dir.listFiles(new FileFilter() {
|
||||||
|
@Override
|
||||||
|
public boolean accept(File pathname) {
|
||||||
|
return pathname.isDirectory();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return dirs.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readFileToEnd(File file) {
|
||||||
|
String output = "";
|
||||||
|
try {
|
||||||
|
try(FileInputStream is = new FileInputStream(file))
|
||||||
|
{
|
||||||
|
Scanner scanner = new Scanner(is);
|
||||||
|
scanner.useDelimiter("\\A");
|
||||||
|
while (scanner.hasNext()) {
|
||||||
|
output += scanner.next();
|
||||||
|
}
|
||||||
|
scanner.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) { }
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deleteFileHistory(String fileId) {
|
||||||
|
// 判断文件存在不存在
|
||||||
|
String histDir = OnlineDocumentUtil.getHistoryDir(OnlineDocumentUtil.getStoragePath(fileId));
|
||||||
|
File hisDirFile = FileUtil.file(histDir);
|
||||||
|
if (!FileUtil.exist(hisDirFile)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除文件
|
||||||
|
FileUtil.del(hisDirFile);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue