Browse Source

前端脚手架

master
zhanglei 2 weeks ago
parent
commit
55e356d67e
  1. 12
      config.yml
  2. 100
      frontend_vue.py
  3. 2
      generator.py
  4. 0
      templates/java/21.FilesUtil.java.j2
  5. 0
      templates/java/21.MinioUpComponent.java.j2
  6. 0
      templates/java/21.SaTokenConfig.java.j2
  7. 0
      templates/java/21.SwaggerConfig.java.j2
  8. 0
      templates/java/21.controller.java.j2
  9. 0
      templates/java/21.main.pom.xml.j2
  10. 0
      templates/java/21.project.pom.xml.j2
  11. 0
      templates/java/21.webLogAspect.java.j2
  12. 0
      templates/java/FilesUtil.java.j2
  13. 0
      templates/java/Md5HashUtil.java.j2
  14. 0
      templates/java/MinioConfig.java.j2
  15. 0
      templates/java/MinioUpComponent.java.j2
  16. 0
      templates/java/MinioUpController.java.j2
  17. 0
      templates/java/SaTokenConfig.java.j2
  18. 0
      templates/java/SwaggerConfig.java.j2
  19. 0
      templates/java/application-dev.yml.j2
  20. 0
      templates/java/application.java.j2
  21. 0
      templates/java/application.yml.j2
  22. 0
      templates/java/applicationTests.java.j2
  23. 0
      templates/java/baseEntity.java.j2
  24. 0
      templates/java/controller.java.j2
  25. 0
      templates/java/entity.java.j2
  26. 0
      templates/java/globalException.java.j2
  27. 0
      templates/java/logback.xml.j2
  28. 0
      templates/java/main.pom.xml.j2
  29. 0
      templates/java/mapper.java.j2
  30. 0
      templates/java/mapper.xml.j2
  31. 0
      templates/java/mybatis-config.xml
  32. 0
      templates/java/mybatisPlusConfig.java.j2
  33. 0
      templates/java/project.pom.xml.j2
  34. 0
      templates/java/result.java.j2
  35. 0
      templates/java/service.java.j2
  36. 0
      templates/java/serviceImpl.java.j2
  37. 0
      templates/java/testJob.java.j2
  38. 0
      templates/java/webLogAspect.java.j2
  39. 0
      templates/java/xxlJobConfig.java.j2
  40. 22
      templates/vue/data.ts.j2
  41. 24
      templates/vue/form.ts.j2
  42. 64
      templates/vue/index.vue.j2
  43. 57
      templates/vue/mock.ts.j2
  44. 31
      templates/vue/router.ts.j2
  45. 12
      utils.py
  46. 165
      vue-vben-admin/README.subdirectory‌.md
  47. 40
      vue-vben-admin/apps/web-antd/src/api/user/user.ts
  48. 14
      vue-vben-admin/apps/web-antd/src/locales/langs/zh-CN/user.json

12
config.yml

@ -83,4 +83,14 @@ application:
port: 3728
user: root
password: Khq#P9hZ4L@EwCZw
database: health_ai_b
database: health_ai_b
# ===============================
# vue 应用级配置
# ===============================
frontend:
root: F:/zxmgee/codegen/vue-vben-admin
api: apps/web-antd/src/api
views: apps/web-antd/src/views
router: apps/web-antd/src/router/routes/modules
mock: apps/web-antd/mock

100
frontend_vue.py

