@blueking/bk-user-selector
v0.1.6
Published
蓝鲸用户选择器
Readme
蓝鲸多租户人员选择器组件
蓝鲸多租户人员选择器(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>自定义渲染
支持自定义标签和列表项的渲染:
<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>排除指定用户
从下拉列表中排除特定用户:
<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 | 否 |
| renderTag | 自定义标签渲染函数 | (h, userInfo) => VNode | - | 否 |
| renderListItem | 自定义列表项渲染函数 | (h, userInfo) => VNode | - | 否 |
| excludeUserIds | 排除的用户 ID 列表 | string[] | [] | 否 |
| enableMultiTenantMode | 是否启用多租户模式 | boolean | true | 否 |
| allowCreate | 是否允许自定义输入,按 Enter 确认 | boolean | false | 否 |
| freePaste | 是否允许粘贴任意文本 | boolean | false | 否 |
| maxCount | 最大可选数量(0 表示不限制) | number | 0 | 否 |
| type | 输入框类型 | 'input' / 'textarea' | 'input' | 否 |
| rows | 默认行数(仅 textarea 模式生效) | number | 4 | 否 |
| resize | 是否允许拖拽调整高度(仅 textarea 模式生效) | boolean | true | 否 |
| autoFocus | 是否自动聚焦 | 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 | 输入框失去焦点时触发 | - |
Methods 方法
通过模板 ref 调用组件方法:
| 方法名 | 说明 | 参数 | | ------ | ---------- | ---- | | focus | 使组件聚焦 | - | | blur | 使组件失焦 | - |
<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>类型定义
// 用户信息
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;💡 功能说明
快速选择"我"
当设置了 currentUserId 属性后,组件会在输入框右侧显示一个"我"的标签:
- 单选模式:点击"我"直接选中当前用户
- 多选模式:点击"我"将当前用户添加到已选列表
- 状态反馈:当前用户已被选中时,"我"标签显示为灰色且不可点击
用户组显示
当设置了 userGroup 属性后:
- 用户组会显示在下拉列表的独立分组中(默认名称为"用户群组")
- 用户组数据优先展示在列表顶部
- 聚焦时会自动展示下拉框
- 设置
hidden: true的用户组不会在下拉列表中显示,但选中后会正常回显
多租户模式
通过 enableMultiTenantMode 控制:
- 开启(默认):使用多租户用户管理接口查询,支持跨租户显示
- 关闭:使用原有用户管理接口查询
多行输入模式(Textarea)
通过 type="textarea" 启用多行模式:
- 完整展示:未聚焦时不折叠标签,完整展示所有已选用户
- 高度可配:通过
rows设置默认行数,每行约 32px - 可拖拽调整:默认允许拖拽调整容器高度,可通过
resize=false禁用 - 自动滚动:内容超出容器高度时自动出现滚动条
- 聚焦同步:切换聚焦/失焦状态时自动同步容器高度
拖拽排序
在多选模式下启用 draggable:
- 支持拖拽调整已选用户的顺序
- 拖拽时会有视觉反馈
- 拖拽完成后会触发
change事件
键盘导航
组件支持完整的键盘操作:
| 按键 | 功能 |
| ----------- | --------------------------------------------------------- |
| ↑ / ↓ | 在下拉列表中切换高亮选项 |
| Enter | 选中当前高亮的选项(allowCreate=true 时创建自定义用户) |
| ← / → | 在已选标签之间移动光标 |
| Backspace | 删除光标前的已选用户 |
- 输入搜索内容后,第一个选项会自动高亮
- 高亮选项会自动滚动到可视区域
- 支持用户组、普通用户、虚拟账号的键盘选择
⚠️ 注意事项
- API 配置:使用前必须正确配置
apiBaseUrl和tenantId - CSS 引入:记得引入对应版本的样式文件
- v-model 类型:
- 单选模式:
v-model应为string类型 - 多选模式:
v-model应为string[]类型
- 单选模式:
- 跨租户显示:跨租户用户会在名称旁显示租户标识
- 自定义输入:启用
allowCreate后,用户输入的内容会作为id值
❓ 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 属性传入需要排除的用户 ID 数组。
Q: 如何获取完整的用户信息?
A: 通过 change 事件获取,它会返回完整的用户信息对象,而不仅仅是 ID。
Q: 多选模式下如何限制选择数量?
A: 使用 maxCount 属性设置最大可选数量,0 表示不限制。
Q: 搜索没有结果怎么办?
A: 检查以下几点:
apiBaseUrl和tenantId是否正确配置- 网络请求是否正常
- 搜索关键词是否匹配
exactSearchKey配置的字段
🛠️ 开发
# 安装依赖
pnpm install
# 开发模式
pnpm run dev
# 构建
pnpm run build
# 类型检查
pnpm run type-check📄 许可证
MIT © 蓝鲸智云
