From 27283c0a22a035bdbc35b58e3b4332dd3fdb992e Mon Sep 17 00:00:00 2001 From: DaxPay Dev Date: Mon, 20 Jul 2026 08:21:39 +0800 Subject: [PATCH] =?UTF-8?q?fix(log):=20=E6=97=A5=E5=BF=97=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E6=8A=BD=E5=B1=89=E5=8C=96=20+=20JSON=20=E5=8F=8B?= =?UTF-8?q?=E5=A5=BD=E6=B8=B2=E6=9F=93=20+=20JsonViewer=20=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=E6=80=A7=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 三个日志详情 (支付接口/操作/登录) 由 Modal 改为 Drawer, 适配长内容滚动 - 支付接口/操作日志的 reqParam/resBody 用 JsonViewer 渲染, 支持折叠/复制/语法高亮 - a-descriptions 加 label-style + table-layout:fixed, 修复长 token 字段挤压 label 换行 - 修复 errorCode (unipay) / browser (operate) 单字段行 span 不匹配 column 的警告 - 修复 vue-json-viewer UMD 默认导出兼容 (Vite 预构建后 default 是命名空间对象) - 修复 json-bigint 解析返回 Object.create(null) 对象与 vue-json-viewer 内部 hasOwnProperty 冲突 --- .../views/system/log/login/LoginLogInfo.vue | 31 ++++-- .../system/log/operate/OperateLogInfo.vue | 98 ++++++++++++++++--- .../system/log/unipay/UnipayApiLogInfo.vue | 92 +++++++++++++---- .../src/components/json-viewer/index.vue | 32 +++++- 4 files changed, 206 insertions(+), 47 deletions(-) diff --git a/apps/daxpay-admin/src/views/system/log/login/LoginLogInfo.vue b/apps/daxpay-admin/src/views/system/log/login/LoginLogInfo.vue index 6c82f0727..3db368416 100644 --- a/apps/daxpay-admin/src/views/system/log/login/LoginLogInfo.vue +++ b/apps/daxpay-admin/src/views/system/log/login/LoginLogInfo.vue @@ -27,17 +27,23 @@ + + diff --git a/apps/daxpay-admin/src/views/system/log/operate/OperateLogInfo.vue b/apps/daxpay-admin/src/views/system/log/operate/OperateLogInfo.vue index 2034677d8..e71ecbea4 100644 --- a/apps/daxpay-admin/src/views/system/log/operate/OperateLogInfo.vue +++ b/apps/daxpay-admin/src/views/system/log/operate/OperateLogInfo.vue @@ -1,6 +1,7 @@ + + diff --git a/apps/daxpay-admin/src/views/system/log/unipay/UnipayApiLogInfo.vue b/apps/daxpay-admin/src/views/system/log/unipay/UnipayApiLogInfo.vue index 930371dd1..1c8d4a5bc 100644 --- a/apps/daxpay-admin/src/views/system/log/unipay/UnipayApiLogInfo.vue +++ b/apps/daxpay-admin/src/views/system/log/unipay/UnipayApiLogInfo.vue @@ -1,6 +1,7 @@ + + diff --git a/packages/effects/common-ui/src/components/json-viewer/index.vue b/packages/effects/common-ui/src/components/json-viewer/index.vue index 415e0c798..e9165e92a 100644 --- a/packages/effects/common-ui/src/components/json-viewer/index.vue +++ b/packages/effects/common-ui/src/components/json-viewer/index.vue @@ -12,7 +12,7 @@ import type { import { computed, useAttrs } from 'vue'; // @ts-expect-error - vue-json-viewer does not expose compatible typings for this import path -import VueJsonViewer from 'vue-json-viewer'; +import VueJsonViewerRaw from 'vue-json-viewer'; import { $t } from '@vben/locales'; @@ -42,6 +42,11 @@ const emit = defineEmits<{ valueClick: [value: JsonViewerValue]; }>(); +// vue-json-viewer@3.0.4 是 webpack4 UMD 老包, Vite/esbuild 预构建后 default 导出是 +// { default: Component, __esModule: true } 命名空间对象, 真组件挂在 .default 上 +// 直接渲染整个命名空间对象会触发 "Component is missing template or render function" +const VueJsonViewer = (VueJsonViewerRaw as any).default || VueJsonViewerRaw; + const attrs: SetupContext['attrs'] = useAttrs(); function handleClick(event: MouseEvent) { @@ -66,14 +71,35 @@ function handleClick(event: MouseEvent) { emit('click', event); } +/** + * 递归将对象转换为带 Object.prototype 原型的普通对象 {} + * 修复: json-bigint 解析返回 Object.create(null) 对象 (无原型链), + * 与 vue-json-viewer 内部 this.ordered.hasOwnProperty(o) 直接调用冲突, + * 报 "obj.hasOwnProperty is not a function" + */ +function deepToPlain(value: T): T { + if (value === null || typeof value !== 'object') { + return value; + } + if (Array.isArray(value)) { + return value.map((item) => deepToPlain(item)) as unknown as T; + } + const plain: Record = {}; + for (const key of Object.keys(value)) { + plain[key] = deepToPlain((value as Record)[key]); + } + return plain as unknown as T; +} + // 支持显示 bigint 数据,如较长的订单号 const jsonData = computed>(() => { if (typeof props.value !== 'string') { - return props.value || {}; + return props.value ? deepToPlain(props.value) : {}; } try { - return JsonBigint({ storeAsString: true }).parse(props.value); + const parsed = JsonBigint({ storeAsString: true }).parse(props.value); + return deepToPlain(parsed); } catch (error) { console.error('JSON parse error:', error); return {};