Browse Source

update 申报流程

warrior 8 months ago
parent
commit
ac4c6dff79
36 changed files with 1898 additions and 604 deletions
  1. 5 5
      projects/textbook/src/app/comp-manage/comp-manage.component.ts
  2. 0 0
      projects/textbook/src/modules/nav-admin/collection/collection-edit/collection-edit.component.html
  3. 0 0
      projects/textbook/src/modules/nav-admin/collection/collection-edit/collection-edit.component.scss
  4. 0 0
      projects/textbook/src/modules/nav-admin/collection/collection-edit/collection-edit.component.spec.ts
  5. 4 4
      projects/textbook/src/modules/nav-admin/collection/collection-edit/collection-edit.component.ts
  6. 0 0
      projects/textbook/src/modules/nav-admin/collection/create-collection/create-collection.component.html
  7. 0 0
      projects/textbook/src/modules/nav-admin/collection/create-collection/create-collection.component.scss
  8. 0 0
      projects/textbook/src/modules/nav-admin/collection/create-collection/create-collection.component.spec.ts
  9. 5 5
      projects/textbook/src/modules/nav-admin/collection/create-collection/create-collection.component.ts
  10. 0 0
      projects/textbook/src/modules/nav-admin/collection/page-collection/page-collection.component.html
  11. 0 0
      projects/textbook/src/modules/nav-admin/collection/page-collection/page-collection.component.scss
  12. 0 0
      projects/textbook/src/modules/nav-admin/collection/page-collection/page-collection.component.spec.ts
  13. 2 2
      projects/textbook/src/modules/nav-admin/collection/page-collection/page-collection.component.ts
  14. 61 24
      projects/textbook/src/modules/nav-admin/components/profile/profile.component.html
  15. 27 4
      projects/textbook/src/modules/nav-admin/components/profile/profile.component.ts
  16. 27 16
      projects/textbook/src/modules/nav-admin/modules.routes.ts
  17. 34 0
      projects/textbook/src/modules/nav-admin/page-process/page-process.component.html
  18. 30 0
      projects/textbook/src/modules/nav-admin/page-process/page-process.component.scss
  19. 24 0
      projects/textbook/src/modules/nav-admin/page-process/page-process.component.spec.ts
  20. 67 0
      projects/textbook/src/modules/nav-admin/page-process/page-process.component.ts
  21. 393 0
      projects/textbook/src/modules/nav-admin/page-process/process-create/process-create.component.html
  22. 137 0
      projects/textbook/src/modules/nav-admin/page-process/process-create/process-create.component.scss
  23. 0 0
      projects/textbook/src/modules/nav-admin/page-process/process-create/process-create.component.spec.ts
  24. 307 0
      projects/textbook/src/modules/nav-admin/page-process/process-create/process-create.component.ts
  25. 229 0
      projects/textbook/src/modules/nav-admin/page-process/process-list/process-list.component.html
  26. 167 0
      projects/textbook/src/modules/nav-admin/page-process/process-list/process-list.component.scss
  27. 24 0
      projects/textbook/src/modules/nav-admin/page-process/process-list/process-list.component.spec.ts
  28. 330 0
      projects/textbook/src/modules/nav-admin/page-process/process-list/process-list.component.ts
  29. 3 2
      projects/textbook/src/modules/nav-admin/page-role/page-role.component.scss
  30. 1 1
      projects/textbook/src/modules/nav-admin/page-role/page-role.component.ts
  31. 0 257
      projects/textbook/src/modules/nav-admin/process-create/process-create.component.html
  32. 0 74
      projects/textbook/src/modules/nav-admin/process-create/process-create.component.scss
  33. 0 205
      projects/textbook/src/modules/nav-admin/process-create/process-create.component.ts
  34. 1 1
      projects/textbook/src/modules/nav-admin/user-edit/user-edit.component.html
  35. 2 1
      projects/textbook/src/modules/nav-admin/user-edit/user-edit.component.ts
  36. 18 3
      server/db/schemas/EduProcess.js

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

