|
@@ -2,71 +2,35 @@
|
|
|
<el-collapse v-model="activeCollapse" class="tools-collapse">
|
|
|
<el-collapse-item :name="collapseKey" class="tools-collapse-item">
|
|
|
<template #title>
|
|
|
- <div class="collapse-header" :class="getRequestTypeClass()">
|
|
|
- <div class="header-left">
|
|
|
- <el-icon class="request-icon">
|
|
|
- <component :is="getRequestIcon()" />
|
|
|
- </el-icon>
|
|
|
- <span class="request-type">{{ toolData.requestType }}</span>
|
|
|
- <el-divider direction="vertical" />
|
|
|
- <span class="tool-name">{{ toolData.toolName || '未知工具' }}</span>
|
|
|
- </div>
|
|
|
- <div class="header-right">
|
|
|
- <el-icon :class="{ 'is-loading': isLoading }">
|
|
|
- <Loading v-if="isLoading" />
|
|
|
- <Check v-else />
|
|
|
- </el-icon>
|
|
|
- </div>
|
|
|
+ <div class="collapse-header">
|
|
|
+ <el-tag :type="getRequestTagType()" size="small" class="type-tag">
|
|
|
+ {{ toolData.requestType }}
|
|
|
+ </el-tag>
|
|
|
+ <span class="tool-name">{{ toolData.toolName || '未知工具' }}</span>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<div class="collapse-content">
|
|
|
- <div class="content-section">
|
|
|
- <h4 class="section-title">调用详情</h4>
|
|
|
- <el-descriptions :column="1" border size="small">
|
|
|
- <el-descriptions-item label="请求类型">
|
|
|
- <el-tag :type="getRequestTagType()" size="small">
|
|
|
- {{ toolData.requestType }}
|
|
|
- </el-tag>
|
|
|
- </el-descriptions-item>
|
|
|
- <el-descriptions-item label="工具名称">
|
|
|
- {{ toolData.toolName || '未知工具' }}
|
|
|
- </el-descriptions-item>
|
|
|
- <el-descriptions-item label="执行状态">
|
|
|
- <el-tag :type="getStatusType()" size="small">
|
|
|
- {{ getStatusText() }}
|
|
|
- </el-tag>
|
|
|
- </el-descriptions-item>
|
|
|
- </el-descriptions>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="content-section">
|
|
|
- <h4 class="section-title">{{ getDataSectionTitle() }}</h4>
|
|
|
- <div v-if="toolData.data">
|
|
|
- <pre class="json-content">{{ formatData(toolData.data) }}</pre>
|
|
|
- </div>
|
|
|
- <div v-else-if="isLoading">
|
|
|
- <el-skeleton :rows="3" animated />
|
|
|
- </div>
|
|
|
- <el-empty v-else :description="getEmptyDescription()" />
|
|
|
+ <div v-if="toolData.data">
|
|
|
+ <pre class="json-content">{{ formatData(toolData.data) }}</pre>
|
|
|
</div>
|
|
|
+ <el-empty v-else description="暂无数据" />
|
|
|
</div>
|
|
|
</el-collapse-item>
|
|
|
</el-collapse>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
-import { ref, computed, onMounted } from 'vue'
|
|
|
-import { Loading, Check, ArrowRight, ArrowLeft, Tools } from '@element-plus/icons-vue'
|
|
|
+import { ref, onMounted } from 'vue'
|
|
|
|
|
|
type Props = {
|
|
|
data: string
|
|
|
}
|
|
|
|
|
|
interface ToolData {
|
|
|
- requestType: string // request/response
|
|
|
- toolName: string // 工具名
|
|
|
- data: string // 参数或返回结果
|
|
|
+ requestType: string // request/response
|
|
|
+ toolName: string // 工具名
|
|
|
+ data: string // 参数或返回结果
|
|
|
}
|
|
|
|
|
|
const props = defineProps<Props>()
|
|
@@ -79,10 +43,7 @@ const toolData = ref<ToolData>({
|
|
|
data: ''
|
|
|
})
|
|
|
|
|
|
-// 计算是否为加载状态(request类型且无数据表示正在加载)
|
|
|
-const isLoading = computed(() => {
|
|
|
- return toolData.value.requestType.toLowerCase() === 'request' && !toolData.value.data
|
|
|
-})
|
|
|
+
|
|
|
|
|
|
// 解析传入的数据
|
|
|
onMounted(() => {
|
|
@@ -100,7 +61,7 @@ onMounted(() => {
|
|
|
toolData.value = {
|
|
|
requestType: 'error',
|
|
|
toolName: '数据格式错误',
|
|
|
- data: '应为3行格式:request/response、工具名、参数/结果'
|
|
|
+ data: '应为2-3行格式:request/response、工具名、参数/结果'
|
|
|
}
|
|
|
}
|
|
|
} catch (e) {
|
|
@@ -113,27 +74,6 @@ onMounted(() => {
|
|
|
}
|
|
|
})
|
|
|
|
|
|
-// 获取请求类型对应的图标
|
|
|
-const getRequestIcon = () => {
|
|
|
- const type = toolData.value.requestType.toLowerCase()
|
|
|
- switch (type) {
|
|
|
- case 'request':
|
|
|
- return ArrowRight
|
|
|
- case 'response':
|
|
|
- return ArrowLeft
|
|
|
- case 'error':
|
|
|
- return Tools
|
|
|
- default:
|
|
|
- return Tools
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 获取请求类型对应的CSS类
|
|
|
-const getRequestTypeClass = () => {
|
|
|
- const type = toolData.value.requestType.toLowerCase()
|
|
|
- return `request-type-${type}`
|
|
|
-}
|
|
|
-
|
|
|
// 获取请求类型标签类型
|
|
|
const getRequestTagType = () => {
|
|
|
const type = toolData.value.requestType.toLowerCase()
|
|
@@ -149,58 +89,7 @@ const getRequestTagType = () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// 获取状态类型
|
|
|
-const getStatusType = () => {
|
|
|
- if (isLoading.value) return 'warning'
|
|
|
- const type = toolData.value.requestType.toLowerCase()
|
|
|
- return type === 'error' ? 'danger' : 'success'
|
|
|
-}
|
|
|
|
|
|
-// 获取状态文本
|
|
|
-const getStatusText = () => {
|
|
|
- if (isLoading.value) return '执行中'
|
|
|
- const type = toolData.value.requestType.toLowerCase()
|
|
|
- switch (type) {
|
|
|
- case 'request':
|
|
|
- return '请求发送'
|
|
|
- case 'response':
|
|
|
- return '响应接收'
|
|
|
- case 'error':
|
|
|
- return '执行错误'
|
|
|
- default:
|
|
|
- return '执行完成'
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 获取数据区域标题
|
|
|
-const getDataSectionTitle = () => {
|
|
|
- const type = toolData.value.requestType.toLowerCase()
|
|
|
- switch (type) {
|
|
|
- case 'request':
|
|
|
- return '请求参数'
|
|
|
- case 'response':
|
|
|
- return '响应结果'
|
|
|
- case 'error':
|
|
|
- return '错误信息'
|
|
|
- default:
|
|
|
- return '数据内容'
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 获取空数据描述
|
|
|
-const getEmptyDescription = () => {
|
|
|
- const type = toolData.value.requestType.toLowerCase()
|
|
|
- switch (type) {
|
|
|
- case 'request':
|
|
|
- return '无请求参数'
|
|
|
- case 'response':
|
|
|
- return '暂无响应结果'
|
|
|
- case 'error':
|
|
|
- return '无错误详情'
|
|
|
- default:
|
|
|
- return '无数据'
|
|
|
- }
|
|
|
-}
|
|
|
|
|
|
// 格式化数据显示
|
|
|
const formatData = (data: string) => {
|
|
@@ -220,6 +109,7 @@ const formatData = (data: string) => {
|
|
|
border: 1px solid var(--el-border-color-light);
|
|
|
border-radius: 6px;
|
|
|
overflow: hidden;
|
|
|
+ margin: 8px 0;
|
|
|
}
|
|
|
|
|
|
.tools-collapse-item {
|
|
@@ -230,6 +120,9 @@ const formatData = (data: string) => {
|
|
|
padding: 0;
|
|
|
border: none;
|
|
|
background: transparent;
|
|
|
+ height: auto;
|
|
|
+ min-height: 16px;
|
|
|
+ position: relative;
|
|
|
}
|
|
|
|
|
|
.tools-collapse-item :deep(.el-collapse-item__content) {
|
|
@@ -237,134 +130,61 @@ const formatData = (data: string) => {
|
|
|
border: none;
|
|
|
}
|
|
|
|
|
|
-.collapse-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- padding: 12px 16px;
|
|
|
- width: 100%;
|
|
|
- transition: all 0.3s ease;
|
|
|
-}
|
|
|
-
|
|
|
-.collapse-header:hover {
|
|
|
- background-color: var(--el-fill-color-light);
|
|
|
+/* 调整展开箭头位置 */
|
|
|
+:deep(.el-collapse-item__arrow) {
|
|
|
+ margin-top: 8px;
|
|
|
+ margin-bottom: 8px;
|
|
|
}
|
|
|
|
|
|
-.header-left {
|
|
|
+.collapse-header {
|
|
|
+ padding: 2px 8px;
|
|
|
+ width: 100%;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
gap: 8px;
|
|
|
- flex: 1;
|
|
|
+ line-height: 1;
|
|
|
}
|
|
|
|
|
|
-.header-right {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
-}
|
|
|
-
|
|
|
-.request-icon {
|
|
|
- font-size: 16px;
|
|
|
- transition: all 0.3s ease;
|
|
|
-}
|
|
|
-
|
|
|
-.request-type {
|
|
|
- font-weight: 600;
|
|
|
- font-size: 14px;
|
|
|
- text-transform: uppercase;
|
|
|
- letter-spacing: 0.5px;
|
|
|
+.type-tag {
|
|
|
+ font-size: 10px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ padding: 1px 4px;
|
|
|
+ line-height: 1;
|
|
|
+ height: auto;
|
|
|
}
|
|
|
|
|
|
.tool-name {
|
|
|
+ font-size: 12px;
|
|
|
font-weight: 500;
|
|
|
color: var(--el-text-color-primary);
|
|
|
-}
|
|
|
-
|
|
|
-/* 不同请求类型的样式 */
|
|
|
-.request-type-request {
|
|
|
- border-left: 4px solid var(--el-color-primary);
|
|
|
-}
|
|
|
-
|
|
|
-.request-type-request .request-icon {
|
|
|
- color: var(--el-color-primary);
|
|
|
-}
|
|
|
-
|
|
|
-.request-type-request .request-type {
|
|
|
- color: var(--el-color-primary);
|
|
|
-}
|
|
|
-
|
|
|
-.request-type-response .request-icon {
|
|
|
- color: var(--el-color-success);
|
|
|
-}
|
|
|
-
|
|
|
-.request-type-response .request-type {
|
|
|
- color: var(--el-color-success);
|
|
|
-}
|
|
|
-
|
|
|
-.request-type-error {
|
|
|
- border-left: 4px solid var(--el-color-danger);
|
|
|
-}
|
|
|
-
|
|
|
-.request-type-error .request-icon {
|
|
|
- color: var(--el-color-danger);
|
|
|
-}
|
|
|
-
|
|
|
-.request-type-error .request-type {
|
|
|
- color: var(--el-color-danger);
|
|
|
-}
|
|
|
-
|
|
|
-.el-icon {
|
|
|
- transition: all 0.3s ease;
|
|
|
-}
|
|
|
-
|
|
|
-.is-loading {
|
|
|
- color: var(--el-color-warning);
|
|
|
- animation: rotating 2s linear infinite;
|
|
|
-}
|
|
|
-
|
|
|
-@keyframes rotating {
|
|
|
- 0% {
|
|
|
- transform: rotate(0deg);
|
|
|
- }
|
|
|
- 100% {
|
|
|
- transform: rotate(360deg);
|
|
|
- }
|
|
|
+ word-break: break-all;
|
|
|
+ flex: 1;
|
|
|
+ line-height: 1;
|
|
|
+ padding: 0;
|
|
|
+ margin: 0;
|
|
|
}
|
|
|
|
|
|
.collapse-content {
|
|
|
- padding: 16px;
|
|
|
- background-color: var(--el-fill-color-blank);
|
|
|
+ padding: 4px 8px 4px 8px;
|
|
|
border-top: 1px solid var(--el-border-color-lighter);
|
|
|
}
|
|
|
|
|
|
-.content-section {
|
|
|
- margin-bottom: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.content-section:last-child {
|
|
|
- margin-bottom: 0;
|
|
|
-}
|
|
|
-
|
|
|
-.section-title {
|
|
|
- margin: 0 0 12px 0;
|
|
|
- font-size: 14px;
|
|
|
- font-weight: 600;
|
|
|
- color: var(--el-text-color-primary);
|
|
|
-}
|
|
|
-
|
|
|
.json-content {
|
|
|
background-color: var(--el-fill-color-light);
|
|
|
border: 1px solid var(--el-border-color-light);
|
|
|
- border-radius: 6px;
|
|
|
- padding: 16px;
|
|
|
+ border-radius: 3px;
|
|
|
+ padding: 4px 6px;
|
|
|
margin: 0;
|
|
|
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
|
- font-size: 13px;
|
|
|
- line-height: 1.5;
|
|
|
+ font-size: 11px;
|
|
|
+ line-height: 1.2;
|
|
|
color: var(--el-text-color-primary);
|
|
|
white-space: pre-wrap;
|
|
|
word-break: break-all;
|
|
|
overflow-x: auto;
|
|
|
- max-height: 300px;
|
|
|
+ max-height: 120px;
|
|
|
overflow-y: auto;
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
</style>
|