NEZ-956 feat: chart 增加 logs 图表类型(60%)

This commit is contained in:
zhangyu
2021-09-03 11:10:24 +08:00
parent c09ecaadb1
commit fa2920dc9e
10 changed files with 881 additions and 12 deletions

View File

@@ -1414,7 +1414,6 @@ export default {
// 设置图表的尺寸 // 设置图表的尺寸
setChartSize (item, index) { setChartSize (item, index) {
// console.log(item)
this.$nextTick(() => { this.$nextTick(() => {
const chartBox = document.getElementById('chart-' + item.id) const chartBox = document.getElementById('chart-' + item.id)
if (chartBox) { if (chartBox) {

View File

@@ -77,6 +77,20 @@
:chart-index="index" :chart-index="index"
@dropmenu-change="(show) => {dropmenuChange(item.id, show)}" @dropmenu-change="(show) => {dropmenuChange(item.id, show)}"
:chart-data="item"></line-chart-block> :chart-data="item"></line-chart-block>
<logs v-if="item.type === 'logs'" :key="'inner' + item.id"
:from="from" :ref="'editChart'+item.id" :temp-dom="tempDom"
:startTime="filter.start_time" :endTime="filter.end_time"
@on-refresh-data="refreshChart"
@on-remove-chart-block="removeChart"
@on-duplicate-chart-block="duplicateChart"
@on-drag-chart="editChartForDrag"
@on-edit-chart-block="editData"
@sync="()=>{chartBySync(item)}"
:panel-id="filter.panelId"
:is-lock="panelLock"
:chart-index="index"
@dropmenu-change="(show) => {dropmenuChange(item.id, show)}"
:chart-data="item"></logs>
<chart-single-stat :from="from" :key="'inner' + item.id" :ref="'editChart'+item.id" v-if="item.type === 'singleStat'" <chart-single-stat :from="from" :key="'inner' + item.id" :ref="'editChart'+item.id" v-if="item.type === 'singleStat'"
@on-refresh-data="refreshChart" @on-refresh-data="refreshChart"
@@ -247,6 +261,7 @@ import diagramChart from './diagram-chart'
import chartPie from './chart-pie' import chartPie from './chart-pie'
import chartBarStatis from './chart-bar-statistics' import chartBarStatis from './chart-bar-statistics'
import chartGroup from './chart-group' import chartGroup from './chart-group'
import logs from './logs'
import { fromRoute } from '@/components/common/js/constants' import { fromRoute } from '@/components/common/js/constants'
import chartTempData from '@/components/charts/chartTempData' import chartTempData from '@/components/charts/chartTempData'
import { chartResizeTool } from '@/components/common/js/tools' import { chartResizeTool } from '@/components/common/js/tools'
@@ -275,7 +290,8 @@ export default {
chartPie, chartPie,
chartGroup, chartGroup,
chartBarStatis, chartBarStatis,
diagramChart diagramChart,
logs
// visNetwork, // visNetwork,
}, },
data () { data () {
@@ -800,6 +816,14 @@ export default {
this.$refs['editChart' + chartItem.id][0].setData(chartItem, null, this.$refs['editChart' + chartItem.id][0].setData(chartItem, null,
panelId, filter, null, '') panelId, filter, null, '')
} }
} else if (chartItem.type === 'logs') {
if (filterType === 'showFullScreen') { // 全屏查询
this.$refs['editChart' + chartItem.id][0].setData(chartItem, null,
panelId, filter, null, filterType)
} else {
this.$refs['editChart' + chartItem.id][0].setData(chartItem, null,
panelId, filter, null, '')
}
} }
} }
} else { } else {
@@ -868,7 +892,18 @@ export default {
} }
return return
} }
if (chartItem.type == 'logs') {
if (this.$refs['editChart' + chartItem.id] && this.$refs['editChart' + chartItem.id].length > 0) {
if (filterType === 'showFullScreen') { // 全屏查询
this.$refs['editChart' + chartItem.id][0].setData(chartItem, null,
this.filter.panelId, null, filterType)
} else {
this.$refs['editChart' + chartItem.id][0].setData(chartItem, null,
this.filter.panelId, null, '')
}
}
return
}
if (this.isModel) { if (this.isModel) {
this.modelStaticData(chartInfo, filterType) this.modelStaticData(chartInfo, filterType)
} else { } else {
@@ -890,6 +925,8 @@ export default {
if (numInterval >= 60000) { // 大于1分钟则start、end均往后移numInterval否则时间不变 if (numInterval >= 60000) { // 大于1分钟则start、end均往后移numInterval否则时间不变
startTime = this.getNewTime(this.filter.start_time, numInterval) startTime = this.getNewTime(this.filter.start_time, numInterval)
endTime = bus.timeFormate(now, 'yyyy-MM-dd hh:mm:ss') endTime = bus.timeFormate(now, 'yyyy-MM-dd hh:mm:ss')
this.filter.start_time = startTime
this.filter.end_time = endTime
} else { } else {
startTime = this.filter.start_time startTime = this.filter.start_time
endTime = this.filter.end_time endTime = this.filter.end_time
@@ -918,6 +955,9 @@ export default {
if (this.from === fromRoute.chartTemp) { if (this.from === fromRoute.chartTemp) {
return chartTempData return chartTempData
} }
if (chartInfo.type == 'logs') {
return chartTempData
}
return this.$get('/prom/api/v1/query_range?query=' + query + '&start=' + this.$stringTimeParseToUnix(startTime) + '&end=' + this.$stringTimeParseToUnix(endTime) + '&step=' + step) return this.$get('/prom/api/v1/query_range?query=' + query + '&start=' + this.$stringTimeParseToUnix(startTime) + '&end=' + this.$stringTimeParseToUnix(endTime) + '&step=' + step)
}) })
// 一个图表的所有element单独获取数据 // 一个图表的所有element单独获取数据
@@ -1186,6 +1226,14 @@ export default {
this.$refs['editChart' + chartItem.id][0].setData(chartItem, singleStatRlt, this.$refs['editChart' + chartItem.id][0].setData(chartItem, singleStatRlt,
this.filter.panelId, this.filter, '', errorMsg) this.filter.panelId, this.filter, '', errorMsg)
} }
} else if (chartItem.type === 'logs') {
if (filterType === 'showFullScreen') { // 全屏查询
this.$refs['editChart' + chartItem.id][0].setData(chartItem, singleStatRlt,
this.filter.panelId, this.filter, filterType, errorMsg)
} else {
this.$refs['editChart' + chartItem.id][0].setData(chartItem, singleStatRlt,
this.filter.panelId, this.filter, '', errorMsg)
}
} }
} }
} else { } else {
@@ -1215,6 +1263,14 @@ export default {
this.$refs['editChart' + chartItem.id][0].setData(chartItem, '', this.$refs['editChart' + chartItem.id][0].setData(chartItem, '',
this.filter.panelId, this.filter) this.filter.panelId, this.filter)
} }
} else if (chartItem.type === 'logs') {
if (filterType === 'showFullScreen') { // 全屏查询
this.$refs['editChart' + chartItem.id][0].setData(chartItem, '',
this.filter.panelId, this.filter, filterType)
} else {
this.$refs['editChart' + chartItem.id][0].setData(chartItem, '',
this.filter.panelId, this.filter)
}
} }
} }
} }
@@ -1361,6 +1417,14 @@ export default {
this.$refs['editChart' + chartInfo.id][0].setData(chartInfo, singleStatRlt, this.$refs['editChart' + chartInfo.id][0].setData(chartInfo, singleStatRlt,
this.filter.panelId, this.filter, '', errorMsg) this.filter.panelId, this.filter, '', errorMsg)
} }
} else if (chartInfo.type === 'logs') {
if (filterType === 'showFullScreen') { // 全屏查询
this.$refs['editChart' + chartInfo.id][0].setData(chartInfo, singleStatRlt,
this.filter.panelId, this.filter, filterType, errorMsg)
} else {
this.$refs['editChart' + chartInfo.id][0].setData(chartInfo, singleStatRlt,
this.filter.panelId, this.filter, '', errorMsg)
}
} }
} }
}, },

