5 changed files with 417 additions and 3 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