764 lines
29 KiB
Vue
764 lines
29 KiB
Vue
<template>
|
||
<basic-form :model="formData" ref="addForm" label-width="0" :disabled="disabled">
|
||
<basic-table :data="showParamList" ref="addTable">
|
||
<el-table-column label="序号" show-overflow-tooltip width="60px">
|
||
<template slot-scope="{ $index }">
|
||
<basic-form-item label="">
|
||
{{ $index + 1 }}
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="命名规则" show-overflow-tooltip width="160px">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="" :prop="`showParamList.${$index}.configs.nameRuleId`">
|
||
<el-select v-model="row.configs.nameRuleId" placeholder="请选择命名规则" clearable filterable>
|
||
<el-option v-for="(item, index) in nameruleList" :key="index" :label="item.name" :value="item.id"> </el-option>
|
||
</el-select>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="主机名" show-overflow-tooltip width="160px">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="" validate="required,vmHostName" :prop="`showParamList.${$index}.configs.vmHostName`">
|
||
<el-input v-model="row.configs.vmHostName"> </el-input>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<!-- <el-table-column label="云平台类型" show-overflow-tooltip>
|
||
<template slot-scope="{ row,$index }">
|
||
<basic-form-item label="">
|
||
<el-select v-model="row.subLocation.vendorType">
|
||
<el-option :label="item | vendorName" :value="item" v-for="item in vendorTypelist" :key="item"></el-option>
|
||
</el-select>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column> -->
|
||
<el-table-column label="区域" show-overflow-tooltip width="180px">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.subLocation.region`">
|
||
<el-select v-model="row.subLocation.region" @change="changeRegion(row, true)">
|
||
<el-option :label="item.regionName" :value="item.region" v-for="item in regionList" :key="item.region"></el-option>
|
||
</el-select>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="可用区" show-overflow-tooltip width="180px">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.subLocation.az`">
|
||
<el-select v-model="row.subLocation.az" @change="changeAz(row, true)">
|
||
<el-option :label="item.azName" :value="item.availablitiyZone" v-for="item in getZoneListByRegion(row)" :key="item.availablitiyZone"></el-option>
|
||
</el-select>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="镜像类型" show-overflow-tooltip width="180px">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.configs.osCategory`">
|
||
<el-select v-model="row.configs.osCategory" placeholder="请选择" @change="getVersionList(row, true)">
|
||
<el-option v-for="(item, index) in row.osList" :key="index" :label="item" :value="item"> </el-option>
|
||
</el-select>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="镜像版本" show-overflow-tooltip width="180px">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.configs.osVersion`">
|
||
<el-select v-model="row.configs.osVersion" placeholder="请选择" @change="getImage(row, true)">
|
||
<el-option v-for="(item, index) in row.versionList" :key="index" :label="item" :value="item"> </el-option>
|
||
</el-select>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="CPU(核)" show-overflow-tooltip width="160px">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.configs.cpu`">
|
||
<el-input-number :min="1" :max="500" v-model="row.configs.cpu" @change="(val) => changeCpu(val, row)"> </el-input-number>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="内存(GB)" show-overflow-tooltip width="160px">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.configs.memory`">
|
||
<el-input-number :min="row.configs.templateRam" :max="500" v-model="row.configs.memory" @change="(val) => changeMemory(val, row)"> </el-input-number>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="磁盘(GB)" show-overflow-tooltip width="160px">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.configs.sysDisk.disk`">
|
||
<span class="detail-href" @click="handleOpenDiskDialog(row, $index)">
|
||
<template v-if="getDiskTotalSize(row) > 0">{{ getDiskTotalSize(row) }}</template>
|
||
<template v-else>配置</template>
|
||
</span>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="网络" show-overflow-tooltip width="180px">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="" :prop="`showParamList.${$index}`" :rules="rules.networkCardConfigsRule">
|
||
<span class="detail-href" @click="handleOpenNetworkDialog(row, $index)">
|
||
<template v-if="!row.configs.networkCardConfigs.length || row.configs.networkCardConfigs[0].ipPoolId">
|
||
<div v-for="(item, index) in row.configs.networkCardConfigs" :key="index">
|
||
{{ item.ipPoolName }} <span v-if="item.address.length">-{{ item.address.join('、') }}</span>
|
||
</div>
|
||
</template>
|
||
<template v-else>配置</template>
|
||
</span>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="密码" show-overflow-tooltip width="160px">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="" validate="required,vmPassword" :prop="`showParamList.${$index}.configs.password`">
|
||
<el-input v-model="row.configs.password" placeholder="请输入密码" show-password></el-input>
|
||
</basic-form-item>
|
||
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.configs.confirm_password`">
|
||
<el-input v-model="row.configs.confirm_password" placeholder="请再次输入密码" show-password></el-input>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="用途" show-overflow-tooltip width="160px">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.subLocation.purpose`">
|
||
<el-input v-model="row.subLocation.purpose"> </el-input>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="软件配置" show-overflow-tooltip width="160px">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="">
|
||
<span class="detail-href" @click="openGraph(row, $index)"> {{ getGraphConfigLabel(row) }} </span>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="数量" show-overflow-tooltip width="160px">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="" validate="required" :prop="`showParamList.${$index}.emption.count`">
|
||
<el-input-number v-model="row.emption.count"> </el-input-number>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="160px" fixed="right">
|
||
<template slot-scope="{ row, $index }">
|
||
<basic-form-item label="">
|
||
<el-button type="text" @click="handleClone(row)">复制</el-button>
|
||
<el-button type="text" @click="handleSub($index)">删除</el-button>
|
||
</basic-form-item>
|
||
</template>
|
||
</el-table-column>
|
||
<span slot="pagination"></span>
|
||
</basic-table>
|
||
<DataDisk v-if="addDiskDialog.visible" :dialog="addDiskDialog" @success="changeDisk"></DataDisk>
|
||
<Ippool v-if="addNetworkDialog.visible" :dialog="addNetworkDialog" :disabled="disabled"></Ippool>
|
||
<el-dialog :visible.sync="graphDialog.visible" title="作业编排" width="1200px" append-to-body top="5vh" :closeOnClickModal="false">
|
||
<Graph v-if="graphDialog.visible" :addData="addData" :graphDialog="graphDialog" @back="graphDialog.visible = false" :disabled="disabled"></Graph>
|
||
</el-dialog>
|
||
</basic-form>
|
||
</template>
|
||
|
||
<script>
|
||
import { conditionService, conditionImage, getNameRule } from 'services/platform/index'
|
||
import { generateSpec, getSpecValue } from 'views/resource-apply/utils/index'
|
||
import { getPoolCondition } from 'services/platform/pool'
|
||
import { uniqBy, cloneDeep } from 'lodash-es'
|
||
import { transformNetworkConfig } from './ImageItem'
|
||
import { subApplicationParam, GEN_UUID, ServiceCodeMap, defaultTask } from '../data/EFCInit'
|
||
import Ippool, { CECSTACK_DEFAULT_CONFIG, CLOUDTOWER_DEFAULT_CONFIG } from './EFCIppool'
|
||
import DataDisk from './EFCDataDisk'
|
||
import sku from '../mixins/EFCsku'
|
||
import Graph from '../graph/graph.vue'
|
||
import { getVolumeTpl } from 'services/platform/smart.js'
|
||
export default {
|
||
name: 'VmList',
|
||
mixins: [sku],
|
||
components: {
|
||
Ippool,
|
||
DataDisk,
|
||
Graph
|
||
},
|
||
props: {
|
||
itemData: {
|
||
type: [Object, Boolean]
|
||
},
|
||
showParamList: {
|
||
type: Array,
|
||
required: true,
|
||
default: () => []
|
||
},
|
||
addData: {
|
||
type: Object,
|
||
required: true,
|
||
default: () => {}
|
||
},
|
||
disabled: {
|
||
type: Boolean
|
||
}
|
||
},
|
||
provide() {
|
||
// 使用函数的形式,可以访问到 `this`
|
||
return {
|
||
getSubApplicationParamsForTaskServer: () => this.addData.subApplicationParams.filter((item) => item.taskGroupUuid === this.graphDialog.task.taskGroupUuid)
|
||
}
|
||
},
|
||
computed: {
|
||
formData() {
|
||
return { showParamList: this.showParamList }
|
||
},
|
||
regionList() {
|
||
return this.allPoolList.reduce((pre, cur) => {
|
||
if (!pre.find((item) => item.region == cur.region)) {
|
||
pre.push({
|
||
regionName: cur.regionName,
|
||
region: cur.region
|
||
})
|
||
}
|
||
return pre
|
||
}, [])
|
||
}
|
||
},
|
||
data() {
|
||
return {
|
||
nameruleList: [],
|
||
vendorTypelist: [],
|
||
allPoolList: [],
|
||
addDiskDialog: {
|
||
visible: false,
|
||
index: '',
|
||
row: {}
|
||
},
|
||
addNetworkDialog: {
|
||
visible: false,
|
||
row: {},
|
||
cb: () => {}
|
||
},
|
||
rules: {
|
||
networkCardConfigsRule: [
|
||
{
|
||
required: true,
|
||
validator: (rule, value, callback) => {
|
||
const validateNetworkCard = this.validateNetworkCard(value)
|
||
if (validateNetworkCard.valid) {
|
||
callback()
|
||
} else {
|
||
callback(new Error(validateNetworkCard.message))
|
||
}
|
||
},
|
||
trigger: null
|
||
}
|
||
]
|
||
},
|
||
graphDialog: {
|
||
visible: false,
|
||
task: {},
|
||
cb: () => {}
|
||
},
|
||
CTDataDisktemplateData: []
|
||
}
|
||
},
|
||
created() {
|
||
getNameRule({
|
||
page: 1,
|
||
rows: 9999
|
||
}).then((data) => {
|
||
if (data.success) {
|
||
this.nameruleList = data.data.rows
|
||
}
|
||
})
|
||
this.getAllPool()
|
||
// 获取云平台类型
|
||
conditionService('server').then((data) => {
|
||
if (data.success) {
|
||
this.vendorTypelist = data.data
|
||
}
|
||
})
|
||
},
|
||
methods: {
|
||
getGraphConfigLabel(row) {
|
||
const task = this.addData.tasks.find(({ taskGroupUuid }) => taskGroupUuid === row.taskGroupUuid)
|
||
if (!task) return '配置'
|
||
return `${task.taskName}`
|
||
},
|
||
openGraph(row) {
|
||
if (!this.addData.location.name) return this.$message.error('请填写业务信息')
|
||
if (!row.configs.vmHostName) return this.$message.error('请填写主机名')
|
||
if (!row.configs.password) return this.$message.error('请填写密码')
|
||
this.$emit('handleUpdateParamList')
|
||
this.graphDialog.visible = true
|
||
this.graphDialog.task = cloneDeep(
|
||
this.addData.tasks.find((item) => item.taskGroupUuid === row.taskGroupUuid) || {
|
||
...defaultTask,
|
||
taskGroupUuid: row.taskGroupUuid
|
||
}
|
||
)
|
||
this.graphDialog.cb = () => {
|
||
this.graphDialog.task.taskName = `${this.addData.location.name}_${this.graphDialog.task.name}`
|
||
const findIndex = this.addData.tasks.findIndex((item) => item.taskGroupUuid === row.taskGroupUuid)
|
||
if (findIndex > -1) {
|
||
this.addData.tasks[findIndex] = this.graphDialog.task
|
||
} else {
|
||
this.addData.tasks.push(this.graphDialog.task)
|
||
}
|
||
}
|
||
},
|
||
changeCpu(val, row) {
|
||
row.elements[0].specs[0].cpu = val
|
||
},
|
||
changeMemory(val, row) {
|
||
row.elements[0].specs[1].memory = val
|
||
},
|
||
// 将磁盘配置保存到 elements 中
|
||
async changeDisk(index = -1, row) {
|
||
row = index > -1 ? this.showParamList[index] : row
|
||
// 系统盘
|
||
row.elements[1].specs = [{ disk: row.configs.sysDisk.disk }]
|
||
row.configs.sysDisk.categoryId = row.elements[1].categoryId
|
||
// 数据盘
|
||
row.elements.splice(2)
|
||
if (row.configs.addDiskList.length) {
|
||
const dataDiskElementClone = cloneDeep(row.elements[1])
|
||
row.configs.addDiskList.map((item) => {
|
||
row.elements.push({ ...dataDiskElementClone, specs: [{ disk: item.disk }] })
|
||
})
|
||
}
|
||
// 设置各个云平台的默认磁盘配置
|
||
const vendorType = row.subLocation.vendorType
|
||
const vendorId = row.subLocation.vendorId
|
||
switch (vendorType) {
|
||
case 'VMWARE':
|
||
row.configs.sysDisk.diskType = 'thin'
|
||
// 设置磁盘默认数据
|
||
row.configs.addDiskList.forEach((item) => {
|
||
item.createLvm = false
|
||
item.diskType = 'thin'
|
||
item.fileSystem = 'ext3'
|
||
item.forceMount = false
|
||
})
|
||
break
|
||
case 'INSPURRAIL':
|
||
row.configs.sysDisk.diskType = 'thin'
|
||
// 设置磁盘默认数据
|
||
row.configs.addDiskList.forEach((item) => {
|
||
item.createLvm = false
|
||
item.diskType = 'thin'
|
||
item.fileSystem = 'ext3'
|
||
item.forceMount = false
|
||
})
|
||
break
|
||
case 'CLOUDTOWER':
|
||
const busData = [
|
||
{ name: 'VIRTIO', value: 'VIRTIO' },
|
||
{ name: 'SCSI', value: 'SCSI' },
|
||
{ name: 'IDE', value: 'IDE' }
|
||
]
|
||
// 设置磁盘默认数据
|
||
if (!this.CTDataDisktemplateData.length || this.CTDataDisktemplateData[0].vendorId !== vendorId) {
|
||
await getVolumeTpl({
|
||
simple: true,
|
||
params: this.$tools.handleSearchParam({ vendorId })
|
||
}).then((data) => {
|
||
if (data.success) {
|
||
if (!data.data.rows.length) {
|
||
row.configs.addDiskList = []
|
||
return this.$message.error('获取CLOUDTOWER存储策略数据为空,请联系管理员')
|
||
}
|
||
this.CTDataDisktemplateData = data.data.rows
|
||
}
|
||
})
|
||
}
|
||
row.configs.addDiskList.forEach((item) => {
|
||
item.type = 'newDisk'
|
||
item.bus = busData[0].value
|
||
item.volumeTemplateId = this.CTDataDisktemplateData[0].id // 存储策略
|
||
item.volumeTemplateName = this.CTDataDisktemplateData[0].name
|
||
})
|
||
break
|
||
case 'CECSTACK':
|
||
row.configs.addDiskList.forEach((item) => {
|
||
item.deleteWithInstance = true
|
||
item.bootVolume = false
|
||
// item.size = ''
|
||
// item.volumeType = ''
|
||
item.volumeUnit = 'GiB'
|
||
// item.bootIndex = ''
|
||
})
|
||
break
|
||
default:
|
||
break
|
||
}
|
||
},
|
||
handleClone(row = subApplicationParam) {
|
||
const cloneData = cloneDeep(row)
|
||
cloneData.taskGroupUuid = GEN_UUID()
|
||
cloneData.taskTargetUuid = GEN_UUID()
|
||
cloneData.configs.name = ''
|
||
this.showParamList.push(cloneData)
|
||
},
|
||
handleSub(index) {
|
||
this.showParamList.splice(index, 1)
|
||
},
|
||
handleOpenNetworkDialog(row, index) {
|
||
this.addNetworkDialog.visible = true
|
||
this.addNetworkDialog.row = row
|
||
this.addNetworkDialog.cb = () => {
|
||
this.$refs.addForm && this.$refs.addForm.$refs.formRef.validateField(`showParamList.${index}`)
|
||
}
|
||
},
|
||
getDiskTotalSize(row) {
|
||
return row.configs.sysDisk.disk + row.configs.addDiskList.reduce((pre, cur) => pre + cur.disk, 0)
|
||
},
|
||
handleOpenDiskDialog(row, index) {
|
||
this.addDiskDialog.visible = true
|
||
this.addDiskDialog.row = row
|
||
this.addDiskDialog.index = index
|
||
},
|
||
getOsList(row) {
|
||
if (!row.subLocation.vendorId) return
|
||
let params
|
||
if (row.subLocation.vendorType === 'CECSTACK') {
|
||
params = {
|
||
condition: 'listByImageType',
|
||
vendorId: row.subLocation.vendorId,
|
||
status: 'ACTIVE',
|
||
tenantId: 0,
|
||
regionId: row.subLocation.region,
|
||
imageType: 'PUBLIC'
|
||
}
|
||
} else {
|
||
params = {
|
||
condition: 'listTenantImages',
|
||
vendorId: row.subLocation.vendorId
|
||
}
|
||
if (row.subLocation.vendorType === 'SANGFOR') {
|
||
if (!row.subLocation.azUuid) return
|
||
params.azUuid = row.subLocation.azUuid
|
||
}
|
||
}
|
||
conditionImage(params).then((data) => {
|
||
if (data.success) {
|
||
row.imageData = data.data
|
||
this.$set(row, 'osList', Object.keys(row.imageData))
|
||
if (!this.itemData) {
|
||
row.configs.osCategory = row.osList[0]
|
||
row.configs.osVersion = ''
|
||
}
|
||
this.$set(row, 'versionList', [])
|
||
this.getVersionList(row, !row.configs.osVersion)
|
||
}
|
||
})
|
||
return row.osList
|
||
},
|
||
|
||
getVersionList(row, flag) {
|
||
if (row.subLocation.vendorType === 'CECSTACK') {
|
||
row.versionList = row.imageData[row.configs.osCategory].map(({ name }) => name)
|
||
} else {
|
||
row.versionList = Object.keys(row.imageData[row.configs.osCategory])
|
||
}
|
||
if (flag) {
|
||
row.configs.osVersion = row.versionList[0]
|
||
this.getImage(row, true)
|
||
} else {
|
||
this.getImage(row, false)
|
||
}
|
||
},
|
||
getImage(row, flag) {
|
||
let obj
|
||
if (row.subLocation.vendorType === 'CECSTACK') {
|
||
obj = row.imageData[row.configs.osCategory].find(({ name }) => row.configs.osVersion === name)
|
||
} else {
|
||
obj = row.imageData[row.configs.osCategory][row.configs.osVersion]?.[0]
|
||
}
|
||
if (!obj) return
|
||
if (flag) {
|
||
row.configs.imageId = obj.id
|
||
// 电子云为 minDisk
|
||
// cloudtower 镜像中可能没系统盘大小
|
||
row.configs.templateDisk = obj.templateDisk || obj.minDisk || 50
|
||
row.configs.templateRam = obj.minRam / 1024 || 1
|
||
if (row.configs.memory < row.configs.templateRam) row.configs.memory = row.configs.templateRam
|
||
row.configs.sysDisk.disk = row.configs.templateDisk
|
||
}
|
||
if (row.subLocation.vendorType == 'CECSTACK') {
|
||
if (flag) {
|
||
this.$set(row.configs, 'networkCardConfigs', [
|
||
{
|
||
networkId: obj.networkId,
|
||
ipPolicy: 'Auto',
|
||
ipPoolId: '',
|
||
ipPoolName: '',
|
||
address: [],
|
||
portGroupId: '',
|
||
loading: false,
|
||
// 电子云特殊参数
|
||
...CECSTACK_DEFAULT_CONFIG
|
||
}
|
||
])
|
||
}
|
||
} else if (row.subLocation.vendorType == 'SANGFOR') {
|
||
row.configs.vmUuid = obj.imageUuid
|
||
if (flag && row.configs.networkCardConfigs.length == 0) {
|
||
const hardware_status = JSON.parse(obj.detail || '{}')?.hardware_status
|
||
if (!hardware_status) return this.$message.error('镜像缺少网卡,请检查镜像是否正确')
|
||
const configs = transformNetworkConfig(hardware_status).map((item) => ({
|
||
ipPolicy: 'Auto',
|
||
ipPoolId: '',
|
||
ipPoolName: '',
|
||
address: [],
|
||
portGroupId: '',
|
||
loading: false
|
||
}))
|
||
this.$set(row.configs, 'networkCardConfigs', configs)
|
||
}
|
||
} else if (row.subLocation.vendorType == 'VMWARE') {
|
||
if (flag && (row.configs.networkCardConfigs.length == 0 || row.configs.networkCardConfigs[0].networkCardId != obj.networkCards?.[0]?.id)) {
|
||
if (!obj.networkCards?.length) this.$message.error('镜像缺少网卡,请检查镜像是否正确')
|
||
this.$set(
|
||
row.configs,
|
||
'networkCardConfigs',
|
||
obj.networkCards.map((item) => {
|
||
return {
|
||
networkCardId: item.id,
|
||
ipPolicy: 'Auto',
|
||
ipPoolId: '',
|
||
ipPoolName: '',
|
||
address: [],
|
||
portGroupId: '',
|
||
loading: false
|
||
}
|
||
})
|
||
)
|
||
}
|
||
} else if (row.subLocation.vendorType == 'INSPURRAIL') {
|
||
if (flag) {
|
||
if (row.configs.networkCardConfigs.length == 0 || row.configs.networkCardConfigs[0].networkCardId != obj.networkCards?.[0]?.id) {
|
||
if (!obj.networkCards?.length) this.$message.error('镜像缺少网卡,请检查镜像是否正确')
|
||
this.$set(
|
||
row.configs,
|
||
'networkCardConfigs',
|
||
obj.networkCards.map((item) => {
|
||
return {
|
||
networkCardId: item.id,
|
||
ipPolicy: 'Auto',
|
||
ipPoolId: '',
|
||
ipPoolName: '',
|
||
address: [],
|
||
portGroupId: '',
|
||
loading: false
|
||
}
|
||
})
|
||
)
|
||
}
|
||
// 模板里面的磁盘配置
|
||
const volumes = obj.volumes || []
|
||
volumes.map(({ bootVolume, size }) => {
|
||
if (bootVolume) {
|
||
row.configs.templateDisk = size
|
||
row.configs.sysDisk.disk = size
|
||
} else {
|
||
row.configs.addDiskList.push({ disk: size, templateDisk: size })
|
||
}
|
||
})
|
||
}
|
||
} else if (row.subLocation.vendorType == 'CLOUDTOWER') {
|
||
if (flag) {
|
||
this.$set(row.configs, 'networkCardConfigs', [
|
||
{
|
||
networkId: obj.networkId,
|
||
ipPolicy: 'Auto',
|
||
ipPoolId: '',
|
||
ipPoolName: '',
|
||
address: [],
|
||
portGroupId: '',
|
||
loading: false,
|
||
// CLOUDTOWER特殊参数
|
||
...CLOUDTOWER_DEFAULT_CONFIG
|
||
}
|
||
])
|
||
}
|
||
} else if (row.subLocation.vendorType === 'CNWARE') {
|
||
const res = JSON.parse(obj.configuration).devices.map((d) => {
|
||
if (d.capacity) {
|
||
const size = Number(d.capacity) / 1024 / 1024 / 1024
|
||
// 系统盘大小
|
||
row.configs.templateDisk = size
|
||
}
|
||
return {
|
||
...d
|
||
}
|
||
})
|
||
if (flag) {
|
||
row.configs.sysDiskList = res.flat()
|
||
}
|
||
}
|
||
// 设置硬盘参数
|
||
if (flag) this.changeDisk(-1, row)
|
||
},
|
||
setVendor(row, manual = true) {
|
||
const findVendorList = this.getVendorListByRegionZone(row)
|
||
const pool = findVendorList.filter((item) => item.vendorId == row.subLocation.vendorId)[0]
|
||
if (!pool) return this.$message.error('当前可用区下不存在资源池')
|
||
console.log('当前资源池:', pool.vendorType, pool.name)
|
||
const { vendorType, id, azUuid } = pool
|
||
row.subLocation.poolGroupId = id
|
||
row.subLocation.azUuid = azUuid
|
||
row.subLocation.vendorType = vendorType
|
||
row.networkRelations = pool.networkRelations || []
|
||
row.service = ServiceCodeMap.server[vendorType]
|
||
row.elements.map((item, index) => {
|
||
item.serviceCode = index === 0 ? ServiceCodeMap.server[vendorType] : ServiceCodeMap.disk[vendorType]
|
||
})
|
||
switch (vendorType) {
|
||
case 'VMWARE':
|
||
row.configs.isAddShterm = false
|
||
break
|
||
case 'INSPURRAIL':
|
||
row.configs.isAddShterm = false
|
||
break
|
||
case 'CLOUDTOWER':
|
||
row.configs.serverId = 0
|
||
row.configs.ha = true
|
||
row.configs.firmware = 'BIOS'
|
||
row.configs.status = 'running'
|
||
row.configs.fullClone = false
|
||
break
|
||
default:
|
||
break
|
||
}
|
||
// 根据云平台类型设置默认磁盘配置
|
||
this.changeDisk(-1, row)
|
||
this.getData(row, manual)
|
||
},
|
||
getData(row, manual = true) {
|
||
// 加载服务目录
|
||
if (!this.itemData || !this.disabled) this.loadSku(row)
|
||
this.getOsList(row)
|
||
},
|
||
|
||
getZoneListByRegion(row) {
|
||
const filterPools = this.allPoolList.filter((item) => item.region == row.subLocation.region)
|
||
if (!filterPools.length) return []
|
||
// 同一地域下可能会存在重复可用区,去重处理
|
||
if (filterPools[0].vendorType === 'CECSTACK') {
|
||
const formatPools = []
|
||
// 将多个可用区扁平化放在资源池中
|
||
filterPools.map((pool) => {
|
||
pool.regionRelations.map((zone) => {
|
||
formatPools.push({ ...pool, availablitiyZone: zone.zoneId, azName: zone.zoneName })
|
||
})
|
||
})
|
||
return uniqBy(formatPools, 'availablitiyZone')
|
||
} else {
|
||
return uniqBy(filterPools, 'availablitiyZone')
|
||
}
|
||
},
|
||
getVendorListByRegionZone(row) {
|
||
const zoneList = this.getZoneListByRegion(row)
|
||
return zoneList.filter((item) => item.availablitiyZone == row.subLocation.az)
|
||
},
|
||
// 地域变化
|
||
// manual 手动切换
|
||
changeRegion(row, manual = true) {
|
||
this.setZone(row, manual)
|
||
},
|
||
// 设置可用区
|
||
setZone(row, manual = true) {
|
||
const zoneList = this.getZoneListByRegion(row)
|
||
// 手动切换才需要置空
|
||
if (manual && !zoneList.length) return (row.subLocation.az = '')
|
||
if (!zoneList.find((item) => item.availablitiyZone === row.subLocation.az)) {
|
||
row.subLocation.az = zoneList[0].availablitiyZone
|
||
}
|
||
this.changeAz(row, manual)
|
||
},
|
||
// 可用区改变
|
||
changeAz(row, manual = true) {
|
||
const findVendorList = this.getVendorListByRegionZone(row)
|
||
if (manual && !findVendorList.length) return (row.subLocation.vendorId = '')
|
||
if (!findVendorList.find((item) => item.vendorId === row.subLocation.vendorId)) {
|
||
row.subLocation.vendorId = findVendorList[0].vendorId
|
||
}
|
||
this.setVendor(row, manual)
|
||
},
|
||
// 所有资源池
|
||
async getAllPool() {
|
||
const res = await getPoolCondition({
|
||
condition: 'listPoolGroups',
|
||
tenantId: this.addData.location.tenantId
|
||
})
|
||
if (!res.success) return
|
||
this.allPoolList = res.data
|
||
if (!this.regionList.length) return
|
||
const [{ region }] = this.regionList
|
||
if (!this.showParamList[0].subLocation.region) {
|
||
this.showParamList[0].subLocation.region = region
|
||
}
|
||
this.changeRegion(this.showParamList[0], false)
|
||
},
|
||
validateNetworkCard(param) {
|
||
const res = {
|
||
valid: true,
|
||
message: ''
|
||
}
|
||
let flag = false
|
||
let addressLenFlag = false
|
||
let cecstackFlag = false
|
||
param.configs.networkCardConfigs.forEach((item) => {
|
||
if (!item.ipPoolId || (item.ipPolicy == 'Manual' && item.address.length == 0) || (item.checkIpv6 && (!item.ipv6PoolId || (item.ipv6Policy == 'Manual' && item.ipv6Address.length == 0)))) flag = true
|
||
if (item.ipPolicy == 'Manual' && item.address.length !== param.emption.count) {
|
||
addressLenFlag = true
|
||
}
|
||
if (param.subLocation.vendorType === 'CECSTACK' && !(item.vpcUuid || item.subnetUuid)) {
|
||
cecstackFlag = true
|
||
}
|
||
})
|
||
if (flag) {
|
||
res.valid = false
|
||
res.message = '网卡信息配置不完善'
|
||
return res
|
||
}
|
||
if (addressLenFlag) {
|
||
res.valid = false
|
||
res.message = 'IP数量与云主机订购数量不一致'
|
||
return res
|
||
}
|
||
if (cecstackFlag) {
|
||
res.valid = false
|
||
res.message = '缺少 VPC 和子网信息'
|
||
}
|
||
return res
|
||
},
|
||
getParams() {
|
||
let data = false
|
||
this.$refs.addForm.validate((valid) => {
|
||
if (valid) {
|
||
const result = []
|
||
this.showParamList.forEach((param) => {
|
||
const validateNetworkCard = this.validateNetworkCard(param)
|
||
if (!validateNetworkCard.valid) {
|
||
data = false
|
||
return
|
||
}
|
||
const { password, confirm_password, ...other } = param.configs
|
||
if (password !== confirm_password) {
|
||
data = false
|
||
this.$message.error('两次密码输入不一致')
|
||
return
|
||
}
|
||
result.push({
|
||
...other,
|
||
categoryId: param.elements[0].categoryId
|
||
})
|
||
})
|
||
if (result.length === this.showParamList.length) data = result
|
||
} else {
|
||
this.$message.error('虚拟机信息未填写完整')
|
||
}
|
||
})
|
||
return data
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss"></style>
|