@blueking/bk-user-selector 0.1.6 → 0.1.7
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 +114 -34
- package/package.json +6 -3
- package/typings/components/selection-popover.vue.d.ts +8 -2
- package/typings/components/user-selector.vue.d.ts +9 -1
- package/typings/hooks/use-api-config.d.ts +33 -0
- package/typings/locale/en-us.d.ts +1 -0
- package/typings/locale/zh-cn.d.ts +1 -0
- package/typings/types/index.d.ts +45 -0
- package/typings/utils/logger.d.ts +9 -1
- package/vue2/index.es.min.js +5475 -2514
- package/vue2/index.iife.min.js +6230 -3171
- package/vue2/index.umd.min.js +5653 -2691
- package/vue2/vue2.css +53 -8
- package/vue3/index.es.min.js +1200 -277
- package/vue3/index.iife.min.js +5460 -2506
- package/vue3/index.umd.min.js +1200 -277
- package/vue3/vue3.css +53 -8
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
| 🎨 **可拖拽** | 多选模式下支持拖拽排序 |
|
|
19
19
|
| ⚡ **快捷操作** | 支持快速选择当前用户("我") |
|
|
20
20
|
| 👥 **用户组** | 支持用户组/角色分组显示 |
|
|
21
|
+
| 🕘 **最近选择** | 支持在下拉右侧展示最近选择人员 |
|
|
21
22
|
| ✏️ **自定义输入** | 支持创建自定义用户和自由粘贴 |
|
|
22
23
|
| 🎭 **自定义渲染** | 支持自定义标签和列表项渲染 |
|
|
23
24
|
| 📝 **多行输入** | 支持 textarea 模式,完整展示所有标签 |
|
|
@@ -158,6 +159,29 @@ export default {
|
|
|
158
159
|
</script>
|
|
159
160
|
```
|
|
160
161
|
|
|
162
|
+
### 最近选择
|
|
163
|
+
|
|
164
|
+
业务只需传入最近选择用户 ID,组件会自动补全并展示在下拉右侧:
|
|
165
|
+
|
|
166
|
+
```vue
|
|
167
|
+
<template>
|
|
168
|
+
<BkUserSelector
|
|
169
|
+
v-model="selectedUsers"
|
|
170
|
+
:api-base-url="apiBaseUrl"
|
|
171
|
+
:multiple="true"
|
|
172
|
+
:recent-user-ids="recentUserIds"
|
|
173
|
+
/>
|
|
174
|
+
</template>
|
|
175
|
+
|
|
176
|
+
<script setup>
|
|
177
|
+
import { ref } from 'vue';
|
|
178
|
+
|
|
179
|
+
const apiBaseUrl = ref('https://api.example.com');
|
|
180
|
+
const selectedUsers = ref([]);
|
|
181
|
+
const recentUserIds = ref(['admin', 'operator']);
|
|
182
|
+
</script>
|
|
183
|
+
```
|
|
184
|
+
|
|
161
185
|
### 自定义渲染
|
|
162
186
|
|
|
163
187
|
支持自定义标签和列表项的渲染:
|
|
@@ -295,34 +319,35 @@ export default {
|
|
|
295
319
|
|
|
296
320
|
### Props 属性
|
|
297
321
|
|
|
298
|
-
| 参数 | 说明
|
|
299
|
-
| --------------------- |
|
|
300
|
-
| modelValue / v-model | 绑定值,单选为字符串,多选为数组
|
|
301
|
-
| apiBaseUrl | API 基础 URL
|
|
302
|
-
| tenantId | 租户 ID
|
|
303
|
-
| hasAvatar | 是否显示头像
|
|
304
|
-
| avatarBaseUrl | 头像基础 URL
|
|
305
|
-
| label | 文本标签
|
|
306
|
-
| placeholder | 占位文本
|
|
307
|
-
| multiple | 是否多选
|
|
308
|
-
| draggable | 是否可拖拽排序(仅多选模式有效)
|
|
309
|
-
| exactSearchKey | 精确查找 key
|
|
310
|
-
| currentUserId | 当前用户 ID(用于快速选择"我")
|
|
311
|
-
| userGroup | 用户组列表
|
|
312
|
-
| userGroupName | 用户组分类名称
|
|
313
|
-
| emptyText | 无匹配人员时的提示文本
|
|
314
|
-
| disabled | 是否禁用
|
|
315
|
-
| renderTag | 自定义标签渲染函数
|
|
316
|
-
| renderListItem | 自定义列表项渲染函数
|
|
317
|
-
| excludeUserIds | 排除的用户 ID 列表
|
|
318
|
-
|
|
|
319
|
-
|
|
|
320
|
-
|
|
|
321
|
-
|
|
|
322
|
-
|
|
|
323
|
-
|
|
|
324
|
-
|
|
|
325
|
-
|
|
|
322
|
+
| 参数 | 说明 | 类型 | 默认值 | 必填 |
|
|
323
|
+
| --------------------- | -------------------------------------------------- | ------------------------------------------------ | ---------------------- | ---- |
|
|
324
|
+
| modelValue / v-model | 绑定值,单选为字符串,多选为数组 | `string` / `string[]` | `''` / `[]` | 是 |
|
|
325
|
+
| apiBaseUrl | API 基础 URL | `string` | `''` | 是 |
|
|
326
|
+
| tenantId | 租户 ID | `string` | `'default'` | 否 |
|
|
327
|
+
| hasAvatar | 是否显示头像 | `boolean` | `false` | 否 |
|
|
328
|
+
| avatarBaseUrl | 头像基础 URL | `string` | `` | 否 |
|
|
329
|
+
| label | 文本标签 | `string` | `'人员选择'` | 否 |
|
|
330
|
+
| placeholder | 占位文本 | `string` | `'请输入人员名称搜索'` | 否 |
|
|
331
|
+
| multiple | 是否多选 | `boolean` | `false` | 否 |
|
|
332
|
+
| draggable | 是否可拖拽排序(仅多选模式有效) | `boolean` | `false` | 否 |
|
|
333
|
+
| exactSearchKey | 精确查找 key | `'bk_username'` / `'login_name'` / `'full_name'` | `'bk_username'` | 否 |
|
|
334
|
+
| currentUserId | 当前用户 ID(用于快速选择"我") | `string` | `''` | 否 |
|
|
335
|
+
| userGroup | 用户组列表 | `UserGroupItem[]` | `[]` | 否 |
|
|
336
|
+
| userGroupName | 用户组分类名称 | `string` | `'用户群组'` | 否 |
|
|
337
|
+
| emptyText | 无匹配人员时的提示文本 | `string` | `'无匹配人员'` | 否 |
|
|
338
|
+
| disabled | 是否禁用 | `boolean` | `false` | 否 |
|
|
339
|
+
| renderTag | 自定义标签渲染函数 | `(h, userInfo) => VNode` | - | 否 |
|
|
340
|
+
| renderListItem | 自定义列表项渲染函数 | `(h, userInfo) => VNode` | - | 否 |
|
|
341
|
+
| excludeUserIds | 排除的用户 ID 列表 | `string[]` | `[]` | 否 |
|
|
342
|
+
| recentUserIds | 最近选择用户 ID 列表,传入后在下拉右侧展示最近选择 | `string[]` | `[]` | 否 |
|
|
343
|
+
| enableMultiTenantMode | 是否启用多租户模式 | `boolean` | `true` | 否 |
|
|
344
|
+
| allowCreate | 是否允许自定义输入,按 Enter 确认 | `boolean` | `false` | 否 |
|
|
345
|
+
| freePaste | 是否允许粘贴任意文本 | `boolean` | `false` | 否 |
|
|
346
|
+
| maxCount | 最大可选数量(0 表示不限制) | `number` | `0` | 否 |
|
|
347
|
+
| type | 输入框类型 | `'input'` / `'textarea'` | `'input'` | 否 |
|
|
348
|
+
| rows | 默认行数(仅 textarea 模式生效) | `number` | `4` | 否 |
|
|
349
|
+
| resize | 是否允许拖拽调整高度(仅 textarea 模式生效) | `boolean` | `true` | 否 |
|
|
350
|
+
| autoFocus | 是否自动聚焦 | `boolean` | `false` | 否 |
|
|
326
351
|
|
|
327
352
|
#### exactSearchKey 说明
|
|
328
353
|
|
|
@@ -337,12 +362,14 @@ export default {
|
|
|
337
362
|
|
|
338
363
|
### Events 事件
|
|
339
364
|
|
|
340
|
-
| 事件名称 | 说明
|
|
341
|
-
| ----------------- |
|
|
342
|
-
| update:modelValue | 绑定值变化时触发
|
|
343
|
-
| change | 选中值变化时触发
|
|
344
|
-
| focus | 输入框获得焦点时触发
|
|
345
|
-
| blur | 输入框失去焦点时触发
|
|
365
|
+
| 事件名称 | 说明 | 回调参数 |
|
|
366
|
+
| ----------------- | ---------------------------------------------------------------------------------- | ------------------------------------ |
|
|
367
|
+
| update:modelValue | 绑定值变化时触发 | `(value: string \| string[])` |
|
|
368
|
+
| change | 选中值变化时触发 | `(userInfo: UserInfo \| UserInfo[])` |
|
|
369
|
+
| focus | 输入框获得焦点时触发 | - |
|
|
370
|
+
| blur | 输入框失去焦点时触发 | - |
|
|
371
|
+
| error | 任意接口请求失败时触发(包含 401、网络错误等),业务可在此弹 Message、上报 Sentry | `(error: ApiError)` |
|
|
372
|
+
| unauthorized | 登录态失效(HTTP 401)时触发,同时也会触发 `error`,业务可在此跳转登录或刷新 token | `(error: ApiError)` |
|
|
346
373
|
|
|
347
374
|
### Methods 方法
|
|
348
375
|
|
|
@@ -397,8 +424,56 @@ type RenderFunction = (
|
|
|
397
424
|
h: CreateElement, // Vue createElement 函数
|
|
398
425
|
userInfo: UserInfo, // 用户信息
|
|
399
426
|
) => VNode;
|
|
427
|
+
|
|
428
|
+
// 接口错误
|
|
429
|
+
interface ApiError {
|
|
430
|
+
scene: string; // 业务场景,如 '搜索用户'、'批量查找用户'
|
|
431
|
+
cause: unknown; // 原始错误对象
|
|
432
|
+
status?: number; // HTTP 状态码(网络错误时为 undefined)
|
|
433
|
+
isUnauthorized: boolean; // 是否为登录态失效(HTTP 401)
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
## 🛡️ 错误处理
|
|
438
|
+
|
|
439
|
+
组件遵循「不强依赖 UI 反馈」的设计原则,接口失败时**不会自动弹 Message**,而是通过事件向业务侧暴露错误,由业务自行决定弹消息、上报监控或静默处理。
|
|
440
|
+
|
|
441
|
+
```vue
|
|
442
|
+
<template>
|
|
443
|
+
<BkUserSelector
|
|
444
|
+
v-model="selectedUser"
|
|
445
|
+
:api-base-url="apiBaseUrl"
|
|
446
|
+
:tenant-id="tenantId"
|
|
447
|
+
@error="handleApiError"
|
|
448
|
+
@unauthorized="handleUnauthorized"
|
|
449
|
+
/>
|
|
450
|
+
</template>
|
|
451
|
+
|
|
452
|
+
<script setup lang="ts">
|
|
453
|
+
import { Message } from 'bkui-vue';
|
|
454
|
+
|
|
455
|
+
import type { ApiError } from '@blueking/bk-user-selector';
|
|
456
|
+
|
|
457
|
+
const handleApiError = (err: ApiError) => {
|
|
458
|
+
// 401 不需要重复弹 Message,由 unauthorized 单独处理
|
|
459
|
+
if (err.isUnauthorized) return;
|
|
460
|
+
Message({ theme: 'error', message: `${err.scene}失败,请稍后重试` });
|
|
461
|
+
// 也可以上报 Sentry / 蓝鲸监控
|
|
462
|
+
// sentry.captureException(err.cause, { extra: { scene: err.scene, status: err.status } });
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
const handleUnauthorized = (err: ApiError) => {
|
|
466
|
+
location.href = `/login?next=${encodeURIComponent(location.href)}`;
|
|
467
|
+
};
|
|
468
|
+
</script>
|
|
400
469
|
```
|
|
401
470
|
|
|
471
|
+
行为说明:
|
|
472
|
+
|
|
473
|
+
- 失败统一构造 `ApiError`,已通过 `console.error` 打印兜底日志
|
|
474
|
+
- 401 会同时触发 `unauthorized` 和 `error` 事件,便于业务统一收口或独立处理
|
|
475
|
+
- 业务回调如果抛错不会影响组件正常流程
|
|
476
|
+
|
|
402
477
|
## 💡 功能说明
|
|
403
478
|
|
|
404
479
|
### 快速选择"我"
|
|
@@ -467,6 +542,7 @@ type RenderFunction = (
|
|
|
467
542
|
- 多选模式:`v-model` 应为 `string[]` 类型
|
|
468
543
|
4. **跨租户显示**:跨租户用户会在名称旁显示租户标识
|
|
469
544
|
5. **自定义输入**:启用 `allowCreate` 后,用户输入的内容会作为 `id` 值
|
|
545
|
+
6. **批量粘贴限制**:单次粘贴最多处理 `100` 个用户标识,超出部分会被截断;批量精准查询按后端限制分批执行(每批最多 `100` 个)
|
|
470
546
|
|
|
471
547
|
## ❓ FAQ
|
|
472
548
|
|
|
@@ -494,6 +570,10 @@ A: 通过 `change` 事件获取,它会返回完整的用户信息对象,而
|
|
|
494
570
|
|
|
495
571
|
A: 使用 `maxCount` 属性设置最大可选数量,`0` 表示不限制。
|
|
496
572
|
|
|
573
|
+
### Q: 一次粘贴很多用户,为什么没有全部添加?
|
|
574
|
+
|
|
575
|
+
A: 出于性能与安全保护,批量粘贴单次最多处理 `100` 个用户标识,超出部分会被截断;组件会按后端限制分批查询(每批最多 `100` 个)。如需导入更多用户,请分批粘贴。
|
|
576
|
+
|
|
497
577
|
### Q: 搜索没有结果怎么办?
|
|
498
578
|
|
|
499
579
|
A: 检查以下几点:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blueking/bk-user-selector",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "蓝鲸用户选择器",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Tencent BlueKing",
|
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
"build": "vite-node ./scripts/vite.build.ts",
|
|
11
11
|
"dts": "vue-tsc --project tsconfig.dts.json",
|
|
12
12
|
"prettier": "prettier ./src ./scripts ./playground --write",
|
|
13
|
-
"visualize": "vite-bundle-visualizer -c scripts/vite.visualizer.ts"
|
|
13
|
+
"visualize": "vite-bundle-visualizer -c scripts/vite.visualizer.ts",
|
|
14
|
+
"docs:dev": "vitepress dev docs",
|
|
15
|
+
"docs:build": "vitepress build docs",
|
|
16
|
+
"docs:preview": "vitepress preview docs"
|
|
14
17
|
},
|
|
15
18
|
"exports": {
|
|
16
19
|
".": {
|
|
@@ -61,4 +64,4 @@
|
|
|
61
64
|
"lodash": "^4.17.23",
|
|
62
65
|
"sortablejs": "^1.15.6"
|
|
63
66
|
}
|
|
64
|
-
}
|
|
67
|
+
}
|
|
@@ -21,6 +21,10 @@ interface SelectionPopoverProps {
|
|
|
21
21
|
loading?: boolean;
|
|
22
22
|
/** 搜索结果选项 */
|
|
23
23
|
options?: FormattedUser[];
|
|
24
|
+
/** 最近选择用户 */
|
|
25
|
+
recentUsers?: FormattedUser[];
|
|
26
|
+
/** 最近选择标题 */
|
|
27
|
+
recentUsersName?: string;
|
|
24
28
|
/** 渲染列表项 */
|
|
25
29
|
renderListItem?: RenderFunction;
|
|
26
30
|
/** 搜索关键词 */
|
|
@@ -34,9 +38,9 @@ interface SelectionPopoverProps {
|
|
|
34
38
|
/** 用户组名称 */
|
|
35
39
|
userGroupName?: string;
|
|
36
40
|
}
|
|
37
|
-
declare var
|
|
41
|
+
declare var __VLS_27: {};
|
|
38
42
|
type __VLS_Slots = {} & {
|
|
39
|
-
default?: (props: typeof
|
|
43
|
+
default?: (props: typeof __VLS_27) => any;
|
|
40
44
|
};
|
|
41
45
|
declare const __VLS_base: import("vue").DefineComponent<SelectionPopoverProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
42
46
|
"click-outside": (event: MouseEvent) => any;
|
|
@@ -58,6 +62,8 @@ declare const __VLS_base: import("vue").DefineComponent<SelectionPopoverProps, {
|
|
|
58
62
|
isShow: boolean;
|
|
59
63
|
loading: boolean;
|
|
60
64
|
options: FormattedUser[];
|
|
65
|
+
recentUsers: FormattedUser[];
|
|
66
|
+
recentUsersName: string;
|
|
61
67
|
userGroupName: string;
|
|
62
68
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
63
69
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
import { FormattedUser, UserSelectorProps } from '../types';
|
|
1
|
+
import { ApiError, FormattedUser, UserSelectorProps } from '../types';
|
|
2
2
|
declare const __VLS_export: import("vue").DefineComponent<UserSelectorProps, {
|
|
3
3
|
focus: () => void;
|
|
4
4
|
blur: () => void;
|
|
5
5
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
+
error: (error: ApiError) => any;
|
|
6
7
|
blur: () => any;
|
|
7
8
|
change: (user: FormattedUser | FormattedUser[] | null) => any;
|
|
8
9
|
focus: () => any;
|
|
9
10
|
dragEnd: (event: Sortable.SortableEvent) => any;
|
|
10
11
|
dragStart: (event: Sortable.SortableEvent) => any;
|
|
12
|
+
unauthorized: (error: ApiError) => any;
|
|
11
13
|
"update:modelValue": (value: string | string[]) => any;
|
|
12
14
|
}, string, import("vue").PublicProps, Readonly<UserSelectorProps> & Readonly<{
|
|
15
|
+
onError?: ((error: ApiError) => any) | undefined;
|
|
13
16
|
onBlur?: (() => any) | undefined;
|
|
14
17
|
onChange?: ((user: FormattedUser | FormattedUser[] | null) => any) | undefined;
|
|
15
18
|
onFocus?: (() => any) | undefined;
|
|
16
19
|
onDragEnd?: ((event: Sortable.SortableEvent) => any) | undefined;
|
|
17
20
|
onDragStart?: ((event: Sortable.SortableEvent) => any) | undefined;
|
|
21
|
+
onUnauthorized?: ((error: ApiError) => any) | undefined;
|
|
18
22
|
"onUpdate:modelValue"?: ((value: string | string[]) => any) | undefined;
|
|
19
23
|
}>, {
|
|
20
24
|
userGroup: import("../types").UserGroupConfig[];
|
|
@@ -39,7 +43,11 @@ declare const __VLS_export: import("vue").DefineComponent<UserSelectorProps, {
|
|
|
39
43
|
modelValue: string | string[];
|
|
40
44
|
multiple: boolean;
|
|
41
45
|
rows: number;
|
|
46
|
+
allowCrossOriginCredentials: boolean;
|
|
47
|
+
allowedApiOrigins: string[];
|
|
48
|
+
allowPrivateApiHost: boolean;
|
|
42
49
|
placeholder: string;
|
|
50
|
+
recentUserIds: string[];
|
|
43
51
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
44
52
|
declare const _default: typeof __VLS_export;
|
|
45
53
|
export default _default;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type InjectionKey } from 'vue';
|
|
2
|
+
import type { ApiErrorHandler } from '../types';
|
|
3
|
+
export interface ApiConfig {
|
|
4
|
+
allowCrossOriginCredentials: boolean;
|
|
5
|
+
allowedApiOrigins: string[];
|
|
6
|
+
allowPrivateApiHost: boolean;
|
|
7
|
+
apiBaseUrl: string;
|
|
8
|
+
/**
|
|
9
|
+
* 接口失败回调
|
|
10
|
+
* 由组件透传或调用方在直接调用 API 函数时传入
|
|
11
|
+
*/
|
|
12
|
+
onError?: ApiErrorHandler;
|
|
13
|
+
/**
|
|
14
|
+
* 登录态失效回调(HTTP 401)
|
|
15
|
+
* 由组件透传或调用方在直接调用 API 函数时传入
|
|
16
|
+
*/
|
|
17
|
+
onUnauthorized?: ApiErrorHandler;
|
|
18
|
+
tenantId: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 可选回调集合,用于向 provideApiConfig 注入回调
|
|
22
|
+
*/
|
|
23
|
+
export interface ApiConfigCallbacks {
|
|
24
|
+
onError?: ApiErrorHandler;
|
|
25
|
+
onUnauthorized?: ApiErrorHandler;
|
|
26
|
+
}
|
|
27
|
+
export declare const API_CONFIG_KEY: InjectionKey<ApiConfig>;
|
|
28
|
+
export declare const normalizeAllowedOrigins: (allowedApiOrigins?: string[]) => string[];
|
|
29
|
+
export declare const sanitizeApiBaseUrl: (apiBaseUrl: string, allowedApiOrigins?: string[], allowPrivateApiHost?: boolean) => string;
|
|
30
|
+
export declare const sanitizeTenantId: (tenantId: string) => string;
|
|
31
|
+
export declare const getApiConfig: () => ApiConfig;
|
|
32
|
+
export declare const provideApiConfig: (apiBaseUrl: string, tenantId: string, allowedApiOrigins?: string[], allowPrivateApiHost?: boolean, allowCrossOriginCredentials?: boolean, callbacks?: ApiConfigCallbacks) => void;
|
|
33
|
+
export declare const useApiConfig: (fallbackApiBaseUrl?: string, fallbackTenantId?: string, fallbackAllowedApiOrigins?: string[], fallbackAllowPrivateApiHost?: boolean, fallbackAllowCrossOriginCredentials?: boolean) => ApiConfig;
|
package/typings/types/index.d.ts
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
import type { createVNode } from 'vue';
|
|
2
2
|
import type { VNode } from 'vue';
|
|
3
3
|
import type { USER_TYPE } from '../constants';
|
|
4
|
+
/**
|
|
5
|
+
* API 请求错误对象
|
|
6
|
+
* 组件内部所有接口请求失败时统一构造此对象,向外暴露给业务侧
|
|
7
|
+
*/
|
|
8
|
+
export interface ApiError {
|
|
9
|
+
/**
|
|
10
|
+
* 原始错误对象
|
|
11
|
+
*/
|
|
12
|
+
cause: unknown;
|
|
13
|
+
/**
|
|
14
|
+
* 是否为登录态失效(HTTP 401)
|
|
15
|
+
* 同时会触发 onUnauthorized 回调
|
|
16
|
+
*/
|
|
17
|
+
isUnauthorized: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* 业务场景描述
|
|
20
|
+
* 例如:'获取租户信息'、'搜索用户'、'批量查找用户'
|
|
21
|
+
*/
|
|
22
|
+
scene: string;
|
|
23
|
+
/**
|
|
24
|
+
* HTTP 状态码(仅在响应已到达时存在;网络错误等情况下为 undefined)
|
|
25
|
+
*/
|
|
26
|
+
status?: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* API 错误回调
|
|
30
|
+
* 所有接口失败(含 401、网络错误等)都会触发此回调
|
|
31
|
+
*/
|
|
32
|
+
export type ApiErrorHandler = (error: ApiError) => void;
|
|
4
33
|
/**
|
|
5
34
|
* 基础选择器属性
|
|
6
35
|
*/
|
|
@@ -9,6 +38,18 @@ export interface BaseSelectorProps {
|
|
|
9
38
|
* 是否允许创建用户
|
|
10
39
|
*/
|
|
11
40
|
allowCreate?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* 是否允许跨域请求携带 Cookie
|
|
43
|
+
*/
|
|
44
|
+
allowCrossOriginCredentials?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* 允许访问的跨域 API 源白名单
|
|
47
|
+
*/
|
|
48
|
+
allowedApiOrigins?: string[];
|
|
49
|
+
/**
|
|
50
|
+
* 是否允许 apiBaseUrl 指向私网或 localhost
|
|
51
|
+
*/
|
|
52
|
+
allowPrivateApiHost?: boolean;
|
|
12
53
|
/**
|
|
13
54
|
* 接口基础URL
|
|
14
55
|
*/
|
|
@@ -55,6 +96,10 @@ export interface BaseSelectorProps {
|
|
|
55
96
|
* 占位文字
|
|
56
97
|
*/
|
|
57
98
|
placeholder?: string;
|
|
99
|
+
/**
|
|
100
|
+
* 最近选择用户 ID 列表
|
|
101
|
+
*/
|
|
102
|
+
recentUserIds?: string[];
|
|
58
103
|
/**
|
|
59
104
|
* 渲染列表项
|
|
60
105
|
*/
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 日志工具
|
|
3
|
+
* @module utils/logger
|
|
4
|
+
*/
|
|
5
|
+
import type { ApiConfig } from '../hooks/use-api-config';
|
|
1
6
|
/**
|
|
2
7
|
* 日志级别
|
|
3
8
|
*/
|
|
@@ -38,8 +43,11 @@ export declare const logger: {
|
|
|
38
43
|
};
|
|
39
44
|
/**
|
|
40
45
|
* API 错误处理
|
|
46
|
+
* - 打印错误日志(兜底)
|
|
47
|
+
* - 触发 apiConfig.onError 回调
|
|
48
|
+
* - 如果是 401,额外触发 apiConfig.onUnauthorized 回调
|
|
41
49
|
*/
|
|
42
|
-
export declare const handleApiError: (operation: string, error: unknown) => void;
|
|
50
|
+
export declare const handleApiError: (operation: string, error: unknown, apiConfig?: ApiConfig, status?: number, isUnauthorized?: boolean) => void;
|
|
43
51
|
/**
|
|
44
52
|
* 参数校验警告
|
|
45
53
|
*/
|