cos-web/src/views/cosa/config/recycleResource.vue

532 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<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>