Commit d2142368 authored by 智勇's avatar 智勇

Merge branch 'dbsync' into 'master'

Dbsync



See merge request !4
parents ac17fb0f 64f83ad0
...@@ -23,3 +23,35 @@ export function deleteConfig(query) { ...@@ -23,3 +23,35 @@ export function deleteConfig(query) {
params: query params: query
}) })
} }
export function getNamespace(query) {
return request({
url: '/dbsync/get_name_space',
method: 'get',
params: query
})
}
export function getDBName(query) {
return request({
url: '/dbsync/get_dbs',
method: 'get',
params: query
})
}
export function dbSync(data) {
return request({
url: '/dbsync/db_sync',
method: 'post',
data
})
}
export function dbSyncQuery(data) {
return request({
url: '/dbsync/db_sync_query',
method: 'post',
data
})
}
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1552358833449" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5768" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M512 438.857143q135.428571 0 253.142857-24.571429t185.714286-72.571428v97.142857q0 39.428571-58.857143 73.142857t-160 53.428571-220 19.714286-220-19.714286T132 512 73.142857 438.857143V341.714286q68 48 185.714286 72.571428t253.142857 24.571429z m0 438.857143q135.428571 0 253.142857-24.571429t185.714286-72.571428v97.142857q0 39.428571-58.857143 73.142857t-160 53.428571-220 19.714286-220-19.714286-160-53.428571-58.857143-73.142857v-97.142857q68 48 185.714286 72.571428t253.142857 24.571429z m0-219.428572q135.428571 0 253.142857-24.571428t185.714286-72.571429v97.142857q0 39.428571-58.857143 73.142857t-160 53.428572-220 19.714286-220-19.714286-160-53.428572-58.857143-73.142857V561.142857q68 48 185.714286 72.571429t253.142857 24.571428zM512 0q118.857143 0 220 19.714286t160 53.428571 58.857143 73.142857v73.142857q0 39.428571-58.857143 73.142858t-160 53.428571T512 365.714286t-220-19.714286T132 292.571429 73.142857 219.428571V146.285714q0-39.428571 58.857143-73.142857t160-53.428571T512 0z" p-id="5769"></path></svg>
\ No newline at end of file
...@@ -7,11 +7,11 @@ Vue.use(Router) ...@@ -7,11 +7,11 @@ Vue.use(Router)
import Layout from '@/views/layout/Layout' import Layout from '@/views/layout/Layout'
/* Router Modules */ /* Router Modules */
import componentsRouter from './modules/components' // import componentsRouter from './modules/components'
import chartsRouter from './modules/charts' // import chartsRouter from './modules/charts'
// import tableRouter from './modules/table'
// import nestedRouter from './modules/nested'
import dockersRouter from './modules/docker' import dockersRouter from './modules/docker'
import tableRouter from './modules/table'
import nestedRouter from './modules/nested'
/** note: sub-menu only appear when children.length>=1 /** note: sub-menu only appear when children.length>=1
* detail see https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html * detail see https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
...@@ -90,33 +90,33 @@ export const constantRouterMap = [ ...@@ -90,33 +90,33 @@ export const constantRouterMap = [
meta: { title: 'indexList', icon: 'link' } meta: { title: 'indexList', icon: 'link' }
} }
] ]
},
{
path: '/documentation',
component: Layout,
redirect: '/documentation/index',
children: [
{
path: 'index',
component: () => import('@/views/documentation/index'),
name: 'Documentation',
meta: { title: 'documentation', icon: 'documentation', affix: true }
}
]
},
{
path: '/guide',
component: Layout,
redirect: '/guide/index',
children: [
{
path: 'index',
component: () => import('@/views/guide/index'),
name: 'Guide',
meta: { title: 'guide', icon: 'guide', noCache: true }
}
]
} }
// {
// path: '/documentation',
// component: Layout,
// redirect: '/documentation/index',
// children: [
// {
// path: 'index',
// component: () => import('@/views/documentation/index'),
// name: 'Documentation',
// meta: { title: 'documentation', icon: 'documentation', affix: true }
// }
// ]
// },
// {
// path: '/guide',
// component: Layout,
// redirect: '/guide/index',
// children: [
// {
// path: 'index',
// component: () => import('@/views/guide/index'),
// name: 'Guide',
// meta: { title: 'guide', icon: 'guide', noCache: true }
// }
// ]
// }
] ]
export default new Router({ export default new Router({
...@@ -126,111 +126,59 @@ export default new Router({ ...@@ -126,111 +126,59 @@ export default new Router({
}) })
export const asyncRouterMap = [ export const asyncRouterMap = [
dockersRouter,
{ {
path: '/dbconfig', path: '/dbsync',
component: Layout,
redirect: 'noredirect',
children: [
{
path: 'manager',
component: () => import('@/views/dbconfig/manager/index'),
name: 'DB同步信息管理',
meta: { title: 'DB同步信息管理', icon: 'mysql' }
}
]
},
{
path: '/statistics',
component: Layout, component: Layout,
redirect: 'noredirect', redirect: 'noredirect',
children: [ children: [
{ {
path: '', path: '',
component: () => import('@/views/statistics/index'), component: () => import('@/views/dbconfig/sync/index'),
name: 'statistics', name: 'DB同步',
meta: { title: '用户行为记录', icon: 'peoples' } meta: { title: '执行DB同步', icon: 'database' }
}
]
},
{
path: '/pipeline',
component: Layout,
redirect: 'application',
name: 'Pipeline',
meta: {
title: 'Pipeline',
icon: 'nested'
},
children: [
{
path: 'application',
component: () => import('@/views/pipeline/application/index'),
name: 'application',
meta: { title: '应用管理', icon: 'example' }
},
{
path: 'quali',
component: () => import('@/views/testdata/index'),
name: 'quali',
meta: { title: '质效管理', icon: 'tab' }
} }
] ]
}, },
{ {
path: '/permission', path: '/dbconfig',
component: Layout, component: Layout,
redirect: '/permission/index', redirect: 'noredirect',
alwaysShow: true, // will always show the root menu
meta: {
title: 'permission',
icon: 'lock',
roles: ['admin', 'editor'] // you can set roles in root nav
},
children: [ children: [
{ {
path: 'page', path: 'manager',
component: () => import('@/views/permission/page'), component: () => import('@/views/dbconfig/manager/index'),
name: 'PagePermission', name: 'DB同步信息管理',
meta: { meta: { title: 'DB同步信息管理', icon: 'mysql' }
title: 'pagePermission',
roles: ['admin'] // or you can only set roles in sub nav
}
},
{
path: 'directive',
component: () => import('@/views/permission/directive'),
name: 'DirectivePermission',
meta: {
title: 'directivePermission'
// if do not set roles, means: this page does not require permission
}
} }
] ]
}, },
{ {
path: '/icon', path: '/proconfig',
component: Layout, component: Layout,
redirect: 'noredirect',
children: [ children: [
{ {
path: 'index', path: '',
component: () => import('@/views/svg-icons/index'), component: () => import('@/views/proconfig/index'),
name: 'Icons', name: 'proconfig',
meta: { title: 'icons', icon: 'icon', noCache: true } meta: { title: '项目配置文件管理', icon: 'documentation' }
} }
] ]
}, },
{ {
path: '/proconfig', path: '/statistics',
component: Layout, component: Layout,
redirect: 'noredirect', redirect: 'noredirect',
children: [ children: [
{ {
path: '', path: '',
component: () => import('@/views/proconfig/index'), component: () => import('@/views/statistics/index'),
name: 'proconfig', name: 'statistics',
meta: { title: '配置文件管理', icon: 'documentation' } meta: { title: '用户行为记录', icon: 'peoples' }
} }
] ]
}, },
...@@ -249,214 +197,284 @@ export const asyncRouterMap = [ ...@@ -249,214 +197,284 @@ export const asyncRouterMap = [
] ]
}, },
/** When your routing table is too long, you can split it into small modules**/
componentsRouter,
chartsRouter,
nestedRouter,
tableRouter,
dockersRouter,
{ {
path: '/example', path: '/pipeline',
component: Layout, component: Layout,
redirect: '/example/list', redirect: 'application',
name: 'Example', name: 'Pipeline',
meta: { meta: {
title: 'example', title: 'Pipeline',
icon: 'example' icon: 'nested'
}, },
children: [ children: [
{ {
path: 'create', path: 'application',
component: () => import('@/views/example/create'), component: () => import('@/views/pipeline/application/index'),
name: 'CreateArticle', name: 'application',
meta: { title: 'createArticle', icon: 'edit' } meta: { title: '应用管理', icon: 'example' }
},
{
path: 'edit/:id(\\d+)',
component: () => import('@/views/example/edit'),
name: 'EditArticle',
meta: { title: 'editArticle', noCache: true },
hidden: true
}, },
{ {
path: 'list', path: 'quali',
component: () => import('@/views/example/list'), component: () => import('@/views/testdata/index'),
name: 'ArticleList', name: 'quali',
meta: { title: 'articleList', icon: 'list' } meta: { title: '质效管理', icon: 'tab' }
} }
] ]
}, },
{ // {
path: '/tab', // path: '/permission',
component: Layout, // component: Layout,
children: [ // redirect: '/permission/index',
{ // alwaysShow: true, // will always show the root menu
path: 'index', // meta: {
component: () => import('@/views/tab/index'), // title: 'permission',
name: 'Tab', // icon: 'lock',
meta: { title: 'tab', icon: 'tab' } // roles: ['admin', 'editor'] // you can set roles in root nav
} // },
] // children: [
}, // {
// path: 'page',
// component: () => import('@/views/permission/page'),
// name: 'PagePermission',
// meta: {
// title: 'pagePermission',
// roles: ['admin'] // or you can only set roles in sub nav
// }
// },
// {
// path: 'directive',
// component: () => import('@/views/permission/directive'),
// name: 'DirectivePermission',
// meta: {
// title: 'directivePermission'
// // if do not set roles, means: this page does not require permission
// }
// }
// ]
// },
{ // {
path: '/error', // path: '/icon',
component: Layout, // component: Layout,
redirect: 'noredirect', // children: [
name: 'ErrorPages', // {
meta: { // path: 'index',
title: 'errorPages', // component: () => import('@/views/svg-icons/index'),
icon: '404' // name: 'Icons',
}, // meta: { title: 'icons', icon: 'icon', noCache: true }
children: [ // }
{ // ]
path: '401', // },
component: () => import('@/views/errorPage/401'),
name: 'Page401',
meta: { title: 'page401', noCache: true }
},
{
path: '404',
component: () => import('@/views/errorPage/404'),
name: 'Page404',
meta: { title: 'page404', noCache: true }
}
]
},
{ /** When your routing table is too long, you can split it into small modules**/
path: '/error-log', // componentsRouter,
component: Layout, // chartsRouter,
redirect: 'noredirect', // nestedRouter,
children: [ // tableRouter,
{
path: 'log',
component: () => import('@/views/errorLog/index'),
name: 'ErrorLog',
meta: { title: 'errorLog', icon: 'bug' }
}
]
},
{ // {
path: '/excel', // path: '/example',
component: Layout, // component: Layout,
redirect: '/excel/export-excel', // redirect: '/example/list',
name: 'Excel', // name: 'Example',
meta: { // meta: {
title: 'excel', // title: 'example',
icon: 'excel' // icon: 'example'
}, // },
children: [ // children: [
{ // {
path: 'export-excel', // path: 'create',
component: () => import('@/views/excel/exportExcel'), // component: () => import('@/views/example/create'),
name: 'ExportExcel', // name: 'CreateArticle',
meta: { title: 'exportExcel' } // meta: { title: 'createArticle', icon: 'edit' }
}, // },
{ // {
path: 'export-selected-excel', // path: 'edit/:id(\\d+)',
component: () => import('@/views/excel/selectExcel'), // component: () => import('@/views/example/edit'),
name: 'SelectExcel', // name: 'EditArticle',
meta: { title: 'selectExcel' } // meta: { title: 'editArticle', noCache: true },
}, // hidden: true
{ // },
path: 'upload-excel', // {
component: () => import('@/views/excel/uploadExcel'), // path: 'list',
name: 'UploadExcel', // component: () => import('@/views/example/list'),
meta: { title: 'uploadExcel' } // name: 'ArticleList',
} // meta: { title: 'articleList', icon: 'list' }
] // }
}, // ]
// },
{ // {
path: '/zip', // path: '/tab',
component: Layout, // component: Layout,
redirect: '/zip/download', // children: [
alwaysShow: true, // {
meta: { title: 'zip', icon: 'zip' }, // path: 'index',
children: [ // component: () => import('@/views/tab/index'),
{ // name: 'Tab',
path: 'download', // meta: { title: 'tab', icon: 'tab' }
component: () => import('@/views/zip/index'), // }
name: 'ExportZip', // ]
meta: { title: 'exportZip' } // },
}
]
},
{ // {
path: '/pdf', // path: '/error',
component: Layout, // component: Layout,
redirect: '/pdf/index', // redirect: 'noredirect',
children: [ // name: 'ErrorPages',
{ // meta: {
path: 'index', // title: 'errorPages',
component: () => import('@/views/pdf/index'), // icon: '404'
name: 'PDF', // },
meta: { title: 'pdf', icon: 'pdf' } // children: [
} // {
] // path: '401',
}, // component: () => import('@/views/errorPage/401'),
{ // name: 'Page401',
path: '/pdf/download', // meta: { title: 'page401', noCache: true }
component: () => import('@/views/pdf/download'), // },
hidden: true // {
}, // path: '404',
// component: () => import('@/views/errorPage/404'),
// name: 'Page404',
// meta: { title: 'page404', noCache: true }
// }
// ]
// },
{ // {
path: '/theme', // path: '/error-log',
component: Layout, // component: Layout,
redirect: 'noredirect', // redirect: 'noredirect',
children: [ // children: [
{ // {
path: 'index', // path: 'log',
component: () => import('@/views/theme/index'), // component: () => import('@/views/errorLog/index'),
name: 'Theme', // name: 'ErrorLog',
meta: { title: 'theme', icon: 'theme' } // meta: { title: 'errorLog', icon: 'bug' }
} // }
] // ]
}, // },
{ // {
path: '/clipboard', // path: '/excel',
component: Layout, // component: Layout,
redirect: 'noredirect', // redirect: '/excel/export-excel',
children: [ // name: 'Excel',
{ // meta: {
path: 'index', // title: 'excel',
component: () => import('@/views/clipboard/index'), // icon: 'excel'
name: 'ClipboardDemo', // },
meta: { title: 'clipboardDemo', icon: 'clipboard' } // children: [
} // {
] // path: 'export-excel',
}, // component: () => import('@/views/excel/exportExcel'),
// name: 'ExportExcel',
// meta: { title: 'exportExcel' }
// },
// {
// path: 'export-selected-excel',
// component: () => import('@/views/excel/selectExcel'),
// name: 'SelectExcel',
// meta: { title: 'selectExcel' }
// },
// {
// path: 'upload-excel',
// component: () => import('@/views/excel/uploadExcel'),
// name: 'UploadExcel',
// meta: { title: 'uploadExcel' }
// }
// ]
// },
{ // {
path: '/i18n', // path: '/zip',
component: Layout, // component: Layout,
children: [ // redirect: '/zip/download',
{ // alwaysShow: true,
path: 'index', // meta: { title: 'zip', icon: 'zip' },
component: () => import('@/views/i18n-demo/index'), // children: [
name: 'I18n', // {
meta: { title: 'i18n', icon: 'international' } // path: 'download',
} // component: () => import('@/views/zip/index'),
] // name: 'ExportZip',
}, // meta: { title: 'exportZip' }
// }
// ]
// },
{ // {
path: 'external-link', // path: '/pdf',
component: Layout, // component: Layout,
children: [ // redirect: '/pdf/index',
{ // children: [
path: 'https://github.com/PanJiaChen/vue-element-admin', // {
meta: { title: 'externalLink', icon: 'link' } // path: 'index',
} // component: () => import('@/views/pdf/index'),
] // name: 'PDF',
}, // meta: { title: 'pdf', icon: 'pdf' }
// }
// ]
// },
// {
// path: '/pdf/download',
// component: () => import('@/views/pdf/download'),
// hidden: true
// },
// {
// path: '/theme',
// component: Layout,
// redirect: 'noredirect',
// children: [
// {
// path: 'index',
// component: () => import('@/views/theme/index'),
// name: 'Theme',
// meta: { title: 'theme', icon: 'theme' }
// }
// ]
// },
// {
// path: '/clipboard',
// component: Layout,
// redirect: 'noredirect',
// children: [
// {
// path: 'index',
// component: () => import('@/views/clipboard/index'),
// name: 'ClipboardDemo',
// meta: { title: 'clipboardDemo', icon: 'clipboard' }
// }
// ]
// },
// {
// path: '/i18n',
// component: Layout,
// children: [
// {
// path: 'index',
// component: () => import('@/views/i18n-demo/index'),
// name: 'I18n',
// meta: { title: 'i18n', icon: 'international' }
// }
// ]
// },
// {
// path: 'external-link',
// component: Layout,
// children: [
// {
// path: 'https://github.com/PanJiaChen/vue-element-admin',
// meta: { title: 'externalLink', icon: 'link' }
// }
// ]
// },
{ path: '*', redirect: '/404', hidden: true } { path: '*', redirect: '/404', hidden: true }
] ]
...@@ -161,7 +161,14 @@ export default { ...@@ -161,7 +161,14 @@ export default {
createData() { createData() {
this.$refs['dataForm'].validate((valid) => { this.$refs['dataForm'].validate((valid) => {
if (valid) { if (valid) {
saveConfig(this.temp).then(() => { saveConfig(this.temp).then((res) => {
if (res.data.code !== '0000') {
this.$notify({
message: `${res.data.msg}`,
type: 'error',
duration: 2000
})
} else {
this.dialogFormVisible = false this.dialogFormVisible = false
this.$notify({ this.$notify({
title: '成功', title: '成功',
...@@ -170,6 +177,7 @@ export default { ...@@ -170,6 +177,7 @@ export default {
duration: 2000 duration: 2000
}) })
this.getConfig() this.getConfig()
}
}) })
} }
}) })
......
<template>
<div >
<div class="app-container" style="width:1000px; margin:0 auto;">
<el-form ref="dataForm" :inline="true" :rules="rules" :model="temp" label-width="150px" style="margin-bottom:15px">
<el-form-item label="Namespace" prop="namespace">
<el-select :disabled="disableBool" v-model="temp.namespace" style="width:310px" placeholder="要同步数据库的环境">
<el-option v-for="item in namespaces" :value="item" :label="item" :key="item" />
</el-select>
</el-form-item>
<el-form-item label="数据库名称" prop="dbname">
<el-select :disabled="disableBool" v-model="temp.dbname" placeholder="要同步表结构及配置数据的数据库名称" style="width:310px">
<el-option v-for="item in dbnames" :value="item" :label="item" :key="item" />
</el-select>
</el-form-item>
</el-form>
<el-form :inline="true" :model="temp" label-width="150px">
<el-form-item label="保留业务数据">
<el-switch :disabled="disableBool" v-model="temp.not_delete_business_data" style="margin-right:280px" />
<span 是否保留当前已经存在的测试数据/>
</el-form-item>
<el-form-item label="使用备份数据">
<el-switch :disabled="disableBool" v-model="temp.use_cache"/>
</el-form-item>
</el-form>
<div style="margin-left:420px">
<el-button :disabled="disableBool" type="primary" @click="sync()">{{ $t('table.confirm') }}</el-button>
<el-button :disabled="disableBool" @click="resetTemp()">{{ $t('table.cancel') }}</el-button>
</div >
</div >
<div style="padding:10px 20px 0px">
<!-- <div v-if="desc" style="padding:10px 20px 0px"> -->
<textarea v-if="desc" v-model="desc" style="min-height:600px;background-color:black;width:-webkit-fill-available;color:white"/>
</div>
</div>
</template>
<script>
import { getNamespace, getDBName, dbSync, dbSyncQuery } from '@/api/dbconfig'
import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
import JsonEditor from '@/components/JsonEditor'
export default {
name: 'DBSync',
components: { Pagination, JsonEditor },
filters: {
},
data() {
return {
dialogFormVisible: false,
dialogDeleteVisible: false,
dialogStatus: '',
rules: {
dbname: [{ required: true, message: '请输入', trigger: 'change' }],
namespace: [{ required: true, message: '请输入', trigger: 'change' }]
},
configs: [],
namespace: undefined,
namespaces: [],
dbname: undefined,
dbnames: [],
temp: {
not_delete_business_data: true,
use_cache: true
},
desc: '',
location: '',
time: undefined,
disableBool: false
}
},
computed: {
},
watch: {
},
created() {
this.getNamespace()
this.getDBName()
},
methods: {
getNamespace() {
getNamespace().then(res => {
this.namespaces = res.data.data.map(item => item.name)
})
},
getDBName() {
getDBName().then(res => {
this.dbnames = res.data.data.map(item => item.dbname)
this.dbnames.unshift('all(no_mall)')
})
},
resetTemp() {
this.temp = {
namespace: '',
dbname: '',
not_delete_business_data: false,
use_cache: false
}
},
syncQuery(location) {
dbSyncQuery({ location }).then(res => {
res = res.data.data
if (this.timer > 300) {
this.$notify({
title: '超时',
message: '同步超时!',
type: 'error',
duration: 2000
})
return true
}
if (res.status === 'complete') {
this.desc = new Date().toLocaleTimeString() + ' 完成同步: ' + res.msg.result + '; ID: ' + res.msg.number + '\n\n\n' + res.log.body
this.disableBool = false
this.$notify({
title: '成功',
message: '完成同步!',
type: 'success',
duration: 2000
})
return true
}
this.timer = this.timer + 3
this.desc = new Date().toLocaleTimeString() + ` 测试环境 ${this.temp.namespace} 正在同步 ${this.temp.dbname} 数据库,已等待 ${this.timer}s...\n\n\n` + res.log.body
setTimeout(() => {
this.syncQuery(location)
}, 3000)
})
},
sync() {
console.log(1, this)
this.$refs['dataForm'].validate((valid) => {
if (valid) {
dbSync(this.temp).then((res) => {
this.dialogFormVisible = false
this.location = res.data.data.location
this.$notify({
message: '正在同步',
type: 'success',
duration: 2000
})
this.desc = ''
this.timer = 0
this.disableBool = true
this.syncQuery(this.location)
})
}
})
}
}
}
</script>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment