Browse Source

高校管理员 工作联系人

warrior 8 months ago
parent
commit
fa6325298c
52 changed files with 2641 additions and 314 deletions
  1. 1 1
      projects/textbook/src/app/app.routes.ts
  2. 25 23
      projects/textbook/src/app/comp-manage/comp-manage.component.ts
  3. 140 0
      projects/textbook/src/app/textbook/textbook.component.html
  4. 59 0
      projects/textbook/src/app/textbook/textbook.component.scss
  5. 24 0
      projects/textbook/src/app/textbook/textbook.component.spec.ts
  6. 142 0
      projects/textbook/src/app/textbook/textbook.component.ts
  7. 2 1
      projects/textbook/src/modules/login/account-info/account-info.component.ts
  8. 2 0
      projects/textbook/src/modules/nav-admin/components/profile/profile.component.html
  9. 2 1
      projects/textbook/src/modules/nav-admin/components/profile/profile.component.ts
  10. 3 2
      projects/textbook/src/modules/nav-admin/page-process/page-process.component.html
  11. 3 1
      projects/textbook/src/modules/nav-admin/page-process/page-process.component.ts
  12. 11 1
      projects/textbook/src/modules/nav-admin/page-process/process-create/process-create.component.ts
  13. 15 20
      projects/textbook/src/modules/nav-admin/page-process/process-list/process-list.component.html
  14. 7 1
      projects/textbook/src/modules/nav-admin/page-process/process-list/process-list.component.scss
  15. 5 27
      projects/textbook/src/modules/nav-admin/page-process/process-list/process-list.component.ts
  16. 24 3
      projects/textbook/src/modules/nav-admin/page-role/page-role.component.html
  17. 6 0
      projects/textbook/src/modules/nav-admin/page-role/page-role.component.scss
  18. 8 2
      projects/textbook/src/modules/nav-admin/page-role/page-role.component.ts
  19. 5 2
      projects/textbook/src/modules/nav-admin/page-textbook/page-textbook.component.html
  20. 4 0
      projects/textbook/src/modules/nav-admin/page-textbook/page-textbook.component.scss
  21. 12 5
      projects/textbook/src/modules/nav-admin/page-textbook/page-textbook.component.ts
  22. 3 3
      projects/textbook/src/modules/nav-admin/page-user/page-user.component.html
  23. 7 1
      projects/textbook/src/modules/nav-admin/page-user/page-user.component.scss
  24. 12 6
      projects/textbook/src/modules/nav-admin/page-user/page-user.component.ts
  25. 4 2
      projects/textbook/src/modules/nav-author/space/space.component.html
  26. 9 3
      projects/textbook/src/modules/nav-author/space/space.component.ts
  27. 23 3
      projects/textbook/src/modules/nav-province-contact/modules.routes.ts
  28. 0 35
      projects/textbook/src/modules/nav-province-contact/page-collection/page-collection.component.html
  29. 0 10
      projects/textbook/src/modules/nav-province-contact/page-collection/page-collection.component.scss
  30. 0 61
      projects/textbook/src/modules/nav-province-contact/page-collection/page-collection.component.ts
  31. 16 39
      projects/textbook/src/modules/nav-province-contact/page-process/page-process.component.html
  32. 16 8
      projects/textbook/src/modules/nav-province-contact/page-process/page-process.component.scss
  33. 17 30
      projects/textbook/src/modules/nav-province-contact/page-process/page-process.component.ts
  34. 254 0
      projects/textbook/src/modules/nav-province-contact/page-process/process-create/process-create.component.html
  35. 144 0
      projects/textbook/src/modules/nav-province-contact/page-process/process-create/process-create.component.scss
  36. 24 0
      projects/textbook/src/modules/nav-province-contact/page-process/process-create/process-create.component.spec.ts
  37. 66 0
      projects/textbook/src/modules/nav-province-contact/page-process/process-create/process-create.component.ts
  38. 223 0
      projects/textbook/src/modules/nav-province-contact/page-process/process-list/process-list.component.html
  39. 173 0
      projects/textbook/src/modules/nav-province-contact/page-process/process-list/process-list.component.scss
  40. 24 0
      projects/textbook/src/modules/nav-province-contact/page-process/process-list/process-list.component.spec.ts
  41. 311 0
      projects/textbook/src/modules/nav-province-contact/page-process/process-list/process-list.component.ts
  42. 304 0
      projects/textbook/src/modules/nav-province-contact/page-role/page-role.component.html
  43. 118 0
      projects/textbook/src/modules/nav-province-contact/page-role/page-role.component.scss
  44. 6 6
      projects/textbook/src/modules/nav-province-contact/page-role/page-role.component.spec.ts
  45. 335 0
      projects/textbook/src/modules/nav-province-contact/page-role/page-role.component.ts
  46. 6 3
      projects/textbook/src/modules/nav-province-contact/page-textbook/page-textbook.component.html
  47. 4 0
      projects/textbook/src/modules/nav-province-contact/page-textbook/page-textbook.component.scss
  48. 16 12
      projects/textbook/src/modules/nav-province-contact/page-textbook/page-textbook.component.ts
  49. 17 0
      projects/textbook/src/modules/nav-province-school-contact/modules.routes.ts
  50. 2 1
      projects/textbook/src/services/auth.service.ts
  51. 3 1
      projects/textbook/src/services/common.modules.ts
  52. 4 0
      server/db/schemas/EduTextbook.js

+ 1 - 1
projects/textbook/src/app/app.routes.ts

