Browse Source

Merge branch 'master' of http://git.fmode.cn:3000/bin/edu-textbook

warrior 8 months ago
parent
commit
8883dd8507
49 changed files with 1114 additions and 43 deletions
  1. 18 0
      docs/Schema.md
  2. 1 0
      projects/textbook/public/img/404-empty.svg
  3. BIN
      projects/textbook/public/img/approval-no-permissions.png
  4. BIN
      projects/textbook/public/img/group-empty.png
  5. BIN
      projects/textbook/public/img/pipeline-empty.png
  6. BIN
      projects/textbook/public/img/role-new-default.png
  7. BIN
      projects/textbook/public/img/sourceEmpty.png
  8. BIN
      projects/textbook/public/img/sso-empty.png
  9. BIN
      projects/textbook/public/img/webhook-empty.png
  10. BIN
      projects/textbook/public/img/whitelist-default.png
  11. 10 0
      projects/textbook/src/app/comp-comfirm-dialog/comp-comfirm-dialog.component.html
  12. 0 0
      projects/textbook/src/app/comp-comfirm-dialog/comp-comfirm-dialog.component.scss
  13. 23 0
      projects/textbook/src/app/comp-comfirm-dialog/comp-comfirm-dialog.component.spec.ts
  14. 34 0
      projects/textbook/src/app/comp-comfirm-dialog/comp-comfirm-dialog.component.ts
  15. 20 0
      projects/textbook/src/app/comp-table/comp-edit-object/comp-edit-object.component.html
  16. 4 0
      projects/textbook/src/app/comp-table/comp-edit-object/comp-edit-object.component.scss
  17. 23 0
      projects/textbook/src/app/comp-table/comp-edit-object/comp-edit-object.component.spec.ts
  18. 106 0
      projects/textbook/src/app/comp-table/comp-edit-object/comp-edit-object.component.ts
  19. 64 9
      projects/textbook/src/app/comp-table/comp-table-list/comp-table-list.component.html
  20. 65 0
      projects/textbook/src/app/comp-table/comp-table-list/comp-table-list.component.scss
  21. 80 3
      projects/textbook/src/app/comp-table/comp-table-list/comp-table-list.component.ts
  22. 21 0
      projects/textbook/src/modules/nav-admin/modules.routes.ts
  23. 32 0
      projects/textbook/src/modules/nav-admin/page-collection/page-collection.component.html
  24. 10 0
      projects/textbook/src/modules/nav-admin/page-collection/page-collection.component.scss
  25. 22 0
      projects/textbook/src/modules/nav-admin/page-collection/page-collection.component.spec.ts
  26. 61 0
      projects/textbook/src/modules/nav-admin/page-collection/page-collection.component.ts
  27. 3 3
      projects/textbook/src/modules/nav-admin/page-home/page-home.component.html
  28. 1 1
      projects/textbook/src/modules/nav-admin/page-home/page-home.component.scss
  29. 19 6
      projects/textbook/src/modules/nav-admin/page-home/page-home.component.ts
  30. 8 0
      projects/textbook/src/modules/nav-admin/page-role/page-role.component.html
  31. 0 0
      projects/textbook/src/modules/nav-admin/page-role/page-role.component.scss
  32. 22 0
      projects/textbook/src/modules/nav-admin/page-role/page-role.component.spec.ts
  33. 52 0
      projects/textbook/src/modules/nav-admin/page-role/page-role.component.ts
  34. 8 0
      projects/textbook/src/modules/nav-admin/page-user/page-user.component.html
  35. 0 0
      projects/textbook/src/modules/nav-admin/page-user/page-user.component.scss
  36. 22 0
      projects/textbook/src/modules/nav-admin/page-user/page-user.component.spec.ts
  37. 52 0
      projects/textbook/src/modules/nav-admin/page-user/page-user.component.ts
  38. 1 3
      projects/textbook/src/modules/nav-author/page-home/page-home.component.scss
  39. 63 0
      projects/textbook/src/schemas/EduCollection.ts
  40. 5 18
      projects/textbook/src/schemas/EduTextbook.ts
  41. 42 0
      projects/textbook/src/schemas/_Role.ts
  42. 62 0
      projects/textbook/src/schemas/_User.ts
  43. 76 0
      projects/textbook/src/schemas/func-parse.ts
  44. 1 0
      projects/textbook/src/styles.scss
  45. 20 0
      server/db/data/init-data.sql
  46. 1 0
      server/db/index.js
  47. 53 0
      server/db/schemas/EduCollection.js
  48. 3 0
      server/db/schemas/_Role.js
  49. 6 0
      server/db/schemas/_User.js

+ 18 - 0
docs/Schema.md

@@ -0,0 +1,18 @@
+# 数据范式说明
+
+
+
+# 系统范式
+- _User 注册账号
+- _Role 用户组/角色
+- Profile 角色认证审核档案
+
+
+# 教材范式
+- EduTextbook
+    - 教材详情内容
+
+
+# 合集范式
+- EduCollection
+    - 配置身份、报送人、配额数量

