feat: mysql/pgsql 创建完成

develop
时启龙 2024-09-06 10:50:59 +08:00
parent a569bed271
commit ca0d49281c
14 changed files with 1819 additions and 51 deletions

View File

@ -13,47 +13,48 @@
</el-radio-group>
</cb-form-item>
<cb-form-item label="地域: " prop="regionId" :rules="[required]">
<el-select v-model="formData.regionId" clearable placeholder="请选择地域" @change="changeRegion">
<el-select v-model="formData.regionId" placeholder="请选择地域" @change="changeRegion">
<el-option v-for="item in regionData" :key="item.code" :value="item.code" :label="item.name"></el-option>
</el-select>
</cb-form-item>
<cb-form-item label="企业项目: " prop="projectId" :rules="[required]">
<el-select v-model="formData.projectId" clearable placeholder="请选择企业项目" @change="changeProject">
<el-select v-model="formData.projectId" placeholder="请选择企业项目" @change="changeProject">
<el-option v-for="item in projectList" :key="item.projectSetId" :value="item.projectSetId" :label="item.projectSetName"></el-option>
</el-select>
</cb-form-item>
<cb-form-item label="数据库类型: " prop="type" :rules="[required]">
<el-select v-model="formData.type" clearable placeholder="请选择类型">
<el-option v-for="(item, key) in sqlTypeMap" :key="key" :value="key" :label="key"></el-option>
</el-select>
<cb-form-item label="数据库类型: " prop="type" :rules="[required]" v-if="formData.type">
<el-radio-group v-model="formData.type" placeholder="请选择类型">
<el-radio label="MYSQL" v-if="formData.type === 'MYSQL'">MySQL</el-radio>
<el-radio label="POSTGRESQL" v-if="formData.type === 'POSTGRESQL'">PostgreSQL</el-radio>
</el-radio-group>
</cb-form-item>
<cb-form-item label="数据库版本: " prop="prodVersion" :rules="[required]">
<el-radio-group v-model="formData.prodVersion" clearable placeholder="请选择版本" @change="changeVersion">
<el-radio-group v-model="formData.prodVersion" placeholder="请选择版本" @change="changeVersion">
<el-radio v-for="item in versionList" :key="item.value" :value="item.value" :label="item.name"></el-radio>
</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-group v-model="formData.prodSpecName" 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-group v-model="formData.mysqlNodeInfoList[0].availabilityZoneInfo[0].availabilityZoneName" 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-group v-model="formData.mysqlNodeInfoList[0].availabilityZoneInfo[1].availabilityZoneName" 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-group v-model="formData.mysqlNodeInfoList[0].availabilityZoneInfo[2].availabilityZoneName" 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-group v-model="formData.mysqlNodeInfoList[0].instSpec" 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>
@ -69,7 +70,7 @@
</cb-smart-table>
</cb-form-item>
<cb-form-item label="存储类型: " prop="mysqlNodeInfoList.0.storageType" :rules="[required]">
<el-select v-model="formData.mysqlNodeInfoList[0].storageType" clearable placeholder="请选择类型">
<el-select v-model="formData.mysqlNodeInfoList[0].storageType" placeholder="请选择类型">
<el-option v-for="(item, index) in storageTypeList" :key="index" :value="item.value" :label="item.name"></el-option>
</el-select>
</cb-form-item>
@ -79,7 +80,7 @@
</div>
</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-select v-model="formData.period" filterable>
<el-option v-for="(item, index) in periodList" :key="index" :value="item.value" :label="item.name"></el-option>
</el-select>
</cb-form-item>
@ -89,17 +90,17 @@
<cb-form v-show="active === 1" :model="formData" ref="data" label-width="120px">
<el-row>
<cb-form-item label="虚拟私有云: " prop="vpcId" :rules="[required]">
<el-select v-model="formData.vpcId" clearable placeholder="请选择虚拟私有云" @change="changeVpc">
<el-select v-model="formData.vpcId" placeholder="请选择虚拟私有云" @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="subnetId" :rules="[required]">
<el-select v-model="formData.subnetId" clearable placeholder="请选择子网">
<el-select v-model="formData.subnetId" placeholder="请选择子网">
<el-option v-for="(item, index) in subnetList" :key="index" :value="item.value" :label="item.name"></el-option>
</el-select>
</cb-form-item>
<cb-form-item label="安全组: " prop="securityGroupId">
<el-select v-model="formData.securityGroupId" clearable filterable>
<el-select v-model="formData.securityGroupId" filterable>
<el-option v-for="(item, index) in sgroupList" :key="index" :value="item.value" :label="item.name"></el-option>
</el-select>
</cb-form-item>
@ -127,7 +128,7 @@ import validate from '@/validate'
import { getRegion } from 'services/platform/index'
import { getSubnet } from 'views/resource/ctstack/services/subnet.js'
import { getGroup } from 'views/resource/ctstack/services/group.js'
import { getFlavor, createRds, getRdsProject, getRdsZone } from 'views/resource/ctstack/services/database/rds.js'
import { getFlavor, createRds, getRdsProject, getRdsZone, getStorageType } from 'views/resource/ctstack/services/database/rds.js'
import { getVpc } from 'views/resource/ctstack/services/vpcs.js'
import { encrypt, handleSearchParam } from '@cmp/cmp-element'
import { uniqBy, cloneDeep } from 'lodash-es'
@ -204,32 +205,8 @@ export default {
},
projectList: [],
regionData: [],
sqlTypeMap: {
MySQL: ['5.7', '8.0']
},
prodSpecNameList: [],
storageTypeList: [
{
name: '极速型SSD',
value: 'FAST-SSD'
},
{
name: '通用型SSD',
value: 'SSD-genric'
},
{
name: '高IO',
value: 'SAS'
},
{
name: '普通IO',
value: 'SATA'
},
{
name: '超高IO',
value: 'SSD'
}
],
storageTypeList: [],
periodList: [
{ name: '1个月', value: '1' },
{ name: '2个月', value: '2' },
@ -256,9 +233,19 @@ export default {
},
created() {
this.getRegionList()
this.getStorageTypeList()
},
mounted() {},
methods: {
getStorageTypeList() {
getStorageType({
type: this.addData.type
}).then(data => {
if (data.success) {
this.storageTypeList = data.data
}
})
},
getRegionList() {
const { vendorId, type } = this.formData
if (type) {
@ -499,5 +486,4 @@ export default {
}
</script>
//
//

View File

@ -263,7 +263,7 @@
<script>
import validate from '@/validate'
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 '../components/add.vue'
import ModifyRole from './ModifyRole.vue'
import { keywords } from './validate'
import { handleSearchParam } from '@cmp/cmp-element'
@ -563,7 +563,7 @@ export default {
this.addData = {
dialog: true,
vendorId: this.platformObject.vendorId,
type: 'MySQL'
type: 'MYSQL'
}
},
getDetail(id) {

View File

@ -0,0 +1,135 @@
<template>
<el-dialog title="修改权限" :close-on-click-modal="false" :visible.sync="dialog.visible" width="1100px" append-to-body>
<cb-form ref="addFormRef" :model="addData" label-width="140px">
<cb-form-item label-width="0">
<el-transfer
style="text-align: left; display: inline-block"
v-model="addData.checkedUseRoleIds"
filterable
:titles="['未选择', '已选择']"
:format="{
noChecked: '${total}',
hasChecked: '${checked}/${total}'
}"
:props="{ key: 'name', label: 'name' }"
:data="list"
>
<span slot-scope="{ option }">
<span style="margin-right: 10px">{{ option.name }}</span>
<el-radio-group v-model="option.role" class="role-group">
<el-radio label="ReadWrite">读写</el-radio>
<el-radio label="ReadOnly">只读</el-radio>
<el-radio label="DDLOnly">DDL</el-radio>
<el-radio label="DMLOnly">DML</el-radio>
</el-radio-group>
</span>
</el-transfer>
</cb-form-item>
</cb-form>
<div slot="footer" class="dialog-footer">
<el-button type="ghost" @click.native="dialog.visible = false">取消</el-button>
<el-button type="primary" @click.native="addSubmit" :loading="loading">确定</el-button>
</div>
</el-dialog>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import { Message } from 'element-ui'
import { handleSearchParam } from '@cmp/cmp-element'
import { getRdsDbs, authRdsUser } from '@/views/resource/ctstack/services/database/rds'
export default defineComponent({
props: {
dialog: {
type: Object
}
},
setup(props: any, context: any) {
const { record } = props.dialog
const addData = ref({
...record,
checkedUseRoleIds: record.privileges && JSON.parse(record.privileges).map((item: any) => item.name),
privileges: record.privileges ? JSON.parse(record.privileges) : []
})
const list = ref([])
const { vendorId, rdsId } = addData.value
;(async () => {
const res = await getRdsDbs(rdsId, { params: handleSearchParam({ vendorId, rdsId }) })
if (res.success) {
const { checkedUseRoleIds, privileges } = addData.value
console.log(privileges)
list.value = res.data.rows.map((item: any) => {
if (checkedUseRoleIds.includes(item.name)) {
const { accountPrivilege = '' } = privileges.find((role: any) => role.name === item.name) || {}
return {
...item,
role: accountPrivilege
}
} else {
return {
role: 'ReadWrite',
...item
}
}
})
}
})()
const loading = ref(false)
const addFormRef = ref(null)
function addSubmit() {
//
const { validate } = (addFormRef.value || context.refs.addFormRef) as HTMLFormElement
validate(async (valid: boolean) => {
if (valid) {
loading.value = true
const { rdsId, id, checkedUseRoleIds: checkedUserIds, username } = addData.value
const userRoles = list.value
.filter((item: any) => checkedUserIds.includes(item.name))
.map(({ name, role }: any) => {
return {
name,
accountPrivilege: role
}
})
const data = await authRdsUser({ rdsId, userId: id, id, username, privileges: userRoles })
loading.value = false
if (data.success) {
Message({
message: data.message,
type: 'success'
})
context.emit('getData')
;(props.dialog as Base.IDialog).visible = false
}
}
})
}
return {
loading,
addFormRef,
addData,
addSubmit,
list
}
}
})
</script>
<style lang="scss" scoped>
.slider-wrapper {
display: flex;
::v-deep .el-slider__marks-text {
white-space: nowrap;
}
}
::v-deep .el-transfer-panel:nth-child(1) .role-group {
display: none;
}
::v-deep .el-transfer-panel:nth-child(3) {
width: 600px;
}
</style>

View File

@ -0,0 +1,76 @@
/** * Created by HaijunZhang on 2019/4/28. */
<template>
<el-row :gutter="20">
<el-col :span="24">
<cb-form-item label="所属地域:" prop="regionId" validate="required">
<el-radio-group v-model="addData.regionId" @change="getZoneList">
<el-radio-button :label="item.regionId" v-for="item in regionList" :key="item.regionId">{{ item.name }}</el-radio-button>
</el-radio-group>
</cb-form-item>
</el-col>
<el-col :span="24">
<cb-form-item label="可用区:" prop="zone" validate="required">
<el-radio-group v-model="addData.zone" class="simple-radio">
<el-radio-button :label="item.zoneId" v-for="item in zoneList" :key="item.zoneId">{{ item.name }}</el-radio-button>
</el-radio-group>
</cb-form-item>
</el-col>
</el-row>
</template>
<script>
import { computed, defineComponent, reactive, ref, Ref, toRefs } from 'vue'
import { getRegion, getZone } from 'services/platform/index'
export default {
props: {
addData: {
type: Object,
required: true
}
},
setup(props, { root: { $set } }) {
const regionList = ref([])
const zoneList = ref([])
async function getRegionList() {
const res = await getRegion({ vendorId: props.addData.vendorId })
if (res.success) {
regionList.value = res.data
if (!props.addData.regionId) {
$set(props.addData, 'regionId', res.data[0].regionId)
}
getZoneList()
}
}
getRegionList()
async function getZoneList(rgId) {
// rgId
if (props.addData.zone && rgId) props.addData.zone = ''
const { vendorId, regionId } = props.addData
const res = await getZone({ vendorId, regionId })
if (res.success) {
zoneList.value = res.data
if (!props.addData.zone) {
$set(props.addData, 'zone', res.data[0].zoneId)
}
}
}
return {
regionList,
zoneList,
getZoneList
}
}
}
</script>
<style scoped>
.el-radio-button {
margin-bottom: 8px;
}
::v-deep .el-radio-button__inner {
border-left: solid 1px #dcdfe6;
}
.el-icon-question {
color: #bbbbbd;
margin-left: 10px;
}
</style>

View File

@ -0,0 +1,225 @@
<template>
<cb-card-layout title="授权数据库">
<el-row :gutter="10" class="m-b">
<el-col :span="8">
<el-card style="height: 408px">
<div slot="header">
<span>未授权数据库</span>
</div>
<el-form :inline="true">
<el-form-item>
<el-input placeholder="名称" v-model="listQuery.name"> </el-input>
</el-form-item>
<el-form-item>
<el-button type="ghost" icon="el-icon-search" @click="handleSearch"></el-button>
</el-form-item>
</el-form>
<cb-table ref="userTable" :small="true" :data="list" :params="params" :get-list="getList" :total="total" @selection-change="selectionChange">
<el-table-column type="selection" :selectable="selectAble" width="60"> </el-table-column>
<el-table-column show-overflow-tooltip label="名称" prop="name"> </el-table-column>
<el-pagination class="pull-right m-t-sm" slot="pagination" background :page-size="params.rows" :pager-count="5" layout="prev, pager, next" @current-change="getList" :current-page.sync="params.page" :total="total"> </el-pagination>
</cb-table>
</el-card>
</el-col>
<el-col :span="2">
<div>
<div style="height: 204px; line-height: 330px">
<el-button type="primary" size="mini" :disabled="leftSlection.length === 0" @click="addUser"><i class="el-icon-right"></i></el-button>
</div>
<div style="height: 204px">
<el-button type="primary" size="mini" @click="removeUser" :disabled="rightSlection.length === 0"><i class="el-icon-back"></i></el-button>
</div>
</div>
</el-col>
<el-col :span="14">
<el-card style="height: 408px">
<div slot="header">
<span class="">已授权数据库</span>
<span class="pull-right">
全部设 <el-button class="m-r" type="text" @click="setAuth">{{ buttonName }}</el-button>
</span>
</div>
<cb-smart-table :data="selectUserList" :rows="5" @selection-change="selectionChangeCheck">
<el-table-column type="selection" width="60"> </el-table-column>
<el-table-column show-overflow-tooltip label="名称" prop="name"> </el-table-column>
<el-table-column show-overflow-tooltip label="权限" prop="name" width="400px">
<template slot-scope="scope">
<el-radio-group v-model="scope.row.accountPrivilege">
<el-radio label="ReadWrite">读写(DDL+DML)</el-radio>
<el-radio label="ReadOnly">只读</el-radio>
<el-radio label="DDLOnly">仅DDL</el-radio>
<el-radio label="DMLOnly">仅DML</el-radio>
</el-radio-group>
</template>
</el-table-column>
</cb-smart-table>
</el-card>
</el-col>
</el-row>
</cb-card-layout>
</template>
<script>
import { handleSearchParam } from '@cmp/cmp-element'
import { getRdsDbs } from 'views/resource/ctstack/services/database/rds.js'
export default {
props: {
dbIds: {
type: Array,
default: function () {
return []
}
},
rdsId: {
type: Number
},
flag: {
type: Number
}
},
data() {
return {
list: [],
total: 0,
listQuery: {
name: ''
},
params: {
page: 1,
rows: 5
},
leftSlection: [],
rightSlection: [],
selectUserList: [],
buttonName: '读写(DDL+DML)'
}
},
computed: {
userIds() {
const ids = []
for (const a of this.selectUserList) {
ids.push(a.name)
}
return ids
},
privileges() {
const arr = []
for (const a of this.selectUserList) {
const obj = {
name: a.name,
accountPrivilege: a.accountPrivilege
}
arr.push(obj)
}
return arr
}
},
created() {
this.getSelectUser()
},
watch: {
flag: {
handler(newVal, oldVal) {
this.getSelectUser()
}
}
},
methods: {
setAuth() {
if (this.buttonName == '读写(DDL+DML)') {
this.selectUserList.forEach(item => {
this.$set(item, 'accountPrivilege', 'ReadWrite')
})
this.buttonName = '只读'
} else if (this.buttonName == '只读') {
this.selectUserList.forEach(item => {
this.$set(item, 'accountPrivilege', 'ReadOnly')
})
this.buttonName = '仅DDL'
} else if (this.buttonName == '仅DDL') {
this.selectUserList.forEach(item => {
this.$set(item, 'accountPrivilege', 'DDLOnly')
})
this.buttonName = '仅DML'
} else if (this.buttonName == '仅DML') {
this.selectUserList.forEach(item => {
this.$set(item, 'accountPrivilege', 'DMLOnly')
})
this.buttonName = '读写(DDL+DML)'
}
},
getSelectUser() {
getRdsDbs(this.rdsId, {
page: 1,
rows: 999999,
params: handleSearchParam({
rdsId: this.rdsId
})
}).then(data => {
if (data.success) {
const list = data.data.rows
list.forEach(item => {
if (this.dbIds.indexOf(item.name) > -1) {
this.selectUserList.push(item)
}
})
}
})
this.handleSearch()
},
getList() {
getRdsDbs(this.rdsId, this.params).then(data => {
if (data.success) {
this.list = data.data.rows
this.total = data.data.total
//
this.$nextTick(() => {
this.list.forEach(item => {
if (this.userIds.indexOf(item.name) > -1) this.$refs.userTable.toggleRowSelection(item, true)
})
})
}
})
},
//
handleSearch() {
this.params.page = 1
this.params.params = handleSearchParam({
rdsId: this.rdsId,
'name:LK': this.listQuery.name
})
this.getList()
},
selectionChange(selection) {
this.leftSlection = selection
},
selectionChangeCheck(selection) {
this.rightSlection = selection
},
selectAble(row) {
return !this.userIds.includes(row.name)
},
addUser() {
const users = this.leftSlection.filter(item => {
this.$set(item, 'accountPrivilege', 'ReadWrite')
return !this.userIds.includes(item.name)
})
this.selectUserList.unshift(...users)
},
removeUser() {
const ids = []
this.rightSlection.forEach(item => {
ids.push(item.name)
})
for (let i = 0; i < this.selectUserList.length; i++) {
const item = this.selectUserList[i]
if (ids.includes(item.name)) {
this.selectUserList.splice(i, 1)
i--
}
}
}
}
}
</script>
<style></style>

View File

@ -0,0 +1,865 @@
<template>
<div class="wrapper">
<cb-advance-table title="" :search-configs="searchConfigs" :data="tableData" :params="params" :columns="columns" :get-list="getData" :total="total" :loading="loading">
<template v-slot:action>
<el-button type="primary" @click="handleCreate()"></el-button>
</template>
<template #status="status">
<cb-status-icon :type="statusFilter[status]">
{{ filter[status] }}
</cb-status-icon>
</template>
<template #type="type">
{{ filter[type] }}
</template>
<template #payType="payType">
{{ filter[payType] }}
</template>
<template #name="val, record">
<span class="detail-href" @click="getDetail(record.id)">{{ (record.instanceId || '--') + ' / ' + val }}</span>
</template>
<template #operate="val, record">
<el-button type="text" @click="patch(record)" :disabled="record.status !== 'Running'"> 重启 </el-button>
<div class="action-divider"></div>
<el-button type="text" @click="removeRds(record)" :disabled="record.status !== 'Running'"> 释放实例 </el-button>
</template>
</cb-advance-table>
<add :add-data="addData" v-if="addData.dialog" @back="getData"></add>
<cb-detail v-if="detailFlag" :title="detailData.instanceId + ' / ' + detailData.name" @goBack="goBack">
<template v-slot:item_container>
<cb-detail-item label="名称">{{ detailData.name }}</cb-detail-item>
<cb-detail-item label="状态">{{ filter[detailData.status] }}</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="数据库类型">{{ detailData.dataStoreType }}</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.region }}</cb-detail-item>
</template>
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="账号列表" name="account">
<el-button class="m-b" type="primary" @click="createAccount()"></el-button>
<cb-table :data="usersList" :params="paramsUsers" :total="totalUsers" :get-list="getUsersList">
<el-table-column prop="username" label="账号" show-overflow-tooltip></el-table-column>
<el-table-column prop="permission" label="类型" show-overflow-tooltip>
<template slot-scope="scope">
{{ scope.row.permission | typeFilter }}
</template>
</el-table-column>
<el-table-column prop="status" label="状态" show-overflow-tooltip>
<template slot-scope="scope">
<cb-status-icon :type="scope.row.status | statusFilter('color')">{{ scope.row.status | statusFilter('status') }} </cb-status-icon>
</template>
</el-table-column>
<el-table-column prop="db" label="所属数据库" show-overflow-tooltip>
<template slot-scope="scope">
<div v-for="item in JSON.parse(scope.row.privileges)" :key="item.name">{{ item.name }} {{ item.accountPrivilege | authFilter }}</div>
</template>
</el-table-column>
<el-table-column prop="remark" label="账号描述" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" show-overflow-tooltip width="250px">
<template slot-scope="scope">
<el-button type="text" @click="resetPasd(scope.row)"></el-button>
<div class="action-divider"></div>
<!-- <el-button type="text" v-if="scope.row.permission == 'Super'" @click="resetAuth(scope.row)"></el-button> -->
<el-button type="text" v-if="scope.row.permission == 'Normal'" @click="modifyAuth(scope.row)"></el-button>
<div class="action-divider" v-if="scope.row.permission == 'Normal'"></div>
<!-- <div class="action-divider" v-if="scope.row.permission == 'Super'"></div> -->
<el-button type="text" @click="deleteAccount(scope.row)"></el-button>
</template>
</el-table-column>
<!-- <div slot="pagination"></div> -->
</cb-table>
<el-dialog title="重置账号" append-to-body v-if="resetFlag" :visible.sync="resetFlag" :close-on-click-modal="false">
<cb-form ref="resetData" :model="resetData" label-width="120px">
<cb-form-item label="数据库账号:" prop="username">
{{ resetData.username }}
</cb-form-item>
<cb-form-item label="密码:" prop="password" :rules="[required, rdsDBPassword]">
<el-input type="password" v-model="resetData.password"></el-input>
</cb-form-item>
</cb-form>
<span slot="footer" class="dialog-footer">
<el-button type="ghost" @click.native="resetFlag = false"> </el-button>
<el-button type="primary" @click.native="submitReset"> </el-button>
</span>
</el-dialog>
<el-dialog title="重置账号密码" append-to-body v-if="resetPasdFlag" :visible.sync="resetPasdFlag" :close-on-click-modal="false">
<cb-form ref="resetData" :model="resetData" label-width="120px">
<cb-form-item label="密码:" prop="password" :rules="[required, rdsDBPassword]">
<el-input type="password" v-model="resetData.password" show-password></el-input>
</cb-form-item>
<cb-form-item label="确认密码:" prop="password2" :rules="[required, rdsDBPassword]">
<el-input type="password" v-model="resetData.password2" show-password></el-input>
</cb-form-item>
</cb-form>
<span slot="footer" class="dialog-footer">
<el-button type="ghost" @click.native="resetPasdFlag = false"> </el-button>
<el-button type="primary" @click.native="submitResetPasd"> </el-button>
</span>
</el-dialog>
<el-drawer append-to-body title="创建用户账号" :visible.sync="drawer" direction="rtl" size="40%">
<el-card>
<cb-form ref="accountData" :model="accountData" label-width="120px">
<cb-form-item label="数据库账号:" prop="username" maxlength="16" :rules="[required, rdsAccountName, { validator: validateKeyword, trigger: 'blur' }]">
<el-tooltip class="item" effect="dark" content="由小写字母、数字、下划线_组成以字母开头以字母或数字结尾最多16个字符" placement="top">
<el-input v-model="accountData.username" auto-complete="off"></el-input>
</el-tooltip>
</cb-form-item>
<cb-form-item class="m-t-lg" label="账号类型:" prop="permission" :rules="[required]">
<el-radio-group v-model="accountData.permission">
<el-radio label="Super" :disabled="Super">高权限账号</el-radio>
<el-radio label="Normal">普通账号</el-radio>
</el-radio-group>
</cb-form-item>
<cb-form-item class="m-t-lg" label="密码:" prop="password" :rules="[required, rdsDBPassword]">
<el-input type="password" v-model="accountData.password" auto-complete="off"></el-input>
</cb-form-item>
<cb-form-item class="m-t-lg" label="确认密码:" prop="password2" :rules="[required]">
<el-input type="password" v-model="accountData.password2" auto-complete="off"></el-input>
</cb-form-item>
<cb-form-item class="m-t-lg" label="备注:" prop="remark" maxlength="256">
<el-input type="textarea" v-model="accountData.remark"></el-input>
<div class="text_mine">请输入备注说明,最多256个字符</div>
</cb-form-item>
<el-button type="primary" @click="submitAccount()"></el-button>
<el-button type="ghost" @click="drawer = false">取消</el-button>
</cb-form>
</el-card>
</el-drawer>
<!-- 修改权限 -->
<ModifyRole :dialog="editDialog" v-if="editDialog.visible" @getData="getUsersList"></ModifyRole>
<!-- <el-drawer append-to-body :with-header="false" :visible.sync="drawerAuth" direction="rtl" size="1200px">
<el-card>
<cb-form :model="accountData" label-width="120px">
<cb-form-item label="数据库账号:" prop="username" maxlength="16">
{{accountData.username}}
</cb-form-item>
<modify-db class="m-b" ref="modifyDb" :rdsId="detailData.id" :dbIds="accountData.dbIds" :flag="flag"></modify-db>
<el-button type="primary" @click="submitAuth()"></el-button>
<el-button type="ghost" @click="drawerAuth = false">取消</el-button>
</cb-form>
</el-card>
</el-drawer> -->
</el-tab-pane>
<el-tab-pane label="数据库列表" name="database">
<el-button class="m-b" type="primary" @click="createDB"></el-button>
<cb-table :data="databaseList" :params="paramsDb" :total="totalDb" :get-list="getDbList">
<el-table-column prop="name" label="名称" show-overflow-tooltip></el-table-column>
<el-table-column prop="status" label="状态" show-overflow-tooltip>
<!-- <template slot-scope="scope">
<cb-status-icon :type="scope.row.status | vmStatusColor">{{ scope.row.status | database }} </cb-status-icon>
</template> -->
</el-table-column>
<el-table-column prop="characterSet" label="字符集" show-overflow-tooltip></el-table-column>
<el-table-column prop="accounts" label="绑定账号" show-overflow-tooltip>
<template slot-scope="scope">
<div v-for="(item, index) in JSON.parse(scope.row.accounts)" :key="index">
{{ item.account }}
</div>
</template>
</el-table-column>
<el-table-column prop="remark" label="备注说明" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" show-overflow-tooltip>
<template slot-scope="scope">
<el-button type="text" @click="deleteDB(scope.row)"></el-button>
</template>
</el-table-column>
</cb-table>
<el-drawer append-to-body title="创建数据库" :visible.sync="drawerDB" direction="rtl" size="40%">
<el-card>
<cb-form ref="databaseData" :model="databaseData" label-width="140px">
<cb-form-item
label="数据库(DB)名称:"
prop="name"
:rules="[
{
pattern: /^[a-z]([a-z0-9_-]{1,62})?([a-z0-9])$/,
message: '由小写字母、数字、下划线、中划线组成以字母开头字母或数字结尾最多64个字符',
trigger: null
},
{
validator: validateKeyword,
trigger: 'blur'
}
]"
validate="required"
>
<el-input v-model="databaseData.name" placeholder="请输入数据库名称" clearable></el-input>
</cb-form-item>
<cb-form-item class="m-t-lg" label="支持字符集:" prop="characterSet">
<el-select v-model="databaseData.characterSet" placeholder="请选择">
<el-option v-for="item in codeData" :key="item" :label="item" :value="item"> </el-option>
</el-select>
</cb-form-item>
<!-- <cb-form-item class="m-t-lg" label="授权账号:" prop="accountId">
<el-select v-model="databaseData.accountId" placeholder="请选择">
<el-option v-for="item in accounts" :key="item.id" :label="item.username" :value="item.id">
</el-option>
</el-select>
</cb-form-item> -->
<cb-form-item class="m-t-lg" label="账号类型:" prop="accountPrivilege" :rules="[required]" v-if="databaseData.accountId" key="accountPrivilege">
<el-radio-group v-model="databaseData.accountPrivilege">
<el-radio label="ReadWrite">读写 </el-radio>
<el-radio label="ReadOnly">只读 </el-radio>
<el-radio label="DDLOnly">仅DDL </el-radio>
<el-radio label="DMLOnly">仅DML </el-radio>
</el-radio-group>
</cb-form-item>
<cb-form-item class="m-t-lg" label="备注说明:" prop="remark" maxlength="256">
<el-input type="textarea" v-model="databaseData.remark"></el-input>
<div class="text_mine">请输入备注说明,最多256个字符</div>
</cb-form-item>
<el-button type="primary" @click="submitDB()"></el-button>
<el-button type="ghost" @click="drawerDB = false">取消</el-button>
</cb-form>
</el-card>
</el-drawer>
</el-tab-pane>
<el-tab-pane label="连接地址管理" name="connection">
<cb-table :data="connectionList" :params="paramsCo" :total="totalDo" :get-list="getCoList">
<el-table-column label="网络类型" show-overflow-tooltip>
<template slot-scope="scope">
{{ instanceNetworkTypeMap[scope.row.instanceNetworkType] + '(' + ipTypeMap[scope.row.ipType] + ')' }}
</template>
</el-table-column>
<el-table-column prop="connectionString" label="连接地址" show-overflow-tooltip></el-table-column>
<el-table-column prop="port" label="端口" show-overflow-tooltip></el-table-column>
</cb-table>
</el-tab-pane>
<!-- <el-tab-pane label="参数设置" name="params">
<el-tabs value="modify">
<el-tab-pane label="可修改参数" name="modify">
<cb-table :data="detailData.nodes">
<el-table-column prop="name" label="参数名" show-overflow-tooltip></el-table-column>
<el-table-column prop="type" label="参数默认值" show-overflow-tooltip></el-table-column>
<el-table-column prop="db" label="运行参数值" show-overflow-tooltip>
<template slot-scope="scope">
{{scope.row.params}} <el-button type="text" class="el-icon-edit"></el-button>
</template>
</el-table-column>
<el-table-column prop="remark" label="是否重启" show-overflow-tooltip></el-table-column>
<el-table-column prop="remark" label="参数值范围" show-overflow-tooltip></el-table-column>
<el-table-column prop="remark" label="参数描述" show-overflow-tooltip></el-table-column>
<div slot="pagination"></div>
</cb-table>
</el-tab-pane>
<el-tab-pane label="参数修改历史" name="history">
<cb-table :data="detailData.nodes">
<el-table-column prop="name" label="参数名" show-overflow-tooltip></el-table-column>
<el-table-column prop="type" label="变更前参数值" show-overflow-tooltip></el-table-column>
<el-table-column prop="db" label="变更后参数值" show-overflow-tooltip></el-table-column>
<el-table-column prop="remark" label="是否生效" show-overflow-tooltip></el-table-column>
<el-table-column prop="remark" label="变更时间" show-overflow-tooltip></el-table-column>
</cb-table>
</el-tab-pane>
</el-tabs>
</el-tab-pane> -->
</el-tabs>
</cb-detail>
</div>
</template>
<script>
import validate from '@/validate'
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 '../components/add.vue'
import ModifyRole from './ModifyRole.vue'
import { keywords } from './validate'
import { handleSearchParam } from '@cmp/cmp-element'
const columns = [
{
label: '实例ID/名称',
prop: 'name',
scopedSlots: { customRender: 'name' }
},
{
label: '状态',
prop: 'status',
scopedSlots: { customRender: 'status' }
},
{
label: '版本',
prop: 'dataStoreVersion'
},
{
label: '规格',
prop: 'cpu',
customRender(cpu, { memory }) {
return cpu && memory ? `${cpu}C/${memory}GB` : '--'
}
},
{
label: '存储空间GB',
prop: 'volSize'
},
{
label: '创建时间',
prop: 'createDate'
},
{
label: '操作',
disabled: true,
width: '220px',
scopedSlots: { customRender: 'operate' }
}
]
const validateKeyword = (rule, value, callback) => {
const valid = keywords.find(item => item.toLocaleLowerCase() === value)
if (!valid) {
callback()
} else {
callback(new Error(`${valid.toLocaleLowerCase()}为关键字,不能输入`))
}
}
const instanceNetworkTypeMap = {
VPC: '专有网络',
Classic: '经典网络'
}
const ipTypeMap = {
Inner: '内网',
Public: '外网',
Private: '内网'
}
export default {
props: {
platformObject: {
type: Object
}
},
components: { add, ModifyRole },
filters: {
typeFilter(value) {
const obj = {
Normal: '普通账号',
Super: '高权限账号'
}
return obj[value]
},
statusFilter(value, type) {
const obj = {
Unavailable: {
status: '未激活',
color: 'info'
},
Available: {
status: ' 已激活',
color: 'success'
}
}
return obj[value] && obj[value][type]
},
authFilter(value) {
const obj = {
ReadWrite: '读写(DDL+DML)',
ReadOnly: '只读',
DDLOnly: '仅DDL',
DMLOnly: 'DMLOnly'
}
return obj[value]
}
},
data() {
return {
validateKeyword,
ipTypeMap,
instanceNetworkTypeMap,
required: validate.required,
rdsAccountName: { pattern: /^[a-z]([a-z0-9_-]{0,14}[a-z0-9])?$/, message: '由小写字母、数字、下划线_组成以字母开头以字母或数字结尾最多16个字符', trigger: null },
rdsDBName: { pattern: /^[a-z]([a-z0-9_-]{0,62}[a-z0-9])?$/, message: '由小写字母、数字、下划线_、中划线-组成以字母开头字母或数字结尾最多64个字符', 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: [
{ type: 'Input', label: '名称', value: 'name' },
{ type: 'Const', value: 'vendorId', initValue: this.platformObject.vendorId },
{ type: 'Const', value: 'dbType', initValue: 'POSTGRESQL' }
],
columns,
loading: false,
params: {
page: 1,
rows: 10
},
searchData: {
name: '',
regionId: '',
zone: ''
},
zoneList: [],
tableData: [],
total: 0,
detailFlag: false,
detailData: {},
filter: {
Primary: '主实例',
Readonly: '只读实例',
Guard: '灾备实例',
Temp: '临时实例',
VPC: 'VPC',
Classic: '经典网络',
Postpaid: '按量付费',
Prepaid: '包年包月',
Creating: '创建中',
Running: '使用中',
Deleting: '删除中',
Rebooting: '重启中',
RebootFailed: '重启失败',
DBInstanceClassChanging: '升降级中'
},
statusFilter: {
Creating: 'warning',
Running: 'success',
Deleting: 'warning',
Rebooting: 'warning',
RebootFailed: 'danger',
DBInstanceClassChanging: 'warning'
},
addData: {
dialog: false,
data: {}
},
activeName: 'account',
//
paramsUsers: {
page: 1,
rows: 10
},
totalUsers: 0,
usersList: [],
drawer: false,
accountData: {},
drawerAuth: false,
//
resetFlag: false,
resetPasdFlag: false,
resetData: {},
//
drawerDB: false,
databaseData: {},
codeData: [
'utf8mb4',
'utf8',
'gbk',
'gb18030',
'latin1',
'euckr',
'armscii8',
'ascii',
'big5',
'binary',
'cp1250',
'cp1251',
'cp1256',
'cp1257',
'cp850',
'cp852',
'cp866',
'cp932',
'dec8',
'eucjpms',
'gb2312',
'geostd8',
'greek',
'hebrew',
'hp8',
'keybcs2',
'koi8r',
'koi8u',
'latin2',
'latin5',
'latin7',
'macce',
'macroman',
'sjis',
'swe7',
'tis620',
'ucs2',
'ujis',
'utf16',
'utf16le',
'utf32'
],
accounts: [],
databases: [],
databaseList: [],
paramsDb: {
page: 1,
rows: 10
},
totalDb: 0,
flag: 0,
Super: false,
connectionList: [],
paramsCo: {
page: 1,
rows: 10
},
totalDo: 0,
editDialog: {
visible: false,
record: {}
}
}
},
methods: {
async getCoList(id) {
this.paramsCo.params = handleSearchParam({
vendorId: this.detailData.vendorId,
rdsId: this.detailData.id
})
const res = await getRdsCos(id, this.paramsCo)
if (res.success) {
this.totalDo = res.data.total
this.connectionList = res.data.rows
}
},
patch(data) {
this.$confirm('确定重启该实例吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
patchRds(data.id).then(data => {
if (data.success) {
this.$message({
type: 'success',
message: data.message
})
this.getData()
}
})
})
},
removeRds(data) {
this.$confirm('确定释放该实例吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
removeRds(data.id).then(data => {
if (data.success) {
this.$message({
type: 'success',
message: data.message
})
this.getData()
}
})
})
},
getData() {
this.loading = true
getRds(this.params).then(data => {
this.loading = false
if (data.success) {
this.tableData = data.data.rows
this.total = data.data.total
}
})
},
handleCreate() {
this.addData = {
dialog: true,
vendorId: this.platformObject.vendorId,
type: 'POSTGRESQL'
}
},
getDetail(id) {
this.Super = false
detailRds(id).then(data => {
if (data.success) {
this.detailData = data.data
this.detailFlag = true
this.getUsersList()
}
})
},
handleClick() {
switch (this.activeName) {
case 'account':
this.getUsersList()
break
case 'database':
this.getDbList()
break
case 'connection':
this.getCoList(this.detailData.id)
break
}
},
getUsersList() {
this.paramsUsers.params = handleSearchParam({
vendorId: this.detailData.vendorId,
rdsId: this.detailData.id
})
getRdsUsers(this.detailData.id, this.paramsUsers).then(data => {
if (data.success) {
this.usersList = data.data.rows
this.totalUsers = data.data.total
}
})
getRdsUsers(this.detailData.id, {
simple: true,
params: handleSearchParam({
vendorId: this.detailData.vendorId,
rdsId: this.detailData.id
})
}).then(data => {
if (data.success) {
const list = data.data.rows
list.forEach(item => {
if (item.permission == 'Super') {
this.Super = true
}
})
}
})
},
getDbList() {
this.paramsDb.params = handleSearchParam({
vendorId: this.detailData.vendorId,
rdsId: this.detailData.id
})
getRdsDbs(this.detailData.id, this.paramsDb).then(data => {
if (data.success) {
this.databaseList = data.data.rows
this.totalDb = data.data.total
}
})
},
goBack() {
this.detailFlag = false
},
//
createAccount() {
this.drawer = true
this.accountData = {
rdsId: this.detailData.id,
vendorId: this.detailData.vendorId
}
},
submitAccount() {
this.$refs.accountData.validate(valid => {
if (valid) {
if (this.accountData.password !== this.accountData.password2) {
return this.$message.error('两次密码输入不一致')
}
const { vendorId, username, password, rdsId, permission, remark } = this.accountData
createRdsUsers(this.accountData.rdsId, {
rdsId: rdsId,
vendorId: vendorId,
username: username,
permission: permission,
password: crypto.encrypt(password),
remark: remark
}).then(data => {
if (data.success) {
this.$message.success(data.message)
this.drawer = false
this.getUsersList()
}
})
}
})
},
//
deleteAccount(data) {
this.$confirm(`您确定要删除【${data.username}】吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
removeRdsUsers({
rdsId: this.detailData.id,
userId: data.id
}).then(data => {
if (data.success) {
this.$message({
type: 'success',
message: data.message
})
this.getUsersList()
}
})
})
},
//
modifyAuth(data) {
// this.getDbList()
this.flag++
const privilege = data.privilege ? JSON.parse(data.privilege) : []
const arr = []
privilege.forEach(element => {
arr.push(element.name)
})
// this.accountData = {
// rdsId: this.detailData.id,
// userId: data.id,
// username: data.username,
// dbIds: arr
// }
this.editDialog = {
record: { ...data },
visible: true
}
},
submitAuth() {
const { rdsId, username, userId } = this.accountData
authRdsUser({
rdsId: rdsId,
userId: userId,
id: userId,
username: username,
privileges: this.$refs.modifyDb.privileges
}).then(data => {
if (data.success) {
this.$message.success(data.message)
this.getUsersList()
this.drawerAuth = false
}
})
},
//
resetAuth(data) {
this.resetData = {
rdsId: this.detailData.id,
userId: data.id,
password: '',
username: data.username
}
this.resetFlag = true
},
submitReset() {
this.$refs.resetData.validate(valid => {
if (valid) {
const { rdsId, userId, password } = this.resetData
resetRdsUser({
rdsId: rdsId,
userId: userId,
password: crypto.encrypt(password)
}).then(data => {
if (data.success) {
this.$message({
type: 'success',
message: data.message
})
this.resetFlag = false
this.getUsersList()
}
})
}
})
},
resetPasd(data) {
//
this.resetData = {
rdsId: this.detailData.id,
userId: data.id,
username: data.username
}
this.resetPasdFlag = true
},
submitResetPasd() {
this.$refs.resetData.validate(valid => {
if (valid) {
if (this.resetData.password !== this.resetData.password2) {
return this.$message.error('两次密码输入不一致')
}
const { rdsId, userId, password } = this.resetData
resetRdsUserPasd({
rdsId: rdsId,
userId: userId,
password: crypto.encrypt(password)
}).then(data => {
if (data.success) {
this.$message({
type: 'success',
message: data.message
})
this.resetPasdFlag = false
this.getUsersList()
}
})
}
})
},
createDB() {
this.drawerDB = true
getRdsUsers(this.detailData.id, {
page: 1,
rows: 99999,
params: handleSearchParam({
vendorId: this.detailData.vendorId,
rdsId: this.detailData.id,
permission: 'Normal'
})
}).then(data => {
if (data.success) {
this.accounts = data.data.rows
}
})
this.databaseData = {
name: '',
accountPrivilege: 'ReadWrite',
characterSet: 'utf8'
}
},
submitDB() {
this.$refs.databaseData.validate(valid => {
if (valid) {
createRdsDbs(this.detailData.id, this.databaseData).then(data => {
if (data.success) {
this.$message.success(data.message)
this.drawerDB = false
this.getDbList()
}
})
}
})
},
deleteDB(data) {
this.$confirm(`您确定要删除【${data.name}】吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
removeRdsDbs({
rdsId: this.detailData.id,
dbId: data.id
}).then(data => {
if (data.success) {
this.$message({
type: 'success',
message: data.message
})
this.getDbList()
}
})
})
}
},
watch: {
platformObject: {
handler(newVal, oldVal) {
this.searchConfigs = [
{ type: 'Input', label: '名称', value: 'name' },
{ type: 'Const', value: 'vendorId', initValue: newVal.vendorId }
]
if (this.detailFlag) {
this.handleClick()
}
},
deep: true
}
}
}
</script>
<style scoped>
.tooltip {
font-size: 12px;
color: #666;
}
</style>