@@ -22,7 +22,7 @@ export const routes: Routes = [
   },
 
   {
-    path: 'nav-province-contact',//报送联系人:中央部门所属高校联系人、部省合建高校联系人、出版单位联系人、省属高校流程管理员
+    path: 'nav-province-contact',//工作联系人:中央部门所属高校联系人、部省合建高校联系人、出版单位联系人、省属高校流程管理员
     component: CompManageComponent,
     canActivate: mapToCanActivate([AuthGuard]),
     loadChildren: () =>import('../modules/nav-province-contact/modules.routes').then((mod) => mod.NavProContactRoutingModule),

+ 25 - 23
projects/textbook/src/app/comp-manage/comp-manage.component.ts

@@ -76,54 +76,56 @@ export class CompManageComponent implements OnInit {
       //   id:'4',
       // },
     ],
-    "报送联系人":[
+    "工作联系人":[
       {
-        name:'教材管理',
+        name:'教材申报',
         id:'1',
         child:[
           {
             name:'申报流程',
-            path:'/nav-province-contact/manage/process',
+            path:"/nav-province-contact/manage/process",
             id:'1-1',
           },
           {
             name:'全部教材',
-            path:"/nav-province-contact/manage/textbook",
+            path:'/nav-province-contact/manage/textbook',
             id:'1-2',
           },
         ]
       },
-    ],
-    "高校联系人":[
-      {
-        name:'教材管理',
-        id:'1',
-        child:[
-          {
-            name:'报送合集',
-            path:'/nav-province-school-contact/manage/collection',
-            id:'1-1',
-          },
-        ]
-      },
       {
         name:'用户管理',
         id:'2',
         child:[
           {
             name:'用户列表',
+            path:"/nav-province-contact/manage/user",
             id:'2-1',
           },
           {
-            name:'用户组管理',
-            id:'2-2',
-          },
-          {
-            name:'邀请注册',
+            name:'申报单位管理',
+            path:"/nav-province-contact/manage/role",
             id:'2-3',
           },
         ]
-      }
+      },
+    ],
+    "高校联系人":[
+      {
+        id:'1',
+        name:'全部教材',
+        path:'/nav-province-school-contact/manage/textbook',
+      },
+      {
+        name:'申报单位管理',
+        path:"/nav-province-school-contact/manage/role",
+        id:'2',
+      },
+      {
+        name:'个人空间',
+        id:'3',
+        path: '/nav-province-school-contact/manage/space',
+      },
     ],
     "评审专家":[
       {

+ 140 - 0
projects/textbook/src/app/textbook/textbook.component.html

@@ -0,0 +1,140 @@
+<div class="textbook-table">
+  <div class="tool">
+     <div class="search">
+        <nz-input-group style="width: 280px" [nzPrefix]="prefixTemplateUser">
+          <input
+            type="text"
+            nz-input
+            placeholder="输入教材名称 / ISBN / 作者名搜索"
+            [(ngModel)]="searchValue"
+            (ngModelChange)="onSearch($event)"
+          />
+        </nz-input-group>
+        <ng-template #prefixTemplateUser
+          ><span nz-icon nzType="search"></span
+        ></ng-template>
+      </div>
+  </div>
+  <nz-table
+    #tableData
+    [nzData]="textbookList"
+    [nzTotal]="textbookList.length"
+    [nzPageSize]="10"
+    style="margin: 10px 0"
+    [nzLoading]="loading"
+    nzSize="middle"
+    [nzNoResult]="emptyResult"
+    nzTableLayout="fixed"
+  >
+    <thead>
+      <tr>
+        <th
+          nzWidth="50px"
+          nzLeft
+          [nzChecked]="checkedAll"
+          [nzIndeterminate]="false"
+          nzLabel="Select all"
+          (nzCheckedChange)="onAllChecked($event)"
+        ></th>
+        <th nzEllipsis nzWidth="50px" nzLeft>申报编号</th>
+        <th nzEllipsis nzWidth="120px">教材名称</th>
+        <th nzEllipsis nzWidth="50px">册数</th>
+        <th nzEllipsis nzWidth="80px">第一主编/作者</th>
+        <th nzEllipsis nzWidth="120px">所属本科专业</th>
+        <th nzEllipsis nzWidth="80px">主要语种类型</th>
+        <th nzEllipsis nzWidth="50px" nzRight>操作</th>
+      </tr>
+    </thead>
+    <tbody>
+      @for (data of textbookList; track data.id) {
+      <tr>
+        <td nzEllipsis
+          nzLeft
+          [nzChecked]="setOfCheckedId.has(data.id)"
+          (nzCheckedChange)="onItemChecked(data.id, $event)"
+        ></td>
+        <td nzEllipsis
+          nzLeft
+          nzEllipsis
+          class="activeTd"
+        >
+          {{ data?.get('ISBN') || "-" }}
+        </td>
+        <td nzEllipsis>
+          {{ data?.get('title') || "-" }}
+        </td>
+        <td nzEllipsis>
+          {{ data?.get('type') == '单册' ? '单册' : data?.get('typeNumber') || "-"  }}
+        </td>
+        <td nzEllipsis>
+          {{ data?.get('author') || "-" }}
+        </td>
+        <td nzEllipsis>
+          {{ data?.get('major').name || "-" }}
+        </td>
+        <td nzEllipsis>
+          {{ data?.get('lang') || "-" }}
+        </td>
+        <td nzEllipsis 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>
+              <li nz-menu-item>
+                <button
+                  nz-button
+                  nzType="link"
+                  style="color: #231c1f"
+                >
+                  <span
+                    nz-icon
+                    nzType="caret-right"
+                    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>
+<!-- 全选操作:批量操作 -->
+@if (setOfCheckedId.size) {
+  <div class="batch-toolbar-modal">
+    <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>
+  
+}

+ 59 - 0
projects/textbook/src/app/textbook/textbook.component.scss

@@ -0,0 +1,59 @@
+.activeTd{
+  cursor: pointer;
+}
+.activeTd:hover{
+  color: #c6233f;
+}
+// 选中,批量操作区域
+.batch-toolbar-modal{
+  position: fixed;
+  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;
+}

+ 24 - 0
projects/textbook/src/app/textbook/textbook.component.spec.ts

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

+ 142 - 0
projects/textbook/src/app/textbook/textbook.component.ts

@@ -0,0 +1,142 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { CommonCompModule } from '../../services/common.modules';
+import { Router, ActivatedRoute } from '@angular/router';
+import Parse from 'parse';
+import { textbookServer } from '../../services/textbook';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import { NzModalService } from 'ng-zorro-antd/modal';
+import { MatButtonModule } from '@angular/material/button';
+import { NzRadioModule } from 'ng-zorro-antd/radio';
+import { DatePipe } from '@angular/common';
+import { NzEmptyModule } from 'ng-zorro-antd/empty';
+
+@Component({
+  selector: 'app-textbook',
+  templateUrl: './textbook.component.html',
+  styleUrls: ['./textbook.component.scss'],
+  imports: [
+    CommonCompModule,
+    FormsModule,
+    ReactiveFormsModule,
+    MatButtonModule,
+    NzRadioModule,
+    DatePipe,
+    NzEmptyModule,
+  ],
+  standalone: true,
+})
+export class TextbookComponent implements OnInit {
+  textbookList: Array<Parse.Object> = [];
+  @Input('maxWidth') maxWidth: any; //最大宽度
+  @Input('depart') depart: any; //指定申报单位
+  @Input('recommend') recommend: any; //是否推荐
+  @Input('uid') uid: string = ''; //个人空间
+
+  loading: boolean = false;
+  checkedAll: boolean = false; //全选
+  setOfCheckedId = new Set<string>();
+  searchValue: string = '';
+
+  constructor(
+    public tbookSer: textbookServer,
+    private route: Router,
+    private activeRoute: ActivatedRoute,
+    private message: NzMessageService,
+    private modal: NzModalService
+  ) {}
+
+  ngOnInit() {
+    this.getTextbook();
+  }
+  async getTextbook(val?: string) {
+    this.loading = true;
+    let query = new Parse.Query('EduTextbook');
+    if (val) {
+      let query1 = Parse.Query.fromJSON('EduTextbook', {
+        where: {
+          $or: [
+            {
+              title: { $regex: `.*${val}.*` },
+            },
+          ],
+        },
+      });
+      let query2 = Parse.Query.fromJSON('EduTextbook', {
+        where: {
+          $or: [
+            {
+              ISBN: { $regex: `.*${val}.*` },
+            },
+          ],
+        },
+      });
+      query = Parse.Query.or(query1, query2);
+    }
+    if (this.tbookSer.profile.user.department.objectId) {
+      query.equalTo(
+        'department',
+        this.tbookSer.profile.user.department.objectId
+      );
+    }
+    this.depart && query.equalTo('department', this.depart);
+    this.recommend && query.equalTo('recommend', true);
+    this.uid && query.equalTo('user', this.uid);
+    query.notEqualTo('isDeleted', true);
+    this.textbookList = await query.find();
+    console.log(this.textbookList);
+    this.loading = false;
+  }
+  onSearch(e: string) {
+    console.log(e);
+    this.getTextbook(e);
+  }
+  //全选
+  onAllChecked(checked: boolean) {
+    console.log(checked);
+    this.textbookList.forEach((item: any) => {
+      if (checked) {
+        this.setOfCheckedId.add(item.id);
+      } else {
+        this.setOfCheckedId.delete(item.id);
+      }
+    });
+    this.checkedAll = checked;
+  }
+  //单选
+  onItemChecked(id: string, e: boolean) {
+    if (e) {
+      this.setOfCheckedId.add(id);
+    } else {
+      this.setOfCheckedId.delete(id);
+    }
+    this.checkedAll = this.textbookList.every((item) =>
+      this.setOfCheckedId.has(item.id)
+    );
+  }
+  deleteSelected() {
+    this.modal.confirm({
+      nzTitle: '批量删除',
+      nzContent: `删除后数据不可恢复,请谨慎操作`,
+      nzOkText: '确认',
+      nzOkType: 'primary',
+      nzOkDanger: true,
+      nzOnOk: async () => {
+        let selectedList = this.textbookList.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'),
+    });
+  }
+}

+ 2 - 1
projects/textbook/src/modules/login/account-info/account-info.component.ts

@@ -65,7 +65,7 @@ export class AccountInfoComponent implements OnInit {
   provinces: Array<string> = provinces.options; //省份
   unitTypes: Array<any> = [];
   companys: Array<any> = [];
-  userType: Array<string> = ['报送联系人', '评审专家', '高校联系人', '个人'];
+  userType: Array<string> = ['工作联系人', '评审专家', '高校联系人', '个人'];
 
   constructor(
     public tbookSer: textbookServer,
@@ -128,6 +128,7 @@ export class AccountInfoComponent implements OnInit {
     if (isChange) this.companyId = '';
     this.companys = [];
     let parent = this.unitTypes.find(item=>item.name == this.validateForm.value.companyType)
+    console.log(parent);
     let query = new Parse.Query('Department');
     // query.equalTo('branch', this.validateForm.value.companyType);
     query.equalTo('parent', parent.id);

+ 2 - 0
projects/textbook/src/modules/nav-admin/components/profile/profile.component.html

@@ -43,6 +43,7 @@
         {{ data?.get("user").get("departmentName") || "-" }}
       </td>
       <td nzEllipsis nzRight>
+        @if (hideBtn) { - } @else {
         <button
           nz-button
           nz-dropdown
@@ -76,6 +77,7 @@
             </li>
           </ul>
         </nz-dropdown-menu>
+        }
       </td>
     </tr>
     }

+ 2 - 1
projects/textbook/src/modules/nav-admin/components/profile/profile.component.ts

@@ -21,7 +21,8 @@ export class ProfileComponent  implements OnInit {
   @Input('idList') idList:Array<string> = [] //已指向id
   @Input('identity') identity:any //指定身份类型
   @Input('depart') depart:any //指定单位
-  @Input('disabled') disabled:boolean = false //禁止编辑
+  @Input('disabled') disabled:boolean = false //只查询传入id
+  @Input('hideBtn') hideBtn:boolean = false//隐藏编辑
 
   @Output() change: EventEmitter<any> = new EventEmitter<any>();
 

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

@@ -20,14 +20,15 @@
     </nz-tab>
     <nz-tab nzTitle="教材列表">
       @if (active == 1) {
-      <comp-table-list
+      <!-- <comp-table-list
         #list
         [schema]="EduTextbook"
         *ngIf="className && fieldsArray"
         [className]="className"
         [fieldsArray]="fieldsArray"
         [queryParams]="queryParams"
-      ></comp-table-list>
+      ></comp-table-list> -->
+      <app-textbook [depart]="eduProcess?.get('department')?.id"></app-textbook>
       }
     </nz-tab>
   </nz-tabset>

+ 3 - 1
projects/textbook/src/modules/nav-admin/page-process/page-process.component.ts

@@ -8,6 +8,7 @@ import Parse from 'parse';
 import { EduTextbook } from '../../../schemas/EduTextbook';
 import { CompTableListComponent } from '../../../app/comp-table/comp-table-list/comp-table-list.component';
 import { ProcessCreateComponent } from './process-create/process-create.component';
+import { TextbookComponent } from '../../../app/textbook/textbook.component';
 
 @Component({
   selector: 'app-page-process',
@@ -19,7 +20,8 @@ import { ProcessCreateComponent } from './process-create/process-create.componen
     CommonCompModule,
     NzTabsModule,
     ProcessCreateComponent,
-    CompTableListComponent
+    CompTableListComponent,
+    TextbookComponent,
   ],
   standalone: true,
 })

+ 11 - 1
projects/textbook/src/modules/nav-admin/page-process/process-create/process-create.component.ts

@@ -246,6 +246,10 @@ export class ProcessCreateComponent implements OnInit {
   }
   //选择联系人
   onShowCheck() {
+    if(!this.eduProcess?.get('department')?.id){
+      this.msg.error('请先选择申报单位')
+      return
+    }
     if(this.profileId)return
     this.showProfileFrom = true;
   }
@@ -272,7 +276,7 @@ export class ProcessCreateComponent implements OnInit {
       },
     };
     let query = Parse.Query.fromJSON('Profile', queryParams);
-    query.equalTo('identity', '报送联系人');
+    query.equalTo('identity', '工作联系人');
     query.notEqualTo('isDeleted', true);
     query.select('user');
     let r = await query.first();
@@ -295,6 +299,11 @@ export class ProcessCreateComponent implements OnInit {
         : null
     );
     await this.eduProcess?.save();
+    if(this.profileId){
+      this.msg.success('成功设置联系人')
+    }else{
+      this.msg.success('已删除联系人,请重新选择')
+    }
     this.showProfileFrom = false
   }
   onCheck(e: any) {
@@ -323,6 +332,7 @@ export class ProcessCreateComponent implements OnInit {
       });
     await this.eduProcess?.save();
     this.ngOnInit();
+    this.msg.success('申报单位设置成功')
     this.isVisible = false;
   }
 }

+ 15 - 20
projects/textbook/src/modules/nav-admin/page-process/process-list/process-list.component.html

@@ -76,7 +76,7 @@
         </nz-dropdown-menu>
       </div>
       <div class="">
-        <nz-input-group style="width: 280px" [nzPrefix]="prefixTemplateUser">
+        <nz-input-group style="width: 210px" [nzPrefix]="prefixTemplateUser">
           <input
             type="text"
             nz-input
@@ -124,10 +124,10 @@
             <th nzWidth="120px" nzLeft>流程名称</th>
             <th nzWidth="120px">流程code</th>
             <th nzWidth="120px">流程描述</th>
-            <th nzWidth="120px">申报限额</th>
+            <th nzWidth="80px">申报限额</th>
             <th nzWidth="120px">流程联系人</th>
-            <th nzWidth="120px">流程状态</th>
-            <th nzWidth="80px" nzRight>操作</th>
+            <th nzWidth="80px">流程状态</th>
+            <th nzWidth="50px" nzRight>操作</th>
           </tr>
         </thead>
         <tbody>
@@ -138,8 +138,17 @@
               [nzChecked]="data.checked"
               (nzCheckedChange)="onItemChecked(data.objectId, $event)"
             ></td>
-            <td nzLeft>
-              {{ data?.name || '-' }}
+            <td
+              nzLeft
+              nzEllipsis
+              (click)="
+                toUrl('/nav-admin/manage/process/page', {
+                  id: data?.objectId
+                })
+              "
+              class="activeTd"
+            >
+              {{ data?.name || "-" }}
             </td>
             <td>
               {{ data?.code || '-' }}
@@ -215,20 +224,6 @@
                       </button>
                     </li>
                   }
-                  <li nz-menu-item>
-                    <button
-                      (click)="
-                        toUrl('/nav-admin/manage/process/page', {
-                          id: data?.objectId
-                        })
-                      "
-                      nz-button
-                      nzType="link"
-                      style="color: #231c1f"
-                    >
-                    <span nz-icon nzType="pic-right" nzTheme="outline"></span>流程详情
-                    </button>
-                  </li>
                 </ul>
               </nz-dropdown-menu>
             </td>

+ 7 - 1
projects/textbook/src/modules/nav-admin/page-process/process-list/process-list.component.scss

@@ -64,6 +64,12 @@
     }
     .breadcrumb{
       flex: 1;
+      .activeTd{
+        cursor: pointer;
+      }
+      .activeTd:hover{
+        color: #c6233f;
+      }
     }
   }
 }
