ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ai coding 项目案例开发

ai coding 项目案例开发

从 0 到 1:搭建企业级通用业务基座平台(统一身份 · 统一权限 · 统一基础数据)

每一个做过多套业务系统的团队,都经历过"重复造轮子"的痛苦:每开一个新项目,就要重新写一遍登录、权限、用户、部门、字典……今天就分享如何一次性把这些公共能力沉淀成一个企业级通用业务基座平台,让后续所有业务系统直接复用。

一、为什么要做"业务基座"

先看一个常见的痛点:公司有 ERP、CRM、OA、报表中心等多个系统,每个系统都各自维护一套:

  • 自己的登录注册和密码体系;

  • 自己的用户表、角色表、权限表;

  • 自己的部门组织架构(还不一致);

  • 自己的数据字典(男/女的取值都可能是 1/2 或 M/F);

  • 自己的系统配置(改个系统名称要翻代码)。

结果就是:用户在多个系统要记多套密码,管理员要重复配置 N 遍权限,基础数据各说各话

企业级基座平台就是用来根治这个问题的:

它作为整套业务体系的底层根基,对外统一提供身份认证、RBAC 权限控制、组织架构、数据字典、系统全局配置、数据可视化仪表盘等公共能力,让其他业务系统只做业务、不重复造轮子

一句话:多应用统一身份、统一权限、统一基础数据管理

二、需求拆解(10 大核心功能)

我们把它拆成 10 个可交付的功能模块:

编号功能说明
1用户管理用户 CRUD、角色分配、状态启停、重置密码
2登录注册JWT 认证、注册自动分配默认角色、登录日志
3RBAC 角色管理基于角色的访问控制,角色 CRUD + 数据权限范围
4按钮级权限权限颗粒化到按钮,前端指令 + 后端中间件双重校验
5菜单管理目录/菜单/按钮三级,动态路由、权限分配可视化
6组织架构集团 → 公司 → 部门三级树形组织
7数据字典字典类型 + 字典数据,动态数据、全局常量的唯一来源
8系统配置系统名称/Logo/分页/安全级别,配置值受数据字典控制
9个人中心用户自我管理:资料、头像、密码
10数据仪表盘基础数据可视化 + 仪表盘升级能力,为更多模块分析预留入口

三、技术选型(以及为什么不是 Spring Boot)

作为中文企业级项目,大家第一反应通常都是Spring Boot + MyBatis-Plus + MySQL。但这次我选择了全栈 Node.js

后端:Node.js + Express + SQLite(node:sqlite 内置模块) 前端:Vue 3 + Vite + Element Plus + Pinia + ECharts

原因主要有三:

  1. 零原生依赖。Node 22.5+ 内置了node:sqlite模块,不需要安装任何原生编译的数据库驱动,跨平台开箱即用,学习成本也低。

  2. 一套语言打通全栈。前端 Vue、后端 Node 都是 JavaScript/TypeScript,模型定义、枚举常量前后端可以共享心智,不用在 Java 和 JS 之间来回切换。

  3. 轻量、易部署、易复用。基座平台本身要"轻",其他业务系统集成它时,Node 后端比 Java 后端更接近前端团队的技术栈。

架构上做好了分层和接口抽象,如果未来要切 MySQL/Spring Cloud,数据访问层和服务层都可以平滑替换——基座的定位是能力沉淀,不是技术绑定

四、系统架构

┌─────────────────────────────────────────────┐ │ 前端 web(Vue3 + Element Plus) │ │ 动态路由 │ v-permission 按钮指令 │ ECharts │ └───────────────┬─────────────────────────────┘ │ /api(vite 代理 / axios) ┌───────────────▼─────────────────────────────┐ │ 后端 server(Express) │ │ routes → middleware(认证/RBAC) → services │ │ → db(SQLite / node:sqlite) │ └─────────────────────────────────────────────┘ 统一提供:认证 / 权限 / 组织 / 字典 / 配置 / 统计

