This commit is contained in:
Jane
2023-12-22 12:18:52 +08:00
parent 340f82a67e
commit 812109656a
746 changed files with 84928 additions and 0 deletions

View File

@@ -0,0 +1,148 @@
<template>
<el-card class="box-card" shadow="always">
<div slot="header" class="clearfix">
<span>{{ title }}</span>
<el-button-group style="float: right;">
<el-button v-hasPerm="['metadata:changerecord:add']" size="mini" icon="el-icon-plus" round :loading="loadingOptions.loading" :disabled="loadingOptions.isDisabled" @click="submitForm">{{ loadingOptions.loadingText }}</el-button>
<el-button size="mini" icon="el-icon-back" round @click="showCard">返回</el-button>
</el-button-group>
</div>
<div class="body-wrapper">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="源数据表主键" prop="objectId">
<el-input v-model="form.objectId" placeholder="请输入源数据表主键" />
</el-form-item>
<el-form-item label="源数据表的字段名" prop="fieldName">
<el-input v-model="form.fieldName" placeholder="请输入源数据表的字段名" />
</el-form-item>
<el-form-item label="原来的值" prop="fieldOldValue">
<el-input v-model="form.fieldOldValue" placeholder="请输入原来的值" />
</el-form-item>
<el-form-item label="最新的值" prop="fieldNewValue">
<el-input v-model="form.fieldNewValue" placeholder="请输入最新的值" />
</el-form-item>
<el-form-item label="版本号" prop="version">
<el-input v-model="form.version" placeholder="请输入版本号" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in statusOptions"
:key="dict.id"
:label="dict.itemText"
>{{ dict.itemValue }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
</div>
</el-card>
</template>
<script>
import { addChangeRecord } from '@/api/metadata/changerecord'
export default {
name: 'ChangeRecordAdd',
props: {
data: {
type: Object,
default: function() {
return {}
}
}
},
data() {
return {
title: '变更记录新增',
// 展示切换
showOptions: {
data: {},
showList: true,
showAdd: false,
showEdit: false,
showDetail: false
},
// 保存按钮
loadingOptions: {
loading: false,
loadingText: '保存',
isDisabled: false
},
// 表单参数
form: {
status: '1'
},
// 表单校验
rules: {
objectId: [
{ required: true, message: '源数据表主键不能为空', trigger: 'blur' }
],
fieldName: [
{ required: true, message: '数据表的字段名不能为空', trigger: 'blur' }
],
fieldOldValue: [
{ required: true, message: '原来的值不能为空', trigger: 'blur' }
],
fieldNewValue: [
{ required: true, message: '最新的值不能为空', trigger: 'blur' }
],
version: [
{ required: true, message: '版本号不能为空', trigger: 'blur' }
]
},
// 状态数据字典
statusOptions: []
}
},
created() {
this.getDicts('sys_common_status').then(response => {
if (response.success) {
this.statusOptions = response.data
}
})
},
methods: {
showCard() {
this.$emit('showCard', this.showOptions)
},
/** 提交按钮 */
submitForm: function() {
this.$refs['form'].validate(valid => {
if (valid) {
this.loadingOptions.loading = true
this.loadingOptions.loadingText = '保存中...'
this.loadingOptions.isDisabled = true
addChangeRecord(this.form).then(response => {
if (response.success) {
this.$message.success('保存成功')
setTimeout(() => {
// 2秒后跳转列表页
this.$emit('showCard', this.showOptions)
}, 2000)
} else {
this.$message.error('保存失败')
this.loadingOptions.loading = false
this.loadingOptions.loadingText = '保存'
this.loadingOptions.isDisabled = false
}
}).catch(() => {
this.loadingOptions.loading = false
this.loadingOptions.loadingText = '保存'
this.loadingOptions.isDisabled = false
})
}
})
}
}
}
</script>
<style lang="scss" scoped>
.el-card ::v-deep .el-card__body {
height: calc(100vh - 230px);
overflow-y: auto;
}
</style>

View File

@@ -0,0 +1,127 @@
<template>
<el-card class="box-card" shadow="always">
<div slot="header" class="clearfix">
<span>{{ title }}</span>
<el-button-group style="float: right;">
<el-button size="mini" icon="el-icon-back" round @click="showCard">返回</el-button>
</el-button-group>
</div>
<div class="body-wrapper">
<el-form ref="form" :model="form" label-width="80px" disabled>
<el-form-item label="数据源" prop="sourceName">
<el-input v-model="form.sourceName" />
</el-form-item>
<el-form-item label="数据库表" prop="tableName">
<el-input v-model="form.tableName" />
</el-form-item>
<el-form-item label="变更字段" prop="fieldName">
<el-input v-model="form.fieldName" />
</el-form-item>
<el-form-item label="变更类型" prop="objectType">
<el-input v-model="objectType" />
</el-form-item>
<el-form-item label="版本号" prop="version">
<el-input v-model="form.version" />
</el-form-item>
<el-form-item label="原来的值" prop="fieldOldValue">
<el-input v-model="form.fieldOldValue" />
</el-form-item>
<el-form-item label="最新的值" prop="fieldNewValue">
<el-input v-model="form.fieldNewValue" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in statusOptions"
:key="dict.id"
:label="dict.itemText"
>{{ dict.itemValue }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" />
</el-form-item>
</el-form>
</div>
</el-card>
</template>
<script>
import { getChangeRecord } from '@/api/metadata/changerecord'
export default {
name: 'ChangeRecordDetail',
props: {
data: {
type: Object,
default: function() {
return {}
}
}
},
data() {
return {
title: '变更记录详情',
// 展示切换
showOptions: {
data: {},
showList: true,
showAdd: false,
showEdit: false,
showDetail: false
},
// 表单参数
form: {},
// 状态数据字典
statusOptions: [],
dicts: new Map([
['columnName', '字段名称'],
['columnComment', '字段注释'],
['dataDefault', '数据默认值'],
['columnKey', '是否主键'],
['columnNullable', '是否允许为空'],
['dataType', '数据类型'],
['dataLength', '数据长度'],
['dataPrecision', '数据精度'],
['dataScale', '数据小数位']
])
}
},
computed: {
objectType() {
return this.dicts.get(this.form.objectType)
}
},
created() {
console.log('id:' + this.data.id)
this.getDicts('sys_common_status').then(response => {
if (response.success) {
this.statusOptions = response.data
}
})
},
mounted() {
this.getChangeRecord(this.data.id)
},
methods: {
showCard() {
this.$emit('showCard', this.showOptions)
},
/** 获取详情 */
getChangeRecord: function(id) {
getChangeRecord(id).then(response => {
if (response.success) {
this.form = response.data
}
})
}
}
}
</script>
<style lang="scss" scoped>
.el-card ::v-deep .el-card__body {
height: calc(100vh - 230px);
overflow-y: auto;
}
</style>

View File

@@ -0,0 +1,180 @@
<template>
<el-card class="box-card" shadow="always">
<div slot="header" class="clearfix">
<span>{{ title }}</span>
<el-button-group style="float: right;">
<el-button v-hasPerm="['metadata:changerecord:edit']" size="mini" icon="el-icon-plus" round :loading="loadingOptions.loading" :disabled="loadingOptions.isDisabled" @click="submitForm">{{ loadingOptions.loadingText }}</el-button>
<el-button size="mini" icon="el-icon-back" round @click="showCard">返回</el-button>
</el-button-group>
</div>
<div class="body-wrapper">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="数据源" prop="sourceName">
<el-input v-model="form.sourceName" placeholder="请输入数据源" disabled />
</el-form-item>
<el-form-item label="数据库表" prop="tableName">
<el-input v-model="form.tableName" placeholder="请输入数据库表" disabled />
</el-form-item>
<el-form-item label="变更字段" prop="fieldName">
<el-input v-model="form.fieldName" placeholder="请输入变更字段" disabled />
</el-form-item>
<el-form-item label="变更类型" prop="fieldName">
<el-input v-model="objectType" placeholder="请输入变更类型" disabled />
</el-form-item>
<el-form-item label="版本号" prop="version">
<el-input v-model="form.version" placeholder="请输入版本号" />
</el-form-item>
<el-form-item label="原来的值" prop="fieldOldValue">
<el-input v-model="form.fieldOldValue" placeholder="请输入原来的值" disabled />
</el-form-item>
<el-form-item label="最新的值" prop="fieldNewValue">
<el-input v-model="form.fieldNewValue" placeholder="请输入最新的值" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in statusOptions"
:key="dict.id"
:label="dict.itemText"
>{{ dict.itemValue }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
</div>
</el-card>
</template>
<script>
import { getChangeRecord, updateChangeRecord } from '@/api/metadata/changerecord'
export default {
name: 'ChangeRecordEdit',
props: {
data: {
type: Object,
default: function() {
return {}
}
}
},
data() {
return {
title: '变更记录编辑',
// 展示切换
showOptions: {
data: {},
showList: true,
showAdd: false,
showEdit: false,
showDetail: false
},
// 保存按钮
loadingOptions: {
loading: false,
loadingText: '保存',
isDisabled: false
},
// 表单参数
form: {},
// 表单校验
rules: {
objectId: [
{ required: true, message: '源数据表主键不能为空', trigger: 'blur' }
],
fieldName: [
{ required: true, message: '数据表的字段名不能为空', trigger: 'blur' }
],
/* fieldOldValue: [
{ required: true, message: '原来的值不能为空', trigger: 'blur' }
], */
fieldNewValue: [
{ required: true, message: '最新的值不能为空', trigger: 'blur' }
],
version: [
{ required: true, message: '版本号不能为空', trigger: 'blur' }
]
},
// 状态数据字典
statusOptions: [],
dicts: new Map([
['columnName', '字段名称'],
['columnComment', '字段注释'],
['dataDefault', '数据默认值'],
['columnKey', '是否主键'],
['columnNullable', '是否允许为空'],
['dataType', '数据类型'],
['dataLength', '数据长度'],
['dataPrecision', '数据精度'],
['dataScale', '数据小数位']
])
}
},
computed: {
objectType() {
return this.dicts.get(this.form.objectType)
}
},
created() {
console.log('id:' + this.data.id)
this.getDicts('sys_common_status').then(response => {
if (response.success) {
this.statusOptions = response.data
}
})
},
mounted() {
this.getChangeRecord(this.data.id)
},
methods: {
showCard() {
this.$emit('showCard', this.showOptions)
},
/** 获取详情 */
getChangeRecord: function(id) {
getChangeRecord(id).then(response => {
if (response.success) {
this.form = response.data
}
})
},
/** 提交按钮 */
submitForm: function() {
this.$refs['form'].validate(valid => {
if (valid) {
this.loadingOptions.loading = true
this.loadingOptions.loadingText = '保存中...'
this.loadingOptions.isDisabled = true
updateChangeRecord(this.form).then(response => {
if (response.success) {
this.$message.success('保存成功')
setTimeout(() => {
// 2秒后跳转列表页
this.$emit('showCard', this.showOptions)
}, 2000)
} else {
this.$message.error('保存失败')
this.loadingOptions.loading = false
this.loadingOptions.loadingText = '保存'
this.loadingOptions.isDisabled = false
}
}).catch(() => {
this.loadingOptions.loading = false
this.loadingOptions.loadingText = '保存'
this.loadingOptions.isDisabled = false
})
}
})
}
}
}
</script>
<style lang="scss" scoped>
.el-card ::v-deep .el-card__body {
height: calc(100vh - 230px);
overflow-y: auto;
}
</style>

View File

@@ -0,0 +1,320 @@
<template>
<el-card class="box-card" shadow="always">
<el-form ref="queryForm" :model="queryParams" :inline="true">
<el-form-item label="字段名称" prop="fieldName">
<el-input
v-model="queryParams.fieldName"
placeholder="请输入字段名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row type="flex" justify="space-between">
<el-col :span="12">
<el-button-group />
</el-col>
<el-col :span="12">
<div class="right-toolbar">
<el-tooltip content="密度" effect="dark" placement="top">
<el-dropdown trigger="click" @command="handleCommand">
<el-button circle size="mini">
<svg-icon class-name="size-icon" icon-class="colum-height" />
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="medium">正常</el-dropdown-item>
<el-dropdown-item command="small">中等</el-dropdown-item>
<el-dropdown-item command="mini">紧凑</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-tooltip>
<el-tooltip content="刷新" effect="dark" placement="top">
<el-button circle size="mini" @click="handleRefresh">
<svg-icon class-name="size-icon" icon-class="shuaxin" />
</el-button>
</el-tooltip>
<el-tooltip content="列设置" effect="dark" placement="top">
<el-popover placement="bottom" width="100" trigger="click">
<el-checkbox-group v-model="checkedTableColumns" @change="handleCheckedColsChange">
<el-checkbox
v-for="(item, index) in tableColumns"
:key="index"
:label="item.prop"
>{{ item.label }}</el-checkbox>
</el-checkbox-group>
<span slot="reference">
<el-button circle size="mini">
<svg-icon class-name="size-icon" icon-class="shezhi" />
</el-button>
</span>
</el-popover>
</el-tooltip>
</div>
</el-col>
</el-row>
<el-table
v-loading="loading"
:data="changeRecordList"
border
tooltip-effect="dark"
:size="tableSize"
:height="tableHeight"
style="width: 100%;margin: 15px 0;"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" width="55" align="center">
<template slot-scope="scope">
<span>{{ scope.$index +1 }}</span>
</template>
</el-table-column>
<template v-for="(item, index) in tableColumns">
<el-table-column
v-if="item.show"
:key="index"
:prop="item.prop"
:label="item.label"
:formatter="item.formatter"
align="center"
show-overflow-tooltip
/>
</template>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-popover
placement="left"
trigger="click"
>
<el-button
v-hasPerm="['metadata:changerecord:edit']"
size="mini"
type="text"
icon="el-icon-edit-outline"
@click="handleEdit(scope.row)"
>修改</el-button>
<el-button
v-hasPerm="['metadata:changerecord:detail']"
size="mini"
type="text"
icon="el-icon-view"
@click="handleDetail(scope.row)"
>详情</el-button>
<el-button
v-hasPerm="['metadata:changerecord:remove']"
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除</el-button>
<el-button slot="reference">操作</el-button>
</el-popover>
</template>
</el-table-column>
</el-table>
<el-pagination
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:current-page.sync="queryParams.pageNum"
:page-size.sync="queryParams.pageSize"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-card>
</template>
<script>
import { pageChangeRecord, delChangeRecord } from '@/api/metadata/changerecord'
export default {
name: 'ChangeRecordList',
data() {
return {
tableHeight: document.body.offsetHeight - 310 + 'px',
// 展示切换
showOptions: {
data: {},
showList: true,
showAdd: false,
showEdit: false,
showDetail: false
},
// 遮罩层
loading: true,
// 表格头
tableColumns: [
{ prop: 'sourceName', label: '数据源', show: true },
{ prop: 'tableName', label: '数据库表', show: true },
{ prop: 'fieldName', label: '变更字段', show: true },
{ prop: 'objectType', label: '变更类型', show: true, formatter: this.fieldNameFormatter },
{ prop: 'fieldOldValue', label: '原来的值', show: true },
{ prop: 'fieldNewValue', label: '最新的值', show: true },
{ prop: 'version', label: '版本号', show: true },
{
prop: 'status',
label: '状态',
show: true,
formatter: this.statusFormatter
},
{ prop: 'createTime', label: '创建时间', show: true }
],
// 默认选择中表格头
checkedTableColumns: [],
tableSize: 'medium',
// 状态数据字典
statusOptions: [],
// 表格数据
changeRecordList: [],
// 总数据条数
total: 0,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 20,
fieldName: ''
},
dicts: new Map([
['columnName', '字段名称'],
['columnComment', '字段注释'],
['dataDefault', '数据默认值'],
['columnKey', '是否主键'],
['columnNullable', '是否允许为空'],
['dataType', '数据类型'],
['dataLength', '数据长度'],
['dataPrecision', '数据精度'],
['dataScale', '数据小数位']
])
}
},
created() {
this.getDicts('sys_common_status').then(response => {
if (response.success) {
this.statusOptions = response.data
}
})
this.getList()
},
mounted() {
this.initCols()
},
methods: {
/** 查询数据源列表 */
getList() {
this.loading = true
pageChangeRecord(this.queryParams).then(response => {
this.loading = false
if (response.success) {
const { data } = response
this.changeRecordList = data.data
this.total = data.total
}
})
},
initCols() {
this.checkedTableColumns = this.tableColumns.map(col => col.prop)
},
handleCheckedColsChange(val) {
this.tableColumns.forEach(col => {
if (!this.checkedTableColumns.includes(col.prop)) {
col.show = false
} else {
col.show = true
}
})
},
handleCommand(command) {
this.tableSize = command
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.queryParams = {
pageNum: 1,
pageSize: 20,
fieldName: ''
}
this.handleQuery()
},
/** 刷新列表 */
handleRefresh() {
this.getList()
},
/** 修改按钮操作 */
handleEdit(row) {
this.showOptions.data.id = row.id
this.showOptions.showList = false
this.showOptions.showAdd = false
this.showOptions.showEdit = true
this.showOptions.showDetail = false
this.$emit('showCard', this.showOptions)
},
/** 详情按钮操作 */
handleDetail(row) {
this.showOptions.data.id = row.id
this.showOptions.showList = false
this.showOptions.showAdd = false
this.showOptions.showEdit = false
this.showOptions.showDetail = true
this.$emit('showCard', this.showOptions)
},
/** 删除按钮操作 */
handleDelete(row) {
this.$confirm('选中数据将被永久删除, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delChangeRecord(row.id).then(response => {
if (response.success) {
this.$message.success('删除成功')
this.getList()
}
})
}).catch(() => {
})
},
handleSizeChange(val) {
console.log(`每页 ${val}`)
this.queryParams.pageNum = 1
this.queryParams.pageSize = val
this.getList()
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`)
this.queryParams.pageNum = val
this.getList()
},
statusFormatter(row, column, cellValue, index) {
const dictLabel = this.selectDictLabel(this.statusOptions, cellValue)
if (cellValue === '1') {
return <el-tag type='success'>{dictLabel}</el-tag>
} else {
return <el-tag type='warning'>{dictLabel}</el-tag>
}
},
fieldNameFormatter(row, column, cellValue, index) {
return this.dicts.get(cellValue)
}
}
}
</script>
<style lang="scss" scoped>
.right-toolbar {
float: right;
}
.el-card ::v-deep .el-card__body {
height: calc(100vh - 170px);
}
</style>

View File

@@ -0,0 +1,48 @@
<template>
<div class="app-container">
<transition name="el-zoom-in-center">
<change-record-list v-if="options.showList" @showCard="showCard" />
</transition>
<transition name="el-zoom-in-top">
<change-record-add v-if="options.showAdd" :data="options.data" @showCard="showCard" />
</transition>
<transition name="el-zoom-in-top">
<change-record-edit v-if="options.showEdit" :data="options.data" @showCard="showCard" />
</transition>
<transition name="el-zoom-in-bottom">
<change-record-detail v-if="options.showDetail" :data="options.data" @showCard="showCard" />
</transition>
</div>
</template>
<script>
import ChangeRecordList from './ChangeRecordList'
import ChangeRecordAdd from './ChangeRecordAdd'
import ChangeRecordEdit from './ChangeRecordEdit'
import ChangeRecordDetail from './ChangeRecordDetail'
export default {
name: 'ChangeRecord',
components: { ChangeRecordList, ChangeRecordAdd, ChangeRecordEdit, ChangeRecordDetail },
data() {
return {
options: {
data: {},
showList: true,
showAdd: false,
showEdit: false,
showDetail: false
}
}
},
methods: {
showCard(data) {
Object.assign(this.options, data)
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,197 @@
<template>
<div class="app-container">
<el-row :gutter="20">
<el-col :span="6">
<el-card class="box-card tree-wrapper" shadow="always">
<el-tree
ref="leftTree"
:data="leftTreeOptions"
node-key="id"
empty-text="加载中请稍后"
:props="leftTreeDefaultProps"
default-expand-all
highlight-current
:expand-on-click-node="false"
@node-click="handleNodeClick"
>
<span slot-scope="{ node, data }" class="custom-tree-node">
<span><i v-if="node.level === 1" class="iconfont icon-zuzhi tree-folder" />{{ node.label }}</span>
</span>
</el-tree>
</el-card>
</el-col>
<el-col :span="18">
<el-card class="box-card tree-wrapper" shadow="always">
<el-row type="flex" justify="space-between">
<el-col :span="12">
<el-button-group>
<el-button
v-hasPerm="['metadata:dataauthorize:refresh']"
type="warning"
icon="el-icon-refresh"
size="mini"
@click="handleCacheRefresh"
>刷新缓存</el-button>
</el-button-group>
</el-col>
<el-col :span="12">
<el-button-group style="float: right;">
<template v-if="showBtns">
<el-button v-if="disabled" v-hasPerm="['metadata:dataauthorize:edit']" size="mini" round @click="disabled = false">修改</el-button>
<el-button v-else v-hasPerm="['metadata:dataauthorize:edit']" size="mini" round @click="handSubmit">保存</el-button>
</template>
</el-button-group>
</el-col>
</el-row>
<el-divider />
<el-form ref="form" :model="form" :disabled="disabled">
<el-tree
ref="rightTree"
:data="rightTreeOptions"
show-checkbox
accordion
node-key="id"
empty-text="加载中请稍后"
:props="rightTreeDefaultProps"
highlight-current
:expand-on-click-node="false"
:check-strictly="checkStrictly"
>
<span slot-scope="{ node, data }" class="custom-tree-node">
<span>
<i v-if="node.level === 1" class="iconfont icon-shujuku tree-folder" />
<i v-else-if="node.level === 2" class="iconfont icon-shujubiao tree-folder" />
<i v-else-if="node.level === 3" class="iconfont icon-shujuziduan tree-folder" />
{{ data.code ? (data.name ? data.code + '(' + data.name + ')' : data.code) : data.name }}
</span>
</span>
</el-tree>
</el-form>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import { listRole } from '@/api/systemMarket/role'
import { getDataMetadataTree } from '@/api/metadata/datacolumn'
import { getAuthorizedMetadata, metadataAuthorize, refreshAuthorize } from '@/api/metadata/dataauthorize'
export default {
name: 'DataAuthorize',
data() {
return {
tableHeight: document.body.offsetHeight - 310 + 'px',
// 左侧树
leftTreeOptions: [],
leftTreeDefaultProps: {
children: 'children',
label: 'roleName'
},
// 右侧树
rightTreeOptions: [],
rightTreeDefaultProps: {
children: 'children',
label: 'label'
},
checkStrictly: false,
form: {},
disabled: true,
showBtns: false,
btnSubmitEnable: false
}
},
created() {
this.getLeftTree()
this.getRightTree()
},
methods: {
getLeftTree() {
listRole().then(response => {
if (response.success) {
const { data } = response
const tree = {}
tree.roleName = '角色组'
tree.children = data
this.leftTreeOptions = []
this.leftTreeOptions.push(tree)
}
})
},
handleNodeClick(data) {
if (data.id) {
this.form.roleId = data.id
getAuthorizedMetadata(data.id).then(response => {
if (response.success) {
this.$refs.rightTree.setCheckedKeys([])
const checkedKeys = response.data || []
if (checkedKeys && checkedKeys.length > 0) {
this.checkStrictly = true
this.$nextTick(() => {
this.$refs.rightTree.setCheckedKeys(checkedKeys)
this.checkStrictly = false
})
}
this.showBtns = true
}
})
}
},
getRightTree() {
getDataMetadataTree('column').then(response => {
if (response.success) {
const { data } = response
this.rightTreeOptions = data
}
})
},
handSubmit() {
const data = []
const checkedNodes = this.$refs.rightTree.getCheckedNodes(false, true)
checkedNodes.forEach((item, index, arr) => {
const obj = {}
obj.objectId = item.id
obj.roleId = this.form.roleId
obj.objectType = item.type
data.push(obj)
})
metadataAuthorize({ roleId: this.form.roleId, authorizeDataList: data }).then(response => {
if (response.success) {
this.$message.success('保存成功')
this.disabled = true
}
})
},
handleCacheRefresh() {
refreshAuthorize().then(response => {
if (response.success) {
this.$message.success('刷新缓存成功')
} else {
this.$message.error('刷新缓存失败')
}
})
}
}
}
</script>
<style lang="scss" scoped>
.el-card ::v-deep .el-card__body {
height: calc(100vh - 170px);
}
.tree-wrapper {
overflow-y: auto;
::v-deep .custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
.tree-folder {
margin-right: 5px;
color: #f6cf07;
}
}
}
</style>

View File

@@ -0,0 +1,151 @@
<template>
<div class="app-container">
<el-card class="box-card" shadow="always">
<el-row>
<el-col :span="24">
<el-form ref="queryForm" :model="queryParams" :inline="true" class="demo-form-inline">
<el-form-item label="数据表名">
<el-input
v-model="queryParams.tableName"
placeholder="请输入数据表名"
clearable
size="small"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery">查询</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-table
:data="tableDataList"
stripe
border
:max-height="200"
style="width: 100%; margin: 15px 0;"
>
<el-table-column prop="subjectArea" label="数据主题域" align="center" show-overflow-tooltip />
<el-table-column prop="mappingName" label="映射名称" align="center" show-overflow-tooltip />
<el-table-column prop="sourceTable" label="源表" align="center" show-overflow-tooltip />
<el-table-column prop="targetTable" label="目标表" align="center" show-overflow-tooltip />
</el-table>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<div id="chart" style="width: 100%; height: 300px;" />
</el-col>
</el-row>
</el-card>
</div>
</template>
<script>
import echarts from 'echarts'
export default {
name: 'DataBlood',
data: function() {
return {
queryParams: {
tableName: ''
},
chart: null,
tableDataList: []
}
},
created() {
},
mounted() {
this.chart = echarts.init(document.getElementById('chart'))
},
beforeDestroy() {
if (!this.chart) {
return false
}
this.chart.dispose()
this.chart = null
},
methods: {
handleQuery() {
this.tableDataList = [
{ subjectArea: 'DataCenter', mappingName: 'm_ts_test_table_inc', sourceTable: 'src_test_table', targetTable: 'ts_test_table' },
{ subjectArea: 'DataCenter', mappingName: 'm_ts_test_table_inc', sourceTable: 'ts_test_table', targetTable: 'th_test_table' },
{ subjectArea: 'DataCenter', mappingName: 'm_ts_test_table_inc', sourceTable: 'ts_test_table', targetTable: 'ti_test_table' },
{ subjectArea: 'DataCenter', mappingName: 'm_ods_test_table_inc', sourceTable: 'ti_test_table', targetTable: 't_test_table' }
]
let data = { nodes: [], links: [] }
const nodes = []
const links = []
const colors = ['#fbb4ae', '#b3cde3', '#ccebc5', '#decbe4']
this.tableDataList.forEach(item => {
nodes.push({
name: item.sourceTable,
itemStyle: {
normal: {
color: colors[Math.floor(Math.random() * colors.length)]
}
}
})
nodes.push({
name: item.targetTable,
itemStyle: {
normal: {
color: colors[Math.floor(Math.random() * colors.length)]
}
}
})
links.push({
source: item.sourceTable,
target: item.targetTable,
value: item.mappingName.length,
mapping: item.mappingName
})
})
// nodes数组去重
const res = new Map()
const nodes_uniq = nodes.filter((node) => !res.has(node.name) && res.set(node.name, 1))
data = {
nodes: nodes_uniq,
links: links
}
this.chart.clear()
this.chart.setOption({
title: {
text: '血缘流向'
},
tooltip: {
trigger: 'item',
triggerOn: 'mousemove',
formatter: function(x) {
return x.data.mapping
}
},
animation: false,
series: [
{
type: 'sankey',
focusNodeAdjacency: 'allEdges',
nodeAlign: 'left',
data: data.nodes,
links: data.links,
lineStyle: {
color: 'source',
curveness: 0.5
}
}
]
})
}
}
}
</script>
<style lang="scss" scoped>
.el-card ::v-deep .el-card__body {
height: calc(100vh - 170px);
}
</style>

View File

@@ -0,0 +1,300 @@
<template>
<el-card class="box-card" shadow="always">
<div slot="header" class="clearfix">
<span>{{ title }}</span>
<el-button-group style="float: right;">
<el-button size="mini" icon="el-icon-back" round @click="showCard">返回</el-button>
</el-button-group>
</div>
<div class="body-wrapper">
<el-form ref="form" :model="form" label-width="100px" size="mini">
<el-row>
<el-col :span="8">
<el-form-item label="字段名称" prop="columnName">
<el-input v-model="form.columnName" disabled>
<el-button slot="append" v-hasPerm="['metadata:changerecord:add']" icon="el-icon-edit-outline" @click="changeRecord('columnName')" />
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="字段注释" prop="columnComment">
<el-input v-model="form.columnComment" disabled>
<el-button slot="append" v-hasPerm="['metadata:changerecord:add']" icon="el-icon-edit-outline" @click="changeRecord('columnComment')" />
</el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="数据默认值" prop="dataDefault">
<el-input v-model="form.dataDefault" disabled>
<el-button slot="append" v-hasPerm="['metadata:changerecord:add']" icon="el-icon-edit-outline" @click="changeRecord('dataDefault')" />
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="是否主键" prop="columnKey">
<el-input v-model="form.columnKey === '1' ? 'Y' : 'N'" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="是否允许为空" prop="columnNullable">
<el-input v-model="form.columnNullable === '1' ? 'Y' : 'N'" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="数据类型" prop="dataType">
<el-input v-model="form.dataType" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="数据长度" prop="dataLength">
<el-input v-model="form.dataLength" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="数据精度" prop="dataPrecision">
<el-input v-model="form.dataPrecision" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="数据小数位" prop="dataScale">
<el-input v-model="form.dataScale" disabled />
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-divider content-position="center">变更记录</el-divider>
<el-row>
<el-col :span="24">
<el-table
:data="changeData.dataList"
stripe
border
:max-height="200"
style="width: 100%; margin: 15px 0;"
>
<el-table-column label="序号" align="center">
<template slot-scope="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column prop="sourceName" label="数据源" align="center" show-overflow-tooltip />
<el-table-column prop="tableName" label="数据库表" align="center" show-overflow-tooltip />
<el-table-column prop="fieldName" label="变更字段" align="center" show-overflow-tooltip />
<el-table-column prop="objectType" label="变更类型" align="center" show-overflow-tooltip :formatter="fieldNameFormatter" />
<el-table-column prop="version" label="版本号" align="center" show-overflow-tooltip />
<el-table-column prop="fieldOldValue" label="原来的值" align="center" show-overflow-tooltip />
<el-table-column prop="fieldNewValue" label="最新的值" align="center" show-overflow-tooltip />
</el-table>
<el-pagination
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:current-page.sync="changeData.pageNum"
:page-size.sync="changeData.pageSize"
:total="changeData.dataTotal"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-col>
</el-row>
</div>
<!-- 变更弹框 -->
<el-dialog :title="record.title" :visible.sync="record.open" min-width="600px" append-to-body>
<el-form ref="form2" :model="form2" :rules="rules2" label-width="80px">
<el-form-item label="变更类型" prop="objectTypeStr">
<el-input v-model="form2.objectTypeStr" placeholder="请输入变更字段" :disabled="true" />
</el-form-item>
<el-form-item label="字段名称" prop="fieldName">
<el-input v-model="form2.fieldName" placeholder="请输入版本号" :disabled="true" />
</el-form-item>
<el-form-item label="版本号" prop="version">
<el-input v-model="form2.version" placeholder="请输入版本号" />
</el-form-item>
<el-form-item label="原来的值" prop="fieldOldValue">
<el-input v-model="form2.fieldOldValue" placeholder="请输入原来的值" :disabled="true" />
</el-form-item>
<el-form-item label="最新的值" prop="fieldNewValue">
<el-input v-model="form2.fieldNewValue" placeholder="请输入最新的值" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form2.status">
<el-radio
v-for="dict in statusOptions"
:key="dict.id"
:label="dict.itemText"
>{{ dict.itemValue }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form2.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitRecordForm"> </el-button>
<el-button @click="record.open = false"> </el-button>
</div>
</el-dialog>
</el-card>
</template>
<script>
import { getDataColumn } from '@/api/metadata/datacolumn'
import { pageChangeRecord, addChangeRecord } from '@/api/metadata/changerecord'
export default {
name: 'DataColumnDetail',
props: {
data: {
type: Object,
default: function() {
return {}
}
}
},
data() {
return {
title: '元数据详情(注意:此处变更元数据信息只会保存变更记录,不会真正修改元数据,只是辅助记录作用!)',
// 展示切换
showOptions: {
data: {},
showList: true,
showDetail: false
},
// 表单参数
form: {},
changeData: {
dataList: [],
pageNum: 1,
pageSize: 20,
dataTotal: 0
},
dicts: new Map([
['columnName', '字段名称'],
['columnComment', '字段注释'],
['dataDefault', '数据默认值'],
['columnKey', '是否主键'],
['columnNullable', '是否允许为空'],
['dataType', '数据类型'],
['dataLength', '数据长度'],
['dataPrecision', '数据精度'],
['dataScale', '数据小数位']
]),
record: {
// 是否显示弹出层
open: false,
// 弹出层标题
title: '元数据变更'
},
form2: {
status: '1'
},
rules2: {
fieldName: [
{ required: true, message: '字段名称不能为空', trigger: 'blur' }
],
objectTypeStr: [
{ required: true, message: '变更类型不能为空', trigger: 'blur' }
],
// zrx
/* fieldOldValue: [
{ required: true, message: '原来的值不能为空', trigger: 'blur' }
], */
fieldNewValue: [
{ required: true, message: '最新的值不能为空', trigger: 'blur' }
],
version: [
{ required: true, message: '版本号不能为空', trigger: 'blur' }
]
},
// 状态数据字典
statusOptions: []
}
},
created() {
console.log('id:' + this.data.id)
this.getDicts('sys_common_status').then(response => {
if (response.success) {
this.statusOptions = response.data
}
})
},
mounted() {
this.getDataColumn(this.data.id)
this.getChangeRecordList()
},
methods: {
showCard() {
this.$emit('showCard', this.showOptions)
},
/** 获取详情 */
getDataColumn: function(id) {
getDataColumn(id).then(response => {
if (response.success) {
this.form = response.data
}
})
},
handleSizeChange(val) {
this.changeData.pageNum = 1
this.changeData.pageSize = val
this.getChangeRecordList()
},
handleCurrentChange(val) {
this.changeData.pageNum = val
this.getChangeRecordList()
},
getChangeRecordList() {
const data = {}
data.objectId = this.data.id
data.pageNum = this.changeData.pageNum
data.pageSize = this.changeData.pageSize
pageChangeRecord(data).then(response => {
if (response.success) {
const { data } = response
this.changeData.dataList = data.data
this.changeData.dataTotal = data.total
}
})
},
fieldNameFormatter(row, column, cellValue, index) {
return this.dicts.get(cellValue)
},
changeRecord(field) {
this.record.open = true
this.form2.objectId = this.data.id
console.log(this.form)
this.form2.objectType = field
this.form2.objectTypeStr = this.dicts.get(field)
this.form2.fieldName = this.form.columnName
this.form2.fieldOldValue = this.form[field]
console.log(this.form2)
},
submitRecordForm() {
this.$refs['form2'].validate(valid => {
if (valid) {
addChangeRecord(this.form2).then(response => {
if (response.success) {
this.$message.success('保存成功(变更记录只会保存记录,并不会真正去变更元数据!)')
this.getChangeRecordList()
} else {
this.$message.error('保存失败')
}
this.record.open = false
})
}
})
}
}
}
</script>
<style lang="scss" scoped>
.el-card ::v-deep .el-card__body {
height: calc(100vh - 230px);
overflow-y: auto;
}
</style>

View File

@@ -0,0 +1,334 @@
<template>
<el-row :gutter="20">
<el-col :span="6">
<el-card class="box-card tree-wrapper" shadow="always">
<el-tree
ref="tree"
:data="treeOptions"
node-key="id"
empty-text="加载中请稍后"
:props="defaultProps"
default-expand-all
highlight-current
:expand-on-click-node="false"
@node-click="handleNodeClick"
>
<span slot-scope="{ node, data }" class="custom-tree-node">
<i v-if="node.level === 1" class="iconfont icon-shujuku" />
<i v-else-if="node.level === 2" class="iconfont icon-shujubiao" />
<span>{{ node.label }}</span>
</span>
</el-tree>
</el-card>
</el-col>
<el-col :span="18">
<el-card class="box-card" shadow="always">
<el-form ref="queryForm" :model="queryParams" :inline="true">
<el-form-item label="字段名称" prop="columnName">
<el-input
v-model="queryParams.columnName"
placeholder="请输入字段名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row type="flex" justify="space-between">
<el-col :span="12">
<el-button-group />
</el-col>
<el-col :span="12">
<div class="right-toolbar">
<el-tooltip content="密度" effect="dark" placement="top">
<el-dropdown trigger="click" @command="handleCommand">
<el-button circle size="mini">
<svg-icon class-name="size-icon" icon-class="colum-height" />
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="medium">正常</el-dropdown-item>
<el-dropdown-item command="small">中等</el-dropdown-item>
<el-dropdown-item command="mini">紧凑</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-tooltip>
<el-tooltip content="刷新" effect="dark" placement="top">
<el-button circle size="mini" @click="handleRefresh">
<svg-icon class-name="size-icon" icon-class="shuaxin" />
</el-button>
</el-tooltip>
<el-tooltip content="列设置" effect="dark" placement="top">
<el-popover placement="bottom" width="100" trigger="click">
<el-checkbox-group
v-model="checkedTableColumns"
@change="handleCheckedColsChange"
>
<el-checkbox
v-for="(item, index) in tableColumns"
:key="index"
:label="item.prop"
>{{ item.label }}</el-checkbox>
</el-checkbox-group>
<span slot="reference">
<el-button circle size="mini">
<svg-icon class-name="size-icon" icon-class="shezhi" />
</el-button>
</span>
</el-popover>
</el-tooltip>
</div>
</el-col>
</el-row>
<el-table
v-loading="loading"
:data="columnList"
border
tooltip-effect="dark"
:size="tableSize"
:height="tableHeight"
style="width: 100%;margin: 15px 0;"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" width="55" align="center">
<template slot-scope="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<template v-for="(item, index) in tableColumns">
<el-table-column
v-if="item.show"
:key="index"
:prop="item.prop"
:label="item.label"
:formatter="item.formatter"
align="center"
show-overflow-tooltip
/>
</template>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-popover
placement="left"
trigger="click"
>
<el-button
v-hasPerm="['metadata:datacolumn:detail']"
size="mini"
type="text"
icon="el-icon-view"
@click="handleDetail(scope.row)"
>详情</el-button>
<el-button slot="reference">操作</el-button>
</el-popover>
</template>
</el-table-column>
</el-table>
<el-pagination
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:current-page.sync="queryParams.pageNum"
:page-size.sync="queryParams.pageSize"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-card>
</el-col>
</el-row>
</template>
<script>
import { pageDataColumn, getDataMetadataTree } from '@/api/metadata/datacolumn'
export default {
name: 'DataColumnList',
data() {
return {
tableHeight: document.body.offsetHeight - 310 + 'px',
// 展示切换
showOptions: {
data: {},
showList: true,
showDetail: false
},
// 遮罩层
loading: true,
// 表格头
tableColumns: [
{ prop: 'columnName', label: '字段名称', show: true },
{ prop: 'columnComment', label: '字段注释', show: true },
{ prop: 'columnKey', label: '是否主键', show: true, formatter: this.keyFormatter },
{ prop: 'columnNullable', label: '是否允许为空', show: true, formatter: this.nullableFormatter },
{ prop: 'dataType', label: '数据类型', show: true },
{ prop: 'dataLength', label: '数据长度', show: true },
{ prop: 'dataPrecision', label: '数据精度', show: true },
{ prop: 'dataScale', label: '数据小数位', show: true },
{ prop: 'dataDefault', label: '数据默认值', show: true }
],
// 默认选择中表格头
checkedTableColumns: [],
tableSize: 'medium',
// 表格数据
columnList: [],
// 总数据条数
total: 0,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 20,
columnName: '',
sourceId: '',
tableId: ''
},
// 左侧树
treeOptions: [],
defaultProps: {
children: 'children',
label: 'label'
}
}
},
created() {
this.getList()
this.getTree()
},
mounted() {
this.initCols()
},
methods: {
/** 查询列表 */
getList() {
this.loading = true
pageDataColumn(this.queryParams).then(response => {
this.loading = false
if (response.success) {
const { data } = response
this.columnList = data.data
this.total = data.total
}
})
},
/** 查询树结构 */
getTree() {
getDataMetadataTree('table').then(response => {
if (response.success) {
const { data } = response
this.treeOptions = data
}
})
},
initCols() {
this.checkedTableColumns = this.tableColumns.map(col => col.prop)
},
handleCheckedColsChange(val) {
this.tableColumns.forEach(col => {
if (!this.checkedTableColumns.includes(col.prop)) {
col.show = false
} else {
col.show = true
}
})
},
handleCommand(command) {
this.tableSize = command
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.queryParams = {
pageNum: 1,
pageSize: 20,
columnName: '',
sourceId: '',
tableId: ''
}
this.handleQuery()
},
/** 刷新列表 */
handleRefresh() {
this.getList()
},
/** 详情按钮操作 */
handleDetail(row) {
this.showOptions.data.id = row.id
this.showOptions.showList = false
this.showOptions.showDetail = true
this.$emit('showCard', this.showOptions)
},
handleSizeChange(val) {
console.log(`每页 ${val}`)
this.queryParams.pageNum = 1
this.queryParams.pageSize = val
this.getList()
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`)
this.queryParams.pageNum = val
this.getList()
},
/** 节点单击事件 */
handleNodeClick(data) {
if (data.type === 'database') {
this.queryParams.sourceId = data.id
this.queryParams.tableId = ''
} else if (data.type === 'table') {
this.queryParams.tableId = data.id
this.queryParams.sourceId = ''
}
this.getList()
},
keyFormatter(row, column, cellValue, index) {
if (cellValue === '1') {
return 'Y'
} else {
return 'N'
}
},
nullableFormatter(row, column, cellValue, index) {
if (cellValue === '1') {
return 'Y'
} else {
return 'N'
}
}
}
}
</script>
<style lang="scss" scoped>
.right-toolbar {
float: right;
}
.el-card ::v-deep .el-card__body {
height: calc(100vh - 170px);
}
.tree-wrapper {
overflow-y: auto;
::v-deep .custom-tree-node {
flex: 1;
display: flex;
font-size: 14px;
i {
margin-right: 10px;
}
.icon-shujuku {
color: #20a0ff;
}
.icon-shujubiao {
color: #38dcec;
}
}
}
</style>

