From ceb438644006970b9340eaaad4d64f2ed7f6503e Mon Sep 17 00:00:00 2001 From: zhenhui <1276357500@qq.com> Date: Wed, 24 Jun 2026 16:49:34 +0800 Subject: [PATCH] =?UTF-8?q?1.=E4=BC=98=E5=8C=96=E8=B0=B7=E6=AD=8C=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E5=99=A8-=E5=89=8D=E7=AB=AF=E4=B8=8D=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E9=AA=8C=E8=AF=81=E5=99=A8=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/table/fieldRender/buttons.vue | 14 ++++++++- web/src/lang/backend/en/auth/admin.ts | 1 + web/src/lang/backend/zh-cn/auth/admin.ts | 1 + web/src/views/backend/auth/admin/index.vue | 31 ++++++++++++++++--- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/web/src/components/table/fieldRender/buttons.vue b/web/src/components/table/fieldRender/buttons.vue index 60f5b72..d0edf6e 100644 --- a/web/src/components/table/fieldRender/buttons.vue +++ b/web/src/components/table/fieldRender/buttons.vue @@ -45,7 +45,7 @@ () const baTable = inject('baTable') as baTableClass +const adminInfo = useAdminInfo() const onButtonClick = (btn: OptButton) => { if (typeof btn.click === 'function') { @@ -128,6 +130,16 @@ const onButtonClick = (btn: OptButton) => { baTable.onTableAction(btn.name as BaTableActionEventName, props) } +const isConfirmButtonVisible = (btn: OptButton) => { + if (btn.name === 'delete') { + return baTable.auth('del') + } + if (btn.name === 'resetTotp') { + return adminInfo.super || baTable.auth('resetTotp') + } + return true +} + const getTranslation = (key?: string) => { if (!key) return '' return te(key) ? t(key) : key diff --git a/web/src/lang/backend/en/auth/admin.ts b/web/src/lang/backend/en/auth/admin.ts index 494d036..5721568 100644 --- a/web/src/lang/backend/en/auth/admin.ts +++ b/web/src/lang/backend/en/auth/admin.ts @@ -15,4 +15,5 @@ export default { 'Not bound': 'Not bound', 'Reset authenticator': 'Reset authenticator', 'Reset authenticator confirm': 'Reset this admin\'s Google Authenticator? They must re-bind on next login.', + 'Pending bind tip': 'Not bound yet. This admin must complete binding on next login.', } diff --git a/web/src/lang/backend/zh-cn/auth/admin.ts b/web/src/lang/backend/zh-cn/auth/admin.ts index 4951761..cb927e3 100644 --- a/web/src/lang/backend/zh-cn/auth/admin.ts +++ b/web/src/lang/backend/zh-cn/auth/admin.ts @@ -15,4 +15,5 @@ export default { 'Not bound': '未绑定', 'Reset authenticator': '重置验证器', 'Reset authenticator confirm': '确定要重置该管理员的谷歌验证器吗?重置后该管理员下次登录需重新绑定。', + 'Pending bind tip': '该管理员尚未绑定,需在其下次登录时自行完成绑定', } diff --git a/web/src/views/backend/auth/admin/index.vue b/web/src/views/backend/auth/admin/index.vue index 3782c70..bc52cde 100644 --- a/web/src/views/backend/auth/admin/index.vue +++ b/web/src/views/backend/auth/admin/index.vue @@ -9,7 +9,6 @@ /> - @@ -36,6 +35,18 @@ defineOptions({ const { t } = useI18n() const adminInfo = useAdminInfo() +/** 超管或拥有 resetTotp 权限,且不能操作自己 */ +const canManageTotp = (row: TableRow) => { + if (row.id == adminInfo.id) { + return false + } + return adminInfo.super +} + +const isTotpBound = (row: TableRow) => { + return row.totp_bound === true || row.totp_bound === 1 || row.totp_bound === '1' +} + const optButtons: OptButton[] = [ { render: 'confirmButton', @@ -52,15 +63,25 @@ const optButtons: OptButton[] = [ title: t('auth.admin.Reset authenticator confirm'), }, disabledTip: false, - display: (row: TableRow) => { - return adminInfo.super && row.id != adminInfo.id && !!row.totp_bound - }, + display: (row: TableRow) => canManageTotp(row) && isTotpBound(row), click: (row: TableRow) => { resetTotp(row.id).then(() => { baTable.onTableHeaderAction('refresh', {}) }) }, }, + { + render: 'tipButton', + name: 'bindTip', + title: 'auth.admin.Pending bind tip', + text: '', + type: 'info', + icon: 'fa fa-shield', + class: 'table-row-bind-tip', + disabledTip: false, + display: (row: TableRow) => canManageTotp(row) && !isTotpBound(row), + disabled: () => true, + }, ...defaultOptButtons(['edit', 'delete']).map((btn) => { if (btn.name === 'delete') { return { @@ -115,7 +136,7 @@ const baTable = new baTableClass( { label: t('Operate'), align: 'center', - width: '140', + width: '170', render: 'buttons', buttons: optButtons, operator: false,