From d2fe1f8304e02d116c70b1ea4c4de4f97f61ef34 Mon Sep 17 00:00:00 2001 From: smail Date: Sat, 17 Oct 2026 22:38:40 +0800 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=E6=94=AF=E6=8C=81=E5=A4=96?= =?UTF-8?q?=E9=83=A8=E9=82=AE=E7=AE=B1=E5=90=AF=E7=94=A8=E8=A7=A3=E7=BB=91?= =?UTF-8?q?=E4=B8=8E=E8=B4=A6=E5=8F=B7=E7=AE=A1=E7=90=86=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=8F=91=E5=B8=83V2.12.0=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/package.mjs | 5 +++ .../SecuritySettings/SecuritySettings.css | 17 +++++++- .../SecuritySettings/SecuritySettings.js | 25 ++++++++++- .../SecuritySettings/SecuritySettings.vue | 6 ++- .../UserManagement/UserManagement.js | 42 +++++++++++++++++-- .../UserManagement/UserManagement.vue | 13 +++++- 6 files changed, 100 insertions(+), 8 deletions(-) diff --git a/deploy/package.mjs b/deploy/package.mjs index da93bc14..e7fea4f6 100644 --- a/deploy/package.mjs +++ b/deploy/package.mjs @@ -139,6 +139,11 @@ export async function packageRelease(selectedTargets = targets, { workspace = ro const legacyArchive = path.join(releaseRoot, legacyArchiveName) try { await copyFile(archive, legacyArchive) } catch (e) {} } + // 同步复制到 out 根目录,满足直接从 out 目录引用的部署习惯 + try { + await copyFile(archive, path.join(outputRoot, archiveName)) + await copyFile(archive, path.join(outputRoot, legacyArchiveName)) + } catch (e) {} await rename(stagedReceipt, receipt) await rename(staging, directory) releases.push({ target, directory, archive, receipt }) diff --git a/frontend/src/views/components/SecuritySettings/SecuritySettings.css b/frontend/src/views/components/SecuritySettings/SecuritySettings.css index 4fd08f70..3287371d 100644 --- a/frontend/src/views/components/SecuritySettings/SecuritySettings.css +++ b/frontend/src/views/components/SecuritySettings/SecuritySettings.css @@ -1401,4 +1401,19 @@ max-width: none !important; overflow: visible !important; } -} \ No newline at end of file +} +.external-item-actions { + display: inline-flex; + align-items: center; + justify-content: flex-end; + gap: 8px; + flex-shrink: 0; +} + +.external-item-actions :deep(.el-button) { + display: inline-flex; + align-items: center; + justify-content: center; + margin: 0; + white-space: nowrap; +} diff --git a/frontend/src/views/components/SecuritySettings/SecuritySettings.js b/frontend/src/views/components/SecuritySettings/SecuritySettings.js index bb0c3b64..d56b4901 100644 --- a/frontend/src/views/components/SecuritySettings/SecuritySettings.js +++ b/frontend/src/views/components/SecuritySettings/SecuritySettings.js @@ -337,7 +337,28 @@ export function usePage() { notify('外部安全邮箱绑定成功', 'success') } - const disableExternalEmail = async item => { + const rebindExternalEmail = (item) => { + openExternalEmailDialog() + } + + const deleteExternalEmail = async item => { + try { + await ElMessageBox.confirm(`确定彻底删除/解绑安全邮箱 ${item.email} 吗?解绑后将移除该邮箱记录。`, '删除外部邮箱', { + type: 'warning', + confirmButtonText: '确定删除', + cancelButtonText: '取消' + }) + const res = await http.post('/api/v1/security/external-email/delete', { id: item.id }) + if (res.errorNo !== 0) throw new Error(res.errorMsg || '删除外部邮箱失败') + await loadSecurityData() + await globalStatus.refresh() + notify('外部安全邮箱已删除', 'success') + } catch (error) { + if (error !== 'cancel' && error !== 'close') notify(error?.message || '删除外部邮箱失败') + } + } + +const disableExternalEmail = async item => { try { await ElMessageBox.confirm(`确定停用 ${item.email} 吗?停用后不能用于登录验证和恢复。`, '停用外部邮箱', { type: 'warning' }) const res = await http.post('/api/v1/security/external-email/disable', { id: item.id }) @@ -451,6 +472,6 @@ export function usePage() { externalDialogVisible, ruleForm, rules, submit, registerCredential, renameCredential, revokeCredential, saveSecurityQuestion, generateRecoveryCodes, revealRecoveryCodes, saveRecoveryCodes, revokeRecoveryCodes, openExternalEmailDialog, handleExternalEmailBound, - disableExternalEmail, formatTime, + rebindExternalEmail, deleteExternalEmail, disableExternalEmail, formatTime, } } diff --git a/frontend/src/views/components/SecuritySettings/SecuritySettings.vue b/frontend/src/views/components/SecuritySettings/SecuritySettings.vue index 0a7a49ab..67dee8d8 100644 --- a/frontend/src/views/components/SecuritySettings/SecuritySettings.vue +++ b/frontend/src/views/components/SecuritySettings/SecuritySettings.vue @@ -136,7 +136,11 @@
{{ item.email }}{{ item.type === 'primary' ? '主要邮箱' : '备用邮箱' }}{{ item.status === 'verified' ? '已验证' : item.status === 'pending' ? '待验证' : '已停用' }}
- 停用 +
+ 启用 + 停用 + 删除 +
diff --git a/frontend/src/views/components/UserManagement/UserManagement.js b/frontend/src/views/components/UserManagement/UserManagement.js index 483f7a6f..afc8fa62 100644 --- a/frontend/src/views/components/UserManagement/UserManagement.js +++ b/frontend/src/views/components/UserManagement/UserManagement.js @@ -4,7 +4,7 @@ import lang from '../../../i18n/i18n'; import {http} from "@/utils/axios"; -import {ElNotification} from "element-plus"; +import {ElNotification, ElMessageBox} from "element-plus"; import {Plus} from "@element-plus/icons-vue"; @@ -283,7 +283,41 @@ export function usePage() { reflushList() - return { + const canDeleteUser = user => { + return canEditUser(user) && !isSameUser(user, globalStatus.userInfos) + } + + const handleDeleteUser = async user => { + if (!canDeleteUser(user)) { + ElNotification({ type: 'error', message: '无法删除该用户' }) + return + } + try { + await ElMessageBox.confirm( + `确定彻底删除用户 "${user.Account}" 吗?此操作将永久清理该用户的所有关联配置、安全密钥与绑定数据,且不可逆!`, + '删除用户警告', + { + type: 'warning', + confirmButtonText: '确定删除', + cancelButtonText: '取消', + confirmButtonClass: 'el-button--danger' + } + ) + const res = await http.post('/api/v1/user/delete', { id: user.ID, account: user.Account }) + if (res.errorNo !== 0) { + throw new Error(res.errorMsg || '删除用户失败') + } + ElNotification({ type: 'success', message: `用户 ${user.Account} 已删除` }) + await reflushList() + await globalStatus.refresh() + } catch (error) { + if (error !== 'cancel' && error !== 'close') { + ElNotification({ type: 'error', message: error?.message || '删除用户失败' }) + } + } + } + +return { reactive, ref, lang, @@ -320,6 +354,8 @@ export function usePage() { handleEdit, canEditUser, createUser, + canDeleteUser, + handleDeleteUser, submit, roleMeta, recoveryCodeMeta, @@ -331,4 +367,4 @@ export function usePage() { export { Plus, roleMeta -} +} \ No newline at end of file diff --git a/frontend/src/views/components/UserManagement/UserManagement.vue b/frontend/src/views/components/UserManagement/UserManagement.vue index ad059dc8..c4a1c2c8 100644 --- a/frontend/src/views/components/UserManagement/UserManagement.vue +++ b/frontend/src/views/components/UserManagement/UserManagement.vue @@ -84,7 +84,7 @@ - +