fix(admin): CredsPane 单卡保存不再联动重置兄弟卡

旧 array-source watch 盯 [emailGroup, pushGroup, aiGroup] 三元数组——任一
组引用变化即 resetAll 三卡齐重建:单卡保存(如 email)后父层 onPaneSaved
换整份快照引用,push/ai 卡上未保存的编辑被静默丢弃(Task 14 评审挂账)。

改为三表各自 watch 本组 props 引用:父层保存回写是 {...snapshot, [group]:
config} 展开——只有被保存组引用换新,兄弟组引用不动 → 只重建该卡;切租户/
回滚时快照先置 null 再整份换新,三组引用齐变 → 三卡全量重置(行为保持)。
resetAll 相应拆为 resetEmailCard / resetPushCard / resetAiCard(备注/错误/
测试态随所属卡重置)。

自查两场景:改 email 保存 → push 草稿与 dirty 均保留;切租户 → 三卡齐重置。

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-10-14 21:23:18 +08:00
parent f92a4be139
commit c6bd54229d
+31 -24
View File
@@ -411,7 +411,8 @@
(e: 'dirty', value: boolean): void (e: 'dirty', value: boolean): void
}>() }>()
// ---- 编辑态(组引用变化 = 保存回写/租户切换/重载 → 重置表单与密钥态) ---------------- // ---- 编辑态(单组引用变化 = 该卡保存回写/重载 → 只重置该卡;切租户/回滚时
// 父层整份快照换新 → 三组引用齐变 → 三卡各自重置) ------------------------------------
const emailForm = reactive<EmailCredsForm>(normalizeEmailCredsGroup(undefined).form) const emailForm = reactive<EmailCredsForm>(normalizeEmailCredsGroup(undefined).form)
const pushForm = reactive<PushCredsForm>(normalizePushCredsGroup(undefined).form) const pushForm = reactive<PushCredsForm>(normalizePushCredsGroup(undefined).form)
@@ -434,8 +435,8 @@
const emailError = ref('') const emailError = ref('')
const pushError = ref('') const pushError = ref('')
const aiError = ref('') const aiError = ref('')
/** dirty 基线(三表单各自 normalize*Group().form 的 JSON 快照——与 /** dirty 基线(三表单各自 normalize*Group().form 的 JSON 快照——随各组
* resetAll 同 watch 刷新;密钥输入不进基线:掩码 GET 本就无原值可比, * watch 刷新;密钥输入不进基线:掩码 GET 本就无原值可比,
* 由 dirty 计算里的三态判定补足) */ * 由 dirty 计算里的三态判定补足) */
const emailBaseline = ref(JSON.stringify(normalizeEmailCredsGroup(undefined).form)) const emailBaseline = ref(JSON.stringify(normalizeEmailCredsGroup(undefined).form))
const pushBaseline = ref(JSON.stringify(normalizePushCredsGroup(undefined).form)) const pushBaseline = ref(JSON.stringify(normalizePushCredsGroup(undefined).form))
@@ -453,44 +454,50 @@
const pushProbe = ref<PushTestResponse | null>(null) const pushProbe = ref<PushTestResponse | null>(null)
const pushProbeError = ref('') const pushProbeError = ref('')
function resetAll( /** 单卡重置:只重建该卡的表单/密钥态/备注/错误/测试态——单卡保存回写
emailGroup: Record<string, unknown> | null | undefined, * 不再联动丢弃兄弟卡未保存草稿(Task 14 评审挂账,Task 15 修复) */
pushGroup: Record<string, unknown> | null | undefined, function resetEmailCard(emailGroup: Record<string, unknown> | null | undefined): void {
aiGroup: Record<string, unknown> | null | undefined
): void {
const es = normalizeEmailCredsGroup(emailGroup) const es = normalizeEmailCredsGroup(emailGroup)
Object.assign(emailForm, es.form) Object.assign(emailForm, es.form)
emailPasswordMasked.value = es.passwordMasked emailPasswordMasked.value = es.passwordMasked
emailPasswordCleared.value = false emailPasswordCleared.value = false
emailBaseline.value = JSON.stringify(es.form) emailBaseline.value = JSON.stringify(es.form)
emailComment.value = ''
emailError.value = ''
emailTestResult.value = null
emailTesting.value = false
}
function resetPushCard(pushGroup: Record<string, unknown> | null | undefined): void {
const ps = normalizePushCredsGroup(pushGroup) const ps = normalizePushCredsGroup(pushGroup)
Object.assign(pushForm, ps.form) Object.assign(pushForm, ps.form)
pushApiKeyMasked.value = ps.apiKeyMasked pushApiKeyMasked.value = ps.apiKeyMasked
pushApiKeyCleared.value = false pushApiKeyCleared.value = false
pushBaseline.value = JSON.stringify(ps.form) pushBaseline.value = JSON.stringify(ps.form)
const as = normalizeAiCredsGroup(aiGroup)
Object.assign(aiForm, as.form)
aiApiKeyMasked.value = as.apiKeyMasked
aiApiKeyCleared.value = false
aiBaseline.value = JSON.stringify(as.form)
emailComment.value = ''
pushComment.value = '' pushComment.value = ''
aiComment.value = ''
emailError.value = ''
pushError.value = '' pushError.value = ''
aiError.value = ''
emailTestResult.value = null
emailTesting.value = false
pushProbe.value = null pushProbe.value = null
pushProbeError.value = '' pushProbeError.value = ''
pushProbing.value = false pushProbing.value = false
} }
watch( function resetAiCard(aiGroup: Record<string, unknown> | null | undefined): void {
() => [props.emailGroup, props.pushGroup, props.aiGroup], const as = normalizeAiCredsGroup(aiGroup)
([emailGroup, pushGroup, aiGroup]) => resetAll(emailGroup, pushGroup, aiGroup), Object.assign(aiForm, as.form)
{ immediate: true } aiApiKeyMasked.value = as.apiKeyMasked
) aiApiKeyCleared.value = false
aiBaseline.value = JSON.stringify(as.form)
aiComment.value = ''
aiError.value = ''
}
// 分组 watch(替代旧 array-source 全量 resetAll):父层 onPaneSaved 对快照做
// {...snapshot, [group]: config} 展开——只有被保存组引用换新,兄弟组引用不动
// → 只重建该卡;切租户/回滚时快照先置 null 再整份换新,三组引用齐变 → 三卡
// 全量重置(保持既有行为)
watch(() => props.emailGroup, resetEmailCard, { immediate: true })
watch(() => props.pushGroup, resetPushCard, { immediate: true })
watch(() => props.aiGroup, resetAiCard, { immediate: true })
/** 未保存判定:三表单任一偏离基线,或密钥三态(输入非空 = 覆盖新值 / /** 未保存判定:三表单任一偏离基线,或密钥三态(输入非空 = 覆盖新值 /
* cleared = 显式清除)——密钥输入框基线恒空串,只能独立判定 */ * cleared = 显式清除)——密钥输入框基线恒空串,只能独立判定 */