View File

@@ -0,0 +1,710 @@
<style lang="scss">
@import './chart.scss';
</style>
<template>
<div class="nz-chart-resize">
<div class="resize-shadow" ref="resizeShadow"></div>
<div class="resize-box resize-box-single" ref="resizeBox">
<div class="chart-text" :id="'logsDiv'+chartIndex" @mouseenter="caretShow=true" @mouseleave="caretShow=false">
<loading :ref="'localLoading'+chartIndex"></loading>
<div class="clearfix chartTitle" :class="{'dragTitle':dragTitleShow}" :id="'chartTitle'+chartIndex">
<el-popover
v-if="isError"
placement="top-start"
:close-delay=10
trigger="hover"
popper-class="chart-error-popper">
<div >{{errorContent}}</div>
<span slot="reference" class="panel-info-corner panel-info-corner--error">
<i class="nz-icon nz-icon-warning fa"></i>
<span class="panel-info-corner-inner"></span>
</span>
</el-popover>
<!-- <span class="moreTitle">-->
<!-- <el-popover-->
<!-- v-if="seriesItem.length!==seriesItemArr.length"-->
<!-- placement="top-start"-->
<!-- :close-delay=10-->
<!-- trigger="hover"-->
<!-- popper-class="chart-warring-popper">-->
<!-- <div class="moreTitle">{{$t('dashboard.panel.moreTitle')}}{{$t('dashboard.panel.showAll')}}{{seriesItem.length}}</div>-->
<!-- <span slot="reference" class="panel-info-corner panel-info-corner&#45;&#45;error" @click="loadMore">-->
<!-- <i class="nz-icon nz-icon-warning fa"></i>-->
<!-- <span class="panel-info-corner-inner"></span>-->
<!-- </span>-->
<!-- </el-popover>-->
<!-- </span>-->
<el-dropdown trigger="click" class="nz-chart-top" :key="'chartDropdown'+chartIndex" v-clickoutside="clickos" :class="{'move-able':!isLock}">
<el-dropdown-menu style="display: none"></el-dropdown-menu>
<span class="el-dropdown-link chart-title">
<span class="chart-title-text">{{chartData.name}}</span>
<span class="chart-title-icon" :class="{'visible':caretShow,'hidden':!caretShow}">
<span v-if="chartData.remark">
<el-tooltip :content="chartData.remark" placement="top" effect="light">
<i class="nz-icon nz-icon-info-normal"></i>
</el-tooltip>
</span>
<span v-has="'panel_chart_edit'" :title="$t('dashboard.refresh')" class="" @click="refreshChart">
<i class="nz-icon nz-icon-replay"></i>
</span>
<span @click="showAllScreen" v-if="from !== 'chartTemp'" class="" :title="$t('dashboard.screen')">
<i class="nz-icon nz-icon-maxview"></i>
</span>
<span><i class="el-icon-more" @click.stop="dropdownMenuShow=!dropdownMenuShow"></i></span>
</span>
</span>
<ul slot="dropdown" v-show="dropdownMenuShow" :id="'dropdownUl'+chartIndex" class="el-dropdown-menu nz-chart-dropdown" style="" >
<li @click="editChart" class="el-dropdown-menu__item">
<i class="nz-icon nz-icon-edit" style="font-size: 16px;"></i><span>{{$t('dashboard.edit')}}</span></li>
<li v-has="'panel_chart_delete'" class="el-dropdown-menu__item" @click="removeChart">
<i class="nz-icon nz-icon-delete" style="font-size: 16px;"></i>{{$t('dashboard.delete')}}</li>
<li v-has="'panel_chart_add'" class="el-dropdown-menu__item" @click="duplicate">
<i class="el-icon-copy-document" style="font-size: 16px;"></i>{{$t('dashboard.duplicate')}}</li>
<li v-has="'panel_chart_edit'" v-if="from !== 'chartTemp'&&chartData.pid" class="el-dropdown-menu__item" @click="$emit('sync')">
<i class="nz-icon nz-icon-sync" style="font-size: 16px;"></i>{{$t('overall.syncChart')}}</li>
</ul>
</el-dropdown>
</div>
<div class="mt-10 rich-text-container" v-cloak v-show="firstShow" >
<div :id="'chartContainer'+chartIndex" ref="chartContainer" class="logs-content" >
<div v-if="showTab.indexOf('1') > -1" name="1" title="Graph" style="height: 100%">
<div class="chart-room" style="height: 100%">
<chart ref="logChart" :unit="chartUnit"></chart>
</div>
</div>
<div v-show="showTab.indexOf('2') > -1" name="2" title="Logs">
<log-tab ref="logDetail" :log-data="logData" :showSwitch="false" :tab-index="tabIndex" @exportLog="exportLog" @limitChange="queryLogData"></log-tab>
</div>
</div>
</div>
<!--全屏-->
<el-dialog class="nz-dialog table-chart-dialog"
:title="$t('dashboard.panel.view')"
:visible.sync="screenModal"
width="90%"
@close="screenModal = false;screenLegendListMore=[]"
style="margin-top: 1vh !important;"
@opened="initDialog"
@closed="closeDialog"
:modal-append-to-body="false"
>
<el-popover
v-if="isError"
placement="top-start"
:close-delay=10
trigger="hover"
popper-class="chart-error-popper">
<div >{{errorContent}}</div>
<span slot="reference" class="panel-info-corner panel-info-corner--error">
<i class="nz-icon nz-icon-warning fa-model" ></i>
<span class="panel-info-corner-inner"></span>
</span>
</el-popover>
<div slot="title" >
<span class="nz-dialog-title">{{data.title}}</span>
<div class="float-right panel-calendar dialog-tool">
<!-- <time-picker ref="calendarPanel" class="nz-dashboard-picker" style="margin-top: -12px;" @change="dateChange"></time-picker>-->
<pick-time :refresh-data-func="dateChange" v-model="searchTime" :use-chart-unit="false" ref="pickTime" style="height: 28px;" id="line-chart"></pick-time>
</div>
<!-- <span class="float-right dialog-tool" @click="screenRefreshChart" style="margin-right: 15px"><i class="global-active-color nz-icon nz-icon-refresh"/></span>-->
</div>
<div :id="'chartContainer'+chartIndex" ref="chartContainer" class="logs-content" >
<div v-if="showTab.indexOf('1') > -1" name="1" title="Graph" style="height: 100%">
<div class="chart-room" style="height: 100%">
<chart ref="logChartScreen" :unit="chartUnit"></chart>
</div>
</div>
<div v-show="showTab.indexOf('2') > -1" name="2" title="Logs">
<log-tab ref="logDetailScreen" :log-data="logDataScreen" :showSwitch="false" :tab-index="tabIndex" @exportLog="exportLog" @limitChange="queryLogData"></log-tab>
</div>
</div>
<loading :ref="'localLoadingScreen'+chartIndex"></loading>
</el-dialog>
</div>
<span class="vue-resizable-handle" @mousedown="startResize" v-if="!isLock"></span>
</div>
</div>
</template>
<script>
import loading from '../common/loading'
import 'quill/dist/quill.snow.css'
import axios from 'axios'
import chart from '@/components/page/dashboard/overview/chart'
import logTab from '@/components/page/dashboard/explore/logTab'
import bus from '@/libs/bus'
export default {
name: 'logs',
components: {
loading: loading,
chart,
logTab
},
props: {
chartData: {
type: Object
},
// 看板id
panelId: {
type: Number,
default: 0
},
editChartId: {
type: String,
default: 'editChartId'
},
chartIndex: {
type: Number,
default: 0
},
from: { type: String },
startTime: {},
endTime: {},
isLock: { type: Boolean, default: false }
},
data () {
return {
data: {}, // 该图表信息,chartItem
noData: false,
unit: {},
text: '', // 保存信息
screenText: '', // 全屏数据
loading: Object,
panelIdInner: '', // 看板id=panelId,原写作chart,由set_data获取
firstLoad: false, // 是否第一次加载
screenModal: false,
firstShow: false, // 默认不显示操作按钮,
caretShow: false,
dragTitleShow: false,
dropdownMenuShow: false,
divFirstShow: false,
showTab: ['1', '2'],
chartUnit: 2,
logData: [],
logDataScreen: [],
tabIndex: 1,
isError: false,
errorContent: '',
seriesItem: '',
searchTime: [new Date().setHours(new Date().getHours() - 1), new Date()],
oldSearchTime: [new Date().setHours(new Date().getHours() - 1), new Date()],
filter: {},
stableFilter: {},
}
},
created () {
},
computed: {},
watch: {
dropdownMenuShow (n) {
this.$emit('dropmenu-change', n)
}
},
methods: {
startResize (e) {
const vm = this
this.$chartResizeTool.start(vm, this.data, e)
},
startLoading (area) {
if (area === 'screen') {
this.$refs['localLoadingScreen' + this.chartIndex].startLoading()
} else {
// this.showLoading = true;
this.$refs['localLoading' + this.chartIndex].startLoading()
}
},
endLoading (area) {
if (area === 'screen') {
// this.showLoadingScreen = false;
this.$refs['localLoadingScreen' + this.chartIndex].endLoading()
} else {
// this.showLoading = false;
this.$refs['localLoading' + this.chartIndex].endLoading()
}
},
showLoad (chartItem) {
this.$nextTick(() => {
const chartBox = document.getElementById('logsDiv' + this.chartIndex)
let height = Math.floor(chartItem.height / 10) * 10// 图表高度四舍五入
if (height < this.minHeight) {
height = this.minHeight
}
chartBox.style.height = `${height - this.chartSpaceHeight}px`
const singleStatBox = document.getElementById('chartContainer' + this.chartIndex)
singleStatBox.style.height = `${height - this.chartSpaceHeight - this.titleHeight}px`// -75-32
})
this.startLoading()
this.divFirstShow = true
},
// 重新请求数据 刷新操作-local
refreshChart () {
this.dropdownMenuShow = false
this.startLoading()
this.firstShow = false
this.$emit('on-refresh-data', this.data.id)
},
// 编辑图表
editChart () {
this.dropdownMenuShow = false
this.$emit('on-edit-chart-block', this.data.id)
},
// 删除该图表
removeChart () {
this.dropdownMenuShow = false
this.$emit('on-remove-chart-block', this.data.id)
},
clickos () {
this.dropdownMenuShow = false
},
clearChart () {
this.data = {}
},
duplicate () {
this.dropdownMenuShow = false
this.$emit('on-duplicate-chart-block', this.data.id)
},
// 全屏查看
showAllScreen () {
this.dropdownMenuShow = false
// 初始化同步时间
this.filter.start_time = this.stableFilter.start_time
this.filter.end_time = this.stableFilter.end_time
// this.searchTime = this.oldSearchTime;
this.$set(this.searchTime, 0, this.oldSearchTime[0])
this.$set(this.searchTime, 1, this.oldSearchTime[1])
this.screenModal = true
this.isGreyScreen = []
this.$refs.pickTime.$refs.timePicker.setCustomTime(this.stableFilter)
this.seriesItemScreen = this.seriesItem
this.screenModal = true
},
resize (chartItem) {
document.querySelector('#logsDiv' + this.chartIndex + ' .rich-text-container').style.height = `calc(100% - ${this.$chartResizeTool.titleHeight}px)`
},
// 设置数据, filter区分
setData (chartItem, seriesItem, panelId, filter, area) {
if (filter) { // 保存数据,用于同步时间
this.stableFilter = filter
this.searchTime[0] = filter.start_time
this.searchTime[1] = filter.end_time
this.oldSearchTime[0] = this.searchTime[0]
this.oldSearchTime[1] = this.searchTime[1]
}
console.log(chartItem, this.$refs.logDetail)
this.$nextTick(() => {
this.resize(chartItem)
})
this.divFirstShow = true
this.firstShow = true // 展示操作按键
this.panelIdInner = panelId
this.data = chartItem
this.text = chartItem.param.text
this.screenText = chartItem.param.text
this.chartUnit = chartItem.unit
this.endLoading()
this.queryLogData(this.data.param.limit)
},
queryLogData (limit) { // log的chart和table是一个请求
if (!limit) {
limit = this.data.param.limit || 1000
}
this.expressions = this.chartData.elements.map(elements => elements.expression)
if (this.expressions.length > 0) {
const requestArr = []
this.expressions.forEach((item, index) => {
if (item != '') {
requestArr.push(this.$get('/logs/loki/api/v1/query_range?format=1&query=' + item + '&start=' + this.$stringTimeParseToUnix(this.startTime) + '&end=' + this.$stringTimeParseToUnix(this.endTime) + '&limit=' + limit))
}
})
if (requestArr.length > 0) {
this.showIntroduce = false
this.saveDisabled = false
}
axios.all(requestArr).then(res => {
const errorRowIndex = []
res.forEach((r, i) => {
if (typeof r === 'string') {
errorRowIndex.push(i)
}
})
if (errorRowIndex.length > 0) {
this.$message.error(this.$t('tip.errorInRow') + ': ' + errorRowIndex.map(e => e + 1).join(' ,'))
res = res.filter((r, i) => errorRowIndex.indexOf(i) === -1)
}
if (res.length > 0) {
const logData = res.map(r => r.data)
const hasGraph = logData.some(d => d.resultType === 'matrix')
const hasLog = logData.some(d => d.resultType === 'streamsFormat')
const graphTabIndex = this.showTab.indexOf('1')
if (hasGraph) {
if (graphTabIndex === -1) {
this.showTab.push('1')
}
} else {
if (graphTabIndex > -1) {
this.showTab.splice(graphTabIndex, 1)
}
}
const logTabIndex = this.showTab.indexOf('2')
if (hasLog) {
if (logTabIndex === -1) {
this.showTab.push('2')
}
} else {
if (logTabIndex > -1) {
this.showTab.splice(logTabIndex, 1)
}
}
this.$nextTick(() => {
if (this.$refs.logDetail) {
this.$refs.logDetail.time = this.chartData.param.time
this.$refs.logDetail.wrapLines = this.chartData.param.wrapLines
this.$refs.logDetail.operations.descending = this.chartData.param.descending
}
logData.forEach((item, index) => {
item.result.forEach(result => {
result.elements = this.chartData.elements[index]
})
})
this.logData = logData
this.logDataScreen = logData
hasGraph && this.loadLogGraph()
})
}
}).catch(e => {
this.isError = true
this.errorContent = this.$t('terminallog.statusItem.unknownError')
this.$message.error(this.$t('terminallog.statusItem.unknownError'))
})
}
},
queryLogDataScreen (limit) { // log的chart和table是一个请求
if (!limit) {
limit = this.data.param.limit || 1000
}
this.expressions = this.chartData.elements.map(elements => elements.expression)
if (this.expressions.length > 0) {
const requestArr = []
this.expressions.forEach((item, index) => {
if (item != '') {
requestArr.push(this.$get('/logs/loki/api/v1/query_range?format=1&query=' + item + '&start=' + this.$stringTimeParseToUnix(this.searchTime[0]) + '&end=' + this.$stringTimeParseToUnix(this.searchTime[1]) + '&limit=' + limit))
}
})
if (requestArr.length > 0) {
this.showIntroduce = false
this.saveDisabled = false
}
axios.all(requestArr).then(res => {
const errorRowIndex = []
res.forEach((r, i) => {
if (typeof r === 'string') {
errorRowIndex.push(i)
}
})
if (errorRowIndex.length > 0) {
this.$message.error(this.$t('tip.errorInRow') + ': ' + errorRowIndex.map(e => e + 1).join(' ,'))
res = res.filter((r, i) => errorRowIndex.indexOf(i) === -1)
}
if (res.length > 0) {
const logData = res.map(r => r.data)
const hasGraph = logData.some(d => d.resultType === 'matrix')
const hasLog = logData.some(d => d.resultType === 'streamsFormat')
const graphTabIndex = this.showTab.indexOf('1')
if (hasGraph) {
if (graphTabIndex === -1) {
this.showTab.push('1')
}
} else {
if (graphTabIndex > -1) {
this.showTab.splice(graphTabIndex, 1)
}
}
const logTabIndex = this.showTab.indexOf('2')
if (hasLog) {
if (logTabIndex === -1) {
this.showTab.push('2')
}
} else {
if (logTabIndex > -1) {
this.showTab.splice(logTabIndex, 1)
}
}
this.$nextTick(() => {
if (this.$refs.logDetail) {
this.$refs.logDetail.time = this.chartData.param.time
this.$refs.logDetail.wrapLines = this.chartData.param.wrapLines
this.$refs.logDetail.operations.descending = this.chartData.param.descending
}
logData.forEach((item, index) => {
item.result.forEach(result => {
result.elements = this.chartData.elements[index]
})
})
this.logDataScreen = logData
hasGraph && this.loadLogGraphScreen()
})
}
}).catch(e => {
this.isError = true
this.errorContent = this.$t('terminallog.statusItem.unknownError')
this.$message.error(this.$t('terminallog.statusItem.unknownError'))
})
}
},
loadLogGraph () {
const graphData = this.logData.filter(l => l.resultType === 'matrix')
if (graphData && graphData.length > 0) {
this.$refs.logChart.startLoading()
const queryExpression = []
const series = []
const legend = []
this.expressions.forEach((item, index) => {
if (item !== '') {
queryExpression.push(item)
}
})
this.logData.forEach((response, index) => {
if (response.resultType === 'matrix') {
console.log(12312313123)
const data = response.result
if (!data || data.length < 1) {
return
}
data.forEach((result, i) => {
const seriesItem = {
name: '',
symbol: 'emptyCircle', // 去掉点
symbolSize: [2, 2],
showSymbol: false,
smooth: 0.2, // 曲线变平滑
data: [],
lineStyle: {
width: 1,
opacity: 0.9
},
type: 'line'
}
seriesItem.data = result.values.map((item) => {
return [item[0] * 1000, item[1]]
})
let host = ''// up,
let alias = ''
if (result.metric && Object.keys(result.metric).length > 0) {
const metric = Object.keys(result.metric)
if (metric.__name__) {
host = `${metric.__name__}{`// up,
}
metric.forEach((tag, i) => {
if (tag !== '__name__') {
host += `${tag}="${result.metric[tag]}",`
}
})
if (host.endsWith(',')) {
host = host.substr(0, host.length - 1)
}
if (metric.__name__) {
host += '}'
}
// 处理legend别名
alias = this.dealLegendAlias(host, this.chartData.elements[index].legend)
if (!alias || alias === '') {
alias = host
}
} else {
alias = queryExpression[index]
}
console.log(this.chartData, this.chartData.elements[index].legend)
seriesItem.name = alias + '-' + index
series.push(seriesItem)
legend.push({ name: seriesItem.name, alias: alias, isGray: false })
console.log()
})
}
})
this.$refs.logChart.setLegend(legend)
this.$refs.logChart.setRandomColors(series.length)
console.log(series)
this.$refs.logChart.setSeries(series)
this.defaultChartVisible = true
this.$nextTick(() => {
this.$refs.logChart.endLoading()
})
}
},
loadLogGraphScreen () {
const graphData = this.logDataScreen.filter(l => l.resultType === 'matrix')
if (graphData && graphData.length > 0) {
this.$refs.logChartScreen.startLoading()
const queryExpression = []
const series = []
const legend = []
this.expressions.forEach((item, index) => {
if (item !== '') {
queryExpression.push(item)
}
})
this.logDataScreen.forEach((response, index) => {
if (response.resultType === 'matrix') {
console.log(12312313123)
const data = response.result
if (!data || data.length < 1) {
return
}
data.forEach((result, i) => {
const seriesItem = {
name: '',
symbol: 'emptyCircle', // 去掉点
symbolSize: [2, 2],
showSymbol: false,
smooth: 0.2, // 曲线变平滑
data: [],
lineStyle: {
width: 1,
opacity: 0.9
},
type: 'line'
}
seriesItem.data = result.values.map((item) => {
return [item[0] * 1000, item[1]]
})
let host = ''// up,
let alias = ''
if (result.metric && Object.keys(result.metric).length > 0) {
const metric = Object.keys(result.metric)
if (metric.__name__) {
host = `${metric.__name__}{`// up,
}
metric.forEach((tag, i) => {
if (tag !== '__name__') {
host += `${tag}="${result.metric[tag]}",`
}
})
if (host.endsWith(',')) {
host = host.substr(0, host.length - 1)
}
if (metric.__name__) {
host += '}'
}
// 处理legend别名
alias = this.dealLegendAlias(host, this.chartData.elements[index].legend)
if (!alias || alias === '') {
alias = host
}
} else {
alias = queryExpression[index]
}
console.log(this.chartData, this.chartData.elements[index].legend)
seriesItem.name = alias + '-' + index
series.push(seriesItem)
legend.push({ name: seriesItem.name, alias: alias, isGray: false })
console.log()
})
}
})
this.$refs.logChartScreen.setLegend(legend)
this.$refs.logChartScreen.setRandomColors(series.length)
console.log(series)
this.$refs.logChartScreen.setSeries(series)
this.defaultChartVisible = true
this.$nextTick(() => {
this.$refs.logChartScreen.endLoading()
})
}
},
chartUnitChange (unit) {
this.chartUnit = unit
this.$nextTick(() => {
this.expressionChange()
})
},
exportLog ({ limit, descending }) {
const params = {
logql: this.expressions,
start: this.$stringTimeParseToUnix(this.filterTime[0]),
end: this.$stringTimeParseToUnix(this.filterTime[1]),
direction: descending ? 'backward' : 'forward',
limit
}
axios.get('/logs/loki/export', { responseType: 'blob', params: params }).then(res => {
if (window.navigator.msSaveOrOpenBlob) {
// 兼容ie11
const blobObject = new Blob([res.data])
window.navigator.msSaveOrOpenBlob(blobObject, 'log')
} else {
const url = URL.createObjectURL(new Blob([res.data]))
const a = document.createElement('a')
document.body.appendChild(a) // 此处增加了将创建的添加到body当中
a.href = url
a.download = 'log'
a.target = '_blank'
a.click()
a.remove() // 将a标签移除
}
}, error => {
const $self = this
const reader = new FileReader()
reader.onload = function (event) {
const responseText = reader.result
const exception = JSON.parse(responseText)
if (exception.message) {
$self.$message.error(exception.message)
} else {
console.error(error)
}
}
reader.readAsText(error.response.data)
})
},
dealLegendAlias: function (legend, expression) {
if (/\{\{.+\}\}/.test(expression)) {
const labelValue = expression.replace(/(\{\{.+?\}\})/g, function (i) {
const label = i.substr(i.indexOf('{{') + 2, i.indexOf('}}') - i.indexOf('{{') - 2)
const reg = new RegExp(label + '=".+?"')
let value = null
if (reg.test(legend)) {
const find = legend.match(reg)[0]
value = find.substr(find.indexOf('"') + 1, find.lastIndexOf('"') - find.indexOf('"') - 1)
}
return value || label
})
return labelValue
} else {
return expression
}
},
dateChange (time) {
this.filter.start_time = bus.timeFormate(this.searchTime[0], 'yyyy-MM-dd hh:mm:ss')
this.filter.end_time = bus.timeFormate(this.searchTime[1], 'yyyy-MM-dd hh:mm:ss')
// this.echartModalStore.clear()
this.showLegend = false
this.$refs['localLoadingScreen' + this.chartIndex].startLoading()
this.queryLogDataScreen()
},
initDialog () {
this.queryLogDataScreen(this.data.param.limit)
},
closeDialog () {}
},
mounted () {
this.firstLoad = false
},
beforeDestroy () {
this.clearChart()
}
}
</script>
<style scoped>
.chartTitle{
position: relative;
z-index: 1;
}
.logs-content{
overflow-y: auto;
width: calc(100% - 20px);
height: calc(100% - 20px);
padding: 10px;
}
</style>

