@blueking/bk-org-selector

蓝鲸多租户组织架构选择器
8,279
Install
npm install @blueking/bk-org-selector
Latest Version:0.5.7
Older releases:3
License:MIT
Last Updated:Sep 14, 2026
Links: npm
Maintainer: blueking-magicbox

蓝鲸多租户组织选择器

npm version License

蓝鲸多租户组织选择器是一个用于选择组织架构的 Vue 组件,支持 Vue2 和 Vue3 双版本,适用于蓝鲸智云平台的多租户场景。

✨ 特性

  • 🎯 双版本支持 - 同时支持 Vue2 和 Vue3
  • 🌲 组织架构树形展示 - 清晰展示多层级组织结构
  • 👥 人员选择 - 支持选择普通用户和虚拟账号
  • 🏢 多租户支持 - 支持跨租户协同场景
  • 🔍 搜索功能 - 支持组织名称搜索;开启选人能力后可搜索用户 / 虚拟账号
  • 📋 批量录入 - 支持批量粘贴用户名/虚拟账号名快速添加
  • 🪟 内联模式 - 支持免弹框直接嵌入页面的选择面板
  • 👤 仅选人员 - 可保留组织树浏览能力,同时禁止选择组织
  • 🚫 禁选节点 - 可禁止新增选择指定组织或人员,不级联子节点
  • 🙈 黑名单隐藏 - 可隐藏指定组织及其子孙、指定人员
  • ✅ 叶子组织限制 - 可限制组织选择到最小组级别
  • 🌐 国际化 - 内置中英文语言包
  • 📝 TypeScript - 完整的类型定义支持
  • 🎨 自定义渲染 - 支持自定义空状态和结果展示

📦 安装

npm install @blueking/bk-org-selector @blueking/bkui-library
# 或
pnpm add @blueking/bk-org-selector @blueking/bkui-library

依赖说明:

  • peer:@blueking/bkui-library(^0.0.0-beta.4),需引入样式(如 style.variable.css)
  • 建议:bkui-vue >= 2.0.2-beta.110(Dialog 无 title / 空 header 时不再渲染空 header;更低版本在 dialog 模式下顶部可能多约 46px 空白,不影响功能)

🚀 快速开始

Vue3 版本

<template>
  <bk-org-selector
    v-model="selectedOrg"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    has-user
    @change="handleChange"
    @confirm="handleConfirm"
  />
</template>

<script setup lang="ts">
  import { ref } from 'vue';
  import BkOrgSelector from '@blueking/bk-org-selector';
  import '@blueking/bk-org-selector/vue3/vue3.css';

  import type { TreeItem } from '@blueking/bk-org-selector';

  const apiBaseUrl = 'https://your-api-domain.com';
  const tenantId = 'your-tenant-id';
  const selectedOrg = ref<TreeItem[]>([]);

  const handleChange = (value: TreeItem[]) => {
    console.log('选中数据变化:', value);
  };

  const handleConfirm = (result: any) => {
    console.log('确认选择:', result);
  };
</script>

Vue2 版本

<template>
  <bk-org-selector
    v-model="selectedOrg"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    has-user
    @change="handleChange"
    @confirm="handleConfirm"
  >
    <bk-button>请选择组织或人员</bk-button>
  </bk-org-selector>
</template>

<script>
  import BkOrgSelector from '@blueking/bk-org-selector/vue2';
  import '@blueking/bk-org-selector/vue2/vue2.css';

  export default {
    components: {
      BkOrgSelector,
    },
    data() {
      return {
        apiBaseUrl: 'https://your-api-domain.com',
        tenantId: 'your-tenant-id',
        selectedOrg: [],
      };
    },
    methods: {
      handleChange(value) {
        console.log('选中数据变化:', value);
      },
      handleConfirm(result) {
        console.log('确认选择:', result);
      },
    },
  };
</script>

批量录入模式

通过 has-batch-input 启用批量录入能力,在弹窗左侧面板顶部显示「组织架构 / 批量录入」Tab 切换,支持通过粘贴用户名或虚拟账号名批量添加。

<template>
  <bk-org-selector
    v-model="selectedOrg"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    has-batch-input
    has-user
    has-virtual-users
    @confirm="handleConfirm"
  />
</template>

批量录入特性:

  • 支持回车、分号、逗号、空格等多种分隔符
  • 自动去除括号中的备注信息(如 zhangsan(张三) → zhangsan)
  • 通过 login_name 字段精确匹配用户
  • 解析结果支持全选/单选,勾选后添加到右侧结果预览
  • 未匹配的用户名会显示警告提示
  • 当前仅支持批量添加用户和虚拟账号,不支持批量添加组织
  • 中文等输入法组词期间,键盘操作不会触发弹窗关闭等全局快捷键

