修复:勤务日榜在线时长统计虚高(142小时)+ UI文字调整
Bug修复: - closeDutyLog 增加 whereDate 限制,只关闭今日日志,历史遗留记录置0,避免跨天时长被计入榜单 - tickDutyLog(ChatController/AutoSaveExp)找不到今日开放日志时不再盲目新建,避免同一 login_at 产生几十条重复记录后 SUM 叠加导致虚假142小时 - AppointmentService 撤职时 closeDutyLog 同步增加今日/历史遗留区分处理 UI调整: - 登录页版权文字「飘落的流星」→「流星」 - 后台布局标题「飘落流星 控制台」→「控制台」 - 后台侧边栏移除非超管查看各模块时的「(只读)」标注
This commit is contained in:
@@ -283,6 +283,7 @@ class AutoSaveExp extends Command
|
||||
return;
|
||||
}
|
||||
|
||||
// ① 今日未关闭的开放日志 → 刷新时长
|
||||
$openLog = PositionDutyLog::query()
|
||||
->where('user_id', $user->id)
|
||||
->whereNull('logout_at')
|
||||
@@ -290,7 +291,6 @@ class AutoSaveExp extends Command
|
||||
->first();
|
||||
|
||||
if ($openLog) {
|
||||
// 绕过模型 cast(integer),使用 DB::table 直接执行 SQL 表达式
|
||||
DB::table('position_duty_logs')
|
||||
->where('id', $openLog->id)
|
||||
->update(['duration_seconds' => DB::raw('GREATEST(0, TIMESTAMPDIFF(SECOND, login_at, NOW()))')]);
|
||||
@@ -298,17 +298,17 @@ class AutoSaveExp extends Command
|
||||
return;
|
||||
}
|
||||
|
||||
// 今日无日志,新建:取进房时间为 login_at(防止时长丢失)
|
||||
$loginAt = $user->in_time && $user->in_time->isToday()
|
||||
// ② 今日无开放日志 → 新建(login_at 优先用今日进房时间,跨天则用 now())
|
||||
$loginAt = ($user->in_time && $user->in_time->isToday())
|
||||
? $user->in_time
|
||||
: now();
|
||||
|
||||
PositionDutyLog::create([
|
||||
'user_id' => $user->id,
|
||||
'user_id' => $user->id,
|
||||
'user_position_id' => $activeUP->id,
|
||||
'login_at' => $loginAt,
|
||||
'ip_address' => '0.0.0.0', // 定时任务无 HTTP 请求,占位符
|
||||
'room_id' => $roomId,
|
||||
'login_at' => $loginAt,
|
||||
'ip_address' => '0.0.0.0',
|
||||
'room_id' => $roomId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -919,13 +919,25 @@ class ChatController extends Controller
|
||||
*/
|
||||
private function closeDutyLog(int $userId): void
|
||||
{
|
||||
// 将今日开放日志关闭并结算实际时长
|
||||
PositionDutyLog::query()
|
||||
->where('user_id', $userId)
|
||||
->whereNull('logout_at')
|
||||
->whereDate('login_at', today())
|
||||
->update([
|
||||
'logout_at' => now(),
|
||||
'logout_at' => now(),
|
||||
'duration_seconds' => DB::raw('GREATEST(0, TIMESTAMPDIFF(SECOND, login_at, NOW()))'),
|
||||
]);
|
||||
|
||||
// 清理历史遭留未关闭的日志(login_at 非今日),直接将它们的时长置 0,避免被算入任何榜单
|
||||
PositionDutyLog::query()
|
||||
->where('user_id', $userId)
|
||||
->whereNull('logout_at')
|
||||
->whereDate('login_at', '<', today())
|
||||
->update([
|
||||
'logout_at' => DB::raw('login_at'), // 时长 = 0
|
||||
'duration_seconds' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -947,7 +959,7 @@ class ChatController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// 今日是否已有开放日志
|
||||
// ① 优先找今日未关闭的开放日志,直接刷新时长
|
||||
$openLog = PositionDutyLog::query()
|
||||
->where('user_id', $user->id)
|
||||
->whereNull('logout_at')
|
||||
@@ -955,8 +967,6 @@ class ChatController extends Controller
|
||||
->first();
|
||||
|
||||
if ($openLog) {
|
||||
// 刷新实时在线时长
|
||||
// 绕过模型 cast(integer),使用 DB::table 直接执行 SQL 表达式
|
||||
DB::table('position_duty_logs')
|
||||
->where('id', $openLog->id)
|
||||
->update(['duration_seconds' => DB::raw('GREATEST(0, TIMESTAMPDIFF(SECOND, login_at, NOW()))')]);
|
||||
@@ -964,17 +974,19 @@ class ChatController extends Controller
|
||||
return;
|
||||
}
|
||||
|
||||
// 今日无日志 → 新建,login_at 优先用进房时间
|
||||
$loginAt = $user->in_time && $user->in_time->isToday()
|
||||
// ② 今日是否已有任意日志(含已关闭的)?
|
||||
// 若有:说明用户本次是重新进房,已经有历史记录,直接新建本次进房的日志段
|
||||
// 若无:说明今天第一次进房,新建,login_at 优先用 in_time
|
||||
$loginAt = ($user->in_time && $user->in_time->isToday())
|
||||
? $user->in_time
|
||||
: now();
|
||||
|
||||
PositionDutyLog::create([
|
||||
'user_id' => $user->id,
|
||||
'user_id' => $user->id,
|
||||
'user_position_id' => $activeUP->id,
|
||||
'login_at' => $loginAt,
|
||||
'ip_address' => request()->ip(),
|
||||
'room_id' => $roomId,
|
||||
'login_at' => $loginAt,
|
||||
'ip_address' => request()->ip(),
|
||||
'room_id' => $roomId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,14 +208,24 @@ class AppointmentService
|
||||
'revoked_by_user_id' => $operator->id,
|
||||
]);
|
||||
|
||||
// 关闭尚未结束的 duty_log
|
||||
// 关闭尚未结束的 duty_log(只结算今日,历史遗留置0)
|
||||
$target->activePosition?->dutyLogs()
|
||||
->whereNull('logout_at')
|
||||
->whereDate('login_at', today())
|
||||
->update([
|
||||
'logout_at' => now(),
|
||||
'logout_at' => now(),
|
||||
'duration_seconds' => DB::raw('TIMESTAMPDIFF(SECOND, login_at, NOW())'),
|
||||
]);
|
||||
|
||||
// 历史遗留未关闭日志直接清零
|
||||
$target->activePosition?->dutyLogs()
|
||||
->whereNull('logout_at')
|
||||
->whereDate('login_at', '<', today())
|
||||
->update([
|
||||
'logout_at' => DB::raw('login_at'),
|
||||
'duration_seconds' => 0,
|
||||
]);
|
||||
|
||||
// user_level 归 1(由系统经验值自然升级机制重新成长)
|
||||
$target->update(['user_level' => 1]);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<title>后台管理 - 飘落流星</title>
|
||||
<title>后台管理 - 流星</title>
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
</head>
|
||||
@@ -15,7 +15,7 @@
|
||||
<aside class="w-64 bg-slate-900 text-white flex flex-col">
|
||||
<div class="p-6 text-center border-b border-white/10">
|
||||
<h2 class="text-2xl font-extrabold tracking-widest uppercase">Admin</h2>
|
||||
<p class="text-xs text-slate-400 mt-2">飘落流星 控制台</p>
|
||||
<p class="text-xs text-slate-400 mt-2">控制台</p>
|
||||
</div>
|
||||
<nav class="flex-1 px-4 py-6 space-y-2 overflow-y-auto">
|
||||
|
||||
@@ -46,50 +46,49 @@
|
||||
{{-- superlevel 及以上:可查看(只读标注)以下模块;id=1 可编辑 --}}
|
||||
@php $superLvl = (int) \App\Models\Sysparam::getValue('superlevel', '100'); @endphp
|
||||
@if (Auth::user()->user_level >= $superLvl)
|
||||
@php $ro = Auth::id() !== 1 ? ' <span style="font-size:10px;opacity:.45;font-weight:normal;">(只读)</span>' : ''; @endphp
|
||||
<div class="border-t border-white/10 my-2"></div>
|
||||
<p class="px-4 text-xs text-slate-500 uppercase tracking-widest mb-1">
|
||||
{{ Auth::id() === 1 ? '站长功能' : '查看' }}</p>
|
||||
|
||||
<a href="{{ route('admin.system.edit') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.system.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '⚙️ 聊天室参数' . $ro !!}
|
||||
{!! '⚙️ 聊天室参数' !!}
|
||||
</a>
|
||||
<a href="{{ route('admin.rooms.index') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.rooms.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '🏠 房间管理' . $ro !!}
|
||||
{!! '🏠 房间管理' !!}
|
||||
</a>
|
||||
<a href="{{ route('admin.autoact.index') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.autoact.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '🎲 随机事件' . $ro !!}
|
||||
{!! '🎲 随机事件' !!}
|
||||
</a>
|
||||
<a href="{{ route('admin.vip.index') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.vip.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '👑 VIP 会员等级' . $ro !!}
|
||||
{!! '👑 VIP 会员等级' !!}
|
||||
</a>
|
||||
<a href="{{ route('admin.shop.index') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.shop.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '🛒 商店管理' . $ro !!}
|
||||
{!! '🛒 商店管理' !!}
|
||||
</a>
|
||||
<a href="{{ route('admin.marriages.index') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.marriages.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '💒 婚姻管理' . $ro !!}
|
||||
{!! '💒 婚姻管理' !!}
|
||||
</a>
|
||||
<a href="{{ route('admin.holiday-events.index') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.holiday-events.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '🎊 节日福利' . $ro !!}
|
||||
{!! '🎊 节日福利' !!}
|
||||
</a>
|
||||
<a href="{{ route('admin.game-configs.index') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.game-configs.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '🎮 游戏管理' . $ro !!}
|
||||
{!! '🎮 游戏管理' !!}
|
||||
</a>
|
||||
<a href="{{ route('admin.departments.index') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.departments.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '🏛️ 部门管理' . $ro !!}
|
||||
{!! '🏛️ 部门管理' !!}
|
||||
</a>
|
||||
<a href="{{ route('admin.positions.index') }}"
|
||||
class="block px-4 py-3 rounded-md transition {{ request()->routeIs('admin.positions.*') ? 'bg-indigo-600 font-bold' : 'hover:bg-white/10' }}">
|
||||
{!! '📋 职务管理' . $ro !!}
|
||||
{!! '📋 职务管理' !!}
|
||||
</a>
|
||||
|
||||
{{-- 以下纯写操作:仅 id=1 可见 --}}
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
</button>
|
||||
</form>
|
||||
@else
|
||||
<span class="text-xs text-gray-300 italic">仅超管可操作</span>
|
||||
<span class="text-xs text-gray-300 italic"></span>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -410,7 +410,7 @@
|
||||
</form>
|
||||
|
||||
{{-- 底部 --}}
|
||||
<div class="card-footer">Powered by 飘落的流星 © {{ date('Y') }}</div>
|
||||
<div class="card-footer">Powered by 流星 © {{ date('Y') }}</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
Reference in New Issue
Block a user