View File

@@ -314,6 +314,9 @@ const cn = {
}, },
group: { group: {
label: '组' label: '组'
},
logs: {
label: '日志'
} }
}, },
statisticsVal: { statisticsVal: {

View File

@@ -330,6 +330,9 @@ const en = {
}, },
group: { group: {
label: 'Group' label: 'Group'
},
logs: {
label: 'Logs'
} }
}, },
statisticsVal: { statisticsVal: {

View File

@@ -287,7 +287,7 @@
</el-select> </el-select>
</el-form-item>--> </el-form-item>-->
<!--lock--> <!--lock-->
<el-form-item v-if="editChart.type ==='diagram'" :label="$t('dashboard.panel.chartForm.lock')" class="form-item--half-width" prop="unit"> <el-form-item v-if="editChart.type ==='diagram'" :label="$t('dashboard.panel.chartForm.lock')" class="form-item--half-width" prop="lock">
<el-select id="chart-box-statistics" v-model="editChart.param.lock" placeholder="" popper-class="chart-box-dropdown-mini prevent-clickoutside" size="small" @change="$forceUpdate"> <el-select id="chart-box-statistics" v-model="editChart.param.lock" placeholder="" popper-class="chart-box-dropdown-mini prevent-clickoutside" size="small" @change="$forceUpdate">
<el-option v-for="item in lockList" :key="item.value" :label="item.label" :value="item.value"> <el-option v-for="item in lockList" :key="item.value" :label="item.label" :value="item.value">
<span class="panel-dropdown-label-txt" >{{item.label}}</span> <span class="panel-dropdown-label-txt" >{{item.label}}</span>
@@ -312,6 +312,33 @@
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item class="form-item--half-width" v-if="editChart.type == 'logs'" :label='$t("dashboard.panel.chartForm.time")' :rules="{ required: true, message: $t('validate.required'), trigger: 'blur' }" prop="param.time">
<el-switch id="chart-box-time"
v-model="editChart.param.time"
:active-value="true"
:inactive-value="false"
active-color="#ee9d3f"
size="small"></el-switch>
</el-form-item>
<el-form-item class="form-item--half-width" v-if="editChart.type == 'logs'" :label='$t("dashboard.panel.chartForm.descending")' :rules="{ required: true, message: $t('validate.required'), trigger: 'blur' }" prop="param.descending">
<el-switch id="chart-box-descending"
v-model="editChart.param.descending"
:active-value="true"
:inactive-value="false"
active-color="#ee9d3f"
size="small"></el-switch>
</el-form-item>
<el-form-item class="form-item--half-width" v-if="editChart.type == 'logs'" :label='$t("dashboard.panel.chartForm.wrapLines")' :rules="{ required: true, message: $t('validate.required'), trigger: 'blur' }" prop="param.wrapLines">
<el-switch id="chart-box-wrapLines"
v-model="editChart.param.wrapLines"
:active-value="true"
:inactive-value="false"
active-color="#ee9d3f"
size="small"></el-switch>
</el-form-item>
<el-form-item class="form-item--half-width" v-if="editChart.type == 'logs'" :label='$t("dashboard.panel.chartForm.limit")' :rules="{ required: true, message: $t('validate.required'), trigger: 'blur' }" prop="param.limit">
<el-input id="chart-box-limit" v-model="editChart.param.limit" maxlength="1024" show-word-limit size="small"></el-input>
</el-form-item>
</div> </div>
<div v-if="editChart.type ==='diagram'" class="form__sub-title"> <div v-if="editChart.type ==='diagram'" class="form__sub-title">
@@ -350,6 +377,7 @@
:expression-list="expressions" :expression-list="expressions"
:id="promqlKeys[index-1]" :id="promqlKeys[index-1]"
:index="index-1" :index="index-1"
:type="promqlType"
:key="promqlKeys[index-1]" :key="promqlKeys[index-1]"
:plugins="['metric-selector', 'metric-input', 'remove']" :plugins="['metric-selector', 'metric-input', 'remove']"
:ref="'promql-'+(index-1)" :ref="'promql-'+(index-1)"
@@ -596,6 +624,10 @@ export default {
id: 'alertList', id: 'alertList',
name: this.$t('dashboard.panel.chartForm.typeVal.alertList.label') name: this.$t('dashboard.panel.chartForm.typeVal.alertList.label')
}, },
{
id: 'logs',
name: this.$t('dashboard.panel.chartForm.typeVal.logs.label')
},
{ {
id: 'text', id: 'text',
name: this.$t('dashboard.panel.chartForm.typeVal.text.label') name: this.$t('dashboard.panel.chartForm.typeVal.text.label')
@@ -651,7 +683,8 @@ export default {
{ name: 'Asset', id: 1 }, { name: 'Asset', id: 1 },
{ name: 'Endpoint', id: 2 } { name: 'Endpoint', id: 2 }
], ],
topologyDialog: false topologyDialog: false,
promqlType: 'metric'
// metricStore: [] // metricStore: []
} }
}, },
@@ -1436,6 +1469,7 @@ export default {
const chartType = this.editChart.type const chartType = this.editChart.type
this.editChart.param.url = '' this.editChart.param.url = ''
this.editChart.height = 4 this.editChart.height = 4
this.promqlType = 'metric'
if (chartType === 'url') { if (chartType === 'url') {
this.setIsUrl() this.setIsUrl()
/* if(this.$refs.chartTag){ /* if(this.$refs.chartTag){
@@ -1490,6 +1524,8 @@ export default {
this.showPicker = [{ bac: false, text: false }] this.showPicker = [{ bac: false, text: false }]
this.statisticsList = JSON.parse(JSON.stringify(this.$CONSTANTS.statisticsList)) this.statisticsList = JSON.parse(JSON.stringify(this.$CONSTANTS.statisticsList))
this.statisticsList.push({ value: 'null', label: i18n.t('dashboard.panel.chartForm.statisticsVal.null') }) this.statisticsList.push({ value: 'null', label: i18n.t('dashboard.panel.chartForm.statisticsVal.null') })
} else if (chartType == 'logs') {
this.promqlType = 'log'
} }
/* if(this.$refs.chartTag){ /* if(this.$refs.chartTag){
this.$refs.chartTag.forEach((item, index) => { this.$refs.chartTag.forEach((item, index) => {

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="log-detail"> <div class="log-detail">
<div :id="`logChart${tabIndex}`" class="log-chart"></div> <div :id="`logChart${tabIndex}`" class="log-chart" v-if="showSwitch"></div>
<div class="log-operations"> <div class="log-operations" v-if="showSwitch">
<div class="log-operation"> <div class="log-operation">
<span class="operation-label">{{$t('overall.time')}}</span> <span class="operation-label">{{$t('overall.time')}}</span>
<el-switch <el-switch
@@ -63,6 +63,13 @@
> >
<template slot-scope="{ row }">{{utcTimeToTimezoneStr(row.date)}}</template> <template slot-scope="{ row }">{{utcTimeToTimezoneStr(row.date)}}</template>
</el-table-column> </el-table-column>
<el-table-column
v-if="!showSwitch"
prop="legend"
width="140"
>
<template slot-scope="{ row }">{{aliasLegend(row)}}</template>
</el-table-column>
<el-table-column <el-table-column
prop="message" prop="message"
> >
@@ -78,7 +85,11 @@ export default {
name: 'logTab', name: 'logTab',
props: { props: {
logData: Array, logData: Array,
tabIndex: Number tabIndex: Number,
showSwitch: {
type: Boolean,
default: true
}
}, },
computed: { computed: {
tableTimeFormat () { tableTimeFormat () {
@@ -406,6 +417,52 @@ export default {
}, },
resizeChart () { resizeChart () {
this.myChart.resize() this.myChart.resize()
},
aliasLegend (row) {
let host = ''// up,
let alias = ''
if (row.labels && Object.keys(row.labels).length > 0) {
const metric = Object.keys(row.labels)
if (metric.__name__) {
host = `${metric.__name__}{`// up,
}
metric.forEach((tag, i) => {
if (tag !== '__name__') {
host += `${tag}="${row.labels[tag]}",`
}
})
if (host.endsWith(',')) {
host = host.substr(0, host.length - 1)
}
if (metric.__name__) {
host += '}'
}
// 处理legend别名
alias = this.dealLegendAlias(host, row.elements.legend)
if (!alias || alias === '') {
alias = host
}
} else {
alias = row.elements.legend
}
return alias
},
dealLegendAlias: function (legend, expression) {
if (/\{\{.+\}\}/.test(expression)) {
const labelValue = expression.replace(/(\{\{.+?\}\})/g, function (i) {
const label = i.substr(i.indexOf('{{') + 2, i.indexOf('}}') - i.indexOf('{{') - 2)
const reg = new RegExp(label + '=".+?"')
let value = null
if (reg.test(legend)) {
const find = legend.match(reg)[0]
value = find.substr(find.indexOf('"') + 1, find.lastIndexOf('"') - find.indexOf('"') - 1)
}
return value || label
})
return labelValue
} else {
return expression
}
} }
}, },
watch: { watch: {

View File

@@ -176,7 +176,6 @@ export default {
saveChart () { // 新增chart saveChart () { // 新增chart
this.$refs.addChartModal.setTitle(this.$t('dashboard.panel.createChartTitle')) this.$refs.addChartModal.setTitle(this.$t('dashboard.panel.createChartTitle'))
this.$refs.addChartModal.show(true) this.$refs.addChartModal.show(true)
// console.log('1_+_+_+_+_+_+',JSON.stringify(this.metricInfo));
this.$refs.addChartModal.createData(-1, this.metricInfo) this.$refs.addChartModal.createData(-1, this.metricInfo)
}, },
// 删除指标,第一步, 新方法 // 删除指标,第一步, 新方法

View File

@@ -62,7 +62,6 @@ const store = new Vuex.Store({
return state.showTopoScreen return state.showTopoScreen
}, },
getLogo (state) { getLogo (state) {
// console.log('get logo', state)
return state.logo return state.logo
}, },
getIsShrink (state) { getIsShrink (state) {
@@ -142,7 +141,6 @@ const store = new Vuex.Store({
state.showTopoScreen = boolean state.showTopoScreen = boolean
}, },
setLogo (state, logo) { setLogo (state, logo) {
// console.log('set log', logo)
state.logo = logo state.logo = logo
}, },
isShrink (state) { isShrink (state) {

View File

@@ -1 +1 @@
{"baseUrl":"/", "version": "21.04"} {"baseUrl":"http://192.168.40.42:8080/nz-admin/", "version": "21.04"}