@blueking/bk-user-selector

蓝鲸用户选择器
27,993
Install
npm install @blueking/bk-user-selector
Latest Version:0.1.15
Older releases:2 · 3
License:MIT
Last Updated:Aug 24, 2026
Links: npm
Maintainer: blueking-magicbox

蓝鲸多租户人员选择器组件

npm version License Vue2 Vue3

蓝鲸多租户人员选择器(BkUserSelector)是一个用于在蓝鲸系统中选择用户的组件,支持单选和多选模式,具备搜索、跨租户查询等功能。

✨ 特性

特性 说明
🎯 双版本支持 同时支持 Vue2 和 Vue3
🔄 单选/多选 灵活切换单选和多选模式
🔍 智能搜索 支持用户名、登录名、全名等多字段搜索
🏢 跨租户 支持多租户场景下的用户选择和显示
🎨 可拖拽 多选模式下支持拖拽排序
⚡ 快捷操作 支持快速选择当前用户("我")
👥 用户组 支持用户组/角色分组显示
🕘 最近选择 支持在下拉右侧展示最近选择人员
✏️ 自定义输入 支持创建自定义用户和自由粘贴
🎭 自定义渲染 支持自定义标签和列表项渲染
📝 多行输入 支持 textarea 模式,完整展示所有标签
⌨️ 键盘导航 支持上下键切换选项、Enter 快速选中
🎯 焦点控制 支持自动聚焦和手动 focus/blur 方法

📦 安装

# npm
npm install @blueking/bk-user-selector

# yarn
yarn add @blueking/bk-user-selector

# pnpm
pnpm add @blueking/bk-user-selector

🚀 快速开始

在 Vue3 中使用

import BkUserSelector from '@blueking/bk-user-selector';
import '@blueking/bk-user-selector/vue3/vue3.css';

export default {
  components: {
    BkUserSelector,
  },
};

在 Vue2 中使用

import BkUserSelector from '@blueking/bk-user-selector/vue2';
import '@blueking/bk-user-selector/vue2/vue2.css';

export default {
  components: {
    BkUserSelector,
  },
};

📖 使用示例

基本用法

<template>
  <!-- 单选模式 -->
  <BkUserSelector
    v-model="selectedUser"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    :current-user-id="currentUserId"
    @change="handleUserChange"
  />

  <!-- 多选模式 -->
  <BkUserSelector
    v-model="selectedUsers"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    :current-user-id="currentUserId"
    :multiple="true"
    :draggable="true"
    @change="handleUsersChange"
  />
</template>

<script setup>
  import { ref } from 'vue';

  const apiBaseUrl = ref('https://api.example.com');
  const tenantId = ref('default');
  const currentUserId = ref('admin');

  // 单选选中值
  const selectedUser = ref('');
  // 多选选中值
  const selectedUsers = ref([]);

  const handleUserChange = user => {
    console.log('Selected user:', user);
  };

  const handleUsersChange = users => {
    console.log('Selected users:', users);
  };
</script>

用户组/角色模式

当需要在下拉列表中展示用户组(如角色、部门等)时:

<template>
  <BkUserSelector
    v-model="selectedUsers"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    :multiple="true"
    :user-group="userGroup"
    :user-group-name="userGroupName"
    @change="handleChange"
  />
</template>

<script setup>
  import { ref } from 'vue';

  const apiBaseUrl = ref('https://api.example.com');
  const tenantId = ref('default');
  const selectedUsers = ref([]);

  // 用户组配置
  const userGroup = ref([
    {
      id: '1',
      name: '运维人员',
      hidden: true, // hidden 为 true 时,不会展示在下拉列表里,但回显时会展示
    },
    {
      id: '2',
      name: '产品人员',
    },
  ]);
  const userGroupName = ref('角色');

  const handleChange = users => {
    console.log('Selected:', users);
  };
</script>

最近选择

业务只需传入最近选择用户 ID,组件会自动补全并展示在下拉右侧:

