master
tanyp 2023-04-23 16:55:41 +08:00
parent 44b0ca4601
commit b9ca3ba3cb
14 changed files with 940 additions and 94 deletions

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,42 @@
import request from '@/utils/request'
export function page(params:any){
return new Promise((resolve, reject) => {
request({
url: '/tansci/lowcode/code/page',
method: 'get',
params: params
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}
export function del(id:String){
return new Promise((resolve, reject) => {
request({
url: '/tansci/lowcode/code/delete/' + id,
method: 'delete',
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}
export function execute(param:any){
return new Promise((resolve, reject) => {
request({
url: '/tansci/lowcode/code/execute',
method: 'post',
data: param
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}

View File

@ -0,0 +1,43 @@
import request from '@/utils/request'
export function tables(params:any){
return new Promise((resolve, reject) => {
request({
url: '/tansci/source/tables',
method: 'get',
params: params
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}
export function columns(params:any){
return new Promise((resolve, reject) => {
request({
url: '/tansci/source/columns',
method: 'get',
params: params
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}
export function primary(params:any){
return new Promise((resolve, reject) => {
request({
url: '/tansci/source/primary',
method: 'get',
params: params
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import {defineProps, reactive, toRefs} from 'vue' import {defineProps, reactive, toRefs, watch} from 'vue'
import common from '@/utils/common' import common from '@/utils/common'
const prop = defineProps({ const prop = defineProps({
@ -49,7 +49,11 @@
maxHeight: window.innerHeight - 280, maxHeight: window.innerHeight - 280,
tableHeight: prop.tableHeight, tableHeight: prop.tableHeight,
headerCellStyle: prop.headerCellStyle, headerCellStyle: prop.headerCellStyle,
cellStyle: function(e){ size: 'default',
columns: prop.column.map((item:any) => {return item.prop}),
checkColAll: true,
isIndeterminate: true,
cellStyle: function(e:any){
let obj:any = {}; let obj:any = {};
emit('setCellColor', e, (color = {}) =>{ emit('setCellColor', e, (color = {}) =>{
obj = color; obj = color;
@ -59,20 +63,42 @@
}, },
}) })
const { const {
maxHeight,tableHeight,headerCellStyle,cellStyle, maxHeight,tableHeight,headerCellStyle,cellStyle,size,columns,checkColAll,isIndeterminate
} = toRefs(state) } = toRefs(state)
const onSizeChange = (e) =>{ const onSizeChange = (e:any) =>{
emit('onSizeChange', e) emit('onSizeChange', e)
} }
const onCurrentChange = (e) =>{ const onCurrentChange = (e:any) =>{
emit('onCurrentChange', e) emit('onCurrentChange', e)
} }
function onFind(arr:any,val:any){ function onFind(arr:any,val:any){
if(!arr) return 'info'; if(!arr) return 'info';
return arr.find(v=>{ return v.value == val}).label; return arr.find((item:any)=>{ return item.value == val}).label;
} }
function onCheckColAll(val:boolean){
const _columns = prop.column.map((item:any) => {return item.prop})
state.columns = val ? _columns : []
state.isIndeterminate = false
}
function onCheckedCol(value: string[]){
let checkedCount = value.length
state.checkColAll = checkedCount === prop.column.length
state.isIndeterminate = checkedCount > 0 && checkedCount < prop.column.length
}
watch(columns, (newValue, oldValue) =>{
prop.column.filter((item:any) =>{
if(newValue.indexOf(item.prop) != -1){
item.isShow = false
}else{
item.isShow = true
}
})
})
</script> </script>
<template> <template>
<div class="table-container"> <div class="table-container">
@ -80,20 +106,51 @@
<slot name="search"></slot> <slot name="search"></slot>
</div> </div>
<div class="table-wrap"> <div class="table-wrap">
<el-table :data="data" border stripe size="mini" :height="tableHeight" :max-height="maxHeight" row-key="id" :tree-props="{children: 'children', hasChildren: 'hasChildren'}" <div class="header">
<el-popover placement="bottom" :width="80" trigger="click">
<template #reference>
<el-button link>
<el-icon :size="20"><Sort /></el-icon>
</el-button>
</template>
<div>
<el-radio-group v-model="size">
<el-radio label="small">紧凑</el-radio>
<el-radio label="default">默认</el-radio>
<el-radio label="large">中等</el-radio>
</el-radio-group>
</div>
</el-popover>
<el-popover placement="bottom" :width="120" trigger="click">
<template #reference>
<el-button link>
<el-icon :size="20"><Setting /></el-icon>
</el-button>
</template>
<div>
<el-checkbox v-model="checkColAll" :indeterminate="isIndeterminate" @change="onCheckColAll">/</el-checkbox>
<el-scrollbar height="400px">
<el-checkbox-group v-model="columns" @change="onCheckedCol" >
<el-checkbox v-for="col in column" :key="col" :label="col.prop">{{col.label}}</el-checkbox>
</el-checkbox-group>
</el-scrollbar>
</div>
</el-popover>
</div>
<el-table :data="data" border stripe :size="size" :height="tableHeight" :max-height="maxHeight" row-key="id" :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
v-loading="loading" :header-cell-style="headerCellStyle" :cell-style="cellStyle" v-loading="loading" :header-cell-style="headerCellStyle" :cell-style="cellStyle"
@selection-change="onSelectionChange" style="width: 100%;"> @selection-change="onSelectionChange" style="width: 100%;">
<template v-for="item in column" :key="item"> <template v-for="item in column" :key="item">
<el-table-column v-if="!item.prop && !item.label" :fixed="item.fixed" type="selection" width="45"></el-table-column> <el-table-column v-if="!item.prop && !item.label && !item.isShow" :fixed="item.fixed" type="selection" width="45"></el-table-column>
<!-- color值 --> <!-- color值 -->
<el-table-column v-else-if="item.type == 'color'" <el-table-column v-else-if="item.type == 'color' && !item.isShow"
:label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width"> :label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width">
<template #default="scope"> <template #default="scope">
<span :style="{color: scope.row[item.prop]}">{{scope.row[item.prop]}}</span> <span :style="{color: scope.row[item.prop]}">{{scope.row[item.prop]}}</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- icon图标 --> <!-- icon图标 -->
<el-table-column v-else-if="item.type == 'icon'" <el-table-column v-else-if="item.type == 'icon' && !item.isShow"
:label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width"> :label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width">
<template #default="scope"> <template #default="scope">
<el-icon :size="20"> <el-icon :size="20">
@ -102,7 +159,7 @@
</template> </template>
</el-table-column> </el-table-column>
<!-- el-statistic --> <!-- el-statistic -->
<el-table-column v-else-if="item.type == 'statistic'" <el-table-column v-else-if="item.type == 'statistic' && !item.isShow"
:label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width"> :label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width">
<template #default="scope"> <template #default="scope">
<el-statistic :value="scope.row[item.prop]" <el-statistic :value="scope.row[item.prop]"
@ -113,21 +170,21 @@
</template> </template>
</el-table-column> </el-table-column>
<!-- el-image --> <!-- el-image -->
<el-table-column v-else-if="item.type == 'image'" <el-table-column v-else-if="item.type == 'image' && !item.isShow"
:label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width"> :label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width">
<template #default="scope"> <template #default="scope">
<el-image :src="scope.row[item.prop]" :preview-src-list="[scope.row[item.prop]]" :z-index="9999" fit="cover" style="width: 50px; height: 50px"/> <el-image :src="scope.row[item.prop]" :preview-src-list="[scope.row[item.prop]]" :z-index="9999" fit="cover" style="width: 50px; height: 50px"/>
</template> </template>
</el-table-column> </el-table-column>
<!-- el-rate --> <!-- el-rate -->
<el-table-column v-else-if="item.type == 'rate'" <el-table-column v-else-if="item.type == 'rate' && !item.isShow"
:label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width"> :label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width">
<template #default="scope"> <template #default="scope">
<el-rate v-model="scope.row[item.prop]" disabled allow-half /> <el-rate v-model="scope.row[item.prop]" disabled allow-half />
</template> </template>
</el-table-column> </el-table-column>
<!-- el-tag --> <!-- el-tag -->
<el-table-column v-else-if="item.type == 'tag'" show-overflow-tooltip <el-table-column v-else-if="item.type == 'tag' && !item.isShow" show-overflow-tooltip
:label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width"> :label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width">
<template #default="scope"> <template #default="scope">
<el-tag :size="item.option.size" <el-tag :size="item.option.size"
@ -138,7 +195,7 @@
</template> </template>
</el-table-column> </el-table-column>
<!-- el-button --> <!-- el-button -->
<el-table-column v-else-if="item.type == 'button'" show-overflow-tooltip <el-table-column v-else-if="item.type == 'button' && !item.isShow" show-overflow-tooltip
:label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width"> :label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width">
<template #default="scope"> <template #default="scope">
<el-button @click="$emit('onButtonClick',scope.row)" :type="item.option.type" link :size="item.option.size"> <el-button @click="$emit('onButtonClick',scope.row)" :type="item.option.type" link :size="item.option.size">
@ -147,7 +204,7 @@
</template> </template>
</el-table-column> </el-table-column>
<!-- el-switch --> <!-- el-switch -->
<el-table-column v-else-if="item.type == 'switch'" show-overflow-tooltip <el-table-column v-else-if="item.type == 'switch' && !item.isShow" show-overflow-tooltip
:label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width"> :label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width">
<template #default="scope"> <template #default="scope">
<el-switch @change="$emit('onSwitchChange',scope.row)" :inline-prompt="item.option.inlinePrompt?false:true" <el-switch @change="$emit('onSwitchChange',scope.row)" :inline-prompt="item.option.inlinePrompt?false:true"
@ -159,7 +216,7 @@
</template> </template>
</el-table-column> </el-table-column>
<!-- el-progress --> <!-- el-progress -->
<el-table-column v-else-if="item.type == 'progress'" show-overflow-tooltip <el-table-column v-else-if="item.type == 'progress' && !item.isShow" show-overflow-tooltip
:label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width"> :label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width">
<template #default="scope"> <template #default="scope">
<el-progress :percentage="scope.row[item.alias==null?item.prop:item.alias]" <el-progress :percentage="scope.row[item.alias==null?item.prop:item.alias]"
@ -168,14 +225,14 @@
</template> </template>
</el-table-column> </el-table-column>
<!-- 字典值 --> <!-- 字典值 -->
<el-table-column v-else-if="item.type == 'dict'" <el-table-column v-else-if="item.type == 'dict' && !item.isShow"
:label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width"> :label="item.label" :align="item.align != null ? item.align : 'center'" :width="item.width">
<template #default="scope"> <template #default="scope">
<span>{{common.getDictLabel(item.dictType, scope.row[item.prop])}}</span> <span>{{common.getDictLabel(item.dictType, scope.row[item.prop])}}</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- 其他数据列 --> <!-- 其他数据列 -->
<el-table-column v-else show-overflow-tooltip <el-table-column v-else-if="!item.isShow" show-overflow-tooltip
:prop="item.alias==null?item.prop:item.alias" :prop="item.alias==null?item.prop:item.alias"
:label="item.label" :label="item.label"
:align="item.align != null ? item.align : 'center'" :align="item.align != null ? item.align : 'center'"

View File

@ -1,6 +1,6 @@
$--colors: ( $--colors: (
"primary": ( "primary": (
"base": #2F9688, "base": #45a79a,
), ),
"success": ( "success": (
"base": #21ba45, "base": #21ba45,

View File

@ -3,7 +3,7 @@
:root { :root {
// //
--theme: #2F9688; --theme: #45a79a;
// //
--t: #1d1d1f; --t: #1d1d1f;
@ -49,29 +49,36 @@ body {
*/ */
.table-container{ .table-container{
.search-wrap{ .search-wrap{
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
// background: var(--bg1); // background: var(--bg1);
border: 1px solid var(--el-border-color);
border-radius: var(--el-border-radius-base);
padding: 1.2rem 0;
} }
.search-wrap>div{ .search-wrap>div{
line-height: 40px; line-height: 40px;
padding: 0.2rem 0.8rem; padding: 0.2rem 0.8rem;
} }
.button-wrap{ .button-wrap{
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
padding-top: 0.6rem; padding-top: 0.6rem;
} }
.button-wrap>div{ .button-wrap>div{
line-height: 40px; line-height: 40px;
padding: 0.2rem 0.8rem; padding: 0.2rem 0.8rem;
} }
.table-wrap{ .table-wrap{
padding: 1rem 0; padding: 1rem 0;
.header{
float: right;
padding-bottom: 0.4rem;
}
} }
.pagination-wrap{ .pagination-wrap{
padding-bottom: 0.2rem; padding-bottom: 0.2rem;
text-align: right; float: right;
} }
} }

View File

@ -2,7 +2,10 @@
import { reactive, onMounted } from "vue" import { reactive, onMounted } from "vue"
const state = reactive({ const state = reactive({
versionList: [
{content:'项目初始化',timestamp:'2023-04-01'},
{content:'项目初始化',timestamp:'2023-04-01'},
]
}) })
onMounted(()=>{ onMounted(()=>{
@ -12,11 +15,76 @@
</script> </script>
<template> <template>
<div class="home-container"> <div class="home-container">
首页 <el-card shadow="never">
<template #header>
<span>公告</span>
</template>
<div>
<div>
<span class="title">Tansci Boot</span>
<el-divider direction="vertical" />
<el-link type="primary" href="https://gitee.com/typ1805" target="_blank">Gitee</el-link>
<el-divider direction="vertical" />
<el-link type="primary" href="https://github.com/typ1805" target="_blank">GitHub</el-link>
</div>
<div class="text">
<el-space alignment="normal" direction="vertical">
<el-text tag="p">一款基于 SpringBoot + Vue3.2 + Element Plus 的后台管理系统带你快速掌握SpringBoot核心知识 + Vue全家桶全栈技能在此过程中从0到1经历开发全流程掌握前后端分离开发模式搭建一个专属自己的内容可灵活配置的知识库系统</el-text>
<el-text tag="p">此项目是为了减少业务代码的重复轮子,它具有一个系统该有的通用性核心业务代码,无论是微服务还是单体,都是通用的业务 但更多的,是为了学习微服务的理念以及开发 您可以使用它进行网站管理后台网站会员中心CMSCRMOA等待系统的开发, 当然,不仅仅是一些小系统,我们可以生产更多的服务模块,不断完善项目</el-text>
<el-text tag="p">系统初心是为了能够更快地完成业务的需求带来更好的体验更多的时间它将会用于孵化一些实用的功能点 我们希望它们是轻量级可移植性高的功能插件</el-text>
<el-text tag="p">同时我们更希望广大开发者能在其中更快地获得更好的解决方案尽量降低我们的学习成本 由此我们应当把更多的时间投入到其它更有意义的事情当中我们深知知识的重要性并不希望仅拥有单一知识 去感受/关爱更多光彩无论人它们也将成为你最好的灵感</el-text>
</el-space>
</div>
</div>
</el-card>
<div class="cards">
<el-card shadow="never">
<template #header>
<span>官方信息</span>
</template>
<div>
<div>
<el-text>官网</el-text>
<el-link type="success" href="https://typ1805.gitee.io" target="_blank">https://typ1805.gitee.io</el-link>
</div>
<div style="padding-top: 1rem;">
<el-text>交流群</el-text>
<el-link type="success">747200630</el-link>
</div>
</div>
</el-card>
<el-card shadow="never" style="flex: 1;">
<template #header>
<span>Tansci发展史</span>
</template>
<div>
<el-timeline>
<el-timeline-item v-for="item in state.versionList" :key="item" :timestamp="item.timestamp">
{{ item.content }}
</el-timeline-item>
</el-timeline>
</div>
</el-card>
</div>
</div> </div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.home-container{ .home-container{
.title{
font-size: 20px;
font-weight: 700;
}
.text{
padding: 2rem 0;
}
.el-card{
margin: 1rem 0;
}
.cards{
display: flex;
.el-card{
margin-right: 1rem;
}
}
} }
</style> </style>

View File

@ -1,18 +1,197 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, onMounted } from "vue" import { reactive, onMounted, ref } from "vue"
import {ElMessage, ElMessageBox} from 'element-plus'
import type {FormInstance} from 'element-plus'
import Table from '@/components/Table.vue'
import { page, del, execute } from "@/api/lowcode/codeGen"
import { tables, columns, primary } from "@/api/lowcode/source"
const state = reactive({ const searchForm = reactive({
shadow: 'always', tableName: null
})
const table = reactive({
loading: false,
page: {
current: 1,
size: 10,
total: 1,
},
operation:{
isShow: true,
width: '240'
},
tableTitle: [
{prop:'dataSource',label:'数据源'},
{prop:'tableName',label:'表名'},
{prop:'tableComment',label:'表注释'},
{prop:'subTableName',label:'子表名称'},
{prop:'subTableComment',label:'子表注释'},
{prop:'updateTime',label:'更新时间'},
{prop:'createTime',label:'创建时间'}
],
tableData:[],
}) })
onMounted(()=>{ onMounted(()=>{
onCodeGenPage()
}) })
function onCodeGenPage(){
table.loading = true;
page(Object.assign(table.page, searchForm)).then((res:any)=>{
if(res){
table.loading = false;
table.tableData = res.result.records;
table.page.current = res.result.current;
table.page.size = res.result.size;
table.page.total = res.result.total;
}
})
}
function onSizeChange(e){
table.page.size = e;
onCodeGenPage();
}
function onCurrentChange(e){
table.page.current = e;
onCodeGenPage();
}
function onRefresh(){
searchForm.tableName = null
onCodeGenPage();
}
function onSearch(){
onCodeGenPage();
}
const formRef = ref<FormInstance>()
const form = reactive({
tableList: [],
columnList: [],
primary:'',
tabsActive: 'table',
codeVisible: false,
codeForm: {
tableName: '',
tableSchema: '',
tableComment: '',
}
})
function onTables(){
tables({name: 'tansci_boot'}).then((res:any)=>{
form.tableList = res.result
})
}
function onColumns(name:String){
columns({name: name}).then((res:any)=>{
form.columnList = res.result
})
}
function onPrimary(name:String){
primary({name: name}).then((res:any)=>{
form.primary = res.result
})
}
function onDelete(val:any){
ElMessageBox.confirm('此操作将永久删除, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
del(val.column.row.id).then(res=>{
if(res){
ElMessage.success('删除成功!');
onCodeGenPage();
}
})
}).catch(e=>{
console.log(e)
})
}
function onAdd(){
onTables()
form.tabsActive = 'table'
form.codeVisible = true
}
function onTabsClick(tab:any){
form.tabsActive = tab.paneName.value
}
function onTablechange(val:any){
let table = form.tableList.find(item => val == item.tableName )
form.codeForm.tableComment = table.tableComment
form.codeForm.tableSchema = table.tableSchema
}
const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid)=>{
if(valid){
execute(form.codeForm).then(res=>{
if(res){
ElMessage.success("添加成功!");
onCodeGenPage()
}
})
form.codeVisible = false
}
})
}
</script> </script>
<template> <template>
<div class="codegen-container"> <div class="codegen-container">
开发中 <Table :data="table.tableData" :column="table.tableTitle" :operation="table.operation" :page="table.page" :loading="table.loading"
@onSizeChange="onSizeChange" @onCurrentChange="onCurrentChange">
<template #search>
<div><el-button type="primary" @click="onAdd"></el-button></div>
<div><el-input v-model="searchForm.tableName" placeholder="请输入表名"></el-input></div>
<div><el-button @click="onRefresh" icon="RefreshRight" circle></el-button></div>
<div><el-button @click="onSearch" type="primary" icon="Search">查询</el-button></div>
</template>
<template #column="scope">
<el-button @click="onDelete(scope)" type='primary' link style="color:var(--delete); padding:0;">删除</el-button>
</template>
</Table>
<el-dialog title="代码生成" v-model="form.codeVisible" :show-close="false" width="50%">
<el-form :model="form.codeForm" ref="formRef" :rules="rules" label-width="80px" status-icon>
<el-tabs v-model="form.tabsActive" tab-position="left" @tab-click="onTabsClick">
<el-tab-pane name="table" label="表信息">
<el-form-item label="表名" prop="tableName" :rules="[{required: true,message:'请选择表',trigger: 'change'}]">
<el-select v-model="form.codeForm.tableName" @change="onTablechange" placeholder="请选表" style="width: 100%">
<el-option v-for="item in form.tableList" :key="item.tableName" :label="item.tableName" :value="item.tableName">
<span style="float: left">{{ item.tableName }}</span>
<span style="float: right;color: var(--el-text-color-secondary);">{{ item.tableComment }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="描述" prop="tableComment" :rules="[{required: true,message:'请输入描述',trigger: 'blur'}]">
<el-input v-model="form.codeForm.tableComment" placeholder="请输入描述" style="width: 100%"/>
</el-form-item>
</el-tab-pane>
<el-tab-pane name="column" label="字段信息">
</el-tab-pane>
<el-tab-pane name="code" label="生成信息">
</el-tab-pane>
</el-tabs>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="form.codeVisible = false">取消</el-button>
<el-button type="primary" @click="onSubmit(formRef)"></el-button>
</span>
</template>
</el-dialog>
</div> </div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -0,0 +1,57 @@
package com.tansci.controller;
import com.tansci.common.WrapMapper;
import com.tansci.common.Wrapper;
import com.tansci.common.annotation.Log;
import com.tansci.common.constant.Constants;
import com.tansci.domain.vo.ColumnsVo;
import com.tansci.domain.vo.TablesVo;
import com.tansci.service.DataSourceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @ClassName DataSourceController.java
* @ClassPath com.tansci.controller.DataSourceController.java
* @Description
* @Author tanyp
* @Date 2023/4/23 15:19
**/
@Slf4j
@RestController
@RequestMapping("/source")
@Api(value = "source", tags = "数据源")
public class DataSourceController {
@Autowired
private DataSourceService dataSourceService;
@ApiOperation(value = "数据表", notes = "数据表")
@Log(modul = "数据源", type = Constants.SELECT, desc = "数据表")
@GetMapping("/tables")
public Wrapper<List<TablesVo>> tables(String name) {
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, dataSourceService.tables(name));
}
@ApiOperation(value = "数据列", notes = "数据列")
@Log(modul = "数据列", type = Constants.SELECT, desc = "数据列")
@GetMapping("/columns")
public Wrapper<List<ColumnsVo>> columns(String name) {
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, dataSourceService.columns(name));
}
@ApiOperation(value = "获取住建", notes = "获取住建")
@Log(modul = "数据源", type = Constants.SELECT, desc = "获取住建")
@GetMapping("/primary")
public Wrapper<Object> primary(String name) {
return WrapMapper.wrap(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, dataSourceService.primary(name));
}
}

View File

@ -0,0 +1,48 @@
package com.tansci.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @ClassName ColumnsVo.java
* @ClassPath com.tansci.domain.vo.ColumnsVo.java
* @Description
* @Author tanyp
* @Date 2023/4/23 15:00
**/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "数据列")
public class ColumnsVo {
@ApiModelProperty(value = "数据库")
private String tableSchema;
@ApiModelProperty(value = "数据表")
private String tableName;
@ApiModelProperty(value = "列名称")
private String columnName;
@ApiModelProperty(value = "列描述")
private String columnComment;
@ApiModelProperty(value = "数据类型")
private String dataType;
@ApiModelProperty(value = "是否为空")
private String isNullable;
@ApiModelProperty(value = "列类型")
private String columnType;
@ApiModelProperty(value = "列长")
private String columnLength;
}

View File

@ -0,0 +1,33 @@
package com.tansci.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @ClassName TablesVo.java
* @ClassPath com.tansci.domain.vo.TablesVo.java
* @Description
* @Author tanyp
* @Date 2023/4/23 14:53
**/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "数据表")
public class TablesVo {
@ApiModelProperty(value = "数据库")
private String tableSchema;
@ApiModelProperty(value = "数据表")
private String tableName;
@ApiModelProperty(value = "描述")
private String tableComment;
}

View File

@ -0,0 +1,30 @@
package com.tansci.mapper;
import com.tansci.domain.vo.ColumnsVo;
import com.tansci.domain.vo.TablesVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @ClassName DataSourceMapper.java
* @ClassPath com.tansci.mapper.DataSourceMapper.java
* @Description
* @Author tanyp
* @Date 2023/4/23 14:44
**/
@Mapper
public interface DataSourceMapper {
@Select("select table_schema,table_name,table_comment from information_schema.tables where table_schema = #{sourceName}")
List<TablesVo> tables(@Param("sourceName") String sourceName);
@Select("select table_schema,table_name,column_name,column_comment,column_type,data_type,is_nullable,CHARACTER_MAXIMUM_LENGTH as columnLength from information_schema.columns where table_name = #{tableName}")
List<ColumnsVo> columns(@Param("tableName") String tableName);
@Select("select column_name from information_schema.columns where table_name = #{tableName} and column_key = 'PRI' and table_schema = database() limit 1")
String primary(@Param("tableName") String tableName);
}

View File

@ -0,0 +1,23 @@
package com.tansci.service;
import com.tansci.domain.vo.ColumnsVo;
import com.tansci.domain.vo.TablesVo;
import java.util.List;
/**
* @ClassName DataSourceService.java
* @ClassPath com.tansci.service.DataSourceService.java
* @Description
* @Author tanyp
* @Date 2023/4/23 15:20
**/
public interface DataSourceService {
List<TablesVo> tables(String sourceName);
List<ColumnsVo> columns(String tableName);
String primary(String tableName);
}

View File

@ -0,0 +1,41 @@
package com.tansci.service.impl;
import com.tansci.domain.vo.ColumnsVo;
import com.tansci.domain.vo.TablesVo;
import com.tansci.mapper.DataSourceMapper;
import com.tansci.service.DataSourceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @ClassName DataSourceServiceImpl.java
* @ClassPath com.tansci.service.impl.DataSourceServiceImpl.java
* @Description
* @Author tanyp
* @Date 2023/4/23 15:20
**/
@Slf4j
@Service
public class DataSourceServiceImpl implements DataSourceService {
@Autowired
private DataSourceMapper dataSourceMapper;
@Override
public List<TablesVo> tables(String sourceName) {
return dataSourceMapper.tables(sourceName);
}
@Override
public List<ColumnsVo> columns(String tableName) {
return dataSourceMapper.columns(tableName);
}
@Override
public String primary(String tableName) {
return dataSourceMapper.primary(tableName);
}
}