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

532 lines
20 KiB
Vue
Raw Normal View History

2024-05-18 08:53:17 +00:00
<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',
2024-05-28 07:53:11 +00:00
types: ['OPENSTACK', 'VMWARE', 'INSPURRAIL', 'CECSTACK', 'CNWARE', 'EASYSTACK', 'ARCHEROS', 'CLOUDTOWER', 'FUSIONSPHERE']
2024-05-18 08:53:17 +00:00
})
}).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>