<template>
  <BkUserSelector
    v-model="selectedUsers"
    :api-base-url="apiBaseUrl"
    :multiple="true"
    :recent-user-ids="recentUserIds"
  />
</template>

<script setup>
  import { ref } from 'vue';

  const apiBaseUrl = ref('https://api.example.com');
  const selectedUsers = ref([]);
  const recentUserIds = ref(['admin', 'operator']);
</script>

自定义渲染

支持自定义标签和列表项的渲染:

<template>
  <BkUserSelector
    v-model="selectedUsers"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    :multiple="true"
    :render-tag="renderTag"
    :render-list-item="renderListItem"
  />
</template>

<script setup>
  import { ref, h } from 'vue';

  const apiBaseUrl = ref('https://api.example.com');
  const tenantId = ref('default');
  const selectedUsers = ref([]);

  // 自定义标签渲染
  const renderTag = (createElement, userInfo) => {
    return createElement('span', { class: 'custom-tag' }, [
      createElement('img', { src: userInfo.logo, class: 'avatar' }),
      userInfo.display_name,
    ]);
  };

  // 自定义列表项渲染
  const renderListItem = (createElement, userInfo) => {
    return createElement('div', { class: 'custom-item' }, [
      createElement('img', { src: userInfo.logo, class: 'avatar' }),
      createElement('div', { class: 'info' }, [
        createElement('span', { class: 'name' }, userInfo.display_name),
        createElement('span', { class: 'username' }, `@${userInfo.username}`),
      ]),
    ]);
  };
</script>

自定义输入

当 API 无法覆盖所有用户时,允许用户自定义输入:

<template>
  <BkUserSelector
    v-model="selectedUsers"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    :multiple="true"
    :allow-create="true"
    :free-paste="true"
    placeholder="输入用户名,按 Enter 确认"
    @change="handleChange"
  />
</template>

<script setup>
  import { ref } from 'vue';

  const apiBaseUrl = ref('https://api.example.com');
  const tenantId = ref('default');
  const selectedUsers = ref([]);

  const handleChange = users => {
    // 自定义输入的用户 id 为输入的文本
    console.log('Selected:', users);
  };
</script>

多行输入模式(Textarea)

当需要展示大量已选用户时,可使用 textarea 模式完整展示所有标签:

<template>
  <BkUserSelector
    v-model="selectedUsers"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    :multiple="true"
    type="textarea"
    :rows="4"
    :resize="true"
    @change="handleChange"
  />
</template>

<script setup>
  import { ref } from 'vue';

  const apiBaseUrl = ref('https://api.example.com');
  const tenantId = ref('default');
  const selectedUsers = ref([]);

  const handleChange = users => {
    console.log('Selected:', users);
  };
</script>

复制全部与删除全部

多选模式下可按需开启批量操作。存在已选人员时,组件右侧会展示“复制全部”和“删除全部”:

<BkUserSelector
  v-model="selectedUsers"
  :api-base-url="apiBaseUrl"
  :multiple="true"
  :show-copy-all="true"
  :show-delete-all="true"
/>

“复制全部”会按当前顺序复制 v-model 中的全部用户 ID,并使用英文分号连接,可直接粘贴回组件,复制成功或失败时通过 Message 提示结果;“删除全部”会先进行二次确认,确认后清空已选人员并正常触发 update:modelValue、change 和校验。

排除指定用户

从下拉列表中排除特定用户:

<template>
  <BkUserSelector
    v-model="selectedUser"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    :exclude-user-ids="excludeUserIds"
  />
</template>

<script setup>
  import { ref } from 'vue';

  const apiBaseUrl = ref('https://api.example.com');
  const tenantId = ref('default');
  const selectedUser = ref('');

  // 排除这些用户,不会出现在搜索结果中
  const excludeUserIds = ref(['user1', 'user2', 'user3']);
</script>

📋 API 文档

Props 属性

