feat(web): 客户端密钥页新增 Agent 版本上传与设为当前动作 (#384)

actionLabels 增加 release_upload、release_activate;勾选设为当前时提示
「设为当前后,所有设备会提示更新」。

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTDbDcwbDw1TSAcE6wfh2F
This commit is contained in:
QiuSW
2026-10-12 18:07:57 +08:00
co-authored by Claude Sonnet 5.5
parent 19484f0a68
commit 6107c235cf
2 changed files with 8 additions and 1 deletions
+3 -1
View File
@@ -29,6 +29,7 @@
<div v-for="m in group.modules" :key="m.key" class="module-row">
<div class="module-main"><el-checkbox :model-value="!!grants[m.key]" :disabled="readonly || saving" @change="value => selectModule(m.key, value)">{{ m.title }}</el-checkbox><el-radio-group v-if="grants[m.key]" v-model="grants[m.key].write" :disabled="readonly || saving" size="small" :aria-label="`${m.title}访问方式`"><el-radio-button :value="false">只读</el-radio-button><el-radio-button :value="true" :disabled="!m.writable">读写</el-radio-button></el-radio-group></div>
<div v-if="grants[m.key] && m.actions.length" class="actions"><span class="muted">独立动作:</span><el-checkbox-group v-model="grants[m.key].actions" :disabled="readonly || saving"><el-checkbox v-for="action in m.actions" :key="action" :value="action">{{ actionName(action) }}</el-checkbox></el-checkbox-group></div>
<p v-if="grants[m.key] && grants[m.key].actions.includes('release_activate')" class="risk" role="note">设为当前后,所有设备会提示更新</p>
</div>
</section>
</div>
@@ -51,7 +52,7 @@
import { ElMessage, ElMessageBox } from 'element-plus'
import { listClientKeys, clientKeyModules, createClientKey, editClientKey, disableClientKey } from '@/api/goauto/client-keys'
const actionLabels = { sync: '立即同步', import: '导入', match: '匹配 / 确认', collect: '创建 / 重新采集', purchase: '创建 / 重试采购', writeback: '回写', delete: '删除', reparse: '重新解析', activate: '设置当前规则' }
const actionLabels = { sync: '立即同步', import: '导入', match: '匹配 / 确认', collect: '创建 / 重新采集', purchase: '创建 / 重试采购', writeback: '回写', delete: '删除', reparse: '重新解析', activate: '设置当前规则', release_upload: '上传 Agent 版本', release_activate: '设置当前 Agent 版本' }
const snapshot = grants => JSON.stringify(Object.values(grants).map(g => ({ ...g, actions: [...g.actions].sort() })).sort((a, b) => a.module.localeCompare(b.module)))
const errorText = error => error.response?.data?.message || '请求失败,请检查网络后重试'
@@ -114,6 +115,7 @@ h2 { margin: 0 0 12px; }
.module-row { padding: 10px 0; border-top: 1px solid var(--el-border-color-lighter); }
.module-main { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
.actions { padding: 4px 0 0 22px; }
.risk { margin: 4px 0 0; padding-left: 22px; color: var(--el-color-warning); font-size: 13px; }
.notice, .el-pagination { margin: 16px 0; }
.validation { color: var(--el-color-danger); }
.secret { white-space: pre-wrap; overflow-wrap: anywhere; padding: 16px; background: var(--el-fill-color-light); }
+5
View File
@@ -59,3 +59,8 @@ test('late creation response after navigation does not retain a secret', async()
resolve({ data: { secret: 'DEMO_ONLY_NOT_A_VALID_SECRET' }}); await pending
expect(p.secret).toBe(''); expect(p.secretOpen).toBe(false)
})
test('agent release actions have distinct labels', () => {
const p = vm()
expect(p.actionName('release_upload')).toBe('上传 Agent 版本')
expect(p.actionName('release_activate')).toBe('设置当前 Agent 版本')
})