diff --git a/README.md b/README.md index ab7fef8..ff0604f 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,33 @@ import type { IFieldConfig, IMenuItem, IMeResult } from "shrimp-server/types" ## 约定 +shrimp 不是铁板一块的协议,它是**一组可选拼装件**。每个件对外有自己的契约,你用了哪个件就被哪个件的契约绑住,不用就不必遵守。盘点时按**作用域**分两层。 + +### 🌐 全局约定(只要你说"我在写 shrimp",就跑不掉) + +| 契约 | 说明 | +|---|---| +| `IModuleInfo` 形状 | 任何模块声明都得这么写 — 见 [src/IShrimpType.ts](src/IShrimpType.ts) `IModuleInfo` | +| `IFieldConfig` 形状 | 字段就这样描述(`name` / `label` / `type` / `relation` / `rules` …) | +| Shrimp 树结构 | `parent`/`children` 嵌套、`getFullPath()` 路径语义 | +| Power / Role 声明 | `power` 树形 + `role` 持 `powers[]` | +| `ILabel` 多语言形态 | 见下方 §国际化 — 6 选 1 的标签类型 | + +### 🔌 条件约定(用了某个件,才被它的契约绑住) + +| 启用前提 | 它的契约 | +|---|---| +| **使用 `ShrimpTable`(前端表格组件)** | • list 响应必须是 `IPageResult` = `{ list, total, page, pageSize, totalPages }`
• 字段 `type` 必须落在内置枚举:`string` / `number` / `boolean` / `date` / `select` / `textarea` / `password` / `relation` / `json` / `tab` —— 或自行注册 `IFieldTypeHandler`
• populate 字段旁挂 `${key}_label`(数组关联挂数组) | +| **使用 `buildShrimpRouter` / `ShrimpServer`** | • HTTP 路由形状:`GET /config`、`POST /login`、`GET /me`、`POST //`
• JWT 携带:`Authorization: Bearer `
• 后端需实现 `IUserAccessor`(getJwtPayload / isUserActive / getUserRoleIds / isRoleSuperAdmin / getRolePowers / getUserDisplayName) — 见 [src/forExpress/types.ts](src/forExpress/types.ts) | +| **使用 `MongoShrimp`** | • User/Role/OperationLog 的 mongoose Schema 形状
• `onDbConnected` 钩子时序:连接就绪后才能注册需要 DB 的模块 | +| **挂 `OperationLogModule`** | • CRUD 动作自动写日志的字段集(operator / module / action / target / time) | +| **使用默认 `Field*.vue` 渲染**(前端) | • 字段 `type` 必须是内置枚举之一,否则需注册 `typeHandler` 才能渲染 | +| **使用 Shrimp 子模块机制** | • 子表 `ownerKey` 是后端注册侧独占,**不进 fields[]**
• 前端只发通用 `ownerId`,不感知 `ownerKey` 的实际字段名 | + +> 替换某个件,这个件的条件契约自动失效。例如:你换掉 `ShrimpTable` 用 AG-Grid,list 响应格式和字段 type 枚举两条对你都不再生效;你不挂 `OperationLogModule`,日志契约就不存在。 + +--- + ### 国际化 (ILabel) 所有前端可见文本字段(`label` / `tip` / `menu.label` / `power.label` / `field.label` / `rule.message` …)统一类型 `ILabel`。**用哪种形态取决于你写在哪一层**。