perf: 文件上传支持覆盖上传

This commit is contained in:
kuaifan 2024-03-13 13:42:45 +09:00
parent d553f77533
commit 16359a968d
7 changed files with 104 additions and 18 deletions

View File

@ -699,6 +699,9 @@ class FileController extends AbstractController
* @apiName content__upload * @apiName content__upload
* *
* @apiParam {Number} [pid] 父级ID * @apiParam {Number} [pid] 父级ID
* @apiParam {Number} [cover] 覆盖已存在的文件
* - 0:不覆盖,保留两者(默认)
* - 1:覆盖
* @apiParam {String} [files] 文件名 * @apiParam {String} [files] 文件名
* *
* @apiSuccess {Number} ret 返回状态码1正确、0错误 * @apiSuccess {Number} ret 返回状态码1正确、0错误
@ -709,8 +712,9 @@ class FileController extends AbstractController
{ {
$user = User::auth(); $user = User::auth();
$pid = intval(Request::input('pid')); $pid = intval(Request::input('pid'));
$overwrite = intval(Request::input('cover'));
$webkitRelativePath = Request::input('webkitRelativePath'); $webkitRelativePath = Request::input('webkitRelativePath');
$data = (new File)->contentUpload($user, $pid, $webkitRelativePath); $data = (new File)->contentUpload($user, $pid, $webkitRelativePath, $overwrite);
return Base::retSuccess($data['data']['name'] . ' 上传成功', $data['addItem']); return Base::retSuccess($data['data']['name'] . ' 上传成功', $data['addItem']);
} }

View File