File diff suppressed because it is too large
+ 1 - 0
projects/textbook/public/img/404-empty.svg


BIN
projects/textbook/public/img/approval-no-permissions.png


BIN
projects/textbook/public/img/group-empty.png


BIN
projects/textbook/public/img/pipeline-empty.png


BIN
projects/textbook/public/img/role-new-default.png


BIN
projects/textbook/public/img/sourceEmpty.png


BIN
projects/textbook/public/img/sso-empty.png


BIN
projects/textbook/public/img/webhook-empty.png


BIN
projects/textbook/public/img/whitelist-default.png


+ 10 - 0
projects/textbook/src/app/comp-comfirm-dialog/comp-comfirm-dialog.component.html

@@ -0,0 +1,10 @@
+<h1 mat-dialog-title>{{data.title}}</h1>
+<div mat-dialog-content *ngIf="data?.message">
+  <p>{{data?.message}}</p>
+</div>
+<div mat-dialog-actions>
+  <!-- <button mat-button (click)="confirm(false)" >{{'取消'}}</button>
+  <button mat-button (click)="confirm(true)">{{'确认'}}</button> -->
+  <button nz-button nzType="text" nzShape="round" (click)="confirm(false)" >取消</button>
+  <button nz-button nzType="text" [nzDanger]="data?.danger" nzShape="round" (click)="confirm(true)">确认</button>
+</div>

+ 0 - 0
projects/textbook/src/app/comp-comfirm-dialog/comp-comfirm-dialog.component.scss


+ 23 - 0
projects/textbook/src/app/comp-comfirm-dialog/comp-comfirm-dialog.component.spec.ts

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

+ 34 - 0
projects/textbook/src/app/comp-comfirm-dialog/comp-comfirm-dialog.component.ts

@@ -0,0 +1,34 @@
+import { CommonModule } from '@angular/common';
+import { Component, Inject } from '@angular/core';
+import { MatButtonModule } from '@angular/material/button';
+import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { NzButtonModule } from 'ng-zorro-antd/button';
+
+@Component({
+  selector: 'app-comp-comfirm-dialog',
+  standalone:true,
+  imports:[ 
+    CommonModule,
+    MatButtonModule,
+    MatDialogModule,
+    NzButtonModule,
+  ],
+  templateUrl: './comp-comfirm-dialog.component.html',
+  styleUrls: ['./comp-comfirm-dialog.component.scss']
+})
+export class CompComfirmDialogComponent {
+  constructor(
+    public dialogRef: MatDialogRef<CompComfirmDialogComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: {
+      title:string|null,
+      message:string|null,
+      mode?:string|null,
+      danger?:boolean|null,
+    },
+  ){
+  }
+  confirm(result:any){
+    this.dialogRef.close(result)
+  }
+
+}

+ 20 - 0
projects/textbook/src/app/comp-table/comp-edit-object/comp-edit-object.component.html

@@ -0,0 +1,20 @@
+<h1 mat-dialog-title *ngIf="data?.object?.id">{{"编辑"}}-{{data?.object?.get("name")}}</h1>
+<h1 mat-dialog-title *ngIf="!data?.object?.id">{{"创建新"}}{{data?.title}}</h1>
+<div mat-dialog-content>
+    <form *ngIf="isFormShow">
+        <ng-container *ngFor="let field of data?.fieldsArray">
+            <mat-form-field>
+                <mat-label >{{field?.name}}</mat-label>
+                <!-- [errorState]="requiredErrorMap[field?.key]" -->
+                <input matInput [(ngModel)]="jsonData[field?.key]" [formControl]="formControlMap[field?.key]||null" >
+                <mat-error *ngIf="requiredErrorMap[field?.key]">
+                    {{field?.name}}<strong >必填</strong>
+                </mat-error>
+            </mat-form-field>
+        </ng-container>
+    </form>
+</div>
+<div mat-dialog-actions>
+  <button mat-button [disabled]="isSaving" (click)="close()" >{{"取消"}}</button>
+  <button mat-button [disabled]="isSaving" (click)="save()" >{{"保存"}}</button>
+</div>

+ 4 - 0
projects/textbook/src/app/comp-table/comp-edit-object/comp-edit-object.component.scss

@@ -0,0 +1,4 @@
+form{
+    display: flex;
+    flex-direction: column;
+}

+ 23 - 0
projects/textbook/src/app/comp-table/comp-edit-object/comp-edit-object.component.spec.ts

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

+ 106 - 0
projects/textbook/src/app/comp-table/comp-edit-object/comp-edit-object.component.ts

