fix(密钥配置): 保存沿用刚检测过的输入值结果,消除「三项检测通过却提示未检测」死循环
- 服务端:对「输入值(未保存)」的检测结果按 uid+模块+值指纹暂存 Redis(TTL 30min, Redis 异常降级为需重新检测,不阻断保存);保存同一个值时落库该结果 (passed/failed/error 一并沿用),改过值或从未检测则维持未检测 - 前端:保存后清理本地「输入值(未保存)」绿字,展示统一走服务端快照,避免展示与门禁矛盾; 门禁提示改列「模块名(掩码):未检测 / 检测失败:原因 / 未配置」,同名掩码也能分辨模块 - 测试:UserApiSecretServiceTest 补沿用 / 值不一致 / Redis 降级用例; 新增前后端一致性守卫测试(保存后必须清检测结果、提示必须带模块名)
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
<div class="setup-card-title">完成密钥配置后即可使用</div>
|
||||
<div class="setup-card-desc">
|
||||
密钥保存在服务端并绑定当前账号,换设备登录后自动同步。
|
||||
请填写以下密钥并保存,检测通过后即可进入工具台。
|
||||
请填写以下密钥,点「检测」确认可用后保存;全部检测通过即可进入工具台。
|
||||
</div>
|
||||
|
||||
<ApiSecretSettingsPanel ref="panelRef" />
|
||||
@@ -48,7 +48,7 @@ const route = useRoute()
|
||||
const panelRef = ref<InstanceType<typeof ApiSecretSettingsPanel> | null>(null)
|
||||
const submitting = ref(false)
|
||||
const username = ref('')
|
||||
const hint = ref('填写密钥并保存后,请点击对应模块的「检测」按钮确认可用,全部检测通过后即可进入工具台。')
|
||||
const hint = ref('填写密钥后请先点「检测」确认可用再保存(检测通过的输入值保存时会沿用同一结果),全部检测通过后即可进入工具台。')
|
||||
|
||||
onMounted(() => {
|
||||
try {
|
||||
@@ -58,7 +58,10 @@ onMounted(() => {
|
||||
}
|
||||
})
|
||||
|
||||
/** 提交:保存后只校验检测状态;检测一律由用户手动点击「检测」触发(2026-09-13 起不再自动补检)。 */
|
||||
/**
|
||||
* 提交:保存后只校验检测状态;检测一律由用户手动点「检测」触发(服务端会沿用刚检测过的同一个输入值,
|
||||
* 因此「检测 → 保存并进入」一次即可通过;改过值或从未检测的模块仍需重新检测)。
|
||||
*/
|
||||
async function submit() {
|
||||
if (submitting.value) return
|
||||
const panel = panelRef.value
|
||||
@@ -71,9 +74,24 @@ async function submit() {
|
||||
const state = await loadApiSecrets({ force: true })
|
||||
if (state === 'incomplete') {
|
||||
const failed = listApiSecretModules()
|
||||
.map((module) => getStoredApiSecretSnapshot(module.moduleKey as ApiSecretModuleKey))
|
||||
.filter((snapshot) => !snapshot.exists || (snapshot.checkStatus !== 'passed' && snapshot.checkStatus !== 'error'))
|
||||
hint.value = `以下密钥尚未通过检测:${failed.map((item) => item.masked || '未配置').join('、')},请点击上方的「检测」按钮逐项确认后重试。`
|
||||
.map((module) => ({
|
||||
module,
|
||||
snapshot: getStoredApiSecretSnapshot(module.moduleKey as ApiSecretModuleKey),
|
||||
}))
|
||||
.filter(({ snapshot }) => !snapshot.exists || (snapshot.checkStatus !== 'passed' && snapshot.checkStatus !== 'error'))
|
||||
// 逐项列出「模块名(掩码)+ 未通过原因」:同一密钥填进多个模块时也能分清是哪个模块
|
||||
const detail = failed.map(({ module, snapshot }) => {
|
||||
const masked = snapshot.masked || '未配置'
|
||||
if (!snapshot.exists) {
|
||||
return `${module.moduleLabel}(${masked})尚未配置`
|
||||
}
|
||||
if (snapshot.checkStatus === 'failed') {
|
||||
const reason = snapshot.checkMessage ? `:${snapshot.checkMessage.slice(0, 40)}` : ''
|
||||
return `${module.moduleLabel}(${masked})检测失败${reason}`
|
||||
}
|
||||
return `${module.moduleLabel}(${masked})尚未检测`
|
||||
})
|
||||
hint.value = `以下密钥尚未通过检测:${detail.join(';')}。请点击上方对应模块的「检测」按钮确认后重试。`
|
||||
ElMessage.warning('密钥尚未全部检测通过,请点击「检测」按钮逐项确认')
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user