This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
nezha-nezha-fronted/nezha-fronted/src/components/page/dashboard/explore/promqlInput.vue

1177 lines
36 KiB
Vue
Raw Normal View History

<template>
<div class="promqlInput">
<div class="query-row">
2021-04-30 18:54:11 +08:00
<!--explore页面的样式-->
<template v-if="styleType == 1">
<div v-if="plugins.indexOf('metric-selector') > -1">
<el-dropdown class="metric-selector">
<el-dropdown-menu style="display: none"></el-dropdown-menu>
2022-04-19 11:57:55 +08:00
<button
class="top-tool-btn top-tool-btn--text"
type="button"
@click="toggleDropdown"
>
{{
type === "log" ? $t("overall.logLabels") : $t("overall.metric")
}}
<i class="nz-icon nz-icon-arrow-down" style="font-size: 12px"></i>
</button>
<el-cascader-panel
v-show="dropDownVisible"
ref="metricSelector"
slot="dropdown"
v-model="cascaderValue"
v-clickoutside="closeDropdown"
v-my-loading="tempBoxShowLoading"
:loading="loading"
:options="metricOptions"
v-if="type !== 'log'"
:props="cascaderProps"
@change="metricChangeNew"
style="margin-top: 5px"
>
2021-04-30 18:54:11 +08:00
<template slot-scope="{ node, data }">
2022-04-19 11:57:55 +08:00
<div
:class="[
'nz-cascade',
data.temp && !data.child ? 'nz-cascade-temp' : '',
data.more ? 'cascader-panel-more' : '',
]"
@click="
() => {
lazyLoad(node, data);
}
"
:title="data.label"
>
2021-04-30 18:54:11 +08:00
<i class="nz-icon nz-icon-template2"></i>
2022-04-19 11:57:55 +08:00
{{ data.label }}
<i v-if="data.more" class="nz-icon nz-icon-arrow-down"></i>
2021-04-30 18:54:11 +08:00
</div>
</template>
2021-08-02 20:36:10 +08:00
</el-cascader-panel>
2022-04-19 11:57:55 +08:00
<el-cascader-panel
v-else
v-show="dropDownVisible"
ref="metricSelector"
slot="dropdown"
v-model="cascaderValue"
v-clickoutside="closeDropdown"
v-my-loading="tempBoxShowLoading"
:loading="loading"
:props="cascaderProps"
@change="logLabelChange"
style="margin-top: 5px"
>
2021-08-02 20:36:10 +08:00
<template slot-scope="{ node, data }">
<div :title="data.label" class="nz-cascade">
2022-04-19 11:57:55 +08:00
{{ data.label }}
2021-08-02 20:36:10 +08:00
</div>
</template>
2021-04-30 18:54:11 +08:00
</el-cascader-panel>
</el-dropdown>
</div>
2022-04-19 11:57:55 +08:00
<div
v-if="plugins.indexOf('metric-input') > -1"
class="input-box"
@click="dropDownVisible = false"
>
<div
:id="pqid + 'editor'+index"
v-if="type !== 'log'"
class="not-fixed-height no-resize no-close"
2022-04-19 11:57:55 +08:00
>
</div>
<!-- <div id='editor'
class="not-fixed-height no-resize no-close"
>
</div> -->
<el-input
v-if="type == 'log'"
2022-04-19 11:57:55 +08:00
:id="inputId"
v-model="expressionList[index]"
2022-06-10 14:55:46 +08:00
size="small" :rows="2"
2022-04-19 11:57:55 +08:00
class="not-fixed-height no-resize"
type="textarea"
2022-06-10 14:55:46 +08:00
show-word-limit maxlength="256"
2022-04-19 11:57:55 +08:00
@input="metricKeyDown"
@keyup.enter.native="expressionChange"
ref="elInput"
></el-input>
2022-04-19 11:57:55 +08:00
<div v-if="errorMsg" class="append-msg error">
<span>{{ errorMsg }}</span>
</div>
<div v-if="appendMsg" class="append-msg error">
<span>{{ appendMsg }}</span>
</div>
2021-04-30 18:54:11 +08:00
</div>
2021-11-17 18:12:03 +08:00
<div class="top-tool-btn-group">
2022-04-19 11:57:55 +08:00
<button
v-if="plugins.indexOf('add') > -1"
class="top-tool-btn"
@click="addExpression"
>
<i class="nz-icon nz-icon-plus"></i>
</button>
<button
v-if="plugins.indexOf('copy') > -1"
class="top-tool-btn"
@click="copyExpression"
>
<i class="nz-icon nz-icon-override"></i>
</button>
<button
v-if="plugins.indexOf('remove') > -1"
class="top-tool-btn"
@click="removeExpression"
>
<i class="nz-icon nz-icon-minus"></i>
</button>
2021-04-30 18:54:11 +08:00
</div>
</template>
<!--right-box里的样式-->
<template v-if="styleType === 2 || styleType === 3">
2022-04-19 11:57:55 +08:00
<el-row
v-if="
plugins.indexOf('metric-input') > -1 ||
plugins.indexOf('metric-selector') > -1
"
style="width: 100%"
>
<el-col
:class="[
plugins.indexOf('metric-selector') > -1
? 'metric-selector-title'
: 'metric-null-title',
]"
>
<el-dropdown
class="metric-selector"
v-if="plugins.indexOf('metric-selector') > -1"
>
<el-dropdown-menu style="display: none"></el-dropdown-menu>
<span
:class="{ 'expr-title': projectRightBox }"
style="cursor: pointer"
@click="toggleDropdown"
>{{
type === "log"
? $t("overall.logLabels")
: $t("overall.metric")
}}<i
class="nz-icon nz-icon-arrow-down"
2022-04-19 11:57:55 +08:00
style="
font-size: 14px;
-webkit-transform: scale(0.75);
display: inline-block;
"
></i
></span>
<el-cascader-panel
v-my-loading="tempBoxShowLoading"
v-show="dropDownVisible"
v-clickoutside="closeDropdown"
v-model="cascaderValue"
style="text-align: left; margin-top: 5px"
slot="dropdown"
ref="metricSelector"
v-if="type !== 'log'"
:props="{ emitPath: false }"
:options="metricOptions"
@change="metricChangeNew"
>
<template slot-scope="{ node, data }">
<div
:class="[
'nz-cascade',
data.temp && !data.child ? 'nz-cascade-temp' : '',
data.more ? 'cascader-panel-more' : '',
]"
@click="
() => {
lazyLoad(node, data);
}
"
:title="data.label"
>
<i class="nz-icon nz-icon-template2"></i>
{{ data.label }}
<i v-if="data.more" class="nz-icon nz-icon-arrow-down"></i>
</div>
</template>
</el-cascader-panel>
<el-cascader-panel
v-else
v-show="dropDownVisible"
ref="metricSelector"
slot="dropdown"
v-model="cascaderValue"
v-clickoutside="closeDropdown"
v-my-loading="tempBoxShowLoading"
:loading="loading"
:props="cascaderProps"
@change="logLabelChange"
>
<template slot-scope="{ node, data }">
<div :title="data.label" class="nz-cascade">
{{ data.label }}
</div>
</template>
</el-cascader-panel>
</el-dropdown>
</el-col>
<el-col
:class="
plugins.indexOf('metric-selector') > -1
? 'metric-selector-input-box'
: 'metric-null-input-box'
"
:style="{ height: '100%' }"
>
2022-04-19 11:57:55 +08:00
<div
class="input-box"
@click="dropDownVisible = false"
v-if="plugins.indexOf('metric-input') > -1"
>
<div
:id="pqid + 'editor'+index"
v-if="type !== 'log'"
class="not-fixed-height no-resize no-close"
>
</div>
<!-- <div id="editor"
class="not-fixed-height no-resize no-close"
2022-04-19 11:57:55 +08:00
ref="elInput"
></div> -->
<el-input
2022-04-19 11:57:55 +08:00
v-model="expressionList[index]"
v-if="type === 'log'"
2022-04-19 11:57:55 +08:00
@input="metricKeyDown"
type="textarea"
:maxlength="styleType === 3 ? 512 : 4096"
show-word-limit
2022-06-10 14:55:46 +08:00
size="small" :rows="2"
2022-04-19 11:57:55 +08:00
class="not-fixed-height no-resize"
ref="elInput"
></el-input>
2022-04-19 11:57:55 +08:00
<div class="append-msg error" v-if="errorMsg">
<span>{{ errorMsg }}</span>
</div>
2022-04-19 11:57:55 +08:00
<div class="append-msg error" v-if="appendMsg">
<span>{{ appendMsg }}</span>
</div>
</div>
</el-col>
</el-row>
</template>
</div>
2022-04-19 11:57:55 +08:00
<div v-if="styleType == 2 && showRemove">
<div
class="option"
@click="addExpression"
v-if="plugins.indexOf('add') > -1"
>
<i class="nz-icon nz-icon-plus"></i>
</div>
<div
class="option"
style="margin-left: 5px; line-height: 32px"
@click="removeExpression"
v-if="plugins.indexOf('remove') > -1"
>
<i class="nz-icon nz-icon-minus"></i>
2020-07-02 22:25:06 +08:00
</div>
</div>
<el-dialog
:visible.sync="tempBoxShow"
:append-to-body="true"
:width="'auto'"
:custom-class="'nz-temp-box'"
:destroy-on-close="true"
@closed="tempBoxClose"
2022-04-19 11:57:55 +08:00
center
>
<el-form
v-model="tempBox"
class="temp-form-box"
ref="tempFormBox"
v-if="tempBoxShow"
>
<span class="temp-form-box-title">Expression</span>
<el-form-item prop="expression">
2022-04-19 11:57:55 +08:00
<el-input
class="temp-form-box-input"
v-model="tempBox.expression"
size="small"
disabled
></el-input>
</el-form-item>
2022-04-19 11:57:55 +08:00
<span class="temp-form-box-title" v-if="tempBox.vars.length"
>Variable</span
>
<el-form-item
v-for="(item, index) in tempBox.vars"
:prop="item"
:key="index"
>
<el-row>
<el-col :span="7" class="temp-form-box-col">
2022-04-19 11:57:55 +08:00
<el-input
class="temp-form-box-input"
v-model="tempBox.vars[index]"
:id="'tempBox' + index"
size="small"
:disabled="true"
></el-input>
</el-col>
<el-col :span="16" v-if="format(item).key">
2022-04-19 11:57:55 +08:00
<select-alert-silence
:filter-silence="filterSilence"
:silence-data="format(item).arr"
:panel-lock="false"
:placement="'bottom-start'"
:typeContentLoading="typeContentLoading"
@selectSilence="
(val) => {
silenceChange(val, item);
}
"
ref="selectPanel"
style="width: 240px"
>
<template v-slot:header>
2021-08-27 17:13:26 +08:00
<div class="explore-select-header">
2022-04-19 11:57:55 +08:00
<el-input
:placeholder="$t('overall.search')"
clearable
size="mini"
style="width: 300px; padding: 0 10px"
v-model="filterSilence"
id="panel-list-search"
></el-input>
</div>
</template>
<template v-slot:trigger>
2022-04-19 11:57:55 +08:00
<el-input
class="panel-name"
placeholder=""
readonly="readonly"
v-model="tempBox[item]"
size="small"
>
<span
slot="suffix"
class="
el-input__icon
el-icon-circle-close
el-input__clear
"
@click.stop="clearValue(item)"
></span>
</el-input>
</template>
</select-alert-silence>
</el-col>
<el-col :span="17" v-else>
2022-04-19 11:57:55 +08:00
<el-input
v-model="tempBox[item]"
:id="'tempBox' + item"
size="small"
></el-input>
</el-col>
</el-row>
</el-form-item>
</el-form>
<span slot="footer">
2022-04-19 11:57:55 +08:00
<button
id="temp-box-esc"
class="nz-btn nz-btn-size-normal nz-btn-style-light"
@click="tempBoxShowChange(false)"
>
<span>{{ $t("overall.cancel") }}</span>
</button>
<button
id="chart-box-save"
v-has="`expressionTemplate_add`"
:disabled="prevent_opt.save"
class="nz-btn nz-btn-size-normal nz-btn-style-normal"
@click="tempBoxShowChange(true)"
>
<span>{{ $t("overall.save") }}</span>
</button>
</span>
</el-dialog>
</div>
</template>
<script>
2022-04-20 16:57:14 +08:00
import selectAlertSilence from '../../../common/alert/selectAlertSilence'
import { get } from '@/http'
import { PromQLExtension } from 'codemirror-promql'
import { basicSetup } from '@codemirror/basic-setup'
2022-04-19 11:57:55 +08:00
// import { EditorState } from '@codemirror/state';
2022-04-20 16:57:14 +08:00
import { highlightSelectionMatches } from '@codemirror/search'
import { EditorState, Prec, Compartment } from '@codemirror/state'
import { indentOnInput, syntaxTree } from '@codemirror/language'
import { EditorView, highlightSpecialChars, keymap, ViewUpdate, placeholder } from '@codemirror/view'
import { history, historyKeymap } from '@codemirror/history'
import { bracketMatching } from '@codemirror/matchbrackets'
import { defaultKeymap, insertNewlineAndIndent } from '@codemirror/commands'
import { commentKeymap } from '@codemirror/comment'
import { lintKeymap } from '@codemirror/lint'
import { baseTheme, promqlHighlighter } from './CMTheme.tsx'
import { closeBrackets, closeBracketsKeymap } from '@codemirror/closebrackets'
import { autocompletion, completionKeymap, CompletionContext, CompletionResult } from '@codemirror/autocomplete'
2022-04-22 18:55:50 +08:00
import { newCompleteStrategy } from 'codemirror-promql/dist/esm/complete'
2022-04-20 16:57:14 +08:00
2021-03-19 18:52:19 +08:00
export default {
name: 'promqlInput',
components: {
selectAlertSilence
},
props: {
index: { type: Number },
pqid: {
type: String, default: ''
},
expressionList: { type: Array },
2021-03-19 18:52:19 +08:00
plugins: { type: Array },
styleType: Number,
historyParam: { type: Object },
showRemove: { type: Boolean, default: true },
projectRightBox: { type: Boolean, default: false },
metricOptionsParent: { type: Array },
inputId: String,
required: {
type: Boolean, default: false
},
2021-03-19 18:52:19 +08:00
showTemp: {
type: Boolean,
default: true
},
typeContentLoading: {
type: Boolean,
default: false
},
fromFatherData: {
type: Boolean,
default: false
2021-07-26 18:14:31 +08:00
},
2021-08-02 20:36:10 +08:00
type: {
type: String // metric和log两种为空时视为metric
},
isTopo: {
type: Boolean,
default: false
2021-08-02 20:36:10 +08:00
}
2021-03-19 18:52:19 +08:00
// metricOptions: {type: Array},
// metricStore: {type: Array}
},
data () {
return {
2022-04-22 18:55:50 +08:00
oldcCodeLength: '',
newView: null,
codeMirrorValue: [],
2021-03-19 18:52:19 +08:00
dropDownVisible: false,
// metricStore:[],
metricOptions: [],
cascaderValue: '',
errorMsg: null,
appendMsg: null,
firstAddEvent: true,
tempBoxShow: false,
tempBox: {
expression: '',
vars: []
},
2021-03-19 18:52:19 +08:00
tempBoxShowLoading: false,
assetOption: [],
moduleOption: [],
endpointOption: [],
datacenterOption: [],
projectOption: [],
filterSilence: '',
tempBoxId: {},
loading: false
2021-03-19 18:52:19 +08:00
}
},
2021-08-02 20:36:10 +08:00
computed: {
cascaderProps () {
if (this.type === 'log') {
return {
lazy: true,
lazyLoad (node, resolve) {
const { level } = node
if (level === 0) {
get('/logs/loki/api/v1/labels').then(res => {
if (res.data) {
const nodes = res.data.sort().map(d => ({
value: d,
label: d,
leaf: false
}))
resolve(nodes)
} else {
resolve([])
}
})
} else if (level === 1) {
get(`/logs/loki/api/v1/label/${node.value}/values`).then(res => {
if (res.data) {
const nodes = res.data.sort().map(d => ({
value: d,
label: d,
leaf: true
}))
resolve(nodes)
} else {
resolve([])
}
})
}
}
}
} else {
return { emitPath: false }
}
}
},
mounted () {
if (!this.fromFatherData && this.type !== 'log') {
this.queryMetrics()
}
2021-03-19 18:52:19 +08:00
},
methods: {
initCodeMirror () {
const self = this
const promQL = new PromQLExtension().setComplete(
{
2022-04-22 18:55:50 +08:00
completeStrategy: query(newCompleteStrategy({
remote: {
url: 'http://192.168.40.42:8080/prom',
fetchFn: this.fetchFn
}
2022-04-22 18:55:50 +08:00
}))
2022-04-20 16:57:14 +08:00
}
)
2022-04-22 18:55:50 +08:00
function query (CompleteStrategy) {
const obj = {}
obj.complete = CompleteStrategy
obj.queryHistory = []
obj.promQL = function (context) {
return Promise.resolve(this.complete.promQL(context)).then((res) => {
const { state, pos } = context
const tree = syntaxTree(state).resolve(pos, -1)
const start = res != null ? res.from : tree.from
if (start !== 0) {
return res
}
const historyItems = {
from: start,
to: pos,
options: this.queryHistory.map((q) => ({
label: q.length < 80 ? q : q.slice(0, 76).concat('...'),
detail: 'past query',
apply: q,
info: q.length < 80 ? undefined : q
})),
span: /^[a-zA-Z0-9_:]+$/
}
if (res !== null) {
historyItems.options = historyItems.options.concat(res.options)
}
// console.log(historyItems)
return historyItems
})
}
return obj
}
const dynamicConfigCompartment = new Compartment()
const dynamicConfig = [
promqlHighlighter,
promQL.asExtension(),
baseTheme
]
if (!this.newView) {
const EditorViewstate = EditorState.create({
extensions: [
baseTheme,
highlightSpecialChars(),
history(),
EditorState.allowMultipleSelections.of(true),
indentOnInput(),
bracketMatching(),
closeBrackets(),
autocompletion(),
highlightSelectionMatches(),
EditorView.lineWrapping,
keymap.of([
...closeBracketsKeymap,
...defaultKeymap,
...historyKeymap,
...commentKeymap,
...completionKeymap,
...lintKeymap
]),
// placeholder('Expression (press Shift+Enter for newlines)'),
dynamicConfigCompartment.of(dynamicConfig),
// This keymap is added without precedence so that closing the autocomplete dropdown
// via Escape works without blurring the editor.
keymap.of([
{
key: 'Escape',
run: (v) => {
v.contentDOM.blur()
return false
}
}
]),
Prec.override(
keymap.of([
{
key: 'Enter',
run: (v) => {
self.newChange()
return true
}
},
{
key: 'Shift-Enter',
run: insertNewlineAndIndent
}
])
),
EditorView.updateListener.of((update) => {
self.newChange(update.state.doc.toString())
})
],
doc: self.codeMirrorValue[self.index],
editorState: {
changeByRange: self.newChange(),
changes: self.newDoc(),
facet: self.newChange()
}
})
const view = new EditorView({
state: EditorViewstate,
// parent: document.getElementById('editor')
parent: document.getElementById(this.pqid + 'editor' + self.index)
})
self.newView = view
} else {
2022-04-22 18:55:50 +08:00
// console.log('viewIsOk')
// const { from} = self.newView.state.selection.ranges[0]
// const to = self.codeMirrorValue.length
const to = self.oldcCodeLength
const from = self.oldcCodeLength
self.newView.dispatch(
self.newView.state.update({
effects: dynamicConfigCompartment.reconfigure(dynamicConfig),
2022-04-22 18:55:50 +08:00
changes: { from, to, insert: self.codeMirrorValue[self.index] }
})
)
}
},
2022-04-20 16:57:14 +08:00
newChange (val) {
2022-04-22 18:55:50 +08:00
// console.log('newchange', val)
if (val) {
this.oldcCodeLength = val.length
2022-04-22 18:55:50 +08:00
// console.log(this.oldcCodeLength)
this.codeMirrorValue[this.index] = val
this.expressionList[this.index] = val
2022-04-22 18:55:50 +08:00
// console.log(this.codeMirrorValue)
this.metricKeyDown(val)
2022-04-22 18:55:50 +08:00
} else {
this.oldcCodeLength = 0
this.codeMirrorValue[this.index] = ''
}
2022-04-20 16:57:14 +08:00
},
newDoc (val) {
2022-04-22 18:55:50 +08:00
// console.log('doc', val)
2022-04-20 19:22:40 +08:00
},
fetchFn (a, b) {
2022-04-22 18:55:50 +08:00
const params = {}
2022-04-20 19:22:40 +08:00
if (b) {
2022-04-22 18:55:50 +08:00
params['match[]'] = b.body.get('match[]')
params.start = b.body.get('start')
params.end = b.body.get('end')
a += '?match[]=' + b.body.get('match[]')
return fetch(a, {
...b,
// body: JSON.stringify(params),
redirect: 'follow',
headers: {
Authorization: localStorage.getItem('nz-token'),
'content-type': 'application/x-www-form-urlencoded'
2022-04-20 19:22:40 +08:00
}
2022-04-22 18:55:50 +08:00
})
}
return fetch(a, {
...b,
headers: {
Authorization: localStorage.getItem('nz-token')
2022-04-20 19:22:40 +08:00
}
})
},
2021-03-19 18:52:19 +08:00
closeDropdown () {
this.dropDownVisible = false
},
2021-03-19 18:52:19 +08:00
clearExpression: function () {
this.expressionChange()
this.cascaderValue = ''
},
2021-03-19 18:52:19 +08:00
addExpression: function () {
this.$emit('addExpression', this.index)
},
2021-03-19 18:52:19 +08:00
copyExpression () {
this.$emit('copyExpression', this.index)
},
removeExpression: function () {
this.$emit('removeExpression', this.index)
},
toggleDropdown () {
this.dropDownVisible = !this.dropDownVisible
this.getMetricOptions()
},
getMetricOptions () {
if (!this.metricOptions.length) {
this.queryMetrics()
}
2021-03-19 18:52:19 +08:00
},
queryMetrics: function () {
this.loading = true
2021-03-19 18:52:19 +08:00
this.$get('prom/api/v1/label/__name__/values').then(response => {
if (response.status == 'success') {
2021-03-22 10:25:41 +08:00
const metrics = response.data.sort()
const metricMap = new Map()
2021-03-19 18:52:19 +08:00
metrics.forEach((item) => {
let key = ''
if (/^[a-zA-Z_:][a-zA-Z0-9_:]*/.test(item)) {
key = item.split(/[_:]/, 1)[0]
2021-03-19 18:52:19 +08:00
} else {
key = item
}
if (metricMap.get(key)) {
2021-03-22 10:25:41 +08:00
const values = metricMap.get(key)
2021-03-19 18:52:19 +08:00
values.push({ label: item, value: item })
} else {
2021-03-22 10:25:41 +08:00
const values = [{ label: item, value: item }]
2021-03-19 18:52:19 +08:00
metricMap.set(key, values)
}
2021-03-19 18:52:19 +08:00
// this.metricStore.push({label:item,value:item,insertText:item})
})
2021-03-22 10:25:41 +08:00
for (const key of metricMap.keys()) {
const option = {
2021-03-19 18:52:19 +08:00
label: key,
value: key
}
2021-03-19 18:52:19 +08:00
if (metricMap.get(key) && metricMap.get(key).length > 1) {
option.children = metricMap.get(key)
}
this.metricOptions.push(option)
}
2021-03-19 18:52:19 +08:00
if (this.showTemp) {
this.getExprTemp()
}
2021-03-19 18:52:19 +08:00
}
})
},
filterInput: function (queryString, cb) {
2021-03-22 10:25:41 +08:00
const metrics = Object.assign([], this.metricStore)
const result = queryString
2021-03-19 18:52:19 +08:00
? metrics.filter((item) => {
return item.value.toLowerCase().indexOf(queryString.toLowerCase()) != -1
})
2021-03-19 18:52:19 +08:00
: metrics
cb(result)
},
metricChange: function (value) {
this.expressionList[this.index] = value
this.codeMirrorValue[this.index] = value
this.dropDownVisible = false
this.$emit('change', value)
// this.initCodeMirror()
this.$forceUpdate()
this.cascaderValue = ''
},
metricChangeNew (value) {
2022-04-22 18:55:50 +08:00
// console.log(value)
2021-03-19 18:52:19 +08:00
if (!value) return
this.insertText(value)
2021-03-19 18:52:19 +08:00
this.dropDownVisible = false
2021-05-12 19:07:07 +08:00
this.$emit('change', value)
2021-04-22 18:03:56 +08:00
this.$forceUpdate()
this.cascaderValue = ''
2021-03-19 18:52:19 +08:00
},
2021-08-02 20:36:10 +08:00
logLabelChange (value) {
if (!value || value.length === 0) return
this.expressionList[this.index] = `{${value[0]}="${value[1]}"}`
this.codeMirrorValue[this.index] = `{${value[0]}="${value[1]}"}`
2021-08-02 20:36:10 +08:00
this.dropDownVisible = false
this.$emit('change', value)
this.$forceUpdate()
this.cascaderValue = ''
},
2021-03-19 18:52:19 +08:00
metricKeyDown (val) {
if (this.required) {
this.metricChange(val)
}
},
expressionChange: function () {
2021-05-12 19:07:07 +08:00
this.$emit('change')
2021-03-19 18:52:19 +08:00
},
setError: function (errMsg) {
this.errorMsg = errMsg
},
getExprTemp () {
this.$get('/expression/tmpl/gname').then(res => {
this.loading = false
2021-03-19 18:52:19 +08:00
if (res.code === 200) {
res.data.list.forEach(item => {
this.metricOptions.unshift({
label: item,
value: item,
children: [],
temp: true,
child: false
})
2021-03-19 18:52:19 +08:00
})
}
2021-03-19 18:52:19 +08:00
})
},
lazyLoad (node, data) {
if (data.temp) {
if (!data.child) {
this.tempBoxShowLoading = true
this.$get('/expression/tmpl?pageSize=-1&gname=' + data.value).then(res => {
this.tempBoxShowLoading = false
if (res.code === 200) {
res.data.list.forEach(item => {
item.label = item.name
item.value = false
item.temp = true
item.child = true
})
this.metricOptions.find(item => item.value === data.value).children = res.data.list
}
2021-03-19 18:52:19 +08:00
})
} else {
this.dropDownVisible = false
this.$get('/expression/tmpl/' + data.id).then(res => {
if (res.code === 200) {
if (!res.data.vars || !res.data.vars.length) {
this.metricChange(data.expression)
return
}
2021-03-19 18:52:19 +08:00
res.data.vars.forEach(item => {
res.data[item] = ''
const arr = item.split('.')
const keyword = arr[0].toLowerCase()
this.getAllOptins(keyword, keyword + 'Option')
})
this.tempBox = {
...this.tempBox,
...res.data
}
2021-03-19 18:52:19 +08:00
setTimeout(() => {
this.tempBoxShow = true
}, 100)
2020-11-24 17:31:40 +08:00
}
})
}
} else if (data.children && (!data.children.length || data.children.length > 100) && this.type !== 'log') {
this.metricOptions.forEach(item => {
if (!item.temp && item.children && item.value != data.value) {
item.children = []
}
})
setTimeout(() => {
new Promise(resolve => {
const children = this.$store.state.metricsList.find(item => item.value === data.value).children
resolve(children)
}).then((children) => {
const childrenCopy = JSON.parse(JSON.stringify(children))
const findChild = this.metricOptions.find(item => item.label === data.label)
if (childrenCopy.length > 100) {
childrenCopy.splice(100, childrenCopy.length)
childrenCopy.push({
label: 'More',
value: false,
parent: data.label,
more: true
})
findChild.children = childrenCopy
} else {
findChild.children = childrenCopy
}
})
})
} else if (data.more) {
setTimeout(() => {
new Promise(resolve => {
const children = this.$store.state.metricsList.find(item => item.label === data.parent).children
resolve(children)
}).then((children) => {
let childrenCopy = JSON.parse(JSON.stringify(children))
const findChild = this.metricOptions.find(item => item.label === data.parent)
if (childrenCopy.length > 100) {
childrenCopy = childrenCopy.splice(findChild.children.length, findChild.children.length + 101)
findChild.children.splice(findChild.children.length - 1, 1)
findChild.children.push(...childrenCopy)
if (findChild.children.length < children.length - 1) {
findChild.children.push({
label: 'More',
value: false,
parent: data.parent,
more: true
})
} else {
findChild.children.splice(findChild.children.length - 1, 1)
}
} else {
findChild.children = childrenCopy
}
})
})
2021-03-19 18:52:19 +08:00
}
},
tempBoxShowChange (flag) {
this.tempBoxShow = flag
if (flag) {
this.cascaderValue = ''
2021-03-22 10:25:41 +08:00
const params = {}
2021-03-19 18:52:19 +08:00
params.expression = this.tempBox.expression
params.varsVal = {}
let returnFlag = false
let errorStr = ''
this.tempBox.vars.forEach((item) => {
2021-03-22 16:02:58 +08:00
params.varsVal[item] = this.tempBoxId[item] || this.tempBox[item]
2021-03-19 18:52:19 +08:00
if (!this.tempBox[item]) {
errorStr += item + ','
returnFlag = true
}
})
2021-03-19 18:52:19 +08:00
if (returnFlag) {
this.$message({
message: this.$t('config.exprTemp.errorStr', { errorStr: errorStr }),
type: 'error'
})
return
}
2021-03-19 18:52:19 +08:00
if (this.tempBox.vars.length == 0) {
this.tempBoxShow = false
2021-03-22 16:02:58 +08:00
// eslint-disable-next-line vue/no-mutating-props
// this.expressionList[this.index] = params.expression
this.insertText(params.expression)
2021-05-12 19:07:07 +08:00
this.$emit('change', params.expression)
2021-03-19 18:52:19 +08:00
return
}
2021-03-19 18:52:19 +08:00
this.$post('/expression/tmpl/render', params).then(res => {
if (res.code === 200) {
this.tempBoxShow = false
// this.expressionList[this.index] = res.data.expression
this.insertText(res.data.expression)
2021-05-12 19:07:07 +08:00
this.$emit('change', res.data.expression)
2021-03-19 18:52:19 +08:00
}
})
} else {
this.tempBox = {}
}
},
2021-03-19 18:52:19 +08:00
format (str) {
2021-03-22 10:25:41 +08:00
const arr = str.split('.')
const keyword = arr[0].toLowerCase()
2021-03-19 18:52:19 +08:00
switch (keyword) {
case 'asset':
case 'module':
case 'endpoint':
case 'datacenter':
case 'project':
return {
arr: this[keyword + 'Option'],
key: keyword,
value: ((keyword == 'module' || keyword == 'project' || keyword == 'datacenter') ? 'name' : 'host')
}
default:
return {
key: false
}
}
},
getAllOptins (key, arr) {
switch (key) {
case 'asset':
this.$get('asset/asset', { pageNo: 1, pageSize: -1 }).then(response => {
2021-03-19 18:52:19 +08:00
if (response.code == 200) {
2021-03-22 10:25:41 +08:00
const arr = []
2021-03-19 18:52:19 +08:00
response.data.list.forEach(asset => {
asset.name = asset.sn
const dcF = arr.find(dc => dc.id === asset.dc.id)
if (dcF) {
dcF.children.push(asset)
2021-03-19 18:52:19 +08:00
} else {
const dc = { ...asset.dc }
dc.children = [asset]
arr.push(dc)
2021-03-19 18:52:19 +08:00
}
})
this.assetOption = arr
}
})
break
case 'module':
this.$get('monitor/module/tree', { pageNo: 1, pageSize: -1 }).then(response => {
2021-03-19 18:52:19 +08:00
if (response.code == 200) {
this.moduleOption = response.data.list
2021-03-19 18:52:19 +08:00
}
})
break
case 'endpoint':
this.$get('monitor/endpoint/tree', { pageNo: 1, pageSize: -1 }).then(response => {
2021-03-19 18:52:19 +08:00
if (response.code == 200) {
this.endpointOption = response.data.list
2021-03-19 18:52:19 +08:00
}
})
break
case 'datacenter':
this.$get('dc', { pageNo: 1, pageSize: -1 }).then(response => {
2021-03-19 18:52:19 +08:00
if (response.code == 200) {
this.datacenterOption = response.data.list
}
})
break
case 'project':
this.$get('monitor/project', { pageNo: 1, pageSize: -1 }).then(response => {
2021-03-19 18:52:19 +08:00
if (response.code == 200) {
this.projectOption = response.data.list
}
})
break
default:
break
}
},
silenceChange (val, key) {
this.tempBox[key] = val.name
2021-03-22 10:25:41 +08:00
this.tempBoxId[key] = val.id
2021-03-19 18:52:19 +08:00
},
clearValue (key) {
this.tempBox[key] = ''
},
tempBoxClose () {
this.cascaderValue = ''
},
insertText (insertTxt) {
// 获取el-input中的input元素
// const elInput = this.$refs.elInput.$el.firstElementChild
// 获取el-input的值
// const txt = elInput.value
// 获取选区开始位置
// const startPos = elInput.selectionStart
// 获取选区结束位置
// const endPos = elInput.selectionEnd
// if (startPos === undefined || endPos === undefined) return
// 将文本插入光标位置
// this.expressionList[this.index] = txt.substring(0, startPos) + insertTxt + txt.substring(endPos)
// 将光标移至文本末尾
// elInput.focus()
// elInput.selectionStart = startPos + insertTxt.length
// elInput.selectionEnd = startPos + insertTxt.length
this.expressionList[this.index] = insertTxt
this.codeMirrorValue[this.index] = insertTxt
this.initCodeMirror()
}
2021-03-19 18:52:19 +08:00
/* setMsg:function(){
this.appendMsg
2021-03-19 18:52:19 +08:00
} */
},
watch: {
2021-08-02 20:36:10 +08:00
dropDownVisible (n, o) {
2021-03-19 18:52:19 +08:00
if (this.$refs.metricSelector) {
this.$refs.metricSelector.dropDownVisible = n
if (!this.expressionList[this.index] || this.expressionList[this.index] == '') {
this.cascaderValue = ''
}
2021-03-19 18:52:19 +08:00
}
},
metricOptionsParent: {
deep: true,
immediate: true,
handler (n, o) {
if (n) {
this.metricOptions = JSON.parse(JSON.stringify(n))
}
}
},
2022-04-22 18:55:50 +08:00
expressionList: {
deep: true,
immediate: true,
handler (n, o) {
2022-04-22 18:55:50 +08:00
this.codeMirrorValue[this.index] = n[this.index]
if (this.isTopo) {
setTimeout(() => {
const text = this.newView.state.doc.toString()
this.newView.dispatch(
this.newView.state.update({
changes: { from: 0, to: text.length, insert: this.codeMirrorValue[this.index] }
})
)
}, 200)
}
}
},
2022-04-22 18:55:50 +08:00
// codeMirrorValue:{
// deep:true,
// imediate:true,
// handler(n){
// if(n){
// this.oldcCodeLength = n.length
// }
// }
// }
type: {
deep: true,
immediate: true,
handler (n) {
if (n !== 'log') {
this.$nextTick(() => {
this.initCodeMirror()
})
}
}
}
}
2021-03-19 18:52:19 +08:00
}
</script>
<style>
2022-04-19 11:57:55 +08:00
.input-box .el-input__inner {
height: 30px;
}
.nz-temp-box /deep/ .el-dialog__body {
padding: 10px 20px 0 20px;
}
.nz-temp-box /deep/ .el-dialog__footer {
margin-top: 0;
}
.nz-temp-box .nz-btn-style-light {
margin-right: 10px;
}
.nz-temp-box .nz-btn-style-normal {
margin-left: 10px;
}
</style>