Appearance
最佳实践
本文档引用文件
- README.md
- package.json
- codegen/package.json
- deno/package.json
- pc/package.json
- uni/package.json
- codegen/src/config.ts
- deno/graphql.config.js
- pc/graphql.config.js
- uni/graphql.config.js
- pc/src/main.ts
- deno/mod.ts
- uni/src/main.ts
目录
项目概述
本项目是一个基于低代码理念的全栈开发框架,旨在通过智能代码生成与手动开发的无缝融合,提升开发效率。系统采用模块化设计,支持多端(PC、移动端)统一开发,并通过 GraphQL 实现前后端数据交互。其核心创新在于代码生成器能够识别并保留手动修改的代码,避免传统代码生成器覆盖已有变更的问题,从而支持项目全生命周期的持续迭代。
项目包含四个主要模块:
- codegen:代码生成引擎,负责根据数据库表结构生成前后端代码。
- deno:后端服务,基于 Deno 运行时,提供 GraphQL API 接口。
- pc:PC 端前端应用,基于 Vue3 和 Vite 构建。
- uni:移动端前端应用,基于 Uni-app 框架,支持多平台发布。
Section sources
项目结构
项目采用多包(multi-package)结构,各模块职责清晰,便于独立开发与部署。
Diagram sources
技术栈与架构
项目采用现代化的技术栈,前后端均使用 TypeScript,保证类型安全。
前端技术栈
- PC端:Vue3 + Vite + Element Plus + TypeScript + UnoCSS
- 移动端:Uni-app + Vue3 + TypeScript
- 状态管理:Pinia (uni) / Vuex-like (pc)
- 路由:Vue Router
- GraphQL客户端:集成 graphql 包进行数据查询
后端技术栈
- 运行时:Deno (主) / Rust (备选)
- 数据库:MySQL
- API协议:GraphQL
- 服务器框架:Oak (Deno 的 Web 框架)
- 文件存储:S3 兼容服务
架构图
Diagram sources
代码生成与增量更新机制
本项目的核心优势在于其智能代码生成机制,解决了传统代码生成器“覆盖修改”的痛点。
工作原理
- 代码生成:
codegen模块读取数据库表结构和配置,使用预定义的模板生成初始代码。 - 变更检测:当需要重新生成代码时,系统使用
git diff比较新生成的代码与现有代码的差异。 - 增量应用:利用
git apply将新代码中的变更以补丁形式应用到现有代码库,从而保留开发者的手动修改。
关键脚本
npm run codegen: 执行代码生成。npm run codeapply: 应用代码变更(内部调用codeapply.ts)。npm run coderemove: 移除已生成的模块。
Diagram sources
模块划分与目录结构
项目遵循功能模块化和分层架构原则。
codegen 模块
- bin/: 命令行入口 (
codegen.ts,codeapply.ts)。 - lib/: 核心逻辑,如数据库连接 (
information_schema.ts)、S3 客户端。 - tables/: 定义基础表结构和 SQL 脚本。
- template/: 包含 Deno、PC、Uni 三端的代码模板,使用
[[mod_slash_table]]等占位符。 - util/: 各类工具函数,如数据库初始化、CSV 导入、密码加密。
deno 模块
- gen/: 由 codegen 生成的 GraphQL 模型、DAO、Resolver。
- lib/: 核心服务,如
auth.service.ts、oss.service.ts、websocket.router.ts。 - src/: 开发者自定义的业务逻辑,优先级高于
gen/目录。
pc 模块
- views/base/: 由 codegen 生成的页面组件。
- components/: 可复用的 UI 组件,如
CustomInput.vue、DictSelect.vue。 - store/: Pinia 状态管理模块。
- router/: 路由配置,
gen.ts为生成的路由。
uni 模块
- pages/: 页面文件,
optbiz等目录为生成的业务页面。 - uni_modules/tm-ui: 第三方 UI 组件库。
Section sources
命名规范
项目整体遵循 TypeScript 和 Vue 社区的通用规范。
文件与目录命名
- PascalCase: 组件文件 (e.g.,
CustomInput.vue,KFrame.vue)。 - camelCase: 非组件脚本 (e.g.,
Api.ts,Model.ts)。 - kebab-case: 目录名 (e.g.,
background_task,field_permit),与数据库表名保持一致。
变量与函数命名
- camelCase: 变量、函数、方法 (e.g.,
userName,getUserInfo())。 - PascalCase: 类、接口、类型 (e.g.,
UserService,LoginRequest)。 - UPPER_CASE: 常量 (e.g.,
MAX_RETRY_COUNT)。
GraphQL 相关命名
- 类型 (Type):
User,Dept(与数据库表名对应)。 - 查询 (Query):
users,depts(复数形式)。 - 变更 (Mutation):
createUser,updateDept(动词+名词)。
Section sources
错误处理与日志记录
后端错误处理
在 deno/lib/exceptions/ 目录下定义了自定义异常类,如 ServiceException 和 UniqueException。服务层 (*.service.ts) 在捕获到业务或数据异常时,抛出自定义异常,由 GraphQL 的全局错误处理机制捕获并返回结构化错误信息。
前端错误处理
- 网络请求: 使用
try-catch包裹 GraphQL 请求,捕获网络或 GraphQL 错误。 - 用户提示: 通过
MessageBox.ts统一弹窗,提供友好的错误信息。 - 日志记录: 在
utils/request.ts中集成请求日志,记录请求 URL、参数和响应时间。
日志工具
- 后端:
deno/lib/util/log.ts提供日志记录功能。 - 前端:
unplugin-turbo-console插件用于开发环境的增强日志。
Section sources
- deno/lib/exceptions/service.exception.ts
- pc/src/utils/request.ts
- pc/src/components/MessageBox.ts
- deno/lib/util/log.ts
版本管理与协作流程
Git 分支策略
建议采用简化版的 Git Flow:
- main: 生产环境分支,受保护。
- develop: 集成开发分支。
- feature/*: 功能开发分支,从
develop创建,完成后合并回develop。 - hotfix/*: 热修复分支,从
main创建,合并回main和develop。
提交信息规范
采用 Angular 提交规范:
- feat: 新功能
- fix: 修复 Bug
- docs: 文档更新
- style: 代码格式调整
- refactor: 代码重构
- test: 测试相关
- chore: 构建或辅助工具变动
代码审查流程
- 创建 Pull Request (PR)。
- 至少一名团队成员进行代码审查。
- CI/CD 流水线自动运行
lint-staged和测试。 - 审查通过后合并。
Section sources
前端组件设计最佳实践
可复用性
- 原子化设计: 组件如
CustomInput.vue、CustomSelect.vue封装了基础表单元素,统一了样式和行为。 - 属性驱动: 通过
props接收配置,如placeholder,disabled,提高灵活性。 - 插槽 (Slots): 使用
<slot>支持内容分发,增强扩展性。
可访问性 (Accessibility)
- 语义化标签: 使用正确的 HTML 元素。
- ARIA 属性: 为自定义组件添加
aria-*属性。 - 键盘导航: 确保组件可通过 Tab 键访问。
响应式设计
- CSS 框架: 使用 UnoCSS 提供原子化 CSS,结合
@unocss/preset-rem-to-px实现移动端适配。 - 媒体查询: 在 SCSS 文件中定义断点。
- 弹性布局: 大量使用 Flexbox 和 Grid 布局。
Section sources
后端服务开发最佳实践
API 设计
- GraphQL 优先: 使用 GraphQL 提供灵活的数据查询,减少网络请求。
- 类型安全: 通过
graphql-codegen自动生成 TypeScript 类型,保证前后端类型一致。 - 分页与过滤: 在
*.graphql.ts中定义标准的分页输入类型 (PaginationInput)。
事务管理
- 数据库事务: 在
*.dao.ts中,对于涉及多表操作的业务,使用BEGIN TRANSACTION和COMMIT/ROLLBACK。 - 服务层协调:
*.service.ts调用多个 DAO 方法时,负责开启和提交事务。
并发控制
- 乐观锁: 在数据表中增加
version字段,更新时检查版本号。 - 缓存: 使用
lru-cache库缓存高频读取的数据,减少数据库压力。 - 异步处理: 耗时操作(如文件上传、批量导入)放入
background_task表,由后台任务处理。
Section sources
正反例对比分析
正例:智能代码生成
场景: 开发者修改了 pc/views/base/usr/UserList.vue,增加了自定义筛选功能。 正确做法: 再次运行 npm run codegen && npm run codeapply。 结果: 新生成的代码中,UserList.vue 的其他部分(如表格列)被更新,而开发者添加的筛选功能被保留。
反例:直接覆盖生成
场景: 开发者手动修改了 deno/gen/base/usr/usr.resolver.ts。 错误做法: 直接运行 npm run codegen 覆盖整个 gen/ 目录。 后果: 手动修改的 Resolver 逻辑丢失,导致线上功能异常。
正例:模块化状态管理
场景: 管理用户权限。 正确做法: 在 pc/store/permit.ts 中定义独立的 Pinia store。 优点: 逻辑集中,易于维护和测试。
反例:全局状态滥用
场景: 在多个组件中直接使用全局变量存储用户信息。 错误做法: 使用 window.currentUser。 缺点: 难以追踪状态变化,不利于单元测试,违反单向数据流原则。
Section sources