feat 代码生成

This commit is contained in:
lbw 2023-02-08 08:47:22 +08:00
parent 820a0dbbed
commit d594dda9a2
25 changed files with 7142 additions and 1931 deletions

6098
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -12,10 +12,11 @@
"dependencies": {
"@element-plus/icons-vue": "^2.0.10",
"axios": "^1.2.1",
"crypto-js": "^3.1.9-1",
"echarts": "^5.4.1",
"element-plus": "^2.2.26",
"js-cookie": "^3.0.1",
"js-table2excel": "^1.0.3",
"echarts": "^5.4.1",
"mitt": "^3.0.0",
"nprogress": "^0.2.0",
"pinia": "^2.0.28",
@ -30,7 +31,8 @@
"vue-grid-layout": "^3.0.0-beta1",
"vue-i18n": "^9.2.2",
"vue-router": "^4.1.6",
"crypto-js": "^3.1.9-1"
"vxe-table": "^4.3.5",
"xe-utils": "^3.5.4"
},
"devDependencies": {
"@types/node": "^18.11.13",
@ -40,6 +42,7 @@
"@typescript-eslint/parser": "^5.46.0",
"@vitejs/plugin-vue": "^4.0.0",
"@vue/compiler-sfc": "^3.2.45",
"consola": "^2.15.3",
"eslint": "8.22.0",
"eslint-plugin-vue": "^9.8.0",
"prettier": "^2.8.1",
@ -47,6 +50,7 @@
"typescript": "^4.9.4",
"unplugin-auto-import": "^0.13.0",
"vite": "^4.0.0",
"vite-plugin-style-import": "^2.0.0",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vue-eslint-parser": "^9.1.0"
},

55
src/api/gen/datasource.ts Normal file
View File

@ -0,0 +1,55 @@
import request from "/@/utils/request"
export function fetchList(query?: Object) {
return request({
url: '/gen/dsconf/page',
method: 'get',
params: query
})
}
export function list(query?: Object) {
return request({
url: '/gen/dsconf/list',
method: 'get',
params: query
})
}
export function listTable(query?: Object) {
return request({
url: '/gen/dsconf/table/list',
method: 'get',
params: query
})
}
export function addObj(obj?: Object) {
return request({
url: '/gen/dsconf',
method: 'post',
data: obj
})
}
export function getObj(id?: string) {
return request({
url: '/gen/dsconf/' + id,
method: 'get'
})
}
export function delObj(id?: string) {
return request({
url: '/gen/dsconf/' + id,
method: 'delete'
})
}
export function putObj(obj?: Object) {
return request({
url: '/gen/dsconf',
method: 'put',
data: obj
})
}

39
src/api/gen/fieldtype.ts Normal file
View File

@ -0,0 +1,39 @@
import request from "/@/utils/request"
export function fetchList(query?: Object) {
return request({
url: '/gen/fieldtype/page',
method: 'get',
params: query
})
}
export function addObj(obj?: Object) {
return request({
url: '/gen/fieldtype',
method: 'post',
data: obj
})
}
export function getObj(id?: string) {
return request({
url: '/gen/fieldtype/' + id,
method: 'get'
})
}
export function delObj(id?: string) {
return request({
url: '/gen/fieldtype/' + id,
method: 'delete'
})
}
export function putObj(obj?: Object) {
return request({
url: '/gen/fieldtype',
method: 'put',
data: obj
})
}

53
src/api/gen/table.ts Normal file
View File

@ -0,0 +1,53 @@
import request from "/@/utils/request"
export function fetchList(query?: Object) {
return request({
url: '/gen/table/page',
method: 'get',
params: query
})
}
export function addObj(obj?: Object) {
return request({
url: '/gen/table',
method: 'post',
data: obj
})
}
export function getObj(id?: string) {
return request({
url: '/gen/table/' + id,
method: 'get'
})
}
export function delObj(id?: string) {
return request({
url: '/gen/table/' + id,
method: 'delete'
})
}
export function putObj(obj?: Object) {
return request({
url: '/gen/table',
method: 'put',
data: obj
})
}
export const useTableApi = (dsName: string, tableName: string) => {
return request.get('/gen/table/' + dsName + "/" + tableName)
}
export const useTableFieldSubmitApi = (dsName: string, tableName: string, fieldList: any) => {
return request.put('/gen/table/field/' + dsName + '/' + tableName, fieldList)
}
// 生成代码(自定义目录)
export const useGeneratorApi = (tableIds: any[]) => {
return request.post('/gen/generator/code', tableIds)
}

View File

@ -1,16 +1,7 @@
<template>
<el-pagination
@size-change="sizeChangeHandle"
@current-change="currentChangeHandle"
class="mt15"
:pager-count="5"
:page-sizes="prop.pageSizes"
v-model:current-page="prop.current"
background
v-model:page-size="prop.size"
:layout="prop.layout"
:total="prop.total"
>
<el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" class="mt15" :pager-count="5"
:page-sizes="prop.pageSizes" v-model:current-page="prop.current" background v-model:page-size="prop.size"
:layout="prop.layout" :total="prop.total">
</el-pagination>
</template>
@ -42,15 +33,11 @@ const prop = defineProps({
})
//
const sizeChangeHandle = (val: number) => {
emit('sizeChange',val)
emit('sizeChange', val)
};
//
const currentChangeHandle = (val: number) => {
emit('currentChange',val)
emit('currentChange', val)
};
</script>
<style scoped>
</style>

View File

@ -1,18 +1,21 @@
import { createApp } from 'vue';
import pinia from '/@/stores/index';
import App from './App.vue';
import router from './router';
import { directive } from '/@/directive/index';
import { i18n } from '/@/i18n/index';
import other from '/@/utils/other';
import { parseTime, parseDate } from '/@/utils/formatTime';
import { createApp } from 'vue'
import pinia from '/@/stores/index'
import App from './App.vue'
import router from './router'
import { directive } from '/@/directive/index'
import { i18n } from '/@/i18n/index'
import other from '/@/utils/other'
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import elementIcons from '/@//components/svgIcon/svgicon'
import '/@/theme/index.scss';
import VueGridLayout from 'vue-grid-layout';
import '/@/theme/index.scss'
import VueGridLayout from 'vue-grid-layout'
import 'vxe-table/lib/style.css'
import 'xe-utils'
import VXETable from 'vxe-table'
import { Pagination, RightToolbar, DictTag, UploadExcel } from '/@/components/index'
import { parseTime, parseDate } from '/@/utils/formatTime'
@ -34,6 +37,7 @@ other.elSvg(app);
app.use(pinia) // pinia 存储
.use(router) // 路由
.use(ElementPlus, { i18n: i18n.global.t }) // ElementPlus 全局引入
.use(VXETable) // VXETable 全局引入
.use(elementIcons) // elementIcons 图标全局引入
.use(i18n) // 国际化
.use(VueGridLayout)

View File

