feat(servers): 未设路径区块与行内详情;命令栏恢复单色

服务器页拆分未设路径列表、行内展开详情;API target_path_unset 可选过滤。
命令栏取消 Shell 语法彩色,ANSI 仅保留 xterm SSH 输出区。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Nexus Agent
2026-06-08 12:48:45 +08:00
parent 8312a6cf81
commit 8c86b50d09
473 changed files with 9171 additions and 219 deletions
+30
View File
@@ -816,3 +816,33 @@
{"ts":"2026-06-08T12:33:55+08:00","date":"2026-06-08","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"}
{"ts":"2026-06-08T12:33:55+08:00","date":"2026-06-08","gate":"text_eol","result":"PASS","detail":"git index LF"}
{"ts":"2026-06-08T12:33:55+08:00","date":"2026-06-08","gate":"summary","result":"PASS","detail":"7/7"}
{"ts":"2026-06-08T12:43:48+08:00","date":"2026-06-08","gate":"changelog","result":"PASS","detail":"2026-06-08-servers-unset-path-inline-detail.md 35lines"}
{"ts":"2026-06-08T12:43:48+08:00","date":"2026-06-08","gate":"audit","result":"PASS","detail":"2026-06-08-webssh-xterm-ansi-output-fix.md"}
{"ts":"2026-06-08T12:43:48+08:00","date":"2026-06-08","gate":"test","result":"PASS","detail":"all passed"}
{"ts":"2026-06-08T12:43:48+08:00","date":"2026-06-08","gate":"lint","result":"PASS","detail":"0 violations"}
{"ts":"2026-06-08T12:43:48+08:00","date":"2026-06-08","gate":"import","result":"PASS","detail":"ok"}
{"ts":"2026-06-08T12:43:48+08:00","date":"2026-06-08","gate":"security","result":"PASS","detail":"0 HIGH"}
{"ts":"2026-06-08T12:43:48+08:00","date":"2026-06-08","gate":"review","result":"PASS","detail":"audit covers changes"}
{"ts":"2026-06-08T12:43:48+08:00","date":"2026-06-08","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"}
{"ts":"2026-06-08T12:43:48+08:00","date":"2026-06-08","gate":"text_eol","result":"PASS","detail":"git index LF"}
{"ts":"2026-06-08T12:43:48+08:00","date":"2026-06-08","gate":"summary","result":"PASS","detail":"7/7"}
{"ts":"2026-06-08T12:47:12+08:00","date":"2026-06-08","gate":"changelog","result":"PASS","detail":"2026-06-08-terminal-cmdbar-monochrome.md 25lines"}
{"ts":"2026-06-08T12:47:12+08:00","date":"2026-06-08","gate":"audit","result":"PASS","detail":"2026-06-08-servers-unset-path-inline-detail.md"}
{"ts":"2026-06-08T12:47:12+08:00","date":"2026-06-08","gate":"test","result":"PASS","detail":"all passed"}
{"ts":"2026-06-08T12:47:12+08:00","date":"2026-06-08","gate":"lint","result":"PASS","detail":"0 violations"}
{"ts":"2026-06-08T12:47:12+08:00","date":"2026-06-08","gate":"import","result":"PASS","detail":"ok"}
{"ts":"2026-06-08T12:47:12+08:00","date":"2026-06-08","gate":"security","result":"PASS","detail":"0 HIGH"}
{"ts":"2026-06-08T12:47:12+08:00","date":"2026-06-08","gate":"review","result":"BLOCK","detail":"audit missing changed files"}
{"ts":"2026-06-08T12:47:12+08:00","date":"2026-06-08","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"}
{"ts":"2026-06-08T12:47:12+08:00","date":"2026-06-08","gate":"text_eol","result":"PASS","detail":"git index LF"}
{"ts":"2026-06-08T12:47:12+08:00","date":"2026-06-08","gate":"summary","result":"BLOCK","detail":"6/7"}
{"ts":"2026-06-08T12:47:57+08:00","date":"2026-06-08","gate":"changelog","result":"PASS","detail":"2026-06-08-terminal-cmdbar-monochrome.md 25lines"}
{"ts":"2026-06-08T12:47:57+08:00","date":"2026-06-08","gate":"audit","result":"PASS","detail":"2026-06-08-deploy-production-batch.md"}
{"ts":"2026-06-08T12:47:57+08:00","date":"2026-06-08","gate":"test","result":"PASS","detail":"all passed"}
{"ts":"2026-06-08T12:47:57+08:00","date":"2026-06-08","gate":"lint","result":"PASS","detail":"0 violations"}
{"ts":"2026-06-08T12:47:57+08:00","date":"2026-06-08","gate":"import","result":"PASS","detail":"ok"}
{"ts":"2026-06-08T12:47:57+08:00","date":"2026-06-08","gate":"security","result":"PASS","detail":"0 HIGH"}
{"ts":"2026-06-08T12:47:57+08:00","date":"2026-06-08","gate":"review","result":"PASS","detail":"audit covers changes"}
{"ts":"2026-06-08T12:47:57+08:00","date":"2026-06-08","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"}
{"ts":"2026-06-08T12:47:57+08:00","date":"2026-06-08","gate":"text_eol","result":"PASS","detail":"git index LF"}
{"ts":"2026-06-08T12:47:57+08:00","date":"2026-06-08","gate":"summary","result":"PASS","detail":"7/7"}
@@ -0,0 +1,46 @@
# 审计 — 生产部署批次(WebSSH ANSI + 服务器未设路径 + 命令栏单色)
**Changelog**:
- `docs/changelog/2026-06-08-webssh-xterm-ansi-output-fix.md`
- `docs/changelog/2026-06-08-servers-unset-path-inline-detail.md`
- `docs/changelog/2026-06-08-terminal-cmdbar-monochrome.md`
## 变更文件
| 模块 | 文件 |
|------|------|
| WebSSH relay | `server/api/webssh.py` |
| 终端解码 | `frontend/src/utils/terminalPayload.ts` |
| 终端会话 | `frontend/src/composables/terminal/useTerminalSessions.ts` |
| 终端页 | `frontend/src/pages/TerminalPage.vue` |
| 命令栏 | `frontend/src/components/terminal/TerminalCmdBar.vue` |
| WebSSH 单测 | `tests/test_webssh_terminal_payload.py` |
| 路径判定 | `server/utils/posix_paths.py` |
| 服务器仓储 | `server/infrastructure/database/server_repo.py` |
| 服务器 API | `server/api/servers.py` |
| 前端路径 util | `frontend/src/utils/serverTargetPath.ts` |
| 分页 composable | `frontend/src/composables/useServerPagination.ts` |
| 行内详情 | `frontend/src/components/servers/ServerInlineDetail.vue` |
| 未设路径面板 | `frontend/src/components/servers/ServerUnsetPathPanel.vue` |
| 服务器页 | `frontend/src/pages/ServersPage.vue` |
| 路径过滤单测 | `tests/test_server_target_path_filter.py` |
## Step 3
| 项 | 结论 |
|----|------|
| xterm ANSI 在 SSH 输出区 | PASSPTY env + data_b64 |
| 命令栏单色 | PASS`.sh-*` 统一 on-surface |
| `target_path_unset` 默认 None | PASS |
| 双表 refresh / 行内详情 | PASS |
## Closure
Gate 7/7 PASS · pytest + local_verify + build · 生产部署
## DoD
- [x] WebSSH xterm ANSI
- [x] 命令栏无彩色
- [x] 服务器未设路径区块 + 行内详情
- [x] 单测与门控
@@ -0,0 +1,30 @@
# 审计 — 服务器未设路径区块 + 行内详情
**Changelog**: `docs/changelog/2026-06-08-servers-unset-path-inline-detail.md`
## 变更文件
`posix_paths.py` · `server_repo.py` · `servers.py` · `serverTargetPath.ts` · `useServerPagination.ts` · `ServerInlineDetail.vue` · `ServerUnsetPathPanel.vue` · `ServersPage.vue` · `tests/test_server_target_path_filter.py` · `web/app/assets/ServersPage-*`
## Step 3
| 项 | 结论 |
|----|------|
| `target_path_unset` 默认 None | PASSTerminal/Dashboard 零回归) |
| 未设路径判定单一真相 | PASSPython + TS 镜像,`/www/wwwroot/` 不算未设) |
| 双表 refresh / 展开态 reset | PASS |
| 行内 logs 防竞态 + formatApiError | PASS(禁止静默空列表) |
| 未设路径表不纳入主表批量勾选 | PASS |
## Closure
Gate 7/7 PASS · 本地 build + pytest 12/12 · 待用户批准部署
## DoD
- [x] 主表 `target_path_unset=false` 排除未设路径
- [x] 未设路径独立卡片(失败列表上方)
- [x] 名称点击行内展开紧凑详情
- [x] 移除底部 `detailServer` 大块详情卡
- [x] 保存路径后双表迁移 + 展开态清理
- [x] 单测 util / repo / API 三态
@@ -0,0 +1,38 @@
# 2026-06-08 — 服务器未设路径区块 + 行内详情
## 摘要
服务器页主列表排除未设路径机器;新增「未设置路径服务器」独立卡片(失败列表上方);点击名称行内展开紧凑详情,移除底部大块详情卡。
## 动机
未配置真实推送路径的机器与已配置机器混排不便运维;底部详情卡占用空间大,需行内紧凑展示。
## 涉及文件
- `server/utils/posix_paths.py``is_unset_target_path`
- `server/infrastructure/database/server_repo.py`
- `server/api/servers.py`
- `frontend/src/utils/serverTargetPath.ts`
- `frontend/src/composables/useServerPagination.ts`
- `frontend/src/components/servers/ServerInlineDetail.vue`
- `frontend/src/components/servers/ServerUnsetPathPanel.vue`
- `frontend/src/pages/ServersPage.vue`
- `tests/test_server_target_path_filter.py`
## 迁移 / 重启
- 无 DB 迁移;后端 API 新增可选 Query;需重启 API + 前端 build
## 验证
```bash
.venv/bin/python -m pytest tests/test_server_target_path_filter.py -q # 12 passed
bash scripts/local_verify.sh # 26/26
cd frontend && npm run build # PASS
bash deploy/pre_deploy_check.sh # 7/7
```
详细报告:`docs/reports/2026-06-08-servers-unset-path-verification.md`
浏览器终验:主表 / 未设路径 / 失败列表三区 + 名称展开 + 改路径迁移 + Terminal 仍可连未设路径机器。
@@ -0,0 +1,25 @@
# 2026-06-08 — 命令栏取消 Shell 语法彩色
## 摘要
底部命令输入栏恢复统一单色文字;ANSI 彩色仅保留在上方 xterm WebSSH 交互输出区。
## 动机
用户要求:命令栏不要彩色,只要 WebSSH 交互显示有颜色。
## 涉及文件
- `frontend/src/components/terminal/TerminalCmdBar.vue` — 移除 `.sh-*` 分色,统一 `on-surface`
## 迁移 / 重启
- 仅前端 build + 部署;无需重启 API
## 验证
```bash
cd frontend && npm run build
```
浏览器:命令栏输入 `ls -la | grep foo` 全为单色;xterm 区 `ls --color` / `printf '\033[31mred\033[0m'` 仍有彩色。
@@ -0,0 +1,16 @@
# 实施计划 — 服务器未设路径 + 行内详情
**日期**: 2026-06-08
## 步骤
1. `posix_paths.is_unset_target_path` + `server_repo` 过滤 + `servers.py` Query
2. `tests/test_server_target_path_filter.py`
3. `serverTargetPath.ts` + `useServerPagination({ targetPathUnset: false })`
4. `ServerInlineDetail.vue` + `ServerUnsetPathPanel.vue`
5. `ServersPage.vue` 整合,删底部详情卡
6. local_verify + build + 门控 + 验证报告
## 回滚
移除 Query 参数与前端卡片;恢复底部 `detailServer` 面板。
@@ -0,0 +1,20 @@
# 设计 — 服务器未设路径区块 + 行内详情
**日期**: 2026-06-08
**状态**: 已实施
## 背景与目标
主列表排除 `target_path` 为空或 `/www/wwwroot` 的机器,独立展示「未设置路径服务器」卡片(位于连接失败列表上方);主/副表点击名称行内展开紧凑详情,移除底部大块详情卡。
## API
`GET /api/servers/?target_path_unset=true|false`**默认不传(不过滤)**Terminal/Dashboard 零回归。
## 判定
`is_unset_target_path`: trim 后 `''``'/www/wwwroot'``'/www/wwwroot/'` 不算未设置。
## 验收
主表无未设路径机器;未设路径卡片在失败列表上方;名称行内详情;改路径后双表迁移。
@@ -0,0 +1,39 @@
# 验证 — 服务器未设路径区块 + 行内详情(2026-06-08
## 自动化
| 检查 | 结果 |
|------|------|
| `pytest tests/test_server_target_path_filter.py -q` | 12 passed |
| `bash scripts/local_verify.sh` | 26/26 |
| `cd frontend && npm run build` | PASSvue-tsc + vite |
| `bash deploy/pre_deploy_check.sh` | 7/7 |
## 单测覆盖
- `is_unset_target_path` 真值表(空、`/www/wwwroot`、尾斜杠、子路径)
- `ServerRepositoryImpl.get_paginated` unset true/false + search 组合
- `GET /api/servers/?target_path_unset=` true / false / 默认三态
## 布局与交互(本地 build 代码审查)
| 场景 | 预期 | 结论 |
|------|------|------|
| 主表列表 | 不含 target_path 为空或 `/www/wwwroot` 的机器 | PASS(显式 `target_path_unset=false` |
| 未设路径卡片 | 位于连接失败列表上方,独立分页 | PASS |
| 名称点击 | 主表 / 未设路径表各展开一行紧凑详情 | PASS |
| 底部详情卡 | 已删除 `detailServer` 大块 UI | PASS |
| 保存真实路径 | 从未设路径表消失 → 主表出现 | PASS(双表 refresh + `clearExpandedForPathMigration` |
| 保存 `/www/wwwroot` | 从主表 → 未设路径表 | PASS |
| 分页/搜索/分类/排序 | 双表 reload + 展开态 reset | PASS |
| 30s 静默刷新 | `refreshServersSilent``loadUnsetPathServers` | PASS |
| API 未传参 | Dashboard / Terminal 仍返回全部 | PASS(默认 None 不过滤) |
## 手动终验(用户)
1. `#/servers` · 确认三区:主列表 → 未设置路径服务器 → 连接失败列表
2. 主表点击服务器名称 · 行内展开 CPU/内存/磁盘/Agent/路径/同步日志
3. 未设路径表点击名称 · 同样行内展开
4. 编辑目标路径为真实目录 · 机器从未设路径表移至主表
5. 编辑目标路径为 `/www/wwwroot` · 机器从主表移至未设路径表
6. `#/terminal` · 仍可连接未设路径机器(列表未过滤)
@@ -34,9 +34,10 @@
## 部署
- 后端 WebSocket relay 变更 → **需重启 API**
- 前端 → `vite build` 已产出 `web/app/`
- 待用户批准后执行 `bash deploy/deploy-production.sh`
- Commit: `8312a6c` — fix(terminal): WebSSH xterm SSH 交互区 ANSI 彩色输出
- 生产 `/health` → ok`/app/` → 200
- 后端 WebSocket relay 已随 Docker 重建生效
- **请 Ctrl+Shift+R 强刷并重连 SSH 会话**后再做浏览器终验
## 回滚
@@ -0,0 +1,142 @@
<template>
<div class="server-inline-detail bg-surface-variant pa-3 rounded-b-lg">
<div class="d-flex flex-wrap ga-4 mb-2 text-body-2">
<div>
<span class="text-caption text-medium-emphasis">CPU</span>
{{ server.system_info?.cpu_usage ?? '—' }}%
</div>
<div>
<span class="text-caption text-medium-emphasis">内存</span>
{{ server.system_info?.mem_usage ?? '—' }}%
</div>
<div>
<span class="text-caption text-medium-emphasis">磁盘</span>
{{ server.system_info?.disk_usage ?? '—' }}%
</div>
<div>
<span class="text-caption text-medium-emphasis">Agent</span>
{{ server.agent_version || '未安装' }}
</div>
</div>
<div class="d-flex align-center ga-2 mb-2">
<span class="text-caption text-medium-emphasis shrink-0">目标路径</span>
<span class="text-body-2 text-truncate">
{{ server.target_path?.trim() || '未配置(推送页留空时无法推送到此机)' }}
</span>
<v-btn
icon="mdi-pencil"
size="x-small"
variant="text"
density="compact"
title="编辑目标路径"
@click.stop="$emit('edit-path')"
/>
</div>
<div class="text-caption text-medium-emphasis mb-1">同步日志最近 5 </div>
<v-skeleton-loader v-if="loading" type="list-item-two-line@2" />
<div v-else-if="error" class="text-caption text-error py-1">{{ error }}</div>
<div v-else-if="logs.length === 0" class="text-caption text-medium-emphasis py-1">暂无同步日志</div>
<v-list v-else density="compact" class="bg-transparent pa-0">
<v-list-item
v-for="log in logs"
:key="log.id"
:subtitle="formatSyncLogTime(log)"
:title="`${log.source_path} → ${log.target_path}`"
class="px-0"
>
<template #append>
<v-chip size="x-small" :color="syncLogStatusColor(log.status)" variant="tonal" label>
{{ syncLogStatusLabel(log.status) }}
</v-chip>
</template>
</v-list-item>
</v-list>
</div>
</template>
<script setup lang="ts">
import { ref, watch, onBeforeUnmount } from 'vue'
import { http } from '@/api'
import { formatPushPermission } from '@/composables/push/labels'
import { formatApiError } from '@/utils/apiError'
import type { PushItem, ServerApiItem } from '@/types/api'
const props = defineProps<{
server: ServerApiItem
}>()
defineEmits<{
'edit-path': []
}>()
const loading = ref(false)
const error = ref('')
const logs = ref<PushItem[]>([])
let requestId = 0
function syncLogStatusColor(status: string): string {
switch (status) {
case 'success': return 'success'
case 'failed': return 'error'
case 'running': return 'warning'
case 'cancelled': return 'grey'
default: return 'default'
}
}
function syncLogStatusLabel(status: string): string {
switch (status) {
case 'success': return '成功'
case 'failed': return '失败'
case 'running': return '进行中'
case 'cancelled': return '已取消'
default: return status
}
}
function formatSyncLogTime(log: PushItem): string {
const parts: string[] = []
if (log.started_at) parts.push(log.started_at)
if (log.sync_mode) parts.push(log.sync_mode)
if (log.trigger_type) parts.push(log.trigger_type)
if (log.push_permission) parts.push(`权限 ${formatPushPermission(log.push_permission)}`)
return parts.join(' · ') || '—'
}
function parseServerSyncLogs(res: unknown): PushItem[] {
if (Array.isArray(res)) return res as PushItem[]
if (res && typeof res === 'object' && Array.isArray((res as { items?: unknown }).items)) {
return (res as { items: PushItem[] }).items
}
return []
}
async function loadLogs() {
const myId = ++requestId
loading.value = true
error.value = ''
logs.value = []
try {
const res = await http.get<PushItem[] | { items: PushItem[] }>(
`/servers/${props.server.id}/logs`,
{ limit: 5 },
)
if (myId !== requestId) return
logs.value = parseServerSyncLogs(res)
} catch (e: unknown) {
if (myId !== requestId) return
error.value = formatApiError(e, '加载同步日志失败')
logs.value = []
} finally {
if (myId === requestId) loading.value = false
}
}
watch(() => props.server.id, () => { void loadLogs() }, { immediate: true })
onBeforeUnmount(() => {
requestId += 1
})
</script>
@@ -0,0 +1,145 @@
<template>
<v-card elevation="0" rounded="lg" class="my-5" border>
<v-card-title class="d-flex align-center">
未设置路径服务器
<v-chip v-if="total > 0" size="small" class="ml-2" color="warning" variant="tonal" label>
{{ total }}
</v-chip>
<v-spacer />
<v-btn
variant="text"
size="small"
prepend-icon="mdi-refresh"
:loading="loading"
@click="$emit('refresh')"
>
刷新
</v-btn>
</v-card-title>
<v-data-table-server
class="server-unset-path-table"
:items="servers"
:headers="headers"
:items-length="total"
:loading="loading"
:page="page"
:items-per-page="itemsPerPage"
:items-per-page-options="itemsPerPageOptions"
hover
density="compact"
item-value="id"
show-expand
v-model:expanded="expandedModel"
@update:page="$emit('update:page', $event)"
@update:items-per-page="$emit('update:items-per-page', $event)"
>
<template #item.data-table-expand="{ item, toggleExpand, isExpanded }">
<span class="d-none">{{ item.id }}{{ toggleExpand }}{{ isExpanded }}</span>
</template>
<template #item.status="{ item }">
<v-chip :color="statusChipColor(item.status)" size="x-small" variant="tonal" label border="sm">
{{ statusLabel(item.status) }}
</v-chip>
</template>
<template #item.name="{ item }">
<div
class="d-flex align-center cursor-pointer text-primary"
@click.stop="$emit('toggle-expand', item)"
>
<v-icon size="small" class="mr-1">
{{ isExpandedId(item.id) ? 'mdi-chevron-down' : 'mdi-chevron-right' }}
</v-icon>
<span class="font-weight-medium">{{ item.name }}</span>
</div>
</template>
<template #item.domain="{ item }">
<span class="text-medium-emphasis">{{ item.domain }}:{{ item.port }}</span>
</template>
<template #item.actions="{ item }">
<div class="d-flex ga-1">
<v-btn variant="text" size="x-small" color="primary" density="compact" @click.stop="$emit('terminal', item)">
终端
</v-btn>
<v-btn variant="text" size="x-small" density="compact" @click.stop="$emit('detect-path', item)">
检测路径
</v-btn>
<v-btn variant="text" size="x-small" density="compact" @click.stop="$emit('edit', item)">
编辑
</v-btn>
</div>
</template>
<template #expanded-row="{ columns, item }">
<tr>
<td :colspan="columns.length" class="pa-0">
<ServerInlineDetail :server="item" @edit-path="$emit('edit-path', item)" />
</td>
</tr>
</template>
<template #no-data>
<div class="text-center text-medium-emphasis py-6">暂无未设置路径的服务器</div>
</template>
</v-data-table-server>
</v-card>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { ServerApiItem } from '@/types/api'
import { statusChipColor, statusLabel } from '@/utils/status'
import ServerInlineDetail from '@/components/servers/ServerInlineDetail.vue'
const props = defineProps<{
servers: ServerApiItem[]
loading: boolean
total: number
page: number
itemsPerPage: number
itemsPerPageOptions: ReadonlyArray<{ readonly value: number; readonly title: string }>
expandedIds: string[]
}>()
const emit = defineEmits<{
refresh: []
'update:page': [page: number]
'update:items-per-page': [n: number]
'toggle-expand': [item: ServerApiItem]
terminal: [item: ServerApiItem]
'detect-path': [item: ServerApiItem]
edit: [item: ServerApiItem]
'edit-path': [item: ServerApiItem]
'update:expanded-ids': [ids: string[]]
}>()
const headers = [
{ title: '状态', key: 'status', width: 100 },
{ title: '名称', key: 'name' },
{ title: '地址', key: 'domain' },
{ title: '操作', key: 'actions', width: 220, align: 'end' as const, sortable: false },
]
const expandedModel = computed({
get: () => props.expandedIds,
set: (ids: string[]) => emit('update:expanded-ids', ids),
})
function isExpandedId(id: number): boolean {
return props.expandedIds.includes(String(id))
}
</script>
<style scoped>
.server-unset-path-table :deep(.v-data-table__td--expand-column),
.server-unset-path-table :deep(.v-data-table-column--expand),
.server-unset-path-table :deep(th.v-data-table__th--expand) {
display: none !important;
width: 0 !important;
padding: 0 !important;
}
</style>
@@ -86,49 +86,23 @@ defineExpose({
font-family: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', Menlo, monospace;
}
/* Shell 语法高亮(仅命令栏,与 xterm SSH 输出 ANSI 无关) */
:deep(.sh-keyword) {
color: #2563eb;
font-weight: 500;
}
:deep(.sh-builtin) {
color: #0284c7;
}
:deep(.sh-sudo) {
color: #dc2626;
font-weight: 600;
}
/* 命令栏统一单色;ANSI 彩色仅由上方 xterm SSH 输出区呈现 */
:deep(.sh-keyword),
:deep(.sh-builtin),
:deep(.sh-sudo),
:deep(.sh-pipe),
:deep(.sh-operator) {
color: #ca8a04;
font-weight: 600;
}
:deep(.sh-redirect) {
color: #ea580c;
}
:deep(.sh-string) {
color: #16a34a;
}
:deep(.sh-flag) {
color: #9333ea;
}
:deep(.sh-variable) {
color: #db2777;
}
:deep(.sh-backtick) {
color: #7c3aed;
}
:deep(.sh-comment) {
color: #94a3b8;
font-style: italic;
}
:deep(.sh-number) {
color: #d97706;
}
:deep(.sh-path) {
color: #0d9488;
}
:deep(.sh-operator),
:deep(.sh-redirect),
:deep(.sh-string),
:deep(.sh-flag),
:deep(.sh-variable),
:deep(.sh-backtick),
:deep(.sh-comment),
:deep(.sh-number),
:deep(.sh-path),
:deep(.sh-text) {
color: rgb(var(--v-theme-on-surface));
font-weight: inherit;
font-style: inherit;
}
</style>
+20 -12
View File
@@ -9,7 +9,14 @@ import type { ServerApiItem } from '@/types/api'
import { fetchPagePerPage } from '@/utils/paginatedFetch'
import { toServerApiSort, type TableSortItem } from '@/utils/serverTableSort'
export function useServerPagination() {
export interface UseServerPaginationOptions {
/** When set, passed as target_path_unset query param (true/false). Omit for no filter. */
targetPathUnset?: boolean
}
export function useServerPagination(options?: UseServerPaginationOptions) {
const targetPathUnset = options?.targetPathUnset
const servers = ref<ServerApiItem[]>([])
const loading = ref(false)
const page = ref(1)
@@ -20,16 +27,21 @@ export function useServerPagination() {
const categoryFilter = ref('')
const sortBy = ref<TableSortItem[]>([])
function listQueryParams(): Record<string, unknown> {
return {
search: search.value || undefined,
category: categoryFilter.value || undefined,
...toServerApiSort(sortBy.value),
...(targetPathUnset !== undefined ? { target_path_unset: targetPathUnset } : {}),
}
}
async function loadServers(opts?: { silent?: boolean }) {
if (!opts?.silent) loading.value = true
try {
const res = await fetchPagePerPage<ServerApiItem>(
'/servers/',
{
search: search.value || undefined,
category: categoryFilter.value || undefined,
...toServerApiSort(sortBy.value),
},
listQueryParams(),
page.value,
itemsPerPage.value,
)
@@ -83,11 +95,7 @@ export function useServerPagination() {
async function loadAllServers(): Promise<ServerApiItem[]> {
const res = await fetchPagePerPage<ServerApiItem>(
'/servers/',
{
search: search.value || undefined,
category: categoryFilter.value || undefined,
...toServerApiSort(sortBy.value),
},
listQueryParams(),
1,
-1,
)
@@ -97,6 +105,6 @@ export function useServerPagination() {
return {
servers, loading, page, itemsPerPage, total, search, categoryFilter, sortBy,
loadServers, onSearch, onPageChange, onItemsPerPageChange, onCategoryChange,
loadAllServers,
loadAllServers, listQueryParams,
}
}
+173 -161
View File
@@ -125,10 +125,13 @@
show-select
v-model="selectedItems"
v-model:sort-by="sortBy"
@update:page="onPageChange"
@update:items-per-page="onItemsPerPageChange"
@click:row="(_e: Event, { item }: { item: ServerApiItem }) => showDetail(item)"
v-model:expanded="expandedMainIds"
show-expand
class="server-main-table"
@update:page="onMainPageChange"
@update:items-per-page="onMainItemsPerPageChange"
>
<template #item.data-table-expand />
<template #item.status="{ item }">
<v-chip :color="statusChipColor(item.status)" size="x-small" variant="tonal" label border="sm">
{{ statusLabel(item.status) }}
@@ -136,7 +139,15 @@
</template>
<template #item.name="{ item }">
<span class="font-weight-medium">{{ item.name }}</span>
<div
class="d-flex align-center cursor-pointer text-primary"
@click.stop="toggleMainExpand(item)"
>
<v-icon size="small" class="mr-1">
{{ expandedMainIds.includes(String(item.id)) ? 'mdi-chevron-down' : 'mdi-chevron-right' }}
</v-icon>
<span class="font-weight-medium">{{ item.name }}</span>
</div>
</template>
<template #item.domain="{ item }">
@@ -201,6 +212,14 @@
</div>
</template>
<template #expanded-row="{ columns, item }">
<tr>
<td :colspan="columns.length" class="pa-0">
<ServerInlineDetail :server="item" @edit-path="startEditPath(item)" />
</td>
</tr>
</template>
<template #no-data>
<div class="text-center text-medium-emphasis py-6">暂无服务器数据</div>
</template>
@@ -246,8 +265,6 @@
<tr
v-for="item in group.servers"
:key="item.id"
class="cursor-pointer"
@click="showDetail(item)"
>
<td @click.stop>
<v-checkbox-btn
@@ -279,6 +296,25 @@
</div>
</v-card>
<ServerUnsetPathPanel
:servers="unsetPathServers"
:loading="unsetPathLoading"
:total="unsetPathTotal"
:page="unsetPathPage"
:items-per-page="unsetPathItemsPerPage"
:items-per-page-options="dataTablePageOptions"
:expanded-ids="expandedUnsetIds"
@refresh="loadUnsetPathServers()"
@update:page="onUnsetPageChange"
@update:items-per-page="onUnsetItemsPerPageChange"
@update:expanded-ids="expandedUnsetIds = $event"
@toggle-expand="toggleUnsetExpand"
@terminal="openTerminal"
@detect-path="detectPathSingle"
@edit="editServer"
@edit-path="startEditPath"
/>
<!-- Pending / failed SSH connections -->
<v-card elevation="0" rounded="lg" class="my-5" border>
<v-card-title class="d-flex align-center">
@@ -322,78 +358,6 @@
</v-data-table>
</v-card>
<!-- Server Detail Panel -->
<v-expand-transition>
<v-card v-if="detailServer" class="mt-4" elevation="0" border rounded="lg">
<v-card-title class="d-flex align-center">
<v-icon class="mr-2">mdi-information-outline</v-icon>
{{ detailServer.name }}
<v-chip :color="statusChipColor(detailServer.status)" size="small" variant="tonal" label class="ml-2">
{{ statusLabel(detailServer.status) }}
</v-chip>
<v-spacer />
<v-btn icon="mdi-close" size="small" variant="text" @click="detailServer = null" />
</v-card-title>
<v-divider />
<v-tabs v-model="detailTab" density="compact">
<v-tab value="info">系统信息</v-tab>
<v-tab value="logs">同步日志</v-tab>
</v-tabs>
<v-tabs-window v-model="detailTab">
<v-tabs-window-item value="info">
<v-card-text>
<v-row dense>
<v-col cols="6" md="3">
<div class="text-caption text-medium-emphasis">CPU</div>
<div class="text-h6">{{ detailServer.system_info?.cpu_usage ?? '—' }}%</div>
</v-col>
<v-col cols="6" md="3">
<div class="text-caption text-medium-emphasis">内存</div>
<div class="text-h6">{{ detailServer.system_info?.mem_usage ?? '—' }}%</div>
</v-col>
<v-col cols="6" md="3">
<div class="text-caption text-medium-emphasis">磁盘</div>
<div class="text-h6">{{ detailServer.system_info?.disk_usage ?? '—' }}%</div>
</v-col>
<v-col cols="6" md="3">
<div class="text-caption text-medium-emphasis">Agent</div>
<div class="text-h6">{{ detailServer.agent_version || '未安装' }}</div>
</v-col>
<v-col cols="12" md="6">
<div class="text-caption text-medium-emphasis">目标路径</div>
<div class="text-body-1 font-weight-medium text-truncate">
{{ detailServer.target_path?.trim() || '未配置(推送页留空时无法推送到此机)' }}
</div>
</v-col>
</v-row>
</v-card-text>
</v-tabs-window-item>
<v-tabs-window-item value="logs">
<v-card-text>
<div v-if="syncLogsLoading" class="text-center py-4">
<v-progress-circular indeterminate size="24" />
</div>
<div v-else-if="syncLogs.length === 0" class="text-medium-emphasis text-center py-4">暂无同步日志</div>
<v-list v-else density="compact">
<v-list-item
v-for="log in syncLogs"
:key="log.id"
:subtitle="formatSyncLogTime(log)"
:title="`${log.source_path} → ${log.target_path}`"
>
<template #append>
<v-chip size="x-small" :color="syncLogStatusColor(log.status)" variant="tonal" label>
{{ syncLogStatusLabel(log.status) }}
</v-chip>
</template>
</v-list-item>
</v-list>
</v-card-text>
</v-tabs-window-item>
</v-tabs-window>
</v-card>
</v-expand-transition>
<ServerFormDialog
v-model="serverFormVisible"
:form="serverForm"
@@ -617,15 +581,18 @@ import { http } from '@/api'
import { useSnackbar } from '@/composables/useSnackbar'
import { useServerPagination } from '@/composables/useServerPagination'
import { categoryDisplayLabel, useServerCategories } from '@/composables/useServerCategories'
import { formatPushPermission } from '@/composables/push/labels'
import { statusChipColor, statusLabel, formatRelativeTime } from '@/utils/status'
import type { AddByIpResponse, AddByIpsBatchResult, BatchJobStarted, PendingServerItem, PollErrorItem, PushItem, ServerApiItem } from '@/types/api'
import { fetchPagePerPage } from '@/utils/paginatedFetch'
import { isUnsetTargetPath } from '@/utils/serverTargetPath'
import type { AddByIpResponse, AddByIpsBatchResult, BatchJobStarted, PendingServerItem, PollErrorItem, ServerApiItem } from '@/types/api'
import { normalizeServerIds } from '@/utils/serverSelection'
import { formatApiError } from '@/utils/apiError'
import { registerServerBatchJob, onScriptExecutionComplete } from '@/composables/useScriptExecutionQueue'
import { showScriptSubmitToast } from '@/composables/useScriptSubmitToast'
import StatCardsRow from '@/components/StatCardsRow.vue'
import ServerFormDialog from '@/components/servers/ServerFormDialog.vue'
import ServerInlineDetail from '@/components/servers/ServerInlineDetail.vue'
import ServerUnsetPathPanel from '@/components/servers/ServerUnsetPathPanel.vue'
import CredentialsDialog from '@/components/credentials/CredentialsDialog.vue'
import { useServerFormDialog } from '@/composables/servers/useServerFormDialog'
import { DATA_TABLE_ITEMS_PER_PAGE_OPTIONS } from '@/constants/dataTable'
@@ -667,7 +634,7 @@ async function submitServerBatchJob(
onMounted(() => {
offBatchComplete = onScriptExecutionComplete((alert) => {
if (alert.taskKind !== 'server_batch') return
void Promise.all([loadServers(true), loadCategories(), loadStats(true)])
void Promise.all([loadServers(true), loadUnsetPathServers(true), loadCategories(), loadStats(true)])
})
})
@@ -700,8 +667,84 @@ watch(() => route.query.credentials, () => openCredentialsFromQuery(), { immedia
const {
servers, loading, page, itemsPerPage, total, search, categoryFilter, sortBy,
loadServers: _load, onSearch, onPageChange, onItemsPerPageChange, onCategoryChange,
loadAllServers,
} = useServerPagination()
loadAllServers, listQueryParams,
} = useServerPagination({ targetPathUnset: false })
const unsetPathServers = ref<ServerApiItem[]>([])
const unsetPathTotal = ref(0)
const unsetPathLoading = ref(false)
const unsetPathPage = ref(1)
const unsetPathItemsPerPage = ref(10)
const expandedMainIds = ref<string[]>([])
const expandedUnsetIds = ref<string[]>([])
async function loadUnsetPathServers(silent = false) {
if (!silent) unsetPathLoading.value = true
try {
const res = await fetchPagePerPage<ServerApiItem>(
'/servers/',
{ ...listQueryParams(), target_path_unset: true },
unsetPathPage.value,
unsetPathItemsPerPage.value,
)
unsetPathServers.value = res.items
unsetPathTotal.value = res.total
} catch {
unsetPathServers.value = []
unsetPathTotal.value = 0
if (!silent) snackbar('加载未设置路径服务器失败', 'error')
} finally {
if (!silent) unsetPathLoading.value = false
}
}
function toggleMainExpand(item: ServerApiItem) {
const key = String(item.id)
expandedMainIds.value = expandedMainIds.value.includes(key) ? [] : [key]
}
function toggleUnsetExpand(item: ServerApiItem) {
const key = String(item.id)
expandedUnsetIds.value = expandedUnsetIds.value.includes(key) ? [] : [key]
}
function onMainPageChange(p: number) {
expandedMainIds.value = []
onPageChange(p)
}
function onMainItemsPerPageChange(n: number) {
expandedMainIds.value = []
onItemsPerPageChange(n)
}
function onUnsetPageChange(p: number) {
expandedUnsetIds.value = []
unsetPathPage.value = p
void loadUnsetPathServers()
}
function onUnsetItemsPerPageChange(n: number) {
expandedUnsetIds.value = []
unsetPathItemsPerPage.value = n
unsetPathPage.value = 1
void loadUnsetPathServers()
}
async function detectPathSingle(item: ServerApiItem) {
try {
await submitServerBatchJob('detect-path', [item.id])
} catch (e: unknown) {
snackbar(formatApiError(e, '提交检测任务失败'), 'error')
}
}
function clearExpandedForPathMigration(serverId: number, newPath: string) {
const key = String(serverId)
const unset = isUnsetTargetPath(newPath)
if (expandedMainIds.value.includes(key) && unset) expandedMainIds.value = []
if (expandedUnsetIds.value.includes(key) && !unset) expandedUnsetIds.value = []
}
const {
categories: categoryList,
@@ -718,6 +761,7 @@ const expandedCategories = ref<string[]>([])
async function loadServers(silent = false) {
try {
await _load({ silent })
await loadUnsetPathServers(silent)
if (viewMode.value === 'group') {
await loadGroupServers(silent)
}
@@ -744,6 +788,7 @@ async function loadGroupServers(silent = false) {
async function refreshServersSilent() {
try {
await _load({ silent: true })
await loadUnsetPathServers(true)
if (viewMode.value === 'group') await loadGroupServers(true)
} catch {
/* 后台刷新失败不打断用户操作 */
@@ -816,12 +861,27 @@ function toggleGroupAll(groupServers: ServerApiItem[]) {
selectedItems.value = [...next]
}
watch(categoryFilter, () => { selectedItems.value = [] })
watch(categoryFilter, () => {
selectedItems.value = []
expandedMainIds.value = []
expandedUnsetIds.value = []
unsetPathPage.value = 1
void loadUnsetPathServers()
})
watch(sortBy, () => {
selectedItems.value = []
expandedMainIds.value = []
expandedUnsetIds.value = []
unsetPathPage.value = 1
if (viewMode.value === 'group') void loadGroupServers()
void loadUnsetPathServers()
}, { deep: true })
watch(search, () => { selectedItems.value = [] })
watch(search, () => {
selectedItems.value = []
expandedMainIds.value = []
expandedUnsetIds.value = []
unsetPathPage.value = 1
})
watch(viewMode, mode => {
if (mode === 'group') {
@@ -984,49 +1044,6 @@ watch(serverFormVisible, (open, wasOpen) => {
const selectedItems = ref<Array<ServerApiItem | number>>([])
const selectedIds = computed(() => new Set(normalizeServerIds(selectedItems.value)))
// ── Detail panel ──
const detailServer = ref<ServerApiItem | null>(null)
const detailTab = ref('info')
const syncLogs = ref<PushItem[]>([])
const syncLogsLoading = ref(false)
function syncLogStatusColor(status: string): string {
switch (status) {
case 'success': return 'success'
case 'failed': return 'error'
case 'running': return 'warning'
case 'cancelled': return 'grey'
default: return 'default'
}
}
function syncLogStatusLabel(status: string): string {
switch (status) {
case 'success': return '成功'
case 'failed': return '失败'
case 'running': return '进行中'
case 'cancelled': return '已取消'
default: return status
}
}
function formatSyncLogTime(log: PushItem): string {
const parts: string[] = []
if (log.started_at) parts.push(log.started_at)
if (log.sync_mode) parts.push(log.sync_mode)
if (log.trigger_type) parts.push(log.trigger_type)
if (log.push_permission) parts.push(`权限 ${formatPushPermission(log.push_permission)}`)
return parts.join(' · ') || '—'
}
function parseServerSyncLogs(res: unknown): PushItem[] {
if (Array.isArray(res)) return res as PushItem[]
if (res && typeof res === 'object' && Array.isArray((res as { items?: unknown }).items)) {
return (res as { items: PushItem[] }).items
}
return []
}
// ── Table config ──
const headers = [
{ title: '状态', key: 'status', width: 100 },
@@ -1073,6 +1090,15 @@ function openFiles(item: ServerApiItem) {
router.push({ path: '/files', query: { server_id: String(item.id) } })
}
function editServer(item: ServerApiItem) {
void openEditServerDialog(item)
}
function confirmDelete(item: ServerApiItem) {
deletingServer.value = item
showDelete.value = true
}
// ── Batch category ──
const showBatchCategory = ref(false)
const batchCategoryValue = ref('')
@@ -1223,10 +1249,8 @@ async function saveTargetPath(serverId: number) {
await http.put(`/servers/${serverId}`, { target_path: tp })
snackbar('目标路径已更新')
cancelEditPath()
loadServers()
if (detailServer.value?.id === serverId) {
detailServer.value = { ...detailServer.value, target_path: tp }
}
await Promise.all([loadServers(), loadUnsetPathServers()])
clearExpandedForPathMigration(serverId, tp)
} catch (e: unknown) {
snackbar(formatApiError(e, '保存失败'), 'error')
} finally {
@@ -1348,42 +1372,20 @@ async function submitBatchAdd() {
}
}
// ── Server detail panel ──
async function showDetail(item: ServerApiItem) {
detailServer.value = item
detailTab.value = 'info'
syncLogsLoading.value = true
syncLogs.value = []
try {
const res = await http.get<PushItem[] | { items: PushItem[] }>(`/servers/${item.id}/logs`, { limit: 20 })
syncLogs.value = parseServerSyncLogs(res)
} catch {
syncLogs.value = []
} finally {
syncLogsLoading.value = false
}
}
function editServer(item: ServerApiItem) {
void openEditServerDialog(item)
}
function confirmDelete(item: ServerApiItem) {
deletingServer.value = item
showDelete.value = true
}
async function doDelete() {
if (!deletingServer.value) return
const deletedId = deletingServer.value.id
deleting.value = true
try {
await http.delete(`/servers/${deletingServer.value.id}`)
await http.delete(`/servers/${deletedId}`)
showDelete.value = false
loadServers()
expandedMainIds.value = expandedMainIds.value.filter(id => id !== String(deletedId))
expandedUnsetIds.value = expandedUnsetIds.value.filter(id => id !== String(deletedId))
await Promise.all([loadServers(), loadUnsetPathServers()])
loadStats()
snackbar('已删除')
} catch (e: any) {
snackbar(e.message || '删除失败', 'error')
} catch (e: unknown) {
snackbar(formatApiError(e, '删除失败'), 'error')
} finally {
deleting.value = false
}
@@ -1400,3 +1402,13 @@ async function refreshServersPage(silent = false) {
usePageActivateRefresh((silent) => refreshServersPage(silent))
</script>
<style scoped>
.server-main-table :deep(.v-data-table__td--expand-column),
.server-main-table :deep(.v-data-table-column--expand),
.server-main-table :deep(th.v-data-table__th--expand) {
display: none !important;
width: 0 !important;
padding: 0 !important;
}
</style>
+5
View File
@@ -0,0 +1,5 @@
/** True when push target path is empty or BT default placeholder (mirrors backend posix_paths). */
export function isUnsetTargetPath(raw: string | null | undefined): boolean {
const p = (raw ?? '').trim()
return p === '' || p === '/www/wwwroot'
}
+5
View File
@@ -60,6 +60,9 @@ async def list_servers(
sort_by: Optional[str] = Query(None, description="Sort field: name/domain/status/heartbeat/agent_version/category/id"),
sort_order: Optional[str] = Query("asc", description="Sort direction: asc or desc"),
is_online: Optional[bool] = Query(None, description="Filter by online status"),
target_path_unset: Optional[bool] = Query(
None, description="Filter unset target paths: true=only unset, false=exclude unset",
),
page: int = Query(1, ge=1, description="Page number"),
per_page: int = Query(50, ge=1, le=200, description="Items per page"),
admin: Admin = Depends(get_current_admin),
@@ -91,6 +94,7 @@ async def list_servers(
node_id,
search=search,
is_online=db_online_filter,
target_path_unset=target_path_unset,
max_rows=MAX_LIVE_SORT_ROWS,
)
if db_total > MAX_LIVE_SORT_ROWS:
@@ -116,6 +120,7 @@ async def list_servers(
sort_by=sort_by,
sort_order=order,
is_online=is_online,
target_path_unset=target_path_unset,
)
result = await _build_server_list_with_overlay(redis, page_servers)
if is_online is not None:
+21 -1
View File
@@ -4,7 +4,7 @@ Concrete implementation of ServerRepository protocol.
from datetime import datetime, timezone
from typing import Optional, List, Tuple
from sqlalchemy import select, update, func, asc, desc, or_
from sqlalchemy import select, update, func, asc, desc, or_, not_
from sqlalchemy.ext.asyncio import AsyncSession
from server.domain.models import Server
@@ -19,6 +19,20 @@ def _category_filter(category: str):
return Server.category == category
def _target_path_unset_filter(unset: bool):
"""Filter servers by whether target_path is unset (empty or BT default).
Mirrors :func:`server.utils.posix_paths.is_unset_target_path` using SQL TRIM.
"""
tp = func.trim(Server.target_path)
unset_expr = or_(
Server.target_path.is_(None),
tp == "",
tp == "/www/wwwroot",
)
return unset_expr if unset else not_(unset_expr)
# Whitelist of sortable columns (prevents SQL injection via sort_by)
_SORT_COLUMNS = {
"id": Server.id,
@@ -65,6 +79,7 @@ class ServerRepositoryImpl:
sort_by: Optional[str] = None,
sort_order: Optional[str] = "asc",
is_online: Optional[bool] = None,
target_path_unset: Optional[bool] = None,
) -> Tuple[List[Server], int]:
"""Get paginated server list with total count.
@@ -85,6 +100,8 @@ class ServerRepositoryImpl:
filters.append(Server.name.ilike(term) | Server.domain.ilike(term))
if is_online is not None:
filters.append(Server.is_online == is_online)
if target_path_unset is not None:
filters.append(_target_path_unset_filter(target_path_unset))
# Count query
count_query = select(func.count(Server.id))
@@ -118,6 +135,7 @@ class ServerRepositoryImpl:
node_id: Optional[int] = None,
search: Optional[str] = None,
is_online: Optional[bool] = None,
target_path_unset: Optional[bool] = None,
max_rows: int = 5000,
) -> Tuple[List[Server], int]:
"""All servers matching filters (no sort/pagination), capped at *max_rows*."""
@@ -133,6 +151,8 @@ class ServerRepositoryImpl:
filters.append(Server.name.ilike(term) | Server.domain.ilike(term))
if is_online is not None:
filters.append(Server.is_online == is_online)
if target_path_unset is not None:
filters.append(_target_path_unset_filter(target_path_unset))
count_query = select(func.count(Server.id))
for f in filters:
+9
View File
@@ -147,3 +147,12 @@ def normalize_remote_dest(path: str | None, *, default: str = "/tmp/sync") -> st
"""Normalize remote target directory (push/rsync/diagnose); uses *default* when empty."""
raw = (path or "").strip() or default
return normalize_remote_abs_path(raw)
def is_unset_target_path(path: str | None) -> bool:
"""True when push target path is empty or still the BT default placeholder.
``/www/wwwroot/`` (trailing slash) is *not* unset — only exact ``/www/wwwroot`` after trim.
"""
p = (path or "").strip()
return p == "" or p == "/www/wwwroot"
+166
View File
@@ -0,0 +1,166 @@
"""Tests for server list target_path_unset filter."""
from unittest.mock import AsyncMock, MagicMock, patch
import bcrypt
import pytest
import pytest_asyncio
from httpx import ASGITransport, AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from server.application.services.auth_service import AuthService
from server.domain.models import Admin, Base, Server
from server.infrastructure.database.admin_repo import AdminRepositoryImpl
from server.infrastructure.database.audit_log_repo import AuditLogRepositoryImpl
from server.infrastructure.database.server_repo import ServerRepositoryImpl
from server.utils.posix_paths import is_unset_target_path
@pytest_asyncio.fixture
async def db_session():
engine = create_async_engine("sqlite+aiosqlite://", echo=False)
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
session_factory = async_sessionmaker(engine, class_=AsyncSession)
session = session_factory()
try:
yield session
finally:
await session.close()
await engine.dispose()
@pytest_asyncio.fixture
async def api_client(db_session):
from server.api.dependencies import get_db
from server.main import app
async def override_get_session():
yield db_session
app.dependency_overrides[get_db] = override_get_session
transport = ASGITransport(app=app)
client = AsyncClient(transport=transport, base_url="http://test")
try:
yield client
finally:
await client.aclose()
app.dependency_overrides.clear()
@pytest_asyncio.fixture
async def test_admin(db_session):
password_hash = bcrypt.hashpw(b"test123", bcrypt.gensalt()).decode()
admin = Admin(
username="testadmin",
password_hash=password_hash,
is_active=True,
totp_enabled=False,
)
db_session.add(admin)
await db_session.commit()
await db_session.refresh(admin)
auth_service = AuthService(
admin_repo=AdminRepositoryImpl(db_session),
attempt_repo=MagicMock(),
audit_repo=AuditLogRepositoryImpl(db_session),
)
token = auth_service._create_access_token(admin)
return {"admin": admin, "token": token}
@pytest.mark.parametrize(
"raw,expected",
[
(None, True),
("", True),
(" ", True),
("/www/wwwroot", True),
(" /www/wwwroot ", True),
("/www/wwwroot/", False),
("/www/wwwroot/site", False),
("/var/www/html", False),
],
)
def test_is_unset_target_path(raw, expected):
assert is_unset_target_path(raw) is expected
async def _seed_servers(db_session):
rows = [
Server(name="empty-path", domain="1.1.1.1", target_path=None),
Server(name="default-path", domain="2.2.2.2", target_path="/www/wwwroot"),
Server(name="custom-path", domain="3.3.3.3", target_path="/www/wwwroot/site"),
Server(name="trailing-slash", domain="4.4.4.4", target_path="/www/wwwroot/"),
]
for row in rows:
db_session.add(row)
await db_session.commit()
return rows
@pytest.mark.asyncio
async def test_repo_filter_unset_true(db_session):
await _seed_servers(db_session)
repo = ServerRepositoryImpl(db_session)
servers, total = await repo.get_paginated(target_path_unset=True, limit=50)
names = {s.name for s in servers}
assert total == 2
assert names == {"empty-path", "default-path"}
@pytest.mark.asyncio
async def test_repo_filter_unset_false(db_session):
await _seed_servers(db_session)
repo = ServerRepositoryImpl(db_session)
servers, total = await repo.get_paginated(target_path_unset=False, limit=50)
names = {s.name for s in servers}
assert total == 2
assert names == {"custom-path", "trailing-slash"}
@pytest.mark.asyncio
async def test_repo_filter_with_search(db_session):
await _seed_servers(db_session)
repo = ServerRepositoryImpl(db_session)
servers, total = await repo.get_paginated(
search="default", target_path_unset=True, limit=50,
)
assert total == 1
assert servers[0].name == "default-path"
@pytest.mark.asyncio
async def test_api_target_path_unset(api_client, test_admin, db_session):
await _seed_servers(db_session)
headers = {"Authorization": f"Bearer {test_admin['token']}"}
admin = test_admin["admin"]
async def fake_verify(token, request):
return admin if token == test_admin["token"] else None
with patch("server.api.auth_jwt._verify_token", side_effect=fake_verify), patch(
"server.api.servers.get_redis",
) as mock_redis:
pipe = AsyncMock()
pipe.hgetall = MagicMock(return_value=pipe)
pipe.execute = AsyncMock(return_value=[{}] * 4)
mock_redis.return_value.pipeline = MagicMock(return_value=pipe)
unset = await api_client.get(
"/api/servers/?target_path_unset=true&per_page=50",
headers=headers,
)
assert unset.status_code == 200
unset_names = {i["name"] for i in unset.json()["items"]}
assert unset_names == {"empty-path", "default-path"}
configured = await api_client.get(
"/api/servers/?target_path_unset=false&per_page=50",
headers=headers,
)
configured_names = {i["name"] for i in configured.json()["items"]}
assert configured_names == {"custom-path", "trailing-slash"}
all_resp = await api_client.get("/api/servers/?per_page=50", headers=headers)
assert all_resp.json()["total"] == 4
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-CuoDLDz6.js";import{n as r,t as i}from"./VRow-DoFEriUB.js";import{$r as a,Br as o,Jt as s,Nr as c,X as l,_ as u,_r as d,cr as f,fr as p,h as m,hr as h,jr as g,l as _,m as v,pr as y,qr as b,ri as x,vr as S,y as C,yr as w}from"./index-C-0InWiN.js";import{t as T}from"./usePageActivateRefresh-DvwpdC2e.js";import{n as E}from"./dataTable-esDY4cOk.js";import{_ as D,y as O}from"./VTextField-Dh7LxFTC.js";import{t as k}from"./VDataTableServer-NOoqoVGA.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=w({name:`AlertsPage`,__name:`AlertsPage`,setup(w){let N=e(),P=b(!1),F=b([]),I=b(0),L=b(1),R=b(null),z=b(null),B=b([{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=E([{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(e=!1){e||(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{e||(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`}async function J(e=!1){await Promise.all([W(),G(e)])}return T(e=>J(e)),(e,s)=>(g(),y(n,{fluid:``,class:`pa-6`},{default:o(()=>[S(i,{class:`mb-4`},{default:o(()=>[(g(!0),h(f,null,c(B.value,e=>(g(),y(r,{cols:`12`,sm:`6`,lg:`3`,key:e.label},{default:o(()=>[S(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:o(()=>[S(v,null,{append:o(()=>[S(l,{color:e.color,size:`30`},{default:o(()=>[d(x(e.icon),1)]),_:2},1032,[`color`])]),default:o(()=>[S(m,{class:`text-body-small`},{default:o(()=>[d(x(e.label),1)]),_:2},1024),S(m,null,{default:o(()=>[d(x(e.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),S(D,{elevation:`0`,border:``,rounded:`lg`},{default:o(()=>[S(O,{class:`d-flex align-center`},{default:o(()=>[s[5]||=d(` 告警历史 `,-1),S(u),S(t,{modelValue:R.value,"onUpdate:modelValue":[s[0]||=e=>R.value=e,s[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`]),S(t,{modelValue:z.value,"onUpdate:modelValue":[s[2]||=e=>z.value=e,s[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}),S(k,{items:F.value,headers:a(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":s[4]||=e=>{L.value=e,G()}},{"item.alert_type":o(({item:e})=>[S(C,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:o(()=>[S(l,{size:`12`},{default:o(()=>[d(x(q(e.alert_type)),1)]),_:2},1024)]),default:o(()=>[d(` `+x(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":o(({item:e})=>[p(`span`,A,x(e.server_name),1)]),"item.value":o(({item:e})=>[p(`span`,j,x(e.value),1)]),"item.is_recovery":o(({item:e})=>[e.is_recovery?(g(),y(C,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:o(()=>[...s[6]||=[d(`已恢复`,-1)]]),_:1})):(g(),y(C,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:o(()=>[...s[7]||=[d(`告警中`,-1)]]),_:1}))]),"item.created_at":o(({item:e})=>[p(`span`,M,x(e.created_at),1)]),"no-data":o(()=>[...s[8]||=[p(`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-B41HpgCF.js";import{n as r,t as i}from"./VRow-Y_XeN2_E.js";import{$r as a,Br as o,Jt as s,Nr as c,X as l,_ as u,_r as d,cr as f,fr as p,h as m,hr as h,jr as g,l as _,m as v,pr as y,qr as b,ri as x,vr as S,y as C,yr as w}from"./index-DCfqeweT.js";import{t as T}from"./usePageActivateRefresh-C555Oz1J.js";import{n as E}from"./dataTable-esDY4cOk.js";import{_ as D,y as O}from"./VTextField-bhIeNGqx.js";import{t as k}from"./VDataTableServer-DTfPxuos.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=w({name:`AlertsPage`,__name:`AlertsPage`,setup(w){let N=e(),P=b(!1),F=b([]),I=b(0),L=b(1),R=b(null),z=b(null),B=b([{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=E([{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(e=!1){e||(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{e||(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`}async function J(e=!1){await Promise.all([W(),G(e)])}return T(e=>J(e)),(e,s)=>(g(),y(n,{fluid:``,class:`pa-6`},{default:o(()=>[S(i,{class:`mb-4`},{default:o(()=>[(g(!0),h(f,null,c(B.value,e=>(g(),y(r,{cols:`12`,sm:`6`,lg:`3`,key:e.label},{default:o(()=>[S(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:o(()=>[S(v,null,{append:o(()=>[S(l,{color:e.color,size:`30`},{default:o(()=>[d(x(e.icon),1)]),_:2},1032,[`color`])]),default:o(()=>[S(m,{class:`text-body-small`},{default:o(()=>[d(x(e.label),1)]),_:2},1024),S(m,null,{default:o(()=>[d(x(e.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),S(D,{elevation:`0`,border:``,rounded:`lg`},{default:o(()=>[S(O,{class:`d-flex align-center`},{default:o(()=>[s[5]||=d(` 告警历史 `,-1),S(u),S(t,{modelValue:R.value,"onUpdate:modelValue":[s[0]||=e=>R.value=e,s[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`]),S(t,{modelValue:z.value,"onUpdate:modelValue":[s[2]||=e=>z.value=e,s[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}),S(k,{items:F.value,headers:a(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":s[4]||=e=>{L.value=e,G()}},{"item.alert_type":o(({item:e})=>[S(C,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:o(()=>[S(l,{size:`12`},{default:o(()=>[d(x(q(e.alert_type)),1)]),_:2},1024)]),default:o(()=>[d(` `+x(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":o(({item:e})=>[p(`span`,A,x(e.server_name),1)]),"item.value":o(({item:e})=>[p(`span`,j,x(e.value),1)]),"item.is_recovery":o(({item:e})=>[e.is_recovery?(g(),y(C,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:o(()=>[...s[6]||=[d(`已恢复`,-1)]]),_:1})):(g(),y(C,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:o(()=>[...s[7]||=[d(`告警中`,-1)]]),_:1}))]),"item.created_at":o(({item:e})=>[p(`span`,M,x(e.created_at),1)]),"no-data":o(()=>[...s[8]||=[p(`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-rP81fnpc.js";import{n as r,t as i}from"./VRow-DsaAVGoF.js";import{$r as a,Br as o,Jt as s,Nr as c,X as l,_ as u,_r as d,cr as f,fr as p,h as m,hr as h,jr as g,l as _,m as v,pr as y,qr as b,ri as x,vr as S,y as C,yr as w}from"./index-DAQ8Nzd7.js";import{t as T}from"./usePageActivateRefresh-hyRkArJ0.js";import{n as E}from"./dataTable-esDY4cOk.js";import{_ as D,y as O}from"./VTextField-CqnXgqAI.js";import{t as k}from"./VDataTableServer-Cvy_Dzfu.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=w({name:`AlertsPage`,__name:`AlertsPage`,setup(w){let N=e(),P=b(!1),F=b([]),I=b(0),L=b(1),R=b(null),z=b(null),B=b([{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=E([{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(e=!1){e||(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{e||(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`}async function J(e=!1){await Promise.all([W(),G(e)])}return T(e=>J(e)),(e,s)=>(g(),y(n,{fluid:``,class:`pa-6`},{default:o(()=>[S(i,{class:`mb-4`},{default:o(()=>[(g(!0),h(f,null,c(B.value,e=>(g(),y(r,{cols:`12`,sm:`6`,lg:`3`,key:e.label},{default:o(()=>[S(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:o(()=>[S(v,null,{append:o(()=>[S(l,{color:e.color,size:`30`},{default:o(()=>[d(x(e.icon),1)]),_:2},1032,[`color`])]),default:o(()=>[S(m,{class:`text-body-small`},{default:o(()=>[d(x(e.label),1)]),_:2},1024),S(m,null,{default:o(()=>[d(x(e.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),S(D,{elevation:`0`,border:``,rounded:`lg`},{default:o(()=>[S(O,{class:`d-flex align-center`},{default:o(()=>[s[5]||=d(` 告警历史 `,-1),S(u),S(t,{modelValue:R.value,"onUpdate:modelValue":[s[0]||=e=>R.value=e,s[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`]),S(t,{modelValue:z.value,"onUpdate:modelValue":[s[2]||=e=>z.value=e,s[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}),S(k,{items:F.value,headers:a(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":s[4]||=e=>{L.value=e,G()}},{"item.alert_type":o(({item:e})=>[S(C,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:o(()=>[S(l,{size:`12`},{default:o(()=>[d(x(q(e.alert_type)),1)]),_:2},1024)]),default:o(()=>[d(` `+x(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":o(({item:e})=>[p(`span`,A,x(e.server_name),1)]),"item.value":o(({item:e})=>[p(`span`,j,x(e.value),1)]),"item.is_recovery":o(({item:e})=>[e.is_recovery?(g(),y(C,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:o(()=>[...s[6]||=[d(`已恢复`,-1)]]),_:1})):(g(),y(C,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:o(()=>[...s[7]||=[d(`告警中`,-1)]]),_:1}))]),"item.created_at":o(({item:e})=>[p(`span`,M,x(e.created_at),1)]),"no-data":o(()=>[...s[8]||=[p(`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-CxIgrALN.js";import{n as r,t as i}from"./VRow-CB160lPB.js";import{$r as a,Br as o,Jt as s,Nr as c,X as l,_ as u,_r as d,cr as f,fr as p,h as m,hr as h,jr as g,l as _,m as v,pr as y,qr as b,ri as x,vr as S,y as C,yr as w}from"./index-CLYaSJSV.js";import{t as T}from"./usePageActivateRefresh-D1E3V_5C.js";import{n as E}from"./dataTable-esDY4cOk.js";import{_ as D,y as O}from"./VTextField-DL63Pt8A.js";import{t as k}from"./VDataTableServer-9aNMIT8a.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=w({name:`AlertsPage`,__name:`AlertsPage`,setup(w){let N=e(),P=b(!1),F=b([]),I=b(0),L=b(1),R=b(null),z=b(null),B=b([{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=E([{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(e=!1){e||(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{e||(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`}async function J(e=!1){await Promise.all([W(),G(e)])}return T(e=>J(e)),(e,s)=>(g(),y(n,{fluid:``,class:`pa-6`},{default:o(()=>[S(i,{class:`mb-4`},{default:o(()=>[(g(!0),h(f,null,c(B.value,e=>(g(),y(r,{cols:`12`,sm:`6`,lg:`3`,key:e.label},{default:o(()=>[S(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:o(()=>[S(v,null,{append:o(()=>[S(l,{color:e.color,size:`30`},{default:o(()=>[d(x(e.icon),1)]),_:2},1032,[`color`])]),default:o(()=>[S(m,{class:`text-body-small`},{default:o(()=>[d(x(e.label),1)]),_:2},1024),S(m,null,{default:o(()=>[d(x(e.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),S(D,{elevation:`0`,border:``,rounded:`lg`},{default:o(()=>[S(O,{class:`d-flex align-center`},{default:o(()=>[s[5]||=d(` 告警历史 `,-1),S(u),S(t,{modelValue:R.value,"onUpdate:modelValue":[s[0]||=e=>R.value=e,s[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`]),S(t,{modelValue:z.value,"onUpdate:modelValue":[s[2]||=e=>z.value=e,s[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}),S(k,{items:F.value,headers:a(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":s[4]||=e=>{L.value=e,G()}},{"item.alert_type":o(({item:e})=>[S(C,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:o(()=>[S(l,{size:`12`},{default:o(()=>[d(x(q(e.alert_type)),1)]),_:2},1024)]),default:o(()=>[d(` `+x(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":o(({item:e})=>[p(`span`,A,x(e.server_name),1)]),"item.value":o(({item:e})=>[p(`span`,j,x(e.value),1)]),"item.is_recovery":o(({item:e})=>[e.is_recovery?(g(),y(C,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:o(()=>[...s[6]||=[d(`已恢复`,-1)]]),_:1})):(g(),y(C,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:o(()=>[...s[7]||=[d(`告警中`,-1)]]),_:1}))]),"item.created_at":o(({item:e})=>[p(`span`,M,x(e.created_at),1)]),"no-data":o(()=>[...s[8]||=[p(`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-DgmpIJ0-.js";import{n as r,t as i}from"./VRow-Dp-mItU3.js";import{$r as a,Br as o,Jt as s,Nr as c,X as l,_ as u,_r as d,cr as f,fr as p,h as m,hr as h,jr as g,l as _,m as v,pr as y,qr as b,ri as x,vr as S,y as C,yr as w}from"./index-B1boYHjE.js";import{t as T}from"./usePageActivateRefresh-85rCMLDQ.js";import{n as E}from"./dataTable-esDY4cOk.js";import{_ as D,y as O}from"./VTextField-CWk_xMst.js";import{t as k}from"./VDataTableServer-BOzWB3oR.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=w({name:`AlertsPage`,__name:`AlertsPage`,setup(w){let N=e(),P=b(!1),F=b([]),I=b(0),L=b(1),R=b(null),z=b(null),B=b([{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=E([{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(e=!1){e||(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{e||(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`}async function J(e=!1){await Promise.all([W(),G(e)])}return T(e=>J(e)),(e,s)=>(g(),y(n,{fluid:``,class:`pa-6`},{default:o(()=>[S(i,{class:`mb-4`},{default:o(()=>[(g(!0),h(f,null,c(B.value,e=>(g(),y(r,{cols:`12`,sm:`6`,lg:`3`,key:e.label},{default:o(()=>[S(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:o(()=>[S(v,null,{append:o(()=>[S(l,{color:e.color,size:`30`},{default:o(()=>[d(x(e.icon),1)]),_:2},1032,[`color`])]),default:o(()=>[S(m,{class:`text-body-small`},{default:o(()=>[d(x(e.label),1)]),_:2},1024),S(m,null,{default:o(()=>[d(x(e.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),S(D,{elevation:`0`,border:``,rounded:`lg`},{default:o(()=>[S(O,{class:`d-flex align-center`},{default:o(()=>[s[5]||=d(` 告警历史 `,-1),S(u),S(t,{modelValue:R.value,"onUpdate:modelValue":[s[0]||=e=>R.value=e,s[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`]),S(t,{modelValue:z.value,"onUpdate:modelValue":[s[2]||=e=>z.value=e,s[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}),S(k,{items:F.value,headers:a(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":s[4]||=e=>{L.value=e,G()}},{"item.alert_type":o(({item:e})=>[S(C,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:o(()=>[S(l,{size:`12`},{default:o(()=>[d(x(q(e.alert_type)),1)]),_:2},1024)]),default:o(()=>[d(` `+x(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":o(({item:e})=>[p(`span`,A,x(e.server_name),1)]),"item.value":o(({item:e})=>[p(`span`,j,x(e.value),1)]),"item.is_recovery":o(({item:e})=>[e.is_recovery?(g(),y(C,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:o(()=>[...s[6]||=[d(`已恢复`,-1)]]),_:1})):(g(),y(C,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:o(()=>[...s[7]||=[d(`告警中`,-1)]]),_:1}))]),"item.created_at":o(({item:e})=>[p(`span`,M,x(e.created_at),1)]),"no-data":o(()=>[...s[8]||=[p(`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-C9h2QNwU.js";import{n as r,t as i}from"./VRow-CRxvLYTf.js";import{$r as a,Br as o,Jt as s,Nr as c,X as l,_ as u,_r as d,cr as f,fr as p,h as m,hr as h,jr as g,l as _,m as v,pr as y,qr as b,ri as x,vr as S,y as C,yr as w}from"./index-C6-Dyy9B.js";import{t as T}from"./usePageActivateRefresh-BWZBQKtm.js";import{n as E}from"./dataTable-esDY4cOk.js";import{_ as D,y as O}from"./VTextField-B_95spZa.js";import{t as k}from"./VDataTableServer-DDaIMFdh.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=w({name:`AlertsPage`,__name:`AlertsPage`,setup(w){let N=e(),P=b(!1),F=b([]),I=b(0),L=b(1),R=b(null),z=b(null),B=b([{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=E([{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(e=!1){e||(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{e||(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`}async function J(e=!1){await Promise.all([W(),G(e)])}return T(e=>J(e)),(e,s)=>(g(),y(n,{fluid:``,class:`pa-6`},{default:o(()=>[S(i,{class:`mb-4`},{default:o(()=>[(g(!0),h(f,null,c(B.value,e=>(g(),y(r,{cols:`12`,sm:`6`,lg:`3`,key:e.label},{default:o(()=>[S(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:o(()=>[S(v,null,{append:o(()=>[S(l,{color:e.color,size:`30`},{default:o(()=>[d(x(e.icon),1)]),_:2},1032,[`color`])]),default:o(()=>[S(m,{class:`text-body-small`},{default:o(()=>[d(x(e.label),1)]),_:2},1024),S(m,null,{default:o(()=>[d(x(e.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),S(D,{elevation:`0`,border:``,rounded:`lg`},{default:o(()=>[S(O,{class:`d-flex align-center`},{default:o(()=>[s[5]||=d(` 告警历史 `,-1),S(u),S(t,{modelValue:R.value,"onUpdate:modelValue":[s[0]||=e=>R.value=e,s[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`]),S(t,{modelValue:z.value,"onUpdate:modelValue":[s[2]||=e=>z.value=e,s[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}),S(k,{items:F.value,headers:a(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":s[4]||=e=>{L.value=e,G()}},{"item.alert_type":o(({item:e})=>[S(C,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:o(()=>[S(l,{size:`12`},{default:o(()=>[d(x(q(e.alert_type)),1)]),_:2},1024)]),default:o(()=>[d(` `+x(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":o(({item:e})=>[p(`span`,A,x(e.server_name),1)]),"item.value":o(({item:e})=>[p(`span`,j,x(e.value),1)]),"item.is_recovery":o(({item:e})=>[e.is_recovery?(g(),y(C,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:o(()=>[...s[6]||=[d(`已恢复`,-1)]]),_:1})):(g(),y(C,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:o(()=>[...s[7]||=[d(`告警中`,-1)]]),_:1}))]),"item.created_at":o(({item:e})=>[p(`span`,M,x(e.created_at),1)]),"no-data":o(()=>[...s[8]||=[p(`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-i5lN3C8G.js";import{n as r,t as i}from"./VRow-DkZ5JfsP.js";import{$r as a,Br as o,Jt as s,Nr as c,X as l,_ as u,_r as d,cr as f,fr as p,h as m,hr as h,jr as g,l as _,m as v,pr as y,qr as b,ri as x,vr as S,y as C,yr as w}from"./index-CGZBwSYH.js";import{t as T}from"./usePageActivateRefresh-DqGnYiLP.js";import{n as E}from"./dataTable-esDY4cOk.js";import{_ as D,y as O}from"./VTextField-BW0CzHfL.js";import{t as k}from"./VDataTableServer-viCCdEcM.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=w({name:`AlertsPage`,__name:`AlertsPage`,setup(w){let N=e(),P=b(!1),F=b([]),I=b(0),L=b(1),R=b(null),z=b(null),B=b([{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=E([{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(e=!1){e||(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{e||(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`}async function J(e=!1){await Promise.all([W(),G(e)])}return T(e=>J(e)),(e,s)=>(g(),y(n,{fluid:``,class:`pa-6`},{default:o(()=>[S(i,{class:`mb-4`},{default:o(()=>[(g(!0),h(f,null,c(B.value,e=>(g(),y(r,{cols:`12`,sm:`6`,lg:`3`,key:e.label},{default:o(()=>[S(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:o(()=>[S(v,null,{append:o(()=>[S(l,{color:e.color,size:`30`},{default:o(()=>[d(x(e.icon),1)]),_:2},1032,[`color`])]),default:o(()=>[S(m,{class:`text-body-small`},{default:o(()=>[d(x(e.label),1)]),_:2},1024),S(m,null,{default:o(()=>[d(x(e.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),S(D,{elevation:`0`,border:``,rounded:`lg`},{default:o(()=>[S(O,{class:`d-flex align-center`},{default:o(()=>[s[5]||=d(` 告警历史 `,-1),S(u),S(t,{modelValue:R.value,"onUpdate:modelValue":[s[0]||=e=>R.value=e,s[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`]),S(t,{modelValue:z.value,"onUpdate:modelValue":[s[2]||=e=>z.value=e,s[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}),S(k,{items:F.value,headers:a(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":s[4]||=e=>{L.value=e,G()}},{"item.alert_type":o(({item:e})=>[S(C,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:o(()=>[S(l,{size:`12`},{default:o(()=>[d(x(q(e.alert_type)),1)]),_:2},1024)]),default:o(()=>[d(` `+x(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":o(({item:e})=>[p(`span`,A,x(e.server_name),1)]),"item.value":o(({item:e})=>[p(`span`,j,x(e.value),1)]),"item.is_recovery":o(({item:e})=>[e.is_recovery?(g(),y(C,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:o(()=>[...s[6]||=[d(`已恢复`,-1)]]),_:1})):(g(),y(C,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:o(()=>[...s[7]||=[d(`告警中`,-1)]]),_:1}))]),"item.created_at":o(({item:e})=>[p(`span`,M,x(e.created_at),1)]),"no-data":o(()=>[...s[8]||=[p(`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-B_6Vp6qA.js";import{n as r,t as i}from"./VRow-q7h3kXM6.js";import{Jr as a,Jt as o,Mr as s,Pr as c,Vr as l,X as u,_ as d,br as f,ei as p,gr as m,h,ii as g,l as _,lr as v,m as y,mr as b,pr as x,vr as S,y as C,yr as w}from"./index-CLdQHC4h.js";import{t as T}from"./usePageActivateRefresh-BpIWjk_F.js";import{n as E}from"./dataTable-esDY4cOk.js";import{_ as D,y as O}from"./VTextField-BGLB-ir3.js";import{t as k}from"./VDataTableServer-CE7yQuNc.js";var A={class:`font-weight-medium`},j={class:`text-body-2`},M={class:`text-caption text-medium-emphasis`},N=f({name:`AlertsPage`,__name:`AlertsPage`,setup(f){let N=e(),P=a(!1),F=a([]),I=a(0),L=a(1),R=a(null),z=a(null),B=a([{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=E([{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 o.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(e=!1){e||(P.value=!0);try{let e=await o.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{e||(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`}async function J(e=!1){await Promise.all([W(),G(e)])}return T(e=>J(e)),(e,a)=>(s(),b(n,{fluid:``,class:`pa-6`},{default:l(()=>[w(i,{class:`mb-4`},{default:l(()=>[(s(!0),m(v,null,c(B.value,e=>(s(),b(r,{cols:`12`,sm:`6`,lg:`3`,key:e.label},{default:l(()=>[w(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:l(()=>[w(y,null,{append:l(()=>[w(u,{color:e.color,size:`30`},{default:l(()=>[S(g(e.icon),1)]),_:2},1032,[`color`])]),default:l(()=>[w(h,{class:`text-body-small`},{default:l(()=>[S(g(e.label),1)]),_:2},1024),w(h,null,{default:l(()=>[S(g(e.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),w(D,{elevation:`0`,border:``,rounded:`lg`},{default:l(()=>[w(O,{class:`d-flex align-center`},{default:l(()=>[a[5]||=S(` 告警历史 `,-1),w(d),w(t,{modelValue:R.value,"onUpdate:modelValue":[a[0]||=e=>R.value=e,a[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`]),w(t,{modelValue:z.value,"onUpdate:modelValue":[a[2]||=e=>z.value=e,a[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}),w(k,{items:F.value,headers:p(U),"items-length":I.value,loading:P.value,page:L.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":a[4]||=e=>{L.value=e,G()}},{"item.alert_type":l(({item:e})=>[w(C,{color:K(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:l(()=>[w(u,{size:`12`},{default:l(()=>[S(g(q(e.alert_type)),1)]),_:2},1024)]),default:l(()=>[S(` `+g(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":l(({item:e})=>[x(`span`,A,g(e.server_name),1)]),"item.value":l(({item:e})=>[x(`span`,j,g(e.value),1)]),"item.is_recovery":l(({item:e})=>[e.is_recovery?(s(),b(C,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:l(()=>[...a[6]||=[S(`已恢复`,-1)]]),_:1})):(s(),b(C,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:l(()=>[...a[7]||=[S(`告警中`,-1)]]),_:1}))]),"item.created_at":l(({item:e})=>[x(`span`,M,g(e.created_at),1)]),"no-data":l(()=>[...a[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{_ as e,t,v as n}from"./VSelect-B_6Vp6qA.js";import{Jr as r,Jt as i,Mr as a,P as o,Tt as s,Vr as c,_ as l,br as u,cr as d,ei as f,hr as p,ii as m,mr as h,pr as g,vr as _,y as v,yr as y}from"./index-CLdQHC4h.js";import{t as b}from"./usePageActivateRefresh-BpIWjk_F.js";import{n as x}from"./dataTable-esDY4cOk.js";import{_ as S,t as C,y as w}from"./VTextField-BGLB-ir3.js";import{t as T}from"./VDataTableServer-CE7yQuNc.js";import{a as E,n as D,r as O,t as k}from"./auditNormalize-DWYIxo0q.js";var A=new Set([`batch_install_agent`,`batch_upgrade_agent`,`batch_uninstall_agent`,`batch_detect_path`,`batch_health_check`,`batch_update_category`,`batch_server_op`]);function j(e){return A.has(e)}function M(e){let t=(e||``).trim();if(!t.startsWith(`{`))return null;try{let e=JSON.parse(t);return typeof e.job_id!=`number`||!e.summary?null:e}catch{return null}}function N(e){let t=[e.summary],n=e.failures||[];if(n.length){let e=n.slice(0,3).map(e=>e.server_name).join(``);t.push(`失败: ${e}${n.length>3?``:``}`)}return t.join(` · `)}var P={class:`font-weight-medium`},F={class:`text-body-2`},I={class:`d-flex align-center ga-2 flex-wrap`},L={class:`text-body-2 text-medium-emphasis`,style:{"max-width":`360px`}},R={class:`text-caption text-medium-emphasis`},z={class:`text-caption text-medium-emphasis`},B=u({name:`AuditPage`,__name:`AuditPage`,setup(u){let A=e(),B=r(!1),V=r([]),H=r(0),U=r(1),W=r(null),G=r(``),K=r(``),q=D,J=x([{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 Y(e=!1){e||(B.value=!0);try{let e=(U.value-1)*50,t=await i.get(`/audit/`,{limit:50,offset:e,action:W.value||void 0,admin_username:G.value||void 0,date_from:K.value||void 0});V.value=k(t.items||[]),H.value=t.total||0}catch{V.value=[],e||A(`加载审计日志失败`,`error`)}finally{e||(B.value=!1)}}function X(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`}function Z(e){return j(e.action)?M(e.detail):null}function Q(e){let t=Z(e);return t?N(t):(e.detail||``).trim()||``}function $(e){s(e.job_id,e.summary)}return b(e=>Y(e)),(e,r)=>(a(),h(n,{fluid:``,class:`pa-6`},{default:c(()=>[y(S,{elevation:`0`,border:``,rounded:`lg`},{default:c(()=>[y(w,{class:`d-flex align-center`},{default:c(()=>[r[7]||=_(` 审计日志 `,-1),y(l),y(t,{modelValue:W.value,"onUpdate:modelValue":[r[0]||=e=>W.value=e,r[1]||=e=>{U.value=1,Y()}],items:f(q),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),y(C,{modelValue:G.value,"onUpdate:modelValue":[r[2]||=e=>G.value=e,r[3]||=e=>{U.value=1,Y()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),y(C,{modelValue:K.value,"onUpdate:modelValue":[r[4]||=e=>K.value=e,r[5]||=e=>{U.value=1,Y()}],"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}),y(T,{items:V.value,headers:f(J),"items-length":H.value,loading:B.value,page:U.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":r[6]||=e=>{U.value=e,Y()}},{"item.action":c(({item:e})=>[y(v,{color:X(e.action),size:`small`,variant:`tonal`,label:``},{default:c(()=>[_(m(f(O)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":c(({item:e})=>[g(`span`,P,m(e.admin_username),1)]),"item.target":c(({item:e})=>[g(`span`,F,m(f(E)(e.resource_type))+m(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":c(({item:e})=>[g(`div`,I,[g(`span`,L,m(Q(e)),1),Z(e)?(a(),h(o,{key:0,size:`x-small`,variant:`tonal`,color:`primary`,onClick:d(t=>$(Z(e)),[`stop`])},{default:c(()=>[...r[8]||=[_(` 查看结果 `,-1)]]),_:1},8,[`onClick`])):p(``,!0)])]),"item.ip_address":c(({item:e})=>[g(`span`,R,m(e.ip_address||``),1)]),"item.created_at":c(({item:e})=>[g(`span`,z,m(e.created_at),1)]),"no-data":c(()=>[...r[9]||=[g(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{B as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-CuoDLDz6.js";import{$r as r,Br as i,Jt as a,P as o,Tt as s,_ as c,_r as l,fr as u,jr as d,mr as f,pr as p,qr as m,ri as h,sr as g,vr as _,y as v,yr as y}from"./index-C-0InWiN.js";import{t as b}from"./usePageActivateRefresh-DvwpdC2e.js";import{n as x}from"./dataTable-esDY4cOk.js";import{_ as S,t as C,y as w}from"./VTextField-Dh7LxFTC.js";import{t as T}from"./VDataTableServer-NOoqoVGA.js";import{a as E,n as D,r as O,t as k}from"./auditNormalize-DWYIxo0q.js";var A=new Set([`batch_install_agent`,`batch_upgrade_agent`,`batch_uninstall_agent`,`batch_detect_path`,`batch_health_check`,`batch_update_category`,`batch_server_op`]);function j(e){return A.has(e)}function M(e){let t=(e||``).trim();if(!t.startsWith(`{`))return null;try{let e=JSON.parse(t);return typeof e.job_id!=`number`||!e.summary?null:e}catch{return null}}function N(e){let t=[e.summary],n=e.failures||[];if(n.length){let e=n.slice(0,3).map(e=>e.server_name).join(``);t.push(`失败: ${e}${n.length>3?``:``}`)}return t.join(` · `)}var P={class:`font-weight-medium`},F={class:`text-body-2`},I={class:`d-flex align-center ga-2 flex-wrap`},L={class:`text-body-2 text-medium-emphasis`,style:{"max-width":`360px`}},R={class:`text-caption text-medium-emphasis`},z={class:`text-caption text-medium-emphasis`},B=y({name:`AuditPage`,__name:`AuditPage`,setup(y){let A=e(),B=m(!1),V=m([]),H=m(0),U=m(1),W=m(null),G=m(``),K=m(``),q=D,J=x([{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 Y(e=!1){e||(B.value=!0);try{let e=(U.value-1)*50,t=await a.get(`/audit/`,{limit:50,offset:e,action:W.value||void 0,admin_username:G.value||void 0,date_from:K.value||void 0});V.value=k(t.items||[]),H.value=t.total||0}catch{V.value=[],e||A(`加载审计日志失败`,`error`)}finally{e||(B.value=!1)}}function X(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`}function Z(e){return j(e.action)?M(e.detail):null}function Q(e){let t=Z(e);return t?N(t):(e.detail||``).trim()||``}function $(e){s(e.job_id,e.summary)}return b(e=>Y(e)),(e,a)=>(d(),p(n,{fluid:``,class:`pa-6`},{default:i(()=>[_(S,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[_(w,{class:`d-flex align-center`},{default:i(()=>[a[7]||=l(` 审计日志 `,-1),_(c),_(t,{modelValue:W.value,"onUpdate:modelValue":[a[0]||=e=>W.value=e,a[1]||=e=>{U.value=1,Y()}],items:r(q),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),_(C,{modelValue:G.value,"onUpdate:modelValue":[a[2]||=e=>G.value=e,a[3]||=e=>{U.value=1,Y()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),_(C,{modelValue:K.value,"onUpdate:modelValue":[a[4]||=e=>K.value=e,a[5]||=e=>{U.value=1,Y()}],"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}),_(T,{items:V.value,headers:r(J),"items-length":H.value,loading:B.value,page:U.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":a[6]||=e=>{U.value=e,Y()}},{"item.action":i(({item:e})=>[_(v,{color:X(e.action),size:`small`,variant:`tonal`,label:``},{default:i(()=>[l(h(r(O)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":i(({item:e})=>[u(`span`,P,h(e.admin_username),1)]),"item.target":i(({item:e})=>[u(`span`,F,h(r(E)(e.resource_type))+h(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":i(({item:e})=>[u(`div`,I,[u(`span`,L,h(Q(e)),1),Z(e)?(d(),p(o,{key:0,size:`x-small`,variant:`tonal`,color:`primary`,onClick:g(t=>$(Z(e)),[`stop`])},{default:i(()=>[...a[8]||=[l(` 查看结果 `,-1)]]),_:1},8,[`onClick`])):f(``,!0)])]),"item.ip_address":i(({item:e})=>[u(`span`,R,h(e.ip_address||``),1)]),"item.created_at":i(({item:e})=>[u(`span`,z,h(e.created_at),1)]),"no-data":i(()=>[...a[9]||=[u(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{B as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-CxIgrALN.js";import{$r as r,Br as i,Jt as a,P as o,Tt as s,_ as c,_r as l,fr as u,jr as d,mr as f,pr as p,qr as m,ri as h,sr as g,vr as _,y as v,yr as y}from"./index-CLYaSJSV.js";import{t as b}from"./usePageActivateRefresh-D1E3V_5C.js";import{n as x}from"./dataTable-esDY4cOk.js";import{_ as S,t as C,y as w}from"./VTextField-DL63Pt8A.js";import{t as T}from"./VDataTableServer-9aNMIT8a.js";import{a as E,n as D,r as O,t as k}from"./auditNormalize-DWYIxo0q.js";var A=new Set([`batch_install_agent`,`batch_upgrade_agent`,`batch_uninstall_agent`,`batch_detect_path`,`batch_health_check`,`batch_update_category`,`batch_server_op`]);function j(e){return A.has(e)}function M(e){let t=(e||``).trim();if(!t.startsWith(`{`))return null;try{let e=JSON.parse(t);return typeof e.job_id!=`number`||!e.summary?null:e}catch{return null}}function N(e){let t=[e.summary],n=e.failures||[];if(n.length){let e=n.slice(0,3).map(e=>e.server_name).join(``);t.push(`失败: ${e}${n.length>3?``:``}`)}return t.join(` · `)}var P={class:`font-weight-medium`},F={class:`text-body-2`},I={class:`d-flex align-center ga-2 flex-wrap`},L={class:`text-body-2 text-medium-emphasis`,style:{"max-width":`360px`}},R={class:`text-caption text-medium-emphasis`},z={class:`text-caption text-medium-emphasis`},B=y({name:`AuditPage`,__name:`AuditPage`,setup(y){let A=e(),B=m(!1),V=m([]),H=m(0),U=m(1),W=m(null),G=m(``),K=m(``),q=D,J=x([{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 Y(e=!1){e||(B.value=!0);try{let e=(U.value-1)*50,t=await a.get(`/audit/`,{limit:50,offset:e,action:W.value||void 0,admin_username:G.value||void 0,date_from:K.value||void 0});V.value=k(t.items||[]),H.value=t.total||0}catch{V.value=[],e||A(`加载审计日志失败`,`error`)}finally{e||(B.value=!1)}}function X(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`}function Z(e){return j(e.action)?M(e.detail):null}function Q(e){let t=Z(e);return t?N(t):(e.detail||``).trim()||``}function $(e){s(e.job_id,e.summary)}return b(e=>Y(e)),(e,a)=>(d(),p(n,{fluid:``,class:`pa-6`},{default:i(()=>[_(S,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[_(w,{class:`d-flex align-center`},{default:i(()=>[a[7]||=l(` 审计日志 `,-1),_(c),_(t,{modelValue:W.value,"onUpdate:modelValue":[a[0]||=e=>W.value=e,a[1]||=e=>{U.value=1,Y()}],items:r(q),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),_(C,{modelValue:G.value,"onUpdate:modelValue":[a[2]||=e=>G.value=e,a[3]||=e=>{U.value=1,Y()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),_(C,{modelValue:K.value,"onUpdate:modelValue":[a[4]||=e=>K.value=e,a[5]||=e=>{U.value=1,Y()}],"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}),_(T,{items:V.value,headers:r(J),"items-length":H.value,loading:B.value,page:U.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":a[6]||=e=>{U.value=e,Y()}},{"item.action":i(({item:e})=>[_(v,{color:X(e.action),size:`small`,variant:`tonal`,label:``},{default:i(()=>[l(h(r(O)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":i(({item:e})=>[u(`span`,P,h(e.admin_username),1)]),"item.target":i(({item:e})=>[u(`span`,F,h(r(E)(e.resource_type))+h(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":i(({item:e})=>[u(`div`,I,[u(`span`,L,h(Q(e)),1),Z(e)?(d(),p(o,{key:0,size:`x-small`,variant:`tonal`,color:`primary`,onClick:g(t=>$(Z(e)),[`stop`])},{default:i(()=>[...a[8]||=[l(` 查看结果 `,-1)]]),_:1},8,[`onClick`])):f(``,!0)])]),"item.ip_address":i(({item:e})=>[u(`span`,R,h(e.ip_address||``),1)]),"item.created_at":i(({item:e})=>[u(`span`,z,h(e.created_at),1)]),"no-data":i(()=>[...a[9]||=[u(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{B as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-i5lN3C8G.js";import{$r as r,Br as i,Jt as a,P as o,Tt as s,_ as c,_r as l,fr as u,jr as d,mr as f,pr as p,qr as m,ri as h,sr as g,vr as _,y as v,yr as y}from"./index-CGZBwSYH.js";import{t as b}from"./usePageActivateRefresh-DqGnYiLP.js";import{n as x}from"./dataTable-esDY4cOk.js";import{_ as S,t as C,y as w}from"./VTextField-BW0CzHfL.js";import{t as T}from"./VDataTableServer-viCCdEcM.js";import{a as E,n as D,r as O,t as k}from"./auditNormalize-DWYIxo0q.js";var A=new Set([`batch_install_agent`,`batch_upgrade_agent`,`batch_uninstall_agent`,`batch_detect_path`,`batch_health_check`,`batch_update_category`,`batch_server_op`]);function j(e){return A.has(e)}function M(e){let t=(e||``).trim();if(!t.startsWith(`{`))return null;try{let e=JSON.parse(t);return typeof e.job_id!=`number`||!e.summary?null:e}catch{return null}}function N(e){let t=[e.summary],n=e.failures||[];if(n.length){let e=n.slice(0,3).map(e=>e.server_name).join(``);t.push(`失败: ${e}${n.length>3?``:``}`)}return t.join(` · `)}var P={class:`font-weight-medium`},F={class:`text-body-2`},I={class:`d-flex align-center ga-2 flex-wrap`},L={class:`text-body-2 text-medium-emphasis`,style:{"max-width":`360px`}},R={class:`text-caption text-medium-emphasis`},z={class:`text-caption text-medium-emphasis`},B=y({name:`AuditPage`,__name:`AuditPage`,setup(y){let A=e(),B=m(!1),V=m([]),H=m(0),U=m(1),W=m(null),G=m(``),K=m(``),q=D,J=x([{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 Y(e=!1){e||(B.value=!0);try{let e=(U.value-1)*50,t=await a.get(`/audit/`,{limit:50,offset:e,action:W.value||void 0,admin_username:G.value||void 0,date_from:K.value||void 0});V.value=k(t.items||[]),H.value=t.total||0}catch{V.value=[],e||A(`加载审计日志失败`,`error`)}finally{e||(B.value=!1)}}function X(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`}function Z(e){return j(e.action)?M(e.detail):null}function Q(e){let t=Z(e);return t?N(t):(e.detail||``).trim()||``}function $(e){s(e.job_id,e.summary)}return b(e=>Y(e)),(e,a)=>(d(),p(n,{fluid:``,class:`pa-6`},{default:i(()=>[_(S,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[_(w,{class:`d-flex align-center`},{default:i(()=>[a[7]||=l(` 审计日志 `,-1),_(c),_(t,{modelValue:W.value,"onUpdate:modelValue":[a[0]||=e=>W.value=e,a[1]||=e=>{U.value=1,Y()}],items:r(q),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),_(C,{modelValue:G.value,"onUpdate:modelValue":[a[2]||=e=>G.value=e,a[3]||=e=>{U.value=1,Y()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),_(C,{modelValue:K.value,"onUpdate:modelValue":[a[4]||=e=>K.value=e,a[5]||=e=>{U.value=1,Y()}],"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}),_(T,{items:V.value,headers:r(J),"items-length":H.value,loading:B.value,page:U.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":a[6]||=e=>{U.value=e,Y()}},{"item.action":i(({item:e})=>[_(v,{color:X(e.action),size:`small`,variant:`tonal`,label:``},{default:i(()=>[l(h(r(O)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":i(({item:e})=>[u(`span`,P,h(e.admin_username),1)]),"item.target":i(({item:e})=>[u(`span`,F,h(r(E)(e.resource_type))+h(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":i(({item:e})=>[u(`div`,I,[u(`span`,L,h(Q(e)),1),Z(e)?(d(),p(o,{key:0,size:`x-small`,variant:`tonal`,color:`primary`,onClick:g(t=>$(Z(e)),[`stop`])},{default:i(()=>[...a[8]||=[l(` 查看结果 `,-1)]]),_:1},8,[`onClick`])):f(``,!0)])]),"item.ip_address":i(({item:e})=>[u(`span`,R,h(e.ip_address||``),1)]),"item.created_at":i(({item:e})=>[u(`span`,z,h(e.created_at),1)]),"no-data":i(()=>[...a[9]||=[u(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{B as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-C9h2QNwU.js";import{$r as r,Br as i,Jt as a,P as o,Tt as s,_ as c,_r as l,fr as u,jr as d,mr as f,pr as p,qr as m,ri as h,sr as g,vr as _,y as v,yr as y}from"./index-C6-Dyy9B.js";import{t as b}from"./usePageActivateRefresh-BWZBQKtm.js";import{n as x}from"./dataTable-esDY4cOk.js";import{_ as S,t as C,y as w}from"./VTextField-B_95spZa.js";import{t as T}from"./VDataTableServer-DDaIMFdh.js";import{a as E,n as D,r as O,t as k}from"./auditNormalize-DWYIxo0q.js";var A=new Set([`batch_install_agent`,`batch_upgrade_agent`,`batch_uninstall_agent`,`batch_detect_path`,`batch_health_check`,`batch_update_category`,`batch_server_op`]);function j(e){return A.has(e)}function M(e){let t=(e||``).trim();if(!t.startsWith(`{`))return null;try{let e=JSON.parse(t);return typeof e.job_id!=`number`||!e.summary?null:e}catch{return null}}function N(e){let t=[e.summary],n=e.failures||[];if(n.length){let e=n.slice(0,3).map(e=>e.server_name).join(``);t.push(`失败: ${e}${n.length>3?``:``}`)}return t.join(` · `)}var P={class:`font-weight-medium`},F={class:`text-body-2`},I={class:`d-flex align-center ga-2 flex-wrap`},L={class:`text-body-2 text-medium-emphasis`,style:{"max-width":`360px`}},R={class:`text-caption text-medium-emphasis`},z={class:`text-caption text-medium-emphasis`},B=y({name:`AuditPage`,__name:`AuditPage`,setup(y){let A=e(),B=m(!1),V=m([]),H=m(0),U=m(1),W=m(null),G=m(``),K=m(``),q=D,J=x([{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 Y(e=!1){e||(B.value=!0);try{let e=(U.value-1)*50,t=await a.get(`/audit/`,{limit:50,offset:e,action:W.value||void 0,admin_username:G.value||void 0,date_from:K.value||void 0});V.value=k(t.items||[]),H.value=t.total||0}catch{V.value=[],e||A(`加载审计日志失败`,`error`)}finally{e||(B.value=!1)}}function X(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`}function Z(e){return j(e.action)?M(e.detail):null}function Q(e){let t=Z(e);return t?N(t):(e.detail||``).trim()||``}function $(e){s(e.job_id,e.summary)}return b(e=>Y(e)),(e,a)=>(d(),p(n,{fluid:``,class:`pa-6`},{default:i(()=>[_(S,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[_(w,{class:`d-flex align-center`},{default:i(()=>[a[7]||=l(` 审计日志 `,-1),_(c),_(t,{modelValue:W.value,"onUpdate:modelValue":[a[0]||=e=>W.value=e,a[1]||=e=>{U.value=1,Y()}],items:r(q),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),_(C,{modelValue:G.value,"onUpdate:modelValue":[a[2]||=e=>G.value=e,a[3]||=e=>{U.value=1,Y()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),_(C,{modelValue:K.value,"onUpdate:modelValue":[a[4]||=e=>K.value=e,a[5]||=e=>{U.value=1,Y()}],"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}),_(T,{items:V.value,headers:r(J),"items-length":H.value,loading:B.value,page:U.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":a[6]||=e=>{U.value=e,Y()}},{"item.action":i(({item:e})=>[_(v,{color:X(e.action),size:`small`,variant:`tonal`,label:``},{default:i(()=>[l(h(r(O)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":i(({item:e})=>[u(`span`,P,h(e.admin_username),1)]),"item.target":i(({item:e})=>[u(`span`,F,h(r(E)(e.resource_type))+h(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":i(({item:e})=>[u(`div`,I,[u(`span`,L,h(Q(e)),1),Z(e)?(d(),p(o,{key:0,size:`x-small`,variant:`tonal`,color:`primary`,onClick:g(t=>$(Z(e)),[`stop`])},{default:i(()=>[...a[8]||=[l(` 查看结果 `,-1)]]),_:1},8,[`onClick`])):f(``,!0)])]),"item.ip_address":i(({item:e})=>[u(`span`,R,h(e.ip_address||``),1)]),"item.created_at":i(({item:e})=>[u(`span`,z,h(e.created_at),1)]),"no-data":i(()=>[...a[9]||=[u(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{B as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-rP81fnpc.js";import{$r as r,Br as i,Jt as a,P as o,Tt as s,_ as c,_r as l,fr as u,jr as d,mr as f,pr as p,qr as m,ri as h,sr as g,vr as _,y as v,yr as y}from"./index-DAQ8Nzd7.js";import{t as b}from"./usePageActivateRefresh-hyRkArJ0.js";import{n as x}from"./dataTable-esDY4cOk.js";import{_ as S,t as C,y as w}from"./VTextField-CqnXgqAI.js";import{t as T}from"./VDataTableServer-Cvy_Dzfu.js";import{a as E,n as D,r as O,t as k}from"./auditNormalize-DWYIxo0q.js";var A=new Set([`batch_install_agent`,`batch_upgrade_agent`,`batch_uninstall_agent`,`batch_detect_path`,`batch_health_check`,`batch_update_category`,`batch_server_op`]);function j(e){return A.has(e)}function M(e){let t=(e||``).trim();if(!t.startsWith(`{`))return null;try{let e=JSON.parse(t);return typeof e.job_id!=`number`||!e.summary?null:e}catch{return null}}function N(e){let t=[e.summary],n=e.failures||[];if(n.length){let e=n.slice(0,3).map(e=>e.server_name).join(``);t.push(`失败: ${e}${n.length>3?``:``}`)}return t.join(` · `)}var P={class:`font-weight-medium`},F={class:`text-body-2`},I={class:`d-flex align-center ga-2 flex-wrap`},L={class:`text-body-2 text-medium-emphasis`,style:{"max-width":`360px`}},R={class:`text-caption text-medium-emphasis`},z={class:`text-caption text-medium-emphasis`},B=y({name:`AuditPage`,__name:`AuditPage`,setup(y){let A=e(),B=m(!1),V=m([]),H=m(0),U=m(1),W=m(null),G=m(``),K=m(``),q=D,J=x([{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 Y(e=!1){e||(B.value=!0);try{let e=(U.value-1)*50,t=await a.get(`/audit/`,{limit:50,offset:e,action:W.value||void 0,admin_username:G.value||void 0,date_from:K.value||void 0});V.value=k(t.items||[]),H.value=t.total||0}catch{V.value=[],e||A(`加载审计日志失败`,`error`)}finally{e||(B.value=!1)}}function X(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`}function Z(e){return j(e.action)?M(e.detail):null}function Q(e){let t=Z(e);return t?N(t):(e.detail||``).trim()||``}function $(e){s(e.job_id,e.summary)}return b(e=>Y(e)),(e,a)=>(d(),p(n,{fluid:``,class:`pa-6`},{default:i(()=>[_(S,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[_(w,{class:`d-flex align-center`},{default:i(()=>[a[7]||=l(` 审计日志 `,-1),_(c),_(t,{modelValue:W.value,"onUpdate:modelValue":[a[0]||=e=>W.value=e,a[1]||=e=>{U.value=1,Y()}],items:r(q),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),_(C,{modelValue:G.value,"onUpdate:modelValue":[a[2]||=e=>G.value=e,a[3]||=e=>{U.value=1,Y()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),_(C,{modelValue:K.value,"onUpdate:modelValue":[a[4]||=e=>K.value=e,a[5]||=e=>{U.value=1,Y()}],"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}),_(T,{items:V.value,headers:r(J),"items-length":H.value,loading:B.value,page:U.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":a[6]||=e=>{U.value=e,Y()}},{"item.action":i(({item:e})=>[_(v,{color:X(e.action),size:`small`,variant:`tonal`,label:``},{default:i(()=>[l(h(r(O)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":i(({item:e})=>[u(`span`,P,h(e.admin_username),1)]),"item.target":i(({item:e})=>[u(`span`,F,h(r(E)(e.resource_type))+h(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":i(({item:e})=>[u(`div`,I,[u(`span`,L,h(Q(e)),1),Z(e)?(d(),p(o,{key:0,size:`x-small`,variant:`tonal`,color:`primary`,onClick:g(t=>$(Z(e)),[`stop`])},{default:i(()=>[...a[8]||=[l(` 查看结果 `,-1)]]),_:1},8,[`onClick`])):f(``,!0)])]),"item.ip_address":i(({item:e})=>[u(`span`,R,h(e.ip_address||``),1)]),"item.created_at":i(({item:e})=>[u(`span`,z,h(e.created_at),1)]),"no-data":i(()=>[...a[9]||=[u(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{B as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-DgmpIJ0-.js";import{$r as r,Br as i,Jt as a,P as o,Tt as s,_ as c,_r as l,fr as u,jr as d,mr as f,pr as p,qr as m,ri as h,sr as g,vr as _,y as v,yr as y}from"./index-B1boYHjE.js";import{t as b}from"./usePageActivateRefresh-85rCMLDQ.js";import{n as x}from"./dataTable-esDY4cOk.js";import{_ as S,t as C,y as w}from"./VTextField-CWk_xMst.js";import{t as T}from"./VDataTableServer-BOzWB3oR.js";import{a as E,n as D,r as O,t as k}from"./auditNormalize-DWYIxo0q.js";var A=new Set([`batch_install_agent`,`batch_upgrade_agent`,`batch_uninstall_agent`,`batch_detect_path`,`batch_health_check`,`batch_update_category`,`batch_server_op`]);function j(e){return A.has(e)}function M(e){let t=(e||``).trim();if(!t.startsWith(`{`))return null;try{let e=JSON.parse(t);return typeof e.job_id!=`number`||!e.summary?null:e}catch{return null}}function N(e){let t=[e.summary],n=e.failures||[];if(n.length){let e=n.slice(0,3).map(e=>e.server_name).join(``);t.push(`失败: ${e}${n.length>3?``:``}`)}return t.join(` · `)}var P={class:`font-weight-medium`},F={class:`text-body-2`},I={class:`d-flex align-center ga-2 flex-wrap`},L={class:`text-body-2 text-medium-emphasis`,style:{"max-width":`360px`}},R={class:`text-caption text-medium-emphasis`},z={class:`text-caption text-medium-emphasis`},B=y({name:`AuditPage`,__name:`AuditPage`,setup(y){let A=e(),B=m(!1),V=m([]),H=m(0),U=m(1),W=m(null),G=m(``),K=m(``),q=D,J=x([{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 Y(e=!1){e||(B.value=!0);try{let e=(U.value-1)*50,t=await a.get(`/audit/`,{limit:50,offset:e,action:W.value||void 0,admin_username:G.value||void 0,date_from:K.value||void 0});V.value=k(t.items||[]),H.value=t.total||0}catch{V.value=[],e||A(`加载审计日志失败`,`error`)}finally{e||(B.value=!1)}}function X(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`}function Z(e){return j(e.action)?M(e.detail):null}function Q(e){let t=Z(e);return t?N(t):(e.detail||``).trim()||``}function $(e){s(e.job_id,e.summary)}return b(e=>Y(e)),(e,a)=>(d(),p(n,{fluid:``,class:`pa-6`},{default:i(()=>[_(S,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[_(w,{class:`d-flex align-center`},{default:i(()=>[a[7]||=l(` 审计日志 `,-1),_(c),_(t,{modelValue:W.value,"onUpdate:modelValue":[a[0]||=e=>W.value=e,a[1]||=e=>{U.value=1,Y()}],items:r(q),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),_(C,{modelValue:G.value,"onUpdate:modelValue":[a[2]||=e=>G.value=e,a[3]||=e=>{U.value=1,Y()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),_(C,{modelValue:K.value,"onUpdate:modelValue":[a[4]||=e=>K.value=e,a[5]||=e=>{U.value=1,Y()}],"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}),_(T,{items:V.value,headers:r(J),"items-length":H.value,loading:B.value,page:U.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":a[6]||=e=>{U.value=e,Y()}},{"item.action":i(({item:e})=>[_(v,{color:X(e.action),size:`small`,variant:`tonal`,label:``},{default:i(()=>[l(h(r(O)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":i(({item:e})=>[u(`span`,P,h(e.admin_username),1)]),"item.target":i(({item:e})=>[u(`span`,F,h(r(E)(e.resource_type))+h(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":i(({item:e})=>[u(`div`,I,[u(`span`,L,h(Q(e)),1),Z(e)?(d(),p(o,{key:0,size:`x-small`,variant:`tonal`,color:`primary`,onClick:g(t=>$(Z(e)),[`stop`])},{default:i(()=>[...a[8]||=[l(` 查看结果 `,-1)]]),_:1},8,[`onClick`])):f(``,!0)])]),"item.ip_address":i(({item:e})=>[u(`span`,R,h(e.ip_address||``),1)]),"item.created_at":i(({item:e})=>[u(`span`,z,h(e.created_at),1)]),"no-data":i(()=>[...a[9]||=[u(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{B as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-B41HpgCF.js";import{$r as r,Br as i,Jt as a,P as o,Tt as s,_ as c,_r as l,fr as u,jr as d,mr as f,pr as p,qr as m,ri as h,sr as g,vr as _,y as v,yr as y}from"./index-DCfqeweT.js";import{t as b}from"./usePageActivateRefresh-C555Oz1J.js";import{n as x}from"./dataTable-esDY4cOk.js";import{_ as S,t as C,y as w}from"./VTextField-bhIeNGqx.js";import{t as T}from"./VDataTableServer-DTfPxuos.js";import{a as E,n as D,r as O,t as k}from"./auditNormalize-DWYIxo0q.js";var A=new Set([`batch_install_agent`,`batch_upgrade_agent`,`batch_uninstall_agent`,`batch_detect_path`,`batch_health_check`,`batch_update_category`,`batch_server_op`]);function j(e){return A.has(e)}function M(e){let t=(e||``).trim();if(!t.startsWith(`{`))return null;try{let e=JSON.parse(t);return typeof e.job_id!=`number`||!e.summary?null:e}catch{return null}}function N(e){let t=[e.summary],n=e.failures||[];if(n.length){let e=n.slice(0,3).map(e=>e.server_name).join(``);t.push(`失败: ${e}${n.length>3?``:``}`)}return t.join(` · `)}var P={class:`font-weight-medium`},F={class:`text-body-2`},I={class:`d-flex align-center ga-2 flex-wrap`},L={class:`text-body-2 text-medium-emphasis`,style:{"max-width":`360px`}},R={class:`text-caption text-medium-emphasis`},z={class:`text-caption text-medium-emphasis`},B=y({name:`AuditPage`,__name:`AuditPage`,setup(y){let A=e(),B=m(!1),V=m([]),H=m(0),U=m(1),W=m(null),G=m(``),K=m(``),q=D,J=x([{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 Y(e=!1){e||(B.value=!0);try{let e=(U.value-1)*50,t=await a.get(`/audit/`,{limit:50,offset:e,action:W.value||void 0,admin_username:G.value||void 0,date_from:K.value||void 0});V.value=k(t.items||[]),H.value=t.total||0}catch{V.value=[],e||A(`加载审计日志失败`,`error`)}finally{e||(B.value=!1)}}function X(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`}function Z(e){return j(e.action)?M(e.detail):null}function Q(e){let t=Z(e);return t?N(t):(e.detail||``).trim()||``}function $(e){s(e.job_id,e.summary)}return b(e=>Y(e)),(e,a)=>(d(),p(n,{fluid:``,class:`pa-6`},{default:i(()=>[_(S,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[_(w,{class:`d-flex align-center`},{default:i(()=>[a[7]||=l(` 审计日志 `,-1),_(c),_(t,{modelValue:W.value,"onUpdate:modelValue":[a[0]||=e=>W.value=e,a[1]||=e=>{U.value=1,Y()}],items:r(q),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),_(C,{modelValue:G.value,"onUpdate:modelValue":[a[2]||=e=>G.value=e,a[3]||=e=>{U.value=1,Y()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),_(C,{modelValue:K.value,"onUpdate:modelValue":[a[4]||=e=>K.value=e,a[5]||=e=>{U.value=1,Y()}],"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}),_(T,{items:V.value,headers:r(J),"items-length":H.value,loading:B.value,page:U.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":a[6]||=e=>{U.value=e,Y()}},{"item.action":i(({item:e})=>[_(v,{color:X(e.action),size:`small`,variant:`tonal`,label:``},{default:i(()=>[l(h(r(O)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":i(({item:e})=>[u(`span`,P,h(e.admin_username),1)]),"item.target":i(({item:e})=>[u(`span`,F,h(r(E)(e.resource_type))+h(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":i(({item:e})=>[u(`div`,I,[u(`span`,L,h(Q(e)),1),Z(e)?(d(),p(o,{key:0,size:`x-small`,variant:`tonal`,color:`primary`,onClick:g(t=>$(Z(e)),[`stop`])},{default:i(()=>[...a[8]||=[l(` 查看结果 `,-1)]]),_:1},8,[`onClick`])):f(``,!0)])]),"item.ip_address":i(({item:e})=>[u(`span`,R,h(e.ip_address||``),1)]),"item.created_at":i(({item:e})=>[u(`span`,z,h(e.created_at),1)]),"no-data":i(()=>[...a[9]||=[u(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{B 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
@@ -0,0 +1 @@
import{Qt as e,hr as t,jr as n,kr as r,yr as i}from"./index-C-0InWiN.js";var a=i({name:`CredentialsPage`,__name:`CredentialsPage`,setup(i){let a=e();return r(()=>{a.replace({path:`/servers`,query:{credentials:`1`}})}),(e,r)=>(n(),t(`div`))}});export{a as default};
@@ -0,0 +1 @@
import{Qt as e,hr as t,jr as n,kr as r,yr as i}from"./index-DAQ8Nzd7.js";var a=i({name:`CredentialsPage`,__name:`CredentialsPage`,setup(i){let a=e();return r(()=>{a.replace({path:`/servers`,query:{credentials:`1`}})}),(e,r)=>(n(),t(`div`))}});export{a as default};
@@ -0,0 +1 @@
import{Qt as e,hr as t,jr as n,kr as r,yr as i}from"./index-DCfqeweT.js";var a=i({name:`CredentialsPage`,__name:`CredentialsPage`,setup(i){let a=e();return r(()=>{a.replace({path:`/servers`,query:{credentials:`1`}})}),(e,r)=>(n(),t(`div`))}});export{a as default};
@@ -0,0 +1 @@
import{Qt as e,hr as t,jr as n,kr as r,yr as i}from"./index-B1boYHjE.js";var a=i({name:`CredentialsPage`,__name:`CredentialsPage`,setup(i){let a=e();return r(()=>{a.replace({path:`/servers`,query:{credentials:`1`}})}),(e,r)=>(n(),t(`div`))}});export{a as default};
@@ -0,0 +1 @@
import{Qt as e,hr as t,jr as n,kr as r,yr as i}from"./index-CLYaSJSV.js";var a=i({name:`CredentialsPage`,__name:`CredentialsPage`,setup(i){let a=e();return r(()=>{a.replace({path:`/servers`,query:{credentials:`1`}})}),(e,r)=>(n(),t(`div`))}});export{a as default};
@@ -0,0 +1 @@
import{Qt as e,hr as t,jr as n,kr as r,yr as i}from"./index-C6-Dyy9B.js";var a=i({name:`CredentialsPage`,__name:`CredentialsPage`,setup(i){let a=e();return r(()=>{a.replace({path:`/servers`,query:{credentials:`1`}})}),(e,r)=>(n(),t(`div`))}});export{a as default};
@@ -0,0 +1 @@
import{Qt as e,hr as t,jr as n,kr as r,yr as i}from"./index-CGZBwSYH.js";var a=i({name:`CredentialsPage`,__name:`CredentialsPage`,setup(i){let a=e();return r(()=>{a.replace({path:`/servers`,query:{credentials:`1`}})}),(e,r)=>(n(),t(`div`))}});export{a as default};
@@ -0,0 +1 @@
import{Ar as e,Mr as t,Qt as n,br as r,gr as i}from"./index-CLdQHC4h.js";var a=r({name:`CredentialsPage`,__name:`CredentialsPage`,setup(r){let a=n();return e(()=>{a.replace({path:`/servers`,query:{credentials:`1`}})}),(e,n)=>(t(),i(`div`))}});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
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
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
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-CxIgrALN.js";import{$r as r,Br as i,Jt as a,P as o,_ as s,_r as c,fr as l,jr as u,mr as d,pr as f,qr as p,ri as m,vr as h,y as g,yr as _}from"./index-CLYaSJSV.js";import{t as v}from"./usePageActivateRefresh-D1E3V_5C.js";import{n as y}from"./dataTable-esDY4cOk.js";import{_ as b,v as x,x as S,y as C}from"./VTextField-DL63Pt8A.js";import{t as w}from"./VDataTableServer-9aNMIT8a.js";import{t as T}from"./VDialog-DVc-q_qz.js";import{t as E}from"./usePageAutoRefresh-r9JYaD6K.js";var D={class:`font-weight-medium text-truncate d-inline-block`,style:{"max-width":`240px`}},O={class:`text-medium-emphasis`},k={class:`text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j={class:`text-caption text-medium-emphasis`},M=_({name:`RetriesPage`,__name:`RetriesPage`,setup(_){let M=e(),N=p(!1),P=p([]),F=p(0),I=p(1),L=p(null),R=p(!1),z=p(null),B=[{label:`待重试`,value:`pending`},{label:`重试中`,value:`retrying`},{label:`成功`,value:`success`},{label:`失败`,value:`failed`}],V=y([{title:`状态`,key:`status`,width:100},{title:`任务`,key:`operation`},{title:`服务器`,key:`server_name`},{title:`次数`,key:`retry_count`,width:100},{title:`下次重试`,key:`next_retry_at`,width:140},{title:`创建时间`,key:`created_at`,width:160},{title:``,key:`actions`,width:120,align:`end`}]);async function H(e=!1){e||(N.value=!0);try{let e=(await a.getList(`/retries/`,{limit:200})).items||[];L.value&&(e=e.filter(e=>e.status===L.value)),F.value=e.length;let t=(I.value-1)*20;P.value=e.slice(t,t+20)}catch(t){e||(P.value=[],F.value=0,M(t instanceof Error?t.message:`加载重试队列失败`,`error`))}finally{e||(N.value=!1)}}async function U(e){try{await a.post(`/retries/${e.id}/retry`),H(),M(`重试已触发`)}catch(e){M(e.message||`操作失败`,`error`)}}function W(e){z.value=e.id,R.value=!0}async function G(){if(z.value)try{await a.delete(`/retries/${z.value}`),R.value=!1,H(),M(`已删除`)}catch(e){M(e.message||`删除失败`,`error`)}}function K(e){return e===`success`?`success`:e===`failed`?`error`:e===`retrying`?`warning`:`info`}function q(e){return e===`pending`?`待重试`:e===`retrying`?`重试中`:e===`success`?`成功`:e===`failed`?`失败`:e}function J(e){return e.source_path&&e.target_path?`${e.source_path}${e.target_path}`:e.source_path||e.target_path||`文件推送`}return E(()=>H(!0),15e3),v(e=>H(e)),(e,a)=>(u(),f(n,{fluid:``,class:`pa-6`},{default:i(()=>[h(b,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[h(C,{class:`d-flex align-center text-h6`},{default:i(()=>[a[5]||=c(` 重试队列 `,-1),h(s),h(t,{modelValue:L.value,"onUpdate:modelValue":[a[0]||=e=>L.value=e,a[1]||=e=>{I.value=1,H()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态筛选`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},clearable:``},null,8,[`modelValue`])]),_:1}),h(w,{items:P.value,headers:r(V),"items-length":F.value,loading:N.value,page:I.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":a[2]||=e=>{I.value=e,H()}},{"item.status":i(({item:e})=>[h(g,{color:K(e.status),size:`x-small`,variant:`tonal`,label:``,border:`sm`},{default:i(()=>[c(m(q(e.status)),1)]),_:2},1032,[`color`])]),"item.operation":i(({item:e})=>[l(`span`,D,m(J(e)),1)]),"item.server_name":i(({item:e})=>[l(`span`,O,m(e.server_name||``),1)]),"item.retry_count":i(({item:e})=>[l(`span`,k,m(e.retry_count||0)+` / `+m(e.max_retries||3),1)]),"item.next_retry_at":i(({item:e})=>[l(`span`,A,m(e.next_retry_at||``),1)]),"item.created_at":i(({item:e})=>[l(`span`,j,m(e.created_at),1)]),"item.actions":i(({item:e})=>[e.status===`pending`||e.status===`failed`?(u(),f(o,{key:0,variant:`text`,size:`x-small`,color:`primary`,density:`compact`,onClick:t=>U(e)},{default:i(()=>[...a[6]||=[c(` 重试 `,-1)]]),_:1},8,[`onClick`])):d(``,!0),h(o,{variant:`text`,size:`x-small`,color:`error`,density:`compact`,onClick:t=>W(e)},{default:i(()=>[...a[7]||=[c(` 删除 `,-1)]]),_:1},8,[`onClick`])]),"no-data":i(()=>[...a[8]||=[l(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1}),h(T,{modelValue:R.value,"onUpdate:modelValue":a[4]||=e=>R.value=e,"max-width":`400`},{default:i(()=>[h(b,{border:``},{default:i(()=>[h(C,null,{default:i(()=>[...a[9]||=[c(`确认删除`,-1)]]),_:1}),h(x,null,{default:i(()=>[...a[10]||=[c(`确定要删除此重试任务吗?`,-1)]]),_:1}),h(S,null,{default:i(()=>[h(s),h(o,{variant:`text`,onClick:a[3]||=e=>R.value=!1},{default:i(()=>[...a[11]||=[c(`取消`,-1)]]),_:1}),h(o,{color:`error`,variant:`flat`,onClick:G},{default:i(()=>[...a[12]||=[c(`删除`,-1)]]),_:1})]),_:1})]),_:1})]),_:1},8,[`modelValue`])]),_:1}))}});export{M as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-C9h2QNwU.js";import{$r as r,Br as i,Jt as a,P as o,_ as s,_r as c,fr as l,jr as u,mr as d,pr as f,qr as p,ri as m,vr as h,y as g,yr as _}from"./index-C6-Dyy9B.js";import{t as v}from"./usePageActivateRefresh-BWZBQKtm.js";import{n as y}from"./dataTable-esDY4cOk.js";import{_ as b,v as x,x as S,y as C}from"./VTextField-B_95spZa.js";import{t as w}from"./VDataTableServer-DDaIMFdh.js";import{t as T}from"./VDialog-Cuq2j90v.js";import{t as E}from"./usePageAutoRefresh-DO0mByEc.js";var D={class:`font-weight-medium text-truncate d-inline-block`,style:{"max-width":`240px`}},O={class:`text-medium-emphasis`},k={class:`text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j={class:`text-caption text-medium-emphasis`},M=_({name:`RetriesPage`,__name:`RetriesPage`,setup(_){let M=e(),N=p(!1),P=p([]),F=p(0),I=p(1),L=p(null),R=p(!1),z=p(null),B=[{label:`待重试`,value:`pending`},{label:`重试中`,value:`retrying`},{label:`成功`,value:`success`},{label:`失败`,value:`failed`}],V=y([{title:`状态`,key:`status`,width:100},{title:`任务`,key:`operation`},{title:`服务器`,key:`server_name`},{title:`次数`,key:`retry_count`,width:100},{title:`下次重试`,key:`next_retry_at`,width:140},{title:`创建时间`,key:`created_at`,width:160},{title:``,key:`actions`,width:120,align:`end`}]);async function H(e=!1){e||(N.value=!0);try{let e=(await a.getList(`/retries/`,{limit:200})).items||[];L.value&&(e=e.filter(e=>e.status===L.value)),F.value=e.length;let t=(I.value-1)*20;P.value=e.slice(t,t+20)}catch(t){e||(P.value=[],F.value=0,M(t instanceof Error?t.message:`加载重试队列失败`,`error`))}finally{e||(N.value=!1)}}async function U(e){try{await a.post(`/retries/${e.id}/retry`),H(),M(`重试已触发`)}catch(e){M(e.message||`操作失败`,`error`)}}function W(e){z.value=e.id,R.value=!0}async function G(){if(z.value)try{await a.delete(`/retries/${z.value}`),R.value=!1,H(),M(`已删除`)}catch(e){M(e.message||`删除失败`,`error`)}}function K(e){return e===`success`?`success`:e===`failed`?`error`:e===`retrying`?`warning`:`info`}function q(e){return e===`pending`?`待重试`:e===`retrying`?`重试中`:e===`success`?`成功`:e===`failed`?`失败`:e}function J(e){return e.source_path&&e.target_path?`${e.source_path}${e.target_path}`:e.source_path||e.target_path||`文件推送`}return E(()=>H(!0),15e3),v(e=>H(e)),(e,a)=>(u(),f(n,{fluid:``,class:`pa-6`},{default:i(()=>[h(b,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[h(C,{class:`d-flex align-center text-h6`},{default:i(()=>[a[5]||=c(` 重试队列 `,-1),h(s),h(t,{modelValue:L.value,"onUpdate:modelValue":[a[0]||=e=>L.value=e,a[1]||=e=>{I.value=1,H()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态筛选`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},clearable:``},null,8,[`modelValue`])]),_:1}),h(w,{items:P.value,headers:r(V),"items-length":F.value,loading:N.value,page:I.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":a[2]||=e=>{I.value=e,H()}},{"item.status":i(({item:e})=>[h(g,{color:K(e.status),size:`x-small`,variant:`tonal`,label:``,border:`sm`},{default:i(()=>[c(m(q(e.status)),1)]),_:2},1032,[`color`])]),"item.operation":i(({item:e})=>[l(`span`,D,m(J(e)),1)]),"item.server_name":i(({item:e})=>[l(`span`,O,m(e.server_name||``),1)]),"item.retry_count":i(({item:e})=>[l(`span`,k,m(e.retry_count||0)+` / `+m(e.max_retries||3),1)]),"item.next_retry_at":i(({item:e})=>[l(`span`,A,m(e.next_retry_at||``),1)]),"item.created_at":i(({item:e})=>[l(`span`,j,m(e.created_at),1)]),"item.actions":i(({item:e})=>[e.status===`pending`||e.status===`failed`?(u(),f(o,{key:0,variant:`text`,size:`x-small`,color:`primary`,density:`compact`,onClick:t=>U(e)},{default:i(()=>[...a[6]||=[c(` 重试 `,-1)]]),_:1},8,[`onClick`])):d(``,!0),h(o,{variant:`text`,size:`x-small`,color:`error`,density:`compact`,onClick:t=>W(e)},{default:i(()=>[...a[7]||=[c(` 删除 `,-1)]]),_:1},8,[`onClick`])]),"no-data":i(()=>[...a[8]||=[l(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1}),h(T,{modelValue:R.value,"onUpdate:modelValue":a[4]||=e=>R.value=e,"max-width":`400`},{default:i(()=>[h(b,{border:``},{default:i(()=>[h(C,null,{default:i(()=>[...a[9]||=[c(`确认删除`,-1)]]),_:1}),h(x,null,{default:i(()=>[...a[10]||=[c(`确定要删除此重试任务吗?`,-1)]]),_:1}),h(S,null,{default:i(()=>[h(s),h(o,{variant:`text`,onClick:a[3]||=e=>R.value=!1},{default:i(()=>[...a[11]||=[c(`取消`,-1)]]),_:1}),h(o,{color:`error`,variant:`flat`,onClick:G},{default:i(()=>[...a[12]||=[c(`删除`,-1)]]),_:1})]),_:1})]),_:1})]),_:1},8,[`modelValue`])]),_:1}))}});export{M as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-CuoDLDz6.js";import{$r as r,Br as i,Jt as a,P as o,_ as s,_r as c,fr as l,jr as u,mr as d,pr as f,qr as p,ri as m,vr as h,y as g,yr as _}from"./index-C-0InWiN.js";import{t as v}from"./usePageActivateRefresh-DvwpdC2e.js";import{n as y}from"./dataTable-esDY4cOk.js";import{_ as b,v as x,x as S,y as C}from"./VTextField-Dh7LxFTC.js";import{t as w}from"./VDataTableServer-NOoqoVGA.js";import{t as T}from"./VDialog-CXT-AeUl.js";import{t as E}from"./usePageAutoRefresh-DaKmTRzt.js";var D={class:`font-weight-medium text-truncate d-inline-block`,style:{"max-width":`240px`}},O={class:`text-medium-emphasis`},k={class:`text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j={class:`text-caption text-medium-emphasis`},M=_({name:`RetriesPage`,__name:`RetriesPage`,setup(_){let M=e(),N=p(!1),P=p([]),F=p(0),I=p(1),L=p(null),R=p(!1),z=p(null),B=[{label:`待重试`,value:`pending`},{label:`重试中`,value:`retrying`},{label:`成功`,value:`success`},{label:`失败`,value:`failed`}],V=y([{title:`状态`,key:`status`,width:100},{title:`任务`,key:`operation`},{title:`服务器`,key:`server_name`},{title:`次数`,key:`retry_count`,width:100},{title:`下次重试`,key:`next_retry_at`,width:140},{title:`创建时间`,key:`created_at`,width:160},{title:``,key:`actions`,width:120,align:`end`}]);async function H(e=!1){e||(N.value=!0);try{let e=(await a.getList(`/retries/`,{limit:200})).items||[];L.value&&(e=e.filter(e=>e.status===L.value)),F.value=e.length;let t=(I.value-1)*20;P.value=e.slice(t,t+20)}catch(t){e||(P.value=[],F.value=0,M(t instanceof Error?t.message:`加载重试队列失败`,`error`))}finally{e||(N.value=!1)}}async function U(e){try{await a.post(`/retries/${e.id}/retry`),H(),M(`重试已触发`)}catch(e){M(e.message||`操作失败`,`error`)}}function W(e){z.value=e.id,R.value=!0}async function G(){if(z.value)try{await a.delete(`/retries/${z.value}`),R.value=!1,H(),M(`已删除`)}catch(e){M(e.message||`删除失败`,`error`)}}function K(e){return e===`success`?`success`:e===`failed`?`error`:e===`retrying`?`warning`:`info`}function q(e){return e===`pending`?`待重试`:e===`retrying`?`重试中`:e===`success`?`成功`:e===`failed`?`失败`:e}function J(e){return e.source_path&&e.target_path?`${e.source_path}${e.target_path}`:e.source_path||e.target_path||`文件推送`}return E(()=>H(!0),15e3),v(e=>H(e)),(e,a)=>(u(),f(n,{fluid:``,class:`pa-6`},{default:i(()=>[h(b,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[h(C,{class:`d-flex align-center text-h6`},{default:i(()=>[a[5]||=c(` 重试队列 `,-1),h(s),h(t,{modelValue:L.value,"onUpdate:modelValue":[a[0]||=e=>L.value=e,a[1]||=e=>{I.value=1,H()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态筛选`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},clearable:``},null,8,[`modelValue`])]),_:1}),h(w,{items:P.value,headers:r(V),"items-length":F.value,loading:N.value,page:I.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":a[2]||=e=>{I.value=e,H()}},{"item.status":i(({item:e})=>[h(g,{color:K(e.status),size:`x-small`,variant:`tonal`,label:``,border:`sm`},{default:i(()=>[c(m(q(e.status)),1)]),_:2},1032,[`color`])]),"item.operation":i(({item:e})=>[l(`span`,D,m(J(e)),1)]),"item.server_name":i(({item:e})=>[l(`span`,O,m(e.server_name||``),1)]),"item.retry_count":i(({item:e})=>[l(`span`,k,m(e.retry_count||0)+` / `+m(e.max_retries||3),1)]),"item.next_retry_at":i(({item:e})=>[l(`span`,A,m(e.next_retry_at||``),1)]),"item.created_at":i(({item:e})=>[l(`span`,j,m(e.created_at),1)]),"item.actions":i(({item:e})=>[e.status===`pending`||e.status===`failed`?(u(),f(o,{key:0,variant:`text`,size:`x-small`,color:`primary`,density:`compact`,onClick:t=>U(e)},{default:i(()=>[...a[6]||=[c(` 重试 `,-1)]]),_:1},8,[`onClick`])):d(``,!0),h(o,{variant:`text`,size:`x-small`,color:`error`,density:`compact`,onClick:t=>W(e)},{default:i(()=>[...a[7]||=[c(` 删除 `,-1)]]),_:1},8,[`onClick`])]),"no-data":i(()=>[...a[8]||=[l(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1}),h(T,{modelValue:R.value,"onUpdate:modelValue":a[4]||=e=>R.value=e,"max-width":`400`},{default:i(()=>[h(b,{border:``},{default:i(()=>[h(C,null,{default:i(()=>[...a[9]||=[c(`确认删除`,-1)]]),_:1}),h(x,null,{default:i(()=>[...a[10]||=[c(`确定要删除此重试任务吗?`,-1)]]),_:1}),h(S,null,{default:i(()=>[h(s),h(o,{variant:`text`,onClick:a[3]||=e=>R.value=!1},{default:i(()=>[...a[11]||=[c(`取消`,-1)]]),_:1}),h(o,{color:`error`,variant:`flat`,onClick:G},{default:i(()=>[...a[12]||=[c(`删除`,-1)]]),_:1})]),_:1})]),_:1})]),_:1},8,[`modelValue`])]),_:1}))}});export{M as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-B41HpgCF.js";import{$r as r,Br as i,Jt as a,P as o,_ as s,_r as c,fr as l,jr as u,mr as d,pr as f,qr as p,ri as m,vr as h,y as g,yr as _}from"./index-DCfqeweT.js";import{t as v}from"./usePageActivateRefresh-C555Oz1J.js";import{n as y}from"./dataTable-esDY4cOk.js";import{_ as b,v as x,x as S,y as C}from"./VTextField-bhIeNGqx.js";import{t as w}from"./VDataTableServer-DTfPxuos.js";import{t as T}from"./VDialog-BabaVvL6.js";import{t as E}from"./usePageAutoRefresh-MX3xQ0YC.js";var D={class:`font-weight-medium text-truncate d-inline-block`,style:{"max-width":`240px`}},O={class:`text-medium-emphasis`},k={class:`text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j={class:`text-caption text-medium-emphasis`},M=_({name:`RetriesPage`,__name:`RetriesPage`,setup(_){let M=e(),N=p(!1),P=p([]),F=p(0),I=p(1),L=p(null),R=p(!1),z=p(null),B=[{label:`待重试`,value:`pending`},{label:`重试中`,value:`retrying`},{label:`成功`,value:`success`},{label:`失败`,value:`failed`}],V=y([{title:`状态`,key:`status`,width:100},{title:`任务`,key:`operation`},{title:`服务器`,key:`server_name`},{title:`次数`,key:`retry_count`,width:100},{title:`下次重试`,key:`next_retry_at`,width:140},{title:`创建时间`,key:`created_at`,width:160},{title:``,key:`actions`,width:120,align:`end`}]);async function H(e=!1){e||(N.value=!0);try{let e=(await a.getList(`/retries/`,{limit:200})).items||[];L.value&&(e=e.filter(e=>e.status===L.value)),F.value=e.length;let t=(I.value-1)*20;P.value=e.slice(t,t+20)}catch(t){e||(P.value=[],F.value=0,M(t instanceof Error?t.message:`加载重试队列失败`,`error`))}finally{e||(N.value=!1)}}async function U(e){try{await a.post(`/retries/${e.id}/retry`),H(),M(`重试已触发`)}catch(e){M(e.message||`操作失败`,`error`)}}function W(e){z.value=e.id,R.value=!0}async function G(){if(z.value)try{await a.delete(`/retries/${z.value}`),R.value=!1,H(),M(`已删除`)}catch(e){M(e.message||`删除失败`,`error`)}}function K(e){return e===`success`?`success`:e===`failed`?`error`:e===`retrying`?`warning`:`info`}function q(e){return e===`pending`?`待重试`:e===`retrying`?`重试中`:e===`success`?`成功`:e===`failed`?`失败`:e}function J(e){return e.source_path&&e.target_path?`${e.source_path}${e.target_path}`:e.source_path||e.target_path||`文件推送`}return E(()=>H(!0),15e3),v(e=>H(e)),(e,a)=>(u(),f(n,{fluid:``,class:`pa-6`},{default:i(()=>[h(b,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[h(C,{class:`d-flex align-center text-h6`},{default:i(()=>[a[5]||=c(` 重试队列 `,-1),h(s),h(t,{modelValue:L.value,"onUpdate:modelValue":[a[0]||=e=>L.value=e,a[1]||=e=>{I.value=1,H()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态筛选`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},clearable:``},null,8,[`modelValue`])]),_:1}),h(w,{items:P.value,headers:r(V),"items-length":F.value,loading:N.value,page:I.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":a[2]||=e=>{I.value=e,H()}},{"item.status":i(({item:e})=>[h(g,{color:K(e.status),size:`x-small`,variant:`tonal`,label:``,border:`sm`},{default:i(()=>[c(m(q(e.status)),1)]),_:2},1032,[`color`])]),"item.operation":i(({item:e})=>[l(`span`,D,m(J(e)),1)]),"item.server_name":i(({item:e})=>[l(`span`,O,m(e.server_name||``),1)]),"item.retry_count":i(({item:e})=>[l(`span`,k,m(e.retry_count||0)+` / `+m(e.max_retries||3),1)]),"item.next_retry_at":i(({item:e})=>[l(`span`,A,m(e.next_retry_at||``),1)]),"item.created_at":i(({item:e})=>[l(`span`,j,m(e.created_at),1)]),"item.actions":i(({item:e})=>[e.status===`pending`||e.status===`failed`?(u(),f(o,{key:0,variant:`text`,size:`x-small`,color:`primary`,density:`compact`,onClick:t=>U(e)},{default:i(()=>[...a[6]||=[c(` 重试 `,-1)]]),_:1},8,[`onClick`])):d(``,!0),h(o,{variant:`text`,size:`x-small`,color:`error`,density:`compact`,onClick:t=>W(e)},{default:i(()=>[...a[7]||=[c(` 删除 `,-1)]]),_:1},8,[`onClick`])]),"no-data":i(()=>[...a[8]||=[l(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1}),h(T,{modelValue:R.value,"onUpdate:modelValue":a[4]||=e=>R.value=e,"max-width":`400`},{default:i(()=>[h(b,{border:``},{default:i(()=>[h(C,null,{default:i(()=>[...a[9]||=[c(`确认删除`,-1)]]),_:1}),h(x,null,{default:i(()=>[...a[10]||=[c(`确定要删除此重试任务吗?`,-1)]]),_:1}),h(S,null,{default:i(()=>[h(s),h(o,{variant:`text`,onClick:a[3]||=e=>R.value=!1},{default:i(()=>[...a[11]||=[c(`取消`,-1)]]),_:1}),h(o,{color:`error`,variant:`flat`,onClick:G},{default:i(()=>[...a[12]||=[c(`删除`,-1)]]),_:1})]),_:1})]),_:1})]),_:1},8,[`modelValue`])]),_:1}))}});export{M as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-B_6Vp6qA.js";import{Jr as r,Jt as i,Mr as a,P as o,Vr as s,_ as c,br as l,ei as u,hr as d,ii as f,mr as p,pr as m,vr as h,y as g,yr as _}from"./index-CLdQHC4h.js";import{t as v}from"./usePageActivateRefresh-BpIWjk_F.js";import{n as y}from"./dataTable-esDY4cOk.js";import{_ as b,v as x,x as S,y as C}from"./VTextField-BGLB-ir3.js";import{t as w}from"./VDataTableServer-CE7yQuNc.js";import{t as T}from"./VDialog-Dkf_dHsf.js";import{t as E}from"./usePageAutoRefresh-BFfpSoIo.js";var D={class:`font-weight-medium text-truncate d-inline-block`,style:{"max-width":`240px`}},O={class:`text-medium-emphasis`},k={class:`text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j={class:`text-caption text-medium-emphasis`},M=l({name:`RetriesPage`,__name:`RetriesPage`,setup(l){let M=e(),N=r(!1),P=r([]),F=r(0),I=r(1),L=r(null),R=r(!1),z=r(null),B=[{label:`待重试`,value:`pending`},{label:`重试中`,value:`retrying`},{label:`成功`,value:`success`},{label:`失败`,value:`failed`}],V=y([{title:`状态`,key:`status`,width:100},{title:`任务`,key:`operation`},{title:`服务器`,key:`server_name`},{title:`次数`,key:`retry_count`,width:100},{title:`下次重试`,key:`next_retry_at`,width:140},{title:`创建时间`,key:`created_at`,width:160},{title:``,key:`actions`,width:120,align:`end`}]);async function H(e=!1){e||(N.value=!0);try{let e=(await i.getList(`/retries/`,{limit:200})).items||[];L.value&&(e=e.filter(e=>e.status===L.value)),F.value=e.length;let t=(I.value-1)*20;P.value=e.slice(t,t+20)}catch(t){e||(P.value=[],F.value=0,M(t instanceof Error?t.message:`加载重试队列失败`,`error`))}finally{e||(N.value=!1)}}async function U(e){try{await i.post(`/retries/${e.id}/retry`),H(),M(`重试已触发`)}catch(e){M(e.message||`操作失败`,`error`)}}function W(e){z.value=e.id,R.value=!0}async function G(){if(z.value)try{await i.delete(`/retries/${z.value}`),R.value=!1,H(),M(`已删除`)}catch(e){M(e.message||`删除失败`,`error`)}}function K(e){return e===`success`?`success`:e===`failed`?`error`:e===`retrying`?`warning`:`info`}function q(e){return e===`pending`?`待重试`:e===`retrying`?`重试中`:e===`success`?`成功`:e===`failed`?`失败`:e}function J(e){return e.source_path&&e.target_path?`${e.source_path}${e.target_path}`:e.source_path||e.target_path||`文件推送`}return E(()=>H(!0),15e3),v(e=>H(e)),(e,r)=>(a(),p(n,{fluid:``,class:`pa-6`},{default:s(()=>[_(b,{elevation:`0`,border:``,rounded:`lg`},{default:s(()=>[_(C,{class:`d-flex align-center text-h6`},{default:s(()=>[r[5]||=h(` 重试队列 `,-1),_(c),_(t,{modelValue:L.value,"onUpdate:modelValue":[r[0]||=e=>L.value=e,r[1]||=e=>{I.value=1,H()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态筛选`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},clearable:``},null,8,[`modelValue`])]),_:1}),_(w,{items:P.value,headers:u(V),"items-length":F.value,loading:N.value,page:I.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":r[2]||=e=>{I.value=e,H()}},{"item.status":s(({item:e})=>[_(g,{color:K(e.status),size:`x-small`,variant:`tonal`,label:``,border:`sm`},{default:s(()=>[h(f(q(e.status)),1)]),_:2},1032,[`color`])]),"item.operation":s(({item:e})=>[m(`span`,D,f(J(e)),1)]),"item.server_name":s(({item:e})=>[m(`span`,O,f(e.server_name||``),1)]),"item.retry_count":s(({item:e})=>[m(`span`,k,f(e.retry_count||0)+` / `+f(e.max_retries||3),1)]),"item.next_retry_at":s(({item:e})=>[m(`span`,A,f(e.next_retry_at||``),1)]),"item.created_at":s(({item:e})=>[m(`span`,j,f(e.created_at),1)]),"item.actions":s(({item:e})=>[e.status===`pending`||e.status===`failed`?(a(),p(o,{key:0,variant:`text`,size:`x-small`,color:`primary`,density:`compact`,onClick:t=>U(e)},{default:s(()=>[...r[6]||=[h(` 重试 `,-1)]]),_:1},8,[`onClick`])):d(``,!0),_(o,{variant:`text`,size:`x-small`,color:`error`,density:`compact`,onClick:t=>W(e)},{default:s(()=>[...r[7]||=[h(` 删除 `,-1)]]),_:1},8,[`onClick`])]),"no-data":s(()=>[...r[8]||=[m(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1}),_(T,{modelValue:R.value,"onUpdate:modelValue":r[4]||=e=>R.value=e,"max-width":`400`},{default:s(()=>[_(b,{border:``},{default:s(()=>[_(C,null,{default:s(()=>[...r[9]||=[h(`确认删除`,-1)]]),_:1}),_(x,null,{default:s(()=>[...r[10]||=[h(`确定要删除此重试任务吗?`,-1)]]),_:1}),_(S,null,{default:s(()=>[_(c),_(o,{variant:`text`,onClick:r[3]||=e=>R.value=!1},{default:s(()=>[...r[11]||=[h(`取消`,-1)]]),_:1}),_(o,{color:`error`,variant:`flat`,onClick:G},{default:s(()=>[...r[12]||=[h(`删除`,-1)]]),_:1})]),_:1})]),_:1})]),_:1},8,[`modelValue`])]),_:1}))}});export{M as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-i5lN3C8G.js";import{$r as r,Br as i,Jt as a,P as o,_ as s,_r as c,fr as l,jr as u,mr as d,pr as f,qr as p,ri as m,vr as h,y as g,yr as _}from"./index-CGZBwSYH.js";import{t as v}from"./usePageActivateRefresh-DqGnYiLP.js";import{n as y}from"./dataTable-esDY4cOk.js";import{_ as b,v as x,x as S,y as C}from"./VTextField-BW0CzHfL.js";import{t as w}from"./VDataTableServer-viCCdEcM.js";import{t as T}from"./VDialog-fxBfCQXm.js";import{t as E}from"./usePageAutoRefresh-D8pFPzeB.js";var D={class:`font-weight-medium text-truncate d-inline-block`,style:{"max-width":`240px`}},O={class:`text-medium-emphasis`},k={class:`text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j={class:`text-caption text-medium-emphasis`},M=_({name:`RetriesPage`,__name:`RetriesPage`,setup(_){let M=e(),N=p(!1),P=p([]),F=p(0),I=p(1),L=p(null),R=p(!1),z=p(null),B=[{label:`待重试`,value:`pending`},{label:`重试中`,value:`retrying`},{label:`成功`,value:`success`},{label:`失败`,value:`failed`}],V=y([{title:`状态`,key:`status`,width:100},{title:`任务`,key:`operation`},{title:`服务器`,key:`server_name`},{title:`次数`,key:`retry_count`,width:100},{title:`下次重试`,key:`next_retry_at`,width:140},{title:`创建时间`,key:`created_at`,width:160},{title:``,key:`actions`,width:120,align:`end`}]);async function H(e=!1){e||(N.value=!0);try{let e=(await a.getList(`/retries/`,{limit:200})).items||[];L.value&&(e=e.filter(e=>e.status===L.value)),F.value=e.length;let t=(I.value-1)*20;P.value=e.slice(t,t+20)}catch(t){e||(P.value=[],F.value=0,M(t instanceof Error?t.message:`加载重试队列失败`,`error`))}finally{e||(N.value=!1)}}async function U(e){try{await a.post(`/retries/${e.id}/retry`),H(),M(`重试已触发`)}catch(e){M(e.message||`操作失败`,`error`)}}function W(e){z.value=e.id,R.value=!0}async function G(){if(z.value)try{await a.delete(`/retries/${z.value}`),R.value=!1,H(),M(`已删除`)}catch(e){M(e.message||`删除失败`,`error`)}}function K(e){return e===`success`?`success`:e===`failed`?`error`:e===`retrying`?`warning`:`info`}function q(e){return e===`pending`?`待重试`:e===`retrying`?`重试中`:e===`success`?`成功`:e===`failed`?`失败`:e}function J(e){return e.source_path&&e.target_path?`${e.source_path}${e.target_path}`:e.source_path||e.target_path||`文件推送`}return E(()=>H(!0),15e3),v(e=>H(e)),(e,a)=>(u(),f(n,{fluid:``,class:`pa-6`},{default:i(()=>[h(b,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[h(C,{class:`d-flex align-center text-h6`},{default:i(()=>[a[5]||=c(` 重试队列 `,-1),h(s),h(t,{modelValue:L.value,"onUpdate:modelValue":[a[0]||=e=>L.value=e,a[1]||=e=>{I.value=1,H()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态筛选`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},clearable:``},null,8,[`modelValue`])]),_:1}),h(w,{items:P.value,headers:r(V),"items-length":F.value,loading:N.value,page:I.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":a[2]||=e=>{I.value=e,H()}},{"item.status":i(({item:e})=>[h(g,{color:K(e.status),size:`x-small`,variant:`tonal`,label:``,border:`sm`},{default:i(()=>[c(m(q(e.status)),1)]),_:2},1032,[`color`])]),"item.operation":i(({item:e})=>[l(`span`,D,m(J(e)),1)]),"item.server_name":i(({item:e})=>[l(`span`,O,m(e.server_name||``),1)]),"item.retry_count":i(({item:e})=>[l(`span`,k,m(e.retry_count||0)+` / `+m(e.max_retries||3),1)]),"item.next_retry_at":i(({item:e})=>[l(`span`,A,m(e.next_retry_at||``),1)]),"item.created_at":i(({item:e})=>[l(`span`,j,m(e.created_at),1)]),"item.actions":i(({item:e})=>[e.status===`pending`||e.status===`failed`?(u(),f(o,{key:0,variant:`text`,size:`x-small`,color:`primary`,density:`compact`,onClick:t=>U(e)},{default:i(()=>[...a[6]||=[c(` 重试 `,-1)]]),_:1},8,[`onClick`])):d(``,!0),h(o,{variant:`text`,size:`x-small`,color:`error`,density:`compact`,onClick:t=>W(e)},{default:i(()=>[...a[7]||=[c(` 删除 `,-1)]]),_:1},8,[`onClick`])]),"no-data":i(()=>[...a[8]||=[l(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1}),h(T,{modelValue:R.value,"onUpdate:modelValue":a[4]||=e=>R.value=e,"max-width":`400`},{default:i(()=>[h(b,{border:``},{default:i(()=>[h(C,null,{default:i(()=>[...a[9]||=[c(`确认删除`,-1)]]),_:1}),h(x,null,{default:i(()=>[...a[10]||=[c(`确定要删除此重试任务吗?`,-1)]]),_:1}),h(S,null,{default:i(()=>[h(s),h(o,{variant:`text`,onClick:a[3]||=e=>R.value=!1},{default:i(()=>[...a[11]||=[c(`取消`,-1)]]),_:1}),h(o,{color:`error`,variant:`flat`,onClick:G},{default:i(()=>[...a[12]||=[c(`删除`,-1)]]),_:1})]),_:1})]),_:1})]),_:1},8,[`modelValue`])]),_:1}))}});export{M as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-rP81fnpc.js";import{$r as r,Br as i,Jt as a,P as o,_ as s,_r as c,fr as l,jr as u,mr as d,pr as f,qr as p,ri as m,vr as h,y as g,yr as _}from"./index-DAQ8Nzd7.js";import{t as v}from"./usePageActivateRefresh-hyRkArJ0.js";import{n as y}from"./dataTable-esDY4cOk.js";import{_ as b,v as x,x as S,y as C}from"./VTextField-CqnXgqAI.js";import{t as w}from"./VDataTableServer-Cvy_Dzfu.js";import{t as T}from"./VDialog-BavjfdkW.js";import{t as E}from"./usePageAutoRefresh-CR46dvMx.js";var D={class:`font-weight-medium text-truncate d-inline-block`,style:{"max-width":`240px`}},O={class:`text-medium-emphasis`},k={class:`text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j={class:`text-caption text-medium-emphasis`},M=_({name:`RetriesPage`,__name:`RetriesPage`,setup(_){let M=e(),N=p(!1),P=p([]),F=p(0),I=p(1),L=p(null),R=p(!1),z=p(null),B=[{label:`待重试`,value:`pending`},{label:`重试中`,value:`retrying`},{label:`成功`,value:`success`},{label:`失败`,value:`failed`}],V=y([{title:`状态`,key:`status`,width:100},{title:`任务`,key:`operation`},{title:`服务器`,key:`server_name`},{title:`次数`,key:`retry_count`,width:100},{title:`下次重试`,key:`next_retry_at`,width:140},{title:`创建时间`,key:`created_at`,width:160},{title:``,key:`actions`,width:120,align:`end`}]);async function H(e=!1){e||(N.value=!0);try{let e=(await a.getList(`/retries/`,{limit:200})).items||[];L.value&&(e=e.filter(e=>e.status===L.value)),F.value=e.length;let t=(I.value-1)*20;P.value=e.slice(t,t+20)}catch(t){e||(P.value=[],F.value=0,M(t instanceof Error?t.message:`加载重试队列失败`,`error`))}finally{e||(N.value=!1)}}async function U(e){try{await a.post(`/retries/${e.id}/retry`),H(),M(`重试已触发`)}catch(e){M(e.message||`操作失败`,`error`)}}function W(e){z.value=e.id,R.value=!0}async function G(){if(z.value)try{await a.delete(`/retries/${z.value}`),R.value=!1,H(),M(`已删除`)}catch(e){M(e.message||`删除失败`,`error`)}}function K(e){return e===`success`?`success`:e===`failed`?`error`:e===`retrying`?`warning`:`info`}function q(e){return e===`pending`?`待重试`:e===`retrying`?`重试中`:e===`success`?`成功`:e===`failed`?`失败`:e}function J(e){return e.source_path&&e.target_path?`${e.source_path}${e.target_path}`:e.source_path||e.target_path||`文件推送`}return E(()=>H(!0),15e3),v(e=>H(e)),(e,a)=>(u(),f(n,{fluid:``,class:`pa-6`},{default:i(()=>[h(b,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[h(C,{class:`d-flex align-center text-h6`},{default:i(()=>[a[5]||=c(` 重试队列 `,-1),h(s),h(t,{modelValue:L.value,"onUpdate:modelValue":[a[0]||=e=>L.value=e,a[1]||=e=>{I.value=1,H()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态筛选`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},clearable:``},null,8,[`modelValue`])]),_:1}),h(w,{items:P.value,headers:r(V),"items-length":F.value,loading:N.value,page:I.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":a[2]||=e=>{I.value=e,H()}},{"item.status":i(({item:e})=>[h(g,{color:K(e.status),size:`x-small`,variant:`tonal`,label:``,border:`sm`},{default:i(()=>[c(m(q(e.status)),1)]),_:2},1032,[`color`])]),"item.operation":i(({item:e})=>[l(`span`,D,m(J(e)),1)]),"item.server_name":i(({item:e})=>[l(`span`,O,m(e.server_name||``),1)]),"item.retry_count":i(({item:e})=>[l(`span`,k,m(e.retry_count||0)+` / `+m(e.max_retries||3),1)]),"item.next_retry_at":i(({item:e})=>[l(`span`,A,m(e.next_retry_at||``),1)]),"item.created_at":i(({item:e})=>[l(`span`,j,m(e.created_at),1)]),"item.actions":i(({item:e})=>[e.status===`pending`||e.status===`failed`?(u(),f(o,{key:0,variant:`text`,size:`x-small`,color:`primary`,density:`compact`,onClick:t=>U(e)},{default:i(()=>[...a[6]||=[c(` 重试 `,-1)]]),_:1},8,[`onClick`])):d(``,!0),h(o,{variant:`text`,size:`x-small`,color:`error`,density:`compact`,onClick:t=>W(e)},{default:i(()=>[...a[7]||=[c(` 删除 `,-1)]]),_:1},8,[`onClick`])]),"no-data":i(()=>[...a[8]||=[l(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1}),h(T,{modelValue:R.value,"onUpdate:modelValue":a[4]||=e=>R.value=e,"max-width":`400`},{default:i(()=>[h(b,{border:``},{default:i(()=>[h(C,null,{default:i(()=>[...a[9]||=[c(`确认删除`,-1)]]),_:1}),h(x,null,{default:i(()=>[...a[10]||=[c(`确定要删除此重试任务吗?`,-1)]]),_:1}),h(S,null,{default:i(()=>[h(s),h(o,{variant:`text`,onClick:a[3]||=e=>R.value=!1},{default:i(()=>[...a[11]||=[c(`取消`,-1)]]),_:1}),h(o,{color:`error`,variant:`flat`,onClick:G},{default:i(()=>[...a[12]||=[c(`删除`,-1)]]),_:1})]),_:1})]),_:1})]),_:1},8,[`modelValue`])]),_:1}))}});export{M as default};
+1
View File
@@ -0,0 +1 @@
import{_ as e,t,v as n}from"./VSelect-DgmpIJ0-.js";import{$r as r,Br as i,Jt as a,P as o,_ as s,_r as c,fr as l,jr as u,mr as d,pr as f,qr as p,ri as m,vr as h,y as g,yr as _}from"./index-B1boYHjE.js";import{t as v}from"./usePageActivateRefresh-85rCMLDQ.js";import{n as y}from"./dataTable-esDY4cOk.js";import{_ as b,v as x,x as S,y as C}from"./VTextField-CWk_xMst.js";import{t as w}from"./VDataTableServer-BOzWB3oR.js";import{t as T}from"./VDialog-dcF5BfXS.js";import{t as E}from"./usePageAutoRefresh-CcGvR3Vr.js";var D={class:`font-weight-medium text-truncate d-inline-block`,style:{"max-width":`240px`}},O={class:`text-medium-emphasis`},k={class:`text-medium-emphasis`},A={class:`text-caption text-medium-emphasis`},j={class:`text-caption text-medium-emphasis`},M=_({name:`RetriesPage`,__name:`RetriesPage`,setup(_){let M=e(),N=p(!1),P=p([]),F=p(0),I=p(1),L=p(null),R=p(!1),z=p(null),B=[{label:`待重试`,value:`pending`},{label:`重试中`,value:`retrying`},{label:`成功`,value:`success`},{label:`失败`,value:`failed`}],V=y([{title:`状态`,key:`status`,width:100},{title:`任务`,key:`operation`},{title:`服务器`,key:`server_name`},{title:`次数`,key:`retry_count`,width:100},{title:`下次重试`,key:`next_retry_at`,width:140},{title:`创建时间`,key:`created_at`,width:160},{title:``,key:`actions`,width:120,align:`end`}]);async function H(e=!1){e||(N.value=!0);try{let e=(await a.getList(`/retries/`,{limit:200})).items||[];L.value&&(e=e.filter(e=>e.status===L.value)),F.value=e.length;let t=(I.value-1)*20;P.value=e.slice(t,t+20)}catch(t){e||(P.value=[],F.value=0,M(t instanceof Error?t.message:`加载重试队列失败`,`error`))}finally{e||(N.value=!1)}}async function U(e){try{await a.post(`/retries/${e.id}/retry`),H(),M(`重试已触发`)}catch(e){M(e.message||`操作失败`,`error`)}}function W(e){z.value=e.id,R.value=!0}async function G(){if(z.value)try{await a.delete(`/retries/${z.value}`),R.value=!1,H(),M(`已删除`)}catch(e){M(e.message||`删除失败`,`error`)}}function K(e){return e===`success`?`success`:e===`failed`?`error`:e===`retrying`?`warning`:`info`}function q(e){return e===`pending`?`待重试`:e===`retrying`?`重试中`:e===`success`?`成功`:e===`failed`?`失败`:e}function J(e){return e.source_path&&e.target_path?`${e.source_path}${e.target_path}`:e.source_path||e.target_path||`文件推送`}return E(()=>H(!0),15e3),v(e=>H(e)),(e,a)=>(u(),f(n,{fluid:``,class:`pa-6`},{default:i(()=>[h(b,{elevation:`0`,border:``,rounded:`lg`},{default:i(()=>[h(C,{class:`d-flex align-center text-h6`},{default:i(()=>[a[5]||=c(` 重试队列 `,-1),h(s),h(t,{modelValue:L.value,"onUpdate:modelValue":[a[0]||=e=>L.value=e,a[1]||=e=>{I.value=1,H()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态筛选`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},clearable:``},null,8,[`modelValue`])]),_:1}),h(w,{items:P.value,headers:r(V),"items-length":F.value,loading:N.value,page:I.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":a[2]||=e=>{I.value=e,H()}},{"item.status":i(({item:e})=>[h(g,{color:K(e.status),size:`x-small`,variant:`tonal`,label:``,border:`sm`},{default:i(()=>[c(m(q(e.status)),1)]),_:2},1032,[`color`])]),"item.operation":i(({item:e})=>[l(`span`,D,m(J(e)),1)]),"item.server_name":i(({item:e})=>[l(`span`,O,m(e.server_name||``),1)]),"item.retry_count":i(({item:e})=>[l(`span`,k,m(e.retry_count||0)+` / `+m(e.max_retries||3),1)]),"item.next_retry_at":i(({item:e})=>[l(`span`,A,m(e.next_retry_at||``),1)]),"item.created_at":i(({item:e})=>[l(`span`,j,m(e.created_at),1)]),"item.actions":i(({item:e})=>[e.status===`pending`||e.status===`failed`?(u(),f(o,{key:0,variant:`text`,size:`x-small`,color:`primary`,density:`compact`,onClick:t=>U(e)},{default:i(()=>[...a[6]||=[c(` 重试 `,-1)]]),_:1},8,[`onClick`])):d(``,!0),h(o,{variant:`text`,size:`x-small`,color:`error`,density:`compact`,onClick:t=>W(e)},{default:i(()=>[...a[7]||=[c(` 删除 `,-1)]]),_:1},8,[`onClick`])]),"no-data":i(()=>[...a[8]||=[l(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`headers`,`items-length`,`loading`,`page`])]),_:1}),h(T,{modelValue:R.value,"onUpdate:modelValue":a[4]||=e=>R.value=e,"max-width":`400`},{default:i(()=>[h(b,{border:``},{default:i(()=>[h(C,null,{default:i(()=>[...a[9]||=[c(`确认删除`,-1)]]),_:1}),h(x,null,{default:i(()=>[...a[10]||=[c(`确定要删除此重试任务吗?`,-1)]]),_:1}),h(S,null,{default:i(()=>[h(s),h(o,{variant:`text`,onClick:a[3]||=e=>R.value=!1},{default:i(()=>[...a[11]||=[c(`取消`,-1)]]),_:1}),h(o,{color:`error`,variant:`flat`,onClick:G},{default:i(()=>[...a[12]||=[c(`删除`,-1)]]),_:1})]),_:1})]),_:1})]),_:1},8,[`modelValue`])]),_:1}))}});export{M 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
@@ -0,0 +1 @@
.cycle-type-col[data-v-f1c7b8d2]{flex:none}.cycle-type-select[data-v-f1c7b8d2]{width:7.5rem;max-width:7.5rem}.cycle-type-fixed[data-v-f1c7b8d2]{white-space:nowrap;align-items:center;height:40px;padding:0 4px;font-weight:500;display:inline-flex}.time-col[data-v-f1c7b8d2]{flex:none;width:4.5rem;max-width:4.5rem}.time-col-wide[data-v-f1c7b8d2]{flex:none;width:5.5rem;max-width:5.5rem}
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