fix(frontend): 脚本库与推送调度对齐设计文档
修复 ScriptsPage 执行契约(script_id/command、历史过滤、长任务/凭据)及 SchedulesPage 缺失能力(target_path、next_run、push/script、cron/once、sync_mode);后端补迁移与 schedule_runner 传参。
This commit is contained in:
@@ -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>
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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}",
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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
@@ -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
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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
@@ -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
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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
@@ -0,0 +1 @@
|
||||
import{sn as e}from"./index-BihgjXCy.js";var t=e(`v-spacer`,`div`,`VSpacer`);export{t};
|
||||
@@ -0,0 +1 @@
|
||||
import{sn as e}from"./index-CLVw8WaP.js";var t=e(`v-spacer`,`div`,`VSpacer`);export{t};
|
||||
@@ -0,0 +1 @@
|
||||
import{sn as e}from"./index-DNlvHxBC.js";var t=e(`v-spacer`,`div`,`VSpacer`);export{t};
|
||||
@@ -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};
|
||||
@@ -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};
|
||||
@@ -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
Reference in New Issue
Block a user