This commit is contained in:
tanyp 2023-07-07 17:20:23 +08:00
parent 7d27d97aea
commit 4417a6fad6
41 changed files with 401 additions and 1911 deletions

View File

@ -3,26 +3,6 @@
#### 介绍
Tansci Boot
#### 软件架构
软件架构说明
#### 安装教程
1. xxxx
2. xxxx
3. xxxx
#### 使用说明
1. xxxx
2. xxxx
3. xxxx
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
版本2.0.0
api 接口全部使用 magic-api 方式

View File

@ -11,7 +11,7 @@
<groupId>com.tansci</groupId>
<artifactId>tansci-boot-parent</artifactId>
<version>1.0.0</version>
<version>2.0.0</version>
<packaging>pom</packaging>
<name>tansci-boot-parent</name>

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
VITE_BASE_API = 'http://localhost:8000/'
VITE_BASE_API = 'http://localhost:8000'
VITE_EDITOR_URL = 'http://localhost:5173'

View File

@ -1 +1 @@
window.common={API_QUERY_URL:"http://localhost:5173/tansci/lcPages/get/",API_SAVE_URL:"http://localhost:5173/tansci/lcPages/update",TOKEN_KEY:"token"};
window.common={API_QUERY_URL:"http://localhost:5173/lowcode/lcPages/get/",API_SAVE_URL:"http://localhost:5173/lowcode/lcPages/update",TOKEN_KEY:"token"};

View File