View File

@ -0,0 +1,439 @@
export const keywords = [
// RDS MySQL
'ACTION',
'ADD',
'ADMIN',
'ALL',
'ALTER',
'ANALYZE',
'AND',
'AS',
'ASC',
'ASENSITIVE',
'BEFORE',
'BETWEEN',
'BIGINT',
'BINARY',
'BLOB',
'BOTH',
'BY',
'CALL',
'CASCADE',
'CASE',
'CHANGE',
'CHAR',
'CHARACTER',
'CHECK',
'COLLATE',
'COLUMN',
'CONDITION',
'CONNECTION',
'CONSTRAINT',
'CONTINUE',
'CONVERT',
'CREATE',
'CROSS',
'CURRENT_DATE',
'CURRENT_TIME',
'CURRENT_TIMESTAMP',
'CURRENT_USER',
'CURSOR',
'DATABASE',
'DATABASES',
'DAY_HOUR',
'DAY_MICROSECOND',
'DAY_MINUTE',
'DAY_SECOND',
'DEC',
'DECIMAL',
'DECLARE',
'DEFAULT',
'DELAYED',
'DELETE',
'DESC',
'DESCRIBE',
'DETERMINISTIC',
'DISTINCT',
'DISTINCTROW',
'DIV',
'DOUBLE',
'DROP',
'DUAL',
'EACH',
'EAGLEYE',
'ELSE',
'ELSEIF',
'ENCLOSED',
'ESCAPED',
'EXISTS',
'EXIT',
'EXPLAIN',
'FALSE',
'FETCH',
'FLOAT',
'FLOAT4',
'FLOAT8',
'FOR',
'FORCE',
'FOREIGN',
'FROM',
'FULLTEXT',
'GOTO',
'GRANT',
'GROUP',
'GUEST',
'HAVING',
'HIGH_PRIORITY',
'HOUR_MICROSECOND',
'HOUR_MINUTE',
'HOUR_SECOND',
'IF',
'IGNORE',
'IN',
'INDEX',
'INFILE',
'INFORMATION_SCHEMA',
'INNER',
'INOUT',
'INSENSITIVE',
'INSERT',
'INT',
'INT1',
'INT2',
'INT3',
'INT4',
'INT8',
'INTEGER',
'INTERVAL',
'INTO',
'IS',
'ITERATE',
'JOIN',
'KEY',
'KEYS',
'KILL',
'LABEL',
'LEADING',
'LEAVE',
'LEFT',
'LIKE',
'LIMIT',
'LINEAR',
'LINES',
'LOAD',
'LOCALTIME',
'LOCALTIMESTAMP',
'LOCK',
'LONG',
'LONGBLOB',
'LONGTEXT',
'LOOP',
'LOW_PRIORITY',
'MATCH',
'MEDIUMBLOB',
'MEDIUMINT',
'MEDIUMTEXT',
'MIDDLEINT',
'MINUTE_MICROSECOND',
'MINUTE_SECOND',
'MOD',
'MODIFIES',
'MYSQL',
'NATURAL',
'NO_WRITE_TO_BINLOG',
'NOT',
'NULL',
'NUMERIC',
'ON',
'OPTIMIZE',
'OPTION',
'OPTIONALLY',
'OR',
'ORDER',
'OUT',
'OUTER',
'OUTFILE',
'PERFORMANCE_SCHEMA',
'PRECISION',
'PRIMARY',
'PROCEDURE',
'PURGE',
'RAID0',
'RANGE',
'READ',
'READS',
'REAL',
'REFERENCES',
'REGEXP',
'RELEASE',
'RENAME',
'REPEAT',
'REPLACE',
'REPLICATOR',
'REQUIRE',
'RESTRICT',
'RETURN',
'REVOKE',
'RIGHT',
'RLIKE',
'ROOT',
'SCHEMA',
'SCHEMAS',
'SECOND_MICROSECOND',
'SELECT',
'SENSITIVE',
'SEPARATOR',
'SET',
'SHOW',
'SMALLINT',
'SPATIAL',
'SPECIFIC',
'SQL',
'SQL_BIG_RESULT',
'SQL_CALC_FOUND_ROWS',
'SQL_SMALL_RESULT',
'SQLEXCEPTION',
'SQLSTATE',
'SQLWARNING',
'SSL',
'STARTING',
'STRAIGHT_JOIN',
'TABLE',
'TERMINATED',
'TEST',
'THEN',
'TINYBLOB',
'TINYINT',
'TINYTEXT',
'TO',
'TRAILING',
'TRIGGER',
'TRUE',
'UNDO',
'UNION',
'UNIQUE',
'UNLOCK',
'UNSIGNED',
'UPDATE',
'USAGE',
'USE',
'USING',
'UTC_DATE',
'UTC_TIME',
'UTC_TIMESTAMP',
'VALUES',
'VARBINARY',
'VARCHAR',
'VARCHARACTER',
'VARYING',
'WHEN',
'WHERE',
'WHILE',
'WITH',
'WRITE',
'X509',
'XOR',
'XTRABAK',
'YEAR_MONTH',
'ZEROFILL',
// RDS SQL Server
'ADD',
'ADMIN',
'ADMINISTRATOR',
'ALL',
'ALTER',
'AND',
'ANY',
'AS',
'ASC',
'AURORA',
'AUTHORIZATION',
'BACKUP',
'BEGIN',
'BETWEEN',
'BREAK',
'BROWSE',
'BULK',
'BULKADMIN',
'BY',
'CASCADE',
'CASE',
'CHECK',
'CHECKPOINT',
'CLOSE',
'CLUSTERED',
'COALESCE',
'COLLATE',
'COLUMN',
'COMMIT',
'COMPUTE',
'CONSTRAINT',
'CONTAINS',
'CONTAINSTABLE',
'CONTINUE',
'CONVERT',
'CREATE',
'CROSS',
'CURRENT',
'CURRENT_DATE',
'CURRENT_TIME',
'CURRENT_TIMESTAMP',
'CURRENT_USER',
'CURSOR',
'DATABASE',
'DBCC',
'DBCREATOR',
'DEALLOCATE',
'DECLARE',
'DEFAULT',
'DELETE',
'DENY',
'DESC',
'DISK',
'DISKADMIN',
'DISTINCT',
'DISTRIBUTED',
'DISTRIBUTION',
'DOUBLE',
'DROP',
'DUMMY',
'DUMP',
'EAGLEYE',
'ELSE',
'END',
'ERRLVL',
'ESCAPE',
'EXCEPT',
'EXEC',
'EXECUTE',
'EXISTS',
'EXIT',
'FETCH',
'FILE',
'FILLFACTOR',
'FOR',
'FOREIGN',
'FREETEXT',
'FREETEXTTABLE',
'FROM',
'FULL',
'FUNCTION',
'GALAXY',
'GOTO',
'GRANT',
'GROUP',
'GUEST',
'HAVING',
'HOLDLOCK',
'IDENTITY',
'IDENTITY_INSERT',
'IDENTITYCOL',
'IF',
'IN',
'INDEX',
'INNER',
'INSERT',
'INTERSECT',
'INTO',
'IS',
'JOIN',
'KEY',
'KILL',
'LEFT',
'LIKE',
'LINENO',
'LOAD',
'MASTER',
'MODEL',
'MSDB',
'MSSQLD',
'MSSQLSYSTEMRESOURCE',
'NATIONAL',
'NOCHECK',
'NONCLUSTERED',
'NOT',
'NULL',
'NULLIF',
'OF',
'OFF',
'OFFSETS',
'ON',
'OPEN',
'OPENDATASOURCE',
'OPENQUERY',
'OPENROWSET',
'OPENXML',
'OPTION',
'OR',
'ORDER',
'OUTER',
'OVER',
'PERCENT',
'PLAN',
'PRECISION',
'PRIMARY',
'PRINT',
'PROC',
'PROCEDURE',
'PROCESSADMIN',
'PUBLIC',
'PUBLIC',
'RAISERROR',
'READ',
'READTEXT',
'RECONFIGURE',
'REFERENCES',
'REPLICATION',
'RESTORE',
'RESTRICT',
'RETURN',
'REVOKE',
'RIGHT',
'ROLLBACK',
'ROOT',
'ROWCOUNT',
'ROWGUIDCOL',
'RULE',
'SA',
'SAVE',
'SCHEMA',
'SECURITYADMIN',
'SELECT',
'SERVERADMIN',
'SESSION_USER',
'SET',
'SETUPADMIN',
'SETUSER',
'SHUTDOWN',
'SOME',
'STATISTICS',
'SYSADMIN',
'SYSTEM_USER',
'TABLE',
'TEMPDB',
'TEXTSIZE',
'THEN',
'TO',
'TOP',
'TRAN',
'TRANSACTION',
'TRIGGER',
'TRUNCATE',
'TSEQUAL',
'UNION',
'UNIQUE',
'UPDATE',
'UPDATETEXT',
'USE',
'USER',
'VALUES',
'VARYING',
'VIEW',
'WAITFOR',
'WHEN',
'WHERE',
'WHILE',
'WITH',
'WRITETEXT'
]

