优化体验,新增多项功能,美化界面
This commit is contained in:
@@ -8,11 +8,12 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.3.4",
|
||||
"vue-router": "^4.2.4",
|
||||
"@element-plus/icons-vue": "^2.1.0",
|
||||
"axios": "^1.5.0",
|
||||
"element-plus": "^2.3.14",
|
||||
"@element-plus/icons-vue": "^2.1.0"
|
||||
"vue": "^3.3.4",
|
||||
"vue-json-pretty": "^2.6.0",
|
||||
"vue-router": "^4.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.3.4",
|
||||
|
||||
Generated
+13
@@ -20,6 +20,9 @@ importers:
|
||||
vue:
|
||||
specifier: ^3.3.4
|
||||
version: 3.5.35
|
||||
vue-json-pretty:
|
||||
specifier: ^2.6.0
|
||||
version: 2.6.0(vue@3.5.35)
|
||||
vue-router:
|
||||
specifier: ^4.2.4
|
||||
version: 4.6.4(vue@3.5.35)
|
||||
@@ -486,6 +489,12 @@ packages:
|
||||
vue-component-type-helpers@3.3.3:
|
||||
resolution: {integrity: sha512-x4nsFpy5Pe8fqPzp/5vkTPeTTDBpAx4WVtV47Ejt0+2FQrq4pRRsJs7JmYRqMFzTu/LW+pCWEjQ3YVCkPV7f9g==}
|
||||
|
||||
vue-json-pretty@2.6.0:
|
||||
resolution: {integrity: sha512-glz1aBVS35EO8+S9agIl3WOQaW2cJZW192UVKTuGmryx01ZvOVWc4pR3t+5UcyY4jdOfBUgVHjcpRpcnjRhCAg==}
|
||||
engines: {node: '>= 10.0.0', npm: '>= 5.0.0'}
|
||||
peerDependencies:
|
||||
vue: '>=3.0.0'
|
||||
|
||||
vue-router@4.6.4:
|
||||
resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==}
|
||||
peerDependencies:
|
||||
@@ -899,6 +908,10 @@ snapshots:
|
||||
|
||||
vue-component-type-helpers@3.3.3: {}
|
||||
|
||||
vue-json-pretty@2.6.0(vue@3.5.35):
|
||||
dependencies:
|
||||
vue: 3.5.35
|
||||
|
||||
vue-router@4.6.4(vue@3.5.35):
|
||||
dependencies:
|
||||
'@vue/devtools-api': 6.6.4
|
||||
|
||||
@@ -60,6 +60,56 @@ export function updateModel(id, data, config = {}) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取型号 EQ 缓存(Redis)
|
||||
* @param {number} id - 型号 ID
|
||||
*/
|
||||
export function getModelEqCache(id) {
|
||||
return request({
|
||||
url: `/models/${id}/eq-cache`,
|
||||
method: 'get',
|
||||
timeout: 30000
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取型号 EQ 缓存单个 hash field 的 value
|
||||
* @param {number} id - 型号 ID
|
||||
* @param {string} fieldKey - hash field 名称
|
||||
*/
|
||||
export function getModelEqCacheField(id, fieldKey) {
|
||||
return request({
|
||||
url: `/models/${id}/eq-cache/field`,
|
||||
method: 'get',
|
||||
params: { key: fieldKey },
|
||||
timeout: 30000
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取型号在 Meilisearch 中的推送数据
|
||||
* @param {number} id - 型号 ID
|
||||
*/
|
||||
export function getModelMeilisearch(id) {
|
||||
return request({
|
||||
url: `/models/${id}/meilisearch`,
|
||||
method: 'get',
|
||||
timeout: 30000
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取型号在 S3 上的频响 CSV 内容(仅 Eafonyoung)
|
||||
* @param {number} id - 型号 ID
|
||||
*/
|
||||
export function getModelMeasurement(id) {
|
||||
return request({
|
||||
url: `/models/${id}/measurement`,
|
||||
method: 'get',
|
||||
timeout: 30000
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除型号
|
||||
* @param {number} id - 型号 ID
|
||||
|
||||
@@ -81,25 +81,56 @@
|
||||
<span v-else>{{ scope.row.form || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="rig" label="阻抗" width="150" />
|
||||
<el-table-column prop="source" label="来源" width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="create_at" label="创建时间" width="180" sortable="custom" />
|
||||
<el-table-column label="操作" width="200" fixed="right">
|
||||
<el-table-column prop="create_at" label="创建时间" width="180" sortable="custom">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleEdit(scope.row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="handleDelete(scope.row)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
{{ formatDateTime(scope.row.create_at) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="300" fixed="right">
|
||||
<template #default="scope">
|
||||
<div class="row-actions">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleEdit(scope.row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
@click="handleDelete(scope.row)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
trigger="click"
|
||||
class="row-actions-more"
|
||||
@command="(cmd) => handleMoreAction(cmd, scope.row)"
|
||||
>
|
||||
<el-button
|
||||
type="success"
|
||||
size="small"
|
||||
:loading="moreActionLoadingId === scope.row.id"
|
||||
>
|
||||
更多操作
|
||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="push">查看搜索</el-dropdown-item>
|
||||
<el-dropdown-item command="eq">查看 EQ 缓存</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
v-if="isEafonyoungSource(scope.row.source)"
|
||||
command="csv"
|
||||
>
|
||||
查看 CSV
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -208,6 +239,114 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="pushViewDialogVisible"
|
||||
:title="pushViewDialogTitle"
|
||||
width="520px"
|
||||
@closed="resetPushViewDialog"
|
||||
>
|
||||
<div v-if="pushViewLoading" class="push-view-loading">
|
||||
<el-icon class="is-loading"><Loading /></el-icon>
|
||||
加载中…
|
||||
</div>
|
||||
<template v-else-if="!pushViewPushed">
|
||||
<el-empty description="还没推送" :image-size="80" />
|
||||
</template>
|
||||
<el-descriptions v-else :column="1" border>
|
||||
<el-descriptions-item label="ID">{{ pushViewDocument.id }}</el-descriptions-item>
|
||||
<el-descriptions-item label="品牌">{{ pushViewDocument.brand_name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="型号">{{ pushViewDocument.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="佩戴方式">{{ formatFormLabel(pushViewDocument.form) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="阻抗">{{ pushViewDocument.rig || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="来源">{{ pushViewDocument.source || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<template #footer>
|
||||
<el-button @click="pushViewDialogVisible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="eqCacheDialogVisible"
|
||||
:title="eqCacheDialogTitle"
|
||||
width="720px"
|
||||
class="eq-cache-dialog"
|
||||
>
|
||||
<div v-if="eqCacheView === 'loading'" class="push-view-loading">
|
||||
<el-icon class="is-loading"><Loading /></el-icon>
|
||||
加载中…
|
||||
</div>
|
||||
<div v-else-if="eqCacheView === 'empty'">
|
||||
<el-empty description="暂无 EQ 缓存" :image-size="80" />
|
||||
<p v-if="eqCacheRedisKey" class="csv-s3-key">Redis Key: {{ eqCacheRedisKey }}</p>
|
||||
</div>
|
||||
<div v-else-if="eqCacheView === 'list'" class="eq-cache-content">
|
||||
<p class="csv-s3-key">Redis Key: {{ eqCacheRedisKey }}</p>
|
||||
<p class="eq-cache-keys-title">Hash Keys({{ eqCacheFieldKeys.length }})</p>
|
||||
<ul class="eq-cache-keys">
|
||||
<li
|
||||
v-for="key in eqCacheFieldKeys"
|
||||
:key="key"
|
||||
:class="{ 'is-active': eqCacheActiveKey === key }"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="eq-cache-key-btn"
|
||||
@click="handleEqFieldClick(key)"
|
||||
>
|
||||
<span class="eq-cache-key-text">{{ key }}</span>
|
||||
<el-icon
|
||||
v-if="eqCacheFieldLoadingKey === key"
|
||||
class="is-loading eq-cache-key-icon"
|
||||
>
|
||||
<Loading />
|
||||
</el-icon>
|
||||
<el-icon v-else class="eq-cache-key-icon">
|
||||
<ArrowDown />
|
||||
</el-icon>
|
||||
</button>
|
||||
<div
|
||||
v-if="eqCacheActiveKey === key && eqCacheFieldData !== null"
|
||||
class="eq-cache-value"
|
||||
>
|
||||
<VueJsonPretty
|
||||
:data="eqCacheFieldData"
|
||||
:deep="2"
|
||||
:show-length="true"
|
||||
:show-line-number="false"
|
||||
:show-icon="true"
|
||||
:show-select-controller="false"
|
||||
:editable="false"
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="eqCacheDialogVisible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="csvDialogVisible"
|
||||
:title="csvDialogTitle"
|
||||
width="720px"
|
||||
class="csv-dialog"
|
||||
@closed="resetCsvDialog"
|
||||
>
|
||||
<p v-if="csvS3Key" class="csv-s3-key">{{ csvS3Key }}</p>
|
||||
<el-input
|
||||
v-model="csvContent"
|
||||
type="textarea"
|
||||
:rows="18"
|
||||
readonly
|
||||
placeholder="暂无内容"
|
||||
class="csv-content"
|
||||
/>
|
||||
<template #footer>
|
||||
<el-button @click="csvDialogVisible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="pushProgressVisible"
|
||||
title="推送到搜索"
|
||||
@@ -284,7 +423,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted, nextTick } from 'vue'
|
||||
import { ref, reactive, computed, onMounted, nextTick, watch } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
Search,
|
||||
@@ -294,17 +433,24 @@ import {
|
||||
UploadFilled,
|
||||
Loading,
|
||||
CircleCheck,
|
||||
CircleClose
|
||||
CircleClose,
|
||||
ArrowDown
|
||||
} from '@element-plus/icons-vue'
|
||||
import {
|
||||
getModels,
|
||||
createModel,
|
||||
updateModel,
|
||||
deleteModel,
|
||||
getModelMeasurement,
|
||||
getModelMeilisearch,
|
||||
getModelEqCache,
|
||||
getModelEqCacheField,
|
||||
validatePushToMeilisearch,
|
||||
pushToMeilisearch
|
||||
} from '@/api/model'
|
||||
import { getBrands, createBrand } from '@/api/brand'
|
||||
import VueJsonPretty from 'vue-json-pretty'
|
||||
import 'vue-json-pretty/lib/styles.css'
|
||||
|
||||
const loading = ref(false)
|
||||
const submitLoading = ref(false)
|
||||
@@ -335,6 +481,26 @@ const brandOptions = ref([])
|
||||
const selectedIds = ref([])
|
||||
const fileList = ref([])
|
||||
const uploadedFile = ref(null)
|
||||
const csvDialogVisible = ref(false)
|
||||
const csvDialogTitle = ref('频响 CSV')
|
||||
const csvContent = ref('')
|
||||
const csvS3Key = ref('')
|
||||
const pushViewDialogVisible = ref(false)
|
||||
const pushViewDialogTitle = ref('查看推送')
|
||||
const pushViewLoading = ref(false)
|
||||
const pushViewPushed = ref(false)
|
||||
const pushViewDocument = ref({})
|
||||
const moreActionLoadingId = ref(null)
|
||||
const eqCacheDialogVisible = ref(false)
|
||||
const eqCacheDialogTitle = ref('查看 EQ 缓存')
|
||||
/** idle | loading | empty | list */
|
||||
const eqCacheView = ref('idle')
|
||||
const eqCacheRedisKey = ref('')
|
||||
const eqCacheFieldKeys = ref([])
|
||||
const eqCacheModelId = ref(null)
|
||||
const eqCacheActiveKey = ref('')
|
||||
const eqCacheFieldLoadingKey = ref('')
|
||||
const eqCacheFieldData = ref(null)
|
||||
|
||||
const searchForm = reactive({
|
||||
brand_name: '',
|
||||
@@ -556,6 +722,189 @@ const handleAdd = () => {
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
function formatDateTime(value) {
|
||||
if (!value) return '-'
|
||||
const date = new Date(value)
|
||||
if (Number.isNaN(date.getTime())) return value
|
||||
const pad = (n) => String(n).padStart(2, '0')
|
||||
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
|
||||
}
|
||||
|
||||
function formatFormLabel(form) {
|
||||
if (form === 'in-ear') return '入耳式'
|
||||
if (form === 'over-ear') return '头戴式'
|
||||
if (form === 'earbud') return '耳塞式'
|
||||
return form || '-'
|
||||
}
|
||||
|
||||
function resetPushViewDialog() {
|
||||
pushViewLoading.value = false
|
||||
pushViewPushed.value = false
|
||||
pushViewDocument.value = {}
|
||||
pushViewDialogTitle.value = '查看推送'
|
||||
}
|
||||
|
||||
const handleViewPush = async (row) => {
|
||||
pushViewDialogTitle.value = `${row.brand_name} · ${row.name}`
|
||||
pushViewDialogVisible.value = true
|
||||
pushViewLoading.value = true
|
||||
pushViewPushed.value = false
|
||||
pushViewDocument.value = {}
|
||||
moreActionLoadingId.value = row.id
|
||||
|
||||
try {
|
||||
const res = await getModelMeilisearch(row.id)
|
||||
if (res.code === 1 && res.data) {
|
||||
pushViewPushed.value = !!res.data.pushed
|
||||
pushViewDocument.value = res.data.document || {}
|
||||
} else {
|
||||
ElMessage.error(res.msg || '查询推送数据失败')
|
||||
pushViewDialogVisible.value = false
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('查询推送数据失败:', error)
|
||||
ElMessage.error(error.message || '查询推送数据失败')
|
||||
pushViewDialogVisible.value = false
|
||||
} finally {
|
||||
pushViewLoading.value = false
|
||||
moreActionLoadingId.value = null
|
||||
}
|
||||
}
|
||||
|
||||
function resetEqCacheDialog() {
|
||||
eqCacheView.value = 'idle'
|
||||
eqCacheRedisKey.value = ''
|
||||
eqCacheFieldKeys.value = []
|
||||
eqCacheModelId.value = null
|
||||
eqCacheActiveKey.value = ''
|
||||
eqCacheFieldLoadingKey.value = ''
|
||||
eqCacheFieldData.value = null
|
||||
eqCacheDialogTitle.value = '查看 EQ 缓存'
|
||||
}
|
||||
|
||||
function parseEqFieldValue(value) {
|
||||
if (value === null || value === undefined) return null
|
||||
if (typeof value === 'object') return value
|
||||
if (typeof value === 'string') {
|
||||
try {
|
||||
return JSON.parse(value)
|
||||
} catch {
|
||||
return { _raw: value }
|
||||
}
|
||||
}
|
||||
return { value }
|
||||
}
|
||||
|
||||
const handleEqFieldClick = async (key) => {
|
||||
if (eqCacheActiveKey.value === key && !eqCacheFieldLoadingKey.value) {
|
||||
eqCacheActiveKey.value = ''
|
||||
eqCacheFieldData.value = null
|
||||
return
|
||||
}
|
||||
|
||||
eqCacheActiveKey.value = key
|
||||
eqCacheFieldData.value = null
|
||||
eqCacheFieldLoadingKey.value = key
|
||||
|
||||
try {
|
||||
const res = await getModelEqCacheField(eqCacheModelId.value, key)
|
||||
if (res.code === 1 && res.data) {
|
||||
eqCacheFieldData.value = parseEqFieldValue(res.data.value)
|
||||
} else {
|
||||
ElMessage.error(res.msg || '加载 hash value 失败')
|
||||
eqCacheActiveKey.value = ''
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载 hash value 失败:', error)
|
||||
ElMessage.error(error.message || '加载 hash value 失败')
|
||||
eqCacheActiveKey.value = ''
|
||||
} finally {
|
||||
eqCacheFieldLoadingKey.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
watch(eqCacheDialogVisible, (visible, wasVisible) => {
|
||||
if (wasVisible && !visible) {
|
||||
resetEqCacheDialog()
|
||||
}
|
||||
})
|
||||
|
||||
const handleViewEqCache = async (row) => {
|
||||
eqCacheDialogTitle.value = `${row.brand_name} · ${row.name}`
|
||||
eqCacheView.value = 'loading'
|
||||
eqCacheRedisKey.value = ''
|
||||
eqCacheFieldKeys.value = []
|
||||
eqCacheModelId.value = row.id
|
||||
eqCacheActiveKey.value = ''
|
||||
eqCacheFieldData.value = null
|
||||
moreActionLoadingId.value = row.id
|
||||
eqCacheDialogVisible.value = true
|
||||
|
||||
try {
|
||||
const res = await getModelEqCache(row.id)
|
||||
if (res.code !== 1) {
|
||||
ElMessage.error(res.msg || '获取 EQ 缓存失败')
|
||||
eqCacheDialogVisible.value = false
|
||||
return
|
||||
}
|
||||
|
||||
const fieldKeys = Array.isArray(res.data?.field_keys) ? res.data.field_keys : []
|
||||
eqCacheRedisKey.value = res.data?.redis_key || `${row.brand_name} ${row.name}`
|
||||
eqCacheFieldKeys.value = fieldKeys
|
||||
eqCacheView.value = fieldKeys.length > 0 ? 'list' : 'empty'
|
||||
} catch (error) {
|
||||
console.error('获取 EQ 缓存失败:', error)
|
||||
ElMessage.error(error.message || '获取 EQ 缓存失败')
|
||||
eqCacheDialogVisible.value = false
|
||||
} finally {
|
||||
moreActionLoadingId.value = null
|
||||
}
|
||||
}
|
||||
|
||||
const handleMoreAction = async (command, row) => {
|
||||
if (command === 'push') {
|
||||
await handleViewPush(row)
|
||||
return
|
||||
}
|
||||
if (command === 'eq') {
|
||||
await handleViewEqCache(row)
|
||||
return
|
||||
}
|
||||
if (command === 'csv') {
|
||||
await handleViewCsv(row)
|
||||
}
|
||||
}
|
||||
|
||||
function isEafonyoungSource(source) {
|
||||
return String(source || '').trim().toLowerCase() === 'eafonyoung'
|
||||
}
|
||||
|
||||
function resetCsvDialog() {
|
||||
csvContent.value = ''
|
||||
csvS3Key.value = ''
|
||||
csvDialogTitle.value = '频响 CSV'
|
||||
}
|
||||
|
||||
const handleViewCsv = async (row) => {
|
||||
moreActionLoadingId.value = row.id
|
||||
try {
|
||||
const res = await getModelMeasurement(row.id)
|
||||
if (res.code === 1 && res.data) {
|
||||
csvDialogTitle.value = `${row.brand_name} · ${row.name}`
|
||||
csvS3Key.value = res.data.s3_key || ''
|
||||
csvContent.value = res.data.content || ''
|
||||
csvDialogVisible.value = true
|
||||
} else {
|
||||
ElMessage.error(res.msg || '获取 CSV 失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取 CSV 失败:', error)
|
||||
ElMessage.error(error.message || '获取 CSV 失败')
|
||||
} finally {
|
||||
moreActionLoadingId.value = null
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑
|
||||
const handleEdit = (row) => {
|
||||
dialogTitle.value = '编辑型号'
|
||||
@@ -961,4 +1310,156 @@ onMounted(() => {
|
||||
line-height: 1.6;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.csv-s3-key {
|
||||
margin: 0 0 10px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
color: #94a3b8;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.eq-cache-content {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.eq-cache-keys-title {
|
||||
margin: 12px 0 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
.eq-cache-keys {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
max-height: 360px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.eq-cache-keys li {
|
||||
margin-bottom: 8px;
|
||||
border-radius: 8px;
|
||||
background: rgba(148, 163, 184, 0.08);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.eq-cache-keys li.is-active {
|
||||
background: rgba(148, 163, 184, 0.14);
|
||||
}
|
||||
|
||||
.eq-cache-key-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
color: #cbd5e1;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.eq-cache-key-btn:hover {
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
.eq-cache-key-text {
|
||||
flex: 1;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.eq-cache-key-icon {
|
||||
flex-shrink: 0;
|
||||
font-size: 14px;
|
||||
color: #94a3b8;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.eq-cache-keys li.is-active .eq-cache-key-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.eq-cache-value {
|
||||
padding: 0 12px 12px;
|
||||
max-height: 420px;
|
||||
overflow: auto;
|
||||
border-top: 1px solid rgba(148, 163, 184, 0.12);
|
||||
}
|
||||
|
||||
.eq-cache-value :deep(.vjs-tree) {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
color: #cbd5e1;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.eq-cache-value :deep(.vjs-tree-node.is-highlight),
|
||||
.eq-cache-value :deep(.vjs-tree-node:hover) {
|
||||
background-color: rgba(51, 65, 85, 0.72);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.eq-cache-value :deep(.vjs-tree-node .vjs-tree-node-actions) {
|
||||
background-color: rgba(30, 41, 59, 0.95);
|
||||
}
|
||||
|
||||
.eq-cache-value :deep(.vjs-tree-brackets:hover),
|
||||
.eq-cache-value :deep(.vjs-carets:hover) {
|
||||
color: #7dd3fc;
|
||||
}
|
||||
|
||||
.eq-cache-value :deep(.vjs-key) {
|
||||
color: #7dd3fc;
|
||||
}
|
||||
|
||||
.eq-cache-value :deep(.vjs-value-string) {
|
||||
color: #86efac;
|
||||
}
|
||||
|
||||
.eq-cache-value :deep(.vjs-value-number) {
|
||||
color: #fcd34d;
|
||||
}
|
||||
|
||||
.eq-cache-value :deep(.vjs-value-boolean) {
|
||||
color: #f9a8d4;
|
||||
}
|
||||
|
||||
.eq-cache-value :deep(.vjs-value-null) {
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.csv-content :deep(textarea) {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.push-view-loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 32px 0;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.row-actions {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
gap: 8px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.row-actions-more {
|
||||
flex-shrink: 0;
|
||||
margin-left: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user