@@ -30,13 +30,13 @@ export class CompManageComponent implements OnInit {
         id:'1',
         child:[
           {
-            name:'报送合集',
-            path:"/nav-admin/manage/collection",
+            name:'申报流程',
+            path:"/nav-admin/manage/process",
             id:'1-1',
           },
           {
             name:'全部教材',
-            path:'/nav-admin/manage/allcollection',
+            path:'/nav-admin/manage/textbook',
             id:'1-2',
           },
         ]
@@ -82,8 +82,8 @@ export class CompManageComponent implements OnInit {
         id:'1',
         child:[
           {
-            name:'报送合集',
-            path:'/nav-province-contact/manage/collection',
+            name:'申报流程',
+            path:'/nav-province-contact/manage/process',
             id:'1-1',
           },
           {

+ 0 - 0
projects/textbook/src/modules/nav-admin/collection-edit/collection-edit.component.html → projects/textbook/src/modules/nav-admin/collection/collection-edit/collection-edit.component.html


+ 0 - 0
projects/textbook/src/modules/nav-admin/collection-edit/collection-edit.component.scss → projects/textbook/src/modules/nav-admin/collection/collection-edit/collection-edit.component.scss


+ 0 - 0
projects/textbook/src/modules/nav-admin/collection-edit/collection-edit.component.spec.ts → projects/textbook/src/modules/nav-admin/collection/collection-edit/collection-edit.component.spec.ts


+ 4 - 4
projects/textbook/src/modules/nav-admin/collection-edit/collection-edit.component.ts → projects/textbook/src/modules/nav-admin/collection/collection-edit/collection-edit.component.ts

@@ -1,14 +1,14 @@
 import { Component, Input, OnInit } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { NzSpaceModule } from 'ng-zorro-antd/space';
-import { CommonCompModule } from '../../../services/common.modules';
+import { CommonCompModule } from '../../../../services/common.modules';
 import { NzTabsModule } from 'ng-zorro-antd/tabs';
-import { ProcessComponent } from '../components/process/process.component';
+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 { EduTextbook } from '../../../../schemas/EduTextbook';
+import { CompTableListComponent } from '../../../../app/comp-table/comp-table-list/comp-table-list.component';
 @Component({
   selector: 'app-collection-edit',
   templateUrl: './collection-edit.component.html',

+ 0 - 0
projects/textbook/src/modules/nav-admin/create-collection/create-collection.component.html → projects/textbook/src/modules/nav-admin/collection/create-collection/create-collection.component.html


+ 0 - 0
projects/textbook/src/modules/nav-admin/create-collection/create-collection.component.scss → projects/textbook/src/modules/nav-admin/collection/create-collection/create-collection.component.scss


+ 0 - 0
projects/textbook/src/modules/nav-admin/create-collection/create-collection.component.spec.ts → projects/textbook/src/modules/nav-admin/collection/create-collection/create-collection.component.spec.ts


+ 5 - 5
projects/textbook/src/modules/nav-admin/create-collection/create-collection.component.ts → projects/textbook/src/modules/nav-admin/collection/create-collection/create-collection.component.ts

@@ -1,6 +1,6 @@
 import { Component, Input, OnInit } from '@angular/core';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { CommonCompModule } from '../../../services/common.modules';
+import { CommonCompModule } from '../../../../services/common.modules';
 import { Router, ActivatedRoute } from '@angular/router';
 import { NzSelectModule } from 'ng-zorro-antd/select';
 import Parse from 'parse';
@@ -10,12 +10,12 @@ import {
   NonNullableFormBuilder,
   Validators,
 } from '@angular/forms';
-import { textbookServer } from '../../../services/textbook';
+import { textbookServer } from '../../../../services/textbook';
 import { NzMessageService } from 'ng-zorro-antd/message';
 import { NzModalService } from 'ng-zorro-antd/modal';
-import { provinces } from '../../../services/provinces';
-import { SubmittedComponent } from '../components/submitted/submitted.component';
-import { ProfileComponent } from '../components/profile/profile.component';
+import { provinces } from '../../../../services/provinces';
+import { SubmittedComponent } from '../../components/submitted/submitted.component';
+import { ProfileComponent } from '../../components/profile/profile.component';
 import { MatButtonModule } from '@angular/material/button';
 @Component({
   selector: 'app-create-collection',

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


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


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


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

@@ -1,7 +1,7 @@
 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 { 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';

+ 61 - 24
projects/textbook/src/modules/nav-admin/components/profile/profile.component.html

@@ -12,47 +12,84 @@
   [nzScroll]="{ x: (maxWidth || '800') + 'px', y: '480px' }"
   [nzTotal]="profiles.length"
   [nzPageSize]="10"
-  style="margin: 10px 0"
+    nzTableLayout="fixed"
+    style="margin: 10px 0"
 >
   <thead>
     <tr>
-      <th nzWidth="120px" nzLeft>姓名</th>
+      <th nzWidth="120px" nzLeft>账号</th>
       <th nzWidth="120px">电话号码</th>
       <th nzWidth="120px">邮箱</th>
-      <th nzWidth="120px">注册时间</th>
-      <th nzWidth="120px">是否填报人</th>
+      <th nzWidth="120px">所属部门</th>
       @if (!disabled) {
-      <th nzWidth="120px" nzRight>操作</th>
+      <th nzWidth="50px" nzRight>操作</th>
       }
     </tr>
   </thead>
   <tbody>
     @for (data of profiles; track data.id) {
     <tr>
-      <td nzLeft>
-        {{ data?.get('user').get("name") }}
+      <td nzEllipsis nzLeft>
+        <nz-avatar nzIcon="user"></nz-avatar>
+        {{ data?.get("user").get("name") }}
       </td>
-      <td>
-        {{ data?.get('user').get("phone") }}
+      <td nzEllipsis>
+        {{ data?.get("user").get("phone") }}
       </td>
-      <td>
-        {{ data?.get('user').get("phone") || data?.get("email") }}
+      <td nzEllipsis>
+        {{ data?.get("user").get("phone") || data?.get("email") }}
       </td>
-      <td>
-        {{ data?.createdAt | date : "yyyy-MM-dd" }}
+      <td nzEllipsis>
+        {{ data?.get("user").get("departmentName") }}
       </td>
-      <td>
-        <nz-switch [ngModel]="checked(data.id)" nzDisabled></nz-switch>
+      <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>
+            @if (!disabled) {
+            <li nz-menu-item>
+              @if(checked(data.id)){
+              <button
+                nz-button
+                (click)="onChange(data.id)"
+                nzType="link"
+                style="color: #231c1f"
+              >
+                <span nz-icon nzType="delete" nzTheme="outline"></span>取消权限
+              </button>
+              }@else {
+              <button
+                nz-button
+                (click)="onChange(data.id)"
+                nzType="link"
+                style="color: #231c1f"
+              >
+                <span nz-icon nzType="edit" nzTheme="outline"></span>设置权限
+              </button>
+              }
+            </li>
+            } @else {
+            <li nz-menu-item>
+              <button
+                nz-button
+                [disabled]="user?.get('isDeleted')"
+                nzType="link"
+                style="color: #231c1f"
+              >
+                <span nz-icon nzType="delete" nzTheme="outline"></span>删除
+              </button>
+            </li>
+            }
+          </ul>
+        </nz-dropdown-menu>
       </td>
-      @if (!disabled) {
-      <td nzRight>
-        @if(checked(data.id)){
-        <a (click)="onChange(data.id)" style="color: #c6233f">取消权限</a>
-        }@else {
-        <a (click)="onChange(data.id)">设置权限</a>
-        }
-      </td>
-      }
     </tr>
     }
   </tbody>

+ 27 - 4
projects/textbook/src/modules/nav-admin/components/profile/profile.component.ts

@@ -5,12 +5,13 @@ import { CompTableListComponent } from '../../../../app/comp-table/comp-table-li
 import { Profile } from '../../../../schemas/Profile';
 import * as Parse from 'parse';
 import { CommonModule } from '@angular/common';
+import { NzAvatarModule } from 'ng-zorro-antd/avatar';
 import { NzMessageService } from 'ng-zorro-antd/message';
 @Component({
   selector: 'app-profile',
   templateUrl: './profile.component.html',
   styleUrls: ['./profile.component.scss'],
-  imports: [CommonModule, RouterOutlet, CompTableListComponent, CommonCompModule],
+  imports: [CommonModule, RouterOutlet, CompTableListComponent, CommonCompModule,NzAvatarModule],
   standalone: true,
 })
 export class ProfileComponent  implements OnInit {
@@ -18,7 +19,7 @@ export class ProfileComponent  implements OnInit {
   @Input('maxChecked') maxChecked:number = 1 //最大可操作数量
   @Input('idList') idList:Array<string> = [] //已指向id
   @Input('identity') identity:any //指定身份类型
-  @Input('province') province:any //指定省份
+  @Input('depart') depart:any //指定单位
   @Input('disabled') disabled:boolean = false //禁止编辑
 
   @Output() change: EventEmitter<any> = new EventEmitter<any>();
@@ -54,10 +55,29 @@ export class ProfileComponent  implements OnInit {
   }
   async getProfile(){
     let query = new Parse.Query('Profile')
+    if(this.depart){
+      let queryParams = {
+        where : {
+          "$or": [{
+            "user": {
+              "$inQuery": {
+                "where": {
+                  "$or": [{
+                    "department": { "$eq": this.depart},
+                    },
+                  ]
+                },
+                "className": "_User"
+              }
+            }
+          }]
+        }
+      }
+      query = Parse.Query.fromJSON('Profile',queryParams);
+    }
     this.identity && query.equalTo('identity',this.identity)
-    this.province && query.equalTo('province',this.province)
     this.disabled && query.containedIn('objectId',this.idList)
-    query.include('user')
+    query.include('user','user.department')
     this.profiles = await query.find()
   }
   onChange(id:string){
@@ -66,6 +86,9 @@ export class ProfileComponent  implements OnInit {
     if(index == -1){
       if(this.idList.length >= this.maxChecked){
         this.msg.warning('超出数量限制')
+        this.idList.shift()
+        this.idList.push(id)
+        console.log(this.idList);
         return
       }
       this.idList.push(id)

+ 27 - 16
projects/textbook/src/modules/nav-admin/modules.routes.ts

@@ -1,13 +1,15 @@
 import { NgModule } from '@angular/core';
 import { RouterModule, Routes } from '@angular/router';
-import { CollectionEditComponent } from './collection-edit/collection-edit.component';
-import { CreateCollectionComponent } from './create-collection/create-collection.component';
-import { PageCollectionComponent } from './page-collection/page-collection.component';
+import { CollectionEditComponent } from './collection/collection-edit/collection-edit.component';
+import { CreateCollectionComponent } from './collection/create-collection/create-collection.component';
+import { PageCollectionComponent } from './collection/page-collection/page-collection.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 { PageUserComponent } from './page-user/page-user.component';
-import { ProcessCreateComponent } from './process-create/process-create.component';
+import { ProcessCreateComponent } from './page-process/process-create/process-create.component';
 import { UserEditComponent } from './user-edit/user-edit.component';
+import { PageProcessComponent } from './page-process/page-process.component';
 const routes: Routes = [
   {
     path: '',
@@ -18,23 +20,32 @@ const routes: Routes = [
     path: 'manage',
     children:[
       {
-        path: 'collection', //合集列表
-        component: PageCollectionComponent,
+        path: 'process', //流程申报
+        component: ProcessListComponent,
       },
       {
-        path: 'collection/create', //创建&管理合集
-        component: CreateCollectionComponent,
-      },
-      {
-        path: 'collection/edit', //合集编辑
-        component: CollectionEditComponent,
+        path: 'process/create', //创建流程
+        component: ProcessCreateComponent,
       },
       {
-        path: 'process/create', //合集编辑
-        component: ProcessCreateComponent,
+        path: 'process/page', //流程详情
+        component: PageProcessComponent,
       },
+      // {
+      //   path: 'collection', //合集列表
+      //   component: PageCollectionComponent,
+      // },
+      // {
+      //   path: 'collection/create', //创建&管理合集
+      //   component: CreateCollectionComponent,
+      // },
+      // {
+      //   path: 'collection/edit', //合集编辑
+      //   component: CollectionEditComponent,
+      // },
+
       {
-        path: 'allcollection', //合集列表
+        path: 'textbook', //全部教材
         component: PageTextbookComponent,
       },
       {
@@ -46,7 +57,7 @@ const routes: Routes = [
         component: UserEditComponent,
       },
       {
-        path: 'role', //列表
+        path: 'role', //组织列表
         component: PageRoleComponent,
       },
     ]

+ 34 - 0
projects/textbook/src/modules/nav-admin/page-process/page-process.component.html

@@ -0,0 +1,34 @@
+<nz-page-header>
+  <nz-breadcrumb nz-page-header-breadcrumb>
+    <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>
+<div class="edit-content">
+  <nz-tabset [(nzSelectedIndex)]="active">
+    <nz-tab nzTitle="报送流程">
+      @if (active == 0) {
+      <app-process-create [isEdit]="true"></app-process-create>
+      }
+    </nz-tab>
+    <nz-tab nzTitle="教材列表">
+      @if (active == 1) {
+      <comp-table-list
+        #list
+        [schema]="EduTextbook"
+        *ngIf="className && fieldsArray"
+        [className]="className"
+        [fieldsArray]="fieldsArray"
+        [queryParams]="queryParams"
+      ></comp-table-list>
+      }
+    </nz-tab>
+  </nz-tabset>
+</div>

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

@@ -0,0 +1,30 @@
+.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 - 250px);
+}
+::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;
+}

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

@@ -0,0 +1,24 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+import { IonicModule } from '@ionic/angular';
+
+import { PageProcessComponent } from './page-process.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();
+  });
+});

+ 67 - 0
projects/textbook/src/modules/nav-admin/page-process/page-process.component.ts

@@ -0,0 +1,67 @@
+import { Component, Input, OnInit } from '@angular/core';
+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 { 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';
+
+@Component({
+  selector: 'app-page-process',
+  templateUrl: './page-process.component.html',
+  styleUrls: ['./page-process.component.scss'],
+  imports: [
+    CommonModule,
+    NzSpaceModule,
+    CommonCompModule,
+    NzTabsModule,
+    ProcessCreateComponent,
+    CompTableListComponent
+  ],
+  standalone: true,
+})
+export class PageProcessComponent  implements OnInit {
+  active: number = 0;
+  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,
+  ) {
+    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('EduProcess');
+        query.include('branch', 'department');
+        query.equalTo('objectId', id);
+        this.eduProcess = await query.first();
+      }
+    })
+  }
+
+  onCreateProcess(){
+    this.router.navigate(['/nav-admin/manage/process/create',{cid:this.eduProcess?.id}])
+  }
+}

+ 393 - 0
projects/textbook/src/modules/nav-admin/page-process/process-create/process-create.component.html

@@ -0,0 +1,393 @@
+@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'">
+  <form
+    nz-form
+    [formGroup]="validateForm"
+    class="login-form"
+    (ngSubmit)="submitForm('save')"
+  >
+    <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
+                [nzAddOnAfter]="validateForm.value.name.length + '/' + 50"
+              >
+                <input
+                  nz-input
+                  type="text"
+                  placeholder="请填写流程名称"
+                  formControlName="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
+                [nzAddOnAfter]="validateForm.value.desc.length + '/' + 50"
+              >
+                <input
+                  nz-input
+                  type="text"
+                  placeholder="请填流程描述"
+                  formControlName="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
+                [nzAddOnAfter]="validateForm.value.code.length + '/' + 50"
+              >
+                <input
+                  nz-input
+                  type="text"
+                  placeholder="请填写流程唯一标识"
+                  formControlName="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>
+              <nz-select
+                style="width: 100%"
+                nzShowSearch
+                nzAllowClear
+                nzPlaceHolder="请选择一个类别"
+                formControlName="branch"
+              >
+                @for(item of unitTypes; track item;let index = $index){
+                <nz-option
+                  nzCustomContent
+                  [nzValue]="item.id"
+                  [nzLabel]="item.name"
+                  >{{ item.name }}</nz-option
+                >
+                }
+              </nz-select>
+            </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
+            >
+            <nz-form-control
+              class="val"
+              nzErrorTip="请填写开始时间"
+              style="width: 100%"
+            >
+              <nz-date-picker
+                nzFormat="yyyy-MM-dd HH:mm:ss"
+                formControlName="startDate"
+                [nzShowTime]="{ nzDefaultOpenValue: timeDefaultValue }"
+              ></nz-date-picker>
+            </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-date-picker
+                nzFormat="yyyy-MM-dd HH:mm:ss"
+                formControlName="deadline"
+                [nzShowTime]="{ nzDefaultOpenValue: timeDefaultValue }"
+              ></nz-date-picker>
+            </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="number"
+                  placeholder="请输入限额数值,单本教材与全册教材均占 1 份额度"
+                  formControlName="num"
+                  nzStatus=""
+                  maxlength="3"
+                />
+              </nz-input-group>
+            </nz-form-control>
+          </nz-form-item>
+        </div>
+        <div nz-col nzSpan="11"></div>
+      </div>
+      <div class="rows" nz-row>
+        <div nz-col nzSpan="24">
+          <div class="fonter">
+            @if (!eduProcess?.id) {
+            <button
+              class="form-button"
+              type="button"
+              mat-raised-button
+              (click)="submitForm('save')"
+            >
+              创建
+            </button>
+            <button
+              class="form-button close"
+              type="button"
+              mat-raised-button
+              (click)="submitForm('close')"
+            >
+              取消
+            </button>
+            } @else {
+            <button
+              class="form-button"
+              type="button"
+              mat-raised-button
+              (click)="submitForm('save')"
+            >
+              保存
+            </button>
+            <button
+              class="form-button close"
+              type="button"
+              mat-raised-button
+              (click)="submitForm('reset')"
+            >
+              重置
+            </button>
+            }
+          </div>
+        </div>
+      </div>
+    </div>
+  </form>
+  @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">
+          申报单位
+          <a class="btn" (click)="showModalDepart()">选择部门</a>
+        </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">
+          工作联系人
+          <a class="btn" (click)="onShowCheck()">选择联系人</a>
+        </div>
+      </div>
+      <div class="table" #maxWidth>
+        @if (eduProcess?.get('profileSubmitted') && !showProfileFrom) {
+        <app-profile
+          [idList]="profileId ? [profileId] : []"
+          (change)="changeSubmitted($event)"
+          [maxWidth]="maxWidth"
+          [disabled]="true"
+        ></app-profile>
+        } @else if(showProfileFrom){
+        <app-profile
+          [idList]="profileId ? [profileId] : []"
+          [maxWidth]="maxWidth"
+          (change)="changeSubmitted($event)"
+        ></app-profile>
+        }
+      </div>
+    </div>
+  </div>
+  }
+</div>
+
+<nz-modal
+  [(nzVisible)]="isVisible"
+  nzTitle="选择部门"
+  (nzOnCancel)="handleCancel()"
+  nzWidth="400px"
+  nzCentered
+>
+  <ng-container *nzModalContent>
+    <div class="rows" nz-row class="depart-modal">
+      <div nz-col nzSpan="24">
+        <div class="row">
+          <div class="label">选择部门</div>
+          <div class="value">
+            <input
+              nz-input
+              [(ngModel)]="searchValue"
+              (ngModelChange)="provinceChange('', $event)"
+              placeholder="搜索或选择一个下方部门"
+              type="text"
+            />
+          </div>
+        </div>
+        <div class="select">
+          <div class="bar">
+            <a style="color: #86909c">教材遴选</a>
+            @for (data of parentMap; track data.title) {
+            <span style="margin: 0 10px">/</span>
+            @if($index == 0){
+            <a>{{ data.title }}</a>
+            }@else {
+            <a (click)="onCheck(data)">{{ data.title }}</a>
+            } }
+          </div>
+          <div class="tree">
+            @for (data of parentList; track $index) {
+            <div class="li" (click)="onCheckedDepart(data)">
+              <label
+                nz-radio
+                [ngModel]="department == data.id"
+                [nzValue]="data.id"
+                (click)="onCheckedDepart(data, true)"
+                >{{ data.get("name") }}</label
+              >
+              <span nz-icon nzType="right" nzTheme="outline"></span>
+            </div>
+            }
+          </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>

+ 137 - 0
projects/textbook/src/modules/nav-admin/page-process/process-create/process-create.component.scss

@@ -0,0 +1,137 @@
+.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;
+    }
+  }
+  .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;
+}

+ 0 - 0
projects/textbook/src/modules/nav-admin/process-create/process-create.component.spec.ts → projects/textbook/src/modules/nav-admin/page-process/process-create/process-create.component.spec.ts


+ 307 - 0
projects/textbook/src/modules/nav-admin/page-process/process-create/process-create.component.ts

@@ -0,0 +1,307 @@
+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 {
+  FormControl,
+  FormGroup,
+  NonNullableFormBuilder,
+  Validators,
+} from '@angular/forms';
+import { textbookServer } from '../../../../services/textbook';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import { NzModalService } from 'ng-zorro-antd/modal';
+import { SubmittedComponent } from '../../components/submitted/submitted.component';
+import { ProfileComponent } from '../../components/profile/profile.component';
+import { MatButtonModule } from '@angular/material/button';
+import { differenceInCalendarDays, setHours } from 'date-fns';
+import { NzRadioModule } from 'ng-zorro-antd/radio';
+@Component({
+  selector: 'app-process-create',
+  templateUrl: './process-create.component.html',
+  styleUrls: ['./process-create.component.scss'],
+  imports: [
+    CommonCompModule,
+    FormsModule,
+    ReactiveFormsModule,
+    NzSelectModule,
+    SubmittedComponent,
+    MatButtonModule,
+    ProfileComponent,NzRadioModule
+  ],
+  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 = '' //搜索部门内容
+  
+  validateForm: FormGroup<{
+    name: FormControl<Array<string> | any>; //流程名称
+    desc: FormControl<Array<string> | any>; //流程描述
+    code: FormControl<string | any>; //流程唯一标识
+    num: FormControl<number | any>; //报送配额
+    branch: FormControl<Array<string> | any>; //所属分类
+    startDate: FormControl<Date>; //开始时间
+    deadline: FormControl<Date>; //结束时间
+  }> = this.fb.group({
+    name: ['', [Validators.required]],
+    desc: ['', [Validators.required]],
+    code: ['', [Validators.required]],
+    num: ['', [Validators.required]],
+    branch: ['', [Validators.required]],
+    startDate: [new Date(), [Validators.required]],
+    deadline: [new Date(), [Validators.required]],
+  });
+  department: string = ''; //所属单位
+  unitTypes: Array<any> = []; //单位类型
+
+  getNumlength(): number {
+    return this.validateForm.value.num.toString().length;
+  }
+  parentMap: Array<any> = [];
+  parentList: Array<any> = []; //单位列表
+
+  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');
+      await this.getUnitTypes();
+      if (id) {
+        this.isEdit = true;
+        let query = new Parse.Query('EduProcess');
+        query.include('branch', 'department');
+        query.equalTo('objectId', id);
+        this.eduProcess = await query.first();
+        this.validateForm = this.fb.group({
+          name: [this.eduProcess?.get('name') || '', [Validators.required]],
+          desc: [this.eduProcess?.get('desc') || '', [Validators.required]],
+          code: [this.eduProcess?.get('code') || '', [Validators.required]],
+          num: [this.eduProcess?.get('num') || '', [Validators.required]],
+          branch: [this.eduProcess?.get('branch')?.id || '', [Validators.required]],
+          startDate: [
+            this.eduProcess?.get('startDate')
+              ? this.eduProcess?.get('startDate')
+              : new Date(),
+            [Validators.required],
+          ],
+          deadline: [
+            this.eduProcess?.get('deadline')
+              ? this.eduProcess?.get('deadline')
+              : new Date(),
+            [Validators.required],
+          ],
+        });
+      }
+      this.profileId = this.eduProcess?.get('profileSubmitteds')?.id || '';
+      this.department = this.eduProcess?.get('department')?.id || '';
+    });
+  }
+  async getUnitTypes() {
+    let query = new Parse.Query('Department');
+    query.equalTo('branch', undefined);
+    query.equalTo('parent', undefined);
+    query.notEqualTo('isDeleted', true);
+    query.select('name');
+    let r = await query.find();
+    r.forEach((item) => {
+      this.unitTypes.push({ id: item.id, name: item.get('name') });
+    });
+  }
+  //根据所选单位类型获取对应单位
+  async provinceChange(id?: string, val?: string) {
+    let query = new Parse.Query('Department');
+    id && query.equalTo('parent', id);
+    query.select('name', 'branch');
+    query.limit(100);
+    val && query.contains('name', val);
+    let r = await query.find();
+    this.parentList = r
+  }
+  async submitForm(type: string): Promise<void> {
+    if (type == 'close') {
+      this.modal.confirm({
+        nzTitle: '你确定取消吗?',
+        nzContent: '',
+        nzOkText: '是',
+        nzOkType: 'primary',
+        nzOkDanger: true,
+        nzOnOk: () => history.back(),
+        nzCancelText: '否',
+        nzOnCancel: () => console.log('Cancel'),
+      });
+      return;
+    }
+    console.log('submit', this.validateForm.value);
+    if (this.validateForm.valid) {
+      let params = this.validateForm.value;
+      this.saveEduCollection(params);
+    } else {
+      this.msg.warning('请填写完整信息');
+      Object.values(this.validateForm.controls).forEach((control) => {
+        if (control.invalid) {
+          control.markAsDirty();
+          control.updateValueAndValidity({ onlySelf: true });
+        }
+      });
+    }
+  }
+  async saveEduCollection(params: any) {
+    if (!this.eduProcess?.id) {
+      let obj = Parse.Object.extend('EduProcess');
+      this.eduProcess = new obj();
+    }
+    // this.eduProcess?.set('user', Parse.User.current()?.toPointer());
+    this.eduProcess?.set('company', {
+      __type: 'Pointer',
+      className: 'Company',
+      objectId: this.tbookSer.company,
+    });
+    this.eduProcess?.set('branch', {
+      __type: 'Pointer',
+      className: 'Department',
+      objectId: params.branch,
+    });
+    this.department &&
+      this.eduProcess?.set('department', {
+        __type: 'Pointer',
+        className: 'Department',
+        objectId: this.department,
+      });
+    this.eduProcess?.set('name', params.name);
+    this.eduProcess?.set('desc', params.desc);
+    this.eduProcess?.set('code', params.code);
+    this.eduProcess?.set('num', params.num);
+    this.eduProcess?.set('startDate', params.startDate);
+    this.eduProcess?.set('deadline', params.deadline);
+    let pid = await this.getProfile();
+    this.eduProcess?.set('profileSubmitteds', {
+      __type: 'Pointer',
+      className: 'Profile',
+      objectId: pid,
+    });
+    this.eduProcess = await this.eduProcess?.save();
+    this.msg.success(this.isEdit ? '已保存' : '已创建');
+    this.showProfileFrom = false;
+    this.router.navigate([
+      '/nav-admin/manage/process/page',
+      { id: this.eduProcess?.id },
+    ]);
+  }
+  //选择部门
+  async showModalDepart() {
+    if (this.eduProcess?.get('department')) {
+      this.parentMap = await this.formatNode(
+        this.eduProcess?.get('department').id
+      );
+    } else {
+      let dp = this.unitTypes.find(item=> item.id == this.validateForm.value.branch)
+      this.parentMap = [
+        {
+          title: dp?.name,
+          id: dp?.id,
+        },
+      ];
+    }
+    this.provinceChange(this.validateForm.value.branch);
+    this.isVisible = true;
+  }
+  async formatNode(id: string): Promise<Array<any>> {
+    let arr = [];
+    if (id) {
+      let query = new Parse.Query('Department');
+      query.equalTo('objectId', id);
+      query.select('parent', 'name');
+      let r = await query.first();
+      arr.push({
+        title: r?.get('name'),
+        id: r?.id,
+      });
+      arr.unshift(...(await this.formatNode(r?.get('parent')?.id)));
+    }
+    return arr;
+  }
+  //选择联系人
+  onShowCheck() {
+    this.showProfileFrom = true;
+  }
+  //获取联系人
+  async getProfile(): Promise<string | any> {
+    let queryParams = {
+      where: {
+        $or: [
+          {
+            user: {
+              $inQuery: {
+                where: {
+                  $or: [
+                    {
+                      department: { $eq: this.validateForm.value.branch },
+                    },
+                  ],
+                },
+                className: '_User',
+              },
+            },
+          },
+        ],
+      },
+    };
+    let query = Parse.Query.fromJSON('Profile', queryParams);
+    query.equalTo('identity', '报送联系人');
+    query.notEqualTo('isDeleted', true);
+    query.select('user');
+    let r = await query.first();
+    if (r?.id) {
+      return r.id;
+    }
+    return;
+  }
+  async changeSubmitted(e: Array<string>) {
+    console.log(e);
+    if (e[0]) this.profileId = e[0];
+  }
+  onCheck(e: any) {
+    console.log(e);
+  }
+  //选择部门
+  async onCheckedDepart(e: any, checked?: boolean) {
+    console.log(e);
+    this.department = e.id
+  }
+  handleCancel(): void {
+    console.log('Button cancel clicked!');
+    this.isVisible = false;
+  }
+  async handleOk():Promise<void> {
+    this.eduProcess?.set('branch', {
+      __type: 'Pointer',
+      className: 'Department',
+      objectId: this.validateForm.value.branch
+    });
+    this.department &&
+      this.eduProcess?.set('department', {
+        __type: 'Pointer',
+        className: 'Department',
+        objectId: this.department,
+      });
+     await this.eduProcess?.save()
+     this.ngOnInit()
+    this.isVisible = false;
+  }
+}

+ 229 - 0
projects/textbook/src/modules/nav-admin/page-process/process-list/process-list.component.html

@@ -0,0 +1,229 @@
+<nz-page-header>
+  <!--title-->
+  <nz-page-header-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)="toUrl('/nav-admin/manage/process/create')"
+      >
+        创建流程
+      </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="">
+        <nz-input-group style="width: 280px" [nzPrefix]="prefixTemplateUser">
+          <input
+            type="text"
+            nz-input
+            placeholder="搜索流程名称 / 流程 code"
+            [(ngModel)]="searchValue"
+          />
+        </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"
+      >
+        <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="120px">申报限额</th>
+            <th nzWidth="120px">流程联系人</th>
+            <th nzWidth="120px">流程状态</th>
+            <th nzWidth="80px" 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>
+              {{ data?.name }}
+            </td>
+            <td>
+              {{ data?.code }}
+            </td>
+            <td>
+              {{ data?.desc }}
+            </td>
+            <td>
+              {{ data?.num }}
+            </td>
+            <td>
+              {{ data?.profileSubmitted?.user.name }}
+            </td>
+            <td>
+              {{ data?.status }}
+            </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
+                      [disabled]="user?.get('isDeleted')"
+                      nzType="link"
+                      style="color: #231c1f"
+                    >
+                      <span nz-icon nzType="delete" nzTheme="outline"></span
+                      >删除流程
+                    </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>
+          </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>

+ 167 - 0
projects/textbook/src/modules/nav-admin/page-process/process-list/process-list.component.scss

@@ -0,0 +1,167 @@
+.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: 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;
+    }
+  }
+}
+.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: absolute;
+  display: flex;
+  justify-content: center;
+  bottom: 80px;
+  left: calc(50% - 134px);
+  -webkit-transform: translate(0);
+  transform: translate(0);
+}
+.batch-toolbar {
+  display: flex;
+  align-items: center;
+  height: 56px;
+  // min-width: 600px;
+  background: #fff;
+  border: 1px solid #e5e6eb;
+  box-sizing: border-box;
+  box-shadow: 0 16px 32px -10px rgba(4, 24, 115, .1);
+  border-radius: 4px;
+  button{
+      color:#545968;
+  }
+}
+.batch-toolbar .styles_counter__18S08 {
+  color: #fff;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 100%;
+  background: #C6233F;
+  width: 100px;
+  font-size: 12px;
+  border-top-left-radius: 4px;
+  border-bottom-left-radius: 4px;
+}
+.batch-toolbar .batch-toolbar-actions {
+  display: flex;
+  margin: auto;
+  padding: 0 20px;
+}
+.batch-toolbar .styles_cancel__AARoT {
+  font-size: 16px;
+  border-left: 1px solid #a9aeb8;
+  // padding-left: 20px;
+  display: flex;
+  justify-content: center;
+  width: 128px;
+}
+.batch-toolbar .styles_counter__18S08 .styles_num__178Wa {
+  font-size: 24px;
+  margin-left: 8px;
+}
+
+
+::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-admin/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();
+  });
+});