参数 说明 类型 默认值 必填
modelValue / v-model 绑定值,单选为字符串,多选为数组 string / string[] '' / [] 是
apiBaseUrl API 基础 URL string '' 是
tenantId 租户 ID string 'default' 否
hasAvatar 是否显示头像 boolean false 否
avatarBaseUrl 头像基础 URL string `` 否
label 文本标签 string '人员选择' 否
placeholder 占位文本 string '请输入人员名称搜索' 否
multiple 是否多选 boolean false 否
draggable 是否可拖拽排序(仅多选模式有效) boolean false 否
exactSearchKey 精确查找 key 'bk_username' / 'login_name' / 'full_name' 'bk_username' 否
currentUserId 当前用户 ID(用于快速选择"我") string '' 否
userGroup 用户组列表 UserGroupItem[] [] 否
userGroupName 用户组分类名称 string '用户群组' 否
emptyText 无匹配人员时的提示文本 string '无匹配人员' 否
disabled 是否禁用 boolean false 否
disabledUserIds 禁用的用户 ID 或 exactSearchKey 字段值列表,用户仍展示但不可选择 string[] [] 否
renderTag 自定义标签渲染函数 (h, userInfo) => VNode - 否
renderListItem 自定义列表项渲染函数 (h, userInfo) => VNode - 否
excludeUserIds 排除的用户 ID 列表 string[] [] 否
recentUserIds 最近选择用户 ID 列表,传入后在下拉右侧展示最近选择 string[] [] 否
enableMultiTenantMode 是否启用多租户模式 boolean true 否
allowCreate 是否允许自定义输入,按 Enter 确认 boolean false 否
freePaste 是否允许粘贴任意文本 boolean false 否
maxCount 最大可选数量(0 表示不限制) number 0 否
mode 展示模式,cell 为可编辑表格单元格简洁模式 'default' / 'cell' 'default' 否
rules 校验规则,调用 validate / getValue 时执行 ValidationRule[] [] 否
type 输入框类型 'input' / 'textarea' 'input' 否
rows 默认行数(仅 textarea 模式生效) number 4 否
resize 是否允许拖拽调整高度(仅 textarea 模式生效) boolean true 否
autoHeight 聚焦后标签换行时是否允许组件高度自适应(cell 模式下不生效) boolean false 否
autoFocus 是否自动聚焦 boolean false 否
showCopyAll 是否展示复制全部操作(仅多选且存在已选人员时生效) boolean false 否
showDeleteAll 是否展示删除全部操作(仅多选且存在已选人员时生效) boolean false 否
exactSearchKey 说明

支持多个字段组合搜索,以逗号分隔:

值 说明
bk_username 按蓝鲸用户名搜索
login_name 按登录名搜索
full_name 按全名搜索
bk_username,full_name 同时按用户名和全名搜索

Events 事件

事件名称 说明 回调参数
update:modelValue 绑定值变化时触发 (value: string | string[])
change 选中值变化时触发 (userInfo: UserInfo | UserInfo[])
focus 输入框获得焦点时触发 -
blur 输入框失去焦点时触发 -
error 任意接口请求失败时触发(包含 401、网络错误等),业务可在此弹 Message、上报 Sentry (error: ApiError)
unauthorized 登录态失效(HTTP 401)时触发,同时也会触发 error,业务可在此跳转登录或刷新 token (error: ApiError)

Methods 方法

通过模板 ref 调用组件方法:

方法名 说明 参数
focus 使组件聚焦 -
blur 使组件失焦 -
validate 执行 rules 校验,返回 Promise<boolean> -
getValue 校验并返回当前 v-model 值,失败时 reject Error -
<template>
  <BkUserSelector
    ref="selectorRef"
    v-model="value"
    :api-base-url="apiBaseUrl"
  />
  <button @click="selectorRef?.focus()">聚焦</button>
  <button @click="selectorRef?.blur()">失焦</button>
</template>

<script setup>
  import { ref } from 'vue';
  const selectorRef = ref(null);
  const value = ref('');
  const apiBaseUrl = 'https://api.example.com';
</script>

可编辑表格简洁模式