核心设计原则:

  • 前后端分离,接口统一/api前缀,天然适合作为公共基座被其他系统调用;

  • 分层清晰:路由层只管 HTTP,中间件管认证与鉴权,服务层管业务,数据层管 SQL;

  • 约定大于配置:统一响应格式{code, msg, data}、统一分页结构、统一异常处理。

五、数据库设计(核心表)

全部围绕"用户-角色-权限"和"元数据驱动"两大主题:

用户 sys_user 用户基础信息 + 所属部门 + 是否超管 组织架构 sys_dept 集团/公司/部门 三级树 角色 sys_role 角色 + 数据权限范围 用户角色 sys_user_role 多对多 菜单/权限 sys_menu 目录/菜单/按钮三级,按钮含权限标识 perms 角色权限 sys_role_menu 多对多 字典类型 sys_dict_type 如 sys_user_gender、sys_security_level 字典数据 sys_dict_data 如 {男:1, 女:2} 系统配置 sys_config 配置项 + 关联字典类型 dict_type 登录日志 sys_login_log 仪表盘数据来源

其中sys_menu是 RBAC 的核心,它把"菜单"和"权限"统一建模:

  • type='M'目录(如"系统管理");

  • type='C'菜单(可跳转的页面路由);

  • type='F'按钮perms字段存权限标识,如system:user:add)。

按钮级权限就是这么来的:一个"新增用户"按钮,在权限树里就是一个叶子节点,权限标识为system:user:add。角色勾选了这个节点,用户就拥有了对应的操作权。

六、几个核心实现

1. RBAC 按钮级权限(前端 + 后端双重校验)

后端——每个接口都要过权限中间件:

// 权限中间件:没有 system:user:add 权限直接 403 router.post('/', authenticate, checkPerm('system:user:add'), handler)

前端——按钮级显隐用指令控制:

<el-button v-permission="'system:user:add'" type="primary">新增用户</el-button>

指令内部逻辑:从用户 Store 的权限码集合判断,无权限直接移除该 DOM 节点:

