mirror of
https://github.com/lkddi/Xboard.git
synced 2026-04-14 11:20:53 +08:00
feat: improve traffic reset precision and admin features
- Increase traffic reset granularity to seconds - Add next reset time display in admin pane
This commit is contained in:
@@ -82,7 +82,8 @@ class TrafficResetService
|
||||
if (
|
||||
!$user->plan
|
||||
|| $user->plan->reset_traffic_method === Plan::RESET_TRAFFIC_NEVER
|
||||
|| ($user->plan->reset_traffic_method === Plan::RESET_TRAFFIC_FOLLOW_SYSTEM && (int) admin_setting('reset_traffic_method', Plan::RESET_TRAFFIC_MONTHLY) === Plan::RESET_TRAFFIC_NEVER)
|
||||
|| ($user->plan->reset_traffic_method === Plan::RESET_TRAFFIC_FOLLOW_SYSTEM
|
||||
&& (int) admin_setting('reset_traffic_method', Plan::RESET_TRAFFIC_MONTHLY) === Plan::RESET_TRAFFIC_NEVER)
|
||||
|| $user->expired_at === NULL
|
||||
) {
|
||||
return null;
|
||||
@@ -94,7 +95,7 @@ class TrafficResetService
|
||||
$resetMethod = (int) admin_setting('reset_traffic_method', Plan::RESET_TRAFFIC_MONTHLY);
|
||||
}
|
||||
|
||||
$now = Carbon::now();
|
||||
$now = Carbon::now(config('app.timezone'));
|
||||
|
||||
return match ($resetMethod) {
|
||||
Plan::RESET_TRAFFIC_FIRST_DAY_MONTH => $this->getNextMonthFirstDay($now),
|
||||
@@ -124,38 +125,20 @@ class TrafficResetService
|
||||
*/
|
||||
private function getNextMonthlyReset(User $user, Carbon $from): Carbon
|
||||
{
|
||||
$expiredAt = Carbon::createFromTimestamp($user->expired_at);
|
||||
$expiredAt = Carbon::createFromTimestamp($user->expired_at, config('app.timezone'));
|
||||
$resetDay = $expiredAt->day;
|
||||
|
||||
return $this->getNextResetByDay($from, $resetDay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next reset time based on a specific day of the month.
|
||||
*/
|
||||
private function getNextResetByDay(Carbon $from, int $targetDay): Carbon
|
||||
{
|
||||
$currentMonthTarget = $this->getValidDayInMonth($from->copy(), $targetDay);
|
||||
$resetTime = [$expiredAt->hour, $expiredAt->minute, $expiredAt->second];
|
||||
// 当前月目标时间
|
||||
$currentMonthTarget = $from->copy()->day($resetDay)
|
||||
->setTime(...$resetTime);
|
||||
if ($currentMonthTarget->timestamp > $from->timestamp) {
|
||||
return $currentMonthTarget;
|
||||
}
|
||||
|
||||
// 下月目标时间
|
||||
$nextMonth = $from->copy()->addMonth();
|
||||
return $this->getValidDayInMonth($nextMonth, $targetDay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a valid day in a given month, handling non-existent dates.
|
||||
*/
|
||||
private function getValidDayInMonth(Carbon $month, int $targetDay): Carbon
|
||||
{
|
||||
$lastDayOfMonth = $month->copy()->endOfMonth()->day;
|
||||
|
||||
if ($targetDay > $lastDayOfMonth) {
|
||||
return $month->endOfMonth()->startOfDay();
|
||||
}
|
||||
|
||||
return $month->day($targetDay)->startOfDay();
|
||||
$lastDayOfNextMonth = $nextMonth->copy()->endOfMonth()->day;
|
||||
$targetDay = min($resetDay, $lastDayOfNextMonth);
|
||||
return $nextMonth->copy()->day($targetDay)->setTime(...$resetTime);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,30 +160,21 @@ class TrafficResetService
|
||||
*/
|
||||
private function getNextYearlyReset(User $user, Carbon $from): Carbon
|
||||
{
|
||||
$expiredAt = Carbon::createFromTimestamp($user->expired_at);
|
||||
|
||||
$currentYearTarget = $this->getValidYearDate($from->copy(), $expiredAt);
|
||||
$expiredAt = Carbon::createFromTimestamp($user->expired_at, config('app.timezone'));
|
||||
$resetMonth = $expiredAt->month;
|
||||
$resetDay = $expiredAt->day;
|
||||
$resetTime = [$expiredAt->hour, $expiredAt->minute, $expiredAt->second];
|
||||
|
||||
$currentYearTarget = $from->copy()->month($resetMonth)->day($resetDay)->setTime(...$resetTime);
|
||||
if ($currentYearTarget->timestamp > $from->timestamp) {
|
||||
return $currentYearTarget;
|
||||
}
|
||||
|
||||
return $this->getValidYearDate($from->copy()->addYear(), $expiredAt);
|
||||
$nextYear = $from->copy()->addYear();
|
||||
$lastDayOfMonth = $nextYear->copy()->month($resetMonth)->endOfMonth()->day;
|
||||
$targetDay = min($resetDay, $lastDayOfMonth);
|
||||
return $nextYear->copy()->month($resetMonth)->day($targetDay)->setTime(...$resetTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a valid date in a given year, handling leap year cases for Feb 29th.
|
||||
*/
|
||||
private function getValidYearDate(Carbon $year, Carbon $expiredAt): Carbon
|
||||
{
|
||||
$target = $year->month($expiredAt->month)->day($expiredAt->day)->startOfDay();
|
||||
|
||||
if ($expiredAt->month === 2 && $expiredAt->day === 29 && !$target->isLeapYear()) {
|
||||
$target->day(28);
|
||||
}
|
||||
|
||||
return $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the traffic reset log.
|
||||
|
||||
12
public/assets/admin/assets/index.js
vendored
12
public/assets/admin/assets/index.js
vendored
File diff suppressed because one or more lines are too long
1
public/assets/admin/locales/en-US.js
vendored
1
public/assets/admin/locales/en-US.js
vendored
@@ -2310,6 +2310,7 @@ window.XBOARD_TRANSLATIONS['en-US'] = {
|
||||
"commission": "Commission",
|
||||
"register_time": "Register Time",
|
||||
"actions": "Actions",
|
||||
"next_reset_at": "Next Reset At",
|
||||
"device_limit": {
|
||||
"unlimited": "No device limit",
|
||||
"limited": "Maximum {{count}} devices allowed"
|
||||
|
||||
1
public/assets/admin/locales/zh-CN.js
vendored
1
public/assets/admin/locales/zh-CN.js
vendored
@@ -2383,6 +2383,7 @@ window.XBOARD_TRANSLATIONS['zh-CN'] = {
|
||||
"commission": "佣金",
|
||||
"register_time": "注册时间",
|
||||
"actions": "操作",
|
||||
"next_reset_at": "下次重置时间",
|
||||
"device_limit": {
|
||||
"unlimited": "无设备数限制",
|
||||
"limited": "最多可同时在线 {{count}} 台设备"
|
||||
|
||||
Reference in New Issue
Block a user