@ -84,7 +84,7 @@ export function setFilterRouteEnd() {
let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
// notFoundAndNoPower 防止 404、401 不在 layout 布局中不设置的话404、401 界面将全屏显示
// 关联问题 No match found for location with path 'xxx'
console.log(filterRouteEnd,'filterRouteEnd')
console.log(filterRouteEnd, 'filterRouteEnd')
filterRouteEnd[0].children = [...filterRouteEnd[0].children, ...notFoundAndNoPower];
return filterRouteEnd;
}
@ -97,7 +97,7 @@ export function setFilterRouteEnd() {
*/
export async function setAddRoute() {
await setFilterRouteEnd().forEach((route: RouteRecordRaw) => {
console.log(route,'route')
console.log(route, 'route')
router.addRoute(route);
});
}
@ -143,10 +143,9 @@ export function backEndComponent(routes: any) {
export function dynamicImport(dynamicViewsModules: Record<string, Function>, component: string) {
const keys = Object.keys(dynamicViewsModules);
const matchKeys = keys.filter((key) => {
const k = key.replace(/..\/views|../, '');
return k.startsWith(`${component}`) || k.startsWith(`/${component}`);
return k.startsWith(`${component}.vue`) || k.startsWith(`/${component}.vue`);
});
if (matchKeys?.length === 1) {
const matchKey = matchKeys[0];

View File

@ -89,12 +89,7 @@ export const staticConfigRoutes: Array<RouteRecordRaw> = [
component: () => import('/@/views/personal/index.vue'),
meta: {
"title": "router.personal",
"isLink": "",
"isHide": false,
"isKeepAlive": true,
"isAffix": false,
"isIframe": false,
"icon": "iconfont icon-gerenzhongxin"
"isHide": true
},
}
];

View File

@ -11,6 +11,7 @@
font-size: 14px !important;
margin-right: 5px;
}
.el-button--small i.iconfont,
.el-button--small i.fa {
font-size: 12px !important;
@ -27,20 +28,24 @@
/* Form 表单
------------------------------- */
.el-form {
// 用于修改弹窗时表单内容间隔太大问题如系统设置的新增菜单弹窗里的表单内容
.el-form-item:last-of-type {
margin-bottom: 0 !important;
}
// 修复行内表单最后一个 el-form-item 位置下移问题
&.el-form--inline {
.el-form-item--large.el-form-item:last-of-type {
margin-bottom: 22px !important;
}
.el-form-item--default.el-form-item:last-of-type,
.el-form-item--small.el-form-item:last-of-type {
margin-bottom: 18px !important;
}
}
// https://gitee.com/lyt-top/vue-next-admin/issues/I5K1PM
.el-form-item .el-form-item__label .el-icon {
margin-right: 0px;
@ -52,6 +57,7 @@
.el-alert {
border: 1px solid;
}
.el-alert__title {
word-break: break-all;
}
@ -70,23 +76,28 @@
.el-menu-hover-bg-color {
background-color: var(--next-bg-menuBarActiveColor) !important;
}
// 默认样式修改
.el-menu {
border-right: none !important;
width: 220px;
}
.el-menu-item {
height: 56px !important;
line-height: 56px !important;
}
.el-menu-item,
.el-sub-menu__title {
color: var(--next-bg-menuBarColor);
}
// 修复点击左侧菜单折叠再展开时宽度不跟随问题
.el-menu--collapse {
width: 64px !important;
}
// 外部链接时
.el-menu-item a,
.el-menu-item a:hover,
@ -95,6 +106,7 @@
color: inherit;
text-decoration: none;
}
// 第三方图标字体间距/大小设置
.el-menu-item .iconfont,
.el-sub-menu .iconfont,
@ -102,18 +114,22 @@
.el-sub-menu .fa {
@include generalIcon;
}
// 水平菜单横向菜单高亮 背景色鼠标 hover 有子级菜单的背景色
.el-menu-item.is-active,
.el-sub-menu.is-active .el-sub-menu__title,
.el-sub-menu:not(.is-opened):hover .el-sub-menu__title {
@extend .el-menu-hover-bg-color;
}
.el-menu-item:hover {
@extend .el-menu-hover-bg-color;
}
.el-sub-menu.is-active.is-opened .el-sub-menu__title {
background-color: unset !important;
}
// 子级菜单背景颜色
// .el-menu--inline {
// background: var(--next-bg-menuBar-light-1);
@ -123,66 +139,80 @@
color: var(--el-color-white) !important;
text-decoration: none;
}
// 水平菜单横向菜单折叠背景色
.el-popper.is-pure.is-light {
// 水平菜单
.el-menu--vertical {
background: var(--next-bg-menuBar);
.el-sub-menu.is-active .el-sub-menu__title {
color: var(--el-menu-active-color);
}
.el-popper.is-pure.is-light {
.el-menu--vertical {
.el-sub-menu .el-sub-menu__title {
background-color: unset !important;
color: var(--next-bg-menuBarColor);
}
.el-sub-menu.is-active .el-sub-menu__title {
color: var(--el-menu-active-color);
}
}
}
}
// 横向菜单
.el-menu--horizontal {
background: var(--next-bg-topBar);
.el-menu-item,
.el-sub-menu {
height: 50px !important;
line-height: 50px !important;
color: var(--next-bg-topBarColor);
.el-sub-menu__title {
height: 50px !important;
line-height: 50px !important;
color: var(--next-bg-topBarColor);
}
.el-popper.is-pure.is-light {
.el-menu--horizontal {
.el-sub-menu .el-sub-menu__title {
background-color: unset !important;
color: var(--next-bg-topBarColor);
}
.el-sub-menu.is-active .el-sub-menu__title {
color: var(--el-menu-active-color);
}
}
}
}
.el-menu-item.is-active,
.el-sub-menu.is-active .el-sub-menu__title {
color: var(--el-menu-active-color);
}
}
}
// 横向菜单经典横向布局
.el-menu.el-menu--horizontal {
border-bottom: none !important;
width: 100% !important;
.el-menu-item,
.el-sub-menu__title {
height: 50px !important;
color: var(--next-bg-topBarColor);
}
.el-menu-item:not(.is-active):hover,
.el-sub-menu:not(.is-active):hover .el-sub-menu__title {
color: var(--next-bg-topBarColor);
@ -198,10 +228,13 @@
/* Dropdown 下拉菜单
------------------------------- */
.el-dropdown-menu {
list-style: none !important; /*修复 Dropdown 下拉菜单样式问题 2022.03.04*/
list-style: none !important;
/*修复 Dropdown 下拉菜单样式问题 2022.03.04*/
}
.el-dropdown-menu .el-dropdown-menu__item {
white-space: nowrap;
&:not(.is-disabled):hover {
background-color: var(--el-dropdown-menuItem-hover-fill);
color: var(--el-dropdown-menuItem-hover-color);
@ -214,6 +247,7 @@
font-size: 30px !important;
font-weight: 400 !important;
}
.el-step__title {
font-size: 14px;
}
@ -222,6 +256,7 @@
------------------------------- */
.el-overlay {
overflow: hidden;
.el-overlay-dialog {
display: flex;
align-items: center;
@ -229,15 +264,18 @@
position: unset !important;
width: 100%;
height: 100%;
.el-dialog {
margin: 0 auto !important;
position: absolute;
.el-dialog__body {
padding: 20px !important;
}
}
}
}
.el-dialog__body {
max-height: calc(90vh - 111px) !important;
overflow-y: auto;
@ -263,25 +301,31 @@
.el-scrollbar__bar {
z-index: 4;
}
/*防止页面切换时,滚动条高度不变的问题(滚动条高度非滚动条滚动高度)*/
.el-scrollbar__wrap {
max-height: 100%;
}
.el-select-dropdown .el-scrollbar__wrap {
overflow-x: scroll !important;
}
/*修复Select 选择器高度问题*/
.el-select-dropdown__wrap {
max-height: 274px !important;
}
/*修复Cascader 级联选择器高度问题*/
.el-cascader-menu__wrap.el-scrollbar__wrap {
height: 204px !important;
}
/*用于界面高度自适应main.vue区分 scrollbar__view防止其它使用 scrollbar 的地方出现滚动条消失*/
.layout-container-view .el-scrollbar__view {
height: 100%;
}
/*防止分栏布局二级菜单很多时,滚动条消失问题*/
.layout-columns-warp .layout-aside .el-scrollbar__view {
height: unset !important;
@ -292,6 +336,12 @@
.el-pagination__editor {
margin-right: 8px;
}
.el-pagination {
margin-top: 15px;
justify-content: flex-end;
}
/*深色模式时分页高亮问题*/
.el-pagination.is-background .btn-next.is-active,
.el-pagination.is-background .btn-prev.is-active,
@ -300,22 +350,3 @@
color: var(--el-color-white) !important;
}
/* Drawer 抽屉
------------------------------- */
.el-drawer {
--el-drawer-padding-primary: unset !important;
.el-drawer__header {
padding: 0 15px !important;
height: 50px;
display: flex;
align-items: center;
margin-bottom: 0 !important;
border-bottom: 1px solid var(--el-border-color);
color: var(--el-text-color-primary);
}
.el-drawer__body {
width: 100%;
height: 100%;
overflow: auto;
}
}

View File

@ -0,0 +1,177 @@
<template>
<el-dialog :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" v-model="visible"
:close-on-click-modal="false" draggable>
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px">
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.name')" prop="name">
<el-input v-model="form.name" :placeholder="t('datasourceconf.inputnameTip')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.url')" prop="url">
<el-input v-model="form.url" :placeholder="t('datasourceconf.inputurlTip')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.username')" prop="username">
<el-input v-model="form.username" :placeholder="t('datasourceconf.inputusernameTip')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.password')" prop="password">
<el-input v-model="form.password" :placeholder="t('datasourceconf.inputpasswordTip')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.dsType')" prop="dsType">
<el-input v-model="form.dsType" :placeholder="t('datasourceconf.inputdsTypeTip')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.confType')" prop="confType">
<el-radio-group v-model="form.confType">
<el-radio :label="Number(item.value)" v-for="(item, index) in ds_config_type" border :key="index">{{
item.label
}}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.dsName')" prop="dsName">
<el-input v-model="form.dsName" :placeholder="t('datasourceconf.inputdsNameTip')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.instance')" prop="instance">
<el-input v-model="form.instance" :placeholder="t('datasourceconf.inputinstanceTip')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.port')" prop="port">
<el-input v-model="form.port" :placeholder="t('datasourceconf.inputportTip')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.host')" prop="host">
<el-input v-model="form.host" :placeholder="t('datasourceconf.inputhostTip')" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false" formDialogRef>{{ $t('common.cancelButtonText') }}</el-button>
<el-button type="primary" @click="onSubmit" formDialogRef>{{ $t('common.confirmButtonText') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="systemDatasourceConfDialog">
// /
const emit = defineEmits(['refresh']);
import { useMessage } from "/@/hooks/message";
import { getObj, addObj, putObj } from '/@/api/gen/datasource'
import { useI18n } from "vue-i18n"
import { useDict } from '/@/hooks/dict'
const { t } = useI18n();
//
const dataFormRef = ref();
const visible = ref(false)
const { ds_config_type } = useDict('ds_config_type')
//
const form = reactive({
id: '',
name: '',
url: '',
username: '',
password: '',
createTime: '',
updateTime: '',
dsType: '',
confType: 0,
dsName: '',
instance: '',
port: '',
host: '',
});
//
const dataRules = ref({
name: [{ required: true, message: '别名不能为空', trigger: 'blur' }],
url: [{ required: true, message: 'jdbcurl不能为空', trigger: 'blur' }],
username: [{ required: true, message: '用户名不能为空', trigger: 'blur' }],
password: [{ required: true, message: '密码不能为空', trigger: 'blur' }],
dsType: [{ required: true, message: '数据库类型不能为空', trigger: 'blur' }],
confType: [{ required: true, message: '配置类型不能为空', trigger: 'blur' }],
dsName: [{ required: true, message: '数据库名称不能为空', trigger: 'blur' }],
instance: [{ required: true, message: '实例不能为空', trigger: 'blur' }],
port: [{ required: true, message: '端口不能为空', trigger: 'blur' }],
host: [{ required: true, message: '主机不能为空', trigger: 'blur' }],
})
//
const openDialog = (id: string) => {
visible.value = true
form.id = ''
//
if (dataFormRef.value) {
dataFormRef.value.resetFields()
}
// DatasourceConf
if (id) {
form.id = id
getDatasourceConfData(id)
}
};
//
const onSubmit = () => {
dataFormRef.value.validate((valid: boolean) => {
if (!valid) {
return false
}
//
if (form.id) {
putObj(form).then(() => {
useMessage().success(t('common.editSuccessText'))
visible.value = false //
emit('refresh')
}).catch((err: any) => {
useMessage().error(err.msg)
})
} else {
addObj(form).then(() => {
useMessage().success(t('common.addSuccessText'))
visible.value = false //
emit('refresh')
}).catch((err: any) => {
useMessage().error(err.msg)
})
}
})
}
//
const getDatasourceConfData = (id: string) => {
//
getObj(id).then((res: any) => {
Object.assign(form, res.data)
})
};
//
defineExpose({
openDialog
});
</script>

View File

@ -0,0 +1,36 @@
export default {
datasourceconf: {
index: 'index',
importDatasourceConfTip: ' import DatasourceConf',
id: 'id',
name: 'name',
url: 'url',
username: 'username',
password: 'password',
createTime: 'createTime',
updateTime: 'updateTime',
delFlag: 'delFlag',
tenantId: 'tenantId',
dsType: 'dsType',
confType: 'confType',
dsName: 'dsName',
instance: 'instance',
port: 'port',
host: 'host',
inputidTip: 'input id',
inputnameTip: 'input name',
inputurlTip: 'input url',
inputusernameTip: 'input username',
inputpasswordTip: 'input password',
inputcreateTimeTip: 'input createTime',
inputupdateTimeTip: 'input updateTime',
inputdelFlagTip: 'input delFlag',
inputtenantIdTip: 'input tenantId',
inputdsTypeTip: 'input dsType',
inputconfTypeTip: 'input confType',
inputdsNameTip: 'input dsName',
inputinstanceTip: 'input instance',
inputportTip: 'input port',
inputhostTip: 'input host',
}
}

View File

@ -0,0 +1,36 @@
export default {
datasourceconf: {
index: '序号',
importDatasourceConfTip: '导入数据源',
id: '主键',
name: '别名',
url: 'jdbcurl',
username: '用户名',
password: '密码',
createTime: '创建时间',
updateTime: '更新',
delFlag: '删除标记',
tenantId: '租户ID',
dsType: '数据库类型',
confType: '配置类型',
dsName: '数据库名称',
instance: '实例',
port: '端口',
host: '主机',
inputidTip: '请输入主键',
inputnameTip: '请输入别名',
inputurlTip: '请输入jdbcurl',
inputusernameTip: '请输入用户名',
inputpasswordTip: '请输入密码',
inputcreateTimeTip: '请输入创建时间',
inputupdateTimeTip: '请输入更新',
inputdelFlagTip: '请输入删除标记',
inputtenantIdTip: '请输入租户ID',
inputdsTypeTip: '请输入数据库类型',
inputconfTypeTip: '请输入配置类型',
inputdsNameTip: '请输入数据库名称',
inputinstanceTip: '请输入实例',
inputportTip: '请输入端口',
inputhostTip: '请输入主机',
}
}

View File

@ -0,0 +1,127 @@
<template>
<div class="layout-padding">
<el-card class="layout-padding-auto">
<el-row v-show="showSearch" class="mb8">
<el-form :model="state.queryForm" ref="queryRef" :inline="true">
<el-form-item :label="$t('datasourceconf.dsName')" prop="dsName">
<el-input formDialogRef :placeholder="$t('datasourceconf.inputdsNameTip')" v-model="state.queryForm.dsName"
style="max-width: 180px" />
</el-form-item>
<el-form-item class="ml2">
<el-button icon="search" type="primary" @click="getDataList">
{{ $t('common.queryBtn') }}
</el-button>
<el-button icon="Refresh" formDialogRef @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
</el-form-item>
</el-form>
</el-row>
<el-row>
<div class="mb8" style="width: 100%">
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()">
{{ $t('common.addBtn') }}
</el-button>
<el-button icon="upload-filled" type="primary" class="ml10" @click="excelUploadRef.show()">
{{ $t('common.importBtn') }}
</el-button>
<el-button :disabled="multiple" icon="Delete" type="primary" class="ml10"
@click="handleDelete(undefined)">
{{ $t('common.delBtn') }}
</el-button>
<right-toolbar v-model:showSearch="showSearch" class="ml10" style="float: right;margin-right: 20px"
@queryTable="getDataList"></right-toolbar>
</div>
</el-row>
<el-table :data="state.dataList" v-loading="state.loading" style="width: 100%"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column type="index" :label="t('datasourceconf.index')" width="80" />
<el-table-column prop="name" :label="t('datasourceconf.name')" show-overflow-tooltip />
<el-table-column prop="dsName" :label="t('datasourceconf.dsName')" show-overflow-tooltip />
<el-table-column prop="dsType" :label="t('datasourceconf.dsType')" show-overflow-tooltip />
<el-table-column prop="username" :label="t('datasourceconf.username')" show-overflow-tooltip />
<el-table-column prop="createTime" :label="t('datasourceconf.createTime')" show-overflow-tooltip />
<el-table-column :label="$t('common.action')" width="150">
<template #default="scope">
<el-button size="small" text type="primary" @click="formDialogRef.openDialog(scope.row.id)">{{
$t('common.editBtn')
}}</el-button>
<el-button size="small" text type="primary" @click="handleDelete(scope.row)">{{
$t('common.delBtn')
}}</el-button>
</template>
</el-table-column>
</el-table>
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
</el-card>
<!-- 编辑新增 -->
<form-dialog ref="formDialogRef" @refresh="getDataList()" />
</div>
</template>
<script setup lang="ts" name="systemDatasourceConf">
import { BasicTableProps, useTable } from "/@/hooks/table";
import { fetchList, delObj } from "/@/api/gen/datasource";
import { useMessage, useMessageBox } from "/@/hooks/message";
import { useI18n } from "vue-i18n";
//
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
const { t } = useI18n()
//
const formDialogRef = ref()
const excelUploadRef = ref()
//
const queryRef = ref()
const showSearch = ref(true)
//
const selectObjs = ref([])
const multiple = ref(true)
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
pageList: fetchList
})
// table hook
const {
getDataList,
currentChangeHandle,
sizeChangeHandle,
} = useTable(state)
//
const resetQuery = () => {
queryRef.value.resetFields()
getDataList()
}
//
const handleSelectionChange = (val: any) => {
selectObjs.value = val
multiple.value = !val.length
}
//
const handleDelete = (row: any) => {
if (!row) {
selectObjs.value.forEach((val: any) => {
handleDelete(val)
});
return
}
useMessageBox().confirm(t('common.delConfirmText') + row.id)
.then(() => {
delObj(row.id).then(() => {
getDataList();
useMessage().success(t('common.delSuccessText'));
}).catch((err: any) => {
useMessage().error(err.msg)
})
})
};
</script>

View File

@ -0,0 +1,119 @@
<template>
<el-dialog :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" v-model="visible"
:close-on-click-modal="false" draggable>
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px">
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item :label="t('fieldtype.columnType')" prop="columnType">
<el-input v-model="form.columnType" :placeholder="t('fieldtype.inputcolumnTypeTip')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('fieldtype.attrType')" prop="attrType">
<el-input v-model="form.attrType" :placeholder="t('fieldtype.inputattrTypeTip')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('fieldtype.packageName')" prop="packageName">
<el-input v-model="form.packageName" :placeholder="t('fieldtype.inputpackageNameTip')" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false" formDialogRef>{{ $t('common.cancelButtonText') }}</el-button>
<el-button type="primary" @click="onSubmit" formDialogRef>{{ $t('common.confirmButtonText') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="systemFieldTypeDialog">
// /
const emit = defineEmits(['refresh']);
import { useMessage } from "/@/hooks/message";
import { getObj, addObj, putObj } from '/@/api/gen/fieldtype'
import { useI18n } from "vue-i18n"
const { t } = useI18n();
//
const dataFormRef = ref();
const visible = ref(false)
//
const form = reactive({
id: '',
columnType: '',
attrType: '',
packageName: '',
createTime: '',
});
//
const dataRules = ref({
columnType: [{ required: true, message: '字段类型不能为空', trigger: 'blur' }],
attrType: [{ required: true, message: '属性类型不能为空', trigger: 'blur' }],
packageName: [{ required: true, message: '属性包名不能为空', trigger: 'blur' }],
createTime: [{ required: true, message: '创建时间不能为空', trigger: 'blur' }],
})
//
const openDialog = (id: string) => {
visible.value = true
form.id = ''
//
if (dataFormRef.value) {
dataFormRef.value.resetFields()
}
// FieldType
if (id) {
form.id = id
getFieldTypeData(id)
}
};
//
const onSubmit = () => {
dataFormRef.value.validate((valid: boolean) => {
if (!valid) {
return false
}
//
if (form.id) {
putObj(form).then(() => {
useMessage().success(t('common.editSuccessText'))
visible.value = false //
emit('refresh')
}).catch((err: any) => {
useMessage().error(err.msg)
})
} else {
addObj(form).then(() => {
useMessage().success(t('common.addSuccessText'))
visible.value = false //
emit('refresh')
}).catch((err: any) => {
useMessage().error(err.msg)
})
}
})
}
//
const getFieldTypeData = (id: string) => {
//
getObj(id).then((res: any) => {
Object.assign(form, res.data)
})
};
//
defineExpose({
openDialog
});
</script>

View File

@ -0,0 +1,16 @@
export default {
fieldtype: {
index: 'index',
importFieldTypeTip: ' import FieldType',
id: 'id',
columnType: 'columnType',
attrType: 'attrType',
packageName: 'packageName',
createTime: 'createTime',
inputidTip: 'input id',
inputcolumnTypeTip: 'input columnType',
inputattrTypeTip: 'input attrType',
inputpackageNameTip: 'input packageName',
inputcreateTimeTip: 'input createTime',
}
}

View File

@ -0,0 +1,16 @@
export default {
fieldtype: {
index: '序号',
importFieldTypeTip: '导入列属性',
id: 'id',
columnType: '字段类型',
attrType: '属性类型',
packageName: '属性包名',
createTime: '创建时间',
inputidTip: '请输入id',
inputcolumnTypeTip: '请输入字段类型',
inputattrTypeTip: '请输入属性类型',
inputpackageNameTip: '请输入属性包名',
inputcreateTimeTip: '请输入创建时间',
}
}

View File

@ -0,0 +1,131 @@
<template>
<div class="layout-padding">
<el-card class="layout-padding-auto">
<el-row v-show="showSearch" class="mb8">
<el-form :model="state.queryForm" ref="queryRef" :inline="true">
<el-form-item :label="$t('fieldtype.columnType')" prop="columnType">
<el-input formDialogRef :placeholder="$t('fieldtype.inputcolumnTypeTip')"
v-model="state.queryForm.columnType" style="max-width: 180px" />
</el-form-item>
<el-form-item class="ml2">
<el-button icon="search" type="primary" @click="getDataList">
{{ $t('common.queryBtn') }}
</el-button>
<el-button icon="Refresh" formDialogRef @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
</el-form-item>
</el-form>
</el-row>
<el-row>
<div class="mb8" style="width: 100%">
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()">
{{ $t('common.addBtn') }}
</el-button>
<el-button icon="Download" type="primary" class="ml10" @click="exportExcel">
{{ $t('common.exportBtn') }}
</el-button>
<el-button :disabled="multiple" icon="Delete" type="primary" class="ml10"
@click="handleDelete(undefined)">
{{ $t('common.delBtn') }}
</el-button>
<right-toolbar v-model:showSearch="showSearch" class="ml10" style="float: right;margin-right: 20px"
@queryTable="getDataList"></right-toolbar>
</div>
</el-row>
<el-table :data="state.dataList" v-loading="state.loading" style="width: 100%"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column type="index" :label="t('fieldtype.index')" width="80" />
<el-table-column prop="columnType" :label="t('fieldtype.columnType')" show-overflow-tooltip />
<el-table-column prop="attrType" :label="t('fieldtype.attrType')" show-overflow-tooltip />
<el-table-column prop="packageName" :label="t('fieldtype.packageName')" show-overflow-tooltip />
<el-table-column prop="createTime" :label="t('fieldtype.createTime')" show-overflow-tooltip />
<el-table-column :label="$t('common.action')" width="150">
<template #default="scope">
<el-button size="small" text type="primary" @click="formDialogRef.openDialog(scope.row.id)">{{
$t('common.editBtn')
}}</el-button>
<el-button size="small" text type="primary" @click="handleDelete(scope.row)">{{
$t('common.delBtn')
}}</el-button>
</template>
</el-table-column>
</el-table>
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
</el-card>
<!-- 编辑新增 -->
<form-dialog ref="formDialogRef" @refresh="getDataList()" />
</div>
</template>
<script setup lang="ts" name="systemFieldType">
import { BasicTableProps, useTable } from "/@/hooks/table";
import { fetchList, delObj } from "/@/api/gen/fieldtype";
import { useMessage, useMessageBox } from "/@/hooks/message";
import { useI18n } from "vue-i18n";
//
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
const { t } = useI18n()
//
const formDialogRef = ref()
//
const queryRef = ref()
const showSearch = ref(true)
//
const selectObjs = ref([])
const multiple = ref(true)
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
pageList: fetchList
})
// table hook
const {
getDataList,
currentChangeHandle,
sizeChangeHandle,
downBlobFile
} = useTable(state)
//
const resetQuery = () => {
queryRef.value.resetFields()
getDataList()
}
//
const handleSelectionChange = (val: any) => {
selectObjs.value = val
multiple.value = !val.length
}
// excel
const exportExcel = () => {
downBlobFile('/gen/fieldtype/export', state.queryForm, 'fieldtype.xlsx')
}
//
const handleDelete = (row: any) => {
if (!row) {
selectObjs.value.forEach((val: any) => {
handleDelete(val)
});
return
}
useMessageBox().confirm(t('common.delConfirmText') + row.id)
.then(() => {
delObj(row.id).then(() => {
getDataList();
useMessage().success(t('common.delSuccessText'));
}).catch((err: any) => {
useMessage().error(err.msg)
})
})
};
</script>

View File

@ -0,0 +1,251 @@
<template>
<el-drawer v-model="visible" title="编辑" :size="1200" :with-header="false">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="属性设置" name="field">
<vxe-table ref="fieldTable" border row-key class="sortable-row-gen" :data="fieldList"
:checkbox-config="{ checkStrictly: true }" :edit-config="{ trigger: 'click', mode: 'cell' }">
<vxe-column type="seq" width="60"></vxe-column>
<vxe-column width="60" title="拖动">
<template #default>
<span class="drag-btn">
<i class="vxe-icon-sort"></i>
</span>
</template>
<template #header>
<el-tooltip class="item" effect="dark" content="按住后可以上下拖动排序" placement="top-start">
<i class="vxe-icon-question-circle-fill"></i>
</el-tooltip>
</template>
</vxe-column>
<vxe-column field="fieldName" title="字段名"></vxe-column>
<vxe-column field="fieldComment" title="说明" :edit-render="{ name: 'input' }"></vxe-column>
<vxe-column field="fieldType" title="字段类型"></vxe-column>
<vxe-column field="attrName" title="属性名" :edit-render="{ name: 'input' }"></vxe-column>
<vxe-column field="attrType" title="属性类型">
<template #default="{ row }">
<vxe-select v-model="row.attrType">
<vxe-option v-for="item in typeList" :key="item.value" :value="item.value"
:label="item.label"></vxe-option>
</vxe-select>
</template>
</vxe-column>
<vxe-column field="autoFill" title="自动填充">
<template #default="{ row }">
<vxe-select v-model="row.autoFill">
<vxe-option v-for="item in fillList" :key="item.value" :value="item.value"
:label="item.label"></vxe-option>
</vxe-select>
</template>
</vxe-column>
<vxe-column field="primaryPk" title="主键">
<template #default="{ row }">
<vxe-checkbox v-model="row.primaryPk"></vxe-checkbox>
</template>
</vxe-column>
</vxe-table>
</el-tab-pane>
<el-tab-pane label="表单页面" name="form">
<vxe-table ref="formTable" border row-key :data="fieldList" :checkbox-config="{ checkStrictly: true }"
:edit-config="{ trigger: 'click', mode: 'cell' }">
<vxe-column field="attrName" title="属性名"></vxe-column>
<vxe-column field="fieldComment" title="说明"></vxe-column>
<vxe-column field="formItem" title="表单显示">
<template #default="{ row }">
<vxe-checkbox v-model="row.formItem"></vxe-checkbox>
</template>
</vxe-column>
<vxe-column field="formRequired" title="表单必填">
<template #default="{ row }">
<vxe-checkbox v-model="row.formRequired"></vxe-checkbox>
</template>
</vxe-column>
<vxe-column field="formValidator" title="表单效验" :edit-render="{ name: 'input' }"></vxe-column>
<vxe-column field="formType" title="表单类型">
<template #default="{ row }">
<vxe-select v-model="row.formType">
<vxe-option v-for="item in formTypeList" :key="item.value" :value="item.value"
:label="item.label"></vxe-option>
</vxe-select>
</template>
</vxe-column>
<vxe-column field="formDict" title="表单字典类型" :edit-render="{ name: 'input' }"></vxe-column>
</vxe-table>
</el-tab-pane>
<el-tab-pane label="列表查询" name="third">
<vxe-table ref="gridTable" border row-key :data="fieldList" :checkbox-config="{ checkStrictly: true }"
:edit-config="{ trigger: 'click', mode: 'cell' }">
<vxe-column field="attrName" title="属性名"></vxe-column>
<vxe-column field="fieldComment" title="说明"></vxe-column>
<vxe-column field="gridItem" title="列表显示">
<template #default="{ row }">
<vxe-checkbox v-model="row.gridItem"></vxe-checkbox>
</template>
</vxe-column>
<vxe-column field="gridSort" title="列表排序">
<template #default="{ row }">
<vxe-checkbox v-model="row.gridSort"></vxe-checkbox>
</template>
</vxe-column>
<vxe-column field="queryItem" title="查询显示">
<template #default="{ row }">
<vxe-checkbox v-model="row.queryItem"></vxe-checkbox>
</template>
</vxe-column>
<vxe-column field="queryType" title="查询方式">
<template #default="{ row }">
<vxe-select v-model="row.queryType">
<vxe-option v-for="item in queryList" :key="item.value" :value="item.value"
:label="item.label"></vxe-option>
</vxe-select>
</template>
</vxe-column>
<vxe-column field="queryFormType" title="查询表单类型">
<template #default="{ row }">
<vxe-select v-model="row.queryFormType">
<vxe-option v-for="item in formTypeList" :key="item.value" :value="item.value"
:label="item.label"></vxe-option>
</vxe-select>
</template>
</vxe-column>
<vxe-column field="queryDict" title="查询字典类型" :edit-render="{ name: 'input' }"></vxe-column>
</vxe-table>
</el-tab-pane>
</el-tabs>
<template #footer>
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="submitHandle()">确定</el-button>
</template>
</el-drawer>
</template>
<script setup lang="ts">
import { TabsPaneContext } from 'element-plus/es'
import Sortable from 'sortablejs'
import { useTableFieldSubmitApi, useTableApi } from '/@/api/gen/table'
import { fetchList } from '/@/api/gen/fieldtype'
import { VxeTableInstance } from 'vxe-table'
import { useMessage } from '/@/hooks/message'
import { useI18n } from 'vue-i18n'
const { t } = useI18n();
const activeName = ref()
const fieldTable = ref<VxeTableInstance>()
const formTable = ref<VxeTableInstance>()
const gridTable = ref<VxeTableInstance>()
const handleClick = (tab: TabsPaneContext) => {
if (tab.paneName !== 'field') {
formTable.value?.loadData(fieldList.value)
gridTable.value?.loadData(fieldList.value)
}
}
const emit = defineEmits(['refreshDataList'])
const visible = ref(false)
const sortable = ref() as any
const typeList = ref([]) as any
const dsName = ref()
const tableName = ref()
const fieldList = ref([])
const fillList = reactive([
{ label: 'DEFAULT', value: 'DEFAULT' },
{ label: 'INSERT', value: 'INSERT' },
{ label: 'UPDATE', value: 'UPDATE' },
{ label: 'INSERT_UPDATE', value: 'INSERT_UPDATE' }
])
const queryList = reactive([
{ label: '=', value: '=' },
{ label: '!=', value: '!=' },
{ label: '>', value: '>' },
{ label: '>=', value: '>=' },
{ label: '<', value: '<' },
{ label: '<=', value: '<=' },
{ label: 'like', value: 'like' },
{ label: 'left like', value: 'left like' },
{ label: 'right like', value: 'right like' }
])
const formTypeList = reactive([
{ label: '单行文本', value: 'text' },
{ label: '多行文本', value: 'textarea' },
{ label: '富文本编辑器', value: 'editor' },
{ label: '下拉框', value: 'select' },
{ label: '单选按钮', value: 'radio' },
{ label: '复选框', value: 'checkbox' },
{ label: '日期', value: 'date' },
{ label: '日期时间', value: 'datetime' }
])
const openDialog = (dName: string, tName: string) => {
visible.value = true
tableName.value = tName
dsName.value = dName
activeName.value = 'field'
rowDrop()
getTable(dName, tName)
getFieldTypeList()
}
const rowDrop = () => {
nextTick(() => {
const el: any = window.document.querySelector('.body--wrapper>.vxe-table--body tbody')
sortable.value = Sortable.create(el, {
handle: '.drag-btn',
onEnd: (e: any) => {
const { newIndex, oldIndex } = e
const currRow = fieldList.value.splice(oldIndex, 1)[0]
fieldList.value.splice(newIndex, 0, currRow)
}
})
})
}
const getTable = (dsName: string, tableName: string) => {
useTableApi(dsName, tableName).then(res => {
fieldList.value = res.data.fieldList
})
}
const getFieldTypeList = async () => {
typeList.value = []
//
const { data } = await fetchList()
//
data.records.forEach((item: any) => typeList.value.push({ label: item.attrType, value: item.columnType }))
// Object
typeList.value.push({ label: 'Object', value: 'Object' })
}
//
const submitHandle = () => {
useTableFieldSubmitApi(dsName.value, tableName.value, fieldList.value).then(() => {
useMessage().success(t('common.addSuccessText'))
visible.value = false //
emit('refreshDataList')
})
}
defineExpose({
openDialog
})
</script>
<style lang="scss">
.sortable-row-gen .drag-btn {
cursor: move;
font-size: 12px;
}
.sortable-row-gen .vxe-body--row.sortable-ghost,
.sortable-row-gen .vxe-body--row.sortable-chosen {
background-color: #dfecfb;
}
</style>

View File

@ -0,0 +1,195 @@
<template>
<el-dialog v-model="visible" title="生成代码" :close-on-click-modal="false" draggable>
<el-form ref="dataFormRef" :model="dataForm" :rules="dataRules" label-width="120px">
<el-row>
<el-col :span="12" class="mb20">
<el-form-item label="表名" prop="tableName">
<el-input v-model="dataForm.tableName" disabled placeholder="表名"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="说明" prop="tableComment">
<el-input v-model="dataForm.tableComment" placeholder="说明"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" class="mb20">
<el-form-item label="类名" prop="className">
<el-input v-model="dataForm.className" placeholder="类名"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="作者" prop="author">
<el-input v-model="dataForm.author" placeholder="默认作者"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" class="mb20">
<el-form-item label="项目包名" prop="packageName">
<el-input v-model="dataForm.packageName" placeholder="项目包名"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="模块名" prop="moduleName">
<el-input v-model="dataForm.moduleName" placeholder="模块名"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" class="mb20">
<el-form-item label="功能名" prop="functionName">
<el-input v-model="dataForm.functionName" placeholder="功能名"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="表单布局" prop="formLayout">
<el-radio-group v-model="dataForm.formLayout">
<el-radio :label="1" border>一列</el-radio>
<el-radio :label="2" border>两列</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="18" class="mb20">
<el-form-item label="生成方式" prop="generatorType">
<el-radio-group v-model="dataForm.generatorType">
<el-radio :label="0">zip压缩包</el-radio>
<el-radio :label="1">自定义路径</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-form-item v-if="dataForm.generatorType === 1" label="后端生成路径" prop="backendPath">
<el-input v-model="dataForm.backendPath" placeholder="后端生成路径"></el-input>
</el-form-item>
<el-form-item v-if="dataForm.generatorType === 1" label="前端生成路径" prop="frontendPath">
<el-input v-model="dataForm.frontendPath" placeholder="前端生成路径"></el-input>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="submitHandle()">保存</el-button>
<el-button type="danger" @click="generatorHandle()">生成代码</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { useI18n } from 'vue-i18n';
import { putObj, useTableApi } from '/@/api/gen/table'
import { useMessage } from '/@/hooks/message';
import { downBlobFile } from '/@/utils/other';
const emit = defineEmits(['refreshDataList'])
const { t } = useI18n()
const visible = ref(false)
const dataFormRef = ref()
const dataForm = reactive({
id: '',
generatorType: 0,
formLayout: 1,
backendPath: '',
frontendPath: '',
packageName: '',
email: '',
author: '',
version: '',
moduleName: '',
functionName: '',
className: '',
tableComment: '',
tableName: '',
dsName: ''
})
const openDialog = (dName: string, tName: string) => {
visible.value = true
dataForm.id = ''
dataForm.tableName = tName
dataForm.dsName = dName
//
if (dataFormRef.value) {
dataFormRef.value.resetFields()
}
getTable(dName, tName)
}
const getTable = (dsName: string, tableName: string) => {
useTableApi(dsName, tableName).then(res => {
Object.assign(dataForm, res.data)
})
}
const dataRules = ref({
tableName: [{ required: true, message: '必填项不能为空', trigger: 'blur' }],
tableComment: [{ required: true, message: '必填项不能为空', trigger: 'blur' }],
className: [{ required: true, message: '必填项不能为空', trigger: 'blur' }],
packageName: [{ required: true, message: '必填项不能为空', trigger: 'blur' }],
author: [{ required: true, message: '必填项不能为空', trigger: 'blur' }],
moduleName: [{ required: true, message: '必填项不能为空', trigger: 'blur' }],
functionName: [{ required: true, message: '必填项不能为空', trigger: 'blur' }],
generatorType: [{ required: true, message: '必填项不能为空', trigger: 'blur' }],
formLayout: [{ required: true, message: '必填项不能为空', trigger: 'blur' }],
backendPath: [{ required: true, message: '必填项不能为空', trigger: 'blur' }],
frontendPath: [{ required: true, message: '必填项不能为空', trigger: 'blur' }]
})
//
const submitHandle = () => {
dataFormRef.value.validate((valid: boolean) => {
if (!valid) {
return false
}
putObj(dataForm).then(() => {
visible.value = false
emit('refreshDataList')
useMessage().success(t('common.editSuccessText'))
})
})
}
//
const generatorHandle = () => {
dataFormRef.value.validate(async (valid: boolean) => {
if (!valid) {
return false
}
//
await submitHandle()
// zip
if (dataForm.generatorType === 0) {
downBlobFile('/gen/generator/download?tableIds=' + [dataForm.id].join(','), {}, 'file.zip')
visible.value = false
return
}
// //
// useGeneratorApi([dataForm.id]).then(() => {
// visible.value = false
// emit('refreshDataList')
// useMessage().success(t('common.addSuccessText'))
// })
})
}
defineExpose({
openDialog
})
</script>
<style lang="scss" scoped>
.generator-code .el-dialog__body {
padding: 15px 30px 0 20px;
}
</style>

View File

@ -0,0 +1,43 @@
export default {
gen: {
genBtn: 'generator code'
},
table: {
index: 'index',
importTableTip: ' import Table',
id: 'id',
tableName: 'tableName',
className: 'className',
tableComment: 'tableComment',
author: 'author',
email: 'email',
packageName: 'packageName',
version: 'version',
generatorType: 'generatorType',
backendPath: 'backendPath',
frontendPath: 'frontendPath',
moduleName: 'moduleName',
functionName: 'functionName',
formLayout: 'formLayout',
datasourceId: 'datasourceId',
baseclassId: 'baseclassId',
createTime: 'createTime',
inputidTip: 'input id',
inputtableNameTip: 'input tableName',
inputclassNameTip: 'input className',
inputtableCommentTip: 'input tableComment',
inputauthorTip: 'input author',
inputemailTip: 'input email',
inputpackageNameTip: 'input packageName',
inputversionTip: 'input version',
inputgeneratorTypeTip: 'input generatorType',
inputbackendPathTip: 'input backendPath',
inputfrontendPathTip: 'input frontendPath',
inputmoduleNameTip: 'input moduleName',
inputfunctionNameTip: 'input functionName',
inputformLayoutTip: 'input formLayout',
inputdatasourceIdTip: 'input datasourceId',
inputbaseclassIdTip: 'input baseclassId',
inputcreateTimeTip: 'input createTime',
}
}

View File

@ -0,0 +1,43 @@
export default {
gen: {
genBtn: '生成代码',
},
table: {
index: '序号',
importTableTip: '导入列属性',
id: 'id',
tableName: '表名',
className: '类名',
tableComment: '说明',
author: '作者',
email: '邮箱',
packageName: '项目包名',
version: '项目版本号',
generatorType: '生成方式 0zip压缩包 1自定义目录',
backendPath: '后端生成路径',
frontendPath: '前端生成路径',
moduleName: '模块名',
functionName: '功能名',
formLayout: '表单布局 1一列 2两列',
datasourceId: '数据源ID',
baseclassId: '基类ID',
createTime: '创建时间',
inputidTip: '请输入id',
inputtableNameTip: '请输入表名',
inputclassNameTip: '请输入类名',
inputtableCommentTip: '请输入说明',
inputauthorTip: '请输入作者',
inputemailTip: '请输入邮箱',
inputpackageNameTip: '请输入项目包名',
inputversionTip: '请输入项目版本号',
inputgeneratorTypeTip: '请输入生成方式 0zip压缩包 1自定义目录',
inputbackendPathTip: '请输入后端生成路径',
inputfrontendPathTip: '请输入前端生成路径',
inputmoduleNameTip: '请输入模块名',
inputfunctionNameTip: '请输入功能名',
inputformLayoutTip: '请输入表单布局 1一列 2两列',
inputdatasourceIdTip: '请输入数据源ID',
inputbaseclassIdTip: '请输入基类ID',
inputcreateTimeTip: '请输入创建时间',
}
}

View File

@ -0,0 +1,155 @@
<template>
<div class="layout-padding">
<el-card class="layout-padding-auto">
<el-row v-show="showSearch" class="mb8">
<el-form :model="state.queryForm" ref="queryRef" :inline="true">
<el-form-item label="数据源" prop="name">
<el-select v-model="state.queryForm.name" style="width: 100%" placeholder="请选择数据源" @change="getDataList">
<el-option label="默认数据源" value=""></el-option>
<el-option v-for="ds in datasourceList" :key="ds.id" :label="ds.name" :value="ds.name">
</el-option>
</el-select>
</el-form-item>
<el-form-item :label="$t('table.tableName')" prop="tableName">
<el-input :placeholder="$t('table.inputtableNameTip')" v-model="state.queryForm.tableName"
style="max-width: 180px" />
</el-form-item>
<el-form-item class="ml2">
<el-button icon="search" type="primary" @click="getDataList">
{{ $t('common.queryBtn') }}
</el-button>
<el-button icon="Refresh" @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
</el-form-item>
</el-form>
</el-row>
<el-row>
<div class="mb8" style="width: 100%">
<el-button icon="Download" type="primary" class="ml10" @click="exportExcel">
{{ $t('common.exportBtn') }}
</el-button>
<el-button :disabled="multiple" icon="Delete" type="primary" class="ml10" @click="handleDelete(undefined)">
{{ $t('common.delBtn') }}
</el-button>
<right-toolbar v-model:showSearch="showSearch" class="ml10" style="float: right;margin-right: 20px"
@queryTable="getDataList"></right-toolbar>
</div>
</el-row>
<el-table :data="state.dataList" v-loading="state.loading" style="width: 100%"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column type="index" :label="t('table.index')" width="80" />
<el-table-column prop="tableName" :label="t('table.tableName')" show-overflow-tooltip />
<el-table-column prop="tableComment" :label="t('table.tableComment')" show-overflow-tooltip />
<el-table-column prop="createTime" :label="t('table.createTime')" show-overflow-tooltip />
<el-table-column :label="$t('common.action')" width="150">
<template #default="scope">
<el-button size="small" text type="primary"
@click="formDialogRef.openDialog(state.queryForm.name, scope.row.tableName)">{{
$t('common.editBtn')
}}</el-button>
<el-button size="small" text type="primary"
@click="generatorRef.openDialog(state.queryForm.name, scope.row.tableName)">{{
$t('gen.genBtn')
}}</el-button>
<el-button size="small" text type="primary" @click="handleDelete(scope.row)">{{
$t('common.delBtn')
}}</el-button>
</template>
</el-table-column>
</el-table>
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
</el-card>
<!-- 编辑 -->
<edit-dialog ref="formDialogRef" @refresh="getDataList()" />
<!-- 生成配置 -->
<generator-dialog ref="generatorRef" @refreshDataList="getDataList" />
</div>
</template>
<script setup lang="ts" name="systemTable">
import { BasicTableProps, useTable } from "/@/hooks/table";
import { fetchList, delObj } from "/@/api/gen/table";
import { list } from '/@/api/gen/datasource'
import { useMessage, useMessageBox } from "/@/hooks/message";
import { useI18n } from "vue-i18n";
//
const EditDialog = defineAsyncComponent(() => import('./edit.vue'));
const GeneratorDialog = defineAsyncComponent(() => import('./generator.vue'));
const { t } = useI18n()
//
const formDialogRef = ref()
const generatorRef = ref()
//
const queryRef = ref()
const showSearch = ref(true)
//
const selectObjs = ref([])
const multiple = ref(true)
const datasourceList = ref()
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
pageList: fetchList
})
// table hook
const {
getDataList,
currentChangeHandle,
sizeChangeHandle,
downBlobFile
} = useTable(state)
//
onMounted(() => {
list().then(res => {
datasourceList.value = res.data
//
state.queryForm.name = datasourceList.value[0].name
})
})
//
const resetQuery = () => {
queryRef.value.resetFields()
getDataList()
}
//
const handleSelectionChange = (val: any) => {
selectObjs.value = val
multiple.value = !val.length
}
// excel
const exportExcel = () => {
downBlobFile('/gen/table/export', state.queryForm, 'table.xlsx')
}
//
const handleDelete = (row: any) => {
if (!row) {
selectObjs.value.forEach((val: any) => {
handleDelete(val)
});
return
}
useMessageBox().confirm(t('common.delConfirmText') + row.id)
.then(() => {
delObj(row.id).then(() => {
getDataList();
useMessage().success(t('common.delSuccessText'));
}).catch((err: any) => {
useMessage().error(err.msg)
})
})
};
</script>

View File

@ -5,6 +5,8 @@ import vueSetupExtend from 'vite-plugin-vue-setup-extend';
// vue3 自动引入
import AutoImport from 'unplugin-auto-import/vite'
// 按需加载
import { createStyleImportPlugin, VxeTableResolve } from 'vite-plugin-style-import'
const pathResolve = (dir: string) => {
return resolve(__dirname, '.', dir);
@ -18,13 +20,17 @@ const alias: Record<string, string> = {
const viteConfig = defineConfig((mode: ConfigEnv) => {
const env = loadEnv(mode.mode, process.cwd());
return {
plugins: [vue(), vueSetupExtend(),AutoImport({
plugins: [vue(), vueSetupExtend(), AutoImport({
imports: [
'vue',
'vue-router',
'pinia'
],
dts: './auto-imports.d.ts',
}), createStyleImportPlugin({
resolves: [
VxeTableResolve()
],
})],
root: process.cwd(),
resolve: { alias },
@ -43,6 +49,11 @@ const viteConfig = defineConfig((mode: ConfigEnv) => {
ws: true,
changeOrigin: true,
},
'/gen': {
target: 'http://localhost:5003',
ws: true,
changeOrigin: true,
},
},
},
build: {

1326
yarn.lock

File diff suppressed because it is too large Load Diff