fix(frontend): 脚本库与推送调度对齐设计文档

修复 ScriptsPage 执行契约(script_id/command、历史过滤、长任务/凭据)及 SchedulesPage 缺失能力(target_path、next_run、push/script、cron/once、sync_mode);后端补迁移与 schedule_runner 传参。
This commit is contained in:
Nexus Agent
2026-06-08 02:39:18 +08:00
parent f12a0b6a36
commit dfb0ea2d8f
167 changed files with 4182 additions and 227 deletions
@@ -0,0 +1,44 @@
# 2026-06-07 — 推送调度对齐设计文档
## 摘要
修复推送调度 SPA 与后端契约断裂:`target_path` 未持久化、`schedule_runner` 未传递目标路径、`next_run` 恒为空;补全调度类型(push/script)、运行模式(cron/once)、同步模式与脚本调度 UI。
## 动机
- 前端表单有「目标路径」但未提交,DB 无 `target_path` 列,`runNow` 错误默认 `/tmp`
- 设计文档(附录 E.1)要求 source/target + sync_mode 或 script_id,旧版 SPA 仅支持 cron 推送
- 表格「下次运行」无 API 计算,用户无法判断调度是否生效
## 涉及文件
| 层 | 文件 |
|----|------|
| 模型 | `server/domain/models/__init__.py``PushSchedule.target_path` |
| 迁移 | `server/infrastructure/database/migrations.py`, `server/api/install.py` |
| Schema | `server/api/schemas.py``ScheduleCreate/Update.target_path` |
| API | `server/api/settings.py``_schedule_to_dict` + `next_run` |
| Runner | `server/background/schedule_runner.py` — 传 `target_path``compute_schedule_next_run` |
| 前端 | `frontend/src/pages/SchedulesPage.vue`, `frontend/src/types/api.ts` |
| 测试 | `tests/test_schedule_next_run.py` |
## 是否需迁移/重启
- **是**`push_schedules.target_path` 列(启动时 `run_schema_migrations` 自动 ADD
- **需重启 API** 以加载新代码;前端需 `vite build` 后部署
## 验证方式
```bash
bash scripts/local_verify.sh
python -m pytest tests/test_schedule_next_run.py tests/test_schedule_runner_once.py -q
```
- 新建 cron 推送调度,填写可选目标路径 → 列表显示 target_path、next_run
- `runNow` 留空目标路径 → 走各机 `servers.target_path`(与推送页一致)
- 新建 script 调度 → `schedule_runner` 调 ScriptService
## 行为说明
- **目标路径留空**:与推送页相同,各服务器使用「服务器管理」中的 `target_path`;未配置则 sync 引擎 fallback `/tmp/sync`
- **一次性调度**`fire_at` 到期后 runner 执行一次并 `enabled=false`;失败时 rollback 恢复 enabled
@@ -0,0 +1,45 @@
# Changelog — 2026-06-07 脚本库 SPA 对齐设计文档
## 摘要
修复脚本库前后端多处契约断裂:库内脚本执行不传 command、分类校验失败、执行历史无法按 script_id 过滤、执行状态/重试/长任务/DB 凭据等设计能力在 SPA 缺失。
## 动机
用户反馈脚本库「大量问题」;对照 `docs/project/script-execution.md``ScriptsPage.vue` 发现执行链路几乎不可用(422/tracking id 错误),且 UI 未覆盖长任务、凭据、停止/重试/详情等 SSOT 能力。
## 变更
### 后端
- `ScriptExecute``command``script_id` 二选一;API 按 `script_id` 加载脚本内容
- `GET /api/scripts/executions?script_id=` 过滤单脚本历史
- 创建脚本时自动写入 `created_by`
### 前端
- 新建 `ScriptContentEditor.vue`Monaco shell 编辑)
- 重写 `ScriptsPage.vue`:分类下拉、exec-config 提示、长任务/DB 凭据、执行状态条(10s 轮询)、停止/重试/标记卡住、历史与详情(含长任务拉日志)
- 修正 `ScriptItem` / `ScriptExecItem` / `DbCredentialItem` 类型
## 涉及文件
- `server/api/schemas.py`, `server/api/scripts.py`
- `server/application/services/script_service.py`
- `server/infrastructure/database/script_repo.py`
- `frontend/src/pages/ScriptsPage.vue`
- `frontend/src/components/ScriptContentEditor.vue`
- `frontend/src/types/api.ts`
## 迁移 / 重启
- 需部署后端 + 前端构建
- 无 DB 迁移
## 验证
```bash
cd frontend && npx vite build
# 脚本库:新建(ops 分类) → 选服务器执行 → 状态条出现 #id
# 历史对话框仅显示该脚本记录;失败可重试;长任务可勾选
```
@@ -0,0 +1,74 @@
<template>
<div ref="host" class="script-content-editor" />
</template>
<script setup lang="ts">
import { ref, watch, onMounted, onBeforeUnmount } from 'vue'
import { buildMonacoEditorOptions, initMonaco } from '@/monaco/initMonaco'
import type * as Monaco from 'monaco-editor'
const props = defineProps<{
modelValue: string
readonly?: boolean
}>()
const emit = defineEmits<{
'update:modelValue': [value: string]
}>()
const monaco = initMonaco()
const host = ref<HTMLElement>()
let editor: Monaco.editor.IStandaloneCodeEditor | null = null
let syncing = false
function bindEditor() {
if (!host.value) return
editor?.dispose()
editor = monaco.editor.create(host.value, {
...buildMonacoEditorOptions({ language: 'shell', readOnly: props.readonly ?? false }),
value: props.modelValue || '',
})
editor.onDidChangeModelContent(() => {
if (syncing || !editor) return
emit('update:modelValue', editor.getValue())
})
}
watch(
() => props.modelValue,
(val) => {
if (!editor) return
const current = editor.getValue()
if (current === val) return
syncing = true
editor.setValue(val || '')
syncing = false
},
)
watch(
() => props.readonly,
(ro) => {
editor?.updateOptions({ readOnly: ro ?? false })
},
)
onMounted(() => {
bindEditor()
})
onBeforeUnmount(() => {
editor?.dispose()
editor = null
})
</script>
<style scoped>
.script-content-editor {
height: 360px;
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
border-radius: 8px;
overflow: hidden;
}
</style>
+268 -50
View File
@@ -19,6 +19,28 @@
@update:page="onPageChange"
@update:items-per-page="onItemsPerPageChange"
>
<template #item.schedule_type="{ item }">
<v-chip size="small" variant="tonal" :color="item.schedule_type === 'script' ? 'secondary' : 'primary'" label>
{{ item.schedule_type === 'script' ? '脚本' : '推送' }}
</v-chip>
</template>
<template #item.run_mode="{ item }">
<span class="text-caption">{{ item.run_mode === 'once' ? '一次性' : 'Cron' }}</span>
</template>
<template #item.cron_expr="{ item }">
<v-chip v-if="item.run_mode === 'cron'" size="small" variant="tonal" label prepend-icon="mdi-clock-outline">
{{ item.cron_expr || '' }}
</v-chip>
<span v-else class="text-caption text-medium-emphasis">{{ formatFireAt(item.fire_at) }}</span>
</template>
<template #item.sync_mode="{ item }">
<span v-if="item.schedule_type !== 'script'" class="text-caption">{{ syncModeLabel(item.sync_mode) }}</span>
<span v-else class="text-caption text-medium-emphasis"></span>
</template>
<template #item.enabled="{ item }">
<v-switch
v-model="item.enabled"
@@ -30,12 +52,6 @@
/>
</template>
<template #item.cron_expr="{ item }">
<v-chip size="small" variant="tonal" label prepend-icon="mdi-clock-outline">
{{ item.cron_expr || '—' }}
</v-chip>
</template>
<template #item.server_count="{ item }">
<span class="text-medium-emphasis">{{ serverIdCount(item.server_ids) }} </span>
</template>
@@ -59,15 +75,99 @@
</v-data-table-server>
</v-card>
<!-- Editor Dialog -->
<v-dialog v-model="showEditor" max-width="600">
<v-dialog v-model="showEditor" max-width="640" scrollable>
<v-card border>
<v-card-title>{{ editingSchedule ? '编辑调度' : '新建调度' }}</v-card-title>
<v-card-text>
<v-text-field v-model="form.name" label="调度名称" variant="outlined" density="compact" class="mb-2" />
<v-text-field v-model="form.cron" label="Cron 表达式" variant="outlined" density="compact" hint="例如: */30 * * * *" persistent-hint class="mb-2" />
<v-text-field v-model="form.source_path" label="推送源路径" variant="outlined" density="compact" class="mb-2" />
<v-text-field v-model="form.target_path" label="目标路径" variant="outlined" density="compact" class="mb-2" />
<v-btn-toggle v-model="form.schedule_type" mandatory density="compact" class="mb-3" color="primary">
<v-btn value="push" size="small">文件推送</v-btn>
<v-btn value="script" size="small">脚本执行</v-btn>
</v-btn-toggle>
<v-btn-toggle v-model="form.run_mode" mandatory density="compact" class="mb-3" color="primary">
<v-btn value="cron" size="small">Cron 循环</v-btn>
<v-btn value="once" size="small">一次性</v-btn>
</v-btn-toggle>
<v-text-field
v-if="form.run_mode === 'cron'"
v-model="form.cron"
label="Cron 表达式(5 字段)"
variant="outlined"
density="compact"
hint="分 时 日 月 周,例如: 0 2 * * *"
persistent-hint
class="mb-2"
/>
<v-text-field
v-else
v-model="form.fire_at"
label="执行时间"
type="datetime-local"
variant="outlined"
density="compact"
class="mb-2"
/>
<template v-if="form.schedule_type === 'push'">
<v-text-field v-model="form.source_path" label="推送源路径(Nexus 主机)" variant="outlined" density="compact" class="mb-2" />
<v-text-field
v-model="form.target_path"
label="目标路径(可选)"
variant="outlined"
density="compact"
hint="留空则使用各服务器在「服务器管理」中配置的目标路径"
persistent-hint
class="mb-2"
/>
<v-select
v-model="form.sync_mode"
:items="syncModeOptions"
item-title="label"
item-value="value"
label="同步模式"
variant="outlined"
density="compact"
class="mb-2"
/>
</template>
<template v-else>
<v-select
v-model="form.script_id"
:items="scriptList"
item-title="name"
item-value="id"
label="脚本库(可选)"
variant="outlined"
density="compact"
clearable
class="mb-2"
/>
<v-textarea
v-model="form.script_content"
label="命令内容(无脚本库时必填)"
variant="outlined"
density="compact"
rows="4"
auto-grow
class="mb-2"
/>
<v-text-field
v-model.number="form.exec_timeout"
label="超时(秒)"
type="number"
min="10"
max="600"
variant="outlined"
density="compact"
class="mb-2"
/>
<v-switch v-model="form.long_task" label="长任务(nohup" color="primary" density="compact" hide-details class="mb-2" />
</template>
<v-select
v-model="form.server_ids"
:items="serverList"
@@ -90,7 +190,6 @@
</v-card>
</v-dialog>
<!-- Delete Confirm -->
<v-dialog v-model="showDelete" max-width="400">
<v-card border>
<v-card-title>确认删除</v-card-title>
@@ -110,40 +209,59 @@ import { ref, onMounted } from 'vue'
import { http } from '@/api'
import { useServerList } from '@/composables/useServerList'
import { useSnackbar } from '@/composables/useSnackbar'
import type { ScheduleItem } from '@/types/api'
import type { ScheduleItem, ScriptItem } from '@/types/api'
const snackbar = useSnackbar()
const { servers: serverList, loadServers } = useServerList()
// ── State ──
const syncModeOptions = [
{ value: 'incremental', label: '增量' },
{ value: 'full', label: '完全同步' },
{ value: 'overwrite', label: '覆盖' },
{ value: 'checksum', label: '校验和' },
]
const loading = ref(false)
const togglingId = ref<number | null>(null)
const runningId = ref<number | null>(null)
const schedules = ref<ScheduleItem[]>([])
const scriptList = ref<ScriptItem[]>([])
// Pagination
const page = ref(1)
const totalItems = ref(0)
const itemsPerPage = ref(20)
// Editor
const showEditor = ref(false)
const editingSchedule = ref<ScheduleItem | null>(null)
const saving = ref(false)
const form = ref({
name: '', cron: '', source_path: '', target_path: '',
server_ids: [] as number[], enabled: true,
name: '',
schedule_type: 'push' as 'push' | 'script',
run_mode: 'cron' as 'cron' | 'once',
cron: '',
fire_at: '',
source_path: '',
target_path: '',
sync_mode: 'incremental' as string,
script_id: null as number | null,
script_content: '',
exec_timeout: 60,
long_task: false,
server_ids: [] as number[],
enabled: true,
})
// Delete
const showDelete = ref(false)
const deletingSchedule = ref<ScheduleItem | null>(null)
const headers = [
{ title: '名称', key: 'name' },
{ title: 'Cron', key: 'cron_expr', width: 160 },
{ title: '类型', key: 'schedule_type', width: 80 },
{ title: '模式', key: 'run_mode', width: 72 },
{ title: 'Cron / 执行时间', key: 'cron_expr', width: 160 },
{ title: '源路径', key: 'source_path' },
{ title: '目标路径', key: 'target_path' },
{ title: '同步', key: 'sync_mode', width: 88 },
{ title: '服务器', key: 'server_count', width: 80 },
{ title: '上次运行', key: 'last_run_at', width: 140 },
{ title: '下次运行', key: 'next_run', width: 140 },
@@ -151,6 +269,23 @@ const headers = [
{ title: '操作', key: 'actions', width: 200, align: 'end' as const },
]
function syncModeLabel(mode?: string): string {
return syncModeOptions.find((o) => o.value === mode)?.label || mode || '增量'
}
function formatFireAt(raw: string | null | undefined): string {
if (!raw) return '—'
return raw.replace('T', ' ').slice(0, 16)
}
function toDatetimeLocalValue(raw: string | null | undefined): string {
if (!raw) return ''
const d = new Date(raw)
if (Number.isNaN(d.getTime())) return raw.slice(0, 16)
const pad = (n: number) => String(n).padStart(2, '0')
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`
}
function parseServerIds(raw: unknown): number[] {
if (Array.isArray(raw)) return raw.map((x) => Number(x)).filter((n) => !Number.isNaN(n))
if (typeof raw === 'string' && raw.trim()) {
@@ -170,23 +305,51 @@ function normalizeSchedule(row: ScheduleItem): ScheduleItem {
return { ...row, server_ids: parseServerIds(row.server_ids) }
}
function buildSchedulePayload() {
function validateCron(expr: string): boolean {
const parts = expr.trim().split(/\s+/)
if (parts.length !== 5) return false
return parts.every((p) => /^[\d*/,\-]+$/.test(p))
}
function buildSchedulePayload(): Record<string, unknown> {
const ids = form.value.server_ids
if (!form.value.name.trim()) throw new Error('请填写调度名称')
if (!form.value.cron.trim()) throw new Error('请填写 Cron 表达式')
if (!/^[\d\s*/,\-]+$/.test(form.value.cron.trim())) throw new Error('Cron 表达式格式不正确')
if (!ids.length) throw new Error('请至少选择一台服务器')
if (!form.value.source_path.trim()) throw new Error('请填写推送源路径')
return {
const payload: Record<string, unknown> = {
name: form.value.name.trim(),
cron_expr: form.value.cron.trim(),
source_path: form.value.source_path.trim(),
schedule_type: form.value.schedule_type,
run_mode: form.value.run_mode,
server_ids: JSON.stringify(ids),
run_mode: 'cron' as const,
schedule_type: 'push' as const,
enabled: form.value.enabled,
sync_mode: 'incremental',
}
if (form.value.run_mode === 'cron') {
if (!form.value.cron.trim()) throw new Error('请填写 Cron 表达式')
if (!validateCron(form.value.cron.trim())) throw new Error('Cron 须为 5 字段(分 时 日 月 周)')
payload.cron_expr = form.value.cron.trim()
} else {
if (!form.value.fire_at) throw new Error('请选择一次性执行时间')
payload.fire_at = new Date(form.value.fire_at).toISOString()
}
if (form.value.schedule_type === 'push') {
if (!form.value.source_path.trim()) throw new Error('请填写推送源路径')
payload.source_path = form.value.source_path.trim()
const tp = form.value.target_path.trim()
if (tp) payload.target_path = tp
payload.sync_mode = form.value.sync_mode
} else {
if (!form.value.script_id && !form.value.script_content.trim()) {
throw new Error('脚本调度须选择脚本库或填写命令内容')
}
if (form.value.script_id) payload.script_id = form.value.script_id
if (form.value.script_content.trim()) payload.script_content = form.value.script_content.trim()
payload.exec_timeout = form.value.exec_timeout
payload.long_task = form.value.long_task
}
return payload
}
function onPageChange(p: number) {
@@ -200,7 +363,15 @@ function onItemsPerPageChange(n: number) {
loadSchedules()
}
// ── Data loading ──
async function loadScripts() {
try {
const res = await http.getList<ScriptItem>('/scripts/')
scriptList.value = res.items || []
} catch {
scriptList.value = []
}
}
async function loadSchedules() {
loading.value = true
try {
@@ -213,21 +384,47 @@ async function loadSchedules() {
schedules.value = []
totalItems.value = 0
snackbar(e instanceof Error ? e.message : '加载调度列表失败', 'error')
} finally {
loading.value = false
}
finally { loading.value = false }
}
// ── Actions ──
function openEditor(schedule: ScheduleItem | null) {
editingSchedule.value = schedule
if (schedule) {
form.value = {
name: schedule.name, cron: schedule.cron_expr || '', source_path: schedule.source_path || '',
target_path: schedule.target_path || '', server_ids: parseServerIds(schedule.server_ids),
name: schedule.name,
schedule_type: (schedule.schedule_type === 'script' ? 'script' : 'push'),
run_mode: (schedule.run_mode === 'once' ? 'once' : 'cron'),
cron: schedule.cron_expr || '',
fire_at: toDatetimeLocalValue(schedule.fire_at),
source_path: schedule.source_path || '',
target_path: schedule.target_path || '',
sync_mode: schedule.sync_mode || 'incremental',
script_id: schedule.script_id ?? null,
script_content: schedule.script_content || '',
exec_timeout: schedule.exec_timeout ?? 60,
long_task: !!schedule.long_task,
server_ids: parseServerIds(schedule.server_ids),
enabled: schedule.enabled,
}
} else {
form.value = { name: '', cron: '', source_path: '', target_path: '', server_ids: [], enabled: true }
form.value = {
name: '',
schedule_type: 'push',
run_mode: 'cron',
cron: '',
fire_at: '',
source_path: '',
target_path: '',
sync_mode: 'incremental',
script_id: null,
script_content: '',
exec_timeout: 60,
long_task: false,
server_ids: [],
enabled: true,
}
}
showEditor.value = true
}
@@ -241,17 +438,21 @@ async function saveSchedule() {
showEditor.value = false
loadSchedules()
snackbar('保存成功')
} catch (e: any) { snackbar(e.message || '保存失败', 'error') }
finally { saving.value = false }
} catch (e: unknown) {
snackbar(e instanceof Error ? e.message : '保存失败', 'error')
} finally {
saving.value = false
}
}
async function toggleEnabled(item: ScheduleItem) {
togglingId.value = item.id
try {
await http.put(`/schedules/${item.id}`, { enabled: item.enabled })
} catch (e: any) {
loadSchedules()
} catch (e: unknown) {
item.enabled = !item.enabled
snackbar(e.message || '操作失败', 'error')
snackbar(e instanceof Error ? e.message : '操作失败', 'error')
} finally {
togglingId.value = null
}
@@ -260,14 +461,29 @@ async function toggleEnabled(item: ScheduleItem) {
async function runNow(item: ScheduleItem) {
runningId.value = item.id
try {
await http.post('/sync/files', {
source_path: item.source_path,
target_path: item.target_path || '/tmp',
server_ids: parseServerIds(item.server_ids),
})
snackbar('已触发推送')
} catch (e: any) { snackbar(e.message || '执行失败', 'error') }
finally {
const serverIds = parseServerIds(item.server_ids)
if (item.schedule_type === 'script') {
await http.post('/scripts/exec', {
server_ids: serverIds,
script_id: item.script_id ?? undefined,
command: item.script_content || undefined,
timeout: item.exec_timeout ?? 60,
long_task: !!item.long_task,
})
snackbar('已触发脚本执行')
} else {
const body: Record<string, unknown> = {
source_path: item.source_path,
server_ids: serverIds,
sync_mode: item.sync_mode || 'incremental',
}
if (item.target_path?.trim()) body.target_path = item.target_path.trim()
await http.post('/sync/files', body)
snackbar('已触发推送')
}
} catch (e: unknown) {
snackbar(e instanceof Error ? e.message : '执行失败', 'error')
} finally {
runningId.value = null
}
}
@@ -284,12 +500,14 @@ async function doDelete() {
showDelete.value = false
loadSchedules()
snackbar('已删除')
} catch (e: any) { snackbar(e.message || '删除失败', 'error') }
} catch (e: unknown) {
snackbar(e instanceof Error ? e.message : '删除失败', 'error')
}
}
onMounted(() => {
loadSchedules()
loadServers()
loadScripts()
})
</script>
+539 -159
View File
@@ -2,8 +2,11 @@
<v-container fluid class="pa-6">
<!-- Toolbar -->
<v-card elevation="0" border rounded="lg" class="mb-4">
<v-card-title class="d-flex align-center">
<v-card-title class="d-flex flex-wrap align-center ga-2">
脚本库
<v-chip v-if="execConfig" size="small" variant="tonal" label class="ml-1">
分批 {{ execConfig.batch_size }} · 并发 {{ execConfig.concurrency }}
</v-chip>
<v-spacer />
<v-text-field
v-model="search"
@@ -15,13 +18,13 @@
rounded
style="max-width: 240px"
/>
<v-btn color="primary" variant="flat" class="ml-3" prepend-icon="mdi-plus" size="small" @click="openEditor(null)">
<v-btn color="primary" variant="flat" class="ml-1" prepend-icon="mdi-plus" size="small" @click="openEditor(null)">
新建脚本
</v-btn>
</v-card-title>
</v-card>
<!-- Quick Execute Panel -->
<!-- Quick Execute -->
<v-card elevation="0" border rounded="lg" class="mb-4">
<v-card-title class="d-flex align-center" style="cursor: pointer" @click="showQuickExec = !showQuickExec">
<v-icon class="mr-2">mdi-console</v-icon>
@@ -40,12 +43,12 @@
density="compact"
rows="3"
placeholder="输入要执行的命令... (Ctrl+Enter 执行)"
class="mb-3"
class="mb-3 font-monospace"
@keydown.ctrl.enter="doQuickExec"
:rules="[required('命令')]"
/>
<v-row dense>
<v-col cols="12" md="6">
<v-col cols="12" md="5">
<v-select
v-model="quickServerIds"
:items="serverList"
@@ -59,11 +62,38 @@
closable-chips
/>
</v-col>
<v-col cols="6" md="3">
<v-text-field v-model.number="quickTimeout" label="超时(秒)" variant="outlined" density="compact" type="number" />
<v-col cols="6" md="2">
<v-text-field
v-model.number="quickTimeout"
label="超时(秒)"
variant="outlined"
density="compact"
type="number"
:max="execConfig?.max_timeout ?? 600"
/>
</v-col>
<v-col cols="6" md="3" class="d-flex align-center">
<v-btn color="primary" variant="flat" @click="doQuickExec" :loading="quickExecuting" :disabled="!quickCommand || quickServerIds.length === 0">
<v-col cols="6" md="3">
<v-select
v-model="quickCredentialId"
:items="credentialOptions"
item-title="title"
item-value="value"
label="DB 凭据(可选)"
variant="outlined"
density="compact"
clearable
hide-details
/>
</v-col>
<v-col cols="12" md="2" class="d-flex align-center ga-2">
<v-switch v-model="quickLongTask" label="长任务" density="compact" hide-details color="primary" />
<v-btn
color="primary"
variant="flat"
@click="doQuickExec"
:loading="quickExecuting"
:disabled="!quickCommand.trim() || quickServerIds.length === 0"
>
执行
</v-btn>
</v-col>
@@ -75,8 +105,8 @@
<!-- Script Grid -->
<v-progress-linear v-if="loading" indeterminate color="primary" />
<v-row>
<v-col cols="12" sm="6" md="4" v-for="script in filteredScripts" :key="script.id">
<v-row v-if="pagedScripts.length">
<v-col cols="12" sm="6" md="4" v-for="script in pagedScripts" :key="script.id">
<v-card elevation="0" border rounded="lg" class="fill-height">
<v-card-title class="d-flex align-center">
<v-icon color="primary" class="mr-2">mdi-code-braces</v-icon>
@@ -100,31 +130,42 @@
</v-menu>
</v-card-title>
<v-card-text>
<v-chip v-if="script.category" size="small" variant="tonal" label class="mb-2">{{ script.category }}</v-chip>
<v-chip v-if="script.category" size="small" variant="tonal" label class="mb-2">
{{ categoryLabel(script.category) }}
</v-chip>
<div class="text-body-2 text-medium-emphasis">{{ script.description || '无描述' }}</div>
<div class="text-caption text-medium-emphasis mt-2">
更新于 {{ script.updated_at || script.created_at }}
更新于 {{ script.updated_at || script.created_at || '—' }}
</div>
</v-card-text>
<v-card-actions>
<v-btn size="small" variant="tonal" prepend-icon="mdi-play" color="primary" @click="runScript(script)">执行</v-btn>
<v-btn size="small" variant="tonal" prepend-icon="mdi-play" color="primary" @click="runScript(script)">
执行
</v-btn>
<v-spacer />
<v-btn size="small" variant="text" @click="viewHistory(script)">历史</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
<v-card v-else-if="!loading" elevation="0" border rounded="lg">
<v-card-text class="text-center text-medium-emphasis py-10">暂无脚本点击新建脚本添加</v-card-text>
</v-card>
<!-- Pagination -->
<div v-if="totalItems > itemsPerPage" class="d-flex justify-center mt-4">
<v-pagination v-model="page" :length="Math.ceil(totalItems / itemsPerPage)" rounded density="compact" @update:model-value="loadScripts" />
<v-pagination
v-model="page"
:length="Math.ceil(totalItems / itemsPerPage)"
rounded
density="compact"
/>
</div>
<!-- Execution Status Panel -->
<v-card v-if="trackedExecs.length > 0" elevation="0" border rounded="lg" class="mt-4">
<v-card-title class="d-flex align-center text-subtitle-1">
<v-icon class="mr-2">mdi-progress-clock</v-icon>
执行状态
批量执行状态
<v-spacer />
<v-btn size="small" variant="text" @click="trackedExecs = []">清除</v-btn>
</v-card-title>
@@ -133,19 +174,47 @@
<v-list density="compact">
<v-list-item v-for="exec in trackedExecs" :key="exec.id" :title="exec.name">
<template #subtitle>
<span class="text-caption">ID: {{ exec.id }} · {{ exec.totalServers }} 台服务器</span>
<span class="text-caption">
#{{ exec.id }} · {{ exec.progress || '—' }} · {{ exec.totalServers }}
<span v-if="exec.longTask" class="ml-1">· 长任务</span>
</span>
</template>
<template #append>
<div class="d-flex align-center ga-2">
<div class="d-flex align-center flex-wrap ga-1 justify-end">
<v-chip :color="execStatusColor(exec.status)" size="x-small" variant="tonal" label>
{{ execStatusLabel(exec.status) }}
</v-chip>
<v-btn size="x-small" variant="text" @click="openExecDetail(exec.id)">详情</v-btn>
<v-btn size="x-small" variant="text" @click="refreshExecStatus(exec)" :loading="exec.refreshing">
刷新
</v-btn>
<v-btn v-if="exec.status === 'running'" size="x-small" variant="text" color="error" @click="stopExec(exec)">
<v-btn
v-if="exec.status === 'running'"
size="x-small"
variant="text"
color="warning"
@click="markExecStuck(exec)"
>
卡住
</v-btn>
<v-btn
v-if="exec.status === 'running' || exec.status === 'partial'"
size="x-small"
variant="text"
color="error"
@click="stopExec(exec)"
>
停止
</v-btn>
<v-btn
v-if="exec.status === 'failed' || exec.status === 'partial'"
size="x-small"
variant="text"
color="primary"
@click="retryExec(exec)"
>
重试
</v-btn>
</div>
</template>
</v-list-item>
@@ -153,36 +222,40 @@
</v-card-text>
</v-card>
<!-- Script Editor Dialog -->
<v-dialog v-model="showEditor" max-width="800" scrollable>
<!-- Editor Dialog -->
<v-dialog v-model="showEditor" max-width="900" scrollable>
<v-card border>
<v-card-title>{{ editingScript ? '编辑脚本' : '新建脚本' }}</v-card-title>
<v-divider />
<v-card-text>
<v-text-field v-model="form.name" label="脚本名称" variant="outlined" density="compact" class="mb-2" :rules="[required('脚本名称')]" />
<v-text-field v-model="form.category" label="分类" variant="outlined" density="compact" class="mb-2" />
<v-textarea v-model="form.description" label="描述" variant="outlined" density="compact" rows="2" class="mb-2" />
<v-textarea
v-model="form.content"
label="脚本内容"
<v-select
v-model="form.category"
:items="categoryOptions"
item-title="label"
item-value="value"
label="分类"
variant="outlined"
density="compact"
rows="14"
class="mt-2 font-monospace"
:rules="[required('脚本内容')]"
class="mb-2"
/>
<v-textarea v-model="form.description" label="描述" variant="outlined" density="compact" rows="2" class="mb-2" />
<div class="text-caption text-medium-emphasis mb-1">脚本内容</div>
<ScriptContentEditor v-model="form.content" />
</v-card-text>
<v-divider />
<v-card-actions>
<v-spacer />
<v-btn variant="text" @click="showEditor = false">取消</v-btn>
<v-btn color="primary" variant="flat" @click="saveScript" :loading="saving">保存</v-btn>
<v-btn color="primary" variant="flat" @click="saveScript" :loading="saving" :disabled="!form.content.trim()">
保存
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- Run Script Dialog -->
<v-dialog v-model="showRun" max-width="600">
<!-- Run Dialog -->
<v-dialog v-model="showRun" max-width="640">
<v-card border>
<v-card-title>执行脚本: {{ runningScript?.name }}</v-card-title>
<v-card-text>
@@ -198,12 +271,38 @@
chips
class="mb-2"
/>
<v-text-field v-model="runTimeout" label="超时(秒)" variant="outlined" density="compact" type="number" />
<v-row dense>
<v-col cols="6">
<v-text-field
v-model.number="runTimeout"
label="超时(秒)"
variant="outlined"
density="compact"
type="number"
:max="execConfig?.max_timeout ?? 600"
/>
</v-col>
<v-col cols="6">
<v-select
v-model="runCredentialId"
:items="credentialOptions"
item-title="title"
item-value="value"
label="DB 凭据(可选)"
variant="outlined"
density="compact"
clearable
/>
</v-col>
</v-row>
<v-switch v-model="runLongTask" label="长任务(nohup + Agent 回调,适合超时较长的脚本)" density="compact" color="primary" />
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn variant="text" @click="showRun = false">取消</v-btn>
<v-btn color="primary" variant="flat" @click="doRun" :loading="executing">执行</v-btn>
<v-btn color="primary" variant="flat" @click="doRun" :loading="executing" :disabled="!runServerIds.length">
执行
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
@@ -221,179 +320,337 @@
</v-card>
</v-dialog>
<!-- Execution History Dialog -->
<v-dialog v-model="showHistory" max-width="800" scrollable>
<!-- History Dialog -->
<v-dialog v-model="showHistory" max-width="960" scrollable>
<v-card border>
<v-card-title>执行历史: {{ historyScript?.name }}</v-card-title>
<v-card-title class="d-flex align-center">
执行历史: {{ historyScript?.name }}
<v-spacer />
<v-btn size="small" variant="text" icon="mdi-refresh" @click="historyScript && viewHistory(historyScript)" />
</v-card-title>
<v-divider />
<v-card-text>
<v-data-table
:items="execHistory"
:headers="execHeaders"
density="compact"
hover
>
<v-data-table :items="execHistory" :headers="execHeaders" density="compact" hover>
<template #item.status="{ item }">
<v-chip :color="item.status === 'completed' ? 'success' : item.status === 'failed' ? 'error' : 'info'" size="small" variant="tonal" label>
{{ item.status }}
<v-chip :color="execStatusColor(item.status)" size="x-small" variant="tonal" label>
{{ execStatusLabel(item.status) }}
</v-chip>
</template>
<template #item.command="{ item }">
<code class="text-body-2">{{ item.command.length > 60 ? item.command.slice(0, 60) + '…' : item.command }}</code>
<code class="text-body-2">{{ truncateCommand(item.command) }}</code>
</template>
<template #item.progress="{ item }">
<span v-if="item.progress">{{ item.progress.done }}/{{ item.progress.total }}</span>
<span v-else class="text-medium-emphasis"></span>
<span>{{ formatProgress(item.progress) }}</span>
</template>
<template #item.actions="{ item }">
<v-btn size="x-small" variant="text" @click="openExecDetail(item.id)">详情</v-btn>
<v-btn
v-if="item.status === 'running' || item.status === 'partial'"
size="x-small"
variant="text"
color="error"
@click="stopHistoryExec(item)"
>
停止
</v-btn>
<v-btn
v-if="item.status === 'failed' || item.status === 'partial'"
size="x-small"
variant="text"
color="primary"
@click="retryHistoryExec(item)"
>
重试
</v-btn>
</template>
<template #no-data>
<div class="text-center text-medium-emphasis py-6">暂无数据</div>
<div class="text-center text-medium-emphasis py-6">暂无执行记录</div>
</template>
</v-data-table>
</v-card-text>
</v-card>
</v-dialog>
<!-- Execution Detail Dialog -->
<v-dialog v-model="showExecDetail" max-width="900" scrollable>
<v-card border>
<v-card-title class="d-flex align-center">
执行详情 #{{ execDetail?.id }}
<v-spacer />
<v-btn
v-if="execDetail?.long_task"
size="small"
variant="tonal"
:loading="detailLoading"
@click="loadExecDetail(true)"
>
拉取日志
</v-btn>
</v-card-title>
<v-divider />
<v-card-text v-if="execDetail">
<div class="text-caption text-medium-emphasis mb-3">
{{ execStatusLabel(execDetail.status) }} · {{ formatProgress(execDetail.progress) }}
· 操作人 {{ execDetail.operator || '—' }}
</div>
<pre class="text-body-2 mb-4 pa-3 rounded bg-surface-variant overflow-auto" style="max-height: 120px">{{ execDetail.command }}</pre>
<v-table density="compact">
<thead>
<tr>
<th>服务器</th>
<th>状态</th>
<th>退出码</th>
<th>输出摘要</th>
</tr>
</thead>
<tbody>
<tr v-for="row in execDetailRows" :key="row.serverId">
<td>#{{ row.serverId }}</td>
<td>{{ row.status }}</td>
<td>{{ row.exitCode ?? '—' }}</td>
<td class="text-truncate" style="max-width: 360px">{{ row.summary }}</td>
</tr>
</tbody>
</v-table>
</v-card-text>
<v-card-actions v-if="execDetail">
<v-spacer />
<v-btn variant="text" @click="showExecDetail = false">关闭</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-container>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
import ScriptContentEditor from '@/components/ScriptContentEditor.vue'
import { http } from '@/api'
import { useServerList } from '@/composables/useServerList'
import { useSnackbar } from '@/composables/useSnackbar'
import { formatApiError } from '@/utils/apiError'
import { required } from '@/utils/validation'
import type { DbCredentialItem, ScriptExecItem, ScriptItem } from '@/types/api'
const snackbar = useSnackbar()
const { servers: serverList, loadServers } = useServerList()
// ── State ──
const categoryOptions = [
{ label: '运维', value: 'ops' },
{ label: '部署', value: 'deploy' },
{ label: '检查', value: 'check' },
{ label: '清理', value: 'cleanup' },
]
interface ExecConfig {
batch_size: number
concurrency: number
max_timeout: number
}
interface TrackedExec {
id: number
name: string
status: string
totalServers: number
progress: string
longTask: boolean
refreshing: boolean
}
interface ExecDetailRow {
serverId: string
status: string
exitCode: number | null
summary: string
}
const loading = ref(false)
const search = ref('')
const scripts = ref<ScriptItem[]>([])
const execConfig = ref<ExecConfig | null>(null)
const credentials = ref<DbCredentialItem[]>([])
// Pagination
const page = ref(1)
const totalItems = ref(0)
const itemsPerPage = ref(20)
// Editor
const showEditor = ref(false)
const editingScript = ref<ScriptItem | null>(null)
const saving = ref(false)
const form = ref({ name: '', category: '', description: '', content: '' })
const form = ref({ name: '', category: 'ops', description: '', content: '' })
// Run
const showRun = ref(false)
const runningScript = ref<ScriptItem | null>(null)
const runServerIds = ref<number[]>([])
const runTimeout = ref(300)
const runLongTask = ref(false)
const runCredentialId = ref<number | null>(null)
const executing = ref(false)
// Delete
const showDelete = ref(false)
const deletingScript = ref<ScriptItem | null>(null)
// History
const showHistory = ref(false)
const historyScript = ref<ScriptItem | null>(null)
interface ExecHistoryItem {
id: number
script_id: number
command: string
server_ids: string
status: string
results: Record<string, { status?: string; output?: string; exit_code?: number }>
events: Array<{ event: string; ts: string }>
operator: string | null
started_at: string | null
completed_at: string | null
long_task?: boolean
progress?: { total: number; done: number; succeeded: number; failed: number }
source: string
}
const execHistory = ref<ScriptExecItem[]>([])
const execHistory = ref<ExecHistoryItem[]>([])
// Quick Execute
const showQuickExec = ref(false)
const quickCommand = ref('')
const quickServerIds = ref<number[]>([])
const quickTimeout = ref(60)
const quickLongTask = ref(false)
const quickCredentialId = ref<number | null>(null)
const quickExecuting = ref(false)
// Execution Tracking
interface TrackedExec {
id: number
name: string
status: 'running' | 'completed' | 'failed' | 'partial'
totalServers: number
completedServers: number
refreshing: boolean
}
const trackedExecs = ref<TrackedExec[]>([])
let pollTimer: ReturnType<typeof setInterval> | null = null
const execHeaders = [
{ title: '命令', key: 'command' },
{ title: '状态', key: 'status', width: 100 },
{ title: '进度', key: 'progress', width: 100 },
{ title: '操作人', key: 'operator', width: 80 },
{ title: '开始时间', key: 'started_at', width: 160 },
]
const showExecDetail = ref(false)
const execDetail = ref<ScriptExecItem | null>(null)
const detailLoading = ref(false)
const detailExecId = ref<number | null>(null)
const credentialOptions = computed(() =>
credentials.value.map(c => ({ title: c.name, value: c.id })),
)
const filteredScripts = computed(() => {
if (!search.value) return scripts.value
const q = search.value.toLowerCase()
const q = search.value.trim().toLowerCase()
if (!q) return scripts.value
return scripts.value.filter(s =>
s.name.toLowerCase().includes(q) ||
(s.category || '').toLowerCase().includes(q)
(s.category || '').toLowerCase().includes(q) ||
(s.description || '').toLowerCase().includes(q),
)
})
// ── Data loading ──
const totalItems = computed(() => filteredScripts.value.length)
const pagedScripts = computed(() => {
const start = (page.value - 1) * itemsPerPage.value
return filteredScripts.value.slice(start, start + itemsPerPage.value)
})
watch(search, () => { page.value = 1 })
const execHeaders = [
{ title: '命令', key: 'command' },
{ title: '状态', key: 'status', width: 100 },
{ title: '进度', key: 'progress', width: 88 },
{ title: '操作人', key: 'operator', width: 88 },
{ title: '开始时间', key: 'started_at', width: 160 },
{ title: '操作', key: 'actions', width: 180, sortable: false },
]
const execDetailRows = computed<ExecDetailRow[]>(() => {
if (!execDetail.value?.results) return []
return Object.entries(execDetail.value.results)
.filter(([k]) => k !== '_meta' && /^\d+$/.test(k))
.map(([serverId, entry]) => ({
serverId,
status: String(entry.status || entry.phase || '—'),
exitCode: entry.exit_code ?? null,
summary: (entry.stdout || entry.stderr || entry.message || '').slice(0, 200) || '—',
}))
})
function categoryLabel(v: string) {
return categoryOptions.find(o => o.value === v)?.label || v
}
function truncateCommand(cmd: string) {
if (!cmd) return '—'
return cmd.length > 60 ? `${cmd.slice(0, 60)}` : cmd
}
function formatProgress(p: string | undefined) {
if (!p) return '—'
return p
}
function parseServerCount(serverIds: string | undefined): number {
if (!serverIds) return 0
try {
const arr = JSON.parse(serverIds) as unknown
return Array.isArray(arr) ? arr.length : 0
} catch {
return 0
}
}
function executionId(res: { id?: number; execution_id?: number }) {
const id = res.id ?? res.execution_id
if (id == null) throw new Error('执行响应缺少 id')
return id
}
async function loadScripts() {
loading.value = true
try {
const res = await http.getList<ScriptItem>('/scripts/', {
page: page.value,
per_page: itemsPerPage.value,
})
const res = await http.getList<ScriptItem>('/scripts/')
scripts.value = res.items
totalItems.value = res.total
} catch (e: unknown) {
scripts.value = []
snackbar(formatApiError(e, '加载脚本列表失败'), 'error')
} finally {
loading.value = false
}
finally { loading.value = false }
}
watch(search, () => { page.value = 1; loadScripts() })
async function loadExecConfig() {
try {
execConfig.value = await http.get<ExecConfig>('/scripts/exec-config')
} catch {
execConfig.value = null
}
}
async function loadCredentials() {
try {
credentials.value = await http.getList<DbCredentialItem>('/scripts/credentials').then(r => r.items)
} catch {
credentials.value = []
}
}
// ── Actions ──
function openEditor(script: ScriptItem | null) {
editingScript.value = script
if (script) {
form.value = { name: script.name, category: script.category || '', description: script.description || '', content: script.content || '' }
form.value = {
name: script.name,
category: script.category || 'ops',
description: script.description || '',
content: script.content || '',
}
} else {
form.value = { name: '', category: '', description: '', content: '' }
form.value = { name: '', category: 'ops', description: '', content: '' }
}
showEditor.value = true
}
async function saveScript() {
if (!form.value.name.trim() || !form.value.content.trim()) {
snackbar('请填写名称与脚本内容', 'warning')
return
}
saving.value = true
try {
const body = {
name: form.value.name.trim(),
category: form.value.category,
description: form.value.description.trim() || null,
content: form.value.content,
}
if (editingScript.value) {
await http.put(`/scripts/${editingScript.value.id}`, form.value)
await http.put(`/scripts/${editingScript.value.id}`, body)
} else {
await http.post('/scripts/', form.value)
await http.post('/scripts/', body)
}
showEditor.value = false
loadScripts()
await loadScripts()
snackbar('保存成功')
} catch (e: any) {
snackbar(e.message || '保存失败', 'error')
} catch (e: unknown) {
snackbar(formatApiError(e, '保存失败'), 'error')
} finally {
saving.value = false
}
@@ -402,9 +659,18 @@ async function saveScript() {
function runScript(script: ScriptItem) {
runningScript.value = script
runServerIds.value = []
runLongTask.value = false
runCredentialId.value = null
showRun.value = true
}
async function submitExec(payload: Record<string, unknown>, label: string, serverCount: number) {
const res = await http.post<ScriptExecItem & { execution_id?: number }>('/scripts/exec', payload)
const id = executionId(res)
addTrackedExecution(label, id, serverCount, Boolean(payload.long_task), res.progress, res.status)
return res
}
async function doRun() {
if (!runningScript.value || !runServerIds.value.length) {
snackbar('请选择服务器', 'warning')
@@ -412,16 +678,21 @@ async function doRun() {
}
executing.value = true
try {
const res = await http.post<{ execution_id: number }>('/scripts/exec', {
script_id: runningScript.value.id,
server_ids: runServerIds.value,
timeout: runTimeout.value,
})
await submitExec(
{
script_id: runningScript.value.id,
server_ids: runServerIds.value,
timeout: runTimeout.value,
long_task: runLongTask.value,
credential_id: runCredentialId.value ?? undefined,
},
runningScript.value.name,
runServerIds.value.length,
)
showRun.value = false
snackbar('脚本已提交执行')
addTrackedExecution(runningScript.value.name, res.execution_id, runServerIds.value.length)
} catch (e: any) {
snackbar(e.message || '执行失败', 'error')
} catch (e: unknown) {
snackbar(formatApiError(e, '执行失败'), 'error')
} finally {
executing.value = false
}
@@ -437,10 +708,10 @@ async function doDelete() {
try {
await http.delete(`/scripts/${deletingScript.value.id}`)
showDelete.value = false
loadScripts()
await loadScripts()
snackbar('已删除')
} catch (e: any) {
snackbar(e.message || '删除失败', 'error')
} catch (e: unknown) {
snackbar(formatApiError(e, '删除失败'), 'error')
}
}
@@ -448,88 +719,197 @@ async function viewHistory(script: ScriptItem) {
historyScript.value = script
showHistory.value = true
try {
const res = await http.get<{ items: ExecHistoryItem[]; total: number }>('/scripts/executions', { script_id: script.id })
const res = await http.get<{ items: ScriptExecItem[]; total: number }>('/scripts/executions', {
script_id: script.id,
limit: 50,
})
execHistory.value = res.items || []
} catch {
execHistory.value = []
}
}
// ── Quick Execute ──
async function doQuickExec() {
if (!quickCommand.value || quickServerIds.value.length === 0) return
if (!quickCommand.value.trim() || quickServerIds.value.length === 0) return
quickExecuting.value = true
try {
const res = await http.post<{ execution_id: number; results: Record<string, unknown> }>('/scripts/exec', {
command: quickCommand.value,
server_ids: quickServerIds.value,
timeout: quickTimeout.value,
})
await submitExec(
{
command: quickCommand.value.trim(),
server_ids: quickServerIds.value,
timeout: quickTimeout.value,
long_task: quickLongTask.value,
credential_id: quickCredentialId.value ?? undefined,
},
'临时命令',
quickServerIds.value.length,
)
snackbar(`已在 ${quickServerIds.value.length} 台服务器上执行`)
addTrackedExecution('临时命令', res.execution_id, quickServerIds.value.length)
} catch (e: any) { snackbar(e.message || '执行失败', 'error') }
finally { quickExecuting.value = false }
} catch (e: unknown) {
snackbar(formatApiError(e, '执行失败'), 'error')
} finally {
quickExecuting.value = false
}
}
// ── Execution Tracking ──
function addTrackedExecution(name: string, execId: number, totalServers: number) {
trackedExecs.value.unshift({ id: execId, name, status: 'running', totalServers, completedServers: 0, refreshing: false })
function addTrackedExecution(
name: string,
execId: number,
totalServers: number,
longTask: boolean,
progress?: string,
status?: string,
) {
if (trackedExecs.value.some(e => e.id === execId)) return
trackedExecs.value.unshift({
id: execId,
name,
status: status || 'running',
totalServers,
progress: progress || `0/${totalServers}`,
longTask,
refreshing: false,
})
startPolling()
}
function startPolling() {
if (pollTimer) return
pollTimer = setInterval(async () => {
const running = trackedExecs.value.filter(e => e.status === 'running')
if (running.length === 0) { stopPolling(); return }
for (const exec of running) await refreshExecStatus(exec)
}, 5000)
const active = trackedExecs.value.filter(e => e.status === 'running' || e.status === 'partial')
if (active.length === 0) {
stopPolling()
return
}
for (const exec of active) await refreshExecStatus(exec)
}, 10_000)
}
function stopPolling() {
if (pollTimer) { clearInterval(pollTimer); pollTimer = null }
if (pollTimer) {
clearInterval(pollTimer)
pollTimer = null
}
}
async function refreshExecStatus(exec: TrackedExec) {
exec.refreshing = true
try {
const res = await http.get<{ status: string; results: Record<string, { status: string }> }>(`/scripts/executions/${exec.id}`)
const results = res.results || {}
const statuses = Object.values(results)
exec.completedServers = statuses.filter(s => s.status !== 'running' && s.status !== 'pending').length
exec.status = res.status as TrackedExec['status']
} catch { /* ignore */ }
finally { exec.refreshing = false }
const res = await http.get<ScriptExecItem>(`/scripts/executions/${exec.id}`)
exec.status = res.status
exec.progress = formatProgress(res.progress)
exec.longTask = Boolean(res.long_task)
} catch {
/* keep last known */
} finally {
exec.refreshing = false
}
}
async function stopExec(exec: TrackedExec) {
try {
await http.post(`/scripts/executions/${exec.id}/stop`)
exec.status = 'failed'
await refreshExecStatus(exec)
snackbar('已发送停止指令')
} catch (e: any) { snackbar(e.message || '停止失败', 'error') }
} catch (e: unknown) {
snackbar(formatApiError(e, '停止失败'), 'error')
}
}
async function markExecStuck(exec: TrackedExec) {
try {
await http.post(`/scripts/executions/${exec.id}/mark-stuck`, { detail: '用户在脚本库标记可能卡住' })
snackbar('已标记')
} catch (e: unknown) {
snackbar(formatApiError(e, '标记失败'), 'error')
}
}
async function retryExec(exec: TrackedExec) {
try {
const res = await http.post<ScriptExecItem & { parent_execution_id?: number }>(
`/scripts/executions/${exec.id}/retry`,
{},
)
const newId = executionId(res)
addTrackedExecution(`${exec.name}(重试)`, newId, exec.totalServers, exec.longTask, res.progress, res.status)
snackbar(`已创建重试任务 #${newId}`)
} catch (e: unknown) {
snackbar(formatApiError(e, '重试失败'), 'error')
}
}
async function stopHistoryExec(item: ScriptExecItem) {
try {
await http.post(`/scripts/executions/${item.id}/stop`)
if (historyScript.value) await viewHistory(historyScript.value)
snackbar('已发送停止指令')
} catch (e: unknown) {
snackbar(formatApiError(e, '停止失败'), 'error')
}
}
async function retryHistoryExec(item: ScriptExecItem) {
try {
const res = await http.post<ScriptExecItem>(`/scripts/executions/${item.id}/retry`, {})
addTrackedExecution(`${historyScript.value?.name || '脚本'}(重试)`, executionId(res), parseServerCount(item.server_ids) || parseServerCount(res.server_ids), Boolean(item.long_task), res.progress, res.status)
if (historyScript.value) await viewHistory(historyScript.value)
snackbar('重试已提交')
} catch (e: unknown) {
snackbar(formatApiError(e, '重试失败'), 'error')
}
}
async function openExecDetail(id: number) {
detailExecId.value = id
showExecDetail.value = true
await loadExecDetail(false)
}
async function loadExecDetail(fetchLogs: boolean) {
if (detailExecId.value == null) return
detailLoading.value = true
try {
execDetail.value = await http.get<ScriptExecItem>(`/scripts/executions/${detailExecId.value}`, {
fetch_logs: fetchLogs,
log_lines: 100,
})
} catch (e: unknown) {
snackbar(formatApiError(e, '加载详情失败'), 'error')
showExecDetail.value = false
} finally {
detailLoading.value = false
}
}
function execStatusColor(s: string) {
return s === 'running' ? 'blue' : s === 'completed' ? 'green' : s === 'failed' ? 'red' : 'orange'
if (s === 'running') return 'blue'
if (s === 'completed') return 'green'
if (s === 'failed') return 'red'
if (s === 'partial') return 'orange'
if (s === 'cancelled') return 'grey'
return 'info'
}
function execStatusLabel(s: string) {
return s === 'running' ? '执行中' : s === 'completed' ? '已完成' : s === 'failed' ? '失败' : '部分完成'
const map: Record<string, string> = {
running: '执行中',
completed: '已完成',
failed: '失败',
partial: '部分成功',
cancelled: '已取消',
}
return map[s] || s
}
onMounted(() => {
loadScripts()
loadServers()
loadExecConfig()
loadCredentials()
})
onUnmounted(() => {
stopPolling()
})
interface ScriptItem {
id: number; name: string; category: string | null; description: string | null
content: string | null; created_at: string; updated_at: string
}
</script>
+28 -7
View File
@@ -269,9 +269,10 @@ export interface RetryItem {
export interface ScriptItem {
id: number
name: string
description: string
content: string
script_type: string
category: string | null
description: string | null
content: string | null
created_by?: string | null
created_at: string | null
updated_at: string | null
}
@@ -297,7 +298,8 @@ export interface PushItem {
export interface ScheduleItem {
id: number
name: string
cron_expr: string
cron_expr: string | null
fire_at?: string | null
command?: string
source_path?: string
target_path?: string
@@ -330,20 +332,39 @@ export interface AuditItem {
created_at: string | null
}
/** DB credential from /api/scripts/credentials (password never returned) */
export interface DbCredentialItem {
id: number
name: string
db_type?: string
host: string
port: number
username: string
database?: string
created_at?: string | null
}
/** Script execution item from /api/scripts/executions */
export interface ScriptExecItem {
id: number
script_id: number
script_id: number | null
command: string
server_ids: string
status: string
results: Record<string, { status?: string; output?: string; exit_code?: number }>
results: Record<string, {
status?: string
phase?: string
stdout?: string
stderr?: string
message?: string
exit_code?: number
}>
events: Array<{ event: string; ts: string }>
operator: string | null
started_at: string | null
completed_at: string | null
long_task?: boolean
progress?: { total: number; done: number; succeeded: number; failed: number }
progress?: string
credential_id?: number | null
source: string
}
+1
View File
@@ -1196,6 +1196,7 @@ async def init_db(req: InitDbRequest):
# Schema migrations for existing databases (safe — no-op if column exists)
migrations = [
"ALTER TABLE push_schedules ADD COLUMN sync_mode VARCHAR(20) DEFAULT 'incremental' COMMENT '同步模式'",
"ALTER TABLE push_schedules ADD COLUMN target_path VARCHAR(500) NULL COMMENT '推送目标路径(留空则各机target_path)'",
]
for mig_sql in migrations:
try:
+23 -2
View File
@@ -465,13 +465,22 @@ class ScriptUpdate(BaseModel):
class ScriptExecute(BaseModel):
script_id: Optional[int] = None
command: str = Field(..., min_length=1)
script_id: Optional[int] = Field(None, ge=1)
command: Optional[str] = Field(None, min_length=1)
server_ids: List[int] = Field(..., min_length=1, max_length=2000)
credential_id: Optional[int] = None
timeout: int = Field(60, ge=1, le=600)
long_task: bool = False
@model_validator(mode="after")
def require_command_or_script(self) -> "ScriptExecute":
cmd = (self.command or "").strip()
if cmd:
self.command = cmd
elif not self.script_id:
raise ValueError("须提供 command 或 script_id")
return self
class ScriptExecutionRetry(BaseModel):
server_ids: Optional[List[int]] = None
@@ -529,6 +538,7 @@ class ScheduleCreate(BaseModel):
schedule_type: str = Field("push", pattern="^(push|script)$")
# Push-specific (required when schedule_type == 'push')
source_path: Optional[str] = None
target_path: Optional[str] = None
sync_mode: str = Field("incremental", pattern="^(incremental|full|overwrite|checksum)$")
# Script-specific (required when schedule_type == 'script')
script_id: Optional[int] = None
@@ -558,10 +568,16 @@ class ScheduleCreate(BaseModel):
return None
return coerce_nexus_host_abs_path(text)
@field_validator("target_path", mode="before")
@classmethod
def _normalize_target_path(cls, v: object) -> object:
return coerce_optional_remote_abs_path(v if v is None else str(v))
class ScheduleUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=1, max_length=100)
source_path: Optional[str] = None
target_path: Optional[str] = None
server_ids: Optional[str] = None
run_mode: Optional[str] = Field(None, pattern="^(once|cron)$")
cron_expr: Optional[str] = None
@@ -584,6 +600,11 @@ class ScheduleUpdate(BaseModel):
return None
return coerce_nexus_host_abs_path(text)
@field_validator("target_path", mode="before")
@classmethod
def _normalize_target_path(cls, v: object) -> object:
return coerce_optional_remote_abs_path(v if v is None else str(v))
# ── Preset ──
+24 -4
View File
@@ -153,11 +153,14 @@ async def list_executions(
limit: int = Query(50, ge=1, le=200),
offset: int = Query(0, ge=0),
status: Optional[str] = Query(None, description="Filter: running/completed/failed/partial"),
script_id: Optional[int] = Query(None, ge=1, description="Filter by script library id"),
admin: Admin = Depends(get_current_admin),
service: ScriptService = Depends(get_script_service),
):
"""List script execution history (newest first)."""
return await service.list_executions(limit=limit, offset=offset, status=status)
return await service.list_executions(
limit=limit, offset=offset, status=status, script_id=script_id,
)
@router.post("/executions/{id}/stop", response_model=dict)
@@ -273,7 +276,9 @@ async def create_script(
db: AsyncSession = Depends(get_db),
):
"""Create a new script"""
script = Script(**payload.model_dump(exclude_none=True))
data = payload.model_dump(exclude_none=True)
data.setdefault("created_by", admin.username)
script = Script(**data)
created = await service.create_script(script)
audit_repo = AuditLogRepositoryImpl(db)
@@ -342,6 +347,19 @@ async def delete_script(
# ── Command Execution ──
async def _resolve_exec_command(service: ScriptService, payload: ScriptExecute) -> str:
"""Use explicit command or load content from script library."""
if payload.command:
return payload.command
script = await service.get_script(payload.script_id) # type: ignore[arg-type]
if not script:
raise HTTPException(status_code=404, detail="脚本不存在")
content = (script.content or "").strip()
if not content:
raise HTTPException(status_code=400, detail="脚本内容为空,无法执行")
return content
@router.post("/exec", response_model=dict)
async def execute_command(
payload: ScriptExecute,
@@ -351,7 +369,9 @@ async def execute_command(
"""Execute a shell command on multiple servers via Agent /api/exec"""
# P2-18: Log dangerous commands for audit trail
from server.api.dependencies import check_dangerous_command
warnings = check_dangerous_command(payload.command)
command = await _resolve_exec_command(service, payload)
warnings = check_dangerous_command(command)
if warnings:
raise HTTPException(
status_code=400,
@@ -360,7 +380,7 @@ async def execute_command(
try:
execution = await service.execute_command(
command=payload.command,
command=command,
server_ids=payload.server_ids,
script_id=payload.script_id,
credential_id=payload.credential_id,
+6 -1
View File
@@ -442,7 +442,7 @@ async def update_schedule(
raise HTTPException(status_code=404, detail="Schedule not found")
# Explicit allowlist to prevent mass-assignment to sensitive columns
ALLOWED_FIELDS = {
"name", "source_path", "server_ids", "run_mode", "cron_expr",
"name", "source_path", "target_path", "server_ids", "run_mode", "cron_expr",
"fire_at", "sync_mode", "enabled", "schedule_type",
"script_id", "script_content", "exec_timeout", "long_task",
}
@@ -1490,10 +1490,14 @@ async def delete_retry_job(
# ── Helper functions ──
def _schedule_to_dict(schedule: PushSchedule) -> dict:
from server.background.schedule_runner import compute_schedule_next_run
next_run_dt = compute_schedule_next_run(schedule)
return {
"id": schedule.id,
"name": schedule.name,
"source_path": schedule.source_path,
"target_path": getattr(schedule, "target_path", None),
"server_ids": schedule.server_ids,
"run_mode": getattr(schedule, "run_mode", None) or "once",
"cron_expr": schedule.cron_expr,
@@ -1506,6 +1510,7 @@ def _schedule_to_dict(schedule: PushSchedule) -> dict:
"exec_timeout": getattr(schedule, "exec_timeout", 60),
"long_task": getattr(schedule, "long_task", False),
"last_run_at": str(schedule.last_run_at) if schedule.last_run_at else None,
"next_run": str(next_run_dt) if next_run_dt else None,
"created_at": str(schedule.created_at) if schedule.created_at else None,
}
@@ -223,9 +223,12 @@ class ScriptService:
limit: int = 50,
offset: int = 0,
status: Optional[str] = None,
script_id: Optional[int] = None,
) -> dict:
"""List execution history (MySQL list + Redis overlay when live)."""
rows, total = await self.execution_repo.list_recent(limit, offset, status)
rows, total = await self.execution_repo.list_recent(
limit, offset, status, script_id=script_id,
)
items = []
for ex in rows:
view = await ses.get_execution_view(self.execution_repo, ex.id)
+37 -2
View File
@@ -5,7 +5,7 @@ Every 60 seconds: check PushSchedule cron expressions, trigger due schedules.
import asyncio
import json
import logging
from datetime import datetime, timezone
from datetime import datetime, timedelta, timezone
from server.infrastructure.database.session import AsyncSessionLocal
from server.domain.models import PushSchedule
@@ -73,6 +73,40 @@ def _field_match(expr: str, value: int) -> bool:
return False
def _compute_next_cron_run(cron_expr: str, after: datetime) -> datetime | None:
"""Return the next minute strictly after *after* that matches *cron_expr*."""
candidate = after.replace(second=0, microsecond=0) + timedelta(minutes=1)
limit = after + timedelta(days=366)
while candidate <= limit:
if _cron_match(cron_expr, candidate):
return candidate
candidate += timedelta(minutes=1)
return None
def compute_schedule_next_run(schedule: PushSchedule, now: datetime | None = None) -> datetime | None:
"""Compute next scheduled run time for API display."""
if not schedule.enabled:
return None
now = now or datetime.now(timezone.utc)
run_mode = getattr(schedule, "run_mode", None) or "cron"
if run_mode == "once":
fire_at = getattr(schedule, "fire_at", None)
if not fire_at or schedule.last_run_at:
return None
now_naive = now.replace(tzinfo=None)
fire_naive = fire_at.replace(tzinfo=None) if fire_at.tzinfo else fire_at
if fire_naive <= now_naive:
return None
return fire_at
cron_expr = schedule.cron_expr
if not cron_expr:
return None
return _compute_next_cron_run(cron_expr.strip(), now)
def _schedule_is_due(schedule: PushSchedule, now: datetime) -> bool:
"""Return True if *schedule* should fire at *now* (cron or once)."""
run_mode = getattr(schedule, "run_mode", None) or "cron"
@@ -225,7 +259,8 @@ async def schedule_runner_loop():
result = await engine.sync_files(
server_ids=server_ids,
source_path=schedule.source_path or '/tmp',
sync_mode=getattr(schedule, 'sync_mode', None) or "incremental",
target_path=getattr(schedule, "target_path", None) or None,
sync_mode=getattr(schedule, "sync_mode", None) or "incremental",
trigger_type="schedule",
operator=f"schedule:{schedule.name}",
)
+1
View File
@@ -266,6 +266,7 @@ class PushSchedule(Base):
# ── Push-specific fields (schedule_type = 'push') ──
source_path = Column(String(500), nullable=True, comment="推送源目录(push 类型必填)")
target_path = Column(String(500), nullable=True, comment="推送目标路径(留空则各机 target_path")
sync_mode = Column(String(20), default="incremental", comment="同步模式: incremental/full/overwrite/checksum")
# ── Script-specific fields (schedule_type = 'script') ──
@@ -144,6 +144,7 @@ async def run_schema_migrations():
"ALTER TABLE push_schedules ADD COLUMN run_mode VARCHAR(10) DEFAULT 'once' COMMENT '运行模式: once|cron'",
"ALTER TABLE push_schedules ADD COLUMN fire_at DATETIME NULL COMMENT '一次性执行时间(once模式)'",
"ALTER TABLE push_schedules MODIFY COLUMN cron_expr VARCHAR(100) NULL COMMENT 'cron表达式(cron模式)'",
"ALTER TABLE push_schedules ADD COLUMN target_path VARCHAR(500) NULL COMMENT '推送目标路径(留空则各机target_path)'",
# ── Server table: columns added after initial schema ──
"ALTER TABLE servers ADD COLUMN platform_id INT NULL COMMENT '平台类型ID'",
"ALTER TABLE servers ADD COLUMN node_id INT NULL COMMENT '所属节点ID'",
@@ -63,10 +63,13 @@ class ScriptExecutionRepositoryImpl:
limit: int = 50,
offset: int = 0,
status: Optional[str] = None,
script_id: Optional[int] = None,
) -> Tuple[List[ScriptExecution], int]:
filters = []
if status:
filters.append(ScriptExecution.status == status)
if script_id is not None:
filters.append(ScriptExecution.script_id == script_id)
count_stmt = select(func.count(ScriptExecution.id))
if filters:
count_stmt = count_stmt.where(*filters)
+50
View File
@@ -0,0 +1,50 @@
"""Schedule next-run computation and cron stepping."""
from datetime import datetime, timezone
from types import SimpleNamespace
from server.background.schedule_runner import (
_compute_next_cron_run,
compute_schedule_next_run,
)
def test_compute_next_cron_run_finds_next_minute():
after = datetime(2026, 6, 7, 1, 59, tzinfo=timezone.utc)
nxt = _compute_next_cron_run("0 2 * * *", after)
assert nxt == datetime(2026, 6, 7, 2, 0, tzinfo=timezone.utc)
def test_compute_schedule_next_run_once_future():
schedule = SimpleNamespace(
enabled=True,
run_mode="once",
fire_at=datetime(2026, 12, 1, 10, 0),
last_run_at=None,
cron_expr=None,
)
now = datetime(2026, 6, 7, 12, 0, tzinfo=timezone.utc)
assert compute_schedule_next_run(schedule, now) == schedule.fire_at
def test_compute_schedule_next_run_once_already_ran():
schedule = SimpleNamespace(
enabled=True,
run_mode="once",
fire_at=datetime(2026, 12, 1, 10, 0),
last_run_at=datetime(2026, 12, 1, 10, 1),
cron_expr=None,
)
now = datetime(2026, 6, 7, 12, 0, tzinfo=timezone.utc)
assert compute_schedule_next_run(schedule, now) is None
def test_compute_schedule_next_run_cron_disabled():
schedule = SimpleNamespace(
enabled=False,
run_mode="cron",
cron_expr="*/5 * * * *",
last_run_at=None,
fire_at=None,
)
assert compute_schedule_next_run(schedule) is None
+1
View File
@@ -0,0 +1 @@
import{A as e,F as t,N as n,Vr as r,Z as i,Zn as a,ar as o,er as s,gr as c,jr as l,k as u,mr as d,or as f,rr as p,sr as m,tr as h,vr as g,w as _,wr as v,zt as y}from"./index-CLVw8WaP.js";import{o as b,t as x}from"./VContainer-FlPueFWR.js";import{t as S}from"./VChip-CoJQpM5X.js";import{t as C}from"./VSelect-C9Xea3xT.js";import{t as w}from"./VDataTableServer-CihJhzNQ.js";import{n as T,t as E}from"./VRow-CGrZcJ6l.js";import{t as D}from"./VSpacer-BKvfPYW2.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=m({__name:`AlertsPage`,setup(m){let j=b(),M=l(!1),N=l([]),P=l(0),F=l(1),I=l(null),L=l(null),R=l([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await y.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await y.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{H(),U()}),(l,d)=>(c(),h(x,{fluid:``,class:`pa-6`},{default:v(()=>[f(E,{class:`mb-4`},{default:v(()=>[(c(!0),p(a,null,g(R.value,t=>(c(),h(T,{cols:`12`,sm:`6`,lg:`3`,key:t.label},{default:v(()=>[f(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:v(()=>[f(u,null,{append:v(()=>[f(i,{color:t.color,size:`30`},{default:v(()=>[o(r(t.icon),1)]),_:2},1032,[`color`])]),default:v(()=>[f(e,{class:`text-body-small`},{default:v(()=>[o(r(t.label),1)]),_:2},1024),f(e,null,{default:v(()=>[o(r(t.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),f(n,{elevation:`0`,border:``,rounded:`lg`},{default:v(()=>[f(t,{class:`d-flex align-center`},{default:v(()=>[d[5]||=o(` 告警历史 `,-1),f(D),f(C,{modelValue:I.value,"onUpdate:modelValue":[d[0]||=e=>I.value=e,d[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),f(C,{modelValue:L.value,"onUpdate:modelValue":[d[2]||=e=>L.value=e,d[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),f(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{F.value=e,U()}},{"item.alert_type":v(({item:e})=>[f(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:v(()=>[f(i,{size:`12`},{default:v(()=>[o(r(G(e.alert_type)),1)]),_:2},1024)]),default:v(()=>[o(` `+r(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":v(({item:e})=>[s(`span`,O,r(e.server_name),1)]),"item.value":v(({item:e})=>[s(`span`,k,r(e.value),1)]),"item.is_recovery":v(({item:e})=>[e.is_recovery?(c(),h(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[6]||=[o(`已恢复`,-1)]]),_:1})):(c(),h(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[7]||=[o(`告警中`,-1)]]),_:1}))]),"item.created_at":v(({item:e})=>[s(`span`,A,r(e.created_at),1)]),"no-data":v(()=>[...d[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,F as t,N as n,Vr as r,Z as i,Zn as a,ar as o,er as s,gr as c,jr as l,k as u,mr as d,or as f,rr as p,sr as m,tr as h,vr as g,w as _,wr as v,zt as y}from"./index-BihgjXCy.js";import{o as b,t as x}from"./VContainer-V_R05OUP.js";import{t as S}from"./VChip-FKNgTWw3.js";import{t as C}from"./VSelect-CGF0mOJJ.js";import{t as w}from"./VDataTableServer-Pl72x6lf.js";import{n as T,t as E}from"./VRow-D6NnUZV_.js";import{t as D}from"./VSpacer-2YW4-MQQ.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=m({__name:`AlertsPage`,setup(m){let j=b(),M=l(!1),N=l([]),P=l(0),F=l(1),I=l(null),L=l(null),R=l([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await y.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await y.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{H(),U()}),(l,d)=>(c(),h(x,{fluid:``,class:`pa-6`},{default:v(()=>[f(E,{class:`mb-4`},{default:v(()=>[(c(!0),p(a,null,g(R.value,t=>(c(),h(T,{cols:`12`,sm:`6`,lg:`3`,key:t.label},{default:v(()=>[f(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:v(()=>[f(u,null,{append:v(()=>[f(i,{color:t.color,size:`30`},{default:v(()=>[o(r(t.icon),1)]),_:2},1032,[`color`])]),default:v(()=>[f(e,{class:`text-body-small`},{default:v(()=>[o(r(t.label),1)]),_:2},1024),f(e,null,{default:v(()=>[o(r(t.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),f(n,{elevation:`0`,border:``,rounded:`lg`},{default:v(()=>[f(t,{class:`d-flex align-center`},{default:v(()=>[d[5]||=o(` 告警历史 `,-1),f(D),f(C,{modelValue:I.value,"onUpdate:modelValue":[d[0]||=e=>I.value=e,d[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),f(C,{modelValue:L.value,"onUpdate:modelValue":[d[2]||=e=>L.value=e,d[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),f(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{F.value=e,U()}},{"item.alert_type":v(({item:e})=>[f(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:v(()=>[f(i,{size:`12`},{default:v(()=>[o(r(G(e.alert_type)),1)]),_:2},1024)]),default:v(()=>[o(` `+r(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":v(({item:e})=>[s(`span`,O,r(e.server_name),1)]),"item.value":v(({item:e})=>[s(`span`,k,r(e.value),1)]),"item.is_recovery":v(({item:e})=>[e.is_recovery?(c(),h(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[6]||=[o(`已恢复`,-1)]]),_:1})):(c(),h(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[7]||=[o(`告警中`,-1)]]),_:1}))]),"item.created_at":v(({item:e})=>[s(`span`,A,r(e.created_at),1)]),"no-data":v(()=>[...d[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{A as e,F as t,N as n,Vr as r,Z as i,Zn as a,ar as o,er as s,gr as c,jr as l,k as u,mr as d,or as f,rr as p,sr as m,tr as h,vr as g,w as _,wr as v,zt as y}from"./index-DNlvHxBC.js";import{o as b,t as x}from"./VContainer-CbSJCQsb.js";import{t as S}from"./VChip-BbRVKa0H.js";import{t as C}from"./VSelect-D0AqVzoi.js";import{t as w}from"./VDataTableServer-BUUXYQSU.js";import{n as T,t as E}from"./VRow-DW-g9AN1.js";import{t as D}from"./VSpacer-DDACi18G.js";var O={class:`font-weight-medium`},k={class:`text-body-2`},A={class:`text-caption text-medium-emphasis`},j=m({__name:`AlertsPage`,setup(m){let j=b(),M=l(!1),N=l([]),P=l(0),F=l(1),I=l(null),L=l(null),R=l([{label:`今日告警`,value:`0`,color:`blue`,icon:`mdi-alert`},{label:`活跃告警`,value:`0`,color:`orange`,icon:`mdi-bell-ring`},{label:`已恢复`,value:`0`,color:`green`,icon:`mdi-check-circle`},{label:`Top 服务器`,value:``,color:`red`,icon:`mdi-server`}]),z=[{label:`CPU`,value:`cpu`},{label:`内存`,value:`memory`},{label:`磁盘`,value:`disk`},{label:`连接`,value:`connection`}],B=[{label:`活跃`,value:`active`},{label:`已恢复`,value:`recovered`}],V=[{title:`类型`,key:`alert_type`,width:100},{title:`服务器`,key:`server_name`},{title:`详情`,key:`value`},{title:`状态`,key:`is_recovery`,width:100},{title:`时间`,key:`created_at`,width:160}];async function H(){try{let e=await y.get(`/alert-history/stats`);R.value[0].value=String(e.today||0),R.value[1].value=String(e.active||0),R.value[2].value=String(e.recovered||0),R.value[3].value=e.top_server||``}catch{j(`加载统计失败`,`error`)}}async function U(){M.value=!0;try{let e=await y.get(`/alert-history/`,{page:F.value,per_page:20,type:I.value||void 0,status:L.value||void 0});N.value=e.items||[],P.value=e.total||0}catch{N.value=[]}finally{M.value=!1}}function W(e){return e===`cpu`||e===`CPU`?`error`:e===`memory`||e===`内存`?`warning`:e===`disk`||e===`磁盘`?`info`:`primary`}function G(e){return e===`cpu`||e===`CPU`?`mdi-chip`:e===`memory`||e===`内存`?`mdi-memory`:e===`disk`||e===`磁盘`?`mdi-harddisk`:`mdi-lan-disconnect`}return d(()=>{H(),U()}),(l,d)=>(c(),h(x,{fluid:``,class:`pa-6`},{default:v(()=>[f(E,{class:`mb-4`},{default:v(()=>[(c(!0),p(a,null,g(R.value,t=>(c(),h(T,{cols:`12`,sm:`6`,lg:`3`,key:t.label},{default:v(()=>[f(_,{elevation:`0`,lines:`two`,rounded:`lg`,border:``},{default:v(()=>[f(u,null,{append:v(()=>[f(i,{color:t.color,size:`30`},{default:v(()=>[o(r(t.icon),1)]),_:2},1032,[`color`])]),default:v(()=>[f(e,{class:`text-body-small`},{default:v(()=>[o(r(t.label),1)]),_:2},1024),f(e,null,{default:v(()=>[o(r(t.value),1)]),_:2},1024)]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}),f(n,{elevation:`0`,border:``,rounded:`lg`},{default:v(()=>[f(t,{class:`d-flex align-center`},{default:v(()=>[d[5]||=o(` 告警历史 `,-1),f(D),f(C,{modelValue:I.value,"onUpdate:modelValue":[d[0]||=e=>I.value=e,d[1]||=e=>{F.value=1,U()}],items:z,"item-title":`label`,"item-value":`value`,label:`类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},clearable:``},null,8,[`modelValue`]),f(C,{modelValue:L.value,"onUpdate:modelValue":[d[2]||=e=>L.value=e,d[3]||=e=>{F.value=1,U()}],items:B,"item-title":`label`,"item-value":`value`,label:`状态`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`])]),_:1}),f(w,{items:N.value,headers:V,"items-length":P.value,loading:M.value,page:F.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":d[4]||=e=>{F.value=e,U()}},{"item.alert_type":v(({item:e})=>[f(S,{color:W(e.alert_type),size:`small`,variant:`tonal`,label:``},{prepend:v(()=>[f(i,{size:`12`},{default:v(()=>[o(r(G(e.alert_type)),1)]),_:2},1024)]),default:v(()=>[o(` `+r(e.alert_type),1)]),_:2},1032,[`color`])]),"item.server_name":v(({item:e})=>[s(`span`,O,r(e.server_name),1)]),"item.value":v(({item:e})=>[s(`span`,k,r(e.value),1)]),"item.is_recovery":v(({item:e})=>[e.is_recovery?(c(),h(S,{key:0,color:`success`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[6]||=[o(`已恢复`,-1)]]),_:1})):(c(),h(S,{key:1,color:`error`,size:`small`,variant:`tonal`,label:``},{default:v(()=>[...d[7]||=[o(`告警中`,-1)]]),_:1}))]),"item.created_at":v(({item:e})=>[s(`span`,A,r(e.created_at),1)]),"no-data":v(()=>[...d[8]||=[s(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{j as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,N as n,Vr as r,ar as i,er as a,gr as o,jr as s,mr as c,or as l,sr as u,t as d,tr as f,wr as p,zt as m}from"./index-CLVw8WaP.js";import{o as h,t as g}from"./VContainer-FlPueFWR.js";import{t as _}from"./VChip-CoJQpM5X.js";import{t as v}from"./VSelect-C9Xea3xT.js";import{t as y}from"./VDataTableServer-CihJhzNQ.js";import{t as b}from"./VSpacer-BKvfPYW2.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-bmSA0RyN.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=u({__name:`AuditPage`,setup(u){let A=h(),j=s(!1),M=s([]),N=s(0),P=s(1),F=s(null),I=s(``),L=s(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>B()),(s,c)=>(o(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[l(e,{class:`d-flex align-center`},{default:p(()=>[c[7]||=i(` 审计日志 `,-1),l(b),l(v,{modelValue:F.value,"onUpdate:modelValue":[c[0]||=e=>F.value=e,c[1]||=e=>{P.value=1,B()}],items:t(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:I.value,"onUpdate:modelValue":[c[2]||=e=>I.value=e,c[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[4]||=e=>L.value=e,c[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{P.value=e,B()}},{"item.action":p(({item:e})=>[l(_,{color:V(e.action),size:`small`,variant:`tonal`,label:``},{default:p(()=>[i(r(t(C)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":p(({item:e})=>[a(`span`,T,r(e.admin_username),1)]),"item.target":p(({item:e})=>[a(`span`,E,r(t(x)(e.resource_type))+r(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":p(({item:e})=>[a(`span`,D,r(e.detail||``),1)]),"item.ip_address":p(({item:e})=>[a(`span`,O,r(e.ip_address||``),1)]),"item.created_at":p(({item:e})=>[a(`span`,k,r(e.created_at),1)]),"no-data":p(()=>[...c[8]||=[a(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,N as n,Vr as r,ar as i,er as a,gr as o,jr as s,mr as c,or as l,sr as u,t as d,tr as f,wr as p,zt as m}from"./index-DNlvHxBC.js";import{o as h,t as g}from"./VContainer-CbSJCQsb.js";import{t as _}from"./VChip-BbRVKa0H.js";import{t as v}from"./VSelect-D0AqVzoi.js";import{t as y}from"./VDataTableServer-BUUXYQSU.js";import{t as b}from"./VSpacer-DDACi18G.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-bmSA0RyN.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=u({__name:`AuditPage`,setup(u){let A=h(),j=s(!1),M=s([]),N=s(0),P=s(1),F=s(null),I=s(``),L=s(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>B()),(s,c)=>(o(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[l(e,{class:`d-flex align-center`},{default:p(()=>[c[7]||=i(` 审计日志 `,-1),l(b),l(v,{modelValue:F.value,"onUpdate:modelValue":[c[0]||=e=>F.value=e,c[1]||=e=>{P.value=1,B()}],items:t(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:I.value,"onUpdate:modelValue":[c[2]||=e=>I.value=e,c[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[4]||=e=>L.value=e,c[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{P.value=e,B()}},{"item.action":p(({item:e})=>[l(_,{color:V(e.action),size:`small`,variant:`tonal`,label:``},{default:p(()=>[i(r(t(C)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":p(({item:e})=>[a(`span`,T,r(e.admin_username),1)]),"item.target":p(({item:e})=>[a(`span`,E,r(t(x)(e.resource_type))+r(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":p(({item:e})=>[a(`span`,D,r(e.detail||``),1)]),"item.ip_address":p(({item:e})=>[a(`span`,O,r(e.ip_address||``),1)]),"item.created_at":p(({item:e})=>[a(`span`,k,r(e.created_at),1)]),"no-data":p(()=>[...c[8]||=[a(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,N as n,Vr as r,ar as i,er as a,gr as o,jr as s,mr as c,or as l,sr as u,t as d,tr as f,wr as p,zt as m}from"./index-BihgjXCy.js";import{o as h,t as g}from"./VContainer-V_R05OUP.js";import{t as _}from"./VChip-FKNgTWw3.js";import{t as v}from"./VSelect-CGF0mOJJ.js";import{t as y}from"./VDataTableServer-Pl72x6lf.js";import{t as b}from"./VSpacer-2YW4-MQQ.js";import{a as x,n as S,r as C,t as w}from"./auditNormalize-bmSA0RyN.js";var T={class:`font-weight-medium`},E={class:`text-body-2`},D={class:`text-body-2 text-medium-emphasis text-truncate`,style:{"max-width":`300px`,display:`inline-block`}},O={class:`text-caption text-medium-emphasis`},k={class:`text-caption text-medium-emphasis`},A=u({__name:`AuditPage`,setup(u){let A=h(),j=s(!1),M=s([]),N=s(0),P=s(1),F=s(null),I=s(``),L=s(``),R=S,z=[{title:`操作`,key:`action`,width:100},{title:`用户`,key:`admin_username`,width:100},{title:`目标`,key:`target`,width:140},{title:`详情`,key:`detail`},{title:`IP`,key:`ip_address`,width:120},{title:`时间`,key:`created_at`,width:160}];async function B(){j.value=!0;try{let e=(P.value-1)*50,t=await m.get(`/audit/`,{limit:50,offset:e,action:F.value||void 0,admin_username:I.value||void 0,date_from:L.value||void 0});M.value=w(t.items||[]),N.value=t.total||0}catch{M.value=[],A(`加载审计日志失败`,`error`)}finally{j.value=!1}}function V(e){return e.startsWith(`create`)||e===`login`?`success`:e.startsWith(`update`)?`info`:e.startsWith(`delete`)||e===`logout`?`error`:e.includes(`execute`)||e.includes(`push`)||e.includes(`retry`)?`warning`:`primary`}return c(()=>B()),(s,c)=>(o(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[l(n,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[l(e,{class:`d-flex align-center`},{default:p(()=>[c[7]||=i(` 审计日志 `,-1),l(b),l(v,{modelValue:F.value,"onUpdate:modelValue":[c[0]||=e=>F.value=e,c[1]||=e=>{P.value=1,B()}],items:t(R),"item-title":`label`,"item-value":`value`,label:`操作类型`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`200px`},clearable:``},null,8,[`modelValue`,`items`]),l(d,{modelValue:I.value,"onUpdate:modelValue":[c[2]||=e=>I.value=e,c[3]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-account`,label:`用户`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`140px`},class:`ml-3`,clearable:``},null,8,[`modelValue`]),l(d,{modelValue:L.value,"onUpdate:modelValue":[c[4]||=e=>L.value=e,c[5]||=e=>{P.value=1,B()}],"prepend-inner-icon":`mdi-calendar`,label:`日期`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},class:`ml-3`,type:`date`,clearable:``},null,8,[`modelValue`])]),_:1}),l(y,{items:M.value,headers:z,"items-length":N.value,loading:j.value,page:P.value,"items-per-page":50,hover:``,density:`compact`,"onUpdate:page":c[6]||=e=>{P.value=e,B()}},{"item.action":p(({item:e})=>[l(_,{color:V(e.action),size:`small`,variant:`tonal`,label:``},{default:p(()=>[i(r(t(C)(e.action)),1)]),_:2},1032,[`color`])]),"item.admin_username":p(({item:e})=>[a(`span`,T,r(e.admin_username),1)]),"item.target":p(({item:e})=>[a(`span`,E,r(t(x)(e.resource_type))+r(e.resource_id?` #${e.resource_id}`:``),1)]),"item.detail":p(({item:e})=>[a(`span`,D,r(e.detail||``),1)]),"item.ip_address":p(({item:e})=>[a(`span`,O,r(e.ip_address||``),1)]),"item.created_at":p(({item:e})=>[a(`span`,k,r(e.created_at),1)]),"no-data":p(()=>[...c[8]||=[a(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1})]),_:1}))}});export{A as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,M as n,N as r,Vr as i,ar as a,er as o,gr as s,jr as c,mr as l,or as u,sr as d,tr as f,wr as p,zt as m}from"./index-CLVw8WaP.js";import{o as h,t as g}from"./VContainer-FlPueFWR.js";import{t as _}from"./VChip-CoJQpM5X.js";import{t as v}from"./VSelect-C9Xea3xT.js";import{t as y}from"./VDataTableServer-CihJhzNQ.js";import{t as b}from"./VSpacer-BKvfPYW2.js";import{t as x}from"./apiError-CX6Jp2Ug.js";import{t as S}from"./useServerList-SC0HR6D5.js";var C={class:`text-body-2`},w={class:`text-medium-emphasis`},T={class:`text-medium-emphasis`},E={class:`text-caption text-medium-emphasis`},D={class:`font-weight-medium`},O={class:`text-caption text-medium-emphasis`},k=d({__name:`CommandsPage`,setup(d){let k=h(),{servers:A,loadServers:j}=S(),M=c(!1),N=c(`commands`),P=c(1),F=c(0),I=c(30),L=c(null),R=c([]),z=c([]),B=[{title:`命令`,key:`command`},{title:`服务器`,key:`server_name`},{title:`用户`,key:`admin_username`,width:100},{title:`时间`,key:`created_at`,width:160}],V=[{title:`服务器`,key:`server_name`},{title:`状态`,key:`status`,width:80},{title:`来源`,key:`remote_addr`,width:120},{title:`开始时间`,key:`started_at`,width:160}];async function H(){M.value=!0;try{if(N.value===`commands`){let e=await m.getList(`/assets/command-logs`,{server_id:L.value||void 0,page:P.value,per_page:I.value});R.value=e.items,F.value=e.total}else{let e=await m.getList(`/assets/ssh-sessions`,{server_id:L.value||void 0,page:P.value,per_page:I.value});z.value=e.items,F.value=e.total}}catch(e){R.value=[],z.value=[],k(x(e,`加载命令日志失败`),`error`)}finally{M.value=!1}}return l(()=>{j(),H()}),(c,l)=>(s(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[u(r,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[u(e,{class:`d-flex align-center`},{default:p(()=>[l[4]||=a(` 命令日志 `,-1),u(b),u(v,{modelValue:N.value,"onUpdate:modelValue":[l[0]||=e=>N.value=e,H],items:[{title:`命令视图`,value:`commands`},{title:`会话视图`,value:`sessions`}],"item-title":`title`,"item-value":`value`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`}},null,8,[`modelValue`]),u(v,{modelValue:L.value,"onUpdate:modelValue":[l[1]||=e=>L.value=e,H],items:t(A),"item-title":`name`,"item-value":`id`,label:`服务器`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`180px`},class:`ml-3`,clearable:``},null,8,[`modelValue`,`items`])]),_:1}),u(n),N.value===`commands`?(s(),f(y,{key:0,items:R.value,headers:B,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":l[2]||=e=>{P.value=e,H()}},{"item.command":p(({item:e})=>[o(`code`,C,i(e.command),1)]),"item.server_name":p(({item:e})=>[o(`span`,w,i(e.server_name||``),1)]),"item.admin_username":p(({item:e})=>[o(`span`,T,i(e.admin_username||``),1)]),"item.created_at":p(({item:e})=>[o(`span`,E,i(e.created_at),1)]),"no-data":p(()=>[...l[5]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])):(s(),f(y,{key:1,items:z.value,headers:V,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":l[3]||=e=>{P.value=e,H()}},{"item.server_name":p(({item:e})=>[o(`span`,D,i(e.server_name||``),1)]),"item.status":p(({item:e})=>[u(_,{color:e.status===`closed`?`grey`:`success`,size:`small`,variant:`tonal`,label:``},{default:p(()=>[a(i(e.status),1)]),_:2},1032,[`color`])]),"item.started_at":p(({item:e})=>[o(`span`,O,i(e.started_at),1)]),"no-data":p(()=>[...l[6]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`]))]),_:1})]),_:1}))}});export{k as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,M as n,N as r,Vr as i,ar as a,er as o,gr as s,jr as c,mr as l,or as u,sr as d,tr as f,wr as p,zt as m}from"./index-DNlvHxBC.js";import{o as h,t as g}from"./VContainer-CbSJCQsb.js";import{t as _}from"./VChip-BbRVKa0H.js";import{t as v}from"./VSelect-D0AqVzoi.js";import{t as y}from"./VDataTableServer-BUUXYQSU.js";import{t as b}from"./VSpacer-DDACi18G.js";import{t as x}from"./apiError-DPkg25-7.js";import{t as S}from"./useServerList-CkRTXU3j.js";var C={class:`text-body-2`},w={class:`text-medium-emphasis`},T={class:`text-medium-emphasis`},E={class:`text-caption text-medium-emphasis`},D={class:`font-weight-medium`},O={class:`text-caption text-medium-emphasis`},k=d({__name:`CommandsPage`,setup(d){let k=h(),{servers:A,loadServers:j}=S(),M=c(!1),N=c(`commands`),P=c(1),F=c(0),I=c(30),L=c(null),R=c([]),z=c([]),B=[{title:`命令`,key:`command`},{title:`服务器`,key:`server_name`},{title:`用户`,key:`admin_username`,width:100},{title:`时间`,key:`created_at`,width:160}],V=[{title:`服务器`,key:`server_name`},{title:`状态`,key:`status`,width:80},{title:`来源`,key:`remote_addr`,width:120},{title:`开始时间`,key:`started_at`,width:160}];async function H(){M.value=!0;try{if(N.value===`commands`){let e=await m.getList(`/assets/command-logs`,{server_id:L.value||void 0,page:P.value,per_page:I.value});R.value=e.items,F.value=e.total}else{let e=await m.getList(`/assets/ssh-sessions`,{server_id:L.value||void 0,page:P.value,per_page:I.value});z.value=e.items,F.value=e.total}}catch(e){R.value=[],z.value=[],k(x(e,`加载命令日志失败`),`error`)}finally{M.value=!1}}return l(()=>{j(),H()}),(c,l)=>(s(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[u(r,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[u(e,{class:`d-flex align-center`},{default:p(()=>[l[4]||=a(` 命令日志 `,-1),u(b),u(v,{modelValue:N.value,"onUpdate:modelValue":[l[0]||=e=>N.value=e,H],items:[{title:`命令视图`,value:`commands`},{title:`会话视图`,value:`sessions`}],"item-title":`title`,"item-value":`value`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`}},null,8,[`modelValue`]),u(v,{modelValue:L.value,"onUpdate:modelValue":[l[1]||=e=>L.value=e,H],items:t(A),"item-title":`name`,"item-value":`id`,label:`服务器`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`180px`},class:`ml-3`,clearable:``},null,8,[`modelValue`,`items`])]),_:1}),u(n),N.value===`commands`?(s(),f(y,{key:0,items:R.value,headers:B,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":l[2]||=e=>{P.value=e,H()}},{"item.command":p(({item:e})=>[o(`code`,C,i(e.command),1)]),"item.server_name":p(({item:e})=>[o(`span`,w,i(e.server_name||``),1)]),"item.admin_username":p(({item:e})=>[o(`span`,T,i(e.admin_username||``),1)]),"item.created_at":p(({item:e})=>[o(`span`,E,i(e.created_at),1)]),"no-data":p(()=>[...l[5]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])):(s(),f(y,{key:1,items:z.value,headers:V,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":l[3]||=e=>{P.value=e,H()}},{"item.server_name":p(({item:e})=>[o(`span`,D,i(e.server_name||``),1)]),"item.status":p(({item:e})=>[u(_,{color:e.status===`closed`?`grey`:`success`,size:`small`,variant:`tonal`,label:``},{default:p(()=>[a(i(e.status),1)]),_:2},1032,[`color`])]),"item.started_at":p(({item:e})=>[o(`span`,O,i(e.started_at),1)]),"no-data":p(()=>[...l[6]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`]))]),_:1})]),_:1}))}});export{k as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,Lr as t,M as n,N as r,Vr as i,ar as a,er as o,gr as s,jr as c,mr as l,or as u,sr as d,tr as f,wr as p,zt as m}from"./index-BihgjXCy.js";import{o as h,t as g}from"./VContainer-V_R05OUP.js";import{t as _}from"./VChip-FKNgTWw3.js";import{t as v}from"./VSelect-CGF0mOJJ.js";import{t as y}from"./VDataTableServer-Pl72x6lf.js";import{t as b}from"./VSpacer-2YW4-MQQ.js";import{t as x}from"./apiError-BFaYYBmC.js";import{t as S}from"./useServerList-B6ZsiiQ2.js";var C={class:`text-body-2`},w={class:`text-medium-emphasis`},T={class:`text-medium-emphasis`},E={class:`text-caption text-medium-emphasis`},D={class:`font-weight-medium`},O={class:`text-caption text-medium-emphasis`},k=d({__name:`CommandsPage`,setup(d){let k=h(),{servers:A,loadServers:j}=S(),M=c(!1),N=c(`commands`),P=c(1),F=c(0),I=c(30),L=c(null),R=c([]),z=c([]),B=[{title:`命令`,key:`command`},{title:`服务器`,key:`server_name`},{title:`用户`,key:`admin_username`,width:100},{title:`时间`,key:`created_at`,width:160}],V=[{title:`服务器`,key:`server_name`},{title:`状态`,key:`status`,width:80},{title:`来源`,key:`remote_addr`,width:120},{title:`开始时间`,key:`started_at`,width:160}];async function H(){M.value=!0;try{if(N.value===`commands`){let e=await m.getList(`/assets/command-logs`,{server_id:L.value||void 0,page:P.value,per_page:I.value});R.value=e.items,F.value=e.total}else{let e=await m.getList(`/assets/ssh-sessions`,{server_id:L.value||void 0,page:P.value,per_page:I.value});z.value=e.items,F.value=e.total}}catch(e){R.value=[],z.value=[],k(x(e,`加载命令日志失败`),`error`)}finally{M.value=!1}}return l(()=>{j(),H()}),(c,l)=>(s(),f(g,{fluid:``,class:`pa-6`},{default:p(()=>[u(r,{elevation:`0`,border:``,rounded:`lg`},{default:p(()=>[u(e,{class:`d-flex align-center`},{default:p(()=>[l[4]||=a(` 命令日志 `,-1),u(b),u(v,{modelValue:N.value,"onUpdate:modelValue":[l[0]||=e=>N.value=e,H],items:[{title:`命令视图`,value:`commands`},{title:`会话视图`,value:`sessions`}],"item-title":`title`,"item-value":`value`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`}},null,8,[`modelValue`]),u(v,{modelValue:L.value,"onUpdate:modelValue":[l[1]||=e=>L.value=e,H],items:t(A),"item-title":`name`,"item-value":`id`,label:`服务器`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`180px`},class:`ml-3`,clearable:``},null,8,[`modelValue`,`items`])]),_:1}),u(n),N.value===`commands`?(s(),f(y,{key:0,items:R.value,headers:B,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":l[2]||=e=>{P.value=e,H()}},{"item.command":p(({item:e})=>[o(`code`,C,i(e.command),1)]),"item.server_name":p(({item:e})=>[o(`span`,w,i(e.server_name||``),1)]),"item.admin_username":p(({item:e})=>[o(`span`,T,i(e.admin_username||``),1)]),"item.created_at":p(({item:e})=>[o(`span`,E,i(e.created_at),1)]),"no-data":p(()=>[...l[5]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])):(s(),f(y,{key:1,items:z.value,headers:V,"items-length":F.value,loading:M.value,page:P.value,"items-per-page":30,hover:``,density:`compact`,"onUpdate:page":l[3]||=e=>{P.value=e,H()}},{"item.server_name":p(({item:e})=>[o(`span`,D,i(e.server_name||``),1)]),"item.status":p(({item:e})=>[u(_,{color:e.status===`closed`?`grey`:`success`,size:`small`,variant:`tonal`,label:``},{default:p(()=>[a(i(e.status),1)]),_:2},1032,[`color`])]),"item.started_at":p(({item:e})=>[o(`span`,O,i(e.started_at),1)]),"no-data":p(()=>[...l[6]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`]))]),_:1})]),_:1}))}});export{k as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{$n as e,Br as t,Ft as n,Ht as r,It as i,Lt as a,N as o,Sr as s,Ut as c,Vr as l,Xn as u,ar as d,c as f,er as p,fn as m,gr as h,hr as g,jr as _,l as v,ln as y,mr as b,nr as x,or as S,pn as C,rn as w,rr as T,sr as E,t as D,tr as O,v as k,wr as A,z as j,zr as M,zt as N}from"./index-CLVw8WaP.js";import{t as P}from"./VChip-CoJQpM5X.js";import{t as F}from"./_plugin-vue_export-helper-BDNMzG2s.js";import{t as I}from"./VAlert-DIQTIdOP.js";var L=C({...m(),...v()},`VForm`),R=y()({name:`VForm`,props:L(),emits:{"update:modelValue":e=>!0,submit:e=>!0},setup(e,{slots:n,emit:r}){let i=f(e),a=_();function o(e){e.preventDefault(),i.reset()}function s(e){let t=e,n=i.validate();t.then=n.then.bind(n),t.catch=n.catch.bind(n),t.finally=n.finally.bind(n),r(`submit`,t),t.defaultPrevented||n.then(({valid:e})=>{e&&a.value?.submit()}),t.preventDefault()}return w(()=>p(`form`,{ref:a,class:M([`v-form`,e.class]),style:t(e.style),novalidate:!0,onReset:o,onSubmit:s},[n.default?.({get errors(){return i.errors.value},get isDisabled(){return i.isDisabled.value},get isReadonly(){return i.isReadonly.value},get isValidating(){return i.isValidating.value},get isValid(){return i.isValid.value},get items(){return i.items.value},validate:i.validate,reset:i.reset,resetValidation:i.resetValidation})])),k(i,a)}}),z={class:`login-page`},B={class:`login-center`},V={key:2,class:`text-center mt-4`},H=F(E({__name:`LoginPage`,setup(f){let m=r(),v=c(),y=n(),C=_(``),w=_(``),E=_(``),k=_(!1),M=_(!1),F=_(``),L=_(!1),H=_(0),U=_(null),W=_([]),G=_(0),K=null,q=e(()=>W.value.length===0?``:W.value[G.value]);async function J(){try{let e=await N.get(`/settings/bing-wallpapers`);e?.urls?.length&&(W.value=e.urls,G.value=Math.floor(Math.random()*e.urls.length))}catch{}}function Y(){K&&clearInterval(K),!(W.value.length<=1)&&(K=setInterval(()=>{G.value=(G.value+1)%W.value.length},36e5))}b(async()=>{await J(),Y()}),g(()=>{K&&clearInterval(K),Z&&clearInterval(Z)});let X=_(Date.now()),Z=null,Q=e(()=>{if(!U.value)return 0;let e=new Date(U.value).getTime()-X.value;return Math.max(0,Math.ceil(e/6e4))});s(U,e=>{Z&&=(clearInterval(Z),null),e&&(Z=setInterval(()=>{X.value=Date.now()},3e4))});async function $(){if(!C.value||!w.value){F.value=`请输入用户名和密码`;return}M.value=!0,F.value=``;try{await y.login(C.value,w.value,L.value?E.value:void 0);let e=m.query.redirect||`/`,t=e.startsWith(`/`)&&!e.startsWith(`//`)?e:`/`;v.push(t)}catch(e){e instanceof a?(L.value=!0,F.value=e.message):e instanceof i?e.status===429?(U.value=new Date(Date.now()+900*1e3).toISOString(),F.value=`登录尝试过多,账户已锁定 15 分钟`):(H.value++,F.value=e.message):F.value=`网络错误,请重试`}finally{M.value=!1}}return(e,n)=>(h(),T(`div`,z,[p(`div`,{class:`wallpaper-bg`,style:t({backgroundImage:`url(${q.value})`})},null,4),n[6]||=p(`div`,{class:`wallpaper-overlay`},null,-1),p(`div`,B,[S(o,{elevation:`0`,rounded:`xl`,class:`login-card pa-10`,border:``},{default:A(()=>[F.value?(h(),O(I,{key:0,type:`error`,density:`compact`,class:`mb-4`,closable:``,"onClick:close":n[0]||=e=>F.value=``,rounded:`lg`,variant:`tonal`},{default:A(()=>[d(l(F.value),1)]),_:1})):x(``,!0),U.value?(h(),O(I,{key:1,type:`warning`,density:`compact`,class:`mb-4`,rounded:`lg`,variant:`tonal`},{default:A(()=>[d(` 账户已锁定,请 `+l(Q.value)+` 分钟后重试 `,1)]),_:1})):x(``,!0),S(R,{onSubmit:u($,[`prevent`])},{default:A(()=>[S(D,{modelValue:C.value,"onUpdate:modelValue":n[1]||=e=>C.value=e,label:`用户名`,variant:`outlined`,density:`comfortable`,"prepend-inner-icon":`mdi-account-outline`,disabled:M.value,class:`mb-4`,autocomplete:`username`,rounded:`lg`,"hide-details":`auto`},null,8,[`modelValue`,`disabled`]),S(D,{modelValue:w.value,"onUpdate:modelValue":n[2]||=e=>w.value=e,label:`密码`,variant:`outlined`,density:`comfortable`,"prepend-inner-icon":`mdi-lock-outline`,"append-inner-icon":k.value?`mdi-eye`:`mdi-eye-off`,type:k.value?`text`:`password`,"onClick:appendInner":n[3]||=e=>k.value=!k.value,disabled:M.value,class:`mb-4`,autocomplete:`current-password`,rounded:`lg`,"hide-details":`auto`},null,8,[`modelValue`,`append-inner-icon`,`type`,`disabled`]),L.value?(h(),O(D,{key:0,modelValue:E.value,"onUpdate:modelValue":n[4]||=e=>E.value=e,label:`TOTP 验证码`,variant:`outlined`,density:`comfortable`,"prepend-inner-icon":`mdi-shield-key-outline`,disabled:M.value,class:`mb-4`,autocomplete:`one-time-code`,rounded:`lg`,"hide-details":`auto`},null,8,[`modelValue`,`disabled`])):x(``,!0),S(j,{type:`submit`,color:`primary`,variant:`flat`,block:``,size:`large`,loading:M.value,disabled:!!U.value,rounded:`lg`,class:`mt-2`,height:`48`},{default:A(()=>[...n[5]||=[d(` 登录 `,-1)]]),_:1},8,[`loading`,`disabled`])]),_:1}),H.value>0&&!U.value?(h(),T(`div`,V,[S(P,{size:`small`,variant:`tonal`,color:`warning`,label:``},{default:A(()=>[d(` 已失败 `+l(H.value)+``,1)]),_:1})])):x(``,!0)]),_:1})])]))}}),[[`__scopeId`,`data-v-c0c6156f`]]);export{H as default};
+1
View File
@@ -0,0 +1 @@
import{$n as e,Br as t,Ft as n,Ht as r,It as i,Lt as a,N as o,Sr as s,Ut as c,Vr as l,Xn as u,ar as d,c as f,er as p,fn as m,gr as h,hr as g,jr as _,l as v,ln as y,mr as b,nr as x,or as S,pn as C,rn as w,rr as T,sr as E,t as D,tr as O,v as k,wr as A,z as j,zr as M,zt as N}from"./index-BihgjXCy.js";import{t as P}from"./VChip-FKNgTWw3.js";import{t as F}from"./_plugin-vue_export-helper-BDNMzG2s.js";import{t as I}from"./VAlert-Dm_0fgK_.js";var L=C({...m(),...v()},`VForm`),R=y()({name:`VForm`,props:L(),emits:{"update:modelValue":e=>!0,submit:e=>!0},setup(e,{slots:n,emit:r}){let i=f(e),a=_();function o(e){e.preventDefault(),i.reset()}function s(e){let t=e,n=i.validate();t.then=n.then.bind(n),t.catch=n.catch.bind(n),t.finally=n.finally.bind(n),r(`submit`,t),t.defaultPrevented||n.then(({valid:e})=>{e&&a.value?.submit()}),t.preventDefault()}return w(()=>p(`form`,{ref:a,class:M([`v-form`,e.class]),style:t(e.style),novalidate:!0,onReset:o,onSubmit:s},[n.default?.({get errors(){return i.errors.value},get isDisabled(){return i.isDisabled.value},get isReadonly(){return i.isReadonly.value},get isValidating(){return i.isValidating.value},get isValid(){return i.isValid.value},get items(){return i.items.value},validate:i.validate,reset:i.reset,resetValidation:i.resetValidation})])),k(i,a)}}),z={class:`login-page`},B={class:`login-center`},V={key:2,class:`text-center mt-4`},H=F(E({__name:`LoginPage`,setup(f){let m=r(),v=c(),y=n(),C=_(``),w=_(``),E=_(``),k=_(!1),M=_(!1),F=_(``),L=_(!1),H=_(0),U=_(null),W=_([]),G=_(0),K=null,q=e(()=>W.value.length===0?``:W.value[G.value]);async function J(){try{let e=await N.get(`/settings/bing-wallpapers`);e?.urls?.length&&(W.value=e.urls,G.value=Math.floor(Math.random()*e.urls.length))}catch{}}function Y(){K&&clearInterval(K),!(W.value.length<=1)&&(K=setInterval(()=>{G.value=(G.value+1)%W.value.length},36e5))}b(async()=>{await J(),Y()}),g(()=>{K&&clearInterval(K),Z&&clearInterval(Z)});let X=_(Date.now()),Z=null,Q=e(()=>{if(!U.value)return 0;let e=new Date(U.value).getTime()-X.value;return Math.max(0,Math.ceil(e/6e4))});s(U,e=>{Z&&=(clearInterval(Z),null),e&&(Z=setInterval(()=>{X.value=Date.now()},3e4))});async function $(){if(!C.value||!w.value){F.value=`请输入用户名和密码`;return}M.value=!0,F.value=``;try{await y.login(C.value,w.value,L.value?E.value:void 0);let e=m.query.redirect||`/`,t=e.startsWith(`/`)&&!e.startsWith(`//`)?e:`/`;v.push(t)}catch(e){e instanceof a?(L.value=!0,F.value=e.message):e instanceof i?e.status===429?(U.value=new Date(Date.now()+900*1e3).toISOString(),F.value=`登录尝试过多,账户已锁定 15 分钟`):(H.value++,F.value=e.message):F.value=`网络错误,请重试`}finally{M.value=!1}}return(e,n)=>(h(),T(`div`,z,[p(`div`,{class:`wallpaper-bg`,style:t({backgroundImage:`url(${q.value})`})},null,4),n[6]||=p(`div`,{class:`wallpaper-overlay`},null,-1),p(`div`,B,[S(o,{elevation:`0`,rounded:`xl`,class:`login-card pa-10`,border:``},{default:A(()=>[F.value?(h(),O(I,{key:0,type:`error`,density:`compact`,class:`mb-4`,closable:``,"onClick:close":n[0]||=e=>F.value=``,rounded:`lg`,variant:`tonal`},{default:A(()=>[d(l(F.value),1)]),_:1})):x(``,!0),U.value?(h(),O(I,{key:1,type:`warning`,density:`compact`,class:`mb-4`,rounded:`lg`,variant:`tonal`},{default:A(()=>[d(` 账户已锁定,请 `+l(Q.value)+` 分钟后重试 `,1)]),_:1})):x(``,!0),S(R,{onSubmit:u($,[`prevent`])},{default:A(()=>[S(D,{modelValue:C.value,"onUpdate:modelValue":n[1]||=e=>C.value=e,label:`用户名`,variant:`outlined`,density:`comfortable`,"prepend-inner-icon":`mdi-account-outline`,disabled:M.value,class:`mb-4`,autocomplete:`username`,rounded:`lg`,"hide-details":`auto`},null,8,[`modelValue`,`disabled`]),S(D,{modelValue:w.value,"onUpdate:modelValue":n[2]||=e=>w.value=e,label:`密码`,variant:`outlined`,density:`comfortable`,"prepend-inner-icon":`mdi-lock-outline`,"append-inner-icon":k.value?`mdi-eye`:`mdi-eye-off`,type:k.value?`text`:`password`,"onClick:appendInner":n[3]||=e=>k.value=!k.value,disabled:M.value,class:`mb-4`,autocomplete:`current-password`,rounded:`lg`,"hide-details":`auto`},null,8,[`modelValue`,`append-inner-icon`,`type`,`disabled`]),L.value?(h(),O(D,{key:0,modelValue:E.value,"onUpdate:modelValue":n[4]||=e=>E.value=e,label:`TOTP 验证码`,variant:`outlined`,density:`comfortable`,"prepend-inner-icon":`mdi-shield-key-outline`,disabled:M.value,class:`mb-4`,autocomplete:`one-time-code`,rounded:`lg`,"hide-details":`auto`},null,8,[`modelValue`,`disabled`])):x(``,!0),S(j,{type:`submit`,color:`primary`,variant:`flat`,block:``,size:`large`,loading:M.value,disabled:!!U.value,rounded:`lg`,class:`mt-2`,height:`48`},{default:A(()=>[...n[5]||=[d(` 登录 `,-1)]]),_:1},8,[`loading`,`disabled`])]),_:1}),H.value>0&&!U.value?(h(),T(`div`,V,[S(P,{size:`small`,variant:`tonal`,color:`warning`,label:``},{default:A(()=>[d(` 已失败 `+l(H.value)+``,1)]),_:1})])):x(``,!0)]),_:1})])]))}}),[[`__scopeId`,`data-v-c0c6156f`]]);export{H as default};
+1
View File
@@ -0,0 +1 @@
import{$n as e,Br as t,Ft as n,Ht as r,It as i,Lt as a,N as o,Sr as s,Ut as c,Vr as l,Xn as u,ar as d,c as f,er as p,fn as m,gr as h,hr as g,jr as _,l as v,ln as y,mr as b,nr as x,or as S,pn as C,rn as w,rr as T,sr as E,t as D,tr as O,v as k,wr as A,z as j,zr as M,zt as N}from"./index-DNlvHxBC.js";import{t as P}from"./VChip-BbRVKa0H.js";import{t as F}from"./_plugin-vue_export-helper-BDNMzG2s.js";import{t as I}from"./VAlert-rUS7Wker.js";var L=C({...m(),...v()},`VForm`),R=y()({name:`VForm`,props:L(),emits:{"update:modelValue":e=>!0,submit:e=>!0},setup(e,{slots:n,emit:r}){let i=f(e),a=_();function o(e){e.preventDefault(),i.reset()}function s(e){let t=e,n=i.validate();t.then=n.then.bind(n),t.catch=n.catch.bind(n),t.finally=n.finally.bind(n),r(`submit`,t),t.defaultPrevented||n.then(({valid:e})=>{e&&a.value?.submit()}),t.preventDefault()}return w(()=>p(`form`,{ref:a,class:M([`v-form`,e.class]),style:t(e.style),novalidate:!0,onReset:o,onSubmit:s},[n.default?.({get errors(){return i.errors.value},get isDisabled(){return i.isDisabled.value},get isReadonly(){return i.isReadonly.value},get isValidating(){return i.isValidating.value},get isValid(){return i.isValid.value},get items(){return i.items.value},validate:i.validate,reset:i.reset,resetValidation:i.resetValidation})])),k(i,a)}}),z={class:`login-page`},B={class:`login-center`},V={key:2,class:`text-center mt-4`},H=F(E({__name:`LoginPage`,setup(f){let m=r(),v=c(),y=n(),C=_(``),w=_(``),E=_(``),k=_(!1),M=_(!1),F=_(``),L=_(!1),H=_(0),U=_(null),W=_([]),G=_(0),K=null,q=e(()=>W.value.length===0?``:W.value[G.value]);async function J(){try{let e=await N.get(`/settings/bing-wallpapers`);e?.urls?.length&&(W.value=e.urls,G.value=Math.floor(Math.random()*e.urls.length))}catch{}}function Y(){K&&clearInterval(K),!(W.value.length<=1)&&(K=setInterval(()=>{G.value=(G.value+1)%W.value.length},36e5))}b(async()=>{await J(),Y()}),g(()=>{K&&clearInterval(K),Z&&clearInterval(Z)});let X=_(Date.now()),Z=null,Q=e(()=>{if(!U.value)return 0;let e=new Date(U.value).getTime()-X.value;return Math.max(0,Math.ceil(e/6e4))});s(U,e=>{Z&&=(clearInterval(Z),null),e&&(Z=setInterval(()=>{X.value=Date.now()},3e4))});async function $(){if(!C.value||!w.value){F.value=`请输入用户名和密码`;return}M.value=!0,F.value=``;try{await y.login(C.value,w.value,L.value?E.value:void 0);let e=m.query.redirect||`/`,t=e.startsWith(`/`)&&!e.startsWith(`//`)?e:`/`;v.push(t)}catch(e){e instanceof a?(L.value=!0,F.value=e.message):e instanceof i?e.status===429?(U.value=new Date(Date.now()+900*1e3).toISOString(),F.value=`登录尝试过多,账户已锁定 15 分钟`):(H.value++,F.value=e.message):F.value=`网络错误,请重试`}finally{M.value=!1}}return(e,n)=>(h(),T(`div`,z,[p(`div`,{class:`wallpaper-bg`,style:t({backgroundImage:`url(${q.value})`})},null,4),n[6]||=p(`div`,{class:`wallpaper-overlay`},null,-1),p(`div`,B,[S(o,{elevation:`0`,rounded:`xl`,class:`login-card pa-10`,border:``},{default:A(()=>[F.value?(h(),O(I,{key:0,type:`error`,density:`compact`,class:`mb-4`,closable:``,"onClick:close":n[0]||=e=>F.value=``,rounded:`lg`,variant:`tonal`},{default:A(()=>[d(l(F.value),1)]),_:1})):x(``,!0),U.value?(h(),O(I,{key:1,type:`warning`,density:`compact`,class:`mb-4`,rounded:`lg`,variant:`tonal`},{default:A(()=>[d(` 账户已锁定,请 `+l(Q.value)+` 分钟后重试 `,1)]),_:1})):x(``,!0),S(R,{onSubmit:u($,[`prevent`])},{default:A(()=>[S(D,{modelValue:C.value,"onUpdate:modelValue":n[1]||=e=>C.value=e,label:`用户名`,variant:`outlined`,density:`comfortable`,"prepend-inner-icon":`mdi-account-outline`,disabled:M.value,class:`mb-4`,autocomplete:`username`,rounded:`lg`,"hide-details":`auto`},null,8,[`modelValue`,`disabled`]),S(D,{modelValue:w.value,"onUpdate:modelValue":n[2]||=e=>w.value=e,label:`密码`,variant:`outlined`,density:`comfortable`,"prepend-inner-icon":`mdi-lock-outline`,"append-inner-icon":k.value?`mdi-eye`:`mdi-eye-off`,type:k.value?`text`:`password`,"onClick:appendInner":n[3]||=e=>k.value=!k.value,disabled:M.value,class:`mb-4`,autocomplete:`current-password`,rounded:`lg`,"hide-details":`auto`},null,8,[`modelValue`,`append-inner-icon`,`type`,`disabled`]),L.value?(h(),O(D,{key:0,modelValue:E.value,"onUpdate:modelValue":n[4]||=e=>E.value=e,label:`TOTP 验证码`,variant:`outlined`,density:`comfortable`,"prepend-inner-icon":`mdi-shield-key-outline`,disabled:M.value,class:`mb-4`,autocomplete:`one-time-code`,rounded:`lg`,"hide-details":`auto`},null,8,[`modelValue`,`disabled`])):x(``,!0),S(j,{type:`submit`,color:`primary`,variant:`flat`,block:``,size:`large`,loading:M.value,disabled:!!U.value,rounded:`lg`,class:`mt-2`,height:`48`},{default:A(()=>[...n[5]||=[d(` 登录 `,-1)]]),_:1},8,[`loading`,`disabled`])]),_:1}),H.value>0&&!U.value?(h(),T(`div`,V,[S(P,{size:`small`,variant:`tonal`,color:`warning`,label:``},{default:A(()=>[d(` 已失败 `+l(H.value)+``,1)]),_:1})])):x(``,!0)]),_:1})])]))}}),[[`__scopeId`,`data-v-c0c6156f`]]);export{H as default};
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
.cursor-pointer[data-v-5939ddcd]{cursor:pointer}.delete-target-list[data-v-5939ddcd]{max-height:200px;overflow-y:auto}.staging-preview-body[data-v-adb4800a]{background:rgba(var(--v-theme-on-surface), .04);white-space:pre-wrap;word-break:break-all;border-radius:8px;max-height:420px;margin:0;padding:12px;font-size:12px;line-height:1.5;overflow:auto}@layer vuetify-components{.v-radio-group>.v-input__control{flex-direction:column}.v-radio-group>.v-input__control>.v-label{margin-inline-start:16px}.v-radio-group>.v-input__control>.v-label+.v-selection-control-group{margin-top:8px;padding-inline-start:6px}}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{F as e,L as t,N as n,P as r,Vr as i,ar as a,er as o,gr as s,jr as c,mr as l,nr as u,or as d,sr as f,tr as p,wr as m,z as h,zt as g}from"./index-CLVw8WaP.js";import{o as _,t as v}from"./VContainer-FlPueFWR.js";import{t as y}from"./VChip-CoJQpM5X.js";import{t as b}from"./VSelect-C9Xea3xT.js";import{t as x}from"./VDataTableServer-CihJhzNQ.js";import{t as S}from"./VSpacer-BKvfPYW2.js";import{t as C}from"./VDialog-dL9hfbvp.js";var w={class:`font-weight-medium text-truncate d-inline-block`,style:{"max-width":`240px`}},T={class:`text-medium-emphasis`},E={class:`text-medium-emphasis`},D={class:`text-caption text-medium-emphasis`},O={class:`text-caption text-medium-emphasis`},k=f({__name:`RetriesPage`,setup(f){let k=_(),A=c(!1),j=c([]),M=c(0),N=c(1),P=c(null),F=c(!1),I=c(null),L=[{label:`待重试`,value:`pending`},{label:`重试中`,value:`retrying`},{label:`成功`,value:`success`},{label:`失败`,value:`failed`}],R=[{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`,sortable:!1}];async function z(){A.value=!0;try{let e=(await g.getList(`/retries/`,{limit:200})).items||[];P.value&&(e=e.filter(e=>e.status===P.value)),M.value=e.length;let t=(N.value-1)*20;j.value=e.slice(t,t+20)}catch(e){j.value=[],M.value=0,k(e instanceof Error?e.message:`加载重试队列失败`,`error`)}finally{A.value=!1}}async function B(e){try{await g.post(`/retries/${e.id}/retry`),z(),k(`重试已触发`)}catch(e){k(e.message||`操作失败`,`error`)}}function V(e){I.value=e.id,F.value=!0}async function H(){if(I.value)try{await g.delete(`/retries/${I.value}`),F.value=!1,z(),k(`已删除`)}catch(e){k(e.message||`删除失败`,`error`)}}function U(e){return e===`success`?`success`:e===`failed`?`error`:e===`retrying`?`warning`:`info`}function W(e){return e===`pending`?`待重试`:e===`retrying`?`重试中`:e===`success`?`成功`:e===`failed`?`失败`:e}function G(e){return e.source_path&&e.target_path?`${e.source_path}${e.target_path}`:e.source_path||e.target_path||`文件推送`}return l(()=>z()),(c,l)=>(s(),p(v,{fluid:``,class:`pa-6`},{default:m(()=>[d(n,{elevation:`0`,border:``,rounded:`lg`},{default:m(()=>[d(e,{class:`d-flex align-center text-h6`},{default:m(()=>[l[5]||=a(` 重试队列 `,-1),d(S),d(b,{modelValue:P.value,"onUpdate:modelValue":[l[0]||=e=>P.value=e,l[1]||=e=>{N.value=1,z()}],items:L,"item-title":`label`,"item-value":`value`,label:`状态筛选`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},clearable:``},null,8,[`modelValue`])]),_:1}),d(x,{items:j.value,headers:R,"items-length":M.value,loading:A.value,page:N.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":l[2]||=e=>{N.value=e,z()}},{"item.status":m(({item:e})=>[d(y,{color:U(e.status),size:`x-small`,variant:`tonal`,label:``,border:`sm`},{default:m(()=>[a(i(W(e.status)),1)]),_:2},1032,[`color`])]),"item.operation":m(({item:e})=>[o(`span`,w,i(G(e)),1)]),"item.server_name":m(({item:e})=>[o(`span`,T,i(e.server_name||``),1)]),"item.retry_count":m(({item:e})=>[o(`span`,E,i(e.retry_count||0)+` / `+i(e.max_retries||3),1)]),"item.next_retry_at":m(({item:e})=>[o(`span`,D,i(e.next_retry_at||``),1)]),"item.created_at":m(({item:e})=>[o(`span`,O,i(e.created_at),1)]),"item.actions":m(({item:e})=>[e.status===`pending`||e.status===`failed`?(s(),p(h,{key:0,variant:`text`,size:`x-small`,color:`primary`,density:`compact`,onClick:t=>B(e)},{default:m(()=>[...l[6]||=[a(` 重试 `,-1)]]),_:1},8,[`onClick`])):u(``,!0),d(h,{variant:`text`,size:`x-small`,color:`error`,density:`compact`,onClick:t=>V(e)},{default:m(()=>[...l[7]||=[a(` 删除 `,-1)]]),_:1},8,[`onClick`])]),"no-data":m(()=>[...l[8]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1}),d(C,{modelValue:F.value,"onUpdate:modelValue":l[4]||=e=>F.value=e,"max-width":`400`},{default:m(()=>[d(n,{border:``},{default:m(()=>[d(e,null,{default:m(()=>[...l[9]||=[a(`确认删除`,-1)]]),_:1}),d(r,null,{default:m(()=>[...l[10]||=[a(`确定要删除此重试任务吗?`,-1)]]),_:1}),d(t,null,{default:m(()=>[d(S),d(h,{variant:`text`,onClick:l[3]||=e=>F.value=!1},{default:m(()=>[...l[11]||=[a(`取消`,-1)]]),_:1}),d(h,{color:`error`,variant:`flat`,onClick:H},{default:m(()=>[...l[12]||=[a(`删除`,-1)]]),_:1})]),_:1})]),_:1})]),_:1},8,[`modelValue`])]),_:1}))}});export{k as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,L as t,N as n,P as r,Vr as i,ar as a,er as o,gr as s,jr as c,mr as l,nr as u,or as d,sr as f,tr as p,wr as m,z as h,zt as g}from"./index-BihgjXCy.js";import{o as _,t as v}from"./VContainer-V_R05OUP.js";import{t as y}from"./VChip-FKNgTWw3.js";import{t as b}from"./VSelect-CGF0mOJJ.js";import{t as x}from"./VDataTableServer-Pl72x6lf.js";import{t as S}from"./VSpacer-2YW4-MQQ.js";import{t as C}from"./VDialog-C6lmIorM.js";var w={class:`font-weight-medium text-truncate d-inline-block`,style:{"max-width":`240px`}},T={class:`text-medium-emphasis`},E={class:`text-medium-emphasis`},D={class:`text-caption text-medium-emphasis`},O={class:`text-caption text-medium-emphasis`},k=f({__name:`RetriesPage`,setup(f){let k=_(),A=c(!1),j=c([]),M=c(0),N=c(1),P=c(null),F=c(!1),I=c(null),L=[{label:`待重试`,value:`pending`},{label:`重试中`,value:`retrying`},{label:`成功`,value:`success`},{label:`失败`,value:`failed`}],R=[{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`,sortable:!1}];async function z(){A.value=!0;try{let e=(await g.getList(`/retries/`,{limit:200})).items||[];P.value&&(e=e.filter(e=>e.status===P.value)),M.value=e.length;let t=(N.value-1)*20;j.value=e.slice(t,t+20)}catch(e){j.value=[],M.value=0,k(e instanceof Error?e.message:`加载重试队列失败`,`error`)}finally{A.value=!1}}async function B(e){try{await g.post(`/retries/${e.id}/retry`),z(),k(`重试已触发`)}catch(e){k(e.message||`操作失败`,`error`)}}function V(e){I.value=e.id,F.value=!0}async function H(){if(I.value)try{await g.delete(`/retries/${I.value}`),F.value=!1,z(),k(`已删除`)}catch(e){k(e.message||`删除失败`,`error`)}}function U(e){return e===`success`?`success`:e===`failed`?`error`:e===`retrying`?`warning`:`info`}function W(e){return e===`pending`?`待重试`:e===`retrying`?`重试中`:e===`success`?`成功`:e===`failed`?`失败`:e}function G(e){return e.source_path&&e.target_path?`${e.source_path}${e.target_path}`:e.source_path||e.target_path||`文件推送`}return l(()=>z()),(c,l)=>(s(),p(v,{fluid:``,class:`pa-6`},{default:m(()=>[d(n,{elevation:`0`,border:``,rounded:`lg`},{default:m(()=>[d(e,{class:`d-flex align-center text-h6`},{default:m(()=>[l[5]||=a(` 重试队列 `,-1),d(S),d(b,{modelValue:P.value,"onUpdate:modelValue":[l[0]||=e=>P.value=e,l[1]||=e=>{N.value=1,z()}],items:L,"item-title":`label`,"item-value":`value`,label:`状态筛选`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},clearable:``},null,8,[`modelValue`])]),_:1}),d(x,{items:j.value,headers:R,"items-length":M.value,loading:A.value,page:N.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":l[2]||=e=>{N.value=e,z()}},{"item.status":m(({item:e})=>[d(y,{color:U(e.status),size:`x-small`,variant:`tonal`,label:``,border:`sm`},{default:m(()=>[a(i(W(e.status)),1)]),_:2},1032,[`color`])]),"item.operation":m(({item:e})=>[o(`span`,w,i(G(e)),1)]),"item.server_name":m(({item:e})=>[o(`span`,T,i(e.server_name||``),1)]),"item.retry_count":m(({item:e})=>[o(`span`,E,i(e.retry_count||0)+` / `+i(e.max_retries||3),1)]),"item.next_retry_at":m(({item:e})=>[o(`span`,D,i(e.next_retry_at||``),1)]),"item.created_at":m(({item:e})=>[o(`span`,O,i(e.created_at),1)]),"item.actions":m(({item:e})=>[e.status===`pending`||e.status===`failed`?(s(),p(h,{key:0,variant:`text`,size:`x-small`,color:`primary`,density:`compact`,onClick:t=>B(e)},{default:m(()=>[...l[6]||=[a(` 重试 `,-1)]]),_:1},8,[`onClick`])):u(``,!0),d(h,{variant:`text`,size:`x-small`,color:`error`,density:`compact`,onClick:t=>V(e)},{default:m(()=>[...l[7]||=[a(` 删除 `,-1)]]),_:1},8,[`onClick`])]),"no-data":m(()=>[...l[8]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1}),d(C,{modelValue:F.value,"onUpdate:modelValue":l[4]||=e=>F.value=e,"max-width":`400`},{default:m(()=>[d(n,{border:``},{default:m(()=>[d(e,null,{default:m(()=>[...l[9]||=[a(`确认删除`,-1)]]),_:1}),d(r,null,{default:m(()=>[...l[10]||=[a(`确定要删除此重试任务吗?`,-1)]]),_:1}),d(t,null,{default:m(()=>[d(S),d(h,{variant:`text`,onClick:l[3]||=e=>F.value=!1},{default:m(()=>[...l[11]||=[a(`取消`,-1)]]),_:1}),d(h,{color:`error`,variant:`flat`,onClick:H},{default:m(()=>[...l[12]||=[a(`删除`,-1)]]),_:1})]),_:1})]),_:1})]),_:1},8,[`modelValue`])]),_:1}))}});export{k as default};
+1
View File
@@ -0,0 +1 @@
import{F as e,L as t,N as n,P as r,Vr as i,ar as a,er as o,gr as s,jr as c,mr as l,nr as u,or as d,sr as f,tr as p,wr as m,z as h,zt as g}from"./index-DNlvHxBC.js";import{o as _,t as v}from"./VContainer-CbSJCQsb.js";import{t as y}from"./VChip-BbRVKa0H.js";import{t as b}from"./VSelect-D0AqVzoi.js";import{t as x}from"./VDataTableServer-BUUXYQSU.js";import{t as S}from"./VSpacer-DDACi18G.js";import{t as C}from"./VDialog-CCk-u1DS.js";var w={class:`font-weight-medium text-truncate d-inline-block`,style:{"max-width":`240px`}},T={class:`text-medium-emphasis`},E={class:`text-medium-emphasis`},D={class:`text-caption text-medium-emphasis`},O={class:`text-caption text-medium-emphasis`},k=f({__name:`RetriesPage`,setup(f){let k=_(),A=c(!1),j=c([]),M=c(0),N=c(1),P=c(null),F=c(!1),I=c(null),L=[{label:`待重试`,value:`pending`},{label:`重试中`,value:`retrying`},{label:`成功`,value:`success`},{label:`失败`,value:`failed`}],R=[{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`,sortable:!1}];async function z(){A.value=!0;try{let e=(await g.getList(`/retries/`,{limit:200})).items||[];P.value&&(e=e.filter(e=>e.status===P.value)),M.value=e.length;let t=(N.value-1)*20;j.value=e.slice(t,t+20)}catch(e){j.value=[],M.value=0,k(e instanceof Error?e.message:`加载重试队列失败`,`error`)}finally{A.value=!1}}async function B(e){try{await g.post(`/retries/${e.id}/retry`),z(),k(`重试已触发`)}catch(e){k(e.message||`操作失败`,`error`)}}function V(e){I.value=e.id,F.value=!0}async function H(){if(I.value)try{await g.delete(`/retries/${I.value}`),F.value=!1,z(),k(`已删除`)}catch(e){k(e.message||`删除失败`,`error`)}}function U(e){return e===`success`?`success`:e===`failed`?`error`:e===`retrying`?`warning`:`info`}function W(e){return e===`pending`?`待重试`:e===`retrying`?`重试中`:e===`success`?`成功`:e===`failed`?`失败`:e}function G(e){return e.source_path&&e.target_path?`${e.source_path}${e.target_path}`:e.source_path||e.target_path||`文件推送`}return l(()=>z()),(c,l)=>(s(),p(v,{fluid:``,class:`pa-6`},{default:m(()=>[d(n,{elevation:`0`,border:``,rounded:`lg`},{default:m(()=>[d(e,{class:`d-flex align-center text-h6`},{default:m(()=>[l[5]||=a(` 重试队列 `,-1),d(S),d(b,{modelValue:P.value,"onUpdate:modelValue":[l[0]||=e=>P.value=e,l[1]||=e=>{N.value=1,z()}],items:L,"item-title":`label`,"item-value":`value`,label:`状态筛选`,variant:`outlined`,density:`compact`,"hide-details":``,style:{"max-width":`160px`},clearable:``},null,8,[`modelValue`])]),_:1}),d(x,{items:j.value,headers:R,"items-length":M.value,loading:A.value,page:N.value,"items-per-page":20,hover:``,density:`comfortable`,"onUpdate:page":l[2]||=e=>{N.value=e,z()}},{"item.status":m(({item:e})=>[d(y,{color:U(e.status),size:`x-small`,variant:`tonal`,label:``,border:`sm`},{default:m(()=>[a(i(W(e.status)),1)]),_:2},1032,[`color`])]),"item.operation":m(({item:e})=>[o(`span`,w,i(G(e)),1)]),"item.server_name":m(({item:e})=>[o(`span`,T,i(e.server_name||``),1)]),"item.retry_count":m(({item:e})=>[o(`span`,E,i(e.retry_count||0)+` / `+i(e.max_retries||3),1)]),"item.next_retry_at":m(({item:e})=>[o(`span`,D,i(e.next_retry_at||``),1)]),"item.created_at":m(({item:e})=>[o(`span`,O,i(e.created_at),1)]),"item.actions":m(({item:e})=>[e.status===`pending`||e.status===`failed`?(s(),p(h,{key:0,variant:`text`,size:`x-small`,color:`primary`,density:`compact`,onClick:t=>B(e)},{default:m(()=>[...l[6]||=[a(` 重试 `,-1)]]),_:1},8,[`onClick`])):u(``,!0),d(h,{variant:`text`,size:`x-small`,color:`error`,density:`compact`,onClick:t=>V(e)},{default:m(()=>[...l[7]||=[a(` 删除 `,-1)]]),_:1},8,[`onClick`])]),"no-data":m(()=>[...l[8]||=[o(`div`,{class:`text-center text-medium-emphasis py-6`},`暂无数据`,-1)]]),_:1},8,[`items`,`items-length`,`loading`,`page`])]),_:1}),d(C,{modelValue:F.value,"onUpdate:modelValue":l[4]||=e=>F.value=e,"max-width":`400`},{default:m(()=>[d(n,{border:``},{default:m(()=>[d(e,null,{default:m(()=>[...l[9]||=[a(`确认删除`,-1)]]),_:1}),d(r,null,{default:m(()=>[...l[10]||=[a(`确定要删除此重试任务吗?`,-1)]]),_:1}),d(t,null,{default:m(()=>[d(S),d(h,{variant:`text`,onClick:l[3]||=e=>F.value=!1},{default:m(()=>[...l[11]||=[a(`取消`,-1)]]),_:1}),d(h,{color:`error`,variant:`flat`,onClick:H},{default:m(()=>[...l[12]||=[a(`删除`,-1)]]),_:1})]),_:1})]),_:1})]),_:1},8,[`modelValue`])]),_:1}))}});export{k as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
.script-content-editor[data-v-8c9e5994]{border:1px solid rgba(var(--v-border-color), var(--v-border-opacity));border-radius:8px;height:360px;overflow:hidden}
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{N as e,P as t,R as n,Vr as r,Z as i,Zn as a,er as o,gr as s,hr as c,jr as l,or as u,rr as d,sr as f,tr as p,vr as m,wr as h,zr as g,zt as _}from"./index-BihgjXCy.js";import{n as v,t as y}from"./VRow-D6NnUZV_.js";import{t as b}from"./_plugin-vue_export-helper-BDNMzG2s.js";function x(){let e=l([]),t=l(!1),n=l(1),r=l(20),i=l(0),a=l(``);async function o(){t.value=!0;try{let t=await _.get(`/servers/`,{page:n.value,per_page:r.value,search:a.value||void 0});e.value=t.items||[],i.value=t.total||0}catch(t){throw e.value=[],i.value=0,t}finally{t.value=!1}}let s;c(()=>clearTimeout(s));function u(){clearTimeout(s),s=setTimeout(()=>{n.value=1,o()},300)}function d(e){n.value=e,o()}function f(e){r.value=e,n.value=1,o()}return{servers:e,loading:t,page:n,itemsPerPage:r,total:i,search:a,loadServers:o,onSearch:u,onPageChange:d,onItemsPerPageChange:f}}function S(e){switch(e){case`online`:return`success`;case`offline`:return`error`;default:return`warning`}}function C(e){switch(e){case`online`:return`在线`;case`offline`:return`离线`;default:return`未知`}}function w(e){if(!e)return``;let t=new Date(e);if(isNaN(t.getTime()))return``;let n=Date.now()-t.getTime();return n<6e4?`刚刚`:n<36e5?`${Math.floor(n/6e4)} 分钟前`:n<864e5?`${Math.floor(n/36e5)} 小时前`:`${Math.floor(n/864e5)} 天前`}var T={class:`text-caption text-medium-emphasis mb-1`,style:{"font-size":`14px`,"letter-spacing":`0.5px`,"text-transform":`uppercase`}},E=b(f({__name:`StatCardsRow`,props:{items:{}},setup(c){return(l,f)=>(s(),p(y,null,{default:h(()=>[(s(!0),d(a,null,m(c.items,(a,c)=>(s(),p(v,{key:c,cols:`6`,sm:`3`},{default:h(()=>[u(e,{elevation:`0`,rounded:`xl`,border:``,class:`stat-card`},{default:h(()=>[u(t,{class:`pa-4 d-flex align-center justify-space-between`},{default:h(()=>[o(`div`,null,[o(`div`,T,r(a.subtitle),1),o(`div`,{class:g([`font-weight-bold`,`text-`+a.color]),style:{"font-size":`36px`,"line-height":`1.1`}},r(a.title),3)]),u(n,{color:a.color,size:`48`,rounded:`lg`,class:`stat-icon`},{default:h(()=>[u(i,{icon:a.icon,size:`24`,color:`white`},null,8,[`icon`])]),_:2},1032,[`color`])]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}))}}),[[`__scopeId`,`data-v-68b984da`]]);export{x as a,C as i,w as n,S as r,E as t};
+1
View File
@@ -0,0 +1 @@
import{N as e,P as t,R as n,Vr as r,Z as i,Zn as a,er as o,gr as s,hr as c,jr as l,or as u,rr as d,sr as f,tr as p,vr as m,wr as h,zr as g,zt as _}from"./index-CLVw8WaP.js";import{n as v,t as y}from"./VRow-CGrZcJ6l.js";import{t as b}from"./_plugin-vue_export-helper-BDNMzG2s.js";function x(){let e=l([]),t=l(!1),n=l(1),r=l(20),i=l(0),a=l(``);async function o(){t.value=!0;try{let t=await _.get(`/servers/`,{page:n.value,per_page:r.value,search:a.value||void 0});e.value=t.items||[],i.value=t.total||0}catch(t){throw e.value=[],i.value=0,t}finally{t.value=!1}}let s;c(()=>clearTimeout(s));function u(){clearTimeout(s),s=setTimeout(()=>{n.value=1,o()},300)}function d(e){n.value=e,o()}function f(e){r.value=e,n.value=1,o()}return{servers:e,loading:t,page:n,itemsPerPage:r,total:i,search:a,loadServers:o,onSearch:u,onPageChange:d,onItemsPerPageChange:f}}function S(e){switch(e){case`online`:return`success`;case`offline`:return`error`;default:return`warning`}}function C(e){switch(e){case`online`:return`在线`;case`offline`:return`离线`;default:return`未知`}}function w(e){if(!e)return``;let t=new Date(e);if(isNaN(t.getTime()))return``;let n=Date.now()-t.getTime();return n<6e4?`刚刚`:n<36e5?`${Math.floor(n/6e4)} 分钟前`:n<864e5?`${Math.floor(n/36e5)} 小时前`:`${Math.floor(n/864e5)} 天前`}var T={class:`text-caption text-medium-emphasis mb-1`,style:{"font-size":`14px`,"letter-spacing":`0.5px`,"text-transform":`uppercase`}},E=b(f({__name:`StatCardsRow`,props:{items:{}},setup(c){return(l,f)=>(s(),p(y,null,{default:h(()=>[(s(!0),d(a,null,m(c.items,(a,c)=>(s(),p(v,{key:c,cols:`6`,sm:`3`},{default:h(()=>[u(e,{elevation:`0`,rounded:`xl`,border:``,class:`stat-card`},{default:h(()=>[u(t,{class:`pa-4 d-flex align-center justify-space-between`},{default:h(()=>[o(`div`,null,[o(`div`,T,r(a.subtitle),1),o(`div`,{class:g([`font-weight-bold`,`text-`+a.color]),style:{"font-size":`36px`,"line-height":`1.1`}},r(a.title),3)]),u(n,{color:a.color,size:`48`,rounded:`lg`,class:`stat-icon`},{default:h(()=>[u(i,{icon:a.icon,size:`24`,color:`white`},null,8,[`icon`])]),_:2},1032,[`color`])]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}))}}),[[`__scopeId`,`data-v-68b984da`]]);export{x as a,C as i,w as n,S as r,E as t};
+1
View File
@@ -0,0 +1 @@
import{N as e,P as t,R as n,Vr as r,Z as i,Zn as a,er as o,gr as s,hr as c,jr as l,or as u,rr as d,sr as f,tr as p,vr as m,wr as h,zr as g,zt as _}from"./index-DNlvHxBC.js";import{n as v,t as y}from"./VRow-DW-g9AN1.js";import{t as b}from"./_plugin-vue_export-helper-BDNMzG2s.js";function x(){let e=l([]),t=l(!1),n=l(1),r=l(20),i=l(0),a=l(``);async function o(){t.value=!0;try{let t=await _.get(`/servers/`,{page:n.value,per_page:r.value,search:a.value||void 0});e.value=t.items||[],i.value=t.total||0}catch(t){throw e.value=[],i.value=0,t}finally{t.value=!1}}let s;c(()=>clearTimeout(s));function u(){clearTimeout(s),s=setTimeout(()=>{n.value=1,o()},300)}function d(e){n.value=e,o()}function f(e){r.value=e,n.value=1,o()}return{servers:e,loading:t,page:n,itemsPerPage:r,total:i,search:a,loadServers:o,onSearch:u,onPageChange:d,onItemsPerPageChange:f}}function S(e){switch(e){case`online`:return`success`;case`offline`:return`error`;default:return`warning`}}function C(e){switch(e){case`online`:return`在线`;case`offline`:return`离线`;default:return`未知`}}function w(e){if(!e)return``;let t=new Date(e);if(isNaN(t.getTime()))return``;let n=Date.now()-t.getTime();return n<6e4?`刚刚`:n<36e5?`${Math.floor(n/6e4)} 分钟前`:n<864e5?`${Math.floor(n/36e5)} 小时前`:`${Math.floor(n/864e5)} 天前`}var T={class:`text-caption text-medium-emphasis mb-1`,style:{"font-size":`14px`,"letter-spacing":`0.5px`,"text-transform":`uppercase`}},E=b(f({__name:`StatCardsRow`,props:{items:{}},setup(c){return(l,f)=>(s(),p(y,null,{default:h(()=>[(s(!0),d(a,null,m(c.items,(a,c)=>(s(),p(v,{key:c,cols:`6`,sm:`3`},{default:h(()=>[u(e,{elevation:`0`,rounded:`xl`,border:``,class:`stat-card`},{default:h(()=>[u(t,{class:`pa-4 d-flex align-center justify-space-between`},{default:h(()=>[o(`div`,null,[o(`div`,T,r(a.subtitle),1),o(`div`,{class:g([`font-weight-bold`,`text-`+a.color]),style:{"font-size":`36px`,"line-height":`1.1`}},r(a.title),3)]),u(n,{color:a.color,size:`48`,rounded:`lg`,class:`stat-icon`},{default:h(()=>[u(i,{icon:a.icon,size:`24`,color:`white`},null,8,[`icon`])]),_:2},1032,[`color`])]),_:2},1024)]),_:2},1024)]),_:2},1024))),128))]),_:1}))}}),[[`__scopeId`,`data-v-68b984da`]]);export{x as a,C as i,w as n,S as r,E as t};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{$n as e,Br as t,Ct as n,Et as r,G as i,Gt as a,Kt as o,Mt as s,Pr as c,Qt as l,Tt as u,W as d,Z as f,at as p,bt as m,ct as h,dt as g,en as _,er as v,fn as y,ft as b,ln as x,lt as S,mt as C,nn as w,or as T,ot as E,pn as D,pt as O,sn as k,st as A,ur as j,wt as M,xt as N,z as P,zr as F}from"./index-CLVw8WaP.js";var I=k(`v-alert-title`),L=D({iconSize:[Number,String],iconSizes:{type:Array,default:()=>[[`x-small`,10],[`small`,16],[`default`,24],[`large`,28],[`x-large`,32]]}},`iconSize`);function R(t,n){return{iconSize:e(()=>{let e=new Map(t.iconSizes),r=t.iconSize??n()??`default`;return e.has(r)?e.get(r):r})}}var z=[`success`,`info`,`warning`,`error`],B=D({border:{type:[Boolean,String],validator:e=>typeof e==`boolean`||[`top`,`end`,`bottom`,`start`].includes(e)},borderColor:String,closable:Boolean,closeIcon:{type:w,default:`$close`},closeLabel:{type:String,default:`$vuetify.close`},icon:{type:[Boolean,String,Function,Object],default:null},modelValue:{type:Boolean,default:!0},prominent:Boolean,title:String,text:String,type:{type:String,validator:e=>z.includes(e)},...y(),...h(),...M(),...O(),...L(),...g(),...d(),...m(),...s(),...a(),...E({variant:`flat`})},`VAlert`),V=x()({name:`VAlert`,props:B(),emits:{"click:close":e=>!0,"update:modelValue":e=>!0},setup(e,{emit:a,slots:s}){let d=_(e,`modelValue`),m=c(()=>{if(e.icon!==!1)return e.type?e.icon??`$${e.type}`:e.icon}),{iconSize:h}=R(e,()=>e.prominent?44:void 0),{themeClasses:g}=o(e),{colorClasses:y,colorStyles:x,variantClasses:w}=A(()=>({color:e.color??e.type,variant:e.variant})),{densityClasses:E}=S(e),{dimensionStyles:D}=u(e),{elevationClasses:O}=C(e),{locationStyles:k}=b(e),{positionClasses:M}=i(e),{roundedClasses:L}=N(e),{textColorClasses:z,textColorStyles:B}=n(()=>e.borderColor),{t:V}=l(),H=c(()=>({"aria-label":V(e.closeLabel),onClick(e){d.value=!1,a(`click:close`,e)}}));return()=>{let n=!!(s.prepend||m.value),i=!!(s.title||e.title),a=!!(s.close||e.closable),o={density:e.density,icon:m.value,size:e.iconSize||e.prominent?h.value:void 0};return d.value&&T(e.tag,{class:F([`v-alert`,e.border&&{"v-alert--border":!!e.border,[`v-alert--border-${e.border===!0?`start`:e.border}`]:!0},{"v-alert--prominent":e.prominent},g.value,y.value,E.value,O.value,M.value,L.value,w.value,e.class]),style:t([x.value,D.value,k.value,e.style]),role:`alert`},{default:()=>[p(!1,`v-alert`),e.border&&v(`div`,{key:`border`,class:F([`v-alert__border`,z.value]),style:t(B.value)},null),n&&v(`div`,{key:`prepend`,class:`v-alert__prepend`},[s.prepend?T(r,{key:`prepend-defaults`,disabled:!m.value,defaults:{VIcon:{...o}}},s.prepend):T(f,j({key:`prepend-icon`},o),null)]),v(`div`,{class:`v-alert__content`},[i&&T(I,{key:`title`},{default:()=>[s.title?.()??e.title]}),s.text?.()??e.text,s.default?.()]),s.append&&v(`div`,{key:`append`,class:`v-alert__append`},[s.append()]),a&&v(`div`,{key:`close`,class:`v-alert__close`},[s.close?T(r,{key:`close-defaults`,defaults:{VBtn:{icon:e.closeIcon,size:`x-small`,variant:`text`}}},{default:()=>[s.close?.({props:H.value})]}):T(P,j({key:`close-btn`,icon:e.closeIcon,size:`x-small`,variant:`text`},H.value),null)])]})}}});export{V as t};
+1
View File
@@ -0,0 +1 @@
import{$n as e,Br as t,Ct as n,Et as r,G as i,Gt as a,Kt as o,Mt as s,Pr as c,Qt as l,Tt as u,W as d,Z as f,at as p,bt as m,ct as h,dt as g,en as _,er as v,fn as y,ft as b,ln as x,lt as S,mt as C,nn as w,or as T,ot as E,pn as D,pt as O,sn as k,st as A,ur as j,wt as M,xt as N,z as P,zr as F}from"./index-BihgjXCy.js";var I=k(`v-alert-title`),L=D({iconSize:[Number,String],iconSizes:{type:Array,default:()=>[[`x-small`,10],[`small`,16],[`default`,24],[`large`,28],[`x-large`,32]]}},`iconSize`);function R(t,n){return{iconSize:e(()=>{let e=new Map(t.iconSizes),r=t.iconSize??n()??`default`;return e.has(r)?e.get(r):r})}}var z=[`success`,`info`,`warning`,`error`],B=D({border:{type:[Boolean,String],validator:e=>typeof e==`boolean`||[`top`,`end`,`bottom`,`start`].includes(e)},borderColor:String,closable:Boolean,closeIcon:{type:w,default:`$close`},closeLabel:{type:String,default:`$vuetify.close`},icon:{type:[Boolean,String,Function,Object],default:null},modelValue:{type:Boolean,default:!0},prominent:Boolean,title:String,text:String,type:{type:String,validator:e=>z.includes(e)},...y(),...h(),...M(),...O(),...L(),...g(),...d(),...m(),...s(),...a(),...E({variant:`flat`})},`VAlert`),V=x()({name:`VAlert`,props:B(),emits:{"click:close":e=>!0,"update:modelValue":e=>!0},setup(e,{emit:a,slots:s}){let d=_(e,`modelValue`),m=c(()=>{if(e.icon!==!1)return e.type?e.icon??`$${e.type}`:e.icon}),{iconSize:h}=R(e,()=>e.prominent?44:void 0),{themeClasses:g}=o(e),{colorClasses:y,colorStyles:x,variantClasses:w}=A(()=>({color:e.color??e.type,variant:e.variant})),{densityClasses:E}=S(e),{dimensionStyles:D}=u(e),{elevationClasses:O}=C(e),{locationStyles:k}=b(e),{positionClasses:M}=i(e),{roundedClasses:L}=N(e),{textColorClasses:z,textColorStyles:B}=n(()=>e.borderColor),{t:V}=l(),H=c(()=>({"aria-label":V(e.closeLabel),onClick(e){d.value=!1,a(`click:close`,e)}}));return()=>{let n=!!(s.prepend||m.value),i=!!(s.title||e.title),a=!!(s.close||e.closable),o={density:e.density,icon:m.value,size:e.iconSize||e.prominent?h.value:void 0};return d.value&&T(e.tag,{class:F([`v-alert`,e.border&&{"v-alert--border":!!e.border,[`v-alert--border-${e.border===!0?`start`:e.border}`]:!0},{"v-alert--prominent":e.prominent},g.value,y.value,E.value,O.value,M.value,L.value,w.value,e.class]),style:t([x.value,D.value,k.value,e.style]),role:`alert`},{default:()=>[p(!1,`v-alert`),e.border&&v(`div`,{key:`border`,class:F([`v-alert__border`,z.value]),style:t(B.value)},null),n&&v(`div`,{key:`prepend`,class:`v-alert__prepend`},[s.prepend?T(r,{key:`prepend-defaults`,disabled:!m.value,defaults:{VIcon:{...o}}},s.prepend):T(f,j({key:`prepend-icon`},o),null)]),v(`div`,{class:`v-alert__content`},[i&&T(I,{key:`title`},{default:()=>[s.title?.()??e.title]}),s.text?.()??e.text,s.default?.()]),s.append&&v(`div`,{key:`append`,class:`v-alert__append`},[s.append()]),a&&v(`div`,{key:`close`,class:`v-alert__close`},[s.close?T(r,{key:`close-defaults`,defaults:{VBtn:{icon:e.closeIcon,size:`x-small`,variant:`text`}}},{default:()=>[s.close?.({props:H.value})]}):T(P,j({key:`close-btn`,icon:e.closeIcon,size:`x-small`,variant:`text`},H.value),null)])]})}}});export{V as t};
+1
View File
@@ -0,0 +1 @@
import{$n as e,Br as t,Ct as n,Et as r,G as i,Gt as a,Kt as o,Mt as s,Pr as c,Qt as l,Tt as u,W as d,Z as f,at as p,bt as m,ct as h,dt as g,en as _,er as v,fn as y,ft as b,ln as x,lt as S,mt as C,nn as w,or as T,ot as E,pn as D,pt as O,sn as k,st as A,ur as j,wt as M,xt as N,z as P,zr as F}from"./index-DNlvHxBC.js";var I=k(`v-alert-title`),L=D({iconSize:[Number,String],iconSizes:{type:Array,default:()=>[[`x-small`,10],[`small`,16],[`default`,24],[`large`,28],[`x-large`,32]]}},`iconSize`);function R(t,n){return{iconSize:e(()=>{let e=new Map(t.iconSizes),r=t.iconSize??n()??`default`;return e.has(r)?e.get(r):r})}}var z=[`success`,`info`,`warning`,`error`],B=D({border:{type:[Boolean,String],validator:e=>typeof e==`boolean`||[`top`,`end`,`bottom`,`start`].includes(e)},borderColor:String,closable:Boolean,closeIcon:{type:w,default:`$close`},closeLabel:{type:String,default:`$vuetify.close`},icon:{type:[Boolean,String,Function,Object],default:null},modelValue:{type:Boolean,default:!0},prominent:Boolean,title:String,text:String,type:{type:String,validator:e=>z.includes(e)},...y(),...h(),...M(),...O(),...L(),...g(),...d(),...m(),...s(),...a(),...E({variant:`flat`})},`VAlert`),V=x()({name:`VAlert`,props:B(),emits:{"click:close":e=>!0,"update:modelValue":e=>!0},setup(e,{emit:a,slots:s}){let d=_(e,`modelValue`),m=c(()=>{if(e.icon!==!1)return e.type?e.icon??`$${e.type}`:e.icon}),{iconSize:h}=R(e,()=>e.prominent?44:void 0),{themeClasses:g}=o(e),{colorClasses:y,colorStyles:x,variantClasses:w}=A(()=>({color:e.color??e.type,variant:e.variant})),{densityClasses:E}=S(e),{dimensionStyles:D}=u(e),{elevationClasses:O}=C(e),{locationStyles:k}=b(e),{positionClasses:M}=i(e),{roundedClasses:L}=N(e),{textColorClasses:z,textColorStyles:B}=n(()=>e.borderColor),{t:V}=l(),H=c(()=>({"aria-label":V(e.closeLabel),onClick(e){d.value=!1,a(`click:close`,e)}}));return()=>{let n=!!(s.prepend||m.value),i=!!(s.title||e.title),a=!!(s.close||e.closable),o={density:e.density,icon:m.value,size:e.iconSize||e.prominent?h.value:void 0};return d.value&&T(e.tag,{class:F([`v-alert`,e.border&&{"v-alert--border":!!e.border,[`v-alert--border-${e.border===!0?`start`:e.border}`]:!0},{"v-alert--prominent":e.prominent},g.value,y.value,E.value,O.value,M.value,L.value,w.value,e.class]),style:t([x.value,D.value,k.value,e.style]),role:`alert`},{default:()=>[p(!1,`v-alert`),e.border&&v(`div`,{key:`border`,class:F([`v-alert__border`,z.value]),style:t(B.value)},null),n&&v(`div`,{key:`prepend`,class:`v-alert__prepend`},[s.prepend?T(r,{key:`prepend-defaults`,disabled:!m.value,defaults:{VIcon:{...o}}},s.prepend):T(f,j({key:`prepend-icon`},o),null)]),v(`div`,{class:`v-alert__content`},[i&&T(I,{key:`title`},{default:()=>[s.title?.()??e.title]}),s.text?.()??e.text,s.default?.()]),s.append&&v(`div`,{key:`append`,class:`v-alert__append`},[s.append()]),a&&v(`div`,{key:`close`,class:`v-alert__close`},[s.close?T(r,{key:`close-defaults`,defaults:{VBtn:{icon:e.closeIcon,size:`x-small`,variant:`text`}}},{default:()=>[s.close?.({props:H.value})]}):T(P,j({key:`close-btn`,icon:e.closeIcon,size:`x-small`,variant:`text`},H.value),null)])]})}}});export{V as t};
+1
View File
@@ -0,0 +1 @@
import{Tn as e,en as t,jr as n,ln as r,o as i,or as a,p as o,pn as s,rn as c,s as l,ur as u,v as d,xr as f,zn as p}from"./index-CLVw8WaP.js";import{f as m,p as h}from"./VSelect-C9Xea3xT.js";var g=s({...p(l(),[`direction`]),...p(h(),[`inline`])},`VCheckbox`),_=r()({name:`VCheckbox`,inheritAttrs:!1,props:g(),emits:{"update:modelValue":e=>!0,"update:focused":e=>!0},setup(r,{attrs:s,slots:l}){let p=t(r,`modelValue`),{isFocused:h,focus:g,blur:_}=o(r),v=n(),y=f();return c(()=>{let[t,n]=e(s),o=i.filterProps(r),c=m.filterProps(r);return a(i,u({ref:v,class:[`v-checkbox`,r.class]},t,o,{modelValue:p.value,"onUpdate:modelValue":e=>p.value=e,id:r.id||`checkbox-${y}`,focused:h.value,style:r.style}),{...l,default:({id:e,messagesId:t,isDisabled:r,isReadonly:i,isValid:o})=>a(m,u(c,{id:e.value,"aria-describedby":t.value,disabled:r.value,readonly:i.value},n,{error:o.value===!1,modelValue:p.value,"onUpdate:modelValue":e=>p.value=e,onFocus:g,onBlur:_}),l)})}),d({},v)}});export{_ as t};
+1
View File
@@ -0,0 +1 @@
import{Tn as e,en as t,jr as n,ln as r,o as i,or as a,p as o,pn as s,rn as c,s as l,ur as u,v as d,xr as f,zn as p}from"./index-BihgjXCy.js";import{f as m,p as h}from"./VSelect-CGF0mOJJ.js";var g=s({...p(l(),[`direction`]),...p(h(),[`inline`])},`VCheckbox`),_=r()({name:`VCheckbox`,inheritAttrs:!1,props:g(),emits:{"update:modelValue":e=>!0,"update:focused":e=>!0},setup(r,{attrs:s,slots:l}){let p=t(r,`modelValue`),{isFocused:h,focus:g,blur:_}=o(r),v=n(),y=f();return c(()=>{let[t,n]=e(s),o=i.filterProps(r),c=m.filterProps(r);return a(i,u({ref:v,class:[`v-checkbox`,r.class]},t,o,{modelValue:p.value,"onUpdate:modelValue":e=>p.value=e,id:r.id||`checkbox-${y}`,focused:h.value,style:r.style}),{...l,default:({id:e,messagesId:t,isDisabled:r,isReadonly:i,isValid:o})=>a(m,u(c,{id:e.value,"aria-describedby":t.value,disabled:r.value,readonly:i.value},n,{error:o.value===!1,modelValue:p.value,"onUpdate:modelValue":e=>p.value=e,onFocus:g,onBlur:_}),l)})}),d({},v)}});export{_ as t};
+1
View File
@@ -0,0 +1 @@
import{Tn as e,en as t,jr as n,ln as r,o as i,or as a,p as o,pn as s,rn as c,s as l,ur as u,v as d,xr as f,zn as p}from"./index-DNlvHxBC.js";import{f as m,p as h}from"./VSelect-D0AqVzoi.js";var g=s({...p(l(),[`direction`]),...p(h(),[`inline`])},`VCheckbox`),_=r()({name:`VCheckbox`,inheritAttrs:!1,props:g(),emits:{"update:modelValue":e=>!0,"update:focused":e=>!0},setup(r,{attrs:s,slots:l}){let p=t(r,`modelValue`),{isFocused:h,focus:g,blur:_}=o(r),v=n(),y=f();return c(()=>{let[t,n]=e(s),o=i.filterProps(r),c=m.filterProps(r);return a(i,u({ref:v,class:[`v-checkbox`,r.class]},t,o,{modelValue:p.value,"onUpdate:modelValue":e=>p.value=e,id:r.id||`checkbox-${y}`,focused:h.value,style:r.style}),{...l,default:({id:e,messagesId:t,isDisabled:r,isReadonly:i,isValid:o})=>a(m,u(c,{id:e.value,"aria-describedby":t.value,disabled:r.value,readonly:i.value},n,{error:o.value===!1,modelValue:p.value,"onUpdate:modelValue":e=>p.value=e,onFocus:g,onBlur:_}),l)})}),d({},v)}});export{_ as t};
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
@@ -0,0 +1 @@
import{_ as e,a as t,b as n,c as r,d as i,f as a,g as o,h as s,i as c,l,m as u,n as d,o as f,p,r as m,s as h,u as ee,v as te,y as g}from"./VDataTable-i6orhoys.js";import{$n as _,Fr as v,M as y,Pr as b,Zn as x,_r as S,er as C,ln as w,or as T,pn as E,rn as ne,un as D,ur as O,zn as k}from"./index-DNlvHxBC.js";var A=E({itemsLength:{type:[Number,String],required:!0},...g(),...d(),...e()},`VDataTableServer`),j=w()({name:`VDataTableServer`,props:A(),emits:{"update:modelValue":e=>!0,"update:page":e=>!0,"update:itemsPerPage":e=>!0,"update:sortBy":e=>!0,"update:options":e=>!0,"update:expanded":e=>!0,"update:groupBy":e=>!0},setup(e,{attrs:d,slots:g}){let{groupBy:w}=r(e),{initialSortOrder:E,sortBy:A,multiSort:j,mustSort:M}=a(e),{page:N,itemsPerPage:P}=te(e),{disableSort:F}=v(e),I=_(()=>parseInt(e.itemsLength,10)),{columns:L,headers:R}=s(e,{groupBy:w,showSelect:b(()=>e.showSelect),showExpand:b(()=>e.showExpand)}),{items:z}=c(e,L),{toggleSort:B}=p({initialSortOrder:E,sortBy:A,multiSort:j,mustSort:M,page:N}),{opened:V,isGroupOpen:H,toggleGroup:re,extractRows:U}=l({groupBy:w,sortBy:A,disableSort:F}),{pageCount:W,setItemsPerPage:G,prevPage:K,nextPage:q,setPage:J}=n({page:N,itemsPerPage:P,itemsLength:I}),{flatItems:Y}=ee(z,w,V,()=>!!g[`group-summary`]),{isSelected:X,select:ie,selectAll:ae,toggleSelect:oe,someSelected:se,allSelected:ce}=u(e,{allItems:z,currentPage:z}),{isExpanded:Z,toggleExpand:le}=h(e),Q=_(()=>U(z.value));m({page:N,itemsPerPage:P,sortBy:A,groupBy:w,search:b(()=>e.search)}),S(`v-data-table`,{toggleSort:B,sortBy:A}),D({VDataTableRows:{hideNoData:b(()=>e.hideNoData),noDataText:b(()=>e.noDataText),loading:b(()=>e.loading),loadingText:b(()=>e.loadingText)}});let $=_(()=>({page:N.value,itemsPerPage:P.value,sortBy:A.value,pageCount:W.value,toggleSort:B,setItemsPerPage:G,prevPage:K,nextPage:q,setPage:J,someSelected:se.value,allSelected:ce.value,isSelected:X,select:ie,selectAll:ae,toggleSelect:oe,isExpanded:Z,toggleExpand:le,isGroupOpen:H,toggleGroup:re,items:Q.value.map(e=>e.raw),internalItems:Q.value,groupedItems:Y.value,columns:L.value,headers:R.value}));ne(()=>{let n=o.filterProps(e),r=i.filterProps(k(e,[`multiSort`])),a=f.filterProps(e),s=t.filterProps(e);return T(t,O({class:[`v-data-table`,{"v-data-table--loading":e.loading},e.class],style:e.style},s,{fixedHeader:e.fixedHeader||e.sticky}),{top:()=>g.top?.($.value),default:()=>g.default?g.default($.value):C(x,null,[g.colgroup?.($.value),!e.hideDefaultHeader&&C(`thead`,{key:`thead`,class:`v-data-table__thead`,role:`rowgroup`},[T(i,O(r,{multiSort:!!e.multiSort}),g)]),g.thead?.($.value),!e.hideDefaultBody&&C(`tbody`,{class:`v-data-table__tbody`,role:`rowgroup`},[g[`body.prepend`]?.($.value),g.body?g.body($.value):T(f,O(d,a,{items:Y.value}),g),g[`body.append`]?.($.value)]),g.tbody?.($.value),g.tfoot?.($.value)]),bottom:()=>g.bottom?g.bottom($.value):!e.hideDefaultFooter&&C(x,null,[T(y,null,null),T(o,n,{prepend:g[`footer.prepend`]})])})})}});export{j as t};
@@ -0,0 +1 @@
import{_ as e,a as t,b as n,c as r,d as i,f as a,g as o,h as s,i as c,l,m as u,n as d,o as f,p,r as m,s as h,u as ee,v as te,y as g}from"./VDataTable-a27PQ8_A.js";import{$n as _,Fr as v,M as y,Pr as b,Zn as x,_r as S,er as C,ln as w,or as T,pn as E,rn as ne,un as D,ur as O,zn as k}from"./index-CLVw8WaP.js";var A=E({itemsLength:{type:[Number,String],required:!0},...g(),...d(),...e()},`VDataTableServer`),j=w()({name:`VDataTableServer`,props:A(),emits:{"update:modelValue":e=>!0,"update:page":e=>!0,"update:itemsPerPage":e=>!0,"update:sortBy":e=>!0,"update:options":e=>!0,"update:expanded":e=>!0,"update:groupBy":e=>!0},setup(e,{attrs:d,slots:g}){let{groupBy:w}=r(e),{initialSortOrder:E,sortBy:A,multiSort:j,mustSort:M}=a(e),{page:N,itemsPerPage:P}=te(e),{disableSort:F}=v(e),I=_(()=>parseInt(e.itemsLength,10)),{columns:L,headers:R}=s(e,{groupBy:w,showSelect:b(()=>e.showSelect),showExpand:b(()=>e.showExpand)}),{items:z}=c(e,L),{toggleSort:B}=p({initialSortOrder:E,sortBy:A,multiSort:j,mustSort:M,page:N}),{opened:V,isGroupOpen:H,toggleGroup:re,extractRows:U}=l({groupBy:w,sortBy:A,disableSort:F}),{pageCount:W,setItemsPerPage:G,prevPage:K,nextPage:q,setPage:J}=n({page:N,itemsPerPage:P,itemsLength:I}),{flatItems:Y}=ee(z,w,V,()=>!!g[`group-summary`]),{isSelected:X,select:ie,selectAll:ae,toggleSelect:oe,someSelected:se,allSelected:ce}=u(e,{allItems:z,currentPage:z}),{isExpanded:Z,toggleExpand:le}=h(e),Q=_(()=>U(z.value));m({page:N,itemsPerPage:P,sortBy:A,groupBy:w,search:b(()=>e.search)}),S(`v-data-table`,{toggleSort:B,sortBy:A}),D({VDataTableRows:{hideNoData:b(()=>e.hideNoData),noDataText:b(()=>e.noDataText),loading:b(()=>e.loading),loadingText:b(()=>e.loadingText)}});let $=_(()=>({page:N.value,itemsPerPage:P.value,sortBy:A.value,pageCount:W.value,toggleSort:B,setItemsPerPage:G,prevPage:K,nextPage:q,setPage:J,someSelected:se.value,allSelected:ce.value,isSelected:X,select:ie,selectAll:ae,toggleSelect:oe,isExpanded:Z,toggleExpand:le,isGroupOpen:H,toggleGroup:re,items:Q.value.map(e=>e.raw),internalItems:Q.value,groupedItems:Y.value,columns:L.value,headers:R.value}));ne(()=>{let n=o.filterProps(e),r=i.filterProps(k(e,[`multiSort`])),a=f.filterProps(e),s=t.filterProps(e);return T(t,O({class:[`v-data-table`,{"v-data-table--loading":e.loading},e.class],style:e.style},s,{fixedHeader:e.fixedHeader||e.sticky}),{top:()=>g.top?.($.value),default:()=>g.default?g.default($.value):C(x,null,[g.colgroup?.($.value),!e.hideDefaultHeader&&C(`thead`,{key:`thead`,class:`v-data-table__thead`,role:`rowgroup`},[T(i,O(r,{multiSort:!!e.multiSort}),g)]),g.thead?.($.value),!e.hideDefaultBody&&C(`tbody`,{class:`v-data-table__tbody`,role:`rowgroup`},[g[`body.prepend`]?.($.value),g.body?g.body($.value):T(f,O(d,a,{items:Y.value}),g),g[`body.append`]?.($.value)]),g.tbody?.($.value),g.tfoot?.($.value)]),bottom:()=>g.bottom?g.bottom($.value):!e.hideDefaultFooter&&C(x,null,[T(y,null,null),T(o,n,{prepend:g[`footer.prepend`]})])})})}});export{j as t};
@@ -0,0 +1 @@
import{_ as e,a as t,b as n,c as r,d as i,f as a,g as o,h as s,i as c,l,m as u,n as d,o as f,p,r as m,s as h,u as ee,v as te,y as g}from"./VDataTable-CynA26OW.js";import{$n as _,Fr as v,M as y,Pr as b,Zn as x,_r as S,er as C,ln as w,or as T,pn as E,rn as ne,un as D,ur as O,zn as k}from"./index-BihgjXCy.js";var A=E({itemsLength:{type:[Number,String],required:!0},...g(),...d(),...e()},`VDataTableServer`),j=w()({name:`VDataTableServer`,props:A(),emits:{"update:modelValue":e=>!0,"update:page":e=>!0,"update:itemsPerPage":e=>!0,"update:sortBy":e=>!0,"update:options":e=>!0,"update:expanded":e=>!0,"update:groupBy":e=>!0},setup(e,{attrs:d,slots:g}){let{groupBy:w}=r(e),{initialSortOrder:E,sortBy:A,multiSort:j,mustSort:M}=a(e),{page:N,itemsPerPage:P}=te(e),{disableSort:F}=v(e),I=_(()=>parseInt(e.itemsLength,10)),{columns:L,headers:R}=s(e,{groupBy:w,showSelect:b(()=>e.showSelect),showExpand:b(()=>e.showExpand)}),{items:z}=c(e,L),{toggleSort:B}=p({initialSortOrder:E,sortBy:A,multiSort:j,mustSort:M,page:N}),{opened:V,isGroupOpen:H,toggleGroup:re,extractRows:U}=l({groupBy:w,sortBy:A,disableSort:F}),{pageCount:W,setItemsPerPage:G,prevPage:K,nextPage:q,setPage:J}=n({page:N,itemsPerPage:P,itemsLength:I}),{flatItems:Y}=ee(z,w,V,()=>!!g[`group-summary`]),{isSelected:X,select:ie,selectAll:ae,toggleSelect:oe,someSelected:se,allSelected:ce}=u(e,{allItems:z,currentPage:z}),{isExpanded:Z,toggleExpand:le}=h(e),Q=_(()=>U(z.value));m({page:N,itemsPerPage:P,sortBy:A,groupBy:w,search:b(()=>e.search)}),S(`v-data-table`,{toggleSort:B,sortBy:A}),D({VDataTableRows:{hideNoData:b(()=>e.hideNoData),noDataText:b(()=>e.noDataText),loading:b(()=>e.loading),loadingText:b(()=>e.loadingText)}});let $=_(()=>({page:N.value,itemsPerPage:P.value,sortBy:A.value,pageCount:W.value,toggleSort:B,setItemsPerPage:G,prevPage:K,nextPage:q,setPage:J,someSelected:se.value,allSelected:ce.value,isSelected:X,select:ie,selectAll:ae,toggleSelect:oe,isExpanded:Z,toggleExpand:le,isGroupOpen:H,toggleGroup:re,items:Q.value.map(e=>e.raw),internalItems:Q.value,groupedItems:Y.value,columns:L.value,headers:R.value}));ne(()=>{let n=o.filterProps(e),r=i.filterProps(k(e,[`multiSort`])),a=f.filterProps(e),s=t.filterProps(e);return T(t,O({class:[`v-data-table`,{"v-data-table--loading":e.loading},e.class],style:e.style},s,{fixedHeader:e.fixedHeader||e.sticky}),{top:()=>g.top?.($.value),default:()=>g.default?g.default($.value):C(x,null,[g.colgroup?.($.value),!e.hideDefaultHeader&&C(`thead`,{key:`thead`,class:`v-data-table__thead`,role:`rowgroup`},[T(i,O(r,{multiSort:!!e.multiSort}),g)]),g.thead?.($.value),!e.hideDefaultBody&&C(`tbody`,{class:`v-data-table__tbody`,role:`rowgroup`},[g[`body.prepend`]?.($.value),g.body?g.body($.value):T(f,O(d,a,{items:Y.value}),g),g[`body.append`]?.($.value)]),g.tbody?.($.value),g.tfoot?.($.value)]),bottom:()=>g.bottom?g.bottom($.value):!e.hideDefaultFooter&&C(x,null,[T(y,null,null),T(o,n,{prepend:g[`footer.prepend`]})])})})}});export{j as t};
+1
View File
@@ -0,0 +1 @@
import{Et as e,Sr as t,b as n,dr as r,en as i,jr as a,jt as o,ln as s,or as c,pn as l,rn as u,ur as d,v as f,x as p,y as m,zn as h}from"./index-BihgjXCy.js";var g=l({fullscreen:Boolean,scrollable:Boolean,...h(n({captureFocus:!0,origin:`center center`,scrollStrategy:`block`,transition:{component:o},zIndex:2400,retainFocus:!0}),[`disableInitialFocus`])},`VDialog`),_=s()({name:`VDialog`,props:g(),emits:{"update:modelValue":e=>!0,afterEnter:()=>!0,afterLeave:()=>!0},setup(n,{emit:o,slots:s}){let l=i(n,`modelValue`),{scopeId:h}=p(),g=a();function _(){o(`afterEnter`),(n.scrim||n.retainFocus)&&g.value?.contentEl&&!g.value.contentEl.contains(document.activeElement)&&g.value.contentEl.focus({preventScroll:!0})}function v(){o(`afterLeave`)}return t(l,async e=>{e||(await r(),g.value.activatorEl?.focus({preventScroll:!0}))}),u(()=>{let t=m.filterProps(n),r=d({"aria-haspopup":`dialog`},n.activatorProps),i=d({tabindex:-1},n.contentProps);return c(m,d({ref:g,class:[`v-dialog`,{"v-dialog--fullscreen":n.fullscreen,"v-dialog--scrollable":n.scrollable},n.class],style:n.style},t,{modelValue:l.value,"onUpdate:modelValue":e=>l.value=e,"aria-modal":`true`,activatorProps:r,contentProps:i,height:n.fullscreen?void 0:n.height,width:n.fullscreen?void 0:n.width,maxHeight:n.fullscreen?void 0:n.maxHeight,maxWidth:n.fullscreen?void 0:n.maxWidth,role:`dialog`,onAfterEnter:_,onAfterLeave:v},h),{activator:s.activator,default:(...t)=>c(e,{root:`VDialog`},{default:()=>[s.default?.(...t)]})})}),f({},g)}});export{_ as t};
+1
View File
@@ -0,0 +1 @@
import{Et as e,Sr as t,b as n,dr as r,en as i,jr as a,jt as o,ln as s,or as c,pn as l,rn as u,ur as d,v as f,x as p,y as m,zn as h}from"./index-DNlvHxBC.js";var g=l({fullscreen:Boolean,scrollable:Boolean,...h(n({captureFocus:!0,origin:`center center`,scrollStrategy:`block`,transition:{component:o},zIndex:2400,retainFocus:!0}),[`disableInitialFocus`])},`VDialog`),_=s()({name:`VDialog`,props:g(),emits:{"update:modelValue":e=>!0,afterEnter:()=>!0,afterLeave:()=>!0},setup(n,{emit:o,slots:s}){let l=i(n,`modelValue`),{scopeId:h}=p(),g=a();function _(){o(`afterEnter`),(n.scrim||n.retainFocus)&&g.value?.contentEl&&!g.value.contentEl.contains(document.activeElement)&&g.value.contentEl.focus({preventScroll:!0})}function v(){o(`afterLeave`)}return t(l,async e=>{e||(await r(),g.value.activatorEl?.focus({preventScroll:!0}))}),u(()=>{let t=m.filterProps(n),r=d({"aria-haspopup":`dialog`},n.activatorProps),i=d({tabindex:-1},n.contentProps);return c(m,d({ref:g,class:[`v-dialog`,{"v-dialog--fullscreen":n.fullscreen,"v-dialog--scrollable":n.scrollable},n.class],style:n.style},t,{modelValue:l.value,"onUpdate:modelValue":e=>l.value=e,"aria-modal":`true`,activatorProps:r,contentProps:i,height:n.fullscreen?void 0:n.height,width:n.fullscreen?void 0:n.width,maxHeight:n.fullscreen?void 0:n.maxHeight,maxWidth:n.fullscreen?void 0:n.maxWidth,role:`dialog`,onAfterEnter:_,onAfterLeave:v},h),{activator:s.activator,default:(...t)=>c(e,{root:`VDialog`},{default:()=>[s.default?.(...t)]})})}),f({},g)}});export{_ as t};
+1
View File
@@ -0,0 +1 @@
import{Et as e,Sr as t,b as n,dr as r,en as i,jr as a,jt as o,ln as s,or as c,pn as l,rn as u,ur as d,v as f,x as p,y as m,zn as h}from"./index-CLVw8WaP.js";var g=l({fullscreen:Boolean,scrollable:Boolean,...h(n({captureFocus:!0,origin:`center center`,scrollStrategy:`block`,transition:{component:o},zIndex:2400,retainFocus:!0}),[`disableInitialFocus`])},`VDialog`),_=s()({name:`VDialog`,props:g(),emits:{"update:modelValue":e=>!0,afterEnter:()=>!0,afterLeave:()=>!0},setup(n,{emit:o,slots:s}){let l=i(n,`modelValue`),{scopeId:h}=p(),g=a();function _(){o(`afterEnter`),(n.scrim||n.retainFocus)&&g.value?.contentEl&&!g.value.contentEl.contains(document.activeElement)&&g.value.contentEl.focus({preventScroll:!0})}function v(){o(`afterLeave`)}return t(l,async e=>{e||(await r(),g.value.activatorEl?.focus({preventScroll:!0}))}),u(()=>{let t=m.filterProps(n),r=d({"aria-haspopup":`dialog`},n.activatorProps),i=d({tabindex:-1},n.contentProps);return c(m,d({ref:g,class:[`v-dialog`,{"v-dialog--fullscreen":n.fullscreen,"v-dialog--scrollable":n.scrollable},n.class],style:n.style},t,{modelValue:l.value,"onUpdate:modelValue":e=>l.value=e,"aria-modal":`true`,activatorProps:r,contentProps:i,height:n.fullscreen?void 0:n.height,width:n.fullscreen?void 0:n.width,maxHeight:n.fullscreen?void 0:n.maxHeight,maxWidth:n.fullscreen?void 0:n.maxWidth,role:`dialog`,onAfterEnter:_,onAfterLeave:v},h),{activator:s.activator,default:(...t)=>c(e,{root:`VDialog`},{default:()=>[s.default?.(...t)]})})}),f({},g)}});export{_ as t};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
import{$n as e,In as t,Kn as n,Mt as r,Rr as i,Yt as a,bn as o,cr as s,ct as c,fn as l,ln as u,pn as d}from"./index-CLVw8WaP.js";var f=a.reduce((e,t)=>(e[t]={type:[Boolean,String,Number],default:!1},e),{}),p=a.reduce((e,t)=>{let n=`offset`+i(t);return e[n]={type:[String,Number],default:null},e},{}),m={col:t(f),offset:t(p),order:[`order`,`orderSm`,`orderMd`,`orderLg`,`orderXl`,`orderXxl`]};function h(e){if(typeof e==`string`&&e.includes(`/`)){let[t,n]=e.split(`/`);return{cols:Number(t),size:Number(n)}}return{cols:e}}function g(e,t,n){if(n==null||n===!1)return{};let{cols:r,size:i}=h(n),a=t.replace(e,``).toLowerCase();return e===`offset`?{className:`v-col--offset-${a}-${r}`,variables:[{[`--v-col-offset-base-${a}`]:i}]}:e===`order`?{className:`order-${a}-${r}`}:{className:r===``||r===!0?`v-col--${a}`:`v-col--cols-${a}-${r}`,variables:[{[`--v-col-size-base-${a}`]:i}]}}var _=[`auto`,`start`,`end`,`center`,`baseline`,`stretch`],v=e=>_.includes(e),y=d({cols:{type:[Boolean,String,Number],default:!1},...f,offset:{type:[String,Number],default:null},...p,order:{type:[String,Number],default:null},orderSm:{type:[String,Number],default:null},orderMd:{type:[String,Number],default:null},orderLg:{type:[String,Number],default:null},orderXl:{type:[String,Number],default:null},orderXxl:{type:[String,Number],default:null},alignSelf:{type:String,default:null,validator:v},...l(),...r()},`VCol`),b=u()({name:`VCol`,props:y(),setup(t,{slots:n}){let r=e(()=>h(t.cols).size),i=e(()=>h(t.offset).size),a=e(()=>{let e=[`v-col`],n=[],r;for(r in m)m[r].forEach(i=>{let a=t[i],{className:o,variables:s}=g(r,i,a);o&&e.push(o),s&&n.push(...s)});let{cols:i}=h(t.cols),{cols:a}=h(t.offset);return e.push({[`v-col--cols-${i}`]:i,[`v-col--offset-${a}`]:a,[`order-${t.order}`]:t.order,[`align-self-${t.alignSelf}`]:t.alignSelf}),{classes:e,variables:n}});return()=>s(t.tag,{class:[a.value.classes,t.class],style:[{"--v-col-size-base":r.value},{"--v-col-offset-base":i.value},a.value.variables,t.style]},n.default?.())}}),x=[`start`,`end`,`center`],S=[`space-between`,`space-around`,`space-evenly`],C=[...x,`baseline`,`stretch`],w=e=>C.includes(e),T=[...x,...S],E=e=>T.includes(e),D=[...x,...S,`stretch`],O=e=>D.includes(e),k={align:[`align`,`alignSm`,`alignMd`,`alignLg`,`alignXl`,`alignXxl`],justify:[`justify`,`justifySm`,`justifyMd`,`justifyLg`,`justifyXl`,`justifyXxl`],alignContent:[`alignContent`,`alignContentSm`,`alignContentMd`,`alignContentLg`,`alignContentXl`,`alignContentXxl`]},A={align:`align`,justify:`justify`,alignContent:`align-content`};function j(e,t,n){let r=A[e];if(n!=null){if(t){let n=t.replace(e,``);r+=`-${n}`}return r+=`-${n}`,r.toLowerCase()}}var M=d({dense:Boolean,align:{type:String,default:null,validator:w},alignSm:{type:String,default:null,validator:w},alignMd:{type:String,default:null,validator:w},alignLg:{type:String,default:null,validator:w},alignXl:{type:String,default:null,validator:w},alignXxl:{type:String,default:null,validator:w},justify:{type:String,default:null,validator:E},justifySm:{type:String,default:null,validator:E},justifyMd:{type:String,default:null,validator:E},justifyLg:{type:String,default:null,validator:E},justifyXl:{type:String,default:null,validator:E},justifyXxl:{type:String,default:null,validator:E},alignContent:{type:String,default:null,validator:O},alignContentSm:{type:String,default:null,validator:O},alignContentMd:{type:String,default:null,validator:O},alignContentLg:{type:String,default:null,validator:O},alignContentXl:{type:String,default:null,validator:O},alignContentXxl:{type:String,default:null,validator:O},noGutters:Boolean,gap:[Number,String,Array],size:[Number,String],...l(),...c(),...r()},`VRow`),N=u()({name:`VRow`,props:M(),setup(t,{slots:r}){t.dense&&n(`dense`,`density="comfortable"`);let i=e(()=>{let e=[],n;for(n in k)k[n].forEach(r=>{let i=t[r],a=j(n,r,i);a&&e.push(a)});return e.push({"v-row--no-gutters":t.noGutters,"v-row--density-default":t.density===`default`&&!t.noGutters&&!t.dense,"v-row--density-compact":t.density===`compact`,"v-row--density-comfortable":t.density===`comfortable`||t.dense,[`align-${t.align}`]:t.align,[`justify-${t.justify}`]:t.justify,[`align-content-${t.alignContent}`]:t.alignContent}),e}),a=e(()=>Array.isArray(t.gap)?o(t.gap[0]||0):o(t.gap)),c=e(()=>Array.isArray(t.gap)?o(t.gap[1]||0):a.value);return()=>s(t.tag,{class:[`v-row`,i.value,t.class],style:[{"--v-col-gap-x":a.value,"--v-col-gap-y":c.value,"--v-row-columns":t.size},t.style]},r.default?.())}});export{b as n,N as t};
+1
View File
@@ -0,0 +1 @@
import{$n as e,In as t,Kn as n,Mt as r,Rr as i,Yt as a,bn as o,cr as s,ct as c,fn as l,ln as u,pn as d}from"./index-BihgjXCy.js";var f=a.reduce((e,t)=>(e[t]={type:[Boolean,String,Number],default:!1},e),{}),p=a.reduce((e,t)=>{let n=`offset`+i(t);return e[n]={type:[String,Number],default:null},e},{}),m={col:t(f),offset:t(p),order:[`order`,`orderSm`,`orderMd`,`orderLg`,`orderXl`,`orderXxl`]};function h(e){if(typeof e==`string`&&e.includes(`/`)){let[t,n]=e.split(`/`);return{cols:Number(t),size:Number(n)}}return{cols:e}}function g(e,t,n){if(n==null||n===!1)return{};let{cols:r,size:i}=h(n),a=t.replace(e,``).toLowerCase();return e===`offset`?{className:`v-col--offset-${a}-${r}`,variables:[{[`--v-col-offset-base-${a}`]:i}]}:e===`order`?{className:`order-${a}-${r}`}:{className:r===``||r===!0?`v-col--${a}`:`v-col--cols-${a}-${r}`,variables:[{[`--v-col-size-base-${a}`]:i}]}}var _=[`auto`,`start`,`end`,`center`,`baseline`,`stretch`],v=e=>_.includes(e),y=d({cols:{type:[Boolean,String,Number],default:!1},...f,offset:{type:[String,Number],default:null},...p,order:{type:[String,Number],default:null},orderSm:{type:[String,Number],default:null},orderMd:{type:[String,Number],default:null},orderLg:{type:[String,Number],default:null},orderXl:{type:[String,Number],default:null},orderXxl:{type:[String,Number],default:null},alignSelf:{type:String,default:null,validator:v},...l(),...r()},`VCol`),b=u()({name:`VCol`,props:y(),setup(t,{slots:n}){let r=e(()=>h(t.cols).size),i=e(()=>h(t.offset).size),a=e(()=>{let e=[`v-col`],n=[],r;for(r in m)m[r].forEach(i=>{let a=t[i],{className:o,variables:s}=g(r,i,a);o&&e.push(o),s&&n.push(...s)});let{cols:i}=h(t.cols),{cols:a}=h(t.offset);return e.push({[`v-col--cols-${i}`]:i,[`v-col--offset-${a}`]:a,[`order-${t.order}`]:t.order,[`align-self-${t.alignSelf}`]:t.alignSelf}),{classes:e,variables:n}});return()=>s(t.tag,{class:[a.value.classes,t.class],style:[{"--v-col-size-base":r.value},{"--v-col-offset-base":i.value},a.value.variables,t.style]},n.default?.())}}),x=[`start`,`end`,`center`],S=[`space-between`,`space-around`,`space-evenly`],C=[...x,`baseline`,`stretch`],w=e=>C.includes(e),T=[...x,...S],E=e=>T.includes(e),D=[...x,...S,`stretch`],O=e=>D.includes(e),k={align:[`align`,`alignSm`,`alignMd`,`alignLg`,`alignXl`,`alignXxl`],justify:[`justify`,`justifySm`,`justifyMd`,`justifyLg`,`justifyXl`,`justifyXxl`],alignContent:[`alignContent`,`alignContentSm`,`alignContentMd`,`alignContentLg`,`alignContentXl`,`alignContentXxl`]},A={align:`align`,justify:`justify`,alignContent:`align-content`};function j(e,t,n){let r=A[e];if(n!=null){if(t){let n=t.replace(e,``);r+=`-${n}`}return r+=`-${n}`,r.toLowerCase()}}var M=d({dense:Boolean,align:{type:String,default:null,validator:w},alignSm:{type:String,default:null,validator:w},alignMd:{type:String,default:null,validator:w},alignLg:{type:String,default:null,validator:w},alignXl:{type:String,default:null,validator:w},alignXxl:{type:String,default:null,validator:w},justify:{type:String,default:null,validator:E},justifySm:{type:String,default:null,validator:E},justifyMd:{type:String,default:null,validator:E},justifyLg:{type:String,default:null,validator:E},justifyXl:{type:String,default:null,validator:E},justifyXxl:{type:String,default:null,validator:E},alignContent:{type:String,default:null,validator:O},alignContentSm:{type:String,default:null,validator:O},alignContentMd:{type:String,default:null,validator:O},alignContentLg:{type:String,default:null,validator:O},alignContentXl:{type:String,default:null,validator:O},alignContentXxl:{type:String,default:null,validator:O},noGutters:Boolean,gap:[Number,String,Array],size:[Number,String],...l(),...c(),...r()},`VRow`),N=u()({name:`VRow`,props:M(),setup(t,{slots:r}){t.dense&&n(`dense`,`density="comfortable"`);let i=e(()=>{let e=[],n;for(n in k)k[n].forEach(r=>{let i=t[r],a=j(n,r,i);a&&e.push(a)});return e.push({"v-row--no-gutters":t.noGutters,"v-row--density-default":t.density===`default`&&!t.noGutters&&!t.dense,"v-row--density-compact":t.density===`compact`,"v-row--density-comfortable":t.density===`comfortable`||t.dense,[`align-${t.align}`]:t.align,[`justify-${t.justify}`]:t.justify,[`align-content-${t.alignContent}`]:t.alignContent}),e}),a=e(()=>Array.isArray(t.gap)?o(t.gap[0]||0):o(t.gap)),c=e(()=>Array.isArray(t.gap)?o(t.gap[1]||0):a.value);return()=>s(t.tag,{class:[`v-row`,i.value,t.class],style:[{"--v-col-gap-x":a.value,"--v-col-gap-y":c.value,"--v-row-columns":t.size},t.style]},r.default?.())}});export{b as n,N as t};
+1
View File
@@ -0,0 +1 @@
import{$n as e,In as t,Kn as n,Mt as r,Rr as i,Yt as a,bn as o,cr as s,ct as c,fn as l,ln as u,pn as d}from"./index-DNlvHxBC.js";var f=a.reduce((e,t)=>(e[t]={type:[Boolean,String,Number],default:!1},e),{}),p=a.reduce((e,t)=>{let n=`offset`+i(t);return e[n]={type:[String,Number],default:null},e},{}),m={col:t(f),offset:t(p),order:[`order`,`orderSm`,`orderMd`,`orderLg`,`orderXl`,`orderXxl`]};function h(e){if(typeof e==`string`&&e.includes(`/`)){let[t,n]=e.split(`/`);return{cols:Number(t),size:Number(n)}}return{cols:e}}function g(e,t,n){if(n==null||n===!1)return{};let{cols:r,size:i}=h(n),a=t.replace(e,``).toLowerCase();return e===`offset`?{className:`v-col--offset-${a}-${r}`,variables:[{[`--v-col-offset-base-${a}`]:i}]}:e===`order`?{className:`order-${a}-${r}`}:{className:r===``||r===!0?`v-col--${a}`:`v-col--cols-${a}-${r}`,variables:[{[`--v-col-size-base-${a}`]:i}]}}var _=[`auto`,`start`,`end`,`center`,`baseline`,`stretch`],v=e=>_.includes(e),y=d({cols:{type:[Boolean,String,Number],default:!1},...f,offset:{type:[String,Number],default:null},...p,order:{type:[String,Number],default:null},orderSm:{type:[String,Number],default:null},orderMd:{type:[String,Number],default:null},orderLg:{type:[String,Number],default:null},orderXl:{type:[String,Number],default:null},orderXxl:{type:[String,Number],default:null},alignSelf:{type:String,default:null,validator:v},...l(),...r()},`VCol`),b=u()({name:`VCol`,props:y(),setup(t,{slots:n}){let r=e(()=>h(t.cols).size),i=e(()=>h(t.offset).size),a=e(()=>{let e=[`v-col`],n=[],r;for(r in m)m[r].forEach(i=>{let a=t[i],{className:o,variables:s}=g(r,i,a);o&&e.push(o),s&&n.push(...s)});let{cols:i}=h(t.cols),{cols:a}=h(t.offset);return e.push({[`v-col--cols-${i}`]:i,[`v-col--offset-${a}`]:a,[`order-${t.order}`]:t.order,[`align-self-${t.alignSelf}`]:t.alignSelf}),{classes:e,variables:n}});return()=>s(t.tag,{class:[a.value.classes,t.class],style:[{"--v-col-size-base":r.value},{"--v-col-offset-base":i.value},a.value.variables,t.style]},n.default?.())}}),x=[`start`,`end`,`center`],S=[`space-between`,`space-around`,`space-evenly`],C=[...x,`baseline`,`stretch`],w=e=>C.includes(e),T=[...x,...S],E=e=>T.includes(e),D=[...x,...S,`stretch`],O=e=>D.includes(e),k={align:[`align`,`alignSm`,`alignMd`,`alignLg`,`alignXl`,`alignXxl`],justify:[`justify`,`justifySm`,`justifyMd`,`justifyLg`,`justifyXl`,`justifyXxl`],alignContent:[`alignContent`,`alignContentSm`,`alignContentMd`,`alignContentLg`,`alignContentXl`,`alignContentXxl`]},A={align:`align`,justify:`justify`,alignContent:`align-content`};function j(e,t,n){let r=A[e];if(n!=null){if(t){let n=t.replace(e,``);r+=`-${n}`}return r+=`-${n}`,r.toLowerCase()}}var M=d({dense:Boolean,align:{type:String,default:null,validator:w},alignSm:{type:String,default:null,validator:w},alignMd:{type:String,default:null,validator:w},alignLg:{type:String,default:null,validator:w},alignXl:{type:String,default:null,validator:w},alignXxl:{type:String,default:null,validator:w},justify:{type:String,default:null,validator:E},justifySm:{type:String,default:null,validator:E},justifyMd:{type:String,default:null,validator:E},justifyLg:{type:String,default:null,validator:E},justifyXl:{type:String,default:null,validator:E},justifyXxl:{type:String,default:null,validator:E},alignContent:{type:String,default:null,validator:O},alignContentSm:{type:String,default:null,validator:O},alignContentMd:{type:String,default:null,validator:O},alignContentLg:{type:String,default:null,validator:O},alignContentXl:{type:String,default:null,validator:O},alignContentXxl:{type:String,default:null,validator:O},noGutters:Boolean,gap:[Number,String,Array],size:[Number,String],...l(),...c(),...r()},`VRow`),N=u()({name:`VRow`,props:M(),setup(t,{slots:r}){t.dense&&n(`dense`,`density="comfortable"`);let i=e(()=>{let e=[],n;for(n in k)k[n].forEach(r=>{let i=t[r],a=j(n,r,i);a&&e.push(a)});return e.push({"v-row--no-gutters":t.noGutters,"v-row--density-default":t.density===`default`&&!t.noGutters&&!t.dense,"v-row--density-compact":t.density===`compact`,"v-row--density-comfortable":t.density===`comfortable`||t.dense,[`align-${t.align}`]:t.align,[`justify-${t.justify}`]:t.justify,[`align-content-${t.alignContent}`]:t.alignContent}),e}),a=e(()=>Array.isArray(t.gap)?o(t.gap[0]||0):o(t.gap)),c=e(()=>Array.isArray(t.gap)?o(t.gap[1]||0):a.value);return()=>s(t.tag,{class:[`v-row`,i.value,t.class],style:[{"--v-col-gap-x":a.value,"--v-col-gap-y":c.value,"--v-row-columns":t.size},t.style]},r.default?.())}});export{b as n,N as t};
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{sn as e}from"./index-BihgjXCy.js";var t=e(`v-spacer`,`div`,`VSpacer`);export{t};
+1
View File
@@ -0,0 +1 @@
import{sn as e}from"./index-CLVw8WaP.js";var t=e(`v-spacer`,`div`,`VSpacer`);export{t};
+1
View File
@@ -0,0 +1 @@
import{sn as e}from"./index-DNlvHxBC.js";var t=e(`v-spacer`,`div`,`VSpacer`);export{t};
+1
View File
@@ -0,0 +1 @@
import{At as e,Br as t,Et as n,J as r,K as i,Pr as a,Tn as o,Wn as s,X as c,Z as l,Zn as u,en as d,er as f,jr as p,ln as m,o as h,or as g,p as _,pn as v,rn as y,s as b,ur as x,v as S,xr as C,zr as w}from"./index-DNlvHxBC.js";import{n as T,r as E}from"./VContainer-CbSJCQsb.js";var D=v({indeterminate:Boolean,inset:Boolean,flat:Boolean,loading:{type:[Boolean,String],default:!1},...b(),...E()},`VSwitch`),O=m()({name:`VSwitch`,inheritAttrs:!1,props:D(),emits:{"update:focused":e=>!0,"update:modelValue":e=>!0,"update:indeterminate":e=>!0},setup(m,{attrs:v,slots:b}){let E=d(m,`indeterminate`),D=d(m,`modelValue`),{loaderClasses:O}=r(m),{isFocused:k,focus:A,blur:j}=_(m),M=p(),N=p(),P=s&&window.matchMedia(`(forced-colors: active)`).matches,F=a(()=>typeof m.loading==`string`&&m.loading!==``?m.loading:m.color),I=C(),L=a(()=>m.id||`switch-${I}`);function R(){E.value&&=!1}function z(e){e.stopPropagation(),e.preventDefault(),M.value?.input?.click()}return y(()=>{let[r,a]=o(v),s=h.filterProps(m),d=T.filterProps(m);return g(h,x({ref:N,class:[`v-switch`,{"v-switch--flat":m.flat},{"v-switch--inset":m.inset},{"v-switch--indeterminate":E.value},O.value,m.class]},r,s,{modelValue:D.value,"onUpdate:modelValue":e=>D.value=e,id:L.value,focused:k.value,style:m.style}),{...b,default:({id:r,messagesId:o,isDisabled:s,isReadonly:p,isValid:h})=>{let _={model:D,isValid:h};return g(T,x({ref:M},d,{modelValue:D.value,"onUpdate:modelValue":[e=>D.value=e,R],id:r.value,"aria-describedby":o.value,type:`checkbox`,"aria-checked":E.value?`mixed`:void 0,disabled:s.value,readonly:p.value,onFocus:A,onBlur:j},a),{...b,default:({backgroundColorClasses:e,backgroundColorStyles:n})=>f(`div`,{class:w([`v-switch__track`,P?void 0:e.value]),style:t(n.value),onClick:z},[b[`track-true`]&&f(`div`,{key:`prepend`,class:`v-switch__track-true`},[b[`track-true`](_)]),b[`track-false`]&&f(`div`,{key:`append`,class:`v-switch__track-false`},[b[`track-false`](_)])]),input:({inputNode:r,icon:a,backgroundColorClasses:o,backgroundColorStyles:s})=>f(u,null,[r,f(`div`,{class:w([`v-switch__thumb`,{"v-switch__thumb--filled":a||m.loading},m.inset||P?void 0:o.value]),style:t(m.inset?void 0:s.value)},[b.thumb?g(n,{defaults:{VIcon:{icon:a,size:`x-small`}}},{default:()=>[b.thumb({..._,icon:a})]}):g(e,null,{default:()=>[m.loading?g(i,{name:`v-switch`,active:!0,color:h.value===!1?void 0:F.value},{default:e=>b.loader?b.loader(e):g(c,{active:e.isActive,color:e.color,indeterminate:!0,size:`16`,width:`2`},null)}):a&&g(l,{key:String(a),icon:a,size:`x-small`},null)]})])])})}})}),S({},N)}});export{O as t};
+1
View File
@@ -0,0 +1 @@
import{At as e,Br as t,Et as n,J as r,K as i,Pr as a,Tn as o,Wn as s,X as c,Z as l,Zn as u,en as d,er as f,jr as p,ln as m,o as h,or as g,p as _,pn as v,rn as y,s as b,ur as x,v as S,xr as C,zr as w}from"./index-CLVw8WaP.js";import{n as T,r as E}from"./VContainer-FlPueFWR.js";var D=v({indeterminate:Boolean,inset:Boolean,flat:Boolean,loading:{type:[Boolean,String],default:!1},...b(),...E()},`VSwitch`),O=m()({name:`VSwitch`,inheritAttrs:!1,props:D(),emits:{"update:focused":e=>!0,"update:modelValue":e=>!0,"update:indeterminate":e=>!0},setup(m,{attrs:v,slots:b}){let E=d(m,`indeterminate`),D=d(m,`modelValue`),{loaderClasses:O}=r(m),{isFocused:k,focus:A,blur:j}=_(m),M=p(),N=p(),P=s&&window.matchMedia(`(forced-colors: active)`).matches,F=a(()=>typeof m.loading==`string`&&m.loading!==``?m.loading:m.color),I=C(),L=a(()=>m.id||`switch-${I}`);function R(){E.value&&=!1}function z(e){e.stopPropagation(),e.preventDefault(),M.value?.input?.click()}return y(()=>{let[r,a]=o(v),s=h.filterProps(m),d=T.filterProps(m);return g(h,x({ref:N,class:[`v-switch`,{"v-switch--flat":m.flat},{"v-switch--inset":m.inset},{"v-switch--indeterminate":E.value},O.value,m.class]},r,s,{modelValue:D.value,"onUpdate:modelValue":e=>D.value=e,id:L.value,focused:k.value,style:m.style}),{...b,default:({id:r,messagesId:o,isDisabled:s,isReadonly:p,isValid:h})=>{let _={model:D,isValid:h};return g(T,x({ref:M},d,{modelValue:D.value,"onUpdate:modelValue":[e=>D.value=e,R],id:r.value,"aria-describedby":o.value,type:`checkbox`,"aria-checked":E.value?`mixed`:void 0,disabled:s.value,readonly:p.value,onFocus:A,onBlur:j},a),{...b,default:({backgroundColorClasses:e,backgroundColorStyles:n})=>f(`div`,{class:w([`v-switch__track`,P?void 0:e.value]),style:t(n.value),onClick:z},[b[`track-true`]&&f(`div`,{key:`prepend`,class:`v-switch__track-true`},[b[`track-true`](_)]),b[`track-false`]&&f(`div`,{key:`append`,class:`v-switch__track-false`},[b[`track-false`](_)])]),input:({inputNode:r,icon:a,backgroundColorClasses:o,backgroundColorStyles:s})=>f(u,null,[r,f(`div`,{class:w([`v-switch__thumb`,{"v-switch__thumb--filled":a||m.loading},m.inset||P?void 0:o.value]),style:t(m.inset?void 0:s.value)},[b.thumb?g(n,{defaults:{VIcon:{icon:a,size:`x-small`}}},{default:()=>[b.thumb({..._,icon:a})]}):g(e,null,{default:()=>[m.loading?g(i,{name:`v-switch`,active:!0,color:h.value===!1?void 0:F.value},{default:e=>b.loader?b.loader(e):g(c,{active:e.isActive,color:e.color,indeterminate:!0,size:`16`,width:`2`},null)}):a&&g(l,{key:String(a),icon:a,size:`x-small`},null)]})])])})}})}),S({},N)}});export{O as t};
+1
View File
@@ -0,0 +1 @@
import{At as e,Br as t,Et as n,J as r,K as i,Pr as a,Tn as o,Wn as s,X as c,Z as l,Zn as u,en as d,er as f,jr as p,ln as m,o as h,or as g,p as _,pn as v,rn as y,s as b,ur as x,v as S,xr as C,zr as w}from"./index-BihgjXCy.js";import{n as T,r as E}from"./VContainer-V_R05OUP.js";var D=v({indeterminate:Boolean,inset:Boolean,flat:Boolean,loading:{type:[Boolean,String],default:!1},...b(),...E()},`VSwitch`),O=m()({name:`VSwitch`,inheritAttrs:!1,props:D(),emits:{"update:focused":e=>!0,"update:modelValue":e=>!0,"update:indeterminate":e=>!0},setup(m,{attrs:v,slots:b}){let E=d(m,`indeterminate`),D=d(m,`modelValue`),{loaderClasses:O}=r(m),{isFocused:k,focus:A,blur:j}=_(m),M=p(),N=p(),P=s&&window.matchMedia(`(forced-colors: active)`).matches,F=a(()=>typeof m.loading==`string`&&m.loading!==``?m.loading:m.color),I=C(),L=a(()=>m.id||`switch-${I}`);function R(){E.value&&=!1}function z(e){e.stopPropagation(),e.preventDefault(),M.value?.input?.click()}return y(()=>{let[r,a]=o(v),s=h.filterProps(m),d=T.filterProps(m);return g(h,x({ref:N,class:[`v-switch`,{"v-switch--flat":m.flat},{"v-switch--inset":m.inset},{"v-switch--indeterminate":E.value},O.value,m.class]},r,s,{modelValue:D.value,"onUpdate:modelValue":e=>D.value=e,id:L.value,focused:k.value,style:m.style}),{...b,default:({id:r,messagesId:o,isDisabled:s,isReadonly:p,isValid:h})=>{let _={model:D,isValid:h};return g(T,x({ref:M},d,{modelValue:D.value,"onUpdate:modelValue":[e=>D.value=e,R],id:r.value,"aria-describedby":o.value,type:`checkbox`,"aria-checked":E.value?`mixed`:void 0,disabled:s.value,readonly:p.value,onFocus:A,onBlur:j},a),{...b,default:({backgroundColorClasses:e,backgroundColorStyles:n})=>f(`div`,{class:w([`v-switch__track`,P?void 0:e.value]),style:t(n.value),onClick:z},[b[`track-true`]&&f(`div`,{key:`prepend`,class:`v-switch__track-true`},[b[`track-true`](_)]),b[`track-false`]&&f(`div`,{key:`append`,class:`v-switch__track-false`},[b[`track-false`](_)])]),input:({inputNode:r,icon:a,backgroundColorClasses:o,backgroundColorStyles:s})=>f(u,null,[r,f(`div`,{class:w([`v-switch__thumb`,{"v-switch__thumb--filled":a||m.loading},m.inset||P?void 0:o.value]),style:t(m.inset?void 0:s.value)},[b.thumb?g(n,{defaults:{VIcon:{icon:a,size:`x-small`}}},{default:()=>[b.thumb({..._,icon:a})]}):g(e,null,{default:()=>[m.loading?g(i,{name:`v-switch`,active:!0,color:h.value===!1?void 0:F.value},{default:e=>b.loader?b.loader(e):g(c,{active:e.isActive,color:e.color,indeterminate:!0,size:`16`,width:`2`},null)}):a&&g(l,{key:String(a),icon:a,size:`x-small`},null)]})])])})}})}),S({},N)}});export{O as t};
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