app.directive('permission', { mounted(el, binding) { const perms = useUserStore().perms; // 登录后由后端下发 const has = perms.includes(binding.value); if (!has) el.parentNode.removeChild(el); // 无权限 → 按钮消失 }, });

为什么双重校验:前端控制"看得到",后端控制"用得了"。即使有人绕过前端直接调接口,后端 403 依然兜底。安全永远不能只依赖前端。

动态路由同样由权限驱动:登录后后端返回该用户有权限的菜单树,前端据此动态注册路由 + 渲染侧边栏,普通员工登录后"系统管理"根本不会出现在路由表里。

2. 数据字典驱动的系统配置

需求第 8 条有个硬约束:系统配置的相关数据必须从数据字典进行控制和获取

实现上,sys_config每个配置项可以关联一个字典类型:

sys.page.size = 10 → 来源字典 sys_page_size_options(10/20/50/100) sys.security.level = MEDIUM → 来源字典 sys_security_level(低/中/高) sys.dashboard.version = basic → 来源字典 sys_dashboard_version(基础/专业/旗舰)

后端在保存配置时做了字典值强校验

if (dictType && configType === 'Y') { const valid = one('SELECT id FROM sys_dict_data WHERE dict_type_id=? AND value=?', [dict.id, value]); if (!valid) return res.json(fail(`配置值必须来源于数据字典「${dictType}」`)); }

于是"系统名称、Logo、分页大小、安全级别"这些配置,全部通过字典界面维护,不碰一行代码。前端还能直接GET /api/configs/public拿到 key-value 全量配置做初始化(系统名称、Logo 都会实时反映到登录页和顶栏)。

3. 数据仪表盘 + 升级机制

仪表盘是本平台的"门面",需要基本的数据分析和可视化:

  • 6 张统计卡片(用户/启用用户/今日登录/角色/部门/菜单数量);

  • 4 组 ECharts 图表:近 7 日注册趋势、登录成功/失败对比、组织架构用户分布饼图、角色用户数分布;

  • 最近登录日志表格。

同时,需求还要求"为更多模块数据的分析和可视化保留可能性",所以我们设计了仪表盘版本升级机制:

  • 版本由sys.dashboard.version(数据字典)控制;

  • 系统配置页提供三档升级方案(基础版/专业版/旗舰版),一键切换版本;

  • 基础版展示公共模块数据,专业版/旗舰版预留"登录安全分析、权限审计、组织全景"等模块入口。

新业务模块上线后,只需往仪表盘"模块分析中心"追加自己的可视化卡片,即插即用。

4. 手写 JWT 与密码哈希

后端依赖做到了极致精简(只装了 express + cors),JWT 签发校验和密码哈希全部用 Node 内置模块实现:

// JWT:HMAC-SHA256 签名(crypto 内置) const signature = crypto.createHmac('sha256', secret) .update(`${headerStr}.${bodyStr}`).digest('base64url'); ​ // 密码:scrypt + 随机盐 const hash = scryptSync(plain, salt, 64).toString('hex'); const verify = timingSafeEqual(Buffer.from(hash, 'hex'), test); // 恒时比较防时序攻击

不引第三方依赖,既减少了供应链风险,也让代码更可控——"基座"本来就该把最基础的东西握在自己手里。

七、开发过程中的几个"坑"

  1. node:sqlite的返回值lastInsertRowid可能是 BigInt,拼接 SQL 参数时记得Number()转一下。

  2. 动态路由的组件加载:Vite 无法在运行时静态解析模板字符串 import,需要用import.meta.glob预注册所有视图再按 key 取用。

  3. 树形数据删除:删除部门/菜单前必须检查"是否有子节点/是否有用户",否则会留下孤儿数据。

  4. 权限树回显:角色分配权限用el-tree时,父子联动会把父节点置为半选态,保存时要合并getCheckedKeys() + getHalfCheckedKeys(),否则父目录权限会丢。

  5. 中文参数乱码:本地 curl 调试带中文 query 参数时遇到编码问题,最后统一用 code/ID 查询规避,前端 axios 传参无此问题。

八、效果展示与使用

默认三套账号即可演示完整权限体系:

账号密码角色可见能力
adminadmin123超级管理员全部模块
zhangsan123456系统管理员系统管理 + 仪表盘
lisi123456普通员工仅仪表盘 + 个人中心

lisi登录,你会看到侧边栏只有"数据仪表盘",直接访问/system/user会被路由守卫拦下,调接口会被后端 403——权限从入口到出口都是通的

九、如何让 AI 帮你完成这样的项目

这次整个项目是用 Claude Code 从需求直接生成的。分享几点经验:

  1. 需求要拆到可验证:把"权限管理"拆成"用户/角色/菜单/按钮级权限"等明确条目,AI 才能逐条落地。

  2. 技术选型交给环境说话:先让 AI 检查本机环境(Node/Java/数据库),再决定技术栈,保证"能跑起来"。

  3. 种子数据是试金石:项目能演示,靠的是预置的组织架构、字典、账号数据,这一步不能省。

  4. 让它边做边自测:生成后立即启动服务,用 curl 跑一遍登录 → 鉴权 → CRUD 全链路回归,把"看起来对"变成"验证过对"。

十、写在最后

企业级基座平台的价值,不在于某个功能有多炫,而在于它把重复建设消灭在源头:新业务系统接入时,身份认证、权限控制、组织、字典、配置、可视化都是现成的。它不只是一个系统,而是一套可复用的开发范式

如果你也在规划企业级产品矩阵,建议尽早把公共能力沉淀为基座——造一次轮子,然后永远不再造它


项目完整源码、数据库设计、启动说明见项目 README;文中所有实现均为可运行代码,可在本地npm install && npm start一键体验。

返回列表