@blueking/bk-user-selector 0.0.39-beta.3 → 0.1.1-beta.1

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.
@@ -3,589 +3,228 @@
3
3
  })(this, function(exports2, vue, bkuiVue) {
4
4
  "use strict";
5
5
  var __vite_style__ = document.createElement("style");
6
- __vite_style__.textContent = ".me-tag[data-v-ef4a05c4] {\n position: absolute;\n top: 50%;\n right: 8px;\n z-index: 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0 8px;\n font-size: 12px;\n color: #4d4f56;\n white-space: nowrap;\n cursor: pointer;\n background-color: #e1ecff;\n border-radius: 50%;\n transform: translateY(-50%);\n}\n.me-tag[data-v-ef4a05c4]:hover {\n color: #3a84ff;\n background-color: #cddffe;\n}\n.me-tag.disabled[data-v-ef4a05c4] {\n color: #c4c6cc;\n cursor: not-allowed;\n background-color: #f0f1f5;\n}.dropdown-content[data-v-78875ea6] {\n min-height: 40px;\n max-height: 300px;\n padding: 5px 0;\n overflow-y: auto;\n}\n.dropdown-content .no-data[data-v-78875ea6] {\n padding: 10px;\n color: #979ba5;\n text-align: center;\n}\n.dropdown-content .user-group .group-header[data-v-78875ea6] {\n display: flex;\n align-items: center;\n padding: 8px 12px;\n color: #979ba5;\n}\n.dropdown-content .user-group .group-header .group-count[data-v-78875ea6] {\n margin-left: 4px;\n}\n.dropdown-content .user-option[data-v-78875ea6] {\n display: flex;\n align-items: center;\n height: 32px;\n padding: 8px 12px;\n cursor: pointer;\n}\n.dropdown-content .user-option[data-v-78875ea6]:hover {\n background-color: #f5f7fa;\n}.user-tag[data-v-48ac8fc1] {\n margin-right: 4px;\n margin-left: 0;\n}\n.user-tag.draggable[data-v-48ac8fc1] {\n cursor: move;\n}\n.user-tag.active[data-v-48ac8fc1] {\n background-color: #e1ecff;\n border-color: #3a84ff;\n}\n.user-tag.is-custom[data-v-48ac8fc1] {\n color: #ea3636;\n background-color: #feebea;\n border-color: rgba(234, 53, 54, 0.3019607843);\n}\n.user-tag.is-custom[data-v-48ac8fc1]:hover {\n background-color: #fedddc;\n}\n.user-tag .tag-content .user-name[data-v-48ac8fc1] {\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: 12px;\n white-space: nowrap;\n}.multiple-selector[data-v-2a532f24] {\n position: relative;\n width: 100%;\n}\n.multiple-selector.is-disabled[data-v-2a532f24] {\n pointer-events: none;\n}\n.multiple-selector .tags-container[data-v-2a532f24] {\n min-height: 32px;\n padding: 1px 10px 1px 8px;\n background-color: #fff;\n border: 1px solid #c4c6cc;\n border-radius: 2px;\n transition: all 0.2s ease;\n}\n.multiple-selector .tags-container.focused[data-v-2a532f24] {\n border-color: #3a84ff;\n box-shadow: 0 0 0 2px rgba(58, 132, 255, 0.1);\n}\n.multiple-selector .tags-container.collapsed[data-v-2a532f24] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n}\n.multiple-selector .tag-list[data-v-2a532f24] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n}\n.multiple-selector .tag-wrapper[data-v-2a532f24] {\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n}\n.multiple-selector .search-input[data-v-2a532f24] {\n min-width: 10px;\n height: 28px;\n outline: none;\n background: transparent;\n border: none;\n}\n.multiple-selector .search-input[data-v-2a532f24]::placeholder {\n color: #c4c6cc;\n}\n.multiple-selector .search-input.inline[data-v-2a532f24] {\n min-width: 10px;\n}\n.multiple-selector .search-input.last[data-v-2a532f24], .multiple-selector .search-input.collapsed[data-v-2a532f24] {\n flex: 1;\n}\n.hidden-users[data-v-2a532f24] {\n padding: 6px 10px;\n}.single-selector[data-v-cbe352a6] {\n position: relative;\n width: 100%;\n}\n.single-selector.is-disabled[data-v-cbe352a6] {\n pointer-events: none;\n}\n.input-container[data-v-cbe352a6] {\n position: relative;\n display: flex;\n align-items: center;\n min-height: 32px;\n padding: 0 8px;\n background-color: #fff;\n border: 1px solid #c4c6cc;\n border-radius: 2px;\n}\n.input-container[data-v-cbe352a6]:focus-within {\n border-color: #3a84ff;\n box-shadow: 0 0 0 2px rgba(58, 132, 255, 0.1);\n}\n.search-input[data-v-cbe352a6] {\n flex: 1;\n height: 30px;\n outline: none;\n background: transparent;\n border: none;\n}\n.search-input[data-v-cbe352a6]::placeholder {\n color: #c4c6cc;\n}.bk-user-selector[data-v-9c628c83] {\n position: relative;\n width: 100%;\n font-size: 12px;\n}\n.bk-user-selector.is-disabled[data-v-9c628c83] {\n cursor: not-allowed;\n background-color: #dcdee5;\n}.bk-user-selector-popover {\n padding: 0 !important;\n}";
6
+ __vite_style__.textContent = ".me-tag[data-v-4f251ce1] {\n position: absolute;\n top: 50%;\n right: 8px;\n z-index: 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0 8px;\n font-size: 12px;\n color: #4d4f56;\n white-space: nowrap;\n cursor: pointer;\n background-color: #e1ecff;\n border-radius: 50%;\n transform: translateY(-50%);\n}\n.me-tag[data-v-4f251ce1]:hover {\n color: #3a84ff;\n background-color: #cddffe;\n}\n.me-tag.disabled[data-v-4f251ce1] {\n color: #c4c6cc;\n cursor: not-allowed;\n background-color: #f0f1f5;\n}.dropdown-content[data-v-d5a338f0] {\n min-height: 40px;\n max-height: 300px;\n padding: 5px 0;\n overflow-y: auto;\n}\n.dropdown-content .no-data[data-v-d5a338f0] {\n padding: 10px;\n color: #979ba5;\n text-align: center;\n}\n.dropdown-content .user-group .group-header[data-v-d5a338f0] {\n display: flex;\n align-items: center;\n padding: 8px 12px;\n color: #979ba5;\n}\n.dropdown-content .user-group .group-header .group-count[data-v-d5a338f0] {\n margin-left: 4px;\n}\n.dropdown-content .user-option[data-v-d5a338f0] {\n display: flex;\n align-items: center;\n height: 32px;\n padding: 8px 12px;\n cursor: pointer;\n}\n.dropdown-content .user-option[data-v-d5a338f0]:hover {\n background-color: #f5f7fa;\n}.user-tag[data-v-1f2e0737] {\n margin-right: 4px;\n margin-left: 0;\n}\n.user-tag.draggable[data-v-1f2e0737] {\n cursor: move;\n}\n.user-tag.active[data-v-1f2e0737] {\n background-color: #e1ecff;\n border-color: #3a84ff;\n}\n.user-tag.is-custom[data-v-1f2e0737] {\n color: #ea3636;\n background-color: #feebea;\n border-color: rgba(234, 53, 54, 0.3019607843);\n}\n.user-tag.is-custom[data-v-1f2e0737]:hover {\n background-color: #fedddc;\n}\n.user-tag .tag-content .user-name[data-v-1f2e0737] {\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: 12px;\n white-space: nowrap;\n}.bk-user-selector[data-v-9975c7e1] {\n position: relative;\n width: 100%;\n height: 32px;\n font-size: 12px;\n}\n.bk-user-selector.is-disabled[data-v-9975c7e1] {\n pointer-events: none;\n cursor: not-allowed;\n background-color: #dcdee5;\n}\n.bk-user-selector .tags-container[data-v-9975c7e1] {\n position: relative;\n min-height: 32px;\n padding: 1px 10px 1px 8px;\n background-color: #fff;\n border: 1px solid #c4c6cc;\n border-radius: 2px;\n transition: all 0.2s ease;\n}\n.bk-user-selector .tags-container.focused[data-v-9975c7e1] {\n border-color: #3a84ff;\n box-shadow: 0 0 0 2px rgba(58, 132, 255, 0.1);\n}\n.bk-user-selector .tags-container.tags-container-collapsed[data-v-9975c7e1] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n}\n.bk-user-selector .tag-list[data-v-9975c7e1] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n}\n.bk-user-selector .tag-wrapper[data-v-9975c7e1] {\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n}\n.bk-user-selector .search-input[data-v-9975c7e1] {\n min-width: 20px;\n height: 28px;\n outline: none;\n background: transparent;\n border: none;\n}\n.bk-user-selector .search-input[data-v-9975c7e1]::placeholder {\n color: #c4c6cc;\n}\n.bk-user-selector .search-input.input-inline[data-v-9975c7e1] {\n min-width: 20px;\n}\n.bk-user-selector .search-input.input-last[data-v-9975c7e1], .bk-user-selector .search-input.search-input-collapsed[data-v-9975c7e1] {\n flex: 1;\n}\n.hidden-users[data-v-9975c7e1] {\n padding: 6px 10px;\n}.bk-user-selector-popover {\n padding: 0 !important;\n}";
7
7
  document.head.appendChild(__vite_style__);
8
- const generateCallbackName = () => {
9
- const timestamp = Date.now();
10
- const random = Math.random().toString(36).slice(2, 9);
11
- return `__jsonp_callback_${timestamp}_${random}`;
12
- };
13
- const jsonpRequest = (requestUrl, options = {}) => {
14
- return new Promise((resolve, reject) => {
15
- const url = vue.unref(requestUrl);
16
- const { timeout = 1e3 * 60 * 2, params } = options;
17
- const callbackName = generateCallbackName();
18
- const script = document.createElement("script");
19
- let timeoutId = null;
20
- script.setAttribute("type", "text/javascript");
21
- const cleanup = () => {
22
- if (timeoutId) {
23
- clearTimeout(timeoutId);
8
+ var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
9
+ function getDefaultExportFromCjs(x) {
10
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
11
+ }
12
+ var Sortable$1 = { exports: {} };
13
+ /**!
14
+ * Sortable 1.15.6
15
+ * @author RubaXa <trash@rubaxa.org>
16
+ * @author owenm <owen23355@gmail.com>
17
+ * @license MIT
18
+ */
19
+ (function(module2, exports3) {
20
+ (function(global2, factory) {
21
+ module2.exports = factory();
22
+ })(commonjsGlobal, function() {
23
+ function ownKeys(object, enumerableOnly) {
24
+ var keys = Object.keys(object);
25
+ if (Object.getOwnPropertySymbols) {
26
+ var symbols = Object.getOwnPropertySymbols(object);
27
+ if (enumerableOnly) {
28
+ symbols = symbols.filter(function(sym) {
29
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
30
+ });
31
+ }
32
+ keys.push.apply(keys, symbols);
24
33
  }
25
- if (script.parentNode) {
26
- script.parentNode.removeChild(script);
34
+ return keys;
35
+ }
36
+ function _objectSpread2(target) {
37
+ for (var i = 1; i < arguments.length; i++) {
38
+ var source = arguments[i] != null ? arguments[i] : {};
39
+ if (i % 2) {
40
+ ownKeys(Object(source), true).forEach(function(key) {
41
+ _defineProperty(target, key, source[key]);
42
+ });
43
+ } else if (Object.getOwnPropertyDescriptors) {
44
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
45
+ } else {
46
+ ownKeys(Object(source)).forEach(function(key) {
47
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
48
+ });
49
+ }
27
50
  }
28
- if (window[callbackName]) {
29
- delete window[callbackName];
51
+ return target;
52
+ }
53
+ function _typeof(obj) {
54
+ "@babel/helpers - typeof";
55
+ if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
56
+ _typeof = function(obj2) {
57
+ return typeof obj2;
58
+ };
59
+ } else {
60
+ _typeof = function(obj2) {
61
+ return obj2 && typeof Symbol === "function" && obj2.constructor === Symbol && obj2 !== Symbol.prototype ? "symbol" : typeof obj2;
62
+ };
30
63
  }
31
- };
32
- window[callbackName] = (data) => {
33
- cleanup();
34
- resolve(data.data || data);
35
- };
36
- timeoutId = setTimeout(() => {
37
- cleanup();
38
- reject(new Error(`JSONP request timeout: ${url}`));
39
- }, timeout);
40
- script.onerror = () => {
41
- cleanup();
42
- reject(new Error(`JSONP request failed: ${url}`));
43
- };
44
- const separator = url.includes("?") ? "&" : "?";
45
- const paramsStr = params ? `&${Object.entries(params).map(([key, value]) => value ? `${key}=${value}` : "").filter(Boolean).join("&")}` : "";
46
- script.src = `${url}${separator}callback=${callbackName}${paramsStr}`;
47
- document.head.appendChild(script);
48
- });
49
- };
50
- const getTenants = async (apiBaseUrl, tenantId) => {
51
- if (!apiBaseUrl || !tenantId) {
52
- console.warn("获取租户信息需要提供有效的apiBaseUrl和租户ID");
53
- return [];
54
- }
55
- try {
56
- const url = `${apiBaseUrl}/api/v3/open-web/tenant/data-source-owner-tenants/`;
57
- const response = await fetch(url, {
58
- method: "GET",
59
- headers: {
60
- "x-bk-tenant-id": tenantId
61
- },
62
- credentials: "include"
63
- });
64
- if (!response.ok) {
65
- throw new Error(`获取租户信息失败: ${response.status} ${response.statusText}`);
64
+ return _typeof(obj);
66
65
  }
67
- const data = await response.json();
68
- return data.data || [];
69
- } catch (error) {
70
- console.error("获取租户信息失败:", error);
71
- return [];
72
- }
73
- };
74
- const searchUsers = async (params) => {
75
- const { apiBaseUrl, tenantId, keyword, enableMultiTenantMode = true } = params;
76
- if (!enableMultiTenantMode) {
77
- const userList = await getUserList(apiBaseUrl, {
78
- keyword,
79
- pageSize: 100,
80
- page: 1
81
- }).catch(() => {
82
- return [];
83
- });
84
- return userList;
85
- }
86
- if (!keyword || !apiBaseUrl || !tenantId) {
87
- console.warn("搜索用户需要提供有效的apiBaseUrl、租户ID和关键词");
88
- return [];
89
- }
90
- try {
91
- const url = `${apiBaseUrl}/api/v3/open-web/tenant/users/-/search/?keyword=${encodeURIComponent(keyword)}`;
92
- const response = await fetch(url, {
93
- method: "GET",
94
- headers: {
95
- "x-bk-tenant-id": tenantId
96
- },
97
- credentials: "include"
98
- });
99
- if (!response.ok) {
100
- throw new Error(`搜索用户失败: ${response.status} ${response.statusText}`);
66
+ function _defineProperty(obj, key, value) {
67
+ if (key in obj) {
68
+ Object.defineProperty(obj, key, {
69
+ value,
70
+ enumerable: true,
71
+ configurable: true,
72
+ writable: true
73
+ });
74
+ } else {
75
+ obj[key] = value;
76
+ }
77
+ return obj;
101
78
  }
102
- const data = await response.json();
103
- return data.data || [];
104
- } catch (error) {
105
- console.error("搜索用户失败:", error);
106
- return [];
107
- }
108
- };
109
- const lookupUsers = async (params) => {
110
- const { apiBaseUrl, tenantId, exactSearchKey = "bk_username", usersList = [], enableMultiTenantMode = true } = params;
111
- const users = usersList.filter((user) => user).map((user) => user.trim());
112
- if (!enableMultiTenantMode) {
113
- const userList = await getUserList(apiBaseUrl, {
114
- userIds: users
115
- }).catch(() => {
116
- return [];
117
- });
118
- return users.map((user) => userList.find((u) => u.username === user)).filter(Boolean);
119
- }
120
- if (users.length === 0 || !apiBaseUrl || !tenantId) {
121
- console.warn("批量查找用户需要提供有效的apiBaseUrl、租户ID和至少一个用户名");
122
- return [];
123
- }
124
- try {
125
- const url = `${apiBaseUrl}/api/v3/open-web/tenant/users/-/lookup/?lookups=${users.join(",")}&lookup_fields=${exactSearchKey}`;
126
- const response = await fetch(url, {
127
- method: "GET",
128
- headers: {
129
- "x-bk-tenant-id": tenantId
130
- },
131
- credentials: "include"
132
- });
133
- if (!response.ok) {
134
- throw new Error(`批量查找用户失败: ${response.status} ${response.statusText}`);
79
+ function _extends() {
80
+ _extends = Object.assign || function(target) {
81
+ for (var i = 1; i < arguments.length; i++) {
82
+ var source = arguments[i];
83
+ for (var key in source) {
84
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
85
+ target[key] = source[key];
86
+ }
87
+ }
88
+ }
89
+ return target;
90
+ };
91
+ return _extends.apply(this, arguments);
135
92
  }
136
- const data = await response.json();
137
- return data.data || [];
138
- } catch (error) {
139
- console.error("批量查找用户失败:", error);
140
- return [];
141
- }
142
- };
143
- const formatUsers = (users, enableMultiTenantMode = true) => {
144
- if (!users || !Array.isArray(users)) return [];
145
- if (!enableMultiTenantMode) {
146
- return users.map((user) => ({
147
- ...user,
148
- id: user.username,
149
- name: `${user.display_name}(${user.username})`,
150
- tenantId: user.owner_tenant_id
151
- }));
152
- }
153
- return users.map((user) => ({
154
- id: user.bk_username,
155
- name: user.display_name,
156
- tenantId: user.owner_tenant_id,
157
- ...user
158
- }));
159
- };
160
- const getUserList = async (url, params) => {
161
- const { userIds, keyword, pageSize = 20, page, appCode } = params;
162
- const data = await jsonpRequest(url, {
163
- params: {
164
- exact_lookups: (userIds == null ? void 0 : userIds.join(",")) || void 0,
165
- fuzzy_lookups: keyword || void 0,
166
- page_size: Math.max((userIds == null ? void 0 : userIds.length) || 0, 20, Number(pageSize)).toString(),
167
- page: (page == null ? void 0 : page.toString()) || "1",
168
- app_code: appCode || "bk-magicbox"
93
+ function _objectWithoutPropertiesLoose(source, excluded) {
94
+ if (source == null) return {};
95
+ var target = {};
96
+ var sourceKeys = Object.keys(source);
97
+ var key, i;
98
+ for (i = 0; i < sourceKeys.length; i++) {
99
+ key = sourceKeys[i];
100
+ if (excluded.indexOf(key) >= 0) continue;
101
+ target[key] = source[key];
102
+ }
103
+ return target;
169
104
  }
170
- });
171
- return (data == null ? void 0 : data.results) || [];
172
- };
173
- /*! js-cookie v3.0.5 | MIT */
174
- function assign(target) {
175
- for (var i = 1; i < arguments.length; i++) {
176
- var source = arguments[i];
177
- for (var key in source) {
178
- target[key] = source[key];
105
+ function _objectWithoutProperties(source, excluded) {
106
+ if (source == null) return {};
107
+ var target = _objectWithoutPropertiesLoose(source, excluded);
108
+ var key, i;
109
+ if (Object.getOwnPropertySymbols) {
110
+ var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
111
+ for (i = 0; i < sourceSymbolKeys.length; i++) {
112
+ key = sourceSymbolKeys[i];
113
+ if (excluded.indexOf(key) >= 0) continue;
114
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
115
+ target[key] = source[key];
116
+ }
117
+ }
118
+ return target;
179
119
  }
180
- }
181
- return target;
182
- }
183
- var defaultConverter = {
184
- read: function(value) {
185
- if (value[0] === '"') {
186
- value = value.slice(1, -1);
120
+ function _toConsumableArray(arr) {
121
+ return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
187
122
  }
188
- return value.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent);
189
- },
190
- write: function(value) {
191
- return encodeURIComponent(value).replace(
192
- /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,
193
- decodeURIComponent
194
- );
195
- }
196
- };
197
- function init(converter, defaultAttributes) {
198
- function set(name, value, attributes) {
199
- if (typeof document === "undefined") {
200
- return;
201
- }
202
- attributes = assign({}, defaultAttributes, attributes);
203
- if (typeof attributes.expires === "number") {
204
- attributes.expires = new Date(Date.now() + attributes.expires * 864e5);
123
+ function _arrayWithoutHoles(arr) {
124
+ if (Array.isArray(arr)) return _arrayLikeToArray(arr);
205
125
  }
206
- if (attributes.expires) {
207
- attributes.expires = attributes.expires.toUTCString();
126
+ function _iterableToArray(iter) {
127
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
208
128
  }
209
- name = encodeURIComponent(name).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent).replace(/[()]/g, escape);
210
- var stringifiedAttributes = "";
211
- for (var attributeName in attributes) {
212
- if (!attributes[attributeName]) {
213
- continue;
214
- }
215
- stringifiedAttributes += "; " + attributeName;
216
- if (attributes[attributeName] === true) {
217
- continue;
218
- }
219
- stringifiedAttributes += "=" + attributes[attributeName].split(";")[0];
129
+ function _unsupportedIterableToArray(o, minLen) {
130
+ if (!o) return;
131
+ if (typeof o === "string") return _arrayLikeToArray(o, minLen);
132
+ var n = Object.prototype.toString.call(o).slice(8, -1);
133
+ if (n === "Object" && o.constructor) n = o.constructor.name;
134
+ if (n === "Map" || n === "Set") return Array.from(o);
135
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
220
136
  }
221
- return document.cookie = name + "=" + converter.write(value, name) + stringifiedAttributes;
222
- }
223
- function get(name) {
224
- if (typeof document === "undefined" || arguments.length && !name) {
225
- return;
137
+ function _arrayLikeToArray(arr, len) {
138
+ if (len == null || len > arr.length) len = arr.length;
139
+ for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
140
+ return arr2;
226
141
  }
227
- var cookies = document.cookie ? document.cookie.split("; ") : [];
228
- var jar = {};
229
- for (var i = 0; i < cookies.length; i++) {
230
- var parts = cookies[i].split("=");
231
- var value = parts.slice(1).join("=");
232
- try {
233
- var found = decodeURIComponent(parts[0]);
234
- jar[found] = converter.read(value, found);
235
- if (name === found) {
236
- break;
237
- }
238
- } catch (e) {
239
- }
142
+ function _nonIterableSpread() {
143
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
240
144
  }
241
- return name ? jar[name] : jar;
242
- }
243
- return Object.create(
244
- {
245
- set,
246
- get,
247
- remove: function(name, attributes) {
248
- set(
249
- name,
250
- "",
251
- assign({}, attributes, {
252
- expires: -1
253
- })
254
- );
255
- },
256
- withAttributes: function(attributes) {
257
- return init(this.converter, assign({}, this.attributes, attributes));
258
- },
259
- withConverter: function(converter2) {
260
- return init(assign({}, this.converter, converter2), this.attributes);
145
+ var version = "1.15.6";
146
+ function userAgent(pattern) {
147
+ if (typeof window !== "undefined" && window.navigator) {
148
+ return !!/* @__PURE__ */ navigator.userAgent.match(pattern);
261
149
  }
262
- },
263
- {
264
- attributes: { value: Object.freeze(defaultAttributes) },
265
- converter: { value: Object.freeze(converter) }
266
150
  }
267
- );
268
- }
269
- var api = init(defaultConverter, { path: "/" });
270
- const enUS = {
271
- 我: "Me",
272
- 请输入人员名称搜索: "Please enter the name of the user to search",
273
- 用户群组: "User Group",
274
- 无匹配人员: "No matching users",
275
- 虚拟账号: "Virtual Account",
276
- 用户: "User"
277
- };
278
- const zhCN = {
279
- 我: "我",
280
- 请输入人员名称搜索: "请输入人员名称搜索",
281
- 用户群组: "用户群组",
282
- 无匹配人员: "无匹配人员",
283
- 虚拟账号: "虚拟账号",
284
- 用户: "用户"
285
- };
286
- const BLUEKINNG_LANGUAGE = "blueking_language";
287
- const languageMap = {
288
- "en-US": enUS,
289
- "zh-CN": zhCN
290
- };
291
- const getPath = (obj, path, variables) => {
292
- const pathStack = /^\w/.test(path) ? path.split(".") : [path];
293
- const { length } = pathStack;
294
- let target = obj;
295
- let i = 0;
296
- while (i <= length && target) {
297
- if (typeof target === "string") {
298
- return target;
151
+ var IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
152
+ var Edge = userAgent(/Edge/i);
153
+ var FireFox = userAgent(/firefox/i);
154
+ var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
155
+ var IOS = userAgent(/iP(ad|od|hone)/i);
156
+ var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);
157
+ var captureMode = {
158
+ capture: false,
159
+ passive: false
160
+ };
161
+ function on(el, event, fn) {
162
+ el.addEventListener(event, fn, !IE11OrLess && captureMode);
299
163
  }
300
- if (variables) {
301
- target = target[pathStack[i]];
302
- Object.keys(variables).forEach((key) => {
303
- target = target.replace(`{${key}}`, variables[key]);
304
- });
305
- } else {
306
- target = target[pathStack[i]];
164
+ function off(el, event, fn) {
165
+ el.removeEventListener(event, fn, !IE11OrLess && captureMode);
307
166
  }
308
- i = i + 1;
309
- if (!target) {
310
- return target;
167
+ function matches(el, selector) {
168
+ if (!selector) return;
169
+ selector[0] === ">" && (selector = selector.substring(1));
170
+ if (el) {
171
+ try {
172
+ if (el.matches) {
173
+ return el.matches(selector);
174
+ } else if (el.msMatchesSelector) {
175
+ return el.msMatchesSelector(selector);
176
+ } else if (el.webkitMatchesSelector) {
177
+ return el.webkitMatchesSelector(selector);
178
+ }
179
+ } catch (_) {
180
+ return false;
181
+ }
182
+ }
183
+ return false;
311
184
  }
312
- }
313
- return target;
314
- };
315
- const useI18n = () => {
316
- let localeLanguage = "zh-CN";
317
- const bluekingLanguage = api.get(BLUEKINNG_LANGUAGE);
318
- if (bluekingLanguage && bluekingLanguage.toLowerCase() === "en") {
319
- localeLanguage = "en-US";
320
- }
321
- const languagePackage = languageMap[localeLanguage];
322
- const t = (path, variable) => {
323
- const value = getPath(languagePackage, path, variable);
324
- if (value === void 0) {
325
- console.warn(`缺少索引 * ${path} *`);
185
+ function getParentOrHost(el) {
186
+ return el.host && el !== document && el.host.nodeType ? el.host : el.parentNode;
326
187
  }
327
- return value;
328
- };
329
- return {
330
- local: localeLanguage,
331
- t
332
- };
333
- };
334
- const useTenantData = (apiBaseUrl, tenantId, enableMultiTenantMode = true) => {
335
- const tenants = vue.ref({});
336
- const loading = vue.ref(false);
337
- const fetchTenants = async () => {
338
- if (!apiBaseUrl || !tenantId) {
339
- console.warn("获取租户需要提供有效的API基础URL和租户ID");
340
- return;
188
+ function closest(el, selector, ctx, includeCTX) {
189
+ if (el) {
190
+ ctx = ctx || document;
191
+ do {
192
+ if (selector != null && (selector[0] === ">" ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {
193
+ return el;
194
+ }
195
+ if (el === ctx) break;
196
+ } while (el = getParentOrHost(el));
197
+ }
198
+ return null;
341
199
  }
342
- loading.value = true;
343
- try {
344
- const result = await getTenants(apiBaseUrl, tenantId);
345
- const tenantMap = {};
346
- result.forEach((item) => {
347
- if (item.id && item.name) {
348
- tenantMap[item.id] = item.name;
200
+ var R_SPACE = /\s+/g;
201
+ function toggleClass(el, name, state) {
202
+ if (el && name) {
203
+ if (el.classList) {
204
+ el.classList[state ? "add" : "remove"](name);
205
+ } else {
206
+ var className = (" " + el.className + " ").replace(R_SPACE, " ").replace(" " + name + " ", " ");
207
+ el.className = (className + (state ? " " + name : "")).replace(R_SPACE, " ");
349
208
  }
350
- });
351
- tenants.value = tenantMap;
352
- } catch (error) {
353
- console.error("获取租户数据失败:", error);
354
- } finally {
355
- loading.value = false;
209
+ }
356
210
  }
357
- };
358
- vue.onBeforeMount(() => {
359
- if (enableMultiTenantMode) {
360
- fetchTenants();
361
- }
362
- });
363
- return {
364
- tenants,
365
- loading,
366
- fetchTenants
367
- };
368
- };
369
- var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
370
- function getDefaultExportFromCjs(x) {
371
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
372
- }
373
- var Sortable$1 = { exports: {} };
374
- /**!
375
- * Sortable 1.15.6
376
- * @author RubaXa <trash@rubaxa.org>
377
- * @author owenm <owen23355@gmail.com>
378
- * @license MIT
379
- */
380
- (function(module2, exports3) {
381
- (function(global2, factory) {
382
- module2.exports = factory();
383
- })(commonjsGlobal, function() {
384
- function ownKeys(object, enumerableOnly) {
385
- var keys = Object.keys(object);
386
- if (Object.getOwnPropertySymbols) {
387
- var symbols = Object.getOwnPropertySymbols(object);
388
- if (enumerableOnly) {
389
- symbols = symbols.filter(function(sym) {
390
- return Object.getOwnPropertyDescriptor(object, sym).enumerable;
391
- });
392
- }
393
- keys.push.apply(keys, symbols);
394
- }
395
- return keys;
396
- }
397
- function _objectSpread2(target) {
398
- for (var i = 1; i < arguments.length; i++) {
399
- var source = arguments[i] != null ? arguments[i] : {};
400
- if (i % 2) {
401
- ownKeys(Object(source), true).forEach(function(key) {
402
- _defineProperty(target, key, source[key]);
403
- });
404
- } else if (Object.getOwnPropertyDescriptors) {
405
- Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
406
- } else {
407
- ownKeys(Object(source)).forEach(function(key) {
408
- Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
409
- });
410
- }
411
- }
412
- return target;
413
- }
414
- function _typeof(obj) {
415
- "@babel/helpers - typeof";
416
- if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
417
- _typeof = function(obj2) {
418
- return typeof obj2;
419
- };
420
- } else {
421
- _typeof = function(obj2) {
422
- return obj2 && typeof Symbol === "function" && obj2.constructor === Symbol && obj2 !== Symbol.prototype ? "symbol" : typeof obj2;
423
- };
424
- }
425
- return _typeof(obj);
426
- }
427
- function _defineProperty(obj, key, value) {
428
- if (key in obj) {
429
- Object.defineProperty(obj, key, {
430
- value,
431
- enumerable: true,
432
- configurable: true,
433
- writable: true
434
- });
435
- } else {
436
- obj[key] = value;
437
- }
438
- return obj;
439
- }
440
- function _extends() {
441
- _extends = Object.assign || function(target) {
442
- for (var i = 1; i < arguments.length; i++) {
443
- var source = arguments[i];
444
- for (var key in source) {
445
- if (Object.prototype.hasOwnProperty.call(source, key)) {
446
- target[key] = source[key];
447
- }
448
- }
449
- }
450
- return target;
451
- };
452
- return _extends.apply(this, arguments);
453
- }
454
- function _objectWithoutPropertiesLoose(source, excluded) {
455
- if (source == null) return {};
456
- var target = {};
457
- var sourceKeys = Object.keys(source);
458
- var key, i;
459
- for (i = 0; i < sourceKeys.length; i++) {
460
- key = sourceKeys[i];
461
- if (excluded.indexOf(key) >= 0) continue;
462
- target[key] = source[key];
463
- }
464
- return target;
465
- }
466
- function _objectWithoutProperties(source, excluded) {
467
- if (source == null) return {};
468
- var target = _objectWithoutPropertiesLoose(source, excluded);
469
- var key, i;
470
- if (Object.getOwnPropertySymbols) {
471
- var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
472
- for (i = 0; i < sourceSymbolKeys.length; i++) {
473
- key = sourceSymbolKeys[i];
474
- if (excluded.indexOf(key) >= 0) continue;
475
- if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
476
- target[key] = source[key];
477
- }
478
- }
479
- return target;
480
- }
481
- function _toConsumableArray(arr) {
482
- return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
483
- }
484
- function _arrayWithoutHoles(arr) {
485
- if (Array.isArray(arr)) return _arrayLikeToArray(arr);
486
- }
487
- function _iterableToArray(iter) {
488
- if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
489
- }
490
- function _unsupportedIterableToArray(o, minLen) {
491
- if (!o) return;
492
- if (typeof o === "string") return _arrayLikeToArray(o, minLen);
493
- var n = Object.prototype.toString.call(o).slice(8, -1);
494
- if (n === "Object" && o.constructor) n = o.constructor.name;
495
- if (n === "Map" || n === "Set") return Array.from(o);
496
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
497
- }
498
- function _arrayLikeToArray(arr, len) {
499
- if (len == null || len > arr.length) len = arr.length;
500
- for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
501
- return arr2;
502
- }
503
- function _nonIterableSpread() {
504
- throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
505
- }
506
- var version = "1.15.6";
507
- function userAgent(pattern) {
508
- if (typeof window !== "undefined" && window.navigator) {
509
- return !!/* @__PURE__ */ navigator.userAgent.match(pattern);
510
- }
511
- }
512
- var IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
513
- var Edge = userAgent(/Edge/i);
514
- var FireFox = userAgent(/firefox/i);
515
- var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
516
- var IOS = userAgent(/iP(ad|od|hone)/i);
517
- var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);
518
- var captureMode = {
519
- capture: false,
520
- passive: false
521
- };
522
- function on(el, event, fn) {
523
- el.addEventListener(event, fn, !IE11OrLess && captureMode);
524
- }
525
- function off(el, event, fn) {
526
- el.removeEventListener(event, fn, !IE11OrLess && captureMode);
527
- }
528
- function matches(el, selector) {
529
- if (!selector) return;
530
- selector[0] === ">" && (selector = selector.substring(1));
531
- if (el) {
532
- try {
533
- if (el.matches) {
534
- return el.matches(selector);
535
- } else if (el.msMatchesSelector) {
536
- return el.msMatchesSelector(selector);
537
- } else if (el.webkitMatchesSelector) {
538
- return el.webkitMatchesSelector(selector);
539
- }
540
- } catch (_) {
541
- return false;
542
- }
543
- }
544
- return false;
545
- }
546
- function getParentOrHost(el) {
547
- return el.host && el !== document && el.host.nodeType ? el.host : el.parentNode;
548
- }
549
- function closest(el, selector, ctx, includeCTX) {
550
- if (el) {
551
- ctx = ctx || document;
552
- do {
553
- if (selector != null && (selector[0] === ">" ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {
554
- return el;
555
- }
556
- if (el === ctx) break;
557
- } while (el = getParentOrHost(el));
558
- }
559
- return null;
560
- }
561
- var R_SPACE = /\s+/g;
562
- function toggleClass(el, name, state) {
563
- if (el && name) {
564
- if (el.classList) {
565
- el.classList[state ? "add" : "remove"](name);
566
- } else {
567
- var className = (" " + el.className + " ").replace(R_SPACE, " ").replace(" " + name + " ", " ");
568
- el.className = (className + (state ? " " + name : "")).replace(R_SPACE, " ");
569
- }
570
- }
571
- }
572
- function css(el, prop, val) {
573
- var style = el && el.style;
574
- if (style) {
575
- if (val === void 0) {
576
- if (document.defaultView && document.defaultView.getComputedStyle) {
577
- val = document.defaultView.getComputedStyle(el, "");
578
- } else if (el.currentStyle) {
579
- val = el.currentStyle;
580
- }
581
- return prop === void 0 ? val : val[prop];
582
- } else {
583
- if (!(prop in style) && prop.indexOf("webkit") === -1) {
584
- prop = "-webkit-" + prop;
585
- }
586
- style[prop] = val + (typeof val === "string" ? "" : "px");
587
- }
588
- }
211
+ function css(el, prop, val) {
212
+ var style = el && el.style;
213
+ if (style) {
214
+ if (val === void 0) {
215
+ if (document.defaultView && document.defaultView.getComputedStyle) {
216
+ val = document.defaultView.getComputedStyle(el, "");
217
+ } else if (el.currentStyle) {
218
+ val = el.currentStyle;
219
+ }
220
+ return prop === void 0 ? val : val[prop];
221
+ } else {
222
+ if (!(prop in style) && prop.indexOf("webkit") === -1) {
223
+ prop = "-webkit-" + prop;
224
+ }
225
+ style[prop] = val + (typeof val === "string" ? "" : "px");
226
+ }
227
+ }
589
228
  }
590
229
  function matrix(el, selfOnly) {
591
230
  var appliedTransforms = "";
@@ -3124,15 +2763,583 @@
3124
2763
  multiDragElement.parentNode && multiDragElement.parentNode.removeChild(multiDragElement);
3125
2764
  });
3126
2765
  }
3127
- Sortable2.mount(new AutoScrollPlugin());
3128
- Sortable2.mount(Remove, Revert);
3129
- Sortable2.mount(new SwapPlugin());
3130
- Sortable2.mount(new MultiDragPlugin());
3131
- return Sortable2;
2766
+ Sortable2.mount(new AutoScrollPlugin());
2767
+ Sortable2.mount(Remove, Revert);
2768
+ Sortable2.mount(new SwapPlugin());
2769
+ Sortable2.mount(new MultiDragPlugin());
2770
+ return Sortable2;
2771
+ });
2772
+ })(Sortable$1);
2773
+ var SortableExports = Sortable$1.exports;
2774
+ const Sortable = /* @__PURE__ */ getDefaultExportFromCjs(SortableExports);
2775
+ const RESERVED_SPACE_FOR_INPUT = 100;
2776
+ const SEARCH_DEBOUNCE_DELAY = 300;
2777
+ const DEFAULT_EXACT_SEARCH_KEY = "bk_username";
2778
+ const USER_TYPE = {
2779
+ /** 普通用户 */
2780
+ USER: "user",
2781
+ /** 虚拟账号 */
2782
+ VIRTUAL: "virtual",
2783
+ /** 自定义用户 */
2784
+ CUSTOM: "custom",
2785
+ /** 用户群组 */
2786
+ USER_GROUP: "userGroup"
2787
+ };
2788
+ const DEFAULT_PAGE_SIZE = 100;
2789
+ const generateCallbackName = () => {
2790
+ const timestamp = Date.now();
2791
+ const random = Math.random().toString(36).slice(2, 9);
2792
+ return `__jsonp_callback_${timestamp}_${random}`;
2793
+ };
2794
+ const jsonpRequest = (requestUrl, options = {}) => {
2795
+ return new Promise((resolve, reject) => {
2796
+ const url = vue.unref(requestUrl);
2797
+ const { timeout = 1e3 * 60 * 2, params } = options;
2798
+ const callbackName = generateCallbackName();
2799
+ const script = document.createElement("script");
2800
+ let timeoutId = null;
2801
+ script.setAttribute("type", "text/javascript");
2802
+ const cleanup = () => {
2803
+ if (timeoutId) {
2804
+ clearTimeout(timeoutId);
2805
+ }
2806
+ if (script.parentNode) {
2807
+ script.parentNode.removeChild(script);
2808
+ }
2809
+ if (window[callbackName]) {
2810
+ delete window[callbackName];
2811
+ }
2812
+ };
2813
+ window[callbackName] = (data) => {
2814
+ cleanup();
2815
+ resolve(data.data || data);
2816
+ };
2817
+ timeoutId = setTimeout(() => {
2818
+ cleanup();
2819
+ reject(new Error(`JSONP request timeout: ${url}`));
2820
+ }, timeout);
2821
+ script.onerror = () => {
2822
+ cleanup();
2823
+ reject(new Error(`JSONP request failed: ${url}`));
2824
+ };
2825
+ const separator = url.includes("?") ? "&" : "?";
2826
+ const paramsStr = params ? `&${Object.entries(params).map(([key, value]) => value ? `${key}=${value}` : "").filter(Boolean).join("&")}` : "";
2827
+ script.src = `${url}${separator}callback=${callbackName}${paramsStr}`;
2828
+ document.head.appendChild(script);
2829
+ });
2830
+ };
2831
+ const logger = {
2832
+ /**
2833
+ * 调试日志
2834
+ */
2835
+ debug: (message, ...args) => {
2836
+ },
2837
+ /**
2838
+ * 信息日志
2839
+ */
2840
+ info: (message, ...args) => {
2841
+ },
2842
+ /**
2843
+ * 警告日志
2844
+ */
2845
+ warn: (message, ...args) => {
2846
+ },
2847
+ /**
2848
+ * 错误日志
2849
+ */
2850
+ error: (message, error) => {
2851
+ }
2852
+ };
2853
+ const warnMissingParams = (operation, params) => {
2854
+ logger.warn(`${operation}需要提供有效的参数: ${params.join(", ")}`);
2855
+ };
2856
+ const getTenants = async (apiBaseUrl, tenantId) => {
2857
+ if (!apiBaseUrl || !tenantId) {
2858
+ warnMissingParams("获取租户信息", ["apiBaseUrl", "tenantId"]);
2859
+ return [];
2860
+ }
2861
+ try {
2862
+ const url = `${apiBaseUrl}/api/v3/open-web/tenant/data-source-owner-tenants/`;
2863
+ const response = await fetch(url, {
2864
+ method: "GET",
2865
+ headers: {
2866
+ "x-bk-tenant-id": tenantId
2867
+ },
2868
+ credentials: "include"
2869
+ });
2870
+ if (!response.ok) {
2871
+ throw new Error(`${response.status} ${response.statusText}`);
2872
+ }
2873
+ const data = await response.json();
2874
+ return data.data || [];
2875
+ } catch (error) {
2876
+ return [];
2877
+ }
2878
+ };
2879
+ const searchUsers = async (params) => {
2880
+ const { apiBaseUrl, tenantId, keyword, enableMultiTenantMode = true } = params;
2881
+ if (!enableMultiTenantMode) {
2882
+ try {
2883
+ return await getUserList(apiBaseUrl, {
2884
+ keyword,
2885
+ pageSize: DEFAULT_PAGE_SIZE,
2886
+ page: 1
2887
+ });
2888
+ } catch {
2889
+ return [];
2890
+ }
2891
+ }
2892
+ if (!keyword || !apiBaseUrl || !tenantId) {
2893
+ warnMissingParams("搜索用户", ["apiBaseUrl", "tenantId", "keyword"]);
2894
+ return [];
2895
+ }
2896
+ try {
2897
+ const url = `${apiBaseUrl}/api/v3/open-web/tenant/users/-/search/?keyword=${encodeURIComponent(keyword)}`;
2898
+ const response = await fetch(url, {
2899
+ method: "GET",
2900
+ headers: {
2901
+ "x-bk-tenant-id": tenantId
2902
+ },
2903
+ credentials: "include"
2904
+ });
2905
+ if (!response.ok) {
2906
+ throw new Error(`${response.status} ${response.statusText}`);
2907
+ }
2908
+ const data = await response.json();
2909
+ return data.data || [];
2910
+ } catch (error) {
2911
+ return [];
2912
+ }
2913
+ };
2914
+ const lookupUsers = async (params) => {
2915
+ const { apiBaseUrl, tenantId, exactSearchKey = "bk_username", usersList = [], enableMultiTenantMode = true } = params;
2916
+ const users = usersList.filter(Boolean).map((user) => typeof user === "string" ? user.trim() : String(user).trim());
2917
+ if (!enableMultiTenantMode) {
2918
+ try {
2919
+ const userList = await getUserList(apiBaseUrl, { userIds: users });
2920
+ return users.map((user) => userList.find((u) => u.username === user)).filter(Boolean);
2921
+ } catch {
2922
+ return [];
2923
+ }
2924
+ }
2925
+ if (users.length === 0 || !apiBaseUrl || !tenantId) {
2926
+ warnMissingParams("批量查找用户", ["apiBaseUrl", "tenantId", "usersList"]);
2927
+ return [];
2928
+ }
2929
+ try {
2930
+ const url = `${apiBaseUrl}/api/v3/open-web/tenant/users/-/lookup/?lookups=${users.join(",")}&lookup_fields=${exactSearchKey}`;
2931
+ const response = await fetch(url, {
2932
+ method: "GET",
2933
+ headers: {
2934
+ "x-bk-tenant-id": tenantId
2935
+ },
2936
+ credentials: "include"
2937
+ });
2938
+ if (!response.ok) {
2939
+ throw new Error(`${response.status} ${response.statusText}`);
2940
+ }
2941
+ const data = await response.json();
2942
+ return data.data || [];
2943
+ } catch (error) {
2944
+ return [];
2945
+ }
2946
+ };
2947
+ const formatUsers = (users, enableMultiTenantMode = true) => {
2948
+ if (!users || !Array.isArray(users)) return [];
2949
+ if (!enableMultiTenantMode) {
2950
+ return users.map((user) => ({
2951
+ ...user,
2952
+ id: user.username,
2953
+ name: `${user.display_name}(${user.username})`,
2954
+ type: user.data_source_type,
2955
+ tenantId: user.owner_tenant_id
2956
+ }));
2957
+ }
2958
+ return users.map((user) => ({
2959
+ id: user.bk_username,
2960
+ name: user.display_name,
2961
+ type: user.data_source_type,
2962
+ tenantId: user.owner_tenant_id,
2963
+ ...user
2964
+ }));
2965
+ };
2966
+ const getUserList = async (url, params) => {
2967
+ const { userIds, keyword, pageSize = 20, page = 1, appCode = "bk-magicbox" } = params;
2968
+ const data = await jsonpRequest(url, {
2969
+ params: {
2970
+ exact_lookups: (userIds == null ? void 0 : userIds.join(",")) || void 0,
2971
+ fuzzy_lookups: keyword || void 0,
2972
+ page_size: Math.max((userIds == null ? void 0 : userIds.length) || 0, 20, Number(pageSize)).toString(),
2973
+ page: page.toString(),
2974
+ app_code: appCode
2975
+ }
2976
+ });
2977
+ return (data == null ? void 0 : data.results) || [];
2978
+ };
2979
+ const useCurrentUser = (options) => {
2980
+ const {
2981
+ apiBaseUrl,
2982
+ tenantId,
2983
+ currentUserId,
2984
+ exactSearchKey = DEFAULT_EXACT_SEARCH_KEY,
2985
+ enableMultiTenantMode = true
2986
+ } = options;
2987
+ const loading = vue.ref(false);
2988
+ const fetchCurrentUser = async () => {
2989
+ if (!currentUserId) {
2990
+ return null;
2991
+ }
2992
+ loading.value = true;
2993
+ try {
2994
+ const result = await lookupUsers({
2995
+ apiBaseUrl,
2996
+ tenantId,
2997
+ exactSearchKey,
2998
+ usersList: [currentUserId],
2999
+ enableMultiTenantMode
3000
+ });
3001
+ const formattedUsers = formatUsers(result, enableMultiTenantMode);
3002
+ return formattedUsers.length > 0 ? formattedUsers[0] : null;
3003
+ } catch (error) {
3004
+ console.error("获取当前用户信息失败:", error);
3005
+ return null;
3006
+ } finally {
3007
+ loading.value = false;
3008
+ }
3009
+ };
3010
+ return {
3011
+ loading,
3012
+ fetchCurrentUser
3013
+ };
3014
+ };
3015
+ /*! js-cookie v3.0.5 | MIT */
3016
+ function assign(target) {
3017
+ for (var i = 1; i < arguments.length; i++) {
3018
+ var source = arguments[i];
3019
+ for (var key in source) {
3020
+ target[key] = source[key];
3021
+ }
3022
+ }
3023
+ return target;
3024
+ }
3025
+ var defaultConverter = {
3026
+ read: function(value) {
3027
+ if (value[0] === '"') {
3028
+ value = value.slice(1, -1);
3029
+ }
3030
+ return value.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent);
3031
+ },
3032
+ write: function(value) {
3033
+ return encodeURIComponent(value).replace(
3034
+ /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,
3035
+ decodeURIComponent
3036
+ );
3037
+ }
3038
+ };
3039
+ function init(converter, defaultAttributes) {
3040
+ function set(name, value, attributes) {
3041
+ if (typeof document === "undefined") {
3042
+ return;
3043
+ }
3044
+ attributes = assign({}, defaultAttributes, attributes);
3045
+ if (typeof attributes.expires === "number") {
3046
+ attributes.expires = new Date(Date.now() + attributes.expires * 864e5);
3047
+ }
3048
+ if (attributes.expires) {
3049
+ attributes.expires = attributes.expires.toUTCString();
3050
+ }
3051
+ name = encodeURIComponent(name).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent).replace(/[()]/g, escape);
3052
+ var stringifiedAttributes = "";
3053
+ for (var attributeName in attributes) {
3054
+ if (!attributes[attributeName]) {
3055
+ continue;
3056
+ }
3057
+ stringifiedAttributes += "; " + attributeName;
3058
+ if (attributes[attributeName] === true) {
3059
+ continue;
3060
+ }
3061
+ stringifiedAttributes += "=" + attributes[attributeName].split(";")[0];
3062
+ }
3063
+ return document.cookie = name + "=" + converter.write(value, name) + stringifiedAttributes;
3064
+ }
3065
+ function get(name) {
3066
+ if (typeof document === "undefined" || arguments.length && !name) {
3067
+ return;
3068
+ }
3069
+ var cookies = document.cookie ? document.cookie.split("; ") : [];
3070
+ var jar = {};
3071
+ for (var i = 0; i < cookies.length; i++) {
3072
+ var parts = cookies[i].split("=");
3073
+ var value = parts.slice(1).join("=");
3074
+ try {
3075
+ var found = decodeURIComponent(parts[0]);
3076
+ jar[found] = converter.read(value, found);
3077
+ if (name === found) {
3078
+ break;
3079
+ }
3080
+ } catch (e) {
3081
+ }
3082
+ }
3083
+ return name ? jar[name] : jar;
3084
+ }
3085
+ return Object.create(
3086
+ {
3087
+ set,
3088
+ get,
3089
+ remove: function(name, attributes) {
3090
+ set(
3091
+ name,
3092
+ "",
3093
+ assign({}, attributes, {
3094
+ expires: -1
3095
+ })
3096
+ );
3097
+ },
3098
+ withAttributes: function(attributes) {
3099
+ return init(this.converter, assign({}, this.attributes, attributes));
3100
+ },
3101
+ withConverter: function(converter2) {
3102
+ return init(assign({}, this.converter, converter2), this.attributes);
3103
+ }
3104
+ },
3105
+ {
3106
+ attributes: { value: Object.freeze(defaultAttributes) },
3107
+ converter: { value: Object.freeze(converter) }
3108
+ }
3109
+ );
3110
+ }
3111
+ var api = init(defaultConverter, { path: "/" });
3112
+ const enUS = {
3113
+ 我: "Me",
3114
+ 请输入人员名称搜索: "Please enter the name of the user to search",
3115
+ 用户群组: "User Group",
3116
+ 无匹配人员: "No matching users",
3117
+ 虚拟账号: "Virtual Account",
3118
+ 用户: "User"
3119
+ };
3120
+ const zhCN = {
3121
+ 我: "我",
3122
+ 请输入人员名称搜索: "请输入人员名称搜索",
3123
+ 用户群组: "用户群组",
3124
+ 无匹配人员: "无匹配人员",
3125
+ 虚拟账号: "虚拟账号",
3126
+ 用户: "用户"
3127
+ };
3128
+ const BLUEKINNG_LANGUAGE = "blueking_language";
3129
+ const languageMap = {
3130
+ "en-US": enUS,
3131
+ "zh-CN": zhCN
3132
+ };
3133
+ const getPath = (obj, path, variables) => {
3134
+ const safePath = typeof path === "string" ? path : String(path ?? "");
3135
+ const pathStack = /^\w/.test(safePath) ? safePath.split(".") : [safePath];
3136
+ const { length } = pathStack;
3137
+ let target = obj;
3138
+ let i = 0;
3139
+ while (i <= length && target) {
3140
+ if (typeof target === "string") {
3141
+ return target;
3142
+ }
3143
+ if (variables) {
3144
+ target = target[pathStack[i]];
3145
+ if (typeof target === "string") {
3146
+ Object.keys(variables).forEach((key) => {
3147
+ target = target.replace(`{${key}}`, variables[key]);
3148
+ });
3149
+ }
3150
+ } else {
3151
+ target = target[pathStack[i]];
3152
+ }
3153
+ i = i + 1;
3154
+ if (!target) {
3155
+ return target;
3156
+ }
3157
+ }
3158
+ return target;
3159
+ };
3160
+ const useI18n = () => {
3161
+ let localeLanguage = "zh-CN";
3162
+ const bluekingLanguage = api.get(BLUEKINNG_LANGUAGE);
3163
+ if (bluekingLanguage && bluekingLanguage.toLowerCase() === "en") {
3164
+ localeLanguage = "en-US";
3165
+ }
3166
+ const languagePackage = languageMap[localeLanguage];
3167
+ const t = (path, variable) => {
3168
+ const value = getPath(languagePackage, path, variable);
3169
+ if (value === void 0) {
3170
+ console.warn(`缺少索引 * ${path} *`);
3171
+ }
3172
+ return value;
3173
+ };
3174
+ return {
3175
+ local: localeLanguage,
3176
+ t
3177
+ };
3178
+ };
3179
+ const useInputHandler = (options) => {
3180
+ const {
3181
+ apiBaseUrl,
3182
+ tenantId,
3183
+ searchQuery,
3184
+ selectedUsers,
3185
+ allowCreate = false,
3186
+ freePaste = false,
3187
+ enableMultiTenantMode = true,
3188
+ maxCount = 0,
3189
+ onAddUser,
3190
+ onBatchAddUsers
3191
+ } = options;
3192
+ const isPasting = vue.ref(false);
3193
+ const createCustomUser = (loginName) => ({
3194
+ id: loginName,
3195
+ name: loginName,
3196
+ type: USER_TYPE.CUSTOM,
3197
+ tenantId: "",
3198
+ login_name: loginName
3199
+ });
3200
+ const parsePastedText = (text) => {
3201
+ const usersList = text.split(/[,,;\n\s]+/).filter(Boolean);
3202
+ return usersList.map((user) => user.trim().replace(/\s*\(.*?\)\s*/, "")).filter(Boolean);
3203
+ };
3204
+ const mergeUsers = (existingUsers, newUsers) => {
3205
+ const userMap = /* @__PURE__ */ new Map();
3206
+ for (const user of [...existingUsers, ...newUsers]) {
3207
+ if (!userMap.has(user.id)) {
3208
+ userMap.set(user.id, user);
3209
+ }
3210
+ }
3211
+ return Array.from(userMap.values());
3212
+ };
3213
+ const handleEnterCreate = (event) => {
3214
+ if (event.key !== "Enter" || !allowCreate || !searchQuery.value.trim()) {
3215
+ return;
3216
+ }
3217
+ const customUser = createCustomUser(searchQuery.value.trim());
3218
+ const isDuplicate = selectedUsers.value.some((user) => user.id === customUser.id);
3219
+ if (!isDuplicate) {
3220
+ onAddUser(customUser);
3221
+ }
3222
+ };
3223
+ const handlePaste = async (event) => {
3224
+ var _a, _b;
3225
+ event.preventDefault();
3226
+ const pastedText = (_b = (_a = event.clipboardData) == null ? void 0 : _a.getData("text")) == null ? void 0 : _b.trim();
3227
+ if (!pastedText) return;
3228
+ isPasting.value = true;
3229
+ try {
3230
+ const usersList = parsePastedText(pastedText);
3231
+ if (usersList.length === 0) return;
3232
+ const result = await lookupUsers({
3233
+ apiBaseUrl,
3234
+ tenantId,
3235
+ exactSearchKey: "login_name",
3236
+ usersList,
3237
+ enableMultiTenantMode
3238
+ });
3239
+ const formattedUsers = formatUsers(result, enableMultiTenantMode);
3240
+ if (onBatchAddUsers) {
3241
+ let mergedUsers = mergeUsers(selectedUsers.value, formattedUsers);
3242
+ if (freePaste) {
3243
+ for (const loginName of usersList) {
3244
+ const isDuplicate = mergedUsers.some((item) => item.login_name === loginName || item.id === loginName);
3245
+ if (!isDuplicate) {
3246
+ mergedUsers.push(createCustomUser(loginName));
3247
+ }
3248
+ }
3249
+ }
3250
+ if (maxCount > 0 && mergedUsers.length > maxCount) {
3251
+ mergedUsers = mergedUsers.slice(0, maxCount);
3252
+ }
3253
+ onBatchAddUsers(mergedUsers);
3254
+ } else {
3255
+ if (formattedUsers.length > 0) {
3256
+ onAddUser(formattedUsers[0]);
3257
+ } else if (freePaste && usersList.length > 0) {
3258
+ onAddUser(createCustomUser(usersList[0]));
3259
+ }
3260
+ }
3261
+ } catch (error) {
3262
+ console.error("精准查找用户失败:", error);
3263
+ } finally {
3264
+ isPasting.value = false;
3265
+ }
3266
+ };
3267
+ return {
3268
+ isPasting,
3269
+ parsePastedText,
3270
+ handleEnterCreate,
3271
+ handlePaste
3272
+ };
3273
+ };
3274
+ const useResizeObserver = (target, callback, options = {}) => {
3275
+ const { immediate = true } = options;
3276
+ let observer = null;
3277
+ const cleanup = () => {
3278
+ if (observer) {
3279
+ observer.disconnect();
3280
+ observer = null;
3281
+ }
3282
+ };
3283
+ const observe = () => {
3284
+ cleanup();
3285
+ if (!target.value) return;
3286
+ observer = new ResizeObserver((entries) => {
3287
+ for (const entry of entries) {
3288
+ callback(entry);
3289
+ }
3290
+ });
3291
+ observer.observe(target.value);
3292
+ if (immediate && target.value) {
3293
+ const rect = target.value.getBoundingClientRect();
3294
+ const entry = {
3295
+ target: target.value,
3296
+ contentRect: rect,
3297
+ borderBoxSize: [{ blockSize: rect.height, inlineSize: rect.width }],
3298
+ contentBoxSize: [{ blockSize: rect.height, inlineSize: rect.width }],
3299
+ devicePixelContentBoxSize: [{ blockSize: rect.height, inlineSize: rect.width }]
3300
+ };
3301
+ callback(entry);
3302
+ }
3303
+ };
3304
+ vue.watch(target, observe, { immediate: true });
3305
+ vue.onUnmounted(cleanup);
3306
+ return cleanup;
3307
+ };
3308
+ const useTenantData = (apiBaseUrl, tenantId, enableMultiTenantMode = true) => {
3309
+ const tenants = vue.ref({});
3310
+ const loading = vue.ref(false);
3311
+ const fetchTenants = async () => {
3312
+ if (!apiBaseUrl || !tenantId) {
3313
+ console.warn("获取租户需要提供有效的API基础URL和租户ID");
3314
+ return;
3315
+ }
3316
+ loading.value = true;
3317
+ try {
3318
+ const result = await getTenants(apiBaseUrl, tenantId);
3319
+ const tenantMap = {};
3320
+ result.forEach((item) => {
3321
+ if (item.id && item.name) {
3322
+ tenantMap[item.id] = item.name;
3323
+ }
3324
+ });
3325
+ tenants.value = tenantMap;
3326
+ } catch (error) {
3327
+ console.error("获取租户数据失败:", error);
3328
+ } finally {
3329
+ loading.value = false;
3330
+ }
3331
+ };
3332
+ vue.onBeforeMount(() => {
3333
+ if (enableMultiTenantMode) {
3334
+ fetchTenants();
3335
+ }
3132
3336
  });
3133
- })(Sortable$1);
3134
- var SortableExports = Sortable$1.exports;
3135
- const Sortable = /* @__PURE__ */ getDefaultExportFromCjs(SortableExports);
3337
+ return {
3338
+ tenants,
3339
+ loading,
3340
+ fetchTenants
3341
+ };
3342
+ };
3136
3343
  const debounce = (fn, delay) => {
3137
3344
  let timer = null;
3138
3345
  return function(...args) {
@@ -3171,10 +3378,12 @@
3171
3378
  const performSearch = async (keyword) => {
3172
3379
  if (!(keyword == null ? void 0 : keyword.length)) {
3173
3380
  searchResults.value = [];
3381
+ loading.value = false;
3174
3382
  return;
3175
3383
  }
3176
3384
  if (enableMultiTenantMode && (!apiBaseUrl || !tenantId)) {
3177
3385
  console.warn("执行用户搜索需要提供有效的API基础URL和租户ID");
3386
+ loading.value = false;
3178
3387
  return;
3179
3388
  }
3180
3389
  loading.value = true;
@@ -3193,14 +3402,16 @@
3193
3402
  loading.value = false;
3194
3403
  }
3195
3404
  };
3196
- const debouncedSearch = debounce(performSearch, 300);
3405
+ const debouncedSearch = debounce(performSearch, SEARCH_DEBOUNCE_DELAY);
3197
3406
  const handleSearchInput = (value) => {
3198
- searchQuery.value = value;
3199
- debouncedSearch(value);
3407
+ loading.value = true;
3408
+ searchQuery.value = typeof value === "string" ? value.trim() : String(value ?? "").trim();
3409
+ debouncedSearch(searchQuery.value);
3200
3410
  };
3201
3411
  const clearSearch = () => {
3202
3412
  searchQuery.value = "";
3203
3413
  searchResults.value = [];
3414
+ loading.value = false;
3204
3415
  };
3205
3416
  return {
3206
3417
  searchResults,
@@ -3211,26 +3422,57 @@
3211
3422
  clearSearch
3212
3423
  };
3213
3424
  };
3214
- const _sfc_main$5 = /* @__PURE__ */ vue.defineComponent({
3425
+ const useUserSelection = (options) => {
3426
+ const { selectedUserIds, excludeUserIds, userGroup, searchQuery } = options;
3427
+ const createCustomUser = (loginName) => ({
3428
+ id: loginName,
3429
+ name: loginName,
3430
+ type: USER_TYPE.CUSTOM,
3431
+ tenantId: "",
3432
+ login_name: loginName
3433
+ });
3434
+ const isUserSelected = (userId) => {
3435
+ return selectedUserIds.value.includes(userId);
3436
+ };
3437
+ const filterOptions = (options2) => {
3438
+ return options2.filter((user) => !isUserSelected(user.id)).filter((user) => {
3439
+ var _a;
3440
+ return !((_a = excludeUserIds == null ? void 0 : excludeUserIds.value) == null ? void 0 : _a.includes(user.id));
3441
+ });
3442
+ };
3443
+ const filteredUserGroup = vue.computed(() => {
3444
+ var _a;
3445
+ if (!((_a = userGroup == null ? void 0 : userGroup.value) == null ? void 0 : _a.length)) {
3446
+ return [];
3447
+ }
3448
+ return userGroup.value.filter((group) => {
3449
+ var _a2, _b;
3450
+ const isNotSelectedAndVisible = !isUserSelected(group.id) && !group.hidden;
3451
+ if (!isNotSelectedAndVisible) {
3452
+ return false;
3453
+ }
3454
+ const query = searchQuery.value.trim();
3455
+ if (!query) {
3456
+ return true;
3457
+ }
3458
+ return ((_a2 = group.id) == null ? void 0 : _a2.includes(query)) || ((_b = group.name) == null ? void 0 : _b.includes(query));
3459
+ });
3460
+ });
3461
+ return {
3462
+ createCustomUser,
3463
+ isUserSelected,
3464
+ filterOptions,
3465
+ filteredUserGroup
3466
+ };
3467
+ };
3468
+ const _sfc_main$3 = /* @__PURE__ */ vue.defineComponent({
3215
3469
  ...{
3216
3470
  name: "MeTag"
3217
3471
  },
3218
3472
  __name: "me-tag",
3219
3473
  props: {
3220
- /**
3221
- * 当前用户ID
3222
- */
3223
- currentUserId: {
3224
- type: String,
3225
- default: ""
3226
- },
3227
- /**
3228
- * 是否禁用
3229
- */
3230
- isDisabled: {
3231
- type: Boolean,
3232
- default: false
3233
- }
3474
+ currentUserId: { default: "" },
3475
+ isDisabled: { type: Boolean, default: false }
3234
3476
  },
3235
3477
  emits: ["click"],
3236
3478
  setup(__props, { emit: __emit }) {
@@ -3242,11 +3484,11 @@
3242
3484
  emit("click");
3243
3485
  };
3244
3486
  return (_ctx, _cache) => {
3245
- return __props.currentUserId ? (vue.openBlock(), vue.createElementBlock(
3487
+ return _ctx.currentUserId ? (vue.openBlock(), vue.createElementBlock(
3246
3488
  "div",
3247
3489
  {
3248
3490
  key: 0,
3249
- class: vue.normalizeClass(["me-tag", { disabled: __props.isDisabled }]),
3491
+ class: vue.normalizeClass(["me-tag", { disabled: _ctx.isDisabled }]),
3250
3492
  onClick: vue.withModifiers(handleClick, ["stop"])
3251
3493
  },
3252
3494
  vue.toDisplayString(vue.unref(t)("我")),
@@ -3263,7 +3505,10 @@
3263
3505
  }
3264
3506
  return target;
3265
3507
  };
3266
- const MeTag = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-ef4a05c4"]]);
3508
+ const MeTag = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-4f251ce1"]]);
3509
+ const UserGroupAvatar = "data:image/svg+xml,%3csvg%20viewBox='0%200%201024%201024'%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20style='fill:%20%23A3C5FD;'%3e%3cpath%20fill-rule='evenodd'%20d='M405.7858816%20162.66256256C416.4461344%20160.6535248%20439.8986944%20159.44810208%20457.3815104%20160.25171712%20484.2453504%20161.05533248%20494.052784%20163.4661776%20516.226112%20174.7167888%20567.8217376%20200.43247136%20597.670448%20242.22045568%20606.6250624%20301.28616416%20617.711728%20374.415136%20593.4063488%20443.5260352%20535.8409792%20500.180896%20509.8299584%20525.8965792%20505.565856%20537.5489984%20514.0940608%20557.237568%20521.3430336%20572.9080608%20546.0748224%20586.5695168%20629.2248%20620.3213504%20691.054272%20645.2334208%20760.985536%20687.4232096%20767.8080992%20703.8973216%20774.6306624%20720.3714304%20784.8645056%20752.114224%20791.6870688%20777.4280992%20799.7888608%20807.1618592%20793.3927072%20818.8142784%20761.8383584%20832.4757344%20720.4765728%20850.155264%20669.3073536%20857.3878016%20546.9276416%20862.2094912%20392.9935776%20868.2366048%20227.12002944%20858.5932224%20162.30568672%20840.1100768%20134.5890272%20832.4757344%20108.15159776%20815.1980096%20100.47621504%20799.5275136%2093.6536528%20786.2678656%2094.08006304%20784.2588288%20105.59313696%20746.4889184%20116.67980096%20709.924432%20119.23826176%20705.5045504%20141.41158944%20685.4141728%20143.84821888%20683.2001312%20146.05397248%20681.2036448%20148.2232096%20679.3252416L152.13038144%20676.0501632C159.5946992%20670.0236288%20167.98497088%20664.6722176%20184.94031712%20656.0863296L191.29263904%20652.915344C215.97973152%20640.7492736%20256.51622304%20622.3959904%20329.458464%20589.3821696%20359.7335872%20575.3189056%20371.2466592%20563.6664896%20375.084352%20542.772496%20377.2164032%20530.316464%20374.6579424%20526.7001952%20345.2356416%20496.9664352%20295.34565344%20446.338688%20274.02514592%20396.9163584%20273.59873568%20331.0199232%20273.59873568%20291.24097568%20282.12693888%20265.52529312%20307.71154784%20228.15719168%20332.8697472%20191.19089792%20365.703328%20169.49329056%20405.7858816%20162.66256256ZM668.7713728%20226.60405184C756.683056%20211.50282816%20820.4190272%20263.09867616%20827.0124032%20354.9644544%20831.8475456%20416.6277856%20815.1443264%20461.931456%20770.3093664%20510.1714752%20752.287472%20529.4674848%20747.891888%20536.5986176%20748.3314464%20548.344016%20748.7710048%20555.8946272%20751.4083552%20565.123152%20754.485264%20568.8984576%20757.5621728%20572.2542848%20788.331264%20588.1944672%20823.0563776%20604.1346464%20944.3745024%20659.92528%20966.791984%20682.996592%20958.4403712%20744.6599232%20954.923904%20771.9260224%20956.6821376%20771.0870656%20890.308816%20787.0272448%20867.4517792%20792.8999456%20845.0343008%20798.3531648%20841.0782752%20799.6116%20835.3640128%20801.2895136%20833.1662208%20797.9336864%20830.5288704%20781.5740256%20824.3750528%20739.6261824%20812.0674176%20710.6821696%20790.0894976%20687.6108576%20752.287472%20647.3409248%20703.9360448%20619.6553504%20624.3759712%20593.6476864%20597.5629088%20584.4191616%20560.64%20550.8608864%20560.64%20534.920704%20560.64%20527.7895712%20569.8707264%20514.7857408%20589.6508544%20494.6507744%20620.859504%20461.931456%20639.7605152%20429.631616%20648.5516832%20394.8149056%20655.5846208%20366.7098496%20652.0681504%20283.23364096%20642.837424%20254.7091072%20635.3649312%20231.63779328%20634.4858144%20232.47675008%20668.7713728%20226.60405184Z'%3e%3c/path%3e%3c/svg%3e";
3510
+ const UserAvatar = "data:image/svg+xml,%3c?xml%20version='1.0'%20encoding='UTF-8'?%3e%3csvg%20width='32px'%20height='32px'%20viewBox='0%200%2032%2032'%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20xmlns:xlink='http://www.w3.org/1999/xlink'%3e%3ctitle%3eIcon/用户%3c/title%3e%3cg%20id='Icon/用户'%20stroke='none'%20stroke-width='1'%20fill='none'%20fill-rule='evenodd'%3e%3cg%20id='user-(1)'%20transform='translate(3,%202)'%20fill='%23A3C5FD'%20fill-rule='nonzero'%3e%3cpath%20d='M13.0077612,27.9989067%20C10.3002732,27.9989067%207.59285518,28.0018792%204.88515705,27.997455%20C3.95018807,27.9959342%203.05044678,27.8282323%202.22816433,27.3628696%20C0.998627601,26.6672451%200.29953695,25.6114692%200.0864200465,24.2387462%20C-0.0656962495,23.259079%200.0147040645,22.4675755%200.0874005263,21.4879775%20C0.187970957,20.13461%200.423078914,19.3321844%200.863249688,18.0430358%20C1.22365046,16.9873982%201.73014453,16.0067633%202.49702917,15.175719%20C3.42254341,14.1726178%204.6014447,13.7297906%205.9255989,13.6440041%20C6.33292322,13.6073668%206.66741099,13.712025%206.9979768,13.9263185%20C7.58886318,14.3094892%208.17393665,14.7060014%208.79220674,15.0421658%20C10.1097776,15.758321%2011.5447274,16.1099698%2013.0616182,16.0930337%20C14.6806203,16.0750607%2016.2142496,15.63963%2017.592821,14.8169502%20C18.0555431,14.5407189%2018.5150436,14.256538%2018.9569652,13.9491996%20C19.3610679,13.6681294%2019.7808585,13.5749462%2020.274326,13.6337733%20C21.462472,13.7340074%2022.3872158,14.1103345%2023.2340106,14.8851094%20C23.902636,15.496952%2024.3685096,16.2520257%2024.7518119,17.0611566%20C25.272453,18.1598604%2025.5462904,18.7976948%2025.7441396,19.9861253%20C25.9499728,21.2233595%2026.0256808,22.2792045%2025.9924842,23.5308171%20C25.9627193,24.6543374%2025.6405577,25.6840525%2024.8535729,26.5307194%20C24.1686994,27.2671979%2023.3129402,27.7090574%2022.3211027,27.8808379%20C21.9232331,27.9495501%2021.5154185,27.9922014%2021.1120162,27.9935148%20C18.4104811,28.0036073%2015.7090862,27.9989067%2013.0077612,27.9989067%20L13.0077612,27.9989067%20Z%20M5.91775495,6.98479749%20C5.84814002,3.25685016%209.08684454,-0.00255470186%2013.0162355,1.5025268e-06%20C16.9117994,0.00256071584%2020.1304739,3.23452217%2020.1095656,7.04113598%20C20.0884528,10.8082092%2016.8998935,14.015354%2013.0058002,14.0149393%20C9.10134181,14.0145245%205.83322254,10.7695672%205.91775495,6.98479749%20Z'%20id='形状'%3e%3c/path%3e%3c/g%3e%3c/g%3e%3c/svg%3e";
3511
+ const VirtualAvatar = "data:image/svg+xml,%3c?xml%20version='1.0'%20encoding='UTF-8'?%3e%3csvg%20width='32px'%20height='32px'%20viewBox='0%200%2032%2032'%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20xmlns:xlink='http://www.w3.org/1999/xlink'%3e%3ctitle%3eIcon/虚拟icon%3c/title%3e%3cg%20id='Icon/虚拟icon'%20stroke='none'%20stroke-width='1'%20fill='none'%20fill-rule='evenodd'%3e%3cpath%20d='M27.4705882,3%20C28.315259,3%2029,3.68474098%2029,4.52941178%20L29,22.4623054%20C29,23.3069762%2028.315259,23.9917172%2027.4705882,23.9917172%20L20.5882353,23.9917172%20L20.5882353,27.0244081%20L24.0294118,27.0244081%20C24.2405794,27.0244081%2024.4117647,27.1955933%2024.4117647,27.406761%20L24.4117647,28.617647%20C24.4117647,28.8288148%2024.2405795,29%2024.0294118,29%20L7.97058824,29%20C7.75942054,29%207.58823529,28.8288148%207.58823529,28.617647%20L7.58823529,27.406761%20C7.58823531,27.1955933%207.75942055,27.0244081%207.97058824,27.0244081%20L11.4117647,27.0244081%20L11.4117647,23.9917172%20L4.52941178,23.9917172%20C3.68474098,23.9917172%203,23.3069762%203,22.4623054%20L3,4.52941178%20C3,3.68474098%203.68474098,3%204.52941178,3%20L27.4705882,3%20Z%20M19,24%20L13,24%20L13,27%20L19,27%20L19,24%20Z%20M23.4117647,7%20L8.58823529,7%20C8.03595054,7%207.58823529,7.44771525%207.58823529,8%20L7.58823529,19%20C7.58823529,19.5522847%208.03595054,20%208.58823529,20%20L23.4117647,20%20C23.9640495,20%2024.4117647,19.5522847%2024.4117647,19%20L24.4117647,8%20C24.4117647,7.44771525%2023.9640495,7%2023.4117647,7%20Z%20M12,10%20C12.5522847,10%2013,10.4477153%2013,11%20L13,13%20C13,13.5522847%2012.5522847,14%2012,14%20C11.4477153,14%2011,13.5522847%2011,13%20L11,11%20C11,10.4477153%2011.4477153,10%2012,10%20Z%20M20,10%20C20.5522847,10%2021,10.4477153%2021,11%20L21,13%20C21,13.5522847%2020.5522847,14%2020,14%20C19.4477153,14%2019,13.5522847%2019,13%20L19,11%20C19,10.4477153%2019.4477153,10%2020,10%20Z%20M26,5%20C25.4477153,5%2025,5.44771525%2025,6%20C25,6.55228475%2025.4477153,7%2026,7%20C26.5522847,7%2027,6.55228475%2027,6%20C27,5.44771525%2026.5522847,5%2026,5%20Z'%20id='蒙版'%20fill='%23A3C5FD'%20fill-rule='nonzero'%3e%3c/path%3e%3c/g%3e%3c/svg%3e";
3267
3512
  const UserRender = vue.defineComponent({
3268
3513
  name: "UserRender",
3269
3514
  props: {
@@ -3282,23 +3527,63 @@
3282
3527
  render: {
3283
3528
  type: Function,
3284
3529
  required: false
3530
+ },
3531
+ hasAvatar: {
3532
+ type: Boolean,
3533
+ default: false
3534
+ },
3535
+ avatarBaseUrl: {
3536
+ type: String,
3537
+ default: ""
3285
3538
  }
3286
3539
  },
3287
3540
  setup(props) {
3541
+ const getAvatarUrl = (user) => {
3542
+ if (user.type === "virtual") {
3543
+ return VirtualAvatar;
3544
+ }
3545
+ if (user.type === "userGroup") {
3546
+ return UserGroupAvatar;
3547
+ }
3548
+ if (!props.avatarBaseUrl) {
3549
+ return UserAvatar;
3550
+ }
3551
+ const loginName = user.login_name || user.bk_username || user.id;
3552
+ return `${props.avatarBaseUrl}${loginName}.png?default_when_absent=true`;
3553
+ };
3288
3554
  const defaultRender = (h2, props2) => {
3289
- return h2("div", [
3290
- h2("span", props2.user.name),
3291
- props2.user.tenantId !== props2.tenantId && props2.user.tenantId ? h2(
3292
- "span",
3293
- {
3555
+ return h2(
3556
+ "div",
3557
+ {
3558
+ style: {
3559
+ display: "flex",
3560
+ alignItems: "center"
3561
+ }
3562
+ },
3563
+ [
3564
+ props2.hasAvatar ? h2("img", {
3565
+ src: getAvatarUrl(props2.user),
3294
3566
  style: {
3295
- color: "#f59500",
3296
- marginLeft: "4px"
3567
+ width: "20px",
3568
+ height: "20px",
3569
+ borderRadius: "50%",
3570
+ marginRight: "6px",
3571
+ flexShrink: 0
3297
3572
  }
3298
- },
3299
- `@${props2.tenants[props2.user.tenantId] || props2.user.tenantId}`
3300
- ) : null
3301
- ]);
3573
+ }) : null,
3574
+ h2("span", props2.user.name),
3575
+ props2.user.tenantId !== props2.tenantId && props2.user.tenantId ? h2(
3576
+ "span",
3577
+ {
3578
+ style: {
3579
+ color: "#f59500",
3580
+ marginLeft: "4px"
3581
+ }
3582
+ },
3583
+ `@${props2.tenants[props2.user.tenantId] || props2.user.tenantId}`
3584
+ ) : null
3585
+ ]
3586
+ );
3302
3587
  };
3303
3588
  return () => {
3304
3589
  try {
@@ -3310,106 +3595,38 @@
3310
3595
  };
3311
3596
  }
3312
3597
  });
3313
- const _hoisted_1$2 = {
3598
+ const _hoisted_1$1 = {
3314
3599
  key: 0,
3315
3600
  class: "no-data"
3316
3601
  };
3317
- const _hoisted_2$2 = { class: "group-name" };
3602
+ const _hoisted_2$1 = { class: "group-name" };
3318
3603
  const _hoisted_3$1 = { class: "group-count" };
3319
- const _hoisted_4$1 = ["onClick"];
3320
- const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
3604
+ const _hoisted_4 = ["onClick"];
3605
+ const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
3321
3606
  ...{
3322
3607
  name: "SelectionPopover"
3323
3608
  },
3324
3609
  __name: "selection-popover",
3325
3610
  props: {
3326
- /**
3327
- * 是否显示下拉菜单
3328
- */
3329
- isShow: {
3330
- type: Boolean,
3331
- default: false
3332
- },
3333
- /**
3334
- * 容器宽度
3335
- */
3336
- containerWidth: {
3337
- type: [Number, String],
3338
- default: "auto"
3339
- },
3340
- /**
3341
- * popover crossAxis 偏移量
3342
- */
3343
- crossAxisOffset: {
3344
- type: Number,
3345
- default: 0
3346
- },
3347
- /**
3348
- * 是否加载中
3349
- */
3350
- loading: {
3351
- type: Boolean,
3352
- default: false
3353
- },
3354
- /**
3355
- * 搜索结果选项
3356
- */
3357
- options: {
3358
- type: Array,
3359
- default: () => []
3360
- },
3361
- /**
3362
- * 搜索关键词
3363
- */
3364
- searchQuery: {
3365
- type: String,
3366
- default: ""
3367
- },
3368
- /**
3369
- * 当前租户ID
3370
- */
3371
- tenantId: {
3372
- type: String,
3373
- default: ""
3374
- },
3375
- /**
3376
- * 租户信息映射
3377
- */
3378
- tenants: {
3379
- type: Object,
3380
- default: () => ({})
3381
- },
3382
- /**
3383
- * 用户组
3384
- */
3385
- userGroup: {
3386
- type: Array,
3387
- default: () => []
3388
- },
3389
- /**
3390
- * 用户组名称
3391
- */
3392
- userGroupName: {
3393
- type: String,
3394
- default: ""
3395
- },
3396
- /**
3397
- * 无匹配人员时的提示文本
3398
- */
3399
- emptyText: {
3400
- type: String,
3401
- default: ""
3402
- },
3403
- /**
3404
- * 渲染列表项
3405
- */
3406
- renderListItem: {
3407
- type: Function
3408
- }
3611
+ avatarBaseUrl: { default: "" },
3612
+ containerWidth: { default: "auto" },
3613
+ emptyText: { default: "" },
3614
+ hasAvatar: { type: Boolean, default: false },
3615
+ isShow: { type: Boolean, default: false },
3616
+ loading: { type: Boolean, default: false },
3617
+ options: { default: () => [] },
3618
+ renderListItem: {},
3619
+ searchQuery: { default: "" },
3620
+ tenantId: { default: "" },
3621
+ tenants: { default: () => ({}) },
3622
+ userGroup: { default: () => [] },
3623
+ userGroupName: { default: "" }
3409
3624
  },
3410
- emits: ["select-user", "click-outside"],
3625
+ emits: ["click-outside", "select-user"],
3411
3626
  setup(__props, { emit: __emit }) {
3412
3627
  const { t } = useI18n();
3628
+ const slotContainerRef = vue.ref(null);
3629
+ const contentContainerRef = vue.ref(null);
3413
3630
  const props = __props;
3414
3631
  const emit = __emit;
3415
3632
  const groupedUsers = vue.computed(() => {
@@ -3418,11 +3635,11 @@
3418
3635
  groups[props.userGroupName] = props.userGroup.map((group) => ({
3419
3636
  ...group,
3420
3637
  tenantId: "",
3421
- type: "userGroup"
3638
+ type: USER_TYPE.USER_GROUP
3422
3639
  }));
3423
3640
  }
3424
3641
  props.options.forEach((user) => {
3425
- const groupName = user.data_source_type === "virtual" ? t("虚拟账号") : t("用户");
3642
+ const groupName = user.data_source_type === USER_TYPE.VIRTUAL ? t("虚拟账号") : t("用户");
3426
3643
  if (!groups[groupName]) {
3427
3644
  groups[groupName] = [];
3428
3645
  }
@@ -3434,114 +3651,150 @@
3434
3651
  emit("select-user", user);
3435
3652
  };
3436
3653
  const handleClickOutside = ({ event }) => {
3654
+ var _a, _b;
3655
+ const target = event.target;
3656
+ if ((_a = slotContainerRef.value) == null ? void 0 : _a.contains(target)) {
3657
+ return;
3658
+ }
3659
+ if ((_b = contentContainerRef.value) == null ? void 0 : _b.contains(target)) {
3660
+ return;
3661
+ }
3437
3662
  emit("click-outside", event);
3438
3663
  };
3439
3664
  return (_ctx, _cache) => {
3440
3665
  return vue.openBlock(), vue.createBlock(vue.unref(bkuiVue.Popover), {
3441
3666
  arrow: false,
3442
3667
  "ext-cls": "bk-user-selector-popover",
3443
- "is-show": __props.isShow,
3444
- offset: { mainAxis: 4, crossAxis: __props.crossAxisOffset },
3668
+ "is-show": _ctx.isShow,
3669
+ offset: { mainAxis: 4 },
3445
3670
  placement: "bottom-start",
3446
3671
  theme: "light",
3447
3672
  trigger: "manual",
3448
- width: __props.containerWidth,
3673
+ width: _ctx.containerWidth,
3449
3674
  onClickoutside: handleClickOutside
3450
3675
  }, {
3451
3676
  content: vue.withCtx(() => [
3452
- vue.createVNode(vue.unref(bkuiVue.Loading), {
3453
- class: "dropdown-content",
3454
- loading: __props.loading,
3455
- mode: "spin",
3456
- size: "mini"
3457
- }, {
3458
- default: vue.withCtx(() => [
3459
- __props.options.length === 0 && __props.userGroup.length === 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$2, [
3460
- vue.createElementVNode(
3461
- "span",
3462
- null,
3463
- vue.toDisplayString(__props.emptyText),
3464
- 1
3465
- /* TEXT */
3466
- )
3467
- ])) : (vue.openBlock(true), vue.createElementBlock(
3468
- vue.Fragment,
3469
- { key: 1 },
3470
- vue.renderList(groupedUsers.value, (group, groupName) => {
3471
- return vue.openBlock(), vue.createElementBlock("div", {
3472
- key: groupName,
3473
- class: "user-group"
3474
- }, [
3475
- Object.keys(groupedUsers.value).length > 1 || group.some((user) => user.type === "userGroup") ? (vue.openBlock(), vue.createElementBlock("div", {
3476
- key: 0,
3477
- class: "group-header",
3478
- onClick: _cache[0] || (_cache[0] = vue.withModifiers(() => {
3479
- }, ["prevent"]))
3480
- }, [
3481
- vue.createElementVNode(
3482
- "span",
3483
- _hoisted_2$2,
3484
- vue.toDisplayString(groupName),
3485
- 1
3486
- /* TEXT */
3487
- ),
3488
- vue.createElementVNode(
3489
- "span",
3490
- _hoisted_3$1,
3491
- "(" + vue.toDisplayString(group.length) + ")",
3492
- 1
3493
- /* TEXT */
3494
- )
3495
- ])) : vue.createCommentVNode("v-if", true),
3496
- (vue.openBlock(true), vue.createElementBlock(
3497
- vue.Fragment,
3677
+ vue.createElementVNode(
3678
+ "div",
3679
+ {
3680
+ ref_key: "contentContainerRef",
3681
+ ref: contentContainerRef
3682
+ },
3683
+ [
3684
+ vue.createVNode(vue.unref(bkuiVue.Loading), {
3685
+ class: "dropdown-content",
3686
+ loading: _ctx.loading,
3687
+ mode: "spin",
3688
+ size: "mini"
3689
+ }, {
3690
+ default: vue.withCtx(() => [
3691
+ _ctx.options.length === 0 && _ctx.userGroup.length === 0 ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_1$1, [
3692
+ vue.createElementVNode(
3693
+ "span",
3498
3694
  null,
3499
- vue.renderList(group, (user) => {
3500
- return vue.openBlock(), vue.createElementBlock("div", {
3501
- key: user.id,
3502
- class: "user-option",
3503
- onClick: vue.withModifiers(($event) => selectUser(user), ["prevent"])
3695
+ vue.toDisplayString(_ctx.emptyText),
3696
+ 1
3697
+ /* TEXT */
3698
+ )
3699
+ ])) : (vue.openBlock(true), vue.createElementBlock(
3700
+ vue.Fragment,
3701
+ { key: 1 },
3702
+ vue.renderList(groupedUsers.value, (group, groupName) => {
3703
+ return vue.openBlock(), vue.createElementBlock("div", {
3704
+ key: groupName,
3705
+ class: "user-group"
3706
+ }, [
3707
+ Object.keys(groupedUsers.value).length > 1 || group.some((user) => user.type === "userGroup") ? (vue.openBlock(), vue.createElementBlock("div", {
3708
+ key: 0,
3709
+ class: "group-header",
3710
+ onClick: _cache[0] || (_cache[0] = vue.withModifiers(() => {
3711
+ }, ["prevent"]))
3504
3712
  }, [
3505
- vue.createVNode(vue.unref(UserRender), {
3506
- render: __props.renderListItem,
3507
- "tenant-id": __props.tenantId,
3508
- tenants: __props.tenants,
3509
- user
3510
- }, null, 8, ["render", "tenant-id", "tenants", "user"])
3511
- ], 8, _hoisted_4$1);
3512
- }),
3513
- 128
3514
- /* KEYED_FRAGMENT */
3515
- ))
3516
- ]);
3517
- }),
3518
- 128
3519
- /* KEYED_FRAGMENT */
3520
- ))
3521
- ]),
3522
- _: 1
3523
- /* STABLE */
3524
- }, 8, ["loading"])
3713
+ vue.createElementVNode(
3714
+ "span",
3715
+ _hoisted_2$1,
3716
+ vue.toDisplayString(groupName),
3717
+ 1
3718
+ /* TEXT */
3719
+ ),
3720
+ vue.createElementVNode(
3721
+ "span",
3722
+ _hoisted_3$1,
3723
+ "(" + vue.toDisplayString(group.length) + ")",
3724
+ 1
3725
+ /* TEXT */
3726
+ )
3727
+ ])) : vue.createCommentVNode("v-if", true),
3728
+ (vue.openBlock(true), vue.createElementBlock(
3729
+ vue.Fragment,
3730
+ null,
3731
+ vue.renderList(group, (user) => {
3732
+ return vue.openBlock(), vue.createElementBlock("div", {
3733
+ key: user.id,
3734
+ class: "user-option",
3735
+ onClick: vue.withModifiers(($event) => selectUser(user), ["prevent"]),
3736
+ onMousedown: _cache[1] || (_cache[1] = vue.withModifiers(() => {
3737
+ }, ["prevent"]))
3738
+ }, [
3739
+ vue.createVNode(vue.unref(UserRender), {
3740
+ "avatar-base-url": _ctx.avatarBaseUrl,
3741
+ "has-avatar": _ctx.hasAvatar,
3742
+ render: _ctx.renderListItem,
3743
+ "tenant-id": _ctx.tenantId,
3744
+ tenants: _ctx.tenants,
3745
+ user
3746
+ }, null, 8, ["avatar-base-url", "has-avatar", "render", "tenant-id", "tenants", "user"])
3747
+ ], 40, _hoisted_4);
3748
+ }),
3749
+ 128
3750
+ /* KEYED_FRAGMENT */
3751
+ ))
3752
+ ]);
3753
+ }),
3754
+ 128
3755
+ /* KEYED_FRAGMENT */
3756
+ ))
3757
+ ]),
3758
+ _: 1
3759
+ /* STABLE */
3760
+ }, 8, ["loading"])
3761
+ ],
3762
+ 512
3763
+ /* NEED_PATCH */
3764
+ )
3525
3765
  ]),
3526
3766
  default: vue.withCtx(() => [
3527
- vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
3767
+ vue.createElementVNode(
3768
+ "div",
3769
+ {
3770
+ ref_key: "slotContainerRef",
3771
+ ref: slotContainerRef
3772
+ },
3773
+ [
3774
+ vue.renderSlot(_ctx.$slots, "default", {}, void 0, true)
3775
+ ],
3776
+ 512
3777
+ /* NEED_PATCH */
3778
+ )
3528
3779
  ]),
3529
3780
  _: 3
3530
3781
  /* FORWARDED */
3531
- }, 8, ["is-show", "offset", "width"]);
3782
+ }, 8, ["is-show", "width"]);
3532
3783
  };
3533
3784
  }
3534
3785
  });
3535
- const SelectionPopover = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-78875ea6"]]);
3536
- const _sfc_main$3 = /* @__PURE__ */ vue.defineComponent({
3786
+ const SelectionPopover = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-d5a338f0"]]);
3787
+ const _sfc_main$1 = /* @__PURE__ */ vue.defineComponent({
3537
3788
  ...{
3538
3789
  name: "UserTag"
3539
3790
  },
3540
3791
  __name: "user-tag",
3541
3792
  props: {
3542
3793
  active: { type: Boolean },
3794
+ avatarBaseUrl: {},
3543
3795
  currentTenantId: {},
3544
3796
  draggable: { type: Boolean },
3797
+ hasAvatar: { type: Boolean },
3545
3798
  renderTag: { type: Function },
3546
3799
  showTenant: { type: Boolean },
3547
3800
  tenants: {},
@@ -3566,11 +3819,13 @@
3566
3819
  }, {
3567
3820
  default: vue.withCtx(() => [
3568
3821
  vue.createVNode(vue.unref(UserRender), {
3822
+ "avatar-base-url": _ctx.avatarBaseUrl,
3823
+ "has-avatar": _ctx.hasAvatar,
3569
3824
  render: _ctx.renderTag,
3570
3825
  "tenant-id": _ctx.currentTenantId,
3571
3826
  tenants: _ctx.tenants,
3572
3827
  user: _ctx.user
3573
- }, null, 8, ["render", "tenant-id", "tenants", "user"])
3828
+ }, null, 8, ["avatar-base-url", "has-avatar", "render", "tenant-id", "tenants", "user"])
3574
3829
  ]),
3575
3830
  _: 1
3576
3831
  /* STABLE */
@@ -3578,84 +3833,176 @@
3578
3833
  };
3579
3834
  }
3580
3835
  });
3581
- const UserTag = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-48ac8fc1"]]);
3582
- const _hoisted_1$1 = ["onClick"];
3583
- const _hoisted_2$1 = ["placeholder"];
3584
- const _hoisted_3 = { class: "hidden-users" };
3585
- const _hoisted_4 = ["placeholder"];
3586
- const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
3836
+ const UserTag = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-1f2e0737"]]);
3837
+ const _hoisted_1 = ["placeholder"];
3838
+ const _hoisted_2 = { class: "hidden-users" };
3839
+ const _hoisted_3 = ["placeholder"];
3840
+ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
3587
3841
  ...{
3588
- name: "BkUserSelectorMultiple"
3842
+ name: "BkUserSelector"
3589
3843
  },
3590
- __name: "multiple-selector",
3844
+ __name: "user-selector",
3591
3845
  props: {
3592
3846
  draggable: { type: Boolean, default: false },
3593
- freePaste: { type: Boolean, default: false },
3594
- modelValue: { default: () => [] },
3595
- selectedUsers: { default: () => [] },
3596
- tenants: { default: () => ({}) },
3847
+ maxCount: { default: 0 },
3848
+ modelValue: { default: "" },
3849
+ multiple: { type: Boolean, default: false },
3597
3850
  allowCreate: { type: Boolean, default: false },
3598
3851
  apiBaseUrl: { default: "" },
3852
+ avatarBaseUrl: { default: "" },
3599
3853
  currentUserId: { default: "" },
3600
- disabled: { type: Boolean },
3854
+ disabled: { type: Boolean, default: false },
3601
3855
  emptyText: { default: "" },
3602
- enableMultiTenantMode: { type: Boolean },
3603
- exactSearchKey: { default: "bk_username" },
3856
+ enableMultiTenantMode: { type: Boolean, default: true },
3857
+ exactSearchKey: { default: DEFAULT_EXACT_SEARCH_KEY },
3604
3858
  excludeUserIds: { default: () => [] },
3859
+ freePaste: { type: Boolean, default: false },
3860
+ hasAvatar: { type: Boolean, default: false },
3605
3861
  placeholder: { default: "" },
3606
- tenantId: { default: "" },
3607
- userGroupName: { default: "" },
3608
3862
  renderListItem: {},
3609
3863
  renderTag: {},
3610
- userGroup: { default: () => [] }
3864
+ tenantId: { default: "" },
3865
+ userGroup: { default: () => [] },
3866
+ userGroupName: { default: "" }
3611
3867
  },
3612
- emits: [
3613
- "update:selectedUsers",
3614
- "add-user",
3615
- "remove-user",
3616
- "dragStart",
3617
- "dragEnd",
3618
- "focus",
3619
- "blur"
3620
- ],
3868
+ emits: ["blur", "change", "dragEnd", "dragStart", "focus", "update:modelValue"],
3621
3869
  setup(__props, { emit: __emit }) {
3870
+ const { t } = useI18n();
3871
+ bkuiVue.provideGlobalConfig({
3872
+ prefix: "bk"
3873
+ });
3622
3874
  const props = __props;
3623
3875
  const emit = __emit;
3876
+ const { tenants = {} } = useTenantData(props.apiBaseUrl, props.tenantId, props.enableMultiTenantMode);
3624
3877
  const {
3625
3878
  searchResults,
3626
3879
  loading: searchLoading,
3627
3880
  searchQuery,
3628
- // clearSearch,
3881
+ clearSearch,
3629
3882
  handleSearchInput
3630
3883
  } = useUserSearch(props.apiBaseUrl, props.tenantId, props.enableMultiTenantMode);
3884
+ const { fetchCurrentUser } = useCurrentUser({
3885
+ apiBaseUrl: props.apiBaseUrl,
3886
+ tenantId: props.tenantId,
3887
+ currentUserId: props.currentUserId || "",
3888
+ exactSearchKey: props.exactSearchKey,
3889
+ enableMultiTenantMode: props.enableMultiTenantMode
3890
+ });
3631
3891
  const containerRef = vue.ref(null);
3632
- const tagsContainerRef = vue.ref(null);
3633
3892
  const sortableContainerRef = vue.ref(null);
3634
3893
  const collapsedContainerRef = vue.ref(null);
3635
3894
  const inlineInputRef = vue.ref(null);
3636
3895
  const lastInputRef = vue.ref(null);
3637
- const collapsedInputRef = vue.ref(null);
3638
3896
  const isFocused = vue.ref(false);
3639
- const showDropdown = vue.ref(false);
3640
3897
  const activeTagIndex = vue.ref(-1);
3641
3898
  const sortableInstance = vue.ref(null);
3642
3899
  const visibleUsers = vue.ref([]);
3643
3900
  const hiddenCount = vue.ref(0);
3644
- const options = vue.computed(() => {
3645
- return searchResults.value.filter((user) => !props.selectedUsers.some((selectedUser) => selectedUser.id === user.id)).filter((user) => !props.excludeUserIds.includes(user.id));
3901
+ const selectedUsers = vue.ref([]);
3902
+ const showDropdown = vue.computed(() => {
3903
+ return isFocused.value && (props.userGroup.length > 0 || searchQuery.value.trim() !== "");
3646
3904
  });
3647
- const userGroupFilter = vue.computed(() => {
3648
- return props.userGroup.filter((group) => {
3649
- var _a, _b;
3650
- const filtered = !props.selectedUsers.some((user) => user.id === group.id) && !group.hidden;
3651
- if (filtered) {
3652
- return ((_a = group.id) == null ? void 0 : _a.includes(searchQuery.value)) || ((_b = group.name) == null ? void 0 : _b.includes(searchQuery.value));
3653
- }
3654
- return false;
3655
- });
3905
+ const modelValueIds = vue.computed(() => {
3906
+ if (props.multiple) {
3907
+ return Array.isArray(props.modelValue) ? props.modelValue : [];
3908
+ }
3909
+ return props.modelValue ? [props.modelValue] : [];
3910
+ });
3911
+ const computedPlaceholder = vue.computed(() => props.placeholder || t("请输入人员名称搜索"));
3912
+ const computedUserGroupName = vue.computed(() => props.userGroupName || t("用户群组"));
3913
+ const computedEmptyText = vue.computed(() => props.emptyText || t("无匹配人员"));
3914
+ const selectedUserIds = vue.computed(() => selectedUsers.value.map((user) => user.id));
3915
+ const isMaxCountReached = vue.computed(() => {
3916
+ if (!props.maxCount || props.maxCount <= 0) return false;
3917
+ return selectedUsers.value.length >= props.maxCount;
3918
+ });
3919
+ const isMeTagDisabled = vue.computed(
3920
+ () => isMaxCountReached.value || !!props.currentUserId && selectedUsers.value.some((user) => user[props.exactSearchKey] === props.currentUserId)
3921
+ );
3922
+ const userTagCommonProps = vue.computed(() => ({
3923
+ avatarBaseUrl: props.avatarBaseUrl,
3924
+ currentTenantId: props.tenantId,
3925
+ hasAvatar: props.hasAvatar,
3926
+ renderTag: props.renderTag,
3927
+ tenants
3928
+ }));
3929
+ const { filteredUserGroup, filterOptions, createCustomUser } = useUserSelection({
3930
+ selectedUserIds,
3931
+ excludeUserIds: vue.toRef(props, "excludeUserIds"),
3932
+ userGroup: vue.toRef(props, "userGroup"),
3933
+ searchQuery
3934
+ });
3935
+ const { handlePaste } = useInputHandler({
3936
+ apiBaseUrl: props.apiBaseUrl,
3937
+ tenantId: props.tenantId,
3938
+ searchQuery,
3939
+ selectedUsers,
3940
+ allowCreate: props.allowCreate,
3941
+ freePaste: props.freePaste,
3942
+ enableMultiTenantMode: props.enableMultiTenantMode,
3943
+ maxCount: props.maxCount,
3944
+ onAddUser: addUser,
3945
+ onBatchAddUsers: props.multiple ? updateSelectedUsers : void 0
3946
+ });
3947
+ const displayOptions = vue.computed(() => filterOptions(searchResults.value));
3948
+ const inputWidth = vue.computed(() => {
3949
+ const query = searchQuery.value;
3950
+ if (!query) return "20px";
3951
+ const charWidth = query.split("").reduce((acc, char) => {
3952
+ return acc + (/[\u4e00-\u9fa5]/.test(char) ? 12 : 8);
3953
+ }, 0);
3954
+ return `${Math.max(20, charWidth + 4)}px`;
3656
3955
  });
3956
+ const initSelectedUsers = async () => {
3957
+ const ids = modelValueIds.value;
3958
+ if (ids.length === 0) {
3959
+ selectedUsers.value = [];
3960
+ return;
3961
+ }
3962
+ let userGroupSelected = [];
3963
+ if (props.userGroup.length > 0) {
3964
+ const result = props.userGroup.filter((group) => ids.includes(group.id));
3965
+ userGroupSelected = result.map((group) => ({
3966
+ ...group,
3967
+ tenantId: "",
3968
+ type: USER_TYPE.USER_GROUP
3969
+ }));
3970
+ }
3971
+ try {
3972
+ const result = await lookupUsers({
3973
+ apiBaseUrl: props.apiBaseUrl,
3974
+ tenantId: props.tenantId,
3975
+ exactSearchKey: "bk_username",
3976
+ usersList: ids,
3977
+ enableMultiTenantMode: props.enableMultiTenantMode
3978
+ });
3979
+ const selectedList = [...userGroupSelected, ...formatUsers(result, props.enableMultiTenantMode)];
3980
+ if (props.allowCreate) {
3981
+ selectedList.push(
3982
+ ...ids.filter((id) => !selectedList.some((user) => user.id === id)).map((id) => ({ id, name: id, type: USER_TYPE.CUSTOM, tenantId: "" }))
3983
+ );
3984
+ }
3985
+ selectedUsers.value = ids.map((id) => selectedList.find((user) => user.id === id)).filter(Boolean);
3986
+ } catch (error) {
3987
+ console.error("获取选中用户信息失败:", error);
3988
+ selectedUsers.value = [];
3989
+ }
3990
+ };
3991
+ function updateSelectedUsers(users) {
3992
+ selectedUsers.value = users;
3993
+ if (props.multiple) {
3994
+ const ids = users.map((user) => user.id);
3995
+ emit("update:modelValue", ids);
3996
+ emit("change", users);
3997
+ } else {
3998
+ const user = users.length > 0 ? users[0] : null;
3999
+ const id = user ? user.id : "";
4000
+ emit("update:modelValue", id);
4001
+ emit("change", user);
4002
+ }
4003
+ }
3657
4004
  const initSortable = () => {
3658
- if (!props.draggable || !sortableContainerRef.value) return;
4005
+ if (!props.draggable || !props.multiple || !sortableContainerRef.value) return;
3659
4006
  if (sortableInstance.value) {
3660
4007
  sortableInstance.value.destroy();
3661
4008
  }
@@ -3668,276 +4015,206 @@
3668
4015
  onEnd: (evt) => {
3669
4016
  const { oldIndex, newIndex } = evt;
3670
4017
  if (oldIndex === newIndex || oldIndex === void 0 || newIndex === void 0) return;
3671
- const updatedUsers = [...props.selectedUsers];
4018
+ const updatedUsers = [...selectedUsers.value];
3672
4019
  const [movedUser] = updatedUsers.splice(oldIndex, 1);
3673
4020
  updatedUsers.splice(newIndex, 0, movedUser);
3674
- emit("update:selectedUsers", updatedUsers);
4021
+ updateSelectedUsers(updatedUsers);
3675
4022
  emit("dragEnd", evt);
3676
4023
  }
3677
4024
  });
3678
4025
  };
3679
4026
  const calculateVisibleUsers = () => {
3680
- if (!collapsedContainerRef.value || !props.selectedUsers.length) {
4027
+ if (!selectedUsers.value.length) {
3681
4028
  visibleUsers.value = [];
3682
4029
  hiddenCount.value = 0;
3683
4030
  return;
3684
4031
  }
4032
+ if (!collapsedContainerRef.value) {
4033
+ visibleUsers.value = [...selectedUsers.value];
4034
+ hiddenCount.value = 0;
4035
+ return;
4036
+ }
3685
4037
  const containerWidth = collapsedContainerRef.value.offsetWidth;
3686
4038
  const tagElements = collapsedContainerRef.value.querySelectorAll(".user-tag");
4039
+ if (tagElements.length !== selectedUsers.value.length) {
4040
+ visibleUsers.value = [...selectedUsers.value];
4041
+ hiddenCount.value = 0;
4042
+ vue.nextTick(calculateVisibleUsers);
4043
+ return;
4044
+ }
3687
4045
  const visibleCount = calculateVisibleTags(
3688
4046
  collapsedContainerRef.value,
3689
4047
  tagElements,
3690
- containerWidth - 100
3691
- // 为输入框和更多标签预留空间
4048
+ containerWidth - RESERVED_SPACE_FOR_INPUT
3692
4049
  );
3693
- visibleUsers.value = props.selectedUsers.slice(0, visibleCount);
3694
- hiddenCount.value = Math.max(0, props.selectedUsers.length - visibleCount);
4050
+ visibleUsers.value = selectedUsers.value.slice(0, visibleCount);
4051
+ hiddenCount.value = Math.max(0, selectedUsers.value.length - visibleCount);
3695
4052
  };
3696
4053
  const handleFocus = () => {
3697
4054
  isFocused.value = true;
3698
- if (props.userGroup.length > 0) {
3699
- showDropdown.value = true;
3700
- } else {
3701
- showDropdown.value = false;
3702
- }
3703
4055
  activeTagIndex.value = -1;
3704
4056
  vue.nextTick(() => {
3705
- if (lastInputRef.value) {
3706
- lastInputRef.value.focus();
3707
- }
4057
+ var _a;
4058
+ return (_a = lastInputRef.value) == null ? void 0 : _a.focus();
3708
4059
  });
3709
4060
  };
4061
+ const scheduleVisibleUsersCalculation = () => {
4062
+ if (!isFocused.value) {
4063
+ vue.nextTick(calculateVisibleUsers);
4064
+ }
4065
+ };
3710
4066
  const handleClickOutside = (event) => {
3711
4067
  const target = event.target;
3712
4068
  const container = containerRef.value;
3713
- if ((container == null ? void 0 : container.contains(target)) || container === target) {
3714
- return;
3715
- }
3716
- if (isFocused.value) {
3717
- emit("blur");
3718
- }
4069
+ if ((container == null ? void 0 : container.contains(target)) || container === target) return;
4070
+ if (isFocused.value) emit("blur");
3719
4071
  isFocused.value = false;
3720
- showDropdown.value = false;
3721
4072
  activeTagIndex.value = -1;
3722
- searchQuery.value = "";
3723
- vue.nextTick(() => {
3724
- calculateVisibleUsers();
3725
- });
4073
+ clearSearch();
4074
+ scheduleVisibleUsersCalculation();
3726
4075
  };
3727
4076
  const handleContainerClick = () => {
3728
4077
  activeTagIndex.value = -1;
3729
4078
  vue.nextTick(() => {
3730
- if (lastInputRef.value) {
3731
- lastInputRef.value.focus();
3732
- }
4079
+ var _a;
4080
+ return (_a = lastInputRef.value) == null ? void 0 : _a.focus();
3733
4081
  });
3734
4082
  };
3735
4083
  const handleTagClick = (index) => {
3736
4084
  activeTagIndex.value = index;
3737
4085
  vue.nextTick(() => {
3738
4086
  var _a;
3739
- if (activeTagIndex.value === props.selectedUsers.length - 1) {
3740
- if (lastInputRef.value) {
3741
- lastInputRef.value.focus();
3742
- }
3743
- } else if ((_a = inlineInputRef.value) == null ? void 0 : _a[0]) {
3744
- inlineInputRef.value[0].focus();
3745
- }
4087
+ const isLastTag = index === selectedUsers.value.length - 1;
4088
+ const targetInput = isLastTag ? lastInputRef.value : (_a = inlineInputRef.value) == null ? void 0 : _a[0];
4089
+ targetInput == null ? void 0 : targetInput.focus();
3746
4090
  });
3747
4091
  };
3748
4092
  const handleInputFocus = () => {
3749
4093
  emit("focus");
3750
- if (!isFocused.value) {
3751
- isFocused.value = true;
3752
- }
3753
- if (searchQuery.value.length >= 1) {
3754
- showDropdown.value = true;
3755
- }
4094
+ isFocused.value = true;
3756
4095
  };
3757
4096
  const handleInput = () => {
3758
4097
  handleSearchInput(searchQuery.value);
3759
- if (searchQuery.value.length >= 1) {
3760
- showDropdown.value = true;
3761
- } else {
3762
- showDropdown.value = false;
3763
- }
3764
4098
  };
3765
4099
  const addCurrentUser = async () => {
3766
- if (!props.currentUserId || props.selectedUsers.some((user) => user.id === props.currentUserId)) return;
3767
- try {
3768
- const result = await lookupUsers({
3769
- apiBaseUrl: props.apiBaseUrl,
3770
- tenantId: props.tenantId,
3771
- exactSearchKey: props.exactSearchKey,
3772
- usersList: [props.currentUserId],
3773
- enableMultiTenantMode: props.enableMultiTenantMode
3774
- });
3775
- const formattedUsers = formatUsers(result, props.enableMultiTenantMode);
3776
- if (formattedUsers.length > 0) {
3777
- if (!props.selectedUsers.some((item) => item.id === formattedUsers[0].id)) {
3778
- emit("update:selectedUsers", [...props.selectedUsers, formattedUsers[0]]);
3779
- emit("add-user", formattedUsers[0]);
3780
- }
3781
- searchQuery.value = "";
3782
- showDropdown.value = false;
3783
- }
3784
- } catch (error) {
3785
- console.error("获取当前用户信息失败:", error);
4100
+ if (!props.currentUserId || selectedUsers.value.some((user) => user[props.exactSearchKey] === props.currentUserId))
4101
+ return;
4102
+ if (props.multiple && isMaxCountReached.value) {
4103
+ return;
3786
4104
  }
3787
- };
3788
- const handlePaste = async (event) => {
3789
- var _a;
3790
- event.preventDefault();
3791
- const pastedText = ((_a = event.clipboardData) == null ? void 0 : _a.getData("text")) || "";
3792
- if (pastedText.trim()) {
3793
- try {
3794
- const usersList = pastedText.trim().split(/[,,;\n\s]+/).filter(Boolean);
3795
- const users = usersList.map((user) => user.trim().replace(/\s*\(.*?\)\s*/, "")).filter((user) => user);
3796
- const result = await lookupUsers({
3797
- apiBaseUrl: props.apiBaseUrl,
3798
- tenantId: props.tenantId,
3799
- exactSearchKey: "login_name",
3800
- usersList: users,
3801
- enableMultiTenantMode: props.enableMultiTenantMode
3802
- });
3803
- const formattedUsers = formatUsers(result, props.enableMultiTenantMode);
3804
- if (formattedUsers.length > 0) {
3805
- const userMap = /* @__PURE__ */ new Map();
3806
- [...props.selectedUsers, ...formattedUsers].forEach((user) => {
3807
- if (!userMap.has(user.id)) {
3808
- userMap.set(user.id, user);
3809
- }
3810
- });
3811
- const updatedUsers = Array.from(userMap.values());
3812
- if (props.freePaste) {
3813
- const pastedUsers = usersList.map((user) => ({
3814
- id: user,
3815
- name: user,
3816
- type: "custom",
3817
- tenantId: "",
3818
- login_name: user
3819
- }));
3820
- pastedUsers.forEach((user) => {
3821
- if (!updatedUsers.some((item) => item.login_name === user.login_name)) {
3822
- addUser(user);
3823
- }
3824
- });
3825
- } else {
3826
- emit("update:selectedUsers", updatedUsers);
3827
- }
3828
- } else {
3829
- if (props.freePaste) {
3830
- const pastedUsers = usersList.map((user) => ({
3831
- id: user,
3832
- name: user,
3833
- type: "custom",
3834
- tenantId: "",
3835
- login_name: user
3836
- }));
3837
- pastedUsers.forEach((user) => {
3838
- if (!props.selectedUsers.some((item) => item.login_name === user.login_name)) {
3839
- addUser(user);
3840
- }
3841
- });
3842
- }
3843
- }
3844
- } catch (error) {
3845
- console.error("精准查找用户失败:", error);
4105
+ const currentUser = await fetchCurrentUser();
4106
+ if (currentUser) {
4107
+ if (!props.multiple) {
4108
+ updateSelectedUsers([currentUser]);
4109
+ } else if (!selectedUsers.value.some((item) => item.id === currentUser.id)) {
4110
+ updateSelectedUsers([...selectedUsers.value, currentUser]);
3846
4111
  }
4112
+ clearSearch();
4113
+ isFocused.value = true;
4114
+ vue.nextTick(() => {
4115
+ var _a;
4116
+ return (_a = lastInputRef.value) == null ? void 0 : _a.focus();
4117
+ });
3847
4118
  }
3848
4119
  };
4120
+ const onPaste = (event) => {
4121
+ handlePaste(event);
4122
+ };
3849
4123
  const handleKeyDown = (event) => {
3850
- if (event.key === "Backspace" && !searchQuery.value && props.selectedUsers.length > 0) {
4124
+ if (event.key === "Backspace" && !searchQuery.value && selectedUsers.value.length > 0) {
3851
4125
  if (activeTagIndex.value >= 0) {
3852
- const userToRemove = props.selectedUsers[activeTagIndex.value];
4126
+ const userToRemove = selectedUsers.value[activeTagIndex.value];
3853
4127
  removeUser(userToRemove);
3854
- if (activeTagIndex.value > 0) {
3855
- activeTagIndex.value = activeTagIndex.value - 1;
3856
- } else {
3857
- activeTagIndex.value = -1;
3858
- }
4128
+ activeTagIndex.value = activeTagIndex.value > 0 ? activeTagIndex.value - 1 : -1;
3859
4129
  } else {
3860
- const lastUser = props.selectedUsers[props.selectedUsers.length - 1];
4130
+ const lastUser = selectedUsers.value[selectedUsers.value.length - 1];
3861
4131
  removeUser(lastUser);
3862
4132
  }
3863
- } else if (event.key === "Enter" && props.allowCreate) {
3864
- addUser({
3865
- id: searchQuery.value,
3866
- name: searchQuery.value,
3867
- type: "custom",
3868
- tenantId: "",
3869
- login_name: searchQuery.value
3870
- });
4133
+ } else if (event.key === "Enter" && props.allowCreate && searchQuery.value) {
4134
+ addUser(createCustomUser(searchQuery.value));
3871
4135
  }
3872
4136
  };
3873
- const addUser = (user) => {
4137
+ function addUser(user) {
3874
4138
  if (!(user == null ? void 0 : user.id)) return;
3875
- if (!props.selectedUsers.some((item) => item.id === user.id)) {
4139
+ if (props.multiple && isMaxCountReached.value) {
4140
+ clearSearch();
4141
+ return;
4142
+ }
4143
+ if (!props.multiple) {
4144
+ updateSelectedUsers([user]);
4145
+ } else if (!selectedUsers.value.some((item) => item.id === user.id)) {
4146
+ const updatedUsers = activeTagIndex.value !== -1 ? [
4147
+ ...selectedUsers.value.slice(0, activeTagIndex.value + 1),
4148
+ user,
4149
+ ...selectedUsers.value.slice(activeTagIndex.value + 1)
4150
+ ] : [...selectedUsers.value, user];
4151
+ updateSelectedUsers(updatedUsers);
4152
+ }
4153
+ if (activeTagIndex.value !== -1) {
4154
+ activeTagIndex.value = activeTagIndex.value + 1;
4155
+ }
4156
+ clearSearch();
4157
+ isFocused.value = true;
4158
+ vue.nextTick(() => {
4159
+ var _a, _b, _c;
3876
4160
  if (activeTagIndex.value !== -1) {
3877
- const updatedUsers = [
3878
- ...props.selectedUsers.slice(0, activeTagIndex.value + 1),
3879
- user,
3880
- ...props.selectedUsers.slice(activeTagIndex.value + 1)
3881
- ];
3882
- emit("update:selectedUsers", updatedUsers);
4161
+ (_b = (_a = inlineInputRef.value) == null ? void 0 : _a[0]) == null ? void 0 : _b.focus();
3883
4162
  } else {
3884
- emit("update:selectedUsers", [...props.selectedUsers, user]);
4163
+ (_c = lastInputRef.value) == null ? void 0 : _c.focus();
3885
4164
  }
3886
- emit("add-user", user);
3887
- }
3888
- searchQuery.value = "";
3889
- showDropdown.value = false;
3890
- vue.nextTick(() => {
3891
- var _a;
3892
- (_a = lastInputRef.value) == null ? void 0 : _a.focus();
3893
4165
  });
3894
- };
4166
+ }
3895
4167
  const removeUser = (user) => {
3896
4168
  if (!(user == null ? void 0 : user.id)) return;
3897
- const updatedUsers = props.selectedUsers.filter((item) => item.id !== user.id);
3898
- emit("update:selectedUsers", updatedUsers);
3899
- emit("remove-user", user);
4169
+ const updatedUsers = selectedUsers.value.filter((item) => item.id !== user.id);
4170
+ updateSelectedUsers(updatedUsers);
3900
4171
  if (activeTagIndex.value >= updatedUsers.length) {
3901
- activeTagIndex.value = updatedUsers.length - 1;
3902
- }
3903
- if (!isFocused.value) {
3904
- vue.nextTick(() => {
3905
- calculateVisibleUsers();
3906
- });
4172
+ activeTagIndex.value = updatedUsers.length - 1;
3907
4173
  }
4174
+ scheduleVisibleUsersCalculation();
3908
4175
  };
3909
- const crossAxisOffset = vue.ref(0);
3910
4176
  vue.watch(
3911
- () => props.selectedUsers,
4177
+ selectedUsers,
3912
4178
  () => {
3913
- visibleUsers.value = [...props.selectedUsers];
3914
- if (!isFocused.value) {
3915
- vue.nextTick(() => {
3916
- calculateVisibleUsers();
3917
- });
3918
- }
4179
+ scheduleVisibleUsersCalculation();
3919
4180
  },
3920
4181
  { deep: true }
3921
4182
  );
3922
4183
  vue.watch(isFocused, (newVal) => {
3923
4184
  if (newVal) {
3924
- vue.nextTick(() => {
3925
- initSortable();
3926
- });
4185
+ vue.nextTick(() => initSortable());
3927
4186
  }
3928
4187
  });
3929
- const handleResize = () => {
3930
- if (!isFocused.value) {
3931
- calculateVisibleUsers();
4188
+ vue.watch(
4189
+ () => props.userGroup,
4190
+ () => {
4191
+ initSelectedUsers();
3932
4192
  }
3933
- };
4193
+ );
4194
+ vue.watch(
4195
+ () => props.modelValue,
4196
+ () => {
4197
+ const currentIds = selectedUsers.value.map((u) => u.id);
4198
+ const newIds = modelValueIds.value;
4199
+ if (currentIds.length !== newIds.length || !currentIds.every((id, index) => id === newIds[index])) {
4200
+ initSelectedUsers();
4201
+ }
4202
+ },
4203
+ { deep: true }
4204
+ );
4205
+ useResizeObserver(containerRef, () => {
4206
+ scheduleVisibleUsersCalculation();
4207
+ });
4208
+ vue.onBeforeMount(() => {
4209
+ initSelectedUsers();
4210
+ });
3934
4211
  vue.onMounted(() => {
3935
4212
  initSortable();
3936
- calculateVisibleUsers();
3937
- window.addEventListener("resize", handleResize);
3938
- vue.nextTick(() => {
3939
- calculateVisibleUsers();
3940
- });
4213
+ vue.nextTick(calculateVisibleUsers);
4214
+ });
4215
+ vue.onUnmounted(() => {
4216
+ var _a;
4217
+ (_a = sortableInstance.value) == null ? void 0 : _a.destroy();
3941
4218
  });
3942
4219
  return (_ctx, _cache) => {
3943
4220
  return vue.openBlock(), vue.createElementBlock(
@@ -3945,34 +4222,32 @@
3945
4222
  {
3946
4223
  ref_key: "containerRef",
3947
4224
  ref: containerRef,
3948
- class: vue.normalizeClass(["multiple-selector", { "is-disabled": _ctx.disabled }])
4225
+ class: vue.normalizeClass(["bk-user-selector", { "is-disabled": _ctx.disabled }])
3949
4226
  },
3950
4227
  [
3951
4228
  vue.createCommentVNode(" 下拉选项列表 "),
3952
4229
  vue.createVNode(SelectionPopover, {
4230
+ "avatar-base-url": _ctx.avatarBaseUrl,
3953
4231
  "container-width": containerRef.value ? containerRef.value.offsetWidth : "auto",
3954
- "cross-axis-offset": crossAxisOffset.value,
3955
- "empty-text": _ctx.emptyText,
4232
+ "empty-text": computedEmptyText.value,
4233
+ "has-avatar": _ctx.hasAvatar,
3956
4234
  "is-show": showDropdown.value,
3957
4235
  loading: vue.unref(searchLoading),
3958
- options: options.value,
4236
+ options: displayOptions.value,
3959
4237
  "render-list-item": _ctx.renderListItem,
3960
4238
  "search-query": vue.unref(searchQuery),
3961
4239
  "tenant-id": _ctx.tenantId,
3962
- tenants: _ctx.tenants,
3963
- "user-group": userGroupFilter.value,
3964
- "user-group-name": _ctx.userGroupName,
4240
+ tenants: vue.unref(tenants),
4241
+ "user-group": vue.unref(filteredUserGroup),
4242
+ "user-group-name": computedUserGroupName.value,
3965
4243
  onClickOutside: handleClickOutside,
3966
4244
  onSelectUser: addUser
3967
4245
  }, {
3968
4246
  default: vue.withCtx(() => [
3969
4247
  vue.createCommentVNode(" 聚焦状态 - 可编辑模式 "),
3970
- isFocused.value ? (vue.openBlock(), vue.createElementBlock(
4248
+ vue.withDirectives(vue.createElementVNode(
3971
4249
  "div",
3972
4250
  {
3973
- key: 0,
3974
- ref_key: "tagsContainerRef",
3975
- ref: tagsContainerRef,
3976
4251
  class: "tags-container focused",
3977
4252
  onClick: vue.withModifiers(handleContainerClick, ["stop"])
3978
4253
  },
@@ -3989,24 +4264,20 @@
3989
4264
  (vue.openBlock(true), vue.createElementBlock(
3990
4265
  vue.Fragment,
3991
4266
  null,
3992
- vue.renderList(_ctx.selectedUsers, (user, index) => {
4267
+ vue.renderList(selectedUsers.value, (user, index) => {
3993
4268
  return vue.openBlock(), vue.createElementBlock("div", {
3994
4269
  key: user.id,
3995
- class: "tag-wrapper",
3996
- onClick: vue.withModifiers(($event) => handleTagClick(index), ["stop"])
4270
+ class: "tag-wrapper"
3997
4271
  }, [
3998
- vue.createVNode(UserTag, {
4272
+ vue.createVNode(UserTag, vue.mergeProps({ ref_for: true }, userTagCommonProps.value, {
3999
4273
  active: index === activeTagIndex.value,
4000
- "current-tenant-id": _ctx.tenantId,
4001
- draggable: _ctx.draggable,
4002
- "render-tag": _ctx.renderTag,
4003
- tenants: _ctx.tenants,
4274
+ draggable: _ctx.draggable && _ctx.multiple,
4004
4275
  user,
4005
4276
  onClick: ($event) => handleTagClick(index),
4006
4277
  onClose: ($event) => removeUser(user)
4007
- }, null, 8, ["active", "current-tenant-id", "draggable", "render-tag", "tenants", "user", "onClick", "onClose"]),
4278
+ }), null, 16, ["active", "draggable", "user", "onClick", "onClose"]),
4008
4279
  vue.createCommentVNode(" 在当前激活标签后插入输入框 "),
4009
- index === activeTagIndex.value && activeTagIndex.value !== _ctx.selectedUsers.length - 1 ? vue.withDirectives((vue.openBlock(), vue.createElementBlock(
4280
+ index === activeTagIndex.value && activeTagIndex.value !== selectedUsers.value.length - 1 ? vue.withDirectives((vue.openBlock(), vue.createElementBlock(
4010
4281
  "input",
4011
4282
  {
4012
4283
  key: 0,
@@ -4014,42 +4285,45 @@
4014
4285
  ref_key: "inlineInputRef",
4015
4286
  ref: inlineInputRef,
4016
4287
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => vue.isRef(searchQuery) ? searchQuery.value = $event : null),
4017
- class: "search-input inline",
4288
+ autofocus: "",
4289
+ class: "search-input input-inline",
4290
+ style: vue.normalizeStyle({ width: inputWidth.value }),
4018
4291
  onFocus: handleInputFocus,
4019
4292
  onInput: handleInput,
4020
4293
  onKeydown: handleKeyDown,
4021
- onPaste: handlePaste
4294
+ onPaste
4022
4295
  },
4023
4296
  null,
4024
- 544
4025
- /* NEED_HYDRATION, NEED_PATCH */
4297
+ 36
4298
+ /* STYLE, NEED_HYDRATION */
4026
4299
  )), [
4027
4300
  [vue.vModelText, vue.unref(searchQuery)]
4028
4301
  ]) : vue.createCommentVNode("v-if", true)
4029
- ], 8, _hoisted_1$1);
4302
+ ]);
4030
4303
  }),
4031
4304
  128
4032
4305
  /* KEYED_FRAGMENT */
4033
4306
  )),
4034
4307
  vue.createCommentVNode(" 最后一个输入框 "),
4035
- activeTagIndex.value === -1 || activeTagIndex.value === _ctx.selectedUsers.length - 1 ? vue.withDirectives((vue.openBlock(), vue.createElementBlock("input", {
4308
+ activeTagIndex.value === -1 || activeTagIndex.value === selectedUsers.value.length - 1 ? vue.withDirectives((vue.openBlock(), vue.createElementBlock("input", {
4036
4309
  key: 0,
4037
4310
  ref_key: "lastInputRef",
4038
4311
  ref: lastInputRef,
4039
4312
  "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => vue.isRef(searchQuery) ? searchQuery.value = $event : null),
4040
- class: "search-input last",
4041
- placeholder: !_ctx.selectedUsers.length ? _ctx.placeholder : "",
4313
+ autofocus: "",
4314
+ class: "search-input input-last",
4315
+ placeholder: !selectedUsers.value.length ? computedPlaceholder.value : "",
4042
4316
  onFocus: handleInputFocus,
4043
4317
  onInput: handleInput,
4044
4318
  onKeydown: handleKeyDown,
4045
- onPaste: handlePaste
4046
- }, null, 40, _hoisted_2$1)), [
4319
+ onPaste
4320
+ }, null, 40, _hoisted_1)), [
4047
4321
  [vue.vModelText, vue.unref(searchQuery)]
4048
4322
  ]) : vue.createCommentVNode("v-if", true),
4049
4323
  vue.createCommentVNode(' "我"标签 '),
4050
4324
  vue.createVNode(MeTag, {
4051
4325
  "current-user-id": _ctx.currentUserId,
4052
- "is-disabled": !!_ctx.currentUserId && _ctx.selectedUsers.some((user) => user.id === _ctx.currentUserId),
4326
+ "is-disabled": isMeTagDisabled.value,
4053
4327
  onClick: addCurrentUser
4054
4328
  }, null, 8, ["current-user-id", "is-disabled"])
4055
4329
  ],
@@ -4059,580 +4333,102 @@
4059
4333
  ],
4060
4334
  512
4061
4335
  /* NEED_PATCH */
4062
- )) : (vue.openBlock(), vue.createElementBlock(
4063
- vue.Fragment,
4064
- { key: 1 },
4336
+ ), [
4337
+ [vue.vShow, isFocused.value]
4338
+ ]),
4339
+ vue.createCommentVNode(" 未聚焦状态 - 只读展示模式 "),
4340
+ vue.withDirectives(vue.createElementVNode(
4341
+ "div",
4342
+ {
4343
+ ref_key: "collapsedContainerRef",
4344
+ ref: collapsedContainerRef,
4345
+ class: "tags-container tags-container-collapsed",
4346
+ onClick: vue.withModifiers(handleFocus, ["stop"])
4347
+ },
4065
4348
  [
4066
- vue.createCommentVNode(" 未聚焦状态 - 只读展示模式 "),
4067
- vue.createElementVNode(
4068
- "div",
4069
- {
4070
- ref_key: "collapsedContainerRef",
4071
- ref: collapsedContainerRef,
4072
- class: "tags-container collapsed",
4073
- onClick: vue.withModifiers(handleFocus, ["stop"])
4074
- },
4075
- [
4076
- (vue.openBlock(true), vue.createElementBlock(
4077
- vue.Fragment,
4078
- null,
4079
- vue.renderList(visibleUsers.value, (user) => {
4080
- return vue.openBlock(), vue.createBlock(UserTag, {
4081
- key: user.id,
4082
- "current-tenant-id": _ctx.tenantId,
4083
- "render-tag": _ctx.renderTag,
4084
- "show-tenant": true,
4085
- tenants: _ctx.tenants,
4086
- user,
4087
- onClick: handleFocus,
4088
- onClose: ($event) => removeUser(user)
4089
- }, null, 8, ["current-tenant-id", "render-tag", "tenants", "user", "onClose"]);
4090
- }),
4091
- 128
4092
- /* KEYED_FRAGMENT */
4093
- )),
4094
- vue.createCommentVNode(" 显示折叠标签数量 "),
4095
- hiddenCount.value > 0 ? (vue.openBlock(), vue.createBlock(vue.unref(bkuiVue.Popover), {
4096
- key: 0,
4097
- placement: "top"
4098
- }, {
4099
- content: vue.withCtx(() => [
4100
- vue.createElementVNode("div", _hoisted_3, [
4101
- (vue.openBlock(true), vue.createElementBlock(
4102
- vue.Fragment,
4103
- null,
4104
- vue.renderList(_ctx.selectedUsers.slice(visibleUsers.value.length), (user) => {
4105
- return vue.openBlock(), vue.createBlock(vue.unref(UserRender), {
4106
- key: user.id,
4107
- "tenant-id": _ctx.tenantId,
4108
- tenants: _ctx.tenants,
4109
- user
4110
- }, null, 8, ["tenant-id", "tenants", "user"]);
4111
- }),
4112
- 128
4113
- /* KEYED_FRAGMENT */
4114
- ))
4115
- ])
4116
- ]),
4349
+ (vue.openBlock(true), vue.createElementBlock(
4350
+ vue.Fragment,
4351
+ null,
4352
+ vue.renderList(visibleUsers.value, (user) => {
4353
+ return vue.openBlock(), vue.createBlock(UserTag, vue.mergeProps({
4354
+ key: user.id,
4355
+ ref_for: true
4356
+ }, userTagCommonProps.value, {
4357
+ "show-tenant": true,
4358
+ user,
4359
+ onClick: handleFocus,
4360
+ onClose: ($event) => removeUser(user)
4361
+ }), null, 16, ["user", "onClose"]);
4362
+ }),
4363
+ 128
4364
+ /* KEYED_FRAGMENT */
4365
+ )),
4366
+ vue.createCommentVNode(" 显示折叠标签数量 "),
4367
+ hiddenCount.value > 0 ? (vue.openBlock(), vue.createBlock(vue.unref(bkuiVue.Popover), {
4368
+ key: 0,
4369
+ placement: "top"
4370
+ }, {
4371
+ content: vue.withCtx(() => [
4372
+ vue.createElementVNode("div", _hoisted_2, [
4373
+ (vue.openBlock(true), vue.createElementBlock(
4374
+ vue.Fragment,
4375
+ null,
4376
+ vue.renderList(selectedUsers.value.slice(visibleUsers.value.length), (user) => {
4377
+ return vue.openBlock(), vue.createBlock(vue.unref(UserRender), {
4378
+ key: user.id,
4379
+ "avatar-base-url": _ctx.avatarBaseUrl,
4380
+ "has-avatar": _ctx.hasAvatar,
4381
+ "tenant-id": _ctx.tenantId,
4382
+ tenants: vue.unref(tenants),
4383
+ user
4384
+ }, null, 8, ["avatar-base-url", "has-avatar", "tenant-id", "tenants", "user"]);
4385
+ }),
4386
+ 128
4387
+ /* KEYED_FRAGMENT */
4388
+ ))
4389
+ ])
4390
+ ]),
4391
+ default: vue.withCtx(() => [
4392
+ vue.createVNode(vue.unref(bkuiVue.Tag), null, {
4117
4393
  default: vue.withCtx(() => [
4118
- vue.createVNode(vue.unref(bkuiVue.Tag), null, {
4119
- default: vue.withCtx(() => [
4120
- vue.createTextVNode(
4121
- " +" + vue.toDisplayString(hiddenCount.value),
4122
- 1
4123
- /* TEXT */
4124
- )
4125
- ]),
4126
- _: 1
4127
- /* STABLE */
4128
- })
4394
+ vue.createTextVNode(
4395
+ " +" + vue.toDisplayString(hiddenCount.value),
4396
+ 1
4397
+ /* TEXT */
4398
+ )
4129
4399
  ]),
4130
4400
  _: 1
4131
4401
  /* STABLE */
4132
- })) : vue.createCommentVNode("v-if", true),
4133
- vue.createCommentVNode(" 搜索输入框 "),
4134
- vue.withDirectives(vue.createElementVNode("input", {
4135
- ref_key: "collapsedInputRef",
4136
- ref: collapsedInputRef,
4137
- "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => vue.isRef(searchQuery) ? searchQuery.value = $event : null),
4138
- class: "search-input collapsed",
4139
- placeholder: !_ctx.selectedUsers.length ? _ctx.placeholder : "",
4140
- onFocus: handleFocus
4141
- }, null, 40, _hoisted_4), [
4142
- [vue.vModelText, vue.unref(searchQuery)]
4143
- ]),
4144
- vue.createCommentVNode(' 未聚焦状态下的"我"标签 '),
4145
- vue.createVNode(MeTag, {
4146
- "current-user-id": _ctx.currentUserId,
4147
- "is-disabled": !!_ctx.currentUserId && _ctx.selectedUsers.some((user) => user[props.exactSearchKey] === _ctx.currentUserId),
4148
- onClick: addCurrentUser
4149
- }, null, 8, ["current-user-id", "is-disabled"])
4150
- ],
4151
- 512
4152
- /* NEED_PATCH */
4153
- )
4402
+ })
4403
+ ]),
4404
+ _: 1
4405
+ /* STABLE */
4406
+ })) : vue.createCommentVNode("v-if", true),
4407
+ vue.createCommentVNode(" 搜索输入框 "),
4408
+ vue.withDirectives(vue.createElementVNode("input", {
4409
+ "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => vue.isRef(searchQuery) ? searchQuery.value = $event : null),
4410
+ class: "search-input search-input-collapsed",
4411
+ placeholder: !selectedUsers.value.length ? computedPlaceholder.value : "",
4412
+ onFocus: handleFocus
4413
+ }, null, 40, _hoisted_3), [
4414
+ [vue.vModelText, vue.unref(searchQuery)]
4415
+ ]),
4416
+ vue.createCommentVNode(' 未聚焦状态下的""标签 '),
4417
+ vue.createVNode(MeTag, {
4418
+ "current-user-id": _ctx.currentUserId,
4419
+ "is-disabled": isMeTagDisabled.value,
4420
+ onClick: addCurrentUser
4421
+ }, null, 8, ["current-user-id", "is-disabled"])
4154
4422
  ],
4155
- 2112
4156
- /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
4157
- ))
4158
- ]),
4159
- _: 1
4160
- /* STABLE */
4161
- }, 8, ["container-width", "cross-axis-offset", "empty-text", "is-show", "loading", "options", "render-list-item", "search-query", "tenant-id", "tenants", "user-group", "user-group-name"])
4162
- ],
4163
- 2
4164
- /* CLASS */
4165
- );
4166
- };
4167
- }
4168
- });
4169
- const MultipleSelector = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-2a532f24"]]);
4170
- const _hoisted_1 = { class: "input-container" };
4171
- const _hoisted_2 = ["placeholder"];
4172
- const _sfc_main$1 = /* @__PURE__ */ vue.defineComponent({
4173
- ...{
4174
- name: "BkUserSelectorSingle"
4175
- },
4176
- __name: "single-selector",
4177
- props: {
4178
- modelValue: { default: "" },
4179
- tenants: {},
4180
- allowCreate: { type: Boolean },
4181
- apiBaseUrl: { default: "" },
4182
- currentUserId: { default: "" },
4183
- disabled: { type: Boolean },
4184
- emptyText: { default: "" },
4185
- enableMultiTenantMode: { type: Boolean },
4186
- exactSearchKey: { default: "bk_username" },
4187
- excludeUserIds: { default: () => [] },
4188
- freePaste: { type: Boolean },
4189
- placeholder: { default: "" },
4190
- tenantId: { default: "" },
4191
- userGroupName: { default: "" },
4192
- renderListItem: {},
4193
- renderTag: {},
4194
- userGroup: { default: () => [] }
4195
- },
4196
- emits: ["update:modelValue", "change", "focus", "blur"],
4197
- setup(__props, { emit: __emit }) {
4198
- const props = __props;
4199
- const emit = __emit;
4200
- const containerRef = vue.ref(null);
4201
- const inputRef = vue.ref(null);
4202
- const options = vue.ref([]);
4203
- const isLoading = vue.ref(false);
4204
- const selectedUser = vue.ref(props.modelValue || "");
4205
- const searchQuery = vue.ref("");
4206
- const showDropdown = vue.ref(false);
4207
- const userGroupFilter = vue.computed(() => {
4208
- return props.userGroup.filter((group) => {
4209
- var _a, _b;
4210
- const filtered = group.id !== selectedUser.value && !group.hidden;
4211
- if (filtered) {
4212
- return ((_a = group.id) == null ? void 0 : _a.includes(searchQuery.value)) || ((_b = group.name) == null ? void 0 : _b.includes(searchQuery.value));
4213
- }
4214
- return false;
4215
- });
4216
- });
4217
- const selectedUserInfo = vue.computed(() => {
4218
- const userGroup = (props.userGroup || []).map((group) => ({
4219
- ...group,
4220
- tenantId: "",
4221
- type: "userGroup"
4222
- }));
4223
- const list = [...options.value, ...userGroup];
4224
- const selectedUserInfo2 = list.find((user) => user.id === selectedUser.value);
4225
- emit("change", selectedUserInfo2 || null);
4226
- return selectedUserInfo2;
4227
- });
4228
- const initSelectedUser = async () => {
4229
- if (typeof props.modelValue === "string" && props.modelValue) {
4230
- try {
4231
- isLoading.value = true;
4232
- const result = await lookupUsers({
4233
- apiBaseUrl: props.apiBaseUrl,
4234
- tenantId: props.tenantId,
4235
- exactSearchKey: props.exactSearchKey,
4236
- usersList: [props.modelValue],
4237
- enableMultiTenantMode: props.enableMultiTenantMode
4238
- });
4239
- options.value = formatUsers(result, props.enableMultiTenantMode).filter(
4240
- (user) => !props.excludeUserIds.includes(user.id)
4241
- );
4242
- if (props.userGroup.length > 0) {
4243
- const groupResult = props.userGroup.filter((group) => group.id == props.modelValue);
4244
- options.value = groupResult.map((group) => ({
4245
- ...group,
4246
- tenantId: "",
4247
- type: "userGroup"
4248
- }));
4249
- }
4250
- if (props.allowCreate && options.value.length === 0) {
4251
- options.value.push({
4252
- id: props.modelValue,
4253
- name: props.modelValue,
4254
- type: "custom",
4255
- tenantId: ""
4256
- });
4257
- }
4258
- } catch (error) {
4259
- console.error("获取用户信息失败:", error);
4260
- } finally {
4261
- isLoading.value = false;
4262
- }
4263
- } else {
4264
- options.value = [];
4265
- }
4266
- };
4267
- vue.onBeforeMount(async () => {
4268
- initSelectedUser();
4269
- });
4270
- const addCurrentUser = async () => {
4271
- if (!props.currentUserId || selectedUser.value === props.currentUserId) return;
4272
- try {
4273
- const result = await lookupUsers({
4274
- apiBaseUrl: props.apiBaseUrl,
4275
- tenantId: props.tenantId,
4276
- exactSearchKey: props.exactSearchKey,
4277
- usersList: [props.currentUserId],
4278
- enableMultiTenantMode: props.enableMultiTenantMode
4279
- });
4280
- const formattedResults = formatUsers(result, props.enableMultiTenantMode);
4281
- if (formattedResults.length > 0) {
4282
- options.value = formattedResults.filter((user) => !props.excludeUserIds.includes(user.id));
4283
- addUser(formattedResults[0]);
4284
- }
4285
- } catch (error) {
4286
- console.error("获取当前用户信息失败:", error);
4287
- }
4288
- };
4289
- const fetchUsers = async (keyword = "") => {
4290
- if (!(keyword == null ? void 0 : keyword.length)) {
4291
- options.value = [];
4292
- isLoading.value = false;
4293
- return;
4294
- }
4295
- isLoading.value = true;
4296
- try {
4297
- const result = await searchUsers({
4298
- apiBaseUrl: props.apiBaseUrl,
4299
- tenantId: props.tenantId,
4300
- keyword,
4301
- enableMultiTenantMode: props.enableMultiTenantMode
4302
- });
4303
- options.value = formatUsers(result, props.enableMultiTenantMode).filter((user) => !selectedUser.value || user.id !== selectedUser.value).filter((user) => !props.excludeUserIds.includes(user.id));
4304
- } catch (error) {
4305
- console.error("获取用户列表失败:", error);
4306
- options.value = [];
4307
- } finally {
4308
- isLoading.value = false;
4309
- }
4310
- };
4311
- const handleKeyDown = (event) => {
4312
- if (event.key === "Enter") {
4313
- if (props.allowCreate) {
4314
- const customUser = {
4315
- id: searchQuery.value,
4316
- name: searchQuery.value,
4317
- tenantId: "",
4318
- type: "custom"
4319
- };
4320
- options.value.push(customUser);
4321
- addUser(customUser);
4322
- }
4323
- }
4324
- };
4325
- const handlePaste = (event) => {
4326
- var _a;
4327
- event.preventDefault();
4328
- const pastedText = ((_a = event.clipboardData) == null ? void 0 : _a.getData("text").trim()) || "";
4329
- if (props.freePaste) {
4330
- const customUser = { id: pastedText, name: pastedText, type: "custom", tenantId: "", login_name: pastedText };
4331
- if (!options.value.some((item) => item.login_name === customUser.login_name)) {
4332
- options.value.push(customUser);
4333
- }
4334
- addUser(customUser);
4335
- }
4336
- };
4337
- const addUser = (user) => {
4338
- selectedUser.value = user.id;
4339
- searchQuery.value = "";
4340
- showDropdown.value = false;
4341
- };
4342
- const removeSelectedUser = () => {
4343
- selectedUser.value = "";
4344
- searchQuery.value = "";
4345
- };
4346
- const handleInputFocus = () => {
4347
- if (searchQuery.value.length >= 1 || Array.isArray(props.userGroup) && props.userGroup.length > 0) {
4348
- showDropdown.value = true;
4349
- }
4350
- emit("focus");
4351
- };
4352
- let timer = null;
4353
- const handleInput = () => {
4354
- showDropdown.value = searchQuery.value.length >= 1;
4355
- isLoading.value = true;
4356
- clearTimeout(timer);
4357
- timer = setTimeout(() => {
4358
- fetchUsers(searchQuery.value);
4359
- }, 300);
4360
- };
4361
- const handleClickOutside = () => {
4362
- setTimeout(() => {
4363
- showDropdown.value = false;
4364
- }, 0);
4365
- };
4366
- vue.watch(
4367
- () => props.modelValue,
4368
- (newVal) => {
4369
- selectedUser.value = newVal;
4370
- }
4371
- );
4372
- vue.watch(selectedUser, (newVal) => {
4373
- emit("update:modelValue", newVal);
4374
- });
4375
- return (_ctx, _cache) => {
4376
- return vue.withDirectives((vue.openBlock(), vue.createElementBlock(
4377
- "div",
4378
- {
4379
- ref_key: "containerRef",
4380
- ref: containerRef,
4381
- class: vue.normalizeClass(["single-selector", { "is-disabled": _ctx.disabled }])
4382
- },
4383
- [
4384
- vue.createCommentVNode(" 使用新的公共下拉选项组件 "),
4385
- vue.createVNode(SelectionPopover, {
4386
- "container-width": containerRef.value ? containerRef.value.offsetWidth : "auto",
4387
- "empty-text": _ctx.emptyText,
4388
- "is-show": showDropdown.value,
4389
- loading: isLoading.value,
4390
- options: options.value,
4391
- "render-list-item": _ctx.renderListItem,
4392
- "search-query": searchQuery.value,
4393
- "tenant-id": _ctx.tenantId,
4394
- tenants: _ctx.tenants,
4395
- "user-group": userGroupFilter.value,
4396
- "user-group-name": _ctx.userGroupName,
4397
- onSelectUser: addUser
4398
- }, {
4399
- default: vue.withCtx(() => [
4400
- vue.createCommentVNode(" 输入框 "),
4401
- vue.createElementVNode("div", _hoisted_1, [
4402
- vue.createCommentVNode(" 用户标签显示 "),
4403
- selectedUserInfo.value ? (vue.openBlock(), vue.createElementBlock("div", {
4404
- key: 0,
4405
- onClick: vue.withModifiers(removeSelectedUser, ["stop"])
4406
- }, [
4407
- vue.createVNode(UserTag, {
4408
- "current-tenant-id": _ctx.tenantId,
4409
- "render-tag": _ctx.renderTag,
4410
- tenants: _ctx.tenants,
4411
- user: selectedUserInfo.value,
4412
- onClose: removeSelectedUser
4413
- }, null, 8, ["current-tenant-id", "render-tag", "tenants", "user"])
4414
- ])) : vue.createCommentVNode("v-if", true),
4415
- vue.withDirectives(vue.createElementVNode("input", {
4416
- ref_key: "inputRef",
4417
- ref: inputRef,
4418
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchQuery.value = $event),
4419
- class: "search-input",
4420
- placeholder: selectedUserInfo.value ? "" : _ctx.placeholder,
4421
- onBlur: _cache[1] || (_cache[1] = ($event) => emit("blur")),
4422
- onFocus: handleInputFocus,
4423
- onInput: handleInput,
4424
- onKeydown: handleKeyDown,
4425
- onPaste: handlePaste
4426
- }, null, 40, _hoisted_2), [
4427
- [vue.vModelText, searchQuery.value]
4428
- ]),
4429
- vue.createCommentVNode(' "我"标签 '),
4430
- vue.createVNode(MeTag, {
4431
- "current-user-id": _ctx.currentUserId,
4432
- "is-disabled": !!_ctx.currentUserId && !!selectedUserInfo.value && selectedUserInfo.value[_ctx.exactSearchKey] === _ctx.currentUserId,
4433
- onClick: addCurrentUser
4434
- }, null, 8, ["current-user-id", "is-disabled"])
4423
+ 512
4424
+ /* NEED_PATCH */
4425
+ ), [
4426
+ [vue.vShow, !isFocused.value]
4435
4427
  ])
4436
4428
  ]),
4437
4429
  _: 1
4438
4430
  /* STABLE */
4439
- }, 8, ["container-width", "empty-text", "is-show", "loading", "options", "render-list-item", "search-query", "tenant-id", "tenants", "user-group", "user-group-name"])
4440
- ],
4441
- 2
4442
- /* CLASS */
4443
- )), [
4444
- [vue.unref(bkuiVue.clickoutside), handleClickOutside]
4445
- ]);
4446
- };
4447
- }
4448
- });
4449
- const SingleSelector = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-cbe352a6"]]);
4450
- const _sfc_main = /* @__PURE__ */ vue.defineComponent({
4451
- ...{
4452
- name: "BkUserSelector"
4453
- },
4454
- __name: "user-selector",
4455
- props: {
4456
- draggable: { type: Boolean, default: false },
4457
- modelValue: { default: "" },
4458
- multiple: { type: Boolean, default: false },
4459
- allowCreate: { type: Boolean, default: false },
4460
- apiBaseUrl: { default: "" },
4461
- currentUserId: { default: "" },
4462
- disabled: { type: Boolean, default: false },
4463
- emptyText: { default: "" },
4464
- enableMultiTenantMode: { type: Boolean, default: true },
4465
- exactSearchKey: { default: "bk_username" },
4466
- excludeUserIds: { default: () => [] },
4467
- freePaste: { type: Boolean, default: false },
4468
- placeholder: { default: "" },
4469
- tenantId: { default: "" },
4470
- userGroupName: { default: "" },
4471
- renderListItem: {},
4472
- renderTag: {},
4473
- userGroup: { default: () => [] }
4474
- },
4475
- emits: ["update:modelValue", "change", "dragStart", "dragEnd", "focus", "blur"],
4476
- setup(__props, { emit: __emit }) {
4477
- const { t } = useI18n();
4478
- bkuiVue.provideGlobalConfig({
4479
- prefix: "bk"
4480
- });
4481
- const props = __props;
4482
- const emit = __emit;
4483
- const { tenants = {} } = useTenantData(props.apiBaseUrl, props.tenantId, props.enableMultiTenantMode);
4484
- const selectedUsers = vue.ref([]);
4485
- const selectedUser = vue.ref(props.multiple ? "" : props.modelValue);
4486
- const selectedUserIds = vue.computed(() => {
4487
- return props.multiple ? selectedUsers.value.map((user) => user.id) : [];
4488
- });
4489
- const placeholder = vue.computed(() => props.placeholder || t("请输入人员名称搜索"));
4490
- const userGroupName = vue.computed(() => props.userGroupName || t("用户群组"));
4491
- const emptyText = vue.computed(() => props.emptyText || t("无匹配人员"));
4492
- const initSelectedUsers = async () => {
4493
- if (props.multiple) {
4494
- const ids = Array.isArray(props.modelValue) ? props.modelValue : [];
4495
- let userGroupSelected = [];
4496
- if (props.userGroup.length > 0) {
4497
- const result = props.userGroup.filter((group) => ids.includes(group.id));
4498
- userGroupSelected = result.map((group) => ({
4499
- ...group,
4500
- tenantId: "",
4501
- type: "userGroup"
4502
- }));
4503
- }
4504
- if (ids.length > 0) {
4505
- try {
4506
- const result = await lookupUsers({
4507
- apiBaseUrl: props.apiBaseUrl,
4508
- tenantId: props.tenantId,
4509
- exactSearchKey: "bk_username",
4510
- usersList: ids,
4511
- enableMultiTenantMode: props.enableMultiTenantMode
4512
- });
4513
- const selectedList = [...userGroupSelected, ...formatUsers(result, props.enableMultiTenantMode)];
4514
- if (props.allowCreate) {
4515
- selectedList.push(
4516
- ...ids.filter((id) => !selectedList.some((user) => user.id === id)).map((id) => ({ id, name: id, type: "custom", tenantId: "" }))
4517
- );
4518
- }
4519
- selectedUsers.value = ids.map((id) => selectedList.find((user) => user.id === id)).filter(Boolean);
4520
- } catch (error) {
4521
- console.error("获取选中用户信息失败:", error);
4522
- }
4523
- } else {
4524
- selectedUsers.value = [];
4525
- }
4526
- } else {
4527
- selectedUser.value = props.modelValue;
4528
- }
4529
- };
4530
- const handleUpdateUser = (user) => {
4531
- emit("change", user);
4532
- };
4533
- const handleUpdateSelectedUsers = (users) => {
4534
- selectedUsers.value = users;
4535
- emit(
4536
- "update:modelValue",
4537
- users.map((user) => user.id)
4538
- );
4539
- emit("change", users);
4540
- };
4541
- const handleFocus = () => {
4542
- emit("focus");
4543
- };
4544
- const handleBlur = () => {
4545
- emit("blur");
4546
- };
4547
- vue.watch(selectedUser, (newVal) => {
4548
- if (!props.multiple) {
4549
- emit("update:modelValue", newVal);
4550
- }
4551
- });
4552
- vue.watch(
4553
- () => props.userGroup,
4554
- () => {
4555
- initSelectedUsers();
4556
- }
4557
- );
4558
- vue.watch(
4559
- () => props.modelValue,
4560
- () => {
4561
- initSelectedUsers();
4562
- },
4563
- { deep: true }
4564
- );
4565
- vue.onBeforeMount(() => {
4566
- initSelectedUsers();
4567
- });
4568
- return (_ctx, _cache) => {
4569
- return vue.openBlock(), vue.createElementBlock(
4570
- "section",
4571
- {
4572
- ref: "containerRef",
4573
- class: vue.normalizeClass(["bk-user-selector", { "is-disabled": _ctx.disabled }])
4574
- },
4575
- [
4576
- vue.createCommentVNode(" 单选模式 "),
4577
- !_ctx.multiple ? (vue.openBlock(), vue.createBlock(SingleSelector, {
4578
- key: 0,
4579
- modelValue: selectedUser.value,
4580
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => selectedUser.value = $event),
4581
- "allow-create": _ctx.allowCreate,
4582
- "api-base-url": _ctx.apiBaseUrl,
4583
- "current-user-id": _ctx.currentUserId,
4584
- disabled: _ctx.disabled,
4585
- "empty-text": emptyText.value,
4586
- "enable-multi-tenant-mode": _ctx.enableMultiTenantMode,
4587
- "exact-search-key": _ctx.exactSearchKey,
4588
- "exclude-user-ids": _ctx.excludeUserIds,
4589
- placeholder: placeholder.value,
4590
- "render-list-item": _ctx.renderListItem,
4591
- "render-tag": _ctx.renderTag,
4592
- "tenant-id": _ctx.tenantId,
4593
- tenants: vue.unref(tenants),
4594
- "user-group": _ctx.userGroup,
4595
- "user-group-name": userGroupName.value,
4596
- "free-paste": _ctx.freePaste,
4597
- onBlur: handleBlur,
4598
- onChange: handleUpdateUser,
4599
- onFocus: handleFocus
4600
- }, null, 8, ["modelValue", "allow-create", "api-base-url", "current-user-id", "disabled", "empty-text", "enable-multi-tenant-mode", "exact-search-key", "exclude-user-ids", "placeholder", "render-list-item", "render-tag", "tenant-id", "tenants", "user-group", "user-group-name", "free-paste"])) : (vue.openBlock(), vue.createElementBlock(
4601
- vue.Fragment,
4602
- { key: 1 },
4603
- [
4604
- vue.createCommentVNode(" 多选模式 "),
4605
- vue.createVNode(MultipleSelector, {
4606
- modelValue: selectedUserIds.value,
4607
- "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => selectedUserIds.value = $event),
4608
- "allow-create": _ctx.allowCreate,
4609
- "api-base-url": _ctx.apiBaseUrl,
4610
- "current-user-id": _ctx.currentUserId,
4611
- disabled: _ctx.disabled,
4612
- draggable: _ctx.draggable,
4613
- "empty-text": emptyText.value,
4614
- "enable-multi-tenant-mode": _ctx.enableMultiTenantMode,
4615
- "exact-search-key": _ctx.exactSearchKey,
4616
- "exclude-user-ids": _ctx.excludeUserIds,
4617
- placeholder: placeholder.value,
4618
- "render-list-item": _ctx.renderListItem,
4619
- "render-tag": _ctx.renderTag,
4620
- "selected-users": selectedUsers.value,
4621
- "tenant-id": _ctx.tenantId,
4622
- tenants: vue.unref(tenants),
4623
- "user-group": _ctx.userGroup,
4624
- "user-group-name": userGroupName.value,
4625
- "free-paste": _ctx.freePaste,
4626
- onBlur: handleBlur,
4627
- onDragEnd: _cache[2] || (_cache[2] = ($event) => _ctx.$emit("dragEnd", $event)),
4628
- onDragStart: _cache[3] || (_cache[3] = ($event) => _ctx.$emit("dragStart", $event)),
4629
- onFocus: handleFocus,
4630
- "onUpdate:selectedUsers": handleUpdateSelectedUsers
4631
- }, null, 8, ["modelValue", "allow-create", "api-base-url", "current-user-id", "disabled", "draggable", "empty-text", "enable-multi-tenant-mode", "exact-search-key", "exclude-user-ids", "placeholder", "render-list-item", "render-tag", "selected-users", "tenant-id", "tenants", "user-group", "user-group-name", "free-paste"])
4632
- ],
4633
- 2112
4634
- /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
4635
- ))
4431
+ }, 8, ["avatar-base-url", "container-width", "empty-text", "has-avatar", "is-show", "loading", "options", "render-list-item", "search-query", "tenant-id", "tenants", "user-group", "user-group-name"])
4636
4432
  ],
4637
4433
  2
4638
4434
  /* CLASS */
@@ -4640,7 +4436,7 @@
4640
4436
  };
4641
4437
  }
4642
4438
  });
4643
- const BkUserSelector = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-9c628c83"]]);
4439
+ const BkUserSelector = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-9975c7e1"]]);
4644
4440
  exports2.BkUserSelector = BkUserSelector;
4645
4441
  exports2.default = BkUserSelector;
4646
4442
  Object.defineProperties(exports2, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });