409 lines
12 KiB
Vue
409 lines
12 KiB
Vue
<template>
|
||
<div class="api-does-container">
|
||
<div class="top">
|
||
<h5>{{ selectApi.summary }}</h5>
|
||
<div class="input">
|
||
<InputCard :value="selectApi.method" />
|
||
<j-input :value="selectApi?.url" disabled />
|
||
</div>
|
||
</div>
|
||
|
||
<p>
|
||
<span class="label">请求数据类型</span>
|
||
<span>{{
|
||
getContent(selectApi.requestBody) ||
|
||
'application/x-www-form-urlencoded'
|
||
}}</span>
|
||
<span class="label">响应数据类型</span>
|
||
<span>{{ `["/"]` }}</span>
|
||
</p>
|
||
|
||
<div class="api-card" v-if="props.selectApi.description">
|
||
<h5>接口描述</h5>
|
||
<div>{{ props.selectApi.description }}</div>
|
||
</div>
|
||
<div class="api-card" v-if="requestCard.codeText">
|
||
<h5>请求示例</h5>
|
||
<JsonViewer :value="requestCard.codeText" copyable />
|
||
</div>
|
||
<div class="api-card">
|
||
<h5>请求参数</h5>
|
||
<div class="content">
|
||
<j-pro-table
|
||
:columns="requestCard.columns"
|
||
:dataSource="requestCard.tableData"
|
||
noPagination
|
||
model="TABLE"
|
||
size="small"
|
||
>
|
||
<template #required="slotProps">
|
||
<span>{{ Boolean(slotProps.required) + '' }}</span>
|
||
</template>
|
||
<template #type="slotProps">
|
||
<span>{{ slotProps?.schema.type }}</span>
|
||
</template>
|
||
</j-pro-table>
|
||
</div>
|
||
</div>
|
||
<div class="api-card">
|
||
<h5>响应状态</h5>
|
||
<div class="content">
|
||
<j-pro-table
|
||
:columns="responseStatusCard.columns"
|
||
:dataSource="responseStatusCard.tableData"
|
||
noPagination
|
||
model="TABLE"
|
||
size="small"
|
||
>
|
||
</j-pro-table>
|
||
|
||
<j-tabs v-model:activeKey="responseStatusCard.activeKey">
|
||
<j-tab-pane
|
||
:key="key"
|
||
:tab="key"
|
||
v-for="key in tabs"
|
||
></j-tab-pane>
|
||
</j-tabs>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-card">
|
||
<h5>响应参数</h5>
|
||
<div class="content">
|
||
<j-pro-table
|
||
:columns="respParamsCard.columns"
|
||
:dataSource="respParamsCard.tableData"
|
||
noPagination
|
||
model="TABLE"
|
||
size="small"
|
||
>
|
||
</j-pro-table>
|
||
</div>
|
||
|
||
<JsonViewer :value="respParamsCard.codeText" copyable />
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { JsonViewer } from 'vue3-json-viewer';
|
||
import 'vue3-json-viewer/dist/index.css';
|
||
import type { apiDetailsType } from '../typing';
|
||
import InputCard from './InputCard.vue';
|
||
import { PropType } from 'vue';
|
||
|
||
const props = defineProps({
|
||
selectApi: {
|
||
type: Object as PropType<apiDetailsType>,
|
||
required: true,
|
||
},
|
||
schemas: {
|
||
type: Object,
|
||
required: true,
|
||
},
|
||
});
|
||
const { selectApi } = toRefs(props);
|
||
|
||
type tableCardType = {
|
||
columns: object[];
|
||
tableData: any[];
|
||
codeText?: any;
|
||
activeKey?: any;
|
||
getData?: any;
|
||
};
|
||
const requestCard = reactive<tableCardType>({
|
||
columns: [
|
||
{
|
||
title: '参数名',
|
||
dataIndex: 'name',
|
||
key: 'name',
|
||
},
|
||
{
|
||
title: '参数说明',
|
||
dataIndex: 'description',
|
||
key: 'description',
|
||
},
|
||
{
|
||
title: '请求类型',
|
||
dataIndex: 'in',
|
||
key: 'in',
|
||
},
|
||
{
|
||
title: '是否必须',
|
||
dataIndex: 'required',
|
||
key: 'required',
|
||
scopedSlots: true,
|
||
},
|
||
{
|
||
title: '参数类型',
|
||
dataIndex: 'type',
|
||
key: 'type',
|
||
scopedSlots: true,
|
||
},
|
||
],
|
||
tableData: [],
|
||
codeText: undefined,
|
||
getData: () => {
|
||
if (!props.selectApi.requestBody)
|
||
return (requestCard.tableData = props.selectApi.parameters);
|
||
const schema =
|
||
props.selectApi.requestBody.content['application/json'].schema;
|
||
const _ref = schema.$ref || schema?.items?.$ref;
|
||
if(!_ref) return; // schema不是Java中的类的话则不进行解析,直接结束
|
||
const schemaName = _ref?.split('/').pop();
|
||
const type = schema.type || '';
|
||
const tableData = findData(schemaName);
|
||
if (type === 'array') {
|
||
requestCard.codeText = [getCodeText(tableData, 3)];
|
||
} else requestCard.codeText = getCodeText(tableData, 3);
|
||
// console.clear();
|
||
// console.log(schemaName, tableData);
|
||
|
||
requestCard.tableData = [
|
||
{
|
||
name: schemaName[0].toLowerCase() + schemaName.substring(1),
|
||
description: schemaName,
|
||
in: 'body',
|
||
required: true,
|
||
schema: { type: type || schemaName },
|
||
children: tableData.map((item) => ({
|
||
name: item.paramsName,
|
||
description: item.desc,
|
||
required: false,
|
||
schema: { type: item.paramsType },
|
||
})),
|
||
},
|
||
];
|
||
},
|
||
});
|
||
const responseStatusCard = reactive<tableCardType>({
|
||
activeKey: '',
|
||
columns: [
|
||
{
|
||
title: '状态码',
|
||
dataIndex: 'code',
|
||
key: 'code',
|
||
},
|
||
{
|
||
title: '说明',
|
||
dataIndex: 'desc',
|
||
key: 'desc',
|
||
},
|
||
{
|
||
title: 'schema',
|
||
dataIndex: 'schema',
|
||
key: 'schema',
|
||
},
|
||
],
|
||
tableData: [],
|
||
getData: () => {
|
||
if (!Object.keys(props.selectApi.responses).length)
|
||
return (responseStatusCard.tableData = []);
|
||
|
||
const tableData = <any>[];
|
||
Object.entries(props.selectApi.responses || {}).forEach((item: any) => {
|
||
const desc = item[1].description;
|
||
const schema = item[1].content['*/*'].schema.$ref?.split('/') || '';
|
||
|
||
tableData.push({
|
||
code: item[0],
|
||
desc,
|
||
schema: schema && schema.pop(),
|
||
});
|
||
});
|
||
responseStatusCard.activeKey = tableData[0]?.code;
|
||
responseStatusCard.tableData = tableData;
|
||
},
|
||
});
|
||
const tabs = computed(() =>
|
||
responseStatusCard.tableData
|
||
.map((item: any) => item.code + '')
|
||
.filter((code: string) => code !== '400'),
|
||
);
|
||
const respParamsCard = reactive<tableCardType>({
|
||
columns: [
|
||
{
|
||
title: '参数名称',
|
||
dataIndex: 'paramsName',
|
||
},
|
||
{
|
||
title: '参数说明',
|
||
dataIndex: 'desc',
|
||
},
|
||
{
|
||
title: '类型',
|
||
dataIndex: 'paramsType',
|
||
},
|
||
],
|
||
tableData: [],
|
||
codeText: '',
|
||
getData: (code: string) => {
|
||
const schemaName = responseStatusCard.tableData.find(
|
||
(item: any) => item.code === code,
|
||
)?.schema;
|
||
|
||
const tableData = findData(schemaName);
|
||
respParamsCard.codeText = getCodeText(tableData, 3);
|
||
|
||
respParamsCard.tableData = tableData;
|
||
},
|
||
});
|
||
|
||
const getContent = (data: any) => {
|
||
if (data && data.content) {
|
||
return Object.keys(data.content || {})[0];
|
||
}
|
||
return '';
|
||
};
|
||
onMounted(() => {
|
||
requestCard.getData();
|
||
responseStatusCard.getData();
|
||
});
|
||
watch(
|
||
() => props.selectApi,
|
||
() => {
|
||
requestCard.getData();
|
||
responseStatusCard.getData();
|
||
},
|
||
);
|
||
|
||
watch([() => responseStatusCard.activeKey, () => props.selectApi], (n) => {
|
||
n[0] && respParamsCard.getData(n[0]);
|
||
});
|
||
|
||
function findData(schemaName: string) {
|
||
const schemas = toRaw(props.schemas);
|
||
const basicType = ['string', 'integer', 'boolean'];
|
||
|
||
if (!schemaName || !schemas[schemaName]) {
|
||
return [];
|
||
}
|
||
const result: schemaObjType[] = [];
|
||
const schema = schemas[schemaName];
|
||
Object.entries(schema.properties).forEach((item: [string, any]) => {
|
||
const paramsType =
|
||
item[1].type ||
|
||
(item[1].$ref && item[1].$ref.split('/').pop()) ||
|
||
(item[1].items && item[1].items.$ref.split('/').pop()) ||
|
||
'';
|
||
const schemaObj: schemaObjType = {
|
||
paramsName: item[0],
|
||
paramsType,
|
||
desc: item[1].description || '',
|
||
};
|
||
if (!basicType.includes(paramsType))
|
||
schemaObj.children = findData(paramsType);
|
||
result.push(schemaObj);
|
||
});
|
||
|
||
return result;
|
||
}
|
||
function getCodeText(arr: schemaObjType[], level: number): object {
|
||
const result = {};
|
||
const schemas = toRaw(props.schemas);
|
||
arr.forEach((item) => {
|
||
switch (item.paramsType) {
|
||
case 'string':
|
||
result[item.paramsName] = '';
|
||
break;
|
||
case 'integer':
|
||
result[item.paramsName] = 0;
|
||
break;
|
||
case 'boolean':
|
||
result[item.paramsName] = true;
|
||
break;
|
||
case 'array':
|
||
result[item.paramsName] = [];
|
||
break;
|
||
case 'object':
|
||
result[item.paramsName] = '';
|
||
break;
|
||
default: {
|
||
const properties = schemas[item.paramsType]
|
||
.properties as object;
|
||
const newArr = Object.entries(properties).map(
|
||
(item: [string, any]) => ({
|
||
paramsName: item[0],
|
||
paramsType: level
|
||
? (item[1].$ref && item[1].$ref.split('/').pop()) ||
|
||
(item[1].items &&
|
||
item[1].items.$ref.split('/').pop()) ||
|
||
item[1].type ||
|
||
''
|
||
: item[1].type,
|
||
}),
|
||
);
|
||
result[item.paramsName] = getCodeText(newArr, level - 1);
|
||
}
|
||
}
|
||
});
|
||
|
||
return result;
|
||
}
|
||
|
||
type schemaObjType = {
|
||
paramsName: string;
|
||
paramsType: string;
|
||
desc?: string;
|
||
children?: schemaObjType[];
|
||
};
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.api-does-container {
|
||
.top {
|
||
width: 100%;
|
||
|
||
h5 {
|
||
font-weight: bold;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.input {
|
||
display: flex;
|
||
margin: 24px 0;
|
||
}
|
||
}
|
||
p {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
font-size: 14px;
|
||
|
||
.label {
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
.api-card {
|
||
margin-top: 24px;
|
||
h5 {
|
||
position: relative;
|
||
padding-left: 10px;
|
||
font-weight: 600;
|
||
font-size: 16px;
|
||
|
||
&::before {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 4px;
|
||
height: 100%;
|
||
background-color: #1d39c4;
|
||
border-radius: 0 3px 3px 0;
|
||
content: ' ';
|
||
}
|
||
}
|
||
.content {
|
||
padding-left: 10px;
|
||
|
||
:deep(.jtable-body) {
|
||
padding: 0;
|
||
|
||
.jtable-body-header {
|
||
display: none;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|