feat: 数据库对接(待调试)

develop
时启龙 2024-09-05 21:18:23 +08:00
parent 768259ff5f
commit 01406890f5
5 changed files with 5279 additions and 462 deletions

View File

@ -995,5 +995,17 @@ export default {
callback() callback()
}, },
trigger: trigger trigger: trigger
},
ctstackDatabaseName: {
validator: (rule, value, callback) => {
// 长度在 4 到 64个字符必须以字母开头不区分大小写可以包含字母、数字、中划线或下划线不能包含其他特殊字符
const reg = /^[a-zA-Z][a-zA-Z0-9_-]{3,63}$/
if (reg.test(value)) {
callback()
} else {
callback(new Error('长度在 4 到 64个字符必须以字母开头不区分大小写可以包含字母、数字、中划线或下划线不能包含其他特殊字符'))
}
},
trigger: trigger
} }
} }

View File

@ -1,113 +1,117 @@
<template> <template>
<el-dialog v-if="addData.dialog" title="新增RDS" :visible.sync="addData.dialog" width="950px"> <el-dialog title="新增数据库" :visible.sync="addData.dialog" top="5vh" width="800px" :close-on-click-modal="false">
<el-steps :active="active" finish-status="success"> <el-steps :active="active" finish-status="success">
<el-step title="基础资源"></el-step> <el-step title="基础资源"></el-step>
<el-step title="实例配置"></el-step> <el-step title="实例配置"></el-step>
</el-steps> </el-steps>
<el-row class="box" v-show="active === 0"> <el-row class="box" v-show="active === 0">
<cb-form ref="basicData" :model="addData.data" label-width="120px"> <cb-form ref="basicData" :model="formData" label-width="120px">
<cb-form-item label="计费方式: " prop="payType" :rules="[required]"> <cb-form-item label="计费方式: " prop="billMode" :rules="[required]">
<el-radio-group v-model="addData.data.payType" @change="getFlavorList"> <el-radio-group v-model="formData.billMode" @change="getFlavorList">
<el-radio-button label="Postpaid">后付费按量付费</el-radio-button> <el-radio-button label="2">后付费按量付费</el-radio-button>
<el-radio-button disabled label="Prepaid">预付费包年包月</el-radio-button> <el-radio-button label="1">预付费包年包月</el-radio-button>
</el-radio-group> </el-radio-group>
</cb-form-item> </cb-form-item>
<region-item :add-data="addData.data"></region-item> <cb-form-item label="地域: " prop="regionId" :rules="[required]">
<cb-form-item <el-select v-model="formData.regionId" clearable placeholder="请选择地域" @change="changeRegion">
label="实例名称:" <el-option v-for="item in regionData" :key="item.code" :value="item.code" :label="item.name"></el-option>
prop="name"
:rules="[{ pattern: /^[a-zA-Z\u4e00-\u9fa5?!((https?:)\/\/)][a-zA-Z0-9:_-]([a-zA-Z0-9:_-]{1,62})?$/, message: '由字母、数字、中文、下划线_、中划线-)冒号(:组成以字母或中文开头不能以http://或https://开头长度限制在2-64个字符。', trigger: null }]"
validate="required"
>
<el-input v-model="addData.data.name" placeholder="请输入实例名称" class="basic-cmp"></el-input>
</cb-form-item>
<!-- <el-col :span="12"> -->
<cb-form-item label="类型: " prop="dataStoreType" :rules="[required]">
<el-select v-model="addData.data.dataStoreType" clearable placeholder="请选择类型" @change="changeType">
<el-option v-for="(item, key) in typeList" :key="key" :value="key" :label="key"></el-option>
</el-select> </el-select>
</cb-form-item> </cb-form-item>
<!-- </el-col> --> <cb-form-item label="企业项目: " prop="projectId" :rules="[required]">
<!-- <el-col :span="12"> --> <el-select v-model="formData.projectId" clearable placeholder="请选择企业项目" @change="changeProject">
<cb-form-item label="版本: " prop="dataStoreVersion" :rules="[required]"> <el-option v-for="item in projectList" :key="item.projectSetId" :value="item.projectSetId" :label="item.projectSetName"></el-option>
<el-select v-model="addData.data.dataStoreVersion" clearable placeholder="请选择版本" @change="changeVersion">
<el-option v-for="item in versionList" :key="item.value" :value="item.value" :label="item.name"></el-option>
</el-select> </el-select>
</cb-form-item> </cb-form-item>
<!-- </el-col> --> <cb-form-item label="数据库类型: " prop="type" :rules="[required]">
<cb-form-item label="系列: " prop="series" :rules="[required]"> <el-select v-model="formData.type" clearable placeholder="请选择类型">
<el-select v-model="addData.data.series" clearable placeholder="请选择系列" @change="changeCategory"> <el-option v-for="(item, key) in sqlTypeMap" :key="key" :value="key" :label="key"></el-option>
<el-option v-for="(item, index) in categoryList" :key="index" :value="item.value" :label="item.name"></el-option>
</el-select> </el-select>
</cb-form-item> </cb-form-item>
<cb-form-item label="存储类型: " prop="volType" :rules="[required]"> <cb-form-item label="数据库版本: " prop="prodVersion" :rules="[required]">
<el-select v-model="addData.data.volType" clearable placeholder="请选择类型" @change="getFlavorList"> <el-radio-group v-model="formData.prodVersion" clearable placeholder="请选择版本" @change="changeVersion">
<el-option v-for="(item, index) in volTypeList" :key="index" :value="item.value" :label="item.name"></el-option> <el-radio v-for="item in versionList" :key="item.value" :value="item.value" :label="item.name"></el-radio>
</el-select> </el-radio-group>
</cb-form-item>
<cb-form-item label="实例类型: " prop="prodSpecName" :rules="[required]">
<el-radio-group v-model="formData.prodSpecName" clearable placeholder="请选择实例类型" @change="changeCategory">
<el-radio v-for="item in prodSpecNameList" :key="item" :value="item" :label="item"></el-radio>
</el-radio-group>
</cb-form-item>
<cb-form-item label="主节点可用区: " prop="mysqlNodeInfoList.0.availabilityZoneInfo.0.availabilityZoneName" :rules="[required]">
<el-radio-group v-model="formData.mysqlNodeInfoList[0].availabilityZoneInfo[0].availabilityZoneName" clearable placeholder="请选择类型" @change="changeZone">
<el-radio v-for="item in zoneList" :key="item.availabilityZoneId" :label="item.availabilityZoneId">{{ item.displayName }}</el-radio>
</el-radio-group>
</cb-form-item>
<cb-form-item label="备节点可用区1: " prop="mysqlNodeInfoList.0.availabilityZoneInfo.1.availabilityZoneName" :rules="[required]" v-if="formData.prodSpecName === '一主一备'">
<el-radio-group v-model="formData.mysqlNodeInfoList[0].availabilityZoneInfo[1].availabilityZoneName" clearable placeholder="请选择可用区">
<el-radio v-for="item in zoneList" :key="item.availabilityZoneId" :label="item.availabilityZoneId">{{ item.displayName }}</el-radio>
</el-radio-group>
</cb-form-item>
<cb-form-item label="备节点可用区2: " prop="mysqlNodeInfoList.0.availabilityZoneInfo.2.availabilityZoneName" :rules="[required]" v-if="formData.prodSpecName === '一主两备'">
<el-radio-group v-model="formData.mysqlNodeInfoList[0].availabilityZoneInfo[2].availabilityZoneName" clearable placeholder="请选择可用区">
<el-radio v-for="item in zoneList" :key="item.availabilityZoneId" :label="item.availabilityZoneId">{{ item.displayName }}</el-radio>
</el-radio-group>
</cb-form-item>
<cb-form-item label="性能类型: " prop="mysqlNodeInfoList.0.instSpec" :rules="[required]">
<el-radio-group v-model="formData.mysqlNodeInfoList[0].instSpec" clearable placeholder="请选择性能类型" @change="changeInstSpec">
<el-radio v-for="item in instSpecList" :key="item.value" :label="item.value">{{ item.name }}</el-radio>
</el-radio-group>
</cb-form-item> </cb-form-item>
<cb-form-item label="实例规格: " prop="flavorId" :rules="[required]" required-message=""> <cb-form-item label="实例规格: " prop="flavorId" :rules="[required]" required-message="">
<cb-smart-table :data="specList" stripe> <cb-smart-table :data="flavorList" stripe max-height="300px" :rows="99999">
<el-table-column show-overflow-tooltip label="规格代码" prop="flavorUuid"> <el-table-column show-overflow-tooltip label="规格代码" prop="specName">
<template v-slot="scope"> <template v-slot="scope">
<el-radio v-model="addData.data.flavorId" :label="scope.row.id">{{ scope.row.flavorUuid }}</el-radio> <el-radio v-model="formData.flavorId" :label="scope.row.specName" @input="changeFlavorId">{{ scope.row.specName }}</el-radio>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column show-overflow-tooltip label="实例规格族" prop="typeLabel"></el-table-column> <el-table-column show-overflow-tooltip label="CPU/内存" prop="prodPerformanceSpec"></el-table-column>
<el-table-column show-overflow-tooltip label="CPU" prop="cpu"></el-table-column> <span slot="pagination"></span>
<el-table-column show-overflow-tooltip label="内存GB" prop="memory"></el-table-column>
<el-table-column show-overflow-tooltip label="最大连接数(个)" prop="maxConnections"></el-table-column>
<el-table-column show-overflow-tooltip label="最大IOPS次/秒)" prop="maxIops"></el-table-column>
<el-table-column show-overflow-tooltip label="最大IO带宽Mbps" prop="maxIombps" v-if="addData.data.volType !== 'local_ssd'"></el-table-column>
</cb-smart-table> </cb-smart-table>
</cb-form-item> </cb-form-item>
<cb-form-item label="存储空间(GB): " prop="volSize" :rules="[required]"> <cb-form-item label="存储类型: " prop="mysqlNodeInfoList.0.storageType" :rules="[required]">
<el-select v-model="formData.mysqlNodeInfoList[0].storageType" clearable placeholder="请选择类型">
<el-option v-for="(item, index) in storageTypeList" :key="index" :value="item.value" :label="item.name"></el-option>
</el-select>
</cb-form-item>
<cb-form-item label="存储空间(GB): " prop="mysqlNodeInfoList.0.storageSpace" :rules="[required]">
<div style="padding: 0 10px"> <div style="padding: 0 10px">
<el-slider v-model="addData.data.volSize" :marks="marks" show-input :min="20" :max="6000"> </el-slider> <el-slider v-model="formData.mysqlNodeInfoList[0].storageSpace" show-input :min="100" :max="32768"> </el-slider>
</div> </div>
</cb-form-item> </cb-form-item>
<cb-form-item v-if="formData.billMode == '1'" label="购买时长:" prop="period" :rules="[required]">
<el-select v-model="formData.period" clearable filterable>
<el-option v-for="(item, index) in periodList" :key="index" :value="item.value" :label="item.name"></el-option>
</el-select>
</cb-form-item>
</cb-form> </cb-form>
</el-row> </el-row>
<cb-form v-show="active === 1" :model="addData.data" ref="data" label-width="120px"> <!-- <cb-form :model="formData" ref="data" label-width="120px"> -->
<cb-form v-show="active === 1" :model="formData" ref="data" label-width="120px">
<el-row> <el-row>
<cb-form-item label="网络类型: " prop="instanceNetworkType" :rules="[required]"> <cb-form-item label="虚拟私有云: " prop="vpcId" :rules="[required]">
<el-radio-group v-model="addData.data.instanceNetworkType" @change="changeNetworkType"> <el-select v-model="formData.vpcId" clearable placeholder="请选择虚拟私有云" @change="changeVpc">
<el-radio-button label="Classic">经典网络</el-radio-button> <el-option v-for="(item, index) in vpcList" :key="index" :value="item.value" :label="item.name"></el-option>
<el-radio-button label="VPC">专有网络</el-radio-button>
</el-radio-group>
</cb-form-item>
<div v-if="addData.data.instanceNetworkType == 'VPC'">
<cb-form-item label="VPC: " prop="vpcId" :rules="[required]">
<el-select v-model="addData.data.vpcId" clearable placeholder="请选择VPC" @change="changeVpc">
<el-option v-for="(item, index) in vpcList" :key="index" :value="item.value" :label="item.name"></el-option>
</el-select>
</cb-form-item>
<cb-form-item label="主节点交换机: " prop="vswitchId" :rules="[required]">
<el-select v-model="addData.data.vswitchId" clearable placeholder="请选择主节点交换机">
<el-option v-for="(item, index) in vswitchList" :key="index" :value="item.value" :label="item.name"></el-option>
</el-select>
</cb-form-item>
</div>
<!-- <cb-form-item label="参数模板: " prop="paramGroupId" :rules="[required]">
<el-select v-model="addData.data.paramGroupId" clearable placeholder="请选择参数模板">
<el-option v-for="(item, index) in templateList" :key="index" :value="item.id" :label="item.name"></el-option>
</el-select>
</cb-form-item> -->
<cb-form-item label="时区: " prop="timeZone" :rules="[required]">
<el-select filterable v-model="addData.data.timeZone" clearable placeholder="请选择时区">
<el-option v-for="(item, index) in timeList" :key="index" :value="item.value" :label="item.name"></el-option>
</el-select> </el-select>
</cb-form-item> </cb-form-item>
<cb-form-item label="表名大小写: " prop="IgnoreCase" :rules="[required]"> <cb-form-item label="子网: " prop="subnetId" :rules="[required]">
<el-radio-group v-model="addData.data.IgnoreCase"> <el-select v-model="formData.subnetId" clearable placeholder="请选择子网">
<el-radio label="1">不区分大小写默认</el-radio> <el-option v-for="(item, index) in subnetList" :key="index" :value="item.value" :label="item.name"></el-option>
<el-radio label="0">区分大小写</el-radio>
</el-radio-group>
</cb-form-item>
<!-- <cb-form-item label="资源组: " prop="resourceId">
<el-select v-model="addData.data.resourceId" clearable filterable>
<el-option v-for="(item, index) in rgroupList" :key="index" :value="item.resourceGroupUuid" :label="item.displayName"></el-option>
</el-select> </el-select>
</cb-form-item> --> </cb-form-item>
<cb-form-item label="安全组: " prop="securityGroupId">
<el-select v-model="formData.securityGroupId" clearable filterable>
<el-option v-for="(item, index) in sgroupList" :key="index" :value="item.value" :label="item.name"></el-option>
</el-select>
</cb-form-item>
<cb-form-item label="实例名称:" prop="name" :rules="[required, ctstackDatabaseName]">
<el-input v-model="formData.name" placeholder="请输入实例名称" class="basic-cmp"></el-input>
</cb-form-item>
<cb-form-item label="登录密码:" prop="password" :rules="[required, ctstackBMSPassword]">
<el-input type="password" v-model="formData.password" @blur="PswBlur" show-password></el-input>
</cb-form-item>
<cb-form-item label="确认密码:" prop="endPassword" :rules="[required, ctstackBMSPassword]">
<el-input type="password" v-model="formData.endPassword" @blur="PswBlur"></el-input>
</cb-form-item>
</el-row> </el-row>
</cb-form> </cb-form>
<div slot="footer"> <div slot="footer">
@ -120,13 +124,24 @@
</template> </template>
<script> <script>
import validate from '@/validate' import validate from '@/validate'
import { getRegion } from 'services/platform/index'
import { getSubnet } from 'views/resource/ctstack/services/subnet.js' import { getSubnet } from 'views/resource/ctstack/services/subnet.js'
import { getRegion, getFlavor, getParamGroup, createRds, getFlavorSpec } from 'views/resource/ctstack/services/database/rds.js' import { getGroup } from 'views/resource/ctstack/services/group.js'
import { getFlavor, createRds, getRdsProject, getRdsZone } from 'views/resource/ctstack/services/database/rds.js'
import { getVpc } from 'views/resource/ctstack/services/vpcs.js' import { getVpc } from 'views/resource/ctstack/services/vpcs.js'
import RegionItem from './RegionItem.vue' import { encrypt, handleSearchParam } from '@cmp/cmp-element'
import { handleSearchParam } from '@cmp/cmp-element' import { uniqBy, cloneDeep } from 'lodash-es'
const instSpecMap = {
通用型: '1',
计算增强型: '2',
内存优化型: '3'
}
const instSpecMapRevers = {
1: '通用型',
2: '计算增强型',
3: '内存优化型'
}
export default { export default {
components: { RegionItem },
props: { props: {
addData: { addData: {
type: Object type: Object
@ -135,304 +150,271 @@ export default {
data() { data() {
return { return {
required: validate.required, required: validate.required,
ctstackDatabaseName: validate.ctstackDatabaseName,
ctstackBMSPassword: validate.ctstackBMSPassword,
active: 0, active: 0,
regions: [], formData: {
typeList: { vendorId: this.addData.vendorId,
MySQL: ['5.5', '5.6', '5.7', '8.0'] type: this.addData.type,
// SQLServer: ['2008r2', '08r2_ent_ha', '2012', '2012_ent_ha', '2012_std_ha', '2012_web', '2014_std_ha', '2016_ent_ha', '2016_std_ha', '2016_web', '2017_std_ha', '2017_ent', '2019_std_ha', '2019_ent'], flavorId: '',
// PostgreSQL: ['9.4', '10.0', '11.0', '12.0', '13.0'], billMode: '2', // 12
// MariaDB: ['10.3'] regionId: '',
prodVersion: '', // 12.16
prodSpecName: '', //
mysqlNodeInfoList: [
{
nodeType: 'master', //
instSpec: '1', // 1=2=3=4=
storageType: 'SATA', // : SSD=IOSATA=IOSAS=IOSSD-genric=SSDFAST-SSD=SSD
storageSpace: 100, // (:G100,32768)
prodPerformanceSpec: '', // (: 4C8G)
disks: 1, //
availabilityZoneInfo: [
{
availabilityZoneName: '',
availabilityZoneCount: 1,
nodeType: 'master' // AZmaster/slave/readNode
},
{
availabilityZoneName: '',
availabilityZoneCount: 1,
nodeType: 'slave'
},
{
availabilityZoneName: '',
availabilityZoneCount: 1,
nodeType: 'slave'
}
]
}
],
vpcId: '',
subnetId: '',
securityGroupId: '',
name: '',
password: '',
endPassword: '',
period: '1', // 1-36
count: 1,
autoRenewStatus: 0, // 0-,1-
prodId: '', // id
projectId: '',
projectName: '',
hostType: '' // host type: S6 or S7
}, },
versionList: [], projectList: [],
categoryList: [], regionData: [],
categoryMap: { sqlTypeMap: {
5.5: [ MySQL: ['5.7', '8.0']
{
name: '高可用版',
value: 'HighAvailability',
volType: [
{
name: '本地SSD云盘',
value: 'local_ssd'
}
]
}
],
5.6: [
{
name: '高可用版',
value: 'HighAvailability',
volType: [
{
name: '本地SSD云盘',
value: 'local_ssd'
}
]
},
{ name: '基础版', value: 'Basic', volType: [] }
],
5.7: [
{
name: '高可用版',
value: 'HighAvailability',
volType: [
{
name: '本地SSD云盘',
value: 'local_ssd'
},
{
name: 'ESSD PL1云盘',
value: 'cloud_essd'
},
{
name: 'ESSD PL2云盘',
value: 'cloud_essd2'
},
{
name: 'ESSD PL3云盘',
value: 'cloud_essd3'
},
{
name: 'SSD云盘',
value: 'cloud_ssd'
}
]
},
{
name: '基础版',
value: 'Basic',
volType: [
{
name: 'ESSD PL1云盘',
value: 'cloud_essd'
},
{
name: 'SSD云盘',
value: 'cloud_ssd'
}
]
},
{
name: '三节点企业版',
value: 'Finance',
volType: [
{
name: '本地SSD云盘',
value: 'local_ssd'
}
]
}
],
'8.0': [
{
name: '高可用版',
value: 'HighAvailability',
volType: [
{
name: '本地SSD云盘',
value: 'local_ssd'
},
{
name: 'ESSD PL1云盘',
value: 'cloud_essd'
},
{
name: 'ESSD PL2云盘',
value: 'cloud_essd2'
},
{
name: 'ESSD PL3云盘',
value: 'cloud_essd3'
},
{
name: 'SSD云盘',
value: 'cloud_ssd'
}
]
},
{
name: '基础版',
value: 'Basic',
volType: [
{
name: 'ESSD PL1云盘',
value: 'cloud_essd'
},
{
name: 'SSD云盘',
value: 'cloud_ssd'
}
]
},
{
name: '三节点企业版',
value: 'Finance',
volType: [
{
name: '本地SSD云盘',
value: 'local_ssd'
}
]
}
]
}, },
volTypeList: [], prodSpecNameList: [],
specList: [], storageTypeList: [
vpcList: [], {
vswitchList: [], name: '极速型SSD',
templateList: [], value: 'FAST-SSD'
timeList: [ },
{ name: 'UTC-12:00', value: '-12:00' }, {
{ name: 'UTC-11:00', value: '-11:00' }, name: '通用型SSD',
{ name: 'UTC-10:00', value: '-10:00' }, value: 'SSD-genric'
{ name: 'UTC-09:00', value: '-9:00' }, },
{ name: 'UTC-08:00', value: '-8:00' }, {
{ name: 'UTC-07:00', value: '-7:00' }, name: '高IO',
{ name: 'UTC-06:00', value: '-6:00' }, value: 'SAS'
{ name: 'UTC-05:00', value: '-5:00' }, },
{ name: 'UTC-04:00', value: '-4:00' }, {
{ name: 'UTC-03:00', value: '-3:00' }, name: '普通IO',
{ name: 'UTC-02:00', value: '-2:00' }, value: 'SATA'
{ name: 'UTC-01:00', value: '-1:00' }, },
{ name: 'UTC+00:00', value: '+0:00' }, {
{ name: 'UTC+01:00', value: '+1:00' }, name: '超高IO',
{ name: 'UTC+02:00', value: '+2:00' }, value: 'SSD'
{ name: 'UTC+03:00', value: '+3:00' }, }
{ name: 'UTC+04:00', value: '+4:00' },
{ name: 'UTC+05:00', value: '+5:00' },
{ name: 'UTC+05:30', value: '+5:30' },
{ name: 'UTC+06:00', value: '+6:00' },
{ name: 'UTC+07:00', value: '+7:00' },
{ name: 'UTC+08:00', value: '+8:00' },
{ name: 'UTC+09:00', value: '+9:00' },
{ name: 'UTC+10:00', value: '+10:00' },
{ name: 'UTC+11:00', value: '+11:00' },
{ name: 'UTC+12:00', value: '+12:00' },
{ name: 'UTC+13:00', value: '+13:00' }
], ],
rgroupList: [], periodList: [
marks: { { name: '1个月', value: '1' },
20: '20GB', { name: '2个月', value: '2' },
1500: '1500GB', { name: '3个月', value: '3' },
3000: '3000GB' { name: '4个月', value: '4' },
} { name: '5个月', value: '5' },
{ name: '6个月', value: '6' },
{ name: '7个月', value: '7' },
{ name: '8个月', value: '8' },
{ name: '9个月', value: '9' },
{ name: '12个月', value: '12' },
{ name: '24个月', value: '24' },
{ name: '36个月', value: '36' }
],
allFlavorList: [],
flavorList: [],
versionList: [],
zoneList: [],
instSpecList: [],
vpcList: [],
subnetList: [],
sgroupList: []
} }
}, },
created() { created() {
this.changeType(this.addData.data.dataStoreType) this.getRegionList()
this.getVendorDetail()
}, },
mounted() {}, mounted() {},
computed: {
regionId() {
return this.addData.data.regionId
}
},
watch: {
regionId(newVal) {
this.versionList = []
this.addData.data.dataStoreVersion = ''
this.getVersions()
}
},
methods: { methods: {
getVendorDetail() { getRegionList() {
// detailCloudVendor(this.addData.data.vendorId).then(data => { const { vendorId, type } = this.formData
// if (data.success) { if (type) {
// const authentication = data.data.authentication ? JSON.parse(data.data.authentication) : {} getRegion({
// this.regions = authentication.regions || []
// }
// })
},
getFlavorList() {
const { dataStoreType, dataStoreVersion, series, vendorId, regionId, volType, zone } = this.addData.data
if (dataStoreType && dataStoreVersion && series && regionId && volType && zone) {
getFlavor({
series: series,
vendorId: vendorId, vendorId: vendorId,
regionId: regionId, type: type
zone: zone,
engine: dataStoreType.toLowerCase(),
version: dataStoreVersion,
storageType: volType
}).then(data => { }).then(data => {
if (data.success) { if (data.success) {
this.specList = data.data this.regionData = data.data
this.addData.data.flavorId = this.specList.length ? this.specList[0].id : '' this.formData.regionId = this.regionData.length ? this.regionData[0].code : ''
this.changeRegion()
} }
}) })
} }
}, },
getVersions() { changeRegion() {
const { vendorId, regionId } = this.addData.data this.getVpcList()
const params = { this.getProject()
type: 'version',
vendorId,
regionId,
engine: 'MySQL'
}
// const res = await getFlavorSpec(params)
// if (res) {
// this.versionList = res.data
// }
this.versionList = [
{ name: '8.0', value: '8.0' },
{ name: '5.7', value: '5.7' }
]
}, },
async getSeries(version) { getProject() {
const { vendorId, regionId } = this.addData.data getRdsProject({
const params = { regionId: this.formData.regionId,
type: 'series', vendorId: this.formData.vendorId,
vendorId, type: this.formData.type
regionId, }).then(res => {
version, if (res.success) {
engine: 'MySQL' this.projectList = res.data
} this.formData.projectId = this.projectList.length ? this.projectList[0].projectSetId : ''
const res = await getFlavorSpec(params) this.changeProject()
if (res) { }
this.categoryList = res.data })
},
async changeProject() {
if (!this.formData.projectId) return
this.formData.projectName = this.projectList.find(item => item.projectSetId === this.formData.projectId)?.projectSetName
await this.getZone()
this.getFlavorList()
},
async getZone() {
await getRdsZone({
regionId: this.formData.regionId,
vendorId: this.formData.vendorId,
projectId: this.formData.projectId
}).then(data => {
if (data.success) {
this.zoneList = data.data
}
})
},
getFlavorList() {
const { type, vendorId, regionId, projectId } = this.formData
if ((type, vendorId, regionId, projectId)) {
getFlavor({
type,
vendorId,
regionId,
projectId
}).then(data => {
if (data.success) {
this.allFlavorList = Object.freeze(data.data)
this.getVersionList()
}
})
} }
}, },
async getStorageType(series) { getVersionList() {
const { vendorId, regionId } = this.addData.data const list = this.allFlavorList.map(({ prodVersion }) => ({ name: prodVersion, value: prodVersion }))
const params = { this.versionList = uniqBy(list, 'value')
type: 'storageType', this.formData.prodVersion = this.versionList.length ? this.versionList[0].value : ''
vendorId, this.changeVersion()
regionId,
series,
engine: 'MySQL'
}
const res = await getFlavorSpec(params)
if (res) {
this.volTypeList = res.data
}
}, },
changeVersion(value) { changeVersion() {
this.categoryList = [] this.getCategoryList()
this.$set(this.addData.data, 'series', '')
this.volTypeList = []
this.addData.data.volType = ''
this.specList = []
this.getSeries(value)
}, },
changeCategory(value) { getCategoryList() {
this.volTypeList = [] const { prodVersion } = this.formData
this.addData.data.volType = '' if (!prodVersion) return
this.specList = [] const list = this.allFlavorList.filter(item => item.prodVersion === prodVersion).map(({ prodSpecName }) => prodSpecName)
this.getStorageType(value) this.prodSpecNameList = list
this.formData.prodSpecName = this.prodSpecNameList.length ? this.prodSpecNameList[0] : ''
this.changeCategory()
}, },
changeNetworkType(value) { changeCategory() {
if (value == 'VPC') { this.resetZone()
this.getVpcList() },
resetZone() {
const [first = '', second = '', third = ''] = this.zoneList.map(item => item.availabilityZoneId)
switch (this.formData.prodSpecName) {
case '单机版':
case '只读实例':
this.formData.mysqlNodeInfoList[0].availabilityZoneInfo[0].availabilityZoneName = first
this.formData.mysqlNodeInfoList[0].availabilityZoneInfo[1].availabilityZoneName = ''
this.formData.mysqlNodeInfoList[0].availabilityZoneInfo[2].availabilityZoneName = ''
break
case '一主一备':
this.formData.mysqlNodeInfoList[0].availabilityZoneInfo[0].availabilityZoneName = first
this.formData.mysqlNodeInfoList[0].availabilityZoneInfo[1].availabilityZoneName = second
this.formData.mysqlNodeInfoList[0].availabilityZoneInfo[2].availabilityZoneName = ''
break
case '一主两备':
this.formData.mysqlNodeInfoList[0].availabilityZoneInfo[0].availabilityZoneName = first
this.formData.mysqlNodeInfoList[0].availabilityZoneInfo[1].availabilityZoneName = second
this.formData.mysqlNodeInfoList[0].availabilityZoneInfo[2].availabilityZoneName = third
break
default:
this.formData.mysqlNodeInfoList[0].availabilityZoneInfo[0].availabilityZoneName = first
this.formData.mysqlNodeInfoList[0].availabilityZoneInfo[1].availabilityZoneName = ''
this.formData.mysqlNodeInfoList[0].availabilityZoneInfo[2].availabilityZoneName = ''
break
} }
this.changeZone()
},
changeZone() {
this.getInstSpecList()
},
getInstSpecList() {
const { prodVersion, prodSpecName } = this.formData
if (!prodVersion || !prodSpecName) return
const instSpecMap = {
通用型: '1',
计算增强型: '2',
内存优化型: '3'
}
this.instSpecList = this.allFlavorList.filter(item => item.prodVersion === prodVersion && item.prodSpecName === prodSpecName).map(({ instanceType }) => ({ name: instanceType, value: instSpecMap[instanceType] }))
this.formData.mysqlNodeInfoList[0].instSpec = this.instSpecList.length ? this.instSpecList[0].value : ''
this.changeInstSpec()
},
changeInstSpec() {
this._getFlavor()
},
_getFlavor() {
const { prodVersion, prodSpecName, mysqlNodeInfoList } = this.formData
if (!prodVersion || !prodSpecName || !mysqlNodeInfoList[0].instSpec) return
//
const find = this.allFlavorList.find(item => item.prodVersion === prodVersion && item.prodSpecName === prodSpecName && item.instanceType === instSpecMapRevers[mysqlNodeInfoList[0].instSpec])
if (!find) return console.log('未找到规格', prodVersion, prodSpecName, instSpecMapRevers[mysqlNodeInfoList[0].instSpec])
//
this.flavorList = find.instSpecInfoList.filter(item => item.azList.includes(this.formData.mysqlNodeInfoList[0].availabilityZoneInfo[0].availabilityZoneName)).sort((a, b) => a.prodPerformanceSpec?.split(/[A-Z]/)[0] - b.prodPerformanceSpec?.split(/[A-Z]/)[0])
this.formData.flavorId = this.flavorList.length ? this.flavorList[0].specName : ''
this.changeFlavorId()
},
changeFlavorId() {
const { prodVersion, prodSpecName, mysqlNodeInfoList } = this.formData
const group = this.allFlavorList.find(item => item.prodVersion === prodVersion && item.prodSpecName === prodSpecName && item.instanceType === instSpecMapRevers[mysqlNodeInfoList[0].instSpec]) || {}
this.formData.prodId = group.prodId || ''
const find = this.flavorList.find(item => item.specName === this.formData.flavorId) || {}
this.formData.hostType = find.generation || ''
this.formData.mysqlNodeInfoList[0].prodPerformanceSpec = find.prodPerformanceSpec || ''
}, },
getVpcList() { getVpcList() {
getVpc({ getVpc({
simple: true, simple: true,
params: handleSearchParam({ params: handleSearchParam({
vendorId: this.addData.data.vendorId, vendorId: this.formData.vendorId,
regionId: this.addData.data.regionId regionId: this.formData.regionId
}) })
}).then(data => { }).then(data => {
this.loading = false this.loading = false
@ -442,63 +424,41 @@ export default {
}) })
}, },
changeVpc(value) { changeVpc(value) {
let networkId = '' this.subnetList = []
this.vswitchList = [] this.formData.subnetId = ''
this.addData.data.vswitchId = '' this.getSubnetList()
this.vpcList.forEach(item => { this.getRgroup()
if (value == item.value) {
networkId = item.id
this.getSwitchList(networkId)
}
})
}, },
getSwitchList(networkId) { getSubnetList() {
getSubnet({ getSubnet({
simple: true, simple: true,
params: handleSearchParam({ params: handleSearchParam({
networkId: networkId, vpcUuid: this.formData.vpcId,
vendorId: this.addData.data.vendorId, vendorId: this.formData.vendorId
zone: this.addData.data.zone
}) })
}).then(data => { }).then(data => {
if (data.success) { if (data.success) {
this.vswitchList = data.data.rows this.subnetList = data.data.rows
} this.formData.subnetId = this.subnetList.length ? this.subnetList[0].value : ''
})
},
getTemplateList() {
getParamGroup({
regionId: this.addData.data.regionId,
vendorId: this.addData.data.vendorId,
engine: this.addData.data.dataStoreType.toLowerCase(),
version: this.addData.data.dataStoreVersion
}).then(data => {
if (data.success) {
this.templateList = data.data
} }
}) })
}, },
getRgroup() { getRgroup() {
// getResource({ getGroup({
// page: 1, simple: true,
// rows: 99999, params: JSON.stringify([{ param: { vendorId: this.formData.vendorId, regionId: this.formData.regionId, tenantId: 0, vpcUuid: this.formData.vpcId }, sign: 'EQ' }])
// params: handleSearchParam({ }).then(data => {
// vendorId: this.addData.data.vendorId, if (data.success) {
// 'status:ueq': 'PendingDelete' this.sgroupList = data.data.rows
// }) this.formData.securityGroupId = this.sgroupList.length ? this.sgroupList[0].value : ''
// }).then(data => { }
// if (data.success) { })
// this.rgroupList = data.data.rows
// }
// })
}, },
next(num) { next(num) {
if (num === 0) { if (num === 0) {
this.$refs.basicData.validate(valid => { this.$refs.basicData.validate(valid => {
if (valid) { if (valid) {
this.active = 1 this.active = 1
this.getRgroup()
this.getTemplateList()
} }
}) })
} }
@ -509,7 +469,19 @@ export default {
if (!valid) { if (!valid) {
return false return false
} }
createRds(this.addData.data).then(data => { const params = cloneDeep(this.formData)
//
params.mysqlNodeInfoList[0].availabilityZoneInfo = params.mysqlNodeInfoList[0].availabilityZoneInfo.filter(item => item.availabilityZoneName)
if (params.password !== params.endPassword) {
this.$notify({
title: '提示',
message: '两次密码输入不一致'
})
return
}
if (params.password) params.password = encrypt(params.password)
if (params.endPassword) params.endPassword = encrypt(params.endPassword)
createRds(params).then(data => {
const type = data.success ? 'success' : 'error' const type = data.success ? 'success' : 'error'
this.$message[type](data.message) this.$message[type](data.message)
if (data.success) { if (data.success) {
@ -519,7 +491,13 @@ export default {
} }
}) })
}) })
},
PswBlur(e) {
const value = e.target.value
} }
} }
} }
</script> </script>
//

View File

@ -12,9 +12,6 @@
<template #type="type"> <template #type="type">
{{ filter[type] }} {{ filter[type] }}
</template> </template>
<template #instanceNetworkType="instanceNetworkType">
{{ filter[instanceNetworkType] }}
</template>
<template #payType="payType"> <template #payType="payType">
{{ filter[payType] }} {{ filter[payType] }}
</template> </template>
@ -24,7 +21,7 @@
<template #operate="val, record"> <template #operate="val, record">
<el-button type="text" @click="patch(record)" :disabled="record.status !== 'Running'"> 重启 </el-button> <el-button type="text" @click="patch(record)" :disabled="record.status !== 'Running'"> 重启 </el-button>
<div class="action-divider"></div> <div class="action-divider"></div>
<el-button type="text" @click="removeAliRds(record)" :disabled="record.status !== 'Running'"> 释放实例 </el-button> <el-button type="text" @click="removeRds(record)" :disabled="record.status !== 'Running'"> 释放实例 </el-button>
</template> </template>
</cb-advance-table> </cb-advance-table>
<add :add-data="addData" v-if="addData.dialog" @back="getData"></add> <add :add-data="addData" v-if="addData.dialog" @back="getData"></add>
@ -35,7 +32,6 @@
<cb-detail-item label="版本">{{ detailData.dataStoreVersion }}</cb-detail-item> <cb-detail-item label="版本">{{ detailData.dataStoreVersion }}</cb-detail-item>
<cb-detail-item label="实例类型">{{ filter[detailData.type] }}</cb-detail-item> <cb-detail-item label="实例类型">{{ filter[detailData.type] }}</cb-detail-item>
<cb-detail-item label="数据库类型">{{ detailData.dataStoreType }}</cb-detail-item> <cb-detail-item label="数据库类型">{{ detailData.dataStoreType }}</cb-detail-item>
<cb-detail-item label="网络类型">{{ filter[detailData.instanceNetworkType] }}</cb-detail-item>
<cb-detail-item label="付费类型">{{ filter[detailData.payType] }}</cb-detail-item> <cb-detail-item label="付费类型">{{ filter[detailData.payType] }}</cb-detail-item>
<cb-detail-item label="规格">{{ detailData.flavorId }}</cb-detail-item> <cb-detail-item label="规格">{{ detailData.flavorId }}</cb-detail-item>
<cb-detail-item label="可用区">{{ detailData.region }}</cb-detail-item> <cb-detail-item label="可用区">{{ detailData.region }}</cb-detail-item>
@ -266,7 +262,7 @@
<script> <script>
import validate from '@/validate' import validate from '@/validate'
import { getAliRds, detailAliRds, getRdsCos, patchAliRds, removeAliRds, getRdsUsers, createRdsUsers, removeRdsUsers, resetRdsUserPasd, resetRdsUser, authRdsUser, getRdsDbs, createRdsDbs, removeRdsDbs } from 'views/resource/ctstack/services/database/rds.js' import { getRds, detailRds, getRdsCos, patchRds, removeRds, getRdsUsers, createRdsUsers, removeRdsUsers, resetRdsUserPasd, resetRdsUser, authRdsUser, getRdsDbs, createRdsDbs, removeRdsDbs } from 'views/resource/ctstack/services/database/rds.js'
import add from './add.vue' import add from './add.vue'
import ModifyRole from './ModifyRole.vue' import ModifyRole from './ModifyRole.vue'
import { keywords } from './validate' import { keywords } from './validate'
@ -377,7 +373,8 @@ export default {
rdsDBPassword: { pattern: '^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z\\W_]+$)(?![a-z0-9]+$)(?![a-z\\W_]+$)(?![0-9\\W_]+$)[a-zA-Z0-9\\W_]{8,32}$', message: '必须包含三种及以上类型大小写字母、数字、特殊符号。长度为8-32位特殊字符包括! @ # $ % ^ & * () _ + - =', trigger: null }, rdsDBPassword: { pattern: '^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z\\W_]+$)(?![a-z0-9]+$)(?![a-z\\W_]+$)(?![0-9\\W_]+$)[a-zA-Z0-9\\W_]{8,32}$', message: '必须包含三种及以上类型大小写字母、数字、特殊符号。长度为8-32位特殊字符包括! @ # $ % ^ & * () _ + - =', trigger: null },
searchConfigs: [ searchConfigs: [
{ type: 'Input', label: '名称', value: 'name' }, { type: 'Input', label: '名称', value: 'name' },
{ type: 'Const', value: 'vendorId', initValue: this.platformObject.vendorId } { type: 'Const', value: 'vendorId', initValue: this.platformObject.vendorId },
{ type: 'Const', value: 'dbType', initValue: 'MYSQL' }
], ],
columns, columns,
loading: false, loading: false,
@ -524,7 +521,7 @@ export default {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
patchAliRds(data.id).then(data => { patchRds(data.id).then(data => {
if (data.success) { if (data.success) {
this.$message({ this.$message({
type: 'success', type: 'success',
@ -535,13 +532,13 @@ export default {
}) })
}) })
}, },
removeAliRds(data) { removeRds(data) {
this.$confirm('确定释放该实例吗?', '提示', { this.$confirm('确定释放该实例吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
removeAliRds(data.id).then(data => { removeRds(data.id).then(data => {
if (data.success) { if (data.success) {
this.$message({ this.$message({
type: 'success', type: 'success',
@ -554,7 +551,7 @@ export default {
}, },
getData() { getData() {
this.loading = true this.loading = true
getAliRds(this.params).then(data => { getRds(this.params).then(data => {
this.loading = false this.loading = false
if (data.success) { if (data.success) {
this.tableData = data.data.rows this.tableData = data.data.rows
@ -562,42 +559,16 @@ export default {
} }
}) })
}, },
handleSearch() {
this.params.page = 1
this.params.params = handleSearchParam({
vendorId: this.platformObject.vendorId,
regionId: this.searchData.regionId,
zone: this.searchData.zone,
'name:lk': this.searchData.name
})
this.getData()
},
handleCreate() { handleCreate() {
this.addData = { this.addData = {
dialog: true, dialog: true,
data: { vendorId: this.platformObject.vendorId,
vendorId: this.platformObject.vendorId, type: 'MySQL'
payType: 'Postpaid',
regionId: '',
type: 'MySQL',
dataStoreVersion: '',
category: '',
volType: '',
availZone: '',
flavorId: '',
volSize: 20,
instanceNetworkType: 'Classic',
vpcId: '',
vswitchId: '',
paramGroupId: '',
timeZone: '+8:00',
IgnoreCase: '1'
}
} }
}, },
getDetail(id) { getDetail(id) {
this.Super = false this.Super = false
detailAliRds(id).then(data => { detailRds(id).then(data => {
if (data.success) { if (data.success) {
this.detailData = data.data this.detailData = data.data
this.detailFlag = true this.detailFlag = true

File diff suppressed because it is too large Load Diff

View File

@ -1,79 +1,94 @@
import { request } from '@cmp/cmp-element' import { request } from '@cmp/cmp-element'
import { wrapperParams, downloadFile } from 'utils' import { wrapperParams, downloadFile } from 'utils'
const url = '/cmp/plugins/ctstack/v1/rds' import { projectList, zoneList, flavorList } from './mockData'
const url = '/cmp/plugins/ctstack/v1/cloudrds'
// 是否开发环境
const isDev = process.env.NODE_ENV === 'development'
const mockRequest = data =>
new Promise(resolve =>
resolve({
success: true,
data
})
)
export function getRegion(params) { export function getRegion(params) {
return request.get(`${url}/mysql/regions`, { params }) return request.get(`${url}/regions`, { params })
}
export function getRdsProject(params) {
if (isDev) return mockRequest(projectList)
return request.get(`${url}/projects`, { params })
}
export function getRdsZone(params) {
if (isDev) return mockRequest(zoneList)
return request.get(`${url}/zones`, { params })
} }
export function getFlavor(params) { export function getFlavor(params) {
return request.get(`${url}/mysql/flavors`, { params }) if (isDev) return mockRequest(flavorList)
return request.get(`${url}/flavors`, { params })
} }
export function getParamGroup(params) { export function getParamGroup(params) {
return request.get(`${url}/mysql/param/groups`, { params }) return request.get(`${url}/param/groups`, { params })
} }
export function createRds(params) { export function createRds(params) {
return request.post(`${url}/mysql`, params) return request.post(`${url}`, params)
} }
export function getRdsDbs(id, params) { export function getRdsDbs(id, params) {
return request.get(`${url}/mysql/${id}/dbs`, { params }) return request.get(`${url}/${id}/dbs`, { params })
} }
export function getRdsCos(id, params) { export function getRdsCos(id, params) {
return request.get(`${url}/mysql/${id}/nets`, { params }) return request.get(`${url}/${id}/nets`, { params })
} }
export function getAliRds(params) { export function getRds(params) {
return request.get(`${url}/mysql`, { params }) return request.get(`${url}`, { params })
} }
export function detailAliRds(id) { export function detailRds(id) {
return request.get(`${url}/mysql/${id}`) return request.get(`${url}/${id}`)
} }
export function patchAliRds(id) { export function patchRds(id) {
return request.patch(`${url}/mysql/${id}`) return request.patch(`${url}/${id}`)
} }
export function removeAliRds(id) { export function removeRds(id) {
return request.delete(`${url}/mysql/${id}`) return request.delete(`${url}/${id}`)
} }
export function getRdsUsers(id, params) { export function getRdsUsers(id, params) {
return request.get(`${url}/mysql/${id}/users`, { params }) return request.get(`${url}/${id}/users`, { params })
} }
export function createRdsUsers(id, params) { export function createRdsUsers(id, params) {
return request.post(`${url}/mysql/${id}/users`, params) return request.post(`${url}/${id}/users`, params)
} }
export function removeRdsUsers(params) { export function removeRdsUsers(params) {
return request.delete(`${url}/mysql/${params.rdsId}/users/${params.userId}`) return request.delete(`${url}/${params.rdsId}/users/${params.userId}`)
} }
export function resetRdsUserPasd(params) { export function resetRdsUserPasd(params) {
return request.put(`${url}/mysql/${params.rdsId}/users/${params.userId}/resetpassword`, wrapperParams(params)) return request.put(`${url}/${params.rdsId}/users/${params.userId}/resetpassword`, wrapperParams(params))
} }
export function resetRdsUser(params) { export function resetRdsUser(params) {
return request.put(`${url}/mysql/${params.rdsId}/users/${params.userId}/resetaccount`, wrapperParams(params)) return request.put(`${url}/${params.rdsId}/users/${params.userId}/resetaccount`, wrapperParams(params))
} }
export function authRdsUser(params) { export function authRdsUser(params) {
return request.put(`${url}/mysql/${params.rdsId}/users/${params.userId}/dbs`, wrapperParams(params)) return request.put(`${url}/${params.rdsId}/users/${params.userId}/dbs`, wrapperParams(params))
} }
export function createRdsDbs(id, params) { export function createRdsDbs(id, params) {
return request.post(`${url}/mysql/${id}/dbs`, params) return request.post(`${url}/${id}/dbs`, params)
} }
export function removeRdsDbs(params) { export function removeRdsDbs(params) {
return request.delete(`${url}/mysql/${params.rdsId}/dbs/${params.dbId}`) return request.delete(`${url}/${params.rdsId}/dbs/${params.dbId}`)
}
export function getFlavorSpec(params) {
return request.get(`${url}/mysql/flavors/spec`, { params })
} }