diff --git a/src/dashboard-front/src/http/access-log.ts b/src/dashboard-front/src/http/access-log.ts
index 2d137f831..472a5385a 100644
--- a/src/dashboard-front/src/http/access-log.ts
+++ b/src/dashboard-front/src/http/access-log.ts
@@ -14,7 +14,7 @@ export const fetchApigwAccessLogList = (apigwId: number, params: ChartInterface,
* 获取流程日志chart
* @param apigwId 网关id
*/
-export const fetchApigwAccessLogChart = (apigwId: number, params: ChartInterface) => fetch.get(`${BK_DASHBOARD_URL}/gateways/${apigwId}/logs/timechart/?${json2Query(params)}`);
+export const fetchApigwAccessLogChart = (apigwId: number, params: ChartInterface, extraStr?: string) => fetch.get(`${BK_DASHBOARD_URL}/gateways/${apigwId}/logs/timechart/?${json2Query(params)}${extraStr}`);
/**
* 获取流程日志link
diff --git a/src/dashboard-front/src/http/online-test.ts b/src/dashboard-front/src/http/online-test.ts
index 3a5023727..25e544ba4 100644
--- a/src/dashboard-front/src/http/online-test.ts
+++ b/src/dashboard-front/src/http/online-test.ts
@@ -17,6 +17,14 @@ export const getReleaseResources = (apigwId: number, stageId: string) => fetch.g
*/
export const getStages = (apigwId: number, data: any) => fetch.get(`${BK_DASHBOARD_URL}/gateways/${apigwId}/stages/?${json2Query(data)}`);
+/**
+ * 获取环境下可用的资源列表接口(在线调试)
+ * @param apigwId 网关id
+ * @returns
+ */
+export const getResourcesOnline = (apigwId: number, stageId: number, data: any) => fetch.get(`${BK_DASHBOARD_URL}/gateways/${apigwId}/releases/stages/${stageId}/resources/?${json2Query(data)}`);
+
+
/**
* 在线调试发起请求
* @param apigwId 网关id
@@ -53,3 +61,10 @@ export const resourceSchema = (gatewayId: number, stageId: number, resourceId: n
* @returns
*/
export const getTestHistories = (apigwId: number, data: any) => fetch.get(`${BK_DASHBOARD_URL}/gateways/${apigwId}/tests/histories/?${json2Query(data)}`);
+
+/**
+ * 获取调用历史详情
+ * @param apigwId 网关id
+ * @returns
+ */
+export const getTestHistoriesDetails = (apigwId: number, id: number) => fetch.get(`${BK_DASHBOARD_URL}/gateways/${apigwId}/tests/histories/${id}/`);
diff --git a/src/dashboard-front/src/http/report.ts b/src/dashboard-front/src/http/report.ts
index d17f2f3df..1fd695fa0 100644
--- a/src/dashboard-front/src/http/report.ts
+++ b/src/dashboard-front/src/http/report.ts
@@ -26,7 +26,7 @@ export const getApigwResources = (apigwId: number, params: any) => fetch.get(`${
* @param apigwId 网关id
* @param data 导出参数
*/
-export const exportLogs = async (apigwId: number, data: any) => {
- const res = await fetch.get(`${BK_DASHBOARD_URL}/gateways/${apigwId}/logs/export/`, data, { responseType: 'blob' });
+export const exportLogs = async (apigwId: number, data: any, extraStr?: string) => {
+ const res = await fetch.get(`${BK_DASHBOARD_URL}/gateways/${apigwId}/logs/export/?${json2Query(data)}${extraStr}`, {}, { responseType: 'blob' });
return blobDownLoad(res);
};
diff --git a/src/dashboard-front/src/language/lang.ts b/src/dashboard-front/src/language/lang.ts
index 80d4298e7..ef632be81 100644
--- a/src/dashboard-front/src/language/lang.ts
+++ b/src/dashboard-front/src/language/lang.ts
@@ -1301,6 +1301,7 @@ const lang: ILANG = {
'发布人': ['Releaser'],
'发布资源': ['Release resource'],
'响应状态码': ['Response status code'],
+ '返回响应': ['Return response'],
'调用时间': ['Call time'],
'请求记录': ['Request record'],
'检索项:': ['Search terms:'],
diff --git a/src/dashboard-front/src/views/online-debug/components/edit-table.vue b/src/dashboard-front/src/views/online-debug/components/edit-table.vue
index 2ac8c7d23..ebc405e07 100644
--- a/src/dashboard-front/src/views/online-debug/components/edit-table.vue
+++ b/src/dashboard-front/src/views/online-debug/components/edit-table.vue
@@ -91,7 +91,7 @@
handleCellClick({ event, column, rowIndex: index })"
- v-if="!row?.isEdit">
+ v-if="!row?.editType">
handleCellClick({ event, column, rowIndex: index })">
@@ -109,6 +109,7 @@
:clearable="false"
:filterable="false"
v-model="row.type"
+ @toggle="(v) => handleTypeChange(index, v)"
@change="handleCellBlur(index)"
:ref="(el) => setInputRefs(el, `type-input-${index}-${column?.index}`)"
>
@@ -196,6 +197,7 @@ const getDefaultTbRow = () => {
type: 'string',
instructions: '',
isEdit: true,
+ editType: false,
};
};
@@ -203,15 +205,15 @@ const tableData = ref(props?.list?.length ? props.list : [getDefaultTbRow()
const typeList = ref([
{
- label: 'String',
+ label: 'string',
value: 'string',
},
{
- label: 'Number',
+ label: 'number',
value: 'number',
},
{
- label: 'Boolean',
+ label: 'boolean',
value: 'boolean',
},
]);
@@ -230,6 +232,10 @@ const handleCellClick = async ({ event, column, rowIndex }: any) => {
return;
};
tableData.value[rowIndex].isEdit = true;
+ if (field === 'type') {
+ tableData.value[rowIndex].editType = true;
+ }
+
nextTick(() => {
if (field === 'type') {
// formInputRef.value?.get(`${field}-input-${rowIndex}-${index}`)?.showPopover();
@@ -268,6 +274,10 @@ const handleCellBlur = async (index: number) => {
}
};
+const handleTypeChange = (index: number, v: boolean) => {
+ tableData.value[index].editType = v;
+};
+
const addRow = (index: number) => {
tableData.value?.splice(index + 1, 0, getDefaultTbRow());
};
@@ -365,6 +375,7 @@ watch(
v?.forEach((item: any) => {
list.push({
isEdit: false,
+ editType: false,
name: item.name,
value: item.schema?.default || '',
instructions: item.description,
diff --git a/src/dashboard-front/src/views/online-debug/components/payload-body.vue b/src/dashboard-front/src/views/online-debug/components/payload-body.vue
index b45be62a8..7b0a83766 100644
--- a/src/dashboard-front/src/views/online-debug/components/payload-body.vue
+++ b/src/dashboard-front/src/views/online-debug/components/payload-body.vue
@@ -179,29 +179,29 @@ defineExpose({
color: #FFFFFF;
background: #3A84FF;
position: relative;
- padding-left: 36px;
- &::before {
- position: absolute;
- content: ' ';
- width: 16px;
- height: 16px;
- border-radius: 50%;
- border: 1px solid #fff;
- top: 50%;
- transform: translateY(-50%);
- left: 12px;
- }
- &::after {
- position: absolute;
- content: ' ';
- width: 10px;
- height: 10px;
- border-radius: 50%;
- background: #FFFFFF;
- top: 50%;
- transform: translateY(-50%);
- left: 16px;
- }
+ // padding-left: 36px;
+ // &::before {
+ // position: absolute;
+ // content: ' ';
+ // width: 16px;
+ // height: 16px;
+ // border-radius: 50%;
+ // border: 1px solid #fff;
+ // top: 50%;
+ // transform: translateY(-50%);
+ // left: 12px;
+ // }
+ // &::after {
+ // position: absolute;
+ // content: ' ';
+ // width: 10px;
+ // height: 10px;
+ // border-radius: 50%;
+ // background: #FFFFFF;
+ // top: 50%;
+ // transform: translateY(-50%);
+ // left: 16px;
+ // }
}
}
}
diff --git a/src/dashboard-front/src/views/online-debug/components/payload-headers.vue b/src/dashboard-front/src/views/online-debug/components/payload-headers.vue
index 2cdfb49cd..296c1e665 100644
--- a/src/dashboard-front/src/views/online-debug/components/payload-headers.vue
+++ b/src/dashboard-front/src/views/online-debug/components/payload-headers.vue
@@ -7,7 +7,8 @@
@@ -78,8 +79,11 @@ defineExpose({
display: flex;
align-items: center;
.params-header-fold {
- margin-top: 2px;
margin-right: 8px;
+ transition: all .2s;
+ &.fold {
+ transform: rotate(-90deg);
+ }
}
}
}
diff --git a/src/dashboard-front/src/views/online-debug/components/payload-params.vue b/src/dashboard-front/src/views/online-debug/components/payload-params.vue
index d95962471..3bcc849fd 100644
--- a/src/dashboard-front/src/views/online-debug/components/payload-params.vue
+++ b/src/dashboard-front/src/views/online-debug/components/payload-params.vue
@@ -7,7 +7,8 @@
@@ -21,7 +22,8 @@
@@ -51,13 +53,17 @@ const props = defineProps({
type: Array,
default: [],
},
+ priorityPath: {
+ type: Array,
+ default: [],
+ },
});
const queryRef = ref();
const queryList = ref([]);
const pathRef = ref();
const pathList = ref([]);
-const activeIndex = ref([1, 2]);
+const activeIndex = ref([1]);
const validate = async () => {
const query = await queryRef.value?.validate();
@@ -77,16 +83,27 @@ const getData = () => {
};
watch(
- () => [props.queryPayload, props.pathPayload],
- ([v1, v2]) => {
+ () => [props.queryPayload, props.pathPayload, props.priorityPath],
+ ([v1, v2, v3]) => {
queryList.value = v1;
- pathList.value = v2;
+ pathList.value = v3?.length ? v3 : v2;
},
{
deep: true,
},
);
+watch(
+ () => pathList.value,
+ (v) => {
+ if (v?.length && v[0]?.name) {
+ activeIndex.value = [1, 2];
+ } else {
+ activeIndex.value = [1];
+ }
+ },
+);
+
defineExpose({
validate,
getData,
@@ -108,8 +125,11 @@ defineExpose({
display: flex;
align-items: center;
.params-header-fold {
- margin-top: 2px;
margin-right: 8px;
+ transition: all .2s;
+ &.fold {
+ transform: rotate(-90deg);
+ }
}
}
}
diff --git a/src/dashboard-front/src/views/online-debug/components/request-payload.vue b/src/dashboard-front/src/views/online-debug/components/request-payload.vue
index f605d2ce3..aa129a399 100644
--- a/src/dashboard-front/src/views/online-debug/components/request-payload.vue
+++ b/src/dashboard-front/src/views/online-debug/components/request-payload.vue
@@ -2,6 +2,7 @@
@@ -24,23 +26,27 @@
diff --git a/src/dashboard-front/src/views/online-debug/components/request-record.vue b/src/dashboard-front/src/views/online-debug/components/request-record.vue
index 11dd0ed28..753cda283 100644
--- a/src/dashboard-front/src/views/online-debug/components/request-record.vue
+++ b/src/dashboard-front/src/views/online-debug/components/request-record.vue
@@ -47,9 +47,9 @@
+ :class="['dot', String(data?.response?.data?.status_code)?.startsWith('2') ? 'success' : 'failure']">
- {{ data?.response?.status_code }}
+ {{ data?.response?.data?.status_code }}
@@ -60,16 +60,25 @@
-
+
+
@@ -84,7 +93,7 @@ import { ref, shallowRef, reactive, nextTick } from 'vue';
import { useI18n } from 'vue-i18n';
import { useAccessLog, useCommon } from '@/store';
import editorMonaco from '@/components/ag-editor.vue';
-import { getTestHistories } from '@/http';
+import { getTestHistories, getTestHistoriesDetails } from '@/http';
const { t } = useI18n();
const common = useCommon();
@@ -102,7 +111,7 @@ const shortcutSelectedIndex = shallowRef(-1);
const tableRef = ref(null);
const resourceEditorRef: any = ref>();
const tableList = ref([]);
-const editorText = ref('');
+const placeholderText = ref('');
const tableEmptyConf = reactive({
keyword: '',
isAbnormal: false,
@@ -150,12 +159,16 @@ const handleTimeClear = () => {
setSearchTimeRange();
};
-const handleRowClick = (e: Event, row: Record) => {
+const handleRowClick = async (e: Event, row: Record) => {
e.stopPropagation();
- row.isExpand = !row.isExpand;
- nextTick(() => {
- tableRef.value.setRowExpand(row, row.isExpand);
- });
+ if (!row.isExpand) {
+ await getDetails(row.id, row);
+ } else {
+ row.isExpand = !row.isExpand;
+ nextTick(() => {
+ tableRef.value.setRowExpand(row, row.isExpand);
+ });
+ }
};
const clear = () => {
@@ -179,9 +192,22 @@ const getList = async () => {
...filterData.value,
};
const res = await getTestHistories(common.apigwId, data);
+ res?.forEach((item: any) => {
+ item.editorText = '';
+ });
tableList.value = res;
};
+const getDetails = async (id: number, row: Record) => {
+ const res = await getTestHistoriesDetails(common.apigwId, id);
+
+ row.editorText = res?.response?.data?.curl;
+ row.isExpand = !row.isExpand;
+ nextTick(() => {
+ tableRef.value.setRowExpand(row, row.isExpand);
+ });
+};
+
defineExpose({
show,
});
@@ -207,7 +233,7 @@ defineExpose({
.history-data {
.details {
width: 100%;
- height: 400px;
+ height: 300px;
max-height: 600px;
padding: 12px 0;
background: #FFFFFF;
diff --git a/src/dashboard-front/src/views/online-debug/components/response-content.vue b/src/dashboard-front/src/views/online-debug/components/response-content.vue
index 944cec4c2..d893973cf 100644
--- a/src/dashboard-front/src/views/online-debug/components/response-content.vue
+++ b/src/dashboard-front/src/views/online-debug/components/response-content.vue
@@ -7,14 +7,20 @@
-
+
-
+
Status:
{{ data?.status_code || '--' }}
@@ -186,6 +192,16 @@ watch(
position: relative;
.response-type {
flex: 1;
+ cursor: pointer;
+ transition: all .2s;
+ &.fold-header {
+ display: flex;
+ align-items: center;
+ line-height: 52px;
+ .header-icon {
+ margin-top: 0px;
+ }
+ }
.header-icon {
margin-top: -18px;
margin-right: 8px;
@@ -198,6 +214,11 @@ watch(
.response-type-tab {
flex: 1;
}
+ .fold-title {
+ font-weight: 700;
+ font-size: 14px;
+ color: #313238;
+ }
}
.response-status {
position: absolute;
@@ -252,7 +273,7 @@ watch(
align-items: center;
font-size: 12px;
color: #63656E;
- padding: 4px 10px;
+ padding: 1px 10px;
cursor: pointer;
.apigateway-icon {
margin-right: 4px;
diff --git a/src/dashboard-front/src/views/online-debug/index.vue b/src/dashboard-front/src/views/online-debug/index.vue
index de796ea84..9fdf00bc7 100644
--- a/src/dashboard-front/src/views/online-debug/index.vue
+++ b/src/dashboard-front/src/views/online-debug/index.vue
@@ -100,8 +100,10 @@
{{ curResource?.method }}
{{ curResource?.path }}
-
{{ t('发送') }}
-
{{ t('查看文档') }}
+
+ {{ t('发送') }}
+
+
{{ t('查看文档') }}
@@ -218,8 +220,10 @@
{{ curResource?.method }}
{{ curResource?.path }}
- {{ t('发送') }}
- {{ t('查看文档') }}
+
+ {{ t('发送') }}
+
+ {{ t('查看文档') }}
@@ -234,7 +238,7 @@
>
-
+
@@ -282,7 +286,7 @@ import { useCommon } from '@/store';
import { Message } from 'bkui-vue';
import {
getStages,
- getApigwResourcesDocs,
+ getResourcesOnline,
getApiDetail,
resourceSchema,
postAPITest,
@@ -363,9 +367,11 @@ const payloadType = reactive({
rawPayload: {},
queryPayload: [],
pathPayload: [],
+ priorityPath: [],
headersPayload: [],
fromDataPayload: [],
});
+const tab = ref('Params');
// 编辑应用认证
const appAuthorization = reactive({
@@ -410,9 +416,8 @@ const getApigwReleaseResources = async () => {
const query = {
limit: 10000,
offset: 0,
- stage_name: getStageName.value,
};
- const res = await getApigwResourcesDocs(curApigw.value?.name, query);
+ const res = await getResourcesOnline(common.apigwId, stage.value, query);
const group: any = {};
const defaultItem: any = {
labelId: 'default',
@@ -524,6 +529,7 @@ const clearSchema = () => {
payloadType.rawPayload = {};
payloadType.queryPayload = [];
payloadType.pathPayload = [];
+ payloadType.priorityPath = [];
payloadType.headersPayload = [];
payloadType.fromDataPayload = [];
};
@@ -548,7 +554,34 @@ const getResourceParams = async () => {
payloadType.fromDataPayload?.push(item);
}
});
- console.log('schema: ', payloadType);
+ matchPath(curResource.value);
+};
+
+// path 参数
+const matchPath = (resource: any) => {
+ if (!resource) return;
+
+ const { path } = resource;
+ const pathArr: any[] = [];
+
+ if (path?.indexOf('{') !== -1) {
+ path.split('/').forEach((str: string) => {
+ if (str.indexOf('{') !== -1) {
+ const tempStr = str.split('{')[1];
+ pathArr.push({
+ name: tempStr.split('}')[0],
+ description: '',
+ in: 'path',
+ required: true,
+ schema: {
+ type: 'string',
+ },
+ });
+ }
+ });
+ }
+
+ payloadType.priorityPath = pathArr;
};
// 点击资源列表项
@@ -700,6 +733,7 @@ const formatPayload = () => {
const { headers } = payload;
const { path, query } = payload.params;
const { raw } = payload.body;
+ // formData: formDataList, urlencoded,
const data: any = {};
data.stage_id = stage.value;
@@ -738,12 +772,10 @@ const handleSend = async (e: Event) => {
if (!isValidate) return;
const data = formatPayload();
if (!data) return;
- console.log('....data...', data);
try {
isLoading.value = true;
const res = await postAPITest(common.apigwId, data);
- console.log('res: ', res);
response.value = res;
} catch (e) {
console.log(e);
@@ -800,11 +832,28 @@ watch(
}
},
);
+
+watch(
+ () => curResource.value,
+ (resource) => {
+ if (['POST', 'PUT'].includes(resource?.method)) {
+ tab.value = 'Body';
+ } else {
+ tab.value = 'Params';
+ }
+ },
+);
diff --git a/src/dashboard-front/src/views/operate-data/access-log/index.vue b/src/dashboard-front/src/views/operate-data/access-log/index.vue
index 99964d55a..986a37129 100644
--- a/src/dashboard-front/src/views/operate-data/access-log/index.vue
+++ b/src/dashboard-front/src/views/operate-data/access-log/index.vue
@@ -505,12 +505,10 @@ const getApigwStages = async () => {
}
};
-const getApigwAccessLogList = async () => {
- const params = {
+const getPayload = () => {
+ const params: any = {
...searchParams.value,
query: keyword.value,
- offset: (pagination.value.current - 1) * pagination.value.limit,
- limit: pagination.value.limit,
};
let includeStr = '';
@@ -521,16 +519,26 @@ const getApigwAccessLogList = async () => {
excludeObj.value?.forEach((item: string) => {
excludeStr += `&exclude=${item}`;
});
- return await fetchApigwAccessLogList(apigwId.value, params, includeStr + excludeStr);
+
+ return {
+ params,
+ path: includeStr + excludeStr,
+ };
+};
+
+const getApigwAccessLogList = async () => {
+ const { params, path } = getPayload();
+ params.offset = (pagination.value.current - 1) * pagination.value.limit;
+ params.limit = pagination.value.limit;
+
+ return await fetchApigwAccessLogList(apigwId.value, params, path);
};
const getApigwAccessLogChart = async () => {
- const params = {
- ...searchParams.value,
- query: keyword.value,
- no_page: true,
- };
- return await fetchApigwAccessLogChart(apigwId.value, params);
+ const { params, path } = getPayload();
+ params.no_page = true;
+
+ return await fetchApigwAccessLogChart(apigwId.value, params, path);
};
const getSearchData = async () => {
@@ -635,13 +643,11 @@ const handleClearSearch = () => {
const handleDownload = async (e: Event) => {
e.stopPropagation();
try {
- const exportParams = {
- ...searchParams.value,
- query: keyword.value,
- offset: (pagination.value.current - 1) * pagination.value.limit,
- limit: 10000,
- };
- const res = await exportLogs(apigwId.value, exportParams);
+ const { params, path } = getPayload();
+ params.offset = (pagination.value.current - 1) * pagination.value.limit;
+ params.limit = 10000;
+
+ const res = await exportLogs(apigwId.value, params, path);
if (res.success) {
Message({
message: t('导出成功'),