View File

@@ -0,0 +1,38 @@
<template>
<div class="app-container">
<transition name="el-zoom-in-center">
<data-column-list v-if="options.showList" @showCard="showCard" />
</transition>
<transition name="el-zoom-in-bottom">
<data-column-detail v-if="options.showDetail" :data="options.data" @showCard="showCard" />
</transition>
</div>
</template>
<script>
import DataColumnList from './DataColumnList'
import DataColumnDetail from './DataColumnDetail'
export default {
name: 'DataColumn',
components: { DataColumnList, DataColumnDetail },
data() {
return {
options: {
data: {},
showList: true,
showDetail: false
}
}
},
methods: {
showCard(data) {
Object.assign(this.options, data)
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,460 @@
<template>
<div class="app-container">
<el-card class="box-card" shadow="always">
<div class="body-wrapper">
<el-form :inline="true" :model="searchForm">
<el-form-item label="数据库">
<el-select v-model="searchForm.sourceId" placeholder="数据库">
<el-option
v-for="item in sourceOptions"
:key="item.id"
:label="item.sourceName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="数据表">
<el-select v-model="searchForm.tableId" clearable placeholder="数据表">
<el-option
v-for="item in tableOptions"
:key="item.id"
:label="item.tableComment ? item.tableComment : item.tableName"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" :disabled="btnEnable" @click="onSubmit">查询</el-button>
</el-form-item>
</el-form>
<el-divider />
<div id="chart" :style="{width: '100%', height: 'calc(100vh - 300px)'}" />
</div>
</el-card>
</div>
</template>
<script>
import { listDataSource } from '@/api/metadata/datasource'
import { listDataTable } from '@/api/metadata/datatable'
import { getDataMetadataTree } from '@/api/metadata/datacolumn'
import echarts from 'echarts'
export default {
name: 'DataMap',
data: function() {
return {
searchForm: {
sourceId: '',
tableId: ''
},
btnEnable: true,
sourceOptions: [],
tableOptions: [],
treeData: [],
chart: null,
chartList: [],
chartLinks: [],
chartLegend: [],
colors: [{
c1: '#00c7ef',
c2: '#0AF3FF'
},
{
c1: '#FF8E14',
c2: '#FFA12F'
},
{
c1: '#AF5AFF',
c2: '#B62AFF'
},
{
c1: '#25dd59',
c2: '#29f463'
},
{
c1: '#6E35FF',
c2: '#6E67FF'
},
{
c1: '#002AFF',
c2: '#0048FF'
},
{
c1: '#8CD282',
c2: '#95F300'
},
{
c1: '#3B0EFF',
c2: '#604BFF'
},
{
c1: '#00BE74',
c2: '#04FDB8'
},
{
c1: '#4a3ac6',
c2: '#604BFF'
}
]
}
},
watch: {
'searchForm.sourceId': {
immediate: true,
// handler:是一个回调函数,即监听到变化应该执行的函数
handler(value) {
if (value) {
// 清空数据
this.searchForm.tableId = ''
this.getDataTableList(value)
this.btnEnable = false
}
}
}
},
created() {
this.getDataSourceList()
},
mounted() {
this.chart = echarts.init(document.getElementById('chart'))
},
beforeDestroy() {
if (!this.chart) {
return false
}
this.chart.dispose()
this.chart = null
},
methods: {
getDataSourceList() {
listDataSource().then(response => {
if (response.success) {
this.sourceOptions = response.data
}
})
},
getDataTableList(sourceId) {
const data = {}
data.sourceId = sourceId
listDataTable(data).then(response => {
if (response.success) {
this.tableOptions = response.data
}
})
},
onSubmit() {
getDataMetadataTree('column', { sourceId: this.searchForm.sourceId, tableId: this.searchForm.tableId }).then(response => {
if (response.success) {
const { data } = response
this.treeData = data
this.initChart()
}
})
},
handleList(arr, idx, color, category) {
arr.forEach((item, index) => {
if (item.label === null) {
return false
}
// 设置节点大小
let symbolSize = 10
switch (idx) {
case 0:
symbolSize = 70
break
case 1:
symbolSize = 50
break
default:
symbolSize = 10
break
}
// 每个节点所对应的文本标签的样式
let label = null
switch (idx) {
case 0:
case 1:
label = {
position: 'inside',
rotate: 0
}
break
default:
break
}
// 计算出颜色,从第二级开始
if (idx === 0) {
color = this.colors[0]
}
if (idx === 1) {
color = this.colors.find((itemm, eq) => eq === index % 10)
this.chartLegend.push(item.label)
}
// 设置线条颜色
const lineStyle = {
color: color.c2
}
// 设置节点样式
let bgcolor = null
if (idx === 0) {
bgcolor = {
type: 'radial',
x: 0.5,
y: 0.5,
r: 0.5,
colorStops: [{
offset: 0,
color: color.c1 // 0% 处的颜色
},
{
offset: 0.8,
color: color.c1 // 80% 处的颜色
},
{
offset: 1,
color: 'rgba(0, 0, 0, 0.3)' // 100% 处的颜色
}
],
global: false
}
} else {
bgcolor = {
type: 'radial',
x: 0.5,
y: 0.5,
r: 0.5,
colorStops: [{
offset: 0,
// 0% 处的颜色
color: color.c1
},
{
offset: 0.4,
// 0% 处的颜色
color: color.c1
},
{
offset: 1,
// 100% 处的颜色
color: color.c2
}
],
global: false
}
}
let itemStyle = null
if (item.children && item.children.length !== 0) {
// 非子节点
itemStyle = {
borderColor: color.c2,
color: bgcolor
}
} else {
// 子节点
item.isEnd = true
if (item.isdisease === 'true') {
itemStyle = {
color: color.c2,
borderColor: color.c2
}
} else {
itemStyle = {
color: 'transparent',
borderColor: color.c2
}
}
}
// 可以改变来实现节点发光效果,但体验不好
itemStyle = Object.assign(itemStyle, {
shadowColor: 'rgba(255, 255, 255, 0.5)',
shadowBlur: 10
})
if (idx === 1) {
category = item.label
}
let obj = {
name: item.label,
symbolSize: symbolSize,
category: category,
label,
color: bgcolor,
itemStyle,
lineStyle
}
obj = Object.assign(item, obj)
if (idx === 0) {
obj = Object.assign(obj, {
root: true
})
}
if (item.children && item.children.length === 0) {
obj = Object.assign(obj, {
isEnd: true
})
}
this.chartList.push(obj)
if (item.children && item.children.length > 0) {
this.handleList(item.children, idx + 1, color, category)
}
})
},
handleLink(arr, idx, color) {
arr.forEach(item => {
if (item.children) {
item.children.forEach((item2, eq) => {
if (idx === 0) {
color = this.colors.find((itemm, eq2) => eq2 === eq % 10)
}
let lineStyle = null
switch (idx) {
case 0:
if (item2.children.length > 0) {
lineStyle = {
normal: {
color: 'target'
}
}
} else {
lineStyle = {
normal: {
color: color.c2
}
}
}
break
default:
lineStyle = {
normal: {
color: 'source'
}
}
break
}
const obj = {
source: item.id,
target: item2.id,
lineStyle
}
this.chartLinks.push(obj)
if (item2.children && item.children.length > 0) {
this.handleLink(item.children, idx + 1)
}
})
}
})
},
initChart() {
this.chart.showLoading()
this.chartList = []
this.chartLinks = []
this.chartLegend = []
// 获取表名
const categories = this.treeData[0].children.map(item => {
return {
name: item.label
}
})
// 计算list
this.handleList(JSON.parse(JSON.stringify(this.treeData)), 0)
// 计算links
this.handleLink(JSON.parse(JSON.stringify(this.treeData)), 0)
// 绘制图表
const option = {
backgroundColor: '#000',
toolbox: {
show: true,
left: 'right',
right: 20,
top: 'bottom',
bottom: 20
},
legend: {
show: true,
data: this.chartLegend,
textStyle: {
color: '#fff',
fontSize: 10
},
icon: 'circle',
type: 'scroll',
orient: 'vertical',
left: 'right',
right: 20,
top: 20,
bottom: 80,
pageIconColor: '#00f6ff',
pageIconInactiveColor: '#fff',
pageIconSize: 12,
pageTextStyle: {
color: '#fff',
fontSize: 12
}
},
selectedMode: 'false',
bottom: 20,
left: 0,
right: 0,
top: 0,
animationDuration: 1500,
animationEasingUpdate: 'quinticInOut',
series: [{
name: '数据地图',
type: 'graph',
hoverAnimation: true,
layout: 'force',
force: {
repulsion: 300,
edgeLength: 100
},
nodeScaleRatio: 0.6,
draggable: true,
roam: true,
symbol: 'circle',
data: this.chartList,
links: this.chartLinks,
categories: categories,
focusNodeAdjacency: true,
scaleLimit: {
// 所属组件的z分层z值小的图形会被z值大的图形覆盖
// 最小的缩放值
min: 0.5,
// 最大的缩放值
max: 9
},
edgeSymbol: ['circle', 'arrow'],
edgeSymbolSize: [4, 8],
label: {
normal: {
show: true,
position: 'right',
color: '#fff',
distance: 5,
fontSize: 10
}
},
lineStyle: {
normal: {
width: 1.5,
curveness: 0,
type: 'solid'
}
}
}]
}
this.chart.setOption(option)
this.chart.hideLoading()
}
}
}
</script>
<style lang="scss" scoped>
.el-card ::v-deep .el-card__body {
height: calc(100vh - 170px);
}
::v-deep .el-divider {
margin: 0;
}
</style>

View File

@@ -0,0 +1,55 @@
<template>
<ul class="list-group">
<li v-for="(item, index) in data" :key="index" class="list-group-item">
<span class="list-group-item-heading">{{ item.columnName }}({{ item.columnComment }})</span>
<p class="list-group-item-text">数据源: {{ item.sourceName }} 数据表: {{ item.tableName }}({{ item.tableComment }})</p>
</li>
</ul>
</template>
<script>
export default {
name: 'ColumnPane',
props: {
data: {
type: Array,
default: function() {
return []
}
}
}
}
</script>
<style lang="scss" scoped>
.list-group {
margin-bottom: 20px;
padding-left: 0;
.list-group-item {
position: relative;
display: block;
padding: 10px 15px;
margin-bottom: -1px;
background-color: #fff;
border: 1px solid #ddd;
&:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
&:last-child {
margin-bottom: 0;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.list-group-item-heading {
margin-top: 0;
margin-bottom: 5px;
}
.list-group-item-text {
margin-bottom: 0;
line-height: 1.3;
font-size: 14px;
}
}
}
</style>

View File

@@ -0,0 +1,54 @@
<template>
<ul class="list-group">
<li v-for="(item, index) in data" :key="index" class="list-group-item">
<span class="list-group-item-heading">{{ item.sourceName }}</span>
</li>
</ul>
</template>
<script>
export default {
name: 'SourcePane',
props: {
data: {
type: Array,
default: function() {
return []
}
}
}
}
</script>
<style lang="scss" scoped>
.list-group {
margin-bottom: 20px;
padding-left: 0;
.list-group-item {
position: relative;
display: block;
padding: 10px 15px;
margin-bottom: -1px;
background-color: #fff;
border: 1px solid #ddd;
&:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
&:last-child {
margin-bottom: 0;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.list-group-item-heading {
margin-top: 0;
margin-bottom: 5px;
}
.list-group-item-text {
margin-bottom: 0;
line-height: 1.3;
font-size: 14px;
}
}
}
</style>

View File

@@ -0,0 +1,55 @@
<template>
<ul class="list-group">
<li v-for="(item, index) in data" :key="index" class="list-group-item">
<span class="list-group-item-heading">{{ item.tableName }}({{ item.tableComment }})</span>
<p class="list-group-item-text">数据源: {{ item.sourceName }}</p>
</li>
</ul>
</template>
<script>
export default {
name: 'TablePane',
props: {
data: {
type: Array,
default: function() {
return []
}
}
}
}
</script>
<style lang="scss" scoped>
.list-group {
margin-bottom: 20px;
padding-left: 0;
.list-group-item {
position: relative;
display: block;
padding: 10px 15px;
margin-bottom: -1px;
background-color: #fff;
border: 1px solid #ddd;
&:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
&:last-child {
margin-bottom: 0;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.list-group-item-heading {
margin-top: 0;
margin-bottom: 5px;
}
.list-group-item-text {
margin-bottom: 0;
line-height: 1.3;
font-size: 14px;
}
}
}
</style>

View File

@@ -0,0 +1,166 @@
<template>
<div class="app-container">
<el-card class="box-card" shadow="always">
<div class="body-wrapper">
<div v-if="searchExecuting">
<el-row>
<el-col :span="12" :offset="6">
<el-input v-model="keyword" placeholder="请输入内容">
<el-select slot="prepend" v-model="type" placeholder="请选择" style="width: 100px;" @change="typeSelectChanged">
<el-option label="数据库" value="1" />
<el-option label="数据表" value="2" />
<el-option label="数据元" value="3" />
</el-select>
<el-button slot="append" :disabled="btnEnable" icon="el-icon-search" @click="search" />
</el-input>
</el-col>
</el-row>
<el-divider />
<el-row>
<el-col :span="24">
<source-pane v-if="type === '1'" :data="dataList" />
<table-pane v-if="type === '2'" :data="dataList" />
<column-pane v-if="type === '3'" :data="dataList" />
<el-pagination
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:current-page.sync="queryParams.pageNum"
:page-size.sync="queryParams.pageSize"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-col>
</el-row>
</div>
<div v-else>
<div class="search-container">
<el-input v-model="keyword" placeholder="请输入内容">
<el-select slot="prepend" v-model="type" placeholder="请选择" style="width: 100px;">
<el-option label="数据库" value="1" />
<el-option label="数据表" value="2" />
<el-option label="数据元" value="3" />
</el-select>
<el-button slot="append" icon="el-icon-search" :disabled="btnEnable" @click="search" />
</el-input>
</div>
</div>
</div>
</el-card>
</div>
</template>
<script>
import SourcePane from './SourcePane'
import TablePane from './TablePane'
import ColumnPane from './ColumnPane'
import { pageDataSource } from '@/api/metadata/datasource'
import { pageDataTable } from '@/api/metadata/datatable'
import { pageDataColumn } from '@/api/metadata/datacolumn'
export default {
name: 'DataSearch',
components: { SourcePane, TablePane, ColumnPane },
data() {
return {
searchExecuting: false,
type: '',
keyword: '',
btnEnable: true,
dataList: [],
total: 0,
queryParams: {
pageNum: 1,
pageSize: 20
}
}
},
computed: {
listenChange() {
const { type, keyword } = this
return { type, keyword }
}
},
watch: {
listenChange(val) {
if (val.type && val.keyword) {
this.btnEnable = false
} else {
this.btnEnable = true
}
}
},
methods: {
search() {
this.searchExecuting = true
const data = JSON.parse(JSON.stringify(this.queryParams))
if (this.type === '1') {
data.sourceName = this.keyword
pageDataSource(data).then(response => {
if (response.success) {
const { data } = response
this.dataList = data.data
this.total = data.total
}
})
} else if (this.type === '2') {
data.tableName = this.keyword
pageDataTable(data).then(response => {
if (response.success) {
const { data } = response
this.dataList = data.data
this.total = data.total
}
})
} else if (this.type === '3') {
data.columnName = this.keyword
pageDataColumn(data).then(response => {
if (response.success) {
const { data } = response
this.dataList = data.data
this.total = data.total
}
})
}
},
typeSelectChanged(val) {
this.dataList = []
this.total = 0
this.queryParams.pageNum = 1
this.queryParams.pageSize = 20
console.log(val)
},
handleSizeChange(val) {
this.queryParams.pageNum = 1
this.queryParams.pageSize = val
this.search()
},
handleCurrentChange(val) {
this.queryParams.pageNum = val
this.search()
}
}
}
</script>
<style lang="scss" scoped>
.el-card ::v-deep .el-card__body {
height: calc(100vh - 170px);
}
.search-container {
min-height: 100%;
width: 100%;
text-align: center;
margin-top: 15%;
.el-input {
position: relative;
width: 520px;
max-width: 100%;
margin: 0 auto;
}
}
::v-deep .el-divider {
margin: 10px 0;
}
</style>

View File

@@ -0,0 +1,234 @@
<template>
<el-card class="box-card" shadow="always">
<div slot="header" class="clearfix">
<span>{{ title }}</span>
<el-button-group style="float: right;">
<el-button v-if="active == 2" v-hasPerm="['metadata:datasource:add']" size="mini" icon="el-icon-plus" round :loading="loadingOptions.loading" :disabled="loadingOptions.isDisabled" @click="submitForm">{{ loadingOptions.loadingText }}</el-button>
<el-button size="mini" icon="el-icon-back" round @click="showCard">返回</el-button>
</el-button-group>
</div>
<div class="body-wrapper">
<el-steps :active="active" finish-status="success" align-center>
<el-step title="数据源信息" />
<el-step title="连接信息" />
</el-steps>
<el-form v-if="active == 1" ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="数据源类型" prop="dbType">
<el-select v-model="form.dbType">
<el-option
v-for="item in dbTypeOptions"
:key="item.id"
:label="item.itemValue"
:value="item.itemText"
/>
</el-select>
</el-form-item>
<el-form-item label="数据源名称" prop="sourceName">
<el-input v-model="form.sourceName" placeholder="请输入数据源名称" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in statusOptions"
:key="dict.id"
:label="dict.itemText"
>{{ dict.itemValue }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<el-form v-if="active == 2" ref="form2" :model="form2" :rules="rules2" label-width="80px">
<el-form-item label="主机" prop="host">
<el-input v-model="form2.host" placeholder="请输入主机" />
</el-form-item>
<el-form-item label="端口" prop="port">
<el-input v-model="form2.port" placeholder="请输入端口" />
</el-form-item>
<el-form-item v-if="form.dbType === '3' || form.dbType === '4'" label="服务名" prop="sid">
<el-input v-model="form2.sid" placeholder="请输入服务名" />
</el-form-item>
<el-form-item v-if="form.dbType !== '3' && form.dbType !== '4'" label="数据库" prop="dbName">
<el-input v-model="form2.dbName" placeholder="请输入数据库" />
</el-form-item>
<el-form-item label="用户名" prop="username">
<el-input v-model="form2.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="form2.password" placeholder="请输入密码" />
</el-form-item>
<el-form-item>
<el-button v-hasPerm="['metadata:datasource:connect']" size="mini" type="primary" @click="handleCheckConnection">连通性检测</el-button>
</el-form-item>
</el-form>
<el-button v-if="active == 1" style="margin-top: 12px;" @click="handleNextStep">下一步</el-button>
<el-button v-if="active == 2" style="margin-top: 12px;" @click="handleLastStep">上一步</el-button>
</div>
</el-card>
</template>
<script>
import { addDataSource, checkConnection } from '@/api/metadata/datasource'
export default {
name: 'DataSourceAdd',
props: {
data: {
type: Object,
default: function() {
return {}
}
}
},
data() {
return {
title: '数据源新增',
// 展示切换
showOptions: {
data: {},
showList: true,
showAdd: false,
showEdit: false,
showDetail: false
},
// 保存按钮
loadingOptions: {
loading: false,
loadingText: '保存',
isDisabled: false
},
active: 1,
// 表单参数
form: {
id: undefined,
dbType: undefined,
themeId: undefined,
sourceName: undefined,
dbSchema: {},
status: '1',
remark: undefined
},
// 表单校验
rules: {
dbType: [
{ required: true, message: '数据源类型不能为空', trigger: 'change' }
],
sourceName: [
{ required: true, message: '数据源名称不能为空', trigger: 'blur' }
]
},
form2: {
host: undefined,
port: undefined,
dbName: undefined,
username: undefined,
password: undefined,
sid: undefined
},
rules2: {
host: [
{ required: true, message: '主机不能为空', trigger: 'blur' }
],
port: [
{ required: true, message: '端口不能为空', trigger: 'blur' }
],
sid: [
{ required: true, message: '服务名不能为空', trigger: 'blur' }
],
dbName: [
{ required: true, message: '数据库不能为空', trigger: 'blur' }
],
username: [
{ required: true, message: '用户名不能为空', trigger: 'blur' }
],
password: [
{ required: true, message: '密码不能为空', trigger: 'blur' }
]
},
// 状态数据字典
statusOptions: [],
// 数据源类型数据字典
dbTypeOptions: []
}
},
created() {
this.getDicts('sys_common_status').then(response => {
if (response.success) {
this.statusOptions = response.data
}
})
this.getDicts('data_db_type').then(response => {
if (response.success) {
this.dbTypeOptions = response.data
}
})
},
methods: {
showCard() {
this.$emit('showCard', this.showOptions)
},
/** 步骤条下一步 */
handleNextStep() {
this.$refs['form'].validate(valid => {
if (valid) {
this.active++
}
})
},
/** 步骤条上一步 */
handleLastStep() {
this.active--
},
/** 检测数据库连通性 */
handleCheckConnection() {
this.$refs['form2'].validate(valid => {
if (valid) {
this.form.dbSchema = this.form2
checkConnection(this.form).then(response => {
if (response.success) {
this.$message.success('连接成功')
}
})
}
})
},
/** 提交按钮 */
submitForm: function() {
this.$refs['form2'].validate(valid => {
if (valid) {
this.form.dbSchema = this.form2
this.loadingOptions.loading = true
this.loadingOptions.loadingText = '保存中...'
this.loadingOptions.isDisabled = true
addDataSource(this.form).then(response => {
if (response.success) {
this.$message.success('保存成功')
setTimeout(() => {
// 2秒后跳转列表页
this.$emit('showCard', this.showOptions)
}, 2000)
} else {
this.$message.error('保存失败')
this.loadingOptions.loading = false
this.loadingOptions.loadingText = '保存'
this.loadingOptions.isDisabled = false
}
}).catch(() => {
this.loadingOptions.loading = false
this.loadingOptions.loadingText = '保存'
this.loadingOptions.isDisabled = false
})
}
})
}
}
}
</script>
<style lang="scss" scoped>
.el-card ::v-deep .el-card__body {
height: calc(100vh - 230px);
overflow-y: auto;
}
</style>

View File

@@ -0,0 +1,196 @@
<template>
<el-card class="box-card" shadow="always">
<div slot="header" class="clearfix">
<span>{{ title }}</span>
<el-button-group style="float: right;">
<!-- zrx add-->
<el-button v-if="form.isSync === '0'" v-hasPerm="['metadata:datasource:sync']" size="mini" icon="el-icon-coin" round @click="handleSync">元数据同步</el-button>
<el-button v-if="form.isSync === '2'" v-hasPerm="['metadata:datasource:sync']" size="mini" icon="el-icon-coin" round @click="handleSync">元数据更新</el-button>
<el-button v-if="form.isSync === '2'" v-hasPerm="['metadata:datasource:word']" size="mini" icon="el-icon-coin" round @click="handleWord">数据库文档</el-button>
<el-button v-if="form.isSync === '3'" v-hasPerm="['metadata:datasource:sync']" size="mini" icon="el-icon-coin" round @click="handleSync">元数据再次同步</el-button>
<el-button v-hasPerm="['metadata:datasource:connect']" size="mini" icon="el-icon-coin" round @click="handleCheckConnection">连通性检测</el-button>
<el-button size="mini" icon="el-icon-back" round @click="showCard">返回</el-button>
</el-button-group>
</div>
<div class="body-wrapper">
<el-steps :active="active" finish-status="success" align-center>
<el-step title="数据源信息" />
<el-step title="连接信息" />
</el-steps>
<el-form v-if="active == 1" ref="form" :model="form" label-width="80px" disabled>
<el-form-item label="数据源类型" prop="dbType">
<el-select v-model="form.dbType">
<el-option
v-for="item in dbTypeOptions"
:key="item.id"
:label="item.itemValue"
:value="item.itemText"
/>
</el-select>
</el-form-item>
<el-form-item label="数据源名称" prop="sourceName">
<el-input v-model="form.sourceName" placeholder="请输入数据源名称" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in statusOptions"
:key="dict.id"
:label="dict.itemText"
>{{ dict.itemValue }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<el-form v-if="active == 2" ref="form2" :model="form2" label-width="80px" disabled>
<el-form-item label="主机" prop="host">
<el-input v-model="form2.host" placeholder="请输入主机" />
</el-form-item>
<el-form-item label="端口" prop="port">
<el-input v-model="form2.port" placeholder="请输入端口" />
</el-form-item>
<el-form-item v-if="form.dbType === '3' || form.dbType === '4'" label="服务名" prop="sid">
<el-input v-model="form2.sid" placeholder="请输入服务名" />
</el-form-item>
<el-form-item v-if="form.dbType !== '3' && form.dbType !== '4'" label="数据库" prop="dbName">
<el-input v-model="form2.dbName" placeholder="请输入数据库" />
</el-form-item>
<el-form-item label="用户名" prop="username">
<el-input v-model="form2.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="form2.password" placeholder="请输入密码" />
</el-form-item>
</el-form>
<el-button v-if="active == 1" style="margin-top: 12px;" @click="handleNextStep">下一步</el-button>
<el-button v-if="active == 2" style="margin-top: 12px;" @click="handleLastStep">上一步</el-button>
</div>
</el-card>
</template>
<script>
import { getDataSource, checkConnection, sync, word } from '@/api/metadata/datasource'
export default {
name: 'DataSourceDetail',
props: {
data: {
type: Object,
default: function() {
return {}
}
}
},
data() {
return {
title: '数据源详情',
// 展示切换
showOptions: {
data: {},
showList: true,
showAdd: false,
showEdit: false,
showDetail: false
},
active: 1,
// 表单参数
form: {},
form2: {},
// 状态数据字典
statusOptions: [],
// 数据源类型数据字典
dbTypeOptions: []
}
},
created() {
console.log('id:' + this.data.id)
this.getDicts('sys_common_status').then(response => {
if (response.success) {
this.statusOptions = response.data
}
})
this.getDicts('data_db_type').then(response => {
if (response.success) {
this.dbTypeOptions = response.data
}
})
},
mounted() {
this.getDataSource(this.data.id)
},
methods: {
showCard() {
this.$emit('showCard', this.showOptions)
},
/** 获取详情 */
getDataSource: function(id) {
getDataSource(id).then(response => {
if (response.success) {
this.form = response.data
this.form2 = this.form.dbSchema
}
})
},
/** 步骤条下一步 */
handleNextStep() {
this.$refs['form'].validate(valid => {
if (valid) {
this.active++
}
})
},
/** 步骤条上一步 */
handleLastStep() {
this.active--
},
/** 检测数据库连通性 */
handleCheckConnection() {
checkConnection(this.form).then(response => {
if (response.success) {
this.$message.success('连接成功')
}
})
},
/** 元数据同步 */
handleSync() {
sync(this.data.id).then(response => {
if (response.success) {
this.$set(this.form, 'isSync', '1')
this.$message.success('元数据正在后台同步中,同步完成后刷新缓存即可到元数据管理中查看结果')
}
})
},
/** 数据库文档 */
handleWord() {
word(this.data.id).then(response => {
const blob = new Blob([response])
const fileName = '数据库设计文档.doc'
if ('download' in document.createElement('a')) {
// 非IE下载
const elink = document.createElement('a')
elink.download = fileName
elink.style.display = 'none'
elink.href = URL.createObjectURL(blob)
document.body.appendChild(elink)
elink.click()
URL.revokeObjectURL(elink.href)
// 释放URL 对象
document.body.removeChild(elink)
} else {
// IE10+下载
navigator.msSaveBlob(blob, fileName)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.el-card ::v-deep .el-card__body {
height: calc(100vh - 230px);
overflow-y: auto;
}
</style>

View File

@@ -0,0 +1,232 @@
<template>
<el-card class="box-card" shadow="always">
<div slot="header" class="clearfix">
<span>{{ title }}</span>
<el-button-group style="float: right;">
<el-button v-if="active == 2" v-hasPerm="['metadata:datasource:edit']" size="mini" icon="el-icon-plus" round :loading="loadingOptions.loading" :disabled="loadingOptions.isDisabled" @click="submitForm">{{ loadingOptions.loadingText }}</el-button>
<el-button size="mini" icon="el-icon-back" round @click="showCard">返回</el-button>
</el-button-group>
</div>
<div class="body-wrapper">
<el-steps :active="active" finish-status="success" align-center>
<el-step title="数据源信息" />
<el-step title="连接信息" />
</el-steps>
<el-form v-if="active == 1" ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="数据源类型" prop="dbType">
<el-select v-model="form.dbType">
<el-option
v-for="item in dbTypeOptions"
:key="item.id"
:label="item.itemValue"
:value="item.itemText"
/>
</el-select>
</el-form-item>
<el-form-item label="数据源名称" prop="sourceName">
<el-input v-model="form.sourceName" placeholder="请输入数据源名称" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in statusOptions"
:key="dict.id"
:label="dict.itemText"
>{{ dict.itemValue }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<el-form v-if="active == 2" ref="form2" :model="form2" :rules="rules2" label-width="80px">
<el-form-item label="主机" prop="host">
<el-input v-model="form2.host" placeholder="请输入主机" />
</el-form-item>
<el-form-item label="端口" prop="port">
<el-input v-model="form2.port" placeholder="请输入端口" />
</el-form-item>
<el-form-item v-if="form.dbType === '3' || form.dbType === '4'" label="服务名" prop="sid">
<el-input v-model="form2.sid" placeholder="请输入服务名" />
</el-form-item>
<el-form-item v-if="form.dbType !== '3' && form.dbType !== '4'" label="数据库" prop="dbName">
<el-input v-model="form2.dbName" placeholder="请输入数据库" />
</el-form-item>
<el-form-item label="用户名" prop="username">
<el-input v-model="form2.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="form2.password" placeholder="请输入密码" />
</el-form-item>
<el-form-item>
<el-button v-hasPerm="['metadata:datasource:connect']" size="mini" type="primary" @click="handleCheckConnection">连通性检测</el-button>
</el-form-item>
</el-form>
<el-button v-if="active == 1" style="margin-top: 12px;" @click="handleNextStep">下一步</el-button>
<el-button v-if="active == 2" style="margin-top: 12px;" @click="handleLastStep">上一步</el-button>
</div>
</el-card>
</template>
<script>
import { getDataSource, updateDataSource, checkConnection } from '@/api/metadata/datasource'
export default {
name: 'DataSourceEdit',
props: {
data: {
type: Object,
default: function() {
return {}
}
}
},
data() {
return {
title: '数据源编辑',
// 展示切换
showOptions: {
data: {},
showList: true,
showAdd: false,
showEdit: false,
showDetail: false
},
// 保存按钮
loadingOptions: {
loading: false,
loadingText: '保存',
isDisabled: false
},
active: 1,
// 表单参数
form: {},
// 表单校验
rules: {
dbType: [
{ required: true, message: '数据源类型不能为空', trigger: 'change' }
],
sourceName: [
{ required: true, message: '数据源名称不能为空', trigger: 'blur' }
]
},
form2: {},
rules2: {
host: [
{ required: true, message: '主机不能为空', trigger: 'blur' }
],
port: [
{ required: true, message: '端口不能为空', trigger: 'blur' }
],
sid: [
{ required: true, message: '服务名不能为空', trigger: 'blur' }
],
dbName: [
{ required: true, message: '数据库不能为空', trigger: 'blur' }
],
username: [
{ required: true, message: '用户名不能为空', trigger: 'blur' }
],
password: [
{ required: true, message: '密码不能为空', trigger: 'blur' }
]
},
// 状态数据字典
statusOptions: [],
// 数据源类型数据字典
dbTypeOptions: []
}
},
created() {
console.log('id:' + this.data.id)
this.getDicts('sys_common_status').then(response => {
if (response.success) {
this.statusOptions = response.data
}
})
this.getDicts('data_db_type').then(response => {
if (response.success) {
this.dbTypeOptions = response.data
}
})
},
mounted() {
this.getDataSource(this.data.id)
},
methods: {
showCard() {
this.$emit('showCard', this.showOptions)
},
/** 获取详情 */
getDataSource: function(id) {
getDataSource(id).then(response => {
if (response.success) {
this.form = response.data
this.form2 = this.form.dbSchema
}
})
},
/** 步骤条下一步 */
handleNextStep() {
this.$refs['form'].validate(valid => {
if (valid) {
this.active++
}
})
},
/** 步骤条上一步 */
handleLastStep() {
this.active--
},
/** 检测数据库连通性 */
handleCheckConnection() {
this.$refs['form2'].validate(valid => {
if (valid) {
this.form.dbSchema = this.form2
checkConnection(this.form).then(response => {
if (response.success) {
this.$message.success('连接成功')
}
})
}
})
},
/** 提交按钮 */
submitForm: function() {
this.$refs['form2'].validate(valid => {
if (valid) {
this.form.dbSchema = this.form2
this.loadingOptions.loading = true
this.loadingOptions.loadingText = '保存中...'
this.loadingOptions.isDisabled = true
updateDataSource(this.form).then(response => {
if (response.success) {
this.$message.success('保存成功')
setTimeout(() => {
// 2秒后跳转列表页
this.$emit('showCard', this.showOptions)
}, 2000)
} else {
this.$message.error('保存失败')
this.loadingOptions.loading = false
this.loadingOptions.loadingText = '保存'
this.loadingOptions.isDisabled = false
}
}).catch(() => {
this.loadingOptions.loading = false
this.loadingOptions.loadingText = '保存'
this.loadingOptions.isDisabled = false
})
}
})
}
}
}
</script>
<style lang="scss" scoped>
.el-card ::v-deep .el-card__body {
height: calc(100vh - 230px);
overflow-y: auto;
}
</style>

View File

@@ -0,0 +1,351 @@
<template>
<el-card class="box-card" shadow="always">
<el-form ref="queryForm" :model="queryParams" :inline="true">
<el-form-item label="数据源名称" prop="sourceName">
<el-input
v-model="queryParams.sourceName"
placeholder="请输入数据源名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row type="flex" justify="space-between">
<el-col :span="12">
<el-button-group>
<el-button
v-hasPerm="['metadata:datasource:add']"
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
>新增</el-button>
<el-button
v-hasPerm="['metadata:datasource:refresh']"
type="warning"
icon="el-icon-refresh"
size="mini"
@click="handleCacheRefresh"
>刷新缓存</el-button>
</el-button-group>
</el-col>
<el-col :span="12">
<div class="right-toolbar">
<el-tooltip content="密度" effect="dark" placement="top">
<el-dropdown trigger="click" @command="handleCommand">
<el-button circle size="mini">
<svg-icon class-name="size-icon" icon-class="colum-height" />
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="medium">正常</el-dropdown-item>
<el-dropdown-item command="small">中等</el-dropdown-item>
<el-dropdown-item command="mini">紧凑</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-tooltip>
<el-tooltip content="刷新" effect="dark" placement="top">
<el-button circle size="mini" @click="handleRefresh">
<svg-icon class-name="size-icon" icon-class="shuaxin" />
</el-button>
</el-tooltip>
<el-tooltip content="列设置" effect="dark" placement="top">
<el-popover placement="bottom" width="100" trigger="click">
<el-checkbox-group v-model="checkedTableColumns" @change="handleCheckedColsChange">
<el-checkbox
v-for="(item, index) in tableColumns"
:key="index"
:label="item.prop"
>{{ item.label }}</el-checkbox>
</el-checkbox-group>
<span slot="reference">
<el-button circle size="mini">
<svg-icon class-name="size-icon" icon-class="shezhi" />
</el-button>
</span>
</el-popover>
</el-tooltip>
</div>
</el-col>
</el-row>
<el-table
v-loading="loading"
:data="dataSourceList"
border
tooltip-effect="dark"
:size="tableSize"
:height="tableHeight"
style="width: 100%;margin: 15px 0;"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" width="55" align="center">
<template slot-scope="scope">
<span>{{ scope.$index +1 }}</span>
</template>
</el-table-column>
<template v-for="(item, index) in tableColumns">
<el-table-column
v-if="item.show"
:key="index"
:prop="item.prop"
:label="item.label"
:formatter="item.formatter"
align="center"
show-overflow-tooltip
/>
</template>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-popover
placement="left"
trigger="click"
>
<el-button
v-hasPerm="['metadata:datasource:edit']"
size="mini"
type="text"
icon="el-icon-edit-outline"
@click="handleEdit(scope.row)"
>修改</el-button>
<el-button
v-hasPerm="['metadata:datasource:detail']"
size="mini"
type="text"
icon="el-icon-view"
@click="handleDetail(scope.row)"
>详情</el-button>
<el-button
v-hasPerm="['metadata:datasource:remove']"
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
>删除</el-button>
<el-button slot="reference">操作</el-button>
</el-popover>
</template>
</el-table-column>
</el-table>
<el-pagination
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:current-page.sync="queryParams.pageNum"
:page-size.sync="queryParams.pageSize"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-card>
</template>
<script>
import { pageDataSource, delDataSource, refreshMetadata } from '@/api/metadata/datasource'
export default {
name: 'DataSourceList',
data() {
return {
tableHeight: document.body.offsetHeight - 310 + 'px',
// 展示切换
showOptions: {
data: {},
showList: true,
showAdd: false,
showEdit: false,
showDetail: false
},
// 遮罩层
loading: true,
// 表格头
tableColumns: [
{ prop: 'sourceName', label: '数据源名称', show: true },
{
prop: 'isSync',
label: '同步状态',
show: true,
formatter: this.syncFormatter
},
{
prop: 'status',
label: '状态',
show: true,
formatter: this.statusFormatter
},
{ prop: 'createTime', label: '创建时间', show: true }
],
// 默认选择中表格头
checkedTableColumns: [],
tableSize: 'medium',
// 状态数据字典
statusOptions: [],
// 数据源表格数据
dataSourceList: [],
// 总数据条数
total: 0,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 20,
sourceName: ''
}
}
},
created() {
this.getDicts('sys_common_status').then(response => {
if (response.success) {
this.statusOptions = response.data
}
})
this.getList()
},
mounted() {
this.initCols()
},
methods: {
/** 查询数据源列表 */
getList() {
this.loading = true
pageDataSource(this.queryParams).then(response => {
this.loading = false
if (response.success) {
const { data } = response
this.dataSourceList = data.data
this.total = data.total
}
})
},
initCols() {
this.checkedTableColumns = this.tableColumns.map(col => col.prop)
},
handleCheckedColsChange(val) {
this.tableColumns.forEach(col => {
if (!this.checkedTableColumns.includes(col.prop)) {
col.show = false
} else {
col.show = true
}
})
},
handleCommand(command) {
this.tableSize = command
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.queryParams = {
pageNum: 1,
pageSize: 20,
sourceName: ''
}
this.handleQuery()
},
/** 刷新列表 */
handleRefresh() {
this.getList()
},
/** 新增按钮操作 */
handleAdd() {
this.showOptions.data = {}
this.showOptions.showList = false
this.showOptions.showAdd = true
this.showOptions.showEdit = false
this.showOptions.showDetail = false
this.$emit('showCard', this.showOptions)
},
/** 修改按钮操作 */
handleEdit(row) {
this.showOptions.data.id = row.id
this.showOptions.showList = false
this.showOptions.showAdd = false
this.showOptions.showEdit = true
this.showOptions.showDetail = false
this.$emit('showCard', this.showOptions)
},
/** 详情按钮操作 */
handleDetail(row) {
this.showOptions.data.id = row.id
this.showOptions.showList = false
this.showOptions.showAdd = false
this.showOptions.showEdit = false
this.showOptions.showDetail = true
this.$emit('showCard', this.showOptions)
},
/** 刷新缓存 */
handleCacheRefresh() {
refreshMetadata().then(response => {
if (response.success) {
this.$message.success('刷新缓存成功')
} else {
this.$message.error('刷新缓存失败')
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
this.$confirm('选中数据将被永久删除, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delDataSource(row.id).then(response => {
if (response.success) {
this.$message.success('删除成功')
this.getList()
}
})
}).catch(() => {
})
},
handleSizeChange(val) {
console.log(`每页 ${val}`)
this.queryParams.pageNum = 1
this.queryParams.pageSize = val
this.getList()
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`)
this.queryParams.pageNum = val
this.getList()
},
syncFormatter(row, column, cellValue, index) {
if (cellValue === '0') {
return <el-tag type='warning'>未同步</el-tag>
} else if (cellValue === '1') {
return <el-tag type='info'>同步中</el-tag>
} else if (cellValue === '2') {
return <el-tag type='success'>已同步</el-tag>
} else if (cellValue === '3') {
return <el-tag type='danger'>同步失败</el-tag>
}
},
statusFormatter(row, column, cellValue, index) {
const dictLabel = this.selectDictLabel(this.statusOptions, cellValue)
if (cellValue === '1') {
return <el-tag type='success'>{dictLabel}</el-tag>
} else {
return <el-tag type='warning'>{dictLabel}</el-tag>
}
}
}
}
</script>
<style lang="scss" scoped>
.right-toolbar {
float: right;
}
.el-card ::v-deep .el-card__body {
height: calc(100vh - 170px);
}
</style>

View File

@@ -0,0 +1,48 @@
<template>
<div class="app-container">
<transition name="el-zoom-in-center">
<data-source-list v-if="options.showList" @showCard="showCard" />
</transition>
<transition name="el-zoom-in-top">
<data-source-add v-if="options.showAdd" :data="options.data" @showCard="showCard" />
</transition>
<transition name="el-zoom-in-top">
<data-source-edit v-if="options.showEdit" :data="options.data" @showCard="showCard" />
</transition>
<transition name="el-zoom-in-bottom">
<data-source-detail v-if="options.showDetail" :data="options.data" @showCard="showCard" />
</transition>
</div>
</template>
<script>
import DataSourceList from './DataSourceList'
import DataSourceAdd from './DataSourceAdd'
import DataSourceEdit from './DataSourceEdit'
import DataSourceDetail from './DataSourceDetail'
export default {
name: 'DataSource',
components: { DataSourceList, DataSourceAdd, DataSourceEdit, DataSourceDetail },
data() {
return {
options: {
data: {},
showList: true,
showAdd: false,
showEdit: false,
showDetail: false
}
}
},
methods: {
showCard(data) {
Object.assign(this.options, data)
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,15 @@
<template>
<div class="app-container">
Metadata
</div>
</template>
<script>
export default {
name: 'Metadata'
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,189 @@
<template>
<div class="app-container">
<el-card class="box-card" shadow="always">
<el-row>
<el-col :span="24">
<el-form :inline="true" class="demo-form-inline">
<el-form-item label="数据源">
<el-select v-model="sqlDataSource" placeholder="请选择数据源">
<el-option
v-for="source in sourceOptions"
:key="source.id"
:label="source.sourceName"
:value="source.id"
:disabled="source.status === '0'"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button size="mini" round :disabled="sqlExecuting" @click="runData">运行</el-button>
<el-button size="mini" round :disabled="!sqlExecuting" @click="stopData">停止</el-button>
<el-button size="mini" round :disabled="sqlExecuting" @click="formaterSql">格式化</el-button>
<el-button size="mini" round :disabled="sqlExecuting" @click="refreshData">重置</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<sql-editor
ref="sqleditor"
:value="sqlText"
style="height: 300px; margin: 20px 0;"
@changeTextarea="changeTextarea($event)"
/>
</el-col>
</el-row>
<el-row>
<el-col>
<div v-if="sqlExecuting" v-loading="sqlExecuting">数据加载中...</div>
<div v-else>
<div v-if="sqlConsole.length > 0">
<el-tabs v-model="activeTabName" type="border-card">
<el-tab-pane label="信息" name="table0">
<pre>{{ executeResultInfo }}</pre>
</el-tab-pane>
<el-tab-pane v-for="(item,index) in sqlConsole" :key="(index+1)" :name="'table'+(index+1)" :label="'结果'+(index+1)">
<el-table
:data="item.dataList"
stripe
border
:max-height="300"
style="width: 100%; margin: 15px 0;"
>
<el-table-column label="序号" width="55" align="center">
<template slot-scope="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<template v-for="(column, index) in item.columnList">
<el-table-column
:key="index"
:prop="column"
:label="column"
align="center"
show-overflow-tooltip
/>
</template>
</el-table>
</el-tab-pane>
</el-tabs>
</div>
</div>
</el-col>
</el-row>
</el-card>
</div>
</template>
<script>
import sqlFormatter from 'sql-formatter'
import SqlEditor from '@/components/SqlEditor'
import { listDataSource } from '@/api/metadata/datasource'
import { runSql, stopSql } from '@/api/metadata/sqlconsole'
export default {
name: 'SqlConsole',
components: {
SqlEditor
},
data() {
return {
// 数据源数据字典
sourceOptions: [],
sqlDataSource: undefined,
sqlText: undefined,
sqlExecuting: false,
activeTabName: 'table0',
sqlExecutorId: undefined,
sqlConsole: [],
executeResultInfo: undefined
}
},
created() {
this.getDataSourceList()
},
methods: {
getDataSourceList() {
listDataSource().then(response => {
if (response.success) {
this.sourceOptions = response.data
}
})
},
runData() {
if (!this.sqlDataSource) {
this.$message.error('数据源不能为空')
return
}
if (!this.sqlText) {
this.$message.error('查询SQL不能为空')
return
}
this.sqlExecuting = true
this.sqlExecutorId = (new Date()).getTime() + Math.ceil(Math.random() * 1000)
this.sqlConsole = []
const data = {}
data.sqlKey = this.sqlExecutorId
data.sourceId = this.sqlDataSource
data.sqlText = this.sqlText
runSql(data).then(response => {
if (response.success) {
const { data } = response
let resultStr = ''
for (let i = 0; i < data.length; i++) {
const item = data[i]
resultStr += item.sql
resultStr += '\n> 状态:' + ((item.success) ? '成功' : '失败')
if (item.count && item.count >= 0) {
resultStr += '\n> 影响行数:' + item.count
}
resultStr += '\n> 耗时:' + (item.time || 0) / 1000 + 's'
resultStr += '\n\n'
}
this.executeResultInfo = resultStr
this.sqlConsole = data
}
this.sqlExecuting = false
})
},
stopData() {
const data = {}
data.sqlKey = this.sqlExecutorId
stopSql(data).then(response => {
if (response.success) {
this.$message.success('停止成功')
}
this.sqlExecuting = false
})
},
changeTextarea(val) {
this.sqlText = val
},
formaterSql() {
if (!this.sqlText) {
return
}
this.$refs.sqleditor.editor.setValue(sqlFormatter.format(this.$refs.sqleditor.editor.getValue()))
},
refreshData() {
if (!this.sqlText) {
return
}
this.sqlExecuting = false
this.activeTabName = 'table0'
this.sqlExecutorId = undefined
this.sqlText = undefined
this.$refs.sqleditor.editor.setValue('')
this.sqlConsole = []
this.executeResultInfo = undefined
}
}
}
</script>
<style lang="scss" scoped>
.el-card ::v-deep .el-card__body {
height: calc(100vh - 170px);
}
</style>