仅选择人员

同时开启 has-user 和 only-user-selectable 后,组织节点仍可浏览、搜索和展开,但只能新增选择人员,不能新增选择组织。

<template>
  <bk-org-selector
    v-model="selectedOrg"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    has-user
    only-user-selectable
  />
</template>

已有组织值仍会保留展示并允许取消;虚拟账号是否可选仍由 has-virtual-users 控制。

禁选指定组织或人员

通过 disabled-org-ids / disabled-user-ids 禁止新增选择指定节点。组织树、搜索和批量录入共用规则,支持动态更新。

<bk-org-selector
  v-model="selectedItems"
  :api-base-url="apiBaseUrl"
  :tenant-id="tenantId"
  has-user
  :disabled-org-ids="[1001, 1002]"
  :disabled-user-ids="['zhangsan']"
/>
  • 禁选组织仍可展开,不级联子节点
  • 历史已选项保留且可取消
  • ID 在所有租户中匹配;人员按 bk_username(含虚拟账号)
  • 存在禁选项时不可新增选择「全部人员」
  • 仅约束节点选择,不改变所选组织代表的人员范围

黑名单隐藏

通过 blacklisted-org-ids / blacklisted-user-ids 隐藏指定组织及其全部子孙、指定人员。树、搜索、批量录入及历史已选结果均过滤,黑名单优先于禁选。

<bk-org-selector
  v-model="selectedItems"
  :api-base-url="apiBaseUrl"
  :tenant-id="tenantId"
  has-user
  :blacklisted-org-ids="[1001]"
  :blacklisted-user-ids="['zhangsan']"
/>
  • 不新增请求,正常展开/搜索/查询返回后才过滤;动态修改直接重新过滤缓存
  • 后代判断依赖组织 ancestor_ids 和人员 organization_id_paths(含直属组织,支持多组织归属),ID 须与组织 id 一致
  • 不主动改写外部 v-model,后续确认/选择输出过滤后的值
  • 存在黑名单时不可全选;不改变所选父组织在业务侧代表的人员范围

字段格式详见 接口契约。

内联模式(免弹框)

通过 mode="inline" 将选择面板直接嵌在页面中,无需点击按钮打开弹窗。勾选后即时同步 v-model,不显示「确定 / 取消」按钮,也不会触发 confirm / closed。

Vue3
<template>
  <bk-org-selector
    v-model="selectedOrg"
    mode="inline"
    inline-height="480px"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    has-user
    @change="handleChange"
  />
</template>
Vue2
<template>
  <bk-org-selector
    v-model="selectedOrg"
    mode="inline"
    inline-height="480px"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    has-user
    @change="handleChange"
  />
</template>

内联模式特性:

  • 不渲染外层 Empty / Tag / Path 结果展示区,只展示「左侧组织树 + 右侧结果预览」
  • inlineHeight 默认 400px,可传 100% 交给父容器控高
  • 开启 hasSelectAll 时底部仅显示「全部人员」勾选
  • openEdit() 在内联模式下为空操作
  • Vue2 包装挂载在 div 上,父容器需有可用宽度

路径展示模式

通过 display-mode="path" 切换为路径列表展示,适用于展示已选组织/人员的层级路径,如"启用范围"等场景。

<template>
  <bk-org-selector
    v-model="selectedOrg"
    :api-base-url="apiBaseUrl"
    :tenant-id="tenantId"
    display-mode="path"
    display-width="600px"
    has-user
    @confirm="handleConfirm"
  />
</template>

路径模式特性:

  • 按类型分组展示(组织、用户、虚拟账号)
  • 显示完整组织路径,路径过长时自动截断(保留首段和末段,中间用 ... 代替)
  • 跨租户项显示橙色租户标识(如 @嘉为)
  • hover 时显示删除按钮,支持分组清空
  • 宽度支持 prop 配置 + CSS 变量 --org-path-list-width 覆盖

📖 API 文档

属性 Props

