- 推送/操作/开放接口日志列表各加"大小"列(payload_size/response_size,Utils.getFileSize 格式化)
- 详情弹窗:下载按钮常驻;Utils.canPreview(≤50KB) 才显示"在线预览",点击 fetch 复用各自 /Download/{id} 取原文渲染
- oapilog 详情从无条件内联改为同一套门槛逻辑
- utils 新增 PREVIEW_MAX_BYTES 与 canPreview
This commit is contained in:
@@ -67,6 +67,20 @@ export default class Utils {
|
||||
} else return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 在线预览大小上限(字节):日志大字段(请求体/响应)超过此值时隐藏"在线预览"、只保留"下载"。
|
||||
* 浏览器 JSON 美化 + <pre> 渲染在数百 KB 起会卡顿,50KB 为体验无损的保守阈值。
|
||||
*/
|
||||
public static readonly PREVIEW_MAX_BYTES = 50 * 1024;
|
||||
|
||||
/**
|
||||
* 是否允许在线预览:有内容(size > 0)且字节数不超过阈值。
|
||||
* size 为 null/undefined/0(未记录请求体、saveResponse=false、响应为空)→ 不可预览,仅下载。
|
||||
*/
|
||||
public static canPreview(size?: number | null): boolean {
|
||||
return size != null && size > 0 && size <= Utils.PREVIEW_MAX_BYTES;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定键
|
||||
*/
|
||||
|
||||
@@ -20,7 +20,13 @@
|
||||
<pre class="json-pre">{{ formatJson(row?.requestParams) }}</pre>
|
||||
</FormItem>
|
||||
<FormItem label="响应结果:">
|
||||
<pre class="json-pre">{{ formatJson(row?.responseData) }}</pre>
|
||||
<template v-if="row?.id">
|
||||
<a href="javascript:;" class="download-link" @click.prevent="handleDownload">下载</a>
|
||||
<a v-if="canPreview" href="javascript:;" class="download-link" style="margin-left: 12px"
|
||||
@click.prevent="handlePreview">在线预览</a>
|
||||
<span v-if="sizeText" class="sub-text">({{ sizeText }})</span>
|
||||
</template>
|
||||
<span v-else>-</span>
|
||||
</FormItem>
|
||||
<FormItem label="创建时间:">
|
||||
<span>{{ formatTime(row?.createTime) }}</span>
|
||||
@@ -31,10 +37,18 @@
|
||||
<Button type="primary" @click="show = false">确定</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
|
||||
<Modal v-model="previewVisible" title="响应结果预览" width="760" :mask-closable="true">
|
||||
<pre class="json-pre">{{ previewText }}</pre>
|
||||
<template #footer>
|
||||
<Button @click="previewVisible = false">关闭</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import useCurrentInstance from '@/utils/hook/useCurrentInstance';
|
||||
import Utils from '@/utils';
|
||||
|
||||
interface Props {
|
||||
@@ -81,6 +95,32 @@ function formatTime(val: any): string {
|
||||
if (!val) return '-';
|
||||
return Utils.dateFormat(val, 'yyyy-MM-dd HH:mm:ss');
|
||||
}
|
||||
|
||||
const { $conf } = useCurrentInstance();
|
||||
|
||||
const previewVisible = ref(false);
|
||||
const previewText = ref('');
|
||||
const canPreview = computed(() => Utils.canPreview(props.row?.responseSize));
|
||||
const sizeText = computed(() =>
|
||||
props.row?.responseSize != null && props.row.responseSize > 0 ? Utils.getFileSize(props.row.responseSize) : ''
|
||||
);
|
||||
|
||||
function handleDownload() {
|
||||
if (!props.row?.id) return;
|
||||
location.href = `${$conf.serviceHost}/api/oapilog/Download/${props.row.id}`;
|
||||
}
|
||||
|
||||
async function handlePreview() {
|
||||
if (!props.row?.id) return;
|
||||
previewText.value = '加载中…';
|
||||
previewVisible.value = true;
|
||||
try {
|
||||
const res = await fetch(`${$conf.serviceHost}/api/oapilog/Download/${props.row.id}`, { credentials: 'include' });
|
||||
previewText.value = formatJson(await res.text());
|
||||
} catch (e: any) {
|
||||
previewText.value = '预览加载失败:' + (e?.message || e);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -116,4 +156,32 @@ function formatTime(val: any): string {
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
.download-link {
|
||||
color: #577afb;
|
||||
|
||||
&:hover {
|
||||
color: #3d5afe;
|
||||
}
|
||||
}
|
||||
|
||||
.sub-text {
|
||||
margin-left: 8px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.json-pre {
|
||||
margin: 0;
|
||||
padding: 10px 12px;
|
||||
background: #f7f8fa;
|
||||
border: 1px solid #e8eaec;
|
||||
border-radius: 4px;
|
||||
max-height: 420px;
|
||||
overflow: auto;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -151,6 +151,13 @@ const columns = [
|
||||
align: 'right',
|
||||
render: (h: any, { row }: any) => h('span', row.costTime != null ? `${row.costTime} ms` : '-'),
|
||||
},
|
||||
{
|
||||
title: '响应',
|
||||
key: 'responseSize',
|
||||
width: 90,
|
||||
align: 'right',
|
||||
render: (h: any, { row }: any) => h('span', row.responseSize != null && row.responseSize > 0 ? Utils.getFileSize(row.responseSize) : '-'),
|
||||
},
|
||||
{
|
||||
title: '调用时间',
|
||||
key: 'createTime',
|
||||
|
||||
@@ -20,7 +20,12 @@
|
||||
<pre class="json-pre">{{ formatJson(row?.requestParams) }}</pre>
|
||||
</FormItem>
|
||||
<FormItem label="数据:">
|
||||
<a v-if="row?.id" href="javascript:;" class="download-link" @click.prevent="handleDownload">下载</a>
|
||||
<template v-if="row?.id">
|
||||
<a href="javascript:;" class="download-link" @click.prevent="handleDownload">下载</a>
|
||||
<a v-if="canPreview" href="javascript:;" class="download-link" style="margin-left: 12px"
|
||||
@click.prevent="handlePreview">在线预览</a>
|
||||
<span v-if="sizeText" class="sub-text">({{ sizeText }})</span>
|
||||
</template>
|
||||
<span v-else>-</span>
|
||||
</FormItem>
|
||||
<FormItem label="创建时间:">
|
||||
@@ -32,10 +37,17 @@
|
||||
<Button type="primary" @click="show = false">确定</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
|
||||
<Modal v-model="previewVisible" title="响应结果预览" width="760" :mask-closable="true">
|
||||
<pre class="json-pre">{{ previewText }}</pre>
|
||||
<template #footer>
|
||||
<Button @click="previewVisible = false">关闭</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import useCurrentInstance from '@/utils/hook/useCurrentInstance';
|
||||
import Utils from '@/utils';
|
||||
|
||||
@@ -83,6 +95,25 @@ function handleDownload() {
|
||||
if (!props.row?.id) return;
|
||||
location.href = `${$conf.serviceHost}/api/oplog/Download/${props.row.id}`;
|
||||
}
|
||||
|
||||
const previewVisible = ref(false);
|
||||
const previewText = ref('');
|
||||
const canPreview = computed(() => Utils.canPreview(props.row?.responseSize));
|
||||
const sizeText = computed(() =>
|
||||
props.row?.responseSize != null && props.row.responseSize > 0 ? Utils.getFileSize(props.row.responseSize) : ''
|
||||
);
|
||||
|
||||
async function handlePreview() {
|
||||
if (!props.row?.id) return;
|
||||
previewText.value = '加载中…';
|
||||
previewVisible.value = true;
|
||||
try {
|
||||
const res = await fetch(`${$conf.serviceHost}/api/oplog/Download/${props.row.id}`, { credentials: 'include' });
|
||||
previewText.value = formatJson(await res.text());
|
||||
} catch (e: any) {
|
||||
previewText.value = '预览加载失败:' + (e?.message || e);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -126,4 +157,18 @@ function handleDownload() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.json-pre {
|
||||
margin: 0;
|
||||
padding: 10px 12px;
|
||||
background: #f7f8fa;
|
||||
border: 1px solid #e8eaec;
|
||||
border-radius: 4px;
|
||||
max-height: 420px;
|
||||
overflow: auto;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -152,6 +152,13 @@ const columns = [
|
||||
align: 'right',
|
||||
render: (h: any, { row }: any) => h('span', row.costTime != null ? `${row.costTime} ms` : '-'),
|
||||
},
|
||||
{
|
||||
title: '响应',
|
||||
key: 'responseSize',
|
||||
width: 90,
|
||||
align: 'right',
|
||||
render: (h: any, { row }: any) => h('span', row.responseSize != null && row.responseSize > 0 ? Utils.getFileSize(row.responseSize) : '-'),
|
||||
},
|
||||
{
|
||||
title: '操作时间ed',
|
||||
key: 'createTime',
|
||||
|
||||
@@ -156,6 +156,13 @@ const columns = [
|
||||
align: 'right',
|
||||
render: (h: any, { row }: any) => h('span', row.costMs != null ? `${row.costMs}` : '-'),
|
||||
},
|
||||
{
|
||||
title: '请求体',
|
||||
key: 'payloadSize',
|
||||
width: 100,
|
||||
align: 'right',
|
||||
render: (h: any, { row }: any) => h('span', row.payloadSize != null && row.payloadSize > 0 ? Utils.getFileSize(row.payloadSize) : '-'),
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
|
||||
@@ -43,7 +43,12 @@
|
||||
<span>{{ formatTime(row?.createdAt) }}</span>
|
||||
</FormItem>
|
||||
<FormItem label="请求体:">
|
||||
<a v-if="row?.id" href="javascript:;" class="download-link" @click.prevent="handleDownload">下载请求体</a>
|
||||
<template v-if="row?.id">
|
||||
<a href="javascript:;" class="download-link" @click.prevent="handleDownload">下载请求体</a>
|
||||
<a v-if="canPreview" href="javascript:;" class="download-link" style="margin-left: 12px"
|
||||
@click.prevent="handlePreview">在线预览</a>
|
||||
<span v-if="sizeText" class="sub-text">({{ sizeText }})</span>
|
||||
</template>
|
||||
<span v-else>-</span>
|
||||
</FormItem>
|
||||
</Form>
|
||||
@@ -51,10 +56,17 @@
|
||||
<Button type="primary" @click="show = false">确定</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
|
||||
<Modal v-model="previewVisible" title="请求体预览" width="760" :mask-closable="true">
|
||||
<pre class="json-pre">{{ previewText }}</pre>
|
||||
<template #footer>
|
||||
<Button @click="previewVisible = false">关闭</Button>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import useCurrentInstance from '@/utils/hook/useCurrentInstance';
|
||||
import Utils from '@/utils';
|
||||
|
||||
@@ -87,11 +99,40 @@ function onVisibleChange(val: boolean) {
|
||||
|
||||
const { $conf } = useCurrentInstance();
|
||||
|
||||
const previewVisible = ref(false);
|
||||
const previewText = ref('');
|
||||
|
||||
const canPreview = computed(() => Utils.canPreview(props.row?.payloadSize));
|
||||
const sizeText = computed(() =>
|
||||
props.row?.payloadSize != null && props.row.payloadSize > 0 ? Utils.getFileSize(props.row.payloadSize) : ''
|
||||
);
|
||||
|
||||
function handleDownload() {
|
||||
if (!props.row?.id) return;
|
||||
location.href = `${$conf.serviceHost}/api/push/Download/${props.row.id}`;
|
||||
}
|
||||
|
||||
async function handlePreview() {
|
||||
if (!props.row?.id) return;
|
||||
previewText.value = '加载中…';
|
||||
previewVisible.value = true;
|
||||
try {
|
||||
const res = await fetch(`${$conf.serviceHost}/api/push/Download/${props.row.id}`, { credentials: 'include' });
|
||||
previewText.value = formatJson(await res.text());
|
||||
} catch (e: any) {
|
||||
previewText.value = '预览加载失败:' + (e?.message || e);
|
||||
}
|
||||
}
|
||||
|
||||
function formatJson(val: string): string {
|
||||
if (!val) return '-';
|
||||
try {
|
||||
return JSON.stringify(JSON.parse(val), null, 2);
|
||||
} catch {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
function formatTime(val: any): string {
|
||||
if (!val) return '-';
|
||||
return Utils.dateFormat(val, 'yyyy-MM-dd HH:mm:ss');
|
||||
@@ -135,4 +176,18 @@ function formatTime(val: any): string {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.json-pre {
|
||||
margin: 0;
|
||||
padding: 10px 12px;
|
||||
background: #f7f8fa;
|
||||
border: 1px solid #e8eaec;
|
||||
border-radius: 4px;
|
||||
max-height: 420px;
|
||||
overflow: auto;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user