473 lines
14 KiB
Vue
473 lines
14 KiB
Vue
<template>
|
||
<div>
|
||
<cb-detail v-if="detaildialogVisible" :data="detail" @goBack="detaildialogVisible = false">
|
||
<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.fingerprint }}</cb-detail-item>
|
||
<cb-detail-item label="可用区">{{ detail.regionName }}</cb-detail-item>
|
||
</template>
|
||
<el-tabs value="second">
|
||
<el-tab-pane label="公钥" name="second">
|
||
<div style="width: 100%; word-break: break-all">
|
||
{{ detail.publicKey }}
|
||
</div>
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
</cb-detail>
|
||
<el-dialog title="新增密钥" :visible.sync="addFlag" width="40%" :before-close="handleClose">
|
||
<cb-form ref="addData" :model="addData">
|
||
<cb-form-item label="创建方式">
|
||
<div class="vm-region region-box" :class="{ true: 'region-active' }[row.isRegionActive]" @click="chooseRegion1(row)" v-for="row in createWays" :key="row.id">
|
||
<span class="region-txt">{{ row.name }}</span>
|
||
</div>
|
||
</cb-form-item>
|
||
<cb-form-item label="可用地域" prop="regionId" :rules="[required]">
|
||
<el-select v-model="addData.regionId" @change="getZone">
|
||
<el-option v-for="(item, index) in regionData" :key="index" :label="item.name" :value="item.regionId"></el-option>
|
||
</el-select>
|
||
</cb-form-item>
|
||
<cb-form-item label="可用区域" prop="zoneId" :rules="[required]">
|
||
<el-select v-model="addData.zoneId">
|
||
<el-option v-for="(item, index) in zoneList" :key="index" :label="item.name" :value="item.zoneId"></el-option>
|
||
</el-select>
|
||
</cb-form-item>
|
||
<cb-form-item label="名称" prop="name" :rules="[required, hicNoChinese]" required-message="请输入名称">
|
||
<el-input v-model="addData.name"></el-input>
|
||
</cb-form-item>
|
||
<cb-form-item label="公钥" v-if="way == 'daoru'" prop="publicKey" :rules="[required]" required-message="请输入公钥" :maxlength="10000">
|
||
<el-input type="textarea" v-model="addData.publicKey"></el-input>
|
||
</cb-form-item>
|
||
<cb-form-item label="读取文件" v-if="way == 'daoru'">
|
||
<input type="file" class="file" ref="file" @change="change" />
|
||
</cb-form-item>
|
||
</cb-form>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button type="ghost" @click="cancel('addData')">取 消</el-button>
|
||
<el-button type="primary" @click="addOk('addData')">确 定</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
<el-card class="wrapper" v-if="!detaildialogVisible">
|
||
<cb-advance-table :card-border="false" title="秘钥列表" :search-configs="searchConfigs" :data="list" :params="params" :columns="columns" :get-list="getData" :total="total" :loading="loading" @selection-change="selectionChange">
|
||
<template v-slot:action>
|
||
<el-button type="primary" @click="add"> 新增 </el-button>
|
||
</template>
|
||
<template #name="val, record">
|
||
<span class="detail-href" @click="getDetail(record.id)">{{ record.name }}</span>
|
||
</template>
|
||
<template #operate="val, record">
|
||
<el-button :disabled="record.disabled" type="text" @click="dropdownClick({ id: record.id })"> <i class="el-icon-delete"></i> 删除 </el-button>
|
||
</template>
|
||
</cb-advance-table>
|
||
</el-card>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
/* global $ */
|
||
import validate from '@/validate'
|
||
import { getRegion, getZone } from 'services/platform/index'
|
||
import { getKey, removeKey, createKey, detailKey, existKey, removeKeys } from 'views/resource/ctstack/services/key'
|
||
import { downloadFile } from '@cmp/cmp-common/utils/'
|
||
|
||
const detailSetting = {
|
||
type: 'miyao',
|
||
columns: [
|
||
[
|
||
{ name: '密钥名称', value: 'name' },
|
||
{ name: '所属平台', value: 'vendorName' },
|
||
{ name: '指纹', value: 'fingerprint' }
|
||
],
|
||
[{ name: '可用区', value: 'regionName' }]
|
||
]
|
||
}
|
||
export default {
|
||
props: {
|
||
platformObject: {
|
||
type: Object,
|
||
default: function () {
|
||
return {
|
||
vendorId: -1,
|
||
operate: -1
|
||
}
|
||
}
|
||
}
|
||
},
|
||
data() {
|
||
return {
|
||
required: validate.required,
|
||
hicNoChinese: validate.hicNoChinese,
|
||
detailSetting,
|
||
detaildialogVisible: false,
|
||
detail: {},
|
||
addFlag: false,
|
||
addData: {
|
||
name: '',
|
||
vendorId: this.platformObject.vendorId,
|
||
publicKey: ''
|
||
},
|
||
params: {
|
||
page: 1,
|
||
rows: 10
|
||
},
|
||
searchData: {
|
||
name: '',
|
||
regionId: ''
|
||
},
|
||
list: [],
|
||
total: 0,
|
||
createWays: [
|
||
{ name: '创建密钥', value: 'create', isRegionActive: true },
|
||
{
|
||
name: '导入密钥',
|
||
value: 'daoru',
|
||
isRegionActive: false
|
||
}
|
||
],
|
||
way: 'create',
|
||
regionData: [],
|
||
regionList: [],
|
||
idList: [],
|
||
selectList: [],
|
||
searchConfigs: [
|
||
{ type: 'Input', value: 'name', label: '名称' },
|
||
{ type: 'Select', data: [], value: 'regionId', label: '所属地域', props: { value: 'regionId' } },
|
||
{ type: 'Const', value: 'vendorId', initValue: this.platformObject.vendorId }
|
||
],
|
||
columns: [
|
||
{
|
||
label: '密钥名称',
|
||
prop: 'name',
|
||
scopedSlots: { customRender: 'name' }
|
||
},
|
||
{
|
||
label: '所属平台',
|
||
prop: 'vendorName'
|
||
},
|
||
{
|
||
label: '指纹',
|
||
prop: 'fingerprint'
|
||
},
|
||
{
|
||
label: '操作',
|
||
disabled: true,
|
||
width: '100px',
|
||
scopedSlots: { customRender: 'operate' }
|
||
}
|
||
],
|
||
loading: false,
|
||
zoneList: []
|
||
}
|
||
},
|
||
methods: {
|
||
selectionChange(val) {
|
||
this.selectList = val
|
||
},
|
||
handleDelete() {
|
||
this.refreshId()
|
||
const list = this.idList
|
||
if (list.length == 0) return this.$message.error('请选择VPC')
|
||
this.$confirm('此操作将删除所选密钥, 是否继续?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
removeKeys(list).then(data => {
|
||
if (data.success) {
|
||
this.$message({
|
||
type: 'success',
|
||
message: data.message
|
||
})
|
||
this.getData()
|
||
this.selectList = []
|
||
}
|
||
})
|
||
})
|
||
},
|
||
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.list.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
|
||
}
|
||
}
|
||
}
|
||
})
|
||
}
|
||
},
|
||
// 导入密钥
|
||
change() {
|
||
const that = this
|
||
const data = this.$refs.file.files[0]
|
||
// 对文件大小和类型进行过滤
|
||
const arr = data.name.split('.')
|
||
if (['pem', 'pub'].indexOf(arr[arr.length - 1]) == -1) {
|
||
this.$notify({
|
||
title: '提示',
|
||
message: '请上传此类型的文件,【.pem,.pub】',
|
||
type: 'error'
|
||
})
|
||
return
|
||
}
|
||
if (data.size > 1024 * 1024) {
|
||
this.$notify({
|
||
title: '提示',
|
||
message: '文件大小超过1M',
|
||
type: 'error'
|
||
})
|
||
return
|
||
}
|
||
if (data) {
|
||
// 将文件进行转码,转换为text
|
||
const reader = new FileReader()
|
||
reader.readAsText(data)
|
||
reader.onload = function (f) {
|
||
const data = this.result
|
||
that.addData.publicKey = data
|
||
}
|
||
}
|
||
},
|
||
// 详情
|
||
getDetail(id) {
|
||
this.detaildialogVisible = true
|
||
detailKey(id).then(data => {
|
||
if (data.success) {
|
||
this.detail = data.data
|
||
}
|
||
})
|
||
},
|
||
chooseRegion1(item) {
|
||
this.addData = {
|
||
name: this.addData.name,
|
||
vendorId: this.platformObject.vendorId,
|
||
regionId: this.addData.regionId,
|
||
zoneId: this.addData.zoneId,
|
||
publicKey: ''
|
||
}
|
||
this.way = item.value
|
||
this.createWays.forEach((data, index) => {
|
||
data.isRegionActive = false
|
||
if (data.name == item.name) {
|
||
data.isRegionActive = !item.isRegionActive
|
||
}
|
||
})
|
||
},
|
||
handleClose(done) {
|
||
this.cancel('addData')
|
||
},
|
||
add() {
|
||
this.addFlag = true
|
||
getRegion({ vendorId: this.platformObject.vendorId }).then(data => {
|
||
if (data.success) {
|
||
this.regionData = data.data
|
||
}
|
||
})
|
||
this.addData = {
|
||
name: '',
|
||
vendorId: this.platformObject.vendorId,
|
||
publicKey: ''
|
||
}
|
||
this.way = 'create'
|
||
this.createWays[0].isRegionActive = true
|
||
this.createWays[1].isRegionActive = false
|
||
},
|
||
addOk(formName) {
|
||
this.$refs[formName].validate(valid => {
|
||
if (valid) {
|
||
existKey({
|
||
condition: JSON.stringify({
|
||
condition: 'exist',
|
||
name: this.addData.name,
|
||
vendorId: this.platformObject.vendorId
|
||
})
|
||
}).then(data => {
|
||
if (data.success) {
|
||
if (this.way == 'create') {
|
||
createKey(this.addData).then(data => {
|
||
if (data.success) {
|
||
this.$message({
|
||
type: 'success',
|
||
message: data.message
|
||
})
|
||
this.cancel('addData')
|
||
this.getData()
|
||
downloadFile('/cmp/plugins/ctstack/v1/keypairs/download', {
|
||
id: data.data
|
||
})
|
||
}
|
||
})
|
||
} else {
|
||
createKey(this.addData).then(data => {
|
||
if (data.success) {
|
||
this.$message({
|
||
type: 'success',
|
||
message: data.message
|
||
})
|
||
this.getData()
|
||
this.cancel('addData')
|
||
}
|
||
})
|
||
}
|
||
}
|
||
})
|
||
} else {
|
||
return false
|
||
}
|
||
})
|
||
},
|
||
dropdownClick(command) {
|
||
this.$confirm('此操作将永久删除该密钥, 是否继续?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
removeKey(command.id).then(data => {
|
||
if (data.success) {
|
||
this.$message({
|
||
type: 'success',
|
||
message: data.message
|
||
})
|
||
this.getData()
|
||
}
|
||
})
|
||
})
|
||
},
|
||
getData() {
|
||
this.loading = true
|
||
getKey(this.params)
|
||
.then(data => {
|
||
if (data.success) {
|
||
this.list = data.data.rows
|
||
|
||
this.selectList = []
|
||
this.total = data.data.total
|
||
this.list.forEach(item => {
|
||
if (item.projectVisibility && item.projectVisibility != 'GLOBAL_PROJECT') {
|
||
item.disabled = true
|
||
}
|
||
})
|
||
}
|
||
})
|
||
.finally(() => {
|
||
this.loading = false
|
||
})
|
||
},
|
||
handleSizeChange(val) {
|
||
this.params.rows = val
|
||
this.getData()
|
||
},
|
||
cancel(formName) {
|
||
this.addFlag = false
|
||
this.$refs[[formName]].resetFields()
|
||
},
|
||
// 获取域
|
||
getRegion() {
|
||
getRegion({ vendorId: this.platformObject.vendorId }).then(data => {
|
||
if (data.success) {
|
||
this.regionList = data.data
|
||
this.searchConfigs[1].data = data.data
|
||
}
|
||
})
|
||
},
|
||
getZone() {
|
||
this.addData.zone = ''
|
||
getZone({
|
||
vendorId: this.platformObject.vendorId,
|
||
regionId: this.addData.regionId
|
||
}).then(data => {
|
||
if (data.success) {
|
||
this.zoneList = data.data
|
||
}
|
||
})
|
||
}
|
||
},
|
||
mounted() {
|
||
this.getRegion()
|
||
},
|
||
watch: {
|
||
platformObject: {
|
||
handler(newVal, oldVal) {
|
||
this.searchConfigs = [
|
||
{ type: 'Input', value: 'name', label: '名称' },
|
||
{ type: 'Select', data: [], value: 'regionId', label: '所属地域' },
|
||
{ type: 'Const', value: 'vendorId', initValue: newVal.vendorId }
|
||
]
|
||
this.getRegion()
|
||
},
|
||
deep: true
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
.no-searchBox {
|
||
padding: 10px;
|
||
}
|
||
|
||
.vm-region {
|
||
height: 42px;
|
||
width: 110px;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
margin: 0 10px 0 0;
|
||
border: 1px solid #ddd;
|
||
line-height: 42px;
|
||
font-size: 12px;
|
||
text-align: center;
|
||
color: #666;
|
||
cursor: pointer;
|
||
border-radius: 0;
|
||
display: inline-block;
|
||
}
|
||
|
||
.vm-region:hover {
|
||
border-color: #43bfe3 !important;
|
||
}
|
||
|
||
.vm-region-text {
|
||
border-color: #43bfe3 !important;
|
||
}
|
||
|
||
.region-active {
|
||
background-color: deepskyblue;
|
||
color: #fff;
|
||
}
|
||
</style>
|