+ 330 - 0
projects/textbook/src/modules/nav-admin/page-process/process-list/process-list.component.ts

@@ -0,0 +1,330 @@
+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 {
+  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 { NzModalService } from 'ng-zorro-antd/modal';
+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 = ''; //搜索内容
+  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> = [];
+  parentList: Array<any> = [];
+  setOfCheckedId = new Set<string>();
+
+  constructor(
+    private route: Router,
+    private activeRoute: ActivatedRoute,
+    private nzContextMenuService: NzContextMenuService,
+    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();
+    });
+  }
+  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: true,
+      });
+    });
+    return nodes;
+  }
+  //添加成员
+  addMember() {
+    this.message.warning('权限灰度中');
+  }
+  changeDepart(e: any) {
+    this.currentDepart = e;
+    this.getProfile();
+  }
+
+  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 query = Parse.Query.fromJSON('EduProcess', queryParams);
+    query.include('profileSubmitted','profileSubmitted.user');
+    
+    let r = await query.find();
+    let list: any[] = [];
+    r.forEach((item) => {
+      let _item = item.toJSON();
+      _item['checked'] = false;
+      list.push(_item);
+    });
+    this.eduProcessList = list;
+    this.loading = false;
+  }
+  //搜索触发
+  onSearch(event: NzFormatEmitEvent) {
+    console.log(event);
+  }
+  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;
+  }
+  //新建打开弹窗
+  async showModalDepart(type: string) {
+    this.parentList = this.nodes;
+    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
+        );
+      }
+    }
+    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(data?: any, index?: number) {
+    if (!data) {
+      this.parentList = await this.getDepart();
+      this.parentMap = [];
+      return;
+    }
+    if (index == this.parentMap.length - 1) return;
+    this.parentMap.splice(index || 0 + 1);
+    this.parentList = await this.getDepart(data?.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 = [];
+  }
+
+  /* 组织 */
+  showModalOrganize() {
+    this.message.warning('权限灰度中');
+  }
+  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])
+    }
+  }
+}

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

