diff --git a/.gitignore b/.gitignore index 8e51bc962..347e61ec9 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,4 @@ pnpm-debug.log* output.js webpack.confi.production.js -build/deploy.sh \ No newline at end of file +build/deploy.sh diff --git a/apps/daas/src/i18n/langs/en.js b/apps/daas/src/i18n/langs/en.js index 21d7ddb00..e9b387fd9 100644 --- a/apps/daas/src/i18n/langs/en.js +++ b/apps/daas/src/i18n/langs/en.js @@ -405,6 +405,8 @@ export default { apiaudit_visitor: 'Client Name', apiaudit_ip: 'Visitor IP', apiaudit_interview_time: 'Access Time', + apiaudit_interview_time_req: 'Request Time', + apiaudit_interview_time_db: 'Database Time', apiaudit_interview_time_start: 'Access start time', apiaudit_interview_time_end: 'Access end time', apiaudit_visit_result: 'Result', @@ -412,11 +414,13 @@ export default { apiaudit_log_info: 'Log details', apiaudit_parameter: 'parameter', apiaudit_link: 'Link', + apiaudit_access_records_byte: 'Response Size', apiaudit_access_records: 'Return the number of rows', apiaudit_total_records: 'Match rows', - apiaudit_average_access_rate: 'API access rate', - apiaudit_access_time: 'Request access time', - apiaudit_average_response_time: 'Database response time', + apiaudit_average_access_db_rate: 'Database Response Rate', + apiaudit_average_access_time: 'API Response Time', + apiaudit_access_time: 'Total Request Time', + apiaudit_average_response_time: 'Database Time Consumption', apiaudit_success: 'success', apiaudit_placeholder: 'Please enter name/ID', apiaudit_client_name_placeholder: 'Please enter client name', @@ -429,6 +433,11 @@ export default { connection_reload_schema_confirm_msg: 'If there are too many schemas in this library, it may take a long time. Make sure to refresh the schema of the data source', connection_reload_schema_fail: 'Schema load failed', + apiaudit_time_line:"Time Line", + apiaudit_req_start_point: "Request start", + apiaudit_req_end_point: "Request to end", + apiaudit_db_start_point: "Database response starts", + apiaudit_db_end_point: "Database response completed", //Dag //Task edit缓存节点提示 task_list_status_all: 'All status', diff --git a/apps/daas/src/i18n/langs/zh-CN.js b/apps/daas/src/i18n/langs/zh-CN.js index 36e6a33dd..4ea0e0a8c 100644 --- a/apps/daas/src/i18n/langs/zh-CN.js +++ b/apps/daas/src/i18n/langs/zh-CN.js @@ -391,6 +391,8 @@ export default { apiaudit_visitor: '客户端名称', apiaudit_ip: '访问人员IP', apiaudit_interview_time: '访问时间', + apiaudit_interview_time_req: '请求时间', + apiaudit_interview_time_db: '数据库时间', apiaudit_interview_time_start: '访问开始时间', apiaudit_interview_time_end: '访问结束时间', apiaudit_visit_result: '访问结果', @@ -399,13 +401,21 @@ export default { apiaudit_parameter: '参数', apiaudit_link: '链接', apiaudit_access_records: '返回行数', + apiaudit_access_records_byte: '响应大小', apiaudit_total_records: '匹配行数', - apiaudit_average_access_rate: 'API 访问速率', - apiaudit_access_time: '请求访问耗时', - apiaudit_average_response_time: '数据库响应时间', + apiaudit_average_access_db_rate: '数据库响应速率', + apiaudit_average_access_time: 'API响应耗时', + apiaudit_access_time: '请求总耗时', + apiaudit_average_response_time: '数据库耗时', apiaudit_success: '成功', apiaudit_placeholder: '请输入名称/ID', apiaudit_client_name_placeholder: '请输入客户端名称', + apiaudit_time_line:"时间线", + apiaudit_req_start_point: "请求开始", + apiaudit_req_end_point: "请求结束", + apiaudit_db_start_point: "数据库响应开始", + apiaudit_db_end_point: "数据库响应结束", + // 连接 connection_list_form_database_type: '数据库类型', connection_list_name: '连接名', diff --git a/apps/daas/src/i18n/langs/zh-TW.js b/apps/daas/src/i18n/langs/zh-TW.js index 3a81b1147..d05dc2f93 100644 --- a/apps/daas/src/i18n/langs/zh-TW.js +++ b/apps/daas/src/i18n/langs/zh-TW.js @@ -392,6 +392,8 @@ export default { apiaudit_visitor: '客戶端名稱', apiaudit_ip: '訪問人員IP', apiaudit_interview_time: '訪問時間', + apiaudit_interview_time_req: '請求時間', + apiaudit_interview_time_db: '資料庫時間', apiaudit_interview_time_start: '訪問開始時間', apiaudit_interview_time_end: '訪問結束時間', apiaudit_visit_result: '訪問結果', @@ -400,13 +402,20 @@ export default { apiaudit_parameter: '參數', apiaudit_link: '鏈接', apiaudit_access_records: '返回行數', + apiaudit_access_records_byte: '響應大小', apiaudit_total_records: '匹配行數', - apiaudit_average_access_rate: 'API 訪問速率', - apiaudit_access_time: '請求訪問耗時', - apiaudit_average_response_time: '數據庫回應時間', + apiaudit_average_access_db_rate: '數據庫響應速率', + apiaudit_average_access_time: 'API響應耗時', + apiaudit_access_time: '請求總耗時', + apiaudit_average_response_time: '資料庫耗時', apiaudit_success: '成功', apiaudit_placeholder: '請輸入名稱/ID', apiaudit_client_name_placeholder: '請輸入客戶端名稱', + apiaudit_time_line:"時間線", + apiaudit_req_start_point: "請求開始", + apiaudit_req_end_point: "請求結束", + apiaudit_db_start_point: "資料庫響應開始", + apiaudit_db_end_point: "資料庫響應結束", // 連接 connection_list_form_database_type: '數據庫類型', connection_list_name: '連接名', diff --git a/apps/daas/src/views/data-server-audit/Info.vue b/apps/daas/src/views/data-server-audit/Info.vue index 610d5b2d7..6be794a44 100644 --- a/apps/daas/src/views/data-server-audit/Info.vue +++ b/apps/daas/src/views/data-server-audit/Info.vue @@ -13,31 +13,216 @@ export default { return { auditData: null, loading: true, + hoverTimelineSeg: null, + timelineTooltipPopperOptions: { + modifiers: [ + { + name: 'offset', + options: { offset: [0, 8] }, + }, + { + name: 'flip', + options: { + fallbackPlacements: [ + 'top-start', + 'top-end', + 'bottom', + 'bottom-start', + 'bottom-end', + ], + }, + }, + { + name: 'preventOverflow', + options: { padding: 8 }, + }, + ], + }, list: [ + { + label: this.$t('apiaudit_total_records'), + key: 'totalRows', + value: 0, + }, { label: this.$t('apiaudit_access_records'), key: 'visitTotalCount', value: 0, }, { - label: this.$t('apiaudit_total_records'), - key: 'totalRows', + label: this.$t('apiaudit_access_records_byte'), + key: 'responseBytes', value: 0, }, + { label: this.$t('apiaudit_access_time'), key: 'latency', value: 0 }, { - label: this.$t('apiaudit_average_access_rate'), - key: 'speed', + label: this.$t('apiaudit_average_access_time'), + key: 'httpTime', value: 0, }, - { label: this.$t('apiaudit_access_time'), key: 'latency', value: 0 }, { label: this.$t('apiaudit_average_response_time'), key: 'dataQueryTotalTime', value: 0, }, + { + label: this.$t('apiaudit_average_access_db_rate'), + key: 'dbRate', + value: 0, + }, ], } }, + computed: { + timelinePoints() { + if (!this.auditData) return [] + + const callStart = Number(this.auditData.callStart) + const callEnd = Number(this.auditData.callEnd) + const dbStart = Number(this.auditData.dataQueryFromTime) + const dbEnd = Number(this.auditData.dataQueryEndTime) + + const reqOk = + Number.isFinite(callStart) && + Number.isFinite(callEnd) && + callEnd >= callStart + const dbOk = + reqOk && + Number.isFinite(dbStart) && + Number.isFinite(dbEnd) && + dbEnd >= dbStart && + dbStart >= callStart && + dbEnd <= callEnd + + const reqPoints = [ + { + key: 'callStart', + label: this.$t('apiaudit_req_start_point'), + ts: this.auditData.callStart, + text: this.auditData.callStartTime || '-', + type: 'req', + }, + { + key: 'callEnd', + label: this.$t('apiaudit_req_end_point'), + ts: this.auditData.callEnd, + text: this.auditData.callEndTime || '-', + type: 'req', + }, + ] + + if (!dbOk) { + return [ + { ...reqPoints[0], left: 0 }, + { ...reqPoints[1], left: 100 }, + ] + } + + const points = [ + reqPoints[0], + { + key: 'dataQueryFromTime', + label: this.$t('apiaudit_db_start_point'), + ts: this.auditData.dataQueryFromTime, + text: this.auditData.dataQueryFrom || '-', + type: 'db', + }, + { + key: 'dataQueryEndTime', + label: this.$t('apiaudit_db_end_point'), + ts: this.auditData.dataQueryEndTime, + text: this.auditData.dataQueryEnd || '-', + type: 'db', + }, + reqPoints[1], + ] + + const d0 = Math.max(0, dbStart - callStart) + const d1 = Math.max(0, dbEnd - dbStart) + const d2 = Math.max(0, callEnd - dbEnd) + const total = d0 + d1 + d2 + + let w0 = 33.3333 + let w1 = 33.3333 + if (total > 0) { + w0 = (d0 / total) * 100 + w1 = (d1 / total) * 100 + } + + const lefts = [0, w0, w0 + w1, 100] + return points.map((p, i) => ({ ...p, left: lefts[i] })) + }, + timelineSegments() { + if (!this.auditData) return [] + + const callStart = Number(this.auditData.callStart) + const dbStart = Number(this.auditData.dataQueryFromTime) + const dbEnd = Number(this.auditData.dataQueryEndTime) + const callEnd = Number(this.auditData.callEnd) + + const reqOk = + Number.isFinite(callStart) && + Number.isFinite(callEnd) && + callEnd >= callStart + const dbOk = + reqOk && + Number.isFinite(dbStart) && + Number.isFinite(dbEnd) && + dbEnd >= dbStart && + dbStart >= callStart && + dbEnd <= callEnd + + if (!dbOk) { + return [ + { + key: 'req', + type: reqOk ? 'req' : 'other', + width: 100, + startText: this.auditData.callStartTime || '-', + endText: this.auditData.callEndTime || '-', + }, + ] + } + + let w0 = 33.3333 + let w1 = 33.3333 + let w2 = 33.3334 + + const d0 = Math.max(0, dbStart - callStart) + const d1 = Math.max(0, dbEnd - dbStart) + const d2 = Math.max(0, callEnd - dbEnd) + const total = d0 + d1 + d2 + if (total > 0) { + w0 = (d0 / total) * 100 + w1 = (d1 / total) * 100 + w2 = 100 - w0 - w1 + } + + return [ + { + key: 'req-pre', + type: 'req', + width: w0, + startText: this.auditData.callStartTime || '-', + endText: this.auditData.dataQueryFrom || '-', + }, + { + key: 'db', + type: 'db', + width: w1, + startText: this.auditData.dataQueryFrom || '-', + endText: this.auditData.dataQueryEnd || '-', + }, + { + key: 'req-post', + type: 'req', + width: w2, + startText: this.auditData.dataQueryEnd || '-', + endText: this.auditData.callEndTime || '-', + }, + ] + }, + }, created() { this.getData() }, @@ -54,8 +239,23 @@ export default { this.auditData.createAt = data.createAt ? dayjs(data.createAt).format('YYYY-MM-DD HH:mm:ss') : '-' - this.auditData.reqTime = this.auditData.reqTime - ? dayjs(this.auditData.reqTime).format('YYYY-MM-DD HH:mm:ss') + this.auditData.callStartTime = this.auditData.callStart + ? dayjs(this.auditData.callStart).format( + 'YYYY-MM-DD HH:mm:ss.SSS', + ) + : '-' + this.auditData.callEndTime = this.auditData.callEnd + ? dayjs(this.auditData.callEnd).format('YYYY-MM-DD HH:mm:ss.SSS') + : '-' + this.auditData.dataQueryFrom = this.auditData.dataQueryFromTime + ? dayjs(this.auditData.dataQueryFromTime).format( + 'YYYY-MM-DD HH:mm:ss.SSS', + ) + : '-' + this.auditData.dataQueryEnd = this.auditData.dataQueryEndTime + ? dayjs(this.auditData.dataQueryEndTime).format( + 'YYYY-MM-DD HH:mm:ss.SSS', + ) : '-' const jsonData = this.auditData.body ? this.auditData.body @@ -71,7 +271,7 @@ export default { this.auditData.jsonParam.json = jsonData this.auditData.jsonParam.validation = true } catch (error) { - console.log(`parseJsonData error: ${error}`) + console.error(`parseJsonData error: ${error}`) } this.list.forEach((item) => { @@ -135,6 +335,38 @@ export default { console.error('JSON处理失败:', error) } }, + isTimelinePointActive(pointIndex) { + if ( + this.hoverTimelineSeg === null || + this.hoverTimelineSeg === undefined + ) { + return false + } + return ( + pointIndex === this.hoverTimelineSeg || + pointIndex === this.hoverTimelineSeg + 1 + ) + }, + timelineTooltipPlacement(pointIndex) { + if ( + this.hoverTimelineSeg === null || + this.hoverTimelineSeg === undefined || + !this.isTimelinePointActive(pointIndex) + ) { + return 'top' + } + + const startIndex = this.hoverTimelineSeg + const endIndex = this.hoverTimelineSeg + 1 + const startLeft = Number(this.timelinePoints?.[startIndex]?.left) + const endLeft = Number(this.timelinePoints?.[endIndex]?.left) + const segWidth = endLeft - startLeft + const shouldSplit = + Number.isFinite(segWidth) && segWidth >= 0 && segWidth <= 18 + + if (!shouldSplit) return 'top' + return pointIndex === endIndex ? 'bottom' : 'top' + }, }, } @@ -161,10 +393,6 @@ export default { >{{ $t('apiaudit_link') }}: {{ auditData.apiPath || '-' }} - {{ $t('apiaudit_interview_time') }}: - {{ auditData.reqTime }} {{ $t('apiaudit_ip') }}: {{ auditData.userIp }} + {{ $t('apiaudit_interview_time_req') }}: + + {{ auditData.callStartTime }} ~ {{ auditData.callEndTime }} + {{ $t('apiaudit_interview_time_db') }}: + + {{ auditData.dataQueryFrom }} ~ {{ auditData.dataQueryEnd }} + +
+
+
{{$t('apiaudit_time_line')}}
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+ +
+
{{ p.label }}
+
+
+
+
+
+
+
+
+
+
  • {{ formatDuring(item.value) }}
{{ item.value ? `${calcUnit(item.value, 'b')}/S` : '0 M/S' }}
+
+ {{ item.value ? `${calcUnit(item.value, 'B')}` : '0B' }} +