全局参数化加入请求参数中,参数支持多行编辑,展示值转换,细节优化
This commit is contained in:
32
zyplayer-doc-ui/swagger-ui/src/assets/utils/unitConvert.js
Normal file
32
zyplayer-doc-ui/swagger-ui/src/assets/utils/unitConvert.js
Normal file
@@ -0,0 +1,32 @@
|
||||
export default {
|
||||
formatSeconds(value) {
|
||||
let result = parseInt(value);
|
||||
let second = result / 1000;
|
||||
let s = Math.floor(second % 60);
|
||||
let ms = (result % 1000);
|
||||
if (s > 0) return `${s}.${ms} s`;
|
||||
return `${ms} ms`;
|
||||
},
|
||||
formatFileSize(fileSize) {
|
||||
if (!fileSize) {
|
||||
return '0 B';
|
||||
}
|
||||
let size = "";
|
||||
if (fileSize < 0.1 * 1024) {
|
||||
size = fileSize.toFixed(2) + " B"
|
||||
} else if (fileSize < 0.1 * 1024 * 1024) {
|
||||
size = (fileSize / 1024).toFixed(2) + " KB"
|
||||
} else if (fileSize < 0.1 * 1024 * 1024 * 1024) {
|
||||
size = (fileSize / (1024 * 1024)).toFixed(2) + " MB"
|
||||
} else {
|
||||
size = (fileSize / (1024 * 1024 * 1024)).toFixed(2) + " GB"
|
||||
}
|
||||
let sizeStr = size + "";
|
||||
let index = sizeStr.indexOf(".");
|
||||
let dou = sizeStr.substr(index + 1, 2);
|
||||
if (dou == "00") {
|
||||
return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2)
|
||||
}
|
||||
return size;
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<keep-alive>
|
||||
<component :is="Component" :key="route.fullPath" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'EmptyLayout',
|
||||
components: {},
|
||||
props: [],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
<script>
|
||||
import MenuChildrenLayout from './MenuChildrenLayout.vue'
|
||||
import {customApi} from '../../api'
|
||||
import {customApi, zyplayerApi} from '../../api'
|
||||
import {createTreeViewByTag, getTreeDataForTag} from '../../store/TreeViewByTag'
|
||||
|
||||
export default {
|
||||
@@ -81,6 +81,7 @@
|
||||
this.openKeys = [matched[1].path];
|
||||
}
|
||||
this.getSwaggerResourceList();
|
||||
this.getGlobalParamList();
|
||||
},
|
||||
methods: {
|
||||
docChecked(val, node) {
|
||||
@@ -89,6 +90,12 @@
|
||||
this.$router.push({path: '/doc/view', query: dataRef.query});
|
||||
}
|
||||
},
|
||||
getGlobalParamList() {
|
||||
zyplayerApi.docSwaggerGlobalParamList().then(res => {
|
||||
let globalParam = res.data || [];
|
||||
this.$store.commit('setGlobalParam', globalParam);
|
||||
});
|
||||
},
|
||||
getSwaggerResourceList() {
|
||||
customApi.get('./swagger-resources').then(res => {
|
||||
if (res instanceof Array) {
|
||||
|
||||
@@ -1,48 +1,61 @@
|
||||
<template>
|
||||
<a-table :row-selection="{ selectedRowKeys: queryParamSelectedRowKeys, onChange: queryParamRowSelectionChange }"
|
||||
:dataSource="queryParamList"
|
||||
:columns="queryParamListColumns" size="small"
|
||||
:pagination="false"
|
||||
:scroll="{ y: '300px' }">
|
||||
<template #bodyCell="{ column, text, record }">
|
||||
<template v-if="column.dataIndex === 'name'">
|
||||
<a-input placeholder="请输入参数名" v-model:value="record.name" @change="queryParamChange(record)"></a-input>
|
||||
<div v-if="multilineEdit">
|
||||
<div style="text-align: right;">
|
||||
<a-button @click="toKeyValueEdit" type="link">表单编辑</a-button>
|
||||
</div>
|
||||
<a-textarea v-model:value="multilineEditValue" :auto-size="{ minRows: 14, maxRows: 14 }"></a-textarea>
|
||||
</div>
|
||||
<div v-else>
|
||||
<a-table :row-selection="{ selectedRowKeys: queryParamSelectedRowKeys, onChange: queryParamRowSelectionChange }"
|
||||
:dataSource="paramListRef"
|
||||
:columns="paramListColumns" size="small"
|
||||
:pagination="false"
|
||||
:scroll="{ y: '300px' }">
|
||||
<template #headerCell="{ column }">
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<a-button @click="toMultilineEdit" type="link" style="margin-left: -50px;">多行编辑</a-button>
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'type'">
|
||||
<a-select v-if="record.key >= 10000" v-model:value="record.type">
|
||||
<a-select-option value="integer">Integer</a-select-option>
|
||||
<a-select-option value="string">String</a-select-option>
|
||||
<a-select-option value="file">File</a-select-option>
|
||||
</a-select>
|
||||
<a-tag color="pink" v-else-if="text === 'integer'">Integer</a-tag>
|
||||
<a-tag color="red" v-else-if="text === 'string'">String</a-tag>
|
||||
<a-tag color="green" v-else>{{text||'-'}}</a-tag>
|
||||
<template #bodyCell="{ column, text, record }">
|
||||
<template v-if="column.dataIndex === 'name'">
|
||||
<a-input placeholder="请输入参数名" v-model:value="record.name" @change="queryParamChange(record)"></a-input>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'type'">
|
||||
<a-select v-if="record.key >= 10000" v-model:value="record.type">
|
||||
<a-select-option value="integer">Integer</a-select-option>
|
||||
<a-select-option value="string">String</a-select-option>
|
||||
<a-select-option value="file">File</a-select-option>
|
||||
</a-select>
|
||||
<a-tag color="pink" v-else-if="text === 'integer'">Integer</a-tag>
|
||||
<a-tag color="red" v-else-if="text === 'string'">String</a-tag>
|
||||
<a-tag color="green" v-else>{{text||'-'}}</a-tag>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'value'">
|
||||
<a-select v-if="record.enum && record.type === 'array'" v-model:value="record.value" mode="multiple" :placeholder="record.description || '请选择'" style="width: 100%;">
|
||||
<a-select-option :value="enums" v-for="enums in record.enum">{{enums}}</a-select-option>
|
||||
</a-select>
|
||||
<a-select v-else-if="record.enum" v-model:value="record.value" :placeholder="record.description || '请选择'" style="width: 100%;">
|
||||
<a-select-option :value="enums" v-for="enums in record.enum">{{enums}}</a-select-option>
|
||||
</a-select>
|
||||
<a-upload v-else-if="record.type==='file' || record.subType === 'file' || record.subType === 'MultipartFile'"
|
||||
:file-list="record.value" name="file" :multiple="record.type === 'array'"
|
||||
:before-upload="file=>{return beforeUpload(file, record)}"
|
||||
:remove="file=>{return handleRemove(file, record)}"
|
||||
>
|
||||
<a-button><upload-outlined></upload-outlined>选择文件</a-button>
|
||||
</a-upload>
|
||||
<a-input v-else :placeholder="record.description || '请输入参数值'" v-model:value="record.value" @change="queryParamChange(record)"></a-input>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<CloseOutlined v-if="!record.isLastRow" @click="queryParamRemove(record)" style="cursor: pointer;"/>
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'value'">
|
||||
<a-select v-if="record.enum && record.type === 'array'" v-model:value="record.value" mode="multiple" :placeholder="record.description || '请选择'" style="width: 100%;">
|
||||
<a-select-option :value="enums" v-for="enums in record.enum">{{enums}}</a-select-option>
|
||||
</a-select>
|
||||
<a-select v-else-if="record.enum" v-model:value="record.value" :placeholder="record.description || '请选择'" style="width: 100%;">
|
||||
<a-select-option :value="enums" v-for="enums in record.enum">{{enums}}</a-select-option>
|
||||
</a-select>
|
||||
<a-upload v-else-if="record.type==='file' || record.subType === 'file' || record.subType === 'MultipartFile'"
|
||||
:file-list="record.value" name="file" :multiple="record.type === 'array'"
|
||||
:before-upload="file=>{return beforeUpload(file, record)}"
|
||||
:remove="file=>{return handleRemove(file, record)}"
|
||||
>
|
||||
<a-button><upload-outlined></upload-outlined>选择文件</a-button>
|
||||
</a-upload>
|
||||
<a-input v-else :placeholder="record.description || '请输入参数值'" v-model:value="record.value" @change="queryParamChange(record)"></a-input>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<CloseOutlined v-if="!record.isLastRow" @click="queryParamRemove(record)" style="cursor: pointer;"/>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {toRefs, ref, reactive, onMounted, watch} from 'vue';
|
||||
import {toRefs, toRef, ref, reactive, onMounted, watch} from 'vue';
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import {useStore} from 'vuex';
|
||||
import { message } from 'ant-design-vue';
|
||||
@@ -66,15 +79,15 @@
|
||||
},
|
||||
emits: ['update:selected'],
|
||||
setup(props, { attrs, slots, emit, expose }) {
|
||||
let queryParamList = ref(props.paramList);
|
||||
let paramListRef = ref(props.paramList);
|
||||
let nextIndex = 10000;
|
||||
// Query参数处理
|
||||
if (queryParamList.value.length <= 0 || !queryParamList.value[queryParamList.value.length - 1].isLastRow) {
|
||||
queryParamList.value.push({name: '', value: undefined, type: 'integer', key: ++nextIndex, isLastRow: true});
|
||||
if (paramListRef.value.length <= 0 || !paramListRef.value[paramListRef.value.length - 1].isLastRow) {
|
||||
props.paramList.push({name: '', value: undefined, type: 'integer', key: ++nextIndex, isLastRow: true});
|
||||
}
|
||||
let queryParamSelectedRowKeys = ref([]);
|
||||
queryParamList.value.forEach(item => {
|
||||
item.value = item.example || undefined;
|
||||
paramListRef.value.forEach(item => {
|
||||
item.value = item.value || item.example || undefined;
|
||||
if ((item.enum && item.type === 'array') || item.type === 'file' || item.subType === 'MultipartFile') {
|
||||
item.value = [];
|
||||
}
|
||||
@@ -86,22 +99,23 @@
|
||||
const queryParamChange = (record) => {
|
||||
if (record.isLastRow) {
|
||||
record.isLastRow = false;
|
||||
queryParamList.value.push({name: '', value: undefined, type: 'integer', key: ++nextIndex, isLastRow: true});
|
||||
props.paramList.push({name: '', value: undefined, type: 'integer', key: ++nextIndex, isLastRow: true});
|
||||
queryParamSelectedRowKeys.value.push(nextIndex);
|
||||
}
|
||||
};
|
||||
const queryParamRemove = (record) => {
|
||||
if (!record.isLastRow) {
|
||||
queryParamList.value = queryParamList.value.filter(item => item !== record);
|
||||
let index = props.paramList.findIndex(item => item === record);
|
||||
props.paramList.splice(index, 1);
|
||||
}
|
||||
};
|
||||
let queryParamListColumns = ref([]);
|
||||
queryParamListColumns.value.push({title: '参数名', dataIndex: 'name', width: 250});
|
||||
let paramListColumns = ref([]);
|
||||
paramListColumns.value.push({title: '参数名', dataIndex: 'name', width: 250});
|
||||
if (props.showType) {
|
||||
queryParamListColumns.value.push({title: '类型', dataIndex: 'type', width: 100});
|
||||
// paramListColumns.value.push({title: '类型', dataIndex: 'type', width: 100});
|
||||
}
|
||||
queryParamListColumns.value.push({title: '参数值', dataIndex: 'value'});
|
||||
queryParamListColumns.value.push({title: '', dataIndex: 'action', width: 40});
|
||||
paramListColumns.value.push({title: '参数值', dataIndex: 'value'});
|
||||
paramListColumns.value.push({title: '', dataIndex: 'action', width: 40});
|
||||
const beforeUpload = (file, record) => {
|
||||
if (record.type !== 'array') {
|
||||
record.value = [file];
|
||||
@@ -113,20 +127,71 @@
|
||||
const handleRemove = (file, record) => {
|
||||
record.value = record.value.filter(item => item !== file);
|
||||
};
|
||||
let multilineEdit = ref(false);
|
||||
let multilineEditValue = ref('');
|
||||
const toMultilineEdit = () => {
|
||||
multilineEdit.value = true;
|
||||
multilineEditValue.value = paramListRef.value.filter(item => item.name || item.value)
|
||||
.map(item => (item.name || '') + ':' + (item.value || ''))
|
||||
.join('\n');
|
||||
};
|
||||
const toKeyValueEdit = () => {
|
||||
convertKeyValueEdit();
|
||||
multilineEdit.value = false;
|
||||
};
|
||||
// 将多行转换为表格的方式录入
|
||||
const convertKeyValueEdit = () => {
|
||||
if (!multilineEdit.value) return;
|
||||
let paramMap = {};
|
||||
props.paramList.forEach(item => paramMap[item.name] = item);
|
||||
let lineDataArr = multilineEditValue.value.split('\n');
|
||||
let paramListTemp = [];
|
||||
lineDataArr.forEach(line => {
|
||||
if (!line) return;
|
||||
let index = line.indexOf(':');
|
||||
if (index >= 0) {
|
||||
let name = line.substring(0, index);
|
||||
let value = line.substring(index + 1);
|
||||
if (name || value) {
|
||||
let newLine = paramMap[name] || {name: name, value: value, type: 'integer', key: ++nextIndex};
|
||||
newLine.value = value;
|
||||
paramListTemp.push(newLine);
|
||||
}
|
||||
} else {
|
||||
let newLine = paramMap[line] || {name: line, value: undefined, type: 'integer', key: ++nextIndex};
|
||||
paramListTemp.push(newLine);
|
||||
}
|
||||
});
|
||||
paramListTemp.push({name: '', value: undefined, type: 'integer', key: ++nextIndex, isLastRow: true});
|
||||
queryParamSelectedRowKeys.value = [];
|
||||
// 修改父对象的值,ref引用的值也将一起改变
|
||||
props.paramList.splice(0, props.paramList.length);
|
||||
paramListTemp.forEach(item => {
|
||||
props.paramList.push(item);
|
||||
queryParamSelectedRowKeys.value.push(item.key);
|
||||
});
|
||||
};
|
||||
const getSelectedRowKeys = () => {
|
||||
convertKeyValueEdit();
|
||||
return queryParamSelectedRowKeys.value;
|
||||
};
|
||||
return {
|
||||
queryParamList,
|
||||
paramListRef,
|
||||
queryParamSelectedRowKeys,
|
||||
queryParamRowSelectionChange,
|
||||
queryParamChange,
|
||||
queryParamRemove,
|
||||
beforeUpload,
|
||||
handleRemove,
|
||||
queryParamListColumns,
|
||||
paramListColumns,
|
||||
// 父组件调用
|
||||
getSelectedRowKeys,
|
||||
// 多行编辑
|
||||
multilineEdit,
|
||||
multilineEditValue,
|
||||
toMultilineEdit,
|
||||
toKeyValueEdit,
|
||||
convertKeyValueEdit,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import PageLayout from './components/layouts/PageLayout.vue'
|
||||
import EmptyLayout from './components/layouts/EmptyLayout.vue'
|
||||
import EmptyKeepAliveLayout from './components/layouts/EmptyKeepAliveLayout.vue'
|
||||
|
||||
let routers = [
|
||||
{
|
||||
@@ -35,7 +35,7 @@ let routers = [
|
||||
meta: {
|
||||
icon: 'SettingOutlined'
|
||||
},
|
||||
component: EmptyLayout,
|
||||
component: EmptyKeepAliveLayout,
|
||||
children: [
|
||||
{
|
||||
path: '/doc/setting/globalParam',
|
||||
|
||||
@@ -12,12 +12,17 @@ export default createStore({
|
||||
methodStatistic: {},
|
||||
// 数据库存储的地址信息
|
||||
swaggerResource: {},
|
||||
// 全局参数
|
||||
globalParam: [],
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
setUserInfo(state, userInfo) {
|
||||
state.userInfo = userInfo;
|
||||
},
|
||||
setGlobalParam(state, globalParam) {
|
||||
state.globalParam = globalParam;
|
||||
},
|
||||
setSwaggerResource(state, swaggerResource) {
|
||||
state.swaggerResource = swaggerResource;
|
||||
},
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
zyplayerApi.docSwaggerGlobalParamList().then(res => {
|
||||
setTimeout(() => docListLoading.value = false, 500);
|
||||
docList.value = res.data || [];
|
||||
store.commit('setGlobalParam', docList.value);
|
||||
});
|
||||
};
|
||||
let docEdit = ref({});
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<a-radio value="row">row</a-radio>
|
||||
<a-radio value="binary">binary</a-radio>
|
||||
</a-radio-group>
|
||||
<a-select v-if="bodyParamType === 'row'" v-model:value="consumesParamType" size="small" style="margin-left: 10px;vertical-align: top;width: 90px;">
|
||||
<a-select v-if="bodyParamType === 'row'" v-model:value="consumesParamType" size="small" style="margin-left: 10px;vertical-align: top;width: 100px;">
|
||||
<a-select-option value="json">JSON</a-select-option>
|
||||
<a-select-option value="html">HTML</a-select-option>
|
||||
<a-select-option value="xml">XML</a-select-option>
|
||||
@@ -94,6 +94,7 @@
|
||||
setup(props) {
|
||||
const store = useStore();
|
||||
let swaggerResource = store.state.swaggerResource || {};
|
||||
let globalParam = store.state.globalParam || [];
|
||||
let swaggerDoc = store.state.swaggerDoc || {};
|
||||
let urlDomain = swaggerResource.rewriteDomain || swaggerDoc.host;
|
||||
let docUrl = ref(urlDomain + props.docInfoShow.url);
|
||||
@@ -104,15 +105,28 @@
|
||||
let urlParamList = ref([]);
|
||||
// Header参数处理
|
||||
const headerParamRef = ref();
|
||||
let headerParamListGlobal = globalParam.filter(item => item.paramType === 2);
|
||||
let headerParamListProp = props.requestParamList.filter(item => item.in === 'header');
|
||||
let nextIndex = 1;
|
||||
headerParamListGlobal.forEach(item => {
|
||||
headerParamListProp.push({name: item.paramKey, value: item.paramValue, type: 'string', key: 'g' + (nextIndex++)});
|
||||
});
|
||||
let headerParamList = ref(JSON.parse(JSON.stringify(headerParamListProp)));
|
||||
// cookie参数处理
|
||||
const cookieParamRef = ref();
|
||||
let cookieParamListGlobal = globalParam.filter(item => item.paramType === 3);
|
||||
let cookieParamListProp = props.requestParamList.filter(item => item.in === 'cookie');
|
||||
cookieParamListGlobal.forEach(item => {
|
||||
cookieParamListProp.push({name: item.paramKey, value: item.paramValue, type: 'string', key: 'g' + (nextIndex++)});
|
||||
});
|
||||
let cookieParamList = ref(JSON.parse(JSON.stringify(cookieParamListProp)));
|
||||
// form参数处理
|
||||
const formParamRef= ref();
|
||||
let formParamListGlobal = globalParam.filter(item => item.paramType === 1);
|
||||
let formParamListProp = props.requestParamList.filter(item => item.in === 'formData');
|
||||
formParamListGlobal.forEach(item => {
|
||||
formParamListProp.push({name: item.paramKey, value: item.paramValue, type: 'string', key: 'g' + (nextIndex++)});
|
||||
});
|
||||
let formParamList = ref([]);
|
||||
if (props.docInfoShow.method === 'post') {
|
||||
// post的时候参数否放到form里面
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<a-radio-button value="row">原始值</a-radio-button>
|
||||
<a-radio-button value="preview">预览</a-radio-button>
|
||||
</a-radio-group>
|
||||
<a-select v-if="bodyShowType === 'format'" v-model:value="bodyShowFormatType" size="small" style="margin-left: 10px;">
|
||||
<a-select v-if="bodyShowType === 'format'" v-model:value="bodyShowFormatType" size="small" style="margin-left: 10px;width: 100px;">
|
||||
<a-select-option value="json">JSON</a-select-option>
|
||||
<a-select-option value="html">HTML</a-select-option>
|
||||
<a-select-option value="xml">XML</a-select-option>
|
||||
@@ -40,7 +40,11 @@
|
||||
</a-table>
|
||||
</a-tab-pane>
|
||||
<template #rightExtra>
|
||||
<span class="status-info-box">状态码:<span>{{resultData.status||'200'}}</span>耗时:<span>{{resultData.useTime||0}} ms</span>大小:<span>{{resultData.bodyLength||0}} B</span></span>
|
||||
<span class="status-info-box">
|
||||
状态码:<span>{{resultData.status||'200'}}</span>
|
||||
耗时:<span>{{unitConvert.formatSeconds(resultData.useTime||0)}}</span>
|
||||
大小:<span>{{unitConvert.formatFileSize(resultData.bodyLength||0)}}</span>
|
||||
</span>
|
||||
</template>
|
||||
</a-tabs>
|
||||
</div>
|
||||
@@ -60,6 +64,7 @@
|
||||
import 'mavon-editor/dist/css/index.css'
|
||||
import {zyplayerApi} from "../../../api";
|
||||
import aceEditor from "../../../assets/ace-editor";
|
||||
import unitConvert from "../../../assets/utils/unitConvert.js";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
@@ -132,8 +137,9 @@
|
||||
resultDataContentFormat.value = props.result.data.data;
|
||||
}
|
||||
} else {
|
||||
resultDataContentOrigin.value = JSON.stringify(props.result.data);
|
||||
resultDataContentFormat.value = JSON.stringify(props.result.data, null, 4);
|
||||
let errorSuffix = '\n// 请求失败,以下为封装的返回值对象,仅供参考\n\n';
|
||||
resultDataContentOrigin.value = errorSuffix + JSON.stringify(props.result.data);
|
||||
resultDataContentFormat.value = errorSuffix + JSON.stringify(props.result.data, null, 4);
|
||||
}
|
||||
bodyShowTypeChange();
|
||||
}
|
||||
@@ -148,6 +154,7 @@
|
||||
activePage,
|
||||
bodyShowType,
|
||||
bodyShowTypeChange,
|
||||
unitConvert,
|
||||
bodyShowFormatType,
|
||||
bodyShowFormatPreview,
|
||||
previewHtmlRef,
|
||||
|
||||
Reference in New Issue
Block a user