@ -34,7 +34,7 @@ export function setMenus(menus:any) {
export function login(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/auth/login',
url: '/tansci/system/auth/login',
method: 'post',
data: {
username: data.username,
@ -53,7 +53,7 @@ export function login(data:any){
// 登出
export function logout(){
request({
url: '/system/auth/logout',
url: '/tansci/system/auth/logout',
method: 'get'
}).then(() => {
removeToken()
@ -65,7 +65,7 @@ export function logout(){
export function getCode(){
return new Promise((resolve, reject) => {
request({
url: '/system/auth/code',
url: '/tansci/system/auth/code',
method: 'get'
}).then((res:any) => {
resolve(res)
@ -77,7 +77,7 @@ export function getCode(){
export async function getUserInfo() {
await request({
url: '/system/user/info',
url: '/tansci/system/user/info',
method: 'get'
}).then((res:any) => {
if(res.data.result){

View File

@ -1,56 +0,0 @@
import request from '@/utils/request'
export function page(params:any){
return new Promise((resolve, reject) => {
request({
url: '/system/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: '/system/lowcode/code/delete/' + id,
method: 'delete',
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}
export function save(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/lowcode/code/save',
method: 'post',
data
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}
export function execute(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/lowcode/code/execute',
method: 'post',
data
}).then((res:any) => {
resolve(res.data)
}).catch((e:any) => {
reject(e)
})
})
}

View File

@ -3,7 +3,7 @@ import request from '@/utils/request'
export function page(params:any){
return new Promise((resolve, reject) => {
request({
url: '/system/lcPages/page',
url: '/tansci/lowcode/lcPages/page',
method: 'get',
params: params
}).then((res:any) => {
@ -17,7 +17,7 @@ export function page(params:any){
export function getPagesInfo(menuId:String){
return new Promise((resolve, reject) => {
request({
url: '/system/lcPages/getPagesInfo/' + menuId,
url: '/tansci/lowcode/lcPages/pagesInfo/' + menuId,
method: 'get'
}).then((res:any) => {
resolve(res.data)
@ -30,7 +30,7 @@ export function getPagesInfo(menuId:String){
export function save(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/lcPages/save',
url: '/tansci/lowcode/lcPages/save',
method: 'post',
data
}).then((res:any) => {
@ -44,7 +44,7 @@ export function save(data:any){
export function update(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/lcPages/update',
url: '/tansci/lowcode/lcPages/update',
method: 'post',
data
}).then((res:any) => {
@ -58,7 +58,7 @@ export function update(data:any){
export function bindMenu(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/lcPages/bindMenu',
url: '/tansci/lowcode/lcPages/bindMenu',
method: 'post',
data
}).then((res:any) => {
@ -72,7 +72,7 @@ export function bindMenu(data:any){
export function del(id:String){
return new Promise((resolve, reject) => {
request({
url: '/system/lcPages/delete/' + id,
url: '/tansci/lowcode/lcPages/delete/' + id,
method: 'get',
}).then((res:any) => {
resolve(res.data)
@ -85,7 +85,7 @@ export function del(id:String){
export function batchDelete(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/lcPages/batchDelete',
url: '/tansci/lowcode/lcPages/batchDelete',
method: 'post',
data
}).then((res:any) => {

View File

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

View File

@ -4,7 +4,7 @@ import request from '@/utils/request'
export function page(params:any){
return new Promise((resolve, reject) => {
request({
url: '/system/syslog/loginLog',
url: '/tansci/monitor/loginLog',
method: 'get',
params: params
}).then((res:any) => {

View File

@ -3,7 +3,7 @@ import request from '@/utils/request'
export function page(params:any){
return new Promise((resolve, reject) => {
request({
url: '/system/auth/onlineUser',
url: '/tansci/monitor/onlineUser',
method: 'get',
params: params
}).then((res:any) => {
@ -17,7 +17,7 @@ export function page(params:any){
export function kick(token:String){
return new Promise((resolve, reject) => {
request({
url: '/system/auth/kick/' + token,
url: '/tansci/monitor/kick/' + token,
method: 'get'
}).then((res:any) => {
resolve(res.data)

View File

@ -4,7 +4,7 @@ import request from '@/utils/request'
export function page(params:any){
return new Promise((resolve, reject) => {
request({
url: '/system/syslog/operLog',
url: '/tansci/monitor/operLog',
method: 'get',
params: params
}).then((res:any) => {

View File

@ -4,7 +4,7 @@ import request from '@/utils/request'
export function tree(params:any){
return new Promise((resolve, reject) => {
request({
url: '/system/dict/tree',
url: '/tansci/system/dict/tree',
method: 'get',
params: params
}).then((res:any) => {
@ -19,7 +19,7 @@ export function tree(params:any){
export function list(params:any){
return new Promise((resolve, reject) => {
request({
url: '/system/dict/list',
url: '/tansci/system/dict/list',
method: 'get',
params: params
}).then((res:any) => {
@ -34,7 +34,7 @@ export function list(params:any){
export function save(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/dict/save',
url: '/tansci/system/dict/save',
method: 'post',
data: data
}).then((res:any) => {
@ -49,7 +49,7 @@ export function save(data:any){
export function del(id:String){
return new Promise((resolve, reject) => {
request({
url: '/system/dict/delete/' + id,
url: '/tansci/system/dict/delete/' + id,
method: 'get'
}).then((res:any) => {
resolve(res.data)
@ -63,7 +63,7 @@ export function del(id:String){
export function update(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/dict/update',
url: '/tansci/system/dict/update',
method: 'post',
data: data
}).then((res:any) => {

View File

@ -4,7 +4,7 @@ import request from '@/utils/request'
export function list(params:any){
return new Promise((resolve, reject) => {
request({
url: '/system/menu/tree',
url: '/tansci/system/menu/tree',
method: 'get',
params: params
}).then((res:any) => {
@ -19,7 +19,7 @@ export function list(params:any){
export function save(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/menu/save',
url: '/tansci/system/menu/save',
method: 'post',
data: data
}).then((res:any) => {
@ -34,7 +34,7 @@ export function save(data:any){
export function update(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/menu/update',
url: '/tansci/system/menu/update',
method: 'post',
data: data
}).then((res:any) => {
@ -49,7 +49,7 @@ export function update(data:any){
export function del(id:any){
return new Promise((resolve, reject) => {
request({
url: '/system/menu/delete/' + id,
url: '/tansci/system/menu/delete/' + id,
method: 'get'
}).then((res:any) => {
resolve(res.data)

View File

@ -4,7 +4,7 @@ import request from '@/utils/request'
export function list(params:any){
return new Promise((resolve, reject) => {
request({
url: '/system/org/list',
url: '/tansci/system/org/list',
method: 'get',
params: params
}).then((res:any) => {
@ -19,7 +19,7 @@ export function list(params:any){
export function save(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/org/save',
url: '/tansci/system/org/save',
method: 'post',
data: data
}).then((res:any) => {
@ -34,7 +34,7 @@ export function save(data:any){
export function del(id:String){
return new Promise((resolve, reject) => {
request({
url: '/system/org/delete/' + id,
url: '/tansci/system/org/delete/' + id,
method: 'get'
}).then((res:any) => {
resolve(res.data)
@ -48,7 +48,7 @@ export function del(id:String){
export function update(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/org/update',
url: '/tansci/system/org/update',
method: 'post',
data: data
}).then((res:any) => {

View File

@ -4,7 +4,7 @@ import request from '@/utils/request'
export function page(params:any){
return new Promise((resolve, reject) => {
request({
url: '/system/role/page',
url: '/tansci/system/role/page',
method: 'get',
params: params
}).then((res:any) => {
@ -19,7 +19,7 @@ export function page(params:any){
export function list(params:any){
return new Promise((resolve, reject) => {
request({
url: '/system/role/list',
url: '/tansci/system/role/list',
method: 'get',
params: params
}).then((res:any) => {
@ -34,7 +34,7 @@ export function list(params:any){
export function save(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/role/save',
url: '/tansci/system/role/save',
method: 'post',
data: data
}).then((res:any) => {
@ -49,7 +49,7 @@ export function save(data:any){
export function del(id:String){
return new Promise((resolve, reject) => {
request({
url: '/system/role/delete/' + id,
url: '/tansci/system/role/delete/' + id,
method: 'get'
}).then((res:any) => {
resolve(res.data)
@ -63,7 +63,7 @@ export function del(id:String){
export function update(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/role/update',
url: '/tansci/system/role/update',
method: 'post',
data: data
}).then((res:any) => {
@ -78,7 +78,7 @@ export function update(data:any){
export function dataPermissions(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/role/dataPermissions',
url: '/tansci/system/role/dataPermissions',
method: 'post',
data: data
}).then((res:any) => {
@ -92,7 +92,7 @@ export function dataPermissions(data:any){
export function orgList(roleId:String){
return new Promise((resolve, reject) => {
request({
url: '/system/role/orgList/' + roleId,
url: '/tansci/system/role/orgList/' + roleId,
method: 'get'
}).then((res:any) => {
resolve(res.data)
@ -106,7 +106,7 @@ export function orgList(roleId:String){
export function menuPermissions(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/role/menuPermissions',
url: '/tansci/system/role/menuPermissions',
method: 'post',
data: data
}).then((res:any) => {
@ -120,7 +120,7 @@ export function menuPermissions(data:any){
export function menuList(roleId:String){
return new Promise((resolve, reject) => {
request({
url: '/system/role/menuList/' + roleId,
url: '/tansci/system/role/menuList/' + roleId,
method: 'get'
}).then((res:any) => {
resolve(res.data)

View File

@ -4,7 +4,7 @@ import request from '@/utils/request'
export function page(params:any){
return new Promise((resolve, reject) => {
request({
url: '/system/user/page',
url: '/tansci/system/user/page',
method: 'get',
params: params
}).then((res:any) => {
@ -19,7 +19,7 @@ export function page(params:any){
export function list(params:any){
return new Promise((resolve, reject) => {
request({
url: '/system/user/list',
url: '/tansci/system/user/list',
method: 'get',
params: params
}).then((res:any) => {
@ -34,7 +34,7 @@ export function list(params:any){
export function save(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/user/save',
url: '/tansci/system/user/save',
method: 'post',
data: data
}).then((res:any) => {
@ -49,7 +49,7 @@ export function save(data:any){
export function del(id:String){
return new Promise((resolve, reject) => {
request({
url: '/system/user/delete/' + id,
url: '/tansci/system/user/delete/' + id,
method: 'get'
}).then((res:any) => {
resolve(res.data)
@ -63,7 +63,7 @@ export function del(id:String){
export function update(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/user/update',
url: '/tansci/system/user/update',
method: 'post',
data: data
}).then((res:any) => {
@ -78,7 +78,7 @@ export function update(data:any){
export function modifyPass(data:any){
return new Promise((resolve, reject) => {
request({
url: '/system/user/modifyPass',
url: '/tansci/system/user/modifyPass',
method: 'post',
data: data
}).then((res:any) => {
@ -93,7 +93,7 @@ export function modifyPass(data:any){
export function roleList(){
return new Promise((resolve, reject) => {
request({
url: '/system/role/list',
url: '/tansci/system/role/list',
method: 'get'
}).then((res:any) => {
resolve(res.data)

View File

@ -23,9 +23,9 @@ router.beforeEach(async (to:any, from:any, next) => {
}
if(getToken()){
// if(to.path === '/login'){
// next({ path: '/index' })
// } else {
if(to.path === '/login'){
next({ path: '/index' })
} else {
if(load){
next()
} else {
@ -51,7 +51,7 @@ router.beforeEach(async (to:any, from:any, next) => {
next(`/login`)
}
}
// }
}
} else {
if(whiteList.indexOf(to.path) !== -1){
next()

View File

@ -55,7 +55,7 @@ export const loadView = (view:any) => {
export function generateRoutes(){
return new Promise((resolve, reject) => {
request({
url: '/system/menu/menus',
url: '/tansci/system/menu/menus',
method: 'get'
}).then( (res:any) => {
const routers = filterRouter(res.data.result, 0)

View File

@ -1,384 +0,0 @@
<script setup lang="ts">
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, save, execute } from "@/api/lowcode/codeGen"
import { tables, columns } from "@/api/lowcode/source"
const searchForm = reactive({
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(()=>{
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();
}
var validatePath = (rule:any, value:any, callback:any) => {
if(!value.startsWith('/')){
callback(new Error('请以“/”开头'));
}else if(value.endsWith('/')){
callback(new Error('不能以“/”结尾'));
}else{
callback();
}
}
const formRef = ref<FormInstance>()
const form = reactive({
tableList: [],
primary:'',
tabsActive: 'table',
codeVisible: false,
templates: [
{ label: '单表(增删改查)', value: 'single' },
{ label: '树表(增删改查)', value: 'tree' },
{ label: '主子表(增删改查)', value: 'subTable' }
],
codeForm: {
tableName: '',
dataSource: '',
tableComment: '',
info: {
moduleName: '',
modulePath: '',
businessName: '',
businessPath: '',
template: 'single',
pid: '',
treeId: '',
treePid: '',
subTable: '',
subTableKey: ''
},
columns: [],
subColumns: []
}
})
function onTables(){
tables({name: 'tansci_boot'}).then((res:any)=>{
form.tableList = 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.codeForm = {
tableName: '',
dataSource: '',
tableComment: '',
info: {
moduleName: '',
modulePath: '',
businessName: '',
businessPath: '',
template: 'single',
pid: '',
treeId: '',
treePid: '',
subTable: '',
subTableKey: ''
},
columns: [],
subColumns: []
}
form.codeVisible = true
}
function onTablechange(){
let _table = form.tableList.find(item => form.codeForm.tableName == item.tableName )
form.codeForm.tableComment = _table.tableComment
form.codeForm.dataSource = _table.tableSchema
columns({name: form.codeForm.tableName}).then((res:any)=>{
form.codeForm.columns = res.result
})
}
function onSubTableChange(){
columns({name: form.codeForm.info.subTable}).then((res:any)=>{
form.codeForm.subColumns = res.result
})
}
const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid)=>{
if(valid){
ElMessageBox.confirm('此操作会生成代码并覆盖, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let formData = new FormData()
formData.append("tableName", form.codeForm.tableName)
formData.append("tableComment", form.codeForm.tableComment)
formData.append("dataSource", form.codeForm.dataSource)
formData.append("info", JSON.stringify(form.codeForm.info))
formData.append("columns", JSON.stringify(form.codeForm.columns))
formData.append("subTableName", form.codeForm.info.subTable)
formData.append("subColumns", JSON.stringify(form.codeForm.subColumns))
execute(formData).then((res:any)=>{
formData.append("interfaceId", res.result)
save(formData).then((res:any)=>{
ElMessage.success("添加成功!");
onCodeGenPage()
form.codeVisible = false
})
})
})
}
})
}
</script>
<template>
<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 v-model="form.codeVisible" title="接口生成" :show-close="false" width="60%" >
<el-form ref="formRef" :model="form.codeForm" :rules="rules" status-icon label-width="100px">
<div style="padding-bottom: 1rem;">数据源信息</div>
<el-card shadow="never">
<el-row :gutter="24">
<el-col :span="12">
<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-col>
<el-col :span="12">
<el-form-item label="描 述" prop="tableComment" :rules="[{ required: true, message: '请输入描述', trigger: 'change' }]">
<el-input v-model="form.codeForm.tableComment" />
</el-form-item>
</el-col>
</el-row>
</el-card>
<div style="padding: 1rem ;">生成接口信息</div>
<el-card shadow="never">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="生成模板" prop="info.template" :rules="[{ required: true, message: '请选择模板', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.template" placeholder="请选择模板" style="width:100%">
<el-option v-for="item in form.templates" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>模板单表树表主子表增删改查</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.moduleName" label="模块名称" :rules="[{ required: true, message: '请输入模块名称', trigger: 'change' }]">
<el-input v-model="form.codeForm.info.moduleName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>模块名称第一级分组名称例如系统功能</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.modulePath" label="模块路径" :rules="[{ required: true, message: '请输入模块路径', trigger: 'change' }, { validator: validatePath }]">
<el-input v-model="form.codeForm.info.modulePath"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>模块路径第一级分组的路径例如/system</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.businessName" label="功能名称" :rules="[{ required: true, message: '请输入功能名称', trigger: 'change' }]">
<el-input v-model="form.codeForm.info.businessName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>功能名称第二级分组名称例如菜单管理</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.businessPath" label="功能路径" :rules="[{ required: true, message: '请输入功能路径', trigger: 'change' }, { validator: validatePath }]">
<el-input v-model="form.codeForm.info.businessPath"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>功能路径第二级分组路径例如/menu</span>
</el-col>
</el-row>
<div v-if="form.codeForm.info.template == 'tree'">
<el-divider content-position="left">关联信息</el-divider>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.treeId" label="树编码" :rules="[{ required: true, message: '请选择树编码字段', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.treeId" placeholder="请选择树编码字段" style="width:100%">
<el-option v-for="item in form.codeForm.columns" :key="item.columnName" :label="item.columnComment" :value="item.columnName">
<span style="float: left">{{ item.columnName }}</span>
<span style="float: right;color: var(--el-text-color-secondary);">{{ item.columnComment }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>树编码树显示的编码字段名称例如id</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.treePid" label="父编码" :rules="[{ required: true, message: '请选择树父编码字段', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.treePid" placeholder="请选择树父编码字段" style="width:100%">
<el-option v-for="item in form.codeForm.columns" :key="item.columnName" :label="item.columnComment" :value="item.columnName">
<span style="float: left">{{ item.columnName }}</span>
<span style="float: right;color: var(--el-text-color-secondary);">{{ item.columnComment }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>树父编码树显示的父编码字段名称例如pid</span>
</el-col>
</el-row>
</div>
<div v-if="form.codeForm.info.template == 'subTable'">
<el-divider content-position="left">关联信息</el-divider>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.subTable" label="关联子表名" :rules="[{ required: true, message: '请选择关联子表名称', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.subTable" @change="onSubTableChange()" placeholder="请选择表" style="width:100%">
<el-option v-for="item in form.tableList" :key="item.tableName" :label="item.tableComment" :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-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>关联子表名关联字表的名称例如sys_menu_role</span>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item prop="info.subTableKey" label="子表外键名" :rules="[{ required: true, message: '请选择子表关联的外键名', trigger: 'change' }]">
<el-select v-model="form.codeForm.info.subTableKey" placeholder="请选择子表关联的外键名" style="width:100%">
<el-option v-for="item in form.codeForm.subColumns" :key="item.columnName" :label="item.columnComment" :value="item.columnName">
<span style="float: left">{{ item.columnName }}</span>
<span style="float: right;color: var(--el-text-color-secondary);">{{ item.columnComment }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="form-describe">
<el-icon style="vertical-align: middle; padding-right: 0.2rem"><ElIconInfoFilled /></el-icon>
<span>子表关联的外键名子表关联的外键名例如menu_id</span>
</el-col>
</el-row>
</div>
</el-card>
</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>
</template>
<style lang="scss" scoped>
.codegen-container{
}
</style>

View File

@ -4,7 +4,7 @@
const { proxy } = getCurrentInstance()
const state = reactive({
url: proxy.$global.baseApi + '/tansci/magic/web/index.html'
url: proxy.$global.baseApi + '/api/web/index.html'
})
</script>

View File

@ -127,10 +127,16 @@
function onContextMenu(val){
list({isShow: 1}).then((res) => {
state.menuList = res.result
state.menuList = res.result;
let menuIds = []
if(Object.prototype.toString.call(val.menuIds) === '[object Array]'){
menuIds = val.menuIds
} else {
menuIds = val.menuIds ? [val.menuIds] : []
}
state.menuForm = {
id: val.id,
menuId: val.menuIds
menuId: menuIds
}
state.menuVisible = true
})

View File

@ -15,21 +15,15 @@
width: '80'
},
tableTitle: [
{prop:'module',label:'功能模块'},
{prop:'message',label:'操作描述'},
{prop:'type',label:'操作类型',type:'tag',option:{size:'small',effect:'plain',typeList:[
{value: 'INSERT', label: 'success'},
{value: 'UPDATE', label: 'warning'},
{value: 'DELETE', label: 'danger'},
{value: 'SELECT', label: 'info'},
]}
},
// {prop:'module',label:''},
// {prop:'message',label:''},
{prop:'uri',label:'请求URI'},
{prop:'type',label:'操作类型'},
{prop:'takeUpTime',label:'耗时(ms)'},
{prop:'status',label:'状态', type:'dict',dictType: 'oper_log_status'},
{prop:'method',label:'操作方法'},
{prop:'uri',label:'请求URI'},
{prop:'ip',label:'请求IP'},
{prop:'userName',label:'用户名称'},
// {prop:'userName',label:''},
{prop:'createTime',label:'创建时间'}
],
tableData:[],

View File

@ -8,6 +8,7 @@
const menuFormRef = ref<FormInstance>();
const state = reactive({
treeData: [],
treeList: [],
operate: 0,
type: 1,
menuForm:{
@ -37,9 +38,15 @@
})
function onMenuTree(){
list().then((res:any)=>{
list({}).then((res:any)=>{
if(res){
state.treeData = res.result;
state.treeList = [];
state.treeList.push({
id: '0',
chineseName: "根节点",
children: res.result
})
}
})
}
@ -118,7 +125,7 @@
ElMessage.success("删除成功!");
state.menuForm = {
id: '',
parentId: '',
parentId: '0',
name: '',
url: '',
icon: '',
@ -170,7 +177,7 @@
}
state.menuForm = {
id: '',
parentId: '',
parentId: '0',
name: '',
url: '',
icon: '',
@ -220,6 +227,10 @@
</el-radio-group>
<el-divider content-position="left">菜单详情</el-divider>
<el-form :model="state.menuForm" :rules="rules" ref="menuFormRef" :disabled="state.operate==0 || state.operate==3?true:false" label-position="right" label-width="150px">
<el-form-item v-if="state.type == 1" label="父级菜单" prop="parentId" :rules="[{required: true, message: '父级不能为空', trigger: 'blur'}]">
<el-tree-select v-model="state.menuForm.parentId" :data="state.treeList" :props="{children: 'children', label: 'chineseName'}" node-key="id"
check-strictly :render-after-expand="false" :default-checked-keys="[state.menuForm.parentId]" :default-expanded-keys="[state.menuForm.parentId]" placeholder="请选父级菜单" style="width:50%"/>
</el-form-item>
<el-form-item v-if="state.type == 1" label="菜单名称" prop="name" :rules="[{required: true, message: '名称不能为空', trigger: 'blur'},{pattern: /^[A-Za-z0-9]+$/, message: '必须是字母', trigger: 'blur'}]">
<el-input v-model="state.menuForm.name" placeholder="请输入名称" style="width:50%"></el-input>
</el-form-item>

View File

@ -280,24 +280,24 @@
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="电话" prop="phone" :rules="[{pattern: /^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/, message: '请输入正确的手机号', trigger: 'blur'}]">
<el-form-item label="电话" prop="phone" :rules="[{required: true,message:'请输入电话',trigger: 'blur'},{pattern: /^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/, message: '请输入正确的手机号', trigger: 'blur'}]">
<el-input v-model="form.userForm.phone" placeholder="请输入电话" style="width: 100%"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="生日" prop="birthday">
<el-date-picker v-model="form.userForm.birthday" type="date" placeholder="选择日期" style="width: 100%;"></el-date-picker>
<el-form-item label="生日" prop="birthday" :rules="[{required: true,message:'请选择日期',trigger: 'blur'}]">
<el-date-picker v-model="form.userForm.birthday" type="date" value-format="YYYY-MM-DD" placeholder="选择日期" style="width: 100%;"></el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="地址" prop="address">
<el-form-item label="地址" prop="address" :rules="[{required: true,message:'请输入地址',trigger: 'blur'}]">
<el-input v-model="form.userForm.address" placeholder="请输入地址" style="width: 100%"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email" :rules="[{pattern: /^[a-zA-Z0-9]+([-_.][A-Za-zd]+)*@([a-zA-Z0-9]+[-.])+[A-Za-zd]{2,5}$/, message: '请输入正确邮箱', trigger: 'blur'}]">
<el-form-item label="邮箱" prop="email" :rules="[{required: true,message:'请输入邮箱',trigger: 'blur'},{pattern: /^[a-zA-Z0-9]+([-_.][A-Za-zd]+)*@([a-zA-Z0-9]+[-.])+[A-Za-zd]{2,5}$/, message: '请输入正确邮箱', trigger: 'blur'}]">
<el-input v-model="form.userForm.email" placeholder="请输入邮箱" style="width: 100%"/>
</el-form-item>
</el-col>

View File

@ -2,7 +2,6 @@ import { defineConfig } from 'vite'
import path from 'path'
import vue from '@vitejs/plugin-vue'
const url = "http://127.0.0.1:8000"
export default defineConfig({
resolve: {
alias: {
@ -21,13 +20,11 @@ export default defineConfig({
],
server: {
proxy: {
'/system': {
target: url,
'/tansci': {
target: 'http://127.0.0.1:8000',
changeOrigin: true,
pathRewrite: {
'^/system':'/system'
}
}
pathRewrite: {'^/tansci':'/tansci'}
}
} as any
}
})

View File

@ -5,35 +5,40 @@
<parent>
<groupId>com.tansci</groupId>
<artifactId>tansci-boot-parent</artifactId>
<version>1.0.0</version>
<version>2.0.0</version>
</parent>
<groupId>com.tansci</groupId>
<artifactId>tansci-boot</artifactId>
<version>1.0.0</version>
<version>2.0.0</version>
<name>tansci-boot</name>
<description>Tansci Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<mybatis-plus-boot.varsion>3.4.3.1</mybatis-plus-boot.varsion>
<druid-spring-boot.varsion>1.2.6</druid-spring-boot.varsion>
<sa-token-spring-boot.varsion>1.34.0</sa-token-spring-boot.varsion>
<hutool-all.version>5.7.22</hutool-all.version>
<fastjson2.version>2.0.26</fastjson2.version>
<magic-api.version>2.1.0</magic-api.version>
<magic-api.version>2.1.1</magic-api.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.ssssssss</groupId>
<artifactId>magic-api-spring-boot-starter</artifactId>
<version>${magic-api.version}</version>
</dependency>
<dependency>
@ -42,35 +47,24 @@
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-boot.varsion}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid-spring-boot.varsion}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool-all.version}</version>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>${sa-token-spring-boot.varsion}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool-all.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
@ -78,9 +72,9 @@
</dependency>
<dependency>
<groupId>org.ssssssss</groupId>
<artifactId>magic-api-spring-boot-starter</artifactId>
<version>${magic-api.version}</version>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>

View File

@ -1,6 +1,6 @@
package com.tansci.common;
import org.apache.commons.lang3.StringUtils;
import java.util.Objects;
/**
* @ClassName WrapMapper.java
@ -43,11 +43,11 @@ public class WrapMapper {
}
public static <E> Wrapper<E> error(String message) {
return wrap(Wrapper.ERROR_CODE, StringUtils.isBlank(message) ? Wrapper.ERROR_MESSAGE : message);
return wrap(Wrapper.ERROR_CODE, Objects.isNull(message) ? Wrapper.ERROR_MESSAGE : message);
}
public static <E> Wrapper<E> error(int code, String message) {
return wrap(code, StringUtils.isBlank(message) ? Wrapper.ERROR_MESSAGE : message);
return wrap(code, Objects.isNull(message) ? Wrapper.ERROR_MESSAGE : message);
}
public static <E> Wrapper<E> ok() {

View File

@ -14,23 +14,17 @@ import java.io.Serializable;
public class Wrapper<T> implements Serializable {
/**
* 成功码.
* 错误码成功
*/
public static final int SUCCESS_CODE = 200;
/**
* 成功信息.
*/
public static final String SUCCESS_MESSAGE = "操作成功";
/**
* 错误码.
* 错误码失败
*/
public static final int ERROR_CODE = 500;
/**
* 错误信息.
*/
public static final String ERROR_MESSAGE = "系统异常,请稍后重试!";
/**
@ -38,20 +32,21 @@ public class Wrapper<T> implements Serializable {
*/
public static final int ILLEGAL_ARGUMENT_CODE_ = 400;
/**
* 错误信息参数非法
*/
public static final String ILLEGAL_ARGUMENT_MESSAGE = "请求参数非法,请核查!";
/**
* 错误码参数非法
* 错误码凭证已过
*/
public static final int AUTHORIZATION_CODE = 403;
public static final int AUTHORIZATION_CODE = 402;
public static final String AUTHORIZATION_MESSAGE = "用户凭证已过期,请重新登录!";
/**
* 错误信息参数非法
* 错误禁止访问
*/
public static final String AUTHORIZATION_MESSAGE = "用户凭证已过期,请重新登录!";
public static final int FORBIDDEN_CODE = 403;
public static final String FORBIDDEN_MESSAGE = "禁止访问!";
/**
* 编号.

View File

@ -9,32 +9,6 @@ package com.tansci.common.constant;
**/
public class Constants {
/**
* 删除状态0正常1删除
*/
public final static Integer NOT_DEL_FALG = 0;
public final static Integer IS_DEL_FALG = 1;
/**
* 用户是否禁用0正常1禁用
*/
public final static Integer USER_IS_LOGIN_IN = 0;
public final static Integer USER_IS_LOGIN_ON = 1;
/**
* 操作日志状态0成功1失败
*/
public final static Integer OPER_LOG_STATUS_SUCCESS = 0;
public final static Integer OPER_LOG_STATUS_ERROR = 1;
/**
* 接口操作类型
*/
public final static String SELECT = "SELECT";
public final static String INSERT = "INSERT";
public final static String UPDATE = "INSERT";
public final static String DELETE = "DELETE";
/**
* 权限校验
*/

View File

@ -1,48 +0,0 @@
package com.tansci.common.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.Objects;
/**
* @ClassName Enums.java
* @ClassPath com.tansci.common.constant.Enums.java
* @Description 常用枚举
* @Author tanyp
* @Date 2023/3/20 15:25
**/
@Getter
@NoArgsConstructor
@AllArgsConstructor
public enum Enums {
/**
* 用户性别
*/
USER_GENDER_MALE(0, "user_gender", ""),
USER_GENDER_GIRL(1, "user_gender", ""),
/**
* 用户类型
*/
USER_TYPE_1(1, "user_type", "管理员"),
USER_TYPE_2(2, "user_type", "商户"),
;
private Integer key;
private String group;
private String value;
public static String getVlaueByGroup(Integer key, String group) {
for (Enums item : Enums.values()) {
if (Objects.equals(key, item.key) && Objects.equals(group, item.group)) {
return item.getValue();
}
}
return null;
}
}

View File

@ -1,42 +0,0 @@
package com.tansci.common.exception;
import lombok.Getter;
/**
* @ClassName BusinessException.java
* @ClassPath com.tansci.exception.BusinessException.java
* @Description 业务异常处理
* @Author tanyp
* @Date 2023/3/20 15:31
**/
@Getter
public class BusinessException extends RuntimeException {
/**
* 异常码
*/
private int code = 500;
/**
* 异常描述
*/
private String message;
public BusinessException(String message) {
super(message);
this.message = message;
}
public BusinessException(int code, String message) {
super(message);
this.code = code;
this.message = message;
}
public BusinessException(int code, String message, Throwable throwable) {
super(message, throwable);
this.code = code;
this.message = message;
}
}

View File

@ -1,27 +0,0 @@
package com.tansci.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @ClassName CorsConfig.java
* @ClassPath com.tansci.config.CorsConfig.java
* @Description 跨域配置
* @Author tanyp
* @Date 2023/3/20 15:23
**/
@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 设置允许跨域的路由
registry.addMapping("/**")
.allowedOriginPatterns("*") // 设置允许跨域请求的域名
.allowCredentials(true) // 是否允许证书cookies
.allowedMethods("GET", "POST", "DELETE", "PUT", "OPTIONS") // 设置允许的方法
.maxAge(3600); // 跨域允许时间
}
}

View File

@ -43,7 +43,6 @@ public class MagicAPIJsonConfig implements ResultProvider {
**/
@Override
public Object buildPageResult(RequestEntity requestEntity, Page page, long total, List<Map<String, Object>> data) {
return new HashMap<String,Object>(){
{
put("total", total);

View File

@ -1,29 +0,0 @@
package com.tansci.config;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @ClassName SaTokenConfig.java
* @ClassPath com.tansci.config.SaTokenConfig.java
* @Description 鉴权拦截器
* @Author tanyp
* @Date 2023/3/20 15:03
**/
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册 Sa-Token 拦截器打开注解式鉴权功能
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
// 验证所有接口
.addPathPatterns("/**")
// 忽略校验
.excludePathPatterns("/system/auth/**", "/api/web/**");
}
}

View File

@ -3,7 +3,6 @@ package com.tansci.handler;
import cn.dev33.satoken.exception.NotLoginException;
import com.tansci.common.WrapMapper;
import com.tansci.common.Wrapper;
import com.tansci.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ -20,19 +19,9 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
// @ExceptionHandler
// public SaResult handlerException(Exception e) {
// e.printStackTrace();
// return SaResult.error(e.getMessage());
// }
@ExceptionHandler(value = Exception.class)
public Wrapper handleException(Exception e) {
if (e instanceof BusinessException) {
BusinessException ex = (BusinessException) e;
log.error("系统自定义业务异常:{}", ex.getMessage());
return WrapMapper.wrap(ex.getCode(), ex.getMessage(), null);
} else if (e instanceof MethodArgumentNotValidException) {
if (e instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
log.error("参数校验异常:{}", ex.getBindingResult().getFieldError().getDefaultMessage());
return WrapMapper.wrap(Wrapper.ILLEGAL_ARGUMENT_CODE_, "参数有误:" + ex.getBindingResult().getFieldError().getDefaultMessage(), null);

View File

@ -0,0 +1,49 @@
package com.tansci.handler;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.ssssssss.magicapi.core.context.RequestContext;
import org.ssssssss.magicapi.core.servlet.MagicHttpServletRequest;
import org.ssssssss.magicapi.modules.servlet.ResponseModule;
import org.ssssssss.script.annotation.Comment;
import org.ssssssss.script.functions.ExtensionMethod;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @ClassName ResponseFunctionExtension.java
* @ClassPath com.tansci.handler.ResponseFunctionExtension.java
* @Description
* @Author tanyp
* @Date 2023/7/7 16:08
**/
@Component
public class ResponseFunctionExtension implements ExtensionMethod {
@Override
public Class<?> support() {
return ResponseModule.class;
}
private HttpServletResponse getResponse() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes) {
return ((ServletRequestAttributes) requestAttributes).getResponse();
}
return null;
}
@Comment("转发")
public ResponseModule.NullValue dispatcher(ResponseModule responseModule, String url) throws ServletException, IOException {
MagicHttpServletRequest magicHttpServletRequest = RequestContext.getHttpServletRequest();
HttpServletRequest request = magicHttpServletRequest.getRequest();
request.getRequestDispatcher(url).forward(request, getResponse());
return responseModule.end();
}
}

View File

@ -1,119 +1,111 @@
//package com.tansci.handler;
//
//import cn.dev33.satoken.stp.StpInterface;
//import cn.dev33.satoken.stp.StpUtil;
//import com.baomidou.mybatisplus.core.toolkit.Wrappers;
//import com.tansci.common.constant.Constants;
//import com.tansci.common.constant.Enums;
//import com.tansci.domain.SysMenu;
//import com.tansci.domain.SysRoleMenu;
//import com.tansci.domain.SysUserRole;
//import com.tansci.domain.vo.SysUserSessionVo;
//import com.tansci.service.SysMenuService;
//import com.tansci.service.SysRoleMenuService;
//import com.tansci.service.SysUserRoleService;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Component;
//
//import java.util.List;
//import java.util.Objects;
//import java.util.stream.Collectors;
//
///**
// * @ClassName StpInterfaceHandler.java
// * @ClassPath com.tansci.handler.StpInterfaceHandler.java
// * @Description 自定义权限验证
// * @Author tanyp
// * @Date 2023/4/7 15:07
// **/
//@Component
//public class StpInterfaceHandler implements StpInterface {
//
// @Autowired
// private SysUserRoleService sysUserRoleService;
// @Autowired
// private SysRoleMenuService sysRoleMenuService;
// @Autowired
// private SysMenuService sysMenuService;
//
// /**
// * @MonthName getPermissionList
// * @Description 返回一个账号所拥有的权限码集合
// * @Author tanyp
// * @Date 2023/4/7 15:08
// * @Param [o, s]
// * @return java.util.List<java.lang.String>
// **/
// @Override
// public List<String> getPermissionList(Object loginId, String loginType) {
// SysUserSessionVo userSession = (SysUserSessionVo) StpUtil.getSession().get(StpUtil.getLoginId().toString());
// if (Objects.nonNull(userSession)) {
// if (Objects.nonNull(StpUtil.getSession().get(Constants.PERMISSION_KEY))) {
// return (List<String>) StpUtil.getSession().get(Constants.PERMISSION_KEY);
// }
//
// if (Objects.equals(Enums.USER_TYPE_1.getKey(), userSession.getType())) {
// List<SysMenu> menus = sysMenuService.list(
// Wrappers.<SysMenu>lambdaQuery()
// .eq(SysMenu::getIsDel, Constants.NOT_DEL_FALG)
// .ne(SysMenu::getPermission, "")
// .isNotNull(SysMenu::getPermission)
// );
// List<String> permissions = menus.stream().map(SysMenu::getPermission).collect(Collectors.toList());
// StpUtil.getSession().set(Constants.PERMISSION_KEY, permissions);
// return permissions;
// } else {
// List<SysUserRole> roles = sysUserRoleService.list(Wrappers.<SysUserRole>lambdaQuery().eq(SysUserRole::getUserId, StpUtil.getLoginId()));
// if (Objects.nonNull(roles) && roles.size() > 0) {
// List<String> roleIds = roles.stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
// List<SysRoleMenu> roleMenus = sysRoleMenuService.list(Wrappers.<SysRoleMenu>lambdaQuery().in(SysRoleMenu::getRoleId, roleIds));
// if (Objects.nonNull(roleMenus) && roleMenus.size() > 0) {
// List<SysMenu> menus = sysMenuService.list(
// Wrappers.<SysMenu>lambdaQuery()
// .in(SysMenu::getId, roleMenus.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList()))
// .eq(SysMenu::getIsDel, Constants.NOT_DEL_FALG)
// .ne(SysMenu::getPermission, "")
// .isNotNull(SysMenu::getPermission)
// );
// List<String> permissions = menus.stream().map(SysMenu::getPermission).collect(Collectors.toList());
// StpUtil.getSession().set(Constants.PERMISSION_KEY, permissions);
// return permissions;
// }
// }
// }
// }
// return null;
// }
//
// /**
// * @MonthName getRoleList
// * @Description 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
// * @Author tanyp
// * @Date 2023/4/7 15:08
// * @Param [o, s]
// * @return java.util.List<java.lang.String>
// **/
// @Override
// public List<String> getRoleList(Object loginId, String loginType) {
// SysUserSessionVo userSession = (SysUserSessionVo) StpUtil.getSession().get(StpUtil.getLoginId().toString());
// if (Objects.nonNull(userSession)) {
// if (Objects.nonNull(StpUtil.getSession().get(Constants.ROLE_KEY))) {
// return (List<String>) StpUtil.getSession().get(Constants.ROLE_KEY);
// }
//
// if (Objects.equals(Enums.USER_TYPE_1.getKey(), userSession.getType())) {
// List<String> roleIds = sysUserRoleService.list().stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
// StpUtil.getSession().set(Constants.ROLE_KEY, roleIds);
// return roleIds;
// } else {
// List<SysUserRole> roles = sysUserRoleService.list(Wrappers.<SysUserRole>lambdaQuery().eq(SysUserRole::getUserId, StpUtil.getLoginId()));
// if (Objects.nonNull(roles) && roles.size() > 0) {
// List<String> roleIds = roles.stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
// StpUtil.getSession().set(Constants.ROLE_KEY, roleIds);
// return roleIds;
// }
// }
// }
// return null;
// }
//}
package com.tansci.handler;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson2.JSON;
import com.tansci.common.WrapMapper;
import com.tansci.common.Wrapper;
import com.tansci.common.constant.Constants;
import com.tansci.utils.UUIDUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.ssssssss.magicapi.core.context.RequestEntity;
import org.ssssssss.magicapi.core.interceptor.RequestInterceptor;
import org.ssssssss.magicapi.core.model.ApiInfo;
import org.ssssssss.magicapi.core.model.Options;
import org.ssssssss.magicapi.core.service.MagicAPIService;
import org.ssssssss.magicapi.core.servlet.MagicHttpServletRequest;
import org.ssssssss.magicapi.core.servlet.MagicHttpServletResponse;
import org.ssssssss.script.MagicScriptContext;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* @ClassName StpInterfaceHandler.java
* @ClassPath com.tansci.handler.StpInterfaceHandler.java
* @Description 自定义
* @Author tanyp
* @Date 2023/4/7 15:07
**/
@Component
@Order(1)
public class StpInterfaceHandler implements RequestInterceptor, HandlerInterceptor {
@Autowired
MagicAPIService magicAPIService;
@Autowired
private JdbcTemplate template;
@Override
public Object preHandle(ApiInfo info, MagicScriptContext context, MagicHttpServletRequest request, MagicHttpServletResponse response) throws Exception {
String requireLogin = Objects.toString(info.getOptionValue(Options.REQUIRE_LOGIN), "");
if (requireLogin.equals("false")) {
return null;
}
if (!StpUtil.isLogin()) {
return WrapMapper.wrap(Wrapper.AUTHORIZATION_CODE, Wrapper.AUTHORIZATION_MESSAGE);
} else {
List<String> permissions = null;
if (Objects.nonNull(StpUtil.getSession().get(Constants.PERMISSION_KEY))) {
permissions = (List<String>) StpUtil.getSession().get(Constants.PERMISSION_KEY);
} else {
permissions = magicAPIService.execute("post", "/system/auth/permissions", new HashMap<String, Object>());
StpUtil.getSession().set(Constants.PERMISSION_KEY, permissions);
}
String permission = Objects.toString(info.getOptionValue(Options.PERMISSION), "");
if (StringUtils.isNotBlank(permission) && !permissions.contains(permission)) {
return WrapMapper.wrap(Wrapper.FORBIDDEN_CODE, Wrapper.FORBIDDEN_MESSAGE);
}
}
return null;
}
@Override
public Object postHandle(RequestEntity requestEntity, Object returnValue) throws Exception {
if (StpUtil.isLogin()) {
try {
HttpServletRequest request = requestEntity.getRequest().getRequest();
ApiInfo info = requestEntity.getApiInfo();
template.update("insert into sys_oper_log(id,method,type,message,req_param,res_param,take_up_time,user_id,status,uri,ip,version,create_time) values(?,?,?,?,?,?,?,?,?,?,?,?,?)",
UUIDUtils.getUUID(),
request.getMethod(),
request.getMethod(),
null,
JSON.toJSONString(converMap(request.getParameterMap())),
null,
System.currentTimeMillis() - requestEntity.getRequestTime(),
StpUtil.getLoginId(),
0,
request.getRequestURI(),
ServletUtil.getClientIP(request),
"2.0.0",
LocalDateTime.now()
);
} catch (Exception ignored) {
ignored.printStackTrace();
}
}
return null;
}
public Map<String, String> converMap(Map<String, String[]> paramMap) {
Map<String, String> rtnMap = new HashMap<>();
for (String key : paramMap.keySet()) {
rtnMap.put(key, paramMap.get(key)[0]);
}
return rtnMap;
}
}

View File

@ -0,0 +1,29 @@
package com.tansci.model;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName CodeCacheMap.java
* @ClassPath com.tansci.utils.CodeCacheMap.java
* @Description 验证码缓存
* @Author tanyp
* @Date 2023/3/20 15:34
**/
public class CodeCacheMap {
private static Map<String, String> map = new HashMap<String, String>();
public static void put(String key, String value) {
map.put(key, value);
}
public static void remove(String key) {
map.remove(key);
}
public static String get(String key) {
return map.get(key);
}
}

View File

@ -1 +1,19 @@
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/tansci_boot?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&autoReconnect=true
username: root
password: root
initialSize: 10
minIdle: 10
maxActive: 100
maxWait: 60000
timeBetweenEvictionRunsMillis: 300000
minEvictableIdleTimeMillis: 3600000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20

View File

@ -1,41 +1,17 @@
server:
port: 8000
servlet:
context-path: /tansci
spring:
profiles:
active: dev
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
servlet:
multipart:
enabled: true
max-file-size: 100MB
max-request-size: 100MB
mvc:
pathmatch:
matching-strategy: ant_path_matcher
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/tansci_boot?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&autoReconnect=true
username: root
password: root
initialSize: 10
minIdle: 10
maxActive: 100
maxWait: 60000
timeBetweenEvictionRunsMillis: 300000
minEvictableIdleTimeMillis: 3600000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
mybatis-plus:
mapper-locations: classpath:mapper/**/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# Sa-Token 配置 (文档: https://sa-token.cc)
sa-token: