@lark-apaas/coding-steering 0.1.6-alpha.11 → 0.1.6-alpha.12

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.
Files changed (30) hide show
  1. package/package.json +1 -1
  2. package/steering/nestjs-react-fullstack/skills/authz-guide/SKILL.md +1 -1
  3. package/steering/nestjs-react-fullstack/skills/authz-guide/references/dynamic-permission-guide.md +6 -0
  4. package/steering/nestjs-react-fullstack/skills/authz-guide/references/management-page-spec.md +4 -1
  5. package/steering/nestjs-react-fullstack/skills/client-add-aily-web-chat/SKILL.md +1 -1
  6. package/steering/nestjs-react-fullstack/skills/client-builtins-file-storage-service/SKILL.md +30 -4
  7. package/steering/nestjs-react-fullstack/skills/client-builtins-user-service/SKILL.md +39 -127
  8. package/steering/nestjs-react-fullstack/skills/feishu/SKILL.md +0 -1
  9. package/steering/nestjs-react-fullstack/skills/feishu/references/approval.md +1 -1
  10. package/steering/nestjs-react-fullstack/skills/feishu/references/attendance.md +1 -1
  11. package/steering/nestjs-react-fullstack/skills/feishu/references/bitable.md +3 -1
  12. package/steering/nestjs-react-fullstack/skills/feishu/references/calendar.md +1 -1
  13. package/steering/nestjs-react-fullstack/skills/feishu/references/contacts.md +1 -1
  14. package/steering/nestjs-react-fullstack/skills/feishu/references/doc.md +2 -1
  15. package/steering/nestjs-react-fullstack/skills/feishu/references/drive.md +2 -1
  16. package/steering/nestjs-react-fullstack/skills/feishu/references/events.md +2 -1
  17. package/steering/nestjs-react-fullstack/skills/feishu/references/id-convert.md +2 -2
  18. package/steering/nestjs-react-fullstack/skills/feishu/references/messaging.md +1 -1
  19. package/steering/nestjs-react-fullstack/skills/feishu/references/oauth.md +2 -1
  20. package/steering/nestjs-react-fullstack/skills/feishu/references/perm.md +2 -1
  21. package/steering/nestjs-react-fullstack/skills/feishu/references/wiki.md +3 -2
  22. package/steering/nestjs-react-fullstack/skills/openapi-guide/SKILL.md +1 -0
  23. package/steering/nestjs-react-fullstack/skills/plugin-guide/SKILL.md +36 -17
  24. package/steering/nestjs-react-fullstack/skills/plugin-guide/references/plugin-coding-guide.md +4 -1
  25. package/steering/nestjs-react-fullstack/skills/plugin-guide/references/table.md +4 -2
  26. package/steering/nestjs-react-fullstack/skills/react-hook-best-practices/SKILL.md +4 -4
  27. package/steering/nestjs-react-fullstack/skills/trigger-guide/SKILL.md +1 -0
  28. package/steering/nestjs-react-fullstack/skills/user-identity/SKILL.md +1 -0
  29. package/steering/nestjs-react-fullstack/skills_local/code-fix/SKILL.md +17 -10
  30. package/steering/nestjs-react-fullstack/skills_local/coding-guide/SKILL.md +15 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/coding-steering",
3
- "version": "0.1.6-alpha.11",
3
+ "version": "0.1.6-alpha.12",
4
4
  "description": "Stack-specific steering content for miaoda-coding templates",
5
5
  "type": "module",