属性名 类型 默认值 必填 说明
v-model / modelValue TreeItem[] [] 是 选中的组织/人员列表,支持双向绑定
apiBaseUrl string '' 是 接口基础 URL,所有 API 请求的前缀
apiPrefix string '/api/v3/open-web/tenant' 否 API 路径前缀,用于拼接具体的 API 端点,完整请求路径为 apiBaseUrl + apiPrefix + endpoint
tenantId string 'default' 是 租户 ID,用于多租户系统的数据隔离
hasUser boolean false 否 是否可选择人员;关闭后组织树、搜索、批量录入均不可新增选人,历史已选人员可取消
hasVirtualUsers boolean false 否 是否可选择虚拟账号;关闭后租户列表、搜索、批量录入均不可新增选择虚拟账号
hasCollabTenants boolean true 否 是否展示协同租户;设为 false 时左侧租户列表与搜索结果均不展示协同租户数据
readonly boolean false 否 是否只读模式,只读时可查看已选中数据但不能编辑
disabled boolean false 否 是否禁用整个组件,禁用后所有交互功能不可用
mode string 'dialog' 否 展示形态:'dialog' 弹窗选择(默认);'inline' 页面内直接展示选择面板,勾选即时同步
inlineHeight string '400px' 否 内联模式下面板高度,支持 CSS 值如 '400px'、'100%',仅 mode="inline" 生效
displayMode string 'tag' 否 结果展示模式:'simple' 只显示标题,'tag' 标题+标签列表,'path' 标题+路径列表(仅 dialog 外层结果区)
displayWidth string - 否 结果展示区域宽度,支持 CSS 值如 '400px'、'100%',不传时跟随父容器宽度
isSimpleShow boolean false 否 是否简单展示模式(已废弃,建议使用 displayMode="simple" 替代)
checkStrictly boolean false 否 是否严格遵循父子互相关联,false 时父子节点选中状态互不影响
disableCheck boolean false 否 是否禁用勾选功能
hasBatchInput boolean false 否 是否启用批量录入,启用后弹窗左侧显示「组织架构 / 批量录入」Tab 切换
hasSelectAll boolean false 否 是否显示"全部人员"选项,启用后在弹窗底部显示全选复选框
onlyLeafOrgSelectable boolean false 否 是否只允许选择叶子组织;开启后组织节点仅在 has_child !== true 时可新增选择,用户和虚拟账号仍由原有属性控制
onlyUserSelectable boolean false 否 是否只允许新增选择人员;组织仍可浏览和展开,历史已选组织可取消,虚拟账号仍由 hasVirtualUsers 控制
disabledOrgIds Array<string | number> [] 否 禁选组织 ID,数字和字符串等价,不级联子节点
disabledUserIds string[] [] 否 禁选人员 bk_username,含虚拟账号
blacklistedOrgIds Array<string | number> [] 否 隐藏指定组织及全部子孙组织、人员;黑名单优先于禁选
blacklistedUserIds string[] [] 否 隐藏指定人员 bk_username,含虚拟账号
zIndex number 自动计算 否 弹窗层级(z-index)
renderEmpty Function - 否 空状态自定义渲染函数
renderResult Function - 否 结果区域自定义渲染函数
avatarBaseUrl string '' 否 头像基础 URL,用于拼接用户头像地址
showHoverPath boolean false 否 是否在 hover 树节点时以 Popover 展示组织路径,路径通过接口获取,带缓存
virtualRender boolean false 否 是否启用虚拟渲染,启用后树组件使用虚拟滚动,适用于大数据量场景;组件会根据弹窗可用空间自动计算树高度

事件 Events

事件名 回调参数 说明
change (value: TreeItem[]) 选择值变化时触发(dialog 确认后 / inline 勾选后)
changeResult (result: ResultItem[]) 格式化后的结果变化时触发
confirm (result: ResultItem[]) 点击确认按钮时触发(仅 dialog 模式)
closed - 弹窗关闭时触发(仅 dialog 模式)
update:modelValue (value: TreeItem[]) v-model 更新事件
error (error: ApiError) 任意接口请求失败时触发(包含 401、网络错误、超时、5xx 等),业务可在此弹 Message、上报 Sentry
unauthorized (error: ApiError) 登录态失效(HTTP 401)时触发,同时也会触发 error,业务可在此跳转登录或刷新 token

方法 Methods

通过 ref 获取组件实例后可调用以下方法:

方法名 参数 说明
openEdit - 打开编辑弹窗(mode="inline" 时为空操作)
handleDeleteItem (item: TreeItem, needConfirm?: boolean) 删除单个选中项
handleDeleteAll (type: string, needConfirm?: boolean) 删除指定类型的所有选中项
destroy - 销毁组件,清理所有状态
<template>
  <bk-org-selector
    ref="selectorRef"
    ...
  />
  <button @click="openSelector">打开选择器</button>
</template>

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

  const selectorRef = ref();

  const openSelector = () => {
    selectorRef.value?.openEdit();
  };
</script>

📋 数据结构

TreeItem

选中项的数据结构:

