5 changed files with 421 additions and 2 deletions
@ -0,0 +1,24 @@ |
|||||
|
import request from '@/utils/request'; |
||||
|
import { AxiosPromise } from 'axios'; |
||||
|
|
||||
|
import { |
||||
|
redisConfing, |
||||
|
copyRedisDatabase |
||||
|
} from './types'; |
||||
|
|
||||
|
//测试Redis数据库链接
|
||||
|
export const testRedisLink = (data: redisConfing):any => { |
||||
|
return request({ |
||||
|
url: '/systemapi/redis/testRedisLink', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
|
//迁移Redis数据库
|
||||
|
export const moveOldRedisToNewRedis = (data: copyRedisDatabase):any => { |
||||
|
return request({ |
||||
|
url: '/systemapi/redis/moveOldRedisToNewRedis', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
export interface redisConfing { |
||||
|
ip: string; |
||||
|
port: number; |
||||
|
pwd: string; |
||||
|
state: number; |
||||
|
} |
||||
|
//Redis数据及含有的键数量
|
||||
|
export interface redisKeysNumber { |
||||
|
dbName:number; |
||||
|
dbNumber:number; |
||||
|
} |
||||
|
//迁移Redis数据库参数
|
||||
|
export interface copyRedisDatabase { |
||||
|
originRedis:redisConfing; |
||||
|
targetRedis:redisConfing; |
||||
|
dblist:Number[]; |
||||
|
} |
||||
@ -0,0 +1,373 @@ |
|||||
|
<!-- |
||||
|
@ 作者: 秦东 |
||||
|
@ 时间: 2023-11-13 10:44:48 |
||||
|
@ 备注: Redis数据迁移 |
||||
|
--> |
||||
|
<script lang='ts' setup> |
||||
|
import { Eleme } from '@element-plus/icons-vue' |
||||
|
import { redisConfing,redisKeysNumber } from '@/api/system/redis/types' |
||||
|
import { testRedisLink,moveOldRedisToNewRedis } from '@/api/system/redis/api' |
||||
|
const svg = ` |
||||
|
<path class="path" d=" |
||||
|
M 30 15 |
||||
|
L 28 17 |
||||
|
M 25.61 25.61 |
||||
|
A 15 15, 0, 0, 1, 15 30 |
||||
|
A 15 15, 0, 1, 1, 27.99 7.5 |
||||
|
L 15 15 |
||||
|
" style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/> |
||||
|
` |
||||
|
const originConfig = reactive<redisConfing>({ |
||||
|
ip:"127.0.0.1", |
||||
|
port:6379, |
||||
|
pwd:"", |
||||
|
state:0 |
||||
|
}) |
||||
|
const targetConfig = reactive<redisConfing>({ |
||||
|
ip:"127.0.0.1", |
||||
|
port:6379, |
||||
|
pwd:"", |
||||
|
state:0 |
||||
|
}) |
||||
|
const originTestLoad = ref(false); //测试源 |
||||
|
const originTextType = ref<string>("info") |
||||
|
const originDbNumber = ref<number>(0) |
||||
|
const originCheckList = ref<number[]>([]) |
||||
|
const originKeyList = reactive<redisKeysNumber[]>([]) |
||||
|
//进行源Redis连接测试 |
||||
|
const originTestLink = () =>{ |
||||
|
originTestLoad.value=true |
||||
|
originConfig.port = originConfig.port*1 |
||||
|
originConfig.state = originConfig.state*1 |
||||
|
testRedisLink(originConfig) |
||||
|
.then((data:any)=>{ |
||||
|
if(data.data.isTrue){ |
||||
|
if(data.data.isTrue == 1){ |
||||
|
originConfig.state = 1 |
||||
|
originTextType.value = "success" |
||||
|
}else{ |
||||
|
originConfig.state = 2 |
||||
|
originTextType.value = "danger" |
||||
|
} |
||||
|
}else{ |
||||
|
originConfig.state = 2 |
||||
|
} |
||||
|
if(data.data.dbNumber){ |
||||
|
originDbNumber.value = data.data.dbNumber |
||||
|
} |
||||
|
originKeyList.splice(0,originKeyList.length); |
||||
|
if(data.data.redisList && data.data.redisList.length > 0){ |
||||
|
data.data.redisList.forEach((item:any)=>{ |
||||
|
originKeyList.push({ |
||||
|
dbName: item.dbName, |
||||
|
dbNumber: item.dbNumber |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
// console.log("进行源Redis连接测试",originConfig,originKeyList) |
||||
|
}) |
||||
|
.finally(()=>{ |
||||
|
originTestLoad.value=false |
||||
|
}) |
||||
|
} |
||||
|
const targetTestLoad = ref(false); //测试目标 |
||||
|
const targetTextType = ref<string>("info") |
||||
|
const targetDbNumber = ref<number>(1) |
||||
|
const targetKeyList = reactive<redisKeysNumber[]>([]) |
||||
|
//进行目标Redis连接测试 |
||||
|
const targetTestLink = () =>{ |
||||
|
targetTestLoad.value=true |
||||
|
targetConfig.port = targetConfig.port*1 |
||||
|
targetConfig.state = targetConfig.state*1 |
||||
|
testRedisLink(targetConfig) |
||||
|
.then((data:any)=>{ |
||||
|
if(data.data.isTrue){ |
||||
|
if(data.data.isTrue == 1){ |
||||
|
targetConfig.state = 1 |
||||
|
targetTextType.value = "success" |
||||
|
}else{ |
||||
|
targetConfig.state = 2 |
||||
|
targetTextType.value = "danger" |
||||
|
} |
||||
|
}else{ |
||||
|
targetConfig.state = 2 |
||||
|
} |
||||
|
// targetDbNumber.value = new Array |
||||
|
if(data.data.dbNumber){ |
||||
|
targetDbNumber.value = data.data.dbNumber |
||||
|
} |
||||
|
targetKeyList.splice(0,targetKeyList.length); |
||||
|
if(data.data.redisList && data.data.redisList.length > 0){ |
||||
|
data.data.redisList.forEach((item:any)=>{ |
||||
|
targetKeyList.push({ |
||||
|
dbName: item.dbName, |
||||
|
dbNumber: item.dbNumber |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
}) |
||||
|
.finally(()=>{ |
||||
|
targetTestLoad.value=false |
||||
|
}) |
||||
|
} |
||||
|
//迁移 |
||||
|
const migrateLoad = ref(false) |
||||
|
const logList = ref<any[]>([]) |
||||
|
const migrateRedisInfo = () =>{ |
||||
|
migrateLoad.value = true |
||||
|
if(originConfig.state != 1){ |
||||
|
migrateLoad.value = false; |
||||
|
ElMessageBox({ |
||||
|
title: '温馨提示!', |
||||
|
// message: "您未进行源Redis连通性测试!为确保迁移正常进行,请先测试一下是否可以连通!", |
||||
|
message:h('p', null, [ |
||||
|
h('span', null, '您未进行'), |
||||
|
h('span', { style: 'color: #ff0000' }, '源Redis连通性测试!'), |
||||
|
h('span', null, '为确保迁移正常进行,请先测试一下'), |
||||
|
h('span', { style: 'color: #ff0000' }, '是否可以连通!'), |
||||
|
]) |
||||
|
}) |
||||
|
return |
||||
|
} |
||||
|
if(targetConfig.state != 1){ |
||||
|
migrateLoad.value = false; |
||||
|
ElMessageBox({ |
||||
|
title: '温馨提示!', |
||||
|
// message: "您未进行目标Redis连通性测试!为确保迁移正常进行,请先测试一下是否可以连通!", |
||||
|
message:h('p', null, [ |
||||
|
h('span', null, '您未进行'), |
||||
|
h('span', { style: 'color: #ff0000' }, '目标Redis连通性测试!'), |
||||
|
h('span', null, '为确保迁移正常进行,请先测试一下'), |
||||
|
h('span', { style: 'color: #ff0000' }, '是否可以连通!'), |
||||
|
]) |
||||
|
}) |
||||
|
return |
||||
|
} |
||||
|
if(targetConfig.ip == originConfig.ip && targetConfig.port == originConfig.port){ |
||||
|
migrateLoad.value = false; |
||||
|
ElMessageBox({ |
||||
|
title: '温馨提示!', |
||||
|
// message: "您未进行目标Redis连通性测试!为确保迁移正常进行,请先测试一下是否可以连通!", |
||||
|
message:h('p', null, [ |
||||
|
h('span', { style: 'color: #ff0000' }, '源Redis与目标Redis相同!'), |
||||
|
h('span', null, '不能进行迁移!'), |
||||
|
]) |
||||
|
}) |
||||
|
return |
||||
|
} |
||||
|
let sendInfo = { |
||||
|
originRedis:originConfig, //源 |
||||
|
targetRedis:targetConfig, //目标 |
||||
|
dblist:originCheckList.value //选择库 |
||||
|
} |
||||
|
moveOldRedisToNewRedis(sendInfo) |
||||
|
.then((data)=>{ |
||||
|
console.log("进行源Redis连接测试",data) |
||||
|
logList.value = data.data |
||||
|
}) |
||||
|
.finally(()=>{ |
||||
|
migrateLoad.value = false; |
||||
|
}) |
||||
|
|
||||
|
|
||||
|
} |
||||
|
</script> |
||||
|
<template> |
||||
|
<div class="app-main body_cont"> |
||||
|
<table border="1" class="table_body"> |
||||
|
<tr> |
||||
|
<td rowspan="4" width="10%" align="center">源Redsi</td> |
||||
|
<td width="35%"> |
||||
|
<table border="0"> |
||||
|
<tr> |
||||
|
<td width="60">IP地址</td> |
||||
|
<td><el-input v-model="originConfig.ip" clearable placeholder="请输入Redis源IP"></el-input></td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</td> |
||||
|
<td rowspan="4" colspan="2" width="10%" align="center"> |
||||
|
<el-button :loading-icon="Eleme" :loading="migrateLoad" type="primary" style="width:100%" @click="migrateRedisInfo">迁移</el-button> |
||||
|
</td> |
||||
|
|
||||
|
<td width="35%"> |
||||
|
<table border="0"> |
||||
|
<tr> |
||||
|
<td width="60">IP地址</td> |
||||
|
<td><el-input v-model="targetConfig.ip" clearable placeholder="请输入Redis源IP"></el-input></td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</td> |
||||
|
<td rowspan="4" width="10%" align="center">目标Redis</td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<table border="0"> |
||||
|
<tr> |
||||
|
<td width="60">端口</td> |
||||
|
<td><el-input v-model="originConfig.port" type="number" clearable placeholder="请输入Redis源IP"></el-input></td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</td> |
||||
|
|
||||
|
|
||||
|
<td> |
||||
|
<table border="0"> |
||||
|
<tr> |
||||
|
<td width="60">端口</td> |
||||
|
<td><el-input v-model="targetConfig.port" type="number" clearable placeholder="请输入Redis源IP"></el-input></td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<table border="0"> |
||||
|
<tr> |
||||
|
<td width="60">密码</td> |
||||
|
<td><el-input v-model="originConfig.pwd" type="password" show-password clearable placeholder="请输入Redis源IP"></el-input></td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</td> |
||||
|
|
||||
|
|
||||
|
<td> |
||||
|
<table border="0"> |
||||
|
<tr> |
||||
|
<td width="60">密码</td> |
||||
|
<td><el-input v-model="targetConfig.pwd" type="password" show-password clearable placeholder="请输入Redis源IP"></el-input></td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td> |
||||
|
<table border="0"> |
||||
|
<tr> |
||||
|
<td width="50"> |
||||
|
<el-button :loading-icon="Eleme" :loading="originTestLoad" type="primary" @click="originTestLink">测试链接</el-button> |
||||
|
</td> |
||||
|
<td align="right"> |
||||
|
<el-text class="mx-1" :type="originTextType"> |
||||
|
<i v-if="originConfig.state == 1" class="fa fa-check"></i> |
||||
|
<i v-else-if="originConfig.state == 2" class="fa fa-close"></i> |
||||
|
<span v-else>未测试</span> |
||||
|
</el-text> |
||||
|
|
||||
|
</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</td> |
||||
|
<td> |
||||
|
<table border="0"> |
||||
|
<tr> |
||||
|
<td align="left"> |
||||
|
<el-text class="mx-1" :type="targetTextType"> |
||||
|
<i v-if="targetConfig.state == 1" class="fa fa-check"></i> |
||||
|
<i v-else-if="targetConfig.state == 2" class="fa fa-close"></i> |
||||
|
<span v-else>未测试</span> |
||||
|
</el-text> |
||||
|
</td> |
||||
|
<td width="50"> |
||||
|
<el-button :loading-icon="Eleme" :loading="targetTestLoad" type="primary" @click="targetTestLink">测试链接</el-button> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td valign="top" align="center">数据库列表</td> |
||||
|
<td valign="top" colspan="2" class="min_td_height" width="40%" style="table-layout:fixed"> |
||||
|
|
||||
|
<el-checkbox-group v-model="originCheckList"> |
||||
|
<el-row :gutter="10"> |
||||
|
<el-col v-for="(item,index) in originKeyList" :key="index" :span="6" class="row_col_body"> |
||||
|
<el-checkbox :label="item.dbName" border size="small">DB{{item.dbName}}(Keys:{{item.dbNumber}})</el-checkbox> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</el-checkbox-group> |
||||
|
|
||||
|
</td> |
||||
|
<td valign="top" colspan="2" class="min_td_height" width="40%" style="table-layout:fixed"> |
||||
|
|
||||
|
<el-row :gutter="10"> |
||||
|
<el-col v-for="(item,index) in targetKeyList" :key="index" :span="6" class="row_col_body"> |
||||
|
<el-button size="small">DB{{item.dbName}}(Keys:{{item.dbNumber}})</el-button> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
|
||||
|
</td> |
||||
|
<td valign="top" align="center">数据库列表</td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td valign="top" align="center">处理结果</td> |
||||
|
<td colspan="5" valign="top"> |
||||
|
<div |
||||
|
v-loading="migrateLoad" |
||||
|
element-loading-text="Loading..." |
||||
|
:element-loading-spinner="svg" |
||||
|
element-loading-svg-view-box="-10, -10, 50, 50" |
||||
|
element-loading-background="rgba(122, 122, 122, 0.8)" |
||||
|
class="chuli_jieguo" |
||||
|
> |
||||
|
<div v-for="(item,index) in logList" :key="index" class="text_width"> |
||||
|
<el-text type="warning" >开始迁移Rdis:{{ item.dbName }}库</el-text> |
||||
|
<el-text v-for="(logCont,lgindex) in item.msgList" :key="lgindex" :type="logCont.state==1?'success':'warning'" >{{ logCont.keys }}:{{ logCont.msg }}</el-text> |
||||
|
<el-text type="primary" >Rdis:{{ item.dbName }}库迁移完成</el-text> |
||||
|
</div> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</div> |
||||
|
</template> |
||||
|
<style lang='scss' scoped> |
||||
|
.body_cont{ |
||||
|
padding:20px; |
||||
|
} |
||||
|
.table_body{ |
||||
|
background-color: #FFFFFF; |
||||
|
width:100%; |
||||
|
border-collapse: collapse; |
||||
|
/* |
||||
|
* 设置边框 |
||||
|
*/ |
||||
|
td,th { |
||||
|
border: 1px solid black; |
||||
|
padding: 5px; |
||||
|
table{ |
||||
|
width:100%; |
||||
|
td,th{ |
||||
|
border: 0px solid black; |
||||
|
padding: 0px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
.left_border{ |
||||
|
border-left: 1px solid black; |
||||
|
} |
||||
|
.min_td_height{ |
||||
|
height:150px; |
||||
|
} |
||||
|
.chuli_jieguo{ |
||||
|
height: calc(100vh - 480px); |
||||
|
overflow: hidden; |
||||
|
overflow-y: auto; |
||||
|
} |
||||
|
.checkbox_group{ |
||||
|
max-width:300px; |
||||
|
} |
||||
|
.row_col_body{ |
||||
|
margin-top:10px; |
||||
|
} |
||||
|
.text_width{ |
||||
|
border-bottom: 1px solid #EEEEEE; |
||||
|
padding:5px 0; |
||||
|
span { |
||||
|
display: block; |
||||
|
width: 100%; |
||||
|
margin-top: 5px; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
Loading…
Reference in new issue