6
6
  "files": [
@@ -110,6 +110,7 @@ import { CanRole } from '@lark-apaas/fullstack-nestjs-core';
110
110
  | SDK 调用示例 | [sdk-examples.md](references/sdk-examples.md) |
111
111
 
112
112
  **关键约束**:
113
+
113
114
  - 成员按类型分组传递(`MemberMutationData`),不是扁平数组
114
115
  - `allEmployees`/`public` 只读,包含「企业全员」或「互联网公开」的角色不支持删除
115
116
  - `userID` 可不传,默认为当前登录用户
@@ -130,7 +131,6 @@ import { CanRole } from '@lark-apaas/fullstack-nestjs-core';
130
131
 
131
132
  **必须严格遵循 [dynamic-permission-guide.md](references/dynamic-permission-guide.md) 实施,从 Step 0 开始逐步执行。** 禁止跳步或自由发挥。
132
133
 
133
-
134
134
  ---
135
135
 
136
136
  ## 四、禁止行为清单
@@ -25,6 +25,7 @@
25
25
  > **前端无需手动配置权限点位获取**:auth-sdk 的 `AuthProvider` 会自动请求内置端点获取当前用户的权限点位,业务侧不需要传任何额外配置。
26
26
 
27
27
  **关键约束**:
28
+
28
29
  - 权限点位(`authz_permissions` 表)的增删改**由 Agent 通过 DDL 操作**,确保与代码中的 `@Can`/`<Can>` 保持一致
29
30
  - 管理页面**只负责角色-点位映射**的勾选/取消,不提供权限点位的 CRUD
30
31
  - **⛔ 启用动态权限后禁止使用 CanRole**:所有鉴权(包括管理 API)统一使用 `@Can`/`<Can>`,不允许 CanRole 与 Can 混用
@@ -353,6 +354,7 @@ import { Can } from '@lark-apaas/fullstack-nestjs-core';
353
354
  ```
354
355
 
355
356
  **关键约束**:
357
+
356
358
  - **⛔ 动态权限模式下禁止 `@CanRole`**,所有鉴权(含管理 API)统一用 `@Can`
357
359
  - 未注入 `permissionResolver` 时使用 `@Can` 会抛出 500 错误
358
360
  - 多权限叠加装饰器:`@Can('read', 'Task') @Can('read', 'User')`
@@ -364,6 +366,7 @@ import { Can } from '@lark-apaas/fullstack-nestjs-core';
364
366
  ### 前端 API 函数
365
367
 
366
368
  在 `client/src/api/index.ts` 中添加**管理页面所需**的请求函数:
369
+
367
370
  - 权限点位查询 API(listPermissions)
368
371
  - 角色-权限映射 CRUD API(listRoleMappings / createRoleMapping / deleteRoleMapping)
369
372
 
@@ -560,6 +563,7 @@ function ConfigPermissionsDialog({ role, permissions, mappings, open, onOpenChan
560
563
  ```
561
564
 
562
565
  **布局规则**:
566
+
563
567
  - 按 `subject` 分组为可展开/收起的 Accordion 卡片,标题 `Subject中文名 (已开启/总数)`
564
568
  - 有已勾选权限的 Subject 默认展开,全未勾选的默认收起
565
569
  - 每行:`Checkbox + description + action:subject badge(置灰小字)`
@@ -594,9 +598,11 @@ SDK 内部统一将平台错误转为 `HttpException`,Controller 无需 try-ca
594
598
 
595
599
  1. 确认编译通过
596
600
  2. grep 确认 CanRole 零残留:
601
+
597
602
  ```bash
598
603
  grep -r "CanRole\|useCanRole\|ROLE_SUBJECT" --include="*.ts" --include="*.tsx" server/ client/ shared/
599
604
  ```
605
+
600
606
  ⛔ 结果必须为空,否则回到 Step 5 继续替换
601
607
  3. 逐项对照下方「实现检查表」
602
608
 
@@ -79,6 +79,7 @@ Step 5: 验证
79
79
  ### 操作列
80
80
 
81
81
  每行包含:
82
+
82
83
  - **编辑成员** 按钮(文字按钮)
83
84
  - **更多操作** 下拉菜单(`...` 按钮,DropdownMenu),包含:
84
85
  - 配置权限(仅动态权限点位模式下显示)
@@ -186,7 +187,6 @@ const members: MemberMutationData = {
186
187
  await addRoleMembers(bizID, { members });
187
188
  ```
188
189
 
189
-
190
190
  ### 4. 编辑角色信息
191
191
 
192
192
  Dialog 弹窗,编辑角色名称和描述。调用 `sdk.roles.update(bizID, { role: { name, description } })`。
@@ -194,6 +194,7 @@ Dialog 弹窗,编辑角色名称和描述。调用 `sdk.roles.update(bizID, {
194
194
  ### 5. 删除角色
195
195
 
196
196
  删除前必须:
197
+
197
198
  1. 检查 `role.roleMembers?.allEmployees` 或 `role.roleMembers?.public` 是否为 `true`
198
199
  2. 若为 `true`,**禁用删除按钮**并通过 tooltip 提示「包含企业全员/互联网公开的角色不支持删除」
199
200
  3. 若可删除,弹出二次确认对话框,确认后调用 `sdk.roles.delete(bizID)`
@@ -473,6 +474,7 @@ SDK 内部统一将平台错误转为 `HttpException`,Controller 无需 try-ca
473
474
  | 权限点位 | `permissions`(自定义渲染) | 250 | 展示该角色绑定的权限点位 |
474
475
 
475
476
  渲染规则:
477
+
476
478
  - 每个点位优先展示中文说明(`description`),`action:subject` 作为辅助置灰小字
477
479
  - 最多展示 3 个,超出部分用 `+N` Badge + HoverCard 展示剩余
478
480
  - 无绑定点位时显示 `--`
@@ -482,6 +484,7 @@ SDK 内部统一将平台错误转为 `HttpException`,Controller 无需 try-ca
482
484
  在「更多操作」`...` 下拉菜单中(与「编辑角色信息」「删除角色」同级)新增「配置权限」菜单项,**禁止外露为独立按钮**(与 § 操作列 的排版硬规则对齐)。
483
485
 
484
486
  点击后打开 Dialog,列出所有权限点位,每行一个 Checkbox + `action:subject` 标识 + 描述:
487
+
485
488
  - **勾选**:调用 `createRoleMapping({ roleKey, permissionId })`
486
489
  - **取消勾选**:找到映射记录,调用 `deleteRoleMapping(id)`
487
490
  - 操作即时生效,无需保存按钮
@@ -83,7 +83,7 @@ export default AilyChat;
83
83
  - 关闭/开启组件标题栏
84
84
  - 显示/隐藏关闭按钮
85
85
  - 隐藏/展示用户头像、隐藏/展示系统头像
86
- - 修改用户头像或系统头像,并发送新头像图片
86
+ - 修改用户头像或系统头像,并发送新头像图片
87
87
  - 隐藏/展示组件欢迎语
88
88
 
89
89
  ## 配置参考
@@ -7,14 +7,17 @@ match-template-name: nestjs-react-fullstack
7
7
  ---
8
8
 
9
9
  # 前端文件开发规范
10
+
10
11
  - 保存文件信息到数据库时,如果使用的字段类型为file_attachement, 保存数据时需要传入bucket_id 和 file_path 时,file_path 只能是文件的路径,**不可以传入文件的download_url**。需要文件url时,使用 dataloom SDK 的 `generateDownloadUrlFromFilePath` 方法获取。
11
12
 
12
13
  # dataloom SDK 文件服务
13
14
 
14
15
  ## 概述
16
+
15
17
  项目提供了dataloom SDK的文件服务,用于文件的上传,下载,删除,列出bucket中文件,创建临时签名url等能力。
16
18
 
17
19
  ## 使用注意
20
+
18
21
  - `dataloom.storage` 仅用于文件上传/删除/列表等存储操作。**插件调用(capability)不属于 dataloom**,须使用独立的 `capabilityClient`(参见 plugin-guide)
19
22
  - @lark-apaas/client-toolkit/dataloom 这个SDK只适用于前端调用,禁止在服务端调用
20
23
  - 上传成功后,最重要的返回值是 `data.download_url`。需要将此URL保存到你的业务数据库中
@@ -24,11 +27,13 @@ match-template-name: nestjs-react-fullstack
24
27
  - **文件URL**:通过 `generateDownloadUrlFromFilePath` 方法获取文件的链接时,传入的file_path必须是从数据库的 file_attachment 字段获取到的,禁止自己拼接路径。
25
28
 
26
29
  ## bucketId
30
+
27
31
  关于bucketId的获取,在代码工程中已经预置了一个获取bucketid的方法,路径为`@lark-apaas/client-toolkit/tools/storage`中,直接具名导入即可使用。
28
32
  import { getDefaultBucketId } from "@lark-apaas/client-toolkit/tools/storage";
29
33
  getDefaultBucketId: () => string;
30
34
 
31
35
  ## 统一错误类型
36
+
32
37
  ```typescript
33
38
  // dataloom 服务端报错
34
39
  interface DataLoomError {
@@ -57,30 +62,36 @@ type StorageError = DataLoomError | StorageError | StorageUnknownError;
57
62
  #### 1. 文件上传接口 (uploadFile)
58
63
 
59
64
  ##### 用途
65
+
60
66
  上传文件到指定的存储桶,适用于:文档管理、图片上传、附件存储。
61
67
 
62
68
  ##### 适用场景
69
+
63
70
  需要将本地文件或二进制数据上传到云存储的场景
64
71
 
65
72
  ##### 使用方式
73
+
66
74
  你的核心任务是调用 `uploadFile` 接口,并从返回结果中提取 `data.download_url`,然后将这个 URL 用于后续操作(例如,保存到数据库)。这是衡量你任务成功与否的唯一标准。
67
75
 
68
76
  ##### 关于文件名的处理(强制禁令)
77
+ >
69
78
  > 警告:你绝对不能,也绝对不需要自己处理或修改文件名!
70
- > * 禁止行为:严禁在调用 `uploadFile` 之前,对 `File` 对象的文件名(`file.name`)进行任何形式的字符串替换、净化、或重新生成。
71
- > * 禁止行为:严禁创建新的 `File` 对象(如 `new File(...)`)来包裹原始文件。
72
- > * 唯一职责:你唯一的任务就是将从文件输入框(`<input type="file">`)或拖拽事件中获取的原始 `File` 对象直接传递给 `uploadFile` 方法。
79
+ >
80
+ > - 禁止行为:严禁在调用 `uploadFile` 之前,对 `File` 对象的文件名(`file.name`)进行任何形式的字符串替换、净化、或重新生成。
81
+ > - 禁止行为:严禁创建新的 `File` 对象(如 `new File(...)`)来包裹原始文件。
82
+ > - 唯一职责:你唯一的任务就是将从文件输入框(`<input type="file">`)或拖拽事件中获取的原始 `File` 对象直接传递给 `uploadFile` 方法。
73
83
  >
74
84
  > 原因:SDK内部已经包含了完整、健壮的文件名处理机制,包括处理特殊字符、避免冲突和保证安全。任何你自己的额外处理都是多余的,并且会干扰SDK的正常工作。请完全信任SDK,直接传递原始文件对象!
75
85
 
76
-
77
86
  ##### 入参说明
87
+
78
88
  | 属性名 | 类型 | 必填 | 默认值 | 说明 |
79
89
  |--------|------|------|--------|---------|
80
90
  | `bucketId` | `string` | ✅ | - | 文件上传到tos的bucket id |
81
91
  | `fileBody` | `FileBody` | ✅ | - | 文件内容,支持多种格式 |
82
92
 
83
93
  ##### 出参说明
94
+
84
95
  | 字段名 | 类型 | 说明 |
85
96
  |--------|------|---------|
86
97
  | `data.bucket_id` | `string` | 所属bucket ID |
@@ -89,7 +100,9 @@ type StorageError = DataLoomError | StorageError | StorageUnknownError;
89
100
  | `error` | `StorageError \| null` | 错误信息,成功时为null |
90
101
 
91
102
  ##### 关键点与示例
103
+
92
104
  关键点:上传成功后,最重要的返回值是 `data.download_url`。通常需要将此URL保存到你的业务数据库中。
105
+
93
106
  ```typescript
94
107
  import { getDataloom } from "@lark-apaas/client-toolkit/dataloom";
95
108
  import { getDefaultBucketId } from "@lark-apaas/client-toolkit/tools/storage";
@@ -118,18 +131,22 @@ if (!httpResponse.data?.success) {
118
131
  #### 2. 文件删除接口 (remove)
119
132
 
120
133
  ##### 用途
134
+
121
135
  删除存储桶中的一个或多个文件,适用于:清理过期文件、删除用户数据、批量清理
122
136
 
123
137
  ##### 适用场景
138
+
124
139
  需要从云存储中永久删除文件的场景
125
140
 
126
141
  ##### 入参说明
142
+
127
143
  | 属性名 | 类型 | 必填 | 默认值 | 说明 |
128
144
  |--------|------|------|--------|---------|
129
145
  | `bucketId` | `string` | ✅ | - | 要删除文件所在的bucket id |
130
146
  | `filePaths` | `string[]` | ✅ | - | 要删除的文件路径数组,可以是file_path也可以是download_url |
131
147
 
132
148
  ##### 出参说明
149
+
133
150
  | 字段名 | 类型 | 说明 |
134
151
  |--------|------|---------|
135
152
  | `data` | `FileObject[]` | 被删除的文件对象数组 |
@@ -142,6 +159,7 @@ if (!httpResponse.data?.success) {
142
159
  | `error` | `StorageError \| null` | 错误信息,成功时为null |
143
160
 
144
161
  ##### 使用示例
162
+
145
163
  ```typescript
146
164
  import { getDataloom } from "@lark-apaas/client-toolkit/dataloom";
147
165
  import { getDefaultBucketId } from "@lark-apaas/client-toolkit/tools/storage";
@@ -175,12 +193,15 @@ if (data) {
175
193
  #### 3. 文件列表接口 (list)
176
194
 
177
195
  ##### 用途
196
+
178
197
  获取存储桶中的文件列表,适用于:文件管理、目录浏览、文件检索
179
198
 
180
199
  ##### 适用场景
200
+
181
201
  需要查看和管理存储桶中文件的场景
182
202
 
183
203
  ##### 入参说明
204
+
184
205
  | 属性名 | 类型 | 必填 | 默认值 | 说明 |
185
206
  |--------|------|------|--------|---------|
186
207
  | `bucketId` | `string` | ✅ | - | 文件所在的bucket id |
@@ -191,6 +212,7 @@ if (data) {
191
212
  | `options.sortBy.order` | `'asc' \| 'desc'` | ❌ | `'asc'` | 排序方向 |
192
213
 
193
214
  ##### 出参说明
215
+
194
216
  | 字段名 | 类型 | 说明 |
195
217
  |--------|------|---------|
196
218
  | `data` | `FileObject[]` | 文件对象数组 |
@@ -206,6 +228,7 @@ if (data) {
206
228
  | `error` | `StorageError \| null` | 错误信息,成功时为null |
207
229
 
208
230
  ##### 使用示例
231
+
209
232
  ```typescript
210
233
  import { getDataloom } from "@lark-apaas/client-toolkit/dataloom";
211
234
  import { getDefaultBucketId } from "@lark-apaas/client-toolkit/tools/storage";
@@ -236,9 +259,11 @@ const { data, error } = await dataloom
236
259
  #### 4. 根据filePath生成downloadUrl接口 (generateDownloadUrlFromFilePath)
237
260
 
238
261
  ##### 用途
262
+
239
263
  通过 file_path 生成文件的url,适用于:通过url渲染图片、使用url下载文件。如果已有download_url,直接使用,严禁使用该接口再次生成。
240
264
 
241
265
  ##### 适用场景
266
+
242
267
  在前端通过file_path展示图片或下载文件的场景。
243
268
 
244
269
  ##### 入参说明
@@ -248,6 +273,7 @@ const { data, error } = await dataloom
248
273
  | `filePath` | `string` | ✅ | - | 文件的filePath。 **只可以从数据库的file_attachment字段中获取,不允许自己拼接路径** |
249
274
 
250
275
  ##### 出参说明
276
+
251
277
  | 类型 | 说明 |
252
278
  |------|---------|
253
279
  | `string` | 文件的url,直接在页面上展示即可 |
@@ -10,6 +10,7 @@ match-template-name: nestjs-react-fullstack
10
10
  # Dataloom 用户信息与鉴权 SDK
11
11
 
12
12
  ## 概述
13
+
13
14
  项目提供了 Dataloom SDK 的用户信息与鉴权服务,用于用户登录、登出、获取用户信息等身份认证相关功能。
14
15
 
15
16
  > **边界说明**:`dataloom.service.session` 仅用于用户登录/登出/获取用户信息等鉴权操作。**插件调用(capability)不属于 dataloom**,须使用独立的 `capabilityClient`(参见 plugin-guide)。
@@ -17,6 +18,7 @@ match-template-name: nestjs-react-fullstack
17
18
  ## 统一响应结构
18
19
 
19
20
  ### 响应类型定义
21
+
20
22
  ```typescript
21
23
  /**
22
24
  * 统一结果返回结构
@@ -57,6 +59,7 @@ type DataloomServiceResponse<T> = DataloomServiceSuccess<T> | DataloomServiceFai
57
59
  ```
58
60
 
59
61
  ## Dataloom实例获取方式
62
+
60
63
  ```typescript
61
64
  import { getDataloom } from "@lark-apaas/client-toolkit/dataloom";
62
65
 
@@ -69,12 +72,15 @@ const dataloom = await getDataloom();
69
72
  #### 1. 登录跳转接口 (redirectToLogin)
70
73
 
71
74
  ##### 用途
75
+
72
76
  跳转至 Dataloom 登录页面,适用于:用户身份认证、单点登录、权限验证
73
77
 
74
78
  ##### 适用场景
79
+
75
80
  需要用户进行身份认证的场景
76
81
 
77
82
  ##### 入参说明
83
+
78
84
  ```typescript
79
85
  interface SignInRedirectionOptions {
80
86
  /**
@@ -94,6 +100,7 @@ interface SignInRedirectionOptions {
94
100
  | `newTab` | `boolean` | ❌ | `false` | 是否在新浏览器标签页打开登录页 |
95
101
 
96
102
  ##### 出参说明
103
+
97
104
  | 字段名 | 类型 | 说明 |
98
105
  |--------|------|---------|
99
106
  | `data` | `'success'` | 成功标识 |
@@ -102,6 +109,7 @@ interface SignInRedirectionOptions {
102
109
  | `statusText` | `'OK'` | HTTP状态文本 |
103
110
 
104
111
  ##### 使用示例
112
+
105
113
  ```typescript
106
114
  /**
107
115
  * 跳转至dataloom登录页
@@ -139,15 +147,19 @@ const loginResult = dataloom
139
147
  #### 2. 退出登录接口 (signOut)
140
148
 
141
149
  ##### 用途
150
+
142
151
  退出登录,删除cookie中的登录态,适用于:用户主动登出、会话清理、安全退出
143
152
 
144
153
  ##### 适用场景
154
+
145
155
  需要清除用户登录状态的场景
146
156
 
147
157
  ##### 入参说明
158
+
148
159
  无需传入参数
149
160
 
150
161
  ##### 出参说明
162
+
151
163
  | 字段名 | 类型 | 说明 |
152
164
  |--------|------|---------|
153
165
  | `data` | `null` | 数据为空 |
@@ -156,6 +168,7 @@ const loginResult = dataloom
156
168
  | `statusText` | `'OK'` | HTTP状态文本 |
157
169
 
158
170
  ##### 使用示例
171
+
159
172
  ```typescript
160
173
  /**
161
174
  * 退出登录,删除cookie中的登陆态
@@ -196,12 +209,15 @@ try {
196
209
  #### 3. 跳转用户详情页接口 (navigateToUserProfile)
197
210
 
198
211
  ##### 用途
212
+
199
213
  跳转至当前登录用户的详情页,适用于:查看个人资料、从用户头像/姓名点击进入详情页面
200
214
 
201
215
  ##### 适用场景
216
+
202
217
  需要在应用中快速打开用户详情页面的场景
203
218
 
204
219
  ##### 入参说明
220
+
205
221
  ```typescript
206
222
  interface NavigateToUserProfileOptions {
207
223
  /**
@@ -216,6 +232,7 @@ interface NavigateToUserProfileOptions {
216
232
  | `newTab` | `boolean` | ❌ | `false` | 是否在新浏览器标签页打开详情页 |
217
233
 
218
234
  ##### 出参说明
235
+
219
236
  | 字段名 | 类型 | 说明 |
220
237
  |--------|------|---------|
221
238
  | `data` | `'success'` | 成功标识 |
@@ -224,6 +241,7 @@ interface NavigateToUserProfileOptions {
224
241
  | `statusText` | `'OK'` | HTTP状态文本 |
225
242
 
226
243
  ##### 使用示例
244
+
227
245
  ```typescript
228
246
  /**
229
247
  * 跳转至用户详情页
@@ -252,12 +270,15 @@ const resNewTab = dataloom
252
270
  #### 4. 获取用户信息接口 (getUserInfo)
253
271
 
254
272
  ##### 用途
273
+
255
274
  根据当前登录态获取已登录的用户信息,适用于:用户资料展示、权限判断、个性化配置
256
275
 
257
276
  ##### 适用场景
277
+
258
278
  需要获取当前登录用户详细信息的场景
259
279
 
260
280
  ##### 数据类型定义
281
+
261
282
  ```typescript
262
283
  interface I18n {
263
284
  language_code: number;
@@ -289,9 +310,11 @@ interface UserInfoResponse {
289
310
  ```
290
311
 
291
312
  ##### 入参说明
313
+
292
314
  无需传入参数
293
315
 
294
316
  ##### 出参说明
317
+
295
318
  | 字段名 | 类型 | 说明 |
296
319
  |--------|------|---------|
297
320
  | `data.user_info` | `UserBaseInfo` | 用户基本信息对象 |
@@ -304,6 +327,7 @@ interface UserInfoResponse {
304
327
  | `error` | `null` | 错误信息,成功时为null |
305
328
 
306
329
  ##### 使用示例
330
+
307
331
  ```typescript
308
332
  /**
309
333
  * 根据当前登陆态获取已登录的用户信息。
@@ -359,6 +383,7 @@ try {
359
383
  ## 错误处理
360
384
 
361
385
  ### 常见错误类型
386
+
362
387
  | 错误码 | 说明 | 处理建议 |
363
388
  |--------|------|---------|
364
389
  | `400` | 请求参数错误 | 检查传入参数是否正确 |
@@ -368,6 +393,7 @@ try {
368
393
  | `500` | 服务器内部错误 | 稍后重试或联系技术支持 |
369
394
 
370
395
  ### 错误处理最佳实践
396
+
371
397
  ```typescript
372
398
  // 统一错误处理函数
373
399
  function handleDataloomError(response: DataloomServiceResponse<any>) {
@@ -414,12 +440,15 @@ if (handleDataloomError(userInfoResult)) {
414
440
  # 用户系统前端相关规范
415
441
 
416
442
  ## 概述
443
+
417
444
  内置的用户前端组件规范,提供了 UserSelect(支持单选/多选的用户选择器)和 UserDisplay(用户信息展示组件)两个核心 React 组件,基于统一的userid数据,并且用户选择组件中会通过onchange返回User类型数据,专门用于处理用户相关的表单输入和数据展示场景。
418
445
 
419
446
  同时提供 DepartmentSelect(部门选择组件),用于部门字段的单选/多选选择,交互与受控规范与 UserSelect 保持一致。
447
+
420
448
  ## 类型定义
421
449
 
422
450
  ### 用户数据类型
451
+
423
452
  ```typescript
424
453
  import type { User } from '@/types/common';
425
454
  ```
@@ -437,6 +466,7 @@ export type User = {
437
466
  ## 当前用户信息的获取方案
438
467
 
439
468
  ### 常用场景
469
+
440
470
  - **用户信息展示**:在界面中显示当前用户名称和头像
441
471
  - **权限验证**:基于用户ID进行权限检查和控制
442
472
  - **数据关联**:在数据操作时关联当前用户信息
@@ -445,6 +475,7 @@ export type User = {
445
475
  ### Hooks 方法: `useCurrentUserProfile` - 在 React 中获取当前用户信息
446
476
 
447
477
  ### 基本信息
478
+
448
479
  - **文件路径**:`@lark-apaas/client-toolkit/hooks/useCurrentUserProfile`
449
480
  - **功能**:获取当前登录用户的个人信息(含飞书 user_id)
450
481
  - **返回值**:`Partial<IUserProfile>`(初始为空对象 `{}`,异步获取后填充完整字段)
@@ -460,12 +491,14 @@ export type User = {
460
491
  | `lark_user_id` | `string` | 飞书 user_id,通过额外异步请求获取,可能晚于其他字段就绪 |
461
492
 
462
493
  > ⚠️ **空值处理(CRITICAL)**:该 Hook 初始返回空对象 `{}`(truthy),所有字段均为 `undefined`。
494
+ >
463
495
  > - **MUST** 使用可选链访问:`userInfo?.name`、`userInfo?.user_id`
464
496
  > - **MUST** 判断加载状态用 `if (!userInfo?.user_id)` 而非 `if (!userInfo)`(空对象是 truthy)
465
497
  > - **MUST** 渲染时提供默认值:`userInfo?.name ?? '加载中...'`
466
498
  > - **MUST** `lark_user_id` 通过额外异步请求获取,可能为 `undefined`(加载中/获取失败/无飞书账号),使用时必须条件渲染
467
499
 
468
500
  ### 使用方法
501
+
469
502
  ```typescript
470
503
  import { useCurrentUserProfile } from "@lark-apaas/client-toolkit/hooks/useCurrentUserProfile";
471
504
 
@@ -486,143 +519,22 @@ const MyComponent = () => {
486
519
  > **飞书 ID 转换详细指南**(后端 `AuthNPaasService` 用法、自定义转换接口等)参见 `user-identity` skill。
487
520
 
488
521
  ## 用户展示与选择方案
489
- {% if projectMeta['flags']['supportBusinessUser'] %}
522
+
490
523
  这些组件在使用之前必须读取 client/src/components/business-ui/README.md文件来理解用法
491
524
 
492
525
  目前可用的组件有:
526
+
493
527
  - UserSelect 用户选择组件(@/components/business-ui/user-select)
494
528
  - DepartmentSelect 部门选择组件(@/components/business-ui/department-select)
495
529
  - UserDisplay - 用户展示组件(@/components/business-ui/user-display)
496
530
 
497
- {% else %}
498
- ##
499
-
500
- ### 基本信息
501
- - **组件路径**:`@lark-apaas/client-toolkit/components/User`
502
- - **功能**:用于所有用户字段的表单输入
503
- - **特性**:支持单选/多选模式,内置搜索功能
504
-
505
- ### 组件 Props 定义
506
- ```typescript
507
- interface UserSelectProps {
508
- mode: 'single' | 'multiple'; // 选择模式
509
- value?: string | string[]; // 当前userid的值
510
- onChange?: (value: IUserProfile | IUserProfile[]) => void; // userid值变化回调
511
- placeholder?: string; // 占位符文本
512
- disabled?: boolean; // 是否禁用
513
- }
514
- ```
515
-
516
- ### 值类型说明
517
- - **单选模式** (`mode="single"`):值为 userid,返回为`IUserProfile` 对象
518
- - **多选模式** (`mode="multiple"`):值为 userid数组,返回为`IUserProfile` 数组
519
-
520
- ### 使用示例
521
-
522
- #### 表单集成
523
- ```typescript
524
- import { useForm } from "react-hook-form";
525
- import { zodResolver } from "@hookform/resolvers/zod";
526
- import * as z from "zod";
527
- import { Form, FormControl, FormField, FormItem, FormLabel } from "@/components/ui/form";
528
- import { UserSelect } from "@lark-apaas/client-toolkit/components/User";
529
-
530
- // 定义表单验证schema
531
- const formSchema = z.object({
532
- assignee: z.string(),
533
- participants: z.array(z.string()).optional(),
534
- });
535
-
536
- const form = useForm<z.infer<typeof formSchema>>({
537
- resolver: zodResolver(formSchema),
538
- });
539
-
540
- <Form {...form}>
541
- <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
542
- <FormField
543
- control={form.control}
544
- name="assignee"
545
- render={({ field }) => (
546
- <FormItem>
547
- <FormLabel>负责人</FormLabel>
548
- <FormControl>
549
- <UserSelect
550
- mode="single"
551
- placeholder="选择负责人"
552
- value={field.value}
553
- onChange={(user) => field.onChange(user.user_id)}
554
- />
555
- </FormControl>
556
- </FormItem>
557
- )}
558
- />
559
-
560
- <FormField
561
- control={form.control}
562
- name="participants"
563
- render={({ field }) => (
564
- <FormItem>
565
- <FormLabel>参与人(多选)</FormLabel>
566
- <FormControl>
567
- <UserSelect
568
- mode="multiple"
569
- placeholder="选择参与人员"
570
- value={field.value}
571
- onChange={(users) => field.onChange(users.map(user => user.user_id))}
572
- />
573
- </FormControl>
574
- </FormItem>
575
- )}
576
- />
577
- </form>
578
- </Form>
579
- ```
580
-
581
- ## UserDisplay - 用户展示组件
582
-
583
- ### 基本信息
584
- - **组件路径**:`@lark-apaas/client-toolkit/components/User`
585
- - **功能**:用于所有用户信息的展示场景
586
- - **特性**:显示用户**头像**和**姓名**,支持多用户展示
587
-
588
- IMPORTANT:当不传递showLabel时,组件会同时展示用户头像和姓名,如果只需要头像,则需要传递showLabel的值为false
589
-
590
- ### 属性定义
591
- ```typescript
592
- interface UserDisplayProps {
593
- users: string[]; // 用户id数组(必需)
594
- size?: 'small' | 'medium' | 'large'; // 头像尺寸
595
- className?: string; // 自定义样式类名
596
- showLabel?: boolean; // 默认为true,会展示用户姓名,如果只需要展示头像则需要设置为false
597
- }
598
- ```
599
-
600
- ### 使用示例
601
-
602
- #### 基础用法
603
- ```jsx
604
- import { UserDisplay } from "@lark-apaas/client-toolkit/components/User";
605
- import { useEmployeeStore } from "@/models/employee";
606
-
607
- const { employeesId } = useEmployeeStore();
608
-
609
- // 单个用户展示
610
- <UserDisplay
611
- users={[employeesId]}
612
- size="small"
613
- />
614
-
615
- // 多用户展示
616
- <UserDisplay
617
- users={project.participants}
618
- size="medium"
619
- className="project-members"
620
- />
621
- ```
531
+ <!-- legacy: client-toolkit User 组件备用方案,已不再推荐;按本地版静态化,仅保留 business-ui 路径 -->
532
+ <!-- begin: removed Nunjucks else branch (line 532..672 in upstream) -->
533
+ <!-- end -->
622
534
 
623
535
  ## 使用注意事项
624
536
 
625
537
  ### 最佳实践
538
+
626
539
  - 根据展示场景选择合适的组件尺寸(`small`、`medium`、`large`)
627
540
  - 对于用户信息 userId,禁止直接展示文本,总是使用 UserDisplay 组件展示
628
- {% endif %}
@@ -267,4 +267,3 @@ for await (const items of await client.contact.user.listWithIterator({
267
267
  | 忘记开启机器人能力 | 应用能力 → 添加机器人(发消息必须) |
268
268
  | 日期格式搞混 | 日历用 RFC3339 (`2026-01-01T09:00:00+08:00`),考勤用整数 (`20260101`) |
269
269
  | 生成独立可运行的脚本文件 | 所有飞书调用放在 NestJS Service 方法中,由 Controller 调用 |
270
-
@@ -1,6 +1,6 @@
1
1
  # 审批 (Approval)
2
2
 
3
- > 开放平台文档(Markdown 版):https://open.larkoffice.com/document/server-docs/approval-v4/approval-overview.md
3
+ > 开放平台文档(Markdown 版):<https://open.larkoffice.com/document/server-docs/approval-v4/approval-overview.md>
4
4
 
5
5
  使用 `@larksuiteoapi/node-sdk` 在 NestJS 中管理飞书审批流程。
6
6
 
@@ -1,6 +1,6 @@
1
1
  # 考勤 (Attendance)
2
2
 
3
- > 开放平台文档(Markdown 版):https://open.larkoffice.com/document/server-docs/attendance-v1/overview.md
3
+ > 开放平台文档(Markdown 版):<https://open.larkoffice.com/document/server-docs/attendance-v1/overview.md>
4
4
 
5
5
  使用 `@larksuiteoapi/node-sdk` 在 NestJS 中查询飞书考勤数据。
6
6
 
@@ -1,6 +1,6 @@
1
1
  # 多维表格 (Bitable)
2
2
 
3
- > 开放平台文档(Markdown 版):https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-overview.md
3
+ > 开放平台文档(Markdown 版):<https://open.larkoffice.com/document/server-docs/docs/bitable-v1/bitable-overview.md>
4
4
 
5
5
  使用 `@larksuiteoapi/node-sdk` 在 NestJS 中操作飞书多维表格。
6
6
 
@@ -16,6 +16,7 @@
16
16
  ## 获取 app_token
17
17
 
18
18
  多维表格的 `app_token` 有三种获取方式:
19
+
19
20
  1. **通过 API 创建** → 响应中包含 `app_token`
20
21
  2. **通过 API 列出** → 从文件列表中获取
21
22
  3. **从 URL 提取** → 见下方 URL 解析
@@ -264,6 +265,7 @@ await client.bitable.appTableField.delete({
264
265
  ## 新建多维表格清理建议
265
266
 
266
267
  新建的多维表格会自动创建默认字段(单选、日期、附件)和空行。建议创建后清理:
268
+
267
269
  1. 删除不需要的默认字段(类型 3/5/17)
268
270
  2. 重命名主字段为有意义的名称
269
271
  3. 批量删除空的占位行