@@ -90,7 +96,7 @@
 }
 // 选中,批量操作区域
 .batch-toolbar-modal{
-  position: absolute;
+  position: fixed;
   display: flex;
   justify-content: center;
   bottom: 80px;

+ 5 - 27
projects/textbook/src/modules/nav-admin/page-process/process-list/process-list.component.ts

@@ -218,31 +218,7 @@ export class ProcessListComponent implements OnInit {
   async getProfile() {
     this.eduProcessList = [];
     this.loading = true;
-    let queryParams = {
-      where: {
-        $or: [
-          {
-            branch: { $eq: this.currentDepart.key },
-          },
-          // {
-          //   user: {
-          //     $inQuery: {
-          //       where: {
-          //         $or: [
-          //           {
-          //             eduCollection: { $eq: this.currentDepart.key },
-          //           },
-          //         ],
-          //       },
-          //       className: '_User',
-          //     },
-          //   },
-          // },
-        ],
-      },
-    };
-    let query1 = Parse.Query.fromJSON('EduProcess', queryParams);
-    let query2= Parse.Query.fromJSON('EduProcess', {
+    let query1= Parse.Query.fromJSON('EduProcess', {
       where: {
         $or: [
           {
@@ -251,7 +227,7 @@ export class ProcessListComponent implements OnInit {
         ]
       }
     });
-    let query3= Parse.Query.fromJSON('EduProcess', {
+    let query2= Parse.Query.fromJSON('EduProcess', {
       where: {
         $or: [
           {
@@ -260,8 +236,10 @@ export class ProcessListComponent implements OnInit {
         ]
       }
     });
-    let query = Parse.Query.and(query1,Parse.Query.or(query2, query3));
+    let query = Parse.Query.or(query1, query2)
     query.include('profileSubmitted', 'profileSubmitted.user');
+    query.notEqualTo('isDeleted', true);
+    query.equalTo('branch',this.currentDepart.key)
     let r = await query.find();
     let list: any[] = [];
     r.forEach((item) => {

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

@@ -159,7 +159,13 @@
               [nzChecked]="data.checked"
               (nzCheckedChange)="onItemChecked(data.objectId, $event)"
             ></td>
-            <td nzLeft>
+            <td
+              nzLeft
+              nzEllipsis
+              (click)="goDateil(data.user?.objectId)"
+              class="activeTd"
+            >
+              <nz-avatar nzIcon="user"></nz-avatar>
               {{ data?.user.name }}
             </td>
             <td>
@@ -175,9 +181,24 @@
               {{ data?.user.departmentName }}
             </td>
             <td nzRight>
-              <button nz-button nzType="default">
-                <span nz-icon nzType="stop" nzTheme="outline"></span>移除部门
+              <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>
+                  <li nz-menu-item>
+                    <button nz-button style="color: #231c1f" nzType="link">
+                      <span nz-icon nzType="stop" nzTheme="outline"></span
+                      >移除部门
+                    </button>
+                  </li>
+                </ul>
+              </nz-dropdown-menu>
             </td>
           </tr>
           }

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

@@ -66,6 +66,12 @@
       flex: 1;
     }
   }
+  .activeTd{
+    cursor: pointer;
+  }
+  .activeTd:hover{
+    color: #c6233f;
+  }
 }
 .depart-modal{
   .row{

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

@@ -1,5 +1,5 @@
 import { Component, OnInit, ViewChild } from '@angular/core';
-import { ActivatedRoute, RouterOutlet } from '@angular/router';
+import { ActivatedRoute, Route, Router, 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';
@@ -94,7 +94,7 @@ export class PageRoleComponent implements OnInit {
   parentList: Array<any> = [];
 
   constructor(
-    private route: ActivatedRoute,
+    private route: Router,
     private activeRoute: ActivatedRoute,
     private nzContextMenuService: NzContextMenuService,
     private message: NzMessageService,
@@ -311,4 +311,10 @@ export class PageRoleComponent implements OnInit {
   showModalOrganize(){
     this.message.warning('权限灰度中')
   }
+  goDateil(id:string){
+    this.route.navigate([
+      '/nav-admin/manage/user/edit',
+      { id:id },
+    ])
+  }
 }

+ 5 - 2
projects/textbook/src/modules/nav-admin/page-textbook/page-textbook.component.html

@@ -4,11 +4,14 @@
     <nz-breadcrumb-item><a>报送合集</a></nz-breadcrumb-item>
   </nz-breadcrumb>
 </nz-page-header>
-<comp-table-list
+<!-- <comp-table-list
   #list
   [schema]="EduTextbook"
   *ngIf="className && fieldsArray"
   [className]="className"
   [fieldsArray]="fieldsArray"
   [queryParams]="queryParams"
-></comp-table-list>
+></comp-table-list> -->
+<div class="conetent">
+  <app-textbook></app-textbook>
+</div>

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

@@ -0,0 +1,4 @@
+.conetent{
+  margin: 0 0 20px;
+  padding: 0 24px;
+}

+ 12 - 5
projects/textbook/src/modules/nav-admin/page-textbook/page-textbook.component.ts

@@ -6,11 +6,19 @@ import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
 import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';
 import * as Parse from 'parse';
 import { CommonModule } from '@angular/common';
+import { TextbookComponent } from '../../../app/textbook/textbook.component';
 @Component({
   selector: 'app-page-textbook',
   templateUrl: './page-textbook.component.html',
   styleUrls: ['./page-textbook.component.scss'],
-  imports: [CommonModule, RouterOutlet, CompTableListComponent,NzPageHeaderModule,NzBreadCrumbModule],
+  imports: [
+    CommonModule,
+    RouterOutlet,
+    CompTableListComponent,
+    NzPageHeaderModule,
+    NzBreadCrumbModule,
+    TextbookComponent,
+  ],
   standalone: true,
 })
 export class PageTextbookComponent implements OnInit {
@@ -26,9 +34,8 @@ export class PageTextbookComponent implements OnInit {
 
   constructor(
     private router: Router,
-    private activeRoute: ActivatedRoute
-  ) // private translate:TranslateService,
-  {
+    private activeRoute: ActivatedRoute // private translate:TranslateService,
+  ) {
     this.user = Parse.User.current();
     this.className = this.EduTextbook.className;
     this.fieldsArray = this.EduTextbook.fieldsArray;
@@ -36,7 +43,7 @@ export class PageTextbookComponent implements OnInit {
       where: {
         isDeleted: { $ne: true },
         render: true,
-        discard:{$ne: true},
+        discard: { $ne: true },
       },
     };
   }

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

@@ -110,7 +110,7 @@
             onItemChecked(data.objectId, data.user.objectId, $event)
           "
         ></td>
-        <td nzLeft nzEllipsis>
+        <td nzLeft nzEllipsis (click)="goDateil(data.user?.objectId)" class="activeTd">
           <nz-avatar nzIcon="user"></nz-avatar>
           {{ data?.user.name }}
         </td>
@@ -194,7 +194,7 @@
                   >删除账号
                 </button>
               </li>
-              <li nz-menu-item>
+              <!-- <li nz-menu-item>
                 <button
                   nz-button
                   nzType="link"
@@ -208,7 +208,7 @@
                   ></span
                   >用户详情
                 </button>
-              </li>
+              </li> -->
             </ul>
           </nz-dropdown-menu>
         </td>

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

@@ -54,6 +54,12 @@
     }
 
   }
+  .activeTd{
+    cursor: pointer;
+  }
+  .activeTd:hover{
+    color: #c6233f;
+  }
 }
 .form-button {
   background: #3e49b3; 
@@ -63,7 +69,7 @@
 
 // 选中,批量操作区域
 .batch-toolbar-modal{
-  position: absolute;
+  position: fixed;
   display: flex;
   justify-content: center;
   bottom: 80px;

+ 12 - 6
projects/textbook/src/modules/nav-admin/page-user/page-user.component.ts

@@ -10,8 +10,8 @@ import { NzSpaceModule } from 'ng-zorro-antd/space';
 import { CommonCompModule } from '../../../services/common.modules';
 // 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';
+import { textbookServer } from '../../../services/textbook';
 @Component({
   selector: 'app-page-user',
   templateUrl: './page-user.component.html',
@@ -25,7 +25,6 @@ import { NzModalService } from 'ng-zorro-antd/modal';
     NzBreadCrumbModule,
     CommonCompModule,
     NzEmptyModule,
-    NzAvatarModule
   ],
   standalone: true,
 })
@@ -49,9 +48,10 @@ export class PageUserComponent implements OnInit {
   setOfCheckedId = new Set<string>();
 
   constructor(
+    public tbookSer: textbookServer,
     private modal: NzModalService,
     private route: Router,
-    private activeRoute: ActivatedRoute // private translate:TranslateService,
+    private activeRoute: ActivatedRoute,
   ) {
     this.user = Parse.User.current();
     // this.className = this.ProfileList.className;
@@ -72,16 +72,16 @@ export class PageUserComponent implements OnInit {
   async getProfile() {
     this.profiles = [];
     this.loading = true;
-    let queryParams = {
+    let queryParams:any = {
       where : {
         "$or": [{
           "user": {
             "$inQuery": {
               "where": {
                 "$or": [{
-                  "name": { "$regex": `.*${this.searchValue}.*`}
+                  "name": { "$regex": `.*${this.searchValue}.*`},
                   },
-                ]
+                ],
               },
               "className": "_User"
             }
@@ -89,6 +89,12 @@ export class PageUserComponent implements OnInit {
         }]
       }
     }
+    if(this.tbookSer.profile.identity != '国家级管理员' || this.tbookSer.profile.user.department){
+      this.tbookSer.profile.user.department
+      queryParams['where']['$or'][0]['user']['$inQuery']['where']['department'] = {
+        "$eq": this.tbookSer.profile.user.department.objectId
+      }
+    }
     let query = Parse.Query.fromJSON('Profile',queryParams);
     query.include('user');
     query.notEqualTo('identity', '国家级管理员');

+ 4 - 2
projects/textbook/src/modules/nav-author/space/space.component.html

@@ -23,12 +23,14 @@
     <nz-tabset [(nzSelectedIndex)]="active">
       <nz-tab nzTitle="我的教材">
         @if (active == 0) {
-          <app-page-textbook></app-page-textbook>
+        <!-- <app-page-textbook></app-page-textbook> -->
+        <app-textbook [uid]="user?.id"></app-textbook>
         }
       </nz-tab>
       <nz-tab nzTitle="已提交评审教材">
         @if (active == 1) {
-          <app-page-textbook [render]="true"></app-page-textbook>
+        <!-- <app-page-textbook [render]="true"></app-page-textbook> -->
+        <app-textbook [uid]="user?.id"></app-textbook>
         }
       </nz-tab>
     </nz-tabset>

+ 9 - 3
projects/textbook/src/modules/nav-author/space/space.component.ts

@@ -5,16 +5,22 @@ import * as Parse from 'parse';
 import { NzTabsModule } from 'ng-zorro-antd/tabs';
 import { PageTextbookComponent } from '../components/page-textbook/page-textbook.component';
 import { textbookServer } from '../../../services/textbook';
+import { TextbookComponent } from '../../../app/textbook/textbook.component';
 @Component({
   selector: 'app-space',
   standalone: true,
-  imports: [CommonCompModule, NzTabsModule, PageTextbookComponent],
+  imports: [
+    CommonCompModule,
+    NzTabsModule,
+    PageTextbookComponent,
+    TextbookComponent,
+  ],
   templateUrl: './space.component.html',
   styleUrls: ['./space.component.scss'],
 })
 export class SpaceComponent implements OnInit {
-  user: Parse.Object = Parse.User.current()!;
-  active:number = 0
+  user: Parse.Object | any = Parse.User.current();
+  active: number = 0;
 
   constructor(private router: Router, public tbookSer: textbookServer) {}
 

+ 23 - 3
projects/textbook/src/modules/nav-province-contact/modules.routes.ts

@@ -1,8 +1,12 @@
 import { NgModule } from "@angular/core";
 import { RouterModule, Routes } from "@angular/router";
-import { PageCollectionComponent } from "./page-collection/page-collection.component";
+import { PageUserComponent } from "../nav-admin/page-user/page-user.component";
+import { UserEditComponent } from "../nav-admin/user-edit/user-edit.component";
 import { PageProcessComponent } from "./page-process/page-process.component";
+import { ProcessListComponent } from "./page-process/process-list/process-list.component";
+import { PageRoleComponent } from "./page-role/page-role.component";
 import { PageTextbookComponent } from "./page-textbook/page-textbook.component";
+// import { PageTextbookComponent } from "./page-textbook/page-textbook.component";
 const routes: Routes = [
   {
     path: '',
@@ -13,13 +17,29 @@ const routes: Routes = [
     path: 'manage',
     children:[
       {
-        path: 'collection', //流程列表
+        path: 'process', //流程申报
+        component: ProcessListComponent,
+      },
+      {
+        path: 'process/page', //流程详情
         component: PageProcessComponent,
       },
       {
-        path: 'textbook', //全部材料
+        path: 'textbook', //全部
         component: PageTextbookComponent,
       },
+      {
+        path: 'user', //用户列表
+        component: PageUserComponent,
+      },
+      {
+        path: 'user/edit', //用户管理&编辑
+        component: UserEditComponent,
+      },
+      {
+        path: 'role', //组织列表
+        component: PageRoleComponent,
+      },
     ]
   }
 ];

+ 0 - 35
projects/textbook/src/modules/nav-province-contact/page-collection/page-collection.component.html

@@ -1,35 +0,0 @@
-<!-- 表格头部 -->
-@if (list?.schema?.title) {
-<nz-page-header>
-  <!--title-->
-  <nz-page-header-title
-    >{{ list?.schema?.title }}
-    <br />
-    <div class="subtitle">在每个报送合集内管理该地区的推荐报送教材流程</div>
-  </nz-page-header-title>
-
-  <!--extra-->
-  <nz-page-header-extra>
-    <nz-space>
-      <button
-        style="background: #3e49b3; border: 1px #3e49b3"
-        *nzSpaceItem
-        nz-button
-        nzType="primary"
-        (click)="create()"
-      >
-        创建合集
-      </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>

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

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

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

@@ -1,61 +0,0 @@
-import { Component, OnInit, ViewChild } from '@angular/core';
-import { ActivatedRoute,Router, 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 router: Router,
-    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()
-    });
-  }
-  create(){
-    this.router.navigate(['/nav-admin/manage/collection/create'])
-  }
-}

+ 16 - 39
projects/textbook/src/modules/nav-province-contact/page-process/page-process.component.html

@@ -1,54 +1,31 @@
 <nz-page-header>
-  <!-- <nz-breadcrumb nz-page-header-breadcrumb>
-    <nz-breadcrumb-item>国家级管理</nz-breadcrumb-item>
-    <nz-breadcrumb-item><a>报送合集</a></nz-breadcrumb-item>
-  </nz-breadcrumb> -->
-  <nz-page-header-title>
-    <div style="display:flex;align-items: center;">{{ user?.get("companyName") }} <nz-tag nzColor="processing">遴选中</nz-tag></div>
+  <nz-breadcrumb nz-page-header-breadcrumb>
+    <nz-breadcrumb-item>教材申报</nz-breadcrumb-item>
+    <nz-breadcrumb-item>申报流程</nz-breadcrumb-item>
+    <nz-breadcrumb-item><a>{{eduProcess?.get('department')?.get('name') || '未选择申报单位'}}</a></nz-breadcrumb-item>
+  </nz-breadcrumb>
+  <nz-page-header-title
+    >{{eduProcess?.get('department')?.get('name') || '未选择申报单位'}}
+    <br />
     <div class="subtitle">
-      在合集中,你可以创建多个教材推荐报送流程,指定用户为流程管理员,邀请作者、联系人、评审员注册系统,创建并提交教材,由流程管理员提交至合集管理员完成报送
+      在流程中邀请作者、高校联系人、评审员登录系统,创建并提交教材,由工作联系人评审、提交推荐教材完成流程工作
     </div>
   </nz-page-header-title>
-  <nz-page-header-extra>
-    <nz-space>
-      <button
-        style="background: #3e49b3; border: 1px #3e49b3"
-        *nzSpaceItem
-        nz-button
-        nzType="primary"
-        (click)="onCreateProcess()"
-      >
-      导出函报文件
-      </button>
-      <button
-        style="background: #3e49b3; border: 1px #3e49b3"
-        *nzSpaceItem
-        nz-button
-        nzType="primary"
-        (click)="onCreateProcess()"
-      >
-        确认报送
-      </button>
-    </nz-space>
-  </nz-page-header-extra>
 </nz-page-header>
 <div class="edit-content">
   <nz-tabset [(nzSelectedIndex)]="active">
     <nz-tab nzTitle="报送流程">
       @if (active == 0) {
-      <!-- <app-process [eduCollectionId]="eduCollection?.id"></app-process> -->
+      <app-process-create [isEdit]="true"></app-process-create>
       }
     </nz-tab>
-    <nz-tab nzTitle="推荐材料">
+    <nz-tab nzTitle="教材列表">
       @if (active == 1) {
-      <comp-table-list
-        #list
-        [schema]="EduTextbook"
-        *ngIf="className && fieldsArray"
-        [className]="className"
-        [fieldsArray]="fieldsArray"
-        [queryParams]="queryParams"
-      ></comp-table-list>
+        <div class="title">待评审教材列表</div>
+        <app-textbook></app-textbook>
+        <br>
+        <div class="title">推荐教材列表</div>
+        <app-textbook [recommend]="true"></app-textbook>
       }
     </nz-tab>
   </nz-tabset>

+ 16 - 8
projects/textbook/src/modules/nav-province-contact/page-process/page-process.component.scss

@@ -1,4 +1,4 @@
-.subtitle{
+.subtitle {
   margin-right: 12px;
   color: #00000073;
   font-size: 14px;
@@ -8,23 +8,31 @@
   // white-space: nowrap;
   // text-overflow: ellipsis;
 }
-.edit-content{
+.edit-content {
   margin: 0 0 20px;
   padding: 0 24px;
   height: calc(100vh - 250px);
+  .title {
+    font-family: PingFang SC;
+    font-size: 20px;
+    font-weight: 500;
+    line-height: 32px;
+    text-align: left;
+    margin-bottom: 16px;
+  }
 }
-::ng-deep .ant-page-header-heading-title{
+::ng-deep .ant-page-header-heading-title {
   white-space: normal;
 }
-::ng-deep .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn{
+::ng-deep .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn {
   color: #c6233f;
 }
-::ng-deep .ant-tabs-ink-bar{
+::ng-deep .ant-tabs-ink-bar {
   background: #c6233f;
 }
-::ng-deep .ant-tabs-tab:hover{
+::ng-deep .ant-tabs-tab:hover {
   color: #e97488;
 }
-::ng-deep .ant-tabs-tab-btn:active{
+::ng-deep .ant-tabs-tab-btn:active {
   color: #e97488;
-}
+}

+ 17 - 30
projects/textbook/src/modules/nav-province-contact/page-process/page-process.component.ts

@@ -3,12 +3,11 @@ import { CommonModule } from '@angular/common';
 import { NzSpaceModule } from 'ng-zorro-antd/space';
 import { CommonCompModule } from '../../../services/common.modules';
 import { NzTabsModule } from 'ng-zorro-antd/tabs';
-// import { ProcessComponent } from '../components/process/process.component';
-// import { CreateCollectionComponent } from '../create-collection/create-collection.component';
 import { ActivatedRoute, Router } from '@angular/router';
 import Parse from 'parse';
-import { EduTextbook } from '../../../schemas/EduTextbook';
 import { CompTableListComponent } from '../../../app/comp-table/comp-table-list/comp-table-list.component';
+import { ProcessCreateComponent } from './process-create/process-create.component';
+import { TextbookComponent } from '../../../app/textbook/textbook.component';
 @Component({
   selector: 'app-page-process',
   templateUrl: './page-process.component.html',
@@ -18,50 +17,38 @@ import { CompTableListComponent } from '../../../app/comp-table/comp-table-list/
     NzSpaceModule,
     CommonCompModule,
     NzTabsModule,
-    // ProcessComponent,
-    // CreateCollectionComponent,
-    CompTableListComponent
+    ProcessCreateComponent,
+    CompTableListComponent,
+    TextbookComponent
   ],
   standalone: true,
 })
-export class PageProcessComponent implements OnInit {
+export class PageProcessComponent  implements OnInit {
   active: number = 0;
-  eduCollection: Parse.Object | undefined;
+  eduProcess: Parse.Object | undefined;
 
-  EduTextbook = EduTextbook;
   user: Parse.User | undefined;
-  className: string | undefined;
-  queryParams: any | undefined;
-  fieldsArray: Array<any> | undefined;
 
-  constructor(private activeRoute: ActivatedRoute, private router: Router) {
+  constructor(
+    private activeRoute:ActivatedRoute,
+    private router: Router,
+  ) {
     this.user = Parse.User.current();
-    this.className = this.EduTextbook.className;
-    this.fieldsArray = this.EduTextbook.fieldsArray;
-    this.queryParams = {
-      where: {
-        isDeleted: { $ne: true },
-        render: true,
-        status: '200',
-      },
-    };
   }
 
   ngOnInit() {
     this.activeRoute.paramMap.subscribe(async (params) => {
       let id = params.get('id');
       if (id) {
-        let query = new Parse.Query('EduCollection');
+        let query = new Parse.Query('EduProcess');
+        query.include('branch', 'department');
         query.equalTo('objectId', id);
-        this.eduCollection = await query.first();
+        this.eduProcess = await query.first();
       }
-    });
+    })
   }
 
-  onCreateProcess() {
-    // this.router.navigate([
-    //   '/nav-admin/manage/process/create',
-    //   { cid: this.eduCollection?.id },
-    // ]);
+  onCreateProcess(){
+    this.router.navigate(['/nav-admin/manage/process/create',{cid:this.eduProcess?.id}])
   }
 }

+ 254 - 0
projects/textbook/src/modules/nav-province-contact/page-process/process-create/process-create.component.html

@@ -0,0 +1,254 @@
+@if (!isEdit) {
+<nz-page-header nzTitle="发起报送流程">
+  <nz-breadcrumb nz-page-header-breadcrumb>
+    <nz-breadcrumb-item>申报流程</nz-breadcrumb-item>
+    <nz-breadcrumb-item><a>创建流程</a></nz-breadcrumb-item>
+  </nz-breadcrumb>
+</nz-page-header>
+}
+<div
+  class="content"
+  id="process"
+  [style.padding]="isEdit ? '0' : '0 24px 16px'"
+>
+  <div class="title">基本信息</div>
+  <div class="fill-template">
+    <div class="rows" nz-row>
+      <div nz-col nzSpan="11">
+        <nz-form-item class="row" style="margin-bottom: 6px">
+          <nz-form-label
+            class="label"
+            [nzNoColon]="true"
+            [nzSm]="18"
+            [nzXs]="18"
+            nzRequired
+            >流程名称</nz-form-label
+          >
+          <nz-form-control
+            class="val"
+            nzErrorTip="请填写流程名称"
+            style="width: 100%"
+          >
+            <nz-input-group>
+              <input
+                nz-input
+                type="text"
+                placeholder="请填写流程名称"
+                disabled="true"
+                [ngModel]="eduProcess?.get('name')"
+                nzStatus=""
+                maxlength="50"
+              />
+            </nz-input-group>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col nzSpan="11">
+        <nz-form-item class="row" style="margin-bottom: 6px">
+          <nz-form-label
+            class="label"
+            [nzNoColon]="true"
+            [nzSm]="18"
+            [nzXs]="18"
+            nzRequired
+            >流程描述</nz-form-label
+          >
+          <nz-form-control
+            class="val"
+            nzErrorTip="请填写合集描述"
+            style="width: 100%"
+          >
+            <nz-input-group>
+              <input
+                nz-input
+                type="text"
+                placeholder="请填流程描述"
+                disabled="true"
+                [ngModel]="eduProcess?.get('desc')"
+                nzStatus=""
+                maxlength="50"
+              />
+            </nz-input-group>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+    <div class="rows" nz-row>
+      <div nz-col nzSpan="11">
+        <nz-form-item class="row" style="margin-bottom: 6px">
+          <nz-form-label
+            class="label"
+            [nzNoColon]="true"
+            [nzSm]="18"
+            [nzXs]="18"
+            nzRequired
+            >流程唯一标识</nz-form-label
+          >
+          <nz-form-control
+            class="val"
+            nzErrorTip="请填写流程唯一标识"
+            style="width: 100%"
+          >
+            <nz-input-group>
+              <input
+                nz-input
+                type="text"
+                placeholder="请填写流程唯一标识"
+                disabled="true"
+                [ngModel]="eduProcess?.get('code')"
+                nzStatus=""
+                maxlength="50"
+              />
+            </nz-input-group>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col nzSpan="11">
+        <nz-form-item class="row">
+          <nz-form-label class="label" [nzNoColon]="true" nzRequired
+            >流程所属类别</nz-form-label
+          >
+          <nz-input-group>
+            <input
+              nz-input
+              type="text"
+              placeholder="请填写流程唯一标识"
+              disabled="true"
+              [ngModel]="eduProcess?.get('branch')?.get('name')"
+              nzStatus=""
+              maxlength="50"
+            />
+          </nz-input-group>
+        </nz-form-item>
+      </div>
+    </div>
+    <div class="rows" nz-row>
+      <div nz-col nzSpan="11">
+        <nz-form-item class="row" style="margin-bottom: 6px">
+          <nz-form-label
+            class="label"
+            [nzNoColon]="true"
+            [nzSm]="18"
+            [nzXs]="18"
+            nzRequired
+            >开始时间</nz-form-label
+          >
+          <div class="date">
+            {{ eduProcess?.get("startDate") | date : "yyyy-MM-dd HH:MM" }}
+          </div>
+        </nz-form-item>
+      </div>
+      <div nz-col nzSpan="11">
+        <nz-form-item class="row" style="margin-bottom: 6px">
+          <nz-form-label
+            class="label"
+            [nzNoColon]="true"
+            [nzSm]="18"
+            [nzXs]="18"
+            nzRequired
+            >结束时间</nz-form-label
+          >
+          <div class="date">
+            {{ eduProcess?.get("deadline") | date : "yyyy-MM-dd HH:MM" }}
+          </div>
+        </nz-form-item>
+      </div>
+    </div>
+    <div class="rows" nz-row>
+      <div nz-col nzSpan="11">
+        <nz-form-item class="row" style="margin-bottom: 6px">
+          <nz-form-label
+            class="label"
+            [nzNoColon]="true"
+            [nzSm]="18"
+            [nzXs]="18"
+            nzRequired
+            >推荐限额</nz-form-label
+          >
+          <nz-form-control
+            class="val"
+            nzErrorTip="请填写推荐限额"
+            style="width: 100%"
+          >
+            <nz-input-group>
+              <input
+                nz-input
+                type="text"
+                placeholder="请填写流程唯一标识"
+                disabled="true"
+                [ngModel]="eduProcess?.get('num')"
+                nzStatus=""
+                maxlength="50"
+              />
+            </nz-input-group>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col nzSpan="11"></div>
+    </div>
+  </div>
+  @if (isEdit) {
+  <div nz-row>
+    <div nz-col nzSpan="24">
+      <div class="title-row">
+        <div>
+          <div class="title">申报单位信息</div>
+          <div class="tips">
+            选择一个与流程相关联的申报单位部门节点,该单位部门节点下所有账号创建的教材均可提交至此流程接受评审
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div class="rows" nz-row>
+    <div nz-col nzSpan="24">
+      <div class="title-row">
+        <div class="bar">申报单位</div>
+      </div>
+      <div class="fill-setp">
+        @if (eduProcess?.get('department')?.id) {
+        <nz-tag [nzBordered]="false" style="color: black" [nzColor]="'#efefef'"
+          >“十四五”高等教育国家规划教材申报系统</nz-tag
+        >
+        /
+        <nz-tag
+          [nzBordered]="false"
+          style="color: black"
+          [nzColor]="'#efefef'"
+          >{{ eduProcess?.get("branch")?.get("name") }}</nz-tag
+        >
+        /
+        <nz-tag [nzBordered]="false" [nzColor]="'geekblue'">{{
+          eduProcess?.get("department")?.get("name")
+        }}</nz-tag>
+        }@else { 待选择 }
+      </div>
+    </div>
+  </div>
+  <div class="rows" nz-row>
+    <div nz-col nzSpan="24">
+      <div class="title-row">
+        <div class="bar">工作联系人</div>
+      </div>
+      <div class="table" #maxWidth>
+        @if (eduProcess?.get('profileSubmitted')?.id) {
+        <app-profile
+          [idList]="[eduProcess?.get('profileSubmitted')?.id || '']"
+          [maxWidth]="maxWidth"
+          [disabled]="true"
+          [hideBtn]="true"
+        ></app-profile>
+        } @else{
+        <app-profile
+          [idList]="['']"
+          [maxWidth]="maxWidth"
+          [disabled]="true"
+          [hideBtn]="true"
+          [depart]="eduProcess?.get('department')?.id"
+        ></app-profile>
+        }
+      </div>
+    </div>
+  </div>
+  }
+</div>

+ 144 - 0
projects/textbook/src/modules/nav-province-contact/page-process/process-create/process-create.component.scss

@@ -0,0 +1,144 @@
+.content {
+  padding: 0 24px 16px;
+  min-width: 800px;
+  font-family: PingFang SC;
+  .title {
+    //styleName: 字体/标题-中-Medium;
+    font-family: PingFang SC;
+    font-size: 20px;
+    font-weight: 500;
+    line-height: 32px;
+    text-align: left;
+  }
+  .row {
+    display: flex;
+    flex-direction: column;
+    align-items: start;
+    width: 100%;
+    .label {
+      margin: 10px 0 6px;
+    }
+    .val {
+      min-height: auto;
+    }
+    .date{
+      width: 100%;
+      padding: 4px 10px;
+      background: #f5f5f5;
+      border: 1px solid #d9d9d9;
+      color: rgba(0, 0, 0, .25);
+    }
+  }
+  .rows{
+    display: flex;
+    justify-content: space-between;
+  }
+  .title-row {
+    margin-top: 20px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    .tips {
+      font-family: PingFang SC;
+      font-size: 14px;
+      font-weight: 400;
+      line-height: 16px;
+      text-align: left;
+      margin-top: 10px;
+    }
+    .btn {
+      margin-left: 20px;
+      flex-shrink: 0;
+      color: #006ded;
+      font-size: 14px;
+      font-weight: 400;
+    }
+    .bar {
+      margin: 20px 0 10px;
+      font-family: PingFang SC;
+      font-size: 16px;
+      font-weight: 600;
+      line-height: 22px;
+      text-align: left;
+      display: flex;
+      justify-content: space-between;
+      width: 100%;
+    }
+  }
+  .fill-setp {
+    background-color: #fafbfc;
+    font-family: PingFang SC;
+    font-size: 14px;
+    padding: 10px;
+    .lable {
+      color: #24272299;
+      margin-bottom: 6px;
+    }
+    .value {
+      width: 80%;
+      padding: 4px 8px;
+      background: #f9f9f9;
+      border-radius: 4px;
+      color: #242722;
+      margin-bottom: 10px;
+      overflow: hidden;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+    }
+  }
+}
+.fonter {
+  // text-align: right;
+  .form-button {
+    width: 80px;
+    height: 40px;
+    margin: 20px 0;
+    color: white !important;
+    background-color: #3e49b3 !important;
+    border-radius: 4px;
+    font-family: PingFang SC;
+    font-size: 14px;
+    font-weight: 400;
+    line-height: 20px;
+    text-align: center;
+  }
+  .close {
+    width: 80px;
+    background-color: #eae6e6 !important;
+    color: black !important;
+    margin-left: 20px;
+  }
+}
+.depart-modal{
+  .row{
+    width: 90%;
+    margin-bottom: 20px;
+  }
+  .tree{
+    height: 180px;
+    overflow-y: scroll;
+    .li{
+      display: flex;
+      justify-content: space-between;
+      padding: 8px 4px;
+      span{
+        flex-shrink: 0;
+      }
+    }
+    .li:hover{
+      background-color: #f9f9f9;
+    }
+  }
+}
+// ::ng-deep .ant-page-header {
+//   padding: 16px 24px 0;
+// }
+::ng-deep .ant-page-header-heading-title {
+  color: black;
+}
+::ng-deep .ant-picker {
+  width: 100%;
+}
+::ng-deep .ant-form-item {
+  margin:0px;
+}

+ 24 - 0
projects/textbook/src/modules/nav-province-contact/page-process/process-create/process-create.component.spec.ts

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

+ 66 - 0
projects/textbook/src/modules/nav-province-contact/page-process/process-create/process-create.component.ts

@@ -0,0 +1,66 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { CommonCompModule } from '../../../../services/common.modules';
+import { Router, ActivatedRoute } from '@angular/router';
+import { NzSelectModule } from 'ng-zorro-antd/select';
+import Parse from 'parse';
+import {
+  NonNullableFormBuilder,
+} from '@angular/forms';
+import { textbookServer } from '../../../../services/textbook';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import { NzModalService } from 'ng-zorro-antd/modal';
+import { MatButtonModule } from '@angular/material/button';
+import { setHours } from 'date-fns';
+import { NzRadioModule } from 'ng-zorro-antd/radio';
+import { ProfileComponent } from '../../../nav-admin/components/profile/profile.component';
+import { DatePipe } from '@angular/common';
+@Component({
+  selector: 'app-process-create',
+  templateUrl: './process-create.component.html',
+  styleUrls: ['./process-create.component.scss'],
+  imports: [
+    CommonCompModule,
+    FormsModule,
+    ReactiveFormsModule,
+    NzSelectModule,
+    MatButtonModule,
+    ProfileComponent,
+    NzRadioModule,
+    DatePipe
+  ],
+  standalone: true,
+})
+export class ProcessCreateComponent implements OnInit {
+  timeDefaultValue = setHours(new Date(), 0);
+
+  eduProcess: Parse.Object | undefined;
+  showProfileFrom: boolean = false;
+  @Input('isEdit') isEdit: boolean = false; //当前是否作为编辑子组件
+  profileId: string = '';
+  isVisible: boolean = false;
+  searchValue: string = ''; //搜索部门内容
+
+  constructor(
+    private activeRoute: ActivatedRoute,
+    private router: Router,
+    public tbookSer: textbookServer,
+    private fb: NonNullableFormBuilder,
+    private msg: NzMessageService,
+    private modal: NzModalService
+  ) {}
+
+  ngOnInit() {
+    this.activeRoute.paramMap.subscribe(async (params) => {
+      let id = params.get('id');
+      if (id) {
+        this.isEdit = true;
+        let query = new Parse.Query('EduProcess');
+        query.include('branch', 'department');
+        query.equalTo('objectId', id);
+        this.eduProcess = await query.first();
+        console.log(this.eduProcess?.get('profileSubmitted')?.id);
+      }
+    });
+  }
+}

+ 223 - 0
projects/textbook/src/modules/nav-province-contact/page-process/process-list/process-list.component.html

@@ -0,0 +1,223 @@
+<nz-page-header>
+  <!--title-->
+  <nz-page-header-title
+    >申报流程
+    <br />
+    <div class="subtitle">
+      统一管理各类教材推荐流程和限额,设置各个流程开始和结束时间、查看各流程工作进度
+    </div>
+  </nz-page-header-title>
+
+  <!--extra-->
+  <nz-page-header-extra> </nz-page-header-extra>
+</nz-page-header>
+<div class="edit-content">
+  <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)="onSearch($event)"
+          />
+        </nz-input-group>
+        <ng-template #prefixTemplateUser
+          ><span nz-icon nzType="search"></span
+        ></ng-template>
+      </div> -->
+      <div class="">
+        <nz-input-group style="width: 210px" [nzPrefix]="prefixTemplateUser">
+          <input
+            type="text"
+            nz-input
+            placeholder="搜索流程名称 / 流程 code"
+            [(ngModel)]="searchValuePro"
+            (ngModelChange)="onSearchPro($event)"
+          />
+        </nz-input-group>
+        <ng-template #prefixTemplateUser
+          ><span nz-icon nzType="search"></span
+        ></ng-template>
+      </div>
+    </div>
+    <div class="tool-right"></div>
+  </div>
+  <div class="layout" #maxWidth>
+    <!-- <div class="sider" #sider>
+      <ul nz-menu>
+        @for (item of nodes; track $index) {
+        <li nz-menu-item (click)="changeDepart(item)">{{ item.title }}</li>
+        }
+      </ul>
+    </div> -->
+    <div class="breadcrumb">
+      <nz-table
+        #tableData
+        [nzData]="eduProcessList"
+        [nzTotal]="eduProcessList.length"
+        [nzPageSize]="10"
+        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">流程code</th>
+            <th nzWidth="120px">流程描述</th>
+            <th nzWidth="80px">申报限额</th>
+            <th nzWidth="120px">流程联系人</th>
+            <th nzWidth="80px">流程状态</th>
+            <th nzWidth="50px" nzRight>操作</th>
+          </tr>
+        </thead>
+        <tbody>
+          @for (data of eduProcessList; track data.objectId) {
+          <tr>
+            <td
+              nzLeft
+              [nzChecked]="data.checked"
+              (nzCheckedChange)="onItemChecked(data.objectId, $event)"
+            ></td>
+            <td
+              nzLeft
+              nzEllipsis
+              (click)="
+                toUrl('/nav-province-contact/manage/process/page', {
+                  id: data?.objectId
+                })
+              "
+              class="activeTd"
+            >
+              {{ data?.name || "-" }}
+            </td>
+            <td>
+              {{ data?.code || "-" }}
+            </td>
+            <td>
+              {{ data?.desc || "-" }}
+            </td>
+            <td>
+              {{ data?.num || "-" }}
+            </td>
+            <td>
+              {{ data?.profileSubmitted?.user.name || "-" }}
+            </td>
+            <td>
+              <nz-tag [nzColor]="data?.state.color">
+                {{ data?.state.title }}</nz-tag
+              >
+            </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.state?.strat){
+                  <li nz-menu-item>
+                    <button
+                      nz-button
+                      [disabled]="user?.get('isDeleted')"
+                      nzType="link"
+                      style="color: #231c1f"
+                    >
+                      <span
+                        nz-icon
+                        nzType="caret-right"
+                        nzTheme="outline"
+                      ></span
+                      >开始流程
+                    </button>
+                  </li>
+                  } @if (data.state?.stop){
+                  <li nz-menu-item>
+                    <button
+                      nz-button
+                      [disabled]="user?.get('isDeleted')"
+                      nzType="link"
+                      style="color: #231c1f"
+                    >
+                      <span
+                        nz-icon
+                        nzType="pause-circle"
+                        nzTheme="outline"
+                      ></span
+                      >暂停流程
+                    </button>
+                  </li>
+                  } @if (data.state?.end){
+                  <li nz-menu-item>
+                    <button
+                      nz-button
+                      [disabled]="user?.get('isDeleted')"
+                      nzType="link"
+                      style="color: #231c1f"
+                    >
+                      <span nz-icon nzType="stop" nzTheme="outline"></span
+                      >结束流程
+                    </button>
+                  </li>
+                  } @if (data.state?.del){
+                  <li nz-menu-item>
+                    <button nz-button nzType="link" style="color: #231c1f">
+                      <span nz-icon nzType="delete" 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>
+  </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" (click)="onAllChecked(false)">
+        取消选中
+      </button>
+    </div>
+  </div>
+</div>

+ 173 - 0
projects/textbook/src/modules/nav-province-contact/page-process/process-list/process-list.component.scss

@@ -0,0 +1,173 @@
+.subtitle{
+  margin-right: 12px;
+  color: #00000073;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 1.5715;
+  // overflow: hidden;
+  // white-space: nowrap;
+  // text-overflow: ellipsis;
+}
+.edit-content{
+  margin: 0 0 20px;
+  padding: 0 24px;
+  height: calc(100vh - 192px);
+  min-width: 800px;
+  .tool{
+    display: flex;
+    justify-content: space-between;
+    .tool-left{
+      display: flex;
+      align-items: center;
+      .search{
+        display: flex;
+        width: 210px;
+        margin-right: 20px;
+      }
+      .tag{
+        background: #f7f7f7;
+        display: flex;
+        align-items: center;
+        color: #6f6f6f;
+        line-height: 26px;
+        padding: 0 8px;
+        margin: 0 10px;
+      }
+    }
+  }
+  .layout{
+    display: flex;
+    width: 100%;
+    .sider{
+      width: 210px;
+      margin: 10px 0;
+      height: calc(100vh - 192px);
+      overflow-y: scroll;
+      flex-shrink: 0;
+      margin-right: 20px;
+      .custom-node{
+        display: flex;
+      }
+      .folder-desc{
+        display: none;
+        margin-left: 10px;
+        background-color: white;
+        color: #ba1a1a;
+        border: none;
+      }
+      .custom-node:hover .folder-desc{
+        display: block;
+      }
+      .custom-name:hover .folder-desc{
+        display: block;
+      }
+    }
+    .breadcrumb{
+      flex: 1;
+      .activeTd{
+        cursor: pointer;
+      }
+      .activeTd:hover{
+        color: #c6233f;
+      }
+    }
+  }
+}
+.depart-modal{
+  .row{
+    width: 90%;
+    margin-bottom: 20px;
+  }
+  .tree{
+    height: 180px;
+    overflow-y: scroll;
+    .li{
+      display: flex;
+      justify-content: space-between;
+      padding: 8px 4px;
+      span{
+        flex-shrink: 0;
+      }
+    }
+    .li:hover{
+      background-color: #f9f9f9;
+    }
+  }
+}
+// 选中,批量操作区域
+.batch-toolbar-modal{
+  position: fixed;
+  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;
+}
+
+
+::ng-deep .ant-page-header-heading-title{
+  white-space: normal;
+}
+::ng-deep .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn{
+  color: #c6233f;
+}
+::ng-deep .ant-tabs-ink-bar{
+  background: #c6233f;
+}
+::ng-deep .ant-tabs-tab:hover{
+  color: #e97488;
+}
+::ng-deep .ant-tabs-tab-btn:active{
+  color: #e97488;
+}
+::ng-deep .ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected{
+  background-color: #ba1a1a;
+  color: white;
+}
+::ng-deep .ant-tree .ant-tree-node-content-wrapper:hover{
+  background-color: #eae6e6;
+}

+ 24 - 0
projects/textbook/src/modules/nav-province-contact/page-process/process-list/process-list.component.spec.ts

@@ -0,0 +1,24 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+import { IonicModule } from '@ionic/angular';
+
+import { PageProcessComponent } from './process-list.component';
+
+describe('PageProcessComponent', () => {
+  let component: PageProcessComponent;
+  let fixture: ComponentFixture<PageProcessComponent>;
+
+  beforeEach(waitForAsync(() => {
+    TestBed.configureTestingModule({
+      declarations: [ PageProcessComponent ],
+      imports: [IonicModule.forRoot()]
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(PageProcessComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  }));
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 311 - 0
projects/textbook/src/modules/nav-province-contact/page-process/process-list/process-list.component.ts

@@ -0,0 +1,311 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { ActivatedRoute, RouterOutlet, Router } 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';
+import { Department } from '../../../../schemas/Department';
+import { NzSpaceModule } from 'ng-zorro-antd/space';
+import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
+import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';
+import { CommonCompModule } from '../../../../services/common.modules';
+import { NzModalModule } from 'ng-zorro-antd/modal';
+import {
+  NzFormatEmitEvent,
+  NzTreeModule,
+  NzTreeNode,
+} from 'ng-zorro-antd/tree';
+import { NzCheckboxModule } from 'ng-zorro-antd/checkbox';
+import { NzEmptyModule } from 'ng-zorro-antd/empty';
+import { NzRadioModule } from 'ng-zorro-antd/radio';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import { NzModalService } from 'ng-zorro-antd/modal';
+import { textbookServer } from '../../../../services/textbook';
+interface nodes {
+  title: string;
+  key: string;
+  isLeaf?: boolean;
+  isParent?: boolean;
+  children?: Array<any>;
+}
+interface depart {
+  name: string;
+  id?: string;
+  code?: string;
+  desc?: string;
+  parent?: object | any;
+  branch: string;
+}
+@Component({
+  selector: 'app-process-list',
+  templateUrl: './process-list.component.html',
+  styleUrls: ['./process-list.component.scss'],
+  imports: [
+    CommonModule,
+    CommonCompModule,
+    RouterOutlet,
+    CompTableListComponent,
+    NzSpaceModule,
+    NzPageHeaderModule,
+    NzBreadCrumbModule,
+    NzTreeModule,
+    NzCheckboxModule,
+    NzEmptyModule,
+    NzModalModule,
+    NzRadioModule,
+  ],
+  standalone: true,
+})
+export class ProcessListComponent implements OnInit {
+  @ViewChild(CompTableListComponent) list: CompTableListComponent | undefined;
+
+  // _Role = _Role
+  Department = Department;
+  user: Parse.User | undefined;
+  className: string | undefined;
+  queryParams: any | undefined;
+  fieldsArray: Array<any> | undefined;
+  searchValue: string = ''; //搜索内容
+  searchValuePro: string = ''; //搜索流程内容
+  nodes: Array<nodes | any> = [];
+  currentDepart: nodes | any = null;
+
+  eduProcessList: Array<any> = [];
+  checkedShowFilter: boolean = false;
+
+  checkedAll: boolean = false; //全选
+  indeterminate = false;
+  loading = false;
+
+  isVisible: boolean = false;
+  activatedNode: NzTreeNode | any; //当前选择节点
+  editType: string = 'add'; //弹窗类型
+  activeDepart?: Parse.Object; //当前编辑部门
+  editObject: depart = {
+    name: '',
+    code: '',
+    desc: '',
+    parent: {},
+    branch: '',
+  };
+  parentMap: Array<any> = [];
+  setOfCheckedId = new Set<string>();
+  formatStatus = (e:any)=>{
+    if(e.status == '100'){
+      return {
+        title:'已暂停',
+        color:'lime',
+        strat:true,
+        stop:true,
+        end:false,
+        del:false,
+      }
+    }
+    if(e?.deadline.iso && new Date() > new Date(e.deadline.iso) && e.status == '200'){
+      return {
+        title:'已结束',
+        color:'gold',
+        strat:false,
+        stop:false,
+        end:false,
+        del:true,
+      }
+    }
+    if(e.status == '200'){
+      return {
+        title:'已完成',
+        color:'green',
+        strat:false,
+        stop:false,
+        end:true,
+        del:false,
+      }
+    }
+    if(!e?.startDate.iso || (new Date() < new Date(e.startDate.iso))){
+      return {
+        title:'未开始',
+        color:'grey',
+        strat:true,
+        stop:false,
+        end:false,
+        del:true,
+      }
+    }
+    if(!e.statuse && e.startDate.iso && new Date() >= new Date(e.startDate.iso) ){
+      return {
+        title:'遴选中',
+        color:'blue',
+        strat:false,
+        stop:true,
+        end:true,
+        del:false,
+      }
+    }
+    if(e?.deadline.iso && (new Date() > new Date(e.deadline.iso))){
+      return {
+        title:'已逾期',
+        color:'red',
+        strat:true,
+        stop:false,
+        end:false,
+        del:true,
+      }
+    }
+    return
+  }
+  constructor(
+    public tbookSer: textbookServer,
+    private route: Router,
+    private activeRoute: ActivatedRoute,
+    private message: NzMessageService,
+    private modal: NzModalService
+  ) {
+    this.user = Parse.User.current();
+    this.className = this.Department.className;
+    this.fieldsArray = this.Department.fieldsArray;
+    this.queryParams = {
+      where: {
+        isDeleted: { $ne: true },
+      },
+    };
+  }
+
+  ngOnInit(): void {
+    this.activeRoute.paramMap.subscribe(async (params) => {
+      // this.nodes = await this.getDepart();
+      this.getEduProcess()
+    });
+  }
+  async getDepart(
+    parent?: string,
+    searchValue?: string
+  ): Promise<Array<nodes>> {
+    let nodes: any = [];
+    let query = new Parse.Query('Department');
+    searchValue && query.contains('name', searchValue);
+    query.notEqualTo('isDeleted', true);
+    query.select('code', 'name', 'branch', 'parent', 'type');
+    query.descending('createdAt');
+    query.limit(100);
+    query.equalTo('objectId', this.tbookSer.profile.user.department.objectId)
+    let res = await query.find();
+    res.forEach((item) => {
+      nodes.push({
+        title: item.get('name'),
+        key: item.id,
+        children: [],
+        isLeaf: true,
+      });
+    });
+    return nodes;
+  }
+  async onSearch(e: string) {
+    this.nodes = await this.getDepart('', e);
+  }
+  onSearchPro(e: string){
+    this.getEduProcess()
+  }
+  changeDepart(e: any) {
+    this.currentDepart = e;
+    this.getEduProcess();
+  }
+
+  async getEduProcess() {
+    this.eduProcessList = [];
+    this.loading = true;
+    let query1= Parse.Query.fromJSON('EduProcess', {
+      where: {
+        $or: [
+          {
+            name: { "$regex": `.*${this.searchValuePro}.*`},
+          },
+        ]
+      }
+    });
+    let query2= Parse.Query.fromJSON('EduProcess', {
+      where: {
+        $or: [
+          {
+            code: { "$regex": `.*${this.searchValuePro}.*`},
+          },
+        ]
+      }
+    });
+    let query = Parse.Query.or(query1, query2)
+    query.include('profileSubmitted', 'profileSubmitted.user');
+    query.notEqualTo('isDeleted', true);
+    query.equalTo('department',this.tbookSer.profile.user.department.objectId)
+    let r = await query.find();
+    let list: any[] = [];
+    r.forEach((item) => {
+      let _item = item.toJSON();
+      _item['checked'] = false;
+      _item['state'] = this.formatStatus(_item);
+      list.push(_item);
+    });
+    this.eduProcessList = list;
+    this.loading = false;
+  }
+
+  onAllChecked(checked: boolean): void {
+    console.log(checked);
+    this.eduProcessList = this.eduProcessList.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;
+  }
+  onItemChecked(id: string, e: boolean) {
+    let checkedAll = true;
+    this.eduProcessList = this.eduProcessList.map((item) => {
+      if (id == item.objectId) item.checked = e;
+      if (!item.checked) checkedAll = false;
+      return item;
+    });
+    if (e) {
+      this.setOfCheckedId.add(id);
+    } else {
+      this.setOfCheckedId.delete(id);
+    }
+    this.checkedAll = checkedAll;
+  }
+
+  deleteSelected() {
+    this.modal.confirm({
+      nzTitle: '批量删除',
+      nzContent: `删除后数据不可恢复,请谨慎操作`,
+      nzOkText: '确认',
+      nzOkType: 'primary',
+      nzOkDanger: true,
+      nzOnOk: async () => {
+        let selectedList = this.eduProcessList.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'),
+    });
+  }
+  toUrl(url: string, params?: object) {
+    if (params) {
+      this.route.navigate([url, params]);
+    } else {
+      this.route.navigate([url]);
+    }
+  }
+}

+ 304 - 0
projects/textbook/src/modules/nav-province-contact/page-role/page-role.component.html

@@ -0,0 +1,304 @@
+<nz-page-header>
+  <nz-page-header-title
+    >申报单位管理
+    <br />
+    <div class="subtitle">
+      使用组织机构树管理使用“十四五”高等教育国家规划教材申报系统的所有单位,单位与申报工作流程相关联。
+    </div>
+  </nz-page-header-title>
+  <nz-page-header-extra>
+    <nz-space>
+      <button
+        style="background: #3e49b3; border: 1px #3e49b3"
+        *nzSpaceItem
+        nz-button
+        nzType="primary"
+        (click)="addMember()"
+      >
+        添加账号
+      </button>
+    </nz-space>
+  </nz-page-header-extra>
+</nz-page-header>
+<div class="edit-content">
+  <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"
+          />
+        </nz-input-group>
+        <ng-template #prefixTemplateUser
+          ><span nz-icon nzType="search"></span
+        ></ng-template>
+        <button
+          nz-button
+          nzType="default"
+          nz-dropdown
+          [nzDropdownMenu]="menutep"
+          [nzPlacement]="'bottomLeft'"
+          style="margin-left: 10px"
+        >
+          <span nz-icon nzType="plus" nzTheme="outline"></span>新建
+        </button>
+        <nz-dropdown-menu #menutep="nzDropdownMenu">
+          <ul nz-menu>
+            <li nz-menu-item>
+              <button
+                nz-button
+                nzType="link"
+                (click)="showModalDepart('add')"
+                style="color: #231c1f"
+              >
+                <span nz-icon nzType="plus" nzTheme="outline"></span>添加部门
+              </button>
+            </li>
+            <li nz-menu-item>
+              <button
+                nz-button
+                nzType="link"
+                style="color: #231c1f"
+                (click)="showModalOrganize()"
+              >
+                <span nz-icon nzType="merge" nzTheme="outline"></span>
+                新建组织
+              </button>
+            </li>
+          </ul>
+        </nz-dropdown-menu>
+      </div>
+      <div class="">{{ currentDepart ? currentDepart.title : "" }}</div>
+      <div class="tag">
+        <span nz-icon nzType="team" nzTheme="outline"></span>
+        {{ profiles.length }}人
+      </div>
+      <label nz-checkbox [(ngModel)]="checkedShowFilter"
+        >仅显示部门直属成员</label
+      >
+    </div>
+    <div class="tool-right">
+      <a nz-button nzType="link" (click)="addMember()">
+        <span nz-icon nzType="plus" nzTheme="outline"></span>添加成员
+      </a>
+    </div>
+  </div>
+  <div class="layout" #maxWidth>
+    <div class="sider" #sider>
+      <nz-tree
+        [nzData]="nodes"
+        nzAsyncData
+        [nzSearchValue]="searchValue"
+        (nzClick)="nzEvent($event)"
+        (nzExpandChange)="nzEvent($event)"
+        (nzSearchValueChange)="onSearch($event)"
+        [nzTreeTemplate]="nzTreeTemplate"
+      ></nz-tree>
+      <ng-template #nzTreeTemplate let-node let-origin="origin">
+        <span
+          class="custom-node"
+          (contextmenu)="contextMenu($event, menu, node)"
+        >
+          <span class="folder-name">{{ node.title }}</span>
+        </span>
+      </ng-template>
+      <!-- 节点右键菜单 -->
+      <nz-dropdown-menu #menu="nzDropdownMenu">
+        <ul nz-menu>
+          <li nz-menu-item (click)="showModalDepart('add')">添加下级部门</li>
+          <li nz-menu-item (click)="showModalDepart('edit')">编辑部门</li>
+          <li nz-menu-item (click)="onDelDepart()">删除部门</li>
+        </ul>
+      </nz-dropdown-menu>
+    </div>
+    <div class="breadcrumb">
+      <nz-table
+        #tableData
+        [nzData]="profiles"
+        [nzTotal]="profiles.length"
+        [nzPageSize]="10"
+        style="margin: 10px 0"
+        [nzLoading]="loading"
+        nzSize="middle"
+        [nzNoResult]="emptyResult"
+      >
+        <thead>
+          <tr>
+            <th
+              nzWidth="120px"
+              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="120px">所属部门</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, $event)"
+            ></td>
+            <td
+              nzLeft
+              nzEllipsis
+              (click)="goDateil(data.user?.objectId)"
+              class="activeTd"
+            >
+              <nz-avatar nzIcon="user"></nz-avatar>
+              {{ data?.user.name }}
+            </td>
+            <td>
+              {{ data?.user.phone }}
+            </td>
+            <td>
+              {{ data?.user.email || data?.email }}
+            </td>
+            <td>
+              {{ data?.identity }}
+            </td>
+            <td>
+              {{ data?.user.departmentName }}
+            </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>
+                  <li nz-menu-item>
+                    <button nz-button style="color: #231c1f" nzType="link">
+                      <span nz-icon nzType="stop" 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>
+  </div>
+</div>
+<nz-modal
+  [(nzVisible)]="isVisible"
+  nzTitle="{{ editType == 'edit' ? '编辑' : '新建' }}部门"
+  (nzOnCancel)="handleCancel()"
+  nzWidth="800px"
+  nzCentered
+>
+  <ng-container *nzModalContent>
+    <div nz-row class="depart-modal">
+      <div nz-col nzSpan="12">
+        <div class="row">
+          <div class="label">部门名称</div>
+          <div class="value">
+            <input
+              nz-input
+              placeholder="请输入部门名称"
+              [(ngModel)]="editObject.name"
+              type="text"
+            />
+          </div>
+        </div>
+        <div class="row">
+          <div class="label">code</div>
+          <div class="value">
+            <input
+              nz-input
+              placeholder="请输入code"
+              [(ngModel)]="editObject.code"
+              type="text"
+            />
+          </div>
+        </div>
+        <div class="row">
+          <div class="label">部门描述</div>
+          <div class="value">
+            <textarea
+              [nzAutosize]="{ minRows: 4, maxRows: 4 }"
+              placeholder="请输入部门描述"
+              nz-input
+              [(ngModel)]="editObject.desc"
+            ></textarea>
+          </div>
+        </div>
+      </div>
+      <div nz-col nzSpan="12">
+        <div class="row">
+          <div class="label">上级部门</div>
+          <div class="value">
+            <input
+              nz-input
+              placeholder="请选择上级"
+              [ngModel]="editObject.parent?.title"
+              type="text"
+            />
+          </div>
+        </div>
+        <div class="select">
+          <div class="bar">
+            <a style="color: #86909c" (click)="onPre(nodes[0].key)">{{
+              nodes[0].title
+            }}</a>
+            @for (data of parentMap; track data.title) {
+            <span style="margin: 0 10px">/</span>
+            <a (click)="onPre(data.key, $index)">{{ data.title }}</a>
+            }
+          </div>
+          <div class="tree">
+            @if (parentList.length > 0) { @for (data of parentList; track
+            $index) {
+            <div class="li" (click)="onCheckedDepart(data)">
+              <label
+                nz-radio
+                ngModel
+                [nzValue]="data.key"
+                (click)="onCheckedDepart(data, true)"
+                >{{ data.title }}</label
+              >
+              <span nz-icon nzType="right" nzTheme="outline"></span>
+            </div>
+            } }
+            @else {
+              <nz-empty nzNotFoundContent="暂无部门"></nz-empty> 
+            }
+          </div>
+        </div>
+      </div>
+    </div>
+  </ng-container>
+  <div *nzModalFooter>
+    <button nz-button nzType="default" (click)="handleCancel()">取消</button>
+    <button
+      nz-button
+      nzType="primary"
+      style="background: #3e49b3; border: 1px #3e49b3"
+      (click)="handleOk()"
+    >
+      确定
+    </button>
+  </div>
+</nz-modal>

+ 118 - 0
projects/textbook/src/modules/nav-province-contact/page-role/page-role.component.scss

@@ -0,0 +1,118 @@
+.subtitle{
+  margin-right: 12px;
+  color: #00000073;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 1.5715;
+  // overflow: hidden;
+  // white-space: nowrap;
+  // text-overflow: ellipsis;
+}
+.edit-content{
+  margin: 0 0 20px;
+  padding: 0 24px;
+  height: calc(100vh - 192px);
+  min-width: 1100px;
+  .tool{
+    display: flex;
+    justify-content: space-between;
+    .tool-left{
+      display: flex;
+      align-items: center;
+      .search{
+        display: flex;
+        width: 280px;
+        margin-right: 20px;
+      }
+      .tag{
+        background: #f7f7f7;
+        display: flex;
+        align-items: center;
+        color: #6f6f6f;
+        line-height: 26px;
+        padding: 0 8px;
+        margin: 0 10px;
+      }
+    }
+  }
+  .layout{
+    display: flex;
+    width: 100%;
+    .sider{
+      width: 280px;
+      margin: 10px 0;
+      height: calc(100vh - 192px);
+      overflow-y: scroll;
+      flex-shrink: 0;
+      margin-right: 20px;
+      .custom-node{
+        display: flex;
+      }
+      .folder-desc{
+        display: none;
+        margin-left: 10px;
+        background-color: white;
+        color: #ba1a1a;
+        border: none;
+      }
+      .custom-node:hover .folder-desc{
+        display: block;
+      }
+      .custom-name:hover .folder-desc{
+        display: block;
+      }
+    }
+    .breadcrumb{
+      flex: 1;
+    }
+  }
+  .activeTd{
+    cursor: pointer;
+  }
+  .activeTd:hover{
+    color: #c6233f;
+  }
+}
+.depart-modal{
+  .row{
+    width: 90%;
+    margin-bottom: 20px;
+  }
+  .tree{
+    height: 180px;
+    overflow-y: scroll;
+    .li{
+      display: flex;
+      justify-content: space-between;
+      padding: 8px 4px;
+      span{
+        flex-shrink: 0;
+      }
+    }
+    .li:hover{
+      background-color: #f9f9f9;
+    }
+  }
+}
+::ng-deep .ant-page-header-heading-title{
+  white-space: normal;
+}
+::ng-deep .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn{
+  color: #c6233f;
+}
+::ng-deep .ant-tabs-ink-bar{
+  background: #c6233f;
+}
+::ng-deep .ant-tabs-tab:hover{
+  color: #e97488;
+}
+::ng-deep .ant-tabs-tab-btn:active{
+  color: #e97488;
+}
+::ng-deep .ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected{
+  background-color: #ba1a1a;
+  color: white;
+}
+::ng-deep .ant-tree .ant-tree-node-content-wrapper:hover{
+  background-color: #eae6e6;
+}

+ 6 - 6
projects/textbook/src/modules/nav-province-contact/page-collection/page-collection.component.spec.ts → projects/textbook/src/modules/nav-province-contact/page-role/page-role.component.spec.ts

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

+ 335 - 0
projects/textbook/src/modules/nav-province-contact/page-role/page-role.component.ts

@@ -0,0 +1,335 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { ActivatedRoute, Route, Router, 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';
+import { Department } from '../../../schemas/Department';
+import { NzSpaceModule } from 'ng-zorro-antd/space';
+import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
+import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';
+import { CommonCompModule } from '../../../services/common.modules';
+import { NzModalModule } from 'ng-zorro-antd/modal';
+import {
+  NzFormatEmitEvent,
+  NzTreeModule,
+  NzTreeNode,
+} from 'ng-zorro-antd/tree';
+import {
+  NzContextMenuService,
+  NzDropdownMenuComponent,
+} from 'ng-zorro-antd/dropdown';
+import { NzCheckboxModule } from 'ng-zorro-antd/checkbox';
+import { NzEmptyModule } from 'ng-zorro-antd/empty';
+import { NzRadioModule } from 'ng-zorro-antd/radio';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import { textbookServer } from '../../../services/textbook';
+interface nodes {
+  title: string;
+  key: string;
+  isLeaf?: boolean;
+  isParent?: boolean;
+  children?: Array<any>;
+}
+interface depart {
+  name: string;
+  id?: string;
+  code?: string;
+  desc?: string;
+  parent?: object | any;
+  branch: string;
+}
+@Component({
+  selector: 'app-page-role',
+  templateUrl: './page-role.component.html',
+  styleUrls: ['./page-role.component.scss'],
+  imports: [
+    CommonModule,
+    CommonCompModule,
+    RouterOutlet,
+    CompTableListComponent,
+    NzSpaceModule,
+    NzPageHeaderModule,
+    NzBreadCrumbModule,
+    NzTreeModule,
+    NzCheckboxModule,
+    NzEmptyModule,
+    NzModalModule,
+    NzRadioModule,
+  ],
+  standalone: true,
+})
+export class PageRoleComponent implements OnInit {
+  @ViewChild(CompTableListComponent) list: CompTableListComponent | undefined;
+
+  // _Role = _Role
+  Department = Department;
+  user: Parse.User | undefined;
+  className: string | undefined;
+  queryParams: any | undefined;
+  fieldsArray: Array<any> | undefined;
+  searchValue: string = ''; //搜索内容
+  nodes: Array<nodes | any> = [];
+  currentDepart: nodes | any = null;
+
+  profiles: Array<any> = [];
+  checkedShowFilter: boolean = false;
+
+  checkedAll: boolean = false; //全选
+  indeterminate = false;
+  loading = false;
+
+  isVisible: boolean = false;
+  activatedNode: NzTreeNode | any; //当前选择节点
+  editType: string = 'add'; //弹窗类型
+  activeDepart?: Parse.Object; //当前编辑部门
+  editObject: depart = {
+    name: '',
+    code: '',
+    desc: '',
+    parent: {},
+    branch: '',
+  };
+  parentMap: Array<any> = [];
+  parentList: Array<any> = [];
+
+  constructor(
+    public tbookSer: textbookServer,
+    private route: Router,
+    private activeRoute: ActivatedRoute,
+    private nzContextMenuService: NzContextMenuService,
+    private message: NzMessageService,
+  ) {
+    this.user = Parse.User.current();
+    this.className = this.Department.className;
+    this.fieldsArray = this.Department.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();
+      if(!this.tbookSer.profile.user.department.objectId){
+        this.message.warning('权限不足')
+        history.back()
+        return
+      }
+      this.nodes = [{
+        title: this.tbookSer.profile.user.department.name,
+        key: this.tbookSer.profile.user.department.objectId,
+        children: [...await this.getDepart(this.tbookSer.profile.user.department.objectId)],
+        isParent: false,
+        isLeaf: false,
+      }];
+    });
+  }
+  async getDepart(
+    parent?: string,
+    searchValue?: string
+  ): Promise<Array<nodes>> {
+    let nodes: any = [];
+    let query = new Parse.Query('Department');
+    query.equalTo('parent', parent ? parent : undefined);
+    searchValue && query.contains('name', searchValue);
+    query.notEqualTo('isDeleted', true);
+    query.select('code', 'name', 'branch', 'parent','type');
+    query.descending('createdAt');
+    query.limit(2000);
+    let res = await query.find();
+    res.forEach((item) => {
+      nodes.push({
+        title: item.get('name'),
+        key: item.id,
+        children: [],
+        isParent: item.get('type') =='单位' ? true : false, //是否是最下级
+        isLeaf: false,
+      });
+    });
+    return nodes;
+  }
+  //添加成员
+  addMember() {
+    this.message.warning('权限灰度中')
+  }
+  //展开/合并
+  async nzEvent(event: NzFormatEmitEvent): Promise<void> {
+    console.log(event);
+    let node: any = event.node;
+    if (event.eventName === 'expand') {
+      if (node.origin.isParent) {
+        node.addChildren([]);
+        return;
+      }
+      if (node?._children.length <= 0) {
+        let data = await this.getDepart(node.key);
+        node.addChildren(data);
+      }
+      console.log(this.nodes);
+    } else {
+      // if (node.origin.isParent) {
+        this.currentDepart = node.origin;
+        this.getProfile();
+      // }
+    }
+  }
+  async getProfile() {
+    this.profiles = [];
+    this.loading = true;
+    let queryParams = {
+      where : {
+        "$or": [{
+          "user": {
+            "$inQuery": {
+              "where": {
+                "$or": [{
+                    "department": { "$eq": this.currentDepart.key}
+                  },
+                ]
+              },
+              "className": "_User"
+            }
+          }
+        }]
+      }
+    }
+    let query = Parse.Query.fromJSON('Profile',queryParams);
+    query.include('user');
+    query.notEqualTo('identity', '国家级管理员');
+    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;
+  }
+  //搜索触发
+  onSearch(event: NzFormatEmitEvent) {
+    console.log(event);
+  }
+  contextMenu(
+    $event: MouseEvent,
+    menu: NzDropdownMenuComponent,
+    node?: any
+  ): void {
+    console.log(node);
+    this.activatedNode = node;
+    this.nzContextMenuService.create($event, menu);
+  }
+  //删除部门
+  onDelDepart() {
+    this.message.warning('权限灰度中')
+  }
+
+  onAllChecked(checked: boolean): void {
+    console.log(checked);
+    this.profiles = this.profiles.map((item) => {
+      item.checked = checked;
+      return item;
+    });
+    this.checkedAll = checked;
+  }
+  onItemChecked(id: 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;
+    });
+    this.checkedAll = checkedAll;
+  }
+  //新建打开弹窗
+  async showModalDepart(type: string) {
+    if (type == 'edit') {
+      let query = new Parse.Query('Department');
+      let r = await query.get(this.activatedNode?.key);
+      this.activeDepart = r;
+      this.parentMap = this.formatNode(this.activatedNode);
+      if(this.activatedNode?.parentNode?.origin.key){
+        this.parentList = await this.getDepart(this.activatedNode.parentNode.origin.key);
+      }
+    }else{
+      this.parentList = await this.getDepart(this.tbookSer.profile.user.department.objectId)
+    }
+    this.editType = type;
+    this.isVisible = true;
+  }
+  //格式化链
+  formatNode(node: NzTreeNode): Array<any> {
+    let arr = [];
+    if (node.parentNode?.origin.title) {
+      arr.push({
+        title: node.parentNode?.origin.title,
+        key: node.parentNode?.origin.key,
+      });
+      arr.unshift(...this.formatNode(node.parentNode));
+    }
+    return arr;
+  }
+  async onPre(key?:any,index?:number){
+    if(!key){
+      // this.parentList = await this.getDepart();
+      // this.parentMap = []
+      return
+    }
+    // if(index == this.parentMap.length-1) return
+    if(index !== 0 && !index) this.parentMap.splice(index || 0+1)
+    this.parentList = await this.getDepart(key);
+  }
+  //选择所属类别下级列表
+  async onCheckedDepart(e: any, checked?: boolean) {
+    console.log(e);
+    if (checked) {
+      this.editObject = {
+        name: e.title,
+        code: '',
+        desc: '',
+        parent: e,
+        branch: '',
+      };
+      return;
+    }
+    this.parentMap.push({
+      title: e.title,
+      key: e.key,
+    });
+    this.parentList = await this.getDepart(e?.key);
+  }
+  handleOk(): void {
+    this.message.warning('权限灰度中')
+    this.isVisible = false;
+  }
+
+  handleCancel(): void {
+    console.log('Button cancel clicked!');
+    this.isVisible = false;
+    this.activatedNode = undefined;
+    this.parentMap = [];
+    this.activeDepart = undefined
+  }
+
+  /* 组织 */
+  showModalOrganize(){
+    this.message.warning('权限灰度中')
+  }
+  goDateil(id:string){
+    this.route.navigate([
+      '/nav-admin/manage/user/edit',
+      { id:id },
+    ])
+  }
+}

+ 6 - 3
projects/textbook/src/modules/nav-province-contact/page-textbook/page-textbook.component.html

@@ -1,14 +1,17 @@
 <nz-page-header>
   <nz-breadcrumb nz-page-header-breadcrumb>
-    <nz-breadcrumb-item>报送联系人</nz-breadcrumb-item>
+    <nz-breadcrumb-item>教材申报</nz-breadcrumb-item>
     <nz-breadcrumb-item><a>全部教材</a></nz-breadcrumb-item>
   </nz-breadcrumb>
 </nz-page-header>
-<comp-table-list
+<!-- <comp-table-list
   #list
   [schema]="EduTextbook"
   *ngIf="className && fieldsArray"
   [className]="className"
   [fieldsArray]="fieldsArray"
   [queryParams]="queryParams"
-></comp-table-list>
+></comp-table-list> -->
+<div class="conetent">
+  <app-textbook></app-textbook>
+</div>

+ 4 - 0
projects/textbook/src/modules/nav-province-contact/page-textbook/page-textbook.component.scss

@@ -0,0 +1,4 @@
+.conetent{
+  margin: 0 0 20px;
+  padding: 0 24px;
+}

+ 16 - 12
projects/textbook/src/modules/nav-province-contact/page-textbook/page-textbook.component.ts

@@ -6,11 +6,20 @@ import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
 import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb';
 import * as Parse from 'parse';
 import { CommonModule } from '@angular/common';
+import { textbookServer } from '../../../services/textbook';
+import { TextbookComponent } from '../../../app/textbook/textbook.component';
 @Component({
   selector: 'app-page-textbook',
   templateUrl: './page-textbook.component.html',
   styleUrls: ['./page-textbook.component.scss'],
-  imports: [CommonModule, RouterOutlet, CompTableListComponent,NzPageHeaderModule,NzBreadCrumbModule],
+  imports: [
+    CommonModule,
+    RouterOutlet,
+    TextbookComponent,
+    CompTableListComponent,
+    NzPageHeaderModule,
+    NzBreadCrumbModule,
+  ],
   standalone: true,
 })
 export class PageTextbookComponent implements OnInit {
@@ -25,10 +34,10 @@ export class PageTextbookComponent implements OnInit {
   fieldsArray: Array<any> | undefined;
 
   constructor(
+    public tbookSer: textbookServer,
     private router: Router,
-    private activeRoute: ActivatedRoute
-  ) // private translate:TranslateService,
-  {
+    private activeRoute: ActivatedRoute // private translate:TranslateService,
+  ) {
     this.user = Parse.User.current();
     this.className = this.EduTextbook.className;
     this.fieldsArray = this.EduTextbook.fieldsArray;
@@ -36,16 +45,11 @@ export class PageTextbookComponent implements OnInit {
       where: {
         isDeleted: { $ne: true },
         render: true,
-        discard:{$ne: true},
+        discard: { $ne: true },
+        department: this.tbookSer.profile.user.department.objectId,
       },
     };
   }
 
-  ngOnInit(): void {
-    // this.queryParams.where = {
-    //   isDeleted: { $ne: true },
-    //   discard: this.discard ? { $eq: true } : { $ne: true },
-    //   render: this.render ? { $eq: true } : { $ne: true },
-    // };
-  }
+  ngOnInit(): void {}
 }

+ 17 - 0
projects/textbook/src/modules/nav-province-school-contact/modules.routes.ts

@@ -1,5 +1,10 @@
 import { NgModule } from "@angular/core";
 import { RouterModule, Routes } from "@angular/router";
+import { PageUserComponent } from "../nav-admin/page-user/page-user.component";
+import { UserEditComponent } from "../nav-admin/user-edit/user-edit.component";
+import { SpaceComponent } from "../nav-author/space/space.component";
+import { PageRoleComponent } from "../nav-province-contact/page-role/page-role.component";
+import { PageTextbookComponent } from "../nav-province-contact/page-textbook/page-textbook.component";
 const routes: Routes = [
   {
     path: '',
@@ -9,6 +14,18 @@ const routes: Routes = [
   {
     path: 'manage',
     children:[
+      {
+        path: 'textbook', //全部教材
+        component: PageTextbookComponent,
+      },
+      {
+        path: 'role', //组织列表
+        component: PageRoleComponent,
+      },
+      {
+        path: 'space',//个人空间
+        component: SpaceComponent,
+      },
     ]
   }
 ];

+ 2 - 1
projects/textbook/src/services/auth.service.ts

@@ -17,7 +17,7 @@ export class AuthServr {
   redirectUrl: string = '';
   roterPath: any = {
     '国家级管理员': '/nav-admin',
-    '报送联系人': '/nav-province-contact',
+    '工作联系人': '/nav-province-contact',
     '高校联系人': '/nav-province-school-contact',
     '评审专家': '/nav-review',
     '个人': '/nav-author/manage/space',
@@ -138,6 +138,7 @@ export class AuthServr {
     let query = new Parse.Query('Profile');
     query.equalTo('user', Parse.User.current()?.id);
     query.notEqualTo('isDeleted', true);
+    query.include('user', 'user.department');
     let r = await query.first();
     if (r?.id) {
       let user = Parse.User.current();

+ 3 - 1
projects/textbook/src/services/common.modules.ts

@@ -14,6 +14,7 @@ import { NzInputModule } from 'ng-zorro-antd/input';
 import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
 import { NzModalModule } from 'ng-zorro-antd/modal';
 import { NzSwitchModule } from 'ng-zorro-antd/switch';
+import { NzAvatarModule } from 'ng-zorro-antd/avatar';
 @NgModule({
   exports: [
     FormsModule,
@@ -30,7 +31,8 @@ import { NzSwitchModule } from 'ng-zorro-antd/switch';
     NzInputModule,
     NzDatePickerModule,
     NzModalModule,
-    NzSwitchModule
+    NzSwitchModule,
+    NzAvatarModule
   ]
 })
 export class CommonCompModule { }

+ 4 - 0
server/db/schemas/EduTextbook.js

@@ -20,6 +20,10 @@ export const EduTextbook = {
             "type": "Boolean",
             "required": false
         },
+        "recommend": { //是否推荐
+            "type": "Boolean",
+            "required": false
+        },
         "complete": { //是否填写完整
             "type": "Boolean",
             "required": false