@blueking/bk-user-selector 0.1.5 → 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 CHANGED
@@ -18,10 +18,12 @@
18
18
  | 🎨 **可拖拽** | 多选模式下支持拖拽排序 |
19
19
  | ⚡ **快捷操作** | 支持快速选择当前用户("我") |
20
20
  | 👥 **用户组** | 支持用户组/角色分组显示 |
21
+ | 🕘 **最近选择** | 支持在下拉右侧展示最近选择人员 |
21
22
  | ✏️ **自定义输入** | 支持创建自定义用户和自由粘贴 |
22
23
  | 🎭 **自定义渲染** | 支持自定义标签和列表项渲染 |
23
24
  | 📝 **多行输入** | 支持 textarea 模式,完整展示所有标签 |
24
25
  | ⌨️ **键盘导航** | 支持上下键切换选项、Enter 快速选中 |
26
+ | 🎯 **焦点控制** | 支持自动聚焦和手动 focus/blur 方法 |
25
27
 
26
28
  ## 📦 安装
27
29
 
@@ -157,6 +159,29 @@ export default {
157
159
  </script>
158
160
  ```
159
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
+
160
185
  ### 自定义渲染
161
186
 
162
187
  支持自定义标签和列表项的渲染:
@@ -294,33 +319,35 @@ export default {
294
319
 
295
320
  ### Props 属性
296
321
 
297
- | 参数 | 说明 | 类型 | 默认值 | 必填 |
298
- | --------------------- | --------------------------------- | ------------------------------------------------ | ---------------------- | ---- |
299
- | modelValue / v-model | 绑定值,单选为字符串,多选为数组 | `string` / `string[]` | `''` / `[]` | 是 |
300
- | apiBaseUrl | API 基础 URL | `string` | `''` | 是 |
301
- | tenantId | 租户 ID | `string` | `'default'` | 否 |
302
- | hasAvatar | 是否显示头像 | `boolean` | `false` | 否 |
303
- | avatarBaseUrl | 头像基础 URL | `string` | `` | 否 |
304
- | label | 文本标签 | `string` | `'人员选择'` | 否 |
305
- | placeholder | 占位文本 | `string` | `'请输入人员名称搜索'` | 否 |
306
- | multiple | 是否多选 | `boolean` | `false` | 否 |
307
- | draggable | 是否可拖拽排序(仅多选模式有效) | `boolean` | `false` | 否 |
308
- | exactSearchKey | 精确查找 key | `'bk_username'` / `'login_name'` / `'full_name'` | `'bk_username'` | 否 |
309
- | currentUserId | 当前用户 ID(用于快速选择"我") | `string` | `''` | 否 |
310
- | userGroup | 用户组列表 | `UserGroupItem[]` | `[]` | 否 |
311
- | userGroupName | 用户组分类名称 | `string` | `'用户群组'` | 否 |
312
- | emptyText | 无匹配人员时的提示文本 | `string` | `'无匹配人员'` | 否 |
313
- | disabled | 是否禁用 | `boolean` | `false` | 否 |
314
- | renderTag | 自定义标签渲染函数 | `(h, userInfo) => VNode` | - | 否 |
315
- | renderListItem | 自定义列表项渲染函数 | `(h, userInfo) => VNode` | - | 否 |
316
- | excludeUserIds | 排除的用户 ID 列表 | `string[]` | `[]` | 否 |
317
- | enableMultiTenantMode | 是否启用多租户模式 | `boolean` | `true` | 否 |
318
- | allowCreate | 是否允许自定义输入,按 Enter 确认 | `boolean` | `false` | 否 |
319
- | freePaste | 是否允许粘贴任意文本 | `boolean` | `false` | 否 |
320
- | maxCount | 最大可选数量(0 表示不限制) | `number` | `0` | 否 |
321
- | type | 输入框类型 | `'input'` / `'textarea'` | `'input'` | 否 |
322
- | rows | 默认行数(仅 textarea 模式生效) | `number` | `4` | 否 |
323
- | resize | 是否允许拖拽调整高度(仅 textarea 模式生效) | `boolean` | `true` | 否 |
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` | 否 |
324
351
 
325
352
  #### exactSearchKey 说明
326
353
 
@@ -335,12 +362,42 @@ export default {
335
362
 
336
363
  ### Events 事件
337
364
 
338
- | 事件名称 | 说明 | 回调参数 |
339
- | ----------------- | -------------------- | ------------------------------------ |
340
- | update:modelValue | 绑定值变化时触发 | `(value: string \| string[])` |
341
- | change | 选中值变化时触发 | `(userInfo: UserInfo \| UserInfo[])` |
342
- | focus | 输入框获得焦点时触发 | `(event: FocusEvent)` |
343
- | blur | 输入框失去焦点时触发 | `(event: FocusEvent)` |
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)` |
373
+
374
+ ### Methods 方法
375
+
376
+ 通过模板 ref 调用组件方法:
377
+
378
+ | 方法名 | 说明 | 参数 |
379
+ | ------ | ---------- | ---- |
380
+ | focus | 使组件聚焦 | - |
381
+ | blur | 使组件失焦 | - |
382
+
383
+ ```vue
384
+ <template>
385
+ <BkUserSelector
386
+ ref="selectorRef"
387
+ v-model="value"
388
+ :api-base-url="apiBaseUrl"
389
+ />
390
+ <button @click="selectorRef?.focus()">聚焦</button>
391
+ <button @click="selectorRef?.blur()">失焦</button>
392
+ </template>
393
+
394
+ <script setup>
395
+ import { ref } from 'vue';
396
+ const selectorRef = ref(null);
397
+ const value = ref('');
398
+ const apiBaseUrl = 'https://api.example.com';
399
+ </script>
400
+ ```
344
401
 
345
402
  ### 类型定义
346
403
 
@@ -367,8 +424,56 @@ type RenderFunction = (
367
424
  h: CreateElement, // Vue createElement 函数
368
425
  userInfo: UserInfo, // 用户信息
369
426
  ) => VNode;
427
+
428
+ // 接口错误
429
+ interface ApiError {
430
+ scene: string; // 业务场景,如 '搜索用户'、'批量查找用户'
431
+ cause: unknown; // 原始错误对象
432
+ status?: number; // HTTP 状态码(网络错误时为 undefined)
433
+ isUnauthorized: boolean; // 是否为登录态失效(HTTP 401)
434
+ }
370
435
  ```
371
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>
469
+ ```
470
+
471
+ 行为说明:
472
+
473
+ - 失败统一构造 `ApiError`,已通过 `console.error` 打印兜底日志
474
+ - 401 会同时触发 `unauthorized` 和 `error` 事件,便于业务统一收口或独立处理
475
+ - 业务回调如果抛错不会影响组件正常流程
476
+
372
477
  ## 💡 功能说明
373
478
 
374
479
  ### 快速选择"我"
@@ -437,6 +542,7 @@ type RenderFunction = (
437
542
  - 多选模式:`v-model` 应为 `string[]` 类型
438
543
  4. **跨租户显示**:跨租户用户会在名称旁显示租户标识
439
544
  5. **自定义输入**:启用 `allowCreate` 后,用户输入的内容会作为 `id` 值
545
+ 6. **批量粘贴限制**:单次粘贴最多处理 `100` 个用户标识,超出部分会被截断;批量精准查询按后端限制分批执行(每批最多 `100` 个)
440
546
 
441
547
  ## ❓ FAQ
442
548
 
@@ -462,7 +568,11 @@ A: 通过 `change` 事件获取,它会返回完整的用户信息对象,而
462
568
 
463
569
  ### Q: 多选模式下如何限制选择数量?
464
570
 
465
- A: 目前组件暂不支持直接限制,可以通过 `change` 事件监听并在超出数量时给出提示。
571
+ A: 使用 `maxCount` 属性设置最大可选数量,`0` 表示不限制。
572
+
573
+ ### Q: 一次粘贴很多用户,为什么没有全部添加?
574
+
575
+ A: 出于性能与安全保护,批量粘贴单次最多处理 `100` 个用户标识,超出部分会被截断;组件会按后端限制分批查询(每批最多 `100` 个)。如需导入更多用户,请分批粘贴。
466
576
 
467
577
  ### Q: 搜索没有结果怎么办?
468
578
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blueking/bk-user-selector",
3
- "version": "0.1.5",
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 __VLS_22: {};
41
+ declare var __VLS_27: {};
38
42
  type __VLS_Slots = {} & {
39
- default?: (props: typeof __VLS_22) => any;
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,17 +1,24 @@
1
- import { FormattedUser, UserSelectorProps } from '../types';
2
- declare const __VLS_export: import("vue").DefineComponent<UserSelectorProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
1
+ import { ApiError, FormattedUser, UserSelectorProps } from '../types';
2
+ declare const __VLS_export: import("vue").DefineComponent<UserSelectorProps, {
3
+ focus: () => void;
4
+ blur: () => void;
5
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
6
+ error: (error: ApiError) => any;
3
7
  blur: () => any;
4
8
  change: (user: FormattedUser | FormattedUser[] | null) => any;
5
9
  focus: () => any;
6
10
  dragEnd: (event: Sortable.SortableEvent) => any;
7
11
  dragStart: (event: Sortable.SortableEvent) => any;
12
+ unauthorized: (error: ApiError) => any;
8
13
  "update:modelValue": (value: string | string[]) => any;
9
14
  }, string, import("vue").PublicProps, Readonly<UserSelectorProps> & Readonly<{
15
+ onError?: ((error: ApiError) => any) | undefined;
10
16
  onBlur?: (() => any) | undefined;
11
17
  onChange?: ((user: FormattedUser | FormattedUser[] | null) => any) | undefined;
12
18
  onFocus?: (() => any) | undefined;
13
19
  onDragEnd?: ((event: Sortable.SortableEvent) => any) | undefined;
14
20
  onDragStart?: ((event: Sortable.SortableEvent) => any) | undefined;
21
+ onUnauthorized?: ((error: ApiError) => any) | undefined;
15
22
  "onUpdate:modelValue"?: ((value: string | string[]) => any) | undefined;
16
23
  }>, {
17
24
  userGroup: import("../types").UserGroupConfig[];
@@ -32,10 +39,15 @@ declare const __VLS_export: import("vue").DefineComponent<UserSelectorProps, {},
32
39
  userGroupName: string;
33
40
  disabled: boolean;
34
41
  draggable: boolean;
42
+ autoFocus: boolean;
35
43
  modelValue: string | string[];
36
44
  multiple: boolean;
37
45
  rows: number;
46
+ allowCrossOriginCredentials: boolean;
47
+ allowedApiOrigins: string[];
48
+ allowPrivateApiHost: boolean;
38
49
  placeholder: string;
50
+ recentUserIds: string[];
39
51
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
40
52
  declare const _default: typeof __VLS_export;
41
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;
@@ -1,6 +1,7 @@
1
1
  declare const _default: {
2
2
  我: string;
3
3
  请输入人员名称搜索: string;
4
+ 最近选择: string;
4
5
  用户群组: string;
5
6
  无匹配人员: string;
6
7
  虚拟账号: string;
@@ -1,6 +1,7 @@
1
1
  declare const _default: {
2
2
  我: string;
3
3
  请输入人员名称搜索: string;
4
+ 最近选择: string;
4
5
  用户群组: string;
5
6
  无匹配人员: string;
6
7
  虚拟账号: string;
@@ -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
  */
@@ -204,6 +249,11 @@ export interface UserGroupConfig {
204
249
  * 用户选择器属性
205
250
  */
206
251
  export interface UserSelectorProps extends BaseSelectorProps {
252
+ /**
253
+ * 是否自动聚焦
254
+ * @default false
255
+ */
256
+ autoFocus?: boolean;
207
257
  /**
208
258
  * 是否支持拖拽排序
209
259
  */
@@ -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
  */