master
parent
1fe0acf540
commit
d600578b1a
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
|||
VITE_BASE_API = 'http://localhost:8080/'
|
||||
VITE_BASE_API = 'http://localhost:8000/'
|
||||
|
|
@ -1 +1 @@
|
|||
VITE_BASE_API = 'http://localhost:8080/'
|
||||
VITE_BASE_API = 'http://localhost:8000/'
|
||||
|
|
@ -27,12 +27,26 @@ export function del(id:String){
|
|||
})
|
||||
}
|
||||
|
||||
export function execute(param:any){
|
||||
export function save(data:any){
|
||||
return new Promise((resolve, reject) => {
|
||||
request({
|
||||
url: '/tansci/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: '/tansci/lowcode/code/execute',
|
||||
method: 'post',
|
||||
data: param
|
||||
data
|
||||
}).then((res:any) => {
|
||||
resolve(res.data)
|
||||
}).catch((e:any) => {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@
|
|||
emit('setCellColor', e, (color = {}) =>{
|
||||
obj = color;
|
||||
});
|
||||
obj.padding = '2px';
|
||||
return obj;
|
||||
},
|
||||
})
|
||||
|
|
@ -102,8 +101,10 @@
|
|||
</script>
|
||||
<template>
|
||||
<div class="table-container">
|
||||
<div class="search-wrap">
|
||||
<slot name="search"></slot>
|
||||
<div class="search-wrap" v-if="$slots.search">
|
||||
<el-space wrap>
|
||||
<slot name="search"></slot>
|
||||
</el-space>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<div class="header">
|
||||
|
|
@ -260,4 +261,36 @@
|
|||
</div>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
.table-container{
|
||||
.search-wrap{
|
||||
// background: var(--bg1);
|
||||
border: 1px solid var(--el-border-color);
|
||||
border-radius: var(--el-border-radius-base);
|
||||
padding: 1rem;
|
||||
}
|
||||
.table-wrap{
|
||||
padding: 1rem 0;
|
||||
.header{
|
||||
float: right;
|
||||
padding-bottom: 0.4rem;
|
||||
}
|
||||
}
|
||||
.pagination-wrap{
|
||||
padding-bottom: 0.2rem;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.el-table__body-wrapper::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
height: 1px;
|
||||
}
|
||||
.el-table__body-wrapper::-webkit-scrollbar-thumb {
|
||||
background-color: #909399;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.el-table__body-wrapper::-webkit-scrollbar-track {
|
||||
border-radius: 5px;
|
||||
background: #ededed;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,294 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { reactive, onMounted, onBeforeMount, onDeactivated, getCurrentInstance, ref } from "vue"
|
||||
import type { FormInstance, Action } from 'element-plus'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import { isDark, toggleDark } from '@/composables'
|
||||
import { getMenus, logout } from "@/api/auth"
|
||||
import { modifyPass } from "@/api/system/user"
|
||||
import Submenu from "@/components/Submenu.vue"
|
||||
import TabsMenu from "@/components/TabsMenu.vue"
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const logo = new URL('../../assets/image/logo.png', import.meta.url).href
|
||||
const state = reactive({
|
||||
headerHeight: '52px',
|
||||
asideWidth: '180px',
|
||||
routers: [],
|
||||
defaultHeight: null,
|
||||
userVisible: false,
|
||||
user: {
|
||||
avatar: '',
|
||||
username: '',
|
||||
nickname: '未登录',
|
||||
password: '',
|
||||
rePassword: '',
|
||||
oldPassword: ''
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
state.defaultHeight = (document.body.clientHeight || document.documentElement.clientHeight);
|
||||
})
|
||||
|
||||
onMounted(()=>{
|
||||
// 获取菜单
|
||||
let routers:any = [];
|
||||
let _routes:any = getMenus();
|
||||
|
||||
_routes.forEach((item:any)=>{
|
||||
if(item.children && item.isShow){
|
||||
routers.push(item)
|
||||
}
|
||||
})
|
||||
state.routers = routers
|
||||
|
||||
state.user = proxy.$global.user.info
|
||||
|
||||
window.addEventListener('resize', onDefaultHeight);
|
||||
})
|
||||
|
||||
onDeactivated(()=>{
|
||||
window.removeEventListener('resize', onDefaultHeight, false)
|
||||
})
|
||||
|
||||
function onDefaultHeight(){
|
||||
state.defaultHeight = window.innerHeight
|
||||
}
|
||||
function onHeaderCommand(command:any){
|
||||
if('logout' === command){
|
||||
logout()
|
||||
} else if('personal' === command){
|
||||
state.userVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
const userRef = ref<FormInstance>();
|
||||
const validatePass = (rule, value, callback) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请输入确认密码'));
|
||||
} else if (value !== state.user.password) {
|
||||
callback(new Error('两次输入密码不一致!'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
const onUserSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid)=>{
|
||||
if(valid){
|
||||
modifyPass({
|
||||
username: state.user.username,
|
||||
password: state.user.password,
|
||||
oldPassword: state.user.oldPassword
|
||||
}).then(res=>{
|
||||
if(res){
|
||||
state.userVisible = false
|
||||
ElMessageBox.alert('修改密码成功,请重新登录!', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
type: 'warning',
|
||||
callback: (action: Action) =>{
|
||||
logout()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div class="layout-container">
|
||||
<el-container>
|
||||
<el-header :height="state.headerHeight">
|
||||
<div class="header-logo">
|
||||
<el-image :src="logo"></el-image>
|
||||
<span class="title">{{proxy.$global.title}}</span>
|
||||
</div>
|
||||
<div class="header-content">
|
||||
<div class="header-dark">
|
||||
<el-button @click="toggleDark()" link type="primary">
|
||||
<template #icon>
|
||||
<el-icon :size="20"><Sunny v-show="!isDark"/></el-icon>
|
||||
<el-icon :size="20"><Moon v-show="isDark"/></el-icon>
|
||||
</template>
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="header-login">
|
||||
<el-dropdown @command="onHeaderCommand">
|
||||
<span class="el-dropdown-link">
|
||||
<span>{{state.user.nickname}}</span>
|
||||
<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="personal">个人中心</el-dropdown-item>
|
||||
<el-dropdown-item command="logout">退出</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</el-header>
|
||||
<el-container>
|
||||
<el-aside :width="state.asideWidth" :style="{height: state.defaultHeight+'px'}">
|
||||
<el-menu router :default-active="$route.path">
|
||||
<template v-for="item in state.routers" :key="item">
|
||||
<el-menu-item v-if="!item.children || item.children.length <= 1" :index="item.path">
|
||||
<el-icon v-if="item.icon" style="vertical-align: middle;">
|
||||
<component :is="item.icon"></component>
|
||||
</el-icon>
|
||||
<span style="vertical-align: middle;">{{item.meta.title}}</span>
|
||||
</el-menu-item>
|
||||
<Submenu v-else :data="item"></Submenu>
|
||||
</template>
|
||||
</el-menu>
|
||||
</el-aside>
|
||||
<el-main>
|
||||
<TabsMenu></TabsMenu>
|
||||
<el-card :shadow="proxy.$global.cardShadow" style="margin: 0.3rem;">
|
||||
<el-scrollbar :height="state.defaultHeight-150">
|
||||
<router-view />
|
||||
</el-scrollbar>
|
||||
</el-card>
|
||||
</el-main>
|
||||
</el-container>
|
||||
<el-backtop target=".el-main"></el-backtop>
|
||||
</el-container>
|
||||
<el-dialog v-model="state.userVisible" title="个人中心" width="40%" :show-close="false">
|
||||
<el-form :model="state.user" ref="userRef" :rules="rules" label-width="80px" status-icon>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="用户头像" prop="avatar">
|
||||
<el-avatar :size="50" :src="state.user.avatar" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户名称" prop="username">
|
||||
<el-input v-model="state.user.username" disabled style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户昵称" prop="nickname">
|
||||
<el-input v-model="state.user.nickname" disabled placeholder="请输入昵称" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户电话" prop="phone">
|
||||
<el-input v-model="state.user.phone" disabled style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户邮箱" prop="email">
|
||||
<el-input v-model="state.user.email" disabled style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="原始密码" prop="oldPassword" :rules="[{required: true, message: '请输入原始密码', trigger: 'blur'}]">
|
||||
<el-input v-model="state.user.oldPassword" type="password" placeholder="请输入原始密码" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="用户密码" prop="password" :rules="[{required: true, message: '请输入密码', trigger: 'blur'},
|
||||
{pattern: /^[a-zA-Z]\w{5,17}$/, message: '以字母开头,长度在6~18之间,只能包含字母、数字和下划线', trigger: 'blur'}]">
|
||||
<el-input v-model="state.user.password" type="password" placeholder="请输入密码" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item prop="rePassword" label="确认密码" :rules="[{required: true, message: '请输入确认密码', trigger: 'blur'},{validator: validatePass, trigger: 'blur'}]">
|
||||
<el-input v-model="state.user.rePassword" type="password" placeholder="请输入确认密码"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="onUserSubmit(userRef)" type="primary">修改密码</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.layout-container{
|
||||
background: var(--el-bg-color);
|
||||
.el-header{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
line-height: 52px;
|
||||
.header-logo{
|
||||
display: flex;
|
||||
height: 52px;
|
||||
line-height: 52px;
|
||||
padding-left: 0.2rem;
|
||||
cursor: pointer;
|
||||
.title{
|
||||
padding-left: 0.6rem;
|
||||
color: var(-t);
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
.header-content{
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
.header-dark{
|
||||
padding-right: 1rem;
|
||||
}
|
||||
.header-login{
|
||||
.el-dropdown{
|
||||
cursor: pointer;
|
||||
line-height: 52px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-aside{
|
||||
:deep(.el-menu) {
|
||||
margin: 0 0.6rem;
|
||||
padding: 0 0.2rem;
|
||||
border-right: none;
|
||||
background: transparent;
|
||||
.el-menu-item, .el-sub-menu__title {
|
||||
border-radius: 0.2rem;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
margin: 0.4rem 0;
|
||||
}
|
||||
.el-menu-item, .el-menu-item-group__title, .el-sub-menu, .el-sub-menu__title{
|
||||
padding-left: 0;
|
||||
}
|
||||
.el-sub-menu__title:hover{
|
||||
background: transparent;
|
||||
color: var(--theme);
|
||||
}
|
||||
.el-menu-item:hover{
|
||||
background: transparent;
|
||||
color: var(--theme);
|
||||
}
|
||||
.el-menu-item.is-active {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-aside::-webkit-scrollbar{
|
||||
width: 0px;
|
||||
}
|
||||
.el-main{
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.el-main::-webkit-scrollbar{
|
||||
width: 0px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,29 +1,16 @@
|
|||
<script setup lang="ts">
|
||||
import { reactive, onMounted, onBeforeMount, onDeactivated, getCurrentInstance, ref } from "vue"
|
||||
import type { FormInstance, Action } from 'element-plus'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import { isDark, toggleDark } from '@/composables'
|
||||
import { getMenus, logout } from "@/api/auth"
|
||||
import { modifyPass } from "@/api/system/user"
|
||||
import Submenu from "@/components/Submenu.vue"
|
||||
import TabsMenu from "@/components/TabsMenu.vue"
|
||||
import { reactive, onMounted, onBeforeMount, onDeactivated, getCurrentInstance } from "vue"
|
||||
import { getMenus } from "@/api/auth"
|
||||
import TbMenu from "./component/TbMenu.vue"
|
||||
import TbHeader from "./component/TbHeader.vue"
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const logo = new URL('../../assets/image/logo.png', import.meta.url).href
|
||||
const state = reactive({
|
||||
headerHeight: '52px',
|
||||
asideWidth: '260px',
|
||||
routers: [],
|
||||
defaultHeight: null,
|
||||
userVisible: false,
|
||||
user: {
|
||||
avatar: '',
|
||||
username: '',
|
||||
nickname: '未登录',
|
||||
password: '',
|
||||
rePassword: '',
|
||||
oldPassword: ''
|
||||
}
|
||||
routers: [],
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
|
|
@ -42,8 +29,6 @@
|
|||
})
|
||||
state.routers = routers
|
||||
|
||||
state.user = proxy.$global.user.info
|
||||
|
||||
window.addEventListener('resize', onDefaultHeight);
|
||||
})
|
||||
|
||||
|
|
@ -54,229 +39,48 @@
|
|||
function onDefaultHeight(){
|
||||
state.defaultHeight = window.innerHeight
|
||||
}
|
||||
function onPersonal(){
|
||||
state.userVisible = true
|
||||
}
|
||||
|
||||
const userRef = ref<FormInstance>();
|
||||
const validatePass = (rule, value, callback) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请输入确认密码'));
|
||||
} else if (value !== state.user.password) {
|
||||
callback(new Error('两次输入密码不一致!'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
const onUserSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid)=>{
|
||||
if(valid){
|
||||
modifyPass({
|
||||
username: state.user.username,
|
||||
password: state.user.password,
|
||||
oldPassword: state.user.oldPassword
|
||||
}).then(res=>{
|
||||
if(res){
|
||||
state.userVisible = false
|
||||
ElMessageBox.alert('修改密码成功,请重新登录!', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
type: 'warning',
|
||||
callback: (action: Action) =>{
|
||||
logout()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div class="layout-container">
|
||||
<el-container>
|
||||
<el-aside :width="state.asideWidth">
|
||||
<el-card :shadow="proxy.$global.cardShadow" :body-style="{padding: '1rem'}">
|
||||
<div class="logo">
|
||||
<el-image :src="logo" fit="fit" style="width: 20%; height:00%"></el-image>
|
||||
<span class="title">{{proxy.$global.title}}</span>
|
||||
</div>
|
||||
<el-scrollbar :height="state.defaultHeight-115">
|
||||
<el-menu router :default-active="$route.path">
|
||||
<template v-for="item in state.routers" :key="item">
|
||||
<el-menu-item v-if="!item.children || item.children.length <= 1" :index="item.path">
|
||||
<el-icon v-if="item.icon" style="vertical-align: middle;">
|
||||
<component :is="item.icon"></component>
|
||||
</el-icon>
|
||||
<span style="vertical-align: middle;">{{item.meta.title}}</span>
|
||||
</el-menu-item>
|
||||
<Submenu v-else :data="item"></Submenu>
|
||||
</template>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
</el-card>
|
||||
<TbMenu :routers="state.routers"
|
||||
:logo="logo"
|
||||
:shadow="proxy.$global.cardShadow"
|
||||
:title="proxy.$global.title"
|
||||
:height="state.defaultHeight-105"/>
|
||||
</el-aside>
|
||||
<el-container>
|
||||
<el-header :height="state.headerHeight">
|
||||
<TabsMenu></TabsMenu>
|
||||
<div>
|
||||
<el-card :shadow="proxy.$global.cardShadow" :body-style="{padding: '0 1rem', 'line-height': state.headerHeight+'px'}">
|
||||
<el-button link>
|
||||
<template #icon>
|
||||
<el-icon :size="24"><Monitor /></el-icon>
|
||||
</template>
|
||||
</el-button>
|
||||
<el-button link>
|
||||
<template #icon>
|
||||
<el-icon :size="24"><FullScreen /></el-icon>
|
||||
</template>
|
||||
</el-button>
|
||||
<el-button @click="toggleDark()" link>
|
||||
<template #icon>
|
||||
<el-icon :size="24"><Sunny v-show="!isDark"/></el-icon>
|
||||
<el-icon :size="24"><Sunrise v-show="isDark"/></el-icon>
|
||||
</template>
|
||||
</el-button>
|
||||
<el-popover placement="bottom" :width="260" trigger="click">
|
||||
<template #reference>
|
||||
<el-button link>{{state.user.nickname}}</el-button>
|
||||
</template>
|
||||
<div style="text-align: center;">
|
||||
<div><el-avatar :size="50" :src="state.user.avatar" /></div>
|
||||
<div style="font-size: 22px; padding: 0.4rem 0;">{{state.user.username}}</div>
|
||||
<el-button @click="onPersonal()" type="primary" plain>个人中心</el-button>
|
||||
<el-button @click="logout()" type="danger" plain>注销登录</el-button>
|
||||
</div>
|
||||
</el-popover>
|
||||
</el-card>
|
||||
</div>
|
||||
<TbHeader :height="state.headerHeight"/>
|
||||
</el-header>
|
||||
<el-main>
|
||||
<el-card :shadow="proxy.$global.cardShadow">
|
||||
<el-scrollbar :height="state.defaultHeight-150">
|
||||
<el-scrollbar :height="state.defaultHeight-126">
|
||||
<router-view />
|
||||
</el-scrollbar>
|
||||
</el-card>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
<el-backtop target=".el-main"></el-backtop>
|
||||
<el-dialog v-model="state.userVisible" title="个人中心" width="40%" :show-close="false">
|
||||
<el-form :model="state.user" ref="userRef" :rules="rules" label-width="80px" status-icon>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="用户头像" prop="avatar">
|
||||
<el-avatar :size="50" :src="state.user.avatar" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户名称" prop="username">
|
||||
<el-input v-model="state.user.username" disabled style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户昵称" prop="nickname">
|
||||
<el-input v-model="state.user.nickname" disabled placeholder="请输入昵称" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户电话" prop="phone">
|
||||
<el-input v-model="state.user.phone" disabled style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户邮箱" prop="email">
|
||||
<el-input v-model="state.user.email" disabled style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="原始密码" prop="oldPassword" :rules="[{required: true, message: '请输入原始密码', trigger: 'blur'}]">
|
||||
<el-input v-model="state.user.oldPassword" type="password" placeholder="请输入原始密码" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="用户密码" prop="password" :rules="[{required: true, message: '请输入密码', trigger: 'blur'},
|
||||
{pattern: /^[a-zA-Z]\w{5,17}$/, message: '以字母开头,长度在6~18之间,只能包含字母、数字和下划线', trigger: 'blur'}]">
|
||||
<el-input v-model="state.user.password" type="password" placeholder="请输入密码" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item prop="rePassword" label="确认密码" :rules="[{required: true, message: '请输入确认密码', trigger: 'blur'},{validator: validatePass, trigger: 'blur'}]">
|
||||
<el-input v-model="state.user.rePassword" type="password" placeholder="请输入确认密码"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="onUserSubmit(userRef)" type="primary">修改密码</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.layout-container{
|
||||
height: 100%;
|
||||
background: var(--el-bg-color);
|
||||
.el-header{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.el-card{
|
||||
margin-top: 1.2rem;
|
||||
.el-button{
|
||||
margin: 1rem 0.8rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-aside{
|
||||
margin: 0.6rem;
|
||||
margin: 0.2rem;
|
||||
padding: 0.4rem;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
.logo{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-top: 0.4rem;
|
||||
cursor: pointer;
|
||||
.title{
|
||||
padding-left: 0.6rem;
|
||||
color: var(-t);
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
:deep(.el-menu) {
|
||||
padding-left: 0;
|
||||
border-right: none;
|
||||
background: transparent;
|
||||
.el-menu-item, .el-sub-menu__title {
|
||||
margin: 0.4rem 0;
|
||||
}
|
||||
.el-sub-menu__title:hover{
|
||||
background: transparent;
|
||||
color: var(--theme);
|
||||
}
|
||||
.el-menu-item:hover{
|
||||
background: transparent;
|
||||
color: var(--theme);
|
||||
}
|
||||
.el-menu-item.is-active {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
.el-header{
|
||||
padding: 0 0.6rem 0 0;
|
||||
}
|
||||
.el-main{
|
||||
padding: 1.2rem 0.6rem 0 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,183 @@
|
|||
<script setup lang="ts">
|
||||
import {defineProps,reactive,ref,getCurrentInstance} from 'vue'
|
||||
import { isDark, toggleDark } from '@/composables'
|
||||
import type { FormInstance, Action } from 'element-plus'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import TbNavTabs from "./TbNavTabs.vue"
|
||||
import { logout } from "@/api/auth"
|
||||
import { modifyPass } from "@/api/system/user"
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const props = defineProps({
|
||||
height: Number,
|
||||
})
|
||||
|
||||
const state = reactive({
|
||||
userVisible: false,
|
||||
user: {
|
||||
avatar: proxy.$global.user.info ? proxy.$global.user.info.avatar : '',
|
||||
username: proxy.$global.user.info ? proxy.$global.user.info.username : '',
|
||||
nickname: proxy.$global.user.info ? proxy.$global.user.info.nickname : '未登录',
|
||||
password: '',
|
||||
rePassword: '',
|
||||
oldPassword: ''
|
||||
}
|
||||
})
|
||||
|
||||
function onPersonal(){
|
||||
state.userVisible = true
|
||||
}
|
||||
|
||||
const userRef = ref<FormInstance>();
|
||||
const validatePass = (rule:any, value:any, callback:any) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请输入确认密码'));
|
||||
} else if (value !== state.user.password) {
|
||||
callback(new Error('两次输入密码不一致!'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
const onUserSubmit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid)=>{
|
||||
if(valid){
|
||||
modifyPass({
|
||||
username: state.user.username,
|
||||
password: state.user.password,
|
||||
oldPassword: state.user.oldPassword
|
||||
}).then(res=>{
|
||||
if(res){
|
||||
state.userVisible = false
|
||||
ElMessageBox.alert('修改密码成功,请重新登录!', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
type: 'warning',
|
||||
callback: (action: Action) =>{
|
||||
logout()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onLogout(){
|
||||
ElMessageBox.confirm('确定要退出登录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}).then(()=>{
|
||||
logout()
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div class="tb-header">
|
||||
<TbNavTabs />
|
||||
<div>
|
||||
<el-card :shadow="proxy.$global.cardShadow" :body-style="{padding: '0 1rem', 'line-height': height +'px'}">
|
||||
<el-button link>
|
||||
<template #icon>
|
||||
<el-icon :size="24"><Monitor /></el-icon>
|
||||
</template>
|
||||
</el-button>
|
||||
<el-button link>
|
||||
<template #icon>
|
||||
<el-icon :size="24"><FullScreen /></el-icon>
|
||||
</template>
|
||||
</el-button>
|
||||
<el-button @click="toggleDark()" link>
|
||||
<template #icon>
|
||||
<el-icon :size="24"><Sunny v-show="!isDark"/></el-icon>
|
||||
<el-icon :size="24"><Sunrise v-show="isDark"/></el-icon>
|
||||
</template>
|
||||
</el-button>
|
||||
<el-popover placement="bottom" :width="260" trigger="click">
|
||||
<template #reference>
|
||||
<el-button link>{{state.user.nickname}}</el-button>
|
||||
</template>
|
||||
<div style="text-align: center;">
|
||||
<div><el-avatar :size="50" :src="state.user.avatar" /></div>
|
||||
<div style="font-size: 22px; padding: 0.4rem 0;">{{state.user.username}}</div>
|
||||
<el-button @click="onPersonal()" type="primary" plain>个人中心</el-button>
|
||||
<el-button @click="onLogout()" type="danger" plain>注销登录</el-button>
|
||||
</div>
|
||||
</el-popover>
|
||||
</el-card>
|
||||
</div>
|
||||
<el-dialog v-model="state.userVisible" title="个人中心" width="40%" :show-close="false">
|
||||
<el-form :model="state.user" ref="userRef" :rules="rules" label-width="80px" status-icon>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="用户头像" prop="avatar">
|
||||
<el-avatar :size="50" :src="state.user.avatar" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户名称" prop="username">
|
||||
<el-input v-model="state.user.username" disabled style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户昵称" prop="nickname">
|
||||
<el-input v-model="state.user.nickname" disabled placeholder="请输入昵称" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户电话" prop="phone">
|
||||
<el-input v-model="state.user.phone" disabled style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用户邮箱" prop="email">
|
||||
<el-input v-model="state.user.email" disabled style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="原始密码" prop="oldPassword" :rules="[{required: true, message: '请输入原始密码', trigger: 'blur'}]">
|
||||
<el-input v-model="state.user.oldPassword" type="password" placeholder="请输入原始密码" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="用户密码" prop="password" :rules="[{required: true, message: '请输入密码', trigger: 'blur'},
|
||||
{pattern: /^[a-zA-Z]\w{5,17}$/, message: '以字母开头,长度在6~18之间,只能包含字母、数字和下划线', trigger: 'blur'}]">
|
||||
<el-input v-model="state.user.password" type="password" placeholder="请输入密码" style="width: 100%"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item prop="rePassword" label="确认密码" :rules="[{required: true, message: '请输入确认密码', trigger: 'blur'},{validator: validatePass, trigger: 'blur'}]">
|
||||
<el-input v-model="state.user.rePassword" type="password" placeholder="请输入确认密码"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="onUserSubmit(userRef)" type="primary">修改密码</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.tb-header{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.el-card{
|
||||
.el-button{
|
||||
margin: 1rem 0.6rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<script setup lang="ts">
|
||||
import {defineProps} from 'vue'
|
||||
import TbSubmenu from "./TbSubmenu.vue"
|
||||
|
||||
const props = defineProps({
|
||||
routers: Array,
|
||||
height: Number,
|
||||
logo: Object,
|
||||
shadow: String,
|
||||
title: String
|
||||
})
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<el-card :shadow="shadow" :body-style="{padding: '1rem'}">
|
||||
<div class="logo">
|
||||
<el-image :src="logo" fit="fit" style="width: 20%; height:00%"></el-image>
|
||||
<span class="title">{{title}}</span>
|
||||
</div>
|
||||
<el-scrollbar :height="height">
|
||||
<el-menu router :default-active="$route.path">
|
||||
<template v-for="item in routers" :key="item">
|
||||
<el-menu-item v-if="!item.children || item.children.length <= 1" :index="item.path">
|
||||
<el-icon v-if="item.icon" style="vertical-align: middle;">
|
||||
<component :is="item.icon"></component>
|
||||
</el-icon>
|
||||
<span style="vertical-align: middle;">{{item.meta.title}}</span>
|
||||
</el-menu-item>
|
||||
<TbSubmenu v-else :data="item"></TbSubmenu>
|
||||
</template>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
</el-card>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.logo{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-top: 0.4rem;
|
||||
cursor: pointer;
|
||||
.title{
|
||||
padding-left: 0.6rem;
|
||||
color: var(-t);
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
:deep(.el-menu) {
|
||||
padding-left: 0;
|
||||
border-right: none;
|
||||
background: transparent;
|
||||
.el-sub-menu__title:hover{
|
||||
background: transparent;
|
||||
color: var(--theme);
|
||||
}
|
||||
.el-menu-item:hover{
|
||||
background: transparent;
|
||||
color: var(--theme);
|
||||
}
|
||||
.el-menu-item.is-active {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
let params = {
|
||||
title: route.meta.title as string,
|
||||
path: route.path,
|
||||
close: true
|
||||
close: false
|
||||
};
|
||||
onAddTabManu(params);
|
||||
},
|
||||
|
|
@ -42,12 +42,13 @@
|
|||
router.push(tabItem.path);
|
||||
}
|
||||
|
||||
const onTabMenuClick = (tabItem: TabsPaneContext) =>{
|
||||
function onTabMenuClick(tabItem: TabsPaneContext){
|
||||
console.log(tabItem)
|
||||
let path = tabItem.props.name as string;
|
||||
router.push(path);
|
||||
}
|
||||
|
||||
const onTabMenuRemove = (tabItem: String) =>{
|
||||
function onTabMenuRemove(tabItem: String){
|
||||
let _tabsMenuValue = state.tabsMenuValue;
|
||||
let _tabsMenuList = state.tabsMenuList;
|
||||
if (_tabsMenuValue === tabItem) {
|
||||
|
|
@ -65,18 +66,18 @@
|
|||
state.tabsMenuList = _tabsMenuList.filter(item => item.path !== tabItem);
|
||||
}
|
||||
|
||||
const onCloseCurrentTab = () =>{
|
||||
function onCloseCurrentTab(){
|
||||
if (state.tabsMenuValue === HOME_URL) return;
|
||||
onTabMenuRemove(state.tabsMenuValue);
|
||||
}
|
||||
|
||||
const onCloseOtherTab = () =>{
|
||||
function onCloseOtherTab(){
|
||||
state.tabsMenuList = state.tabsMenuList.filter(item => {
|
||||
return item.path === state.tabsMenuValue || item.path === HOME_URL;
|
||||
});
|
||||
}
|
||||
|
||||
const onCloseAllTab = () =>{
|
||||
function onCloseAllTab(){
|
||||
state.tabsMenuList = state.tabsMenuList.filter(item => {
|
||||
return item.path === HOME_URL;
|
||||
});
|
||||
|
|
@ -86,79 +87,32 @@
|
|||
</script>
|
||||
<template>
|
||||
<div class="tabs-menu">
|
||||
<el-tabs v-model="tabsMenuValue" type="card" @tab-click="onTabMenuClick" @tab-remove="onTabMenuRemove">
|
||||
<el-tabs v-model="tabsMenuValue" @tab-click="onTabMenuClick" @tab-remove="onTabMenuRemove">
|
||||
<el-tab-pane v-for="item in tabsMenuList"
|
||||
:key="item.path"
|
||||
:path="item.path"
|
||||
:label="item.title"
|
||||
:name="item.path"
|
||||
:closable="item.close">
|
||||
:closable="item.close"
|
||||
@node-contextmenu="onTabMenuRemove">
|
||||
<template #label>
|
||||
<el-icon v-if="item.icon" style="vertical-align: middle; padding-right: 0.2rem;">
|
||||
<component :is="item.icon"></component>
|
||||
</el-icon>
|
||||
<span style="vertical-align: middle">{{ item.title }}</span>
|
||||
<el-dropdown :id="item.path" trigger="contextmenu">
|
||||
<span style="vertical-align: middle">{{ item.title }}</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item icon="CircleCloseFilled" @click="onCloseCurrentTab">关闭当前</el-dropdown-item>
|
||||
<el-dropdown-item icon="CircleClose" @click="onCloseOtherTab">关闭其他</el-dropdown-item>
|
||||
<el-dropdown-item icon="CloseBold" @click="onCloseAllTab">关闭所有</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-dropdown trigger="hover">
|
||||
<!-- <el-button size="small" type="primary">
|
||||
<span>更多</span>
|
||||
<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
||||
</el-button> -->
|
||||
<span class="el-dropdown-link" style="cursor: pointer;">
|
||||
<el-icon :size="18"><Tools /></el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item icon="CircleCloseFilled" @click="onCloseCurrentTab">关闭当前</el-dropdown-item>
|
||||
<el-dropdown-item icon="CircleClose" @click="onCloseOtherTab">关闭其他</el-dropdown-item>
|
||||
<el-dropdown-item icon="CloseBold" @click="onCloseAllTab">关闭所有</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" >
|
||||
<style lang="scss">
|
||||
.tabs-menu{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
// border-top: 1px transparent solid;
|
||||
// border-image: linear-gradient(to right, var(--bg1),#DCDFE6, var(--bg1)) 1 10;
|
||||
// box-shadow: rgba(27, 31, 35, 0.04) 0px 1px 0px, rgba(255, 255, 255, 0.25) 0px 1px 0px inset;
|
||||
// margin-bottom: 0.2rem;
|
||||
|
||||
.el-dropdown {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 13px;
|
||||
}
|
||||
|
||||
.el-tabs__nav-wrap {
|
||||
position: absolute;
|
||||
width: calc(100% - 120px);
|
||||
}
|
||||
.el-tabs--card > .el-tabs__header {
|
||||
box-sizing: border-box;
|
||||
height: 40px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.el-tabs--card > .el-tabs__header{
|
||||
border: none;
|
||||
}
|
||||
.el-tabs--card > .el-tabs__header .el-tabs__nav {
|
||||
border: none;
|
||||
}
|
||||
.el-tabs--card > .el-tabs__header .el-tabs__item {
|
||||
border: none;
|
||||
}
|
||||
.el-tabs--card > .el-tabs__header .el-tabs__item.is-active {
|
||||
color: var(--theme);
|
||||
border: none;
|
||||
}
|
||||
.el-tabs__item .is-icon-close svg {
|
||||
margin-top: 0.5px;
|
||||
}
|
||||
margin-top: 1.2rem;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
</el-icon>
|
||||
<span style="vertical-align: middle;">{{item.meta.title}}</span>
|
||||
</el-menu-item>
|
||||
<Submenu v-else :data='item'></Submenu>
|
||||
<TbSubmenu v-else :data='item'></TbSubmenu>
|
||||
</template>
|
||||
</el-sub-menu>
|
||||
</template>
|
||||
|
|
@ -23,7 +23,6 @@
|
|||
--down: #E6A23C;
|
||||
--upper: #67C23A;
|
||||
--role: #006000;
|
||||
|
||||
}
|
||||
|
||||
body {
|
||||
|
|
@ -44,61 +43,6 @@ body {
|
|||
padding: 0.5rem 1rem;
|
||||
}
|
||||
|
||||
/**
|
||||
* table组件样式
|
||||
*/
|
||||
.table-container{
|
||||
.search-wrap{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
// background: var(--bg1);
|
||||
border: 1px solid var(--el-border-color);
|
||||
border-radius: var(--el-border-radius-base);
|
||||
padding: 1.2rem 0;
|
||||
}
|
||||
.search-wrap>div{
|
||||
line-height: 40px;
|
||||
padding: 0.2rem 0.8rem;
|
||||
}
|
||||
.button-wrap{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding-top: 0.6rem;
|
||||
}
|
||||
.button-wrap>div{
|
||||
line-height: 40px;
|
||||
padding: 0.2rem 0.8rem;
|
||||
}
|
||||
.table-wrap{
|
||||
padding: 1rem 0;
|
||||
.header{
|
||||
float: right;
|
||||
padding-bottom: 0.4rem;
|
||||
}
|
||||
}
|
||||
.pagination-wrap{
|
||||
padding-bottom: 0.2rem;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* el-table 滚动条样式
|
||||
*/
|
||||
.el-table__body-wrapper::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
height: 1px;
|
||||
}
|
||||
.el-table__body-wrapper::-webkit-scrollbar-thumb {
|
||||
background-color: #909399;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.el-table__body-wrapper::-webkit-scrollbar-track {
|
||||
border-radius: 5px;
|
||||
background: #ededed;
|
||||
}
|
||||
|
||||
/**
|
||||
* 滚动条样式
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ const baseURL = import.meta.env.VITE_BASE_URL as string;
|
|||
const axiosInstance: AxiosInstance = axios.create({
|
||||
baseURL: baseURL,
|
||||
timeout: 30 * 1000, // 超时时间
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json'
|
||||
// },
|
||||
})
|
||||
|
||||
// axios实例拦截请求
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
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"
|
||||
import { page, del, save, execute } from "@/api/lowcode/codeGen"
|
||||
import { tables, columns } from "@/api/lowcode/source"
|
||||
|
||||
const searchForm = reactive({
|
||||
tableName: null
|
||||
|
|
@ -66,17 +66,44 @@
|
|||
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: [],
|
||||
columnList: [],
|
||||
primary:'',
|
||||
tabsActive: 'table',
|
||||
codeVisible: false,
|
||||
templates: [
|
||||
{ label: '单表(增删改查)', value: 'single' },
|
||||
{ label: '树表(增删改查)', value: 'tree' },
|
||||
{ label: '主子表(增删改查)', value: 'subTable' }
|
||||
],
|
||||
codeForm: {
|
||||
tableName: '',
|
||||
tableSchema: '',
|
||||
dataSource: '',
|
||||
tableComment: '',
|
||||
info: {
|
||||
moduleName: '',
|
||||
modulePath: '',
|
||||
businessName: '',
|
||||
businessPath: '',
|
||||
template: 'single',
|
||||
pid: '',
|
||||
treeId: '',
|
||||
treePid: '',
|
||||
subTable: '',
|
||||
subTableKey: ''
|
||||
},
|
||||
columns: [],
|
||||
subColumns: []
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -86,18 +113,6 @@
|
|||
})
|
||||
}
|
||||
|
||||
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: '确定',
|
||||
|
|
@ -118,30 +133,69 @@
|
|||
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 onTabsClick(tab:any){
|
||||
form.tabsActive = tab.paneName.value
|
||||
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 onTablechange(val:any){
|
||||
let table = form.tableList.find(item => val == item.tableName )
|
||||
form.codeForm.tableComment = table.tableComment
|
||||
form.codeForm.tableSchema = table.tableSchema
|
||||
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){
|
||||
execute(form.codeForm).then(res=>{
|
||||
if(res){
|
||||
ElMessage.success("添加成功!");
|
||||
onCodeGenPage()
|
||||
}
|
||||
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
|
||||
})
|
||||
})
|
||||
})
|
||||
form.codeVisible = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -161,35 +215,164 @@
|
|||
<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-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>
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
transformerVariantGroup,
|
||||
} from 'unocss'
|
||||
|
||||
const url = "http://127.0.0.1:8080"
|
||||
const url = "http://127.0.0.1:8000"
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ public class ColumnsVo {
|
|||
@ApiModelProperty(value = "列描述")
|
||||
private String columnComment;
|
||||
|
||||
@ApiModelProperty(value = "键值")
|
||||
private String columnKey;
|
||||
|
||||
@ApiModelProperty(value = "数据类型")
|
||||
private String dataType;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ 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}")
|
||||
@Select("select table_schema,table_name,column_name,column_comment,column_key,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")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
server:
|
||||
port: 8080
|
||||
port: 8000
|
||||
servlet:
|
||||
context-path: /tansci/
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue