feat(scripts): 异步执行、全局进度看板与完成提示音设置

脚本 exec 立即返回 running 并在后台跑批次;/ws/alerts 推送 script_progress/complete;
新增 ScriptRunsPage、Telegram 汇总通知与可配置的浏览器完成提示音。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Nexus Agent
2026-06-08 07:07:02 +08:00
parent 3f995a74bb
commit 0b2d7ac50d
975 changed files with 18030 additions and 230 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
## 栈
FastAPI + Async SQLAlchemy + Redis · Vue 3 + Vuetify 4 SPA14 页)· Vite → `web/app/`
FastAPI + Async SQLAlchemy + Redis · Vue 3 + Vuetify 4 SPA15 页)· Vite → `web/app/`
## 环境(勿在仓库写密码)
+1 -1
View File
@@ -6,7 +6,7 @@
## 项目概要
Nexus2000+ 子机运维平台。后端 FastAPI + MySQL + Redis;前端 **Vue 3 + Vuetify 4 + TypeScript SPA**14 页,`frontend/src/pages/`);构建输出 `web/app/`;安装向导 `web/app/install.html`
Nexus2000+ 子机运维平台。后端 FastAPI + MySQL + Redis;前端 **Vue 3 + Vuetify 4 + TypeScript SPA**15 页,`frontend/src/pages/`);构建输出 `web/app/`;安装向导 `web/app/install.html`
## 本地开发
@@ -0,0 +1,38 @@
# 审计 — 脚本执行全局进度与看板(2026-06-08)
## 范围
异步脚本执行、WebSocket 进度、Telegram 汇总、ScriptRunsPage、App 全局 UI。
## 安全
| 项 | 结论 |
|----|------|
| 后台任务 DB 会话 | 独立 `AsyncSessionLocal`,请求结束不泄漏 |
| WS 鉴权 | 复用 `/ws/alerts` JWT,无新公开端点 |
| Telegram | 无失败明细、无命令输出;链接为公开 SPA hash 路由(需登录) |
| CUD 审计 | `execute_started` / `execute_command` 仍在 service 层写入 |
## 可靠性
| 项 | 结论 |
|----|------|
| 后台异常 | `_mark_execution_catastrophic_failure` → status=failed + 通知 |
| 长任务回调 | `script_job_callback` 终态触发 `script_complete` |
| WS 断线 | 前端 3s 轮询降级 |
| 任务引用 | `_BG_EXEC_TASKS` 防止 task 被 GC |
## 架构
- 通知编排独立于 `script_execution_store`,避免 store → websocket 循环依赖
- 进度分子仍为 `success/total`(失败不计入 success);`done/remaining` 供文案
## 测试证据
- `tests/test_script_execution_progress_stats.py`3 条)
- 构建:`cd frontend && npm run build`
## 残留风险(可接受)
- 调度器 `schedule_runner` 触发脚本执行时同样走后台任务,不阻塞 60s tick(预期行为)
- 多 worker 下 WS 经 Redis pub/sub 广播(与告警一致)
@@ -0,0 +1,35 @@
# 2026-06-08 — 脚本执行完成提示音可配置
## 摘要
将原先硬编码在 `App.vue` 的双音提示改为系统设置项,支持关闭/三种音色,并可试听。
## 动机
用户需在「设置」中控制脚本执行结束时的浏览器提示音,而非写死在代码里。
## 涉及文件
- `frontend/src/utils/scriptCompleteSound.ts` — 音色预设与播放
- `frontend/src/composables/useScriptCompleteSound.ts` — 与 MySQL 设置同步
- `frontend/src/App.vue` — 使用 composable
- `frontend/src/pages/SettingsPage.vue` — 「界面提示」卡片
- `server/api/settings.py``script_exec_complete_sound` 白名单与枚举校验
## 设置项
| Key | 可选值 | 默认 |
|-----|--------|------|
| `script_exec_complete_sound` | `off` / `beep_short` / `beep_double` / `chime_soft` | `beep_double`(未配置时) |
API`PUT /api/settings/script_exec_complete_sound` `{ "value": "beep_double" }`
## 迁移 / 重启
- 无需迁移;首次保存时写入 `settings`
- 仅前端热更新即可试听;后端需 reload 以识别新白名单键
## 验证
- 设置 → 界面提示 → 切换音色并「试听」
- 触发脚本执行完成,确认按所选音色播放或关闭
@@ -0,0 +1,54 @@
# 2026-06-08 — 脚本执行:全局进度 + 看板 + Telegram 汇总
## 摘要
脚本批量执行改为真后台(API 立即返回 `running`);扩展 `/ws/alerts` 推送 `script_progress` / `script_complete`;全局顶栏进度条与完成 Alert+提示音;新建「脚本看板」页;Telegram 仅发成功/失败汇总与看板深链。
## 动机
366 台同步执行阻塞 HTTP 请求;用户需跨页面查看进度;失败明细应在看板而非 Telegram 长列表。
## 涉及文件
### 后端
- `server/application/services/script_service.py``asyncio` 后台批次
- `server/application/services/script_execution_notify.py` — WS + Telegram 编排
- `server/application/services/script_job_callback.py` — 长任务终态通知
- `server/infrastructure/redis/script_execution_store.py``execution_progress_stats`
- `server/api/websocket.py``broadcast_script_progress/complete`
- `server/infrastructure/telegram/__init__.py``send_telegram_script_summary`
- `server/config.py` / `server/api/settings.py``NOTIFY_SCRIPT_COMPLETE`
### 前端
- `frontend/src/composables/useScriptExecutionQueue.ts`
- `frontend/src/composables/useWebSocket.ts`
- `frontend/src/App.vue` — 全局进度与完成 Alert
- `frontend/src/pages/ScriptRunsPage.vue` — 第 15 页
- `frontend/src/pages/ScriptsPage.vue` — 移除页内批量状态面板
- `frontend/src/router/index.ts` / `frontend/src/types/api.ts`
### 文档
- `docs/project/nexus-functional-development-guide.md` — 15 页 SSOT
- `docs/changelog/2026-06-08-script-exec-global-progress-board.md`
- `docs/audit/2026-06-08-script-exec-global-progress-board.md`
## 迁移 / 重启
- 无需 DB 迁移
- 需重启 API worker;前端 `vite build` 后部署 `web/app/`
- 可选:在设置中配置 `notify_script_complete`
## 验证
```bash
pytest tests/test_script_execution_progress_stats.py tests/test_exec_detail_grouping.py -q
cd frontend && npm run build
bash scripts/local_verify.sh
```
- 提交执行后 1s 内对话框关闭,顶栏显示「已进行 X 台,剩余 Y 台」
- 结束:提示音 + AlertTelegram 仅汇总 + `#/script-runs/{id}` 链接
- WS 断线:3s 轮询直至终态
@@ -0,0 +1,173 @@
# 实施计划 — 脚本库全局执行进度 + Telegram 通知
**日期**: 2026-06-08
**设计**: [2026-06-08-script-exec-global-progress-telegram-design.md](../specs/2026-06-08-script-exec-global-progress-telegram-design.md)
## 分期概览
| 阶段 | 内容 | 估时 | 依赖 |
|------|------|------|------|
| **P0** | 后端异步 exec + terminal hook | 1d | — |
| **P1** | WS `script_progress` / `script_complete` | 0.5d | P0 |
| **P2** | Telegram `send_telegram_script_complete` | 0.5d | P0 |
| **P3** | 前端全局 SnackbarQueue + Progress + Alert + 声音 | 1d | P1 |
| **P4** | ScriptsPage 接入 / 移除页内面板 | 0.5d | P3 |
| **P5** | 测试、changelog、audit、部署 | 0.5d | P0P4 |
**合计**:约 3–4 人日(单 Agent 连续实施)。
---
## P0 — 后端:异步执行(关键路径)
### 涉及文件
| 文件 | 变更 |
|------|------|
| [server/application/services/script_service.py](../../server/application/services/script_service.py) | `execute_command` 拆为 `start_execution` + `_run_execution_batches` |
| [server/api/scripts.py](../../server/api/scripts.py) | `/exec``/retry` 立即返回 running |
| [server/main.py](../../server/main.py) | 确保 task 异常日志 + 可选 task 注册防 shutdown 丢失 |
### 步骤
1. `execute_command` 创建 DB/Redis 记录后 `asyncio.create_task(_run_execution_batches(...))`
2. 将现有 batch 循环移入 `_run_execution_batches`,逻辑不变。
3. Task 顶层 `try/except`:异常时 `apply_update(status=failed, terminal=True)`
4. API 返回 `get_execution_detail(id)`status=running, progress=0/N)。
5. **注意**:同一 worker 内 task 即可;多 worker 时 Redis live 已是 SSOT(已满足)。
### 测试
- `tests/test_script_execution_async.py`mock dispatch,断言 POST /exec 立即返回 & 后台终态。
---
## P1 — WebSocket 进度广播
### 涉及文件
| 文件 | 变更 |
|------|------|
| [server/api/websocket.py](../../server/api/websocket.py) | `broadcast_script_progress` / `broadcast_script_complete` |
| [server/infrastructure/redis/script_execution_store.py](../../server/infrastructure/redis/script_execution_store.py) | `apply_update` 中调用 broadcast(或 script_service 批次回调) |
| [server/application/services/script_job_callback.py](../../server/application/services/script_job_callback.py) | long_task 单台 callback 时也 broadcast |
### 步骤
1. 定义消息 schema(见 design doc)。
2. 每批 `batch_progress` 或每台完成后推送(366 台建议**每完成 1 台或每批**推送,避免 WS 风暴可 batch 每 5 台)。
3. 前端 [useWebSocket.ts](../../frontend/src/composables/useWebSocket.ts) 解析 `script_progress` / `script_complete`
---
## P2 — Telegram 脚本执行结果
### 涉及文件
| 文件 | 变更 |
|------|------|
| [server/infrastructure/telegram/__init__.py](../../server/infrastructure/telegram/__init__.py) | `send_telegram_script_complete` |
| [server/config.py](../../server/config.py) | `NOTIFY_SCRIPT_COMPLETE` |
| [server/api/settings.py](../../server/api/settings.py) | 设置项读写(若 NOTIFY_* 走 settings 表) |
| terminal hook | 组装 failed 列表(server name + exit_code + stderr 首行) |
### 步骤
1. 复用 `send_telegram_sync_complete` 结构与 `_notify_enabled`
2. 失败明细:查 server repo 取 namesummary 用 `sanitize_external_message`
3. 超长分片或截断 + 指向 execution #id
4. 单测:mock httpx,断言 HTML 含失败台名。
---
## P3 — 前端全局 UIVuetify 4
### 涉及文件
| 文件 | 变更 |
|------|------|
| [frontend/src/App.vue](../../frontend/src/App.vue) | `VSnackbarQueue` 替换单条 `v-snackbar`;挂载 `ScriptExecProgressHost` |
| **新建** `frontend/src/components/script/ScriptExecProgressHost.vue` | Queue item 模板:ProgressLinear chunks + 文案 |
| **新建** `frontend/src/composables/useScriptExecutionQueue.ts` | track / onProgress / onComplete / playSound |
| **新建** `frontend/src/components/script/ScriptExecCompleteAlert.vue` | VAlert closable + 1s leave transition |
| `frontend/public/notify.mp3` 或 assets | 提示音(短、免版权) |
### UI 行为
1. **进行中**SnackbarQueue 顶部,`location="top"``timeout="-1"`(手动关闭或完成关闭)。
2. **进度条**`v-progress-linear` `rounded` `height="6"` `:model-value="done/total*100"` `:buffer-value="..."` 制造流动感(见 Vuetify chunks 示例)。
3. **完成**
- Snackbar queue 项 resolvePromise API)。
- 显示 `VAlert`type=success/warning/error),`closable`,点击关闭触发 `v-fade-transition` 1000ms。
- `new Audio(...).play().catch(() => {})`(静默处理自动播放策略拦截)。
4. Alert 可点「查看详情」→ `router.push('#/scripts')` + `openExecDetail(id)`(通过 event bus 或 query)。
### 与现有 `$snackbar` 兼容
- 保留 `window.$snackbar` 给普通 toast;脚本进度走独立 queue,避免互相覆盖。
---
## P4 — ScriptsPage 接入
### 涉及文件
| 文件 | 变更 |
|------|------|
| [frontend/src/pages/ScriptsPage.vue](../../frontend/src/pages/ScriptsPage.vue) | `submitExec``queue.track()`;删除/隐藏页内「批量执行状态」卡片 |
| [frontend/src/pages/SchedulesPage.vue](../../frontend/src/pages/SchedulesPage.vue) | 若 schedule 触发 exec,同样 track(可选 P4+ |
### 步骤
1. `doRun` / `doQuickExec`POST 成功后 `showRun=false`,调用 `queue.track(id, label, total)`
2. 移除 `trackedExecs` / `pollTimer` / `activeTrackedExecs`(逻辑迁至 composable)。
3. WS 断线时 composable 降级 3s 轮询直至终态。
---
## P5 — 验证与交付
```bash
pytest tests/test_script_execution_async.py tests/test_telegram_script.py -q
cd frontend && npx vite build
bash scripts/local_verify.sh
```
### 手动验收
1. 生产 10 台脚本:顶部进度 + 完成 Alert + 声音。
2. 366 台(或 staging):Telegram 汇总与失败明细。
3. 关闭 Telegram 通知设置后无推送。
### 文档
- `docs/changelog/2026-06-08-script-exec-global-progress-telegram.md`
- `docs/audit/2026-06-08-script-exec-global-progress-telegram.md`
- 更新 [AI-HANDOFF-2026-06-08.md](../../project/AI-HANDOFF-2026-06-08.md)
### 回滚
- 后端:revert commit;进行中的 execution 靠 Redis live 继续,无 schema 迁移。
- 前端:revert + vite build deploy。
---
## 风险与对策
| 风险 | 对策 |
|------|------|
| 366 台 WS 消息过多 | 节流:每批或每 5 台推送一次 |
| 浏览器拦截自动播放 | 首次用户手势后解锁;Alert 仍可见 |
| 异步 exec 重复提交 | 可选:同脚本 running 时 confirmP4+ |
| Telegram 过长 | 截断 + 链接 execution id |
| 多 Tab 重复声音 | `localStorage` leader election 或仅 focused tab 播放 |
---
## 建议实施顺序(给 Agent
```
P0 异步 API → P1 WS → P2 Telegram → P3 全局 UI → P4 ScriptsPage 接入 → P5 验证部署
```
**请先确认设计再写代码**perfect-implementation 纪律)。
@@ -0,0 +1,148 @@
# 设计说明 — 脚本库全局执行进度 + Telegram 结果通知
**日期**: 2026-06-08
**基线**: `main@3f995a7`
**参考 UI**: [VSnackbarQueue Promise](https://vuetifyjs.com/zh-Hans/components/snackbar-queue/#promise) · [VProgressLinear chunks](https://vuetifyjs.com/zh-Hans/components/progress-linear/#chunks) · [VAlert 可关闭](https://vuetifyjs.com/zh-Hans/components/alerts/#section-7c7b578b)
## 背景与目标
运维在脚本库对 300+ 台执行命令时,需要:
1. **点击执行后立即返回**,不阻塞对话框/页面,可在其他页面继续操作。
2. **全局顶部**展示执行进度(流动状进度条 +「已进行 3 台,剩余 363 台」)。
3. **执行结束**时:浏览器提醒 + 短促提示音;可点击关闭,**1 秒渐隐**
4. **Telegram** 推送汇总:成功 N / 失败 M;失败项含**服务器名称、退出码、原因摘要**(可多条)。
## 现状差距
| 能力 | 现状 | 缺口 |
|------|------|------|
| 后台执行 | `POST /api/scripts/exec` **同步 await** 全部批次(366 台可阻塞数十秒~数分钟) | 须改为「创建 execution → 立即返回 → 后台 dispatch」 |
| 进度 UI | ScriptsPage 底部「批量执行状态」+ 10s 轮询 | 须全局 Snackbar Queue + 细粒度进度 |
| 实时推送 | Push 有 `/ws/sync`;脚本**无** WS | 须新增 `script_progress` 广播或复用 alerts WS |
| Telegram | 仅有 `send_telegram_sync_complete` | 须新增 `send_telegram_script_complete` + 设置项 |
| 完成提醒 | 终态仅 `snackbar(warning)` | 须 Alert + 声音 + 渐隐动画 |
## 方案对比
### A. 后台执行 + WebSocket 进度(推荐)
```
POST /exec → 202 + execution_id
asyncio.create_task(run_batches)
↓ 每完成一台/一批
broadcast_script_progress → /ws/alerts 或 /ws/scripts
↓ 终态
send_telegram_script_complete + WS terminal event
```
**优点**:进度实时、与 Push 模式一致、Snackbar 可流畅更新。
**缺点**:需改后端执行模型 + WS 协议。
### B. 仅前端全局轮询
API 仍同步,或改为后台但前端 2s 轮询 `GET /executions/{id}`
**优点**:改动小。
**缺点**:366 台时 API 仍可能长时间不返回;轮询粗、流量大;不符合「先返回再执行」。
**选定 A**
## 接口与数据模型
### API 变更
| 端点 | 变更 |
|------|------|
| `POST /api/scripts/exec` | 创建 execution + `init_live` 后**立即返回** `{ id, status: "running", progress: "0/N" }`dispatch 在 `asyncio.create_task` |
| `POST /api/scripts/executions/{id}/retry` | 同上异步模式 |
| `GET /api/scripts/executions/{id}` | 不变(轮询兜底) |
**兼容**:长任务(`long_task`)逻辑保持;短任务也走同一异步路径。
### WebSocket 消息(扩展 `/ws/alerts` 或新建 `/ws/scripts`
推荐 **扩展 `/ws/alerts`**App 已连接),新增 type
```json
{
"type": "script_progress",
"execution_id": 6,
"label": "磁盘检查",
"status": "running",
"done": 3,
"success": 3,
"failed": 0,
"total": 366,
"remaining": 363
}
```
终态:
```json
{
"type": "script_complete",
"execution_id": 6,
"status": "partial",
"success": 363,
"failed": 3,
"total": 366,
"failed_preview": [
{ "server_id": 1, "name": "srv-a", "exit_code": 1, "summary": "Connection timed out" }
]
}
```
`done` = 已有终态结果的台数(含失败);`success` 沿用 `execution_progress_summary` 语义(失败不计入 success)。
### Telegram
新增 `send_telegram_script_complete()`,参照 `send_telegram_sync_complete`
- 设置项:`NOTIFY_SCRIPT_COMPLETE`(默认 `true`Settings 可关)
- 正文:脚本名/命令摘要、操作人、成功/失败/总计、耗时
- **失败明细**:每台一行 — `名称 · exit码 · 原因摘要`HTML escape + sanitize
- 超过 Telegram 4096 字符:首批 20 条 +「…及其他 N 台,详见 Nexus #/scripts 执行 #id
- 触发点:`script_execution_store.apply_update(..., terminal=True)` 或 dedicated `on_execution_terminal` hook
### 前端全局 UI
| 组件 | 用途 |
|------|------|
| `VSnackbarQueue` | 全局顶部(`location="top"`),每任务一条 queue item |
| `VProgressLinear` `buffer-value` + `indeterminate` 交替 | 「流动状」进度;`model-value = done/total*100` |
| `VAlert` closable + `@click:close` + CSS transition 1s | 完成提醒条(成功/部分失败/全失败配色) |
| `Audio` / `new Audio('/app/notify.mp3')` | 终态播放一次(用户可浏览器静音) |
**Snackbar 文案示例**(进行中):
> 磁盘检查 · 已进行 3 台,剩余 363 台
**Promise 模式**queue 项在 `script_complete` 时 resolve,切换为 Alert 或关闭 snackbar 并弹出 Alert。
**状态管理**:新建 `useScriptExecutionQueue`Pinia 或 composable singleton),ScriptsPage / SchedulesPage 提交后只调用 `queue.track(executionId, label, total)`**移除**页面内 `trackedExecs` 面板(或保留「详情」链接)。
## 安全与性能
- WS 消息仅 JWT 已连接管理员可见;不含完整 stderr(Telegram 同样截断)。
- 后台 task 须捕获异常写 execution `failed`,避免 silent hang。
- 366 台 Telegram 分条/截断,防 flood。
- 单 worker`create_task` 绑定 primary worker 约定(与现有 background tasks 一致)。
## 验收标准
- [ ] 选 366 台点执行 → **1s 内**关闭对话框,顶部出现进度 Snackbar。
- [ ] 切换至 Dashboard/其他页,进度条仍更新。
- [ ] 文案显示「已进行 X 台,剩余 Y 台」,X+Y=总数(进行中);Y 随完成递减。
- [ ] 全部结束:短促提示音 + 顶部 Alert「成功 363 台,失败 3 台」;点击后 **1s 渐隐**
- [ ] Telegram 收到汇总 + 3 台失败名称与原因。
- [ ] Settings 关闭 `NOTIFY_SCRIPT_COMPLETE` 时不发 Telegram。
- [ ] 长任务 / retry / 临时命令 行为一致。
## 非目标(本期不做)
- 多 execution 合并为一条 Telegram(每台 execution 一条)。
- 浏览器 Push Notification API(仅站内 Alert + 声音)。
- 修改 `success/total` 进度语义。
@@ -20,7 +20,7 @@
9. [后端 API 全览](#9-后端-api-全览)
10. [核心业务模块详解](#10-核心业务模块详解)
11. [前端 SPA 架构](#11-前端-spa-架构)
12. [14 个业务页面功能说明](#12-14-个业务页面功能说明)
12. [15 个业务页面功能说明](#12-15-个业务页面功能说明)
13. [Composables 与状态管理](#13-composables-与状态管理)
14. [WebSocket 与 WebSSH](#14-websocket-与-webssh)
15. [Agent 与子机协议](#15-agent-与子机协议)
@@ -511,7 +511,7 @@ main.ts → App.vue(侧栏/搜索)→ router-view
---
## 12. 14 个业务页面功能说明
## 12. 15 个业务页面功能说明
> 路由均位于 `#/` 下;除 Login 外需 JWT。
@@ -591,11 +591,21 @@ main.ts → App.vue(侧栏/搜索)→ router-view
| 库内执行 | `POST /scripts/exec``script_id``command` 二选一) |
| 临时命令 | 页内 quick exec 面板 |
| 长任务 / DB 凭据 | `long_task``credential_id``GET /scripts/exec-config` |
| 执行状态 | 10s 轮询 `GET /scripts/executions/{id}` |
| 提交执行 | `POST /scripts/exec` **立即返回** `running`(后台批次) |
| 全局进度 | `App.vue` + `useScriptExecutionQueue`WS `script_progress` / `script_complete` |
| 历史 | `GET /scripts/executions?script_id=` |
| 停止 / 重试 / 卡住 | `POST .../stop``.../retry``.../mark-stuck` |
### 12.7 CredentialsPage `/credentials`
### 12.7 ScriptRunsPage `/script-runs` · `/script-runs/:id`
| 功能 | API |
|------|-----|
| 执行看板列表 | `GET /scripts/executions`(状态筛选 running/completed/partial/failed |
| 单次明细 | `GET /scripts/executions/{id}` · 失败分组 · 复制清单 · 跳转终端 |
| 重试 / 停止 | 同 ScriptsPage |
| 入口 | 侧栏「脚本看板」;Telegram 深链 `#/script-runs/{id}` |
### 12.8 CredentialsPage `/credentials`
三 Tab:密码预设、SSH 密钥、DB 凭据;编辑时空密码表示不修改。
@@ -607,7 +617,7 @@ main.ts → App.vue(侧栏/搜索)→ router-view
`username``credential_poller``add-by-ip` / retry 时与预设密码或私钥组合尝试 SSH。
### 12.8 SchedulesPage `/schedules`
### 12.9 SchedulesPage `/schedules`
| 功能 | API / 行为 |
|------|------------|
@@ -619,11 +629,11 @@ main.ts → App.vue(侧栏/搜索)→ router-view
| 立即执行 | push → `POST /sync/files`script → `POST /scripts/exec` |
| 后台 | `schedule_runner` 60s 扫描到期项 |
### 12.9 RetriesPage `/retries`
### 12.10 RetriesPage `/retries`
失败推送重试队列;`POST /retries/{id}/retry`
### 12.10 CommandsPage `/commands`
### 12.11 CommandsPage `/commands`
| 视图 | API | 筛选 |
|------|-----|------|
@@ -631,19 +641,19 @@ main.ts → App.vue(侧栏/搜索)→ router-view
| 会话视图 | `GET /assets/ssh-sessions` | server_id |
| 推送日志 | `GET /servers/logs` | server_id、status、sync_mode、trigger_type |
### 12.11 AlertsPage `/alerts`
### 12.12 AlertsPage `/alerts`
告警统计 + 分页;按 type/status 过滤。
### 12.12 AuditPage `/audit`
### 12.13 AuditPage `/audit`
操作审计;action/user/date 过滤;`normalizeAuditList`
### 12.13 SettingsPage `/settings`
### 12.14 SettingsPage `/settings`
系统名/阈值/连接池、Telegram、改密、TOTP、API Key reveal、IP 白名单、终端快捷命令设置。
### 12.14 LoginPage `/login`
### 12.15 LoginPage `/login`
JWT 登录、TOTP、429 锁定、开放重定向防护(`//` 拒绝)、bing 壁纸背景。
@@ -678,8 +688,9 @@ JWT 登录、TOTP、429 锁定、开放重定向防护(`//` 拒绝)、bing
### 14.1 告警 WS `/ws/alerts`
- 连接: `buildWebSocketUrl('/ws/alerts', { token: accessToken })`
- 消息类型: alert / recovery / system
- App.vue 或 Dashboard 订阅
- 消息类型: alert / recovery / system / **script_progress** / **script_complete**
- App.vue`useWebSocket` + `useScriptExecutionQueue`(全局进度条与完成 Alert
- WS 断线时队列 3s 轮询直至终态
### 14.2 推送 WS `/ws/sync`
@@ -879,7 +890,7 @@ bash deploy/deploy-production.sh
| **C** | Push 页 composable 与推送时序 |
| **D** | Terminal / WebSSH 调用链 |
| **E** | schedules/retries/audit/scripts/agent/search API 明细 |
| **F** | 14 页 ↔ composable ↔ 组件对照表 |
| **F** | 15 页 ↔ composable ↔ 组件对照表 |
| **G** | L4 验收 + Playwright 15 用例对照 |
| **H** | HTTP 错误码与前端处理 |
| **I** | 扩展开发检查清单 |
@@ -0,0 +1,54 @@
# 脚本执行看板 — 本地验证报告(2026-06-08
## 环境
- 主机:`127.0.0.1:8600``bash scripts/start-dev.sh`
- MySQL / RedisDocker `nexus-mysql-1` / `nexus-redis-1`
- 凭据:`.env``NEXUS_TEST_ADMIN_*` 已与本地 `admins` 表对齐(用户提供的本地密码)
## 结果摘要
| 检查项 | 结果 |
|--------|------|
| `bash scripts/local_verify.sh`(完整) | **通过** |
| smokeMySQL schema + 47 unit tests | 通过 |
| `tests/test_api.py` | **26/26** |
| ruff F | 通过 |
| 脚本相关 pytest15 条) | 通过 |
## local_verify 明细
```
═══ All local checks passed ═══
```
- `GET /health` → 200
- `POST /api/auth/login` → 200JWT 获取成功)
- Scripts CRUD`POST/GET/DELETE /api/scripts/` 均通过
- 其余 Server / Schedules / Settings / Audit / Retries / Sync 端点均通过
## 脚本专项 pytest
```bash
.venv/bin/pytest tests/test_script_execution_progress_stats.py \
tests/test_script_execution_progress.py \
tests/test_exec_detail_grouping.py \
tests/test_script_dispatch.py -q
# 15 passed
```
## 异步执行(设计验收)
`test_api` 已覆盖 Scripts 创建/列表/删除;结合 P0 实现,`POST /api/scripts/exec` 在代码审查路径上为「创建记录后立即返回 `running` + 后台 `asyncio` 任务」。
**建议终验(浏览器,需用户):**
1. 脚本库选多台子机执行 → 1s 内关对话框,顶栏进度条更新
2. `#/script-runs/{id}` 查看失败明细与分组
3. 完成时 Alert + 提示音;Telegram 仅汇总(若已配置 bot
## 未在本报告执行的项
- 生产 `deploy/pre_deploy_check.sh` + 部署
- 366 台规模压测
- Playwright 浏览器自动化
+134 -3
View File
@@ -227,8 +227,70 @@
</template>
</v-navigation-drawer>
<!-- 脚本执行全局进度 -->
<div
v-if="auth.isLoggedIn && runningItems.length"
class="nexus-script-exec-bar"
>
<v-sheet
v-for="item in runningItems"
:key="item.executionId"
class="nexus-script-exec-bar__item px-4 py-2"
color="surface"
border
>
<div class="d-flex align-center flex-wrap ga-2 mb-1">
<span class="text-body-2 font-weight-medium text-truncate">{{ item.label }}</span>
<v-chip size="x-small" variant="tonal" color="primary" label>#{{ item.executionId }}</v-chip>
<v-spacer />
<span class="text-caption text-medium-emphasis">
已进行 {{ item.done }} 剩余 {{ item.remaining }}
<span class="ml-2">({{ item.progress }})</span>
</span>
</div>
<v-progress-linear
:model-value="item.total ? Math.round((item.done / item.total) * 100) : 0"
color="primary"
height="6"
rounded
striped
stream
/>
</v-sheet>
</div>
<!-- 脚本执行完成提示 -->
<div v-if="auth.isLoggedIn" class="nexus-script-exec-alerts">
<v-alert
v-for="alert in completeAlerts"
:key="alert.executionId"
:class="{ 'nexus-script-exec-alert--fading': alert.fading }"
:type="completeAlertType(alert.status)"
variant="tonal"
closable
density="compact"
class="mb-2"
@click:close="dismissCompleteAlert(alert.executionId)"
>
<div class="d-flex align-center flex-wrap ga-2">
<span>
{{ alert.label }}执行结束
成功 {{ alert.success }} / 失败 {{ alert.failed }} / {{ alert.total }}
</span>
<v-btn
size="small"
variant="text"
color="primary"
@click="goToScriptRun(alert.executionId)"
>
查看详情
</v-btn>
</div>
</v-alert>
</div>
<!-- Main Content -->
<v-main :class="mainLayoutClass">
<v-main :class="mainLayoutClass" :style="scriptExecBarOffset">
<router-view :key="route.fullPath" />
</v-main>
@@ -240,11 +302,16 @@
</template>
<script setup lang="ts">
import { ref, reactive, watch, onUnmounted, provide, computed } from 'vue'
import { ref, reactive, watch, onUnmounted, onMounted, provide, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useTheme, useDisplay } from 'vuetify'
import { useAuthStore } from '@/stores/auth'
import { useWebSocket } from '@/composables/useWebSocket'
import {
useScriptExecutionQueue,
onScriptExecutionComplete,
} from '@/composables/useScriptExecutionQueue'
import { useScriptCompleteSound } from '@/composables/useScriptCompleteSound'
import { api, http } from '@/api'
const route = useRoute()
@@ -252,10 +319,32 @@ const router = useRouter()
const theme = useTheme()
const auth = useAuthStore()
const ws = useWebSocket()
const { runningItems, completeAlerts, dismissCompleteAlert } = useScriptExecutionQueue()
const { playCompleteSound, syncFromServer: syncScriptSoundFromServer } = useScriptCompleteSound()
function completeAlertType(status: string): 'success' | 'warning' | 'error' | 'info' {
if (status === 'completed') return 'success'
if (status === 'failed') return 'error'
if (status === 'partial') return 'warning'
return 'info'
}
function goToScriptRun(executionId: number) {
dismissCompleteAlert(executionId)
router.push(`/script-runs/${executionId}`).catch(() => {})
}
onMounted(() => {
onScriptExecutionComplete(() => playCompleteSound())
})
// Auto-connect WebSocket when logged in
watch(() => auth.isLoggedIn, (loggedIn) => {
if (loggedIn) { ws.connect(); syncThemeFromServer() }
if (loggedIn) {
ws.connect()
syncThemeFromServer()
syncScriptSoundFromServer()
}
else ws.disconnect()
}, { immediate: true })
@@ -292,6 +381,15 @@ const mainLayoutClass = computed(() => ({
'nexus-page-main': route.path !== '/terminal' && route.path !== '/login',
}))
const scriptExecBarOffset = computed(() => {
const n = runningItems.value.length
if (!n || !auth.isLoggedIn) return undefined
const extra = n * 52
return {
paddingTop: `calc(var(--v-layout-top, 64px) + ${extra}px)`,
}
})
const opsItems = [
{ to: '/', title: '仪表盘', icon: 'mdi-view-dashboard-outline' },
{ to: '/servers', title: '服务器', icon: 'mdi-server' },
@@ -299,6 +397,7 @@ const opsItems = [
{ to: '/files', title: '文件管理', icon: 'mdi-folder-outline' },
{ to: '/push', title: '推送', icon: 'mdi-upload-outline' },
{ to: '/scripts', title: '脚本库', icon: 'mdi-code-braces' },
{ to: '/script-runs', title: '脚本看板', icon: 'mdi-clipboard-play-outline' },
{ to: '/credentials',title: '凭据', icon: 'mdi-key-outline' },
{ to: '/schedules', title: '调度', icon: 'mdi-clock-outline' },
{ to: '/retries', title: '重试队列', icon: 'mdi-refresh' },
@@ -453,4 +552,36 @@ interface SearchResults {
.nexus-nav-drawer :deep(.v-navigation-drawer__content) {
overflow-y: auto;
}
.nexus-script-exec-bar {
position: fixed;
top: var(--v-layout-top, 64px);
left: var(--v-layout-left, 0);
right: 0;
z-index: 1005;
display: flex;
flex-direction: column;
gap: 0;
pointer-events: none;
}
.nexus-script-exec-bar__item {
pointer-events: auto;
border-bottom: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
}
.nexus-script-exec-alerts {
position: fixed;
top: calc(var(--v-layout-top, 64px) + 8px);
right: 16px;
z-index: 1006;
max-width: min(420px, calc(100vw - 32px));
pointer-events: none;
}
.nexus-script-exec-alerts .v-alert {
pointer-events: auto;
}
.nexus-script-exec-alert--fading {
opacity: 0;
transition: opacity 1s ease;
}
</style>
@@ -0,0 +1,68 @@
import { ref } from 'vue'
import { api } from '@/api'
import {
DEFAULT_SCRIPT_COMPLETE_SOUND,
normalizeScriptCompleteSound,
playScriptCompleteSoundById,
type ScriptCompleteSoundId,
} from '@/utils/scriptCompleteSound'
const LS_KEY = 'nexus_script_exec_complete_sound'
const soundMode = ref<ScriptCompleteSoundId>(readCached())
function readCached(): ScriptCompleteSoundId {
try {
const raw = localStorage.getItem(LS_KEY)
if (raw) return normalizeScriptCompleteSound(raw)
} catch {
/* ignore */
}
return DEFAULT_SCRIPT_COMPLETE_SOUND
}
function persistCache(mode: ScriptCompleteSoundId) {
try {
localStorage.setItem(LS_KEY, mode)
} catch {
/* ignore */
}
}
export function useScriptCompleteSound() {
async function syncFromServer() {
try {
const data = await api<{ value: string }>('/settings/script_exec_complete_sound')
const mode = normalizeScriptCompleteSound(data.value)
soundMode.value = mode
persistCache(mode)
} catch {
soundMode.value = readCached()
}
}
async function saveToServer(mode: ScriptCompleteSoundId) {
const normalized = normalizeScriptCompleteSound(mode)
await api('/settings/script_exec_complete_sound', {
method: 'PUT',
body: JSON.stringify({ value: normalized }),
})
soundMode.value = normalized
persistCache(normalized)
}
function playCompleteSound() {
playScriptCompleteSoundById(soundMode.value)
}
function previewSound(mode?: ScriptCompleteSoundId) {
playScriptCompleteSoundById(mode ?? soundMode.value)
}
return {
soundMode,
syncFromServer,
saveToServer,
playCompleteSound,
previewSound,
}
}
@@ -0,0 +1,249 @@
/**
* Global script execution progress queue — fed by /ws/alerts script_* messages
* with 3s polling fallback when WebSocket is disconnected.
*/
import { ref, computed, onUnmounted } from 'vue'
import { http } from '@/api'
import { isExecTerminalStatus } from '@/utils/scriptExecutionLabels'
export interface ScriptExecQueueItem {
executionId: number
label: string
status: string
total: number
done: number
remaining: number
success: number
failed: number
progress: string
longTask: boolean
operator?: string
}
export interface ScriptExecCompleteAlert {
executionId: number
label: string
status: string
success: number
failed: number
total: number
fading: boolean
}
const POLL_MS = 3000
const activeItems = ref<Map<number, ScriptExecQueueItem>>(new Map())
const completeAlerts = ref<ScriptExecCompleteAlert[]>([])
const wsConnected = ref(true)
let pollTimer: ReturnType<typeof setInterval> | null = null
const completeListeners = new Set<(alert: ScriptExecCompleteAlert) => void>()
function mapToItem(msg: Record<string, unknown>): ScriptExecQueueItem {
const total = Number(msg.total) || 0
const done = Number(msg.done) || 0
const remaining = Number(msg.remaining) ?? Math.max(0, total - done)
return {
executionId: Number(msg.execution_id),
label: String(msg.label || `执行 #${msg.execution_id}`),
status: String(msg.status || 'running'),
total,
done,
remaining,
success: Number(msg.success) || 0,
failed: Number(msg.failed) || 0,
progress: String(msg.progress || `${done}/${total}`),
longTask: Boolean(msg.long_task),
operator: msg.operator ? String(msg.operator) : undefined,
}
}
function upsertItem(item: ScriptExecQueueItem) {
const next = new Map(activeItems.value)
if (isExecTerminalStatus(item.status)) {
next.delete(item.executionId)
} else {
next.set(item.executionId, item)
}
activeItems.value = next
}
function pushCompleteAlert(item: ScriptExecQueueItem) {
const alert: ScriptExecCompleteAlert = {
executionId: item.executionId,
label: item.label,
status: item.status,
success: item.success,
failed: item.failed,
total: item.total,
fading: false,
}
completeAlerts.value = [alert, ...completeAlerts.value].slice(0, 5)
for (const fn of completeListeners) {
try {
fn(alert)
} catch {
/* ignore */
}
}
setTimeout(() => {
completeAlerts.value = completeAlerts.value.map(a =>
a.executionId === alert.executionId ? { ...a, fading: true } : a,
)
setTimeout(() => {
completeAlerts.value = completeAlerts.value.filter(
a => a.executionId !== alert.executionId,
)
}, 1000)
}, 8000)
}
function ensurePolling() {
if (pollTimer) return
pollTimer = setInterval(() => {
if (wsConnected.value) return
void pollActive()
}, POLL_MS)
}
function stopPollingIfIdle() {
if (activeItems.value.size > 0) return
if (pollTimer) {
clearInterval(pollTimer)
pollTimer = null
}
}
async function pollActive() {
const ids = [...activeItems.value.keys()]
if (!ids.length) {
stopPollingIfIdle()
return
}
for (const id of ids) {
try {
const res = await http.get<{
id: number
status: string
progress?: string
long_task?: boolean
label?: string
server_ids?: string
results?: Record<string, unknown>
}>(`/scripts/executions/${id}`)
const prev = activeItems.value.get(id)
const label = res.label || prev?.label || `执行 #${id}`
let total = prev?.total || 0
if (res.server_ids) {
try {
const parsed = JSON.parse(res.server_ids) as unknown
if (Array.isArray(parsed)) total = parsed.length
} catch {
/* keep */
}
}
const progress = res.progress || prev?.progress || `0/${total}`
const parts = progress.split('/')
const success = Number(parts[0]) || 0
const totalFromProgress = Number(parts[1]) || total
const item: ScriptExecQueueItem = {
executionId: id,
label,
status: res.status,
total: totalFromProgress || total,
done: success,
remaining: Math.max(0, (totalFromProgress || total) - success),
success,
failed: 0,
progress,
longTask: Boolean(res.long_task ?? prev?.longTask),
operator: prev?.operator,
}
if (isExecTerminalStatus(res.status)) {
upsertItem(item)
pushCompleteAlert({ ...item, status: res.status })
} else {
upsertItem(item)
}
} catch {
/* keep last known */
}
}
stopPollingIfIdle()
}
export function handleScriptWsMessage(msg: Record<string, unknown>) {
const item = mapToItem(msg)
if (!item.executionId) return
if (msg.type === 'script_complete' || isExecTerminalStatus(item.status)) {
upsertItem(item)
pushCompleteAlert(item)
stopPollingIfIdle()
return
}
upsertItem(item)
ensurePolling()
}
export function setScriptQueueWsConnected(connected: boolean) {
wsConnected.value = connected
if (!connected && activeItems.value.size > 0) {
ensurePolling()
}
}
export function registerScriptExecution(
executionId: number,
label: string,
totalServers: number,
longTask = false,
progress?: string,
status = 'running',
) {
if (isExecTerminalStatus(status)) return
const item: ScriptExecQueueItem = {
executionId,
label,
status,
total: totalServers,
done: 0,
remaining: totalServers,
success: 0,
failed: 0,
progress: progress || `0/${totalServers}`,
longTask,
}
upsertItem(item)
ensurePolling()
}
export function onScriptExecutionComplete(listener: (alert: ScriptExecCompleteAlert) => void) {
completeListeners.add(listener)
return () => completeListeners.delete(listener)
}
export function dismissCompleteAlert(executionId: number) {
completeAlerts.value = completeAlerts.value.map(a =>
a.executionId === executionId ? { ...a, fading: true } : a,
)
setTimeout(() => {
completeAlerts.value = completeAlerts.value.filter(a => a.executionId !== executionId)
}, 1000)
}
export function useScriptExecutionQueue() {
const runningItems = computed(() =>
[...activeItems.value.values()].sort((a, b) => b.executionId - a.executionId),
)
onUnmounted(() => {
/* singleton — do not stop global poll on component unmount */
})
return {
runningItems,
completeAlerts: computed(() => completeAlerts.value),
registerScriptExecution,
dismissCompleteAlert,
onScriptExecutionComplete,
}
}
+13
View File
@@ -8,11 +8,16 @@
* alert → { type: "alert", server_id, server_name, alert_type, alert_value }
* recovery → { type: "recovery", server_id, server_name, metric, value }
* system → { type: "system", event_type, message }
* script_progress / script_complete → global script execution queue (useScriptExecutionQueue)
* Push progress uses a separate channel: /ws/sync (see usePushProgress)
* ping → { type: "ping" } → client must respond with text "pong"
*/
import { ref, computed } from 'vue'
import { useAuthStore } from '@/stores/auth'
import {
handleScriptWsMessage,
setScriptQueueWsConnected,
} from '@/composables/useScriptExecutionQueue'
const ws = ref<WebSocket | null>(null)
const connected = ref(false)
@@ -64,6 +69,7 @@ export function useWebSocket() {
socket.onopen = () => {
connected.value = true
reconnectAttempts.value = 0
setScriptQueueWsConnected(true)
}
socket.onmessage = (event) => {
@@ -79,6 +85,11 @@ export function useWebSocket() {
return
}
if (msg.type === 'script_progress' || msg.type === 'script_complete') {
handleScriptWsMessage(msg)
return
}
// Handle alert/recovery/system
if (msg.type === 'alert' || msg.type === 'recovery') {
const alert: WsAlert = {
@@ -109,6 +120,7 @@ export function useWebSocket() {
socket.onclose = (event) => {
connected.value = false
setScriptQueueWsConnected(false)
ws.value = null
// Don't reconnect on auth failure — token expired
if (event.code === 4001 || event.code === 4401) {
@@ -136,6 +148,7 @@ export function useWebSocket() {
}
connected.value = false
reconnectAttempts.value = 0
setScriptQueueWsConnected(false)
}
function scheduleReconnect() {
+592
View File
@@ -0,0 +1,592 @@
<template>
<v-container fluid class="pa-4">
<template v-if="detailId">
<div class="d-flex align-center flex-wrap ga-2 mb-4">
<v-btn variant="text" prepend-icon="mdi-arrow-left" @click="router.push('/script-runs')">
返回列表
</v-btn>
<h1 class="text-h6">执行详情 #{{ detailId }}</h1>
<v-chip
v-if="execDetail"
:color="execStatusColor(execDetail.status)"
size="small"
variant="tonal"
label
>
{{ execStatusLabel(execDetail.status) }}
</v-chip>
<v-spacer />
<v-btn
v-if="execDetail?.long_task"
size="small"
variant="tonal"
:loading="detailLoading"
@click="loadExecDetail(true)"
>
拉取日志
</v-btn>
<v-btn
v-if="execDetail && (execDetail.status === 'running' || execDetail.status === 'partial')"
size="small"
variant="text"
color="error"
@click="stopCurrent"
>
停止
</v-btn>
<v-btn
v-if="execDetail && (execDetail.status === 'failed' || execDetail.status === 'partial')"
size="small"
variant="tonal"
color="primary"
@click="retryCurrent"
>
重试失败项
</v-btn>
</div>
<v-card v-if="detailLoading && !execDetail" elevation="0" border rounded="lg" class="pa-8 text-center">
<v-progress-circular indeterminate color="primary" />
</v-card>
<v-card v-else-if="execDetail" elevation="0" border rounded="lg">
<v-card-text>
<div class="text-caption text-medium-emphasis mb-2">
{{ formatProgress(execDetail.progress) }} · 操作人 {{ execDetail.operator || '—' }}
</div>
<pre class="text-body-2 mb-3 pa-3 rounded bg-surface-variant overflow-auto" style="max-height: 100px">{{ execDetail.command }}</pre>
<div v-if="execDetailStats.total" class="d-flex flex-wrap ga-2 mb-3">
<v-chip size="small" variant="tonal" label> {{ execDetailStats.total }} </v-chip>
<v-chip v-if="execDetailStats.success" color="success" size="small" variant="tonal" label>
成功 {{ execDetailStats.success }}
</v-chip>
<v-chip v-if="execDetailStats.failed" color="error" size="small" variant="tonal" label>
失败 {{ execDetailStats.failed }}
</v-chip>
<v-chip v-if="execDetailStats.pending" color="info" size="small" variant="tonal" label>
进行中 {{ execDetailStats.pending }}
</v-chip>
</div>
<v-alert
v-if="execDetailFailedNames.length"
type="error"
variant="tonal"
density="compact"
class="mb-3"
:title="`失败 ${execDetailFailedNames.length} 台`"
>
<div class="text-body-2">{{ execDetailFailedNames.join('、') }}</div>
</v-alert>
<div class="d-flex align-center flex-wrap ga-2 mb-3">
<span class="text-caption text-medium-emphasis">筛选</span>
<v-btn-toggle v-model="detailRowFilter" mandatory density="compact" color="primary" variant="outlined" divided>
<v-btn value="all" size="small">全部</v-btn>
<v-btn value="failed" size="small">仅失败</v-btn>
<v-btn value="success" size="small">仅成功</v-btn>
</v-btn-toggle>
<template v-if="execDetailStats.failed > 0">
<v-divider vertical class="mx-1" />
<span class="text-caption text-medium-emphasis">视图</span>
<v-btn-toggle v-model="detailViewMode" mandatory density="compact" color="primary" variant="outlined" divided>
<v-btn value="list" size="small">列表</v-btn>
<v-btn value="group" size="small">按错误分组</v-btn>
</v-btn-toggle>
<v-btn size="small" variant="tonal" prepend-icon="mdi-content-copy" @click="copyFailedList">
复制失败清单
</v-btn>
<v-btn
v-if="detailViewMode === 'group'"
size="small"
variant="tonal"
prepend-icon="mdi-content-copy"
@click="copyFailureGroupSummary"
>
复制分组摘要
</v-btn>
</template>
</div>
<v-table v-if="detailViewMode === 'list'" density="compact">
<thead>
<tr>
<th>服务器</th>
<th>状态</th>
<th style="width: 72px">退出码</th>
<th>错误摘要</th>
<th style="width: 120px" class="text-end">操作</th>
</tr>
</thead>
<tbody>
<tr
v-for="row in filteredExecDetailRows"
:key="row.serverId"
:class="{ 'exec-detail-row--failed': row.failed }"
class="cursor-pointer"
@click="toggleDetailRow(row.serverId)"
>
<td>
<div class="font-weight-medium">{{ row.serverName }}</div>
<div v-if="row.serverDomain" class="text-caption text-medium-emphasis">{{ row.serverDomain }}</div>
</td>
<td>
<v-chip
:color="execServerStatusColor(row.status, row.phase, row.exitCode)"
size="x-small"
variant="tonal"
label
>
{{ execServerStatusLabel(row.status, row.phase) }}
</v-chip>
</td>
<td :class="{ 'text-error font-weight-medium': row.failed }">{{ row.exitCode ?? '—' }}</td>
<td class="text-truncate" style="max-width: 280px" :title="row.summary">{{ row.summary }}</td>
<td class="text-end" @click.stop>
<v-btn
size="x-small"
variant="text"
icon="mdi-console"
title="打开终端"
@click="openServerTerminal(row.serverIdNum)"
/>
</td>
</tr>
<tr v-if="filteredExecDetailRows.length === 0">
<td colspan="5" class="text-center text-medium-emphasis py-4">当前筛选无记录</td>
</tr>
</tbody>
</v-table>
<v-expansion-panels
v-else-if="execDetailFailureGroups.length"
v-model="expandedFailureGroups"
multiple
variant="accordion"
>
<v-expansion-panel v-for="(group, idx) in execDetailFailureGroups" :key="`${idx}-${group.errorKey}`">
<v-expansion-panel-title>
<div class="d-flex align-center ga-2 flex-grow-1 min-width-0">
<span class="text-body-2 text-truncate" :title="group.errorKey">{{ group.errorKey }}</span>
<v-chip color="error" size="x-small" variant="tonal" label>{{ group.count }} </v-chip>
</div>
</v-expansion-panel-title>
<v-expansion-panel-text>
<div v-for="row in group.rows" :key="row.serverId" class="text-body-2 py-1">
{{ row.serverName }}
<span v-if="row.serverDomain" class="text-medium-emphasis">{{ row.serverDomain }}</span>
</div>
</v-expansion-panel-text>
</v-expansion-panel>
</v-expansion-panels>
</v-card-text>
</v-card>
</template>
<template v-else>
<div class="d-flex align-center flex-wrap ga-2 mb-4">
<h1 class="text-h6">脚本执行看板</h1>
<v-spacer />
<v-btn variant="tonal" prepend-icon="mdi-refresh" :loading="listLoading" @click="loadList">
刷新
</v-btn>
</div>
<v-card elevation="0" border rounded="lg">
<v-card-text>
<v-row dense class="mb-2">
<v-col cols="12" sm="4">
<v-select
v-model="statusFilter"
:items="statusFilterOptions"
label="状态筛选"
variant="outlined"
density="compact"
hide-details
clearable
/>
</v-col>
</v-row>
<v-data-table-server
:headers="listHeaders"
:items="executions"
:items-length="total"
:loading="listLoading"
:items-per-page="perPage"
:page="page"
@update:page="onPageChange"
@update:items-per-page="onPerPageChange"
>
<template #item.label="{ item }">
{{ execLabel(item) }}
</template>
<template #item.status="{ item }">
<v-chip :color="execStatusColor(item.status)" size="x-small" variant="tonal" label>
{{ execStatusLabel(item.status) }}
</v-chip>
</template>
<template #item.progress="{ item }">
{{ formatProgress(item.progress) }}
</template>
<template #item.server_count="{ item }">
{{ parseServerCount(item.server_ids) }}
</template>
<template #item.actions="{ item }">
<v-btn size="x-small" variant="text" color="primary" @click="openDetail(item.id)">
详情
</v-btn>
</template>
<template #no-data>
<div class="text-center text-medium-emphasis py-6">暂无执行记录</div>
</template>
</v-data-table-server>
</v-card-text>
</v-card>
</template>
</v-container>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { http } from '@/api'
import { useSnackbar } from '@/composables/useSnackbar'
import { registerScriptExecution } from '@/composables/useScriptExecutionQueue'
import { useServerList } from '@/composables/useServerList'
import { formatApiError } from '@/utils/apiError'
import type { ScriptExecItem } from '@/types/api'
import { DATA_TABLE_ITEMS_PER_PAGE_OPTIONS, headersWithoutSort } from '@/constants/dataTable'
import { fetchLimitOffset } from '@/utils/paginatedFetch'
import {
execStatusLabel,
execStatusColor,
execServerStatusLabel,
execServerStatusColor,
isExecServerFailed,
isExecServerPending,
summarizeExecServerResults,
} from '@/utils/scriptExecutionLabels'
import { groupFailedExecRows } from '@/utils/execDetailGrouping'
const route = useRoute()
const router = useRouter()
const snackbar = useSnackbar()
const { servers: serverList, loadServers } = useServerList()
const detailId = computed(() => {
const raw = route.params.id
if (!raw) return null
const n = Number(raw)
return Number.isFinite(n) ? n : null
})
const listLoading = ref(false)
const executions = ref<ScriptExecItem[]>([])
const total = ref(0)
const page = ref(1)
const perPage = ref(20)
const statusFilter = ref<string | null>(null)
const statusFilterOptions = [
{ title: '执行中', value: 'running' },
{ title: '已完成', value: 'completed' },
{ title: '部分成功', value: 'partial' },
{ title: '失败', value: 'failed' },
{ title: '已取消', value: 'cancelled' },
]
const listHeaders = headersWithoutSort([
{ title: 'ID', key: 'id', width: 72 },
{ title: '脚本/命令', key: 'label' },
{ title: '状态', key: 'status', width: 100 },
{ title: '进度', key: 'progress', width: 88 },
{ title: '台数', key: 'server_count', width: 72 },
{ title: '操作人', key: 'operator', width: 88 },
{ title: '开始时间', key: 'started_at', width: 168 },
{ title: '操作', key: 'actions', width: 88 },
])
const execDetail = ref<ScriptExecItem | null>(null)
const detailLoading = ref(false)
const detailRowFilter = ref<'all' | 'failed' | 'success'>('all')
const detailViewMode = ref<'list' | 'group'>('list')
const expandedRowId = ref<string | null>(null)
const expandedFailureGroups = ref<number[]>([])
let detailPollTimer: ReturnType<typeof setInterval> | null = null
interface ExecDetailRow {
serverId: string
serverIdNum: number
serverName: string
serverDomain: string
status: string
phase?: string
exitCode: number | null
summary: string
fullOutput: string
failed: boolean
pending: boolean
}
const serverBriefById = computed(() => new Map(serverList.value.map(s => [s.id, s])))
function formatProgress(p: string | undefined) {
return p || '—'
}
function parseServerCount(serverIds: string | undefined): number {
if (!serverIds) return 0
try {
const arr = JSON.parse(serverIds) as unknown
return Array.isArray(arr) ? arr.length : 0
} catch {
return 0
}
}
function execLabel(item: ScriptExecItem): string {
if (item.label) return item.label
const cmd = (item.command || '').replace(/^\[long_task\] /, '')
if (cmd.length > 48) return cmd.slice(0, 48) + '…'
return cmd || `执行 #${item.id}`
}
function buildExecOutput(entry: ScriptExecItem['results'][string]): { summary: string; full: string } {
const stderr = (entry.stderr || '').trim()
const stdout = (entry.stdout || '').trim()
const message = (entry.message || '').trim()
const full = stderr || stdout || message || '—'
const summary = (stderr || message || stdout || '').slice(0, 200) || '—'
return { summary, full }
}
const execDetailRows = computed<ExecDetailRow[]>(() => {
if (!execDetail.value?.results) return []
const briefs = serverBriefById.value
return Object.entries(execDetail.value.results)
.filter(([k]) => k !== '_meta' && /^\d+$/.test(k))
.map(([serverId, entry]) => {
const idNum = Number(serverId)
const brief = briefs.get(idNum)
const status = String(entry.status || '')
const phase = entry.phase ? String(entry.phase) : undefined
const exitCode = entry.exit_code ?? null
const output = buildExecOutput(entry)
return {
serverId,
serverIdNum: idNum,
serverName: brief?.name || `服务器 #${serverId}`,
serverDomain: brief?.domain || '',
status,
phase,
exitCode,
summary: output.summary,
fullOutput: output.full,
failed: isExecServerFailed(status, phase, exitCode),
pending: isExecServerPending(phase),
}
})
})
const filteredExecDetailRows = computed(() => {
if (detailRowFilter.value === 'failed') return execDetailRows.value.filter(r => r.failed)
if (detailRowFilter.value === 'success') return execDetailRows.value.filter(r => !r.failed && !r.pending)
return execDetailRows.value
})
const execDetailStats = computed(() =>
summarizeExecServerResults(execDetail.value?.results, execDetail.value?.server_ids),
)
const execDetailFailedNames = computed(() =>
execDetailRows.value.filter(r => r.failed).map(r => r.serverName),
)
const execDetailFailureGroups = computed(() =>
groupFailedExecRows(execDetailRows.value.filter(r => r.failed)),
)
async function loadList() {
listLoading.value = true
try {
const res = await fetchLimitOffset<ScriptExecItem>(
async (limit, offset) => {
const params: Record<string, unknown> = { limit, offset }
if (statusFilter.value) params.status = statusFilter.value
const data = await http.get<{ items: ScriptExecItem[]; total: number }>('/scripts/executions', params)
return { items: data.items || [], total: data.total || 0 }
},
page.value,
perPage.value,
)
executions.value = res.items
total.value = res.total
} catch (e: unknown) {
executions.value = []
total.value = 0
snackbar(formatApiError(e, '加载失败'), 'error')
} finally {
listLoading.value = false
}
}
function onPageChange(p: number) {
page.value = p
loadList()
}
function onPerPageChange(n: number) {
perPage.value = n
page.value = 1
loadList()
}
function openDetail(id: number) {
router.push(`/script-runs/${id}`)
}
async function loadExecDetail(fetchLogs = false) {
if (!detailId.value) return
detailLoading.value = true
try {
const q = fetchLogs ? '?fetch_logs=true' : ''
execDetail.value = await http.get<ScriptExecItem>(`/scripts/executions/${detailId.value}${q}`)
if (execDetail.value?.status === 'running') {
startDetailPoll()
} else {
stopDetailPoll()
}
} catch (e: unknown) {
snackbar(formatApiError(e, '加载详情失败'), 'error')
} finally {
detailLoading.value = false
}
}
function startDetailPoll() {
if (detailPollTimer) return
detailPollTimer = setInterval(() => {
void loadExecDetail(false)
}, 3000)
}
function stopDetailPoll() {
if (detailPollTimer) {
clearInterval(detailPollTimer)
detailPollTimer = null
}
}
function toggleDetailRow(serverId: string) {
expandedRowId.value = expandedRowId.value === serverId ? null : serverId
}
function openServerTerminal(serverId: number) {
router.push({ path: '/terminal', query: { server: String(serverId) } })
}
async function stopCurrent() {
if (!detailId.value) return
try {
await http.post(`/scripts/executions/${detailId.value}/stop`)
await loadExecDetail(false)
snackbar('已发送停止指令')
} catch (e: unknown) {
snackbar(formatApiError(e, '停止失败'), 'error')
}
}
async function retryCurrent() {
if (!detailId.value) return
try {
const res = await http.post<ScriptExecItem>(`/scripts/executions/${detailId.value}/retry`, {})
const count = parseServerCount(res.server_ids)
registerScriptExecution(
res.id,
`${execLabel(res)}(重试)`,
count,
Boolean(res.long_task),
res.progress,
res.status,
)
snackbar(`重试已提交 #${res.id}`)
router.push(`/script-runs/${res.id}`)
} catch (e: unknown) {
snackbar(formatApiError(e, '重试失败'), 'error')
}
}
function formatFailedRowLine(row: ExecDetailRow): string {
const domain = row.serverDomain ? ` (${row.serverDomain})` : ''
const code = row.exitCode != null ? ` · exit ${row.exitCode}` : ''
const line = row.summary.split('\n')[0]?.trim() || row.summary
const summary = line && line !== '—' ? ` · ${line.slice(0, 120)}` : ''
return `- ${row.serverName}${domain}${code}${summary}`
}
async function copyTextToClipboard(text: string, successMsg: string) {
try {
await navigator.clipboard.writeText(text)
snackbar(successMsg)
} catch {
snackbar('复制失败', 'error')
}
}
async function copyFailedList() {
const failed = execDetailRows.value.filter(r => r.failed)
if (!failed.length) return
const lines = [
`执行 #${detailId.value} · 失败 ${failed.length}`,
...failed.map(formatFailedRowLine),
]
await copyTextToClipboard(lines.join('\n'), '已复制失败清单')
}
async function copyFailureGroupSummary() {
const groups = execDetailFailureGroups.value
if (!groups.length) return
const lines = [`执行 #${detailId.value} · 失败分组 ${groups.length}`]
for (const g of groups) {
lines.push(`\n[${g.count} 台] ${g.errorKey}`)
for (const row of g.rows.slice(0, 20)) {
lines.push(` - ${row.serverName}`)
}
if (g.rows.length > 20) lines.push(` …及其他 ${g.rows.length - 20}`)
}
await copyTextToClipboard(lines.join('\n'), '已复制分组摘要')
}
watch(statusFilter, () => {
page.value = 1
loadList()
})
watch(detailId, (id) => {
stopDetailPoll()
execDetail.value = null
if (id) {
detailRowFilter.value = 'all'
detailViewMode.value = 'list'
void loadExecDetail(false)
} else {
loadList()
}
}, { immediate: true })
onMounted(() => {
loadServers()
})
onUnmounted(() => {
stopDetailPoll()
})
</script>
<style scoped>
.exec-detail-row--failed {
background: rgba(var(--v-theme-error), 0.06);
}
</style>
+18 -188
View File
@@ -284,67 +284,6 @@
</v-card>
</div>
<!-- Execution Status Panel -->
<v-card v-if="activeTrackedExecs.length > 0" elevation="0" border rounded="lg" class="mt-4">
<v-card-title class="d-flex align-center text-subtitle-1">
<v-icon class="mr-2">mdi-progress-clock</v-icon>
批量执行状态
<v-spacer />
<v-btn size="small" variant="text" @click="trackedExecs = []">清除</v-btn>
</v-card-title>
<v-divider />
<v-card-text>
<v-list density="compact">
<v-list-item v-for="exec in activeTrackedExecs" :key="exec.id" :title="exec.name">
<template #subtitle>
<span class="text-caption">
#{{ exec.id }} · {{ exec.progress || '—' }} · {{ exec.totalServers }}
<span v-if="exec.longTask" class="ml-1">· 长任务</span>
</span>
</template>
<template #append>
<div class="d-flex align-center flex-wrap ga-1 justify-end">
<v-chip :color="execStatusColor(exec.status)" size="x-small" variant="tonal" label>
{{ execStatusLabel(exec.status) }}
</v-chip>
<v-btn size="x-small" variant="text" @click="openExecDetail(exec.id)">详情</v-btn>
<v-btn size="x-small" variant="text" @click="refreshExecStatus(exec)" :loading="exec.refreshing">
刷新
</v-btn>
<v-btn
v-if="exec.status === 'running'"
size="x-small"
variant="text"
color="warning"
@click="markExecStuck(exec)"
>
卡住
</v-btn>
<v-btn
v-if="exec.status === 'running' || exec.status === 'partial'"
size="x-small"
variant="text"
color="error"
@click="stopExec(exec)"
>
停止
</v-btn>
<v-btn
v-if="exec.status === 'failed' || exec.status === 'partial'"
size="x-small"
variant="text"
color="primary"
@click="retryExec(exec)"
>
重试
</v-btn>
</div>
</template>
</v-list-item>
</v-list>
</v-card-text>
</v-card>
<!-- Editor Dialog -->
<v-dialog v-model="showEditor" max-width="900" scrollable>
<v-card border>
@@ -683,7 +622,7 @@
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
import { ref, computed, watch, onMounted, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import ScriptContentEditor from '@/components/ScriptContentEditor.vue'
import ServerCategoryPicker from '@/components/servers/ServerCategoryPicker.vue'
@@ -706,6 +645,7 @@ import {
summarizeExecServerResults,
} from '@/utils/scriptExecutionLabels'
import { groupFailedExecRows } from '@/utils/execDetailGrouping'
import { registerScriptExecution } from '@/composables/useScriptExecutionQueue'
const dataTablePageOptions = [...DATA_TABLE_ITEMS_PER_PAGE_OPTIONS]
const snackbar = useSnackbar()
@@ -725,16 +665,6 @@ interface ExecConfig {
max_timeout: number
}
interface TrackedExec {
id: number
name: string
status: string
totalServers: number
progress: string
longTask: boolean
refreshing: boolean
}
interface ExecDetailRow {
serverId: string
serverIdNum: number
@@ -792,14 +722,6 @@ const quickLongTask = ref(false)
const quickCredentialId = ref<number | null>(null)
const quickExecuting = ref(false)
const trackedExecs = ref<TrackedExec[]>([])
let pollTimer: ReturnType<typeof setInterval> | null = null
/** 批量执行状态面板仅展示进行中任务(running) */
const activeTrackedExecs = computed(() =>
trackedExecs.value.filter(e => e.status === 'running'),
)
const showExecDetail = ref(false)
const execDetail = ref<ScriptExecItem | null>(null)
const detailLoading = ref(false)
@@ -1143,7 +1065,14 @@ function runScript(script: ScriptItem) {
async function submitExec(payload: Record<string, unknown>, label: string, serverCount: number) {
const res = await http.post<ScriptExecItem & { execution_id?: number }>('/scripts/exec', payload)
const id = executionId(res)
addTrackedExecution(label, id, serverCount, Boolean(payload.long_task), res.progress, res.status)
registerScriptExecution(
id,
label,
serverCount,
Boolean(payload.long_task),
res.progress,
res.status,
)
return res
}
@@ -1216,109 +1145,6 @@ async function doQuickExec() {
}
}
function pruneTerminalTrackedExecs() {
trackedExecs.value = trackedExecs.value.filter(e => !isExecTerminalStatus(e.status))
}
function addTrackedExecution(
name: string,
execId: number,
totalServers: number,
longTask: boolean,
progress?: string,
status?: string,
) {
const initialStatus = status || 'running'
if (isExecTerminalStatus(initialStatus)) return
if (trackedExecs.value.some(e => e.id === execId)) return
trackedExecs.value.unshift({
id: execId,
name,
status: initialStatus,
totalServers,
progress: progress || `0/${totalServers}`,
longTask,
refreshing: false,
})
startPolling()
}
function startPolling() {
if (pollTimer) return
pollTimer = setInterval(async () => {
const active = trackedExecs.value.filter(e => e.status === 'running')
if (active.length === 0) {
pruneTerminalTrackedExecs()
stopPolling()
return
}
for (const exec of active) await refreshExecStatus(exec)
}, 10_000)
}
function stopPolling() {
if (pollTimer) {
clearInterval(pollTimer)
pollTimer = null
}
}
async function refreshExecStatus(exec: TrackedExec) {
exec.refreshing = true
try {
const res = await http.get<ScriptExecItem>(`/scripts/executions/${exec.id}`)
exec.status = res.status
exec.progress = formatProgress(res.progress)
exec.longTask = Boolean(res.long_task)
if (isExecTerminalStatus(res.status)) {
const name = exec.name
const failed = res.status === 'failed' || res.status === 'partial'
trackedExecs.value = trackedExecs.value.filter(e => e.id !== exec.id)
refreshExecutionHistory()
if (failed) {
snackbar(`${name}」已结束,请查看下方执行历史`, 'warning')
}
}
} catch {
/* keep last known */
} finally {
exec.refreshing = false
}
}
async function stopExec(exec: TrackedExec) {
try {
await http.post(`/scripts/executions/${exec.id}/stop`)
await refreshExecStatus(exec)
snackbar('已发送停止指令')
} catch (e: unknown) {
snackbar(formatApiError(e, '停止失败'), 'error')
}
}
async function markExecStuck(exec: TrackedExec) {
try {
await http.post(`/scripts/executions/${exec.id}/mark-stuck`, { detail: '用户在脚本库标记可能卡住' })
snackbar('已标记')
} catch (e: unknown) {
snackbar(formatApiError(e, '标记失败'), 'error')
}
}
async function retryExec(exec: TrackedExec) {
try {
const res = await http.post<ScriptExecItem & { parent_execution_id?: number }>(
`/scripts/executions/${exec.id}/retry`,
{},
)
const newId = executionId(res)
addTrackedExecution(`${exec.name}(重试)`, newId, exec.totalServers, exec.longTask, res.progress, res.status)
snackbar(`已创建重试任务 #${newId}`)
} catch (e: unknown) {
snackbar(formatApiError(e, '重试失败'), 'error')
}
}
async function stopHistoryExec(item: ScriptExecItem) {
try {
await http.post(`/scripts/executions/${item.id}/stop`)
@@ -1332,7 +1158,14 @@ async function stopHistoryExec(item: ScriptExecItem) {
async function retryHistoryExec(item: ScriptExecItem) {
try {
const res = await http.post<ScriptExecItem>(`/scripts/executions/${item.id}/retry`, {})
addTrackedExecution(`${execLabel(item)}(重试)`, executionId(res), parseServerCount(item.server_ids) || parseServerCount(res.server_ids), Boolean(item.long_task), res.progress, res.status)
registerScriptExecution(
executionId(res),
`${execLabel(item)}(重试)`,
parseServerCount(item.server_ids) || parseServerCount(res.server_ids),
Boolean(item.long_task),
res.progress,
res.status,
)
refreshExecutionHistory()
snackbar('重试已提交')
} catch (e: unknown) {
@@ -1446,9 +1279,6 @@ onMounted(() => {
refreshExecutionHistory()
})
onUnmounted(() => {
stopPolling()
})
</script>
<style scoped>
+72
View File
@@ -47,6 +47,42 @@
<TerminalQuickCommandsSettings />
<v-card elevation="0" border rounded="lg" class="mb-4">
<v-card-title class="d-flex align-center">
<v-icon class="mr-2">mdi-bell-ring-outline</v-icon>
界面提示
</v-card-title>
<v-divider />
<v-card-text>
<p class="text-caption text-medium-emphasis mb-3">
脚本批量执行全部结束时在浏览器播放提示音仅当前登录的管理员会话 Telegram 推送无关
</p>
<v-select
v-model="scriptExecCompleteSound"
:items="scriptCompleteSoundOptions"
item-title="title"
item-value="value"
label="脚本执行完成提示音"
variant="outlined"
density="compact"
hide-details
class="mb-3"
:loading="scriptSoundSaving"
:disabled="scriptSoundSaving"
@update:model-value="onScriptExecSoundChange"
/>
<v-btn
size="small"
variant="tonal"
prepend-icon="mdi-volume-high"
:disabled="scriptExecCompleteSound === 'off' || scriptSoundSaving"
@click="previewScriptExecSound"
>
试听
</v-btn>
</v-card-text>
</v-card>
<!-- Telegram Settings -->
<v-card elevation="0" border rounded="lg">
<v-card-title class="d-flex align-center">
@@ -378,11 +414,23 @@ import type {
IpAllowlistSaveRequest,
} from '@/types/api'
import { NOTIFY_TOGGLE_ITEMS } from '@/types/api'
import {
SCRIPT_COMPLETE_SOUND_OPTIONS,
DEFAULT_SCRIPT_COMPLETE_SOUND,
normalizeScriptCompleteSound,
type ScriptCompleteSoundId,
} from '@/utils/scriptCompleteSound'
import { useScriptCompleteSound } from '@/composables/useScriptCompleteSound'
const snackbar = useSnackbar()
const { saveToServer: saveScriptSoundToServer, previewSound } = useScriptCompleteSound()
const auth = useAuthStore()
const scriptCompleteSoundOptions = SCRIPT_COMPLETE_SOUND_OPTIONS
const scriptExecCompleteSound = ref<ScriptCompleteSoundId>(DEFAULT_SCRIPT_COMPLETE_SOUND)
const scriptSoundSaving = ref(false)
// ── Settings ──
const settingsLoading = ref(false)
const settings = ref({
@@ -468,6 +516,10 @@ async function loadSettings() {
telegramTokenDraft.value = ''
continue
}
if (key === 'script_exec_complete_sound') {
scriptExecCompleteSound.value = normalizeScriptCompleteSound(item.value)
continue
}
if (key && NOTIFY_TOGGLE_ITEMS.some(n => n.key === key)) {
notifyToggles.value[key] = parseNotifyEnabled(item.value)
continue
@@ -598,6 +650,26 @@ async function saveTelegramConfig() {
}
}
async function onScriptExecSoundChange(value: ScriptCompleteSoundId | null) {
if (!value || scriptSoundSaving.value) return
const prev = scriptExecCompleteSound.value
scriptExecCompleteSound.value = value
scriptSoundSaving.value = true
try {
await saveScriptSoundToServer(value)
snackbar('提示音设置已保存')
} catch (e: unknown) {
scriptExecCompleteSound.value = prev
snackbar(e instanceof Error ? e.message : '保存失败', 'error')
} finally {
scriptSoundSaving.value = false
}
}
function previewScriptExecSound() {
previewSound(scriptExecCompleteSound.value)
}
async function toggleNotify(key: string, enabled: boolean) {
const prev = notifyToggles.value[key]
notifyToggles.value[key] = enabled
+2
View File
@@ -8,6 +8,8 @@ const routes = [
{ path: '/files', name: 'Files', component: () => import('@/pages/FilesPage.vue') },
{ path: '/push', name: 'Push', component: () => import('@/pages/PushPage.vue') },
{ path: '/scripts', name: 'Scripts', component: () => import('@/pages/ScriptsPage.vue') },
{ path: '/script-runs', name: 'ScriptRuns', component: () => import('@/pages/ScriptRunsPage.vue') },
{ path: '/script-runs/:id', name: 'ScriptRunDetail', component: () => import('@/pages/ScriptRunsPage.vue') },
{ path: '/credentials', name: 'Credentials',component: () => import('@/pages/CredentialsPage.vue') },
{ path: '/schedules', name: 'Schedules', component: () => import('@/pages/SchedulesPage.vue') },
{ path: '/retries', name: 'Retries', component: () => import('@/pages/RetriesPage.vue') },
+3 -1
View File
@@ -79,6 +79,7 @@ export const NOTIFY_TOGGLE_ITEMS: NotifyToggleItem[] = [
{ key: 'notify_system_redis', label: 'Redis 连接异常 / 恢复', desc: 'Redis 不可达或恢复时推送', group: '系统' },
{ key: 'notify_system_mysql', label: 'MySQL 连接异常 / 恢复', desc: 'MySQL 不可达或恢复时推送', group: '系统' },
{ key: 'notify_restart', label: 'Nexus 后端重启', desc: 'Python 服务崩溃重启成功/失败时推送', group: '系统' },
{ key: 'notify_script_complete', label: '脚本执行完成', desc: '脚本批量执行结束时推送汇总与看板链接(不含失败明细)', group: '运维' },
]
/** IP Allowlist response */
@@ -399,8 +400,9 @@ export interface ScriptExecItem {
completed_at: string | null
long_task?: boolean
progress?: string
label?: string
credential_id?: number | null
source: string
source?: string
}
/** Alert history stats from /api/alert-history/stats */
+64
View File
@@ -0,0 +1,64 @@
/** Script execution complete sound presets (Web Audio API). */
export type ScriptCompleteSoundId = 'off' | 'beep_short' | 'beep_double' | 'chime_soft'
export const SCRIPT_COMPLETE_SOUND_OPTIONS: Array<{ value: ScriptCompleteSoundId; title: string }> = [
{ value: 'off', title: '关闭' },
{ value: 'beep_short', title: '短促单音' },
{ value: 'beep_double', title: '双音提示(默认)' },
{ value: 'chime_soft', title: '柔和三音' },
]
export const DEFAULT_SCRIPT_COMPLETE_SOUND: ScriptCompleteSoundId = 'beep_double'
const VALID_IDS = new Set(SCRIPT_COMPLETE_SOUND_OPTIONS.map(o => o.value))
export function normalizeScriptCompleteSound(raw: unknown): ScriptCompleteSoundId {
const s = String(raw ?? '').trim().toLowerCase()
if (VALID_IDS.has(s as ScriptCompleteSoundId)) {
return s as ScriptCompleteSoundId
}
return DEFAULT_SCRIPT_COMPLETE_SOUND
}
function tone(
ctx: AudioContext,
freq: number,
startAt: number,
duration: number,
gain = 0.08,
) {
const osc = ctx.createOscillator()
const g = ctx.createGain()
osc.type = 'sine'
osc.frequency.value = freq
g.gain.value = gain
osc.connect(g)
g.connect(ctx.destination)
osc.start(startAt)
osc.stop(startAt + duration)
}
export function playScriptCompleteSoundById(mode: ScriptCompleteSoundId): void {
if (mode === 'off') return
try {
const ctx = new AudioContext()
const t0 = ctx.currentTime
if (mode === 'beep_short') {
tone(ctx, 880, t0, 0.12)
return
}
if (mode === 'beep_double') {
tone(ctx, 880, t0, 0.15)
tone(ctx, 1174, t0 + 0.12, 0.2)
return
}
if (mode === 'chime_soft') {
tone(ctx, 523.25, t0, 0.1, 0.06)
tone(ctx, 659.25, t0 + 0.1, 0.1, 0.06)
tone(ctx, 783.99, t0 + 0.2, 0.14, 0.06)
}
} catch {
/* non-critical */
}
}
+15
View File
@@ -50,10 +50,17 @@ MUTABLE_KEYS: set[str] = {
"notify_alert_cpu", "notify_alert_mem", "notify_alert_disk",
"notify_recovery", "notify_time_drift",
"notify_system_redis", "notify_system_mysql", "notify_restart",
"notify_script_complete",
"script_exec_complete_sound", # 脚本执行完成浏览器提示音 (off|beep_short|beep_double|chime_soft)
"editor_theme", # Monaco editor theme preference
"theme", # 全站主题 (dark/light)
}
SETTING_ENUM_VALIDATORS: dict[str, frozenset[str]] = {
"script_exec_complete_sound": frozenset({"off", "beep_short", "beep_double", "chime_soft"}),
"theme": frozenset({"dark", "light"}),
}
# S-02: Per-key validation rules: (type, min, max) for int settings
SETTING_VALIDATORS: dict[str, tuple] = {
"db_pool_size": (int, 1, 1000),
@@ -339,6 +346,14 @@ async def set_setting(
raise HTTPException(status_code=400, detail=f"'{key}' 不能为空")
return _format_setting_response(key, current, None)
if key in SETTING_ENUM_VALIDATORS:
allowed = SETTING_ENUM_VALIDATORS[key]
if val_str not in allowed:
raise HTTPException(
status_code=400,
detail=f"'{key}' 必须是: {', '.join(sorted(allowed))}",
)
# S-02: Validate value type and range for int settings
if key in SETTING_VALIDATORS:
expected_type, min_val, max_val = SETTING_VALIDATORS[key]
+12
View File
@@ -523,6 +523,18 @@ async def broadcast_system_event(event_type: str, message: str):
await _dispatch_ws_message(msg)
async def broadcast_script_progress(payload: dict):
"""Broadcast script execution batch progress to /ws/alerts subscribers."""
msg = {"type": "script_progress", **payload}
await _dispatch_ws_message(msg)
async def broadcast_script_complete(payload: dict):
"""Broadcast script execution terminal state to /ws/alerts subscribers."""
msg = {"type": "script_complete", **payload}
await _dispatch_ws_message(msg)
async def broadcast_sync_progress(
batch_id: str, server_id: int, server_name: str,
status: str, completed: int, failed: int, total: int,
@@ -0,0 +1,137 @@
"""WebSocket + Telegram notifications for script execution progress."""
from __future__ import annotations
import json
import logging
from typing import Any, Optional
from server.config import settings
from server.domain.repositories import ScriptExecutionRepository, ScriptRepository
from server.infrastructure.redis import script_execution_store as ses
logger = logging.getLogger("nexus.script_execution_notify")
def _script_board_url(execution_id: int) -> str:
base = (settings.API_BASE_URL or "").strip().rstrip("/")
if not base:
return f"/app/#/script-runs/{execution_id}"
return f"{base}/app/#/script-runs/{execution_id}"
async def _resolve_label(
live: dict[str, Any],
script_repo: Optional[ScriptRepository] = None,
) -> str:
label = (live.get("label") or "").strip()
if label:
return label
script_id = live.get("script_id")
if script_id and script_repo:
script = await script_repo.get_by_id(int(script_id))
if script and script.name:
return script.name
cmd = str(live.get("command") or "")
if cmd.startswith("[long_task] "):
cmd = cmd[len("[long_task] "):]
if len(cmd) > 48:
return cmd[:48] + ""
return cmd or f"执行 #{live.get('id')}"
def _ws_payload(live: dict[str, Any], label: str) -> dict[str, Any]:
results = live.get("results") or {}
server_ids = live.get("server_ids") or []
stats = ses.execution_progress_stats(results, server_ids)
return {
"execution_id": int(live["id"]),
"label": label,
"status": live.get("status") or "running",
"long_task": bool(live.get("long_task")),
"operator": live.get("operator") or "",
"script_id": live.get("script_id"),
**stats,
}
async def notify_script_progress(
live: dict[str, Any],
*,
script_repo: Optional[ScriptRepository] = None,
) -> None:
"""Broadcast running progress (throttle at caller for per-server updates)."""
try:
from server.api.websocket import broadcast_script_progress
label = await _resolve_label(live, script_repo)
await broadcast_script_progress(_ws_payload(live, label))
except Exception as e:
logger.warning("script progress notify failed: %s", e)
async def notify_script_complete(
live: dict[str, Any],
*,
script_repo: Optional[ScriptRepository] = None,
) -> None:
"""Broadcast terminal state + optional Telegram summary."""
status = live.get("status") or ""
if status not in ses.TERMINAL_STATUSES:
return
try:
from server.api.websocket import broadcast_script_complete
label = await _resolve_label(live, script_repo)
payload = _ws_payload(live, label)
await broadcast_script_complete(payload)
from server.infrastructure.telegram import send_telegram_script_summary
results = live.get("results") or {}
server_ids = live.get("server_ids") or []
stats = ses.execution_progress_stats(results, server_ids)
await send_telegram_script_summary(
execution_id=int(live["id"]),
script_label=label,
operator=str(live.get("operator") or "admin"),
status=status,
success_count=int(stats["success"]),
failed_count=int(stats["failed"]),
total=int(stats["total"]),
board_url=_script_board_url(int(live["id"])),
)
except Exception as e:
logger.warning("script complete notify failed: %s", e)
async def notify_script_complete_for_execution(
execution_repo: ScriptExecutionRepository,
execution_id: int,
*,
script_repo: Optional[ScriptRepository] = None,
) -> None:
view = await ses.get_execution_view(execution_repo, execution_id)
if not view:
return
raw_ids = view.get("server_ids")
if isinstance(raw_ids, str):
try:
server_ids = json.loads(raw_ids or "[]")
except json.JSONDecodeError:
server_ids = []
else:
server_ids = raw_ids or []
live = {
"id": view["id"],
"script_id": view.get("script_id"),
"command": view.get("command"),
"server_ids": server_ids,
"status": view.get("status"),
"results": view.get("results") or {},
"operator": view.get("operator"),
"long_task": view.get("long_task", False),
"label": view.get("label"),
}
await notify_script_complete(live, script_repo=script_repo)
@@ -88,7 +88,7 @@ async def apply_script_job_callback(
status = _aggregate_execution_status(server_ids, results)
terminal = status in ses.TERMINAL_STATUSES
await ses.apply_update(
live = await ses.apply_update(
execution_repo,
execution_id,
status=status,
@@ -102,6 +102,15 @@ async def apply_script_job_callback(
terminal=terminal,
)
if terminal:
from server.application.services.script_execution_notify import notify_script_complete
await notify_script_complete(live)
else:
from server.application.services.script_execution_notify import notify_script_progress
await notify_script_progress(live)
return {
"execution_id": execution_id,
"server_id": server_id,
+160 -19
View File
@@ -20,6 +20,8 @@ from server.domain.repositories import (
logger = logging.getLogger("nexus.script_service")
_BG_EXEC_TASKS: set[asyncio.Task] = set()
_NEXUS_JOB_LOG_RE = re.compile(r"log=(/var/log/nexus-job/[^\s\"']+)")
_NEXUS_JOB_PID_RE = re.compile(r"pid=(\d+)")
@@ -95,15 +97,9 @@ class ScriptService:
# Resolve DB credential variables (if provided)
resolved_command = await self._substitute_db_vars(command, credential_id)
from server.application.services.script_jobs import (
build_long_task_command,
master_callback_url,
register_script_job,
)
from server.application.services.script_jobs import master_callback_url
callback_url = None
if long_task:
callback_url = master_callback_url()
callback_url = master_callback_url() if long_task else None
# Create execution record — use sanitized command (password redacted)
sanitized_command = await self._substitute_db_vars(command, credential_id, redact=True)
@@ -118,7 +114,10 @@ class ScriptService:
operator=operator,
)
execution = await self.execution_repo.create(execution)
await ses.init_live_from_execution(execution, long_task=long_task)
label = await self._execution_label(script_id, command)
live = await ses.init_live_from_execution(execution, long_task=long_task)
live["label"] = label
await ses.save_live(live)
await self._audit(
"execute_started", "script_execution", execution.id,
f"开始执行 {len(server_ids)}"
@@ -126,6 +125,132 @@ class ScriptService:
operator=operator,
)
self._schedule_background_execution(
execution_id=execution.id,
resolved_command=resolved_command,
server_ids=list(server_ids),
timeout=timeout,
operator=operator,
long_task=long_task,
callback_url=callback_url,
label=label,
)
return await self.execution_repo.get_by_id(execution.id)
@staticmethod
def _schedule_background_execution(**kwargs: Any) -> None:
task = asyncio.create_task(ScriptService._run_background_execution(**kwargs))
_BG_EXEC_TASKS.add(task)
task.add_done_callback(_BG_EXEC_TASKS.discard)
@staticmethod
async def _run_background_execution(
*,
execution_id: int,
resolved_command: str,
server_ids: List[int],
timeout: int,
operator: str,
long_task: bool,
callback_url: Optional[str],
label: str,
) -> None:
from server.infrastructure.database.session import AsyncSessionLocal
from server.infrastructure.database.script_repo import (
ScriptRepositoryImpl,
ScriptExecutionRepositoryImpl,
)
from server.infrastructure.database.db_credential_repo import DbCredentialRepositoryImpl
from server.infrastructure.database.server_repo import ServerRepositoryImpl
from server.infrastructure.database.audit_log_repo import AuditLogRepositoryImpl
async with AsyncSessionLocal() as session:
service = ScriptService(
script_repo=ScriptRepositoryImpl(session),
execution_repo=ScriptExecutionRepositoryImpl(session),
credential_repo=DbCredentialRepositoryImpl(session),
server_repo=ServerRepositoryImpl(session),
audit_repo=AuditLogRepositoryImpl(session),
)
try:
await service._run_execution_batches(
execution_id=execution_id,
resolved_command=resolved_command,
server_ids=server_ids,
timeout=timeout,
operator=operator,
long_task=long_task,
callback_url=callback_url,
label=label,
)
await session.commit()
except Exception:
logger.exception(
"Background script execution failed (execution_id=%s)", execution_id,
)
await session.rollback()
try:
await service._mark_execution_catastrophic_failure(
execution_id, operator, label,
)
await session.commit()
except Exception:
logger.exception(
"Failed to mark catastrophic failure for execution_id=%s",
execution_id,
)
await session.rollback()
async def _mark_execution_catastrophic_failure(
self,
execution_id: int,
operator: str,
label: str,
) -> None:
from server.application.services.script_execution_notify import notify_script_complete
view = await ses.get_execution_view(self.execution_repo, execution_id)
results = dict((view or {}).get("results") or {})
live = await ses.apply_update(
self.execution_repo,
execution_id,
status="failed",
results=results,
event_action="execution_failed",
event_detail="后台执行异常终止",
operator=operator,
terminal=True,
)
live["label"] = label
await ses.save_live(live)
await notify_script_complete(live, script_repo=self.script_repo)
await self._audit(
"execute_command", "script_execution", execution_id,
"后台执行异常终止",
operator=operator,
)
async def _run_execution_batches(
self,
*,
execution_id: int,
resolved_command: str,
server_ids: List[int],
timeout: int,
operator: str,
long_task: bool,
callback_url: Optional[str],
label: str,
) -> None:
from server.application.services.script_jobs import (
build_long_task_command,
register_script_job,
)
from server.application.services.script_execution_notify import (
notify_script_progress,
notify_script_complete,
)
batch_size = max(1, settings.SCRIPT_EXEC_BATCH_SIZE)
results: Dict[str, dict] = {}
batches = [
@@ -139,14 +264,14 @@ class ScriptService:
batch_idx,
len(batches),
len(batch),
execution.id,
execution_id,
)
per_server_commands: Optional[Dict[int, str]] = None
job_ids_by_server: Dict[int, str] = {}
if long_task:
per_server_commands = {}
for sid in batch:
job_id, secret = await register_script_job(execution.id, sid)
job_id, secret = await register_script_job(execution_id, sid)
job_ids_by_server[sid] = job_id
agent_key = await self._agent_api_key_for_server(sid)
per_server_commands[sid] = build_long_task_command(
@@ -156,15 +281,15 @@ class ScriptService:
batch,
resolved_command,
timeout,
execution_id=execution.id,
execution_id=execution_id,
per_server_commands=per_server_commands,
long_task=long_task,
job_ids_by_server=job_ids_by_server or None,
)
results.update(batch_results)
await ses.apply_update(
live = await ses.apply_update(
self.execution_repo,
execution.id,
execution_id,
status="running",
results=results,
event_action="batch_progress",
@@ -173,8 +298,10 @@ class ScriptService:
terminal=False,
long_task=long_task,
)
live["label"] = label
await ses.save_live(live)
await notify_script_progress(live, script_repo=self.script_repo)
# Determine overall status
if long_task:
start_failed = sum(
1 for r in results.values() if r.get("exit_code", -1) != 0
@@ -196,9 +323,9 @@ class ScriptService:
)
terminal = status in ses.TERMINAL_STATUSES
await ses.apply_update(
live = await ses.apply_update(
self.execution_repo,
execution.id,
execution_id,
status=status,
results=results,
event_action="execution_finished",
@@ -207,13 +334,26 @@ class ScriptService:
terminal=terminal,
long_task=long_task,
)
live["label"] = label
await ses.save_live(live)
await self._audit(
"execute_command", "script_execution", execution.id,
"execute_command", "script_execution", execution_id,
f"执行于 {len(server_ids)} 台: {status} ({failed_count} 台失败)",
operator=operator,
)
return await self.execution_repo.get_by_id(execution.id)
if terminal:
await notify_script_complete(live, script_repo=self.script_repo)
async def _execution_label(self, script_id: Optional[int], command: str) -> str:
if script_id:
script = await self.script_repo.get_by_id(script_id)
if script and script.name:
return script.name
text = (command or "").strip()
if len(text) > 48:
return text[:48] + ""
return text or "临时命令"
async def get_execution(self, id: int) -> Optional[ScriptExecution]:
return await self.execution_repo.get_by_id(id)
@@ -285,6 +425,7 @@ class ScriptService:
"completed_at": view.get("completed_at"),
"long_task": view.get("long_task", False),
"progress": view.get("progress"),
"label": view.get("label"),
"source": view.get("source"),
}
+2
View File
@@ -105,6 +105,7 @@ class Settings(BaseSettings):
NOTIFY_SYSTEM_REDIS: str = "true" # Redis 连接异常/恢复
NOTIFY_SYSTEM_MYSQL: str = "true" # MySQL 连接异常/恢复
NOTIFY_RESTART: str = "true" # Nexus 后端重启通知
NOTIFY_SCRIPT_COMPLETE: str = "true" # 脚本执行完成汇总(含看板链接)
# extra=ignore: .env 中与 MCP 共存的 MYSQL_* / NEXUS_API_BASE_URL 等不进入 Settings
model_config = SettingsConfigDict(
@@ -146,6 +147,7 @@ class Settings(BaseSettings):
"notify_system_redis": "NOTIFY_SYSTEM_REDIS",
"notify_system_mysql": "NOTIFY_SYSTEM_MYSQL",
"notify_restart": "NOTIFY_RESTART",
"notify_script_complete": "NOTIFY_SCRIPT_COMPLETE",
}
# Settings that require int conversion from DB string values
@@ -55,6 +55,47 @@ def _is_server_exec_success(entry: Any) -> bool:
return False
def _is_server_exec_done(entry: Any) -> bool:
"""True when a server has a non-pending result (counts toward done/remaining)."""
if not isinstance(entry, dict) or not entry:
return False
phase = str(entry.get("phase") or "").strip()
if phase == "pending":
return False
return True
def execution_progress_stats(
results: dict[str, Any],
server_ids: Optional[list] = None,
) -> dict[str, Any]:
"""Counts for UI / WebSocket: done, remaining, success, failed, total, progress."""
ids = server_ids
if ids is None:
ids = [int(k) for k in results if k != "_meta" and str(k).isdigit()]
total = len(ids)
done = 0
success = 0
failed_done = 0
for sid in ids:
entry = results.get(str(sid))
if not _is_server_exec_done(entry):
continue
done += 1
if _is_server_exec_success(entry):
success += 1
else:
failed_done += 1
return {
"total": total,
"done": done,
"remaining": max(0, total - done),
"success": success,
"failed": failed_done,
"progress": execution_progress_summary(results, ids),
}
def execution_progress_summary(
results: dict[str, Any],
server_ids: Optional[list] = None,
@@ -278,6 +319,7 @@ async def get_execution_view(
"long_task": live.get("long_task", False),
"progress": execution_progress_summary(results, live.get("server_ids")),
"credential_id": live.get("credential_id"),
"label": live.get("label"),
"source": "redis",
}
@@ -277,3 +277,43 @@ async def send_telegram_sync_complete(
lines.append(f"时间:{_now_cn()}")
return await send_telegram("\n".join(lines))
async def send_telegram_script_summary(
execution_id: int,
script_label: str,
operator: str,
status: str,
success_count: int,
failed_count: int,
total: int,
board_url: str,
) -> bool:
"""Send script execution summary (no per-server failure list) via Telegram."""
if not _notify_enabled(getattr(settings, "NOTIFY_SCRIPT_COMPLETE", "true")):
return False
safe_label = html.escape(sanitize_external_message(script_label, max_len=80))
safe_operator = html.escape(operator)
safe_url = html.escape(board_url)
if status == "completed":
icon = "🟢"
title = "脚本执行完成"
elif status == "failed":
icon = "🔴"
title = "脚本执行失败"
else:
icon = "🟡"
title = "脚本执行部分失败"
lines = [
f"{icon} <b>【{title}】</b>",
f"平台:{_system_name()}",
f"脚本:{safe_label} · 执行 #{execution_id}",
f"统计:成功 {success_count} 台 / 失败 {failed_count} 台 / 总计 {total}",
f"操作人:{safe_operator}",
f"详情:<a href=\"{safe_url}\">打开执行看板</a>",
f"时间:{_now_cn()}",
]
return await send_telegram("\n".join(lines))
@@ -0,0 +1,37 @@
"""Tests for script execution progress stats (done/remaining vs success/total)."""
from server.infrastructure.redis.script_execution_store import execution_progress_stats
def test_progress_stats_empty_results():
stats = execution_progress_stats({}, [1, 2, 3])
assert stats["total"] == 3
assert stats["done"] == 0
assert stats["remaining"] == 3
assert stats["success"] == 0
assert stats["progress"] == "0/3"
def test_progress_stats_mixed_success_and_failure():
results = {
"1": {"exit_code": 0, "status": "success"},
"2": {"exit_code": 1, "status": "failed"},
"3": {"phase": "pending"},
}
stats = execution_progress_stats(results, [1, 2, 3])
assert stats["done"] == 2
assert stats["remaining"] == 1
assert stats["success"] == 1
assert stats["failed"] == 1
assert stats["progress"] == "1/3"
def test_progress_stats_long_task_pending_not_done():
results = {
"10": {"phase": "pending", "exit_code": 0},
"11": {"phase": "done", "exit_code": 0, "status": "completed"},
}
stats = execution_progress_stats(results, [10, 11])
assert stats["done"] == 1
assert stats["remaining"] == 1
assert stats["success"] == 1
+1
View File
@@ -0,0 +1 @@
import{A as e,Er as t,F as n,N as r,Nr as i,Ur as a,Z as o,Zn as s,_r as c,ar as l,er as u,hr as d,k as f,or as p,rr as m,sr as h,tr as g,w as _,yr as v,zr as y,zt as b}from"./index-HeC-ymfd.js";import{o as x,t as S}from"./VContainer-Bqb4OsjX.js";import{n as C}from"./dataTable-esDY4cOk.js";import{t as w}from"./VChip-C-HpH-oj.js";import{t as T}from"./VSelect-CEXOntEU.js";import{t as E}from"./VDataTableServer-_AO1gvgs.js";import{n as D,t as O}from"./VRow-w4SO-kR5.js";import{t as k}from"./VSpacer-C31iLuvS.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=h({__name:`AlertsPage`,setup(h){let N=x(),P=i(!1),F=i([]),I=i(0),L=i(1),R=i(null),z=i(null),B=i([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),V=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],H=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],U=C([{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}]);async function W(){try{let e=await b.get(`/alert-history/stats`);B.value[0].value=String(e.today||0),B.value[1].value=String(e.active||0),B.value[2].value=String(e.recovered||0),B.value[3].value=e.top_server||``}catch{N(`加载统计失败`,`error`)}}async function G(){P.value=!0;try{let e=await b.get(`/alert-history/`,{page:L.value,per_page:20,type:R.value||void 0,status:z.value||void 0});F.value=e.items||[],I.value=e.total||0}catch{F.value=[]}finally{P.value=!1}}function K(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function q(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{W(),G()}),(i,d)=>(c(),g(S,{fluid:``,class:`pa-6`},{default:t(()=>[p(O,{class:`mb-4`},{default:t(()=>[(c(!0),m(s,null,v(B.value,n=>(c(),g(D,{cols:`12`,sm:`6`,lg:`3`,key:n.label},{default:t(()=>[p(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:t(()=>[p(f,null,{append:t(()=>[p(o,{color:n.color,size:`30`},{default:t(()=>[l(a(n.icon),1)]),_:2},1032,[`color`])]),default:t(()=>[p(e,{class:`text-body-small`},{default:t(()=>[l(a(n.label),1)]),_:2},1024),p(e,null,{default:t(()=>[l(a(n.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),p(r,{elevation:`0`,border:``,rounded:`lg`},{default:t(()=>[p(n,{class:`d-flex align-center`},{default:t(()=>[d[5]||=l(` 告警历史 `,-1),p(k),p(T,{modelValue:R.value,"onUpdate:modelValue":[d[0]||=e=>R.value=e,d[1]||=e=>{L.value=1,G()}],items:V,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),p(T,{modelValue:z.value,"onUpdate:modelValue":[d[2]||=e=>z.value=e,d[3]||=e=>{L.value=1,G()}],items:H,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),p(E,{items:F.value,headers:y(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{L.value=e,G()}},{"item.alert_type":t(({item:e})=>[p(w,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:t(()=>[p(o,{size:`12`},{default:t(()=>[l(a(q(e.alert_type)),1)]),_:2},1024)]),default:t(()=>[l(` `+a(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":t(({item:e})=>[u(`span`,A,a(e.server_name),1)]),"item.value":t(({item:e})=>[u(`span`,j,a(e.value),1)]),"item.is_recovery":t(({item:e})=>[e.is_recovery?(c(),g(w,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:t(()=>[...d[6]||=[l(`已恢复`,-1)]]),_:1})):(c(),g(w,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:t(()=>[...d[7]||=[l(`告警中`,-1)]]),_:1}))]),"item.created_at":t(({item:e})=>[u(`span`,M,a(e.created_at),1)]),"no-data":t(()=>[...d[8]||=[u(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{N as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-BBtNL0eJ.js";import{n as r,t as i}from"./VRow-sbIKY3fI.js";import{A as a,B as o,Cr as s,F as c,Gr as l,Mr as u,N as d,R as f,T as p,Tr as m,Yr as h,dr as g,fr as _,j as v,lr as y,or as b,pr as x,qt as S,rr as C,sr as w,ut as T,xr as E,zr as D}from"./index-DXg_pn7T.js";import{n as O}from"./dataTable-esDY4cOk.js";import{t as k}from"./VDataTableServer-CAOCfrD0.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=x({__name:`AlertsPage`,setup(x){let N=e(),P=D(!1),F=D([]),I=D(0),L=D(1),R=D(null),z=D(null),B=D([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),V=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],H=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],U=O([{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}]);async function W(){try{let e=await S.get(`/alert-history/stats`);B.value[0].value=String(e.today||0),B.value[1].value=String(e.active||0),B.value[2].value=String(e.recovered||0),B.value[3].value=e.top_server||``}catch{N(`加载统计失败`,`error`)}}async function G(){P.value=!0;try{let e=await S.get(`/alert-history/`,{page:L.value,per_page:20,type:R.value||void 0,status:z.value||void 0});F.value=e.items||[],I.value=e.total||0}catch{F.value=[]}finally{P.value=!1}}function K(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function q(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return E(()=>{W(),G()}),(e,x)=>(s(),w(n,{fluid:``,class:`pa-6`},{default:u(()=>[_(i,{class:`mb-4`},{default:u(()=>[(s(!0),y(C,null,m(B.value,e=>(s(),w(r,{cols:`12`,sm:`6`,lg:`3`,key:e.label},{default:u(()=>[_(p,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:u(()=>[_(a,null,{append:u(()=>[_(T,{color:e.color,size:`30`},{default:u(()=>[g(h(e.icon),1)]),_:2},1032,[`color`])]),default:u(()=>[_(v,{class:`text-body-small`},{default:u(()=>[g(h(e.label),1)]),_:2},1024),_(v,null,{default:u(()=>[g(h(e.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),_(f,{elevation:`0`,border:``,rounded:`lg`},{default:u(()=>[_(o,{class:`d-flex align-center`},{default:u(()=>[x[5]||=g(` 告警历史 `,-1),_(d),_(t,{modelValue:R.value,"onUpdate:modelValue":[x[0]||=e=>R.value=e,x[1]||=e=>{L.value=1,G()}],items:V,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),_(t,{modelValue:z.value,"onUpdate:modelValue":[x[2]||=e=>z.value=e,x[3]||=e=>{L.value=1,G()}],items:H,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),_(k,{items:F.value,headers:l(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":x[4]||=e=>{L.value=e,G()}},{"item.alert_type":u(({item:e})=>[_(c,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:u(()=>[_(T,{size:`12`},{default:u(()=>[g(h(q(e.alert_type)),1)]),_:2},1024)]),default:u(()=>[g(` `+h(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":u(({item:e})=>[b(`span`,A,h(e.server_name),1)]),"item.value":u(({item:e})=>[b(`span`,j,h(e.value),1)]),"item.is_recovery":u(({item:e})=>[e.is_recovery?(s(),w(c,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:u(()=>[...x[6]||=[g(`已恢复`,-1)]]),_:1})):(s(),w(c,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:u(()=>[...x[7]||=[g(`告警中`,-1)]]),_:1}))]),"item.created_at":u(({item:e})=>[b(`span`,M,h(e.created_at),1)]),"no-data":u(()=>[...x[8]||=[b(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{N as default};
+1
View File
@@ -0,0 +1 @@
import{$n as e,A as t,Ar as n,Br as r,Cr as i,F as a,N as o,Rt as s,X as c,Xn as l,_r as u,ar as d,er as f,hr as p,ir as m,k as h,nr as g,or as _,pr as v,w as y}from"./index-Da-oPxMv.js";import{o as b,t as x}from"./VContainer-Dp-8rduj.js";import{t as S}from"./VChip-uNN5BiCx.js";import{t as C}from"./VSelect-B1u55nVH.js";import{t as w}from"./VDataTableServer-BLAQDDBi.js";import{n as T,t as E}from"./VRow-Rr6vqjSj.js";import{t as D}from"./VSpacer-ZMhNXvUl.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=_({__name:`AlertsPage`,setup(_){let j=b(),M=n(!1),N=n([]),P=n(0),F=n(1),I=n(null),L=n(null),R=n([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await s.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await s.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return v(()=>{H(),U()}),(n,s)=>(p(),f(x,{fluid:``,class:`pa-6`},{default:i(()=>[d(E,{class:`mb-4`},{default:i(()=>[(p(!0),g(l,null,u(R.value,e=>(p(),f(T,{cols:`12`,sm:`6`,lg:`3`,key:e.label},{default:i(()=>[d(y,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:i(()=>[d(h,null,{append:i(()=>[d(c,{color:e.color,size:`30`},{default:i(()=>[m(r(e.icon),1)]),_:2},1032,[`color`])]),default:i(()=>[d(t,{class:`text-body-small`},{default:i(()=>[m(r(e.label),1)]),_:2},1024),d(t,null,{default:i(()=>[m(r(e.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),d(o,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[d(a,{class:`d-flex align-center`},{default:i(()=>[s[5]||=m(` 告警历史 `,-1),d(D),d(C,{modelValue:I.value,"onUpdate:modelValue":[s[0]||=e=>I.value=e,s[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),d(C,{modelValue:L.value,"onUpdate:modelValue":[s[2]||=e=>L.value=e,s[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),d(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":s[4]||=e=>{F.value=e,U()}},{"item.alert_type":i(({item:e})=>[d(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:i(()=>[d(c,{size:`12`},{default:i(()=>[m(r(G(e.alert_type)),1)]),_:2},1024)]),default:i(()=>[m(` `+r(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":i(({item:t})=>[e(`span`,O,r(t.server_name),1)]),"item.value":i(({item:t})=>[e(`span`,k,r(t.value),1)]),"item.is_recovery":i(({item:e})=>[e.is_recovery?(p(),f(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:i(()=>[...s[6]||=[m(`已恢复`,-1)]]),_:1})):(p(),f(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:i(()=>[...s[7]||=[m(`告警中`,-1)]]),_:1}))]),"item.created_at":i(({item:t})=>[e(`span`,A,r(t.created_at),1)]),"no-data":i(()=>[...s[8]||=[e(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,Er as t,F as n,N as r,Nr as i,Ur as a,Z as o,Zn as s,_r as c,ar as l,er as u,hr as d,k as f,or as p,rr as m,sr as h,tr as g,w as _,yr as v,zr as y,zt as b}from"./index-Hwt84p4T.js";import{o as x,t as S}from"./VContainer-DVdhFFDK.js";import{n as C}from"./dataTable-esDY4cOk.js";import{t as w}from"./VChip-BOlm6rKc.js";import{t as T}from"./VSelect-Ce9_iAcL.js";import{t as E}from"./VDataTableServer-Ch0R1ufY.js";import{n as D,t as O}from"./VRow-CW1Gj3Lm.js";import{t as k}from"./VSpacer-Dz9VwXyE.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=h({__name:`AlertsPage`,setup(h){let N=x(),P=i(!1),F=i([]),I=i(0),L=i(1),R=i(null),z=i(null),B=i([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),V=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],H=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],U=C([{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}]);async function W(){try{let e=await b.get(`/alert-history/stats`);B.value[0].value=String(e.today||0),B.value[1].value=String(e.active||0),B.value[2].value=String(e.recovered||0),B.value[3].value=e.top_server||``}catch{N(`加载统计失败`,`error`)}}async function G(){P.value=!0;try{let e=await b.get(`/alert-history/`,{page:L.value,per_page:20,type:R.value||void 0,status:z.value||void 0});F.value=e.items||[],I.value=e.total||0}catch{F.value=[]}finally{P.value=!1}}function K(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function q(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{W(),G()}),(i,d)=>(c(),g(S,{fluid:``,class:`pa-6`},{default:t(()=>[p(O,{class:`mb-4`},{default:t(()=>[(c(!0),m(s,null,v(B.value,n=>(c(),g(D,{cols:`12`,sm:`6`,lg:`3`,key:n.label},{default:t(()=>[p(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:t(()=>[p(f,null,{append:t(()=>[p(o,{color:n.color,size:`30`},{default:t(()=>[l(a(n.icon),1)]),_:2},1032,[`color`])]),default:t(()=>[p(e,{class:`text-body-small`},{default:t(()=>[l(a(n.label),1)]),_:2},1024),p(e,null,{default:t(()=>[l(a(n.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),p(r,{elevation:`0`,border:``,rounded:`lg`},{default:t(()=>[p(n,{class:`d-flex align-center`},{default:t(()=>[d[5]||=l(` 告警历史 `,-1),p(k),p(T,{modelValue:R.value,"onUpdate:modelValue":[d[0]||=e=>R.value=e,d[1]||=e=>{L.value=1,G()}],items:V,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),p(T,{modelValue:z.value,"onUpdate:modelValue":[d[2]||=e=>z.value=e,d[3]||=e=>{L.value=1,G()}],items:H,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),p(E,{items:F.value,headers:y(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{L.value=e,G()}},{"item.alert_type":t(({item:e})=>[p(w,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:t(()=>[p(o,{size:`12`},{default:t(()=>[l(a(q(e.alert_type)),1)]),_:2},1024)]),default:t(()=>[l(` `+a(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":t(({item:e})=>[u(`span`,A,a(e.server_name),1)]),"item.value":t(({item:e})=>[u(`span`,j,a(e.value),1)]),"item.is_recovery":t(({item:e})=>[e.is_recovery?(c(),g(w,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:t(()=>[...d[6]||=[l(`已恢复`,-1)]]),_:1})):(c(),g(w,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:t(()=>[...d[7]||=[l(`告警中`,-1)]]),_:1}))]),"item.created_at":t(({item:e})=>[u(`span`,M,a(e.created_at),1)]),"no-data":t(()=>[...d[8]||=[u(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{N as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,F as t,N as n,Vr as r,Z as i,Zn as a,ar as o,er as s,gr as c,jr as l,k as u,mr as d,or as f,rr as p,sr as m,tr as h,vr as g,w as _,wr as v,zt as y}from"./index-DhXUzl5h.js";import{o as b,t as x}from"./VContainer-CrR_anyV.js";import{t as S}from"./VChip-Bj2Bn9Ad.js";import{t as C}from"./VSelect-B8ti2NSE.js";import{t as w}from"./VDataTableServer-DGuK8add.js";import{n as T,t as E}from"./VRow-C2jem5w2.js";import{t as D}from"./VSpacer-DhDsDhMR.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=m({__name:`AlertsPage`,setup(m){let j=b(),M=l(!1),N=l([]),P=l(0),F=l(1),I=l(null),L=l(null),R=l([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await y.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await y.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{H(),U()}),(l,d)=>(c(),h(x,{fluid:``,class:`pa-6`},{default:v(()=>[f(E,{class:`mb-4`},{default:v(()=>[(c(!0),p(a,null,g(R.value,t=>(c(),h(T,{cols:`12`,sm:`6`,lg:`3`,key:t.label},{default:v(()=>[f(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:v(()=>[f(u,null,{append:v(()=>[f(i,{color:t.color,size:`30`},{default:v(()=>[o(r(t.icon),1)]),_:2},1032,[`color`])]),default:v(()=>[f(e,{class:`text-body-small`},{default:v(()=>[o(r(t.label),1)]),_:2},1024),f(e,null,{default:v(()=>[o(r(t.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),f(n,{elevation:`0`,border:``,rounded:`lg`},{default:v(()=>[f(t,{class:`d-flex align-center`},{default:v(()=>[d[5]||=o(` 告警历史 `,-1),f(D),f(C,{modelValue:I.value,"onUpdate:modelValue":[d[0]||=e=>I.value=e,d[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),f(C,{modelValue:L.value,"onUpdate:modelValue":[d[2]||=e=>L.value=e,d[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),f(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{F.value=e,U()}},{"item.alert_type":v(({item:e})=>[f(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:v(()=>[f(i,{size:`12`},{default:v(()=>[o(r(G(e.alert_type)),1)]),_:2},1024)]),default:v(()=>[o(` `+r(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":v(({item:e})=>[s(`span`,O,r(e.server_name),1)]),"item.value":v(({item:e})=>[s(`span`,k,r(e.value),1)]),"item.is_recovery":v(({item:e})=>[e.is_recovery?(c(),h(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[6]||=[o(`已恢复`,-1)]]),_:1})):(c(),h(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[7]||=[o(`告警中`,-1)]]),_:1}))]),"item.created_at":v(({item:e})=>[s(`span`,A,r(e.created_at),1)]),"no-data":v(()=>[...d[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,F as t,N as n,Vr as r,Z as i,Zn as a,ar as o,er as s,gr as c,jr as l,k as u,mr as d,or as f,rr as p,sr as m,tr as h,vr as g,w as _,wr as v,zt as y}from"./index-gfOrpdmy.js";import{o as b,t as x}from"./VContainer-DoAVnyqr.js";import{t as S}from"./VChip-sW1zi7V6.js";import{t as C}from"./VSelect-KxRF8W0i.js";import{t as w}from"./VDataTableServer-LfNDokVe.js";import{n as T,t as E}from"./VRow-AEPVE_-F.js";import{t as D}from"./VSpacer-ChMx8Hym.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=m({__name:`AlertsPage`,setup(m){let j=b(),M=l(!1),N=l([]),P=l(0),F=l(1),I=l(null),L=l(null),R=l([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await y.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await y.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{H(),U()}),(l,d)=>(c(),h(x,{fluid:``,class:`pa-6`},{default:v(()=>[f(E,{class:`mb-4`},{default:v(()=>[(c(!0),p(a,null,g(R.value,t=>(c(),h(T,{cols:`12`,sm:`6`,lg:`3`,key:t.label},{default:v(()=>[f(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:v(()=>[f(u,null,{append:v(()=>[f(i,{color:t.color,size:`30`},{default:v(()=>[o(r(t.icon),1)]),_:2},1032,[`color`])]),default:v(()=>[f(e,{class:`text-body-small`},{default:v(()=>[o(r(t.label),1)]),_:2},1024),f(e,null,{default:v(()=>[o(r(t.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),f(n,{elevation:`0`,border:``,rounded:`lg`},{default:v(()=>[f(t,{class:`d-flex align-center`},{default:v(()=>[d[5]||=o(` 告警历史 `,-1),f(D),f(C,{modelValue:I.value,"onUpdate:modelValue":[d[0]||=e=>I.value=e,d[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),f(C,{modelValue:L.value,"onUpdate:modelValue":[d[2]||=e=>L.value=e,d[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),f(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{F.value=e,U()}},{"item.alert_type":v(({item:e})=>[f(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:v(()=>[f(i,{size:`12`},{default:v(()=>[o(r(G(e.alert_type)),1)]),_:2},1024)]),default:v(()=>[o(` `+r(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":v(({item:e})=>[s(`span`,O,r(e.server_name),1)]),"item.value":v(({item:e})=>[s(`span`,k,r(e.value),1)]),"item.is_recovery":v(({item:e})=>[e.is_recovery?(c(),h(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[6]||=[o(`已恢复`,-1)]]),_:1})):(c(),h(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[7]||=[o(`告警中`,-1)]]),_:1}))]),"item.created_at":v(({item:e})=>[s(`span`,A,r(e.created_at),1)]),"no-data":v(()=>[...d[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,F as t,N as n,Vr as r,Z as i,Zn as a,ar as o,er as s,gr as c,jr as l,k as u,mr as d,or as f,rr as p,sr as m,tr as h,vr as g,w as _,wr as v,zt as y}from"./index-ia8w6hh3.js";import{o as b,t as x}from"./VContainer-Cg-YgCG2.js";import{t as S}from"./VChip-gd2nTpu3.js";import{t as C}from"./VSelect-DesLFoAg.js";import{t as w}from"./VDataTableServer-D4zQCwj2.js";import{n as T,t as E}from"./VRow-DRmOLWn-.js";import{t as D}from"./VSpacer-BtntPGL0.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=m({__name:`AlertsPage`,setup(m){let j=b(),M=l(!1),N=l([]),P=l(0),F=l(1),I=l(null),L=l(null),R=l([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await y.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await y.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{H(),U()}),(l,d)=>(c(),h(x,{fluid:``,class:`pa-6`},{default:v(()=>[f(E,{class:`mb-4`},{default:v(()=>[(c(!0),p(a,null,g(R.value,t=>(c(),h(T,{cols:`12`,sm:`6`,lg:`3`,key:t.label},{default:v(()=>[f(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:v(()=>[f(u,null,{append:v(()=>[f(i,{color:t.color,size:`30`},{default:v(()=>[o(r(t.icon),1)]),_:2},1032,[`color`])]),default:v(()=>[f(e,{class:`text-body-small`},{default:v(()=>[o(r(t.label),1)]),_:2},1024),f(e,null,{default:v(()=>[o(r(t.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),f(n,{elevation:`0`,border:``,rounded:`lg`},{default:v(()=>[f(t,{class:`d-flex align-center`},{default:v(()=>[d[5]||=o(` 告警历史 `,-1),f(D),f(C,{modelValue:I.value,"onUpdate:modelValue":[d[0]||=e=>I.value=e,d[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),f(C,{modelValue:L.value,"onUpdate:modelValue":[d[2]||=e=>L.value=e,d[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),f(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{F.value=e,U()}},{"item.alert_type":v(({item:e})=>[f(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:v(()=>[f(i,{size:`12`},{default:v(()=>[o(r(G(e.alert_type)),1)]),_:2},1024)]),default:v(()=>[o(` `+r(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":v(({item:e})=>[s(`span`,O,r(e.server_name),1)]),"item.value":v(({item:e})=>[s(`span`,k,r(e.value),1)]),"item.is_recovery":v(({item:e})=>[e.is_recovery?(c(),h(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[6]||=[o(`已恢复`,-1)]]),_:1})):(c(),h(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[7]||=[o(`告警中`,-1)]]),_:1}))]),"item.created_at":v(({item:e})=>[s(`span`,A,r(e.created_at),1)]),"no-data":v(()=>[...d[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,Er as t,F as n,N as r,Nr as i,Ur as a,Z as o,Zn as s,_r as c,ar as l,er as u,hr as d,k as f,or as p,rr as m,sr as h,tr as g,w as _,yr as v,zr as y,zt as b}from"./index-Dp4iCzbs.js";import{o as x,t as S}from"./VContainer-BpcBPa4e.js";import{n as C}from"./dataTable-esDY4cOk.js";import{t as w}from"./VChip-DBjCm_hy.js";import{t as T}from"./VSelect-B3aZ6TxZ.js";import{t as E}from"./VDataTableServer-5YTAzdGq.js";import{n as D,t as O}from"./VRow-B_I9Fnty.js";import{t as k}from"./VSpacer-Dij81TMC.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=h({__name:`AlertsPage`,setup(h){let N=x(),P=i(!1),F=i([]),I=i(0),L=i(1),R=i(null),z=i(null),B=i([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),V=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],H=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],U=C([{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}]);async function W(){try{let e=await b.get(`/alert-history/stats`);B.value[0].value=String(e.today||0),B.value[1].value=String(e.active||0),B.value[2].value=String(e.recovered||0),B.value[3].value=e.top_server||``}catch{N(`加载统计失败`,`error`)}}async function G(){P.value=!0;try{let e=await b.get(`/alert-history/`,{page:L.value,per_page:20,type:R.value||void 0,status:z.value||void 0});F.value=e.items||[],I.value=e.total||0}catch{F.value=[]}finally{P.value=!1}}function K(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function q(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{W(),G()}),(i,d)=>(c(),g(S,{fluid:``,class:`pa-6`},{default:t(()=>[p(O,{class:`mb-4`},{default:t(()=>[(c(!0),m(s,null,v(B.value,n=>(c(),g(D,{cols:`12`,sm:`6`,lg:`3`,key:n.label},{default:t(()=>[p(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:t(()=>[p(f,null,{append:t(()=>[p(o,{color:n.color,size:`30`},{default:t(()=>[l(a(n.icon),1)]),_:2},1032,[`color`])]),default:t(()=>[p(e,{class:`text-body-small`},{default:t(()=>[l(a(n.label),1)]),_:2},1024),p(e,null,{default:t(()=>[l(a(n.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),p(r,{elevation:`0`,border:``,rounded:`lg`},{default:t(()=>[p(n,{class:`d-flex align-center`},{default:t(()=>[d[5]||=l(` 告警历史 `,-1),p(k),p(T,{modelValue:R.value,"onUpdate:modelValue":[d[0]||=e=>R.value=e,d[1]||=e=>{L.value=1,G()}],items:V,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),p(T,{modelValue:z.value,"onUpdate:modelValue":[d[2]||=e=>z.value=e,d[3]||=e=>{L.value=1,G()}],items:H,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),p(E,{items:F.value,headers:y(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{L.value=e,G()}},{"item.alert_type":t(({item:e})=>[p(w,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:t(()=>[p(o,{size:`12`},{default:t(()=>[l(a(q(e.alert_type)),1)]),_:2},1024)]),default:t(()=>[l(` `+a(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":t(({item:e})=>[u(`span`,A,a(e.server_name),1)]),"item.value":t(({item:e})=>[u(`span`,j,a(e.value),1)]),"item.is_recovery":t(({item:e})=>[e.is_recovery?(c(),g(w,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:t(()=>[...d[6]||=[l(`已恢复`,-1)]]),_:1})):(c(),g(w,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:t(()=>[...d[7]||=[l(`告警中`,-1)]]),_:1}))]),"item.created_at":t(({item:e})=>[u(`span`,M,a(e.created_at),1)]),"no-data":t(()=>[...d[8]||=[u(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{N as default};
+1
View File
@@ -0,0 +1 @@
import{a as e,o as t}from"./VSelectionControl-EvpbLA8N.js";import{n,t as r}from"./VRow-ECYmMAi9.js";import{$n as i,A as a,B as o,F as s,Fr as c,Gr as l,N as u,Or as d,R as f,T as p,Ut as m,Vr as h,_r as g,ar as _,cr as v,j as y,lr as b,nr as x,rr as S,sr as C,ut as w,xr as T,yr as E}from"./index-B-qGIXx8.js";import{n as D}from"./dataTable-esDY4cOk.js";import{t as O}from"./VSelect-D0D-yfrH.js";import{t as k}from"./VDataTableServer-DCjhqS-Y.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=b({__name:`AlertsPage`,setup(b){let N=e(),P=c(!1),F=c([]),I=c(0),L=c(1),R=c(null),z=c(null),B=c([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),V=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],H=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],U=D([{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}]);async function W(){try{let e=await m.get(`/alert-history/stats`);B.value[0].value=String(e.today||0),B.value[1].value=String(e.active||0),B.value[2].value=String(e.recovered||0),B.value[3].value=e.top_server||``}catch{N(`加载统计失败`,`error`)}}async function G(){P.value=!0;try{let e=await m.get(`/alert-history/`,{page:L.value,per_page:20,type:R.value||void 0,status:z.value||void 0});F.value=e.items||[],I.value=e.total||0}catch{F.value=[]}finally{P.value=!1}}function K(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function q(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return g(()=>{W(),G()}),(e,c)=>(E(),S(t,{fluid:``,class:`pa-6`},{default:d(()=>[v(r,{class:`mb-4`},{default:d(()=>[(E(!0),_(i,null,T(B.value,e=>(E(),S(n,{cols:`12`,sm:`6`,lg:`3`,key:e.label},{default:d(()=>[v(p,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:d(()=>[v(a,null,{append:d(()=>[v(w,{color:e.color,size:`30`},{default:d(()=>[C(l(e.icon),1)]),_:2},1032,[`color`])]),default:d(()=>[v(y,{class:`text-body-small`},{default:d(()=>[C(l(e.label),1)]),_:2},1024),v(y,null,{default:d(()=>[C(l(e.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),v(f,{elevation:`0`,border:``,rounded:`lg`},{default:d(()=>[v(o,{class:`d-flex align-center`},{default:d(()=>[c[5]||=C(` 告警历史 `,-1),v(u),v(O,{modelValue:R.value,"onUpdate:modelValue":[c[0]||=e=>R.value=e,c[1]||=e=>{L.value=1,G()}],items:V,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),v(O,{modelValue:z.value,"onUpdate:modelValue":[c[2]||=e=>z.value=e,c[3]||=e=>{L.value=1,G()}],items:H,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),v(k,{items:F.value,headers:h(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":c[4]||=e=>{L.value=e,G()}},{"item.alert_type":d(({item:e})=>[v(s,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:d(()=>[v(w,{size:`12`},{default:d(()=>[C(l(q(e.alert_type)),1)]),_:2},1024)]),default:d(()=>[C(` `+l(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":d(({item:e})=>[x(`span`,A,l(e.server_name),1)]),"item.value":d(({item:e})=>[x(`span`,j,l(e.value),1)]),"item.is_recovery":d(({item:e})=>[e.is_recovery?(E(),S(s,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:d(()=>[...c[6]||=[C(`已恢复`,-1)]]),_:1})):(E(),S(s,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:d(()=>[...c[7]||=[C(`告警中`,-1)]]),_:1}))]),"item.created_at":d(({item:e})=>[x(`span`,M,l(e.created_at),1)]),"no-data":d(()=>[...c[8]||=[x(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{N as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,Er as t,F as n,N as r,Nr as i,Ur as a,Z as o,Zn as s,_r as c,ar as l,er as u,hr as d,k as f,or as p,rr as m,sr as h,tr as g,w as _,yr as v,zt as y}from"./index-DoaDMa1C.js";import{o as b,t as x}from"./VContainer-BQRFgmV8.js";import{t as S}from"./VChip-w-VUeBu6.js";import{t as C}from"./VSelect-lvvpsnJa.js";import{t as w}from"./VDataTableServer-CqSShzYP.js";import{n as T,t as E}from"./VRow-CQuw1Sq-.js";import{t as D}from"./VSpacer-DctU2jOI.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=h({__name:`AlertsPage`,setup(h){let j=b(),M=i(!1),N=i([]),P=i(0),F=i(1),I=i(null),L=i(null),R=i([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await y.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await y.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{H(),U()}),(i,d)=>(c(),g(x,{fluid:``,class:`pa-6`},{default:t(()=>[p(E,{class:`mb-4`},{default:t(()=>[(c(!0),m(s,null,v(R.value,n=>(c(),g(T,{cols:`12`,sm:`6`,lg:`3`,key:n.label},{default:t(()=>[p(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:t(()=>[p(f,null,{append:t(()=>[p(o,{color:n.color,size:`30`},{default:t(()=>[l(a(n.icon),1)]),_:2},1032,[`color`])]),default:t(()=>[p(e,{class:`text-body-small`},{default:t(()=>[l(a(n.label),1)]),_:2},1024),p(e,null,{default:t(()=>[l(a(n.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),p(r,{elevation:`0`,border:``,rounded:`lg`},{default:t(()=>[p(n,{class:`d-flex align-center`},{default:t(()=>[d[5]||=l(` 告警历史 `,-1),p(D),p(C,{modelValue:I.value,"onUpdate:modelValue":[d[0]||=e=>I.value=e,d[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),p(C,{modelValue:L.value,"onUpdate:modelValue":[d[2]||=e=>L.value=e,d[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),p(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{F.value=e,U()}},{"item.alert_type":t(({item:e})=>[p(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:t(()=>[p(o,{size:`12`},{default:t(()=>[l(a(G(e.alert_type)),1)]),_:2},1024)]),default:t(()=>[l(` `+a(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":t(({item:e})=>[u(`span`,O,a(e.server_name),1)]),"item.value":t(({item:e})=>[u(`span`,k,a(e.value),1)]),"item.is_recovery":t(({item:e})=>[e.is_recovery?(c(),g(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:t(()=>[...d[6]||=[l(`已恢复`,-1)]]),_:1})):(c(),g(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:t(()=>[...d[7]||=[l(`告警中`,-1)]]),_:1}))]),"item.created_at":t(({item:e})=>[u(`span`,A,a(e.created_at),1)]),"no-data":t(()=>[...d[8]||=[u(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,Er as t,F as n,N as r,Nr as i,Ur as a,Z as o,Zn as s,_r as c,ar as l,er as u,hr as d,k as f,or as p,rr as m,sr as h,tr as g,w as _,yr as v,zt as y}from"./index-DefLgbfN.js";import{o as b,t as x}from"./VContainer-Cfs-evp_.js";import{t as S}from"./VChip-B776T65H.js";import{t as C}from"./VSelect-CI0l_G9L.js";import{t as w}from"./VDataTableServer-BVvotZW1.js";import{n as T,t as E}from"./VRow-DkDIFkCo.js";import{t as D}from"./VSpacer-K-VIfO9Y.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=h({__name:`AlertsPage`,setup(h){let j=b(),M=i(!1),N=i([]),P=i(0),F=i(1),I=i(null),L=i(null),R=i([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await y.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await y.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{H(),U()}),(i,d)=>(c(),g(x,{fluid:``,class:`pa-6`},{default:t(()=>[p(E,{class:`mb-4`},{default:t(()=>[(c(!0),m(s,null,v(R.value,n=>(c(),g(T,{cols:`12`,sm:`6`,lg:`3`,key:n.label},{default:t(()=>[p(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:t(()=>[p(f,null,{append:t(()=>[p(o,{color:n.color,size:`30`},{default:t(()=>[l(a(n.icon),1)]),_:2},1032,[`color`])]),default:t(()=>[p(e,{class:`text-body-small`},{default:t(()=>[l(a(n.label),1)]),_:2},1024),p(e,null,{default:t(()=>[l(a(n.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),p(r,{elevation:`0`,border:``,rounded:`lg`},{default:t(()=>[p(n,{class:`d-flex align-center`},{default:t(()=>[d[5]||=l(` 告警历史 `,-1),p(D),p(C,{modelValue:I.value,"onUpdate:modelValue":[d[0]||=e=>I.value=e,d[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),p(C,{modelValue:L.value,"onUpdate:modelValue":[d[2]||=e=>L.value=e,d[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),p(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{F.value=e,U()}},{"item.alert_type":t(({item:e})=>[p(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:t(()=>[p(o,{size:`12`},{default:t(()=>[l(a(G(e.alert_type)),1)]),_:2},1024)]),default:t(()=>[l(` `+a(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":t(({item:e})=>[u(`span`,O,a(e.server_name),1)]),"item.value":t(({item:e})=>[u(`span`,k,a(e.value),1)]),"item.is_recovery":t(({item:e})=>[e.is_recovery?(c(),g(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:t(()=>[...d[6]||=[l(`已恢复`,-1)]]),_:1})):(c(),g(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:t(()=>[...d[7]||=[l(`告警中`,-1)]]),_:1}))]),"item.created_at":t(({item:e})=>[u(`span`,A,a(e.created_at),1)]),"no-data":t(()=>[...d[8]||=[u(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,F as t,N as n,Vr as r,Z as i,Zn as a,ar as o,er as s,gr as c,jr as l,k as u,mr as d,or as f,rr as p,sr as m,tr as h,vr as g,w as _,wr as v,zt as y}from"./index-3SWW3Wj_.js";import{o as b,t as x}from"./VContainer-B79RFM4s.js";import{t as S}from"./VChip-CMAdQZRJ.js";import{t as C}from"./VSelect-CNVSTEnc.js";import{t as w}from"./VDataTableServer-mXWi-ccO.js";import{n as T,t as E}from"./VRow-CEurQEX3.js";import{t as D}from"./VSpacer-Lz_Er0LP.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=m({__name:`AlertsPage`,setup(m){let j=b(),M=l(!1),N=l([]),P=l(0),F=l(1),I=l(null),L=l(null),R=l([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await y.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await y.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{H(),U()}),(l,d)=>(c(),h(x,{fluid:``,class:`pa-6`},{default:v(()=>[f(E,{class:`mb-4`},{default:v(()=>[(c(!0),p(a,null,g(R.value,t=>(c(),h(T,{cols:`12`,sm:`6`,lg:`3`,key:t.label},{default:v(()=>[f(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:v(()=>[f(u,null,{append:v(()=>[f(i,{color:t.color,size:`30`},{default:v(()=>[o(r(t.icon),1)]),_:2},1032,[`color`])]),default:v(()=>[f(e,{class:`text-body-small`},{default:v(()=>[o(r(t.label),1)]),_:2},1024),f(e,null,{default:v(()=>[o(r(t.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),f(n,{elevation:`0`,border:``,rounded:`lg`},{default:v(()=>[f(t,{class:`d-flex align-center`},{default:v(()=>[d[5]||=o(` 告警历史 `,-1),f(D),f(C,{modelValue:I.value,"onUpdate:modelValue":[d[0]||=e=>I.value=e,d[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),f(C,{modelValue:L.value,"onUpdate:modelValue":[d[2]||=e=>L.value=e,d[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),f(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{F.value=e,U()}},{"item.alert_type":v(({item:e})=>[f(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:v(()=>[f(i,{size:`12`},{default:v(()=>[o(r(G(e.alert_type)),1)]),_:2},1024)]),default:v(()=>[o(` `+r(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":v(({item:e})=>[s(`span`,O,r(e.server_name),1)]),"item.value":v(({item:e})=>[s(`span`,k,r(e.value),1)]),"item.is_recovery":v(({item:e})=>[e.is_recovery?(c(),h(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[6]||=[o(`已恢复`,-1)]]),_:1})):(c(),h(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[7]||=[o(`告警中`,-1)]]),_:1}))]),"item.created_at":v(({item:e})=>[s(`span`,A,r(e.created_at),1)]),"no-data":v(()=>[...d[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,F as t,N as n,Vr as r,Z as i,Zn as a,ar as o,er as s,gr as c,jr as l,k as u,mr as d,or as f,rr as p,sr as m,tr as h,vr as g,w as _,wr as v,zt as y}from"./index-BoZyi8Cu.js";import{o as b,t as x}from"./VContainer-BT9w_m28.js";import{t as S}from"./VChip-BVR48u8E.js";import{t as C}from"./VSelect-BuZWt-gO.js";import{t as w}from"./VDataTableServer-CjBcrBi4.js";import{n as T,t as E}from"./VRow-DNuBhaBk.js";import{t as D}from"./VSpacer-BHLI8VYt.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=m({__name:`AlertsPage`,setup(m){let j=b(),M=l(!1),N=l([]),P=l(0),F=l(1),I=l(null),L=l(null),R=l([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await y.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await y.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{H(),U()}),(l,d)=>(c(),h(x,{fluid:``,class:`pa-6`},{default:v(()=>[f(E,{class:`mb-4`},{default:v(()=>[(c(!0),p(a,null,g(R.value,t=>(c(),h(T,{cols:`12`,sm:`6`,lg:`3`,key:t.label},{default:v(()=>[f(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:v(()=>[f(u,null,{append:v(()=>[f(i,{color:t.color,size:`30`},{default:v(()=>[o(r(t.icon),1)]),_:2},1032,[`color`])]),default:v(()=>[f(e,{class:`text-body-small`},{default:v(()=>[o(r(t.label),1)]),_:2},1024),f(e,null,{default:v(()=>[o(r(t.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),f(n,{elevation:`0`,border:``,rounded:`lg`},{default:v(()=>[f(t,{class:`d-flex align-center`},{default:v(()=>[d[5]||=o(` 告警历史 `,-1),f(D),f(C,{modelValue:I.value,"onUpdate:modelValue":[d[0]||=e=>I.value=e,d[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),f(C,{modelValue:L.value,"onUpdate:modelValue":[d[2]||=e=>L.value=e,d[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),f(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{F.value=e,U()}},{"item.alert_type":v(({item:e})=>[f(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:v(()=>[f(i,{size:`12`},{default:v(()=>[o(r(G(e.alert_type)),1)]),_:2},1024)]),default:v(()=>[o(` `+r(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":v(({item:e})=>[s(`span`,O,r(e.server_name),1)]),"item.value":v(({item:e})=>[s(`span`,k,r(e.value),1)]),"item.is_recovery":v(({item:e})=>[e.is_recovery?(c(),h(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[6]||=[o(`已恢复`,-1)]]),_:1})):(c(),h(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[7]||=[o(`告警中`,-1)]]),_:1}))]),"item.created_at":v(({item:e})=>[s(`span`,A,r(e.created_at),1)]),"no-data":v(()=>[...d[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{a as e,o as t}from"./VSelectionControl-BQRUjX5P.js";import{n,t as r}from"./VRow-C1b4Uu8Q.js";import{$n as i,A as a,B as o,F as s,Fr as c,Gr as l,N as u,Or as d,R as f,T as p,Ut as m,Vr as h,_r as g,ar as _,cr as v,j as y,lr as b,nr as x,rr as S,sr as C,ut as w,xr as T,yr as E}from"./index-DbSyD28P.js";import{n as D}from"./dataTable-esDY4cOk.js";import{t as O}from"./VSelect-glh4Zdhv.js";import{t as k}from"./VDataTableServer-BisDXMgG.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=b({__name:`AlertsPage`,setup(b){let N=e(),P=c(!1),F=c([]),I=c(0),L=c(1),R=c(null),z=c(null),B=c([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),V=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],H=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],U=D([{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}]);async function W(){try{let e=await m.get(`/alert-history/stats`);B.value[0].value=String(e.today||0),B.value[1].value=String(e.active||0),B.value[2].value=String(e.recovered||0),B.value[3].value=e.top_server||``}catch{N(`加载统计失败`,`error`)}}async function G(){P.value=!0;try{let e=await m.get(`/alert-history/`,{page:L.value,per_page:20,type:R.value||void 0,status:z.value||void 0});F.value=e.items||[],I.value=e.total||0}catch{F.value=[]}finally{P.value=!1}}function K(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function q(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return g(()=>{W(),G()}),(e,c)=>(E(),S(t,{fluid:``,class:`pa-6`},{default:d(()=>[v(r,{class:`mb-4`},{default:d(()=>[(E(!0),_(i,null,T(B.value,e=>(E(),S(n,{cols:`12`,sm:`6`,lg:`3`,key:e.label},{default:d(()=>[v(p,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:d(()=>[v(a,null,{append:d(()=>[v(w,{color:e.color,size:`30`},{default:d(()=>[C(l(e.icon),1)]),_:2},1032,[`color`])]),default:d(()=>[v(y,{class:`text-body-small`},{default:d(()=>[C(l(e.label),1)]),_:2},1024),v(y,null,{default:d(()=>[C(l(e.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),v(f,{elevation:`0`,border:``,rounded:`lg`},{default:d(()=>[v(o,{class:`d-flex align-center`},{default:d(()=>[c[5]||=C(` 告警历史 `,-1),v(u),v(O,{modelValue:R.value,"onUpdate:modelValue":[c[0]||=e=>R.value=e,c[1]||=e=>{L.value=1,G()}],items:V,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),v(O,{modelValue:z.value,"onUpdate:modelValue":[c[2]||=e=>z.value=e,c[3]||=e=>{L.value=1,G()}],items:H,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),v(k,{items:F.value,headers:h(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":c[4]||=e=>{L.value=e,G()}},{"item.alert_type":d(({item:e})=>[v(s,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:d(()=>[v(w,{size:`12`},{default:d(()=>[C(l(q(e.alert_type)),1)]),_:2},1024)]),default:d(()=>[C(` `+l(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":d(({item:e})=>[x(`span`,A,l(e.server_name),1)]),"item.value":d(({item:e})=>[x(`span`,j,l(e.value),1)]),"item.is_recovery":d(({item:e})=>[e.is_recovery?(E(),S(s,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:d(()=>[...c[6]||=[C(`已恢复`,-1)]]),_:1})):(E(),S(s,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:d(()=>[...c[7]||=[C(`告警中`,-1)]]),_:1}))]),"item.created_at":d(({item:e})=>[x(`span`,M,l(e.created_at),1)]),"no-data":d(()=>[...c[8]||=[x(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{N as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,F as t,N as n,Vr as r,Z as i,Zn as a,ar as o,er as s,gr as c,jr as l,k as u,mr as d,or as f,rr as p,sr as m,tr as h,vr as g,w as _,wr as v,zt as y}from"./index-DEV2Sc6Q.js";import{o as b,t as x}from"./VContainer-DTFumUOK.js";import{t as S}from"./VChip-DHw3siVg.js";import{t as C}from"./VSelect-Dmadm3KB.js";import{t as w}from"./VDataTableServer-BC4CoMyH.js";import{n as T,t as E}from"./VRow-4Eq778VA.js";import{t as D}from"./VSpacer-sJEakyfC.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=m({__name:`AlertsPage`,setup(m){let j=b(),M=l(!1),N=l([]),P=l(0),F=l(1),I=l(null),L=l(null),R=l([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await y.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await y.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{H(),U()}),(l,d)=>(c(),h(x,{fluid:``,class:`pa-6`},{default:v(()=>[f(E,{class:`mb-4`},{default:v(()=>[(c(!0),p(a,null,g(R.value,t=>(c(),h(T,{cols:`12`,sm:`6`,lg:`3`,key:t.label},{default:v(()=>[f(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:v(()=>[f(u,null,{append:v(()=>[f(i,{color:t.color,size:`30`},{default:v(()=>[o(r(t.icon),1)]),_:2},1032,[`color`])]),default:v(()=>[f(e,{class:`text-body-small`},{default:v(()=>[o(r(t.label),1)]),_:2},1024),f(e,null,{default:v(()=>[o(r(t.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),f(n,{elevation:`0`,border:``,rounded:`lg`},{default:v(()=>[f(t,{class:`d-flex align-center`},{default:v(()=>[d[5]||=o(` 告警历史 `,-1),f(D),f(C,{modelValue:I.value,"onUpdate:modelValue":[d[0]||=e=>I.value=e,d[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),f(C,{modelValue:L.value,"onUpdate:modelValue":[d[2]||=e=>L.value=e,d[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),f(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{F.value=e,U()}},{"item.alert_type":v(({item:e})=>[f(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:v(()=>[f(i,{size:`12`},{default:v(()=>[o(r(G(e.alert_type)),1)]),_:2},1024)]),default:v(()=>[o(` `+r(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":v(({item:e})=>[s(`span`,O,r(e.server_name),1)]),"item.value":v(({item:e})=>[s(`span`,k,r(e.value),1)]),"item.is_recovery":v(({item:e})=>[e.is_recovery?(c(),h(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[6]||=[o(`已恢复`,-1)]]),_:1})):(c(),h(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[7]||=[o(`告警中`,-1)]]),_:1}))]),"item.created_at":v(({item:e})=>[s(`span`,A,r(e.created_at),1)]),"no-data":v(()=>[...d[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,Er as t,F as n,N as r,Nr as i,Ur as a,Z as o,Zn as s,_r as c,ar as l,er as u,hr as d,k as f,or as p,rr as m,sr as h,tr as g,w as _,yr as v,zr as y,zt as b}from"./index-x_UzlvQU.js";import{o as x,t as S}from"./VContainer-9KPDvITd.js";import{n as C}from"./dataTable-esDY4cOk.js";import{t as w}from"./VChip-C55Q03jC.js";import{t as T}from"./VSelect-D6JhGiC7.js";import{t as E}from"./VDataTableServer-2HgZ5qDn.js";import{n as D,t as O}from"./VRow-D24DfLiy.js";import{t as k}from"./VSpacer-JMAll94i.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=h({__name:`AlertsPage`,setup(h){let N=x(),P=i(!1),F=i([]),I=i(0),L=i(1),R=i(null),z=i(null),B=i([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),V=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],H=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],U=C([{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}]);async function W(){try{let e=await b.get(`/alert-history/stats`);B.value[0].value=String(e.today||0),B.value[1].value=String(e.active||0),B.value[2].value=String(e.recovered||0),B.value[3].value=e.top_server||``}catch{N(`加载统计失败`,`error`)}}async function G(){P.value=!0;try{let e=await b.get(`/alert-history/`,{page:L.value,per_page:20,type:R.value||void 0,status:z.value||void 0});F.value=e.items||[],I.value=e.total||0}catch{F.value=[]}finally{P.value=!1}}function K(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function q(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{W(),G()}),(i,d)=>(c(),g(S,{fluid:``,class:`pa-6`},{default:t(()=>[p(O,{class:`mb-4`},{default:t(()=>[(c(!0),m(s,null,v(B.value,n=>(c(),g(D,{cols:`12`,sm:`6`,lg:`3`,key:n.label},{default:t(()=>[p(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:t(()=>[p(f,null,{append:t(()=>[p(o,{color:n.color,size:`30`},{default:t(()=>[l(a(n.icon),1)]),_:2},1032,[`color`])]),default:t(()=>[p(e,{class:`text-body-small`},{default:t(()=>[l(a(n.label),1)]),_:2},1024),p(e,null,{default:t(()=>[l(a(n.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),p(r,{elevation:`0`,border:``,rounded:`lg`},{default:t(()=>[p(n,{class:`d-flex align-center`},{default:t(()=>[d[5]||=l(` 告警历史 `,-1),p(k),p(T,{modelValue:R.value,"onUpdate:modelValue":[d[0]||=e=>R.value=e,d[1]||=e=>{L.value=1,G()}],items:V,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),p(T,{modelValue:z.value,"onUpdate:modelValue":[d[2]||=e=>z.value=e,d[3]||=e=>{L.value=1,G()}],items:H,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),p(E,{items:F.value,headers:y(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{L.value=e,G()}},{"item.alert_type":t(({item:e})=>[p(w,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:t(()=>[p(o,{size:`12`},{default:t(()=>[l(a(q(e.alert_type)),1)]),_:2},1024)]),default:t(()=>[l(` `+a(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":t(({item:e})=>[u(`span`,A,a(e.server_name),1)]),"item.value":t(({item:e})=>[u(`span`,j,a(e.value),1)]),"item.is_recovery":t(({item:e})=>[e.is_recovery?(c(),g(w,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:t(()=>[...d[6]||=[l(`已恢复`,-1)]]),_:1})):(c(),g(w,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:t(()=>[...d[7]||=[l(`告警中`,-1)]]),_:1}))]),"item.created_at":t(({item:e})=>[u(`span`,M,a(e.created_at),1)]),"no-data":t(()=>[...d[8]||=[u(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{N as default};
+1
View File
@@ -0,0 +1 @@
import{$n as e,A as t,Ar as n,Br as r,Cr as i,F as a,N as o,Rt as s,X as c,Xn as l,_r as u,ar as d,er as f,hr as p,ir as m,k as h,nr as g,or as _,pr as v,w as y}from"./index-1vc2lwKY.js";import{o as b,t as x}from"./VContainer-Cyz28tn8.js";import{t as S}from"./VChip-DxlrSIbY.js";import{t as C}from"./VSelect-bmHFJ0Qw.js";import{t as w}from"./VDataTableServer-BgrY7CII.js";import{n as T,t as E}from"./VRow-DWRsOC56.js";import{t as D}from"./VSpacer-DTN9CH1q.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=_({__name:`AlertsPage`,setup(_){let j=b(),M=n(!1),N=n([]),P=n(0),F=n(1),I=n(null),L=n(null),R=n([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await s.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await s.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return v(()=>{H(),U()}),(n,s)=>(p(),f(x,{fluid:``,class:`pa-6`},{default:i(()=>[d(E,{class:`mb-4`},{default:i(()=>[(p(!0),g(l,null,u(R.value,e=>(p(),f(T,{cols:`12`,sm:`6`,lg:`3`,key:e.label},{default:i(()=>[d(y,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:i(()=>[d(h,null,{append:i(()=>[d(c,{color:e.color,size:`30`},{default:i(()=>[m(r(e.icon),1)]),_:2},1032,[`color`])]),default:i(()=>[d(t,{class:`text-body-small`},{default:i(()=>[m(r(e.label),1)]),_:2},1024),d(t,null,{default:i(()=>[m(r(e.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),d(o,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[d(a,{class:`d-flex align-center`},{default:i(()=>[s[5]||=m(` 告警历史 `,-1),d(D),d(C,{modelValue:I.value,"onUpdate:modelValue":[s[0]||=e=>I.value=e,s[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),d(C,{modelValue:L.value,"onUpdate:modelValue":[s[2]||=e=>L.value=e,s[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),d(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":s[4]||=e=>{F.value=e,U()}},{"item.alert_type":i(({item:e})=>[d(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:i(()=>[d(c,{size:`12`},{default:i(()=>[m(r(G(e.alert_type)),1)]),_:2},1024)]),default:i(()=>[m(` `+r(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":i(({item:t})=>[e(`span`,O,r(t.server_name),1)]),"item.value":i(({item:t})=>[e(`span`,k,r(t.value),1)]),"item.is_recovery":i(({item:e})=>[e.is_recovery?(p(),f(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:i(()=>[...s[6]||=[m(`已恢复`,-1)]]),_:1})):(p(),f(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:i(()=>[...s[7]||=[m(`告警中`,-1)]]),_:1}))]),"item.created_at":i(({item:t})=>[e(`span`,A,r(t.created_at),1)]),"no-data":i(()=>[...s[8]||=[e(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,F as t,N as n,Vr as r,Z as i,Zn as a,ar as o,er as s,gr as c,jr as l,k as u,mr as d,or as f,rr as p,sr as m,tr as h,vr as g,w as _,wr as v,zt as y}from"./index-BOX5ad4G.js";import{o as b,t as x}from"./VContainer-CsduC4GT.js";import{t as S}from"./VChip-D0VaTwoJ.js";import{t as C}from"./VSelect-skTyo71B.js";import{t as w}from"./VDataTableServer-CyZWQ374.js";import{n as T,t as E}from"./VRow-A22kGc_y.js";import{t as D}from"./VSpacer-CysfZoCS.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=m({__name:`AlertsPage`,setup(m){let j=b(),M=l(!1),N=l([]),P=l(0),F=l(1),I=l(null),L=l(null),R=l([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await y.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await y.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{H(),U()}),(l,d)=>(c(),h(x,{fluid:``,class:`pa-6`},{default:v(()=>[f(E,{class:`mb-4`},{default:v(()=>[(c(!0),p(a,null,g(R.value,t=>(c(),h(T,{cols:`12`,sm:`6`,lg:`3`,key:t.label},{default:v(()=>[f(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:v(()=>[f(u,null,{append:v(()=>[f(i,{color:t.color,size:`30`},{default:v(()=>[o(r(t.icon),1)]),_:2},1032,[`color`])]),default:v(()=>[f(e,{class:`text-body-small`},{default:v(()=>[o(r(t.label),1)]),_:2},1024),f(e,null,{default:v(()=>[o(r(t.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),f(n,{elevation:`0`,border:``,rounded:`lg`},{default:v(()=>[f(t,{class:`d-flex align-center`},{default:v(()=>[d[5]||=o(` 告警历史 `,-1),f(D),f(C,{modelValue:I.value,"onUpdate:modelValue":[d[0]||=e=>I.value=e,d[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),f(C,{modelValue:L.value,"onUpdate:modelValue":[d[2]||=e=>L.value=e,d[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),f(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{F.value=e,U()}},{"item.alert_type":v(({item:e})=>[f(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:v(()=>[f(i,{size:`12`},{default:v(()=>[o(r(G(e.alert_type)),1)]),_:2},1024)]),default:v(()=>[o(` `+r(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":v(({item:e})=>[s(`span`,O,r(e.server_name),1)]),"item.value":v(({item:e})=>[s(`span`,k,r(e.value),1)]),"item.is_recovery":v(({item:e})=>[e.is_recovery?(c(),h(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[6]||=[o(`已恢复`,-1)]]),_:1})):(c(),h(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[7]||=[o(`告警中`,-1)]]),_:1}))]),"item.created_at":v(({item:e})=>[s(`span`,A,r(e.created_at),1)]),"no-data":v(()=>[...d[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,Er as t,F as n,N as r,Nr as i,Ur as a,Z as o,Zn as s,_r as c,ar as l,er as u,hr as d,k as f,or as p,rr as m,sr as h,tr as g,w as _,yr as v,zr as y,zt as b}from"./index-CITYCKPt.js";import{o as x,t as S}from"./VContainer-D3j80qYo.js";import{n as C}from"./dataTable-esDY4cOk.js";import{t as w}from"./VChip-BZLbsGAB.js";import{t as T}from"./VSelect-BjOTKQYN.js";import{t as E}from"./VDataTableServer-COy02vU2.js";import{n as D,t as O}from"./VRow-BPsTMp9y.js";import{t as k}from"./VSpacer-D1z4iYRg.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=h({__name:`AlertsPage`,setup(h){let N=x(),P=i(!1),F=i([]),I=i(0),L=i(1),R=i(null),z=i(null),B=i([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),V=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],H=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],U=C([{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}]);async function W(){try{let e=await b.get(`/alert-history/stats`);B.value[0].value=String(e.today||0),B.value[1].value=String(e.active||0),B.value[2].value=String(e.recovered||0),B.value[3].value=e.top_server||``}catch{N(`加载统计失败`,`error`)}}async function G(){P.value=!0;try{let e=await b.get(`/alert-history/`,{page:L.value,per_page:20,type:R.value||void 0,status:z.value||void 0});F.value=e.items||[],I.value=e.total||0}catch{F.value=[]}finally{P.value=!1}}function K(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function q(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{W(),G()}),(i,d)=>(c(),g(S,{fluid:``,class:`pa-6`},{default:t(()=>[p(O,{class:`mb-4`},{default:t(()=>[(c(!0),m(s,null,v(B.value,n=>(c(),g(D,{cols:`12`,sm:`6`,lg:`3`,key:n.label},{default:t(()=>[p(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:t(()=>[p(f,null,{append:t(()=>[p(o,{color:n.color,size:`30`},{default:t(()=>[l(a(n.icon),1)]),_:2},1032,[`color`])]),default:t(()=>[p(e,{class:`text-body-small`},{default:t(()=>[l(a(n.label),1)]),_:2},1024),p(e,null,{default:t(()=>[l(a(n.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),p(r,{elevation:`0`,border:``,rounded:`lg`},{default:t(()=>[p(n,{class:`d-flex align-center`},{default:t(()=>[d[5]||=l(` 告警历史 `,-1),p(k),p(T,{modelValue:R.value,"onUpdate:modelValue":[d[0]||=e=>R.value=e,d[1]||=e=>{L.value=1,G()}],items:V,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),p(T,{modelValue:z.value,"onUpdate:modelValue":[d[2]||=e=>z.value=e,d[3]||=e=>{L.value=1,G()}],items:H,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),p(E,{items:F.value,headers:y(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{L.value=e,G()}},{"item.alert_type":t(({item:e})=>[p(w,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:t(()=>[p(o,{size:`12`},{default:t(()=>[l(a(q(e.alert_type)),1)]),_:2},1024)]),default:t(()=>[l(` `+a(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":t(({item:e})=>[u(`span`,A,a(e.server_name),1)]),"item.value":t(({item:e})=>[u(`span`,j,a(e.value),1)]),"item.is_recovery":t(({item:e})=>[e.is_recovery?(c(),g(w,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:t(()=>[...d[6]||=[l(`已恢复`,-1)]]),_:1})):(c(),g(w,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:t(()=>[...d[7]||=[l(`告警中`,-1)]]),_:1}))]),"item.created_at":t(({item:e})=>[u(`span`,M,a(e.created_at),1)]),"no-data":t(()=>[...d[8]||=[u(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{N as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,F as t,N as n,Vr as r,Z as i,Zn as a,ar as o,er as s,gr as c,jr as l,k as u,mr as d,or as f,rr as p,sr as m,tr as h,vr as g,w as _,wr as v,zt as y}from"./index-8R5Vx1WH.js";import{o as b,t as x}from"./VContainer-ByAXNVXy.js";import{t as S}from"./VChip-CO9HT0ch.js";import{t as C}from"./VSelect-BB7JEkD3.js";import{t as w}from"./VDataTableServer-Bx8d7a_i.js";import{n as T,t as E}from"./VRow-BVJ9K6vV.js";import{t as D}from"./VSpacer-CTDq7Cy_.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=m({__name:`AlertsPage`,setup(m){let j=b(),M=l(!1),N=l([]),P=l(0),F=l(1),I=l(null),L=l(null),R=l([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await y.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await y.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{H(),U()}),(l,d)=>(c(),h(x,{fluid:``,class:`pa-6`},{default:v(()=>[f(E,{class:`mb-4`},{default:v(()=>[(c(!0),p(a,null,g(R.value,t=>(c(),h(T,{cols:`12`,sm:`6`,lg:`3`,key:t.label},{default:v(()=>[f(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:v(()=>[f(u,null,{append:v(()=>[f(i,{color:t.color,size:`30`},{default:v(()=>[o(r(t.icon),1)]),_:2},1032,[`color`])]),default:v(()=>[f(e,{class:`text-body-small`},{default:v(()=>[o(r(t.label),1)]),_:2},1024),f(e,null,{default:v(()=>[o(r(t.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),f(n,{elevation:`0`,border:``,rounded:`lg`},{default:v(()=>[f(t,{class:`d-flex align-center`},{default:v(()=>[d[5]||=o(` 告警历史 `,-1),f(D),f(C,{modelValue:I.value,"onUpdate:modelValue":[d[0]||=e=>I.value=e,d[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),f(C,{modelValue:L.value,"onUpdate:modelValue":[d[2]||=e=>L.value=e,d[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),f(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{F.value=e,U()}},{"item.alert_type":v(({item:e})=>[f(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:v(()=>[f(i,{size:`12`},{default:v(()=>[o(r(G(e.alert_type)),1)]),_:2},1024)]),default:v(()=>[o(` `+r(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":v(({item:e})=>[s(`span`,O,r(e.server_name),1)]),"item.value":v(({item:e})=>[s(`span`,k,r(e.value),1)]),"item.is_recovery":v(({item:e})=>[e.is_recovery?(c(),h(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[6]||=[o(`已恢复`,-1)]]),_:1})):(c(),h(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[7]||=[o(`告警中`,-1)]]),_:1}))]),"item.created_at":v(({item:e})=>[s(`span`,A,r(e.created_at),1)]),"no-data":v(()=>[...d[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{Er as e,F as t,N as n,Nr as r,Ur as i,_r as a,ar as o,er as s,hr as c,or as l,sr as u,t as d,tr as f,zr as p,zt as m}from"./index-CITYCKPt.js";import{o as h,t as g}from"./VContainer-D3j80qYo.js";import{n as _}from"./dataTable-esDY4cOk.js";import{t as v}from"./VChip-BZLbsGAB.js";import{t as y}from"./VSelect-BjOTKQYN.js";import{t as b}from"./VDataTableServer-COy02vU2.js";import{t as x}from"./VSpacer-D1z4iYRg.js";import{a as S,n as C,r as w,t as T}from"./auditNormalize-bmSA0RyN.js";var E={class:`font-weight-medium`},D={class:`text-body-2`},O={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},k={class:`text-caption text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j=u({__name:`AuditPage`,setup(u){let j=h(),M=r(!1),N=r([]),P=r(0),F=r(1),I=r(null),L=r(``),R=r(``),z=C,B=_([{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}]);async function V(){M.value=!0;try{let e=(F.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:I.value||void 0,admin_username:L.value||void 0,date_from:R.value||void 0});N.value=T(t.items||[]),P.value=t.total||0}catch{N.value=[],j(`加载审计日志失败`,`error`)}finally{M.value=!1}}function H(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>V()),(r,c)=>(a(),f(g,{fluid:``,class:`pa-6`},{default:e(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:e(()=>[l(t,{class:`d-flex align-center`},{default:e(()=>[c[7]||=o(` 审计日志 `,-1),l(x),l(y,{modelValue:I.value,"onUpdate:modelValue":[c[0]||=e=>I.value=e,c[1]||=e=>{F.value=1,V()}],items:p(z),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[2]||=e=>L.value=e,c[3]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:R.value,"onUpdate:modelValue":[c[4]||=e=>R.value=e,c[5]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(b,{items:N.value,headers:p(B),"items-length":P.value,loading:M.value,page:F.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{F.value=e,V()}},{"item.action":e(({item:t})=>[l(v,{color:H(t.action),size:`small`,variant:`tonal`,label:``},{default:e(()=>[o(i(p(w)(t.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":e(({item:e})=>[s(`span`,E,i(e.admin_username),1)]),"item.target":e(({item:e})=>[s(`span`,D,i(p(S)(e.resource_type))+i(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":e(({item:e})=>[s(`span`,O,i(e.detail||``),1)]),"item.ip_address":e(({item:e})=>[s(`span`,k,i(e.ip_address||``),1)]),"item.created_at":e(({item:e})=>[s(`span`,A,i(e.created_at),1)]),"no-data":e(()=>[...c[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,N as n,Vr as r,ar as i,er as a,gr as o,jr as s,mr as c,or as l,sr as u,t as d,tr as f,wr as p,zt as m}from"./index-gfOrpdmy.js";import{o as h,t as g}from"./VContainer-DoAVnyqr.js";import{t as _}from"./VChip-sW1zi7V6.js";import{t as v}from"./VSelect-KxRF8W0i.js";import{t as y}from"./VDataTableServer-LfNDokVe.js";import{t as b}from"./VSpacer-ChMx8Hym.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-bmSA0RyN.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=u({__name:`AuditPage`,setup(u){let A=h(),j=s(!1),M=s([]),N=s(0),P=s(1),F=s(null),I=s(``),L=s(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>B()),(s,c)=>(o(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[l(e,{class:`d-flex align-center`},{default:p(()=>[c[7]||=i(` 审计日志 `,-1),l(b),l(v,{modelValue:F.value,"onUpdate:modelValue":[c[0]||=e=>F.value=e,c[1]||=e=>{P.value=1,B()}],items:t(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:I.value,"onUpdate:modelValue":[c[2]||=e=>I.value=e,c[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[4]||=e=>L.value=e,c[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{P.value=e,B()}},{"item.action":p(({item:e})=>[l(_,{color:V(e.action),size:`small`,variant:`tonal`,label:``},{default:p(()=>[i(r(t(C)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":p(({item:e})=>[a(`span`,T,r(e.admin_username),1)]),"item.target":p(({item:e})=>[a(`span`,E,r(t(x)(e.resource_type))+r(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":p(({item:e})=>[a(`span`,D,r(e.detail||``),1)]),"item.ip_address":p(({item:e})=>[a(`span`,O,r(e.ip_address||``),1)]),"item.created_at":p(({item:e})=>[a(`span`,k,r(e.created_at),1)]),"no-data":p(()=>[...c[8]||=[a(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
+1
View File
@@ -0,0 +1 @@
import{Er as e,F as t,N as n,Nr as r,Ur as i,_r as a,ar as o,er as s,hr as c,or as l,sr as u,t as d,tr as f,zr as p,zt as m}from"./index-DefLgbfN.js";import{o as h,t as g}from"./VContainer-Cfs-evp_.js";import{t as _}from"./VChip-B776T65H.js";import{t as v}from"./VSelect-CI0l_G9L.js";import{t as y}from"./VDataTableServer-BVvotZW1.js";import{t as b}from"./VSpacer-K-VIfO9Y.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-bmSA0RyN.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=u({__name:`AuditPage`,setup(u){let A=h(),j=r(!1),M=r([]),N=r(0),P=r(1),F=r(null),I=r(``),L=r(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>B()),(r,c)=>(a(),f(g,{fluid:``,class:`pa-6`},{default:e(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:e(()=>[l(t,{class:`d-flex align-center`},{default:e(()=>[c[7]||=o(` 审计日志 `,-1),l(b),l(v,{modelValue:F.value,"onUpdate:modelValue":[c[0]||=e=>F.value=e,c[1]||=e=>{P.value=1,B()}],items:p(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:I.value,"onUpdate:modelValue":[c[2]||=e=>I.value=e,c[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[4]||=e=>L.value=e,c[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{P.value=e,B()}},{"item.action":e(({item:t})=>[l(_,{color:V(t.action),size:`small`,variant:`tonal`,label:``},{default:e(()=>[o(i(p(C)(t.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":e(({item:e})=>[s(`span`,T,i(e.admin_username),1)]),"item.target":e(({item:e})=>[s(`span`,E,i(p(x)(e.resource_type))+i(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":e(({item:e})=>[s(`span`,D,i(e.detail||``),1)]),"item.ip_address":e(({item:e})=>[s(`span`,O,i(e.ip_address||``),1)]),"item.created_at":e(({item:e})=>[s(`span`,k,i(e.created_at),1)]),"no-data":e(()=>[...c[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,N as n,Vr as r,ar as i,er as a,gr as o,jr as s,mr as c,or as l,sr as u,t as d,tr as f,wr as p,zt as m}from"./index-8R5Vx1WH.js";import{o as h,t as g}from"./VContainer-ByAXNVXy.js";import{t as _}from"./VChip-CO9HT0ch.js";import{t as v}from"./VSelect-BB7JEkD3.js";import{t as y}from"./VDataTableServer-Bx8d7a_i.js";import{t as b}from"./VSpacer-CTDq7Cy_.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-bmSA0RyN.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=u({__name:`AuditPage`,setup(u){let A=h(),j=s(!1),M=s([]),N=s(0),P=s(1),F=s(null),I=s(``),L=s(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>B()),(s,c)=>(o(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[l(e,{class:`d-flex align-center`},{default:p(()=>[c[7]||=i(` 审计日志 `,-1),l(b),l(v,{modelValue:F.value,"onUpdate:modelValue":[c[0]||=e=>F.value=e,c[1]||=e=>{P.value=1,B()}],items:t(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:I.value,"onUpdate:modelValue":[c[2]||=e=>I.value=e,c[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[4]||=e=>L.value=e,c[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{P.value=e,B()}},{"item.action":p(({item:e})=>[l(_,{color:V(e.action),size:`small`,variant:`tonal`,label:``},{default:p(()=>[i(r(t(C)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":p(({item:e})=>[a(`span`,T,r(e.admin_username),1)]),"item.target":p(({item:e})=>[a(`span`,E,r(t(x)(e.resource_type))+r(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":p(({item:e})=>[a(`span`,D,r(e.detail||``),1)]),"item.ip_address":p(({item:e})=>[a(`span`,O,r(e.ip_address||``),1)]),"item.created_at":p(({item:e})=>[a(`span`,k,r(e.created_at),1)]),"no-data":p(()=>[...c[8]||=[a(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,N as n,Vr as r,ar as i,er as a,gr as o,jr as s,mr as c,or as l,sr as u,t as d,tr as f,wr as p,zt as m}from"./index-DEV2Sc6Q.js";import{o as h,t as g}from"./VContainer-DTFumUOK.js";import{t as _}from"./VChip-DHw3siVg.js";import{t as v}from"./VSelect-Dmadm3KB.js";import{t as y}from"./VDataTableServer-BC4CoMyH.js";import{t as b}from"./VSpacer-sJEakyfC.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-bmSA0RyN.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=u({__name:`AuditPage`,setup(u){let A=h(),j=s(!1),M=s([]),N=s(0),P=s(1),F=s(null),I=s(``),L=s(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>B()),(s,c)=>(o(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[l(e,{class:`d-flex align-center`},{default:p(()=>[c[7]||=i(` 审计日志 `,-1),l(b),l(v,{modelValue:F.value,"onUpdate:modelValue":[c[0]||=e=>F.value=e,c[1]||=e=>{P.value=1,B()}],items:t(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:I.value,"onUpdate:modelValue":[c[2]||=e=>I.value=e,c[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[4]||=e=>L.value=e,c[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{P.value=e,B()}},{"item.action":p(({item:e})=>[l(_,{color:V(e.action),size:`small`,variant:`tonal`,label:``},{default:p(()=>[i(r(t(C)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":p(({item:e})=>[a(`span`,T,r(e.admin_username),1)]),"item.target":p(({item:e})=>[a(`span`,E,r(t(x)(e.resource_type))+r(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":p(({item:e})=>[a(`span`,D,r(e.detail||``),1)]),"item.ip_address":p(({item:e})=>[a(`span`,O,r(e.ip_address||``),1)]),"item.created_at":p(({item:e})=>[a(`span`,k,r(e.created_at),1)]),"no-data":p(()=>[...c[8]||=[a(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,N as n,Vr as r,ar as i,er as a,gr as o,jr as s,mr as c,or as l,sr as u,t as d,tr as f,wr as p,zt as m}from"./index-ia8w6hh3.js";import{o as h,t as g}from"./VContainer-Cg-YgCG2.js";import{t as _}from"./VChip-gd2nTpu3.js";import{t as v}from"./VSelect-DesLFoAg.js";import{t as y}from"./VDataTableServer-D4zQCwj2.js";import{t as b}from"./VSpacer-BtntPGL0.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-bmSA0RyN.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=u({__name:`AuditPage`,setup(u){let A=h(),j=s(!1),M=s([]),N=s(0),P=s(1),F=s(null),I=s(``),L=s(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>B()),(s,c)=>(o(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[l(e,{class:`d-flex align-center`},{default:p(()=>[c[7]||=i(` 审计日志 `,-1),l(b),l(v,{modelValue:F.value,"onUpdate:modelValue":[c[0]||=e=>F.value=e,c[1]||=e=>{P.value=1,B()}],items:t(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:I.value,"onUpdate:modelValue":[c[2]||=e=>I.value=e,c[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[4]||=e=>L.value=e,c[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{P.value=e,B()}},{"item.action":p(({item:e})=>[l(_,{color:V(e.action),size:`small`,variant:`tonal`,label:``},{default:p(()=>[i(r(t(C)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":p(({item:e})=>[a(`span`,T,r(e.admin_username),1)]),"item.target":p(({item:e})=>[a(`span`,E,r(t(x)(e.resource_type))+r(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":p(({item:e})=>[a(`span`,D,r(e.detail||``),1)]),"item.ip_address":p(({item:e})=>[a(`span`,O,r(e.ip_address||``),1)]),"item.created_at":p(({item:e})=>[a(`span`,k,r(e.created_at),1)]),"no-data":p(()=>[...c[8]||=[a(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
+1
View File
@@ -0,0 +1 @@
import{Er as e,F as t,N as n,Nr as r,Ur as i,_r as a,ar as o,er as s,hr as c,or as l,sr as u,t as d,tr as f,zr as p,zt as m}from"./index-HeC-ymfd.js";import{o as h,t as g}from"./VContainer-Bqb4OsjX.js";import{n as _}from"./dataTable-esDY4cOk.js";import{t as v}from"./VChip-C-HpH-oj.js";import{t as y}from"./VSelect-CEXOntEU.js";import{t as b}from"./VDataTableServer-_AO1gvgs.js";import{t as x}from"./VSpacer-C31iLuvS.js";import{a as S,n as C,r as w,t as T}from"./auditNormalize-bmSA0RyN.js";var E={class:`font-weight-medium`},D={class:`text-body-2`},O={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},k={class:`text-caption text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j=u({__name:`AuditPage`,setup(u){let j=h(),M=r(!1),N=r([]),P=r(0),F=r(1),I=r(null),L=r(``),R=r(``),z=C,B=_([{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}]);async function V(){M.value=!0;try{let e=(F.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:I.value||void 0,admin_username:L.value||void 0,date_from:R.value||void 0});N.value=T(t.items||[]),P.value=t.total||0}catch{N.value=[],j(`加载审计日志失败`,`error`)}finally{M.value=!1}}function H(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>V()),(r,c)=>(a(),f(g,{fluid:``,class:`pa-6`},{default:e(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:e(()=>[l(t,{class:`d-flex align-center`},{default:e(()=>[c[7]||=o(` 审计日志 `,-1),l(x),l(y,{modelValue:I.value,"onUpdate:modelValue":[c[0]||=e=>I.value=e,c[1]||=e=>{F.value=1,V()}],items:p(z),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[2]||=e=>L.value=e,c[3]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:R.value,"onUpdate:modelValue":[c[4]||=e=>R.value=e,c[5]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(b,{items:N.value,headers:p(B),"items-length":P.value,loading:M.value,page:F.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{F.value=e,V()}},{"item.action":e(({item:t})=>[l(v,{color:H(t.action),size:`small`,variant:`tonal`,label:``},{default:e(()=>[o(i(p(w)(t.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":e(({item:e})=>[s(`span`,E,i(e.admin_username),1)]),"item.target":e(({item:e})=>[s(`span`,D,i(p(S)(e.resource_type))+i(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":e(({item:e})=>[s(`span`,O,i(e.detail||``),1)]),"item.ip_address":e(({item:e})=>[s(`span`,k,i(e.ip_address||``),1)]),"item.created_at":e(({item:e})=>[s(`span`,A,i(e.created_at),1)]),"no-data":e(()=>[...c[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{Er as e,F as t,N as n,Nr as r,Ur as i,_r as a,ar as o,er as s,hr as c,or as l,sr as u,t as d,tr as f,zr as p,zt as m}from"./index-Hwt84p4T.js";import{o as h,t as g}from"./VContainer-DVdhFFDK.js";import{n as _}from"./dataTable-esDY4cOk.js";import{t as v}from"./VChip-BOlm6rKc.js";import{t as y}from"./VSelect-Ce9_iAcL.js";import{t as b}from"./VDataTableServer-Ch0R1ufY.js";import{t as x}from"./VSpacer-Dz9VwXyE.js";import{a as S,n as C,r as w,t as T}from"./auditNormalize-bmSA0RyN.js";var E={class:`font-weight-medium`},D={class:`text-body-2`},O={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},k={class:`text-caption text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j=u({__name:`AuditPage`,setup(u){let j=h(),M=r(!1),N=r([]),P=r(0),F=r(1),I=r(null),L=r(``),R=r(``),z=C,B=_([{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}]);async function V(){M.value=!0;try{let e=(F.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:I.value||void 0,admin_username:L.value||void 0,date_from:R.value||void 0});N.value=T(t.items||[]),P.value=t.total||0}catch{N.value=[],j(`加载审计日志失败`,`error`)}finally{M.value=!1}}function H(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>V()),(r,c)=>(a(),f(g,{fluid:``,class:`pa-6`},{default:e(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:e(()=>[l(t,{class:`d-flex align-center`},{default:e(()=>[c[7]||=o(` 审计日志 `,-1),l(x),l(y,{modelValue:I.value,"onUpdate:modelValue":[c[0]||=e=>I.value=e,c[1]||=e=>{F.value=1,V()}],items:p(z),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[2]||=e=>L.value=e,c[3]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:R.value,"onUpdate:modelValue":[c[4]||=e=>R.value=e,c[5]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(b,{items:N.value,headers:p(B),"items-length":P.value,loading:M.value,page:F.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{F.value=e,V()}},{"item.action":e(({item:t})=>[l(v,{color:H(t.action),size:`small`,variant:`tonal`,label:``},{default:e(()=>[o(i(p(w)(t.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":e(({item:e})=>[s(`span`,E,i(e.admin_username),1)]),"item.target":e(({item:e})=>[s(`span`,D,i(p(S)(e.resource_type))+i(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":e(({item:e})=>[s(`span`,O,i(e.detail||``),1)]),"item.ip_address":e(({item:e})=>[s(`span`,k,i(e.ip_address||``),1)]),"item.created_at":e(({item:e})=>[s(`span`,A,i(e.created_at),1)]),"no-data":e(()=>[...c[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-BBtNL0eJ.js";import{B as r,Cr as i,F as a,Gr as o,Mr as s,N as c,R as l,Yr as u,dr as d,fr as f,or as p,pr as m,qt as h,sr as g,t as _,xr as v,zr as y}from"./index-DXg_pn7T.js";import{n as b}from"./dataTable-esDY4cOk.js";import{t as x}from"./VDataTableServer-CAOCfrD0.js";import{a as S,n as C,r as w,t as T}from"./auditNormalize-bmSA0RyN.js";var E={class:`font-weight-medium`},D={class:`text-body-2`},O={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},k={class:`text-caption text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j=m({__name:`AuditPage`,setup(m){let j=e(),M=y(!1),N=y([]),P=y(0),F=y(1),I=y(null),L=y(``),R=y(``),z=C,B=b([{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}]);async function V(){M.value=!0;try{let e=(F.value-1)*50,t=await h.get(`/audit/`,{limit:50,offset:e,action:I.value||void 0,admin_username:L.value||void 0,date_from:R.value||void 0});N.value=T(t.items||[]),P.value=t.total||0}catch{N.value=[],j(`加载审计日志失败`,`error`)}finally{M.value=!1}}function H(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return v(()=>V()),(e,m)=>(i(),g(n,{fluid:``,class:`pa-6`},{default:s(()=>[f(l,{elevation:`0`,border:``,rounded:`lg`},{default:s(()=>[f(r,{class:`d-flex align-center`},{default:s(()=>[m[7]||=d(` 审计日志 `,-1),f(c),f(t,{modelValue:I.value,"onUpdate:modelValue":[m[0]||=e=>I.value=e,m[1]||=e=>{F.value=1,V()}],items:o(z),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),f(_,{modelValue:L.value,"onUpdate:modelValue":[m[2]||=e=>L.value=e,m[3]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),f(_,{modelValue:R.value,"onUpdate:modelValue":[m[4]||=e=>R.value=e,m[5]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),f(x,{items:N.value,headers:o(B),"items-length":P.value,loading:M.value,page:F.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":m[6]||=e=>{F.value=e,V()}},{"item.action":s(({item:e})=>[f(a,{color:H(e.action),size:`small`,variant:`tonal`,label:``},{default:s(()=>[d(u(o(w)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":s(({item:e})=>[p(`span`,E,u(e.admin_username),1)]),"item.target":s(({item:e})=>[p(`span`,D,u(o(S)(e.resource_type))+u(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":s(({item:e})=>[p(`span`,O,u(e.detail||``),1)]),"item.ip_address":s(({item:e})=>[p(`span`,k,u(e.ip_address||``),1)]),"item.created_at":s(({item:e})=>[p(`span`,A,u(e.created_at),1)]),"no-data":s(()=>[...m[8]||=[p(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,N as n,Vr as r,ar as i,er as a,gr as o,jr as s,mr as c,or as l,sr as u,t as d,tr as f,wr as p,zt as m}from"./index-3SWW3Wj_.js";import{o as h,t as g}from"./VContainer-B79RFM4s.js";import{t as _}from"./VChip-CMAdQZRJ.js";import{t as v}from"./VSelect-CNVSTEnc.js";import{t as y}from"./VDataTableServer-mXWi-ccO.js";import{t as b}from"./VSpacer-Lz_Er0LP.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-bmSA0RyN.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=u({__name:`AuditPage`,setup(u){let A=h(),j=s(!1),M=s([]),N=s(0),P=s(1),F=s(null),I=s(``),L=s(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>B()),(s,c)=>(o(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[l(e,{class:`d-flex align-center`},{default:p(()=>[c[7]||=i(` 审计日志 `,-1),l(b),l(v,{modelValue:F.value,"onUpdate:modelValue":[c[0]||=e=>F.value=e,c[1]||=e=>{P.value=1,B()}],items:t(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:I.value,"onUpdate:modelValue":[c[2]||=e=>I.value=e,c[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[4]||=e=>L.value=e,c[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{P.value=e,B()}},{"item.action":p(({item:e})=>[l(_,{color:V(e.action),size:`small`,variant:`tonal`,label:``},{default:p(()=>[i(r(t(C)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":p(({item:e})=>[a(`span`,T,r(e.admin_username),1)]),"item.target":p(({item:e})=>[a(`span`,E,r(t(x)(e.resource_type))+r(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":p(({item:e})=>[a(`span`,D,r(e.detail||``),1)]),"item.ip_address":p(({item:e})=>[a(`span`,O,r(e.ip_address||``),1)]),"item.created_at":p(({item:e})=>[a(`span`,k,r(e.created_at),1)]),"no-data":p(()=>[...c[8]||=[a(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
+1
View File
@@ -0,0 +1 @@
import{Er as e,F as t,N as n,Nr as r,Ur as i,_r as a,ar as o,er as s,hr as c,or as l,sr as u,t as d,tr as f,zr as p,zt as m}from"./index-Dp4iCzbs.js";import{o as h,t as g}from"./VContainer-BpcBPa4e.js";import{n as _}from"./dataTable-esDY4cOk.js";import{t as v}from"./VChip-DBjCm_hy.js";import{t as y}from"./VSelect-B3aZ6TxZ.js";import{t as b}from"./VDataTableServer-5YTAzdGq.js";import{t as x}from"./VSpacer-Dij81TMC.js";import{a as S,n as C,r as w,t as T}from"./auditNormalize-bmSA0RyN.js";var E={class:`font-weight-medium`},D={class:`text-body-2`},O={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},k={class:`text-caption text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j=u({__name:`AuditPage`,setup(u){let j=h(),M=r(!1),N=r([]),P=r(0),F=r(1),I=r(null),L=r(``),R=r(``),z=C,B=_([{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}]);async function V(){M.value=!0;try{let e=(F.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:I.value||void 0,admin_username:L.value||void 0,date_from:R.value||void 0});N.value=T(t.items||[]),P.value=t.total||0}catch{N.value=[],j(`加载审计日志失败`,`error`)}finally{M.value=!1}}function H(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>V()),(r,c)=>(a(),f(g,{fluid:``,class:`pa-6`},{default:e(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:e(()=>[l(t,{class:`d-flex align-center`},{default:e(()=>[c[7]||=o(` 审计日志 `,-1),l(x),l(y,{modelValue:I.value,"onUpdate:modelValue":[c[0]||=e=>I.value=e,c[1]||=e=>{F.value=1,V()}],items:p(z),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[2]||=e=>L.value=e,c[3]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:R.value,"onUpdate:modelValue":[c[4]||=e=>R.value=e,c[5]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(b,{items:N.value,headers:p(B),"items-length":P.value,loading:M.value,page:F.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{F.value=e,V()}},{"item.action":e(({item:t})=>[l(v,{color:H(t.action),size:`small`,variant:`tonal`,label:``},{default:e(()=>[o(i(p(w)(t.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":e(({item:e})=>[s(`span`,E,i(e.admin_username),1)]),"item.target":e(({item:e})=>[s(`span`,D,i(p(S)(e.resource_type))+i(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":e(({item:e})=>[s(`span`,O,i(e.detail||``),1)]),"item.ip_address":e(({item:e})=>[s(`span`,k,i(e.ip_address||``),1)]),"item.created_at":e(({item:e})=>[s(`span`,A,i(e.created_at),1)]),"no-data":e(()=>[...c[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,N as n,Vr as r,ar as i,er as a,gr as o,jr as s,mr as c,or as l,sr as u,t as d,tr as f,wr as p,zt as m}from"./index-DhXUzl5h.js";import{o as h,t as g}from"./VContainer-CrR_anyV.js";import{t as _}from"./VChip-Bj2Bn9Ad.js";import{t as v}from"./VSelect-B8ti2NSE.js";import{t as y}from"./VDataTableServer-DGuK8add.js";import{t as b}from"./VSpacer-DhDsDhMR.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-bmSA0RyN.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=u({__name:`AuditPage`,setup(u){let A=h(),j=s(!1),M=s([]),N=s(0),P=s(1),F=s(null),I=s(``),L=s(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>B()),(s,c)=>(o(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[l(e,{class:`d-flex align-center`},{default:p(()=>[c[7]||=i(` 审计日志 `,-1),l(b),l(v,{modelValue:F.value,"onUpdate:modelValue":[c[0]||=e=>F.value=e,c[1]||=e=>{P.value=1,B()}],items:t(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:I.value,"onUpdate:modelValue":[c[2]||=e=>I.value=e,c[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[4]||=e=>L.value=e,c[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{P.value=e,B()}},{"item.action":p(({item:e})=>[l(_,{color:V(e.action),size:`small`,variant:`tonal`,label:``},{default:p(()=>[i(r(t(C)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":p(({item:e})=>[a(`span`,T,r(e.admin_username),1)]),"item.target":p(({item:e})=>[a(`span`,E,r(t(x)(e.resource_type))+r(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":p(({item:e})=>[a(`span`,D,r(e.detail||``),1)]),"item.ip_address":p(({item:e})=>[a(`span`,O,r(e.ip_address||``),1)]),"item.created_at":p(({item:e})=>[a(`span`,k,r(e.created_at),1)]),"no-data":p(()=>[...c[8]||=[a(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
+1
View File
@@ -0,0 +1 @@
import{Er as e,F as t,N as n,Nr as r,Ur as i,_r as a,ar as o,er as s,hr as c,or as l,sr as u,t as d,tr as f,zr as p,zt as m}from"./index-x_UzlvQU.js";import{o as h,t as g}from"./VContainer-9KPDvITd.js";import{n as _}from"./dataTable-esDY4cOk.js";import{t as v}from"./VChip-C55Q03jC.js";import{t as y}from"./VSelect-D6JhGiC7.js";import{t as b}from"./VDataTableServer-2HgZ5qDn.js";import{t as x}from"./VSpacer-JMAll94i.js";import{a as S,n as C,r as w,t as T}from"./auditNormalize-bmSA0RyN.js";var E={class:`font-weight-medium`},D={class:`text-body-2`},O={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},k={class:`text-caption text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j=u({__name:`AuditPage`,setup(u){let j=h(),M=r(!1),N=r([]),P=r(0),F=r(1),I=r(null),L=r(``),R=r(``),z=C,B=_([{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}]);async function V(){M.value=!0;try{let e=(F.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:I.value||void 0,admin_username:L.value||void 0,date_from:R.value||void 0});N.value=T(t.items||[]),P.value=t.total||0}catch{N.value=[],j(`加载审计日志失败`,`error`)}finally{M.value=!1}}function H(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>V()),(r,c)=>(a(),f(g,{fluid:``,class:`pa-6`},{default:e(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:e(()=>[l(t,{class:`d-flex align-center`},{default:e(()=>[c[7]||=o(` 审计日志 `,-1),l(x),l(y,{modelValue:I.value,"onUpdate:modelValue":[c[0]||=e=>I.value=e,c[1]||=e=>{F.value=1,V()}],items:p(z),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[2]||=e=>L.value=e,c[3]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:R.value,"onUpdate:modelValue":[c[4]||=e=>R.value=e,c[5]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(b,{items:N.value,headers:p(B),"items-length":P.value,loading:M.value,page:F.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{F.value=e,V()}},{"item.action":e(({item:t})=>[l(v,{color:H(t.action),size:`small`,variant:`tonal`,label:``},{default:e(()=>[o(i(p(w)(t.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":e(({item:e})=>[s(`span`,E,i(e.admin_username),1)]),"item.target":e(({item:e})=>[s(`span`,D,i(p(S)(e.resource_type))+i(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":e(({item:e})=>[s(`span`,O,i(e.detail||``),1)]),"item.ip_address":e(({item:e})=>[s(`span`,k,i(e.ip_address||``),1)]),"item.created_at":e(({item:e})=>[s(`span`,A,i(e.created_at),1)]),"no-data":e(()=>[...c[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{a as e,o as t}from"./VSelectionControl-EvpbLA8N.js";import{B as n,F as r,Fr as i,Gr as a,N as o,Or as s,R as c,Ut as l,Vr as u,_r as d,cr as f,lr as p,nr as m,rr as h,sr as g,t as _,yr as v}from"./index-B-qGIXx8.js";import{n as y}from"./dataTable-esDY4cOk.js";import{t as b}from"./VSelect-D0D-yfrH.js";import{t as x}from"./VDataTableServer-DCjhqS-Y.js";import{a as S,n as C,r as w,t as T}from"./auditNormalize-bmSA0RyN.js";var E={class:`font-weight-medium`},D={class:`text-body-2`},O={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},k={class:`text-caption text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j=p({__name:`AuditPage`,setup(p){let j=e(),M=i(!1),N=i([]),P=i(0),F=i(1),I=i(null),L=i(``),R=i(``),z=C,B=y([{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}]);async function V(){M.value=!0;try{let e=(F.value-1)*50,t=await l.get(`/audit/`,{limit:50,offset:e,action:I.value||void 0,admin_username:L.value||void 0,date_from:R.value||void 0});N.value=T(t.items||[]),P.value=t.total||0}catch{N.value=[],j(`加载审计日志失败`,`error`)}finally{M.value=!1}}function H(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return d(()=>V()),(e,i)=>(v(),h(t,{fluid:``,class:`pa-6`},{default:s(()=>[f(c,{elevation:`0`,border:``,rounded:`lg`},{default:s(()=>[f(n,{class:`d-flex align-center`},{default:s(()=>[i[7]||=g(` 审计日志 `,-1),f(o),f(b,{modelValue:I.value,"onUpdate:modelValue":[i[0]||=e=>I.value=e,i[1]||=e=>{F.value=1,V()}],items:u(z),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),f(_,{modelValue:L.value,"onUpdate:modelValue":[i[2]||=e=>L.value=e,i[3]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),f(_,{modelValue:R.value,"onUpdate:modelValue":[i[4]||=e=>R.value=e,i[5]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),f(x,{items:N.value,headers:u(B),"items-length":P.value,loading:M.value,page:F.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":i[6]||=e=>{F.value=e,V()}},{"item.action":s(({item:e})=>[f(r,{color:H(e.action),size:`small`,variant:`tonal`,label:``},{default:s(()=>[g(a(u(w)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":s(({item:e})=>[m(`span`,E,a(e.admin_username),1)]),"item.target":s(({item:e})=>[m(`span`,D,a(u(S)(e.resource_type))+a(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":s(({item:e})=>[m(`span`,O,a(e.detail||``),1)]),"item.ip_address":s(({item:e})=>[m(`span`,k,a(e.ip_address||``),1)]),"item.created_at":s(({item:e})=>[m(`span`,A,a(e.created_at),1)]),"no-data":s(()=>[...i[8]||=[m(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{$n as e,Ar as t,Br as n,Cr as r,F as i,Ir as a,N as o,Rt as s,ar as c,er as l,hr as u,ir as d,or as f,pr as p,t as m}from"./index-Da-oPxMv.js";import{o as h,t as g}from"./VContainer-Dp-8rduj.js";import{t as _}from"./VChip-uNN5BiCx.js";import{t as v}from"./VSelect-B1u55nVH.js";import{t as y}from"./VDataTableServer-BLAQDDBi.js";import{t as b}from"./VSpacer-ZMhNXvUl.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-BHJPJFP9.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=f({__name:`AuditPage`,setup(f){let A=h(),j=t(!1),M=t([]),N=t(0),P=t(1),F=t(null),I=t(``),L=t(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await s.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return p(()=>B()),(t,s)=>(u(),l(g,{fluid:``,class:`pa-6`},{default:r(()=>[c(o,{elevation:`0`,border:``,rounded:`lg`},{default:r(()=>[c(i,{class:`d-flex align-center`},{default:r(()=>[s[7]||=d(` 审计日志 `,-1),c(b),c(v,{modelValue:F.value,"onUpdate:modelValue":[s[0]||=e=>F.value=e,s[1]||=e=>{P.value=1,B()}],items:a(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),c(m,{modelValue:I.value,"onUpdate:modelValue":[s[2]||=e=>I.value=e,s[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),c(m,{modelValue:L.value,"onUpdate:modelValue":[s[4]||=e=>L.value=e,s[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),c(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":s[6]||=e=>{P.value=e,B()}},{"item.action":r(({item:e})=>[c(_,{color:V(e.action),size:`small`,variant:`tonal`,label:``},{default:r(()=>[d(n(a(C)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":r(({item:t})=>[e(`span`,T,n(t.admin_username),1)]),"item.target":r(({item:t})=>[e(`span`,E,n(a(x)(t.resource_type))+n(t.resource_id?` #${t.resource_id}`:``),1)]),"item.detail":r(({item:t})=>[e(`span`,D,n(t.detail||``),1)]),"item.ip_address":r(({item:t})=>[e(`span`,O,n(t.ip_address||``),1)]),"item.created_at":r(({item:t})=>[e(`span`,k,n(t.created_at),1)]),"no-data":r(()=>[...s[8]||=[e(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
+1
View File
@@ -0,0 +1 @@
import{$n as e,Ar as t,Br as n,Cr as r,F as i,Ir as a,N as o,Rt as s,ar as c,er as l,hr as u,ir as d,or as f,pr as p,t as m}from"./index-1vc2lwKY.js";import{o as h,t as g}from"./VContainer-Cyz28tn8.js";import{t as _}from"./VChip-DxlrSIbY.js";import{t as v}from"./VSelect-bmHFJ0Qw.js";import{t as y}from"./VDataTableServer-BgrY7CII.js";import{t as b}from"./VSpacer-DTN9CH1q.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-bmSA0RyN.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=f({__name:`AuditPage`,setup(f){let A=h(),j=t(!1),M=t([]),N=t(0),P=t(1),F=t(null),I=t(``),L=t(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await s.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return p(()=>B()),(t,s)=>(u(),l(g,{fluid:``,class:`pa-6`},{default:r(()=>[c(o,{elevation:`0`,border:``,rounded:`lg`},{default:r(()=>[c(i,{class:`d-flex align-center`},{default:r(()=>[s[7]||=d(` 审计日志 `,-1),c(b),c(v,{modelValue:F.value,"onUpdate:modelValue":[s[0]||=e=>F.value=e,s[1]||=e=>{P.value=1,B()}],items:a(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),c(m,{modelValue:I.value,"onUpdate:modelValue":[s[2]||=e=>I.value=e,s[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),c(m,{modelValue:L.value,"onUpdate:modelValue":[s[4]||=e=>L.value=e,s[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),c(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":s[6]||=e=>{P.value=e,B()}},{"item.action":r(({item:e})=>[c(_,{color:V(e.action),size:`small`,variant:`tonal`,label:``},{default:r(()=>[d(n(a(C)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":r(({item:t})=>[e(`span`,T,n(t.admin_username),1)]),"item.target":r(({item:t})=>[e(`span`,E,n(a(x)(t.resource_type))+n(t.resource_id?` #${t.resource_id}`:``),1)]),"item.detail":r(({item:t})=>[e(`span`,D,n(t.detail||``),1)]),"item.ip_address":r(({item:t})=>[e(`span`,O,n(t.ip_address||``),1)]),"item.created_at":r(({item:t})=>[e(`span`,k,n(t.created_at),1)]),"no-data":r(()=>[...s[8]||=[e(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,N as n,Vr as r,ar as i,er as a,gr as o,jr as s,mr as c,or as l,sr as u,t as d,tr as f,wr as p,zt as m}from"./index-BOX5ad4G.js";import{o as h,t as g}from"./VContainer-CsduC4GT.js";import{t as _}from"./VChip-D0VaTwoJ.js";import{t as v}from"./VSelect-skTyo71B.js";import{t as y}from"./VDataTableServer-CyZWQ374.js";import{t as b}from"./VSpacer-CysfZoCS.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-bmSA0RyN.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=u({__name:`AuditPage`,setup(u){let A=h(),j=s(!1),M=s([]),N=s(0),P=s(1),F=s(null),I=s(``),L=s(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>B()),(s,c)=>(o(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[l(e,{class:`d-flex align-center`},{default:p(()=>[c[7]||=i(` 审计日志 `,-1),l(b),l(v,{modelValue:F.value,"onUpdate:modelValue":[c[0]||=e=>F.value=e,c[1]||=e=>{P.value=1,B()}],items:t(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:I.value,"onUpdate:modelValue":[c[2]||=e=>I.value=e,c[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[4]||=e=>L.value=e,c[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{P.value=e,B()}},{"item.action":p(({item:e})=>[l(_,{color:V(e.action),size:`small`,variant:`tonal`,label:``},{default:p(()=>[i(r(t(C)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":p(({item:e})=>[a(`span`,T,r(e.admin_username),1)]),"item.target":p(({item:e})=>[a(`span`,E,r(t(x)(e.resource_type))+r(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":p(({item:e})=>[a(`span`,D,r(e.detail||``),1)]),"item.ip_address":p(({item:e})=>[a(`span`,O,r(e.ip_address||``),1)]),"item.created_at":p(({item:e})=>[a(`span`,k,r(e.created_at),1)]),"no-data":p(()=>[...c[8]||=[a(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
+1
View File
@@ -0,0 +1 @@
import{a as e,o as t}from"./VSelectionControl-BQRUjX5P.js";import{B as n,F as r,Fr as i,Gr as a,N as o,Or as s,R as c,Ut as l,Vr as u,_r as d,cr as f,lr as p,nr as m,rr as h,sr as g,t as _,yr as v}from"./index-DbSyD28P.js";import{n as y}from"./dataTable-esDY4cOk.js";import{t as b}from"./VSelect-glh4Zdhv.js";import{t as x}from"./VDataTableServer-BisDXMgG.js";import{a as S,n as C,r as w,t as T}from"./auditNormalize-bmSA0RyN.js";var E={class:`font-weight-medium`},D={class:`text-body-2`},O={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},k={class:`text-caption text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j=p({__name:`AuditPage`,setup(p){let j=e(),M=i(!1),N=i([]),P=i(0),F=i(1),I=i(null),L=i(``),R=i(``),z=C,B=y([{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}]);async function V(){M.value=!0;try{let e=(F.value-1)*50,t=await l.get(`/audit/`,{limit:50,offset:e,action:I.value||void 0,admin_username:L.value||void 0,date_from:R.value||void 0});N.value=T(t.items||[]),P.value=t.total||0}catch{N.value=[],j(`加载审计日志失败`,`error`)}finally{M.value=!1}}function H(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return d(()=>V()),(e,i)=>(v(),h(t,{fluid:``,class:`pa-6`},{default:s(()=>[f(c,{elevation:`0`,border:``,rounded:`lg`},{default:s(()=>[f(n,{class:`d-flex align-center`},{default:s(()=>[i[7]||=g(` 审计日志 `,-1),f(o),f(b,{modelValue:I.value,"onUpdate:modelValue":[i[0]||=e=>I.value=e,i[1]||=e=>{F.value=1,V()}],items:u(z),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),f(_,{modelValue:L.value,"onUpdate:modelValue":[i[2]||=e=>L.value=e,i[3]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),f(_,{modelValue:R.value,"onUpdate:modelValue":[i[4]||=e=>R.value=e,i[5]||=e=>{F.value=1,V()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),f(x,{items:N.value,headers:u(B),"items-length":P.value,loading:M.value,page:F.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":i[6]||=e=>{F.value=e,V()}},{"item.action":s(({item:e})=>[f(r,{color:H(e.action),size:`small`,variant:`tonal`,label:``},{default:s(()=>[g(a(u(w)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":s(({item:e})=>[m(`span`,E,a(e.admin_username),1)]),"item.target":s(({item:e})=>[m(`span`,D,a(u(S)(e.resource_type))+a(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":s(({item:e})=>[m(`span`,O,a(e.detail||``),1)]),"item.ip_address":s(({item:e})=>[m(`span`,k,a(e.ip_address||``),1)]),"item.created_at":s(({item:e})=>[m(`span`,A,a(e.created_at),1)]),"no-data":s(()=>[...i[8]||=[m(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{Er as e,F as t,N as n,Nr as r,Ur as i,_r as a,ar as o,er as s,hr as c,or as l,sr as u,t as d,tr as f,zr as p,zt as m}from"./index-DoaDMa1C.js";import{o as h,t as g}from"./VContainer-BQRFgmV8.js";import{t as _}from"./VChip-w-VUeBu6.js";import{t as v}from"./VSelect-lvvpsnJa.js";import{t as y}from"./VDataTableServer-CqSShzYP.js";import{t as b}from"./VSpacer-DctU2jOI.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-bmSA0RyN.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=u({__name:`AuditPage`,setup(u){let A=h(),j=r(!1),M=r([]),N=r(0),P=r(1),F=r(null),I=r(``),L=r(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>B()),(r,c)=>(a(),f(g,{fluid:``,class:`pa-6`},{default:e(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:e(()=>[l(t,{class:`d-flex align-center`},{default:e(()=>[c[7]||=o(` 审计日志 `,-1),l(b),l(v,{modelValue:F.value,"onUpdate:modelValue":[c[0]||=e=>F.value=e,c[1]||=e=>{P.value=1,B()}],items:p(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:I.value,"onUpdate:modelValue":[c[2]||=e=>I.value=e,c[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[4]||=e=>L.value=e,c[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{P.value=e,B()}},{"item.action":e(({item:t})=>[l(_,{color:V(t.action),size:`small`,variant:`tonal`,label:``},{default:e(()=>[o(i(p(C)(t.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":e(({item:e})=>[s(`span`,T,i(e.admin_username),1)]),"item.target":e(({item:e})=>[s(`span`,E,i(p(x)(e.resource_type))+i(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":e(({item:e})=>[s(`span`,D,i(e.detail||``),1)]),"item.ip_address":e(({item:e})=>[s(`span`,O,i(e.ip_address||``),1)]),"item.created_at":e(({item:e})=>[s(`span`,k,i(e.created_at),1)]),"no-data":e(()=>[...c[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,N as n,Vr as r,ar as i,er as a,gr as o,jr as s,mr as c,or as l,sr as u,t as d,tr as f,wr as p,zt as m}from"./index-BoZyi8Cu.js";import{o as h,t as g}from"./VContainer-BT9w_m28.js";import{t as _}from"./VChip-BVR48u8E.js";import{t as v}from"./VSelect-BuZWt-gO.js";import{t as y}from"./VDataTableServer-CjBcrBi4.js";import{t as b}from"./VSpacer-BHLI8VYt.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-bmSA0RyN.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=u({__name:`AuditPage`,setup(u){let A=h(),j=s(!1),M=s([]),N=s(0),P=s(1),F=s(null),I=s(``),L=s(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>B()),(s,c)=>(o(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[l(e,{class:`d-flex align-center`},{default:p(()=>[c[7]||=i(` 审计日志 `,-1),l(b),l(v,{modelValue:F.value,"onUpdate:modelValue":[c[0]||=e=>F.value=e,c[1]||=e=>{P.value=1,B()}],items:t(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:I.value,"onUpdate:modelValue":[c[2]||=e=>I.value=e,c[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[4]||=e=>L.value=e,c[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{P.value=e,B()}},{"item.action":p(({item:e})=>[l(_,{color:V(e.action),size:`small`,variant:`tonal`,label:``},{default:p(()=>[i(r(t(C)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":p(({item:e})=>[a(`span`,T,r(e.admin_username),1)]),"item.target":p(({item:e})=>[a(`span`,E,r(t(x)(e.resource_type))+r(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":p(({item:e})=>[a(`span`,D,r(e.detail||``),1)]),"item.ip_address":p(({item:e})=>[a(`span`,O,r(e.ip_address||``),1)]),"item.created_at":p(({item:e})=>[a(`span`,k,r(e.created_at),1)]),"no-data":p(()=>[...c[8]||=[a(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{$n as e,Ar as t,Br as n,Cr as r,F as i,Ir as a,M as o,N as s,Rt as c,ar as l,er as u,hr as d,ir as f,or as p,pr as m}from"./index-1vc2lwKY.js";import{o as h,t as g}from"./VContainer-Cyz28tn8.js";import{t as _}from"./VChip-DxlrSIbY.js";import{t as v}from"./VSelect-bmHFJ0Qw.js";import{t as y}from"./VDataTableServer-BgrY7CII.js";import{t as b}from"./VSpacer-DTN9CH1q.js";import{t as x}from"./apiError-CCaH8lNC.js";import{t as S}from"./useServerList-BTHLukDM.js";var C={class:`text-body-2`},w={class:`text-medium-emphasis`},T={class:`text-medium-emphasis`},E={class:`text-caption text-medium-emphasis`},D={class:`font-weight-medium`},O={class:`text-caption text-medium-emphasis`},k=p({__name:`CommandsPage`,setup(p){let k=h(),{servers:A,loadServers:j}=S(),M=t(!1),N=t(`commands`),P=t(1),F=t(0),I=t(30),L=t(null),R=t([]),z=t([]),B=[{title:`命令`,key:`command`},{title:`服务器`,key:`server_name`},{title:`用户`,key:`admin_username`,width:100},{title:`时间`,key:`created_at`,width:160}],V=[{title:`服务器`,key:`server_name`},{title:`状态`,key:`status`,width:80},{title:`来源`,key:`remote_addr`,width:120},{title:`开始时间`,key:`started_at`,width:160}];async function H(){M.value=!0;try{if(N.value===`commands`){let e=await c.getList(`/assets/command-logs`,{server_id:L.value||void 0,page:P.value,per_page:I.value});R.value=e.items,F.value=e.total}else{let e=await c.getList(`/assets/ssh-sessions`,{server_id:L.value||void 0,page:P.value,per_page:I.value});z.value=e.items,F.value=e.total}}catch(e){R.value=[],z.value=[],k(x(e,`加载命令日志失败`),`error`)}finally{M.value=!1}}return m(()=>{j(),H()}),(t,c)=>(d(),u(g,{fluid:``,class:`pa-6`},{default:r(()=>[l(s,{elevation:`0`,border:``,rounded:`lg`},{default:r(()=>[l(i,{class:`d-flex align-center`},{default:r(()=>[c[4]||=f(` 命令日志 `,-1),l(b),l(v,{modelValue:N.value,"onUpdate:modelValue":[c[0]||=e=>N.value=e,H],items:[{title:`命令视图`,value:`commands`},{title:`会话视图`,value:`sessions`}],"item-title":`title`,"item-value":`value`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`}},null,8,[`modelValue`]),l(v,{modelValue:L.value,"onUpdate:modelValue":[c[1]||=e=>L.value=e,H],items:a(A),"item-title":`name`,"item-value":`id`,label:`服务器`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`180px`},class:`ml-3`,clearable:``},null,8,[`modelValue`,`items`])]),_:1}),l(o),N.value===`commands`?(d(),u(y,{key:0,items:R.value,headers:B,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":c[2]||=e=>{P.value=e,H()}},{"item.command":r(({item:t})=>[e(`code`,C,n(t.command),1)]),"item.server_name":r(({item:t})=>[e(`span`,w,n(t.server_name||``),1)]),"item.admin_username":r(({item:t})=>[e(`span`,T,n(t.admin_username||``),1)]),"item.created_at":r(({item:t})=>[e(`span`,E,n(t.created_at),1)]),"no-data":r(()=>[...c[5]||=[e(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])):(d(),u(y,{key:1,items:z.value,headers:V,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":c[3]||=e=>{P.value=e,H()}},{"item.server_name":r(({item:t})=>[e(`span`,D,n(t.server_name||``),1)]),"item.status":r(({item:e})=>[l(_,{color:e.status===`closed`?`grey`:`success`,size:`small`,variant:`tonal`,label:``},{default:r(()=>[f(n(e.status),1)]),_:2},1032,[`color`])]),"item.started_at":r(({item:t})=>[e(`span`,O,n(t.started_at),1)]),"no-data":r(()=>[...c[6]||=[e(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`]))]),_:1})]),_:1}))}});export{k as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,M as n,N as r,Vr as i,ar as a,er as o,gr as s,jr as c,mr as l,or as u,sr as d,tr as f,wr as p,zt as m}from"./index-BOX5ad4G.js";import{o as h,t as g}from"./VContainer-CsduC4GT.js";import{t as _}from"./VChip-D0VaTwoJ.js";import{t as v}from"./VSelect-skTyo71B.js";import{t as y}from"./VDataTableServer-CyZWQ374.js";import{t as b}from"./VSpacer-CysfZoCS.js";import{t as x}from"./apiError-D87YOHDz.js";import{t as S}from"./useServerList-EQ3n4ASB.js";var C={class:`text-body-2`},w={class:`text-medium-emphasis`},T={class:`text-medium-emphasis`},E={class:`text-caption text-medium-emphasis`},D={class:`font-weight-medium`},O={class:`text-caption text-medium-emphasis`},k=d({__name:`CommandsPage`,setup(d){let k=h(),{servers:A,loadServers:j}=S(),M=c(!1),N=c(`commands`),P=c(1),F=c(0),I=c(30),L=c(null),R=c([]),z=c([]),B=[{title:`命令`,key:`command`},{title:`服务器`,key:`server_name`},{title:`用户`,key:`admin_username`,width:100},{title:`时间`,key:`created_at`,width:160}],V=[{title:`服务器`,key:`server_name`},{title:`状态`,key:`status`,width:80},{title:`来源`,key:`remote_addr`,width:120},{title:`开始时间`,key:`started_at`,width:160}];async function H(){M.value=!0;try{if(N.value===`commands`){let e=await m.getList(`/assets/command-logs`,{server_id:L.value||void 0,page:P.value,per_page:I.value});R.value=e.items,F.value=e.total}else{let e=await m.getList(`/assets/ssh-sessions`,{server_id:L.value||void 0,page:P.value,per_page:I.value});z.value=e.items,F.value=e.total}}catch(e){R.value=[],z.value=[],k(x(e,`加载命令日志失败`),`error`)}finally{M.value=!1}}return l(()=>{j(),H()}),(c,l)=>(s(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[u(r,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[u(e,{class:`d-flex align-center`},{default:p(()=>[l[4]||=a(` 命令日志 `,-1),u(b),u(v,{modelValue:N.value,"onUpdate:modelValue":[l[0]||=e=>N.value=e,H],items:[{title:`命令视图`,value:`commands`},{title:`会话视图`,value:`sessions`}],"item-title":`title`,"item-value":`value`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`}},null,8,[`modelValue`]),u(v,{modelValue:L.value,"onUpdate:modelValue":[l[1]||=e=>L.value=e,H],items:t(A),"item-title":`name`,"item-value":`id`,label:`服务器`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`180px`},class:`ml-3`,clearable:``},null,8,[`modelValue`,`items`])]),_:1}),u(n),N.value===`commands`?(s(),f(y,{key:0,items:R.value,headers:B,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":l[2]||=e=>{P.value=e,H()}},{"item.command":p(({item:e})=>[o(`code`,C,i(e.command),1)]),"item.server_name":p(({item:e})=>[o(`span`,w,i(e.server_name||``),1)]),"item.admin_username":p(({item:e})=>[o(`span`,T,i(e.admin_username||``),1)]),"item.created_at":p(({item:e})=>[o(`span`,E,i(e.created_at),1)]),"no-data":p(()=>[...l[5]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])):(s(),f(y,{key:1,items:z.value,headers:V,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":l[3]||=e=>{P.value=e,H()}},{"item.server_name":p(({item:e})=>[o(`span`,D,i(e.server_name||``),1)]),"item.status":p(({item:e})=>[u(_,{color:e.status===`closed`?`grey`:`success`,size:`small`,variant:`tonal`,label:``},{default:p(()=>[a(i(e.status),1)]),_:2},1032,[`color`])]),"item.started_at":p(({item:e})=>[o(`span`,O,i(e.started_at),1)]),"no-data":p(()=>[...l[6]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`]))]),_:1})]),_:1}))}});export{k as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,M as n,N as r,Vr as i,ar as a,er as o,gr as s,jr as c,mr as l,or as u,sr as d,tr as f,wr as p,zt as m}from"./index-DhXUzl5h.js";import{o as h,t as g}from"./VContainer-CrR_anyV.js";import{t as _}from"./VChip-Bj2Bn9Ad.js";import{t as v}from"./VSelect-B8ti2NSE.js";import{t as y}from"./VDataTableServer-DGuK8add.js";import{t as b}from"./VSpacer-DhDsDhMR.js";import{t as x}from"./apiError-CNIyCFzv.js";import{t as S}from"./useServerList-mVKIkYtT.js";var C={class:`text-body-2`},w={class:`text-medium-emphasis`},T={class:`text-medium-emphasis`},E={class:`text-caption text-medium-emphasis`},D={class:`font-weight-medium`},O={class:`text-caption text-medium-emphasis`},k=d({__name:`CommandsPage`,setup(d){let k=h(),{servers:A,loadServers:j}=S(),M=c(!1),N=c(`commands`),P=c(1),F=c(0),I=c(30),L=c(null),R=c([]),z=c([]),B=[{title:`命令`,key:`command`},{title:`服务器`,key:`server_name`},{title:`用户`,key:`admin_username`,width:100},{title:`时间`,key:`created_at`,width:160}],V=[{title:`服务器`,key:`server_name`},{title:`状态`,key:`status`,width:80},{title:`来源`,key:`remote_addr`,width:120},{title:`开始时间`,key:`started_at`,width:160}];async function H(){M.value=!0;try{if(N.value===`commands`){let e=await m.getList(`/assets/command-logs`,{server_id:L.value||void 0,page:P.value,per_page:I.value});R.value=e.items,F.value=e.total}else{let e=await m.getList(`/assets/ssh-sessions`,{server_id:L.value||void 0,page:P.value,per_page:I.value});z.value=e.items,F.value=e.total}}catch(e){R.value=[],z.value=[],k(x(e,`加载命令日志失败`),`error`)}finally{M.value=!1}}return l(()=>{j(),H()}),(c,l)=>(s(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[u(r,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[u(e,{class:`d-flex align-center`},{default:p(()=>[l[4]||=a(` 命令日志 `,-1),u(b),u(v,{modelValue:N.value,"onUpdate:modelValue":[l[0]||=e=>N.value=e,H],items:[{title:`命令视图`,value:`commands`},{title:`会话视图`,value:`sessions`}],"item-title":`title`,"item-value":`value`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`}},null,8,[`modelValue`]),u(v,{modelValue:L.value,"onUpdate:modelValue":[l[1]||=e=>L.value=e,H],items:t(A),"item-title":`name`,"item-value":`id`,label:`服务器`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`180px`},class:`ml-3`,clearable:``},null,8,[`modelValue`,`items`])]),_:1}),u(n),N.value===`commands`?(s(),f(y,{key:0,items:R.value,headers:B,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":l[2]||=e=>{P.value=e,H()}},{"item.command":p(({item:e})=>[o(`code`,C,i(e.command),1)]),"item.server_name":p(({item:e})=>[o(`span`,w,i(e.server_name||``),1)]),"item.admin_username":p(({item:e})=>[o(`span`,T,i(e.admin_username||``),1)]),"item.created_at":p(({item:e})=>[o(`span`,E,i(e.created_at),1)]),"no-data":p(()=>[...l[5]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])):(s(),f(y,{key:1,items:z.value,headers:V,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":l[3]||=e=>{P.value=e,H()}},{"item.server_name":p(({item:e})=>[o(`span`,D,i(e.server_name||``),1)]),"item.status":p(({item:e})=>[u(_,{color:e.status===`closed`?`grey`:`success`,size:`small`,variant:`tonal`,label:``},{default:p(()=>[a(i(e.status),1)]),_:2},1032,[`color`])]),"item.started_at":p(({item:e})=>[o(`span`,O,i(e.started_at),1)]),"no-data":p(()=>[...l[6]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`]))]),_:1})]),_:1}))}});export{k as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,M as n,N as r,Vr as i,ar as a,er as o,gr as s,jr as c,mr as l,or as u,sr as d,tr as f,wr as p,zt as m}from"./index-8R5Vx1WH.js";import{o as h,t as g}from"./VContainer-ByAXNVXy.js";import{t as _}from"./VChip-CO9HT0ch.js";import{t as v}from"./VSelect-BB7JEkD3.js";import{t as y}from"./VDataTableServer-Bx8d7a_i.js";import{t as b}from"./VSpacer-CTDq7Cy_.js";import{t as x}from"./apiError-DdoXm_FH.js";import{t as S}from"./useServerList-Xwm-w1s9.js";var C={class:`text-body-2`},w={class:`text-medium-emphasis`},T={class:`text-medium-emphasis`},E={class:`text-caption text-medium-emphasis`},D={class:`font-weight-medium`},O={class:`text-caption text-medium-emphasis`},k=d({__name:`CommandsPage`,setup(d){let k=h(),{servers:A,loadServers:j}=S(),M=c(!1),N=c(`commands`),P=c(1),F=c(0),I=c(30),L=c(null),R=c([]),z=c([]),B=[{title:`命令`,key:`command`},{title:`服务器`,key:`server_name`},{title:`用户`,key:`admin_username`,width:100},{title:`时间`,key:`created_at`,width:160}],V=[{title:`服务器`,key:`server_name`},{title:`状态`,key:`status`,width:80},{title:`来源`,key:`remote_addr`,width:120},{title:`开始时间`,key:`started_at`,width:160}];async function H(){M.value=!0;try{if(N.value===`commands`){let e=await m.getList(`/assets/command-logs`,{server_id:L.value||void 0,page:P.value,per_page:I.value});R.value=e.items,F.value=e.total}else{let e=await m.getList(`/assets/ssh-sessions`,{server_id:L.value||void 0,page:P.value,per_page:I.value});z.value=e.items,F.value=e.total}}catch(e){R.value=[],z.value=[],k(x(e,`加载命令日志失败`),`error`)}finally{M.value=!1}}return l(()=>{j(),H()}),(c,l)=>(s(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[u(r,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[u(e,{class:`d-flex align-center`},{default:p(()=>[l[4]||=a(` 命令日志 `,-1),u(b),u(v,{modelValue:N.value,"onUpdate:modelValue":[l[0]||=e=>N.value=e,H],items:[{title:`命令视图`,value:`commands`},{title:`会话视图`,value:`sessions`}],"item-title":`title`,"item-value":`value`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`}},null,8,[`modelValue`]),u(v,{modelValue:L.value,"onUpdate:modelValue":[l[1]||=e=>L.value=e,H],items:t(A),"item-title":`name`,"item-value":`id`,label:`服务器`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`180px`},class:`ml-3`,clearable:``},null,8,[`modelValue`,`items`])]),_:1}),u(n),N.value===`commands`?(s(),f(y,{key:0,items:R.value,headers:B,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":l[2]||=e=>{P.value=e,H()}},{"item.command":p(({item:e})=>[o(`code`,C,i(e.command),1)]),"item.server_name":p(({item:e})=>[o(`span`,w,i(e.server_name||``),1)]),"item.admin_username":p(({item:e})=>[o(`span`,T,i(e.admin_username||``),1)]),"item.created_at":p(({item:e})=>[o(`span`,E,i(e.created_at),1)]),"no-data":p(()=>[...l[5]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])):(s(),f(y,{key:1,items:z.value,headers:V,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":l[3]||=e=>{P.value=e,H()}},{"item.server_name":p(({item:e})=>[o(`span`,D,i(e.server_name||``),1)]),"item.status":p(({item:e})=>[u(_,{color:e.status===`closed`?`grey`:`success`,size:`small`,variant:`tonal`,label:``},{default:p(()=>[a(i(e.status),1)]),_:2},1032,[`color`])]),"item.started_at":p(({item:e})=>[o(`span`,O,i(e.started_at),1)]),"no-data":p(()=>[...l[6]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`]))]),_:1})]),_:1}))}});export{k as default};
+1
View File
@@ -0,0 +1 @@
import{$n as e,Ar as t,Br as n,Cr as r,F as i,Ir as a,M as o,N as s,Rt as c,ar as l,er as u,hr as d,ir as f,or as p,pr as m}from"./index-Da-oPxMv.js";import{o as h,t as g}from"./VContainer-Dp-8rduj.js";import{t as _}from"./VChip-uNN5BiCx.js";import{t as v}from"./VSelect-B1u55nVH.js";import{t as y}from"./VDataTableServer-BLAQDDBi.js";import{t as b}from"./VSpacer-ZMhNXvUl.js";import{t as x}from"./apiError-DICy4JAA.js";import{t as S}from"./useServerList-Dj3PjUZW.js";var C={class:`text-body-2`},w={class:`text-medium-emphasis`},T={class:`text-medium-emphasis`},E={class:`text-caption text-medium-emphasis`},D={class:`font-weight-medium`},O={class:`text-caption text-medium-emphasis`},k=p({__name:`CommandsPage`,setup(p){let k=h(),{servers:A,loadServers:j}=S(),M=t(!1),N=t(`commands`),P=t(1),F=t(0),I=t(30),L=t(null),R=t([]),z=t([]),B=[{title:`命令`,key:`command`},{title:`服务器`,key:`server_name`},{title:`用户`,key:`admin_username`,width:100},{title:`时间`,key:`created_at`,width:160}],V=[{title:`服务器`,key:`server_name`},{title:`状态`,key:`status`,width:80},{title:`来源`,key:`remote_addr`,width:120},{title:`开始时间`,key:`started_at`,width:160}];async function H(){M.value=!0;try{if(N.value===`commands`){let e=await c.getList(`/assets/command-logs`,{server_id:L.value||void 0,page:P.value,per_page:I.value});R.value=e.items,F.value=e.total}else{let e=await c.getList(`/assets/ssh-sessions`,{server_id:L.value||void 0,page:P.value,per_page:I.value});z.value=e.items,F.value=e.total}}catch(e){R.value=[],z.value=[],k(x(e,`加载命令日志失败`),`error`)}finally{M.value=!1}}return m(()=>{j(),H()}),(t,c)=>(d(),u(g,{fluid:``,class:`pa-6`},{default:r(()=>[l(s,{elevation:`0`,border:``,rounded:`lg`},{default:r(()=>[l(i,{class:`d-flex align-center`},{default:r(()=>[c[4]||=f(` 命令日志 `,-1),l(b),l(v,{modelValue:N.value,"onUpdate:modelValue":[c[0]||=e=>N.value=e,H],items:[{title:`命令视图`,value:`commands`},{title:`会话视图`,value:`sessions`}],"item-title":`title`,"item-value":`value`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`}},null,8,[`modelValue`]),l(v,{modelValue:L.value,"onUpdate:modelValue":[c[1]||=e=>L.value=e,H],items:a(A),"item-title":`name`,"item-value":`id`,label:`服务器`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`180px`},class:`ml-3`,clearable:``},null,8,[`modelValue`,`items`])]),_:1}),l(o),N.value===`commands`?(d(),u(y,{key:0,items:R.value,headers:B,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":c[2]||=e=>{P.value=e,H()}},{"item.command":r(({item:t})=>[e(`code`,C,n(t.command),1)]),"item.server_name":r(({item:t})=>[e(`span`,w,n(t.server_name||``),1)]),"item.admin_username":r(({item:t})=>[e(`span`,T,n(t.admin_username||``),1)]),"item.created_at":r(({item:t})=>[e(`span`,E,n(t.created_at),1)]),"no-data":r(()=>[...c[5]||=[e(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])):(d(),u(y,{key:1,items:z.value,headers:V,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":c[3]||=e=>{P.value=e,H()}},{"item.server_name":r(({item:t})=>[e(`span`,D,n(t.server_name||``),1)]),"item.status":r(({item:e})=>[l(_,{color:e.status===`closed`?`grey`:`success`,size:`small`,variant:`tonal`,label:``},{default:r(()=>[f(n(e.status),1)]),_:2},1032,[`color`])]),"item.started_at":r(({item:t})=>[e(`span`,O,n(t.started_at),1)]),"no-data":r(()=>[...c[6]||=[e(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`]))]),_:1})]),_:1}))}});export{k as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More