@ -190,9 +190,10 @@ class File extends AbstractModel
* @param user $user * @param user $user
* @param int $pid * @param int $pid
* @param string $webkitRelativePath * @param string $webkitRelativePath
* @param bool $overwrite
* @return array * @return array
*/ */
public function contentUpload($user, int $pid, $webkitRelativePath) public function contentUpload($user, int $pid, $webkitRelativePath, $overwrite = false)
{ {
$userid = $user->userid; $userid = $user->userid;
if ($pid > 0) { if ($pid > 0) {
@ -283,17 +284,25 @@ class File extends AbstractModel
if ($data['ext'] == 'markdown') { if ($data['ext'] == 'markdown') {
$data['ext'] = 'md'; $data['ext'] = 'md';
} }
$file = File::createInstance([ $file = null;
$params = [
'pid' => $pid, 'pid' => $pid,
'name' => Base::rightDelete($data['name'], '.' . $data['ext']), 'name' => Base::rightDelete($data['name'], '.' . $data['ext']),
'type' => $type, 'type' => $type,
'ext' => $data['ext'], 'ext' => $data['ext'],
'userid' => $userid, 'userid' => $userid,
'created_id' => $user->userid, 'created_id' => $user->userid,
]); ];
$file->handleDuplicateName(); if ($overwrite) {
$file = self::wherePid($params['pid'])->whereExt($params['ext'])->whereName($params['name'])->first();
}
if (!$file) {
$overwrite = false;
$file = File::createInstance($params);
$file->handleDuplicateName();
}
// 开始创建 // 开始创建
return AbstractModel::transaction(function () use ($addItem, $webkitRelativePath, $type, $user, $data, $file) { return AbstractModel::transaction(function () use ($overwrite, $addItem, $webkitRelativePath, $type, $user, $data, $file) {
$file->size = $data['size'] * 1024; $file->size = $data['size'] * 1024;
$file->saveBeforePP(); $file->saveBeforePP();
// //
@ -321,11 +330,12 @@ class File extends AbstractModel
$tmpRow->pushMsg('add', $tmpRow); $tmpRow->pushMsg('add', $tmpRow);
// //
$data = File::handleImageUrl($tmpRow->toArray()); $data = File::handleImageUrl($tmpRow->toArray());
$data['full_name'] = $webkitRelativePath ?: $data['name']; $data['full_name'] = $webkitRelativePath ?: ($data['name'] . '.' . $data['ext']);
$data['overwrite'] = $overwrite ? 1 : 0;
// //
$addItem[] = $data; $addItem[] = $data;
return ['data'=>$data,'addItem'=>$addItem]; return ['data' => $data, 'addItem' => $addItem];
}); });
} }

View File

@ -1536,3 +1536,8 @@ License Key
不显示该会话 不显示该会话
昨天 昨天
文件已存在
文件(*)已存在,是否替换?
保留两者
替换

View File

@ -55,7 +55,7 @@
"stylus-loader": "^7.1.0", "stylus-loader": "^7.1.0",
"tinymce": "^5.10.3", "tinymce": "^5.10.3",
"tui-calendar-hi": "^1.15.1-5", "tui-calendar-hi": "^1.15.1-5",
"view-design-hi": "^4.7.0-48", "view-design-hi": "^4.7.0-49",
"vite": "^2.9.15", "vite": "^2.9.15",
"vite-plugin-file-copy": "^1.0.0", "vite-plugin-file-copy": "^1.0.0",
"vite-plugin-require": "^1.1.10", "vite-plugin-require": "^1.1.10",

View File

@ -175,7 +175,7 @@ Vue.prototype.copyText = function (obj) {
obj.success && $A.messageSuccess(obj.success) obj.success && $A.messageSuccess(obj.success)
return return
} }
app.$copyText(text).then(_ => { app.$copyText(obj.text).then(_ => {
obj.success && $A.messageSuccess(obj.success) obj.success && $A.messageSuccess(obj.success)
}).catch(_ => { }).catch(_ => {
obj.error && $A.messageError(obj.error) obj.error && $A.messageError(obj.error)

View File

@ -233,8 +233,10 @@
<em v-if="uploadList.find(({status}) => status === 'finished')" @click="uploadClear">{{$L('清空已完成')}}</em> <em v-if="uploadList.find(({status}) => status === 'finished')" @click="uploadClear">{{$L('清空已完成')}}</em>
</div> </div>
<ul class="content"> <ul class="content">
<li v-for="(item, index) in uploadList" :key="index" v-if="index < 100"> <li v-for="(item, index) in uploadList" :key="index" v-if="index < 100" @click="uploadClick(item)">
<AutoTip class="file-name">{{uploadName(item)}}</AutoTip> <AutoTip class="file-name">
<span v-html="uploadName(item)"></span>
</AutoTip>
<AutoTip v-if="item.status === 'finished' && item.response && item.response.ret !== 1" class="file-error">{{item.response.msg}}</AutoTip> <AutoTip v-if="item.status === 'finished' && item.response && item.response.ret !== 1" class="file-error">{{item.response.msg}}</AutoTip>
<Progress v-else :percent="uploadPercentageParse(item.percentage)" :stroke-width="5" /> <Progress v-else :percent="uploadPercentageParse(item.percentage)" :stroke-width="5" />
<Icon class="file-close" type="ios-close-circle-outline" @click="uploadList.splice(index, 1)"/> <Icon class="file-close" type="ios-close-circle-outline" @click="uploadList.splice(index, 1)"/>
@ -536,6 +538,7 @@ export default {
uploadList: [], uploadList: [],
uploadFormat: [], // uploadFormat: [], //
uploadAccept: '', uploadAccept: '',
uploadCover: false,
contextMenuItem: {}, contextMenuItem: {},
contextMenuVisible: false, contextMenuVisible: false,
@ -781,7 +784,7 @@ export default {
}, },
actionUrl() { actionUrl() {
return $A.apiUrl('file/content/upload?pid=' + this.pid) return $A.apiUrl('file/content/upload?pid=' + this.pid + '&cover=' + (this.uploadCover ? 1 : 0))
}, },
headers() { headers() {
@ -879,7 +882,7 @@ export default {
}, },
compressedSownloadDisabled() { compressedSownloadDisabled() {
return this.fileList?.find((res)=> res._checked && res.permission < 1) ? true : false return !!this.fileList?.find((res) => res._checked && res.permission < 1)
}, },
maxSize() { maxSize() {
@ -1057,6 +1060,10 @@ export default {
browseFolder(id, shakeId = null) { browseFolder(id, shakeId = null) {
if (id > 0) { if (id > 0) {
if (this.$route.params.folderId == id) {
this.shakeFile(shakeId);
return;
}
this.goForward({name: 'manage-file', params: {folderId: id, fileId: null, shakeId}}); this.goForward({name: 'manage-file', params: {folderId: id, fileId: null, shakeId}});
} else { } else {
this.searchKey = ''; this.searchKey = '';
@ -1744,8 +1751,30 @@ export default {
}) })
}, },
uploadData(item) {
const data = $A.getObject(item, 'response.data')
if ($A.isArray(data)) {
return data[0]
} else if ($A.isJson(data)) {
return data
}
},
uploadName(item) { uploadName(item) {
return $A.getObject(item, 'response.data.full_name') || item.name const data = this.uploadData(item)
if (!data) {
return item.name
}
const fullName = data.full_name || item.name
return data.overwrite ? `<em class="overwrite">[${this.$L('替换')}]</em> ${fullName}` : fullName
},
uploadClick(item) {
const data = this.uploadData(item)
if (!data) {
return
}
this.browseFolder(data.pid, data.id)
}, },
handleTableSort({key, order}) { handleTableSort({key, order}) {
@ -1948,12 +1977,45 @@ export default {
}); });
}, },
handleBeforeUpload() { handleBeforeUpload(file) {
// //
this.uploadCover = false
if (this.uploadDir) {
this.handleUploadNext();
return true;
}
return new Promise(resolve => {
if (this.fileList.findIndex(item => $A.getFileName(item) === file.name) > -1) {
$A.modalConfirm({
wait: true,
title: '文件已存在',
content: '文件 ' + file.name + ' 已存在,是否替换?',
cancelText: '保留两者',
okText: '替换',
closable: true,
onOk: () => {
this.uploadCover = true
this.handleUploadNext();
resolve();
},
onCancel: (isButton) => {
if (isButton) {
this.handleUploadNext();
resolve();
}
}
});
} else {
this.handleUploadNext();
resolve();
}
})
},
handleUploadNext() {
this.uploadShow = true; this.uploadShow = true;
this.packShow = false; this.packShow = false;
return true; }
},
} }
} }
</script> </script>

View File

@ -552,12 +552,17 @@
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
> li { > li {
cursor: pointer;
list-style: none; list-style: none;
padding: 4px 0; padding: 4px 0;
position: relative; position: relative;
.file-name { .file-name {
line-height: 18px; line-height: 18px;
padding-right: 16px; padding-right: 16px;
.overwrite {
font-style: normal;
color: $flow-status-end-color;
}
} }
.file-error { .file-error {
font-size: 12px; font-size: 12px;