Browse Source

组织管理

warrior 9 months ago
parent
commit
1c1859a5e2

+ 4 - 2
projects/textbook/src/app/comp-table/comp-table-list/comp-table-list.component.html

@@ -10,6 +10,8 @@
 
 <!-- 数据表格:渲染当前页 -->
 <nz-table #editRowTable [nzData]="list" *ngIf="showMode=='list'&&list?.length"
+  [nzWidthConfig]="schema?.nzWidthConfig || []"
+  nzTableLayout="fixed"
   [nzLoading]="isLoading" nzFrontPagination="false">
     <thead>
       <tr>
@@ -22,7 +24,7 @@
             (nzCurrentPageDataChange)="onCurrentPageDataChange($event)"
           ></th>
         <ng-container *ngFor="let field of headerArray">
-            <th >{{field?.name}}</th>
+            <th nzWidth="auto">{{field?.name}}</th>
         </ng-container>
             <th >时间</th>
             <th >操作</th>
@@ -40,7 +42,7 @@
         ></td>
           <ng-container *ngFor="let field of headerArray">
             <!-- 单行数据每个字段渲染 -->
-            <td > 
+            <td nzEllipsis> 
               <ng-contianer [ngSwitch]="field?.type">
                 <ng-container *ngSwitchCase="'Pointer'">
                   {{ pointerShowMap?.[(object?.get(field.key)?.objectId||object?.get(field.key)?.id)+field?.showName] || "-" }}

+ 2 - 2
projects/textbook/src/index.html

@@ -22,8 +22,8 @@
   }
   *::-webkit-scrollbar-thumb { 
     border-radius: 10px;
-    -webkit-box-shadow: inset 0 0 5px #b62749;
-    background: #b62749;
+    -webkit-box-shadow: inset 0 0 5px #f4cbcd;
+    background: #f4cbcd;
     /* -webkit-box-shadow: inset 0 0 5px #e6e6e6;
     background: #e6e6e6; */
   }

+ 2 - 2
projects/textbook/src/modules/nav-admin/page-role/page-role.component.ts

