diff --git a/internal/services/notification_service.go b/internal/services/notification_service.go index da3e2c2..1f45bbb 100644 --- a/internal/services/notification_service.go +++ b/internal/services/notification_service.go @@ -413,7 +413,7 @@ func (s *NotificationService) handleEvent(bindingType string) eventbus.Handler { if len(logSnippet) > extra.LogLimit { logSnippet = "...\n" + logSnippet[len(logSnippet)-extra.LogLimit:] } - currentText += "\n\n【执行日志】\n" + logSnippet + currentText += "\n\n[执行日志]\n" + logSnippet } } diff --git a/web/src/api/index.ts b/web/src/api/index.ts index e1e75cc..0656740 100644 --- a/web/src/api/index.ts +++ b/web/src/api/index.ts @@ -275,7 +275,9 @@ export const api = { listTokens: () => request('/agents/tokens'), createToken: (data: { remark?: string; max_uses?: number; expires_at?: string }) => request('/agents/tokens', { method: 'POST', body: JSON.stringify(data) }), - deleteToken: (id: string) => request('/agents/tokens/' + id, { method: 'DELETE' }) + deleteToken: (id: string) => request('/agents/tokens/' + id, { method: 'DELETE' }), + updateToken: (id: string, data: { remark?: string; max_uses?: number; expires_at?: string }) => + request('/agents/tokens/' + id, { method: 'PUT', body: JSON.stringify(data) }) }, mise: { list: () => request('/mise/ls'), diff --git a/web/src/views/agents/Agents.vue b/web/src/views/agents/Agents.vue index 5f69254..bea8c5f 100644 --- a/web/src/views/agents/Agents.vue +++ b/web/src/views/agents/Agents.vue @@ -29,9 +29,12 @@ const showEditDialog = ref(false) const showDeleteDialog = ref(false) const showDownloadDialog = ref(false) const showTokenDialog = ref(false) +const showEditTokenDialog = ref(false) const showDetailDialog = ref(false) const formData = ref({ name: '', description: '' }) const tokenForm = ref({ remark: '', max_uses: 0, expires_at: '' }) +const editingToken = ref(null) +const editTokenForm = ref({ remark: '', max_uses: 0, expires_at: '' }) const editingAgent = ref(null) const deletingAgent = ref(null) const viewingAgent = ref(null) @@ -71,11 +74,13 @@ async function loadAgents() { } function viewDetail(agent: Agent) { + ;(document.activeElement as HTMLElement)?.blur() viewingAgent.value = agent showDetailDialog.value = true } function openEditDialog(agent: Agent) { + ;(document.activeElement as HTMLElement)?.blur() editingAgent.value = agent formData.value = { name: agent.name, description: agent.description } showEditDialog.value = true @@ -105,10 +110,21 @@ async function toggleEnabled(agent: Agent) { } function confirmDelete(agent: Agent) { + ;(document.activeElement as HTMLElement)?.blur() deletingAgent.value = agent showDeleteDialog.value = true } +function openDownloadDialog() { + ;(document.activeElement as HTMLElement)?.blur() + showDownloadDialog.value = true +} + +function openTokenDialog() { + ;(document.activeElement as HTMLElement)?.blur() + showTokenDialog.value = true +} + async function deleteAgent() { if (!deletingAgent.value) return try { @@ -170,6 +186,35 @@ async function deleteToken(id: string) { } } +function openEditToken(token: AgentToken) { + ;(document.activeElement as HTMLElement)?.blur() + editingToken.value = token + // expires_at 后端格式 "2006-01-02 15:04:05",转回 datetime-local 格式 + const rawExpires = token.expires_at?.replace(' ', 'T').slice(0, 16) || '' + editTokenForm.value = { remark: token.remark || '', max_uses: token.max_uses, expires_at: rawExpires } + showEditTokenDialog.value = true +} + +async function updateToken() { + if (!editingToken.value) return + try { + let expiresAt = editTokenForm.value.expires_at + if (expiresAt) { + expiresAt = expiresAt.replace('T', ' ') + ':00' + } + await api.agents.updateToken(editingToken.value.id, { + remark: editTokenForm.value.remark, + max_uses: editTokenForm.value.max_uses, + expires_at: expiresAt || undefined + }) + showEditTokenDialog.value = false + await loadAgents() + toast.success('更新成功') + } catch (e: unknown) { + toast.error((e as Error).message || '更新失败') + } +} + function isTokenExpired(token: AgentToken) { if (!token.expires_at) return false // 将 "YYYY-MM-DD HH:mm:ss" 转换为 ISO 格式 "YYYY-MM-DDTHH:mm:ss" 以提高浏览器兼容性 @@ -214,7 +259,7 @@ onUnmounted(() => { - +
暂无令牌
- + class="flex items-center gap-2 px-3 py-2 hover:bg-muted/50 transition-colors"> + +
@@ -410,28 +456,33 @@ onUnmounted(() => {
+ {{ token.token }} - {{ token.remark || - '-' }} - + class="flex-1 min-w-0 font-mono text-xs bg-muted px-2 py-0.5 rounded truncate">{{ token.token }} + + + + -
- @@ -629,5 +680,33 @@ onUnmounted(() => { + + + + + + 编辑令牌 + 修改令牌的备注、使用次数和过期时间 + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + + +
+
diff --git a/web/src/views/environments/Environments.vue b/web/src/views/environments/Environments.vue index 5a3d73e..ef7f30e 100644 --- a/web/src/views/environments/Environments.vue +++ b/web/src/views/environments/Environments.vue @@ -287,31 +287,87 @@ onBeforeUnmount(() => {

-
- +
+
+ class="hidden sm:flex items-center gap-4 px-4 py-2 border-b bg-muted/20 text-sm text-muted-foreground font-medium"> + 序号 名称 - + - 操作 + 操作
- -
+ +
{{ activeTab === ENV_TYPE.SECRET ? '暂无机密' : '暂无环境变量' }}
-
+ + +
+
+
+ #{{ total - (currentPage - 1) * pageSize - index }} + {{ env.name }} +
+ +
+ +
+
+ +
+
+
+ + +
+
+ 内容: +
+ +
+
+
+ 备注: + {{ env.remark }} +
+
+ +
+ + + +
+
+ + +
diff --git a/web/src/views/languages/Languages.vue b/web/src/views/languages/Languages.vue index 3f339bf..bdfe565 100644 --- a/web/src/views/languages/Languages.vue +++ b/web/src/views/languages/Languages.vue @@ -335,7 +335,7 @@ onMounted(() => {

语言依赖

-

管理系统环境中的编程语言运行时及相关包依赖 (Mise)

+

管理编程语言及相关包依赖(Mise)

diff --git a/web/src/views/loginlogs/tabs/LoginLogTab.vue b/web/src/views/loginlogs/tabs/LoginLogTab.vue index c489d4d..d8f9450 100644 --- a/web/src/views/loginlogs/tabs/LoginLogTab.vue +++ b/web/src/views/loginlogs/tabs/LoginLogTab.vue @@ -124,37 +124,69 @@ onMounted(loadLogs)
-
- +
+
- 用户名 - IP 地址 - 状态 - - 时间 + class="hidden sm:flex items-center gap-4 px-4 py-2 border-b bg-muted/20 text-sm text-muted-foreground font-medium"> + 序号 + 用户名 + IP 地址 + 状态 + User Agent + 登录时间
+ -
+
暂无登录日志
-
- {{ log.username - }} - {{ log.ip }} - + + +
+
+
+ #{{ total - (currentPage - 1) * pageSize - index }} + {{ log.username }} +
+ +
+ + +
+
+ IP: + {{ log.ip }} +
+
+ 时间: + {{ log.created_at }} +
+
+
+ + +
diff --git a/web/src/views/loginlogs/tabs/SystemEventTab.vue b/web/src/views/loginlogs/tabs/SystemEventTab.vue index 6352cee..e87c7c2 100644 --- a/web/src/views/loginlogs/tabs/SystemEventTab.vue +++ b/web/src/views/loginlogs/tabs/SystemEventTab.vue @@ -127,11 +127,11 @@ const selectedLog = computed(() => logs.value.find((l: AppLog) => l.id === selec function getLevelBadgeClass(level: string) { switch (level) { case LOG_LEVEL.INFO: - return 'bg-blue-500/10 text-blue-700 border-blue-200/50' + return 'bg-blue-500/15 text-blue-500 border-blue-500/30' case LOG_LEVEL.WARNING: - return 'bg-yellow-500/10 text-yellow-700 border-yellow-200/50' + return 'bg-amber-500/15 text-amber-500 border-amber-500/30' case LOG_LEVEL.ERROR: - return 'bg-red-500/10 text-red-700 border-red-200/50' + return 'bg-red-500/15 text-red-500 border-red-500/30' default: return 'bg-secondary text-secondary-foreground border-transparent' } @@ -217,34 +217,63 @@ function onDialogClose(open: boolean) {
-
+
+
- 级别 + class="hidden sm:flex items-center gap-4 px-4 py-2 border-b bg-muted/20 text-sm text-muted-foreground font-medium"> + 序号 + 级别 事件标题 - - 发生时间 + 详情内容 + 发生时间
-
+ +
暂无系统事件
-
+
+
+
+ #{{ total - (filters.page - 1) * pageSize - index }} + + {{ log.title }} +
+
+
+
+ {{ log.content || '-' }} +
+
+
+ {{ formatDate(log.created_at) }} +
+
+ + + @@ -259,10 +288,10 @@ function onDialogClose(open: boolean) {
事件详情 -
+
{{ selectedLog?.level || 'INFO' }}
@@ -273,11 +302,11 @@ function onDialogClose(open: boolean) {
- 标题 - {{ detailDialogProps.title }} + 标题 + {{ detailDialogProps.title }}
- 发生时间 + 发生时间 {{ selectedLog ? formatDate(selectedLog.created_at) : '-' }}
@@ -285,7 +314,7 @@ function onDialogClose(open: boolean) {
+ class="px-6 py-2.5 text-[10px] font-bold text-muted-foreground border-b bg-muted/10 uppercase tracking-widest"> 内容详情
@@ -298,7 +327,7 @@ function onDialogClose(open: boolean) {