- 将 AddDataDialog 组件的布局改为 flex 布局并移除自定义 CSS 类 - 更新 TokenDetailView 的整体布局结构,使用 Tailwind CSS 类替换原生样式 - 优化 TokenManageView 的表单和表格界面,调整响应式设计 - 移除 Element Plus ElContainer 组件的引用 - 合并多个编辑对话框为统一的数据编辑对话框 - 优化进度条和标签的显示样式 - 调整按钮和表单项的间距和对齐方式
This commit is contained in:
Vendored
-1
@@ -16,7 +16,6 @@ declare module 'vue' {
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
ElDivider: typeof import('element-plus/es')['ElDivider']
|
||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||
|
||||
@@ -70,7 +70,7 @@ const handleUpload = async () => {
|
||||
<el-tag type="primary" effect="plain">{{ props.token }}</el-tag>
|
||||
</template>
|
||||
|
||||
<div class="add-data-dialog">
|
||||
<div class="flex flex-col gap-4">
|
||||
<el-input
|
||||
v-model="inputData"
|
||||
type="textarea"
|
||||
@@ -80,13 +80,14 @@ const handleUpload = async () => {
|
||||
class="textarea-input"
|
||||
/>
|
||||
|
||||
<div class="footer">
|
||||
<div class="progress">
|
||||
<div class="flex justify-between items-center gap-4">
|
||||
<div class="flex-1 flex items-center gap-3">
|
||||
<el-progress
|
||||
:percentage="totalCount > 0 ? Math.round((uploadedCount / totalCount) * 100) : 0"
|
||||
:show-text="false"
|
||||
class="flex-1"
|
||||
/>
|
||||
<span class="progress-text">已上传 {{ uploadedCount }}/{{ totalCount }} 行</span>
|
||||
<span class="text-sm text-[var(--el-text-color-secondary)] whitespace-nowrap">已上传 {{ uploadedCount }}/{{ totalCount }} 行</span>
|
||||
</div>
|
||||
|
||||
<el-button
|
||||
@@ -105,39 +106,9 @@ const handleUpload = async () => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.add-data-dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.textarea-input :deep(.el-textarea__inner) {
|
||||
overflow-x: auto;
|
||||
white-space: pre;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.progress {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
font-size: 14px;
|
||||
color: var(--el-text-color-secondary);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.footer .el-progress {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
@@ -142,354 +142,175 @@ const statCards = [
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="token-detail">
|
||||
<div class="mx-auto w-full">
|
||||
<!-- 管理页面 -->
|
||||
<div class="detail-page">
|
||||
<div class="content-card">
|
||||
<div class="page-title">Token 详情</div>
|
||||
<div class="bg-white rounded-lg p-6 shadow-[0_2px_12px_rgba(0,0,0,0.08)]">
|
||||
<div class="text-xl font-semibold text-(--el-text-color-primary) mb-5 pb-3 border-b border-(--el-border-color)">
|
||||
Token 详情
|
||||
</div>
|
||||
|
||||
<!-- 选择 Token -->
|
||||
<div class="token-select">
|
||||
<el-select v-model="value" placeholder="选择 Token" clearable style="width: 100%; max-width: 300px">
|
||||
<el-option v-for="item in options" :key="item" :value="item" :label="item"/>
|
||||
</el-select>
|
||||
<el-button type="primary" @click="refresh" :loading="loading">
|
||||
<el-icon>
|
||||
<Refresh/>
|
||||
</el-icon>
|
||||
刷新
|
||||
</el-button>
|
||||
<span v-if="lastUpdate" class="update-time">上次更新: {{ lastUpdate }}</span>
|
||||
<!-- 选择 Token -->
|
||||
<div class="flex items-center gap-3 mb-6 flex-wrap max-md:flex-col max-md:items-stretch">
|
||||
<el-select v-model="value" placeholder="选择 Token" clearable style="width: 100%; max-width: 300px">
|
||||
<el-option v-for="item in options" :key="item" :value="item" :label="item"/>
|
||||
</el-select>
|
||||
<el-button type="primary" @click="refresh" :loading="loading">
|
||||
<el-icon>
|
||||
<Refresh/>
|
||||
</el-icon>
|
||||
刷新
|
||||
</el-button>
|
||||
<span v-if="lastUpdate" class="text-xs text-(--el-text-color-secondary)">上次更新: {{ lastUpdate }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Token 信息 -->
|
||||
<div v-if="result && value" class="animate-fade-in">
|
||||
<div class="text-base font-semibold text-(--el-text-color-primary) mt-5 mb-4">Token 信息</div>
|
||||
|
||||
<div class="grid grid-cols-4 gap-4 mb-8 max-xl:grid-cols-2 max-md:grid-cols-1">
|
||||
<div v-for="card in statCards" :key="card.key"
|
||||
class="flex items-center gap-4 p-5 bg-(--bg-page) rounded-xl transition-all duration-200 hover:-translate-y-0.5 hover:shadow-[0_4px_16px_rgba(0,0,0,0.1)]">
|
||||
<div class="w-14 h-14 rounded-xl flex items-center justify-center shrink-0"
|
||||
:style="{ background: card.color + '20', color: card.color }">
|
||||
<el-icon size="24">
|
||||
<component :is="card.icon"/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="text-xs text-(--el-text-color-secondary) mb-1">{{ card.label }}</div>
|
||||
<div class="text-lg font-semibold text-(--el-text-color-primary)">{{ result[card.key] || '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Token 信息 -->
|
||||
<div v-if="result && value" class="info-section">
|
||||
<div class="section-title">Token 信息</div>
|
||||
<!-- 管理操作 -->
|
||||
<div class="mt-8">
|
||||
<div class="text-base font-semibold text-(--el-text-color-primary) mt-5 mb-4">数据管理</div>
|
||||
|
||||
<div class="stat-cards">
|
||||
<div v-for="card in statCards" :key="card.key" class="stat-card">
|
||||
<div class="stat-icon" :style="{ background: card.color + '20', color: card.color }">
|
||||
<el-icon size="24">
|
||||
<component :is="card.icon"/>
|
||||
<div class="grid grid-cols-3 gap-4 max-xl:grid-cols-2 max-md:grid-cols-1">
|
||||
<div
|
||||
class="flex items-center gap-4 p-5 bg-(--bg-page) rounded-xl transition-all duration-200 hover:-translate-y-0.5 hover:shadow-[0_4px_16px_rgba(0,0,0,0.1)] max-md:flex-col max-md:text-center">
|
||||
<div
|
||||
class="w-14 h-14 rounded-xl flex items-center justify-center shrink-0 bg-(--el-color-primary) text-white">
|
||||
<el-icon size="28">
|
||||
<Delete/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">{{ card.label }}</div>
|
||||
<div class="stat-value">{{ result[card.key] || '-' }}</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="text-base font-semibold text-(--el-text-color-primary) mb-1">删除全部去重参考值</div>
|
||||
<div class="text-xs text-(--el-text-color-secondary)">清除该 Token 的所有去重布隆过滤器</div>
|
||||
</div>
|
||||
<el-button type="danger" @click="deleteDedup">执行</el-button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex items-center gap-4 p-5 bg-(--bg-page) rounded-xl transition-all duration-200 hover:-translate-y-0.5 hover:shadow-[0_4px_16px_rgba(0,0,0,0.1)] max-md:flex-col max-md:text-center">
|
||||
<div
|
||||
class="w-14 h-14 rounded-xl flex items-center justify-center shrink-0 bg-(--el-color-primary) text-white">
|
||||
<el-icon size="28">
|
||||
<Delete/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="text-base font-semibold text-(--el-text-color-primary) mb-1">删除全部原始数据</div>
|
||||
<div class="text-xs text-(--el-text-color-secondary)">清除该 Token 的所有原始缓存数据</div>
|
||||
</div>
|
||||
<el-button type="danger" @click="deleteRedis">执行</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 管理操作 -->
|
||||
<div class="manage-section">
|
||||
<div class="section-title">数据管理</div>
|
||||
<div class="text-sm font-semibold text-(--el-text-color-secondary) mt-6 mb-4">按数量删除</div>
|
||||
|
||||
<div class="action-grid">
|
||||
<div class="action-card danger">
|
||||
<div class="action-icon">
|
||||
<el-icon size="28">
|
||||
<Delete/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="action-info">
|
||||
<div class="action-label">删除全部去重参考值</div>
|
||||
<div class="action-desc">清除该 Token 的所有去重布隆过滤器</div>
|
||||
</div>
|
||||
<el-button type="danger" @click="deleteDedup">执行</el-button>
|
||||
<div class="grid grid-cols-3 gap-4 max-xl:grid-cols-2 max-md:grid-cols-1">
|
||||
<div
|
||||
class="flex items-center gap-4 p-5 bg-(--bg-page) rounded-xl transition-all duration-200 hover:-translate-y-0.5 hover:shadow-[0_4px_16px_rgba(0,0,0,0.1)] max-md:flex-col max-md:text-center">
|
||||
<div
|
||||
class="w-14 h-14 rounded-xl flex items-center justify-center shrink-0 bg-(--el-color-warning) text-white">
|
||||
<el-icon size="28">
|
||||
<Search/>
|
||||
</el-icon>
|
||||
</div>
|
||||
|
||||
<div class="action-card danger">
|
||||
<div class="action-icon">
|
||||
<el-icon size="28">
|
||||
<Delete/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="action-info">
|
||||
<div class="action-label">删除全部原始数据</div>
|
||||
<div class="action-desc">清除该 Token 的所有原始缓存数据</div>
|
||||
</div>
|
||||
<el-button type="danger" @click="deleteRedis">执行</el-button>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="text-base font-semibold text-(--el-text-color-primary) mb-1">删除指定数量去重参考值</div>
|
||||
<div class="text-xs text-(--el-text-color-secondary)">指定要删除的去重参考值数量</div>
|
||||
</div>
|
||||
<el-button type="warning" @click="deleteSpecifyDedupVisible = true">指定</el-button>
|
||||
</div>
|
||||
|
||||
<div class="section-subtitle">按数量删除</div>
|
||||
|
||||
<div class="action-grid">
|
||||
<div class="action-card">
|
||||
<div class="action-icon warning">
|
||||
<el-icon size="28">
|
||||
<Search/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="action-info">
|
||||
<div class="action-label">删除指定数量去重参考值</div>
|
||||
<div class="action-desc">指定要删除的去重参考值数量</div>
|
||||
</div>
|
||||
<el-button type="warning" @click="deleteSpecifyDedupVisible = true">指定</el-button>
|
||||
<div
|
||||
class="flex items-center gap-4 p-5 bg-(--bg-page) rounded-xl transition-all duration-200 hover:-translate-y-0.5 hover:shadow-[0_4px_16px_rgba(0,0,0,0.1)] max-md:flex-col max-md:text-center">
|
||||
<div
|
||||
class="w-14 h-14 rounded-xl flex items-center justify-center shrink-0 bg-(--el-color-warning) text-white">
|
||||
<el-icon size="28">
|
||||
<Search/>
|
||||
</el-icon>
|
||||
</div>
|
||||
|
||||
<div class="action-card">
|
||||
<div class="action-icon warning">
|
||||
<el-icon size="28">
|
||||
<Search/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="action-info">
|
||||
<div class="action-label">删除指定数量原始数据</div>
|
||||
<div class="action-desc">指定要删除的原始数据数量</div>
|
||||
</div>
|
||||
<el-button type="warning" @click="deleteSpecifyRawVisible = true">指定</el-button>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="text-base font-semibold text-(--el-text-color-primary) mb-1">删除指定数量原始数据</div>
|
||||
<div class="text-xs text-(--el-text-color-secondary)">指定要删除的原始数据数量</div>
|
||||
</div>
|
||||
<el-button type="warning" @click="deleteSpecifyRawVisible = true">指定</el-button>
|
||||
</div>
|
||||
|
||||
<div class="action-card">
|
||||
<div class="action-icon warning">
|
||||
<el-icon size="28">
|
||||
<Search/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="action-info">
|
||||
<div class="action-label">删除指定数量数据</div>
|
||||
<div class="action-desc">同时删除去重参考值和原始数据</div>
|
||||
</div>
|
||||
<el-button type="warning" @click="deleteSpecifyDataVisible = true">指定</el-button>
|
||||
<div
|
||||
class="flex items-center gap-4 p-5 bg-(--bg-page) rounded-xl transition-all duration-200 hover:-translate-y-0.5 hover:shadow-[0_4px_16px_rgba(0,0,0,0.1)] max-md:flex-col max-md:text-center">
|
||||
<div
|
||||
class="w-14 h-14 rounded-xl flex items-center justify-center shrink-0 bg-(--el-color-warning) text-white">
|
||||
<el-icon size="28">
|
||||
<Search/>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="text-base font-semibold text-(--el-text-color-primary) mb-1">删除指定数量数据</div>
|
||||
<div class="text-xs text-(--el-text-color-secondary)">同时删除去重参考值和原始数据</div>
|
||||
</div>
|
||||
<el-button type="warning" @click="deleteSpecifyDataVisible = true">指定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<div v-else-if="value" class="empty-state">
|
||||
<el-icon size="64" color="#dcdfe6">
|
||||
<InfoFilled/>
|
||||
</el-icon>
|
||||
<div class="empty-text">暂无数据</div>
|
||||
</div>
|
||||
|
||||
<!-- 未选择 -->
|
||||
<div v-else class="empty-state">
|
||||
<el-icon size="64" color="#dcdfe6">
|
||||
<Key/>
|
||||
</el-icon>
|
||||
<div class="empty-text">请选择 Token 查看详情</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 删除确认对话框 -->
|
||||
<el-dialog v-model="deleteSpecifyDedupVisible" title="删除指定数量去重参考值" width="400">
|
||||
<el-input v-model="inputSpecifyDedup" placeholder="请输入删除数量" type="number"/>
|
||||
<!-- 空状态 -->
|
||||
<div v-else-if="value" class="flex flex-col items-center p-16 text-(--el-text-color-secondary)">
|
||||
<el-icon size="64" color="#dcdfe6">
|
||||
<InfoFilled/>
|
||||
</el-icon>
|
||||
<div class="mt-4 text-[15px]">暂无数据</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="deleteSpecifyDedupVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="deleteSpecifyDedup" :loading="isLoading">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="deleteSpecifyRawVisible" title="删除指定数量原始数据" width="400">
|
||||
<el-input v-model="inputSpecifyRaw" placeholder="请输入删除数量" type="number"/>
|
||||
<template #footer>
|
||||
<el-button @click="deleteSpecifyRawVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="deleteSpecifyRaw" :loading="isLoading">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="deleteSpecifyDataVisible" title="删除指定数量数据" width="400">
|
||||
<el-input v-model="inputSpecifyData" placeholder="请输入删除数量" type="number"/>
|
||||
<template #footer>
|
||||
<el-button @click="deleteSpecifyDataVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="deleteSpecifyData" :loading="isLoading">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 未选择 -->
|
||||
<div v-else class="flex flex-col items-center p-16 text-(--el-text-color-secondary)">
|
||||
<el-icon size="64" color="#dcdfe6">
|
||||
<Key/>
|
||||
</el-icon>
|
||||
<div class="mt-4 text-[15px]">请选择 Token 查看详情</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 删除确认对话框 -->
|
||||
<el-dialog v-model="deleteSpecifyDedupVisible" title="删除指定数量去重参考值" width="400">
|
||||
<el-input v-model="inputSpecifyDedup" placeholder="请输入删除数量" type="number"/>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="deleteSpecifyDedupVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="deleteSpecifyDedup" :loading="isLoading">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="deleteSpecifyRawVisible" title="删除指定数量原始数据" width="400">
|
||||
<el-input v-model="inputSpecifyRaw" placeholder="请输入删除数量" type="number"/>
|
||||
<template #footer>
|
||||
<el-button @click="deleteSpecifyRawVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="deleteSpecifyRaw" :loading="isLoading">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="deleteSpecifyDataVisible" title="删除指定数量数据" width="400">
|
||||
<el-input v-model="inputSpecifyData" placeholder="请输入删除数量" type="number"/>
|
||||
<template #footer>
|
||||
<el-button @click="deleteSpecifyDataVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="deleteSpecifyData" :loading="isLoading">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.token-detail {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Token 选择 */
|
||||
.token-select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.update-time {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
/* 信息卡片 */
|
||||
.info-section {
|
||||
animation: fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.stat-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 16px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 20px;
|
||||
background: var(--bg-page);
|
||||
border-radius: 12px;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.stat-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* 管理操作 */
|
||||
.manage-section {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-secondary);
|
||||
margin: 24px 0 16px;
|
||||
}
|
||||
|
||||
.action-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.action-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 20px;
|
||||
background: var(--bg-page);
|
||||
border-radius: 12px;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.action-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--el-color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.action-icon.warning {
|
||||
background: var(--el-color-warning);
|
||||
}
|
||||
|
||||
.action-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.action-label {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.action-desc {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 64px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
margin-top: 16px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.stat-cards {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.action-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.token-select {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.stat-cards {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.action-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.action-card {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -9,16 +9,16 @@ const router = useRouter()
|
||||
const tableData = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
const input = ref('')
|
||||
const value = ref('')
|
||||
const dataFormat = ref('')
|
||||
|
||||
const inputDedupObject = ref('')
|
||||
const inputDataFormat = ref('')
|
||||
const inputNotes = ref('')
|
||||
|
||||
const activeNames = ref(['1'])
|
||||
|
||||
const rowOut = ref<any>(null)
|
||||
const addDataDialogVisible = ref(false)
|
||||
const dedupObjectVisible = ref(false)
|
||||
const dataFormatVisible = ref(false)
|
||||
const inputNotesVisible = ref(false)
|
||||
const dataDialogVisible = ref(false)
|
||||
|
||||
const options = [
|
||||
{value: 'uid', label: 'uid'},
|
||||
@@ -46,32 +46,26 @@ const fetchTokens = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (store.isAdmin) {
|
||||
fetchTokens()
|
||||
}
|
||||
})
|
||||
|
||||
const addToken = async () => {
|
||||
if (!input.value || !value.value || !dataFormat.value) {
|
||||
if (!input.value || !inputDedupObject.value || !inputDataFormat.value) {
|
||||
ElMessage.warning('请填写完整信息')
|
||||
return
|
||||
}
|
||||
try {
|
||||
await api.createToken({
|
||||
token: input.value,
|
||||
dedup_object: value.value,
|
||||
data_format: dataFormat.value,
|
||||
dedup_object: inputDedupObject.value,
|
||||
data_format: inputDataFormat.value,
|
||||
notes: inputNotes.value,
|
||||
})
|
||||
ElMessage({message: '添加成功', type: 'success'})
|
||||
input.value = ''
|
||||
value.value = ''
|
||||
dataFormat.value = ''
|
||||
inputDedupObject.value = ''
|
||||
inputDataFormat.value = ''
|
||||
inputNotes.value = ''
|
||||
fetchTokens()
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error.response?.data?.error || '添加失败')
|
||||
ElMessage.error('添加失败' + error.response?.data?.error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,75 +74,38 @@ const viewDetails = (row: any) => {
|
||||
router.push({name: "TokenDetail"})
|
||||
}
|
||||
|
||||
const dialogDedupObjectVisible = (row: any) => {
|
||||
rowOut.value = row
|
||||
value.value = row.dedup_object
|
||||
dedupObjectVisible.value = true
|
||||
}
|
||||
|
||||
const dialogDataFormatVisible = (row: any) => {
|
||||
rowOut.value = row
|
||||
dataFormat.value = row.data_format
|
||||
dataFormatVisible.value = true
|
||||
}
|
||||
|
||||
const dialogNotesVisible = (row: any) => {
|
||||
rowOut.value = row
|
||||
inputNotes.value = row.notes
|
||||
inputNotesVisible.value = true
|
||||
}
|
||||
|
||||
const dialogDataADDVisible = (row: any) => {
|
||||
rowOut.value = row
|
||||
|
||||
addDataDialogVisible.value = true
|
||||
}
|
||||
|
||||
const updateDedupObject = async () => {
|
||||
try {
|
||||
await api.updateToken({
|
||||
token: rowOut.value.token,
|
||||
dedup_object: value.value,
|
||||
data_format: rowOut.value.data_format,
|
||||
notes: rowOut.value.notes,
|
||||
})
|
||||
ElMessage({message: '更新成功', type: 'success'})
|
||||
dedupObjectVisible.value = false
|
||||
fetchTokens()
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error.response?.data?.error || '更新失败')
|
||||
}
|
||||
const displayDataVisible = (row: any) => {
|
||||
rowOut.value = row
|
||||
|
||||
inputDedupObject.value = row.dedup_object
|
||||
inputDataFormat.value = row.data_format
|
||||
inputNotes.value = row.notes
|
||||
|
||||
dataDialogVisible.value = true
|
||||
}
|
||||
|
||||
const updateDataFormat = async () => {
|
||||
const updateData = async () => {
|
||||
try {
|
||||
await api.updateToken({
|
||||
token: rowOut.value.token,
|
||||
dedup_object: rowOut.value.dedup_object,
|
||||
data_format: dataFormat.value,
|
||||
notes: rowOut.value.notes,
|
||||
})
|
||||
ElMessage({message: '更新成功', type: 'success'})
|
||||
dataFormatVisible.value = false
|
||||
fetchTokens()
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error.response?.data?.error || '更新失败')
|
||||
}
|
||||
}
|
||||
|
||||
const updateNotes = async () => {
|
||||
try {
|
||||
await api.updateToken({
|
||||
token: rowOut.value.token,
|
||||
dedup_object: rowOut.value.dedup_object,
|
||||
data_format: rowOut.value.data_format,
|
||||
dedup_object: inputDedupObject.value,
|
||||
data_format: inputDataFormat.value,
|
||||
notes: inputNotes.value,
|
||||
})
|
||||
ElMessage({message: '更新成功', type: 'success'})
|
||||
inputNotesVisible.value = false
|
||||
fetchTokens()
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error.response?.data?.error || '更新失败')
|
||||
ElMessage.error('更新失败' + error.response?.data?.error)
|
||||
dataDialogVisible.value = false
|
||||
return
|
||||
}
|
||||
ElMessage({message: '更新成功', type: 'success'})
|
||||
fetchTokens()
|
||||
dataDialogVisible.value = false
|
||||
}
|
||||
|
||||
const deleteToken = async (row: any) => {
|
||||
@@ -157,282 +114,183 @@ const deleteToken = async (row: any) => {
|
||||
ElMessage({message: '删除成功', type: 'success'})
|
||||
fetchTokens()
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error.response?.data?.error || '删除失败')
|
||||
ElMessage.error('删除失败' + error.response?.data?.error)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (store.isAdmin) {
|
||||
fetchTokens()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="token-manage">
|
||||
<div class="mx-auto w-full bg-white">
|
||||
<!-- 管理页面 -->
|
||||
<div class="manage-page">
|
||||
<div class="content-card">
|
||||
<div class="page-title">Token 管理</div>
|
||||
|
||||
<!-- 添加表单 -->
|
||||
<el-collapse class="add-form" v-model="activeNames">
|
||||
<el-collapse-item title="添加新 Token" name="1">
|
||||
<div class="form-grid">
|
||||
<el-input v-model="input" placeholder="Token 名称" clearable>
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Key/>
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-select v-model="value" placeholder="去重对象" clearable>
|
||||
<el-option v-for="item in options" :key="item.value" :value="item.value" :label="item.label"/>
|
||||
</el-select>
|
||||
|
||||
<el-select v-model="dataFormat" placeholder="数据格式" clearable>
|
||||
<el-option v-for="item in dataFormatOptions" :key="item.value" :value="item.value"
|
||||
:label="item.label"/>
|
||||
</el-select>
|
||||
|
||||
<el-input v-model="inputNotes" placeholder="备注(可选)" clearable>
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Memo/>
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-button type="primary" @click="addToken">
|
||||
<el-icon>
|
||||
<Plus/>
|
||||
</el-icon>
|
||||
添加
|
||||
</el-button>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
|
||||
<!-- Token 列表 -->
|
||||
<div class="table-section">
|
||||
<div class="section-header">
|
||||
<span class="section-title">Token 列表</span>
|
||||
<span class="table-count">共 {{ tableData.length }} 条</span>
|
||||
</div>
|
||||
|
||||
<el-table empty-text="没有数据" stripe style="width: 100%"
|
||||
:data="tableData" v-loading="loading">
|
||||
<el-table-column prop="token" label="Token" min-width="100" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<div class="token-cell">
|
||||
<el-icon>
|
||||
<Key/>
|
||||
</el-icon>
|
||||
<span>{{ row.token }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="dedup_object" label="去重对象" width="150">
|
||||
<template #default="{ row }">
|
||||
<el-tag type="primary" effect="plain">{{ row.dedup_object }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="data_format" label="数据格式" min-width="200" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<div class="format-cell">{{ row.data_format }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="notes" label="备注" min-width="150" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span class="notes-text">{{ row.notes || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="500" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<div class="action-buttons">
|
||||
<el-button type="primary" size="small" text @click="viewDetails(row)">
|
||||
<el-icon>
|
||||
<View/>
|
||||
</el-icon>
|
||||
详情
|
||||
</el-button>
|
||||
<el-button size="small" text @click="dialogDataADDVisible(row)">
|
||||
<el-icon>
|
||||
<Plus/>
|
||||
</el-icon>
|
||||
数据
|
||||
</el-button>
|
||||
<el-button size="small" text @click="dialogDedupObjectVisible(row)">
|
||||
<el-icon>
|
||||
<Edit/>
|
||||
</el-icon>
|
||||
去重对象
|
||||
</el-button>
|
||||
<el-button size="small" text @click="dialogDataFormatVisible(row)">
|
||||
<el-icon>
|
||||
<Edit/>
|
||||
</el-icon>
|
||||
数据格式
|
||||
</el-button>
|
||||
<el-button size="small" text @click="dialogNotesVisible(row)">
|
||||
<el-icon>
|
||||
<Edit/>
|
||||
</el-icon>
|
||||
备注
|
||||
</el-button>
|
||||
<el-popconfirm
|
||||
title="确认删除此 Token 吗?"
|
||||
confirm-button-text="确认"
|
||||
cancel-button-text="取消"
|
||||
@confirm="deleteToken(row)"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button type="danger" size="small" text>
|
||||
<el-icon>
|
||||
<Delete/>
|
||||
</el-icon>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="rounded-lg p-6 shadow-[0_2px_12px_rgba(0,0,0,0.08)]">
|
||||
<div class="text-xl font-semibold text-(--el-text-color-primary) pb-3 border-b border-(--el-border-color)">
|
||||
Token 管理
|
||||
</div>
|
||||
|
||||
<!-- 编辑对话框 -->
|
||||
<el-dialog v-model="dedupObjectVisible" title="更改去重对象" width="400">
|
||||
<el-select v-model="value" placeholder="选择去重对象" style="width: 100%">
|
||||
<el-option v-for="item in options" :key="item.value" :value="item.value" :label="item.label"/>
|
||||
</el-select>
|
||||
<template #footer>
|
||||
<el-button @click="dedupObjectVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="updateDedupObject">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<!-- 添加表单 -->
|
||||
<el-collapse
|
||||
class="rounded-xl"
|
||||
v-model="activeNames"
|
||||
>
|
||||
<el-collapse-item title="添加新 Token" name="1"
|
||||
class="flex flex-wrap gap-3 items-center max-md:flex-col max-md:items-stretch"
|
||||
>
|
||||
<el-input v-model="input" placeholder="Token 名称" clearable class="w-55 max-md:w-full">
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Key/>
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-dialog v-model="dataFormatVisible" title="更改数据格式" width="400">
|
||||
<el-select v-model="dataFormat" placeholder="选择数据格式" style="width: 100%">
|
||||
<el-option v-for="item in dataFormatOptions" :key="item.value" :value="item.value" :label="item.label"/>
|
||||
</el-select>
|
||||
<template #footer>
|
||||
<el-button @click="dataFormatVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="updateDataFormat">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-select v-model="inputDedupObject" placeholder="去重对象" clearable class="w-70 max-md:w-full">
|
||||
<el-option v-for="item in options" :key="item.value" :value="item.value" :label="item.label"/>
|
||||
</el-select>
|
||||
|
||||
<el-dialog v-model="inputNotesVisible" title="更改备注" width="400">
|
||||
<el-input v-model="inputNotes" placeholder="请输入备注"/>
|
||||
<template #footer>
|
||||
<el-button @click="inputNotesVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="updateNotes">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<el-select v-model="inputDataFormat" placeholder="数据格式" clearable class="w-70 max-md:w-full">
|
||||
<el-option v-for="item in dataFormatOptions" :key="item.value" :value="item.value"
|
||||
:label="item.label"/>
|
||||
</el-select>
|
||||
|
||||
<AddDataDialog
|
||||
v-model="addDataDialogVisible"
|
||||
:token="rowOut?.token"
|
||||
/>
|
||||
<el-input v-model="inputNotes" placeholder="备注(可选)" clearable class="w-55 max-md:w-full">
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Memo/>
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-button type="primary" @click="addToken" class="max-md:w-full">
|
||||
<el-icon>
|
||||
<Plus/>
|
||||
</el-icon>
|
||||
添加
|
||||
</el-button>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
|
||||
<!-- Token 列表 -->
|
||||
<div>
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-base font-semibold text-(--el-text-color-primary) mt-5 mb-4">Token 列表</span>
|
||||
<span class="text-xs text-(--el-text-color-secondary)">共 {{ tableData.length }} 条</span>
|
||||
</div>
|
||||
|
||||
<el-table empty-text="没有数据" stripe style="width: 100%"
|
||||
:data="tableData" v-loading="loading">
|
||||
<el-table-column prop="token" label="Token" min-width="100" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center gap-2">
|
||||
<el-icon>
|
||||
<Key/>
|
||||
</el-icon>
|
||||
<span>{{ row.token }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="dedup_object" label="去重对象" width="200">
|
||||
<template #default="{ row }">
|
||||
<el-tag type="primary" effect="plain">{{ row.dedup_object }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="data_format" label="数据格式" min-width="200" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<div class="text-xs break-all">{{ row.data_format }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="notes" label="备注" min-width="150" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span class="text-(--el-text-color-secondary) overflow-hidden text-ellipsis whitespace-nowrap">
|
||||
{{ row.notes || '-' }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="380" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<div class="flex gap-1 flex-wrap max-md:flex-col">
|
||||
<el-button size="small" text @click="viewDetails(row)">
|
||||
<el-icon>
|
||||
<View/>
|
||||
</el-icon>
|
||||
详情
|
||||
</el-button>
|
||||
<el-button size="small" text @click="dialogDataADDVisible(row)">
|
||||
<el-icon>
|
||||
<Plus/>
|
||||
</el-icon>
|
||||
数据
|
||||
</el-button>
|
||||
<el-button type="primary" size="small" text @click="displayDataVisible(row)">
|
||||
<el-icon>
|
||||
<Edit/>
|
||||
</el-icon>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-popconfirm
|
||||
title="确认删除此 Token 吗?"
|
||||
confirm-button-text="确认"
|
||||
cancel-button-text="取消"
|
||||
@confirm="deleteToken(row)"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button type="danger" size="small" text>
|
||||
<el-icon>
|
||||
<Delete/>
|
||||
</el-icon>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 编辑对话框 -->
|
||||
<el-dialog width="400"
|
||||
v-model="dataDialogVisible"
|
||||
>
|
||||
<template #header>
|
||||
编辑Token
|
||||
<el-tag type="primary" effect="plain">{{ rowOut?.token }}</el-tag>
|
||||
</template>
|
||||
|
||||
|
||||
<div class="flex flex-col gap-3">
|
||||
<el-text class="mr-auto">去重对象</el-text>
|
||||
<el-select v-model="inputDedupObject" placeholder="选择去重对象">
|
||||
<el-option v-for="item in options" :key="item.value" :value="item.value" :label="item.label"/>
|
||||
</el-select>
|
||||
|
||||
<el-text class="mr-auto">数据格式</el-text>
|
||||
<el-select v-model="inputDataFormat" placeholder="选择数据格式">
|
||||
<el-option v-for="item in dataFormatOptions" :key="item.value" :value="item.value" :label="item.label"/>
|
||||
</el-select>
|
||||
<el-text class="mr-auto">备注</el-text>
|
||||
<el-input v-model="inputNotes" placeholder="请输入备注"/>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="dataDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="updateData">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<AddDataDialog
|
||||
v-model="addDataDialogVisible"
|
||||
:token="rowOut?.token"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.token-manage {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* 管理页面 */
|
||||
.add-form {
|
||||
margin-bottom: 32px;
|
||||
padding: 24px;
|
||||
background: var(--bg-page);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.form-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form-grid .el-input {
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.form-grid .el-select {
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
/* 表格 */
|
||||
.table-section {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.table-count {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.token-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.format-cell {
|
||||
font-size: 12px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.notes-text {
|
||||
color: var(--el-text-color-secondary);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.form-grid {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.form-grid .el-input,
|
||||
.form-grid .el-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-grid .el-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user