@@ -0,0 +1,106 @@
+import { CommonModule } from '@angular/common';
+import { Component, Inject } from '@angular/core';
+import { FormControl, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatInputModule } from '@angular/material/input';
+import Parse from "parse";
+import { ParseSchema } from '../../../schemas/func-parse';
+
+@Component({
+  selector: 'app-comp-edit-object',
+  standalone:true,
+  imports:[ 
+    CommonModule,
+    FormsModule,
+    ReactiveFormsModule,
+    MatFormFieldModule,
+    MatInputModule,
+    MatButtonModule,
+    MatDialogModule,
+    // MatFormFieldModule,
+  ],
+  templateUrl: './comp-edit-object.component.html',
+  styleUrls: ['./comp-edit-object.component.scss']
+})
+export class CompEditObjectComponent {
+  jsonData:any = {}
+  formControlMap:any = {}
+  isFormShow:boolean = false;
+  constructor(
+    public dialogRef: MatDialogRef<CompEditObjectComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: {
+      schema:ParseSchema|undefined,
+      object:Parse.Object|null|undefined,
+      fieldsArray:Array<any>|null,
+      title:string|null,
+      default?:any
+    },
+  ){
+    // 设置数据校验
+    this.data?.fieldsArray?.forEach(field=>{
+      this.formControlMap[field?.key] = new FormControl({value:field?.key,disabled:field?.isDisabled||false})
+      if(field?.require){
+        this.formControlMap[field?.key] = new FormControl({value:field?.key,disabled:field?.isDisabled||false}, [Validators.required]);
+      }
+    })
+    if(this.data.object?.toJSON()){
+      this.jsonData = this.data?.object?.toJSON();
+      console.log(this.jsonData)
+    }
+    if(!this.data?.object?.id){
+      let className:any = this.data?.object?.className || this.data.schema?.className
+      let SchemaContructor =  Parse.Object.extend(className)
+      this.data.object = new SchemaContructor()
+    }
+  }
+  ngOnInit(){
+    setTimeout(() => {
+      this.isFormShow = true
+    }, 200);
+  }
+  /**
+   * 保存与取消
+   */
+  close(){
+    this.dialogRef.close();
+  }
+  isSaving:boolean = false;
+  requiredErrorMap:any = {}
+  async save() {
+    if(this.isSaving) return;
+    this.isSaving = true
+    // 检查必填项
+    this.requiredErrorMap = {}
+    this.data?.fieldsArray?.forEach(field=>{
+      if(field?.require && typeof this.jsonData[field?.key] == "undefined"){
+        this.requiredErrorMap[field?.key] = true
+      }
+    })
+    if(Object.keys(this.requiredErrorMap)?.length>=1){
+      this.isSaving = false
+      return
+    }
+
+    // 设置编辑结果
+    delete this.jsonData.objectId
+    delete this.jsonData.updatedAt
+    delete this.jsonData.createdAt
+    delete this.jsonData.sessionToken
+    delete this.jsonData.ACL
+    this.data?.object?.set(this.jsonData);
+
+    // 设置默认值
+    if(this.data?.default){
+      this.data?.object?.set(this.data?.default)
+    }
+
+    // 保存并返回
+    this.data.object = await this.data?.object?.save();
+    this.dialogRef.close(this.data?.object);
+    this.isSaving = false
+
+  }
+
+}

+ 64 - 9
projects/textbook/src/app/comp-table/comp-table-list/comp-table-list.component.html

@@ -1,5 +1,6 @@
-<div style="width:100%;display: flex;justify-content: end;">
 
+
+<div style="width:100%;display: flex;justify-content: end;">
   <div style="width:30%;display: flex;justify-content: end;align-items: flex-end;">
     <ng-container *ngFor="let button of schema?.buttons">
       <button *ngIf="button?.place=='top'&&button?.show({queryParams:queryParams})" mat-raised-button color="primary" (click)="batchHandle(button)" >{{button?.name }}</button>
@@ -7,22 +8,36 @@
   </div>
 </div>
 
-<nz-table #editRowTable nzBordered [nzData]="list" *ngIf="showMode=='list'"
-  [nzNoResult]="currentLang=='cn'?'暂无数据':'No Data'"
-  [nzLoading]="isLoading" nzFrontPagination="false"
->
+<!-- 数据表格:渲染当前页 -->
+<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>
-            <th >状态</th>
+            <th >时间</th>
             <th >操作</th>
     </tr>
     </thead>
     <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 > 
@@ -70,12 +85,52 @@
         <!-- <comp-monitor-card [monitor]="object"></comp-monitor-card> -->
       </div>
     </ng-container>
-    <nz-empty *ngIf="!list?.length" nzNotFoundImage="simple" [nzNotFoundContent]="currentLang=='cn'?'暂无数据':'No Data'"></nz-empty>
   </div>
 