@@ -21,7 +21,7 @@
       align-items: center;
       .search{
         display: flex;
-        width: 300px;
+        width: 280px;
         margin-right: 20px;
       }
       .tag{
@@ -39,11 +39,12 @@
     display: flex;
     width: 100%;
     .sider{
-      width: 300px;
+      width: 280px;
       margin: 10px 0;
       height: calc(100vh - 192px);
       overflow-y: scroll;
       flex-shrink: 0;
+      margin-right: 20px;
       .custom-node{
         display: flex;
       }

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

@@ -181,7 +181,7 @@ export class PageRoleComponent implements OnInit {
             "$inQuery": {
               "where": {
                 "$or": [{
-                    "companyName": { "$eq": this.currentDepart.title}
+                    "department": { "$eq": this.currentDepart.key}
                   },
                 ]
               },

+ 0 - 257
projects/textbook/src/modules/nav-admin/process-create/process-create.component.html

@@ -1,257 +0,0 @@
-<nz-page-header nzTitle="发起报送流程">
-  <nz-breadcrumb nz-page-header-breadcrumb>
-    <nz-breadcrumb-item>报送合集</nz-breadcrumb-item>
-    <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>
-<div class="content" [style.padding]="isEdit ? '0' : '0 24px 16px'">
-  <form
-    nz-form
-    [formGroup]="validateForm"
-    class="login-form"
-    (ngSubmit)="submitForm('save')"
-  >
-    <div class="title">基本信息</div>
-    <div class="fill-template">
-      <div nz-row>
-        <div nz-col nzSpan="12">
-          <nz-form-item class="row" style="margin-bottom: 16px">
-            <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
-                [nzAddOnAfter]="validateForm.value.name.length + '/' + 50"
-              >
-                <input
-                  nz-input
-                  type="text"
-                  placeholder="请填写流程名称"
-                  formControlName="name"
-                  nzStatus=""
-                  maxlength="50"
-                />
-              </nz-input-group>
-            </nz-form-control>
-          </nz-form-item>
-        </div>
-        <div nz-col nzSpan="12">
-          <nz-form-item class="row" style="margin-bottom: 16px">
-            <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
-                [nzAddOnAfter]="validateForm.value.desc.length + '/' + 50"
-              >
-                <input
-                  nz-input
-                  type="text"
-                  placeholder="请填流程描述"
-                  formControlName="desc"
-                  nzStatus=""
-                  maxlength="50"
-                />
-              </nz-input-group>
-            </nz-form-control>
-          </nz-form-item>
-        </div>
-      </div>
-      <div nz-row>
-        <div nz-col nzSpan="12">
-          <nz-form-item class="row" style="margin-bottom: 16px">
-            <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
-                [nzAddOnAfter]="validateForm.value.code.length + '/' + 50"
-              >
-                <input
-                  nz-input
-                  type="text"
-                  placeholder="请填写流程唯一标识"
-                  formControlName="code"
-                  nzStatus=""
-                  maxlength="50"
-                />
-              </nz-input-group>
-            </nz-form-control>
-          </nz-form-item>
-        </div>
-        <div nz-col nzSpan="12">
-          <nz-form-item class="row" style="margin-bottom: 16px">
-            <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 [nzAddOnAfter]="getNumlength() + '/' + 50">
-                <input
-                  nz-input
-                  type="number"
-                  placeholder="请填写报送配额"
-                  formControlName="num"
-                  nzStatus=""
-                  maxlength="50"
-                />
-              </nz-input-group>
-            </nz-form-control>
-          </nz-form-item>
-        </div>
-      </div>
-      <div nz-row>
-        <div nz-col nzSpan="12">
-          <nz-form-item class="row" style="margin-bottom: 16px">
-            <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-date-picker
-                nzFormat="yyyy-MM-dd HH:mm:ss"
-                formControlName="startDate"
-                [nzShowTime]="{ nzDefaultOpenValue: timeDefaultValue }"
-              ></nz-date-picker>
-            </nz-form-control>
-          </nz-form-item>
-        </div>
-        <div nz-col nzSpan="12">
-          <nz-form-item class="row" style="margin-bottom: 16px">
-            <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-date-picker
-                nzFormat="yyyy-MM-dd HH:mm:ss"
-                formControlName="deadline"
-                [nzShowTime]="{ nzDefaultOpenValue: timeDefaultValue }"
-              ></nz-date-picker>
-            </nz-form-control>
-          </nz-form-item>
-        </div>
-      </div>
-      <div nz-row>
-        <div nz-col nzSpan="24">
-          <div class="title-row">
-            <div>
-              <div class="title">流程管理员</div>
-              <!-- <div class="tips">
-                流程管理员可查看合集中所有流程报送的教材、报送配额、用户,可创建所属省份与自己相同的账号、用户组;可公示和报送合集中所有教材。
-              </div> -->
-            </div>
-            <a class="btn" (click)="onShowCheck()">选择流程管理员</a>
-          </div>
-          <div class="tabs" #maxWidth>
-            @if (eduProcess?.get('profileSubmitted') && !showProfileFrom) {
-            <app-profile
-              [idList]="profileIds ? profileIds : []"
-              (change)="changeSubmitted($event)"
-              [maxWidth]="maxWidth"
-              [disabled]="true"
-            ></app-profile>
-            } @else if(showProfileFrom){
-            <app-profile
-              [maxChecked]="99"
-              [idList]="profileIds ? profileIds : []"
-              [maxWidth]="maxWidth"
-              (change)="changeSubmitted($event)"
-            ></app-profile>
-            }
-          </div>
-          <div class="fonter">
-            @if (!eduProcess?.id) {
-            <button
-              class="form-button"
-              type="button"
-              mat-raised-button
-              (click)="submitForm('save')"
-            >
-              创建报送流程
-            </button>
-            <button
-              class="form-button close"
-              type="button"
-              mat-raised-button
-              (click)="submitForm('close')"
-            >
-              取消
-            </button>
-            } @else {
-            <button
-              class="form-button"
-              type="button"
-              mat-raised-button
-              (click)="submitForm('save')"
-            >
-              发起报送流程
-            </button>
-            <button
-              class="form-button close"
-              type="button"
-              mat-raised-button
-              (click)="submitForm('close')"
-            >
-              取消
-            </button>
-            }
-          </div>
-        </div>
-      </div>
-    </div>
-  </form>
-</div>

+ 0 - 74
projects/textbook/src/modules/nav-admin/process-create/process-create.component.scss

@@ -1,74 +0,0 @@
-.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: 84%;
-    .label {
-      margin: 10px 0 6px;
-    }
-    .val {
-      min-height: auto;
-    }
-  }
-  .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;
-    }
-  }
-
-}
-.fonter{
-  text-align: right;
-  .form-button {
-    width: 160px;
-    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;
-  }
-}
-
-// ::ng-deep .ant-page-header {
-//   padding: 16px 24px 0;
-// }
-::ng-deep .ant-page-header-heading-title {
-  color: black;
-}

