625 lines
18 KiB
Vue
625 lines
18 KiB
Vue
<template>
|
|
<div>
|
|
<cb-detail v-if="detailFlag" :title="detail.name" :data="detail" @goBack="goBack">
|
|
<template v-slot:item_container>
|
|
<cb-detail-item label="名称">{{ detail.name }}</cb-detail-item>
|
|
<cb-detail-item label="所属平台">{{ detail.vendorName }}</cb-detail-item>
|
|
<cb-detail-item label="描述">{{ detail.remark }}</cb-detail-item>
|
|
<cb-detail-item label="所属地域">{{ detail.regionName }}</cb-detail-item>
|
|
<!-- <cb-detail-item label="所属租户">{{ detail.tenantName }}</cb-detail-item> -->
|
|
</template>
|
|
<el-tabs value="second">
|
|
<el-tab-pane label="规则列表" name="second">
|
|
<cb-advance-table :data="ruleDetailData" :params="paramd" :columns="columns_detail" :get-list="getDetailHost" :total="ruleDetailTotal" :loading="loading">
|
|
<template #protocol="val, record">
|
|
{{ record.protocol | secruityProtocol }}
|
|
</template>
|
|
<template #direction="val, record">
|
|
{{ record.direction | securityGroupFilter }}
|
|
</template>
|
|
<template #tenantName="val, record">
|
|
{{ record.etherType | etherType }}
|
|
</template>
|
|
<template #remoteIpPrefix="val, record">
|
|
{{ record.destinationAddressPrefix || (record.etherType == 'IPv6' ? '::/0' : '0.0.0.0/0') }}
|
|
</template>
|
|
<template #operate="val, record">
|
|
<el-button type="text" icon="el-icon-delete" @click="ruleRemove(record)" :disabled="record.disabled">删除 </el-button>
|
|
</template>
|
|
</cb-advance-table>
|
|
</el-tab-pane>
|
|
</el-tabs>
|
|
</cb-detail>
|
|
<el-dialog :title="titleName" :visible.sync="addFlag" v-if="addFlag" width="50%" :before-close="handleClose">
|
|
<security-item ref="securityItem" :vendorId="platformObject.vendorId" :addData="addData"></security-item>
|
|
<span slot="footer" class="dialog-footer">
|
|
<el-button @click="addFlag = false">取 消</el-button>
|
|
<el-button type="primary" @click="dialogOk(1, 'addData')">确 定</el-button>
|
|
</span>
|
|
</el-dialog>
|
|
<el-dialog title="添加规则" :visible.sync="ruleFlag" width="50%">
|
|
<span>
|
|
<security-rule ref="securityRule" :addData="ruleData" v-if="ruleFlag"></security-rule>
|
|
</span>
|
|
<span slot="footer" class="dialog-footer">
|
|
<el-button type="ghost" @click="ruleFlag = false">取 消</el-button>
|
|
<el-button type="primary" @click="dialogOk(2, 'ruleData')">确 定</el-button>
|
|
</span>
|
|
</el-dialog>
|
|
<el-card class="wrapper" v-if="!detailFlag">
|
|
<cb-advance-table title="安全组列表" :search-configs="searchConfigs" :data="tableData" :params="params" :columns="columns" :get-list="getData" :total="total" :loading="loading" @selection-change="selectChange">
|
|
<template #name="val, record">
|
|
<span class="detail-href" @click="getDetail(record.id)">{{ val }}</span>
|
|
</template>
|
|
<template v-slot:action>
|
|
<el-button type="primary" @click="dialog('addFlag', 1)"> <i class="el-icon-plus" /> 新增 </el-button>
|
|
</template>
|
|
<template #operate="val, record">
|
|
<el-button :disabled="record.disabled" type="text" @click="dropdownClick({ id: record.id, index: 2 })"> <i class="el-icon-delete"></i> 删除 </el-button>
|
|
<div class="action-divider"></div>
|
|
<el-button :disabled="record.disabled" type="text" @click="dropdownClick({ id: record.id, index: 3 })"> 添加规则 </el-button>
|
|
</template>
|
|
</cb-advance-table>
|
|
</el-card>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import securityItem from './components/securityItem.vue'
|
|
import securityRule from './components/securityRule.vue'
|
|
import { getRegion } from 'services/platform/index'
|
|
import { removeGroups, removeGroupRules, getGroup, removeGroup, modifyGroup, createGroup, detailGroup, getGroupRule, createGroupRule, removeGroupRule, detailGroupRule } from 'views/resource/ctstack/services/group'
|
|
const detailSetting = {
|
|
type: 'safe_group',
|
|
columns: [
|
|
[
|
|
{ name: '名称', value: 'name' },
|
|
{ name: '所属平台', value: 'vendorName' },
|
|
{ name: '描述', value: 'remark' }
|
|
],
|
|
[
|
|
{ name: '所属地域', value: 'regionName' }
|
|
// { name: '所属租户', value: 'tenantName' }
|
|
]
|
|
]
|
|
}
|
|
export default {
|
|
components: {
|
|
securityItem,
|
|
securityRule
|
|
},
|
|
props: {
|
|
platformObject: {
|
|
type: Object,
|
|
default: function () {
|
|
return {
|
|
vendorId: -1,
|
|
operate: -1
|
|
}
|
|
}
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
ruleDetailData: [],
|
|
ruleDetailTotal: 0,
|
|
detailSetting,
|
|
paramd: {
|
|
page: 1,
|
|
rows: 10
|
|
},
|
|
detail: '',
|
|
detailFlag: false,
|
|
params: {
|
|
page: 1,
|
|
rows: 10
|
|
},
|
|
searchData: {
|
|
name: '',
|
|
regionId: ''
|
|
},
|
|
regionList: [],
|
|
tableData: [],
|
|
total: 0,
|
|
titleName: '新增',
|
|
addFlag: false,
|
|
addData: {},
|
|
ruleData: {
|
|
remoteIpPrefix: '',
|
|
portMin: '',
|
|
portMax: '',
|
|
direction: 'ingress',
|
|
protocol: 'TCP'
|
|
},
|
|
ruleFlag: false,
|
|
id: '',
|
|
idList: [],
|
|
selectList: [],
|
|
ruleIdList: [],
|
|
ruleSelectList: [],
|
|
columns: [
|
|
{
|
|
label: '名称',
|
|
prop: 'name',
|
|
scopedSlots: { customRender: 'name' }
|
|
},
|
|
{
|
|
label: '所属VPC',
|
|
prop: 'vpcName'
|
|
},
|
|
{
|
|
label: '描述',
|
|
prop: 'remark'
|
|
},
|
|
{
|
|
label: '所属地域',
|
|
prop: 'regionName'
|
|
},
|
|
{
|
|
label: '所属平台',
|
|
prop: 'vendorName'
|
|
},
|
|
{
|
|
label: '操作',
|
|
disabled: true,
|
|
width: '190px',
|
|
scopedSlots: { customRender: 'operate' }
|
|
}
|
|
],
|
|
searchConfigs: [
|
|
{ label: '名称', value: 'name', type: 'Input' },
|
|
{
|
|
value: 'regionId',
|
|
type: 'Select',
|
|
data: [],
|
|
label: '所属地域',
|
|
props: { value: 'regionId' }
|
|
},
|
|
{ type: 'Const', value: 'vendorId', initValue: this.platformObject.vendorId }
|
|
],
|
|
loading: false,
|
|
columns_detail: [
|
|
{
|
|
label: 'IP协议',
|
|
prop: 'protocol',
|
|
scopedSlots: { customRender: 'protocol' }
|
|
},
|
|
{
|
|
label: '方向',
|
|
prop: 'direction',
|
|
scopedSlots: { customRender: 'direction' }
|
|
},
|
|
{
|
|
label: '以太网类型',
|
|
prop: 'etherType',
|
|
scopedSlots: { customRender: 'etherType' }
|
|
},
|
|
{
|
|
label: '端口范围',
|
|
prop: 'destinationPortRange'
|
|
},
|
|
{
|
|
label: '远端地址',
|
|
prop: 'destinationAddressPrefix',
|
|
scopedSlots: { customRender: 'remoteIpPrefix' }
|
|
},
|
|
{
|
|
label: '操作',
|
|
disabled: true,
|
|
width: '220px',
|
|
scopedSlots: { customRender: 'operate' }
|
|
}
|
|
],
|
|
isCreate: false
|
|
}
|
|
},
|
|
methods: {
|
|
selectChange(val) {
|
|
this.selectList = val
|
|
},
|
|
ruleRefreshId() {
|
|
this.ruleIdList = []
|
|
this.ruleSelectList.forEach(item => {
|
|
this.ruleIdList.push(item.id)
|
|
})
|
|
},
|
|
// 单选
|
|
ruleHandleSelectItem(selection, row) {
|
|
this.ruleRefreshId()
|
|
if (this.ruleIdList.indexOf(row.id) > -1) {
|
|
for (let j = 0; j < this.ruleSelectList.length; j++) {
|
|
const item = this.ruleSelectList[j]
|
|
if (item.id == row.id) {
|
|
this.ruleSelectList.splice(j, 1)
|
|
break
|
|
}
|
|
}
|
|
} else {
|
|
this.ruleSelectList.push(row)
|
|
}
|
|
},
|
|
// 全选
|
|
ruleHandleSelectAll(selection) {
|
|
this.ruleRefreshId()
|
|
if (selection.length) {
|
|
// 全选情况下
|
|
this.ruleDetailData.forEach(item => {
|
|
if (this.idList.indexOf(item.id) == -1) {
|
|
this.ruleSelectList.push(item)
|
|
}
|
|
})
|
|
} else {
|
|
// 全不选情况下
|
|
this.ruleDetailData.forEach(item => {
|
|
if (this.idList.indexOf(item.id) > -1) {
|
|
for (let j = 0; j < this.ruleSelectList.length; j++) {
|
|
const row = this.ruleSelectList[j]
|
|
if (item.id == row.id) {
|
|
this.ruleSelectList.splice(j, 1)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
},
|
|
refreshId() {
|
|
this.idList = []
|
|
this.selectList.forEach(item => {
|
|
this.idList.push(item.id)
|
|
})
|
|
},
|
|
// 单选
|
|
handleSelectItem(selection, row) {
|
|
this.refreshId()
|
|
if (this.idList.indexOf(row.id) > -1) {
|
|
for (let j = 0; j < this.selectList.length; j++) {
|
|
const item = this.selectList[j]
|
|
if (item.id == row.id) {
|
|
this.selectList.splice(j, 1)
|
|
break
|
|
}
|
|
}
|
|
} else {
|
|
this.selectList.push(row)
|
|
}
|
|
},
|
|
// 全选
|
|
handleSelectAll(selection) {
|
|
this.refreshId()
|
|
if (selection.length) {
|
|
// 全选情况下
|
|
selection.forEach(item => {
|
|
if (this.idList.indexOf(item.id) == -1) {
|
|
this.selectList.push(item)
|
|
}
|
|
})
|
|
} else {
|
|
// 全不选情况下
|
|
this.tableData.forEach(item => {
|
|
if (this.idList.indexOf(item.id) > -1) {
|
|
for (let j = 0; j < this.selectList.length; j++) {
|
|
const row = this.selectList[j]
|
|
if (item.id == row.id) {
|
|
this.selectList.splice(j, 1)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
},
|
|
ruleHandleDelete() {
|
|
this.ruleRefreshId()
|
|
const list = this.ruleIdList
|
|
this.$confirm('此操作将删除所选规则, 是否继续?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(() => {
|
|
removeGroupRules(list).then(data => {
|
|
if (data.success) {
|
|
this.$message({
|
|
type: 'success',
|
|
message: data.message
|
|
})
|
|
this.getData()
|
|
this.ruleSelectList = []
|
|
}
|
|
})
|
|
})
|
|
},
|
|
// 删除规则
|
|
ruleRemove(data) {
|
|
this.$confirm('此操作将永久删除该规则, 是否继续?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(() => {
|
|
removeGroupRule(data.id).then(data => {
|
|
if (data.success) {
|
|
this.$message({
|
|
type: 'success',
|
|
message: data.message
|
|
})
|
|
this.getDetailHost(1)
|
|
}
|
|
})
|
|
})
|
|
},
|
|
// 详情
|
|
getDetail(id) {
|
|
this.id = id
|
|
detailGroup(id).then(data => {
|
|
if (data.success) {
|
|
this.detail = data.data
|
|
this.detailFlag = true
|
|
this.getDetailHost(1)
|
|
}
|
|
})
|
|
},
|
|
goBack() {
|
|
this.ruleSelectList = []
|
|
this.getData()
|
|
this.detailFlag = false
|
|
},
|
|
getDetailHost(page) {
|
|
this.ruleRefreshId()
|
|
this.paramd.page = page || this.paramd.page
|
|
this.paramd.params = JSON.stringify([
|
|
{
|
|
param: {
|
|
groupId: this.id,
|
|
vendorId: this.platformObject.vendorId
|
|
},
|
|
sign: 'EQ'
|
|
}
|
|
])
|
|
getGroupRule(this.paramd).then(data => {
|
|
if (data.success) {
|
|
this.ruleDetailData = data.data.rows
|
|
this.ruleDetailTotal = data.data.total
|
|
this.ruleDetailData.forEach(data => {
|
|
if ((data.projectVisibility && data.projectVisibility != 'GLOBAL_PROJECT') || data.tenantId || data.tenantIds || data.tenantName) {
|
|
data.disabled = true
|
|
}
|
|
const self = this
|
|
setTimeout(function () {
|
|
if (self.ruleIdList.indexOf(data.id) > -1) self.$refs.ruleMultipleTable.$refs.basicTable.toggleRowSelection(data, true)
|
|
})
|
|
})
|
|
}
|
|
})
|
|
},
|
|
getData() {
|
|
this.loading = true
|
|
getGroup(this.params)
|
|
.then(data => {
|
|
if (data.success) {
|
|
this.tableData = data.data.rows
|
|
this.total = data.data.total
|
|
this.selectList = []
|
|
|
|
this.refreshId()
|
|
this.tableData.forEach(data => {
|
|
if ((data.projectVisibility && data.projectVisibility != 'GLOBAL_PROJECT') || data.tenantId || data.tenantIds || data.tenantName) {
|
|
data.disabled = true
|
|
}
|
|
const self = this
|
|
setTimeout(function () {
|
|
if (self.idList.indexOf(data.id) > -1) self.$refs.multipleTable.$refs.basicTable.toggleRowSelection(data, true)
|
|
})
|
|
})
|
|
}
|
|
})
|
|
.finally(() => {
|
|
this.loading = false
|
|
})
|
|
},
|
|
handleSizeChange(val) {
|
|
this.params.rows = val
|
|
this.getData()
|
|
},
|
|
handleDelete() {
|
|
this.refreshId()
|
|
const list = this.idList
|
|
this.$confirm('此操作将删除所选安全组, 是否继续?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(() => {
|
|
removeGroups(list).then(data => {
|
|
if (data.success) {
|
|
this.$message({
|
|
type: 'success',
|
|
message: data.message
|
|
})
|
|
this.getData()
|
|
this.selectList = []
|
|
}
|
|
})
|
|
})
|
|
},
|
|
// 删除
|
|
remove(id) {
|
|
this.$confirm('此操作将永久删除该安全组, 是否继续?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}).then(() => {
|
|
removeGroup(id).then(data => {
|
|
if (data.success) {
|
|
this.$message({
|
|
type: 'success',
|
|
message: data.message
|
|
})
|
|
this.getData()
|
|
}
|
|
})
|
|
})
|
|
},
|
|
// 下拉框点击事件
|
|
dropdownClick(command) {
|
|
switch (command.index) {
|
|
case 1:
|
|
this.dialog('addFlag', 1, command.id)
|
|
break
|
|
case 2:
|
|
this.remove(command.id)
|
|
break
|
|
case 3:
|
|
this.dialog('ruleFlag', 2, command.id)
|
|
break
|
|
}
|
|
},
|
|
// 模态框开启前执行事件
|
|
dialog(flag, index, id) {
|
|
this[flag] = true
|
|
switch (index) {
|
|
case 1:
|
|
this.titleName = '新增安全组'
|
|
this.addData = {}
|
|
if (id) {
|
|
this.titleName = '编辑安全组'
|
|
detailGroup(id).then(data => {
|
|
if (data.success) {
|
|
const { id, name, remark } = data.data
|
|
this.addData = {
|
|
id,
|
|
name,
|
|
remark
|
|
}
|
|
}
|
|
})
|
|
}
|
|
break
|
|
case 2:
|
|
this.ruleData = {
|
|
vendorId: this.platformObject.vendorId,
|
|
groupId: id,
|
|
destinationAddressPrefix: '0.0.0.0/0',
|
|
direction: 'ingress',
|
|
protocol: 'TCP',
|
|
ethertype: 'IPv4',
|
|
priority: 1,
|
|
action: 'accept',
|
|
portMin: '',
|
|
portMax: ''
|
|
}
|
|
break
|
|
}
|
|
},
|
|
// 模态框确认
|
|
dialogOk(index) {
|
|
switch (index) {
|
|
case 1:
|
|
if (!this.isCreate) {
|
|
const data = this.$refs.securityItem.getPostData()
|
|
if (!data) return
|
|
data.vendorId = this.platformObject.vendorId
|
|
this.isCreate = true
|
|
createGroup(data).then(data => {
|
|
if (data.success) {
|
|
this.$message({
|
|
type: 'success',
|
|
message: data.message
|
|
})
|
|
this.addFlag = false
|
|
this.getData()
|
|
}
|
|
this.isCreate = false
|
|
})
|
|
}
|
|
break
|
|
case 2:
|
|
const data1 = this.$refs.securityRule.getPostData()
|
|
if (!data1) return
|
|
if (data1.portMax < data1.portMin) {
|
|
this.$message('结束端口不能小于起始端口')
|
|
return
|
|
}
|
|
createGroupRule(data1).then(data => {
|
|
if (data.success) {
|
|
this.$message({
|
|
type: 'success',
|
|
message: data.message
|
|
})
|
|
this.getData()
|
|
this.ruleFlag = false
|
|
this.ruleData = {
|
|
remoteIpPrefix: '',
|
|
portMin: '',
|
|
portMax: '',
|
|
direction: 'ingress',
|
|
protocol: 'TCP'
|
|
}
|
|
}
|
|
})
|
|
break
|
|
}
|
|
},
|
|
// 模态框退出及取消触发事件
|
|
cancel(formName, flag) {
|
|
this[flag] = false
|
|
this.$refs[formName].resetFields()
|
|
},
|
|
// 模态框ESE事件
|
|
handleClose(done) {
|
|
const list = ['addFlag', 'ruleFlag']
|
|
for (let i = 0; i < list.length; i++) {
|
|
if (this[list[i]]) {
|
|
switch (list[i]) {
|
|
case 'addFlag':
|
|
this.cancel('addData', 'addFlag')
|
|
break
|
|
case 'ruleFlag':
|
|
this.cancel('ruleData', 'addFlag')
|
|
break
|
|
}
|
|
}
|
|
}
|
|
},
|
|
// 获取域
|
|
getRegion() {
|
|
getRegion({ vendorId: this.platformObject.vendorId }).then(data => {
|
|
if (data.success) {
|
|
this.regionList = data.data
|
|
this.searchConfigs[1].data = data.data
|
|
}
|
|
})
|
|
}
|
|
},
|
|
mounted() {
|
|
this.getRegion()
|
|
},
|
|
watch: {
|
|
platformObject: {
|
|
handler(newVal, oldVal) {
|
|
this.searchConfigs = [
|
|
{ label: '名称', value: 'name', type: 'Input' },
|
|
{
|
|
value: 'regionId',
|
|
type: 'Select',
|
|
data: [],
|
|
label: '所属地域'
|
|
},
|
|
{ type: 'Const', value: 'vendorId', initValue: newVal.vendorId }
|
|
]
|
|
this.getDetailHost()
|
|
this.getRegion()
|
|
},
|
|
deep: true
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.no-searchBox {
|
|
padding: 10px;
|
|
}
|
|
.table-container {
|
|
border: none !important;
|
|
}
|
|
</style>
|