Эх сурвалжийг харах

feat: list select & batch toolbar

MetaPunkGames 9 сар өмнө
parent
commit
b1844a81ba

+ 45 - 5
projects/textbook/src/app/comp-table/comp-table-list/comp-table-list.component.html

@@ -7,10 +7,18 @@
   </div>
 </div>
 
-<nz-table #editRowTable nzBordered [nzData]="list" *ngIf="showMode=='list'&&list?.length"
+<nz-table #editRowTable [nzData]="list" *ngIf="showMode=='list'&&list?.length"
   [nzLoading]="isLoading" nzFrontPagination="false">
     <thead>
       <tr>
+        <!-- 全部选择 -->
+        <th
+            [nzChecked]="checked"
+            [nzIndeterminate]="indeterminate"
+            nzLabel="Select all"
+            (nzCheckedChange)="onAllChecked($event)"
+            (nzCurrentPageDataChange)="onCurrentPageDataChange($event)"
+          ></th>
         <ng-container *ngFor="let field of headerArray">
             <th >{{field?.name}}</th>
         </ng-container>
@@ -21,6 +29,13 @@
     <tbody>
       <ng-container *ngFor="let object of editRowTable.data">
         <tr class="editable-row" *ngIf="object?.get('isDeleted')!=true">
+          <!-- 单行选择 -->
+          <!-- [nzDisabled]="object.disabled" -->
+          <td
+          [nzChecked]="setOfCheckedId.has(object.id)"
+          [nzLabel]="object.className"
+          (nzCheckedChange)="onItemChecked(object.id, $event)"
+        ></td>
           <ng-container *ngFor="let field of headerArray">
             <!-- 单行数据每个字段渲染 -->
             <td > 
@@ -72,9 +87,9 @@
 
   <!-- 暂无数据:提示模板 -->
   <ng-template #noResultTpl>
-    <nz-result [nzIcon]="emptyImgTpl" [nzTitle]="schema?.title+'管理'" [nzSubTitle]="'当前还没有'+schema?.title+'数据哦,请您点击创建。'">
+    <nz-result [nzIcon]="emptyImgTpl" [nzTitle]="schema?.title+'管理'" [nzSubTitle]="schema?.emptyDesc || '当前还没有'+schema?.title+'数据哦,请您点击创建。'">
       <div nz-result-extra>
-        <button mat-raised-button color="primary">创建</button>
+        <button mat-raised-button color="secondary" (click)="createObject()">创建{{schema?.title}}</button>
       </div>
     </nz-result>
   </ng-template>
@@ -86,9 +101,34 @@
     <ng-container *ngTemplateOutlet="noResultTpl"></ng-container>
   </ng-container>
 
-  <div style="width:100%;display: flex;justify-content: center;align-items: center;">
+  <!-- 分页区域:分页组件 -->
+  <div style="width:100%;display: flex;justify-content: end;align-items: center;padding-right: 20px;margin-top:-20px;">
     <nz-pagination 
     [nzPageIndex]="pageIndex"
+    [nzSize]="'small'"
     [nzPageSize]="pageSize" [nzTotal]="pageTotal" (nzPageIndexChange)="onPageIndexChange($event)"
     ></nz-pagination>
-  </div>
+  </div>
+
+  <!-- 全选操作:批量操作 -->
+  <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">
+            <span nz-icon nzType="delete"></span>
+            删除
+          </button>
+        </div>
+      </div>
+    </div>
+    <div class="styles_cancel__AARoT">
+      <button nz-button nzType="text">取消选中</button>
+    </div>
+  </div>
+</div>

+ 65 - 0
projects/textbook/src/app/comp-table/comp-table-list/comp-table-list.component.scss

@@ -2,4 +2,69 @@
 nz-table{
     width:100%;
     padding:20px;
+    th{
+        color:var(--color-text-desc);
+    }
+}
+
+
+// 选中,批量操作区域
+.batch-toolbar-modal{
+    position: absolute;
+    display: flex;
+    justify-content: center;
+    bottom: 80px;
+    left: calc(50% - 210px);
+    -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: #215ae5;
+    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;
 }

+ 49 - 2
projects/textbook/src/app/comp-table/comp-table-list/comp-table-list.component.ts

@@ -15,6 +15,9 @@ import { MatButtonModule } from '@angular/material/button';
 import { MatSlideToggleModule } from '@angular/material/slide-toggle';
 import { UtilnowPipe } from '../../../pipes/utilnow.pipe';
 import { NzTableModule } from 'ng-zorro-antd/table';