View File

@ -19,6 +19,6 @@ export default {
ctstackAddBareMetal: () => import('views/resource/ctstack/page/bareMetal/addBareMetal.vue'),
ctstackBareMetal: () => import('views/resource/ctstack/page/bareMetal/index.vue'),
// 数据库
ctstackRds: () => import('views/resource/ctstack/page/database/rds/index.vue')
// ctstackPgSQL: () => import('views/resource/ctstack/page/database/pgsql/cluster/index.vue')
ctstackMysql: () => import('views/resource/ctstack/page/database/mysql/index.vue'),
ctstackPgSQL: () => import('views/resource/ctstack/page/database/postgresql/index.vue')
}

View File

@ -4839,3 +4839,42 @@ export const flavorList = [
lvsSpec: null
}
]
export const storageTypeMap = {
MYSQL: [
{
name: '高IO',
value: 'SAS'
},
{
name: '普通IO',
value: 'SATA'
},
{
name: '超高IO',
value: 'SSD'
}
],
POSTGRESQL: [
{
name: '极速型SSD',
value: 'FAST-SSD'
},
{
name: '通用型SSD',
value: 'SSD-genric'
},
{
name: '高IO',
value: 'SAS'
},
{
name: '普通IO',
value: 'SATA'
},
{
name: '超高IO',
value: 'SSD'
}
]
}

View File

@ -1,6 +1,6 @@
import { request } from '@cmp/cmp-element'
import { wrapperParams, downloadFile } from 'utils'
import { projectList, zoneList, flavorList } from './mockData'
import { projectList, zoneList, flavorList, storageTypeMap } from './mockData'
const url = '/cmp/plugins/ctstack/v1/cloudrds'
// 是否开发环境
const isDev = process.env.NODE_ENV === 'development'
@ -23,7 +23,10 @@ export function getRdsZone(params) {
if (isDev) return mockRequest(zoneList)
return request.get(`${url}/zones`, { params })
}
export function getStorageType(params) {
const data = storageTypeMap[params.type]
return mockRequest(data)
}
export function getFlavor(params) {
if (isDev) return mockRequest(flavorList)
return request.get(`${url}/flavors`, { params })