interface TreeItem {
  /** 节点 ID */
  id: number | string;
  /** 节点名称 */
  name?: string;
  /** 节点类型:'org' 组织 | 'user' 用户 | 'virtual' 虚拟账号 | 'all' 全部人员 */
  type: 'org' | 'user' | 'virtual' | 'all';
  /** 所属租户 ID */
  owner_tenant_id?: string;
  /** 用户名(用户类型专用) */
  bk_username?: string;
  /** 显示名称 */
  display_name?: string;
  /** 组织路径 */
  organization_path?: string;
  /** 是否有子节点 */
  has_child?: boolean;
  /** 子节点列表 */
  children?: TreeItem[];
}

ResultItem

格式化后的结果数据结构:

interface ResultItem {
  /** 分组名称,如 '组织'、'用户'、'虚拟账号' */
  name: string;
  /** 分组类型 */
  type: 'org' | 'user' | 'virtual' | 'all';
  /** 该分组下的数据列表 */
  data: Array<{
    id: number | string;
    name?: string;
    owner_tenant_id?: string;
  }>;
}

ApiError

接口失败回调中的错误对象:

interface ApiError {
  /** 业务场景描述,如 '查询部门子部门信息'、'批量查找用户' */
  scene: string;
  /** 原始错误对象(Error 实例或网络异常等) */
  cause: unknown;
  /** HTTP 状态码(仅在响应已到达时存在;网络错误/超时等情况下为 undefined) */
  status?: number;
  /** 已重试次数(含本次失败),0 表示首次失败 */
  retryCount: number;
  /** 是否为登录态失效(HTTP 401) */
  isUnauthorized: boolean;
}

🛡️ 错误处理

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

监听接口错误

<template>
  <bk-org-selector
    v-model="selectedOrg"
    :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-org-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 打印兜底日志
  • 网络错误、超时、5xx 错误会自动重试(最多 3 次,指数退避),最终失败才会触发 error
  • retryCount 反映重试次数,status 为最终的 HTTP 状态码(网络错误/超时时为 undefined)
  • 业务回调如果抛错不会影响组件正常流程

在非组件场景使用

直接调用 API 函数时(例如在 store 或工具函数中),可通过 apiConfig 传入回调:

import { searchOrgs } from '@blueking/bk-org-selector';

const orgs = await searchOrgs('xxx', {
  apiBaseUrl: 'https://...',
  tenantId: 'default',
  apiPrefix: '/api/v3/open-web/tenant',
  avatarBaseUrl: '',
  allowedApiOrigins: [],
  allowPrivateApiHost: false,
  allowCrossOriginCredentials: false,
  onError: err => console.error('[org-api]', err.scene, err.cause),
  onUnauthorized: () => (location.href = '/login'),
});

🎨 自定义渲染

自定义空状态

<template>
  <bk-org-selector
    v-model="selectedOrg"
    :render-empty="renderEmpty"
    ...
  />
</template>

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

  const renderEmpty = createElement => {
    return createElement('div', { class: 'custom-empty' }, [createElement('span', '点击选择组织或人员')]);
  };
</script>

自定义结果展示

<template>
  <bk-org-selector
    v-model="selectedOrg"
    :render-result="renderResult"
    ...
  />
</template>

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

  const renderResult = (createElement, props) => {
    const { result } = props;
    return createElement('div', { class: 'custom-result' }, [createElement('span', `已选择 ${result.length} 项`)]);
  };
</script>

🌐 国际化

组件内置中英文语言包,会自动根据 blueking_language Cookie 值切换语言:

  • Cookie 值为 en 时使用英文
  • 其他情况默认使用中文

支持的文案包括:

  • 选择组织、结果预览、确定、取消等操作文案
  • 组织、用户、虚拟账号等类型名称
  • 搜索提示和空状态文案

📁 目录结构

@blueking/bk-org-selector
├── vue3/               # Vue3 构建产物
│   ├── index.es.min.js
│   └── vue3.css
├── vue2/               # Vue2 构建产物
│   ├── index.es.min.js
│   └── vue2.css
└── typings/            # TypeScript 类型定义
    ├── vue3.d.ts
    └── vue2.d.ts

🔧 环境要求

  • Node.js: >= 18.16.0
  • Vue 3: >= 3.0.0
  • Vue 2: >= 2.6.0

🤝 贡献

欢迎提交 Issue 和 Pull Request 来帮助改进这个项目。

📄 许可证

MIT License © Tencent BlueKing

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.5.7 MIT
0.5.6 MIT
0.5.5 MIT
0.5.4 MIT
0.5.3 MIT
Pre-releases (8)
Version Released License
0.0.23-beta.5 MIT
0.0.23-beta.4 MIT
0.0.23-beta.3 MIT
0.0.23-beta.2 MIT
0.0.23-beta.1 MIT