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) {
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)
import Layout from '@/views/layout/Layout'
/* Router Modules */
import componentsRouter from './modules/components'
import chartsRouter from './modules/charts'
// import componentsRouter from './modules/components'
// import chartsRouter from './modules/charts'
// import tableRouter from './modules/table'
// import nestedRouter from './modules/nested'
import dockersRouter from './modules/docker'
import tableRouter from './modules/table'
import nestedRouter from './modules/nested'
/** 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
......@@ -90,33 +90,33 @@ export const constantRouterMap = [
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({
......@@ -126,111 +126,59 @@ export default new Router({
})
export const asyncRouterMap = [
dockersRouter,
{
path: '/dbconfig',
component: Layout,
redirect: 'noredirect',
children: [
{
path: 'manager',
component: () => import('@/views/dbconfig/manager/index'),
name: 'DB同步信息管理',
meta: { title: 'DB同步信息管理', icon: 'mysql' }
}
]
},
{
path: '/statistics',
path: '/dbsync',
component: Layout,
redirect: 'noredirect',
children: [
{
path: '',
component: () => import('@/views/statistics/index'),
name: 'statistics',
meta: { title: '用户行为记录', icon: 'peoples' }
}
]
},
{
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' }
component: () => import('@/views/dbconfig/sync/index'),
name: 'DB同步',
meta: { title: '执行DB同步', icon: 'database' }
}
]
},
{
path: '/permission',
path: '/dbconfig',
component: Layout,
redirect: '/permission/index',
alwaysShow: true, // will always show the root menu
meta: {
title: 'permission',
icon: 'lock',
roles: ['admin', 'editor'] // you can set roles in root nav
},
redirect: 'noredirect',
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: 'manager',
component: () => import('@/views/dbconfig/manager/index'),
name: 'DB同步信息管理',
meta: { title: 'DB同步信息管理', icon: 'mysql' }
}
]
},
{
path: '/icon',
path: '/proconfig',
component: Layout,
redirect: 'noredirect',
children: [
{
path: 'index',
component: () => import('@/views/svg-icons/index'),
name: 'Icons',
meta: { title: 'icons', icon: 'icon', noCache: true }
path: '',
component: () => import('@/views/proconfig/index'),
name: 'proconfig',
meta: { title: '项目配置文件管理', icon: 'documentation' }
}
]
},
{
path: '/proconfig',
path: '/statistics',
component: Layout,
redirect: 'noredirect',
children: [
{
path: '',
component: () => import('@/views/proconfig/index'),
name: 'proconfig',
meta: { title: '配置文件管理', icon: 'documentation' }
component: () => import('@/views/statistics/index'),
name: 'statistics',
meta: { title: '用户行为记录', icon: 'peoples' }
}
]
},
......@@ -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,
redirect: '/example/list',
name: 'Example',
redirect: 'application',
name: 'Pipeline',
meta: {
title: 'example',
icon: 'example'
title: 'Pipeline',
icon: 'nested'
},
children: [
{
path: 'create',
component: () => import('@/views/example/create'),
name: 'CreateArticle',
meta: { title: 'createArticle', icon: 'edit' }
},
{
path: 'edit/:id(\\d+)',
component: () => import('@/views/example/edit'),
name: 'EditArticle',
meta: { title: 'editArticle', noCache: true },
hidden: true
path: 'application',
component: () => import('@/views/pipeline/application/index'),
name: 'application',
meta: { title: '应用管理', icon: 'example' }
},
{
path: 'list',
component: () => import('@/views/example/list'),
name: 'ArticleList',
meta: { title: 'articleList', icon: 'list' }
path: 'quali',
component: () => import('@/views/testdata/index'),
name: 'quali',
meta: { title: '质效管理', icon: 'tab' }
}
]
},
{
path: '/tab',
component: Layout,
children: [
{
path: 'index',
component: () => import('@/views/tab/index'),
name: 'Tab',
meta: { title: 'tab', icon: 'tab' }
}
]
},
// {
// path: '/permission',
// component: Layout,
// redirect: '/permission/index',
// alwaysShow: true, // will always show the root menu
// meta: {
// title: 'permission',
// icon: 'lock',
// 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',
component: Layout,
redirect: 'noredirect',
name: 'ErrorPages',
meta: {
title: 'errorPages',
icon: '404'
},
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 }
}
]
},
// {
// path: '/icon',
// component: Layout,
// children: [
// {
// path: 'index',
// component: () => import('@/views/svg-icons/index'),
// name: 'Icons',
// meta: { title: 'icons', icon: 'icon', noCache: true }
// }
// ]
// },
{
path: '/error-log',
component: Layout,
redirect: 'noredirect',
children: [
{
path: 'log',
component: () => import('@/views/errorLog/index'),
name: 'ErrorLog',
meta: { title: 'errorLog', icon: 'bug' }
}
]
},
/** When your routing table is too long, you can split it into small modules**/
// componentsRouter,
// chartsRouter,
// nestedRouter,
// tableRouter,
{
path: '/excel',
component: Layout,
redirect: '/excel/export-excel',
name: 'Excel',
meta: {
title: 'excel',
icon: 'excel'
},
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: '/example',
// component: Layout,
// redirect: '/example/list',
// name: 'Example',
// meta: {
// title: 'example',
// icon: 'example'
// },
// children: [
// {
// path: 'create',
// component: () => import('@/views/example/create'),
// name: 'CreateArticle',
// meta: { title: 'createArticle', icon: 'edit' }
// },
// {
// path: 'edit/:id(\\d+)',
// component: () => import('@/views/example/edit'),
// name: 'EditArticle',
// meta: { title: 'editArticle', noCache: true },
// hidden: true
// },
// {
// path: 'list',
// component: () => import('@/views/example/list'),
// name: 'ArticleList',
// meta: { title: 'articleList', icon: 'list' }
// }
// ]
// },
{
path: '/zip',
component: Layout,
redirect: '/zip/download',
alwaysShow: true,
meta: { title: 'zip', icon: 'zip' },
children: [
{
path: 'download',
component: () => import('@/views/zip/index'),
name: 'ExportZip',
meta: { title: 'exportZip' }
}
]
},
// {
// path: '/tab',
// component: Layout,
// children: [
// {
// path: 'index',
// component: () => import('@/views/tab/index'),
// name: 'Tab',
// meta: { title: 'tab', icon: 'tab' }
// }
// ]
// },
{
path: '/pdf',
component: Layout,
redirect: '/pdf/index',
children: [
{
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: '/error',
// component: Layout,
// redirect: 'noredirect',
// name: 'ErrorPages',
// meta: {
// title: 'errorPages',
// icon: '404'
// },
// 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 }
// }
// ]
// },
{
path: '/theme',
component: Layout,
redirect: 'noredirect',
children: [
{
path: 'index',
component: () => import('@/views/theme/index'),
name: 'Theme',
meta: { title: 'theme', icon: 'theme' }
}
]
},
// {
// path: '/error-log',
// component: Layout,
// redirect: 'noredirect',
// children: [
// {
// path: 'log',
// component: () => import('@/views/errorLog/index'),
// name: 'ErrorLog',
// meta: { title: 'errorLog', icon: 'bug' }
// }
// ]
// },
{
path: '/clipboard',
component: Layout,
redirect: 'noredirect',
children: [
{
path: 'index',
component: () => import('@/views/clipboard/index'),
name: 'ClipboardDemo',
meta: { title: 'clipboardDemo', icon: 'clipboard' }
}
]
},
// {
// path: '/excel',
// component: Layout,
// redirect: '/excel/export-excel',
// name: 'Excel',
// meta: {
// title: 'excel',
// icon: 'excel'
// },
// 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',
component: Layout,
children: [
{
path: 'index',
component: () => import('@/views/i18n-demo/index'),
name: 'I18n',
meta: { title: 'i18n', icon: 'international' }
}
]
},
// {
// path: '/zip',
// component: Layout,
// redirect: '/zip/download',
// alwaysShow: true,
// meta: { title: 'zip', icon: 'zip' },
// children: [
// {
// path: 'download',
// component: () => import('@/views/zip/index'),
// name: 'ExportZip',
// meta: { title: 'exportZip' }
// }
// ]
// },
{
path: 'external-link',
component: Layout,
children: [
{
path: 'https://github.com/PanJiaChen/vue-element-admin',
meta: { title: 'externalLink', icon: 'link' }
}
]
},
// {
// path: '/pdf',
// component: Layout,
// redirect: '/pdf/index',
// children: [
// {
// 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 }
]
......@@ -161,15 +161,23 @@ export default {
createData() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
saveConfig(this.temp).then(() => {
this.dialogFormVisible = false
this.$notify({
title: '成功',
message: '保存成功',
type: 'success',
duration: 2000
})
this.getConfig()
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.$notify({
title: '成功',
message: '保存成功',
type: 'success',
duration: 2000
})
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