mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-13 12:02:51 +00:00
perf: 优化导出签到功能
This commit is contained in:
parent
1fd7f0314a
commit
a5b8609df1
@ -3,6 +3,8 @@
|
|||||||
namespace App\Http\Controllers\Api;
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
use App\Models\UserDevice;
|
use App\Models\UserDevice;
|
||||||
|
use App\Models\WebSocketDialog;
|
||||||
|
use App\Models\WebSocketDialogMsg;
|
||||||
use Request;
|
use Request;
|
||||||
use Session;
|
use Session;
|
||||||
use Response;
|
use Response;
|
||||||
@ -22,6 +24,7 @@ use App\Module\Apps;
|
|||||||
use App\Module\BillMultipleExport;
|
use App\Module\BillMultipleExport;
|
||||||
use LdapRecord\LdapRecordException;
|
use LdapRecord\LdapRecordException;
|
||||||
use Guanguans\Notify\Messages\EmailMessage;
|
use Guanguans\Notify\Messages\EmailMessage;
|
||||||
|
use Swoole\Coroutine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @apiDefine system
|
* @apiDefine system
|
||||||
@ -1264,7 +1267,7 @@ class SystemController extends AbstractController
|
|||||||
*/
|
*/
|
||||||
public function checkin__export()
|
public function checkin__export()
|
||||||
{
|
{
|
||||||
User::auth('admin');
|
$user = User::auth('admin');
|
||||||
//
|
//
|
||||||
$setting = Base::setting('checkinSetting');
|
$setting = Base::setting('checkinSetting');
|
||||||
if ($setting['open'] !== 'open') {
|
if ($setting['open'] !== 'open') {
|
||||||
@ -1294,126 +1297,179 @@ class SystemController extends AbstractController
|
|||||||
$secondStart = strtotime("2000-01-01 {$time[0]}") - strtotime("2000-01-01 00:00:00");
|
$secondStart = strtotime("2000-01-01 {$time[0]}") - strtotime("2000-01-01 00:00:00");
|
||||||
$secondEnd = strtotime("2000-01-01 {$time[1]}") - strtotime("2000-01-01 00:00:00");
|
$secondEnd = strtotime("2000-01-01 {$time[1]}") - strtotime("2000-01-01 00:00:00");
|
||||||
//
|
//
|
||||||
$headings = [];
|
$botUser = User::botGetOrCreate('system-msg');
|
||||||
$headings[] = Doo::translate('签到人');
|
if (empty($botUser)) {
|
||||||
$headings[] = Doo::translate('签到日期');
|
return Base::retError('系统机器人不存在');
|
||||||
$headings[] = Doo::translate('班次时间');
|
}
|
||||||
$headings[] = Doo::translate('首次签到时间');
|
$dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid);
|
||||||
$headings[] = Doo::translate('首次签到结果');
|
|
||||||
$headings[] = Doo::translate('最后签到时间');
|
|
||||||
$headings[] = Doo::translate('最后签到结果');
|
|
||||||
$headings[] = Doo::translate('参数数据');
|
|
||||||
//
|
//
|
||||||
$sheets = [];
|
go(function () use ($secondStart, $secondEnd, $time, $userid, $date, $user, $botUser, $dialog) {
|
||||||
$startD = Carbon::parse($date[0])->startOfDay();
|
Coroutine::sleep(1);
|
||||||
$endD = Carbon::parse($date[1])->endOfDay();
|
|
||||||
$users = User::whereIn('userid', $userid)->take(100)->get();
|
|
||||||
/** @var User $user */
|
|
||||||
foreach ($users as $user) {
|
|
||||||
$recordTimes = UserCheckinRecord::getTimes($user->userid, [$startD, $endD]);
|
|
||||||
//
|
//
|
||||||
$nickname = Base::filterEmoji($user->nickname);
|
$headings = [];
|
||||||
$styles = ["A1:H1" => ["font" => ["bold" => true]]];
|
$headings[] = Doo::translate('签到人');
|
||||||
$datas = [];
|
$headings[] = Doo::translate('签到日期');
|
||||||
$startT = $startD->timestamp;
|
$headings[] = Doo::translate('班次时间');
|
||||||
$endT = $endD->timestamp;
|
$headings[] = Doo::translate('首次签到时间');
|
||||||
$index = 1;
|
$headings[] = Doo::translate('首次签到结果');
|
||||||
while ($startT < $endT) {
|
$headings[] = Doo::translate('最后签到时间');
|
||||||
$index++;
|
$headings[] = Doo::translate('最后签到结果');
|
||||||
$sameDate = date("Y-m-d", $startT);
|
$headings[] = Doo::translate('参数数据');
|
||||||
$sameTimes = $recordTimes[$sameDate] ?? [];
|
//
|
||||||
$sameCollect = UserCheckinRecord::atCollect($sameDate, $sameTimes);
|
$content = [];
|
||||||
$firstBetween = [Carbon::createFromTimestamp($startT), Carbon::createFromTimestamp($startT + $secondEnd - 1)];
|
$content[] = [
|
||||||
$lastBetween = [Carbon::createFromTimestamp($startT + $secondStart + 1), Carbon::createFromTimestamp($startT + 86400)];
|
'content' => '导出签到数据已完成',
|
||||||
$firstRecord = $sameCollect?->whereBetween("datetime", $firstBetween)->first();
|
'style' => 'font-weight: bold;padding-bottom: 4px;',
|
||||||
$lastRecord = $sameCollect?->whereBetween("datetime", $lastBetween)->last();
|
];
|
||||||
$firstTimestamp = $firstRecord['timestamp'] ?: 0;
|
//
|
||||||
$lastTimestamp = $lastRecord['timestamp'] ?: 0;
|
$sheets = [];
|
||||||
if (Timer::time() < $startT + $secondStart) {
|
$startD = Carbon::parse($date[0])->startOfDay();
|
||||||
$firstResult = "-";
|
$endD = Carbon::parse($date[1])->endOfDay();
|
||||||
} else {
|
$users = User::whereIn('userid', $userid)->take(100)->get();
|
||||||
$firstResult = Doo::translate("正常");
|
/** @var User $user */
|
||||||
if (empty($firstTimestamp)) {
|
foreach ($users as $user) {
|
||||||
$firstResult = Doo::translate("缺卡");
|
$recordTimes = UserCheckinRecord::getTimes($user->userid, [$startD, $endD]);
|
||||||
$styles["E{$index}"] = ["font" => ["color" => ["rgb" => "ff0000"]]];
|
//
|
||||||
} elseif ($firstTimestamp > $startT + $secondStart) {
|
$nickname = Base::filterEmoji($user->nickname);
|
||||||
$firstResult = Doo::translate("迟到");
|
$styles = ["A1:H1" => ["font" => ["bold" => true]]];
|
||||||
$styles["E{$index}"] = ["font" => ["color" => ["rgb" => "436FF6"]]];
|
$datas = [];
|
||||||
|
$startT = $startD->timestamp;
|
||||||
|
$endT = $endD->timestamp;
|
||||||
|
$index = 1;
|
||||||
|
while ($startT < $endT) {
|
||||||
|
$index++;
|
||||||
|
$sameDate = date("Y-m-d", $startT);
|
||||||
|
$sameTimes = $recordTimes[$sameDate] ?? [];
|
||||||
|
$sameCollect = UserCheckinRecord::atCollect($sameDate, $sameTimes);
|
||||||
|
$firstBetween = [Carbon::createFromTimestamp($startT), Carbon::createFromTimestamp($startT + $secondEnd - 1)];
|
||||||
|
$lastBetween = [Carbon::createFromTimestamp($startT + $secondStart + 1), Carbon::createFromTimestamp($startT + 86400)];
|
||||||
|
$firstRecord = $sameCollect?->whereBetween("datetime", $firstBetween)->first();
|
||||||
|
$lastRecord = $sameCollect?->whereBetween("datetime", $lastBetween)->last();
|
||||||
|
$firstTimestamp = $firstRecord['timestamp'] ?: 0;
|
||||||
|
$lastTimestamp = $lastRecord['timestamp'] ?: 0;
|
||||||
|
if (Timer::time() < $startT + $secondStart) {
|
||||||
|
$firstResult = "-";
|
||||||
|
} else {
|
||||||
|
$firstResult = Doo::translate("正常");
|
||||||
|
if (empty($firstTimestamp)) {
|
||||||
|
$firstResult = Doo::translate("缺卡");
|
||||||
|
$styles["E{$index}"] = ["font" => ["color" => ["rgb" => "ff0000"]]];
|
||||||
|
} elseif ($firstTimestamp > $startT + $secondStart) {
|
||||||
|
$firstResult = Doo::translate("迟到");
|
||||||
|
$styles["E{$index}"] = ["font" => ["color" => ["rgb" => "436FF6"]]];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (Timer::time() < $startT + $secondEnd) {
|
||||||
if (Timer::time() < $startT + $secondEnd) {
|
$lastResult = "-";
|
||||||
$lastResult = "-";
|
$lastTimestamp = 0;
|
||||||
$lastTimestamp = 0;
|
} else {
|
||||||
} else {
|
$lastResult = Doo::translate("正常");
|
||||||
$lastResult = Doo::translate("正常");
|
if (empty($lastTimestamp) || $lastTimestamp === $firstTimestamp) {
|
||||||
if (empty($lastTimestamp) || $lastTimestamp === $firstTimestamp) {
|
$lastResult = Doo::translate("缺卡");
|
||||||
$lastResult = Doo::translate("缺卡");
|
$styles["G{$index}"] = ["font" => ["color" => ["rgb" => "ff0000"]]];
|
||||||
$styles["G{$index}"] = ["font" => ["color" => ["rgb" => "ff0000"]]];
|
} elseif ($lastTimestamp < $startT + $secondEnd) {
|
||||||
} elseif ($lastTimestamp < $startT + $secondEnd) {
|
$lastResult = Doo::translate("早退");
|
||||||
$lastResult = Doo::translate("早退");
|
$styles["G{$index}"] = ["font" => ["color" => ["rgb" => "436FF6"]]];
|
||||||
$styles["G{$index}"] = ["font" => ["color" => ["rgb" => "436FF6"]]];
|
}
|
||||||
}
|
}
|
||||||
|
$firstTimestamp = $firstTimestamp ? date("H:i", $firstTimestamp) : "-";
|
||||||
|
$lastTimestamp = $lastTimestamp ? date("H:i", $lastTimestamp) : "-";
|
||||||
|
$section = array_map(function($item) {
|
||||||
|
return $item[0] . "-" . ($item[1] ?: "None");
|
||||||
|
}, UserCheckinRecord::atSection($sameTimes));
|
||||||
|
$datas[] = [
|
||||||
|
"{$nickname} (ID: {$user->userid})",
|
||||||
|
$sameDate,
|
||||||
|
implode("-", $time),
|
||||||
|
$firstTimestamp,
|
||||||
|
$firstResult,
|
||||||
|
$lastTimestamp,
|
||||||
|
$lastResult,
|
||||||
|
implode(", ", $section),
|
||||||
|
];
|
||||||
|
$startT += 86400;
|
||||||
}
|
}
|
||||||
$firstTimestamp = $firstTimestamp ? date("H:i", $firstTimestamp) : "-";
|
$title = (count($sheets) + 1) . "." . ($nickname ?: $user->userid);
|
||||||
$lastTimestamp = $lastTimestamp ? date("H:i", $lastTimestamp) : "-";
|
$sheets[] = BillExport::create()->setTitle($title)->setHeadings($headings)->setData($datas)->setStyles($styles);
|
||||||
$section = array_map(function($item) {
|
|
||||||
return $item[0] . "-" . ($item[1] ?: "None");
|
|
||||||
}, UserCheckinRecord::atSection($sameTimes));
|
|
||||||
$datas[] = [
|
|
||||||
"{$nickname} (ID: {$user->userid})",
|
|
||||||
$sameDate,
|
|
||||||
implode("-", $time),
|
|
||||||
$firstTimestamp,
|
|
||||||
$firstResult,
|
|
||||||
$lastTimestamp,
|
|
||||||
$lastResult,
|
|
||||||
implode(", ", $section),
|
|
||||||
];
|
|
||||||
$startT += 86400;
|
|
||||||
}
|
}
|
||||||
$title = (count($sheets) + 1) . "." . ($nickname ?: $user->userid);
|
if (empty($sheets)) {
|
||||||
$sheets[] = BillExport::create()->setTitle($title)->setHeadings($headings)->setData($datas)->setStyles($styles);
|
$content[] = [
|
||||||
}
|
'content' => '没有任何数据',
|
||||||
if (empty($sheets)) {
|
'style' => 'color: #ff0000;',
|
||||||
return Base::retError('没有任何数据');
|
];
|
||||||
}
|
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'template', [
|
||||||
|
'type' => 'content',
|
||||||
|
'title' => $content[0]['content'],
|
||||||
|
'content' => $content,
|
||||||
|
], $botUser->userid, true, false, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
$fileName = $users[0]->nickname;
|
||||||
|
if (count($users) > 1) {
|
||||||
|
$fileName .= "等" . count($userid) . "位成员的签到记录";
|
||||||
|
} else {
|
||||||
|
$fileName .= '的签到记录';
|
||||||
|
}
|
||||||
|
$fileName = Doo::translate($fileName) . '_' . Timer::time() . '.xlsx';
|
||||||
|
$filePath = "temp/checkin/export/" . date("Ym", Timer::time());
|
||||||
|
$export = new BillMultipleExport($sheets);
|
||||||
|
$res = $export->store($filePath . "/" . $fileName);
|
||||||
|
if ($res != 1) {
|
||||||
|
$content[] = [
|
||||||
|
'content' => "导出失败,{$fileName}!",
|
||||||
|
'style' => 'color: #ff0000;',
|
||||||
|
];
|
||||||
|
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'template', [
|
||||||
|
'type' => 'content',
|
||||||
|
'title' => $content[0]['content'],
|
||||||
|
'content' => $content,
|
||||||
|
], $botUser->userid, true, false, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$xlsPath = storage_path("app/" . $filePath . "/" . $fileName);
|
||||||
|
$zipFile = "app/" . $filePath . "/" . Base::rightDelete($fileName, '.xlsx') . ".zip";
|
||||||
|
$zipPath = storage_path($zipFile);
|
||||||
|
if (file_exists($zipPath)) {
|
||||||
|
Base::deleteDirAndFile($zipPath, true);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Madzipper::make($zipPath)->add($xlsPath)->close();
|
||||||
|
} catch (\Throwable) {
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if (file_exists($zipPath)) {
|
||||||
|
$base64 = base64_encode(Base::array2string([
|
||||||
|
'file' => $zipFile,
|
||||||
|
]));
|
||||||
|
$fileUrl = Base::fillUrl('api/system/checkin/down?key=' . urlencode($base64));
|
||||||
|
Session::put('checkin::export:userid', $user->userid);
|
||||||
|
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'template', [
|
||||||
|
'type' => 'file_download',
|
||||||
|
'title' => '导出签到数据已完成',
|
||||||
|
'name' => $fileName,
|
||||||
|
'size' => filesize($zipPath),
|
||||||
|
'url' => $fileUrl,
|
||||||
|
], $botUser->userid, true, false, true);
|
||||||
|
} else {
|
||||||
|
$content[] = [
|
||||||
|
'content' => "打包失败,请稍后再试...",
|
||||||
|
'style' => 'color: #ff0000;',
|
||||||
|
];
|
||||||
|
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'template', [
|
||||||
|
'type' => 'content',
|
||||||
|
'title' => $content[0]['content'],
|
||||||
|
'content' => $content,
|
||||||
|
], $botUser->userid, true, false, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
//
|
//
|
||||||
$fileName = $users[0]->nickname;
|
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'template', [
|
||||||
if (count($users) > 1) {
|
'type' => 'content',
|
||||||
$fileName .= "等" . count($userid) . "位成员的签到记录";
|
'content' => '正在导出签到数据,请稍等...',
|
||||||
} else {
|
], $botUser->userid, true, false, true);
|
||||||
$fileName .= '的签到记录';
|
|
||||||
}
|
|
||||||
$fileName = Doo::translate($fileName) . '_' . Timer::time() . '.xlsx';
|
|
||||||
$filePath = "temp/checkin/export/" . date("Ym", Timer::time());
|
|
||||||
$export = new BillMultipleExport($sheets);
|
|
||||||
$res = $export->store($filePath . "/" . $fileName);
|
|
||||||
if ($res != 1) {
|
|
||||||
return Base::retError('导出失败,' . $fileName . '!');
|
|
||||||
}
|
|
||||||
$xlsPath = storage_path("app/" . $filePath . "/" . $fileName);
|
|
||||||
$zipFile = "app/" . $filePath . "/" . Base::rightDelete($fileName, '.xlsx') . ".zip";
|
|
||||||
$zipPath = storage_path($zipFile);
|
|
||||||
if (file_exists($zipPath)) {
|
|
||||||
Base::deleteDirAndFile($zipPath, true);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Madzipper::make($zipPath)->add($xlsPath)->close();
|
|
||||||
} catch (\Throwable) {
|
|
||||||
}
|
|
||||||
//
|
//
|
||||||
if (file_exists($zipPath)) {
|
return Base::retSuccess('success');
|
||||||
$base64 = base64_encode(Base::array2string([
|
|
||||||
'file' => $zipFile,
|
|
||||||
]));
|
|
||||||
Session::put('checkin::export:userid', $user->userid);
|
|
||||||
return Base::retSuccess('success', [
|
|
||||||
'size' => Base::twoFloat(filesize($zipPath) / 1024, true),
|
|
||||||
'url' => Base::fillUrl('api/system/checkin/down?key=' . urlencode($base64)),
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
return Base::retError('打包失败,请稍后再试...');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -92,6 +92,8 @@
|
|||||||
正在导出超期任务,请稍等...
|
正在导出超期任务,请稍等...
|
||||||
导出审批数据已完成
|
导出审批数据已完成
|
||||||
正在导出审批数据,请稍等...
|
正在导出审批数据,请稍等...
|
||||||
|
导出签到数据已完成
|
||||||
|
正在导出签到数据,请稍等...
|
||||||
任务列表不存在或已被删除
|
任务列表不存在或已被删除
|
||||||
主任务已完成无法添加子任务
|
主任务已完成无法添加子任务
|
||||||
子任务不支持此功能
|
子任务不支持此功能
|
||||||
|
|||||||
@ -1644,6 +1644,8 @@ Token
|
|||||||
正在导出超期任务,请稍等...
|
正在导出超期任务,请稍等...
|
||||||
导出审批数据已完成
|
导出审批数据已完成
|
||||||
正在导出审批数据,请稍等...
|
正在导出审批数据,请稍等...
|
||||||
|
导出签到数据已完成
|
||||||
|
正在导出签到数据,请稍等...
|
||||||
(*)查看了(*)的联系电话
|
(*)查看了(*)的联系电话
|
||||||
标记任务未完成
|
标记任务未完成
|
||||||
标记任务已完成
|
标记任务已完成
|
||||||
|
|||||||
@ -103,11 +103,9 @@ export default {
|
|||||||
this.$store.dispatch("call", {
|
this.$store.dispatch("call", {
|
||||||
url: 'system/checkin/export',
|
url: 'system/checkin/export',
|
||||||
data: this.formData,
|
data: this.formData,
|
||||||
}).then(({data}) => {
|
}).then(() => {
|
||||||
this.show = false;
|
this.show = false;
|
||||||
this.$store.dispatch('downUrl', {
|
$A.modalSuccess('正在打包,请留意系统消息。');
|
||||||
url: data.url
|
|
||||||
});
|
|
||||||
}).catch(({msg}) => {
|
}).catch(({msg}) => {
|
||||||
$A.modalError(msg);
|
$A.modalError(msg);
|
||||||
}).finally(_ => {
|
}).finally(_ => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user