-  <div style="width:100%;display: flex;justify-content: center;align-items: center;">
+  <!-- 暂无数据:提示模板 -->
+  <ng-template #noResultTpl>
+    <nz-result [nzIcon]="emptyImgTpl" [nzTitle]="schema?.title+'管理'" [nzSubTitle]="schema?.emptyDesc || '当前还没有'+schema?.title+'数据哦,请您点击创建。'">
+      <div nz-result-extra>
+        <button mat-raised-button color="secondary" (click)="createObject()">创建{{schema?.title}}</button>
+      </div>
+    </nz-result>
+  </ng-template>
+  <ng-template #emptyImgTpl>
+    <img style="width:50%;max-width:300px;" [src]="schema?.emptyImg || '/img/404-empty.svg' " alt="">
+  </ng-template>
+
+  <ng-container *ngIf="!list?.length">
+    <ng-container *ngTemplateOutlet="noResultTpl"></ng-container>
+  </ng-container>
+
+  <!-- 分页区域:分页组件 -->
+  <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" (click)="deleteSelected()">
+            <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;
 }

+ 80 - 3
projects/textbook/src/app/comp-table/comp-table-list/comp-table-list.component.ts

@@ -8,12 +8,19 @@ import { CommonModule } from '@angular/common';
 
 import { NzPaginationModule } from 'ng-zorro-antd/pagination';
 import { NzEmptyModule } from 'ng-zorro-antd/empty';
+import { NzResultModule } from 'ng-zorro-antd/result';
 
 import { MatCheckboxModule } from '@angular/material/checkbox';
 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 { confirmDialog, openObjectEditDialog } from '../../../schemas/func-parse';
+import { MatIconModule } from '@angular/material/icon';
+import { NzIconModule } from 'ng-zorro-antd/icon';
+import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
+import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';
+import { NzTagModule } from 'ng-zorro-antd/tag';
 
 interface SchemaFiled{
   key:string,
@@ -30,8 +37,8 @@ interface SchemaFiled{
   imports:[CommonModule,
     UtilnowPipe,
     // TranslateModule,
-    NzPaginationModule,NzEmptyModule,NzTableModule,
-    MatButtonModule,MatCheckboxModule,MatSlideToggleModule,
+    NzPaginationModule,NzEmptyModule,NzTableModule,NzResultModule,NzIconModule,
+    MatButtonModule,MatCheckboxModule,MatSlideToggleModule,MatIconModule,
   ],
   providers:[]
 })
