diff --git a/.gitignore b/.gitignore index 08ad47ef2..67773e1cb 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ logs build.yml .codecc/ .vscode/ + + +pre-*-bkcodeai +bkcodeai.json diff --git a/frontend/package.json b/frontend/package.json index 196869130..66d6fd3ae 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -95,7 +95,7 @@ "acorn": "~6.4.2", "ansi-html-community": "0.0.8", "art-template": "^4.13.2", - "axios": "^0.21.3", + "axios": "^1.6.8", "babel-core": "^7.0.0-bridge.0", "babel-eslint": "~10.0.1", "babel-helper-vue-jsx-merge-props": "^2.0.3", @@ -106,7 +106,7 @@ "babel-plugin-syntax-jsx": "^6.18.0", "babel-plugin-transform-vue-jsx": "^4.0.1", "better-npm-run": "~0.1.1", - "bk-magic-vue": "^2.5.7", + "bk-magic-vue": "^2.5.9-beta.17", "body-parser": "~1.19.0", "chalk": "~2.4.2", "cheerio": "~1.0.0-rc.3", @@ -169,9 +169,9 @@ "postcss-url": "~8.0.0", "query-string": "~6.5.0", "rimraf": "~2.6.3", - "semver": "~6.1.0", + "semver": "~7.5.2", "shelljs": "~0.8.3", - "terser-webpack-plugin": "~1.2.4", + "terser-webpack-plugin": "~4.2.3", "transliteration": "~2.1.3", "url-loader": "~1.1.2", "url-parse": ">=1.5.3", diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 6ef1c6d32..8c905f566 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -8,7 +8,7 @@ { 'no-perm-app-layout': ['403'].includes(routeName) } ]"> @@ -33,11 +33,14 @@ :route-name="routeName" :user-group-id="userGroupId"> - - @@ -80,6 +83,7 @@ provide () { return { reload: this.reload, + reloadCurPage: this.reloadCurPage, showNoticeAlert: this.isShowNoticeAlert }; }, @@ -111,7 +115,7 @@ routeName: '', userGroupId: '', isRouterAlive: true, - showNoticeAlert: true, + showNoticeAlert: false, noticeApi: `${window.AJAX_URL_PREFIX}/notice/announcements/`, enableNotice: window.ENABLE_BK_NOTICE.toLowerCase() === 'true' }; @@ -119,7 +123,10 @@ computed: { ...mapGetters(['mainContentLoading', 'user', 'externalSystemsLayout']), isShowNoticeAlert () { - return this.enableNotice && this.showNoticeAlert && !this.externalSystemsLayout.hideNoticeAlert; + return this.showNoticeAlert && this.isEnableNoticeAlert; + }, + isEnableNoticeAlert () { + return this.enableNotice && !this.externalSystemsLayout.hideNoticeAlert; } }, watch: { @@ -329,7 +336,7 @@ }, handleShowAlertChange (isShow) { - console.log(444, isShow); + console.log(isShow, '跑马灯回调'); this.showNoticeAlert = isShow; } } @@ -400,11 +407,26 @@ } + .user-org-perm-container { + .main-scroller { + height: calc(100% + 278px); + } + .views-layout { + min-width: 100%; + overflow: hidden; + } + } + .notice-app-layout { height: calc(100% - 101px) !important; .main-scroller { height: calc(100% + 91px); } + .user-org-perm-container { + .main-scroller { + height: calc(100% + 312px); + } + } } .no-perm { @@ -414,5 +436,4 @@ background-color: #ffffff; } } - diff --git a/frontend/src/common/router-handle.js b/frontend/src/common/router-handle.js index c2470b621..2639c2c48 100644 --- a/frontend/src/common/router-handle.js +++ b/frontend/src/common/router-handle.js @@ -23,7 +23,7 @@ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ - + /** * 获取不同身份的router差异 * @@ -57,7 +57,8 @@ export const getRouterDiff = (payload) => { 'userGroupSetting', 'sensitivityLevel', 'memberTemplate', - 'resourcePermManage' + 'resourcePermManage', + 'userOrgPerm' ]; } if (payload === 'super_manager') { @@ -95,7 +96,8 @@ export const getRouterDiff = (payload) => { 'permTransfer', 'myManageSpaceSubDetail', 'sensitivityLevel', - 'resourcePermManage' + 'resourcePermManage', + 'userOrgPerm' ]; } if (payload === 'system_manager') { @@ -122,12 +124,11 @@ export const getRouterDiff = (payload) => { 'systemAccessRegistry', 'systemAccessOptimize', 'systemAccessComplete', - 'resourcePermiss', 'firstManageSpace', 'secondaryManageSpace', 'authorBoundary', 'myManageSpace', - 'sensitivityLevel' + 'userOrgPerm' ]; } if (payload === 'rating_manager') { @@ -197,7 +198,8 @@ export const getRouterDiff = (payload) => { 'userGroupSetting', 'sensitivityLevel', 'memberTemplate', - 'resourcePermManage' + 'resourcePermManage', + 'userOrgPerm' ]; } // payload其它取值默认返回全部菜单 @@ -243,13 +245,15 @@ export const getRouterDiff = (payload) => { 'authorBoundaryEditSecondLevel', 'secondaryManageSpace', 'myManageSpace', - 'MyManageSpaceCreate', - 'ResourcePermManage' + 'myManageSpaceCreate', + 'resourcePermManage', + 'resourcePermiss', + 'sensitivityLevel' ]; }; // 导航路由 -export const getNavRouterDiff = (navIndex) => { +export const getNavRouterDiff = (navIndex, managerPerm = '') => { if (navIndex === 0 || navIndex === '') { return [ 'userGroup', @@ -274,7 +278,8 @@ export const getNavRouterDiff = (navIndex) => { 'userGroupSetting', 'sensitivityLevel', 'memberTemplate', - 'resourcePermManage' + 'resourcePermManage', + 'userOrgPerm' ]; } @@ -325,12 +330,13 @@ export const getNavRouterDiff = (navIndex) => { 'userGroupSetting', 'sensitivityLevel', 'memberTemplate', - 'resourcePermManage' + 'resourcePermManage', + 'userOrgPerm' ]; } if (navIndex === 3) { - return [ + const menuList = [ 'applyCustomPerm', 'applyProvisionPerm', 'applyJoinUserGroup', @@ -355,15 +361,40 @@ export const getNavRouterDiff = (navIndex) => { 'permTemplate', 'permTemplateDetail', 'permTemplateCreate', - 'approvalProcess', 'authorBoundary', 'secondaryManageSpace', 'myManageSpace', + 'myManageSpaceCreate', 'secondaryManageSpaceCreate', 'secondaryManageSpaceDetail', + 'authorBoundaryEditFirstLevel', + 'authorBoundaryEditSecondLevel', + 'permTemplateEdit', + 'permTemplateDiff', + 'addGroupPerm', + 'groupPermRenewal', 'userGroupSetting', 'memberTemplate', - 'resourcePermManage' + 'resourcePermManage', + 'userOrgPerm' ]; + if (['hasSystemNoSuperManager'].includes(managerPerm)) { + // 非超管用户隐藏的路由 + const hideMenuList = [ + 'user', + 'approvalProcess', + 'ratingManager', + 'gradingAdminCreate', + 'gradingAdminDetail', + 'gradingAdminEdit', + 'gradingAdminUpdateTemplate' + ]; + const systemManagerMenu = [ + ...menuList, + ...hideMenuList + ]; + return systemManagerMenu; + } + return menuList; } }; diff --git a/frontend/src/common/util.js b/frontend/src/common/util.js index 3fdabaa35..de83cc12c 100644 --- a/frontend/src/common/util.js +++ b/frontend/src/common/util.js @@ -709,3 +709,23 @@ export function isEmojiCharacter (str) { } } } + +// 获取当前unix时间戳 +export function getNowTimeExpired () { + const nowTimestamp = +new Date() / 1000; + const timeList = String(nowTimestamp).split(''); + const timeIndex = timeList.findIndex((item) => item === '.'); + const timestamp = parseInt(timeList.splice(0, timeIndex).join(''), 10); + return timestamp; +} + +// 查找当前管理员最大身份划分导航栏下菜单 +export function getManagerMenuPerm (payload) { + const isSystemManager = payload.find((item) => ['system_manager'].includes(item.type)); + const isSuperManager = payload.find((item) => ['super_manager'].includes(item.type)); + // 最大为系统管理员 + if (isSystemManager && !isSuperManager) { + return 'hasSystemNoSuperManager'; + } + return ''; +} diff --git a/frontend/src/components/choose-ip/topology-tree.vue b/frontend/src/components/choose-ip/topology-tree.vue index 45c0c94fd..d8eb2b1d7 100644 --- a/frontend/src/components/choose-ip/topology-tree.vue +++ b/frontend/src/components/choose-ip/topology-tree.vue @@ -30,7 +30,7 @@ ref="topologyTableRef" size="small" data-test-id="topology_tree_group" - ext-cls="topology-tree-table" + :ext-cls="formatTableCls" :header-border="false" :outer-border="false" :max-height="formatTableHeight" @@ -220,7 +220,7 @@ ref="topologyTableRef" size="small" data-test-id="topology_tree_group" - ext-cls="topology-tree-table" + :ext-cls="formatTableCls" :header-border="false" :outer-border="false" :data="renderTopologyData" @@ -758,6 +758,12 @@ return false; }; }, + formatTableCls () { + if (this.resourceValue) { + return 'topology-tree-table topology-tree-table-radio'; + } + return 'topology-tree-table'; + }, isTreeEmpty () { return this.allTreeData.filter((item) => item.type === 'node').length === 0 || this.searchDisplayText === this.$t(`m.common['搜索结果为空']`); } @@ -2011,4 +2017,15 @@ } } } +/deep/ .topology-tree-table { + &.topology-tree-table-radio { + .bk-table-header-wrapper { + .cell { + .bk-form-checkbox { + display: none !important; + } + } + } + } +} diff --git a/frontend/src/components/custom-perm-system-policy/index.vue b/frontend/src/components/custom-perm-system-policy/index.vue index a61568ca3..3b27112d5 100644 --- a/frontend/src/components/custom-perm-system-policy/index.vue +++ b/frontend/src/components/custom-perm-system-policy/index.vue @@ -1,12 +1,21 @@ - - + + - {{ title }} + {{ title }} + + - {{ $t(`m.common['共']`) }} - {{ permLength }} - {{ $t(`m.common['个']`) }}{{ typeTitle }} + + ({{ $t(`m.common['共']`) }} + {{ permLength }} + {{ $t(`m.common['条']`) }}) + + + {{ $t(`m.common['共']`) }} + {{ permLength }} + {{ $t(`m.common['个']`) }}{{ typeTitle }} + @@ -18,7 +27,7 @@ - + {{ $t(`m.common['点击收起']`) }} @@ -50,6 +59,10 @@ type: String, default: '' }, + customPermRef: { + type: String, + default: '' + }, onePerm: { type: Number, default: 0 @@ -61,6 +74,10 @@ isAllDelete: { type: Boolean, default: false + }, + showCollapse: { + type: Boolean, + default: true } }, data () { @@ -71,13 +88,19 @@ watch: { expanded (value) { this.isExpanded = !!value; - } - }, - created () { - if (this.onePerm === 1) { - this.$nextTick(() => { - this.handleExpanded(); - }); + }, + onePerm: { + handler (value) { + if (value === 1) { + this.$nextTick(() => { + this.handleExpanded(false); + }); + } else { + this.isExpanded = false; + } + }, + immediate: true, + deep: true } }, methods: { @@ -87,11 +110,12 @@ this.$emit('on-expanded', false); }, - handleExpanded () { - this.isExpanded = !this.isExpanded; - this.$emit('update:expanded', true); - this.$emit('on-expanded', true); + handleExpanded (payload) { + this.isExpanded = !payload; + this.$emit('update:expanded', this.isExpanded); + this.$emit('on-expanded', this.isExpanded); }, + handleDeleteAll () { this.$emit('on-delete-all'); } @@ -173,5 +197,40 @@ } } } + + &.userOrgPerm-perm-item { + box-shadow: 0 2px 4px 0 #1919290d; + &:not(&:last-of-type) { + margin-bottom: 12px; + } + .header { + display: flex; + align-items: center; + height: 46px; + line-height: 46px; + padding: 0 32px; + .expanded-icon { + top: 18px; + } + } + .title { + color: #313238; + font-weight: 700; + } + .sub-title { + margin-left: 4px; + color: #63656e; + } + .number { + color: #3a84ff; + font-weight: 700; + } + .content { + .slot-content { + padding: 0 24px; + padding-bottom: 10px; + } + } + } } diff --git a/frontend/src/components/header-nav/index.css b/frontend/src/components/header-nav/index.css index c2d2ad271..5a22f109a 100644 --- a/frontend/src/components/header-nav/index.css +++ b/frontend/src/components/header-nav/index.css @@ -56,7 +56,7 @@ $cubic-bezier: cubic-bezier(0.4, 0, 0.2, 1); color: #3c96ff; } - .heaer-nav-title { + .header-nav-title { margin: 0; padding: 0 20px; display: inline-block; diff --git a/frontend/src/components/header-nav/index.vue b/frontend/src/components/header-nav/index.vue index 7ac5b5e0f..81c186f92 100644 --- a/frontend/src/components/header-nav/index.vue +++ b/frontend/src/components/header-nav/index.vue @@ -10,7 +10,7 @@ @@ -122,7 +122,7 @@ import { il8n, language } from '@/language'; import { bus } from '@/common/bus'; import { buildURLParams } from '@/common/url'; - import { formatI18nKey, jsonpRequest } from '@/common/util'; + import { formatI18nKey, jsonpRequest, getManagerMenuPerm } from '@/common/util'; import { NEED_CONFIRM_DIALOG_ROUTER } from '@/common/constants'; import SystemLog from '../system-log'; import { getRouterDiff, getNavRouterDiff } from '@/common/router-handle'; @@ -203,7 +203,7 @@ ]); export default { - name: '', + inject: ['reloadCurPage'], components: { SystemLog // IamGuide @@ -255,14 +255,16 @@ placeholderValue: '', userGroupName: '', navData: [ - { text: this.$t(`m.nav['个人工作台']`), id: 0, show: true, type: 'staff' }, - { text: this.$t(`m.nav['管理空间']`), id: 1, show: true, type: 'all_manager' }, - { text: this.$t(`m.nav['统计分析']`), id: 2, show: false, type: 'super_manager' }, - { text: this.$t(`m.nav['平台管理']`), id: 3, show: false, type: 'super_manager' } + { text: this.$t(`m.nav['个人工作台']`), id: 0, show: true, type: ['staff'] }, + { text: this.$t(`m.nav['管理空间']`), id: 1, show: true, type: ['all_manager'] }, + { text: this.$t(`m.nav['统计分析']`), id: 2, show: false, type: ['super_manager'] }, + { text: this.$t(`m.nav['平台管理']`), id: 3, show: false, type: ['super_manager'] } ], defaultRouteList: ['myPerm', 'userGroup', 'audit', 'user', 'addGroupPerm'], + systemNoSuperList: ['myPerm', 'userGroup', 'audit', 'resourcePermiss', 'addGroupPerm'], isRatingChange: false, haveManager: false, + isSameRoute: false, showNavDataLength: 0, curHeight: 78, languageList: [ @@ -274,39 +276,41 @@ label: 'English', value: 'en' } - ] + ], + curFromName: '' }; }, computed: { - ...mapGetters([ - 'navStick', - 'headerTitle', - 'backRouter', - 'user', - 'mainContentLoading', - 'roleList', - 'index', - 'navCurRoleId', - 'externalSystemId' - ]), - style () { - return { - // height: `${this.roleList.length ? this.curHeight : 46}px` - height: `46px` - }; - }, - curAccountLogo () { - return [].slice.call(this.user.username)[0].toUpperCase() || '-'; - }, - isHide () { - return this.$route.query.system_id && this.$route.query.tid; - }, - isShowSearch () { - return this.searchValue === ''; - } + ...mapGetters([ + 'navStick', + 'headerTitle', + 'backRouter', + 'user', + 'mainContentLoading', + 'roleList', + 'index', + 'navCurRoleId', + 'externalSystemId' + ]), + style () { + return { + // height: `${this.roleList.length ? this.curHeight : 46}px` + height: `46px` + }; + }, + curAccountLogo () { + return [].slice.call(this.user.username)[0].toUpperCase() || '-'; + }, + isHide () { + return this.$route.query.system_id && this.$route.query.tid; + }, + isShowSearch () { + return this.searchValue === ''; + } }, watch: { $route: function (to, from) { + this.curFromName = from.name || ''; this.hasPageTab = !!to.meta.hasPageTab; if (['permTemplateDetail', 'userGroupDetail'].includes(to.name)) { this.panels = this.getTabData(to.name); @@ -348,7 +352,10 @@ }, routeName: { handler (value) { - const index = this.defaultRouteList.findIndex((item) => item === value); + // const isSystemNoSuper = this.roleList.find((item) => ['system_manager'].includes(item.type) && !['super_manager'].includes(item.type)); + // const list = isSystemNoSuper ? this.systemNoSuperList : this.defaultRouteList; + const list = this.defaultRouteList; + const index = list.findIndex((item) => item === value); if (index > -1) { ['addGroupPerm'].includes(value) ? this.fetchUserGroup() @@ -366,10 +373,18 @@ this.haveManager = this.showNavDataLength && this.showGuide - && newValue.find((item) => ['all_manager'].includes(item.type) && item.show); + && newValue.find((item) => item.type.includes('all_manager') && item.show); }, immediate: true, deep: true + }, + index: { + handler (newValue, oldValue) { + if (oldValue && newValue !== oldValue && !this.curFromName) { + this.isSameRoute = true; + } + }, + deep: true } }, created () { @@ -391,7 +406,7 @@ }); bus.$on('rating-admin-change', () => { - const data = this.navData.find((e) => e.type === 'staff'); + const data = this.navData.find((e) => e.type.includes('staff')); this.isRatingChange = true; this.handleSelect(data, 0); }); @@ -481,14 +496,26 @@ async updateRouter (navIndex = 0) { let difference = []; + const permResult = getManagerMenuPerm(this.roleList); + // const list = permResult.includes('hasSystemNoSuperManager') ? this.systemNoSuperList : this.defaultRouteList; + const list = this.defaultRouteList; if (navIndex === 1) { + // 不同导航栏下相同的权限路由名称跳转增加延时时间,防止相同接口调用多次被节流 await this.$store.dispatch('userInfo'); + if (this.isSameRoute) { + this.reloadCurPage(this.$route); + } const type = this.curRole; difference = getRouterDiff(type); this.$store.commit('updataRouterDiff', type); } else { - difference = getNavRouterDiff(navIndex); + difference = getNavRouterDiff(navIndex, permResult); this.$store.commit('updataNavRouterDiff', navIndex); + // 不同导航栏下相同的权限路由名称跳转增加延时时间,防止相同接口调用多次被节流 + if (this.isSameRoute) { + await this.$store.dispatch('userInfo'); + this.reloadCurPage(this.$route); + } } const curRouterName = this.$route.name; if (difference.length) { @@ -497,19 +524,10 @@ window.localStorage.removeItem('iam-header-title-cache'); window.localStorage.removeItem('iam-header-name-cache'); this.$router.push({ - name: this.isRatingChange ? 'myManageSpace' : this.defaultRouteList[navIndex], + name: this.isRatingChange ? 'myManageSpace' : list[navIndex], params: navIndex === 1 ? { id: this.user.role.id, entry: 'updateRole' } : {} }); } else { - // if (navIndex === 0 && ['gradingAdminDetail', 'gradingAdminCreate', 'gradingAdminEdit'].includes(curRouterName)) { - // this.$router.push({ - // name: 'myPerm' - // }); - // } else if (navIndex === 3 && ['gradingAdminDetail', 'gradingAdminCreate', 'gradingAdminEdit', 'myManageSpaceCreate', 'myManageSpaceSubDetail'].includes(curRouterName)) { - // this.$router.push({ - // name: 'user' - // }); - // } // 修复当前是添加组权限页面点击其他角色菜单会再次跳到权限管理 // 处理二级管理空间点击staff菜单不刷新路由问题 // 处理超级管理员账号下头部导航没选择默认路由问题 @@ -525,7 +543,7 @@ ]; if (OtherRoute.includes(curRouterName)) { this.$router.push({ - name: this.defaultRouteList[navIndex] + name: list[navIndex] }); } } @@ -555,11 +573,6 @@ this.$set(currentData, 'active', true); this.$store.commit('updateIndex', index); window.localStorage.setItem('index', index); - // if (this.routeName === 'addGroupPerm') { - // this.$router.push({ - // name: 'userGroup' - // }); - // } this.isShowGradingWrapper = false; this.isShowUserDropdown = false; try { @@ -635,7 +648,7 @@ }, handleManager () { - const data = this.navData.find((e) => e.type !== 'staff'); + const data = this.navData.find((e) => !e.type.includes('staff')); this.handleSelect(data, 1); this.$store.commit('updateSelectManager', true); }, @@ -678,15 +691,33 @@ // 根据角色设置 setTabRoleData () { const superManager = this.curRoleList.find((e) => e.type === 'super_manager'); + const systemManager = this.curRoleList.find((e) => e.type === 'system_manager'); const allManager = this.curRoleList.find((e) => e.type !== 'staff'); this.navData.forEach((element, i) => { element.active = i === this.index; - if (element.type === 'super_manager' && superManager) { - element.id = superManager.id; - element.show = true; - } else if (element.type === 'all_manager' && allManager) { - element.id = this.navCurRoleId || allManager.id; - // element.id = allManager.id; + const rolesMap = [ + [ + () => element.type.includes('super_manager') && superManager, + () => { + element = Object.assign(element, { id: superManager.id, show: true }); + } + ], + [ + () => element.type.includes('system_manager') && systemManager && !superManager, + () => { + element = Object.assign(element, { id: systemManager.id, show: true }); + } + ], + [ + () => element.type.includes('all_manager') && allManager, + () => { + element = Object.assign(element, { id: this.navCurRoleId || allManager.id }); + } + ] + ]; + const getRole = rolesMap.find((item) => item[0]()); + if (getRole) { + getRole[1](); } }); this.$store.commit('updateNavData', this.navData); @@ -695,7 +726,7 @@ setNavData () { this.$nextTick(() => { for (let i = 0; i < this.navData.length; i++) { - if (this.navData[i].type === 'all_manager') { + if (this.navData[i].type.includes('all_manager')) { this.navData[i].show = !!this.roleList.length; break; } diff --git a/frontend/src/components/iam-member-template-table/index.vue b/frontend/src/components/iam-member-template-table/index.vue index 1dad8ceb0..c8ce92ffb 100644 --- a/frontend/src/components/iam-member-template-table/index.vue +++ b/frontend/src/components/iam-member-template-table/index.vue @@ -250,7 +250,7 @@ fetchSelectedGroupCount () { this.$nextTick(() => { const selectionCount = document.getElementsByClassName('bk-page-selection-count'); - if (this.$refs.templateTableRef && selectionCount && selectionCount.length) { + if (this.$refs.templateTableRef && selectionCount && selectionCount.length && selectionCount[0].children) { selectionCount[0].children[0].innerHTML = this.currentSelectList.length; } }); diff --git a/frontend/src/components/iam-resource-cascade-search/index.vue b/frontend/src/components/iam-resource-cascade-search/index.vue index e43cead9a..4040f99ac 100644 --- a/frontend/src/components/iam-resource-cascade-search/index.vue +++ b/frontend/src/components/iam-resource-cascade-search/index.vue @@ -1,896 +1,1048 @@ - - - - - - - - - - - - - - {{$t(`m.verify['请选择系统']`)}} - - - - - - - - - {{$t(`m.verify['请选择操作']`)}} - - - - - - - - - - - - {{$t(`m.verify['请选择资源类型']`)}} - - - - - - - - - {{$t(`m.resourcePermiss['请选择资源实例']`)}} - - - - - - - - - - - - {{ $t(`m.common['查询']`) }} - - - {{ $t(`m.common['重置']`) }} - - - - - - - - - - - - - - - - {{ $t(`m.common['保存']`) }} - - - {{ $t(`m.common['取消']`) }} - - - - - - - - - + + + + + + + + + + + + + + {{$t(`m.verify['请选择系统']`)}} + + + + + + + + + {{$t(`m.verify['请选择操作']`)}} + + + + + + + + + + + {{$t(`m.verify['请选择资源类型']`)}} + + + + + + + + {{$t(`m.resourcePermiss['请选择资源实例']`)}} + + + + + + + + + + + + + + + + {{ $t(`m.common['查询']`) }} + + + {{ $t(`m.common['重置']`) }} + + + + + + + + + + + + + + + + + + + + + + {{ $t(`m.common['保存']`) }} + + + {{ $t(`m.common['取消']`) }} + + + + + + + + + diff --git a/frontend/src/components/infinite-tree/index.vue b/frontend/src/components/infinite-tree/index.vue index 3468d1380..bdb105b2f 100644 --- a/frontend/src/components/infinite-tree/index.vue +++ b/frontend/src/components/infinite-tree/index.vue @@ -513,6 +513,7 @@ .arrow-icon { color: #c0c4cc; + margin-right: 4px; } .node-title { @@ -543,8 +544,8 @@ .node-radio { /* margin-right: 5px; - float: left; */ - margin-left: 5px; + float: left; + margin-left: 5px; */ .node-checkbox { display: inline-block; position: relative; diff --git a/frontend/src/components/nav/index.vue b/frontend/src/components/nav/index.vue index 24171ad07..8dd95be5c 100644 --- a/frontend/src/components/nav/index.vue +++ b/frontend/src/components/nav/index.vue @@ -274,7 +274,9 @@ // 人员模板 [['memberTemplate'], 'memberTemplateNav'], // 管理空间下资源权限管理 - [['resourcePermManage'], 'resourcePermManageNav'] + [['resourcePermManage'], 'resourcePermManageNav'], + // 用户/组织 + [['userOrgPerm'], 'userOrgPermNav'] ]); export default { @@ -329,11 +331,11 @@ return this.navStick || !this.navFold; }, isShowRouterGroup () { - return (payload) => { - const allRouter = getRouterDiff('all'); - const curRouter = allRouter.filter((item) => !this.routerDiff.includes(item)); - return curRouter.filter((item) => payload.children.map((_) => _.rkey).includes(item)).length > 0; - }; + return (payload) => { + const allRouter = getRouterDiff('all'); + const curRouter = allRouter.filter((item) => !this.routerDiff.includes(item)); + return curRouter.filter((item) => payload.children.map((_) => _.rkey).includes(item)).length > 0; + }; }, formatRoleIcon () { const { role } = this.user; @@ -498,6 +500,7 @@ this.selectCls = 'hide-iam-nav-select-cls'; if (value) { this.selectCls = 'iam-nav-select-dropdown-content'; + this.handleClearSearch(); this.resetPagination(); this.resetSubPagination(); await this.resetRoleList('handleClearSearch'); diff --git a/frontend/src/components/render-perm-boundary/index.vue b/frontend/src/components/render-perm-boundary/index.vue index 49d7b5d0a..167c1d081 100644 --- a/frontend/src/components/render-perm-boundary/index.vue +++ b/frontend/src/components/render-perm-boundary/index.vue @@ -36,7 +36,7 @@ - {{ $t(`m.levelSpace["${BOUNDARY_KEYS_ENUM["membersPerm"].title}"]`) }}: + {{ customTitle || `${$t(`m.levelSpace["${BOUNDARY_KEYS_ENUM["membersPerm"].title}"]`)}: ` }} - - {{ $t(`m.common['共']`) }} - {{ userLength }} - {{ $t(`m.common['个用户']`) }} + + - - {{ $t(`m.common[',']`) }} - - - {{ $t(`m.common['共']`) }} - {{ departLength }} - {{ $t(`m.common['个组织']`) }} + + + {{ $t(`m.common['共']`) }} + {{ userLength }} + {{ $t(`m.common['个用户']`) }} + + + {{ $t(`m.common[',']`) }} + + + {{ $t(`m.common['共']`) }} + {{ departLength }} + {{ $t(`m.common['个组织']`) }} + @@ -86,9 +91,7 @@ { 'perm-boundary-title-custom': isCustomTitleStyle } ]" > - {{ - $t(`m.sensitivityLevel["${BOUNDARY_KEYS_ENUM["transferPreview"].title}"]`) - }} + {{ customTitle || $t(`m.sensitivityLevel["${BOUNDARY_KEYS_ENUM["transferPreview"].title}"]`) }} - {{ $t(`m.common['已选择']`) }} - {{ permLength }} - {{ $t(`m.common['个']`) }}{{ $t(`m.common['操作']`) }} + + + + + {{ $t(`m.common['已选择']`) }} + {{ permLength }} + {{ $t(`m.common['个']`) }}{{ $t(`m.common['操作']`) }} + @@ -184,6 +192,12 @@ isShowClear: { type: Boolean, default: false + }, + customTitle: { + type: String + }, + customSlotName: { + type: String } }, data () { @@ -198,8 +212,14 @@ } }, watch: { - expanded (value) { - this.isExpanded = !!value; + expanded: { + handler (value) { + this.isExpanded = !!value; + if (this.modules.length === 1 && this.expanded) { + this.BOUNDARY_KEYS_ENUM[this.modules[0]].isExpanded = true; + } + }, + immediate: true } }, methods: { @@ -249,12 +269,13 @@ .iam-resource-expand { background-color: #f5f7fa; + border-radius: 2px 2px 0 0; .iam-resource-header-left { - padding: 0 10px !important; + padding: 0 16px !important; display: flex; align-items: center; &-title { - margin-left: 5px; + margin-left: 10px; } } } diff --git a/frontend/src/components/render-renewal-dialog/display.vue b/frontend/src/components/render-renewal-dialog/display.vue index 6b3a09022..eb0993725 100644 --- a/frontend/src/components/render-renewal-dialog/display.vue +++ b/frontend/src/components/render-renewal-dialog/display.vue @@ -1,8 +1,8 @@ {{ curDisplay }} - - + + {{ afterRenewalDisplay }} @@ -10,6 +10,7 @@ diff --git a/frontend/src/components/render-renewal-dialog/index.vue b/frontend/src/components/render-renewal-dialog/index.vue index d85ade436..928481390 100644 --- a/frontend/src/components/render-renewal-dialog/index.vue +++ b/frontend/src/components/render-renewal-dialog/index.vue @@ -27,7 +27,7 @@ {{ $t(`m.common['有效期']`) }} - + @@ -117,6 +117,10 @@ type: String, default: 'department' }, + lineHeight: { + type: String, + default: '32px' + }, list: { type: Array, default: () => [] diff --git a/frontend/src/language/lang/en.js b/frontend/src/language/lang/en.js index 50b067965..f7ddf6237 100644 --- a/frontend/src/language/lang/en.js +++ b/frontend/src/language/lang/en.js @@ -111,6 +111,7 @@ export const m = { '的关联': 'association', '添加成员': 'Add members', '添加成员至': 'Add members to', + '已选': 'Selected', '已选择': 'Selected', '清空': 'Clear', '保存': 'Save', @@ -153,7 +154,7 @@ export const m = { '已获得': 'Acquired', '未选择': 'Not Selected', '选择全部': 'All', - '加载中': 'Loading...', + '加载中': 'Loading', '返回': 'Back', '期限选择提示': '1-365', '临时期限选择提示': '1-24', @@ -287,6 +288,8 @@ export const m = { '解析并添加': 'Parse and add', '搜索解析结果': 'Search parsing results', '请先从左侧输入并解析': 'Please input and parse from the left first', + '剩余加载数据': 'Remaining {value} pieces of data', + '已加载全部数据': 'All data loaded', '实例名称输入错误或不存在于授权资源实例范围内': 'Instance name input error or does not exist within the authorized resource instance scope', '实例名称': 'Instance name', '请输入实例名称,以回车/逗号/分号分割': 'Please enter the instance name, separated by carriage return, comma, or semicolon', @@ -398,7 +401,9 @@ export const m = { '关联成员将不再继承该模板的权限': 'Associated members will no longer inherit the permissions of the template', '该用户组已关联': 'The group has been associated', '添加用户组成功': 'Group Added', + '重置用户组成功': 'Group reset', '添加成员成功': 'Members Added', + '移出成功': 'Removed', '移除成功': 'Removed', '该用户组将不再继承对应模板的权限': 'The group will no longer inherit the permissions of the template', '该成员将不再继承对应模板的权限': 'The member will no longer inherit the permissions of the template', @@ -554,7 +559,8 @@ export const m = { '最多添加一个管理员': 'Add at most one administrator', '管理员不可重复添加': 'Administrators cannot be added repeatedly', '有关联的用户组, 无法删除': 'Associated user groups cannot be deleted', - 'ip选择器每页最大条数': 'items {value}/page' + '不可续期的用户组如下': 'The non renewable user groups are as follows: {value}', + '不可移出的用户组如下': 'The user groups that cannot be removed are as follows' }, // 二次确认弹窗相关 dialog: { @@ -577,7 +583,8 @@ export const m = { '确认批量退出所选的用户组吗?': 'Are you sure to batch quit the selected user groups?', '确认删除该人员模板?': 'Are you sure to delete the member template?', '确认解除与该用户组的关联?': 'Are you sure to dissociate from this user group?', - '确认批量删除所选的人员模板吗?': 'Are you sure to batch delete the selected member templates?' + '确认批量删除所选的人员模板吗?': 'Are you sure to batch delete the selected member templates?', + '确认把用户/组织移出该用户组?': 'Are you sure to move the user/organization out of this user group?' }, nav: { '蓝鲸权限中心': 'BlueKing-IAM', @@ -635,7 +642,8 @@ export const m = { '克隆二级管理空间': 'Clone Secondary management space', '用户组设置': 'User Group Setting', '敏感等级': 'Sensitivity Level', - '人员模板': 'Members Template' + '人员模板': 'Members Template', + '用户/组织': 'User/Organization' }, applyEntrance: { '立刻申请': 'Apply now', @@ -762,7 +770,7 @@ export const m = { '加入用户组的时间': 'Joined at', '加入方式': 'Joined type', '退出该组': 'Quit Group', - '组织名': 'Organization Name', + '组织名': 'Organization name', '加入的用户组': 'Joined Groups', '加入的组织': 'Joined Organizations', '通过组织加入的组无法退出': 'Joined through organization cannot be quit', @@ -1463,6 +1471,52 @@ export const m = { '只读人员模板不能移除': 'The read-only member template cannot be removed', '只读人员模板不能添加、删除、复制成员': 'Read-only member template cannot add, delete, or copy members', '最多只能选择10个人员模板' : 'You can only select up to 10 member templates' + }, + userOrOrg: { + '用户组名': 'User group name', + '批量操作': 'Multi-operate', + '重置用户组': 'Reset user group', + '追加用户组': 'Append user group', + '加入用户组': 'Join user group', + '追加的用户组': 'Append user group', + '批量追加用户组': 'Batch add user groups', + '批量重置用户组': 'Batch reset user groups', + '操作对象': 'Operating object', + '加入的用户组': 'Joined user group', + '重置的用户组': 'Reset user group', + '申请时长': 'Application duration', + '移出': 'Remove', + '续期时长': 'Renewal duration', + '续期预览': 'Renewal preview', + '用户组 ID': 'User group ID', + '用户 / 组织列表': 'User/Organization list', + '移出用户组名': 'Remove user group name', + '批量移出用户组': 'Multi-remove user group', + '清空用户组': 'Empty user groups', + '请先勾选用户': 'Please check the user first', + '请先勾选用户组权限': 'Please check user group permissions first', + '请先勾选用户/组织': 'Please check the user/organization first', + '搜索用户组名、描述': 'Search for user group name and description', + '输入ID、用户组名、用户名、组织名、描述等按回车进行搜索': 'Enter ID, user group name, username, organization name, description, etc. and press enter to search', + '在已有用户组的基础上,追加以下所选的用户组': 'On the basis of existing user groups, add the following selected user groups', + '已选对象的权限将被清空,替换为以下所选的用户组': 'The permissions of the selected objects will be cleared and replaced with the following selected user groups', + '移出后,该用户/组织将不再继承该组的权限。': 'After removal, the user/organization will no longer inherit the permissions of the group.', + '用户组不能为空': 'User group cannot be empty', + '的用户组': " 's Groups", + '清空对象': 'Clear object', + '个人': 'Personal', + '个人用户组权限': 'Personal user group perm', + '用户组权限(不影响因所属组织而拥有的用户组权限)': 'User group permissions (do not affect user group permissions owned by the organization)', + '请选择申请时长': 'Please select the application duration', + '请选择续期时长': 'Please select the renewal duration', + '通过组织': 'Through organization', + '通过人员模板': 'Through member template', + '查看人员模板详情': 'View member template details', + '查看该组织的用户组详情页': 'View the user group details page of the organization', + '当前勾选项都为不可移出的管理员组': 'The current check boxes are all administrator groups that cannot be removed', + '已选择的用户组权限为不可移出的管理员组': 'The selected user group permission is an administrator group that cannot be removed', + '已选择的用户组权限不需要续期': 'The selected user group permissions do not need to be renewed', + '组织用户组权限': 'Organizational user group permissions' } } export default { diff --git a/frontend/src/language/lang/zh.js b/frontend/src/language/lang/zh.js index 20ec7d26f..e6369b1cb 100644 --- a/frontend/src/language/lang/zh.js +++ b/frontend/src/language/lang/zh.js @@ -109,6 +109,7 @@ export const m = { '的关联': '的关联', '添加成员': '添加成员', '添加成员至': '添加成员至', + '已选': '已选', '已选择': '已选择', '清空': '清空', '保存': '保存', @@ -151,7 +152,7 @@ export const m = { '已获得': '已获得', '未选择': '未选择', '选择全部': '选择全部', - '加载中': '加载中...', + '加载中': '加载中', '返回': '返回', '期限选择提示': '1-365,按 Enter 保存', '临时期限选择提示': '1-24,按 Enter 保存', @@ -284,6 +285,8 @@ export const m = { '解析并添加': '解析并添加', '搜索解析结果': '搜索解析结果', '请先从左侧输入并解析': '请先从左侧输入并解析', + '剩余加载数据': '剩余 {value} 条数据', + '已加载全部数据': '已加载全部数据', '实例名称输入错误或不存在于授权资源实例范围内': '实例名称输入错误或不存在于授权资源实例范围内', '实例名称': '实例名称', '请输入实例名称,以回车/逗号/分号分割': '请输入实例名称,以回车/逗号/分号分割', @@ -398,7 +401,9 @@ export const m = { '关联成员将不再继承该模板的权限': '关联成员将不再继承该模板的权限', '该用户组已关联': '该用户组已关联', '添加用户组成功': '添加用户组成功', + '重置用户组成功': '重置用户组成功', '添加成员成功': '添加成员成功', + '移出成功': '移出成功', '移除成功': '移除成功', '该用户组将不再继承对应模板的权限': '该用户组将不再继承对应模板的权限', '该成员将不再继承对应模板的权限': '该成员将不再继承对应模板的权限', @@ -552,7 +557,9 @@ export const m = { '已加入用户组数量 , 新申请数量,总数超过上限:100,请减少申请或退出部分用户组后重试': '已加入用户组数量:{applyCount} , 新申请数量:{newApplyCount},总数超过上限:100,请减少申请或退出部分用户组后重试', '最多添加一个管理员': '最多添加一个管理员', '管理员不可重复添加': '管理员不可重复添加', - '有关联的用户组, 无法删除': '有关联的用户组, 无法删除' + '有关联的用户组, 无法删除': '有关联的用户组, 无法删除', + '不可续期的用户组如下': '不可续期的用户组如下:{value}', + '不可移出的用户组如下': '不可移出的用户组如下:{value}' }, // 二次确认弹窗相关 dialog: { @@ -575,7 +582,8 @@ export const m = { '确认批量退出所选的用户组吗?': '确认批量退出所选的用户组吗?', '确认删除该人员模板?': '确认删除该人员模板?', '确认解除与该用户组的关联?': '确认解除与该用户组的关联?', - '确认批量删除所选的人员模板吗?': '确认批量删除所选的人员模板吗?' + '确认批量删除所选的人员模板吗?': '确认批量删除所选的人员模板吗?', + '确认把用户/组织移出该用户组?': '确认把用户/组织移出该用户组?' }, nav: { '蓝鲸权限中心': '蓝鲸权限中心', @@ -633,7 +641,8 @@ export const m = { '克隆二级管理空间': '克隆二级管理空间', '用户组设置': '用户组设置', '敏感等级': '敏感等级', - '人员模板': '人员模板' + '人员模板': '人员模板', + '用户/组织': '用户/组织' }, applyEntrance: { '立刻申请': '立刻申请', @@ -1464,6 +1473,50 @@ export const m = { '只读人员模板不能移除': '只读人员模板不能移除', '只读人员模板不能添加、删除、复制成员': '只读人员模板不能添加、删除、复制成员', '最多只能选择10个人员模板': '最多只能选择10个人员模板' + }, + userOrOrg: { + '用户组名': '用户组名', + '批量操作': '批量操作', + '重置用户组': '重置用户组', + '追加用户组': '追加用户组', + '加入用户组': '加入用户组', + '追加的用户组': '追加的用户组', + '重置的用户组': '重置的用户组', + '批量追加用户组': '批量追加用户组', + '批量重置用户组': '批量重置用户组', + '操作对象': '操作对象', + '加入的用户组': '加入的用户组', + '重置的用户组': '重置的用户组', + '申请时长': '申请时长', + '移出': '移出', + '续期时长': '续期时长', + '续期预览': '续期预览', + '用户组 ID': '用户组 ID', + '用户 / 组织列表': '用户 / 组织列表', + '移出用户组名': '移出用户组名', + '批量移出用户组': '批量移出用户组', + '清空用户组': '清空用户组', + '请先勾选用户': '请先勾选用户', + '请先勾选用户组权限': '请先勾选用户组权限', + '请先勾选用户/组织': '请先勾选用户/组织', + '搜索用户组名、描述': '搜索用户组名、描述', + '输入ID、用户组名、用户名、组织名、描述等按回车进行搜索': '输入ID、用户组名、用户名、组织名、描述等按回车进行搜索', + '在已有用户组的基础上,追加以下所选的用户组': '在已有用户组的基础上,追加以下所选的用户组', + '已选对象的权限将被清空,替换为以下所选的用户组': '已选对象的权限将被清空,替换为以下所选的用户组', + '移出后,该用户/组织将不再继承该组的权限。': '移出后,该用户/组织将不再继承该组的权限。', + '用户组不能为空': '用户组不能为空', + '的用户组': '的用户组', + '清空对象': '清空对象', + '个人': '个人', + '个人用户组权限': '个人用户组权限', + '用户组权限(不影响因所属组织而拥有的用户组权限)': '用户组权限(不影响因所属组织而拥有的用户组权限)', + '请选择申请时长': '请选择申请时长', + '请选择续期时长': '请选择续期时长', + '查看人员模板详情': '查看人员模板详情', + '查看该组织的用户组详情页': '查看该组织的用户组详情页', + '已选择的用户组权限为不可移出的管理员组': '已选择的用户组权限为不可移出的管理员组', + '已选择的用户组权限不需要续期': '已选择的用户组权限不需要续期', + '组织用户组权限': '组织用户组权限' } } export default { diff --git a/frontend/src/router/ce.js b/frontend/src/router/ce.js index e03e97923..7131e7c58 100644 --- a/frontend/src/router/ce.js +++ b/frontend/src/router/ce.js @@ -189,6 +189,9 @@ const MemberTemplate = () => import(/* webpackChunkName: 'memberTemplate' */ '.. // 系统管理员下的资源权限管理 const ResourcePermManage = () => import(/* webpackChunkName: 'grading-admin' */ '../views/resource-permiss'); +// 用户/组织 +const userOrgPerm = () => import(/* webpackChunkName: 'userOrgPerm' */ '../views/user-org-perm/index.vue'); + const TemplatePermDetail = () => import(/* webpackChunkName: 'my-perm-template-perm' */ '../views/perm/template-perm/detail'); const GroupPermDetail = () => import(/* webpackChunkName: 'my-perm-group-perm' */ '../views/perm/group-perm/detail'); @@ -432,6 +435,14 @@ export const routes = [ }, component: SecondaryManageSpaceDetail }, + { + path: 'user-org-perm', + name: 'userOrgPerm', + meta: { + headerTitle: il8n('nav', '用户/组织') + }, + component: userOrgPerm + }, { path: 'user-group', name: 'userGroup', diff --git a/frontend/src/router/ee.js b/frontend/src/router/ee.js index 3d834574f..d21373f68 100644 --- a/frontend/src/router/ee.js +++ b/frontend/src/router/ee.js @@ -189,6 +189,9 @@ const MemberTemplate = () => import(/* webpackChunkName: 'memberTemplate' */ '.. // 系统管理员下的资源权限管理 const ResourcePermManage = () => import(/* webpackChunkName: 'grading-admin' */ '../views/resource-permiss'); +// 用户/组织 +const userOrgPerm = () => import(/* webpackChunkName: 'userOrgPerm' */ '../views/user-org-perm/index.vue'); + const TemplatePermDetail = () => import(/* webpackChunkName: 'my-perm-template-perm' */ '../views/perm/template-perm/detail'); const GroupPermDetail = () => import(/* webpackChunkName: 'my-perm-group-perm' */ '../views/perm/group-perm/detail'); @@ -432,6 +435,14 @@ export const routes = [ }, component: SecondaryManageSpaceDetail }, + { + path: 'user-org-perm', + name: 'userOrgPerm', + meta: { + headerTitle: il8n('nav', '用户/组织') + }, + component: userOrgPerm + }, { path: 'user-group', name: 'userGroup', diff --git a/frontend/src/router/ieod.js b/frontend/src/router/ieod.js index 8c7c0f3c2..5ad80391c 100644 --- a/frontend/src/router/ieod.js +++ b/frontend/src/router/ieod.js @@ -189,6 +189,9 @@ const MemberTemplate = () => import(/* webpackChunkName: 'memberTemplate' */ '.. // 系统管理员下的资源权限管理 const ResourcePermManage = () => import(/* webpackChunkName: 'grading-admin' */ '../views/resource-permiss'); +// 用户/组织 +const userOrgPerm = () => import(/* webpackChunkName: 'userOrgPerm' */ '../views/user-org-perm/index.vue'); + const TemplatePermDetail = () => import(/* webpackChunkName: 'my-perm-template-perm' */ '../views/perm/template-perm/detail'); const GroupPermDetail = () => import(/* webpackChunkName: 'my-perm-group-perm' */ '../views/perm/group-perm/detail'); @@ -432,6 +435,14 @@ export const routes = [ }, component: SecondaryManageSpaceDetail }, + { + path: 'user-org-perm', + name: 'userOrgPerm', + meta: { + headerTitle: il8n('nav', '用户/组织') + }, + component: userOrgPerm + }, { path: 'user-group', name: 'userGroup', diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index e8fa86cf5..44bdd651d 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -32,8 +32,8 @@ import http from '@/api'; // import il8n from '@/language'; import preload from '@/common/preload'; import { bus } from '@/common/bus'; -// import { existValue, getParamsValue, getTreeNode } from '@/common/util'; import { existValue, getParamsValue } from '@/common/util'; +// import { existValue, getParamsValue, getManagerMenuPerm } from '@/common/util'; import { getRouterDiff, getNavRouterDiff } from '@/common/router-handle'; import { messageError } from '@/common/bkmagic'; @@ -86,15 +86,9 @@ export const beforeEach = async (to, from, next) => { let navIndex = store.state.index || Number(window.localStorage.getItem('index') || 0); let currentRoleId = String(to.query.current_role_id || '').trim(); let curRoleId = store.state.curRoleId; + // 检验有系管没超管身份 + const hasManagerPerm = ''; const defaultRoute = ['my-perm', 'user-group', 'audit', 'user']; - // if (curRole === 'staff') { - // await store.dispatch('role/updateCurrentRole', { id: 0 }); - // } - // 递归改成分级展开 - // const roleList = await store.dispatch('roleList', { - // cancelWhenRouteChange: false, - // cancelPrevious: false - // }); async function getExternalRole () { const { role_id: externalRoleId } = to.query; @@ -130,6 +124,28 @@ export const beforeEach = async (to, from, next) => { } } + // 处理平台管理超管和系管都可以进入,但访问菜单权限不一致 + // 暂时注释掉后期开放 + // async function getPlatManageMenu () { + // hasManagerPerm = ''; + // let roleList = store.state.roleList; + // if (roleList.length > 0) { + // 有系统管理员身份没超管身份 + // hasManagerPerm = getManagerMenuPerm(roleList); + // } else { + // roleList = await store.dispatch('roleList', { + // cancelWhenRouteChange: false, + // cancelPrevious: false + // }); + // } + // 有系统管理员身份没超管身份 + // hasManagerPerm = getManagerMenuPerm(roleList); + // if (['hasSystemNoSuperManager'].includes(hasManagerPerm)) { + // hasManagerPerm = 'hasSystemNoSuperManager'; + // defaultRoute = ['my-perm', 'user-group', 'audit', 'resourcePermiss']; + // } + // } + // 根据不同权限处理不同的导航栏索引 function navDiffMenuIndex (index) { navIndex = index; @@ -161,10 +177,11 @@ export const beforeEach = async (to, from, next) => { navDiffMenuIndex(0); } - if (['userGroup', 'permTemplate', 'approvalProcess'].includes(to.name)) { + if (['userGroup', 'permTemplate'].includes(to.name)) { await store.dispatch('role/updateCurrentRole', { id: curRoleId }); navDiffMenuIndex(1); } + if (to.name === 'userGroupDetail') { navDiffMenuIndex(1); store.dispatch('versionLogInfo'); @@ -194,13 +211,6 @@ export const beforeEach = async (to, from, next) => { } else if (to.name === 'userGroup') { store.dispatch('versionLogInfo'); if (currentRoleId) { - // const roleList = await store.dispatch('roleList', { - // cancelWhenRouteChange: false, - // cancelPrevious: false - // }); - // const currentRole = roleList.find((item) => String(item.id) === currentRoleId); - // const currentRole = getTreeNode(currentRoleId, roleList); - // await getExternalRole(); await getManagerInfo(); } else { if (existValue('externalApp')) { // 外部嵌入页面 @@ -223,9 +233,6 @@ export const beforeEach = async (to, from, next) => { } else { // 邮件点击续期跳转过来的链接需要做身份的前置判断 if (to.name === 'groupPermRenewal' && to.query.source === 'email' && currentRoleId) { - // await store.dispatch('role/updateCurrentRole', { id: +currentRoleId }); - // const { role } = await store.dispatch('userInfo'); - // curRole = role.type; await getManagerInfo(); navDiffMenuIndex(1); } @@ -237,22 +244,15 @@ export const beforeEach = async (to, from, next) => { getExternalRole(); } - // if (to.name === 'gradingAdminEdit') { - // await store.dispatch('role/updateCurrentRole', { id: 0 }); - // await store.dispatch('userInfo'); - // if (to.params.id) { - // store.commit('updateNavId', to.params.id); - // } - // store.commit('updateIndex', 0); - // window.localStorage.setItem('index', 0); - // curRole = 'staff'; - // } - let difference = []; if (navIndex === 1) { difference = getRouterDiff(curRole); } else { - difference = getNavRouterDiff(navIndex); + // 目前只有平台管理需要根据管理员最大身份处理路由权限 + // if ([3].includes(Number(navIndex))) { + // await getPlatManageMenu(); + // } + difference = getNavRouterDiff(navIndex, hasManagerPerm); } if (difference.length) { store.dispatch('versionLogInfo'); diff --git a/frontend/src/store/index.js b/frontend/src/store/index.js index 1e53f0149..4687e15ca 100644 --- a/frontend/src/store/index.js +++ b/frontend/src/store/index.js @@ -27,7 +27,7 @@ import Vue from 'vue'; import Vuex from 'vuex'; import http from '@/api'; -import { unifyObjectStyle, json2Query } from '@/common/util'; +import { unifyObjectStyle, json2Query, getManagerMenuPerm } from '@/common/util'; import { getRouterDiff, getNavRouterDiff } from '@/common/router-handle'; import il8n from '@/language'; @@ -85,12 +85,15 @@ import spaceManage from './modules/space-manage'; // 用户组设置模块 import userGroupSetting from './modules/user-group-setting'; -// 敏感等级 +// 敏感等级模块 import sensitivityLevel from './modules/sensitivity-level'; -// 人员模板 +// 人员模板模块 import memberTemplate from './modules/member-template'; +// 用户/组织模块 +import userOrOrg from './modules/user-org'; + Vue.use(Vuex); const SITE_URL = window.SITE_URL; @@ -161,6 +164,14 @@ const currentNav = [ name: il8n('nav', '权限管理'), rkey: 'managePermission', children: [ + { + icon: 'personal-user', + id: 'userOrgPermNav', + rkey: 'userOrgPerm', + name: il8n('nav', '用户/组织'), + path: `${SITE_URL}user-org-perm`, + disabled: false + }, { icon: 'user-group', id: 'userGroupNav', @@ -177,6 +188,14 @@ const currentNav = [ path: `${SITE_URL}perm-template`, disabled: false }, + { + icon: 'renyuanmuban', + id: 'memberTemplateNav', + rkey: 'memberTemplate', + name: il8n('nav', '人员模板'), + path: `${SITE_URL}member-template`, + disabled: false + }, { icon: 'personal-user', id: 'userNav', @@ -186,11 +205,11 @@ const currentNav = [ disabled: false }, { - icon: 'renyuanmuban', - id: 'memberTemplateNav', - rkey: 'memberTemplate', - name: il8n('nav', '人员模板'), - path: `${SITE_URL}member-template`, + icon: 'resource-perm-manage', + id: 'resourcePermissNav', + rkey: 'resourcePermiss', + name: il8n('nav', '资源权限管理'), + path: `${SITE_URL}resource-permiss`, disabled: false } // { @@ -242,27 +261,19 @@ const currentNav = [ // path: `${SITE_URL}first-manage-space`, // disabled: false // }, - { - icon: 'resource-perm-manage', - id: 'resourcePermissNav', - rkey: 'resourcePermiss', - name: il8n('nav', '资源权限管理'), - path: `${SITE_URL}resource-permiss`, - disabled: false - }, - { - icon: 'mingandengji', - id: 'sensitivityLevelNav', - rkey: 'sensitivityLevel', - name: il8n('nav', '敏感等级'), - path: `${SITE_URL}sensitivity-level`, - disabled: false - }, { icon: 'perm-manage', name: il8n('common', '设置'), rkey: 'set', children: [ + { + icon: 'mingandengji', + id: 'sensitivityLevelNav', + rkey: 'sensitivityLevel', + name: il8n('nav', '敏感等级'), + path: `${SITE_URL}sensitivity-level`, + disabled: false + }, { icon: 'super-admin', name: il8n('common', '管理员'), @@ -348,7 +359,8 @@ const store = new Vuex.Store({ spaceManage, userGroupSetting, sensitivityLevel, - memberTemplate + memberTemplate, + userOrOrg }, state: { mainContentLoading: false, @@ -639,7 +651,8 @@ const store = new Vuex.Store({ }, updataNavRouterDiff (state, index) { - state.routerDiff = [...getNavRouterDiff(index)]; + const result = getManagerMenuPerm(state.roleList); + state.routerDiff = [...getNavRouterDiff(index, result)]; }, updateRoleList (state, payload) { @@ -738,13 +751,7 @@ const store = new Vuex.Store({ const AJAX_URL_PREFIX = window.AJAX_URL_PREFIX; return http.get(`${AJAX_URL_PREFIX}/accounts/user/`, config).then((response) => { const data = response ? response.data : {}; - // 由于现有搜索改成后端接口搜索,去掉之前前端自定义的内容 - // if (data.role.type === 'system_manager') { - // const langManager = ['zh-cn'].includes(window.CUR_LANGUAGE) ? '系统管理员' : ' system administrator'; - // data.role.name = `${data.role.name}${langManager}`; - // } commit('updateUser', data); - if (Object.keys(data).length > 0) { const role = data.role.type; if (role === 'staff') { @@ -784,14 +791,9 @@ const store = new Vuex.Store({ }; return http.get(`${AJAX_URL_PREFIX}/roles/grade_managers/?${json2Query(queryParams)}`).then(({ data }) => { const results = data.results || []; - // results.forEach((item) => { - // if (item.type === 'system_manager') { - // const langManager = ['zh-cn'].includes(window.CUR_LANGUAGE) ? '系统管理员' : ' system administrator'; - // item.name = `${item.name}${langManager}`; - // } - // }); commit('updateRoleListTotal', data.count || 0); commit('updateRoleList', results); + // commit('updateRoleList', results.filter((item) => item.type !== 'super_manager')); return results; }); }, diff --git a/frontend/src/store/modules/user-org.js b/frontend/src/store/modules/user-org.js new file mode 100644 index 000000000..8a2acf410 --- /dev/null +++ b/frontend/src/store/modules/user-org.js @@ -0,0 +1,228 @@ +/* + * 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 http from '@/api'; +import { json2Query } from '@/common/util'; + +const AJAX_URL_PREFIX = window.AJAX_URL_PREFIX; + +export default { + namespaced: true, + state: {}, + mutations: {}, + actions: { + /** + * 分级管理员查看有权限的用户组成员列表 + * + * @param {Function} commit store commit mutation handler + * @param {Object} state store state + * @param {Function} dispatch store dispatch action handler + * @param {Object} params 请求参数 + * @param {Object?} config http config + * + * @return {Promise} promise 对象 + */ + getUserGroupMemberList ({ commit, state, dispatch }, params = {}, config) { + Object.keys(params).forEach((item) => { + if (['offset', 'limit'].includes(item) || params[item] === '') { + delete params[item]; + } + }); + // const queryParams = Object.keys(params).length ? `/?${json2Query(params)}` : '/'; + // return http.get(`${AJAX_URL_PREFIX}/roles/group_members${queryParams}`, config); + const { page, page_size, hidden } = params; + const queryParams = Object.assign({}, { page, page_size }); + if (params.hasOwnProperty('hidden')) { + queryParams.hidden = hidden; + } + return http.post(`${AJAX_URL_PREFIX}/roles/group_members/?${json2Query(queryParams)}`, params, config); + }, + + /** + * 角色用户组成员-用户组列表 + * + * @param {Function} commit store commit mutation handler + * @param {Object} state store state + * @param {Function} dispatch store dispatch action handler + * @param {Object} params 请求参数 + * @param {Object?} config http config + * + * @return {Promise} promise 对象 + */ + getUserOrDepartGroupList ({ commit, state, dispatch }, params, config) { + const { offset, limit, hidden } = params; + const requestParams = Object.assign({}, params); + const queryParams = Object.assign({}, { offset, limit }); + if (params.hasOwnProperty('hidden')) { + queryParams.hidden = hidden; + } + Object.keys(params).forEach((item) => { + if (['subject_type', 'subject_id'].includes(item) || params[item] === '') { + delete params[item]; + } + }); + return http.post(`${AJAX_URL_PREFIX}/roles/group_members/${requestParams.subject_type}/${requestParams.subject_id}/groups/?${json2Query(queryParams)}`, params, config); + }, + + /** + * 角色用户组成员-部门用户组列表 + * + * @param {Function} commit store commit mutation handler + * @param {Object} state store state + * @param {Function} dispatch store dispatch action handler + * @param {Object} params 请求参数 + * @param {Object?} config http config + * + * @return {Promise} promise 对象 + */ + getUserGroupByDepartList ({ commit, state, dispatch }, params, config) { + const { offset, limit, hidden } = params; + const requestParams = Object.assign({}, params); + const queryParams = Object.assign({}, { offset, limit }); + if (params.hasOwnProperty('hidden')) { + queryParams.hidden = hidden; + } + Object.keys(params).forEach((item) => { + if (['subject_type', 'subject_id'].includes(item) || params[item] === '') { + delete params[item]; + } + }); + return http.post(`${AJAX_URL_PREFIX}/roles/group_members/${requestParams.subject_type}/${requestParams.subject_id}/departments/-/groups/?${json2Query(queryParams)}`, params, config); + }, + + /** + * 角色用户组成员-人员模版用户组列表 + * + * @param {Function} commit store commit mutation handler + * @param {Object} state store state + * @param {Function} dispatch store dispatch action handler + * @param {Object} params 请求参数 + * @param {Object?} config http config + * + * @return {Promise} promise 对象 + */ + getUserMemberTempList ({ commit, state, dispatch }, params, config) { + const { offset, limit, hidden } = params; + const requestParams = Object.assign({}, params); + const queryParams = Object.assign({}, { offset, limit }); + if (params.hasOwnProperty('hidden')) { + queryParams.hidden = hidden; + } + Object.keys(params).forEach((item) => { + if (['subject_type', 'subject_id'].includes(item) || params[item] === '') { + delete params[item]; + } + }); + return http.post(`${AJAX_URL_PREFIX}/roles/group_members/${requestParams.subject_type}/${requestParams.subject_id}/subject_template_groups/?${json2Query(queryParams)}`, params, config); + }, + + /** + * 角色用户组成员-部门人员模版用户组列表 + * + * @param {Function} commit store commit mutation handler + * @param {Object} state store state + * @param {Function} dispatch store dispatch action handler + * @param {Object} params 请求参数 + * @param {Object?} config http config + * + * @return {Promise} promise 对象 + */ + getDepartMemberTempList ({ commit, state, dispatch }, params, config) { + const { offset, limit, hidden } = params; + const requestParams = Object.assign({}, params); + const queryParams = Object.assign({}, { offset, limit }); + if (params.hasOwnProperty('hidden')) { + queryParams.hidden = hidden; + } + Object.keys(params).forEach((item) => { + if (['subject_type', 'subject_id'].includes(item) || params[item] === '') { + delete params[item]; + } + }); + return http.post(`${AJAX_URL_PREFIX}/roles/group_members/${requestParams.subject_type}/${requestParams.subject_id}/departments/-/subject_template_groups/?${json2Query(queryParams)}`, params, config); + }, + + /** + * 批量用户组删除成员 + * + * @param {Function} commit store commit mutation handler + * @param {Object} state store state + * @param {Function} dispatch store dispatch action handler + * @param {Object} params 请求参数 + * @param {Object?} config http config + * + * @return {Promise} promise 对象 + */ + deleteGroupMembers ({ commit, state, dispatch }, params, config) { + return http.post(`${AJAX_URL_PREFIX}/groups/members/delete/`, params, config); + }, + + /** + * 批量重置用户组成员 + * + * @param {Function} commit store commit mutation handler + * @param {Object} state store state + * @param {Function} dispatch store dispatch action handler + * @param {Object} params 请求参数 + * @param {Object?} config http config + * + * @return {Promise} promise 对象 + */ + resetGroupMembers ({ commit, state, dispatch }, params, config) { + return http.post(`${AJAX_URL_PREFIX}/roles/group_members/reset/`, params, config); + }, + + /** + * 批量清空用户组成员 + * + * @param {Function} commit store commit mutation handler + * @param {Object} state store state + * @param {Function} dispatch store dispatch action handler + * @param {Object} params 请求参数 + * @param {Object?} config http config + * + * @return {Promise} promise 对象 + */ + cleanGroupMembers ({ commit, state, dispatch }, params, config) { + return http.post(`${AJAX_URL_PREFIX}/roles/group_members/clean/`, params, config); + }, + + /** + * 批量加入用户组/批量续期 + * + * @param {Function} commit store commit mutation handler + * @param {Object} state store state + * @param {Function} dispatch store dispatch action handler + * @param {Object} params 请求参数 + * @param {Object?} config http config + * + * @return {Promise} promise 对象 + */ + batchJoinOrRenewal ({ commit, state, dispatch }, params, config) { + return http.post(`${AJAX_URL_PREFIX}/groups/members/renew/`, params, config); + } + } +}; diff --git a/frontend/src/views/approval-process/index.vue b/frontend/src/views/approval-process/index.vue index 16b88bf5f..327307e15 100644 --- a/frontend/src/views/approval-process/index.vue +++ b/frontend/src/views/approval-process/index.vue @@ -1,6 +1,6 @@ - + - + { @@ -180,14 +201,14 @@ const { code, data } = await this.$store.dispatch('approvalProcess/getDefaultProcesses'); const defaultProcesses = data || []; const grantAction = defaultProcesses.find(item => item.type === 'grant_action'); + const joinGroup = defaultProcesses.find(item => item.type === 'join_group'); + const createRatingManager = defaultProcesses.find(item => item.type === 'create_rating_manager'); if (grantAction) { this.processSetList[0].process_id = grantAction.process_id; } - const joinGroup = defaultProcesses.find(item => item.type === 'join_group'); if (joinGroup) { this.processSetList[1].process_id = joinGroup.process_id; } - const createRatingManager = defaultProcesses.find(item => item.type === 'create_rating_manager'); if (createRatingManager) { this.processSetList[2].process_id = createRatingManager.process_id; } @@ -205,6 +226,10 @@ */ getFilterPanels () { const roleItem = { + super_manager: () => { + this.panels = this.panels.filter(item => ['CustomPermProcess', 'JoinRateManagerProcess', 'JoinGroupProcess'].includes(item.name)); + this.active = 'CustomPermProcess'; + }, system_manager: () => { this.panels = this.panels.filter(item => ['CustomPermProcess', 'JoinGroupProcess'].includes(item.name)); this.active = 'CustomPermProcess'; @@ -218,7 +243,9 @@ this.active = 'JoinGroupProcess'; } }; - return roleItem[this.curRole] ? roleItem[this.curRole]() : 'CustomPermProcess'; + if (roleItem[this.curRole]) { + roleItem[this.curRole](); + } }, /** @@ -263,6 +290,9 @@ margin-top: 20px; min-height: calc(100vh - 250px); } + &.hide-process-table { + display: none; + } .iam-approval-process-set-tab-cls { .bk-tab-header { height: 60px; diff --git a/frontend/src/views/grading-admin/components/render-instance.vue b/frontend/src/views/grading-admin/components/render-instance.vue index 52ea2c16c..f48ebe833 100644 --- a/frontend/src/views/grading-admin/components/render-instance.vue +++ b/frontend/src/views/grading-admin/components/render-instance.vue @@ -71,7 +71,7 @@ }, computed: { expandedText () { - return this.isAllExpanded ? this.$t(`m.grading['逐项编辑']`) : this.$t(`m.grading['展开选择']`); + return this.isAllExpanded ? this.$t(`m.grading['展开选择']`) : this.$t(`m.grading['逐项编辑']`); }, isAggregateDisabled () { return this.policyList.length < 1 diff --git a/frontend/src/views/grading-admin/create/index.vue b/frontend/src/views/grading-admin/create/index.vue index 6cff2197a..f67bafbf2 100644 --- a/frontend/src/views/grading-admin/create/index.vue +++ b/frontend/src/views/grading-admin/create/index.vue @@ -378,7 +378,7 @@ return tempList; }, expandedText () { - return this.isAllExpanded ? this.$t(`m.grading['逐项编辑']`) : this.$t(`m.grading['批量编辑']`); + return this.isAllExpanded ? this.$t(`m.grading['批量编辑']`) : this.$t(`m.grading['逐项编辑']`); }, isAggregateDisabled () { return this.policyList.length < 1 diff --git a/frontend/src/views/grading-admin/edit/index.vue b/frontend/src/views/grading-admin/edit/index.vue index e516b2d8c..c97d32d8d 100644 --- a/frontend/src/views/grading-admin/edit/index.vue +++ b/frontend/src/views/grading-admin/edit/index.vue @@ -341,7 +341,7 @@ return tempList; }, expandedText () { - return this.isAllExpanded ? this.$t(`m.grading['逐项编辑']`) : this.$t(`m.grading['批量编辑']`); + return this.isAllExpanded ? this.$t(`m.grading['批量编辑']`) : this.$t(`m.grading['逐项编辑']`); }, isAggregateDisabled () { return this.policyList.length < 1 diff --git a/frontend/src/views/grading-admin/index.vue b/frontend/src/views/grading-admin/index.vue index db24766f7..d5dd71c79 100644 --- a/frontend/src/views/grading-admin/index.vue +++ b/frontend/src/views/grading-admin/index.vue @@ -10,18 +10,10 @@ {{ isStaff ? $t(`m.common['申请新建']`) : $t(`m.common['新建']`) }} - + {{ $t('m.common["什么是管理空间"]') }} - - + - - + + @@ -84,7 +76,7 @@ @on-change="handleUpdateSubMembers" /> - + - + {{ child.row.updated_time }} - + - - - - {{ $t(`m.levelSpace['进入空间']`) }} - - + + {{ $t(`m.levelSpace['进入空间']`) }} + {{ $t(`m.nav['授权边界']`) }} - @@ -158,7 +137,7 @@ - + @@ -187,12 +166,6 @@ - - + - - + + {{ row.updated_time }} - + - {{ $t(`m.nav['授权边界']`) }} - - {{ $t(`m.grading['克隆']`) }} - + + + + + + {{ $t(`m.levelSpace['克隆']`) }} + + + + @@ -422,10 +408,10 @@ // if (!row.is_member) { // return 'iam-tag-table-cell-cls iam-tag-table-cell-opacity-cls'; // } - if (!row.has_subset_manager) { + if (!row.has_subset_manager && !['right'].includes(column.fixed)) { return 'iam-tag-table-cell-cls iam-tag-table-cell-subset-cls'; } - if (columnIndex === 1 || column.type === 'default') { + if ((columnIndex === 1 || column.type === 'default') && !['right'].includes(column.fixed)) { return 'iam-table-cell-1-cls'; } if (columnIndex === 2) { @@ -435,7 +421,7 @@ }, getSubCellClass ({ row, column, rowIndex, columnIndex }) { - return 'iam-table-cell-1-cls'; + return !['child-operate'].includes(column.property) ? 'iam-table-cell-1-cls' : ''; }, handleExpandChange (row, expandedRows) { @@ -900,134 +886,150 @@ } }; + + + - -> +} +/deep/ .bk-table-fixed, +/deep/ .bk-table-fixed-right { + border-bottom: 0; +} +/deep/ .children-expand-cls { + .bk-table-fixed { + .bk-table-fixed-body-wrapper { + z-index: 900; + } + } + .bk-table-fixed-right { + .bk-table__fixed-body-wrapper{ + z-index: 900; + } + } + .bk-table-body-wrapper { + z-index: 800; + } +} + diff --git a/frontend/src/views/group/add-perm/index.vue b/frontend/src/views/group/add-perm/index.vue index d7d27571e..c091f58e1 100644 --- a/frontend/src/views/group/add-perm/index.vue +++ b/frontend/src/views/group/add-perm/index.vue @@ -167,7 +167,7 @@ return isDisabled; }, expandedText () { - return this.isAllExpanded ? this.$t(`m.grading['逐项编辑']`) : this.$t(`m.grading['批量编辑']`); + return this.isAllExpanded ? this.$t(`m.grading['批量编辑']`) : this.$t(`m.grading['逐项编辑']`); }, defaultValue () { if (this.originalList.length < 1) { diff --git a/frontend/src/views/group/clone/index.vue b/frontend/src/views/group/clone/index.vue index 71538e52b..255e34f7b 100644 --- a/frontend/src/views/group/clone/index.vue +++ b/frontend/src/views/group/clone/index.vue @@ -290,7 +290,7 @@ * expandedText */ expandedText () { - return this.isAllExpanded ? this.$t(`m.grading['逐项编辑']`) : this.$t(`m.grading['批量编辑']`); + return this.isAllExpanded ? this.$t(`m.grading['批量编辑']`) : this.$t(`m.grading['逐项编辑']`); }, members () { const arr = []; @@ -433,7 +433,7 @@ // 获取分级管理员用户组配置 async fetchUserGroupSet () { - if (!['subset_manager'].includes(this.user.role.type)) { + if (!['subset_manager', 'staff', ''].includes(this.user.role.type)) { try { const { data } = await this.$store.dispatch('userGroupSetting/getUserGroupSetConfig'); if (data) { diff --git a/frontend/src/views/group/common/render-member-display.vue b/frontend/src/views/group/common/render-member-display.vue index df2936def..f21631372 100644 --- a/frontend/src/views/group/common/render-member-display.vue +++ b/frontend/src/views/group/common/render-member-display.vue @@ -15,14 +15,24 @@ :key="index" class="member-item" :title="nameType(item)"> - - {{ isDepartment ? item.name : item.username }} - - - ({{ item.count }}) - - - ({{ item.name }}) + + + + + {{ formatCustomTypeName(item) }} + + + + + {{ isHasDepartCount ? item.name : item.username || item.id }} + + + ({{ item.count }}) + + + ({{ item.name }}) + + {{ item.name }} @@ -51,6 +61,9 @@ } }, computed: { + isCustomRoute () { + return ['userOrgPerm'].includes(this.$route.name); + }, icon () { if (this.type === 'user') { return 'personal-user'; @@ -70,30 +83,34 @@ return this.$t(`m.common['组织']`); }, isDepartment () { - return this.type === 'department' && window.ENABLE_ORGANIZATION_COUNT.toLowerCase() === 'true'; + return this.type === 'department'; }, isTemplate () { return this.type === 'template'; }, + isHasDepartCount () { + return this.isDepartment && window.ENABLE_ORGANIZATION_COUNT.toLowerCase() === 'true'; + }, isEdit () { return this.mode === 'edit'; }, nameType () { return (payload) => { - const { name, type, username, full_name: fullName } = payload; + const { name, type, id, username, full_name: fullName } = payload; const typeMap = { user: () => { if (fullName) { return fullName; } else { - return name ? `${username}(${name})` : username; + const curName = username || id; + return name ? `${curName}(${name})` : curName; } }, department: () => { - return fullName || payload.fullName || `${username}(${name})`; + return fullName || payload.fullName || (username ? `${username}(${name})` : name); }, depart: () => { - return fullName || payload.fullName || `${username}(${name})`; + return fullName || payload.fullName || (username ? `${username}(${name})` : name); }, template: () => { return name; @@ -101,6 +118,20 @@ }; return typeMap[type] ? typeMap[type]() : typeMap['user'](); }; + }, + formatCustomTypeName () { + return (payload) => { + const { name, type, id } = payload; + const typeMap = { + user: () => { + return `${id} (${name})`; + }, + department: () => { + return `${name} (${id})`; + } + }; + return typeMap[type] ? typeMap[type]() : typeMap['user'](); + }; } }, methods: { diff --git a/frontend/src/views/group/components/add-action-sideslider.vue b/frontend/src/views/group/components/add-action-sideslider.vue index 59dc62bef..b45cfdcf2 100644 --- a/frontend/src/views/group/components/add-action-sideslider.vue +++ b/frontend/src/views/group/components/add-action-sideslider.vue @@ -515,6 +515,9 @@ * @param {String} systemId 系统id */ async fetchCommonActions (systemId) { + if (!systemId) { + return; + } try { const { code, data } = await this.$store.dispatch('permApply/getUserCommonAction', { systemId }); this.commonActions.splice(0, this.commonActions.length, ...(data || [])); @@ -599,12 +602,15 @@ this.fetchErrorMsg(e); } finally { this.initRequestQueue.shift(); + if (!this.systemList.length) { + this.initRequestQueue = []; + } this.systemListIsLoading = false; } }, async fetchAggregationAction () { - if (this.aggregationData[this.curSystem]) { + if (!this.curSystem || this.aggregationData[this.curSystem]) { return; } try { @@ -618,7 +624,7 @@ }, async fetchAuthorizationScopeActions () { - if (this.authorizationData[this.curSystem]) { + if (!this.curSystem || this.authorizationData[this.curSystem]) { return; } try { @@ -640,6 +646,9 @@ * @param {String} systemId 系统id */ async fetchActions (systemId) { + if (!systemId) { + return; + } const params = { system_id: systemId }; diff --git a/frontend/src/views/group/components/attribute.vue b/frontend/src/views/group/components/attribute.vue index ba8e47c5e..c5a7a9641 100644 --- a/frontend/src/views/group/components/attribute.vue +++ b/frontend/src/views/group/components/attribute.vue @@ -10,7 +10,7 @@ :clearable="false" :disabled="item.disabled || isDisabledMode" searchable - style="width: 130px;" + style="width: 160px;" @selected="handleAttributeSelected(...arguments, item)"> {{ option.display_name }} - + @@ -55,6 +55,7 @@ + + diff --git a/frontend/src/views/perm-apply/apply-custom-perm/index.vue b/frontend/src/views/perm-apply/apply-custom-perm/index.vue index 4c47284e3..ea64231b0 100644 --- a/frontend/src/views/perm-apply/apply-custom-perm/index.vue +++ b/frontend/src/views/perm-apply/apply-custom-perm/index.vue @@ -243,7 +243,7 @@ :disabled="isAggregateDisabled" @change="handleAggregateActionChange"> - {{ isAllExpanded ? $t(`m.grading['逐项编辑']`) : $t(`m.grading['批量编辑']`) }} + {{ isAllExpanded ? $t(`m.grading['批量编辑']`) : $t(`m.grading['逐项编辑']`) }} diff --git a/frontend/src/views/perm-apply/components/attribute.vue b/frontend/src/views/perm-apply/components/attribute.vue index 150a186e4..299d53201 100644 --- a/frontend/src/views/perm-apply/components/attribute.vue +++ b/frontend/src/views/perm-apply/components/attribute.vue @@ -10,7 +10,7 @@ :clearable="false" :disabled="item.disabled" searchable - style="width: 130px;" + style="width: 160px;" @selected="handleAttributeSelected(...arguments, item)"> - @@ -38,7 +39,7 @@ {{ option.display_name }} - + @@ -56,6 +57,7 @@ + + diff --git a/frontend/src/views/user-org-perm/components/clear-user-group-slider.vue b/frontend/src/views/user-org-perm/components/clear-user-group-slider.vue new file mode 100644 index 000000000..133e3c5dd --- /dev/null +++ b/frontend/src/views/user-org-perm/components/clear-user-group-slider.vue @@ -0,0 +1,313 @@ + + + + + + {{ $t(`m.userOrOrg['清空对象']`) }} + + + + {{ $t(`m.common['已选']`) }} + + {{ userList.length }} + {{ $t(`m.common['个用户']`) }} + + | + + {{ $t(`m.common['清空']`) }} + {{ $t(`m.userOrOrg['个人']`) }} + {{ $t(`m.userOrOrg['用户组权限(不影响因所属组织而拥有的用户组权限)']`) }} + + + + + + + + + + + + {{ $t(`m.common['已选']`) }} + + {{ departList.length }} + {{ $t(`m.common['个组织']`) }} + + | + + {{ $t(`m.common['清空']`) }} + {{ $t(`m.common['组织']`) }} + {{ $t(`m.perm['用户组权限']`) }} + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/views/user-org-perm/components/group-perm-table.vue b/frontend/src/views/user-org-perm/components/group-perm-table.vue new file mode 100644 index 000000000..4950ae936 --- /dev/null +++ b/frontend/src/views/user-org-perm/components/group-perm-table.vue @@ -0,0 +1,629 @@ + + + + + + + + + + {{ row.name || "--" }} + + + + + + + + + {{ row.created_time.replace(/T/, " ") }} + + + + + + + + + {{ formatJoinType(row) }} + + ( 0 ? 'memberTemplate' : 'userOrgPerm')" + > + {{ row.template_name || row.department_name }} + + + {{ ` - ${row.department_name}` }} + + ) + + + + + + + + + + + + {{ $t(`m.dialog['确认把用户/组织移出该用户组?']`) }} + + + + + + {{ $t(`m.userOrOrg['操作对象']`) }}: + + {{ formatUserName }} + + + + {{ $t(`m.userOrOrg['用户组名']`) }}: + + {{ row.name }} + + + {{ + $t(`m.userOrOrg['移出后,该用户/组织将不再继承该组的权限。']`) + }} + + + + + + {{ $t(`m.userOrOrg['移出']`) }} + + + + + {{ $t(`m.renewal['续期']`) }} + + + + + + + + + + {{ row[item.prop] || '--'}} + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/views/user-org-perm/components/join-user-group-slider.vue b/frontend/src/views/user-org-perm/components/join-user-group-slider.vue new file mode 100644 index 000000000..91676a7c0 --- /dev/null +++ b/frontend/src/views/user-org-perm/components/join-user-group-slider.vue @@ -0,0 +1,479 @@ + + + + + + + + + + + {{ $t(`m.common['已选']`) }} + + {{ userList.length }} + {{ $t(`m.common['个用户']`) }} + + + {{ $t(`m.common[',']`) }} + + + {{ departList.length }} + {{ $t(`m.common['个组织']`) }} + + + + + + + + + + + + + + + + + + + + + {{ formatGroupTitle }} + + + + {{ formatGroupTip }} + + + + + {{ formatGroupTitle }} + + + + + + + + {{ $t(`m.permApply['请选择用户组']`) }} + + + + {{ $t(`m.userOrOrg['请选择申请时长']`) }} + + + + + + + + + + + + + + diff --git a/frontend/src/views/user-org-perm/components/join-user-group-table.vue b/frontend/src/views/user-org-perm/components/join-user-group-table.vue new file mode 100644 index 000000000..4635fcc92 --- /dev/null +++ b/frontend/src/views/user-org-perm/components/join-user-group-table.vue @@ -0,0 +1,653 @@ + + + + + + + + + + + + + {{ row.name }} + + + + + + + {{ row.description || '--' }} + + + + + + + + + + + {{ $t(`m.common['结果预览']`) }} + + + + {{ $t(`m.common['已选择']`) }} + {{ currentSelectedGroups.length }} + {{ $t(`m.common['个用户组#']`) }} + + + {{ $t(`m.common['清空']`) }} + + + + + + + + {{ item.name }} + + + + + + + + + + + + + + + + + diff --git a/frontend/src/views/user-org-perm/components/left-layout.vue b/frontend/src/views/user-org-perm/components/left-layout.vue new file mode 100644 index 000000000..62f339f88 --- /dev/null +++ b/frontend/src/views/user-org-perm/components/left-layout.vue @@ -0,0 +1,585 @@ + + + + {{ $t(`m.userOrOrg['用户 / 组织列表']`) }} + + + + + {{ $t(`m.userOrOrg['批量操作']`) }} + + + + + + {{ $t(`m.userOrOrg['重置用户组']`) }} + + + + + {{ $t(`m.userOrOrg['追加用户组']`) }} + + + + + {{ $t(`m.userOrOrg['清空用户组']`) }} + + + + + + + + + + + + + {{ item.id }} + ({{ item.name }}) + + + {{ item.name }} + + + + + + + + {{ $t(`m.common['加载中']`) }} + + + {{ $t(`m.common['剩余加载数据']`, { value: pagination.count - list.length }) }} + + + {{ $t(`m.common['已加载全部数据']`, { value: pagination.count - list.length }) }} + + + + + + + + + + + + + + diff --git a/frontend/src/views/user-org-perm/components/multi-type-group-perm.vue b/frontend/src/views/user-org-perm/components/multi-type-group-perm.vue new file mode 100644 index 000000000..74c194f0c --- /dev/null +++ b/frontend/src/views/user-org-perm/components/multi-type-group-perm.vue @@ -0,0 +1,701 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/views/user-org-perm/components/page-layout.vue b/frontend/src/views/user-org-perm/components/page-layout.vue new file mode 100644 index 000000000..f4a4b9898 --- /dev/null +++ b/frontend/src/views/user-org-perm/components/page-layout.vue @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/views/user-org-perm/components/right-layout.vue b/frontend/src/views/user-org-perm/components/right-layout.vue new file mode 100644 index 000000000..7b18f548b --- /dev/null +++ b/frontend/src/views/user-org-perm/components/right-layout.vue @@ -0,0 +1,386 @@ + + + {{ formatUserName }} + + + + {{ $t(`m.userOrOrg['加入用户组']`) }} + + + + + + {{ $t(`m.userOrOrg['批量操作']`) }} + + + + + + {{ $t(`m.userOrOrg['移出']`) }} + + + + + {{ $t(`m.renewal['续期']`) }} + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/views/user-org-perm/components/user-group-table.vue b/frontend/src/views/user-org-perm/components/user-group-table.vue new file mode 100644 index 000000000..4d0f7fb7e --- /dev/null +++ b/frontend/src/views/user-org-perm/components/user-group-table.vue @@ -0,0 +1,277 @@ + + + + + + + + + {{ row.name || '--' }} + + + + + + + + + + + + + + + + + + {{ $t(`m.common['移除']`) }} + + + + + + + + + {{ row[item.prop] || '--' }} + + + + + + + + + + + + + + + diff --git a/frontend/src/views/user-org-perm/index.vue b/frontend/src/views/user-org-perm/index.vue new file mode 100644 index 000000000..b4cc22020 --- /dev/null +++ b/frontend/src/views/user-org-perm/index.vue @@ -0,0 +1,1076 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ tag.label }} + + + + + + + + + + + {{tag.label}}: + {{ tag.value }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/views/user-org-perm/user-org-perm.css b/frontend/src/views/user-org-perm/user-org-perm.css new file mode 100644 index 000000000..2f0981bd3 --- /dev/null +++ b/frontend/src/views/user-org-perm/user-org-perm.css @@ -0,0 +1,207 @@ +.user-org-wrapper { + padding: 0; + color: #313238; + position: relative; + &-search { + box-shadow: 0 2px 3px 0 #0000000a; + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1; + .custom-content { + &-form { + display: flex; + .custom-form-item { + margin-top: 8px; + &:not(&:last-child) { + margin-right: 16px; + } + } + } + &-footer { + margin-top: 16px; + } + &-no-search { + .custom-content-form { + .custom-form-item { + margin-top: 0; + } + } + } + } + &.no-search-data { + display: none; + } + } + &-expand { + width: 64px; + height: 16px; + background-color: #dcdee5; + border-radius: 0 0px 4px 4px; + position: absolute; + top: 225px; + left: 50%; + transform: translate(-50%, -50%); + z-index: 1; + cursor: pointer; + .icon { + color: #ffffff; + font-size: 22px !important; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + &-no-search { + top: 150px; + } + &.no-expand-no-search-data { + top: 8px; + } + &.no-expand-has-search-data { + top: 51px; + } + &:hover { + background-color: #3a84ff; + } + } + &-content { + &-left { + /* padding: 0 16px; */ + /* background-color: #FAFBFD; */ + background-color: #ffffff; + border-right: 1px solid#dcdee5; + height: calc(100vh - 61px); + } + &-center { + width: 16px; + height: calc(100vh - 234px); + .expand-icon { + width: 16px; + height: 64px; + background-color: #dcdee5; + border-radius: 0 4px 4px 0; + position: relative; + top: 50%; + transform: translateY(-50%); + cursor: pointer; + .icon { + color: #ffffff; + font-size: 22px !important; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + &:hover { + background-color: #3a84ff; + } + } + } + &-right { + padding-right: 16px; + position: relative; + height: 100%; + &.no-expand { + padding-right: 0; + } + .right-empty-data { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + } + } + .search-data-no-expand { + min-height: 42px; + line-height: 42px; + background-color: #ffffff; + box-shadow: 0 2px 3px 0 #0000000f; + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1; + .no-expand-search-list { + padding: 0 16px; + .search-data-content { + /* display: flex; + align-items: center; */ + overflow-x: auto; + white-space: nowrap; + word-break: break-all; + .funnel-icon { + color: #979BA5; + } + .tag-list { + .tag-item { + display: flex; + align-items: center; + cursor: pointer; + &-value { + margin-left: 8px; + } + } + } + .delete-all { + margin-left: 8px; + &-icon { + color: #C4C6CC; + font-size: 14px; + cursor: pointer; + vertical-align: middle; + &:hover { + color: #979BA5; + } + } + } + } + } + } +} +.my-perm-group-perm { + height: 100%; + &-header { + margin-bottom: 16px; + } + .iam-perm-ext-cls { + margin-top: 1px; + } + .user-org-perm-table { + border: none; + color: #63656E !important; + .can-view-name { + color: #3a84ff; + cursor: pointer; + &:hover { + color: #699df4; + } + } + /deep/ .bk-table-fixed, + .bk-table-fixed-right { + border-bottom: 0; + } + } +} +.user-org-remove-confirm { + .popover-title { + font-size: 16px; + padding-bottom: 16px; + color: #313238; + } + .popover-content { + color: #63656e; + .popover-content-item { + display: flex; + margin-bottom: 8px; + &-value { + color: #313238; + margin-left: 8px; + } + } + &-tip { + padding-bottom: 20px; + color: #63656E; + } + } +} diff --git a/frontend/src/views/user/components/group-perm.vue b/frontend/src/views/user/components/group-perm.vue index bd9ef069c..2f3daab58 100644 --- a/frontend/src/views/user/components/group-perm.vue +++ b/frontend/src/views/user/components/group-perm.vue @@ -736,7 +736,7 @@ fetchSelectedGroupCount () { this.$nextTick(() => { const selectionCount = document.getElementsByClassName('bk-page-selection-count'); - if (this.$refs.groupPermTableRef && selectionCount) { + if (this.$refs.groupPermTableRef && selectionCount && selectionCount.length && selectionCount[0].children) { selectionCount[0].children[0].innerHTML = this.currentSelectGroupList.length; } }); diff --git a/frontend/src/views/user/components/joined-user-group.vue b/frontend/src/views/user/components/joined-user-group.vue index c3e1d6eac..2f7eae566 100644 --- a/frontend/src/views/user/components/joined-user-group.vue +++ b/frontend/src/views/user/components/joined-user-group.vue @@ -719,7 +719,11 @@ } this.$nextTick(() => { const selectionCount = document.getElementsByClassName('bk-page-selection-count'); - if (this.$refs.groupPermTableRef && selectionCount) { + if (this.$refs.groupPermTableRef + && selectionCount + && selectionCount.length + && selectionCount[0].children + ) { selectionCount[0].children[0].innerHTML = this.currentSelectGroupList.length; } }); diff --git a/frontend/src/views/user/components/render-user.vue b/frontend/src/views/user/components/render-user.vue index fa28f6ffe..65d97495e 100644 --- a/frontend/src/views/user/components/render-user.vue +++ b/frontend/src/views/user/components/render-user.vue @@ -8,7 +8,6 @@ List[ActionBean]: diff --git a/saas/backend/biz/role.py b/saas/backend/biz/role.py index d6f8af024..72d43446b 100644 --- a/saas/backend/biz/role.py +++ b/saas/backend/biz/role.py @@ -645,17 +645,21 @@ def _query_subset_manager_template_id(self) -> List[int]: return template_ids - def query_group(self, inherit: bool = True): + def query_group(self, inherit: bool = True, only_inherit: bool = False): """ 查询用户组列表 """ if self.role.type == RoleType.STAFF.value: return Group.objects.filter(hidden=False) - group_ids = self._get_role_related_object_ids(RoleRelatedObjectType.GROUP.value, inherit=inherit) + group_ids = self._get_role_related_object_ids( + RoleRelatedObjectType.GROUP.value, inherit=inherit, only_inherit=only_inherit + ) return Group.objects.filter(id__in=group_ids) - def _get_role_related_object_ids(self, object_type: str, inherit: bool = True) -> List[int]: + def _get_role_related_object_ids( + self, object_type: str, inherit: bool = True, only_inherit: bool = False + ) -> List[int]: # 分级管理员可以管理子集管理员的所有用户组 if ( self.role.type == RoleType.GRADE_MANAGER.value @@ -663,7 +667,8 @@ def _get_role_related_object_ids(self, object_type: str, inherit: bool = True) - and inherit ): role_ids = RoleRelation.objects.list_sub_id(self.role.id) - role_ids.append(self.role.id) + if not only_inherit: + role_ids.append(self.role.id) return list( RoleRelatedObject.objects.filter(role_id__in=role_ids, object_type=object_type).values_list( "object_id", flat=True diff --git a/saas/backend/service/action.py b/saas/backend/service/action.py index 7c4461dd2..9b9921b38 100644 --- a/saas/backend/service/action.py +++ b/saas/backend/service/action.py @@ -36,7 +36,7 @@ class ActionService: full_fields = ( "id,name,name_en,related_resource_types,version,type,hidden,description,description_en," - "related_actions,related_environments" + "related_actions,related_environments,sensitivity" ) @cachedmethod(timeout=60) diff --git a/saas/backend/service/models/action.py b/saas/backend/service/models/action.py index 2582ced52..f828b77c9 100644 --- a/saas/backend/service/models/action.py +++ b/saas/backend/service/models/action.py @@ -59,6 +59,7 @@ class Action(BaseModel): related_resource_types: List[RelatedResourceType] = [] related_actions: List[str] = [] # 依赖操作 related_environments: List[RelatedEnvironment] = [] + sensitivity: int = 1 def __init__(self, **data: Any): if "related_actions" in data and data["related_actions"] is None: diff --git a/saas/resources/version_log/change_log.md b/saas/resources/version_log/change_log.md index f627d64c7..e60393b04 100644 --- a/saas/resources/version_log/change_log.md +++ b/saas/resources/version_log/change_log.md @@ -1,3 +1,14 @@ + +# V1.10.25 版本更新日志 + +### 新增功能 + +* 管理空间下心中用户/部门权限管理 +* 系统管理员增加查询有权限的人员功能 +* 系统管理员增加操作敏感等级编辑功能 + +--- + # V1.10.24 版本更新日志 diff --git a/saas/resources/version_log/change_log_en.md b/saas/resources/version_log/change_log_en.md index fd7bdb9a5..dfddafa7e 100644 --- a/saas/resources/version_log/change_log_en.md +++ b/saas/resources/version_log/change_log_en.md @@ -1,3 +1,14 @@ + +# V1.10.25 Version Update Log + +### New Features + +* Added the ability to manage permissions for desired users/departments within the management space. +* System administrators can now query personnel with permissions. +* System administrators can now edit sensitivity levels. + +--- + # V1.10.24 Version Update Log
+
{{ $t(`m.common['点击收起']`) }}
- {{$t(`m.verify['请选择系统']`)}} -
- {{$t(`m.verify['请选择操作']`)}} -
- {{$t(`m.verify['请选择资源类型']`)}} -
- {{$t(`m.resourcePermiss['请选择资源实例']`)}} -
+ {{$t(`m.verify['请选择系统']`)}} +
+ {{$t(`m.verify['请选择操作']`)}} +
+ {{$t(`m.verify['请选择资源类型']`)}} +
+ {{$t(`m.resourcePermiss['请选择资源实例']`)}} +
{{ $t(`m.permApply['请选择用户组']`) }}
{{ $t(`m.userOrOrg['请选择申请时长']`) }}