+ 0 - 205
projects/textbook/src/modules/nav-admin/process-create/process-create.component.ts

@@ -1,205 +0,0 @@
-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 {
-  FormControl,
-  FormGroup,
-  NonNullableFormBuilder,
-  Validators,
-} from '@angular/forms';
-import { textbookServer } from '../../../services/textbook';
-import { NzMessageService } from 'ng-zorro-antd/message';
-import { NzModalService } from 'ng-zorro-antd/modal';
-import { SubmittedComponent } from '../components/submitted/submitted.component';
-import { ProfileComponent } from '../components/profile/profile.component';
-import { MatButtonModule } from '@angular/material/button';
-import { differenceInCalendarDays, setHours } from 'date-fns';
-@Component({
-  selector: 'app-process-create',
-  templateUrl: './process-create.component.html',
-  styleUrls: ['./process-create.component.scss'],
-  imports: [
-    CommonCompModule,
-    FormsModule,
-    ReactiveFormsModule,
-    NzSelectModule,
-    SubmittedComponent,
-    ProfileComponent,
-    MatButtonModule,
-  ],
-  standalone: true,
-})
-export class ProcessCreateComponent implements OnInit {
-  eduCollectionId:string|undefined //指向的合集
-
-  eduProcess: Parse.Object | undefined;
-  showProfileFrom: boolean = false;
-  @Input('isEdit') isEdit: boolean = false; //当前是否作为编辑子组件
-  profileIds: Array<string> = []; //报送人
-
-  timeDefaultValue = setHours(new Date(), 0);
-  
-  validateForm: FormGroup<{
-    name: FormControl<Array<string> | any>; //流程名称
-    desc: FormControl<Array<string> | any>; //流程描述
-    code: FormControl<string | any>; //流程唯一标识
-    num: FormControl<number | any>; //报送配额
-    startDate: FormControl<Date>; //开始时间
-    deadline: FormControl<Date>; //结束时间
-  }> = this.fb.group({
-    name: ['', [Validators.required]],
-    desc: ['', [Validators.required]],
-    code: ['', [Validators.required]],
-    num: ['', [Validators.required]],
-    startDate: [new Date(), [Validators.required]],
-    deadline: [new Date(), [Validators.required]],
-  });
-  getNumlength(): number {
-    return this.validateForm.value.num.toString().length;
-  }
-  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');
-      this.eduCollectionId = params.get('cid')!;
-      console.log(id);
-      if (id) {
-        this.isEdit = true;
-        let query = new Parse.Query('EduProcess');
-        query.equalTo('eduProcess', id);
-        this.eduProcess = await query.first();
-        this.validateForm = this.fb.group({
-          name: [this.eduProcess?.get('name') || '', [Validators.required]],
-          desc: [this.eduProcess?.get('desc') || '', [Validators.required]],
-          code: [this.eduProcess?.get('code') || '', [Validators.required]],
-          num: [this.eduProcess?.get('num') || '', [Validators.required]],
-          startDate: [
-            this.eduProcess?.get('startDate') || new Date(),
-            new Date(),
-            [Validators.required],
-          ],
-          deadline: [
-            this.eduProcess?.get('deadline') || new Date(),
-            ,
-            [Validators.required],
-          ],
-        });
-        this.profileIds = this.eduProcess?.get('profileSubmitteds')?.map((item:any)=> item.objectId)
-        // let querySubmitted = new Parse.Query('Submitted')
-        // querySubmitted.equalTo('eduProcess',this.eduProcess?.id)
-        // let submitteds = await querySubmitted.find()
-        // if(submitteds?.length > 0){
-        //   this.profileIds = submitteds.map(item=> item.id)
-        // }
-      }
-    });
-  }
-  onShowCheck() {
-    if (!this.eduProcess?.id) {
-      this.msg.warning('请先创建报送流程');
-      return;
-    }
-    this.showProfileFrom = true;
-  }
-  async submitForm(type: string): Promise<void> {
-    if (type == 'close') {
-      this.modal.confirm({
-        nzTitle: '你确定取消吗?',
-        nzContent: '',
-        nzOkText: '是',
-        nzOkType: 'primary',
-        nzOkDanger: true,
-        nzOnOk: () => history.back(),
-        nzCancelText: '否',
-        nzOnCancel: () => console.log('Cancel'),
-      });
-      return;
-    }
-    if (this.validateForm.valid) {
-      console.log('submit', this.validateForm.value);
-      let params = this.validateForm.value;
-      this.saveEduCollection(params);
-    } else {
-      this.msg.warning('请填写完整信息');
-      Object.values(this.validateForm.controls).forEach((control) => {
-        if (control.invalid) {
-          control.markAsDirty();
-          control.updateValueAndValidity({ onlySelf: true });
-        }
-      });
-    }
-  }
-
-  async saveEduCollection(params: any) {
-    if (!this.eduProcess?.id) {
-      let obj = Parse.Object.extend('EduProcess');
-      this.eduProcess = new obj();
-    }
-    this.eduProcess?.set('user', Parse.User.current()?.toPointer());
-    this.eduProcess?.set('company', {
-      __type: 'Pointer',
-      className: 'Company',
-      objectId: this.tbookSer.company,
-    });
-    this.eduProcess?.set('eduCollection', {
-      __type: 'Pointer',
-      className: 'EduCollection',
-      objectId: this.eduCollectionId,
-    });
-    this.eduProcess?.set('name', params.name);
-    this.eduProcess?.set('desc', params.desc);
-    this.eduProcess?.set('code', params.code);
-    this.eduProcess?.set('num', params.num);
-    this.eduProcess?.set('startDate', params.startDate);
-    this.eduProcess?.set('deadline', params.deadline);
-    let profileSubmitteds = this.profileIds?.map(id=>{
-      let pointer = {
-        __type: 'Pointer',
-        className: 'Profile',
-        objectId: id,
-      }
-      return pointer
-    })|| []
-    this.eduProcess?.set('profileSubmitteds',profileSubmitteds)
-    this.eduProcess = await this.eduProcess?.save();
-    this.msg.success(this.isEdit ? '已保存' : '已创建');
-    this.showProfileFrom = false;
-  }
-  // async setSubmitted(){
-  //   for (let index = 0; index < this.profileIds.length; index++) {
-  //     const id = this.profileIds[index];
-  //     let obj = Parse.Object.extend('Submitted');
-  //     let submitted = new obj();
-  //     this.eduProcess?.set('company', {
-  //       __type: 'Pointer',
-  //       className: 'Company',
-  //       objectId: this.tbookSer.company,
-  //     });
-  //     this.eduProcess?.set('profileSubmitted', {
-  //       __type: 'Pointer',
-  //       className: 'Profile',
-  //       objectId: id,
-  //     })
-  //     this.eduProcess?.set('profileSubmitted', {
-  //       __type: 'Pointer',
-  //       className: 'Profile',
-  //       objectId: id,
-  //     })
-  //   }
-  // }
-  async changeSubmitted(e: Array<string>) {
-    console.log(e);
-    if (e[0]) this.profileIds = e;
-  }
-}

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

