@linyjs/plugin-docs 0.0.14 → 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/docs/api-reference/index.md +2 -0
- package/docs/guides/authentication.md +313 -240
- package/docs/guides/client-hooks.md +625 -0
- package/docs/guides/client-module.md +3 -1
- package/docs/guides/client-routes.md +631 -0
- package/docs/guides/dependency-injection.md +3 -0
- package/docs/guides/permissions.md +124 -53
- package/docs/guides/server-module.md +2 -0
- package/docs/guides/shared-module-interface.md +117 -51
- package/docs/guides/ui-slots.md +3 -1
- package/package.json +1 -1
|
@@ -42,28 +42,41 @@ admin:access # 访问管理后台
|
|
|
42
42
|
|
|
43
43
|
## 服务端权限检查
|
|
44
44
|
|
|
45
|
+
服务端通过依赖注入获取 `IPermissionService` 实例。只需在 ServiceDef 中声明 `dependencies` 引用权限服务的 `serviceTag`,并在模块中声明 `moduleDependencies`,框架会自动注入服务实例。
|
|
46
|
+
|
|
45
47
|
### 在控制器中检查权限
|
|
46
48
|
|
|
47
49
|
```typescript
|
|
48
|
-
|
|
50
|
+
import type { IControllerService, IControllerServiceDef, IModule } from '@linyjs/server-module-interface';
|
|
51
|
+
import type { IPermissionService } from '@linyjs/shared-module-interface';
|
|
52
|
+
|
|
53
|
+
class ArticleController implements IControllerService {
|
|
54
|
+
private permissionService: IPermissionService;
|
|
55
|
+
|
|
56
|
+
// ✅ 通过构造函数注入获取权限服务
|
|
57
|
+
constructor({ permissionService }: { permissionService: IPermissionService }) {
|
|
58
|
+
this.permissionService = permissionService;
|
|
59
|
+
}
|
|
60
|
+
|
|
49
61
|
getRoutes() {
|
|
50
62
|
return [
|
|
51
63
|
{
|
|
52
|
-
method: 'POST',
|
|
64
|
+
method: 'POST' as const,
|
|
53
65
|
path: '/api/articles',
|
|
54
66
|
middlewares: ['auth'],
|
|
55
|
-
responseType: 'json',
|
|
56
|
-
handler: async (params:
|
|
67
|
+
responseType: 'json' as const,
|
|
68
|
+
handler: async (params: Record<string, any>, ctx: any) => {
|
|
57
69
|
const user = ctx.user;
|
|
58
|
-
|
|
59
|
-
//
|
|
60
|
-
|
|
70
|
+
|
|
71
|
+
// 通过权限服务检查权限
|
|
72
|
+
const result = await this.permissionService.check(user, 'article:write');
|
|
73
|
+
if (!result.allowed) {
|
|
61
74
|
return {
|
|
62
75
|
status: 403,
|
|
63
|
-
data: { error:
|
|
76
|
+
data: { error: result.reason }
|
|
64
77
|
};
|
|
65
78
|
}
|
|
66
|
-
|
|
79
|
+
|
|
67
80
|
// 业务逻辑...
|
|
68
81
|
const article = await createArticle(params);
|
|
69
82
|
return { success: true, data: article };
|
|
@@ -72,47 +85,62 @@ class ArticleController {
|
|
|
72
85
|
];
|
|
73
86
|
}
|
|
74
87
|
}
|
|
88
|
+
|
|
89
|
+
// ✅ 在 ServiceDef 中声明 dependencies 引用权限服务的 serviceTag
|
|
90
|
+
const articleControllerDef: IControllerServiceDef = {
|
|
91
|
+
serviceTag: 'articleController',
|
|
92
|
+
serviceImpl: ArticleController,
|
|
93
|
+
dependencies: ['permissionServer.permissionService'], // ← serviceTag
|
|
94
|
+
meta: { usageType: 'controller' },
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const articleServerModule: IModule = {
|
|
98
|
+
name: 'articleServer',
|
|
99
|
+
moduleDependencies: ['permissionServer'], // ← 模块依赖
|
|
100
|
+
serviceDefs: [articleControllerDef],
|
|
101
|
+
};
|
|
75
102
|
```
|
|
76
103
|
|
|
77
104
|
### 创建权限中间件
|
|
78
105
|
|
|
79
106
|
```typescript
|
|
80
|
-
import type { IMiddlewareService } from '@linyjs/server-module-interface';
|
|
107
|
+
import type { IMiddlewareService, IServiceDef } from '@linyjs/server-module-interface';
|
|
108
|
+
import type { IPermissionService } from '@linyjs/shared-module-interface';
|
|
81
109
|
|
|
82
110
|
class PermissionMiddleware implements IMiddlewareService {
|
|
111
|
+
private permissionService: IPermissionService;
|
|
112
|
+
|
|
113
|
+
// ✅ 通过构造函数注入获取权限服务
|
|
114
|
+
constructor({ permissionService }: { permissionService: IPermissionService }) {
|
|
115
|
+
this.permissionService = permissionService;
|
|
116
|
+
}
|
|
117
|
+
|
|
83
118
|
getMiddlewares() {
|
|
84
119
|
return [{
|
|
85
120
|
middlewareId: 'checkPermission',
|
|
86
121
|
handler: async (params: any, ctx: any, next: any) => {
|
|
87
122
|
const user = ctx.user;
|
|
88
|
-
const requiredPermission =
|
|
89
|
-
|
|
90
|
-
if (requiredPermission
|
|
91
|
-
|
|
123
|
+
const requiredPermission = ctx.route?.meta?.requiredPermission;
|
|
124
|
+
|
|
125
|
+
if (requiredPermission) {
|
|
126
|
+
// 通过权限服务检查权限
|
|
127
|
+
const result = await this.permissionService.check(user, requiredPermission);
|
|
128
|
+
if (!result.allowed) {
|
|
129
|
+
throw new Error(result.reason || 'Insufficient permissions');
|
|
130
|
+
}
|
|
92
131
|
}
|
|
93
|
-
|
|
132
|
+
|
|
94
133
|
await next();
|
|
95
134
|
}
|
|
96
135
|
}];
|
|
97
136
|
}
|
|
98
137
|
}
|
|
99
138
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const rolePermissions = {
|
|
103
|
-
admin: ['article:read', 'article:write', 'article:delete'],
|
|
104
|
-
editor: ['article:read', 'article:write'],
|
|
105
|
-
viewer: ['article:read']
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
return user.roles?.some((role: string) =>
|
|
109
|
-
rolePermissions[role]?.includes(permission)
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export const permissionMiddlewareDef = {
|
|
139
|
+
// ✅ 声明 dependencies 引用权限服务的 serviceTag
|
|
140
|
+
export const permissionMiddlewareDef: IServiceDef = {
|
|
114
141
|
serviceTag: 'permissionMiddleware',
|
|
115
142
|
serviceImpl: PermissionMiddleware,
|
|
143
|
+
dependencies: ['permissionServer.permissionService'], // ← serviceTag
|
|
116
144
|
meta: { usageType: 'middleware' }
|
|
117
145
|
};
|
|
118
146
|
```
|
|
@@ -139,28 +167,45 @@ export const permissionMiddlewareDef = {
|
|
|
139
167
|
|
|
140
168
|
### 使用 usePermission Hook
|
|
141
169
|
|
|
170
|
+
客户端通过 `useClientHook` 从 `permissionClient` 模块获取 `usePermission` Hook:
|
|
171
|
+
|
|
142
172
|
```typescript
|
|
143
|
-
import {
|
|
173
|
+
import { useClientHook } from '@linyjs/client-module-interface';
|
|
174
|
+
|
|
175
|
+
type UsePermission = (
|
|
176
|
+
permission: string,
|
|
177
|
+
context?: Record<string, any>
|
|
178
|
+
) => { hasPermission: boolean; loading: boolean };
|
|
144
179
|
|
|
145
180
|
function ArticleEditor() {
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
181
|
+
// 通过 useClientHook 从 permissionClient 模块获取 usePermission Hook
|
|
182
|
+
const usePermission = useClientHook<UsePermission>(
|
|
183
|
+
'permissionClient.permissionHooks.usePermission'
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
if (!usePermission) {
|
|
187
|
+
return <div>权限功能加载中...</div>;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const { hasPermission: canEdit, loading } = usePermission('article:write');
|
|
191
|
+
const { hasPermission: canDelete } = usePermission('article:delete');
|
|
192
|
+
|
|
193
|
+
if (loading) return <div>加载中...</div>;
|
|
194
|
+
|
|
150
195
|
return (
|
|
151
196
|
<div>
|
|
152
197
|
<h1>Edit Article</h1>
|
|
153
|
-
|
|
198
|
+
|
|
154
199
|
{canEdit && (
|
|
155
200
|
<button onClick={handleSave}>Save</button>
|
|
156
201
|
)}
|
|
157
|
-
|
|
202
|
+
|
|
158
203
|
{canDelete && (
|
|
159
204
|
<button onClick={handleDelete} style={{ color: 'red' }}>
|
|
160
205
|
Delete
|
|
161
206
|
</button>
|
|
162
207
|
)}
|
|
163
|
-
|
|
208
|
+
|
|
164
209
|
{!canEdit && (
|
|
165
210
|
<p>You don't have permission to edit this article.</p>
|
|
166
211
|
)}
|
|
@@ -169,18 +214,32 @@ function ArticleEditor() {
|
|
|
169
214
|
}
|
|
170
215
|
```
|
|
171
216
|
|
|
217
|
+
> 💡 引用路径 `permissionClient.permissionHooks.usePermission` 遵循 `moduleName.serviceTag.hookName` 三段式格式。详见 [公共 Hooks 使用](./client-hooks.md)。
|
|
218
|
+
|
|
172
219
|
### 条件渲染组件
|
|
173
220
|
|
|
174
221
|
```typescript
|
|
175
|
-
import {
|
|
222
|
+
import { useClientHook } from '@linyjs/client-module-interface';
|
|
223
|
+
|
|
224
|
+
type UsePermission = (
|
|
225
|
+
permission: string,
|
|
226
|
+
context?: Record<string, any>
|
|
227
|
+
) => { hasPermission: boolean; loading: boolean };
|
|
176
228
|
|
|
177
229
|
function ProtectedComponent({ children }: { children: React.ReactNode }) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
230
|
+
// 通过 useClientHook 从 permissionClient 模块获取 usePermission Hook
|
|
231
|
+
const usePermission = useClientHook<UsePermission>(
|
|
232
|
+
'permissionClient.permissionHooks.usePermission'
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
if (!usePermission) return null;
|
|
236
|
+
|
|
237
|
+
const { hasPermission } = usePermission('admin:access');
|
|
238
|
+
|
|
239
|
+
if (!hasPermission) {
|
|
181
240
|
return null; // 不渲染
|
|
182
241
|
}
|
|
183
|
-
|
|
242
|
+
|
|
184
243
|
return <>{children}</>;
|
|
185
244
|
}
|
|
186
245
|
|
|
@@ -229,6 +288,8 @@ class BlogRouteService {
|
|
|
229
288
|
|
|
230
289
|
### 路由守卫
|
|
231
290
|
|
|
291
|
+
> ⚠️ 路由守卫的 `canEnter` 回调不是 React 组件,不能使用 Hook。可直接调用权限检查 API:
|
|
292
|
+
|
|
232
293
|
```typescript
|
|
233
294
|
{
|
|
234
295
|
path: '/admin',
|
|
@@ -236,12 +297,18 @@ class BlogRouteService {
|
|
|
236
297
|
key: 'admin',
|
|
237
298
|
guard: {
|
|
238
299
|
canEnter: async ({ location }) => {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
300
|
+
// 直接调用权限检查 API(由 permissionServer 模块提供)
|
|
301
|
+
const response = await fetch('/api/permission/check', {
|
|
302
|
+
method: 'POST',
|
|
303
|
+
headers: { 'Content-Type': 'application/json' },
|
|
304
|
+
body: JSON.stringify({ permission: 'admin:access' }),
|
|
305
|
+
});
|
|
306
|
+
const result = await response.json();
|
|
307
|
+
|
|
308
|
+
if (!result.allowed) {
|
|
242
309
|
return '/forbidden'; // 重定向
|
|
243
310
|
}
|
|
244
|
-
|
|
311
|
+
|
|
245
312
|
return true; // 允许访问
|
|
246
313
|
}
|
|
247
314
|
}
|
|
@@ -381,11 +448,12 @@ permissions: ['admin:access']
|
|
|
381
448
|
```typescript
|
|
382
449
|
// 服务端必须再次验证
|
|
383
450
|
handler: async (params, ctx) => {
|
|
384
|
-
//
|
|
385
|
-
|
|
386
|
-
|
|
451
|
+
// 即使客户端已检查,服务端仍需通过权限服务验证
|
|
452
|
+
const result = await this.permissionService.check(ctx.user, 'article:delete');
|
|
453
|
+
if (!result.allowed) {
|
|
454
|
+
return { status: 403, data: { error: result.reason } };
|
|
387
455
|
}
|
|
388
|
-
|
|
456
|
+
|
|
389
457
|
// 执行删除
|
|
390
458
|
}
|
|
391
459
|
```
|
|
@@ -393,11 +461,12 @@ handler: async (params, ctx) => {
|
|
|
393
461
|
### 3. 清晰的错误消息
|
|
394
462
|
|
|
395
463
|
```typescript
|
|
396
|
-
|
|
464
|
+
const result = await this.permissionService.check(user, 'article:write');
|
|
465
|
+
if (!result.allowed) {
|
|
397
466
|
return {
|
|
398
467
|
status: 403,
|
|
399
|
-
data: {
|
|
400
|
-
error: 'You do not have permission to edit articles',
|
|
468
|
+
data: {
|
|
469
|
+
error: result.reason || 'You do not have permission to edit articles',
|
|
401
470
|
requiredPermission: 'article:write'
|
|
402
471
|
}
|
|
403
472
|
};
|
|
@@ -432,6 +501,8 @@ function useUserPermissions() {
|
|
|
432
501
|
|
|
433
502
|
## 相关文档
|
|
434
503
|
|
|
504
|
+
- 📖 [共享模块接口](./shared-module-interface.md) — `IPermissionService` 等类型定义
|
|
505
|
+
- 🪝 [公共 Hooks 使用](./client-hooks.md) — `useClientHook` 获取跨模块 Hook
|
|
435
506
|
- 🎨 [UI 扩展插槽](./ui-slots.md)
|
|
436
507
|
- 💾 [数据持久化](./data-persistence.md)
|
|
437
508
|
|
|
@@ -443,6 +443,8 @@ class MyController {
|
|
|
443
443
|
|
|
444
444
|
- 📖 阅读 [依赖注入机制](./dependency-injection.md) — 完整的 DI 机制说明
|
|
445
445
|
- 💻 阅读 [客户端模块开发](./client-module.md)
|
|
446
|
+
- 🛤️ 阅读 [前端页面路由](./client-routes.md) — 路由定义与使用
|
|
447
|
+
- 🪝 阅读 [公共 Hooks 使用](./client-hooks.md) — 跨模块资源消费
|
|
446
448
|
- 💾 阅读 [数据持久化](./data-persistence.md)
|
|
447
449
|
- 🔒 阅读 [权限管理](./permissions.md)
|
|
448
450
|
|
|
@@ -4,23 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
## 概述
|
|
6
6
|
|
|
7
|
-
`@linyjs/shared-module-interface` 是一个**纯类型包**,汇集了 linyjs
|
|
7
|
+
`@linyjs/shared-module-interface` 是一个**纯类型包**,汇集了 linyjs 框架所有公共服务的 TypeScript 接口和类型定义。
|
|
8
8
|
|
|
9
9
|
### 为什么需要这个包?
|
|
10
10
|
|
|
11
|
-
linyjs
|
|
11
|
+
linyjs 插件通过依赖注入机制获取 `IMongoDBService`、`IUserService`、`IPermissionService` 等服务实例。但 TypeScript 编译器需要类型声明才能提供:
|
|
12
12
|
|
|
13
13
|
- ✅ 构造函数参数的类型提示
|
|
14
14
|
- ✅ 服务方法的自动补全
|
|
15
15
|
- ✅ 编译时类型检查
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- 📦 **包体积增大** — 插件打包了不需要的运行时代码
|
|
20
|
-
- ⚠️ **版本冲突** — 插件与框架使用的模块版本不一致
|
|
21
|
-
- 🔧 **配置冗余** — 每个插件都要在 `package.json` 中声明多个依赖
|
|
22
|
-
|
|
23
|
-
`@linyjs/shared-module-interface` 通过**纯类型导出**解决这些问题——只提供类型声明,不包含任何运行时代码。
|
|
17
|
+
`@linyjs/shared-module-interface` 通过**纯类型导出**解决这些问题——只提供类型声明,不包含任何运行时代码。插件无需安装任何运行时模块包,只需在 `devDependencies` 中添加此类型包即可获得完整的类型支持。
|
|
24
18
|
|
|
25
19
|
## 安装
|
|
26
20
|
|
|
@@ -38,6 +32,15 @@ linyjs 插件作为独立的 npm 包或 git 仓库开发,通过依赖注入机
|
|
|
38
32
|
|
|
39
33
|
## 使用方式
|
|
40
34
|
|
|
35
|
+
### 核心用法:声明即可用
|
|
36
|
+
|
|
37
|
+
使用框架提供的服务只需两步:
|
|
38
|
+
|
|
39
|
+
1. **在 ServiceDef 中声明 `dependencies`**(引用对应的 `serviceTag`)
|
|
40
|
+
2. **在 `moduleDependencies` 中声明模块依赖**
|
|
41
|
+
|
|
42
|
+
框架会自动注入服务实例,无需关心运行时来源。
|
|
43
|
+
|
|
41
44
|
### 导入类型
|
|
42
45
|
|
|
43
46
|
所有导出都使用 `import type` 语法,确保编译后类型被完全擦除:
|
|
@@ -53,10 +56,12 @@ import type { ObjectId, Db, Collection, Document, Filter } from '@linyjs/shared-
|
|
|
53
56
|
|
|
54
57
|
```typescript
|
|
55
58
|
import type { IMongoDBService } from '@linyjs/shared-module-interface';
|
|
59
|
+
import type { IServiceDef, IModule } from '@linyjs/server-module-interface';
|
|
56
60
|
|
|
57
61
|
class ArticleService {
|
|
58
62
|
private mongoDBService: IMongoDBService;
|
|
59
63
|
|
|
64
|
+
// ✅ 解构赋值接收依赖
|
|
60
65
|
constructor({ mongoDBService }: { mongoDBService: IMongoDBService }) {
|
|
61
66
|
this.mongoDBService = mongoDBService;
|
|
62
67
|
}
|
|
@@ -69,34 +74,49 @@ class ArticleService {
|
|
|
69
74
|
});
|
|
70
75
|
}
|
|
71
76
|
}
|
|
77
|
+
|
|
78
|
+
// ✅ 在 ServiceDef 中声明 dependencies 即可获取服务
|
|
79
|
+
const articleServiceDef: IServiceDef = {
|
|
80
|
+
serviceTag: 'articleService',
|
|
81
|
+
serviceImpl: ArticleService,
|
|
82
|
+
dependencies: ['mdb.mongoDBService'], // 引用对应 serviceTag
|
|
83
|
+
meta: { usageType: 'normal_service' }
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const articleServerModule: IModule = {
|
|
87
|
+
name: 'articleServer',
|
|
88
|
+
moduleDependencies: ['mdb'], // 声明模块依赖
|
|
89
|
+
serviceDefs: [articleServiceDef]
|
|
90
|
+
};
|
|
72
91
|
```
|
|
73
92
|
|
|
74
93
|
> 📖 关于依赖注入机制的完整说明,请阅读 [依赖注入机制](./dependency-injection.md)。
|
|
75
94
|
|
|
76
|
-
##
|
|
95
|
+
## 可用服务类型一览
|
|
77
96
|
|
|
78
|
-
|
|
97
|
+
以下是通过 `@linyjs/shared-module-interface` 提供的所有公共服务类型。插件只需在 ServiceDef 中声明对应的 `serviceTag` 和 `moduleDependencies`,即可获取服务实例。
|
|
79
98
|
|
|
80
|
-
|
|
81
|
-
|------|------|------------|
|
|
82
|
-
| `IMongoDBService` | MongoDB 服务接口 | `@linyjs/mdb` 模块通过 `mdb.mongoDBService` 注入 |
|
|
83
|
-
| `ObjectId` | MongoDB ObjectId 类型 | mongodb 包(运行时通过 `service.ObjectId` 获取) |
|
|
84
|
-
| `Db` | MongoDB 数据库实例类型 | mongodb 包 |
|
|
85
|
-
| `Collection` | MongoDB 集合类型 | mongodb 包 |
|
|
86
|
-
| `Document` | MongoDB 文档类型 | mongodb 包 |
|
|
87
|
-
| `Filter` | 查询过滤器类型 | mongodb 包 |
|
|
88
|
-
| `Sort` | 排序类型 | mongodb 包 |
|
|
89
|
-
| `UpdateFilter` | 更新操作类型 | mongodb 包 |
|
|
90
|
-
| `InsertOneResult` | 插入结果类型 | mongodb 包 |
|
|
91
|
-
| `UpdateResult` | 更新结果类型 | mongodb 包 |
|
|
92
|
-
| `DeleteResult` | 删除结果类型 | mongodb 包 |
|
|
93
|
-
| ... | mongodb 包的全部类型 | mongodb 包 |
|
|
99
|
+
### IMongoDBService — 数据库服务
|
|
94
100
|
|
|
95
|
-
|
|
101
|
+
| 类型 | 说明 |
|
|
102
|
+
|------|------|
|
|
103
|
+
| `IMongoDBService` | 数据库服务接口 |
|
|
104
|
+
| `ObjectId` | ObjectId 类型(运行时通过 `service.ObjectId` 获取构造器) |
|
|
105
|
+
| `Db` | 数据库实例类型 |
|
|
106
|
+
| `Collection` | 集合类型 |
|
|
107
|
+
| `Document` | 文档类型 |
|
|
108
|
+
| `Filter` | 查询过滤器类型 |
|
|
109
|
+
| `Sort` | 排序类型 |
|
|
110
|
+
| `UpdateFilter` | 更新操作类型 |
|
|
111
|
+
| `InsertOneResult` | 插入结果类型 |
|
|
112
|
+
| `UpdateResult` | 更新结果类型 |
|
|
113
|
+
| `DeleteResult` | 删除结果类型 |
|
|
114
|
+
|
|
115
|
+
#### 接口定义
|
|
96
116
|
|
|
97
117
|
```typescript
|
|
98
118
|
interface IMongoDBService {
|
|
99
|
-
/**
|
|
119
|
+
/** ObjectId 构造器(运行时通过此属性获取,无需单独安装 mongodb) */
|
|
100
120
|
readonly ObjectId: typeof ObjectId;
|
|
101
121
|
|
|
102
122
|
/** 获取数据库实例 */
|
|
@@ -113,7 +133,24 @@ interface IMongoDBService {
|
|
|
113
133
|
}
|
|
114
134
|
```
|
|
115
135
|
|
|
116
|
-
|
|
136
|
+
#### 声明方式
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
const myServiceDef: IServiceDef = {
|
|
140
|
+
serviceTag: 'myService',
|
|
141
|
+
serviceImpl: MyService,
|
|
142
|
+
dependencies: ['mdb.mongoDBService'], // ← serviceTag
|
|
143
|
+
meta: { usageType: 'normal_service' }
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const myModule: IModule = {
|
|
147
|
+
name: 'myServer',
|
|
148
|
+
moduleDependencies: ['mdb'], // ← 模块依赖
|
|
149
|
+
serviceDefs: [myServiceDef]
|
|
150
|
+
};
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### IUserService — 用户管理服务
|
|
117
154
|
|
|
118
155
|
| 类型 | 说明 |
|
|
119
156
|
|------|------|
|
|
@@ -125,7 +162,7 @@ interface IMongoDBService {
|
|
|
125
162
|
| `IsRootUser` | 判断用户是否为 Root 角色的函数类型 |
|
|
126
163
|
| `IsAdminUser` | 判断用户是否为 Admin 角色的函数类型 |
|
|
127
164
|
|
|
128
|
-
####
|
|
165
|
+
#### 接口定义
|
|
129
166
|
|
|
130
167
|
```typescript
|
|
131
168
|
interface IUserService {
|
|
@@ -137,9 +174,24 @@ interface IUserService {
|
|
|
137
174
|
}
|
|
138
175
|
```
|
|
139
176
|
|
|
140
|
-
|
|
177
|
+
#### 声明方式
|
|
141
178
|
|
|
142
|
-
|
|
179
|
+
```typescript
|
|
180
|
+
const myServiceDef: IServiceDef = {
|
|
181
|
+
serviceTag: 'myService',
|
|
182
|
+
serviceImpl: MyService,
|
|
183
|
+
dependencies: ['authServer.userService'], // ← serviceTag
|
|
184
|
+
meta: { usageType: 'normal_service' }
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const myModule: IModule = {
|
|
188
|
+
name: 'myServer',
|
|
189
|
+
moduleDependencies: ['authServer'], // ← 模块依赖
|
|
190
|
+
serviceDefs: [myServiceDef]
|
|
191
|
+
};
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### IPermissionService — 权限检查服务
|
|
143
195
|
|
|
144
196
|
| 类型 | 说明 |
|
|
145
197
|
|------|------|
|
|
@@ -150,7 +202,7 @@ interface IUserService {
|
|
|
150
202
|
| `IPermissionPolicy` | 权限策略定义 |
|
|
151
203
|
| `IPermissionCheckResult` | 权限检查结果 |
|
|
152
204
|
|
|
153
|
-
####
|
|
205
|
+
#### 接口定义
|
|
154
206
|
|
|
155
207
|
```typescript
|
|
156
208
|
interface IPermissionService {
|
|
@@ -173,11 +225,36 @@ interface IPermissionService {
|
|
|
173
225
|
}
|
|
174
226
|
```
|
|
175
227
|
|
|
176
|
-
|
|
228
|
+
#### 声明方式
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
const myServiceDef: IServiceDef = {
|
|
232
|
+
serviceTag: 'myService',
|
|
233
|
+
serviceImpl: MyService,
|
|
234
|
+
dependencies: ['permissionServer.permissionService'], // ← serviceTag
|
|
235
|
+
meta: { usageType: 'normal_service' }
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const myModule: IModule = {
|
|
239
|
+
name: 'myServer',
|
|
240
|
+
moduleDependencies: ['permissionServer'], // ← 模块依赖
|
|
241
|
+
serviceDefs: [myServiceDef]
|
|
242
|
+
};
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## 可注入服务汇总
|
|
246
|
+
|
|
247
|
+
| 声明 dependencies | 声明 moduleDependencies | 接口类型 |
|
|
248
|
+
|-------------------|------------------------|----------|
|
|
249
|
+
| `'mdb.mongoDBService'` | `'mdb'` | `IMongoDBService` |
|
|
250
|
+
| `'authServer.userService'` | `'authServer'` | `IUserService` |
|
|
251
|
+
| `'permissionServer.permissionService'` | `'permissionServer'` | `IPermissionService` |
|
|
252
|
+
|
|
253
|
+
> 💡 只需在 ServiceDef 的 `dependencies` 中声明 serviceTag、在模块的 `moduleDependencies` 中声明模块依赖,框架会自动注入服务实例。
|
|
177
254
|
|
|
178
255
|
## ObjectId 的运行时使用
|
|
179
256
|
|
|
180
|
-
`@linyjs/shared-module-interface` 是纯类型包,`ObjectId`
|
|
257
|
+
`@linyjs/shared-module-interface` 是纯类型包,`ObjectId` 等类型导入在编译后会被擦除。运行时需要通过注入的服务实例获取 `ObjectId` 构造器:
|
|
181
258
|
|
|
182
259
|
```typescript
|
|
183
260
|
import type { IMongoDBService, ObjectId } from '@linyjs/shared-module-interface';
|
|
@@ -207,7 +284,7 @@ class ArticleService {
|
|
|
207
284
|
|
|
208
285
|
### 在服务类外部使用 ObjectId
|
|
209
286
|
|
|
210
|
-
如果需要在服务类外部(如工具函数、模型层)创建 `ObjectId
|
|
287
|
+
如果需要在服务类外部(如工具函数、模型层)创建 `ObjectId`,可以将服务引用保存到模块级变量:
|
|
211
288
|
|
|
212
289
|
```typescript
|
|
213
290
|
// db.ts
|
|
@@ -240,7 +317,7 @@ class ArticleService {
|
|
|
240
317
|
}
|
|
241
318
|
|
|
242
319
|
async initialize() {
|
|
243
|
-
//
|
|
320
|
+
// 将服务保存到模块级变量,供工具函数使用
|
|
244
321
|
setMongoDBService(this.mongoDBService);
|
|
245
322
|
}
|
|
246
323
|
|
|
@@ -251,20 +328,9 @@ class ArticleService {
|
|
|
251
328
|
}
|
|
252
329
|
```
|
|
253
330
|
|
|
254
|
-
## 可注入服务汇总
|
|
255
|
-
|
|
256
|
-
| 依赖引用 | 接口类型 | 来源模块 | 说明 |
|
|
257
|
-
|----------|----------|----------|------|
|
|
258
|
-
| `'mdb.mongoDBService'` | `IMongoDBService` | mdb | MongoDB 数据库服务 |
|
|
259
|
-
| `'authServer.userService'` | `IUserService` | auth | 用户管理服务 |
|
|
260
|
-
| `'authServer.initService'` | - | auth | 系统初始化服务 |
|
|
261
|
-
| `'permissionServer.permissionService'` | `IPermissionService` | permission | 权限检查服务 |
|
|
262
|
-
|
|
263
|
-
> 💡 使用这些服务时,需要在模块定义中声明 `moduleDependencies`。
|
|
264
|
-
|
|
265
331
|
## 完整示例
|
|
266
332
|
|
|
267
|
-
|
|
333
|
+
以下示例展示如何同时注入多个公共服务:
|
|
268
334
|
|
|
269
335
|
```typescript
|
|
270
336
|
import type { IModule, IServiceDef, IControllerService } from '@linyjs/server-module-interface';
|
|
@@ -339,9 +405,9 @@ export const adminServerModule: IModule = {
|
|
|
339
405
|
## 相关文档
|
|
340
406
|
|
|
341
407
|
- 📖 [依赖注入机制](./dependency-injection.md) — DI 的完整说明
|
|
342
|
-
- 💾 [数据持久化](./data-persistence.md) —
|
|
343
|
-
- 🔐 [用户认证](./authentication.md) —
|
|
344
|
-
- 🛡️ [权限管理](./permissions.md) —
|
|
408
|
+
- 💾 [数据持久化](./data-persistence.md) — 数据库服务详细使用
|
|
409
|
+
- 🔐 [用户认证](./authentication.md) — 用户服务使用
|
|
410
|
+
- 🛡️ [权限管理](./permissions.md) — 权限服务使用
|
|
345
411
|
- 🔧 [API 参考](../api-reference/index.md) — 接口类型定义
|
|
346
412
|
|
|
347
413
|
---
|
package/docs/guides/ui-slots.md
CHANGED
|
@@ -468,8 +468,10 @@ registry.register({
|
|
|
468
468
|
## 相关文档
|
|
469
469
|
|
|
470
470
|
- 📖 [客户端模块开发](./client-module.md)
|
|
471
|
+
- 🛤️ [前端页面路由](./client-routes.md)
|
|
472
|
+
- 🪝 [公共 Hooks 使用](./client-hooks.md)
|
|
471
473
|
- 🔒 [权限管理](./permissions.md)
|
|
472
474
|
|
|
473
475
|
---
|
|
474
476
|
|
|
475
|
-
**上一篇**: [
|
|
477
|
+
**上一篇**: [公共 Hooks 使用](./client-hooks.md) | **下一篇**: [权限管理](./permissions.md)
|