@ -0,0 +1,100 @@
import os
from jinja2 import Environment, FileSystemLoader
from db import get_columns
from utils import *
import yaml
env = Environment(loader=FileSystemLoader("templates/vue"))
def render(template, out, ctx):
tpl = env.get_template(template)
content = tpl.render(**ctx)
os.makedirs(os.path.dirname(out), exist_ok=True)
with open(out, "w", encoding="utf-8") as f:
f.write(content)
def build_fields(table):
cols = get_columns(table)
fields = []
for c in cols:
field = {}
field["name"] = to_camel(c["column_name"])
field["comment"] = c["column_comment"]
field["type"] = c["data_type"]
# ⭐ 在这里调用组件解析
field["component"] = parse_component(c)
fields.append(field)
return fields
def generate(table):
with open("./config.yml", "r", encoding="utf-8") as f:
cfg = yaml.safe_load(f)
cfg = resolve_config(cfg)
API_DIR = cfg["frontend"]["root"]+"/"+cfg["frontend"]["api"]
VIEW_DIR = cfg["frontend"]["root"]+"/"+cfg["frontend"]["views"]
ROUTER_DIR = cfg["frontend"]["root"]+"/"+cfg["frontend"]["router"]
MOCK_DIR = cfg["frontend"]["root"]+"/"+cfg["frontend"]["mock"]
fields = get_columns(table)
entity = table.replace("health_","")
ctx = {
"table":table,
"entity":entity,
"fields":build_fields(table)
}
render(
"api.ts.j2",
f"{API_DIR}/{entity}.ts",
ctx
)
render(
"index.vue.j2",
f"{VIEW_DIR}/{entity}/index.vue",
ctx
)
render(
"data.ts.j2",
f"{VIEW_DIR}/{entity}/data.ts",
ctx
)
render(
"form.ts.j2",
f"{VIEW_DIR}/{entity}/form.ts",
ctx
)
render(
"router.ts.j2",
f"{ROUTER_DIR}/{entity}.ts",
ctx
)
render(
"mock.ts.j2",
f"{MOCK_DIR}/{entity}.ts",
ctx
)
if __name__ == "__main__":
generate("health_user")

2
generator.py

@ -9,7 +9,7 @@ import argparse
import yaml
import re
env = Environment(loader=FileSystemLoader("templates"))
env = Environment(loader=FileSystemLoader("templates/java"))
def build_fields(table_name):
columns = get_columns(table_name)

0
templates/21.FilesUtil.java.j2 → templates/java/21.FilesUtil.java.j2

0
templates/21.MinioUpComponent.java.j2 → templates/java/21.MinioUpComponent.java.j2

0
templates/21.SaTokenConfig.java.j2 → templates/java/21.SaTokenConfig.java.j2

0
templates/21.SwaggerConfig.java.j2 → templates/java/21.SwaggerConfig.java.j2

0
templates/21.controller.java.j2 → templates/java/21.controller.java.j2

0
templates/21.main.pom.xml.j2 → templates/java/21.main.pom.xml.j2

0
templates/21.project.pom.xml.j2 → templates/java/21.project.pom.xml.j2

0
templates/21.webLogAspect.java.j2 → templates/java/21.webLogAspect.java.j2

0
templates/FilesUtil.java.j2 → templates/java/FilesUtil.java.j2

0
templates/Md5HashUtil.java.j2 → templates/java/Md5HashUtil.java.j2

0
templates/MinioConfig.java.j2 → templates/java/MinioConfig.java.j2

0
templates/MinioUpComponent.java.j2 → templates/java/MinioUpComponent.java.j2

0
templates/MinioUpController.java.j2 → templates/java/MinioUpController.java.j2

0
templates/SaTokenConfig.java.j2 → templates/java/SaTokenConfig.java.j2

0
templates/SwaggerConfig.java.j2 → templates/java/SwaggerConfig.java.j2

0
templates/application-dev.yml.j2 → templates/java/application-dev.yml.j2

0
templates/application.java.j2 → templates/java/application.java.j2

0
templates/application.yml.j2 → templates/java/application.yml.j2

0
templates/applicationTests.java.j2 → templates/java/applicationTests.java.j2

0
templates/baseEntity.java.j2 → templates/java/baseEntity.java.j2

0
templates/controller.java.j2 → templates/java/controller.java.j2

0
templates/entity.java.j2 → templates/java/entity.java.j2

0
templates/globalException.java.j2 → templates/java/globalException.java.j2

0
templates/logback.xml.j2 → templates/java/logback.xml.j2

0
templates/main.pom.xml.j2 → templates/java/main.pom.xml.j2

0
templates/mapper.java.j2 → templates/java/mapper.java.j2

