feat(admin-frontend): 完成节点与礼品卡管理工作台

补齐节点管理真实新增、编辑与排序流程,接入权限组与路由组
维护页,并支持 11 种协议的动态配置表单

开放礼品卡管理入口,交付模板、兑换码、使用记录与统计四页签
工作台,接入 gift-card 相关后台接口

将知识库、权限组与路由管理从占位页升级为真实页面,并修复侧边栏
低高度裁切问题

修复仪表盘 24h 流量排行涨跌始终为 0 的问题,改为对比昨天整日统
计并补充单元测试
This commit is contained in:
yinjianm
2026-04-24 21:58:16 +08:00
parent f7cef30b9c
commit e393b11b61
80 changed files with 8811 additions and 278 deletions
@@ -502,6 +502,39 @@ class StatController extends Controller
];
}
/**
* Resolve the comparison window used by traffic rank change calculation.
*
* Daily traffic statistics are stored with `record_at` pinned to the start
* of the day. For the dashboard `24h` preset, comparing by "same span in
* seconds" would shift the previous window to `00:00:01`, which skips the
* whole yesterday row and makes change percentages fall back to `0`.
*
* To keep the requested minimal scope, only the single-day preset is
* aligned to the exact previous calendar day; longer ranges keep the
* existing equal-span comparison behavior.
*
* @param int $startDate
* @param int $endDate
* @return array{start: int, end: int}
*/
protected function resolveTrafficRankComparisonWindow(int $startDate, int $endDate): array
{
$currentWindowDays = (int) floor(max(0, $endDate - $startDate) / 86400) + 1;
if ($currentWindowDays === 1) {
return [
'start' => $startDate - 86400,
'end' => $startDate,
];
}
return [
'start' => $startDate - ($endDate - $startDate),
'end' => $startDate,
];
}
/**
* Get traffic ranking data for nodes or users
*
@@ -521,8 +554,9 @@ class StatController extends Controller
$startDate = $request->input('start_time', strtotime('-7 days'));
$endDate = $request->input('end_time', time());
$limit = (int) $request->input('limit', 10);
$previousStartDate = $startDate - ($endDate - $startDate);
$previousEndDate = $startDate;
$comparisonWindow = $this->resolveTrafficRankComparisonWindow($startDate, $endDate);
$previousStartDate = $comparisonWindow['start'];
$previousEndDate = $comparisonWindow['end'];
if ($type === 'node') {
// Get node traffic data