+import { openObjectEditDialog } from '../../../schemas/func-parse';
+import { MatIconModule } from '@angular/material/icon';
+import { NzIconModule } from 'ng-zorro-antd/icon';
 
 interface SchemaFiled{
   key:string,
@@ -31,8 +34,8 @@ interface SchemaFiled{
   imports:[CommonModule,
     UtilnowPipe,
     // TranslateModule,
-    NzPaginationModule,NzEmptyModule,NzTableModule,NzResultModule,
-    MatButtonModule,MatCheckboxModule,MatSlideToggleModule,
+    NzPaginationModule,NzEmptyModule,NzTableModule,NzResultModule,NzIconModule,
+    MatButtonModule,MatCheckboxModule,MatSlideToggleModule,MatIconModule,
   ],
   providers:[]
 })
@@ -70,6 +73,12 @@ export class CompTableListComponent {
     this.refresh();
   }
 
+  createObject(){
+    openObjectEditDialog(this.dialog,this.schema,undefined,()=>{
+      this.refresh();
+    })
+  }
+
   batchHandle(button:any){
     // console.log(this.currentLang,'888888888888888888')
     button?.handle({
@@ -155,4 +164,42 @@ export class CompTableListComponent {
     object.set(key,!object.get(key))
     object.save();
    }
+
+
+  /**
+   * 行选择处理逻辑
+   */
+  checked = false;
+  indeterminate = false;
+  setOfCheckedId = new Set<string>();
+
+  updateCheckedSet(id: string, checked: boolean): void {
+    if (checked) {
+      this.setOfCheckedId.add(id);
+    } else {
+      this.setOfCheckedId.delete(id);
+    }
+  }
+
+  onCurrentPageDataChange(event:any): void {
+    this.refreshCheckedStatus();
+  }
+
+  refreshCheckedStatus(): void {
+    const listOfEnabledData = this.list // .filter(({ disabled }) => !disabled);
+    this.checked = listOfEnabledData.every(({ id }) => this.setOfCheckedId.has(id));
+    this.indeterminate = listOfEnabledData.some(({ id }) => this.setOfCheckedId.has(id)) && !this.checked;
+  }
+
+  onItemChecked(id: string, checked: boolean): void {
+    this.updateCheckedSet(id, checked);
+    this.refreshCheckedStatus();
+  }
+
+  onAllChecked(checked: boolean): void {
+    this.list
+      // .filter(({ disabled }) => !disabled)
+      .forEach(({ id }) => this.updateCheckedSet(id, checked));
+    this.refreshCheckedStatus();
+  }
 }

+ 0 - 1
projects/textbook/src/modules/nav-admin/page-collection/page-collection.component.html

@@ -5,5 +5,4 @@
   [className]="className"
   [fieldsArray]="fieldsArray"
   [queryParams]="queryParams"
-  [showMode]="'grid'"
 ></comp-table-list>

+ 57 - 56
projects/textbook/src/schemas/EduCollection.ts

@@ -2,60 +2,61 @@ import { MatDialog } from "@angular/material/dialog";
 import { openObjectEditDialog, ParseSchema } from "./func-parse";
 
 
-    const EduCollection:ParseSchema = {
-        "title":"报送合集",
-        "className": "EduCollection",
-        emptyImg:"/img/webhook-empty.png",
-        "fieldsArray": [
-            {
-                "key":"title",
-                "name":"合集名称",
-                "type": "String",
-                isHeader:true
+const EduCollection:ParseSchema = {
+    "title":"报送合集",
+    "className": "EduCollection",
+    emptyImg:"/img/webhook-empty.png",
+    emptyDesc:"请您创建报送合集,分配合集管理员,统一管理各地区的教材推荐报送流程和配额。",
+    "fieldsArray": [
+        {
+            "key":"title",
+            "name":"合集名称",
+            "type": "String",
+            isHeader:true
+        },
+        {
+            "key":"name",
+            "name":"合集CODE",
+            "type": "String",
+            isHeader:true
+        },
+        {
+            "key":"desc",
+            "name":"合集描述",
+            "type": "String",
+            isHeader:true
+        },
+        {
+            "key":"profileSubmitted",
+            "name":"合集报送人",
+            "type": "Pointer",
+            "targetClass":"Profile",
+            isHeader:true
+        },
+        {
+            "key":"status",
+            "name":"合集状态",
+            "type": "String",
+            "options":[
+                {label:"遴选中",value:"遴选中"},
+                {label:"公示中",value:"公示中"},
+                {label:"已完成",value:"已完成"}
+            ],
+            isHeader:true
+        },
+    ],
+    buttons:[
+        {
+            name:"编辑",
+            place:"item",
+            show:(options:{object:Parse.Object})=>{
+                return true
             },
-            {
-                "key":"name",
-                "name":"合集CODE",
-                "type": "String",
-                isHeader:true
-            },
-            {
-                "key":"desc",
-                "name":"合集描述",
-                "type": "String",
-                isHeader:true
-            },
-            {
-                "key":"profileSubmitted",
-                "name":"合集报送人",
-                "type": "Pointer",
-                "className":"Profile",
-                isHeader:true
-            },
-            {
-                "key":"status",
-                "name":"合集状态",
-                "type": "String",
-                "options":[
-                    {label:"遴选中",value:"遴选中"},
-                    {label:"公示中",value:"公示中"},
-                    {label:"已完成",value:"已完成"}
-                ],
-                isHeader:true
-            },
-        ],
-        buttons:[
-            {
-                name:"编辑",
-                place:"item",
-                show:(options:{object:Parse.Object})=>{
-                    return true
-                },
-                handle:(options:{dialog:MatDialog,object:Parse.Object})=>{
-                    openObjectEditDialog(options?.dialog,EduCollection,options?.object)
-                }
-            },
-        ]
-      };
-      
-      export default EduCollection;
+            handle:(options:{dialog:MatDialog,object:Parse.Object})=>{
+                openObjectEditDialog(options?.dialog,EduCollection,options?.object)
+            }
+        },
+    ]
+    };
+    
+    export default EduCollection;

+ 1 - 1
projects/textbook/src/schemas/EduTextbook.ts

@@ -22,6 +22,6 @@ export const EduTextbook:ParseSchema = {
     fieldsArray:[
         {key:"title",name:"教材名称",type:"String",isHeader:true},
         {key:"desc",name:"教材描述",type:"String"},
-        {key:"user",name:"创建人",type:"Pointer",className:"_User",isHeader:true,showName:"${name}"},
+        {key:"user",name:"创建人",type:"Pointer",targetClass:"_User",isHeader:true,showName:"${name}"},
     ]
 }

+ 3 - 2
projects/textbook/src/schemas/func-parse.ts

@@ -7,16 +7,17 @@ export interface ParseSchema{
     title:string
     className:string,
     fieldsArray:Array<ParseField>,
-    emptyImg?:String,
     include?:Array<string>,
     buttons?:Array<any>,
+    emptyImg?:String,
+    emptyDesc?:String,
 }
 export interface ParseField{
   key:string
   name:string
   type:string
   isDisabled?:boolean
-  className?:string
+  targetClass?:string
   showName?:string
   isHeader?:boolean
   options?:Array<ParseFiledOption>

+ 1 - 0
projects/textbook/src/styles.scss

@@ -3,6 +3,7 @@
     --color-primary-blue:#143383;
     --color-secondary-blue:#645bff;
     --color-primary-purple:#143383;
+    --color-text-desc:#878a95;
 }
 // --color-primary-purle:#7F30C5;
 /**

+ 1 - 0
server/db/index.js

@@ -2,6 +2,7 @@
 const EduSchemas = [
     require("./schemas/Company").Company,
     require("./schemas/EduTextbook").EduTextbook,
+    require("./schemas/EduCollection").EduCollection,
     require("./schemas/_User")._User,
     require("./schemas/_Role")._Role,
 ]

+ 53 - 0
server/db/schemas/EduCollection.js

@@ -0,0 +1,53 @@
+const EduCollection = {
+    "className": "EduCollection",
+    "fields": {
+        "title": {
+            "type": "String",
+            "required": false
+        },
+        "name": {
+            "type": "String",
+            "required": false
+        },
+        "desc": {
+            "type": "String",
+            "required": false
+        },
+        "profileSubmitted": {
+            "type": "Pointer",
+            "targetClass":"Profile",
+            "required": false
+        },
+        "status": {
+            "type": "String",
+            "required": false
+        },
+    },
+    "classLevelPermissions": {
+        "find": {
+            "*": true
+        },
+        "get": {
+            "*": true
+        },
+        "count": {
+            "*": true
+        },
+        "create": {
+            "*": true
+        },
+        "update": {
+            "*": true
+        },
+        "delete": {
+            "*": true
+        },
+        "addField": {
+            "*": true
+        },
+        "protectedFields": {
+            "*": []
+        }
+    }
+}
+module.exports.EduCollection = EduCollection