0
templates/mapper.xml.j2 → templates/java/mapper.xml.j2

0
templates/mybatis-config.xml → templates/java/mybatis-config.xml

0
templates/mybatisPlusConfig.java.j2 → templates/java/mybatisPlusConfig.java.j2

0
templates/project.pom.xml.j2 → templates/java/project.pom.xml.j2

0
templates/result.java.j2 → templates/java/result.java.j2

0
templates/service.java.j2 → templates/java/service.java.j2

0
templates/serviceImpl.java.j2 → templates/java/serviceImpl.java.j2

0
templates/testJob.java.j2 → templates/java/testJob.java.j2

0
templates/webLogAspect.java.j2 → templates/java/webLogAspect.java.j2

0
templates/xxlJobConfig.java.j2 → templates/java/xxlJobConfig.java.j2

22
templates/vue/data.ts.j2

@ -0,0 +1,22 @@
/**
* 表格列配置
*/
import type { VxeGridProps } from '#/adapter/vxe-table';
export const columns: VxeGridProps['columns'] = [
{% for f in fields %}
{
// 列标题
title: '{{f.comment}}',
// 对应字段
field: '{{f.name}}',
// 宽度
width: 150,
},
{% endfor %}
];

24
templates/vue/form.ts.j2

@ -0,0 +1,24 @@
/**
* 表单 schema
* component 类型来自 parse_component()
*/
import type { VbenFormSchema } from '#/adapter/form';
export const formSchema: VbenFormSchema[] = [
{% for f in fields %}
{
// 字段名
fieldName: '{{f.name}}',
// label
label: '{{f.comment}}',
// 自动组件
component: '{{f.component}}',
},
{% endfor %}
];

64
templates/vue/index.vue.j2

@ -0,0 +1,64 @@
<script setup lang="ts">
/**
* 页面主入口
*/
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { columns } from './data';
import { {{entity}}Api } from '#/api/{{entity}}';
const [Grid, gridApi] = useVbenVxeGrid({
columns,
proxyConfig: {
ajax: {
query: async ({ page }) => {
const res = await {{entity}}Api.page({
pageNum: page.currentPage,
pageSize: page.pageSize,
})
const data = res.data
const result = {
items: data.records,
total: data.total
}
console.log('=== 返回给 VxeTable 的数据 ===', result)
return result
}
}
},
pagerConfig: {
enabled: true,
},
}
const [Grid, gridApi] = useVbenVxeGrid({
gridOptions,
})
</script>
<template>
<div>
<Grid table-title="用户列表">
<template #toolbar-tools>
<button @click="() => gridApi.reload()">刷新</button>
</template>
</Grid>
</div>
</template>

57
templates/vue/mock.ts.j2

@ -0,0 +1,57 @@
/**
* 自动生成 Mock 数据
*/
import { MockMethod } from 'vite-plugin-mock';
const list = [
{% for i in range(10) %}
{
{% for f in fields %}
{{f.name}}: '{{f.name}}_{{i}}',
{% endfor %}
},
{% endfor %}
];
export default [
{
url: '/api/{{table}}/page',
method: 'get',
response: () => {
return {
code: 0,
data: {
records: list,
total: list.length,
},
};
},
},
{
url: '/api/{{table}}',
method: 'post',
response: () => {
return {
code: 0,
message: 'success',
};
},
},
{
url: '/api/{{table}}/:id',
method: 'delete',
response: () => {
return {
code: 0,
message: 'deleted',
};
},
},
] as MockMethod[];

31
templates/vue/router.ts.j2

@ -0,0 +1,31 @@
/**
* 自动生成路由
*/
import type { RouteRecordRaw } from 'vue-router';
const routes: RouteRecordRaw[] = [
{
path: '/{{entity}}',
name: '{{entityComment}}',
meta: {
icon: 'ic:baseline-view-in-ar',
order: 1000,
keepAlive: true,
title: '{{entityComment}}',
},
children: [
{
meta: {
title: "{{entityComment}}列表",
},
name: '{{entity}}_List',
path: '/{{entity}}',
component: () => import('#/views/{{entity}}/index.vue'),
},
],
}
];
export default routes;

12
utils.py

@ -134,3 +134,15 @@ def mysql_to_java(mysql_type):
"decimal": "BigDecimal"
}
return mapping.get(mysql_type, "String")
def parse_component(field):
t = field["data_type"]
if "datetime" in t:
return "DatePicker"
if "text" in t:
return "InputTextArea"
if "int" in t:
return "InputNumber"
return "Input"

