Browse Source

权限管理优化

shimingxy 9 months ago
parent
commit
3f96dee6b6

+ 125 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/permissions/apps/apps.component.html

@@ -0,0 +1,125 @@
+<page-header> </page-header>
+
+<nz-card [nzBordered]="false">
+    <form nz-form [nzLayout]="'inline'" (ngSubmit)="onSearch()" class="search__form">
+        <div nz-row [nzGutter]="{ xs: 8, sm: 8, md: 24, lg: 24, xl: 48, xxl: 48 }">
+            <div nz-col nzMd="10" nzSm="24">
+                <nz-form-item>
+                    <nz-form-label nzFor="appName">{{ 'mxk.apps.name' | i18n }}</nz-form-label>
+                    <nz-form-control>
+                        <input nz-input [(ngModel)]="query.params.appName" [ngModelOptions]="{ standalone: true }"
+                            name="appName" placeholder="" id="appName" />
+                    </nz-form-control>
+                </nz-form-item>
+            </div>
+            <div nz-col nzMd="10" nzSm="24">
+                <nz-form-item>
+                    <nz-form-label nzFor="protocol">{{ 'mxk.apps.protocol' | i18n }}</nz-form-label>
+                    <nz-form-control>
+                        <nz-select [(ngModel)]="query.params.protocol" [ngModelOptions]="{ standalone: true }">
+                            <nz-option nzValue="" nzLabel="ALL"></nz-option>
+                            <nz-option nzValue="OAuth_v2.0" nzLabel="OAuth v2.0"></nz-option>
+                            <nz-option nzValue="OAuth_v2.1" nzLabel="OAuth v2.1"></nz-option>
+                            <nz-option nzValue="OpenID_Connect_v1.0" nzLabel="OpenID Connect v1.0"></nz-option>
+                            <nz-option nzValue="SAML_v2.0" nzLabel="SAML v2.0"> </nz-option>
+                            <nz-option nzValue="CAS" nzLabel="CAS"></nz-option>
+                            <nz-option nzValue="JWT" nzLabel="JWT"></nz-option>
+                            <nz-option nzValue="Token_Based" nzLabel="Token Based"></nz-option>
+                            <nz-option nzValue="Form_Based" nzLabel="Form Based"></nz-option>
+                            <nz-option nzValue="Extend_API" nzLabel="Extend API"></nz-option>
+                            <nz-option nzValue="Basic" nzLabel="Basic"></nz-option>
+                        </nz-select>
+                    </nz-form-control>
+                </nz-form-item>
+            </div>
+            <div nz-col [nzSpan]="query.expandForm ? 24 : 4" [class.text-right]="query.expandForm">
+                <nz-form-item>
+                    <button nz-button type="submit" [nzType]="'primary'" [nzLoading]="query.submitLoading">{{
+                        'mxk.text.query' | i18n }}</button>
+                    <button nz-button type="reset" (click)="onReset()" class="mx-sm" style="display: none">{{
+                        'mxk.text.reset' | i18n }}</button>
+                    <button nz-button (click)="query.expandForm = !query.expandForm" class="mx-sm"
+                        style="display: none">
+                        {{ query.expandForm ? ('mxk.text.collapse' | i18n) : ('mxk.text.expand' | i18n) }}</button>
+                </nz-form-item>
+            </div>
+        </div>
+    </form>
+</nz-card>
+<nz-card>
+    <div nz-col [nzSpan]="24" class="table-list-toolbar">
+        <nz-table #dynamicTable nzTableLayout="auto" nzSize="small" nzBordered nzShowSizeChanger
+            [nzData]="query.results.rows" [nzFrontPagination]="false" [nzTotal]="query.results.records"
+            [nzPageSizeOptions]="query.params.pageSizeOptions" [nzPageSize]="query.params.pageSize"
+            [nzPageIndex]="query.params.pageNumber" [nzLoading]="this.query.tableLoading"
+            (nzQueryParams)="onQueryParamsChange($event)" nzWidth="100%">
+            <thead>
+                <tr>
+                    <th [nzChecked]="query.checked" [nzIndeterminate]="query.indeterminate"
+                        (nzCheckedChange)="onTableAllChecked($event)"></th>
+
+                    <th nzAlign="center">{{ 'mxk.apps.icon' | i18n }}</th>
+                    <th nzAlign="center">{{ 'mxk.text.id' | i18n }}</th>
+                    <th nzAlign="center">{{ 'mxk.apps.name' | i18n }}</th>
+                    <th nzAlign="center">{{ 'mxk.apps.protocol' | i18n }}</th>
+                    <th nzAlign="center">{{ 'mxk.apps.category' | i18n }}</th>
+                    <th nzAlign="center">{{ 'mxk.text.sortIndex' | i18n }}</th>
+                    <th nzAlign="center">{{ 'mxk.text.status' | i18n }}</th>
+                    <th nzAlign="center" class="table_cell_action_2">{{ 'mxk.text.action' | i18n }}</th>
+                </tr>
+            </thead>
+            <tbody>
+                <tr *ngFor="let data of query.results.rows">
+                    <td [nzChecked]="query.tableCheckedId.has(data.id)" [nzDisabled]="data.disabled"
+                        (nzCheckedChange)="onTableItemChecked(data.id, $event)"></td>
+
+                    <td nzAlign="center"><img height="30" border="0px" src="{{ data.iconBase64 }}" /></td>
+                    <td nzAlign="left"> {{ data.id }} </td>
+                    <td nzAlign="left"> {{ data.appName }}</td>
+                    <td nzAlign="left"> {{ data.protocol }}</td>
+                    <td nzAlign="left">
+                        <div *ngIf="data.category == 'none'">{{ 'mxk.apps.category.none' | i18n }}</div>
+                        <div *ngIf="data.category == '1011'">{{ 'mxk.apps.category.1011' | i18n }}</div>
+                        <div *ngIf="data.category == '1012'">{{ 'mxk.apps.category.1012' | i18n }}</div>
+                        <div *ngIf="data.category == '1013'">{{ 'mxk.apps.category.1013' | i18n }}</div>
+                        <div *ngIf="data.category == '1014'">{{ 'mxk.apps.category.1014' | i18n }}</div>
+                        <div *ngIf="data.category == '1015'">{{ 'mxk.apps.category.1015' | i18n }}</div>
+                        <div *ngIf="data.category == '1016'">{{ 'mxk.apps.category.1016' | i18n }}</div>
+                        <div *ngIf="data.category == '1017'">{{ 'mxk.apps.category.1017' | i18n }}</div>
+                        <div *ngIf="data.category == '1111'">{{ 'mxk.apps.category.1111' | i18n }}</div>
+                        <div *ngIf="data.category == '1112'">{{ 'mxk.apps.category.1112' | i18n }}</div>
+                        <div *ngIf="data.category == '1113'">{{ 'mxk.apps.category.1113' | i18n }}</div>
+                        <div *ngIf="data.category == '1114'">{{ 'mxk.apps.category.1114' | i18n }}</div>
+                        <div *ngIf="data.category == '1211'">{{ 'mxk.apps.category.1211' | i18n }}</div>
+                        <div *ngIf="data.category == '1212'">{{ 'mxk.apps.category.1212' | i18n }}</div>
+                        <div *ngIf="data.category == '1213'">{{ 'mxk.apps.category.1213' | i18n }}</div>
+                        <div *ngIf="data.category == '1214'">{{ 'mxk.apps.category.1214' | i18n }}</div>
+                        <div *ngIf="data.category == '1215'">{{ 'mxk.apps.category.1215' | i18n }}</div>
+                        <div *ngIf="data.category == '1311'">{{ 'mxk.apps.category.1311' | i18n }}</div>
+                        <div *ngIf="data.category == '1411'">{{ 'mxk.apps.category.1411' | i18n }}</div>
+                        <div *ngIf="data.category == '1511'">{{ 'mxk.apps.category.1511' | i18n }}</div>
+                        <div *ngIf="data.category == '1512'">{{ 'mxk.apps.category.1512' | i18n }}</div>
+                        <div *ngIf="data.category == '1611'">{{ 'mxk.apps.category.1611' | i18n }}</div>
+                        <div *ngIf="data.category == '1711'">{{ 'mxk.apps.category.1711' | i18n }}</div>
+                        <div *ngIf="data.category == '1712'">{{ 'mxk.apps.category.1712' | i18n }}</div>
+                        <div *ngIf="data.category == '1811'">{{ 'mxk.apps.category.1811' | i18n }}</div>
+                        <div *ngIf="data.category == '1812'">{{ 'mxk.apps.category.1812' | i18n }}</div>
+                        <div *ngIf="data.category == '1911'">{{ 'mxk.apps.category.1911' | i18n }}</div>
+                        <div *ngIf="data.category == '1912'">{{ 'mxk.apps.category.1912' | i18n }}</div>
+                    </td>
+                    <td nzAlign="left"> {{ data.sortIndex }}</td>
+                    <td nzAlign="center"> <i *ngIf="data.status == 1" nz-icon nzType="check-circle" nzTheme="fill"
+                            style="color: green"></i></td>
+                    <td nzAlign="center" nzBreakWord="false">
+                        <button nz-button type="button" (click)="onEditPermission($event, data.id, data.appName)">{{
+                            'mxk.apps.permission' | i18n
+                            }}</button>
+                        <button nz-button type="button" (click)="onEditResource($event, data.id, data.appName)">{{
+                            'mxk.apps.resources' | i18n
+                            }}</button>
+                    </td>
+                </tr>
+            </tbody>
+        </nz-table>
+    </div>
+</nz-card>

