1
This commit is contained in:
@@ -87,7 +87,7 @@
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
<Modal v-model="detailVisible" title="用户详情" width="800" footer-hide>
|
||||
<Modal v-model="detailVisible" title="用户详情" width="920" footer-hide>
|
||||
<div v-if="detail && detail.user" class="detail-user-bar mb12">
|
||||
<span class="detail-user-item">ID {{ detail.user.id }}</span>
|
||||
<span class="detail-user-item">{{ detail.user.name || '—' }}</span>
|
||||
@@ -110,7 +110,7 @@
|
||||
border />
|
||||
</Modal>
|
||||
|
||||
<Modal v-model="tokenListVisible" :title="tokenListTitle" width="820" footer-hide>
|
||||
<Modal v-model="tokenListVisible" :title="tokenListTitle" width="980" footer-hide>
|
||||
<div v-if="tokenList_target_user" class="mb12">
|
||||
<Button
|
||||
type="primary"
|
||||
@@ -118,14 +118,14 @@
|
||||
:disabled="tokenList_target_user.status !== 'active'"
|
||||
@click="open_create_token_for_user(tokenList_target_user)"
|
||||
>生成 Token</Button>
|
||||
<span class="text-muted ml10">点击行查看单条详情;明文仅在创建/重新生成时展示一次</span>
|
||||
<span class="text-muted ml10">点击行查看详情;列表「明文」来自服务端加密存储(吊销后不可查看)</span>
|
||||
</div>
|
||||
<Table v-if="tokenListRows.length" :columns="tokenCols" :data="tokenListRows" size="small" border highlight-row
|
||||
@on-row-click="onTokenRowClick" />
|
||||
<p v-else class="text-muted">暂无 Token</p>
|
||||
</Modal>
|
||||
|
||||
<Modal v-model="tokenDetailVisible" title="Token 详情" width="520" footer-hide>
|
||||
<Modal v-model="tokenDetailVisible" title="Token 详情" width="600" footer-hide>
|
||||
<div v-if="selectedToken" class="token-detail">
|
||||
<p><span class="label">ID</span>{{ selectedToken.id }}</p>
|
||||
<p><span class="label">名称</span>{{ selectedToken.token_name }}</p>
|
||||
@@ -134,6 +134,14 @@
|
||||
<p><span class="label">状态</span>{{ selectedToken.status }}</p>
|
||||
<p><span class="label">过期时间</span>{{ selectedToken.expire_at || '—' }}</p>
|
||||
<p><span class="label">最后使用</span>{{ selectedToken.last_used_at || '—' }}</p>
|
||||
<div class="token-plain-block">
|
||||
<p><span class="label">明文</span></p>
|
||||
<template v-if="selectedToken.plain_token">
|
||||
<Input type="textarea" :rows="3" :value="selectedToken.plain_token" readonly class="token-plain-ta" />
|
||||
<Button type="primary" size="small" class="mt8" @click="copy_text(selectedToken.plain_token)">复制全文</Button>
|
||||
</template>
|
||||
<p v-else class="text-muted mb0">无存储明文(旧数据或已吊销);可对 active 记录「重新生成」后查看</p>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
@@ -292,6 +300,34 @@ export default {
|
||||
{ title: '状态', key: 'status', width: 90 },
|
||||
{ title: '过期', key: 'expire_at', minWidth: 150 },
|
||||
{ title: '最后使用', key: 'last_used_at', minWidth: 150 },
|
||||
{
|
||||
title: '明文',
|
||||
key: 'plain_token',
|
||||
minWidth: 200,
|
||||
render: (h, p) => {
|
||||
const v = p.row.plain_token
|
||||
if (!v) {
|
||||
return h('span', { class: { 'text-muted': true } }, '—')
|
||||
}
|
||||
const snip = v.length > 28 ? `${v.slice(0, 28)}…` : v
|
||||
return h('div', { class: 'plain-token-row' }, [
|
||||
h('span', { class: 'plain-token-snip', attrs: { title: v } }, snip),
|
||||
h(
|
||||
'Button',
|
||||
{
|
||||
props: { type: 'text', size: 'small' },
|
||||
on: {
|
||||
click: (e) => {
|
||||
e.stopPropagation()
|
||||
this.copy_text(v)
|
||||
},
|
||||
},
|
||||
},
|
||||
'复制'
|
||||
),
|
||||
])
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'tok_op',
|
||||
@@ -339,6 +375,30 @@ export default {
|
||||
this.param.pageOption.pageSize = s
|
||||
this.load(1)
|
||||
},
|
||||
copy_text(text) {
|
||||
if (text == null || text === '') return
|
||||
const s = String(text)
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(s).then(() => this.$Message.success('已复制')).catch(() => this._copy_text_fallback(s))
|
||||
} else {
|
||||
this._copy_text_fallback(s)
|
||||
}
|
||||
},
|
||||
_copy_text_fallback(s) {
|
||||
const ta = document.createElement('textarea')
|
||||
ta.value = s
|
||||
ta.style.position = 'fixed'
|
||||
ta.style.opacity = '0'
|
||||
document.body.appendChild(ta)
|
||||
ta.select()
|
||||
try {
|
||||
document.execCommand('copy')
|
||||
this.$Message.success('已复制')
|
||||
} catch (e) {
|
||||
this.$Message.error('复制失败')
|
||||
}
|
||||
document.body.removeChild(ta)
|
||||
},
|
||||
openEdit(row) {
|
||||
if (row) {
|
||||
this.form = { ...row }
|
||||
@@ -596,6 +656,43 @@ export default {
|
||||
color: #808695;
|
||||
}
|
||||
|
||||
.token-plain-block {
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid #e8eaec;
|
||||
}
|
||||
|
||||
.token-plain-block .label {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.token-plain-ta :deep(textarea) {
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.mb0 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.mt8 {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.plain-token-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.plain-token-snip {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.detail-user-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
Reference in New Issue
Block a user