165
vue-vben-admin/README.subdirectory‌.md

@ -0,0 +1,165 @@
# 根目录结构
~~~shell
vue-vben-admin/
├── apps/ # 应用目录 - 存放各个可运行的应用
├── docs/ # 项目文档
├── internal/ # 内部工具和配置
├── packages/ # 共享包目录
├── playground/ # 测试和演示环境
├── scripts/ # 脚本文件
├── package.json # 根目录依赖配置
├── pnpm-workspace.yaml # pnpm 工作区配置
└── README.md # 项目说明文档
~~~
# packages 共享包目录,存放可复用的代码库,如 UI 组件库、工具库等。
~~~shell
packages/
├── @core/ # 核心功能模块(组件、hooks、utils)
├── constants/ # 全局常量定义
├── effects/ # 副作用处理(如表单、表格)
├── icons/ # 图标资源
├── locales/ # 国际化资源
├── preferences/ # 偏好设置
├── stores/ # 状态管理(Pinia)
├── styles/ # 共享样式
├── types/ # TypeScript 类型定义
└── utils/ # 工具函数
~~~~
# apps/web-antd 应用目录详解
~~~shell
apps/web-antd/
├── src/
│ ├── api/ # API 接口层 - 所有后端接口请求
│ │ ├── user.ts # 用户模块接口
│ │ ├── dashboard.ts # 仪表盘接口
│ │ └── system/ # 系统管理模块
│ │ ├── menu.ts # 菜单管理
│ │ ├── role.ts # 角色管理
│ │ └── user.ts # 系统用户管理
│ │
│ ├── assets/ # 静态资源
│ │ ├── images/ # 图片资源
│ │ └── styles/ # 应用级样式
│ │
│ ├── components/ # 公共组件
│ │ ├── BasicTable.vue # 表格组件
│ │ ├── BasicForm.vue # 表单组件
│ │ └── BasicUpload.vue # 上传组件
│ │
│ ├── hooks/ # 自定义组合式函数
│ │ └── useTable.ts # 表格逻辑封装
│ │
│ ├── layouts/ # 布局组件
│ │ ├── BasicLayout.vue # 基础布局
│ │ ├── Header/ # 头部组件
│ │ └── Sidebar/ # 侧边栏组件
│ │
│ ├── locales/ # 国际化语言包
│ │ ├── zh-CN.ts # 中文
│ │ └── en-US.ts # 英文
│ │
│ ├── router/ # 路由配置
│ │ ├── index.ts # 路由入口
│ │ ├── guard/ # 路由守卫
│ │ ├── constant.ts # 常量路由
│ │ └── modules/ # 按模块划分的路由
│ │ └── [module].ts # 各模块路由
│ │
│ ├── store/ # Pinia 状态管理
│ │ ├── index.ts # 状态入口
│ │ └── modules/ # 模块化状态
│ │ ├── app.ts # 应用状态
│ │ ├── user.ts # 用户状态
│ │ └── permission.ts # 权限状态
│ │
│ ├── utils/ # 工具函数
│ │ └── http/axios.ts # HTTP 请求封装
│ │
│ ├── views/ # 页面组件(核心开发目录)
│ │ ├── dashboard/ # 仪表盘
│ │ ├── system/ # 系统管理
│ │ │ ├── user/ # 用户管理模块
│ │ │ │ ├── index.vue # 列表页面
│ │ │ │ ├── UserDrawer.vue # 表单抽屉
│ │ │ │ └── user.data.ts # 配置数据
│ │ │ └── role/ # 角色管理
│ │ └── demo/ # 示例页面
│ │
│ ├── settings/ # 项目配置
│ │ ├── projectSetting.ts # 项目基础配置
│ │ ├── localeSetting.ts # 多语言配置
│ │ └── designSetting.ts # 主题配置
│ │
│ ├── design/ # 全局样式设计
│ │ ├── index.less # 样式入口
│ │ ├── var/ # 变量定义
│ │ └── theme/ # 主题相关
│ │
│ ├── directives/ # 自定义指令
│ │ ├── permission.ts # 权限指令
│ │ └── resize.ts # 尺寸监听
│ │
│ ├── types/ # 本地类型定义
│ │ └── global.d.ts # 全局类型
│ │
│ ├── main.ts # 应用入口文件
│ └── App.vue # 根组件
├── index.html # HTML 模板
├── package.json # 应用依赖
├── vite.config.ts # Vite 配置
└── .env.* # 环境变量
~~~
三、核心文件功能说明
3.1 入口文件 main.ts
项目的启动入口,执行 bootstrap() 函数完成以下初始化:
创建 Vue 应用实例
配置 Pinia 状态管理
注册全局组件
初始化国际化(i18n)
配置路由并挂载路由守卫
注册全局指令
配置错误处理
3.2 路由配置 router/
modules/:按业务模块划分的路由文件
guard/:路由守卫,处理权限验证、页面状态等
路由配置直接决定侧边栏菜单的生成
3.3 API 层 api/
按模块组织接口请求(user.ts、system/等)
使用封装的 defHttp 或 requestClient 发起请求
包含完整的 TypeScript 类型定义
3.4 视图层 views/
每个业务模块通常由三个文件组成:
index.vue:主页面(列表页)
[Module]Drawer.vue:新增/编辑弹窗
[module].data.ts:配置数据(表格列、表单 Schema)
这种拆分方式使代码更简洁,维护性更好,Git 代码冲突概率低。
四、配置文件说明
配置文件 作用
vite.config.ts Vite 构建配置(端口、代理、插件)
.env.development 开发环境变量
.env.production 生产环境变量
package.json 依赖管理和脚本命令
五、核心设计理念
分层架构:应用层(apps)、共享层(packages)、核心层(@core)清晰分离
配置与逻辑分离:如 .data.ts 存放配置,index.vue 存放逻辑
按模块组织:API、路由、视图、状态都按模块划分
TypeScript 优先:全项目 TypeScript,类型定义完善
六、开发注意事项
所有页面组件必须放在 views/ 目录下
路由配置中父级必须使用 LAYOUT 组件
路由 name 必须全局唯一
使用路径别名 /@/ 指向 src/ 目录
理解这些目录结构和设计理念,您就能更好地在 Vben Admin 中进行开发和代码生成。

40
vue-vben-admin/apps/web-antd/src/api/user/user.ts

@ -0,0 +1,40 @@
import { requestClient } from '#/api/request';
export namespace UserApi {
/**
*
*/
export function page(params:any){
return requestClient.get('/api/user/page',{params});
}
/**
*
*/
export function detail(id:number){
return requestClient.get('/api/user/'+id);
}
/**
*
*/
export function add(data:any){
return requestClient.post('/api/user',data);
}
/**
*
*/
export function update(id:number,data:any){
return requestClient.put('/api/user/'+id,data);
}
/**
*
*/
export function remove(id:number){
return requestClient.delete('/api/user/'+id);
}
}

14
vue-vben-admin/apps/web-antd/src/locales/langs/zh-CN/user.json

@ -0,0 +1,14 @@
{
"title": "用户模块",
"antd": "Ant Design Vue",
"vben": {
"title": "项目",
"about": "关于",
"document": "文档",
"antdv": "Ant Design Vue 版本",
"antdv-next": "Antdv Next 版本",
"naive-ui": "Naive UI 版本",
"element-plus": "Element Plus 版本",
"tdesign": "TDesign Vue 版本"
}
}
Loading…
Cancel
Save