@@ -222,7 +222,7 @@
         >
         /
         <nz-tag [nzBordered]="false" [nzColor]="'geekblue'">{{
-          user?.get("companyName")
+          user?.get("department")?.get('name') || user?.get("companyName")
         }}</nz-tag>
       </div>
       <div class="title">原始JSON数据</div>

+ 2 - 1
projects/textbook/src/modules/nav-admin/user-edit/user-edit.component.ts

@@ -4,7 +4,7 @@ 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 { CreateCollectionComponent } from '../collection/create-collection/create-collection.component';
 import { ActivatedRoute, Router } from '@angular/router';
 import Parse from 'parse';
 import { NzAvatarModule } from 'ng-zorro-antd/avatar';
@@ -57,6 +57,7 @@ export class UserEditComponent implements OnInit {
       console.log(id);
       if (id) {
         let query = new Parse.Query('_User');
+        query.include('department')
         this.user = await query.get(id);
         let queryProfile = new Parse.Query('Profile');
         queryProfile.equalTo('user', id);

+ 18 - 3
server/db/schemas/EduProcess.js

@@ -6,8 +6,23 @@ export const EduProcess = {
       "targetClass": "EduCollection",
       "required": false
     },
-    "profileSubmitteds": {//流程管理员
-      "type": "Array",
+    "branch": { //类别
+      "type": "Pointer",
+      "targetClass": "Department",
+      "required": false
+    },
+    "department": { //部门/单位
+      "type": "Pointer",
+      "targetClass": "Department",
+      "required": false
+    },
+    // "profileSubmitteds": {//流程管理员
+    //   "type": "Array",
+    //   "required": false
+    // },
+    "profileSubmitted": {//流程管理员
+      "type": "Pointer",
+      "targetClass":"Profile",
       "required": false
     },
     "name": {//流程名称
@@ -19,7 +34,7 @@ export const EduProcess = {
       "required": false
     },
     "code": {//流程唯一标识
-      "type": "Number",
+      "type": "String",
       "required": false
     },
     "startDate": {//开始时间