<BkUserSelector
  ref="selectorRef"
  v-model="owners"
  mode="cell"
  multiple
  :api-base-url="apiBaseUrl"
  :rules="[{ validator: value => Array.isArray(value) && value.length > 0, message: '请选择人员' }]"
/>

类型定义

// 用户信息
interface UserInfo {
  id: string; // 用户 ID
  username: string; // 用户名
  display_name: string; // 显示名称
  logo?: string; // 头像 URL
  tenant_id?: string; // 租户 ID
  // ... 其他字段
}

// 用户组项
interface UserGroupItem {
  id: string; // 用户组 ID
  name: string; // 用户组名称
  hidden?: boolean; // 是否隐藏(不在下拉列表显示,但会在回显时展示)
}

// 自定义渲染函数
type RenderFunction = (
  h: CreateElement, // Vue createElement 函数
  userInfo: UserInfo, // 用户信息
) => VNode;

// 接口错误
interface ApiError {
  scene: string; // 业务场景,如 '搜索用户'、'批量查找用户'
  cause: unknown; // 原始错误对象
  status?: number; // HTTP 状态码(网络错误时为 undefined)
  isUnauthorized: boolean; // 是否为登录态失效(HTTP 401)
}

🛡️ 错误处理

组件遵循「不强依赖 UI 反馈」的设计原则,接口失败时不会自动弹 Message,而是通过事件向业务侧暴露错误,由业务自行决定弹消息、上报监控或静默处理。

<template>
  <BkUserSelector
    v-model="selectedUser"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    @error="handleApiError"
    @unauthorized="handleUnauthorized"
  />
</template>

<script setup lang="ts">
  import { Message } from 'bkui-vue';

  import type { ApiError } from '@blueking/bk-user-selector';

  const handleApiError = (err: ApiError) => {
    // 401 不需要重复弹 Message,由 unauthorized 单独处理
    if (err.isUnauthorized) return;
    Message({ theme: 'error', message: `${err.scene}失败,请稍后重试` });
    // 也可以上报 Sentry / 蓝鲸监控
    // sentry.captureException(err.cause, { extra: { scene: err.scene, status: err.status } });
  };

  const handleUnauthorized = (err: ApiError) => {
    location.href = `/login?next=${encodeURIComponent(location.href)}`;
  };
</script>

行为说明:

  • 失败统一构造 ApiError,已通过 console.error 打印兜底日志
  • 401 会同时触发 unauthorized 和 error 事件,便于业务统一收口或独立处理
  • 业务回调如果抛错不会影响组件正常流程

💡 功能说明

快速选择"我"

当设置了 currentUserId 属性后,组件会在输入框右侧显示一个"我"的标签:

  • 单选模式:点击"我"直接选中当前用户
  • 多选模式:点击"我"将当前用户添加到已选列表
  • 状态反馈:当前用户已被选中时,"我"标签显示为灰色且不可点击

用户组显示

当设置了 userGroup 属性后:

  • 用户组会显示在下拉列表的独立分组中(默认名称为"用户群组")
  • 用户组数据优先展示在列表顶部
  • 聚焦时会自动展示下拉框
  • 设置 hidden: true 的用户组不会在下拉列表中显示,但选中后会正常回显

多租户模式

通过 enableMultiTenantMode 控制:

  • 开启(默认):使用多租户用户管理接口查询,支持跨租户显示
  • 关闭:使用原有用户管理接口查询

多行输入模式(Textarea)

通过 type="textarea" 启用多行模式:

  • 完整展示:未聚焦时不折叠标签,完整展示所有已选用户
  • 高度可配:通过 rows 设置默认行数,每行约 32px
  • 可拖拽调整:默认允许拖拽调整容器高度,可通过 resize=false 禁用
  • 自动滚动:内容超出容器高度时自动出现滚动条
  • 聚焦同步:切换聚焦/失焦状态时自动同步容器高度

输入框高度自适应

输入框模式默认保持 32px 固定高度,聚焦后的多行标签会浮层展开且不占用布局高度。需要让后续内容随标签换行下移时,可通过 autoHeight=true 让组件高度自适应;cell 模式不受该属性影响。