@@ -69,6 +76,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({
@@ -83,7 +96,9 @@ export class CompTableListComponent {
   onButtonHandleCallBack:Function|undefined
   buttonHandle(button:any,object:any){
     let that = this
-    button?.handle({object:object,dialog:this.dialog,callback:this.onButtonHandleCallBack},that.currentLang)
+    if(button?.handle){
+      button?.handle({object:object,dialog:this.dialog,callback:this.onButtonHandleCallBack},that.currentLang)
+    }
   }
   refresh(page?:number){
     if(page){this.pageIndex=page}
@@ -152,4 +167,66 @@ 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();
+  }
+  /**
+   * 选择快捷功能:批量处理
+   */
+  // 批量删除
+   deleteSelected(){
+    confirmDialog(this.dialog,{
+      title:"批量删除",
+      message:"删除后数据不可恢复,请谨慎操作",
+      danger:true,
+      handleOK:async ()=>{
+        let selectedList = this.list.filter(item=>this.setOfCheckedId.has(item?.id))
+        let deletePromiseList = selectedList.map(item=>{
+          return new Promise((resolve=>{
+            item.set("isDeleted",true);
+            item.save();
+          }))
+        })
+        try{
+          await Promise.all(deletePromiseList)
+        }catch(err){}
+        this.refresh();
+      }
+    })
+   }
 }

+ 21 - 0
projects/textbook/src/modules/nav-admin/modules.routes.ts

@@ -1,6 +1,9 @@
 import { NgModule } from "@angular/core";
 import { RouterModule, Routes } from "@angular/router";
+import { PageCollectionComponent } from "./page-collection/page-collection.component";
 import { PageHomeComponent } from './page-home/page-home.component';
+import { PageRoleComponent } from "./page-role/page-role.component";
+import { PageUserComponent } from "./page-user/page-user.component";
 const routes: Routes = [
   {
     path: 'home',
@@ -12,6 +15,24 @@ const routes: Routes = [
       //   pathMatch: "full",
       // },
     ]
+  },
+  {
+    path: 'manage',
+    component: PageHomeComponent,
+    children:[
+      {
+        path: 'user',//列表
+        component: PageUserComponent,
+      },
+      {
+        path: 'role',//列表
+        component: PageRoleComponent,
+      },
+      {
+        path: 'collection',//列表
+        component: PageCollectionComponent,
+      },
+    ]
   }
 ];
 @NgModule({

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

@@ -0,0 +1,32 @@
+
+<!-- 表格头部 -->
+<nz-page-header *ngIf="list?.schema?.title">
+  <!--breadcrumb-->
+  <nz-breadcrumb nz-page-header-breadcrumb>
+    <nz-breadcrumb-item>国家级管理</nz-breadcrumb-item>
+    <nz-breadcrumb-item><a>报送合集</a></nz-breadcrumb-item>
+  </nz-breadcrumb>
+
+  <!--title-->
+  <nz-page-header-title>{{list?.schema?.title}}
+    <br>
+    <div class="subtitle">{{list?.schema?.subTitle}}</div>
+  </nz-page-header-title>
+
+  <!--extra-->
+  <nz-page-header-extra>
+    <nz-space>
+      <button *nzSpaceItem nz-button nzType="primary" (click)="list?.createObject()">创建合集</button>
+    </nz-space>
+  </nz-page-header-extra>
+</nz-page-header>
+
+
+<comp-table-list
+  #list
+  [schema]="EduCollection"
+  *ngIf="className && fieldsArray"
+  [className]="className"
+  [fieldsArray]="fieldsArray"
+  [queryParams]="queryParams"
+></comp-table-list>

+ 10 - 0
projects/textbook/src/modules/nav-admin/page-collection/page-collection.component.scss

@@ -0,0 +1,10 @@
+.subtitle{
+        margin-right: 12px;
+        color: #00000073;
+        font-size: 14px;
+        font-weight: normal;
+        line-height: 1.5715;
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+}

+ 22 - 0
projects/textbook/src/modules/nav-admin/page-collection/page-collection.component.spec.ts

@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+
+import { PageCollectionComponent } from './page-collection.component';
+
+describe('PageCollectionComponent', () => {
+  let component: PageCollectionComponent;
+  let fixture: ComponentFixture<PageCollectionComponent>;
+
+  beforeEach(waitForAsync(() => {
+    TestBed.configureTestingModule({
+      imports: [PageCollectionComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(PageCollectionComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  }));
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 61 - 0
projects/textbook/src/modules/nav-admin/page-collection/page-collection.component.ts

@@ -0,0 +1,61 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { ActivatedRoute, RouterOutlet } from '@angular/router';
+import { CompTableListComponent } from '../../../app/comp-table/comp-table-list/comp-table-list.component';
+import EduCollection from '../../../schemas/EduCollection';
+// import { TranslateService } from '@ngx-translate/core';
+import * as Parse from "parse";
+import { CommonModule } from '@angular/common';
+import { NzTagModule } from 'ng-zorro-antd/tag';
+import { NzButtonModule } from 'ng-zorro-antd/button';
+import { NzIconModule } from 'ng-zorro-antd/icon';
+import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
+import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';
+import { NzSpaceModule } from 'ng-zorro-antd/space';
+import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
+
+
+@Component({
+  selector: 'app-page-collection',
+  templateUrl: './page-collection.component.html',
+  styleUrls: ['./page-collection.component.scss'],
+  imports: [
+    CommonModule,RouterOutlet,CompTableListComponent,
+    NzPageHeaderModule,NzBreadCrumbModule,NzTagModule,NzButtonModule,NzIconModule,NzSpaceModule,
+    NzDropDownModule,
+  ],
+  standalone: true,
+})
+export class PageCollectionComponent  implements OnInit {
+  @ViewChild(CompTableListComponent) list:CompTableListComponent|undefined
+
+  EduCollection = EduCollection
+  className:string|undefined
+  queryParams:any|undefined
+  fieldsArray:Array<any>|undefined
+
+  constructor(
+    private route: ActivatedRoute,
+    private activeRoute: ActivatedRoute,
+    // private translate:TranslateService,
+  ) {
+    this.className = this.EduCollection.className
+    this.fieldsArray = this.EduCollection.fieldsArray
+    this.queryParams = {where:{
+      // Collection:this.Collection?.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.list?.ngOnInit()
+    });
+  }
+
+}

+ 3 - 3
projects/textbook/src/modules/nav-admin/page-home/page-home.component.html

@@ -10,7 +10,7 @@
           <li
             nz-menu-item
             [nzSelected]="active == child.id"
-            (click)="toUrl('/nav-admin', child.id, { category: child.id })"
+            (click)="toUrl(child)"
           >
             {{ child.name }}
           </li>
@@ -20,7 +20,7 @@
       } @else {
       <li
         nz-menu-item
-        (click)="toUrl('/nav-admin', 'list')"
+        (click)="toUrl(item)"
         [nzSelected]="active == item.id"
       >
         <span nz-icon nzType="home" nzTheme="outline"></span>
@@ -29,7 +29,7 @@
       } }
     </ul>
   </div>
-  <div class="proview">
+  <div class="preview">
     <router-outlet></router-outlet>
   </div>
 </div>

+ 1 - 1
projects/textbook/src/modules/nav-admin/page-home/page-home.component.scss

@@ -6,7 +6,7 @@
   .content-left{
     background-color:#fff;
   }
-  .content-rifht{
+  .preview{
     height: 100%;
     overflow-y: scroll;
     padding: 20px 0 40px 0;

+ 19 - 6
projects/textbook/src/modules/nav-admin/page-home/page-home.component.ts

@@ -19,6 +19,7 @@ export class PageHomeComponent  implements OnInit {
       child:[
         {
           name:'报送合集',
+          path:"/nav-admin/manage/collection",
           id:'1-1',
         },
         {
@@ -32,13 +33,19 @@ export class PageHomeComponent  implements OnInit {
       id:'2',
       child:[
         {
-          name:'用户列表',
+          name:'用户审核',
           id:'2-1',
         },
         {
-          name:'用户组管理',
+          name:'注册账户',
+          path:"/nav-admin/manage/user",
           id:'2-2',
         },
+        {
+          name:'用户组管理',
+          path:"/nav-admin/manage/role",
+          id:'2-3',
+        },
       ]
     },
     {
@@ -66,9 +73,15 @@ export class PageHomeComponent  implements OnInit {
   ) { }
 
   ngOnInit() {}
-  toUrl(url:string, cateid:string, params?:any){
-    this.active = cateid
-    localStorage.setItem('active', cateid)
-    // this.router.navigate([url, params ? params : {}])
+  toUrl(child: any) {
+    let cateid = child.id;
+    this.active = cateid;
+    localStorage.setItem('active', cateid);
+    console.log(child);
+    if (child.params) {
+      this.router.navigate([child.path, child?.params]);
+    } else {
+      this.router.navigate([child.path]);
+    }
   }
 }

+ 8 - 0
projects/textbook/src/modules/nav-admin/page-role/page-role.component.html

@@ -0,0 +1,8 @@
+<comp-table-list
+  #list
+  [schema]="_Role"
+  *ngIf="className && fieldsArray"
+  [className]="className"
+  [fieldsArray]="fieldsArray"
+  [queryParams]="queryParams"
+></comp-table-list>

+ 0 - 0
projects/textbook/src/modules/nav-admin/page-role/page-role.component.scss


+ 22 - 0
projects/textbook/src/modules/nav-admin/page-role/page-role.component.spec.ts

@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+
+import { PageRoleComponent } from './page-role.component';
+
+describe('PageRoleComponent', () => {
+  let component: PageRoleComponent;
+  let fixture: ComponentFixture<PageRoleComponent>;
+
+  beforeEach(waitForAsync(() => {
+    TestBed.configureTestingModule({
+      imports: [PageRoleComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(PageRoleComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  }));
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

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

@@ -0,0 +1,52 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { ActivatedRoute, RouterOutlet } from '@angular/router';
+import { CompTableListComponent } from '../../../app/comp-table/comp-table-list/comp-table-list.component';
+import _Role from '../../../schemas/_Role';
+// import { TranslateService } from '@ngx-translate/core';
+import * as Parse from "parse";
+import { CommonModule } from '@angular/common';
+
+
+@Component({
+  selector: 'app-page-role',
+  templateUrl: './page-role.component.html',
+  styleUrls: ['./page-role.component.scss'],
+  imports: [CommonModule,RouterOutlet,CompTableListComponent],
+  standalone: true,
+})
+export class PageRoleComponent  implements OnInit {
+  @ViewChild(CompTableListComponent) list:CompTableListComponent|undefined
+
+  _Role = _Role
+  user:Parse.User|undefined
+  className:string|undefined
+  queryParams:any|undefined
+  fieldsArray:Array<any>|undefined
+
+  constructor(
+    private route: ActivatedRoute,
+    private activeRoute: ActivatedRoute,
+    // private translate:TranslateService,
+  ) {
+    this.user = Parse.User.current();
+    this.className = this._Role.className
+    this.fieldsArray = this._Role.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.list?.ngOnInit()
+    });
+  }
+
+}

+ 8 - 0
projects/textbook/src/modules/nav-admin/page-user/page-user.component.html

@@ -0,0 +1,8 @@
+<comp-table-list
+  #list
+  [schema]="_User"
+  *ngIf="className && fieldsArray"
+  [className]="className"
+  [fieldsArray]="fieldsArray"
+  [queryParams]="queryParams"
+></comp-table-list>

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


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

@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+
+import { PageUserComponent } from './page-user.component';
+
+describe('PageUserComponent', () => {
+  let component: PageUserComponent;
+  let fixture: ComponentFixture<PageUserComponent>;
+
+  beforeEach(waitForAsync(() => {
+    TestBed.configureTestingModule({
+      imports: [PageUserComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(PageUserComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  }));
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 52 - 0
projects/textbook/src/modules/nav-admin/page-user/page-user.component.ts

@@ -0,0 +1,52 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { ActivatedRoute, RouterOutlet } from '@angular/router';
+import { CompTableListComponent } from '../../../app/comp-table/comp-table-list/comp-table-list.component';
+import _User from '../../../schemas/_User';
+// import { TranslateService } from '@ngx-translate/core';
+import * as Parse from "parse";
+import { CommonModule } from '@angular/common';
+
+
+@Component({
+  selector: 'app-page-user',
+  templateUrl: './page-user.component.html',
+  styleUrls: ['./page-user.component.scss'],
+  imports: [CommonModule,RouterOutlet,CompTableListComponent],
+  standalone: true,
+})
+export class PageUserComponent  implements OnInit {
+  @ViewChild(CompTableListComponent) list:CompTableListComponent|undefined
+
+  _User = _User
+  user:Parse.User|undefined
+  className:string|undefined
+  queryParams:any|undefined
+  fieldsArray:Array<any>|undefined
+
+  constructor(
+    private route: ActivatedRoute,
+    private activeRoute: ActivatedRoute,
+    // private translate:TranslateService,
+  ) {
+    this.user = Parse.User.current();
+    this.className = this._User.className
+    this.fieldsArray = this._User.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.list?.ngOnInit()
+    });
+  }
+
+}

+ 1 - 3
projects/textbook/src/modules/nav-author/page-home/page-home.component.scss

@@ -32,9 +32,7 @@
     background-color: white;
     border-radius: 10px;
   }
-  .proview{
-    flex: 1;
-  }
+
 }
 ::ng-deep .ant-menu-sub.ant-menu-inline{
   background: #f9eaea;

+ 63 - 0
projects/textbook/src/schemas/EduCollection.ts

@@ -0,0 +1,63 @@
+import { MatDialog } from "@angular/material/dialog";
+import { openObjectEditDialog, ParseSchema } from "./func-parse";
+
+
+const EduCollection:ParseSchema = {
+    "title":"报送合集",
+    "subTitle":"创建报送合集,分配合集管理员,统一管理各地区的教材推荐报送流程和配额。",
+    "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
+            },
+            handle:(options:{dialog:MatDialog,object:Parse.Object})=>{
+                openObjectEditDialog(options?.dialog,EduCollection,options?.object)
+            }
+        },
+    ]
+    };
+    
+    export default EduCollection;

+ 5 - 18
projects/textbook/src/schemas/EduTextbook.ts

@@ -1,26 +1,13 @@
 import { MatDialog } from "@angular/material/dialog";
 import Parse from "parse";
+import { ParseSchema } from "./func-parse";
 
-export const EduTextbook = {
+export const EduTextbook:ParseSchema = {
+    title:"教材",
     className:"EduTextbook",
+    emptyImg:"/img/webhook-empty.png",
     include:["user"],
     buttons:[
-        // 行内操作
-        {
-            name:"绑定",
-            place:"item",
-            show:(options:{object:Parse.Object})=>{
-                if(options?.object?.get("type")=="unit") {return true} else return false
-            },
-            handle:(options:{dialog:MatDialog,object:Parse.Object,callback:any})=>{
-                // options?.clusterServ?.openMinerDialog(options?.dialog,options?.object)
-                console.log(options?.object.toJSON())
-                console.log(options)
-                if(options?.callback){
-                    options?.callback(options?.object)
-                }
-            }
-        },
         {
             name:"编辑",
             place:"item",
@@ -35,6 +22,6 @@ export const EduTextbook = {
     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}"},
     ]
 }

+ 42 - 0
projects/textbook/src/schemas/_Role.ts

@@ -0,0 +1,42 @@
+import { MatDialog } from "@angular/material/dialog";
+import { openObjectEditDialog, ParseSchema } from "./func-parse";
+
+
+    const _Role:ParseSchema = {
+        "title":"用户组",
+        "className": "_Role",
+        emptyImg:"/img/group-empty.png",
+        "fieldsArray": [
+            {
+                "key":"title",
+                "name":"用户组名称",
+                "type": "String",
+                isHeader:true
+            },
+            {
+                "key":"name",
+                "name":"用户组标识",
+                "type": "String",
+                isHeader:true
+            },
+            {
+                "key":"desc",
+                "name":"描述",
+                "type": "String"
+            },
+        ],
+        buttons:[
+            {
+                name:"编辑",
+                place:"item",
+                show:(options:{object:Parse.Object})=>{
+                    return true
+                },
+                handle:(options:{dialog:MatDialog,object:Parse.Object})=>{
+                    openObjectEditDialog(options?.dialog,_Role,options?.object)
+                }
+            },
+        ]
+      };
+      
+      export default _Role;

+ 62 - 0
projects/textbook/src/schemas/_User.ts

@@ -0,0 +1,62 @@
+import { MatDialog } from "@angular/material/dialog";
+import { openObjectEditDialog, ParseSchema } from "./func-parse";
+
+
+    const _User:ParseSchema = {
+        "title":"注册帐号",
+        "className": "_User",
+        emptyImg:"/img/group-empty.png",
+        "fieldsArray": [
+            // {
+            //     "key":"avatar",
+            //     "name":"用户头像",
+            //     "type": "String",
+            //     isHeader:true
+            // },
+            {
+                "key":"username",
+                "name":"用户帐号",
+                "type": "String",
+                isDisabled:true,
+                isHeader:true
+            },
+            {
+                "key":"name",
+                "name":"用户姓名",
+                "type": "String",
+                isHeader:true
+            },
+            {
+                "key":"mobile",
+                "name":"手机号",
+                "type": "String",
+                isHeader:true
+            },
+            {
+                "key":"email",
+                "name":"邮箱帐号",
+                "type": "String",
+                isHeader:true
+            },
+
+            // {
+            //     "key":"desc",
+            //     "name":"描述",
+            //     "type": "String"
+            // },
+        ],
+        buttons:[
+            {
+                name:"编辑",
+                place:"item",
+                show:(options:{object:Parse.Object})=>{
+                    return true
+                },
+                handle:(options:{dialog:MatDialog,object:Parse.Object})=>{
+                    openObjectEditDialog(options?.dialog,_User,options?.object)
+                }
+            },
+        ]
+      };
+      
+      export default _User;

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

@@ -0,0 +1,76 @@
+import { MatDialog } from "@angular/material/dialog";
+import { CompComfirmDialogComponent } from "../app/comp-comfirm-dialog/comp-comfirm-dialog.component";
+import { CompEditObjectComponent } from "../app/comp-table/comp-edit-object/comp-edit-object.component";
+
+
+export interface ParseSchema{
+    title:string,
+    subTitle?:string,
+    className:string,
+    fieldsArray:Array<ParseField>,
+    include?:Array<string>,
+    buttons?:Array<any>,
+    emptyImg?:String,
+    emptyDesc?:String,
+}
+export interface ParseField{
+  key:string
+  name:string
+  type:string
+  isDisabled?:boolean
+  targetClass?:string
+  showName?:string
+  isHeader?:boolean
+  options?:Array<ParseFiledOption>
+}
+export interface ParseFiledOption{
+  label:string
+  value:string
+}
+
+/**
+   * 创建集装箱
+   * @param dialog 
+   * @param cluster 
+   * @param afterClosed 
+   */
+ export function openObjectEditDialog(dialog: MatDialog,schema:ParseSchema, object?: Parse.Object, afterClosed?: Function): void {
+    let dialogRef = dialog.open(CompEditObjectComponent, {
+      data: {
+        title: schema?.title,
+        fieldsArray: schema?.fieldsArray,
+        default: {
+        //   center: this.center?.toPointer(),
+        //   type: "cluster",
+        //   isOnline: true,
+        },
+        schema:schema,
+        object: object,
+      },
+    });
+
+    dialogRef.afterClosed().subscribe(result => {
+      console.log('The dialog was closed', result);
+      afterClosed && afterClosed(result)
+    });
+  }
+  export function confirmDialog(dialog:MatDialog, options: {
+    title: string,
+    mode?: string,
+    danger?: boolean,
+    message?: string,
+    handleOK?: Function
+  }) {
+    let dialogRef = dialog.open(CompComfirmDialogComponent, {
+      data: {
+        title: options?.title,
+        message: options?.message,
+        mode: options?.mode,
+        danger: options?.danger,
+      },
+    });
+
+    dialogRef.afterClosed().subscribe(isOK => {
+      isOK && options?.handleOK && options?.handleOK()
+    });
+  }

+ 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;
 /**

+ 20 - 0
server/db/data/init-data.sql

@@ -16,3 +16,23 @@ SET
 "company" = excluded."company",
 "createdAt"=excluded."createdAt",
 "updatedAt"=excluded."updatedAt";
+
+-- 初始化超级管理员角色
+INSERT INTO "_Role" ("objectId","title", "name", "_rperm", "_wperm", "company", "createdAt", "updatedAt")
+VALUES
+('ZQOwyoDteL','超级管理员', 'superadmin','{*,BOOKADMINI}','{BOOKADMINI}','RbIKpmuaMC','2024-06-16 12:00:00','2024-06-16 12:00:00')
+ON conflict("objectId") DO UPDATE
+SET 
+"title" = excluded."title",
+"name" = excluded."name",
+"company" = excluded."company",
+"createdAt"=excluded."createdAt";
+
+-- 超级管理员帐号,添加至超管用户组
+INSERT INTO "_Join:users:_Role" ("relatedId", "owningId")
+VALUES
+('BOOKADMINI', 'ZQOwyoDteL')
+ON conflict("relatedId","owningId") DO UPDATE
+SET 
+"relatedId" = excluded."relatedId",
+"owningId" = excluded."owningId";

+ 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

+ 3 - 0
server/db/schemas/_Role.js

@@ -1,6 +1,9 @@
 const _Role = {
     "className": "_Role",
     "fields": {
+        "title": {
+            "type": "String"
+        },
         "name": {
             "type": "String"
         },

+ 6 - 0
server/db/schemas/_User.js

@@ -1,9 +1,15 @@
 const _User = {
     "className": "_User",
     "fields": {
+        "avatar": {
+            "type": "String"
+        },
         "name": {
             "type": "String"
         },
+        "mobile": {
+            "type": "String"
+        },
     }
 }
 module.exports._User = _User

Some files were not shown because too many files changed in this diff