diff --git a/frontend/src/common/util.js b/frontend/src/common/util.js index c0d3b3759..89577f5fd 100644 --- a/frontend/src/common/util.js +++ b/frontend/src/common/util.js @@ -557,22 +557,26 @@ export function formatCodeData (type, payload, isEmpty = true) { } /** - * 递归查询匹配角色id - * - * @param {number} id - * @param {Array} list - */ -export function getTreeNode (id, list) { - for (let i = 0; i < list.length; i++) { - if (list[i].id === id) { - return list[i]; - } else if (list[i].sub_roles && list[i].sub_roles.length) { - const result = getTreeNode(id, list[i].sub_roles); - if (result) { - return result; - } + * 查找tree匹配条件的字段 + * + * @param {string} key 匹配的字段key + * @param {string} value 匹配的字段value + * @param {string} childKey 动态子集children字段 + * @param {Array} list 源数组 + */ +export function getTreeNode (list, key, value, childKey) { + const treeData = [...list]; + let node = treeData.shift(); + while (node) { + if (node[key] === value) { + return node; + } + if (node[childKey] && Array.isArray(node[childKey])) { + treeData.push(...node[childKey]); } + node = treeData.shift(); } + return node; } /** diff --git a/frontend/src/components/iam-limit-org-dialog/index.vue b/frontend/src/components/iam-limit-org-dialog/index.vue index a2dcc4317..29d3e845c 100644 --- a/frontend/src/components/iam-limit-org-dialog/index.vue +++ b/frontend/src/components/iam-limit-org-dialog/index.vue @@ -61,8 +61,7 @@ .confirm-content-wrapper { display: flex; align-items: center; - padding-top: 8px; - padding-bottom: 16px; + padding-bottom: 8px; word-break: break-all; .warn { font-size: 22px; diff --git a/frontend/src/css/mixins/member-table.css b/frontend/src/css/mixins/member-table.css index 4f717969c..7c158760c 100644 --- a/frontend/src/css/mixins/member-table.css +++ b/frontend/src/css/mixins/member-table.css @@ -2,29 +2,21 @@ .user-group-member-table { margin-top: 16px; border: none; - tr:hover { - .user, - .depart { - background: #fff; - } - } .user, .depart, .member-template { padding: 4px 6px; background: #f0f1f5; - width: max-content; border-radius: 2px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: max-content; i { font-size: 14px; color: #c4c6cc; } .name { - display: inline-block; - max-width: 350px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; vertical-align: bottom; } } @@ -39,5 +31,9 @@ cursor: pointer; } } + /deep/ .bk-table-fixed, + /deep/ .bk-table-fixed-right { + border-bottom: 0; + } } } diff --git a/frontend/src/directive/click-outside.js b/frontend/src/directive/click-outside.js new file mode 100644 index 000000000..55d20235b --- /dev/null +++ b/frontend/src/directive/click-outside.js @@ -0,0 +1,91 @@ +/* + * Tencent is pleased to support the open source community by making + * 蓝鲸智云-权限中心(BlueKing-IAM) available. + * + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * 蓝鲸智云-权限中心(BlueKing-IAM) is licensed under the MIT License. + * + * License for 蓝鲸智云-权限中心(BlueKing-IAM): + * + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and + * to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. +*/ + +const nodeList = []; +const clickCtx = '$clickoutSideCtx'; +let beginClick; +let seed = 0; + +document.addEventListener('mousedown', event => (beginClick = event)); + +document.addEventListener('mouseup', event => { + nodeList.forEach(node => { + node[clickCtx].clickoutSideHandler(event, beginClick); + }); +}); + +const clickoutSide = { + bind (el, binding, vNode) { + nodeList.push(el); + const id = seed++; + const clickoutSideHandler = (mouseup = {}, mousedown = {}) => { + if (!vNode.context // 点击在 vue 实例之外的 DOM 上 + || !mouseup.target + || !mousedown.target + || el.contains(mouseup.target) // 鼠标按下时的 DOM 节点是当前展开的组件的子元素 + || el.contains(mousedown.target) // 鼠标松开时的 DOM 节点是当前展开的组件的子元素 + || el === mouseup.target // 鼠标松开时的 DOM 节点是当前展开的组件的根元素 + || (vNode.context.popup // 当前点击元素是有弹出层的 + && ( + vNode.context.popup.contains(mouseup.target) // 鼠标按下时的 DOM 节点是当前有弹出层元素的子节点 + || vNode.context.popup.contains(mousedown.target) // 鼠标松开时的 DOM 节点是当前有弹出层元素的子节点 + ) + ) + ) { + return; + } + + if (binding.expression // 传入了指令绑定的表达式 + && el[clickCtx].callbackName // 当前元素的 clickOutside 对象中有回调函数名 + && vNode.context[el[clickCtx].callbackName] // vNode 中存在回调函数 + ) { + vNode.context[el[clickCtx].callbackName](mouseup, mousedown, el); + } else { + el[clickCtx].bindingFn && el[clickCtx].bindingFn(mouseup, mousedown, el); + } + }; + el[clickCtx] = { + id, + clickoutSideHandler, + callbackName: binding.expression, + callbackFn: binding.value + }; + }, + update (el, binding) { + const { expression, value } = binding; + el[clickCtx] = { ...el[clickCtx], ...{ callbackName: expression, callbackFn: value } }; + }, + unbind (el) { + for (let i = 0, len = nodeList.length; i < len; i++) { + if (nodeList[i][clickCtx].id === el[clickCtx].id) { + nodeList.splice(i, 1); + break; + } + } + } +}; + +export default clickoutSide; diff --git a/frontend/src/directive/index.js b/frontend/src/directive/index.js new file mode 100644 index 000000000..2ea094f57 --- /dev/null +++ b/frontend/src/directive/index.js @@ -0,0 +1,36 @@ +/* + * Tencent is pleased to support the open source community by making + * 蓝鲸智云-权限中心(BlueKing-IAM) available. + * + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * 蓝鲸智云-权限中心(BlueKing-IAM) is licensed under the MIT License. + * + * License for 蓝鲸智云-权限中心(BlueKing-IAM): + * + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and + * to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import Vue from 'vue'; +import clickoutSide from './click-outside'; + +const directives = { + clickoutSide +}; + +Object.keys(directives).forEach(key => { + Vue.directive(key, directives[key]); +}); diff --git a/frontend/src/main.js b/frontend/src/main.js index ab0b38aad..7099fe840 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -55,6 +55,7 @@ import './common/bkmagic'; // 全量引入自定义图标 import './assets/iconfont/style.css'; import '@icon-cool/bk-icon-bk-iam'; +import '@/directive'; Vue.component('app-exception', Exception); Vue.component('app-auth', AuthComponent); @@ -79,8 +80,6 @@ Vue.use(magicbox, { i18n: (key, args) => i18n.t(key, args) }); -console.log('start'); - const cn = require('./language/lang/zh'); const en = require('./language/lang/en'); diff --git a/frontend/src/views/group/components/iam-add-member.vue b/frontend/src/views/group/components/iam-add-member.vue index a2d08351d..bc4f5a692 100644 --- a/frontend/src/views/group/components/iam-add-member.vue +++ b/frontend/src/views/group/components/iam-add-member.vue @@ -814,16 +814,12 @@ if (!newVal && oldVal) { if (this.isBeingSearch) { this.infiniteTreeKey = new Date().getTime(); - if (this.isAllFlag) { + this.isBeingSearch = false; + if (this.isAllFlag || !this.isRatingManager) { this.fetchCategories(true, false); - } else { - if (this.isRatingManager) { - this.fetchRoleSubjectScope(true, false); - } else { - this.fetchCategories(true, false); - } + return; } - this.isBeingSearch = false; + this.fetchRoleSubjectScope(true, false); } } }, @@ -1330,59 +1326,43 @@ this.expiredAt = payload; }, + async fetchManagerOrg (treeLoading = false, dialogLoading = true) { + await this.isRatingManager + ? this.fetchRoleSubjectScope(treeLoading, dialogLoading) + : this.fetchCategories(treeLoading, dialogLoading); + }, + async fetchMemberList () { - if (this.curId) { - try { - const params = { - id: this.curId, - limit: 1000, - offset: 0 - }; - let url = 'userGroup/getUserGroupMemberList'; - if (['memberTemplate'].includes(this.routeMode)) { - url = 'memberTemplate/getSubjectTemplateMembers'; - } - const { data } = await this.$store.dispatch(url, params); - const results = data.results || []; - this.defaultDepartments = results.filter((item) => item.type === 'department'); - this.defaultUsers = results.filter((item) => item.type === 'user'); - // const defaultUsers = this.defaultUsers.map((v) => { - // return { - // ...v, - // username: v.username || v.id - // }; - // }); - // this.hasSelectedUsers = [...this.hasSelectedUsers, ...defaultUsers]; - // this.hasSelectedDepartments = [...this.hasSelectedDepartments, ...this.defaultDepartments]; - if (this.isRatingManager) { - this.fetchRoleSubjectScope(false, true); - } else { - this.fetchCategories(false, true); - } - } catch (e) { - console.error(e); - this.messageAdvancedError(e); - } finally { - this.requestQueue.shift(); - } - } else { - if (this.isRatingManager) { - this.fetchRoleSubjectScope(false, true); - } else { - this.fetchCategories(false, true); + if (!this.curId) { + await this.fetchManagerOrg(); + return; + } + try { + const params = { + id: this.curId, + limit: 1000, + offset: 0 + }; + let url = 'userGroup/getUserGroupMemberList'; + if (['memberTemplate'].includes(this.routeMode)) { + url = 'memberTemplate/getSubjectTemplateMembers'; } + const { data } = await this.$store.dispatch(url, params); + const results = data.results || []; + this.defaultDepartments = results.filter((item) => item.type === 'department'); + this.defaultUsers = results.filter((item) => item.type === 'user'); + await this.fetchManagerOrg(); + } catch (e) { + this.messageAdvancedError(e); + } finally { + this.requestQueue.shift(); } }, async fetchCategoriesList () { try { - if (this.isRatingManager) { - await this.fetchRoleSubjectScope(false, true); - } else { - await this.fetchCategories(false, true); - } + await this.fetchManagerOrg(); } catch (e) { - console.error(e); this.messageAdvancedError(e); } finally { this.requestQueue.shift(); @@ -1409,8 +1389,7 @@ child.expanded = false; child.disabled = false; child.type = child.type === 'user' ? 'user' : 'depart'; - // child.count = child.recursive_member_count - child.count = child.member_count; + child.count = child.recursive_member_count; child.showCount = child.type !== 'user'; child.async = child.child_count > 0 || child.member_count > 0; child.isNewMember = false; @@ -1418,6 +1397,9 @@ if (this.isLimitSelectNode(child)) { child.limitOrgNodeTip = this.$t(`m.dialog['用户范围过大,请重新选择']`); } + if (child.async && !child.count) { + child.count = (child.child_count || 0) + (child.member_count || 0); + } if (child.type === 'user') { child.username = child.id; if (this.hasSelectedUsers.length > 0) { @@ -1486,9 +1468,9 @@ child.isSelected = false; child.expanded = false; child.disabled = false; + child.showCount = true; child.type = 'depart'; child.count = child.recursive_member_count; - child.showCount = true; child.async = child.child_count > 0 || child.member_count > 0; child.isNewMember = false; child.parentNodeId = item.id; @@ -1496,6 +1478,9 @@ if (this.isLimitSelectNode(child)) { child.limitOrgNodeTip = this.$t(`m.dialog['用户范围过大,请重新选择']`); } + if (child.async && !child.count) { + child.count = (child.child_count || 0) + (child.member_count || 0); + } if (this.hasSelectedDepartments.length) { child.isSelected = this.hasSelectedDepartments.map((item) => item.id).includes(child.id); } else { @@ -1719,10 +1704,10 @@ child.showRadio = true; child.isSelected = false; child.expanded = false; - child.disabled = this.disabled; + child.showCount = true; child.type = 'depart'; + child.disabled = this.disabled; child.count = child.recursive_member_count; - child.showCount = true; child.async = child.child_count > 0 || child.member_count > 0; child.isNewMember = false; child.parentNodeId = payload.id; @@ -1730,6 +1715,9 @@ if (this.isLimitSelectNode(child)) { child.limitOrgNodeTip = this.$t(`m.dialog['用户范围过大,请重新选择']`); } + if (child.async && !child.count) { + child.count = (child.child_count || 0) + (child.member_count || 0); + } if (this.hasSelectedDepartments.length > 0) { child.isSelected = this.hasSelectedDepartments.map((item) => item.id).includes(child.id); } diff --git a/frontend/src/views/group/components/member-table.vue b/frontend/src/views/group/components/member-table.vue index 83b97fb51..27481e503 100644 --- a/frontend/src/views/group/components/member-table.vue +++ b/frontend/src/views/group/components/member-table.vue @@ -40,11 +40,10 @@ -
+
-
+
- - {{ node.name }} - - - {{ node.name }} - + class="cascade-custom-content" + @click="handleTriggerCopy(...arguments, node)"> + {{ node.name }}
@@ -126,7 +114,7 @@ v-bkloading="{ isLoading: tableLoading, opacity: 1 }" > -