fix: 优化云端变量记录页面样式,对齐其他表格页面

- 移除ID列的font-mono text-xs样式,改用与其他页面一致的truncate样式
- 移除toolbar顶部多余的批量删除按钮,只保留BulkActions组件内的
- 搜索框和日期选择器尺寸对齐其他页面(h-8)
- 日期格式化对齐其他页面(zh-CN格式)
- 动态字段值显示改用truncate+title,替代pre标签
- 移除raw_data调试字段和诊断卡片
This commit is contained in:
2026-05-08 09:31:47 +08:00
parent 375fd46224
commit 29fb448d04
2 changed files with 17 additions and 59 deletions
@@ -1,7 +1,7 @@
<script setup lang="ts">
import type { ColumnDef } from '@tanstack/vue-table'
import { List, Loader2, Search, Trash2 } from 'lucide-vue-next'
import { List, Search, Trash2 } from 'lucide-vue-next'
import { computed, h, onMounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
@@ -30,7 +30,6 @@ interface Variable {
interface VariableRecord {
id: number
data: any
raw_data?: string
user_id?: number
user?: {
id: number
@@ -40,16 +39,7 @@ interface VariableRecord {
}
function parseRecordData(record: VariableRecord): Record<string, any> {
let rawData = record.data
if ((rawData == null || rawData === '') && record.raw_data) {
try {
rawData = JSON.parse(record.raw_data)
}
catch {
rawData = record.raw_data
}
}
const rawData = record.data
if (rawData == null || rawData === '') return {}
@@ -118,24 +108,13 @@ const dynamicKeys = computed(() => {
return Array.from(keys).sort()
})
const debugInfo = computed(() => {
if (records.value.length === 0 || dynamicKeys.value.length > 0) return null
const first = records.value[0]
return {
dataType: first.data === null ? 'null' : first.data === undefined ? 'undefined' : typeof first.data,
dataValue: first.data === null ? 'null' : first.data === undefined ? 'undefined' : typeof first.data === 'object' ? JSON.stringify(first.data) : String(first.data),
rawDataField: first.raw_data === undefined ? '(字段不存在)' : first.raw_data === '' ? '(空字符串)' : first.raw_data || '(falsy)',
parsedKeys: (() => { const p = parseRecordData(first); return p && typeof p === 'object' ? Object.keys(p) : [] })(),
}
})
const columns = computed<ColumnDef<VariableRecord>[]>(() => {
const cols: ColumnDef<VariableRecord>[] = [SelectColumn as ColumnDef<VariableRecord>]
cols.push({
accessorKey: 'id',
header: () => 'ID',
cell: ({ row }) => h('span', { class: 'text-muted-foreground font-mono text-xs' }, String(row.original.id)),
cell: ({ row }) => h('div', { class: 'max-w-xs truncate' }, String(row.original.id)),
size: 80,
})
@@ -169,12 +148,12 @@ const columns = computed<ColumnDef<VariableRecord>[]>(() => {
return h('span', { class: 'text-muted-foreground' }, '-')
}
if (typeof value === 'object') {
return h('pre', { class: 'text-xs bg-muted px-2 py-1 rounded max-w-xs overflow-auto max-h-20' }, JSON.stringify(value, null, 2))
return h('div', { class: 'max-w-xs truncate', title: JSON.stringify(value) }, JSON.stringify(value))
}
if (typeof value === 'boolean') {
return h(Badge, { variant: value ? 'default' : 'secondary' }, () => String(value))
}
return h('span', { class: 'truncate max-w-xs block', title: String(value) }, String(value))
return h('div', { class: 'max-w-xs truncate', title: String(value) }, String(value))
},
size: 150,
})
@@ -189,7 +168,7 @@ const columns = computed<ColumnDef<VariableRecord>[]>(() => {
if (!data || Object.keys(data).length === 0) {
return h('span', { class: 'text-muted-foreground' }, '-')
}
return h('pre', { class: 'text-xs bg-muted px-2 py-1 rounded max-w-md overflow-auto max-h-20' }, JSON.stringify(data, null, 2))
return h('div', { class: 'max-w-md truncate', title: JSON.stringify(data) }, JSON.stringify(data))
},
})
}
@@ -203,7 +182,13 @@ const columns = computed<ColumnDef<VariableRecord>[]>(() => {
try {
const date = new Date(createdAt)
if (Number.isNaN(date.getTime())) return '-'
return h('span', { class: 'text-muted-foreground text-xs' }, date.toLocaleString())
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
})
}
catch {
return '-'
@@ -440,35 +425,11 @@ onMounted(async () => {
</UiCard>
</div>
<div v-if="debugInfo" class="border border-dashed border-yellow-500/50 bg-yellow-500/5 rounded-md p-4 text-sm">
<p class="font-medium text-yellow-600 mb-2">数据诊断 (Data Debug)</p>
<div class="grid grid-cols-1 gap-2 text-xs font-mono">
<div>data 类型: <span class="text-yellow-700">{{ debugInfo.dataType }}</span></div>
<div>data : <span class="text-yellow-700 break-all">{{ debugInfo.dataValue.substring(0, 500) }}</span></div>
<div>raw_data (数据库原始): <span class="text-yellow-700 break-all">{{ debugInfo.rawDataField.substring(0, 500) }}</span></div>
<div>解析后 keys: <span class="text-yellow-700">{{ debugInfo.parsedKeys.length > 0 ? debugInfo.parsedKeys.join(', ') : '(空)' }}</span></div>
</div>
</div>
<UiCard>
<UiCardContent class="p-6">
<DataTable :columns="columns" :data="records" :loading="loading" :table="table" :server-pagination="serverPagination" @refresh="fetchRecords">
<template #toolbar>
<div class="space-y-3">
<div class="flex items-center justify-end">
<UiButton
variant="destructive"
size="sm"
:disabled="table.getSelectedRowModel().rows.length === 0"
@click="openBatchDeleteDialog"
>
<Trash2 class="h-4 w-4 mr-1" />
{{ t('admin.cloudVariables.records.batchDelete') }}
<span v-if="table.getSelectedRowModel().rows.length > 0" class="ml-1">
({{ table.getSelectedRowModel().rows.length }})
</span>
</UiButton>
</div>
<BulkActions :table="table" entity-name="records">
<UiButton variant="destructive" size="sm" @click="openBatchDeleteDialog">
<Trash2 class="h-4 w-4 mr-1" />
@@ -482,23 +443,21 @@ onMounted(async () => {
<Input
v-model="searchQuery"
:placeholder="t('admin.cloudVariables.records.searchPlaceholder')"
class="pl-8 w-[250px] h-9"
class="pl-8 h-8 w-[150px] lg:w-[250px]"
@keydown.enter="handleSearch"
/>
</div>
<Input
v-model="startDate"
type="date"
class="w-36 h-9"
:placeholder="t('admin.cloudVariables.records.startDate')"
class="h-8 w-[140px]"
/>
<Input
v-model="endDate"
type="date"
class="w-36 h-9"
:placeholder="t('admin.cloudVariables.records.endDate')"
class="h-8 w-[140px]"
/>
<Button variant="outline" size="sm" class="h-9" @click="handleSearch">
<Button variant="outline" size="sm" class="h-8" @click="handleSearch">
<Search class="h-4 w-4 mr-1" />
{{ t('admin.cloudVariables.records.search') }}
</Button>