全栈全流程多网站设计框架

一、项目定位

Elpis 是一个企业级全栈低代码后台管理系统,采用 Koa 2 + Vue 3 技术栈,核心理念是配置驱动 UI:通过编写 JSON 配置(Schema)自动生成完整的后台管理页面(菜单、表格、搜索栏、操作按钮),而不需要为每个业务模块重复编写前端页面。

二、解决的痛点

  1. 重复开发成本高

传统后台系统里,每个业务模块(商品管理、订单管理、客户管理...)都要写一套几乎相同的代码:表格 + 搜索栏 + CRUD 按钮 + 分页 + 接口对接。Elpis 把这些全部抽象成配置:

一个新业务模块 = 一段 JSON 配置 + 一个 RESTful API

  1. 多项目配置难以复用

同一套电商系统可能有"拼多多版"、"淘宝版"、"京东版",它们 80% 的菜单和字段相同,只有少量差异。Elpis 用模型继承机制解决这个问题:

基础模型 (model/buiness/model.js)     ← 定义通用菜单、字段
    ├── 拼多多 (project/pdd.js)       ← 继承 + 覆盖/新增
    ├── 淘宝 (project/taobao.js)      ← 继承 + 覆盖/新增
    └── 京东 (project/jd.js)          ← 继承 + 覆盖/新增

项目配置会按 key 字段智能合并:相同 key 的菜单项递归覆盖,新增 key 的菜单项追加,未覆盖的保留继承。

  1. 前后端割裂

Elpis 自研了一个轻量级后端框架 elpis-core(类 Egg.js),约定了目录结构,自动加载 controller / service / middleware / router,前后端在同一个仓库里协作,降低了对接成本。

三、架构设计

整体分层

浏览器
  ↓
Koa Server (BFF 层)
  ├── /view/:page          → Nunjucks 渲染 → 返回 SPA 入口 HTML
  ├── /api/project/*       → ProjectController → ProjectService → model 配置
  └── /api/product/*       → BusinessController → 业务数据
  ↓
Vue 3 SPA (前端)
  ├── boot.js              → 统一初始化 (Vue + ElementPlus + Pinia + Router)
  ├── pages/               → 按页面划分的入口 (entry.*.js)
  ├── widgets/             → 可复用的 Schema 驱动组件
  └── store/               → Pinia 状态管理

后端:自研微框架 elpis-core

不依赖 Egg.js 等重型框架,而是在 Koa 之上用目录约定 + Glob 自动加载实现了一个轻量级框架:

目录加载到作用
app/controller/*.jsapp.controller.*处理请求
app/service/*.jsapp.service.*业务逻辑
app/middleware/*.jsapp.middlewares.*中间件(签名校验、参数校验、项目上下文)
app/router/*.jsKoa Router路由注册
app/router-schema/*.jsapp.routerSchemaAJV 参数校验规则
config/*.jsapp.config环境配置(local/beta/prod)

前端:Schema 驱动 UI

这是 Elpis 最核心的设计。一个完整的业务模块只需要一段配置:

{
  key: 'product',
  moduleType: 'schema',
  schemaConfig: {
    api: '/api/product',          // 数据源
    schema: {                      // 字段定义
      properties: {
        product_name: {
          label: '商品名称',
          tableOption: { width: 200 },      // → 自动生成表格列
          searchOption: { comType: 'input' } // → 自动生成搜索输入框
        }
      }
    },
    tableConfig: {                 // 按钮定义
      headerButtons: [...],        // → 自动生成头部操作按钮
      rowButtons: [...]            // → 自动生成行内操作按钮
    }
  }
}

数据流:

JSON 配置 → useSchema() Hook 解析
                ├── buildDtoSchema(schema, 'table')  → schema-table 组件 → 动态列渲染
                ├── buildDtoSchema(schema, 'search') → schema-search-bar → 动态表单渲染
                └── tableConfig                      → table-panel → 动态按钮渲染

模型继承系统

model/index.js 实现了一套配置继承与合并机制:

model/buiness/model.js          ← 基础模型(通用菜单、通用字段)
model/buiness/project/pdd.js    ← 项目配置(覆盖/新增)
                ↓
         lodash.mergeWith
                ↓
    最终配置(按 key 字段智能合并数组)

这意味着:

  • 基础模型定义了"商品管理"有 6 个字段
  • pdd 项目可以只写"我要覆盖商品名称的列宽",其他字段自动继承
  • pdd 项目也可以新增基础模型没有的菜单项

构建系统

Webpack 5 多入口构建,每个 entry.*.js 生成一个独立的 SPA 页面:

入口页面
entry.project-list.js项目列表页(无路由)
entry.dashboard.js业务仪表盘(带子路由:schema / sider / iframe / todo)

开发时双服务器:Koa(9090)负责 API + 模板渲染,Express(9003)负责 Webpack HMR 热更新。

四、关键设计理念

  1. 约定优于配置 目录结构即规范,放对位置就自动加载,不需要手动注册。

  2. 配置驱动视图 一份 Schema 同时描述表格列、搜索表单、操作按钮,buildDtoSchema 按 xxxOption 后缀分别提取,同一份数据源、不同维度的消费。

  3. 组件即插件 搜索栏的输入类型通过 schema-item-config.js 注册,新增一种输入组件只需要:写组件 → 注册 key → 配置里用对应 comType,搜索栏框架代码零改动。

  4. 继承优于复制 项目配置继承基础模型,只写差异部分,避免多项目间大量重复配置。

  5. 前后端同构约定 前端 $curl 自动带签名和项目标识,后端中间件自动校验,controller 统一响应格式(success / fail),减少前后端对接的心智负担。