破坏性重构。框架对外只暴露一个 `sources` glob 入口,消费侧任何 .vue 都按文件路径后缀匹配同后缀覆盖: - shrimp/components/<name>.vue 同后缀覆盖框架内置(login/layout/topbar/ShrimpTable/...) - shrimp/components/fields/Field<X>.vue 注册类型 <x>(首字母小写) - shrimp/module/<key>.vue 业务模块 变更: - 删除 customFields / moduleSources / overrideField / registerField 旧入口 - 删除 fieldOverrides Map,字段表纯靠 glob 扫描注册 - 框架内 .vue 对可覆盖 peer 改用 defineAsyncComponent(resolveVue(...)) (login → ShrimpLangSwitch / layout → sideM/navMenu/topbar/userbar/logo / ShrimpTable → ShrimpEditDrawer/ShrimpFilterDrawer/...) - views/ 全部并入 components/,App.vue 上提到 src/ 根 - LangSwitch → ShrimpLangSwitch,PowerTree → ShrimpPowerTree - module/FieldRelativeTime.vue → components/fields/FieldRelativeTime.vue - module/user.vue 改用 #column-updatedAt slot 替代旧的 overrideField 字段类型约定从 'field' + Name 改为 lowercase-first(FieldString → 'string'), 内置和消费侧统一。
90 lines
3.4 KiB
Markdown
90 lines
3.4 KiB
Markdown
# shrimp-admin
|
|
|
|
Shrimp 框架前端 —— 一种**经典解决方案**(不是框架本身),消费 [shrimp-server](http://git.zeromvc.com/wc24/shrimp-server) 暴露的 `ShrimpServer` 路由契约 + `ShrimpTable` 数据形状契约,基于 **Vue 3 + Element Plus** 实现一套可直接用的后台壳。
|
|
|
|
如果你想换 UI 库或者换前端技术栈,直接照 shrimp-server 的约定再写一份就行,不依赖本包。
|
|
|
|
## 安装
|
|
|
|
```bash
|
|
npm i git+http://git.zeromvc.com/wc24/shrimp-admin.git#v0.3.0
|
|
```
|
|
|
|
shrimp-admin 是**源码 ship**(.ts + .vue 直接发),由消费侧 Vite 编译。
|
|
|
|
## 使用
|
|
|
|
```ts
|
|
// main.ts
|
|
import { createApp } from 'vue'
|
|
import { createShrimpAdmin, App } from 'shrimp-admin'
|
|
import 'shrimp-admin/style'
|
|
import zhCn from './locales/zh-cn.json'
|
|
import en from './locales/en.json'
|
|
|
|
const app = createApp(App)
|
|
app.use(createShrimpAdmin({
|
|
config: {
|
|
API_URL: '/admin-api',
|
|
TIMEOUT: 10000,
|
|
},
|
|
locales: { 'zh-cn': zhCn, en },
|
|
sources: import.meta.glob('./shrimp/**/*.vue'),
|
|
}))
|
|
app.mount('#app')
|
|
```
|
|
|
|
## 唯一约定: `sources` 路径后缀覆盖
|
|
|
|
消费侧把所有要交给框架的 .vue 通过单个 `sources` 入口注入(`import.meta.glob` 必须由消费侧自己调用,vite 静态扫描相对调用文件)。框架按**文件路径后缀**匹配,同后缀消费侧优先,内置兜底。
|
|
|
|
```
|
|
项目/
|
|
└── src/shrimp/ 消费侧目录,可任意命名
|
|
├── components/
|
|
│ ├── login.vue 覆盖框架内置 login 页
|
|
│ ├── topbar.vue 覆盖顶栏
|
|
│ └── fields/
|
|
│ └── FieldRelativeTime.vue 注册字段类型 relativeTime
|
|
└── module/
|
|
├── product.vue 业务模块,routed by moduleKey
|
|
└── user/
|
|
└── orders.vue 子模块,parent=user
|
|
```
|
|
|
|
### 框架内置 slot(可覆盖,suffix 列表)
|
|
|
|
```
|
|
components/login.vue components/404.vue components/layout.vue
|
|
components/logo.vue components/navMenu.vue components/sideM.vue
|
|
components/topbar.vue components/userbar.vue
|
|
components/ShrimpLangSwitch.vue components/ShrimpPowerTree.vue
|
|
components/ShrimpTable.vue components/ShrimpEditDrawer.vue
|
|
components/ShrimpFilterDrawer.vue components/ShrimpFilterTrigger.vue
|
|
components/ShrimpSearchInput.vue
|
|
components/fields/Field{String,Boolean,Date,Json,Number,Password,Relation,Select,Tab,Textarea,RelativeTime}.vue
|
|
```
|
|
|
|
### 字段类型注册
|
|
|
|
`components/fields/Field<X>.vue` 自动注册类型 `<x>`(首字母小写):
|
|
|
|
| 文件 | type 注册键 |
|
|
| ------------------------ | ------------------ |
|
|
| `FieldString.vue` | `string` |
|
|
| `FieldRelativeTime.vue` | `relativeTime` |
|
|
| 你自己的 `FieldMyType.vue` | `myType` |
|
|
|
|
后端 moduleInfo 里 `field.type === 'myType'` 时就用你这个组件。
|
|
|
|
### 业务模块
|
|
|
|
`components/X.vue` 命中 `moduleKey === 'X'` 的路由,自动作为内容页。子表用嵌套目录(`module/<parent>/<sub>.vue`)。
|
|
|
|
## 消费的契约
|
|
|
|
参见 shrimp-server README `## 约定` 章节。本包消费以下条件契约:
|
|
|
|
- **ShrimpTable**: list 响应 `{list,total,page,pageSize,totalPages}` / 字段 type 枚举 / populate `${key}_label`
|
|
- **ShrimpServer**: HTTP 路由 / JWT Bearer / IUserAccessor 返回的 powers
|