532 lines
20 KiB
Vue
532 lines
20 KiB
Vue
<template>
|
||
<div class="wrapper">
|
||
<div v-show="!detailFlag">
|
||
<table-search :configs="searchConfigs" :onSearch="handleSearch">
|
||
<template v-slot:operate>
|
||
<el-button type="primary" @click="handleCreate()"> <i class="el-icon-plus"></i>新增 </el-button>
|
||
</template>
|
||
</table-search>
|
||
<basic-table :data="list" :params="params" :get-list="getList" :total="total">
|
||
<el-table-column show-overflow-tooltip label="名称" prop="name">
|
||
<template slot-scope="scope">
|
||
<span class="detail-href" @click="getDetail(scope.row)">{{ scope.row.name }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column show-overflow-tooltip label="创建时间" prop="gmtCreate"> </el-table-column>
|
||
|
||
<el-table-column show-overflow-tooltip label="操作" width="220px">
|
||
<template slot-scope="scope">
|
||
<el-button type="text" @click="handleCreate(scope.row)"><i class="el-icon-edit"></i>编辑</el-button>
|
||
<div class="action-divider"></div>
|
||
<el-button type="text" @click="handleDelete(scope.row.id)"><i class="el-icon-delete"></i> 删除</el-button>
|
||
<div class="action-divider"></div>
|
||
<el-dropdown trigger="click">
|
||
<span class="el-dropdown-link"> 更多<i class="el-icon-arrow-down el-icon--right"></i> </span>
|
||
<el-dropdown-menu slot="dropdown">
|
||
<el-dropdown-item @click.native="analysis(scope.row)">分析</el-dropdown-item>
|
||
<el-dropdown-item @click.native="handleHistory(scope.row.id)">历史</el-dropdown-item>
|
||
</el-dropdown-menu>
|
||
</el-dropdown>
|
||
</template>
|
||
</el-table-column>
|
||
</basic-table>
|
||
</div>
|
||
<el-dialog :title="textMap[dialogStatus]" :close-on-click-modal="false" v-if="addFlag" :visible.sync="addFlag" width="70%">
|
||
<basic-form :model="addData" ref="addData" label-width="110px">
|
||
<el-row>
|
||
<el-col :span="24">
|
||
<basic-form-item label="名称:" prop="name" validate="required">
|
||
<el-input v-model="addData.name" auto-complete="off"></el-input>
|
||
</basic-form-item>
|
||
</el-col>
|
||
<el-col :span="24">
|
||
<el-form-item label="规则:">
|
||
<el-row class="rule-box">
|
||
<el-col :span="24" v-for="(row, index) in addData.rules" :key="index" class="m-t">
|
||
<el-row :gutter="10">
|
||
<span class="m-l pull-left" style="display: inline-block; width: 150px">{{ row.metric | alarmMetric }}:</span>
|
||
<el-col :span="5">
|
||
<el-select v-model="row.operator" clearable>
|
||
<el-option v-for="(item, indexItem) in relationList" :key="indexItem" :label="item.value" :value="item.value"></el-option>
|
||
</el-select>
|
||
</el-col>
|
||
<el-col :span="5">
|
||
<el-input-number style="width: 100%" v-model="row.value" controls-position="right" :min="0" :max="100"></el-input-number>
|
||
</el-col>
|
||
<el-col :span="4">
|
||
<el-select v-model="row.valueType" clearable>
|
||
<el-option v-for="item in valueType" :key="item.value" :label="item.name" :value="item.value"></el-option>
|
||
</el-select>
|
||
</el-col>
|
||
<el-col :span="4">
|
||
<el-select v-model="row.relation" clearable>
|
||
<el-option v-for="item in relationType" :key="item.value" :label="item.name" :value="item.value"></el-option>
|
||
</el-select>
|
||
</el-col>
|
||
</el-row>
|
||
</el-col>
|
||
</el-row>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
</basic-form>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button type="ghost" @click.native="addFlag = false">取消</el-button>
|
||
<el-button type="primary" @click.native="addSubmit">确定</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
<el-dialog :title="title2" :close-on-click-modal="false" v-if="analysisFlag" :visible.sync="analysisFlag" width="70%">
|
||
<basic-form :model="analysisData" ref="analysisData" label-width="80px">
|
||
<el-row :gutter="10">
|
||
<el-col :span="8">
|
||
<basic-form-item label="平台:" prop="vendorId" validate="required">
|
||
<el-select :disabled="analysisStatus == 'history'" v-model="analysisData.vendorId" clearable>
|
||
<el-option v-for="item in vendorData" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||
</el-select>
|
||
</basic-form-item>
|
||
</el-col>
|
||
<el-col :span="16">
|
||
<basic-form-item label="时间:" prop="time" validate="required">
|
||
<el-date-picker :disabled="analysisStatus == 'history'" v-model="analysisData.time" :picker-options="forbid" type="datetimerange" value-format="yyyy-MM-dd HH:mm:ss" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"> </el-date-picker>
|
||
<el-button style="margin-left: 10px" v-if="analysisStatus != 'history'" type="primary" @click="handleAnalysis()">分析</el-button>
|
||
</basic-form-item>
|
||
</el-col>
|
||
<el-col :span="24">
|
||
<el-form-item label="规则:">
|
||
<el-row class="rule-box">
|
||
<el-col :span="24" v-for="(row, index) in analysisData.rules" :key="index" class="m-t">
|
||
<el-row :gutter="10">
|
||
<span class="m-l pull-left" style="display: inline-block; width: 150px">{{ row.metric | alarmMetric }}:</span>
|
||
<el-col :span="5">
|
||
<el-select disabled v-model="row.operator">
|
||
<el-option v-for="(item, indexItem) in relationList" :key="indexItem" :label="item.value" :value="item.value"></el-option>
|
||
</el-select>
|
||
</el-col>
|
||
<el-col :span="5">
|
||
<el-input disabled type="number" min="0" v-model="row.value" auto-complete="off"></el-input>
|
||
</el-col>
|
||
<el-col :span="4">
|
||
<el-select disabled v-model="row.valueType">
|
||
<el-option v-for="item in valueType" :key="item.value" :label="item.name" :value="item.value"></el-option>
|
||
</el-select>
|
||
</el-col>
|
||
<el-col :span="4">
|
||
<el-select disabled v-model="row.relation">
|
||
<el-option v-for="item in relationType" :key="item.value" :label="item.name" :value="item.value"></el-option>
|
||
</el-select>
|
||
</el-col>
|
||
</el-row>
|
||
</el-col>
|
||
</el-row>
|
||
</el-form-item>
|
||
</el-col>
|
||
<div v-if="analysisStatus == 'history'">
|
||
<el-col :span="12" class="m-b" v-for="(chart, index) in charts" :key="index">
|
||
<el-card class="box-card">
|
||
<div slot="header" class="clearfix">
|
||
<span>{{ chart.name }}({{ chart.unit }})</span>
|
||
</div>
|
||
<div>
|
||
<bar-reverse-charts :data="chart" height="300px" :setting="configs"></bar-reverse-charts>
|
||
</div>
|
||
</el-card>
|
||
</el-col>
|
||
<el-col :span="24">
|
||
<SmartTable :data="tableList">
|
||
<el-table-column show-overflow-tooltip label="名称" prop="name"> </el-table-column>
|
||
|
||
<el-table-column show-overflow-tooltip label="IP" prop="ip"> </el-table-column>
|
||
|
||
<el-table-column show-overflow-tooltip label="CPU利用率(%)" prop="cpuUsage"> </el-table-column>
|
||
|
||
<el-table-column show-overflow-tooltip label="内存利用率(%)" prop="memUsage"> </el-table-column>
|
||
<el-table-column show-overflow-tooltip label="磁盘利用率(%)" prop="diskUsedPercent"> </el-table-column>
|
||
<div slot="pagination"></div>
|
||
</SmartTable>
|
||
</el-col>
|
||
</div>
|
||
</el-row>
|
||
</basic-form>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button type="primary" v-if="analysisStatus == 'history'" :disabled="analysisId == null" @click.native="handleExport(analysisId)">导出</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
<el-dialog title="历史记录" :close-on-click-modal="false" v-if="historyFlag" :visible.sync="historyFlag" width="70%">
|
||
<basic-table :data="historyList" :params="params2" :get-list="getHistory" :total="total2">
|
||
<el-table-column show-overflow-tooltip label="名称" prop="name">
|
||
<template slot-scope="scope">
|
||
<span class="detail-href" @click="getAnalysisDetail(scope.row)">{{ scope.row.ruleName }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column show-overflow-tooltip label="开始时间" prop="startTime"></el-table-column>
|
||
<el-table-column show-overflow-tooltip label="结束时间" prop="endTime"></el-table-column>
|
||
|
||
<el-table-column show-overflow-tooltip label="创建时间" prop="gmtCreate"> </el-table-column>
|
||
<el-table-column show-overflow-tooltip label="操作" width="160px">
|
||
<template slot-scope="scope">
|
||
<el-button type="text" @click="deleteHistory(scope.row.id)"><i class="el-icon-delete"></i> 删除</el-button>
|
||
<div class="action-divider"></div>
|
||
<el-button type="text" @click="handleExport(scope.row.id)"><i class="el-icon-info"></i> 导出</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</basic-table>
|
||
<div slot="footer" class="dialog-footer"></div>
|
||
</el-dialog>
|
||
<common-detail v-if="detailFlag" :title="detailData.name" @goBack="goBack">
|
||
<el-card class="m-t-n" slot="custom_content">
|
||
<basic-form label-width="110px">
|
||
<div v-for="(row, index) in detailData.rules" :key="index" class="m-t">
|
||
<el-row :gutter="10">
|
||
<span class="m-l pull-left" style="display: inline-block; width: 100px">{{ row.metric | alarmMetric }}:</span>
|
||
<el-col :span="5">
|
||
<el-input disabled v-model="row.operator"></el-input>
|
||
</el-col>
|
||
<el-col :span="5">
|
||
<el-input-number disabled style="width: 100%" v-model="row.value" controls-position="right" :min="0" :max="100"></el-input-number>
|
||
</el-col>
|
||
<el-col :span="5">
|
||
<el-select disabled v-model="row.valueType" clearable>
|
||
<el-option v-for="item in valueType" :key="item.value" :label="item.name" :value="item.value"></el-option>
|
||
</el-select>
|
||
</el-col>
|
||
<el-col :span="5">
|
||
<el-select disabled v-model="row.relation" clearable>
|
||
<el-option v-for="item in relationType" :key="item.value" :label="item.name" :value="item.value"></el-option>
|
||
</el-select>
|
||
</el-col>
|
||
</el-row>
|
||
</div>
|
||
</basic-form>
|
||
</el-card>
|
||
</common-detail>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { getRules, createRules, modifyRules, removeRules, getDetail, getSnapshot, removeSnapshot, getSnapshotDetail, handleAnalysis, exportAnalysis } from 'services/monitor/analysis'
|
||
import { conditionCloudVendor } from 'services/platform/index'
|
||
import { configs } from './chartConfig'
|
||
const searchConfigs = [
|
||
{ type: 'Input', label: '名称', value: 'name' },
|
||
{ type: 'Const', value: 'type', initValue: 'cloudServerRecycle' }
|
||
]
|
||
const relationList = [{ value: '>' }, { value: '>=' }, { value: '==' }, { value: '<' }, { value: '<=' }, { value: '!=' }]
|
||
const valueType = [
|
||
{ name: '最大值', value: 'max' },
|
||
{ name: '最小值', value: 'min' },
|
||
{ name: '平均值', value: 'avg' }
|
||
]
|
||
const relationType = [
|
||
{ name: '与', value: 'and' },
|
||
{ name: '或', value: 'or' }
|
||
]
|
||
export default {
|
||
data() {
|
||
return {
|
||
configs,
|
||
searchConfigs,
|
||
relationList,
|
||
relationType,
|
||
valueType,
|
||
list: null,
|
||
total: null,
|
||
params: {
|
||
page: 1,
|
||
rows: 10
|
||
},
|
||
params2: {
|
||
page: 1,
|
||
rows: 10
|
||
},
|
||
// 新增编辑
|
||
addFlag: false,
|
||
addData: {},
|
||
textMap: {
|
||
update: '编辑回收分析',
|
||
create: '新增回收分析'
|
||
},
|
||
dialogStatus: '',
|
||
analysisFlag: false,
|
||
analysisData: {},
|
||
analysisId: null,
|
||
charts: null,
|
||
tableList: [],
|
||
vendorData: [],
|
||
historyFlag: false,
|
||
analysisStatus: '',
|
||
ruleId: null,
|
||
historyList: [],
|
||
total2: null,
|
||
detailFlag: false,
|
||
detailData: {},
|
||
title2: ''
|
||
}
|
||
},
|
||
computed: {
|
||
forbid() {
|
||
const time = {
|
||
disabledDate: (time) => {
|
||
return time.getTime() > new Date().getTime() // - (24 * 60 * 60 * 1000);
|
||
}
|
||
}
|
||
return time
|
||
}
|
||
},
|
||
created() {},
|
||
methods: {
|
||
getList() {
|
||
getRules(this.params).then((data) => {
|
||
if (data.success) {
|
||
this.list = data.data.rows
|
||
this.total = data.data.total
|
||
}
|
||
})
|
||
},
|
||
// 查询
|
||
handleSearch(params) {
|
||
this.params.page = 1
|
||
this.params.params = params
|
||
this.getList()
|
||
},
|
||
handleCreate(data) {
|
||
if (data) {
|
||
this.addData = Object.assign({}, data)
|
||
this.dialogStatus = 'update'
|
||
this.addData.rules = JSON.parse(this.addData.rules)
|
||
const arr = this.addData.rules.map((item) => item.metric)
|
||
const attr = ['cpuUsageAverage', 'memUsageAverage', 'diskUsedPercent']
|
||
attr.forEach((item) => {
|
||
if (arr.indexOf(item) == -1) {
|
||
this.addData.rules.push({ metric: item, operator: '', value: '', valueType: '', relation: '' })
|
||
}
|
||
})
|
||
this.addFlag = true
|
||
} else {
|
||
this.addData = {
|
||
name: '',
|
||
type: 'cloudServerRecycle',
|
||
rules: [
|
||
{ metric: 'cpuUsageAverage', operator: '', value: '', valueType: '', relation: '' },
|
||
{ metric: 'memUsageAverage', operator: '', value: '', valueType: '', relation: '' },
|
||
{ metric: 'diskUsedPercent', operator: '', value: '', valueType: '', relation: '' }
|
||
]
|
||
}
|
||
this.dialogStatus = 'create'
|
||
this.addFlag = true
|
||
}
|
||
},
|
||
addSubmit() {
|
||
this.$refs.addData.validate((valid) => {
|
||
if (valid) {
|
||
const rulesFlag = this.addData.rules.every((item) => {
|
||
if ((item.operator && item.value && item.valueType) || (!item.operator && !item.value && !item.valueType)) {
|
||
return true
|
||
} else {
|
||
return false
|
||
}
|
||
})
|
||
if (!rulesFlag) {
|
||
return this.$message({
|
||
message: '请确保规则信息填写完整',
|
||
type: 'error'
|
||
})
|
||
}
|
||
const addData = {
|
||
rules: []
|
||
}
|
||
const edit = ['id', 'name', 'type', 'gmtCreate', 'creatorId', 'deleted']
|
||
edit.forEach((attr) => {
|
||
addData[attr] = this.addData[attr]
|
||
})
|
||
addData.rules = Object.assign([], this.addData.rules)
|
||
for (let j = 0; j < addData.rules.length; j++) {
|
||
if (!addData.rules[j].operator) {
|
||
addData.rules.splice(j, 1)
|
||
j--
|
||
}
|
||
}
|
||
if (!addData.rules.length) {
|
||
return this.$message.error('至少选一项规则填写!')
|
||
}
|
||
if (this.dialogStatus == 'update') {
|
||
modifyRules(addData).then((data) => {
|
||
if (data.success) {
|
||
this.$message.success(data.message)
|
||
this.getList()
|
||
this.addFlag = false
|
||
}
|
||
})
|
||
} else {
|
||
createRules(addData).then((data) => {
|
||
if (data.success) {
|
||
this.$message.success(data.message)
|
||
this.getList()
|
||
this.addFlag = false
|
||
}
|
||
})
|
||
}
|
||
}
|
||
})
|
||
},
|
||
handleDelete(id) {
|
||
this.$confirm('您确定要删除该方案吗?', '提示', {
|
||
confirmButtonClass: 'el-button--danger',
|
||
type: 'warning'
|
||
})
|
||
.then(() => {
|
||
removeRules(id).then((data) => {
|
||
if (data.success) {
|
||
this.$message.success({
|
||
message: data.message,
|
||
type: 'success'
|
||
})
|
||
this.getList()
|
||
}
|
||
})
|
||
})
|
||
.catch(() => {})
|
||
},
|
||
analysis(row) {
|
||
this.title2 = '分析'
|
||
this.charts = []
|
||
this.tableList = []
|
||
this.analysisData = Object.assign({}, row)
|
||
this.analysisData.rules = JSON.parse(this.analysisData.rules)
|
||
this.analysisStatus = 'analysis'
|
||
this.analysisId = null
|
||
this.getVendorData()
|
||
this.analysisFlag = true
|
||
},
|
||
handleAnalysis() {
|
||
this.$refs.analysisData.validate((valid) => {
|
||
if (valid) {
|
||
if (!this.analysisData.time.length) {
|
||
return this.$message.error('请选择分析时间范围!')
|
||
}
|
||
handleAnalysis({
|
||
id: this.analysisData.id,
|
||
startTime: this.analysisData.time[0],
|
||
endTime: this.analysisData.time[1],
|
||
vendorId: this.analysisData.vendorId
|
||
}).then((data) => {
|
||
if (data.success) {
|
||
this.$message.success(data.message)
|
||
this.getList()
|
||
this.analysisFlag = false
|
||
}
|
||
})
|
||
}
|
||
})
|
||
},
|
||
handleHistory(id) {
|
||
this.ruleId = id
|
||
this.handleSearchHistory()
|
||
this.historyFlag = true
|
||
},
|
||
getHistory() {
|
||
getSnapshot(this.params2).then((data) => {
|
||
this.historyList = data.data.rows
|
||
this.total2 = data.data.total
|
||
})
|
||
},
|
||
handleSearchHistory() {
|
||
this.params2.page = 1
|
||
this.params2.params = this.$tools.handleSearchParam({
|
||
ruleId: this.ruleId
|
||
})
|
||
this.getHistory()
|
||
},
|
||
getAnalysisDetail(row) {
|
||
this.title2 = '分析结果'
|
||
this.analysisId = row.id
|
||
this.getVendorData()
|
||
getSnapshotDetail({
|
||
id: row.id,
|
||
startTime: row.startTime,
|
||
endTime: row.endTime
|
||
}).then((data) => {
|
||
if (data.success) {
|
||
this.analysisData.vendorId = row.vendorId
|
||
this.analysisData.time = [row.startTime, row.endTime]
|
||
this.analysisData.rules = JSON.parse(row.rule)
|
||
this.charts = JSON.parse(data.data.result).charts.map((item) => {
|
||
const { values, name } = item
|
||
return {
|
||
...item,
|
||
values: [
|
||
{
|
||
name,
|
||
data: values
|
||
}
|
||
]
|
||
}
|
||
})
|
||
this.tableList = JSON.parse(data.data.result).list
|
||
this.analysisStatus = 'history'
|
||
this.analysisFlag = true
|
||
}
|
||
})
|
||
},
|
||
deleteHistory(id) {
|
||
this.$confirm('您确定要删除该历史吗?', '提示', {
|
||
confirmButtonClass: 'el-button--danger',
|
||
type: 'warning'
|
||
})
|
||
.then(() => {
|
||
removeSnapshot(id).then((data) => {
|
||
if (data.success) {
|
||
this.$message.success({
|
||
message: data.message,
|
||
type: 'success'
|
||
})
|
||
this.handleHistory(this.ruleId)
|
||
}
|
||
})
|
||
})
|
||
.catch(() => {})
|
||
},
|
||
getDetail(row) {
|
||
getDetail(row.id).then((data) => {
|
||
if (data.success) {
|
||
this.detailData = data.data
|
||
this.detailData.rules = JSON.parse(this.detailData.rules)
|
||
this.detailFlag = true
|
||
}
|
||
})
|
||
},
|
||
// 导出任务
|
||
handleExport(id) {
|
||
const params = JSON.stringify({ operation: 'download' })
|
||
exportAnalysis(id, params)
|
||
},
|
||
getVendorData() {
|
||
conditionCloudVendor({
|
||
condition: JSON.stringify({
|
||
condition: 'listByTypes',
|
||
types: ['OPENSTACK', 'VMWARE', 'INSPURRAIL', 'CECSTACK', 'CNWARE', 'EASYSTACK', 'ARCHEROS', 'CLOUDTOWER', 'FUSIONSPHERE']
|
||
})
|
||
}).then((data) => {
|
||
if (data.success) {
|
||
this.vendorData = data.data
|
||
}
|
||
})
|
||
},
|
||
goBack() {
|
||
this.detailFlag = false
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
<style scoped>
|
||
.search-item {
|
||
width: 12%;
|
||
}
|
||
.rule-box {
|
||
padding: 10px;
|
||
padding-top: 0px;
|
||
border: 1px solid #dcdfe6;
|
||
}
|
||
</style>
|