@@ -165,10 +165,10 @@ export class PageRoleComponent implements OnInit {
       }
       console.log(this.nodes);
     } else {
-      if (node.origin.isParent) {
+      // if (node.origin.isParent) {
         this.currentDepart = node.origin;
         this.getProfile();
-      }
+      // }
     }
   }
   async getProfile() {

+ 220 - 16
projects/textbook/src/modules/nav-admin/page-user/page-user.component.html

@@ -3,39 +3,243 @@
     >用户列表
     <br />
     <div class="subtitle">
-      当前用户池的所有用户,在这里你可以对用户进行统一管理。
+      使用“十四五”高等教育国家规划教材申报系统的所有用户,在这里你可以对用户账号进行统一管理。
     </div>
   </nz-page-header-title>
   <nz-page-header-extra>
     <nz-space>
-      <!-- <button
+      <button
         style="background: #3e49b3; border: 1px #3e49b3"
         *nzSpaceItem
         nz-button
         nzType="primary"
         (click)="createUser()"
       >
-      创建用户
-      </button> -->
+        创建用户
+      </button>
     </nz-space>
   </nz-page-header-extra>
 </nz-page-header>
-  
-
-<!-- <comp-table-list
+<div class="content">
+  <!-- <comp-table-list
   #list
   [schema]="_User"
   *ngIf="className && fieldsArray"
   [className]="className"
   [fieldsArray]="fieldsArray"
   [queryParams]="queryParams"
-></comp-table-list> -->
+  ></comp-table-list> -->
+  <!-- <comp-table-list
+    #list
+    [schema]="ProfileList"
+    *ngIf="className && fieldsArray"
+    [className]="className"
+    [fieldsArray]="fieldsArray"
+    [queryParams]="queryParams"
+  ></comp-table-list> -->
+  <div class="tool">
+    <div class="tool-left">
+      <div class="search">
+        <nz-input-group style="width: 210px" [nzPrefix]="prefixTemplateUser">
+          <input
+            type="text"
+            nz-input
+            placeholder="输入关键词"
+            [(ngModel)]="searchValue"
+            (ngModelChange)="getProfile()"
+          />
+        </nz-input-group>
+        <ng-template #prefixTemplateUser
+          ><span nz-icon nzType="search"></span
+        ></ng-template>
+      </div>
+      <div class=""></div>
+    </div>
+    <div class="tool-right">
+      <button
+        [ngClass]="{ 'form-button': setOfCheckedId.size }"
+        nz-button
+        [disabled]="!setOfCheckedId.size"
+        nzType="primary"
+        (click)="createUser()"
+      >
+        导出
+        <span nz-icon nzType="down" nzTheme="outline"></span>
+      </button>
+    </div>
+  </div>
+  <nz-table
+    #tableData
+    [nzData]="profiles"
+    [nzTotal]="profileLength"
+    [nzTotal]="profiles.length"
+    [nzPageSize]="pageSize"
+    [nzPageIndex]="pageIndex"
+    style="margin: 10px 0"
+    [nzLoading]="loading"
+    nzSize="middle"
+    [nzNoResult]="emptyResult"
+    nzTableLayout="fixed"
+  >
+    <thead>
+      <tr>
+        <th
+          nzWidth="50px"
+          nzLeft
+          [nzChecked]="checkedAll"
+          [nzIndeterminate]="indeterminate"
+          nzLabel="Select all"
+          (nzCheckedChange)="onAllChecked($event)"
+        ></th>
+        <th nzWidth="120px" nzLeft>用户</th>
+        <th nzWidth="120px">手机号</th>
+        <th nzWidth="120px">邮箱</th>
+        <th nzWidth="120px">人员类型</th>
+        <th nzWidth="80px">认证状态</th>
+        <th nzWidth="150px" nzEllipsis>单位类型</th>
+        <th nzWidth="50px" nzRight>操作</th>
+      </tr>
+    </thead>
+    <tbody>
+      @for (data of profiles; track data.objectId) {
+      <tr>
+        <td
+          nzLeft
+          [nzChecked]="data.checked"
+          (nzCheckedChange)="
+            onItemChecked(data.objectId, data.user.objectId, $event)
+          "
+        ></td>
+        <td nzLeft nzEllipsis>
+          <nz-avatar nzIcon="user"></nz-avatar>
+          {{ data?.user.name }}
+        </td>
+        <td>
+          {{ data?.user.phone }}
+        </td>
+        <td nzEllipsis>
+          <div class="email">
+            <span
+              class="state"
+              [style.background]="
+                data?.user.accountState == '已认证' ? '#1EB76D' : '#C9CDD4'
+              "
+            ></span>
+            <div class="text">{{ data?.user.email || data?.email }}</div>
+          </div>
+        </td>
+        <td>
+          {{ data?.identity }}
+        </td>
+        <td>
+          @switch (data?.user.accountState) { @case ('待认证') {
+          <nz-tag [nzBordered]="false" [nzColor]="'geekblue'">待认证</nz-tag>
+          } @case ('已认证') {
+          <nz-tag [nzBordered]="false" [nzColor]="'success'">已认证</nz-tag>
+          } @case ('已禁用') {
+          <nz-tag [nzBordered]="false" [nzColor]="'error'">已禁用</nz-tag>
+          } }
+        </td>
+        <td nzEllipsis>
+          {{ data?.companyType }}
+        </td>
+        <td nzRight>
+          <button
+            nz-button
+            nz-dropdown
+            [nzDropdownMenu]="menu"
+            [nzPlacement]="'bottomLeft'"
+          >
+            <span nz-icon nzType="ellipsis" nzTheme="outline"></span>
+          </button>
+          <nz-dropdown-menu #menu="nzDropdownMenu">
+            <ul nz-menu>
+              @if (data?.user.accountState == '待认证') {
+              <li nz-menu-item>
+                <button
+                  nz-button
+                  nzType="link"
+                  style="color: #231c1f"
+                  (click)="updateUser(data, '通过认证')"
+                >
+                  <span
+                    nz-icon
+                    nzType="safety-certificate"
+                    nzTheme="outline"
+                  ></span
+                  >通过认证
+                </button>
+              </li>
+              } @if (data?.user.accountState != '已禁用') {
+              <li nz-menu-item>
+                <button
+                  nz-button
+                  nzType="link"
+                  (click)="updateUser(data, '禁用')"
+                  style="color: #231c1f"
+                >
+                  <span nz-icon nzType="stop" nzTheme="outline"></span>禁用账号
+                </button>
+              </li>
+              }
+              <li nz-menu-item>
+                <button
+                  (click)="updateUser(data, '删除')"
+                  nz-button
+                  [disabled]="user?.get('isDeleted')"
+                  nzType="link"
+                  style="color: #231c1f"
+                >
+                  <span nz-icon nzType="delete" nzTheme="outline"></span
+                  >删除账号
+                </button>
+              </li>
+              <li nz-menu-item>
+                <button
+                  nz-button
+                  nzType="link"
+                  style="color: #231c1f"
+                  (click)="goDateil(data.user?.objectId)"
+                >
+                  <span
+                    nz-icon
+                    nzType="user"
+                    nzTheme="outline"
+                  ></span
+                  >用户详情
+                </button>
+              </li>
+            </ul>
+          </nz-dropdown-menu>
+        </td>
+      </tr>
+      }
+    </tbody>
+  </nz-table>
+  <ng-template #emptyResult>
+    <nz-empty nzNotFoundImage="/img/group-empty.png"></nz-empty>
+  </ng-template>
+</div>
 
-<comp-table-list
-  #list
-  [schema]="ProfileList"
-  *ngIf="className && fieldsArray"
-  [className]="className"
-  [fieldsArray]="fieldsArray"
-  [queryParams]="queryParams"
-></comp-table-list>
+<!-- 全选操作:批量操作 -->
+<div class="batch-toolbar-modal" *ngIf="setOfCheckedId?.size">
+  <div class="batch-toolbar">
+    <div class="styles_counter__18S08">
+      <span>已选</span>
+      <span class="styles_num__178Wa">{{ setOfCheckedId.size }}</span>
+    </div>
+    <div class="batch-toolbar-actions">
+      <div class="ant-space ant-space-horizontal ant-space-align-center">
+        <div class="ant-space-item" style="margin-right: 16px">
+          <button nz-button nzType="text" (click)="deleteSelected()">
+            <span nz-icon nzType="delete"></span>
+            删除
+          </button>
+        </div>
+      </div>
+    </div>
+    <div class="styles_cancel__AARoT">
+      <button nz-button nzType="text" (click)="onAllChecked(false)">取消选中</button>
+    </div>
+  </div>
+</div>

+ 111 - 3
projects/textbook/src/modules/nav-admin/page-user/page-user.component.scss

@@ -8,10 +8,118 @@
   // white-space: nowrap;
   // text-overflow: ellipsis;
 }
