XHS / frontend /src /components /JsonViewer.tsx
Trae Bot
Upload Spider_XHS project
c481f8a
import { Tree, Typography } from 'antd'
import type { DataNode } from 'antd/es/tree'
import { useMemo } from 'react'
export type JsonViewerProps = {
value: unknown
height?: number
defaultExpandAll?: boolean
}
function isRecord(value: unknown): value is Record<string, unknown> {
return !!value && typeof value === 'object' && !Array.isArray(value)
}
function preview(value: unknown) {
if (value === null) return 'null'
if (value === undefined) return 'undefined'
if (typeof value === 'string') return JSON.stringify(value)
if (typeof value === 'number' || typeof value === 'boolean') return String(value)
if (Array.isArray(value)) return `[${value.length}]`
if (isRecord(value)) return `{${Object.keys(value).length}}`
return String(value)
}
function toTreeData(value: unknown, path: string): DataNode[] {
if (Array.isArray(value)) {
return value.map((item, idx) => {
const nextPath = `${path}[${idx}]`
const hasChildren = Array.isArray(item) || isRecord(item)
return {
key: nextPath,
title: (
<span>
<Typography.Text code>{idx}</Typography.Text>
<Typography.Text type="secondary" style={{ marginLeft: 8 }}>
{preview(item)}
</Typography.Text>
</span>
),
children: hasChildren ? toTreeData(item, nextPath) : undefined,
}
})
}
if (isRecord(value)) {
return Object.entries(value).map(([k, v]) => {
const nextPath = path ? `${path}.${k}` : k
const hasChildren = Array.isArray(v) || isRecord(v)
return {
key: nextPath,
title: (
<span>
<Typography.Text code>{k}</Typography.Text>
<Typography.Text type="secondary" style={{ marginLeft: 8 }}>
{preview(v)}
</Typography.Text>
</span>
),
children: hasChildren ? toTreeData(v, nextPath) : undefined,
}
})
}
return [
{
key: path || 'value',
title: <Typography.Text type="secondary">{preview(value)}</Typography.Text>,
},
]
}
export default function JsonViewer({
value,
height = 360,
defaultExpandAll = true,
}: JsonViewerProps) {
const treeData = useMemo<DataNode[]>(() => toTreeData(value, ''), [value])
if (value === null || value === undefined) {
return <Typography.Text type="secondary"></Typography.Text>
}
return (
<Tree
blockNode
showLine
height={height}
defaultExpandAll={defaultExpandAll}
treeData={treeData}
/>
)
}