+ 0 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/permissions/apps/apps.component.less


+ 25 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/permissions/apps/apps.component.spec.ts

@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AppsComponent } from './apps.component';
+
+describe('AppsComponent', () => {
+  let component: AppsComponent;
+  let fixture: ComponentFixture<AppsComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [ AppsComponent ]
+    })
+    .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(AppsComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 164 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/permissions/apps/apps.component.ts

@@ -0,0 +1,164 @@
+/*
+ * Copyright [2022] [MaxKey of copyright http://www.maxkey.top]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ChangeDetectionStrategy, ViewContainerRef, ChangeDetectorRef, Component, OnInit, Inject } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { Router } from '@angular/router';
+import { I18NService } from '@core';
+import { _HttpClient, ALAIN_I18N_TOKEN, SettingsService } from '@delon/theme';
+import { format, addDays } from 'date-fns';
+import { NzSafeAny } from 'ng-zorro-antd/core/types';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import { NzModalRef, NzModalService } from 'ng-zorro-antd/modal';
+import { NzTableQueryParams } from 'ng-zorro-antd/table';
+
+import { AppsService } from '../../../service/apps.service';
+import { set2String } from '../../../shared/index';
+
+@Component({
+  selector: 'app-apps',
+  templateUrl: './apps.component.html',
+  styleUrls: ['./apps.component.less']
+})
+export class AppsComponent implements OnInit {
+  query: {
+    params: {
+      appName: String;
+      displayName: String;
+      protocol: String;
+      startDate: String;
+      endDate: String;
+      startDatePicker: Date;
+      endDatePicker: Date;
+      pageSize: number;
+      pageNumber: number;
+      pageSizeOptions: number[];
+    };
+    results: {
+      records: number;
+      rows: NzSafeAny[];
+    };
+    expandForm: Boolean;
+    submitLoading: boolean;
+    tableLoading: boolean;
+    tableCheckedId: Set<String>;
+    indeterminate: boolean;
+    checked: boolean;
+  } = {
+      params: {
+        appName: '',
+        displayName: '',
+        protocol: '',
+        startDate: '',
+        endDate: '',
+        startDatePicker: addDays(new Date(), -30),
+        endDatePicker: new Date(),
+        pageSize: 10,
+        pageNumber: 1,
+        pageSizeOptions: [10, 20, 50]
+      },
+      results: {
+        records: 0,
+        rows: []
+      },
+      expandForm: false,
+      submitLoading: false,
+      tableLoading: false,
+      tableCheckedId: new Set<String>(),
+      indeterminate: false,
+      checked: false
+    };
+
+  constructor(
+    private modalService: NzModalService,
+    private viewContainerRef: ViewContainerRef,
+    private appsService: AppsService,
+    private fb: FormBuilder,
+    private msg: NzMessageService,
+    @Inject(ALAIN_I18N_TOKEN) private i18n: I18NService,
+    private router: Router,
+    private cdr: ChangeDetectorRef
+  ) { }
+
+  ngOnInit(): void {
+    this.fetch();
+  }
+
+  onQueryParamsChange(tableQueryParams: NzTableQueryParams): void {
+    this.query.params.pageNumber = tableQueryParams.pageIndex;
+    this.query.params.pageSize = tableQueryParams.pageSize;
+    this.fetch();
+  }
+
+  onSearch(): void {
+    this.fetch();
+  }
+
+  onReset(): void { }
+
+  onEditPermission(e: MouseEvent, appId: String, appName: String): void {
+    this.router.navigateByUrl(`/permissions/privileges?appId=${appId}&appName=${appName}`);
+  }
+
+  onEditResource(e: MouseEvent, appId: String, appName: String): void {
+    this.router.navigateByUrl(`/permissions/resources?appId=${appId}&appName=${appName}`);
+  }
+
+  fetch(): void {
+    this.query.submitLoading = true;
+    this.query.tableLoading = true;
+    this.query.indeterminate = false;
+    this.query.checked = false;
+    this.query.tableCheckedId.clear();
+    if (this.query.expandForm) {
+      this.query.params.endDate = format(this.query.params.endDatePicker, 'yyyy-MM-dd HH:mm:ss');
+      this.query.params.startDate = format(this.query.params.startDatePicker, 'yyyy-MM-dd HH:mm:ss');
+    } else {
+      this.query.params.endDate = '';
+      this.query.params.startDate = '';
+    }
+    this.appsService.fetch(this.query.params).subscribe(res => {
+      this.query.results = res.data;
+      this.query.submitLoading = false;
+      this.query.tableLoading = false;
+      this.cdr.detectChanges();
+    });
+  }
+
+  updateTableCheckedSet(id: String, checked: boolean): void {
+    if (checked) {
+      this.query.tableCheckedId.add(id);
+    } else {
+      this.query.tableCheckedId.delete(id);
+    }
+  }
+
+  refreshTableCheckedStatus(): void {
+    const listOfEnabledData = this.query.results.rows.filter(({ disabled }) => !disabled);
+    this.query.checked = listOfEnabledData.every(({ id }) => this.query.tableCheckedId.has(id));
+    this.query.indeterminate = listOfEnabledData.some(({ id }) => this.query.tableCheckedId.has(id)) && !this.query.checked;
+  }
+
+  onTableItemChecked(id: String, checked: boolean): void {
+    this.updateTableCheckedSet(id, checked);
+    this.refreshTableCheckedStatus();
+  }
+
+  onTableAllChecked(checked: boolean): void {
+    this.query.results.rows.filter(({ disabled }) => !disabled).forEach(({ id }) => this.updateTableCheckedSet(id, checked));
+    this.refreshTableCheckedStatus();
+  }
+}

+ 7 - 2
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/permissions/permissions.module.ts

@@ -20,11 +20,16 @@ import { RouterModule, Routes } from '@angular/router';
 import { SharedModule } from '@shared';
 import { NzIconModule } from 'ng-zorro-antd/icon';
 
+import { AppsComponent } from './apps/apps.component';
 import { PrivilegesComponent } from './privileges/privileges.component';
 import { ResourceEditerComponent } from './resources/resource-editer/resource-editer.component';
 import { ResourcesComponent } from './resources/resources.component';
 const routes: Routes = [
   {
+    path: 'apps',
+    component: AppsComponent
+  },
+  {
     path: 'resources',
     component: ResourcesComponent
   },
@@ -37,8 +42,8 @@ const routes: Routes = [
 const COMPONENTS = [ResourcesComponent, PrivilegesComponent, ResourceEditerComponent];
 
 @NgModule({
-  declarations: [...COMPONENTS],
+  declarations: [...COMPONENTS, AppsComponent],
   imports: [NzIconModule, SharedModule, CommonModule, RouterModule.forChild(routes)],
   exports: [RouterModule]
 })
-export class PermissionsModule {}
+export class PermissionsModule { }

+ 21 - 61
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/permissions/privileges/privileges.component.html

@@ -5,46 +5,26 @@
     <div nz-row [nzGutter]="{ xs: 8, sm: 8, md: 8, lg: 24, xl: 48, xxl: 48 }">
       <div nz-col nzMd="10" nzSm="24">
         <nz-form-item>
-          <nz-form-label nzFor="groupName">{{ 'mxk.roles.name' | i18n }}</nz-form-label>
-          <nz-form-control>
-            <input
-              nz-input
-              [(ngModel)]="query.params.groupName"
-              [ngModelOptions]="{ standalone: true }"
-              name="groupName"
-              placeholder=""
-              id="groupName"
-            />
-          </nz-form-control>
+          <nz-form-label nzFor="name">{{ 'mxk.resources.appName' | i18n }}</nz-form-label>
+          <input nz-input [(ngModel)]="query.params.appName" [ngModelOptions]="{ standalone: true }" disabled />
         </nz-form-item>
       </div>
       <div nz-col nzMd="10" nzSm="24">
         <nz-form-item>
-          <nz-form-label nzFor="name">{{ 'mxk.resources.appName' | i18n }}</nz-form-label>
+          <nz-form-label nzFor="groupName">{{ 'mxk.roles.name' | i18n }}</nz-form-label>
           <nz-form-control>
-            <nz-input-group nzSearch [nzAddOnAfter]="suffixButton">
-              <input
-                nz-input
-                [(ngModel)]="query.params.appName"
-                [ngModelOptions]="{ standalone: true }"
-                name="appName"
-                readonly
-                placeholder=""
-                id="appName"
-              />
-            </nz-input-group>
-            <ng-template #suffixButton>
-              <button nz-button nzType="primary" (click)="onSelect($event)" nzSearch>{{ 'mxk.text.select' | i18n }}</button>
-            </ng-template>
+            <input nz-input [(ngModel)]="query.params.groupName" [ngModelOptions]="{ standalone: true }"
+              name="groupName" placeholder="" id="groupName" />
           </nz-form-control>
         </nz-form-item>
       </div>
       <div nz-col [nzSpan]="query.expandForm ? 24 : 4" [class.text-right]="query.expandForm">
-        <button nz-button type="submit" [nzType]="'primary'" [nzLoading]="query.submitLoading">{{ 'mxk.text.query' | i18n }}</button>
-        <button nz-button type="reset" (click)="onReset()" class="mx-sm" style="display: none">{{ 'mxk.text.reset' | i18n }}</button>
+        <button nz-button type="submit" [nzType]="'primary'" [nzLoading]="query.submitLoading">{{ 'mxk.text.query' |
+          i18n }}</button>
+        <button nz-button type="reset" (click)="onReset()" class="mx-sm" style="display: none">{{ 'mxk.text.reset' |
+          i18n }}</button>
         <button nz-button (click)="query.expandForm = !query.expandForm" class="mx-sm" style="display: none">
-          {{ query.expandForm ? ('mxk.text.collapse' | i18n) : ('mxk.text.expand' | i18n) }}</button
-        >
+          {{ query.expandForm ? ('mxk.text.collapse' | i18n) : ('mxk.text.expand' | i18n) }}</button>
       </div>
     </div>
   </form>
@@ -55,21 +35,11 @@
   </div>
   <div nz-row [nzGutter]="{ xs: 8, sm: 8, md: 8, lg: 24, xl: 48, xxl: 48 }">
     <div nz-col [nzSpan]="10" class="grid-border">
-      <nz-table
-        #dynamicTable
-        nzTableLayout="auto"
-        nzSize="small"
-        nzBordered
-        nzShowSizeChanger
-        [nzData]="query.results.rows"
-        [nzFrontPagination]="false"
-        [nzTotal]="query.results.records"
-        [nzPageSizeOptions]="query.params.pageSizeOptions"
-        [nzPageSize]="query.params.pageSize"
-        [nzPageIndex]="query.params.pageNumber"
-        [nzLoading]="this.query.tableLoading"
-        (nzQueryParams)="onQueryParamsChange($event)"
-      >
+      <nz-table #dynamicTable nzTableLayout="auto" nzSize="small" nzBordered nzShowSizeChanger
+        [nzData]="query.results.rows" [nzFrontPagination]="false" [nzTotal]="query.results.records"
+        [nzPageSizeOptions]="query.params.pageSizeOptions" [nzPageSize]="query.params.pageSize"
+        [nzPageIndex]="query.params.pageNumber" [nzLoading]="this.query.tableLoading"
+        (nzQueryParams)="onQueryParamsChange($event)">
         <thead>
           <tr>
             <!--<th [nzChecked]="query.checked" [nzIndeterminate]="query.indeterminate" (nzCheckedChange)="onTableAllChecked($event)"></th>
@@ -82,11 +52,8 @@
         </thead>
         <tbody>
           <tr *ngFor="let data of query.results.rows">
-            <td
-              [nzChecked]="query.tableCheckedId.has(data.id)"
-              [nzDisabled]="data.disabled"
-              (nzCheckedChange)="onTableItemChecked(data.id, $event)"
-            ></td>
+            <td [nzChecked]="query.tableCheckedId.has(data.id)" [nzDisabled]="data.disabled"
+              (nzCheckedChange)="onTableItemChecked(data.id, $event)"></td>
             <td nzAlign="left" style="display: none">
               <span>{{ data.id }}</span>
             </td>
@@ -98,16 +65,9 @@
       </nz-table>
     </div>
     <div nz-col [nzSpan]="14" class="grid-border">
-      <nz-tree
-        #nzTreeComponent
-        nzShowLine="false"
-        [nzCheckable]="treeNodes.checkable"
-        [nzCheckedKeys]="treeNodes.checkedKeys"
-        nzBlockNode
-        [nzData]="treeNodes.nodes"
-        (nzDblClick)="openFolder($event)"
-        [nzTreeTemplate]="nzTreeTemplate"
-      ></nz-tree>
+      <nz-tree #nzTreeComponent nzShowLine="false" [nzCheckable]="treeNodes.checkable"
+        [nzCheckedKeys]="treeNodes.checkedKeys" nzBlockNode [nzData]="treeNodes.nodes" (nzDblClick)="openFolder($event)"
+        [nzTreeTemplate]="nzTreeTemplate"></nz-tree>
       <ng-template #nzTreeTemplate let-node let-origin="origin">
         <span class="custom-node">
           <span *ngIf="!node.isLeaf">
@@ -122,4 +82,4 @@
       </ng-template>
     </div>
   </div>
-</nz-card>
+</nz-card>

+ 9 - 1
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/permissions/privileges/privileges.component.ts

@@ -25,6 +25,7 @@ import {
   Inject
 } from '@angular/core';
 import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
 import { I18NService } from '@core';
 import { _HttpClient, ALAIN_I18N_TOKEN, SettingsService } from '@delon/theme';
 import { format, addDays } from 'date-fns';
@@ -36,8 +37,8 @@ import { NzTableQueryParams } from 'ng-zorro-antd/table';
 import { NzFormatEmitEvent, NzTreeNode, NzTreeNodeOptions, NzTreeComponent } from 'ng-zorro-antd/tree';
 
 import { TreeNodes } from '../../../entity/TreeNodes';
-import { GroupsService } from '../../../service/groups.service';
 import { GroupPrivilegesService } from '../../../service/group-privileges.service';
+import { GroupsService } from '../../../service/groups.service';
 import { ResourcesService } from '../../../service/resources.service';
 import { set2String } from '../../../shared/index';
 import { SelectAppsComponent } from '../../apps/select-apps/select-apps.component';
@@ -109,6 +110,7 @@ export class PrivilegesComponent implements OnInit {
     private resourcesService: ResourcesService,
     private groupsService: GroupsService,
     private viewContainerRef: ViewContainerRef,
+    private route: ActivatedRoute,
     private fb: FormBuilder,
     private msg: NzMessageService,
     @Inject(ALAIN_I18N_TOKEN) private i18n: I18NService,
@@ -117,6 +119,12 @@ export class PrivilegesComponent implements OnInit {
   ) { }
 
   ngOnInit(): void {
+    if (this.route.snapshot.queryParams['appId']) {
+      this.query.params.appId = this.route.snapshot.queryParams['appId'];
+      this.query.params.appName = this.route.snapshot.queryParams['appName'];
+      this.fetch();
+      this.tree();
+    }
     this.fetch();
   }
 

+ 37 - 45
maxkey-web-frontend/maxkey-web-mgt-app/src/app/routes/permissions/resources/resources.component.html

@@ -6,16 +6,8 @@
       <div nz-col nzMd="10" nzSm="24">
         <nz-form-item>
           <nz-form-label nzFor="name">{{ 'mxk.resources.appName' | i18n }}</nz-form-label>
-          <nz-form-control>
-            <nz-input-group nzSearch [nzAddOnAfter]="suffixButton">
-              <input nz-input [(ngModel)]="query.params.appName" [ngModelOptions]="{ standalone: true }" name="appName"
-                     readonly placeholder="" id="appName" />
-            </nz-input-group>
-            <ng-template #suffixButton>
-              <button nz-button nzType="primary" (click)="onSelect($event)" nzSearch>{{ 'mxk.text.select' | i18n
-                }}</button>
-            </ng-template>
-          </nz-form-control>
+          <input nz-input [(ngModel)]="query.params.appName" [ngModelOptions]="{ standalone: true }" disabled
+            placeholder="" />
         </nz-form-item>
       </div>
       <div nz-col nzMd="10" nzSm="24">
@@ -23,7 +15,7 @@
           <nz-form-label nzFor="resourceName">{{ 'mxk.resources.name' | i18n }}</nz-form-label>
           <nz-form-control>
             <input nz-input [(ngModel)]="query.params.resourceName" [ngModelOptions]="{ standalone: true }"
-                   name="resourceName" placeholder="" id="resourceName" />
+              name="resourceName" placeholder="" id="resourceName" />
           </nz-form-control>
         </nz-form-item>
       </div>
@@ -48,7 +40,7 @@
     </div>
     <div nz-col nzMd="6" nzSm="24" class="grid-border">
       <nz-tree nzShowLine="false" [nzCheckable]="treeNodes.checkable" nzBlockNode [nzData]="treeNodes.nodes"
-               (nzClick)="activeNode($event)" (nzDblClick)="openFolder($event)" [nzTreeTemplate]="nzTreeTemplate"></nz-tree>
+        (nzClick)="activeNode($event)" (nzDblClick)="openFolder($event)" [nzTreeTemplate]="nzTreeTemplate"></nz-tree>
       <ng-template #nzTreeTemplate let-node let-origin="origin">
         <span class="custom-node">
           <span *ngIf="!node.isLeaf" (contextmenu)="contextMenu($event, menu)">
@@ -69,45 +61,45 @@
       </nz-dropdown-menu>
     </div>
     <div nz-col nzMd="18" nzSm="24" class="grid-border">
-      <nz-table #dynamicTable nzTableLayout="auto" nzSize="small" nzBordered nzShowSizeChanger [nzData]="query.results.rows"
-                [nzFrontPagination]="false" [nzTotal]="query.results.records" [nzPageSizeOptions]="query.params.pageSizeOptions"
-                [nzPageSize]="query.params.pageSize" [nzPageIndex]="query.params.pageNumber"
-                [nzLoading]="this.query.tableLoading" (nzQueryParams)="onQueryParamsChange($event)" nzWidth="100%">
+      <nz-table #dynamicTable nzTableLayout="auto" nzSize="small" nzBordered nzShowSizeChanger
+        [nzData]="query.results.rows" [nzFrontPagination]="false" [nzTotal]="query.results.records"
+        [nzPageSizeOptions]="query.params.pageSizeOptions" [nzPageSize]="query.params.pageSize"
+        [nzPageIndex]="query.params.pageNumber" [nzLoading]="this.query.tableLoading"
+        (nzQueryParams)="onQueryParamsChange($event)" nzWidth="100%">
         <thead>
-        <tr>
-          <th [nzChecked]="query.checked" [nzIndeterminate]="query.indeterminate"
+          <tr>
+            <th [nzChecked]="query.checked" [nzIndeterminate]="query.indeterminate"
               (nzCheckedChange)="onTableAllChecked($event)"></th>
-          <th nzAlign="center">{{ 'mxk.resources.appName' | i18n }}</th>
-          <th nzAlign="center">{{ 'mxk.resources.name' | i18n }}</th>
-          <th nzAlign="center">{{ 'mxk.resources.resourceType' | i18n }}</th>
-          <th nzAlign="center">{{ 'mxk.text.sortIndex' | i18n }}</th>
-          <th nzAlign="center">{{ 'mxk.text.status' | i18n }}</th>
-          <th nzAlign="center" class="table_cell_action_2">{{ 'mxk.text.action' | i18n }}</th>
-        </tr>
+            <th nzAlign="center">{{ 'mxk.resources.appName' | i18n }}</th>
+            <th nzAlign="center">{{ 'mxk.resources.name' | i18n }}</th>
+            <th nzAlign="center">{{ 'mxk.resources.resourceType' | i18n }}</th>
+            <th nzAlign="center">{{ 'mxk.text.sortIndex' | i18n }}</th>
+            <th nzAlign="center">{{ 'mxk.text.status' | i18n }}</th>
+            <th nzAlign="center" class="table_cell_action_2">{{ 'mxk.text.action' | i18n }}</th>
+          </tr>
         </thead>
         <tbody>
-        <tr *ngFor="let data of query.results.rows">
-          <td [nzChecked]="query.tableCheckedId.has(data.id)" [nzDisabled]="data.disabled"
+          <tr *ngFor="let data of query.results.rows">
+            <td [nzChecked]="query.tableCheckedId.has(data.id)" [nzDisabled]="data.disabled"
               (nzCheckedChange)="onTableItemChecked(data.id, $event)"></td>
-          <td nzAlign="center">
-            {{ data.appName }}
-          </td>
-          <td nzAlign="left"> {{ data.resourceName }}</td>
-          <td nzAlign="left"> {{ data.resourceType }}</td>
-          <td nzAlign="center"> {{ data.sortIndex }}</td>
-          <td nzAlign="center"> <i *ngIf="data.status == 1" nz-icon nzType="check-circle" nzTheme="fill"
-                                   style="color: green"></i></td>
-          <td nzAlign="center" nzBreakWord="false">
-            <div nz-col>
-              <button nz-button type="button" (click)="onEdit($event, data.id)">{{ 'mxk.text.edit'
-                | i18n }}</button>
-              <button nz-button type="button" (click)="onDelete($event, data.id)" nzDanger>{{ 'mxk.text.delete' | i18n
-                }}</button>
-            </div>
-          </td>
-        </tr>
+            <td nzAlign="center">
+              {{ data.appName }}
+            </td>
+            <td nzAlign="left"> {{ data.resourceName }}</td>
+            <td nzAlign="left"> {{ data.resourceType }}</td>
+            <td nzAlign="center"> {{ data.sortIndex }}</td>
+            <td nzAlign="center"> <i *ngIf="data.status == 1" nz-icon nzType="check-circle" nzTheme="fill"
+                style="color: green"></i></td>
+            <td nzAlign="center" nzBreakWord="false">
+              <div nz-col>
+                <button nz-button type="button" (click)="onEdit($event, data.id)">{{ 'mxk.text.edit' | i18n }}</button>
+                <button nz-button type="button" (click)="onDelete($event, data.id)" nzDanger>{{ 'mxk.text.delete' | i18n
+                  }}</button>
+              </div>
+            </td>
+          </tr>
         </tbody>
       </nz-table>
     </div>
   </div>
-</nz-card>
+</nz-card>

+ 14 - 29
maxkey-web-frontend/maxkey-web-mgt-app/src/app/theme/layout-default/layout-nav.component.html

@@ -1,16 +1,7 @@
 <ng-template #icon let-i>
   <ng-container *ngIf="i" [ngSwitch]="i.type">
-    <i
-      *ngSwitchCase="'icon'"
-      class="sidebar-nav__item-icon"
-      nz-icon
-      [nzType]="i.value"
-      [nzTheme]="i.theme"
-      [nzSpin]="i.spin"
-      [nzTwotoneColor]="i.twoToneColor"
-      [nzIconfont]="i.iconfont"
-      [nzRotate]="i.rotate"
-    ></i>
+    <i *ngSwitchCase="'icon'" class="sidebar-nav__item-icon" nz-icon [nzType]="i.value" [nzTheme]="i.theme"
+      [nzSpin]="i.spin" [nzTwotoneColor]="i.twoToneColor" [nzIconfont]="i.iconfont" [nzRotate]="i.rotate"></i>
     <i *ngSwitchCase="'iconfont'" class="sidebar-nav__item-icon" nz-icon [nzIconfont]="i.iconfont"></i>
     <img *ngSwitchCase="'img'" [src]="i.value" class="sidebar-nav__item-icon sidebar-nav__item-img" />
     <span *ngSwitchCase="'svg'" class="sidebar-nav__item-icon sidebar-nav__item-svg" [innerHTML]="i.value"></span>
@@ -19,21 +10,12 @@
 </ng-template>
 <ng-template #tree let-ls>
   <ng-container *ngFor="let i of ls">
-    <li
-      *ngIf="i._hidden !== true"
-      class="sidebar-nav__item"
-      [class.sidebar-nav__selected]="i._selected"
-      [class.sidebar-nav__open]="i._open"
-    >
+    <li class="sidebar-nav__item" [class.sidebar-nav__selected]="i._selected" [class.sidebar-nav__open]="i._open"
+      style="display: {{ i._hidden ? 'none;' : 'block' }}">
       <!-- link -->
-      <a
-        *ngIf="i.children.length === 0"
-        (click)="to(i)"
-        [attr.data-id]="i._id"
-        class="sidebar-nav__item-link"
-        [ngClass]="{ 'sidebar-nav__item-disabled': i.disabled }"
-        (mouseenter)="closeSubMenu()"
-      >
+      <a *ngIf="i.children.length === 0 || i.link !== ''" (click)="to(i)" [attr.data-id]="i._id"
+        class="sidebar-nav__item-link" [ngClass]="{ 'sidebar-nav__item-disabled': i.disabled }"
+        (mouseenter)="closeSubMenu()">
         <ng-container *ngIf="i._needIcon">
           <ng-container *ngIf="!collapsed">
             <ng-template [ngTemplateOutlet]="icon" [ngTemplateOutletContext]="{ $implicit: i.icon }"></ng-template>
@@ -45,7 +27,8 @@
         <span class="sidebar-nav__item-text" [innerHTML]="i._text" [attr.title]="i.text"></span>
       </a>
       <!-- has children link -->
-      <a *ngIf="i.children.length > 0" (click)="toggleOpen(i)" (mouseenter)="showSubMenu($event, i)" class="sidebar-nav__item-link">
+      <a *ngIf="i.children.length > 0 && i.link === ''" (click)="toggleOpen(i)" (mouseenter)="showSubMenu($event, i)"
+        class="sidebar-nav__item-link">
         <ng-template [ngTemplateOutlet]="icon" [ngTemplateOutletContext]="{ $implicit: i.icon }"></ng-template>
         <span class="sidebar-nav__item-text" [innerHTML]="i._text" [attr.title]="i.text"></span>
         <i class="sidebar-nav__sub-arrow"></i>
@@ -60,12 +43,14 @@
 </ng-template>
 <ul class="sidebar-nav">
   <ng-container *ngFor="let group of list">
-    <li class="sidebar-nav__item sidebar-nav__group-title" *ngIf="group.group"> <span [innerHTML]="group._text"></span> </li>
+    <li class="sidebar-nav__item sidebar-nav__group-title" *ngIf="group.group"> <span [innerHTML]="group._text"></span>
+    </li>
     <ng-template [ngTemplateOutlet]="tree" [ngTemplateOutletContext]="{ $implicit: group.children }"></ng-template>
   </ng-container>
   <li>
-    <div class="alain-default__nav-item alain-default__nav-item--collapse alain-default__nav-item_collapsed" (click)="toggleCollapsed()">
+    <div class="alain-default__nav-item alain-default__nav-item--collapse alain-default__nav-item_collapsed"
+      (click)="toggleCollapsed()">
       <i nz-icon [nzType]="collapsedIcon"></i>
     </div>
   </li>
-</ul>
+</ul>

+ 22 - 16
maxkey-web-frontend/maxkey-web-mgt-app/src/assets/app-data.json

@@ -20,7 +20,6 @@
         {
           "text": "身份管理",
           "i18n": "mxk.menu.identities",
-          "link": "/organizations",
           "icon": "anticon-user",
           "children": [
             {
@@ -64,7 +63,6 @@
         {
           "text": "访问控制",
           "i18n": "mxk.menu.access",
-          "link": "/access",
           "icon": "anticon-safety",
           "children": [
             {
@@ -86,29 +84,38 @@
         {
           "text": "权限管理",
           "i18n": "mxk.menu.permissions",
-          "link": "/permissions",
           "icon": "anticon-radar-chart",
           "children": [
             {
-              "text": "资源管理",
-              "i18n": "mxk.menu.permissions.resources",
-              "link": "/permissions/resources",
+              "text": "应用列表",
+              "i18n": "mxk.menu.permissions",
+              "link": "/permissions/apps",
               "icon": "anticon-read",
-              "children": []
-            },
-            {
-              "text": "权限管理",
-              "i18n": "mxk.menu.permissions.privileges",
-              "link": "/permissions/privileges",
-              "icon": "anticon-carry-out",
-              "children": []
+              "children": [
+                {
+                  "text": "资源管理",
+                  "i18n": "mxk.menu.permissions.resources",
+                  "link": "/permissions/resources",
+                  "icon": "anticon-read",
+                  "hide":true,
+                  "children": []
+                },
+                {
+                  "text": "权限管理",
+                  "i18n": "mxk.menu.permissions.privileges",
+                  "link": "/permissions/privileges",
+                  "icon": "anticon-carry-out",
+                  "hide":true,
+                  "children": []
+                }
+              ]
             }
+            
           ]
         },
         {
           "text": "配置管理",
           "i18n": "mxk.menu.config",
-          "link": "/config",
           "icon": "anticon-setting",
           "children": [
             {
@@ -179,7 +186,6 @@
         {
           "text": "日志审计",
           "i18n": "mxk.menu.audit",
-          "link": "/audit",
           "icon": "anticon-history",
           "children": [
             {

+ 1 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/en-US.json

@@ -274,6 +274,7 @@
 			"tab.custom": "Custom",
 			"extendapi.tab": "API",
 			"resources":"Resources",
+			"permission":"Permission",
 			"id": "App Id",
 			"name": "App Name",
 			"icon": "Icon",

+ 1 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/zh-CN.json

@@ -275,6 +275,7 @@
 			"tab.custom": "自定义属性",
 			"extendapi.tab": "API配置",
 			"resources":"资源",
+			"permission":"权限",
 			"id": "应用编码",
 			"name": "应用名称",
 			"icon": "图标",

+ 1 - 0
maxkey-web-frontend/maxkey-web-mgt-app/src/assets/i18n/zh-TW.json

@@ -276,6 +276,7 @@
 			"tab.custom": "自訂屬性",
 			"extendapi.tab": "API配置",
 			"resources":"資源",
+			"permission":"權限",
 			"id": "應用編碼",
 			"name": "應用名稱",
 			"icon": "圖標",