feat: auto-format JSON display everywhere
- Shared prettyJson/truncate/isJson utility in src/utils/format.ts - MessageStream: collapsed preview + expanded view both auto-format JSON - LogPanel: log details with JSON content auto-formatted - PresetList: payload preview auto-formatted - Deduplicated isJson/formatPayload logic
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { ref, computed, watch, nextTick } from 'vue'
|
||||
import { useLogs } from '../../stores/useLogs'
|
||||
import { mqttGetLogDir } from '../../stores/useMqttBridge'
|
||||
import { prettyJson } from '../../utils/format'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const { logs, clear } = useLogs()
|
||||
@@ -121,7 +122,7 @@ function eventIcon(event: string): string {
|
||||
<span v-if="log.details" class="log-dtl-btn" @click="toggleDetails(log.id)">{{ expandedDetails.has(log.id) ? '收起' : '详情' }}</span>
|
||||
</div>
|
||||
<div v-if="log.details && expandedDetails.has(log.id)" class="log-dtl-content">
|
||||
{{ log.details }}
|
||||
{{ prettyJson(log.details) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, nextTick } from 'vue'
|
||||
import type { MqttMessage } from '../../types/mqtt'
|
||||
import { prettyJson, isJson, truncate } from '../../utils/format'
|
||||
|
||||
const props = defineProps<{
|
||||
messages: MqttMessage[]
|
||||
@@ -50,11 +51,6 @@ function onScroll() {
|
||||
|
||||
// ─── Payload Format Helpers ────────────────────────────────────
|
||||
|
||||
function isJson(str: string): boolean {
|
||||
try { JSON.parse(str); return true }
|
||||
catch { return false }
|
||||
}
|
||||
|
||||
function getEffectiveFormat(msg: MqttMessage): string {
|
||||
const fmt = messageFormats.value[msg.id] || 'auto'
|
||||
if (fmt === 'auto') return isJson(msg.payload) ? 'json' : 'plain'
|
||||
@@ -64,18 +60,11 @@ function getEffectiveFormat(msg: MqttMessage): string {
|
||||
function formatPayload(msg: MqttMessage): string {
|
||||
const fmt = getEffectiveFormat(msg)
|
||||
switch (fmt) {
|
||||
case 'json':
|
||||
try {
|
||||
const parsed = JSON.parse(msg.payload)
|
||||
return JSON.stringify(parsed, null, 2)
|
||||
} catch { return msg.payload }
|
||||
case 'hex':
|
||||
return bytesToHex(new TextEncoder().encode(msg.payload))
|
||||
case 'base64':
|
||||
return btoa(msg.payload)
|
||||
case 'json': return prettyJson(msg.payload)
|
||||
case 'hex': return bytesToHex(new TextEncoder().encode(msg.payload))
|
||||
case 'base64': return btoa(msg.payload)
|
||||
case 'plain':
|
||||
default:
|
||||
return msg.payload
|
||||
default: return msg.payload
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +169,7 @@ function formatTime(ts: number): string {
|
||||
v-if="expandedPayloads.has(msg.id)"
|
||||
:class="['payload-full', { 'is-json': getEffectiveFormat(msg) === 'json' }]"
|
||||
>{{ formatPayload(msg) }}</pre>
|
||||
<pre v-else class="payload-truncated">{{ msg.payload.substring(0, 200) }}{{ msg.payload.length > 200 ? '...' : '' }}</pre>
|
||||
<pre v-else class="payload-truncated">{{ truncate(prettyJson(msg.payload), 200) }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ref } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { Preset } from '../../types/mqtt'
|
||||
import { usePresets } from '../../stores/usePresets'
|
||||
import { prettyJson, truncate } from '../../utils/format'
|
||||
import PresetForm from './PresetForm.vue'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
@@ -76,7 +77,7 @@ const qosLabel = (qos: number) => `QoS ${qos}`
|
||||
</el-table-column>
|
||||
<el-table-column label="Payload 预览" min-width="200">
|
||||
<template #default="{ row }">
|
||||
<span class="payload-preview">{{ row.payloadTemplate.substring(0, 50) }}{{ row.payloadTemplate.length > 50 ? '...' : '' }}</span>
|
||||
<span class="payload-preview">{{ truncate(prettyJson(row.payloadTemplate), 50) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="160" fixed="right">
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Pretty-print a JSON string if it's valid JSON.
|
||||
* Returns the original string if it's not valid JSON.
|
||||
*/
|
||||
export function prettyJson(str: string): string {
|
||||
if (!str || str.trim() === '') return str
|
||||
try {
|
||||
const parsed = JSON.parse(str)
|
||||
return JSON.stringify(parsed, null, 2)
|
||||
} catch {
|
||||
return str
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string is valid JSON.
|
||||
*/
|
||||
export function isJson(str: string): boolean {
|
||||
try {
|
||||
JSON.parse(str)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate a string to a maximum length, adding an ellipsis if truncated.
|
||||
*/
|
||||
export function truncate(str: string, maxLen: number): string {
|
||||
if (str.length <= maxLen) return str
|
||||
return str.substring(0, maxLen) + '...'
|
||||
}
|
||||
Reference in New Issue
Block a user