mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-14 12:42:51 +00:00
perf: 优化打包下载
This commit is contained in:
parent
ecdabc668d
commit
846fdcf145
@ -13,6 +13,8 @@ use App\Models\FileUser;
|
|||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Module\Base;
|
use App\Module\Base;
|
||||||
use App\Module\Ihttp;
|
use App\Module\Ihttp;
|
||||||
|
use Response;
|
||||||
|
use Session;
|
||||||
use Swoole\Coroutine;
|
use Swoole\Coroutine;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Redirect;
|
use Redirect;
|
||||||
@ -991,9 +993,33 @@ class FileController extends AbstractController
|
|||||||
*/
|
*/
|
||||||
public function download__pack()
|
public function download__pack()
|
||||||
{
|
{
|
||||||
|
$key = Request::input('key');
|
||||||
|
if ($key) {
|
||||||
|
$userid = Session::get('file::pack:userid');
|
||||||
|
if (empty($userid)) {
|
||||||
|
return Base::ajaxError("请求已过期,请重新导出!", [], 0, 502);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$array = Base::string2array(base64_decode(urldecode($key)));
|
||||||
|
$file = $array['file'];
|
||||||
|
if (empty($file) || !file_exists(storage_path($file))) {
|
||||||
|
return Base::ajaxError("文件不存在!", [], 0, 502);
|
||||||
|
}
|
||||||
|
return Response::download(storage_path($file));
|
||||||
|
}
|
||||||
|
|
||||||
$user = User::auth();
|
$user = User::auth();
|
||||||
$ids = Request::input('ids');
|
$ids = Request::input('ids');
|
||||||
$downName = Request::input('name');
|
$fileName = Request::input('name');
|
||||||
|
$fileName = preg_replace("/[\/\\\:\*\?\"\<\>\|]/", "", $fileName);
|
||||||
|
if (empty($fileName)) {
|
||||||
|
$fileName = 'Package_' . $user->userid;
|
||||||
|
}
|
||||||
|
$fileName .= '_' . Base::time() . '.zip';
|
||||||
|
|
||||||
|
$filePath = "temp/file/pack/" . date("Ym", Base::time());
|
||||||
|
$zipFile = "app/" . $filePath . "/" . $fileName;
|
||||||
|
$zipPath = storage_path($zipFile);
|
||||||
|
|
||||||
if (!is_array($ids) || empty($ids)) {
|
if (!is_array($ids) || empty($ids)) {
|
||||||
return Base::retError('请选择下载的文件或文件夹');
|
return Base::retError('请选择下载的文件或文件夹');
|
||||||
@ -1001,9 +1027,6 @@ class FileController extends AbstractController
|
|||||||
if (count($ids) > 100) {
|
if (count($ids) > 100) {
|
||||||
return Base::retError('一次最多可以下载100个文件或文件夹');
|
return Base::retError('一次最多可以下载100个文件或文件夹');
|
||||||
}
|
}
|
||||||
if (count($ids) > 100) {
|
|
||||||
return Base::retError('一次最多可以下载100个文件或文件夹');
|
|
||||||
}
|
|
||||||
|
|
||||||
$files = [];
|
$files = [];
|
||||||
$totalSize = 0;
|
$totalSize = 0;
|
||||||
@ -1017,23 +1040,28 @@ class FileController extends AbstractController
|
|||||||
return Base::retError('文件总大小已超过1GB,请分批下载');
|
return Base::retError('文件总大小已超过1GB,请分批下载');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$base64 = base64_encode(Base::array2string([
|
||||||
|
'file' => $zipFile,
|
||||||
|
]));
|
||||||
|
$fileUrl = Base::fillUrl('api/file/download/pack?key=' . urlencode($base64));
|
||||||
|
Session::put('file::pack:userid', $user->userid);
|
||||||
|
|
||||||
$zip = new \ZipArchive();
|
$zip = new \ZipArchive();
|
||||||
$zipName = 'tmp/file/' . date("Ym") . '/' . $user->userid . '/' . $downName;
|
|
||||||
$zipPath = public_path($zipName);
|
|
||||||
Base::makeDir(dirname($zipPath));
|
Base::makeDir(dirname($zipPath));
|
||||||
|
|
||||||
if ($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
|
if ($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
|
||||||
return Base::retError('创建压缩文件失败');
|
return Base::retError('创建压缩文件失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
go(function() use ($user, $zip, $files, $downName, $zipName) {
|
go(function () use ($zipPath, $fileUrl, $user, $zip, $files, $fileName, $zipFile) {
|
||||||
Coroutine::sleep(0.1);
|
Coroutine::sleep(0.1);
|
||||||
// 压缩进度
|
// 压缩进度
|
||||||
$progress = 0;
|
$progress = 0;
|
||||||
$zip->registerProgressCallback(0.05, function($ratio) use ($downName, &$progress) {
|
$zip->registerProgressCallback(0.05, function ($ratio) use ($fileUrl, $fileName, &$progress) {
|
||||||
$progress = round($ratio * 100);
|
$progress = round($ratio * 100);
|
||||||
File::filePushMsg('compress', [
|
File::filePushMsg('compress', [
|
||||||
'name'=> $downName,
|
'name' => $fileName,
|
||||||
|
'url' => $fileUrl,
|
||||||
'progress' => $progress
|
'progress' => $progress
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
@ -1045,7 +1073,8 @@ class FileController extends AbstractController
|
|||||||
//
|
//
|
||||||
if ($progress < 100) {
|
if ($progress < 100) {
|
||||||
File::filePushMsg('compress', [
|
File::filePushMsg('compress', [
|
||||||
'name'=> $downName,
|
'name' => $fileName,
|
||||||
|
'url' => $fileUrl,
|
||||||
'progress' => 100
|
'progress' => 100
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -1057,39 +1086,17 @@ class FileController extends AbstractController
|
|||||||
if ($dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid)) {
|
if ($dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid)) {
|
||||||
$text = "<b>文件下载打包已完成。</b>";
|
$text = "<b>文件下载打包已完成。</b>";
|
||||||
$text .= "\n\n";
|
$text .= "\n\n";
|
||||||
$text .= "文件名:{$downName}";
|
$text .= "文件名:{$fileName}";
|
||||||
$text .= "\n";
|
$text .= "\n";
|
||||||
$text .= "下载地址:".Base::fillUrl($zipName);
|
$text .= "文件大小:".Base::twoFloat(filesize($zipPath) / 1024, true)."KB";
|
||||||
|
$text .= "\n";
|
||||||
|
$text .= '<a href="' . $fileUrl . '" target="_blank"><button type="button" class="ivu-btn ivu-btn-warning" style="margin-top: 10px;"><span>立即下载</span></button></a>';
|
||||||
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $text], $botUser->userid, false, false, true);
|
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $text], $botUser->userid, false, false, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
return Base::retSuccess('success', [
|
||||||
return Base::retSuccess('success');
|
'name' => $fileName,
|
||||||
}
|
'url' => $fileUrl,
|
||||||
|
]);
|
||||||
/**
|
|
||||||
* @api {get} api/file/download/confirm 20. 确认下载
|
|
||||||
*
|
|
||||||
* @apiDescription 需要token身份
|
|
||||||
* @apiVersion 1.0.0
|
|
||||||
* @apiGroup file
|
|
||||||
* @apiName download__confirm
|
|
||||||
*
|
|
||||||
* @apiParam {String} [name] 下载文件名
|
|
||||||
*
|
|
||||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
|
||||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
|
||||||
* @apiSuccess {Object} data 返回数据
|
|
||||||
*/
|
|
||||||
public function download__confirm()
|
|
||||||
{
|
|
||||||
$user = User::auth();
|
|
||||||
$downName = Request::input('name');
|
|
||||||
$zipName = 'tmp/file/' . date("Ym") . '/' . $user->userid . '/' . $downName;
|
|
||||||
$zipPath = public_path($zipName);
|
|
||||||
if (!file_exists($zipPath)) {
|
|
||||||
abort(403, "The file does not exist.");
|
|
||||||
}
|
|
||||||
return response()->download($zipPath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1200,7 +1200,7 @@ class ProjectController extends AbstractController
|
|||||||
if (Carbon::parse($time[1])->timestamp - Carbon::parse($time[0])->timestamp > 90 * 86400) {
|
if (Carbon::parse($time[1])->timestamp - Carbon::parse($time[0])->timestamp > 90 * 86400) {
|
||||||
return Base::retError('时间范围限制最大90天');
|
return Base::retError('时间范围限制最大90天');
|
||||||
}
|
}
|
||||||
go(function() use ($user, $userid, $time, $type) {
|
go(function () use ($user, $userid, $time, $type) {
|
||||||
Coroutine::sleep(0.1);
|
Coroutine::sleep(0.1);
|
||||||
$headings = [];
|
$headings = [];
|
||||||
$headings[] = '任务ID';
|
$headings[] = '任务ID';
|
||||||
@ -1324,10 +1324,10 @@ class ProjectController extends AbstractController
|
|||||||
$sheets = [];
|
$sheets = [];
|
||||||
foreach ($userid as $ownerid) {
|
foreach ($userid as $ownerid) {
|
||||||
$data = $datas[$ownerid] ?? [
|
$data = $datas[$ownerid] ?? [
|
||||||
'nickname' => Base::filterEmoji(User::userid2nickname($ownerid)),
|
'nickname' => Base::filterEmoji(User::userid2nickname($ownerid)),
|
||||||
'styles' => ["A1:P1" => ["font" => ["bold" => true]]],
|
'styles' => ["A1:P1" => ["font" => ["bold" => true]]],
|
||||||
'data' => [],
|
'data' => [],
|
||||||
];
|
];
|
||||||
$title = (count($sheets) + 1) . "." . ($data['nickname'] ?: $ownerid);
|
$title = (count($sheets) + 1) . "." . ($data['nickname'] ?: $ownerid);
|
||||||
$sheets[] = BillExport::create()->setTitle($title)->setHeadings($headings)->setData($data['data'])->setStyles($data['styles']);
|
$sheets[] = BillExport::create()->setTitle($title)->setHeadings($headings)->setData($data['data'])->setStyles($data['styles']);
|
||||||
}
|
}
|
||||||
@ -1369,14 +1369,14 @@ class ProjectController extends AbstractController
|
|||||||
$text .= "\n\n";
|
$text .= "\n\n";
|
||||||
$text .= "文件名:{$fileName}";
|
$text .= "文件名:{$fileName}";
|
||||||
$text .= "\n";
|
$text .= "\n";
|
||||||
$text .= "文件大小:".Base::twoFloat(filesize($zipPath) / 1024, true)."KB";
|
$text .= "文件大小:" . Base::twoFloat(filesize($zipPath) / 1024, true) . "KB";
|
||||||
$text .= "\n";
|
$text .= "\n";
|
||||||
$text .= '<button class="ivu-btn" style="margin-top: 10px;"><a href="'.$fileUrl.'" target="_blank">立即下载</a></button>';
|
$text .= '<a href="' . $fileUrl . '" target="_blank"><button type="button" class="ivu-btn ivu-btn-warning" style="margin-top: 10px;"><span>立即下载</span></button></a>';
|
||||||
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $text], $botUser->userid, false, false, true);
|
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $text], $botUser->userid, false, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return Base::retSuccess('success',['msg' => '正在打包,请留意系统消息']);
|
return Base::retSuccess('success', ['msg' => '正在打包,请留意系统消息。']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
"ext-libxml": "*",
|
"ext-libxml": "*",
|
||||||
"ext-openssl": "*",
|
"ext-openssl": "*",
|
||||||
"ext-simplexml": "*",
|
"ext-simplexml": "*",
|
||||||
|
"ext-zip": "*",
|
||||||
"directorytree/ldaprecord-laravel": "^2.7",
|
"directorytree/ldaprecord-laravel": "^2.7",
|
||||||
"fideloper/proxy": "^4.4.1",
|
"fideloper/proxy": "^4.4.1",
|
||||||
"firebase/php-jwt": "^6.9",
|
"firebase/php-jwt": "^6.9",
|
||||||
|
|||||||
@ -1491,7 +1491,7 @@ APP推送
|
|||||||
LDAP
|
LDAP
|
||||||
License Key
|
License Key
|
||||||
你确定要打包下载【(*)】文件夹吗?
|
你确定要打包下载【(*)】文件夹吗?
|
||||||
正在打包,请留意系统消息
|
正在打包,请留意系统消息。
|
||||||
发起,参与接龙目前共(*)人
|
发起,参与接龙目前共(*)人
|
||||||
|
|
||||||
选择会员
|
选择会员
|
||||||
@ -1500,3 +1500,5 @@ License Key
|
|||||||
置顶人员
|
置顶人员
|
||||||
置顶了
|
置顶了
|
||||||
你确定取消置顶吗?
|
你确定取消置顶吗?
|
||||||
|
|
||||||
|
打包下载(*)
|
||||||
|
|||||||
@ -19392,17 +19392,6 @@
|
|||||||
"fr": "Êtes-vous sûr de vouloir emballer le dossier download [Bigw]?",
|
"fr": "Êtes-vous sûr de vouloir emballer le dossier download [Bigw]?",
|
||||||
"id": "Kau yakin ingin berkemas untuk download?"
|
"id": "Kau yakin ingin berkemas untuk download?"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"key": "正在打包,请留意系统消息",
|
|
||||||
"zh": "",
|
|
||||||
"zh-CHT": "正在打包,請留意系統消息",
|
|
||||||
"en": "Packing, please pay attention to the system message",
|
|
||||||
"ko": "압축하고 있습니다. 시스템 메시지를 확인하십시오",
|
|
||||||
"ja": "パッケージ化中ですので、システムメッセージにご注意ください。",
|
|
||||||
"de": "Bereits am packen, geben sie eine nachricht nach system ab",
|
|
||||||
"fr": "Emballage en cours, gardez un oeil sur les messages du système",
|
|
||||||
"id": "Paket sedang dikemas"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "创建一个全新的会议视频会议,与会者可以在实时中进行面对面的视听交流。",
|
"key": "创建一个全新的会议视频会议,与会者可以在实时中进行面对面的视听交流。",
|
||||||
"zh": "",
|
"zh": "",
|
||||||
@ -19513,4 +19502,4 @@
|
|||||||
"fr": "Êtes-vous sûr de supprimer le plafond?",
|
"fr": "Êtes-vous sûr de supprimer le plafond?",
|
||||||
"id": "Kau yakin mau membatalkan toplesnya?"
|
"id": "Kau yakin mau membatalkan toplesnya?"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -102,7 +102,7 @@ export default {
|
|||||||
data: this.formData,
|
data: this.formData,
|
||||||
}).then(({data}) => {
|
}).then(({data}) => {
|
||||||
this.show = false;
|
this.show = false;
|
||||||
$A.messageSuccess(data.msg);
|
$A.modalSuccess(data.msg);
|
||||||
}).catch(({msg}) => {
|
}).catch(({msg}) => {
|
||||||
$A.modalError(msg);
|
$A.modalError(msg);
|
||||||
}).finally(_ => {
|
}).finally(_ => {
|
||||||
|
|||||||
@ -254,7 +254,7 @@
|
|||||||
<li v-for="(item, index) in packList" :key="index" v-if="index < 100">
|
<li v-for="(item, index) in packList" :key="index" v-if="index < 100">
|
||||||
<AutoTip class="file-name">
|
<AutoTip class="file-name">
|
||||||
<span v-if="item.status !== 'finished'">{{item.name}}</span>
|
<span v-if="item.status !== 'finished'">{{item.name}}</span>
|
||||||
<a v-else href="javascript:void(0)" @click="downloadPackFile(item.name)">{{item.name}}</a>
|
<a v-else :href="item.url" target="_blank">{{item.name}}</a>
|
||||||
</AutoTip>
|
</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="packPercentageParse(item.percentage)" :stroke-width="5" />
|
<Progress v-else :percent="packPercentageParse(item.percentage)" :stroke-width="5" />
|
||||||
@ -1468,40 +1468,30 @@ export default {
|
|||||||
this.packShow = false;
|
this.packShow = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
async startPack(filePackName) {
|
async startPack(data) {
|
||||||
const file = { name: filePackName, status: 'packing', percentage: 0 };
|
this.packList.push(Object.assign(data, {
|
||||||
this.packList.push(file);
|
status: 'packing',
|
||||||
|
percentage: 0
|
||||||
|
}));
|
||||||
this.uploadShow = false; // 隐藏上传列表
|
this.uploadShow = false; // 隐藏上传列表
|
||||||
this.packShow = true; // 显示打包列表
|
this.packShow = true; // 显示打包列表
|
||||||
},
|
},
|
||||||
|
|
||||||
updatePackProgress () {
|
updatePackProgress() {
|
||||||
this.packList.forEach(file=>{
|
this.packList.forEach(file => {
|
||||||
const pack = this.filePackLists.find(({name}) => name == file.name)
|
const pack = this.filePackLists.find(({name}) => name == file.name)
|
||||||
if(pack){
|
if (pack) {
|
||||||
|
if (typeof file.percentage === "number" && file.percentage >= 100) {
|
||||||
|
return
|
||||||
|
}
|
||||||
file.percentage = Math.max(1, pack.progress);
|
file.percentage = Math.max(1, pack.progress);
|
||||||
if (file.status != 'finished' && file.percentage >= 100) {
|
if (file.percentage >= 100) {
|
||||||
file.status = 'finished';
|
file.status = 'finished';
|
||||||
this.downloadPackFile(file.name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
downloadPackFile(filePackName) {
|
|
||||||
const downloadUrl = $A.apiUrl(`file/download/confirm?name=${filePackName}&token=${this.userToken}`);
|
|
||||||
if (!$A.Electron && !$A.isEEUiApp) {
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.setAttribute('href', downloadUrl);
|
|
||||||
link.setAttribute('download', `${filePackName}`);
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
document.body.removeChild(link);
|
|
||||||
}else{
|
|
||||||
this.$store.dispatch('downUrl', downloadUrl)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
downloadZipFile(ids){
|
downloadZipFile(ids){
|
||||||
if (ids.length === 0) {
|
if (ids.length === 0) {
|
||||||
return
|
return
|
||||||
@ -1510,26 +1500,25 @@ export default {
|
|||||||
const allFolder = !ids.some(id => this.fileLists.some(({ type, id: itemId }) => type !== 'folder' && itemId === id));
|
const allFolder = !ids.some(id => this.fileLists.some(({ type, id: itemId }) => type !== 'folder' && itemId === id));
|
||||||
const typeName = allFolder ? "文件夹" : "文件";
|
const typeName = allFolder ? "文件夹" : "文件";
|
||||||
const fileName = ids.length === 1 ? `【${firstFile.name}】${typeName}` : `【${firstFile.name}】等${ids.length}个${typeName}`;
|
const fileName = ids.length === 1 ? `【${firstFile.name}】${typeName}` : `【${firstFile.name}】等${ids.length}个${typeName}`;
|
||||||
const filePackName = `file_${$A.formatDate("YmdHis")}.zip`;
|
|
||||||
|
|
||||||
$A.modalConfirm({
|
$A.modalConfirm({
|
||||||
title: '打包下载',
|
title: '打包下载',
|
||||||
content: `你确定要打包下载${fileName}吗?`,
|
content: `你确定要打包下载${fileName}吗?`,
|
||||||
okText: '确定',
|
okText: '确定',
|
||||||
onOk: async () => {
|
onOk: () => {
|
||||||
if( this.packList.find(({ status }) => status === 'packing') ){
|
if (this.packList.find(({status}) => status === 'packing')) {
|
||||||
$A.messageWarning("请等待打包完成");
|
$A.messageWarning("请等待打包完成");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
const name = this.$L(`打包下载${fileName}`)
|
||||||
await this.$store.dispatch("call", {
|
this.$store.dispatch("call", {
|
||||||
url: 'file/download/pack',
|
url: 'file/download/pack',
|
||||||
data: { ids, name: filePackName },
|
data: {ids, name},
|
||||||
});
|
}).then(({data}) => {
|
||||||
this.startPack(filePackName);
|
this.startPack(data);
|
||||||
} catch ({ msg }) {
|
}).catch(({msg}) => {
|
||||||
$A.modalError(msg);
|
$A.modalError(msg);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user