统一配置保存提示与未完成状态文案
Some checks are pending
Security Checks / security (push) Waiting to run

This commit is contained in:
smail 2026-09-07 18:03:44 +08:00
parent a7ad2bc32e
commit f4cc8985d6
3 changed files with 21 additions and 21 deletions

View File

@ -80,8 +80,8 @@ export function usePage(pageKey = 'base') {
JSON.stringify(active[id]?.[key]) !== JSON.stringify(candidate[id]?.[key]))
).map(id => sections.find(item => item.value === id)?.label || id)
const scope = pending.payload && loadedText.value
? (changed.length ? `本次候选涉及:${changed.join('、')}。` : '本次候选的插件运行配置未变化。')
: '候选内容尚未完整读取,请刷新后核对。'
? (changed.length ? `上次未完成的保存涉及:${changed.join('、')}。` : '上次未完成保存的插件运行配置未变化。')
: '上次未完成保存的内容尚未完整读取,请刷新后核对。'
return `${scope}三个插件共用一组运行配置,请在对应三级菜单核对;完成保存时会统一生效,其他插件的原有配置会保留。`
}
if (pending?.section !== 'mail' || apiSection() !== 'mail') return ''
@ -99,8 +99,8 @@ export function usePage(pageKey = 'base') {
return Object.keys({ ...before, ...after }).some(field => JSON.stringify(before[field]) !== JSON.stringify(after[field]))
}).map(([, label]) => label)
const scope = pending.payload && loadedText.value
? (changed.length ? `本次候选涉及:${changed.join('、')}。` : '本次候选的邮件服务与安全策略未变化。')
: '候选内容尚未完整读取,请刷新后核对。'
? (changed.length ? `上次未完成的保存涉及:${changed.join('、')}。` : '上次未完成保存的邮件服务与安全策略未变化。')
: '上次未完成保存的内容尚未完整读取,请刷新后核对。'
return `${scope}邮件服务页和安全策略页共用一组运行配置;完成保存时全部变更一起生效,监听端口变更仍需重启后端。`
})
let savedInput = null
@ -229,7 +229,7 @@ export function usePage(pageKey = 'base') {
const loadPending = async () => {
const response = await http.get('/api/v1/config/pending')
if (disposed) return
notifyResponseError(response, '候选配置读取失败')
notifyResponseError(response, '未完成的配置更改读取失败')
pendingCandidate.value = response.data || null
savedGeneration.value = 0
savedInput = null
@ -260,14 +260,14 @@ export function usePage(pageKey = 'base') {
action,
confirmation: { confirmed: true, method: 'recent_auth' }
})
notifyResponseError(response, '候选配置操作失败')
notifyResponseError(response, '未完成的配置更改处理失败')
await loadStatus()
await loadSection()
await loadPending()
if (action === 'cancel') ElMessage.success('本次更改已放弃')
return true
} catch (error) {
if (error !== 'cancel' && error !== 'close') ElMessage.error(error.message || '候选配置操作失败')
if (error !== 'cancel' && error !== 'close') ElMessage.error(error.message || '未完成的配置更改处理失败')
return false
} finally {
working.value = ''
@ -588,11 +588,11 @@ export function usePage(pageKey = 'base') {
}
}
const applyConfig = async ({ successMessage = '配置已应用' } = {}) => {
const applyConfig = async ({ successMessage = '配置已保存' } = {}) => {
if (!canOperate() || !savedGeneration.value) return false
if (!savedInput || savedInput.text !== editorText.value || savedInput.secret !== secretValue.value) {
invalidateCandidate()
ElMessage.warning('填写内容已变更,请重新保存候选配置后再应用')
ElMessage.warning('填写内容已变更,请重新保存配置')
return false
}
working.value = 'apply'
@ -604,7 +604,7 @@ export function usePage(pageKey = 'base') {
candidateId: pendingCandidate.value?.candidateId
}
))
notifyResponseError(response, '配置应用失败')
notifyResponseError(response, '配置保存失败')
savedGeneration.value = 0
await Promise.all([loadStatus(), loadSection()])
await loadPending()
@ -612,7 +612,7 @@ export function usePage(pageKey = 'base') {
return true
} catch (error) {
if (isRecentAuthenticationCancelled(error)) return false
ElMessage.error(error.message || '配置应用失败')
ElMessage.error(error.message || '配置保存失败')
return false
} finally {
working.value = ''

View File

@ -52,7 +52,7 @@ export function useSpamBlockSettings() {
])
notifyResponseError(statusResponse, '配置状态读取失败')
notifyResponseError(pluginsResponse, '插件配置读取失败')
notifyResponseError(pendingResponse, '候选配置读取失败')
notifyResponseError(pendingResponse, '未完成的配置更改读取失败')
pendingCandidate.value = pendingResponse.data || null
savedGeneration.value = 0
activeGeneration.value = Number(statusResponse.data?.activeGeneration || 0)
@ -142,10 +142,10 @@ export function useSpamBlockSettings() {
}
}
const apply = async ({ successMessage = '垃圾邮件插件配置已应用' } = {}) => {
const apply = async ({ successMessage = '垃圾邮件插件配置已保存' } = {}) => {
if (!canWrite() || loading.value || working.value || !savedGeneration.value) return false
if (savedInput !== JSON.stringify(settings)) {
ElMessage.warning('填写内容与候选不一致,请刷新查看候选,或先取消候选再修改')
ElMessage.warning('填写内容已变更,请刷新后核对,或放弃上次未完成的更改')
return false
}
working.value = 'apply'
@ -157,14 +157,14 @@ export function useSpamBlockSettings() {
candidateId: pendingCandidate.value?.candidateId
}
))
notifyResponseError(response, '插件配置应用失败')
notifyResponseError(response, '插件配置保存失败')
savedGeneration.value = 0
await load()
ElMessage.success(successMessage)
return true
} catch (error) {
if (isRecentAuthenticationCancelled(error)) return false
ElMessage.error(error.message || '垃圾邮件插件配置应用失败')
ElMessage.error(error.message || '垃圾邮件插件配置保存失败')
return false
} finally {
working.value = ''
@ -183,12 +183,12 @@ export function useSpamBlockSettings() {
candidateId: pendingCandidate.value.candidateId,
confirmation: { confirmed: true, method: 'recent_auth' }
})
notifyResponseError(response, '候选配置操作失败')
notifyResponseError(response, '未完成的配置更改处理失败')
await load()
if (action === 'cancel') ElMessage.success('本次更改已放弃')
return true
} catch (error) {
if (error !== 'cancel' && error !== 'close') ElMessage.error(error.message || '候选配置操作失败')
if (error !== 'cancel' && error !== 'close') ElMessage.error(error.message || '未完成的配置更改处理失败')
return false
} finally {
working.value = ''

View File

@ -857,12 +857,12 @@ test('邮件页与安全策略页共享候选并明确提示改动范围,忽
page.pendingCandidate.value = { section: 'mail', payload: { ...active, meta: { generation: 2 }, pop3: { tlsPort: 995, port: 110 } } }
assert.match(page.pendingScopeHint.value, /邮件服务与安全策略未变化/)
page.pendingCandidate.value.payload = { ...active, pop3: { port: 1110, tlsPort: 1995 }, policy: { maxMessageBytes: 5678 } }
assert.match(page.pendingScopeHint.value, /本次候选涉及:POP3 监听、邮件与账号策略。/)
assert.match(page.pendingScopeHint.value, /上次未完成的保存涉及:POP3 监听、邮件与账号策略。/)
assert.match(page.pendingScopeHint.value, /邮件服务页和安全策略页共用一组运行配置/)
page.pendingCandidate.value = { section: 'smtp' }
assert.equal(page.pendingScopeHint.value, '')
page.pendingCandidate.value = { section: 'mail' }
assert.match(page.pendingScopeHint.value, /候选内容尚未完整读取/)
assert.match(page.pendingScopeHint.value, /上次未完成保存的内容尚未完整读取/)
}
const template = readFileSync(new URL('../../frontend/src/views/components/ConfigSettings/ConfigEditor/ConfigEditor.vue', import.meta.url), 'utf8')
assert.match(template, /:title="pendingScopeHint"/)
@ -917,7 +917,7 @@ for (const key of ['spam_block', 'telegram_push', 'wechat_push']) {
await page.validateConfig()
await page.saveConfig()
assert.ok(requests.includes('/api/v1/config/plugins/validate'))
assert.match(page.pendingScopeHint.value, new RegExp(`本次候选涉及:${page.currentSection.value.label}。`))
assert.match(page.pendingScopeHint.value, new RegExp(`上次未完成的保存涉及:${page.currentSection.value.label}。`))
const other = Object.keys(original.plugins).find(id => id !== key)
page.updateField(['plugins', other, 'enabled'], true)
assert.equal(page.formConfig.value.plugins[other].enabled, false)