拖拽排序

在多选模式下启用 draggable:

  • 支持拖拽调整已选用户的顺序
  • 拖拽时会有视觉反馈
  • 拖拽完成后会触发 change 事件

键盘导航

组件支持完整的键盘操作:

按键 功能
↑ / ↓ 在下拉列表中切换高亮选项
Enter 选中当前高亮的选项(allowCreate=true 时创建自定义用户)
← / → 在已选标签之间移动光标
Backspace 删除光标前的已选用户
  • 输入搜索内容后,第一个选项会自动高亮
  • 高亮选项会自动滚动到可视区域
  • 支持用户组、普通用户、虚拟账号的键盘选择
  • 中文等输入法组词期间,键盘操作仅用于输入法,不会触发标签删除或选项选择

⚠️ 注意事项

  1. API 配置:使用前必须正确配置 apiBaseUrl 和 tenantId
  2. CSS 引入:记得引入对应版本的样式文件
  3. v-model 类型:
    • 单选模式:v-model 应为 string 类型
    • 多选模式:v-model 应为 string[] 类型
  4. 跨租户显示:跨租户用户会在名称旁显示租户标识
  5. 自定义输入:启用 allowCreate 后,用户输入的内容会作为 id 值
  6. 批量粘贴限制:单选只会保留查询结果中的一个人,需要先开启多选;单次粘贴最多处理 100 个用户标识,超出部分会被截断;不是 login_name 的文本默认不会加入,需要同时开启 freePaste;批量精准查询按后端限制分批执行(每批最多 100 个)

❓ FAQ

Q: 组件没有样式怎么办?

A: 请确保引入了对应版本的 CSS 文件:

// Vue3
import '@blueking/bk-user-selector/vue3/vue3.css';

// Vue2
import '@blueking/bk-user-selector/vue2/vue2.css';

Q: 如何禁止选择某些用户?

A: 如果希望用户不出现在搜索结果中,使用 excludeUserIds;如果希望用户仍展示但不可选择,使用 disabledUserIds。

Q: 如何获取完整的用户信息?

A: 通过 change 事件获取,它会返回完整的用户信息对象,而不仅仅是 ID。

Q: 多选模式下如何限制选择数量?

A: 使用 maxCount 属性设置最大可选数量,0 表示不限制。

Q: 一次粘贴很多用户,为什么没有全部添加?

A: 常见原因有三类:

  • 单选(multiple 为 false)只会保留查询结果中的一个人,需要先开启多选。
  • 单次粘贴最多处理 100 个用户标识,超出部分会被截断;如需导入更多用户,请分批粘贴。
  • 不是 login_name 的文本(例如「TAPD助手」)默认不会加入,需要同时开启 freePaste。

Q: 搜索没有结果怎么办?

A: 检查以下几点:

  1. apiBaseUrl 和 tenantId 是否正确配置
  2. 网络请求是否正常
  3. 搜索关键词是否匹配 exactSearchKey 配置的字段

🛠️ 开发

# 安装依赖
pnpm install

# 开发模式
pnpm run dev

# 构建
pnpm run build

# 类型检查
pnpm run type-check

📄 许可证

MIT © 蓝鲸智云

Related Packages

@blueking/table

蓝鲸 Table

8,037
@blueking/functional-dependency

蓝鲸通用功能依赖展示

6,698
@blueking/bkflow-canvas-editor-vue2

Vue 2.7 适配层,在 Vue 2 项目中使用 @blueking/bkflow-canvas-editor(内置 Vue 3...

6,227

Version History

Version Released License
0.1.15 MIT
0.1.14 MIT
0.1.13 MIT
0.1.12 MIT
0.1.11 MIT
Pre-releases (31)
Version Released License
0.1.3-beta.1 MIT
0.1.1-beta.4 MIT
0.1.1-beta.3 MIT
0.1.1-beta.2 MIT
0.1.1-beta.1 MIT