Commit 523413ac by yuwei

项目初始化

parent 9579d532
......@@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/v1")
@RequestMapping("/sql")
public class SqlConsoleController extends BaseController {
@Autowired
......
import request from '@/utils/request'
export function listDataSource (data) {
return request({
url: '/data/metadata/sources/list',
method: 'get',
params: data
})
}
export function pageDataSource (data) {
return request({
url: '/data/metadata/sources/page',
method: 'get',
params: data
})
}
export function getDataSource (id) {
return request({
url: '/data/metadata/sources/' + id,
method: 'get'
})
}
export function delDataSource (id) {
return request({
url: '/data/metadata/sources/' + id,
method: 'delete'
})
}
export function delDataSources (ids) {
return request({
url: '/data/metadata/sources/batch/' + ids,
method: 'delete'
})
}
export function addDataSource (data) {
return request({
url: '/data/metadata/sources',
method: 'post',
data: data
})
}
export function updateDataSource (data) {
return request({
url: '/data/metadata/sources/' + data.id,
method: 'put',
data: data
})
}
export function checkConnection (data) {
return request({
url: '/data/metadata/sources/checkConnection',
method: 'post',
data: data
})
}
export function queryByPage (data) {
return request({
url: '/data/metadata/sources/queryByPage',
method: 'post',
data: data
})
}
export function getDbTables (id) {
return request({
url: '/data/metadata/sources/' + id + '/tables',
method: 'get'
})
}
export function getDbTableColumns (id, tableName) {
return request({
url: '/data/metadata/sources/' + id + '/' + tableName + '/columns',
method: 'get'
})
}
export function sync (id) {
return request({
url: '/data/metadata/sources/sync/' + id,
method: 'post'
})
}
export function word (id) {
return request({
url: '/data/metadata/sources/word/' + id,
method: 'post',
responseType: 'blob'
})
}
import request from '@/utils/request'
export function runSql (data) {
return request({
url: '/data/console/sql/run',
method: 'post',
data: data
})
}
export function stopSql (data) {
return request({
url: '/data/console/sql/stop',
method: 'post',
data: data
})
}
<template>
<div>
<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-plus" v-if="active == 2" round @click="submitForm" :loading="loadingOptions.loading" :disabled="loadingOptions.isDisabled">{{loadingOptions.loadingText}}</el-button>
<el-button size="mini" icon="el-icon-back" round @click="showCard">返回</el-button>
</el-button-group>
</div>
<div :style="classCardbody">
<el-steps :active="active" finish-status="success" align-center>
<el-step title="数据源信息"></el-step>
<el-step title="连接信息"></el-step>
</el-steps>
<el-form ref="form" :model="form" :rules="rules" label-width="80px" v-if="active == 1">
<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-option>
</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 ref="form2" :model="form2" :rules="rules2" label-width="80px" v-if="active == 2">
<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 label="服务名" prop="sid" v-if="form.dbType === '3' || form.dbType === '4'">
<el-input v-model="form2.sid" placeholder="请输入服务名" />
</el-form-item>
<el-form-item label="数据库" prop="dbName" v-if="form.dbType !== '3' && form.dbType !== '4'">
<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 size="mini" type="primary" @click="handleCheckConnection">连通性检测</el-button>
</el-form-item>
</el-form>
<el-button style="margin-top: 12px;" @click="handleNextStep" v-if="active == 1">下一步</el-button>
<el-button style="margin-top: 12px;" @click="handleLastStep" v-if="active == 2">上一步</el-button>
</div>
</el-card>
</div>
</template>
<script>
import { addDataSource, checkConnection } from '@/api/metadata/datasource'
export default {
name: 'DataSourceAdd',
props: {
data: {
type: Object,
default: function () {
return {}
}
}
},
data () {
return {
classCardbody: {
overflow: 'auto',
height: document.body.offsetHeight - 240 + 'px'
},
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
}
})
}
})
}
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div>
<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-coin" type="primary" round @click="handleSync">元数据同步</el-button>
<el-button size="mini" icon="el-icon-coin" type="primary" round @click="handleWord">数据库文档</el-button>
<el-button size="mini" icon="el-icon-coin" type="primary" round @click="handleCheckConnection" v-if="active == 2">连通性检测</el-button>
<el-button size="mini" icon="el-icon-back" round @click="showCard">返回</el-button>
</el-button-group>
</div>
<div :style="classCardbody">
<el-steps :active="active" finish-status="success" align-center>
<el-step title="数据源信息"></el-step>
<el-step title="连接信息"></el-step>
</el-steps>
<el-form ref="form" :model="form" label-width="80px" v-if="active == 1" 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-option>
</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 ref="form2" :model="form2" label-width="80px" v-if="active == 2" 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 label="服务名" prop="sid" v-if="form.dbType === '3' || form.dbType === '4'">
<el-input v-model="form2.sid" placeholder="请输入服务名" />
</el-form-item>
<el-form-item label="数据库" prop="dbName" v-if="form.dbType !== '3' || form.dbType !== '4'">
<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 style="margin-top: 12px;" @click="handleNextStep" v-if="active == 1">下一步</el-button>
<el-button style="margin-top: 12px;" @click="handleLastStep" v-if="active == 2">上一步</el-button>
</div>
</el-card>
</div>
</template>
<script>
import { getDataSource, checkConnection, sync, word } from '@/api/metadata/datasource'
export default {
name: 'DataSourceDetail',
props: {
data: {
type: Object,
default: function () {
return {}
}
}
},
data () {
return {
classCardbody: {
overflow: 'auto',
height: document.body.offsetHeight - 240 + 'px'
},
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.$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>
</style>
<template>
<div>
<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-plus" v-if="active == 2" round @click="submitForm" :loading="loadingOptions.loading" :disabled="loadingOptions.isDisabled">{{loadingOptions.loadingText}}</el-button>
<el-button size="mini" icon="el-icon-back" round @click="showCard">返回</el-button>
</el-button-group>
</div>
<div :style="classCardbody">
<el-steps :active="active" finish-status="success" align-center>
<el-step title="数据源信息"></el-step>
<el-step title="连接信息"></el-step>
</el-steps>
<el-form ref="form" :model="form" :rules="rules" label-width="80px" v-if="active == 1">
<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-option>
</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 ref="form2" :model="form2" :rules="rules2" label-width="80px" v-if="active == 2">
<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 label="服务名" prop="sid" v-if="form.dbType === '3' || form.dbType === '4'">
<el-input v-model="form2.sid" placeholder="请输入服务名" />
</el-form-item>
<el-form-item label="数据库" prop="dbName" v-if="form.dbType !== '3' && form.dbType !== '4'">
<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 size="mini" type="primary" @click="handleCheckConnection">连通性检测</el-button>
</el-form-item>
</el-form>
<el-button style="margin-top: 12px;" @click="handleNextStep" v-if="active == 1">下一步</el-button>
<el-button style="margin-top: 12px;" @click="handleLastStep" v-if="active == 2">上一步</el-button>
</div>
</el-card>
</div>
</template>
<script>
import { getDataSource, updateDataSource, checkConnection } from '@/api/metadata/datasource'
export default {
name: 'DataSourceEdit',
props: {
data: {
type: Object,
default: function () {
return {}
}
}
},
data () {
return {
classCardbody: {
overflow: 'auto',
height: document.body.offsetHeight - 240 + 'px'
},
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
}
})
}
})
}
}
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div>
<el-card class="box-card" shadow="always">
<el-form :model="queryParams" ref="queryForm" :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
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPerm="['factory:datasource:add']"
>新增</el-button>
<el-button
type="success"
icon="el-icon-edit-outline"
size="mini"
:disabled="single"
@click="handleEdit"
v-hasPerm="['factory:datasource:edit']"
>修改</el-button>
<el-button
type="info"
icon="el-icon-view"
size="mini"
:disabled="single"
@click="handleDetail"
v-hasPerm="['factory:datasource:detail']"
>详情</el-button>
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleBatchDelete"
v-hasPerm="['factory:datasource:remove']"
>删除</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"
@selection-change="handleSelectionChange"
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"
:prop="item.prop"
:label="item.label"
:key="index"
: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
size="mini"
type="text"
icon="el-icon-edit-outline"
@click="handleEdit(scope.row)"
v-hasPerm="['factory:datasource:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-view"
@click="handleDetail(scope.row)"
v-hasPerm="['factory:datasource:detail']"
>详情</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPerm="['factory:datasource:remove']"
>删除</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"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="queryParams.pageNum"
:page-size.sync="queryParams.pageSize"
:total="total"
></el-pagination>
</el-card>
</div>
</template>
<script>
import { pageDataSource, delDataSource, delDataSources } from '@/api/metadata/datasource'
export default {
name: 'DataSourceList',
data () {
return {
tableHeight: document.body.offsetHeight - 340 + 'px',
// 展示切换
showOptions: {
data: {},
showList: true,
showAdd: false,
showEdit: false,
showDetail: false
},
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 表格头
tableColumns: [
{ prop: 'sourceName', label: '数据源名称', show: true },
{
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.$refs['queryForm'].resetFields()
this.handleQuery()
},
/** 刷新列表 */
handleRefresh () {
this.getList()
},
/** 多选框选中数据 */
handleSelectionChange (selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length !== 1
this.multiple = !selection.length
},
/** 新增按钮操作 */
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.ids[0]
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.ids[0]
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(() => {
delDataSource(row.id)
}).then(() => {
this.$message.success('删除成功')
this.getList()
}).catch(() => {
})
},
/** 批量删除按钮操作 */
handleBatchDelete () {
if (!this.ids.length) {
this.$message({
message: '请先选择需要操作的数据',
type: 'warning'
})
}
this.$message.warning('不支持批量删除')
},
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) {
let 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;
}
</style>
<template>
<div class="app-container">
<transition name="el-zoom-in-center">
<data-source-list v-if="options.showList" @showCard="showCard"></data-source-list>
</transition>
<transition name="el-zoom-in-top">
<data-source-add v-if="options.showAdd" :data="options.data" @showCard="showCard"></data-source-add>
</transition>
<transition name="el-zoom-in-top">
<data-source-edit v-if="options.showEdit" :data="options.data" @showCard="showCard"></data-source-edit>
</transition>
<transition name="el-zoom-in-bottom">
<data-source-detail v-if="options.showDetail" :data="options.data" @showCard="showCard"></data-source-detail>
</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>
<template>
<div class="app-container">
<el-card class="box-card" shadow="always">
<div slot="header" class="clearfix">
<span>{{ title }}</span>
</div>
<div :style="classCardbody">
<el-row>
<el-col :span="24">
<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-option>
</el-select>
<el-button size="mini" round @click="runData" :disabled="sqlExecuting">运行</el-button>
<el-button size="mini" round @click="stopData" :disabled="!sqlExecuting">停止</el-button>
<el-button size="mini" round @click="formaterSql" :disabled="sqlExecuting">格式化</el-button>
<el-button size="mini" round @click="refreshData" :disabled="sqlExecuting">重置</el-button>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<sql-editor
ref="sqleditor"
:value="sqlText"
@changeTextarea="changeTextarea($event)"
style="height: 300px;margin: 20px 0;"
></sql-editor>
</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 type="border-card" v-model="activeTabName">
<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
:prop="column"
:label="column"
:key="index"
align="center"
show-overflow-tooltip
/>
</template>
</el-table>
</el-tab-pane>
</el-tabs>
</div>
</div>
</el-col>
</el-row>
</div>
</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 {
classCardbody: {
overflow: 'auto',
height: document.body.offsetHeight - 240 + 'px'
},
title: 'SQL工作台',
// 数据源数据字典
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 = []
let 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++) {
let 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 () {
let 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>
</style>
<template>
<div class="app-container">
DataBoard
</div>
</template>
<script>
export default {
name: 'DataBoard'
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div class="app-container">
DataChart
</div>
</template>
<script>
export default {
name: 'DataChart'
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div class="chart-container">
<el-container>
<el-aside width="250px" class="widget-field-container">
<el-card class="box-card" shadow="always" style="height: 100%;">
<div slot="header" class="clearfix">
<span>数据集</span>
<el-dropdown trigger="click" @command="handleCommand" style="float: right; color: #499df3;">
<span class="el-dropdown-link">
切换<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="item in datasetOptions" :command="item.id">{{item.setName}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<div style="margin: -20px;">
<div class="field-widget-cate"><i class="icon iconfont icon-weidu"></i><span>维度列</span></div>
<draggable v-model="dimensions" class="field-widget-tag" :options="{sort: false, ghostClass: 'ghost', group: {name: 'dimensions', pull: true, put: false}}">
<el-tag v-for="(item, index) in dimensions" :key="index" class="field-widget-label"><div>{{ item.alias ? item.alias + '(' + item.col + ')' : item.col }}</div></el-tag>
</draggable>
<div class="field-widget-cate"><i class="icon iconfont icon-zhibiao"></i><span>指标列</span></div>
<draggable v-model="measures" class="field-widget-tag" :options="{sort: false, ghostClass: 'ghost', group: {name: 'measures', pull: true, put: false}}">
<el-tag v-for="(item, index) in measures" :key="index" class="field-widget-label"><div>{{ item.alias ? item.alias + '(' + item.col + ')' : item.col }}</div></el-tag>
</draggable>
</div>
</el-card>
</el-aside>
<el-container>
<el-header class="chart-action-bar" style="height: 40px;text-align: right;">
<el-button icon="el-icon-view" type="text">
预览
</el-button>
<el-button icon="el-icon-delete" type="text">
清空
</el-button>
<el-button icon="el-icon-plus" type="text">
保存
</el-button>
<el-button icon="el-icon-close" type="text">
取消
</el-button>
</el-header>
<el-main class="widget-center-container">
<el-row>
<el-divider content-position="left">行维</el-divider>
<el-col>
<div class="draggable-wrapper">
<draggable group="dimensions" :list="form.keys">
<el-tag v-for="(item, index) in form.keys" :key="index" class="draggable-item" closable @close="handleKeyTagClose(index, item)">
{{ item.alias ? item.alias : item.col }}
</el-tag>
</draggable>
</div>
</el-col>
</el-row>
<el-row>
<el-divider content-position="left">列维</el-divider>
<el-col>
<div class="draggable-wrapper">
<draggable group="dimensions" :list="form.groups">
<el-tag v-for="(item, index) in form.groups" :key="index" class="draggable-item" closable @close="handleGroupTagClose(index, item)">
{{ item.alias ? item.alias : item.col }}
</el-tag>
</draggable>
</div>
</el-col>
</el-row>
<el-row>
<el-divider content-position="left">指标</el-divider>
<el-col>
<div class="draggable-wrapper">
<draggable group="measures" :list="form.values" @change="handleValueDragChange">
<div v-for="(item, index) in form.values" :key="index" class="draggable-item">
<el-tag>{{ item.alias ? item.aggregate_type + '(' + item.col + ') -> ' + item.alias : item.aggregate_type + '(' + item.col + ')' }}</el-tag>
<span class="draggable-item-handle" v-if="item.radio">
<el-radio-group size="mini" v-model="item.aggregate_type" @change="((label)=>{handleValueChangeTagType(label, index, item)})">
<el-radio label="sum" size="mini">求和</el-radio>
<el-radio label="count" size="mini">计数</el-radio>
<el-radio label="avg" size="mini">平均值</el-radio>
<el-radio label="max" size="mini">最大值</el-radio>
<el-radio label="min" size="mini">最小值</el-radio>
</el-radio-group>
</span>
<span class="draggable-item-handle" v-else @click="handleValueTagType(index, item)"><i class="el-icon-edit-outline"></i></span>
<span class="draggable-item-handle" @click="handleValueTagClose(index, item)"><i class="el-icon-delete"></i></span>
</div>
</draggable>
</div>
</el-col>
</el-row>
<el-row>
<el-divider>预览区</el-divider>
<el-tabs type="card">
<el-tab-pane label="预览">
<div class="data-tab-pane">预览</div>
</el-tab-pane>
<el-tab-pane label="查询脚本">
<div class="script-tab-pane">查询脚本</div>
</el-tab-pane>
</el-tabs>
<el-col>
</el-col>
</el-row>
</el-main>
</el-container>
<el-aside width="300px" class="widget-config-container">
<el-container>
<el-tabs type="border-card" stretch style="width: 100%;">
<el-tab-pane label="图表属性">
<el-main>
<div class="chart-tab-pane">图表属性</div>
</el-main>
</el-tab-pane>
<el-tab-pane label="图表配置">
<el-main>
<div class="chart-tab-pane">图表配置</div>
</el-main>
</el-tab-pane>
</el-tabs>
</el-container>
</el-aside>
</el-container>
</div>
</template>
<script>
import { getDataSet, listDataSet } from '@/api/factory/dataset'
import draggable from 'vuedraggable'
export default {
name: 'ChartMake',
components: {
draggable
},
data () {
return {
form: {
keys: [],
groups: [],
values: []
},
dataset: {},
datasetOptions : [],
dimensions: [],
measures: []
}
},
created () {
this.getDataSetList()
},
methods: {
getDataSetList () {
listDataSet().then(response => {
if (response.success) {
this.datasetOptions = response.data
}
})
},
handleCommand (command) {
getDataSet(command).then(response => {
if (response.success) {
this.dataset = response.data
this.dimensions = this.dataset.schemaConfig.dimensions
this.measures = this.dataset.schemaConfig.measures
}
})
},
handleKeyTagClose (index, tag) {
this.form.keys.splice(index, 1)
this.dimensions.push(tag)
},
handleGroupTagClose (index, tag) {
this.form.groups.splice(index, 1)
this.dimensions.push(tag)
},
handleValueDragChange (tag) {
if (tag.added) {
this.$set(tag.added.element, 'aggregate_type', 'sum')
}
},
handleValueChangeTagType (label, index, tag) {
this.$delete(tag, 'radio')
},
handleValueTagType (index, tag) {
this.$set(tag, 'radio', true)
},
handleValueTagClose (index, tag) {
this.form.values.splice(index, 1)
tag.aggregate_type = ''
this.measures.push(tag)
}
}
}
</script>
<style lang="scss" scoped>
.chart-container {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
.el-container {
height: 100%;
width: 100%;
.widget-field-container {
color: #333;
padding: 0;
margin-bottom: 0;
background: #FFFFFF;
box-shadow: 0 0 1px 1px #ccc;
.el-card >>> .el-card__header {
padding: 0;
border-bottom: 1px solid #EBEEF5;
-webkit-box-sizing: border-box;
box-sizing: border-box;
font-size: 16px;
background-color: lightgrey;
}
.field-widget-cate{
padding: 0px 10px;
font-size: 13px;
background-color: #f5f7fa;
border-bottom: 1px solid #e4e7ed;
.icon {
margin-right: 6px;
}
}
.field-widget-tag {
position: relative;
overflow: hidden;
padding: 10px 10px;
margin: 0;
min-height: 200px;
.field-widget-label {
font-size: 12px;
display: block;
width: 48%;
position: relative;
float: left;
left: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin: 1%;
color: #333;
border: 1px solid #F4F6FC;
&:hover {
color: #409EFF;
border: 1px dashed #409EFF;
}
& > div {
display: block;
cursor: move;
text-align: center;
}
}
}
}
.widget-config-container {
color: #333;
padding: 0;
margin-bottom: 0;
background: #FFFFFF;
box-shadow: 0 0 1px 1px #ccc;
.chart-tab-pane {
}
}
.el-main {
padding: 0;
}
.chart-action-bar {
height: 40px;
line-height: 40px;
height: 40px;
text-align: right;
color: #333;
border-bottom: 2px solid #e4e7ed;
}
.widget-center-container {
box-shadow: 0 0 1px 1px #ccc;
border: 1px dashed #999;
.draggable-wrapper {
height: 40px;
line-height: 40px;
border: 1px solid #d7dae2;
background: #f4f4f7;
margin: 0 10px;
.draggable-item {
margin: 0 5px;
display: inline-block;
border: 1px solid #ebecef;
height: 32px;
line-height: 35px;
border-radius: 4px;
.draggable-item-handle {
background-color: #ecf5ff;
border-color: #d9ecff;
display: inline-block;
height: 32px;
padding: 0 10px;
line-height: 30px;
font-size: 12px;
color: #409EFF;
border-width: 1px;
border-style: solid;
box-sizing: border-box;
white-space: nowrap;
cursor: pointer;
margin-left: -5px;
}
}
}
.data-tab-pane {
margin: 10px;
min-height: 200px;
}
.script-tab-pane {
margin: 10px;
border: 1px dashed rgb(153, 153, 153);
min-height: 200px;
}
}
}
}
</style>
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