feat(ui): 总览/监控中心顶部统计卡片支持点击筛选

- 总览页「总资产」「本年支出」「异常状态」卡片点击跳转资产页并带上对应筛选
  (全部/付费资产TAB/异常状态组合筛选);「30天内到期」及「另有N项已过期」
  子文案点击跳转监控中心并带上到期区间子筛选
- 监控中心顶部统计卡片(30天/7天/已过期/有到期日)支持点击筛选下方列表,
  再点一次取消;SSL 证书卡片(正常/即将到期/已过期或失败)同理
- 资产页状态筛选新增「异常(已停止/已过期)」组合选项:后端 status 只认单值,
  该组合作为前端本地筛选哨兵值处理,不发给 API;切到专有视图 TAB 时自动清空
- 顺带修复监控中心统计卡片数字不随类别 TAB 变化的问题(原先 stats 未按 TAB
  过滤,与列表数据口径不一致)
This commit is contained in:
gouki
2026-09-20 12:53:48 +00:00
parent cbb32ea3b0
commit 7045843db8
4 changed files with 114 additions and 47 deletions
+27 -1
View File
@@ -39,6 +39,8 @@ const store = reactive({
filterProvider: '', // 按平台筛选(slug),从平台页「关联 N 个资产」跳转而来
assetTab: '', // 资产页 TAB:'' 全部 / vps / domain / cloudflare / subscription(付费资产) / ai_agent
monitorTab: '', // 监控中心 TAB:同上
monitorExpiryFilter: '', // 监控中心到期区间子筛选:'' 全部 / soon30 / soon7 / expired
monitorSslStatusFilter: '', // 监控中心 SSL 状态子筛选:'' 全部 / valid / expiring / expired_error
dark: localStorage.getItem('vps_dark') === '1',
loading: false,
error: '',
@@ -101,10 +103,13 @@ function buildAssetPayload(f) {
}
/* ---------------- 数据加载 ---------------- */
// 后端 status 参数只认单个 AssetStatus 枚举值;「异常」是「已停止 + 已过期」的组合概念,
// 后端不支持多值筛选,这里当作前端本地筛选的哨兵值,不发给 API,由视图层自己过滤。
const CLIENT_SIDE_STATUS_FILTERS = new Set(['abnormal']);
async function loadAssets() {
const params = new URLSearchParams();
if (store.filterType) params.set('asset_type', store.filterType);
if (store.filterStatus) params.set('status', store.filterStatus);
if (store.filterStatus && !CLIENT_SIDE_STATUS_FILTERS.has(store.filterStatus)) params.set('status', store.filterStatus);
if (store.filterProvider) params.set('provider', store.filterProvider);
if (store.search) params.set('q', store.search);
params.set('sort', 'expiry_date'); params.set('order', 'asc');
@@ -449,6 +454,27 @@ function clearProviderFilter() {
loadAssets();
}
/* ---------------- 总览页卡片跳转:带预设筛选条件切到资产页 ---------------- */
// 未显式传入的筛选项一律重置,避免带着上一页的旧筛选条件跳过去后数字对不上
function openAssetsWithFilter({ assetTab = '', filterStatus = '', filterType = '', filterProvider = '', search = '' } = {}) {
store.assetTab = assetTab;
store.filterStatus = filterStatus;
store.filterType = filterType;
store.filterProvider = filterProvider;
store.search = search;
if (window.location.hash !== '#assets') window.location.hash = '#assets';
else store.view = 'assets';
loadAssets();
}
/* ---------------- 总览页卡片跳转:带预设到期区间筛选切到监控中心 ---------------- */
function openMonitorWithExpiryFilter(filter) {
store.monitorTab = '';
store.monitorExpiryFilter = filter || '';
if (window.location.hash !== '#monitor') window.location.hash = '#monitor';
else store.view = 'monitor';
}
/* ---------------- 服务器监控 ---------------- */
async function viewServer(a) {
try {