feat(admin): 凭据页套视觉基线+SecretField 四件套
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -7,38 +7,30 @@
|
||||
- AI(ai 组):provider / API Key / base_url / model
|
||||
- 密钥哨兵交互(mask.ts):GET 密钥为 '__SET__' → 输入框留空 + 占位符
|
||||
「已设置,输入新值覆盖」;不动保存回传哨兵保持库值;「清除」按钮 =
|
||||
显式清空意图(提交空串),可再点「恢复保持」撤销
|
||||
显式清空意图(提交空串),可再点「恢复保持」撤销——交互由 SecretField
|
||||
四件套组件承载(Task 5 起),提交值仍由父层 build*Payload 计算
|
||||
- SMTP 测试邮件:收件人 + 按钮 → POST email/test——用**已保存**配置真发
|
||||
一封(先保存再测试);未配置 400 / 发送失败 sent=false 均内联展示
|
||||
- 推送连通性探测:POST push/test(后端发空 messages 批量,零线索数据)
|
||||
——三态展示:不可达(dns/timeout/connect 原因分类)/ 可达但鉴权失败
|
||||
(401·403)/ 正常(2xx);其余状态码 = 可达但鉴权不定
|
||||
- 重置出厂(Task 7d):三卡头部危险色小按钮 → 确认框 → POST
|
||||
- 重置出厂(Task 7d):卡底危险行小按钮 → 确认框 → POST
|
||||
config/{group}/reset → 表单/密钥态回档案值 + emit saved;push 出厂
|
||||
前缀被其他租户占用的 400 detail 内联展示
|
||||
- Task 5 视觉基线:三卡套 ConfigCard(图标/副标题/信息条/footer/danger
|
||||
行);footer-left「出问题?回滚 →」emit navigate('versions')(父层
|
||||
接线在后续任务);表单区双列 grid
|
||||
-->
|
||||
<template>
|
||||
<div class="creds-pane">
|
||||
<!-- 邮件 -->
|
||||
<ElCard shadow="never" class="form-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">邮件(email 组 · SMTP 发信)</span>
|
||||
<div class="header-side">
|
||||
<span class="card-sub">空槽 = 未设置 → 回退平台环境默认;保存即写新版本并热生效</span>
|
||||
<ElButton
|
||||
size="small"
|
||||
type="danger"
|
||||
plain
|
||||
:loading="resettingEmail"
|
||||
@click="onResetGroup('email')"
|
||||
>
|
||||
重置出厂
|
||||
</ElButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<ConfigCard
|
||||
icon="solar:letter-linear"
|
||||
title="邮件通知"
|
||||
subtitle="客户留下线索后,系统用这组配置发通知邮件"
|
||||
info="整组保存 · 立即生效 · 产生新版本可回滚;带 • 的字段留空 = 沿用平台默认"
|
||||
danger-label="恢复出厂:把邮件配置重置为初始档案值"
|
||||
>
|
||||
<ElAlert
|
||||
v-if="emailError"
|
||||
type="error"
|
||||
@@ -49,81 +41,54 @@
|
||||
/>
|
||||
|
||||
<ElForm label-width="130px" @submit.prevent>
|
||||
<ElFormItem label="SMTP 服务器">
|
||||
<ElInput
|
||||
v-model="emailForm.smtpHost"
|
||||
placeholder="如 smtp.exmail.qq.com(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="SMTP 端口">
|
||||
<ElInput
|
||||
v-model="emailForm.smtpPort"
|
||||
placeholder="如 465(1-65535 整数,留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="SMTP 账号">
|
||||
<ElInput
|
||||
v-model="emailForm.smtpUser"
|
||||
placeholder="发件邮箱账号(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="SMTP 密码">
|
||||
<div class="secret-row">
|
||||
<div class="form-grid">
|
||||
<ElFormItem label="SMTP 服务器">
|
||||
<ElInput
|
||||
v-model="emailForm.smtpPassword"
|
||||
type="password"
|
||||
show-password
|
||||
autocomplete="new-password"
|
||||
:placeholder="emailPasswordPlaceholder"
|
||||
class="secret-input"
|
||||
v-model="emailForm.smtpHost"
|
||||
placeholder="如 smtp.exmail.qq.com(留空 = 平台默认)"
|
||||
/>
|
||||
<ElButton
|
||||
v-if="emailPasswordMasked === MASKED_SENTINEL"
|
||||
size="small"
|
||||
:type="emailPasswordCleared ? 'default' : 'danger'"
|
||||
plain
|
||||
@click="emailPasswordCleared = !emailPasswordCleared"
|
||||
>
|
||||
{{ emailPasswordCleared ? '恢复保持' : '清除' }}
|
||||
</ElButton>
|
||||
</div>
|
||||
<p v-if="emailPasswordCleared" class="field-warn">
|
||||
保存后将清除已存密码(空槽回退平台默认)
|
||||
</p>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="发件人名称">
|
||||
<ElInput
|
||||
v-model="emailForm.senderName"
|
||||
placeholder='邮件【发件人名称】展示(留空 = "HESUPIPE")'
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="通知邮箱">
|
||||
<ElSelect
|
||||
v-model="emailForm.notifyEmails"
|
||||
multiple
|
||||
filterable
|
||||
allow-create
|
||||
default-first-option
|
||||
:reserve-keyword="false"
|
||||
placeholder="输入邮箱后回车添加(新询盘通知收件人,留空 = 平台默认)"
|
||||
class="wide-control"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="保存备注">
|
||||
<ElInput
|
||||
v-model="emailComment"
|
||||
maxlength="200"
|
||||
placeholder="可选;写入版本历史 comment"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="SMTP 端口">
|
||||
<ElInput
|
||||
v-model="emailForm.smtpPort"
|
||||
placeholder="如 465(1-65535 整数,留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="SMTP 账号">
|
||||
<ElInput
|
||||
v-model="emailForm.smtpUser"
|
||||
placeholder="发件邮箱账号(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="发件人名称">
|
||||
<ElInput
|
||||
v-model="emailForm.senderName"
|
||||
placeholder='邮件【发件人名称】展示(留空 = "HESUPIPE")'
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="SMTP 密码" class="span-2">
|
||||
<SecretField
|
||||
v-model="emailForm.smtpPassword"
|
||||
:masked="emailPasswordMasked"
|
||||
:cleared="emailPasswordCleared"
|
||||
@update:cleared="emailPasswordCleared = $event"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="通知邮箱" class="span-2">
|
||||
<ElSelect
|
||||
v-model="emailForm.notifyEmails"
|
||||
multiple
|
||||
filterable
|
||||
allow-create
|
||||
default-first-option
|
||||
:reserve-keyword="false"
|
||||
placeholder="输入邮箱后回车添加(新询盘通知收件人,留空 = 平台默认)"
|
||||
class="wide-control"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</div>
|
||||
</ElForm>
|
||||
|
||||
<div class="save-bar">
|
||||
<ElButton type="primary" :loading="emailSaving" @click="onSaveEmail">
|
||||
保存邮件组(整组提交,热生效)
|
||||
</ElButton>
|
||||
</div>
|
||||
|
||||
<ElDivider class="test-divider" align="left">连通性验证(用已保存配置)</ElDivider>
|
||||
<div class="test-row">
|
||||
<ElInput
|
||||
@@ -132,11 +97,11 @@
|
||||
class="test-input"
|
||||
/>
|
||||
<ElButton :loading="emailTesting" :disabled="!slug" @click="onTestEmail">
|
||||
发测试邮件
|
||||
发送测试邮件(真发一封)
|
||||
</ElButton>
|
||||
</div>
|
||||
<p class="test-hint">
|
||||
后端用**已保存**的邮件配置真发一封(主题「[all-kefu] SMTP 测试邮件」)
|
||||
系统用**已保存**的邮件配置真发一封(主题「[all-kefu] SMTP 测试邮件」)
|
||||
——改完先保存再测试;SMTP 未配置时返回 400。
|
||||
</p>
|
||||
<ElAlert
|
||||
@@ -148,28 +113,42 @@
|
||||
class="test-result"
|
||||
@close="emailTestResult = null"
|
||||
/>
|
||||
</ElCard>
|
||||
|
||||
<template #footer-left>
|
||||
<ElButton link type="primary" size="small" @click="$emit('navigate', 'versions')">
|
||||
出问题?回滚 →
|
||||
</ElButton>
|
||||
</template>
|
||||
<template #footer-right>
|
||||
<ElInput
|
||||
v-model="emailComment"
|
||||
maxlength="200"
|
||||
placeholder="备注(选填)"
|
||||
class="comment-input"
|
||||
/>
|
||||
<ElButton type="primary" :loading="emailSaving" @click="onSaveEmail">保存</ElButton>
|
||||
</template>
|
||||
<template #danger>
|
||||
<ElButton
|
||||
size="small"
|
||||
type="danger"
|
||||
plain
|
||||
:loading="resettingEmail"
|
||||
@click="onResetGroup('email')"
|
||||
>
|
||||
重置出厂…
|
||||
</ElButton>
|
||||
</template>
|
||||
</ConfigCard>
|
||||
|
||||
<!-- 推送 -->
|
||||
<ElCard shadow="never" class="form-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">推送(push 组 · 线索推送 UniService)</span>
|
||||
<div class="header-side">
|
||||
<span class="card-sub">数值留空 = 平台默认;前缀全局唯一(跨租户查重)</span>
|
||||
<ElButton
|
||||
size="small"
|
||||
type="danger"
|
||||
plain
|
||||
:loading="resettingPush"
|
||||
@click="onResetGroup('push')"
|
||||
>
|
||||
重置出厂
|
||||
</ElButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<ConfigCard
|
||||
icon="solar:upload-square-line-duotone"
|
||||
title="线索推送"
|
||||
subtitle="新线索实时推送到你的业务系统(UniService)"
|
||||
info="数值留空 = 平台默认;前缀全局唯一(跨租户查重)——整组保存 · 立即生效 · 可回滚"
|
||||
danger-label="恢复出厂:把推送配置重置为初始档案值"
|
||||
>
|
||||
<ElAlert
|
||||
v-if="pushError"
|
||||
type="error"
|
||||
@@ -180,79 +159,52 @@
|
||||
/>
|
||||
|
||||
<ElForm label-width="130px" @submit.prevent>
|
||||
<ElFormItem label="启用推送">
|
||||
<ElSwitch v-model="pushForm.enabled" />
|
||||
<span class="switch-hint">关闭后新线索不推送(只落库)</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="推送 URL">
|
||||
<ElInput
|
||||
v-model="pushForm.url"
|
||||
placeholder="https://push.example/open/v1/inquiry/push(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="API Key">
|
||||
<div class="secret-row">
|
||||
<div class="form-grid">
|
||||
<ElFormItem label="启用推送" class="span-2">
|
||||
<ElSwitch v-model="pushForm.enabled" />
|
||||
<span class="switch-hint">关闭后新线索不推送(只落库)</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="推送 URL">
|
||||
<ElInput
|
||||
v-model="pushForm.apiKey"
|
||||
type="password"
|
||||
show-password
|
||||
autocomplete="new-password"
|
||||
:placeholder="pushApiKeyPlaceholder"
|
||||
class="secret-input"
|
||||
v-model="pushForm.url"
|
||||
placeholder="https://push.example/open/v1/inquiry/push(留空 = 平台默认)"
|
||||
/>
|
||||
<ElButton
|
||||
v-if="pushApiKeyMasked === MASKED_SENTINEL"
|
||||
size="small"
|
||||
:type="pushApiKeyCleared ? 'default' : 'danger'"
|
||||
plain
|
||||
@click="pushApiKeyCleared = !pushApiKeyCleared"
|
||||
>
|
||||
{{ pushApiKeyCleared ? '恢复保持' : '清除' }}
|
||||
</ElButton>
|
||||
</div>
|
||||
<p v-if="pushApiKeyCleared" class="field-warn">
|
||||
保存后将清除已存 API Key(空槽回退平台默认)
|
||||
</p>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="线索前缀">
|
||||
<ElInput
|
||||
v-model="pushForm.prefix"
|
||||
placeholder="external_key 前缀(全局唯一;留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="超时(秒)">
|
||||
<ElInput
|
||||
v-model="pushForm.timeout"
|
||||
placeholder="正数,如 10(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="最大尝试次数">
|
||||
<ElInput
|
||||
v-model="pushForm.maxAttempts"
|
||||
placeholder="1-10 整数,如 3(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="退避基数(秒)">
|
||||
<ElInput
|
||||
v-model="pushForm.backoffBase"
|
||||
placeholder="正数,如 1(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="保存备注">
|
||||
<ElInput
|
||||
v-model="pushComment"
|
||||
maxlength="200"
|
||||
placeholder="可选;写入版本历史 comment"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="线索前缀">
|
||||
<ElInput
|
||||
v-model="pushForm.prefix"
|
||||
placeholder="external_key 前缀(全局唯一;留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="API Key" class="span-2">
|
||||
<SecretField
|
||||
v-model="pushForm.apiKey"
|
||||
:masked="pushApiKeyMasked"
|
||||
:cleared="pushApiKeyCleared"
|
||||
@update:cleared="pushApiKeyCleared = $event"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="超时(秒)">
|
||||
<ElInput
|
||||
v-model="pushForm.timeout"
|
||||
placeholder="正数,如 10(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="最大尝试次数">
|
||||
<ElInput
|
||||
v-model="pushForm.maxAttempts"
|
||||
placeholder="1-10 整数,如 3(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="退避基数(秒)">
|
||||
<ElInput
|
||||
v-model="pushForm.backoffBase"
|
||||
placeholder="正数,如 1(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</div>
|
||||
</ElForm>
|
||||
|
||||
<div class="save-bar">
|
||||
<ElButton type="primary" :loading="pushSaving" @click="onSavePush">
|
||||
保存推送组(整组提交,热生效)
|
||||
</ElButton>
|
||||
</div>
|
||||
|
||||
<ElDivider class="test-divider" align="left">连通性探测(用已保存配置)</ElDivider>
|
||||
<div class="test-row">
|
||||
<ElButton :loading="pushProbing" :disabled="!slug" @click="onProbePush">
|
||||
@@ -304,28 +256,42 @@
|
||||
:description="pushProbe.error || undefined"
|
||||
@close="pushProbe = null"
|
||||
/>
|
||||
</ElCard>
|
||||
|
||||
<template #footer-left>
|
||||
<ElButton link type="primary" size="small" @click="$emit('navigate', 'versions')">
|
||||
出问题?回滚 →
|
||||
</ElButton>
|
||||
</template>
|
||||
<template #footer-right>
|
||||
<ElInput
|
||||
v-model="pushComment"
|
||||
maxlength="200"
|
||||
placeholder="备注(选填)"
|
||||
class="comment-input"
|
||||
/>
|
||||
<ElButton type="primary" :loading="pushSaving" @click="onSavePush">保存</ElButton>
|
||||
</template>
|
||||
<template #danger>
|
||||
<ElButton
|
||||
size="small"
|
||||
type="danger"
|
||||
plain
|
||||
:loading="resettingPush"
|
||||
@click="onResetGroup('push')"
|
||||
>
|
||||
重置出厂…
|
||||
</ElButton>
|
||||
</template>
|
||||
</ConfigCard>
|
||||
|
||||
<!-- AI -->
|
||||
<ElCard shadow="never" class="form-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">AI(ai 组 · 模型服务)</span>
|
||||
<div class="header-side">
|
||||
<span class="card-sub">密钥空槽 = 未设置 → 回退平台集团凭据(spec §5.5)</span>
|
||||
<ElButton
|
||||
size="small"
|
||||
type="danger"
|
||||
plain
|
||||
:loading="resettingAi"
|
||||
@click="onResetGroup('ai')"
|
||||
>
|
||||
重置出厂
|
||||
</ElButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<ConfigCard
|
||||
icon="solar:cpu-bolt-line-duotone"
|
||||
title="AI 服务"
|
||||
subtitle="对话引擎调用的大模型服务凭据"
|
||||
info="整组保存 · 立即生效 · 可回滚;留空 = 平台默认"
|
||||
danger-label="恢复出厂:把 AI 配置重置为初始档案值"
|
||||
>
|
||||
<ElAlert
|
||||
v-if="aiError"
|
||||
type="error"
|
||||
@@ -336,63 +302,62 @@
|
||||
/>
|
||||
|
||||
<ElForm label-width="130px" @submit.prevent>
|
||||
<ElFormItem label="Provider">
|
||||
<ElInput
|
||||
v-model="aiForm.provider"
|
||||
placeholder="如 glm(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="API Key">
|
||||
<div class="secret-row">
|
||||
<div class="form-grid">
|
||||
<ElFormItem label="Provider">
|
||||
<ElInput
|
||||
v-model="aiForm.apiKey"
|
||||
type="password"
|
||||
show-password
|
||||
autocomplete="new-password"
|
||||
:placeholder="aiApiKeyPlaceholder"
|
||||
class="secret-input"
|
||||
v-model="aiForm.provider"
|
||||
placeholder="如 glm(留空 = 平台默认)"
|
||||
/>
|
||||
<ElButton
|
||||
v-if="aiApiKeyMasked === MASKED_SENTINEL"
|
||||
size="small"
|
||||
:type="aiApiKeyCleared ? 'default' : 'danger'"
|
||||
plain
|
||||
@click="aiApiKeyCleared = !aiApiKeyCleared"
|
||||
>
|
||||
{{ aiApiKeyCleared ? '恢复保持' : '清除' }}
|
||||
</ElButton>
|
||||
</div>
|
||||
<p v-if="aiApiKeyCleared" class="field-warn">
|
||||
保存后将清除已存 API Key(空槽回退平台集团凭据)
|
||||
</p>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="Base URL">
|
||||
<ElInput
|
||||
v-model="aiForm.baseUrl"
|
||||
placeholder="如 https://open.bigmodel.cn/api/paas/v4(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="模型">
|
||||
<ElInput
|
||||
v-model="aiForm.model"
|
||||
placeholder="如 glm-4-flash(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="保存备注">
|
||||
<ElInput
|
||||
v-model="aiComment"
|
||||
maxlength="200"
|
||||
placeholder="可选;写入版本历史 comment"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="模型">
|
||||
<ElInput
|
||||
v-model="aiForm.model"
|
||||
placeholder="如 glm-4-flash(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="Base URL" class="span-2">
|
||||
<ElInput
|
||||
v-model="aiForm.baseUrl"
|
||||
placeholder="如 https://open.bigmodel.cn/api/paas/v4(留空 = 平台默认)"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="API Key" class="span-2">
|
||||
<SecretField
|
||||
v-model="aiForm.apiKey"
|
||||
:masked="aiApiKeyMasked"
|
||||
:cleared="aiApiKeyCleared"
|
||||
@update:cleared="aiApiKeyCleared = $event"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</div>
|
||||
</ElForm>
|
||||
|
||||
<div class="save-bar">
|
||||
<ElButton type="primary" :loading="aiSaving" @click="onSaveAi">
|
||||
保存 AI 组(整组提交,热生效)
|
||||
<template #footer-left>
|
||||
<ElButton link type="primary" size="small" @click="$emit('navigate', 'versions')">
|
||||
出问题?回滚 →
|
||||
</ElButton>
|
||||
</div>
|
||||
</ElCard>
|
||||
</template>
|
||||
<template #footer-right>
|
||||
<ElInput
|
||||
v-model="aiComment"
|
||||
maxlength="200"
|
||||
placeholder="备注(选填)"
|
||||
class="comment-input"
|
||||
/>
|
||||
<ElButton type="primary" :loading="aiSaving" @click="onSaveAi">保存</ElButton>
|
||||
</template>
|
||||
<template #danger>
|
||||
<ElButton
|
||||
size="small"
|
||||
type="danger"
|
||||
plain
|
||||
:loading="resettingAi"
|
||||
@click="onResetGroup('ai')"
|
||||
>
|
||||
重置出厂…
|
||||
</ElButton>
|
||||
</template>
|
||||
</ConfigCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -413,8 +378,9 @@
|
||||
type PushCredsForm
|
||||
} from './model'
|
||||
import { putConfigGroup, testEmail, testPush, type PushTestResponse } from '@/api/config'
|
||||
import { MASKED_SENTINEL, secretPlaceholder } from '@/api/mask'
|
||||
import { confirmAndResetGroup } from './reset'
|
||||
import ConfigCard from './ConfigCard.vue'
|
||||
import SecretField from './SecretField.vue'
|
||||
|
||||
defineOptions({ name: 'CredsPane' })
|
||||
|
||||
@@ -439,6 +405,8 @@
|
||||
config: Record<string, unknown>
|
||||
}
|
||||
): void
|
||||
/** footer 回滚入口:请求父层切到对应组('versions' = 版本历史) */
|
||||
(e: 'navigate', group: string): void
|
||||
}>()
|
||||
|
||||
// ---- 编辑态(组引用变化 = 保存回写/租户切换/重载 → 重置表单与密钥态) ----------------
|
||||
@@ -513,20 +481,6 @@
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
const emailPasswordPlaceholder = computed(() =>
|
||||
emailPasswordCleared.value
|
||||
? secretPlaceholder('')
|
||||
: secretPlaceholder(emailPasswordMasked.value)
|
||||
)
|
||||
const pushApiKeyPlaceholder = computed(() =>
|
||||
pushApiKeyCleared.value
|
||||
? secretPlaceholder('')
|
||||
: secretPlaceholder(pushApiKeyMasked.value)
|
||||
)
|
||||
const aiApiKeyPlaceholder = computed(() =>
|
||||
aiApiKeyCleared.value ? secretPlaceholder('') : secretPlaceholder(aiApiKeyMasked.value)
|
||||
)
|
||||
|
||||
// ---- 保存(前端预检 → 整组 PUT;密钥不动回哨兵保持库值) ------------------------------
|
||||
|
||||
async function onSaveEmail(): Promise<void> {
|
||||
@@ -698,7 +652,8 @@
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// 400「SMTP 未配置」等后端预检拒绝(ApiError.message = detail)
|
||||
// 400「SMTP 未配置」/ 429「测试端点调用过于频繁」等后端预检拒绝
|
||||
// (ApiError.message = detail,白话文案直接内联展示)
|
||||
emailTestResult.value = {
|
||||
type: 'error',
|
||||
text: error instanceof Error ? error.message : '测试发送失败'
|
||||
@@ -724,7 +679,7 @@
|
||||
try {
|
||||
pushProbe.value = await testPush(props.slug, { showErrorMessage: false })
|
||||
} catch (error) {
|
||||
// 400「推送 URL 未配置」等后端预检拒绝
|
||||
// 400「推送 URL 未配置」/ 429「测试端点调用过于频繁」等后端预检拒绝
|
||||
pushProbeError.value = error instanceof Error ? error.message : '探测失败'
|
||||
} finally {
|
||||
pushProbing.value = false
|
||||
@@ -742,52 +697,21 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
|
||||
.card-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.card-sub {
|
||||
font-size: 12px;
|
||||
color: var(--art-gray-400);
|
||||
}
|
||||
|
||||
// 头部右列:副标题 + 重置出厂小按钮(Task 7d)
|
||||
.header-side {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.pane-error {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.secret-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
// 表单区双列 grid(span-2 = 独占整行:密钥/长控件/开关)
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
column-gap: 16px;
|
||||
|
||||
.secret-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
.span-2 {
|
||||
grid-column: span 2;
|
||||
}
|
||||
}
|
||||
|
||||
.field-warn {
|
||||
margin: 4px 0 0;
|
||||
font-size: 12px;
|
||||
color: var(--el-color-danger);
|
||||
}
|
||||
|
||||
.switch-hint {
|
||||
margin-left: 10px;
|
||||
font-size: 12px;
|
||||
@@ -798,10 +722,8 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.save-bar {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 8px;
|
||||
.comment-input {
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.test-divider {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
{{ cleared ? '恢复保持' : '清除' }}
|
||||
</ElButton>
|
||||
</div>
|
||||
<p v-if="state.badge === 'pending-clear'" class="field-warn">
|
||||
<p v-if="state.badge === 'pending-clear'" role="status" class="field-warn">
|
||||
保存后将清除已存密钥(空槽回退平台默认)
|
||||
</p>
|
||||
</div>
|
||||
@@ -67,6 +67,10 @@
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
:deep(.el-button) {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.secret-input {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
Reference in New Issue
Block a user