feat(admin): secretFieldState 密钥四态展示纯函数

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-10-14 16:52:25 +08:00
parent eb2220c26c
commit 0a413526bb
2 changed files with 61 additions and 1 deletions
@@ -52,6 +52,7 @@ import {
rowsToEntries,
rowToSingleEntry,
scopedConfigJson,
secretFieldState,
snapshotGroupKeys,
touchstoneSentences,
utf8Bytes,
@@ -745,3 +746,24 @@ describe('通用 JSON 组编辑(终审 I-1:contact/engine/misc)', () => {
expect(JSON_GROUP_FIELDS.misc.map((f) => f.key)).toEqual(['name_to_region_extras'])
})
})
describe('secretFieldState(密钥四件套展示态)', () => {
it('未配置:input 空 + 无掩码', () => {
const s = secretFieldState('', '', false)
expect(s).toMatchObject({ badge: 'unset', badgeType: 'info', badgeLabel: '未配置' })
expect(s.placeholder).toContain('未设置')
})
it('已配置:掩码哨兵且未动', () => {
const s = secretFieldState('', '__SET__', false)
expect(s).toMatchObject({ badge: 'configured', badgeType: 'success', badgeLabel: '已配置' })
expect(s.placeholder).toContain('留空保持不变')
})
it('pending-new:输入了新值(优先级最高)', () => {
const s = secretFieldState('new-secret', '__SET__', true)
expect(s).toMatchObject({ badge: 'pending-new', badgeType: 'warning', badgeLabel: '已输入新值 · 未保存' })
})
it('pending-clear:清除了已配置值', () => {
const s = secretFieldState('', '__SET__', true)
expect(s).toMatchObject({ badge: 'pending-clear', badgeType: 'warning', badgeLabel: '将清除 · 未保存' })
})
})
+39 -1
View File
@@ -23,7 +23,7 @@
* 密钥哨兵交互见 src/api/mask.ts(GET '__SET__' → 空输入 + 占位符;
* 不动保存回传哨兵保持库值;「清除」= 提交空串)。
*/
import { MASKED_SENTINEL, secretToSubmit } from '@/api/mask'
import { MASKED_SENTINEL, isMaskedSentinel, secretToSubmit } from '@/api/mask'
import type { ConfigGroupKey } from '@/api/config'
// ---- 提示词四件套 -----------------------------------------------------------------
@@ -569,6 +569,44 @@ export function normalizeAiCredsGroup(
}
}
// ---- SecretField 展示态(视觉基线 §4.2;提交值仍走 secretToSubmit) -----------------
/** 密钥字段徽章四态:已配置 / 未配置 / 已输入新值(未保存) / 将清除(未保存) */
export type SecretFieldBadge = 'configured' | 'unset' | 'pending-new' | 'pending-clear'
export interface SecretFieldState {
badge: SecretFieldBadge
/** ElTag type 映射(configured=success / unset=info / pending-*=warning) */
badgeType: 'success' | 'info' | 'warning'
badgeLabel: string
placeholder: string
}
/** 输入值 + GET 掩码态 + 清除开关 → 徽章/占位文案(纯展示;优先级 新值 > 清除 > 已配置 > 未配置) */
export function secretFieldState(
input: string,
masked: string,
cleared: boolean
): SecretFieldState {
if (input !== '') {
return {
badge: 'pending-new', badgeType: 'warning', badgeLabel: '已输入新值 · 未保存', placeholder: ''
}
}
if (cleared) {
return {
badge: 'pending-clear', badgeType: 'warning', badgeLabel: '将清除 · 未保存', placeholder: ''
}
}
if (isMaskedSentinel(masked)) {
return {
badge: 'configured', badgeType: 'success', badgeLabel: '已配置',
placeholder: '已设置,输入新值可更换(留空保持不变)'
}
}
return { badge: 'unset', badgeType: 'info', badgeLabel: '未配置', placeholder: '未设置,输入新值' }
}
/**
* 邮件表单 → PUT config/email 整组载荷。密钥走 secretToSubmit(未动 →
* 哨兵保持库值;「清除」按钮已把 maskedState 置 '',提交空串 = 显式清空)。