将账号配置改为管理弹窗,增加管理员查看授权码入口,并在账号列表下方安全展示授权码。
This commit is contained in:
parent
0eb3ff1a81
commit
bf89198414
@ -335,6 +335,84 @@
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.notification-row-actions {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.notification-row-actions :deep(.el-button + .el-button) {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.notification-manager-secret {
|
||||
flex: 1 0 100%;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 8px 14px;
|
||||
align-items: center;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--el-color-success-light-5);
|
||||
border-radius: 10px;
|
||||
background: var(--el-color-success-light-9);
|
||||
}
|
||||
|
||||
.notification-manager-secret-heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px 14px;
|
||||
min-width: 0;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.notification-manager-secret .notification-credential-code {
|
||||
grid-column: 1 / -1;
|
||||
min-width: 0;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
border-radius: 6px;
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
.notification-manager-secret .notification-credential-actions {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.notification-heading-actions {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.notification-detail-modal-active {
|
||||
position: fixed;
|
||||
z-index: 2000;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: auto !important;
|
||||
min-width: 0;
|
||||
max-height: 100vh;
|
||||
padding: 24px !important;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: rgb(15 23 42 / 42%) !important;
|
||||
}
|
||||
|
||||
.notification-detail-modal-active > .notification-detail-dialog {
|
||||
width: min(1080px, 100%);
|
||||
max-height: calc(100vh - 48px);
|
||||
overflow: auto;
|
||||
padding: 18px;
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 20px 60px rgb(15 23 42 / 22%);
|
||||
}
|
||||
|
||||
.notification-settings:has(> .notification-manager-panel) > .notification-detail-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -508,6 +586,10 @@
|
||||
.notification-settings:has(> .notification-manager-panel) > .notification-manager-panel .el-pagination {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.notification-row-actions {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 820px) {
|
||||
@ -520,6 +602,16 @@
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.notification-detail-modal-active {
|
||||
align-items: flex-start;
|
||||
padding: 12px !important;
|
||||
}
|
||||
|
||||
.notification-detail-modal-active > .notification-detail-dialog {
|
||||
max-height: calc(100vh - 24px);
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.notification-settings:has(> .notification-manager-panel) > .notification-detail-panel .notification-columns {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
@ -559,4 +651,14 @@
|
||||
padding-inline: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.notification-row-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.notification-manager-secret {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ export function usePage(props = {}) {
|
||||
const seconds = ref(0)
|
||||
const verifyVisible = ref(false)
|
||||
const verifyPassword = ref('')
|
||||
const manageVisible = ref(false)
|
||||
let verifyTarget = null
|
||||
let secretSequence = 0
|
||||
let secretTimer = null
|
||||
@ -83,6 +84,29 @@ export function usePage(props = {}) {
|
||||
verifyTarget = status.value
|
||||
verifyVisible.value = true
|
||||
}
|
||||
const openManage = async row => {
|
||||
if (loading.value || submitting.value || !(await beforeLeave())) return
|
||||
clearSecret()
|
||||
status.value = null
|
||||
selectedID.value = row.user_id
|
||||
await loadStatus()
|
||||
if (!disposed) manageVisible.value = true
|
||||
}
|
||||
const closeManage = async () => {
|
||||
if (!(await beforeLeave())) return false
|
||||
manageVisible.value = false
|
||||
clearSecret()
|
||||
return true
|
||||
}
|
||||
const revealAccount = async row => {
|
||||
if (loading.value || submitting.value || !row.configured || !(await beforeLeave())) return
|
||||
clearSecret()
|
||||
status.value = null
|
||||
selectedID.value = row.user_id
|
||||
await loadStatus()
|
||||
if (disposed || !status.value || status.value.user_id !== row.user_id) return
|
||||
if (canReveal.value) openVerify()
|
||||
}
|
||||
const verifyAndReveal = async () => {
|
||||
if (!verifyTarget || !verifyPassword.value || submitting.value || !canReveal.value) return
|
||||
const target = verifyTarget
|
||||
@ -229,6 +253,7 @@ export function usePage(props = {}) {
|
||||
accountsSequence += 1
|
||||
clearSecret()
|
||||
clearVerification()
|
||||
manageVisible.value = false
|
||||
document.removeEventListener('visibilitychange', hideOnBackground)
|
||||
})
|
||||
|
||||
@ -236,6 +261,7 @@ export function usePage(props = {}) {
|
||||
manager, loading, submitting, error, status, accounts, page, total, form,
|
||||
secret, secretAccount, secretVisible, seconds, canManage, stateText, dirty,
|
||||
canReveal, verifyVisible, verifyPassword, openVerify, verifyAndReveal, clearVerification,
|
||||
loadAccounts, selectAccount, refresh, save, rotate, clearSecret, copySecret, beforeLeave
|
||||
loadAccounts, selectAccount: openManage, openManage, closeManage, revealAccount, refresh, save, rotate, clearSecret, copySecret, beforeLeave,
|
||||
manageVisible
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,9 +29,17 @@
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90">
|
||||
<el-table-column label="操作" width="170">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" :disabled="submitting || loading" @click="selectAccount(row)">管理</el-button>
|
||||
<div class="notification-row-actions">
|
||||
<el-button link type="primary" :disabled="submitting || loading" @click="openManage(row)">管理</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
:disabled="submitting || loading || !row.configured || row.disabled"
|
||||
@click="revealAccount(row)"
|
||||
>查看授权码</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -43,14 +51,36 @@
|
||||
:disabled="submitting"
|
||||
@current-change="loadAccounts"
|
||||
/>
|
||||
<div v-if="manager && !userId && secretVisible && secretAccount" class="notification-manager-secret" role="status">
|
||||
<div class="notification-manager-secret-heading">
|
||||
<span>账号 {{ secretAccount }} 的通知授权码</span>
|
||||
<span class="notification-countdown">{{ seconds }} 秒后自动隐藏</span>
|
||||
</div>
|
||||
<code class="notification-credential-code">{{ secret }}</code>
|
||||
<div class="notification-credential-actions">
|
||||
<el-button size="small" type="primary" @click="copySecret">复制授权码</el-button>
|
||||
<el-button size="small" @click="clearSecret">隐藏</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-alert v-if="error" :title="error" type="error" :closable="false" show-icon />
|
||||
<div v-loading="loading" class="notification-panel notification-detail-panel" aria-live="polite">
|
||||
<div
|
||||
v-if="!manager || userId || manageVisible"
|
||||
class="notification-detail-modal notification-detail-panel"
|
||||
:class="{ 'notification-detail-modal-active': manager && !userId }"
|
||||
role="dialog"
|
||||
:aria-modal="manager && !userId ? 'true' : undefined"
|
||||
@click.self="manager && !userId ? closeManage() : null"
|
||||
>
|
||||
<div v-loading="loading" class="notification-panel notification-detail-dialog" aria-live="polite">
|
||||
<template v-if="status">
|
||||
<div class="notification-heading">
|
||||
<h3>账号:{{ status.account }}</h3>
|
||||
<el-tag :type="status.enabled && status.configured ? 'success' : 'info'">{{ stateText }}</el-tag>
|
||||
<div class="notification-heading-actions">
|
||||
<el-tag :type="status.enabled && status.configured ? 'success' : 'info'">{{ stateText }}</el-tag>
|
||||
<el-button v-if="manager && !userId" link @click="closeManage">关闭</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="!status.account_available" class="notification-warning">账号已禁用或尚未修改临时密码,不能生成或使用通知凭据。</p>
|
||||
|
||||
@ -127,6 +157,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<el-empty v-else-if="!loading && !error" description="尚未读取账号状态" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
@ -174,7 +205,8 @@ const {
|
||||
manager, loading, submitting, error, status, accounts, page, total, form,
|
||||
secret, secretAccount, secretVisible, seconds, canManage, stateText, dirty,
|
||||
canReveal, verifyVisible, verifyPassword, openVerify, verifyAndReveal, clearVerification,
|
||||
loadAccounts, selectAccount, refresh, save, rotate, clearSecret, copySecret, beforeLeave
|
||||
loadAccounts, openManage, closeManage, revealAccount, manageVisible,
|
||||
refresh, save, rotate, clearSecret, copySecret, beforeLeave
|
||||
} = usePage(props)
|
||||
|
||||
defineExpose({ beforeLeave })
|
||||
|
||||
Loading…
Reference in New Issue
Block a user