-.edit-content{
-  margin: 0 0 20px;
+.content{
+  // margin: 0 0 20px;
   padding: 0 24px;
-  height: calc(100vh - 250px);
+  // height: calc(100vh - 250px);
+  min-width: 1000px;
+  .email{
+    display: flex;
+    align-items: center;
+    width:calc(100% - 10px) ;
+    .text{
+      overflow: hidden;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+    }
+    .state{
+      flex-shrink: 0;
+      display: block;
+      width: 4px;
+      height: 4px;
+      border-radius:50%;
+      margin-right: 4px;
+    }
+  }
+  .tool{
+    display: flex;
+    justify-content: space-between;
+    .tool-left{
+      display: flex;
+      align-items: center;
+      .search{
+        display: flex;
+        width: 300px;
+        margin-right: 20px;
+      }
+      .tag{
+        background: #f7f7f7;
+        display: flex;
+        align-items: center;
+        color: #6f6f6f;
+        line-height: 26px;
+        padding: 0 8px;
+        margin: 0 10px;
+      }
+    }
+
+  }
+}
+.form-button {
+  background: #3e49b3; 
+  border: 1px #3e49b3;
+  color: white;
+}
+
+// 选中,批量操作区域
+.batch-toolbar-modal{
+  position: absolute;
+  display: flex;
+  justify-content: center;
+  bottom: 80px;
+  left: calc(50% - 134px);
+  -webkit-transform: translate(0);
+  transform: translate(0);
+}
+.batch-toolbar {
+  display: flex;
+  align-items: center;
+  height: 56px;
+  // min-width: 600px;
+  background: #fff;
+  border: 1px solid #e5e6eb;
+  box-sizing: border-box;
+  box-shadow: 0 16px 32px -10px rgba(4, 24, 115, .1);
+  border-radius: 4px;
+  button{
+      color:#545968;
+  }
+}
+.batch-toolbar .styles_counter__18S08 {
+  color: #fff;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 100%;
+  background: #C6233F;
+  width: 100px;
+  font-size: 12px;
+  border-top-left-radius: 4px;
+  border-bottom-left-radius: 4px;
+}
+.batch-toolbar .batch-toolbar-actions {
+  display: flex;
+  margin: auto;
+  padding: 0 20px;
+}
+.batch-toolbar .styles_cancel__AARoT {
+  font-size: 16px;
+  border-left: 1px solid #a9aeb8;
+  // padding-left: 20px;
+  display: flex;
+  justify-content: center;
+  width: 128px;
+}
+.batch-toolbar .styles_counter__18S08 .styles_num__178Wa {
+  font-size: 24px;
+  margin-left: 8px;
+}
+.ant-space-align-center {
+  align-items: center;
+}
+
+.ant-space {
+  display: inline-flex;
 }
 ::ng-deep .ant-page-header-heading-title{
   white-space: normal;

+ 159 - 22
projects/textbook/src/modules/nav-admin/page-user/page-user.component.ts

@@ -1,5 +1,5 @@
 import { Component, OnInit, ViewChild } from '@angular/core';
-import { ActivatedRoute, RouterOutlet } from '@angular/router';
+import { ActivatedRoute, Router, RouterOutlet } from '@angular/router';
 import { CompTableListComponent } from '../../../app/comp-table/comp-table-list/comp-table-list.component';
 // import _User from '../../../schemas/_User';
 import * as Parse from 'parse';
@@ -8,7 +8,10 @@ import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
 import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';
 import { NzSpaceModule } from 'ng-zorro-antd/space';
 import { CommonCompModule } from '../../../services/common.modules';
-import { Profile } from '../../../schemas/Profile-list';
+// import { Profile } from '../../../schemas/Profile-list';
+import { NzEmptyModule } from 'ng-zorro-antd/empty';
+import { NzAvatarModule } from 'ng-zorro-antd/avatar';
+import { NzModalService } from 'ng-zorro-antd/modal';
 @Component({
   selector: 'app-page-user',
   templateUrl: './page-user.component.html',
@@ -21,6 +24,8 @@ import { Profile } from '../../../schemas/Profile-list';
     CompTableListComponent,
     NzBreadCrumbModule,
     CommonCompModule,
+    NzEmptyModule,
+    NzAvatarModule
   ],
   standalone: true,
 })
@@ -28,38 +33,170 @@ export class PageUserComponent implements OnInit {
   @ViewChild(CompTableListComponent) list: CompTableListComponent | undefined;
 
   // _User = _User;
-  ProfileList = Profile;
+  // ProfileList = Profile;
+  // className: string | undefined;
+  // queryParams: any | undefined;
+  // fieldsArray: Array<any> | undefined;
   user: Parse.User | undefined;
-  className: string | undefined;
-  queryParams: any | undefined;
-  fieldsArray: Array<any> | undefined;
+  profiles: Array<any> = [];
+  profileLength:number = 0 //总数据
+  pageSize:number = 10
+  pageIndex:number = 1
+  checkedAll: boolean = false; //全选
+  indeterminate = false;
+  loading = false;
+  searchValue: string = ''; //搜索内容
+  setOfCheckedId = new Set<string>();
 
   constructor(
-    private route: ActivatedRoute,
+    private modal: NzModalService,
+    private route: Router,
     private activeRoute: ActivatedRoute // private translate:TranslateService,
   ) {
     this.user = Parse.User.current();
-    this.className = this.ProfileList.className;
-    this.fieldsArray = this.ProfileList.fieldsArray;
-    this.queryParams = {
-      where: {
-        // user:this.user?.toPointer(),
-        isDeleted: { $ne: true },
-      },
-    };
+    // this.className = this.ProfileList.className;
+    // this.fieldsArray = this.ProfileList.fieldsArray;
+    // this.queryParams = {
+    //   where: {
+    //     // user:this.user?.toPointer(),
+    //     isDeleted: { $ne: true },
+    //   },
+    // };
   }
 
   ngOnInit(): void {
     this.activeRoute.paramMap.subscribe(async (params) => {
-      let isDeleted = params.get('isDeleted');
-      if (isDeleted) {
-        this.queryParams.where['isDeleted'] = { $eq: true };
-      } else {
-        this.queryParams.where['isDeleted'] = { $ne: true };
+      this.getProfile()
+    });
+  }
+  async getProfile() {
+    this.profiles = [];
+    this.loading = true;
+    let queryParams = {
+      where : {
+        "$or": [{
+          "user": {
+            "$inQuery": {
+              "where": {
+                "$or": [{
+                  "name": { "$regex": `.*${this.searchValue}.*`}
+                  },
+                ]
+              },
+              "className": "_User"
+            }
+          }
+        }]
       }
-      this.list?.ngOnInit();
+    }
+    let query = Parse.Query.fromJSON('Profile',queryParams);
+    query.include('user');
+    query.notEqualTo('identity', '国家级管理员');
+    this.profileLength = await query.count()
+    query.limit(this.pageSize)
+    query.skip((this.pageIndex - 1) * this.pageSize)
+    let r = await query.find();
+    let profiles: any[] = [];
+    r.forEach((item) => {
+      let _item = item.toJSON();
+      _item['checked'] = false;
+      profiles.push(_item);
     });
+    this.profiles = profiles;
+    this.loading = false;
   }
-
   createUser() {}
+  onItemChecked(id: string,user:string, e: boolean) {
+    let checkedAll = true;
+    this.profiles = this.profiles.map((item) => {
+      if (id == item.objectId) item.checked = e;
+      if (!item.checked) checkedAll = false;
+      return item;
+    });
+    if(e){
+      this.setOfCheckedId.add(user)
+    }else{
+      this.setOfCheckedId.delete(user)
+    }
+    this.checkedAll = checkedAll;
+  }
+  onAllChecked(checked: boolean): void {
+    console.log(checked);
+    this.profiles = this.profiles.map((item) => {
+      item.checked = checked;
+      if(checked){
+        this.setOfCheckedId.add(item.user.objectId)
+      }else{
+        this.setOfCheckedId.delete(item.user.objectId)
+      }
+      return item;
+    });
+    this.checkedAll = checked;
+  }
+  async updateUser(data:any, type: string) {
+    console.log(type);
+    this.modal.confirm({
+      nzTitle: '操作提示',
+      nzContent: `确定${type}吗?`,
+      nzOkText: '确认',
+      nzOkType: 'primary',
+      nzOkDanger: type == '删除' ? true : false,
+      nzOnOk:async () => {
+        let query = new Parse.Query('_User')
+        query.equalTo('objectId',data.user.objectId)
+        let r = await query.first()
+        if(r?.id){
+          switch (type) {
+            case '通过认证':
+              r?.set('accountState', '已认证');
+              break;
+            case '禁用':
+              r?.set('accountState', '已禁用');
+              break;
+            case '删除':
+              r?.set('isDeleted', true);
+              break;
+          }
+          await r?.save();
+        }
+        this.getProfile();
+      },
+      nzCancelText: '取消',
+      nzOnCancel: () => console.log('Cancel')
+    });
+    
+  }
+
+  deleteSelected(){
+    this.modal.confirm({
+      nzTitle: '批量删除',
+      nzContent: `删除后数据不可恢复,请谨慎操作`,
+      nzOkText: '确认',
+      nzOkType: 'primary',
+      nzOkDanger: true,
+      nzOnOk:async () => {
+        let selectedList = this.profiles.filter((item:any)=>this.setOfCheckedId.has(item?.id))
+        let deletePromiseList = selectedList.map((item:any)=>{
+          return new Promise((resolve=>{
+            item.set("isDeleted",true);
+            item.save();
+          }))
+        })
+        try{
+          await Promise.all(deletePromiseList)
+        }
+        catch(err){
+
+        }
+      },
+      nzCancelText: '取消',
+      nzOnCancel: () => console.log('Cancel')
+    });
+   }
+   goDateil(id:string){
+    this.route.navigate([
+      '/nav-admin/manage/user/edit',
+      { id:id },
+    ])
+  }
 }

+ 3 - 4
projects/textbook/src/modules/nav-admin/user-edit/user-edit.component.html

@@ -45,8 +45,8 @@
           </button>
           <nz-dropdown-menu #menu="nzDropdownMenu">
             <ul nz-menu>
+              @if (user?.get('accountState') == '待认证') {
               <li nz-menu-item>
-                @if (user?.get('accountState') == '待认证') {
                 <button
                   nz-button
                   nzType="link"
@@ -60,10 +60,9 @@
                   ></span
                   >通过认证
                 </button>
-                }
               </li>
+              } @if (user?.get('accountState') != '已禁用') {
               <li nz-menu-item>
-                @if (user?.get('accountState') != '已禁用') {
                 <button
                   nz-button
                   nzType="link"
@@ -72,8 +71,8 @@
                 >
                   <span nz-icon nzType="stop" nzTheme="outline"></span>禁用账号
                 </button>
-                }
               </li>
+              }
               <li nz-menu-item>
                 <button
                   (click)="updateUser('删除')"

+ 1 - 0
projects/textbook/src/schemas/Profile-list.ts

@@ -177,4 +177,5 @@ export const Profile: ParseSchema = {
     // {key:"emal",name:"邮箱",type:"String",isHeader:true},
     // {key:"createdAt",name:"创建时间",type:"Date",isHeader:true,},
   ],
+  nzWidthConfig:['50px','100px','100px','100px','100px','100px','100px','100px']
 };

+ 1 - 0
projects/textbook/src/schemas/func-parse.ts

@@ -12,6 +12,7 @@ export interface ParseSchema{
     buttons?:Array<any>,
     emptyImg?:String,
     emptyDesc?:String,
+    nzWidthConfig?:Array<string>
 }
 export interface ParseField{
   key:string