浏览代码

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

ryanemax 8 月之前
父节点
当前提交
64ea18487d
共有 18 个文件被更改,包括 638 次插入249 次删除
  1. 4 0
      projects/textbook/src/app/textbook/textbook.component.ts
  2. 1 0
      projects/textbook/src/modules/login/login/login.component.ts
  3. 13 1
      projects/textbook/src/modules/nav-admin/modules.routes.ts
  4. 18 0
      projects/textbook/src/modules/nav-admin/user-edit/auth.guard.ts
  5. 24 13
      projects/textbook/src/modules/nav-admin/user-edit/user-edit.component.html
  6. 24 1
      projects/textbook/src/modules/nav-admin/user-edit/user-edit.component.scss
  7. 190 28
      projects/textbook/src/modules/nav-admin/user-edit/user-edit.component.ts
  8. 4 1
      projects/textbook/src/modules/nav-author/components/attachment/attachment.component.ts
  9. 4 4
      projects/textbook/src/modules/nav-author/components/basic-in/basic-in.component.html
  10. 21 4
      projects/textbook/src/modules/nav-author/components/faith/faith.component.html
  11. 70 55
      projects/textbook/src/modules/nav-author/components/faith/faith.component.ts
  12. 2 2
      projects/textbook/src/modules/nav-author/components/textbook-pertain/textbook-pertain.component.ts
  13. 40 17
      projects/textbook/src/modules/nav-province-contact/page-process/page-process.component.ts
  14. 31 17
      projects/textbook/src/modules/nav-province-contact/page-textbook/page-textbook.component.ts
  15. 2 2
      projects/textbook/src/modules/nav-province-contact/submitted/export-file/export-file.component.html
  16. 1 0
      projects/textbook/src/services/languages.map.ts
  17. 76 0
      projects/textbook/src/services/route-reuse.service.ts
  18. 113 104
      projects/textbook/src/services/textbook.ts

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

@@ -350,6 +350,10 @@ export class TextbookComponent implements OnInit {
   }
   //退回
   reject(data?: Parse.Object) {
+    if (this.eduProcess?.get('status') != '200') {
+      this.message.warning('当前流程状态非遴选中,不可此操作');
+      return;
+    }
     this.modal.confirm({
       nzTitle: '退回教材',
       nzContent: `确定退回吗?`,

+ 1 - 0
projects/textbook/src/modules/login/login/login.component.ts

@@ -32,6 +32,7 @@ export class LoginComponent implements OnInit{
   @ViewChild("codeloginSign") codeloginSign: any; 
 
   ngOnInit(){
+    localStorage.setItem('active','')
     let parseAuthing = new ParseAuthing({
       // 监听事件:登陆成功后,返回用户信息
       login:(user,authClient)=>{

+ 13 - 1
projects/textbook/src/modules/nav-admin/modules.routes.ts

@@ -1,5 +1,5 @@
 import { NgModule } from '@angular/core';
-import { RouterModule, Routes } from '@angular/router';
+import { RouterModule, Routes,RouteReuseStrategy } from '@angular/router';
 // 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';
@@ -12,6 +12,8 @@ import { UserEditComponent } from './user-edit/user-edit.component';
 import { PageProcessComponent } from './page-process/page-process.component';
 import { TextbookDetailsComponent } from '../common/textbook-details/textbook-details.component';
 import { UserCreateComponent } from './page-user/user-create/user-create.component';
+import { ReuseService } from "../../services/route-reuse.service";
+import { LeaveGuard } from './user-edit/auth.guard';
 const routes: Routes = [
   {
     path: '',
@@ -53,10 +55,14 @@ const routes: Routes = [
       {
         path: 'user', //用户列表
         component: PageUserComponent,
+        data:{
+          keep:true
+        }
       },
       {
         path: 'user/edit', //用户管理&编辑
         component: UserEditComponent,
+        canDeactivate: [LeaveGuard],
       },
       {
         path: 'user/create', //创建用户
@@ -77,5 +83,11 @@ const routes: Routes = [
 @NgModule({
   imports: [RouterModule.forChild(routes)],
   exports: [RouterModule],
+  providers:[
+    {
+      provide:RouteReuseStrategy,
+      useClass:ReuseService
+    }
+  ]
 })
 export class NavAdminRoutingModule {}

+ 18 - 0
projects/textbook/src/modules/nav-admin/user-edit/auth.guard.ts

@@ -0,0 +1,18 @@
+import { Injectable } from '@angular/core';
+import { CanDeactivate } from '@angular/router';
+import { UserEditComponent } from './user-edit.component';
+import { Observable, of } from 'rxjs';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class LeaveGuard implements CanDeactivate<UserEditComponent> {
+
+  public canDeactivate(component: UserEditComponent): Observable<boolean> {
+    if (component.moduleChange && typeof(component.moduleChange) === 'function') {
+      return component.moduleChange();
+    } else {
+      return of(true);
+    }
+  }
+}

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

@@ -1,7 +1,9 @@
 <nz-page-header>
   <nz-breadcrumb nz-page-header-breadcrumb>
     <nz-breadcrumb-item>用户管理</nz-breadcrumb-item>
-    <nz-breadcrumb-item><a (click)="goUserList()">用户列表</a></nz-breadcrumb-item>
+    <nz-breadcrumb-item
+      ><a (click)="goUserList()">用户列表</a></nz-breadcrumb-item
+    >
     <nz-breadcrumb-item><a>用户详情</a></nz-breadcrumb-item>
   </nz-breadcrumb>
   <nz-page-header-content>
@@ -111,13 +113,13 @@
         <div nz-row>
           <div nz-col nzSpan="8">
             <div class="lable">创建时间</div>
-            <div class="value">
+            <div class="value pd4-8">
               {{ user?.createdAt | date : "yyyy-MM-dd HH:MM:ss" || "-" }}
             </div>
           </div>
           <div nz-col nzSpan="8">
             <div class="lable">最后登录时间</div>
-            <div class="value">
+            <div class="value pd4-8">
               {{
                 user?.get("lastLogin")
                   ? (user?.get("lastLogin") | date : "yyyy-MM-dd HH:MM:ss")
@@ -127,21 +129,23 @@
           </div>
           <div nz-col nzSpan="8">
             <div class="lable">最后登录IP</div>
-            <div class="value">{{ user?.get("lastIP") || "-" }}</div>
+            <div class="value pd4-8">{{ user?.get("lastIP") || "-" }}</div>
           </div>
         </div>
         <div nz-row>
           <div nz-col nzSpan="8">
             <div class="lable">登录次数</div>
-            <div class="value">{{ user?.get("loginsCount") || "-" }}</div>
+            <div class="value pd4-8">{{ user?.get("loginsCount") || "-" }}</div>
           </div>
           <div nz-col nzSpan="8">
-            <div class="lable">用户类型</div>
+            <div class="lable">
+              用户类型 <span style="color: #e8353e">*</span>
+            </div>
             <nz-select
               style="width: 80%"
               nzShowSearch
               nzAllowClear
-              [disabled]="!edit"
+              [disabled]="!edit || tbookSer.profile.identity == '高校联系人'"
               nzPlaceHolder="请选择所属的身份类型"
               [(ngModel)]="profileJson.identity"
               [ngModelOptions]="{ standalone: true }"
@@ -156,7 +160,7 @@
           </div>
           <div nz-col nzSpan="8">
             <div class="lable">认证文件</div>
-            <div class="value">
+            <div class="value pd4-8">
               @if (profile?.get('identityFile')) {
               <a (click)="openUrl(profile?.get('identityFile'))">查看文件</a>
               }@else { 未上传 }
@@ -182,7 +186,9 @@
       <div class="fill-template">
         <div nz-row>
           <div nz-col nzSpan="8">
-            <div class="lable">手机号</div>
+            <div class="lable">
+              手机号 <span style="color: #e8353e">*</span>
+            </div>
             <div class="value">
               <input
                 nz-input
@@ -195,7 +201,7 @@
             </div>
           </div>
           <div nz-col nzSpan="8">
-            <div class="lable">邮箱</div>
+            <div class="lable">邮箱 <span style="color: #e8353e">*</span></div>
             <div class="value">
               <input
                 nz-input
@@ -208,7 +214,7 @@
             </div>
           </div>
           <div nz-col nzSpan="8">
-            <div class="lable">姓名</div>
+            <div class="lable">姓名 <span style="color: #e8353e">*</span></div>
             <div class="value">
               <input
                 nz-input
@@ -223,7 +229,9 @@
         </div>
         <div nz-row>
           <div nz-col nzSpan="8">
-            <div class="lable">用户名</div>
+            <div class="lable">
+              用户名 <span style="color: #e8353e">*</span>
+            </div>
             <div class="value">
               <input
                 nz-input
@@ -356,7 +364,7 @@
                 nz-input
                 type="text"
                 [disabled]="!edit"
-                [(ngModel)]="profileJson.postName"
+                [(ngModel)]="profileJson.majorSubject"
                 placeholder="请填写主要学科"
               />
               <!-- {{ profile?.get("majorSubject") || "未填写" }} -->
@@ -507,3 +515,6 @@
     </button>
   </div>
 </nz-modal>
+<div class="loading" [hidden]="!loading">
+  <nz-spin nzSimple [nzSize]="'large'"></nz-spin>
+</div>

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

@@ -8,6 +8,14 @@
   // white-space: nowrap;
   // text-overflow: ellipsis;
 }
+.back {
+  font-family: PingFang SC;
+  font-size: 14px;
+  font-weight: 400;
+  line-height: 22px;
+  text-align: left;
+  cursor: pointer;
+}
 .user-header {
   display: flex;
   justify-content: space-between;
@@ -79,7 +87,7 @@
     }
     .value{
       width: 80%;
-      padding: 4px 8px;
+      // padding: 4px 8px;
       background: #f9f9f9;
       border-radius: 4px;
       color: #242722;
@@ -161,6 +169,21 @@
     }
   }
 }
+.loading{
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100vw;
+  text-align: center;
+  height: 100vh;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: rgb(0 0 0 / 30%);
+}
+.pd4-8{
+  padding: 4px 8px;
+}
 ::ng-deep .ant-page-header-heading-title {
   white-space: normal;
 }

+ 190 - 28
projects/textbook/src/modules/nav-admin/user-edit/user-edit.component.ts

@@ -18,8 +18,8 @@ import { NzImageModule } from 'ng-zorro-antd/image';
 import { NzSelectModule } from 'ng-zorro-antd/select';
 import { MatButtonModule } from '@angular/material/button';
 import { provinces } from '../../../services/provinces';
-
-
+import { NzModalService } from 'ng-zorro-antd/modal';
+import { Observable, of } from 'rxjs';
 @Component({
   selector: 'app-user-edit',
   templateUrl: './user-edit.component.html',
@@ -36,7 +36,8 @@ import { provinces } from '../../../services/provinces';
     NzModalModule,
     NzRadioModule,
     NzImageModule,
-    NzSelectModule,MatButtonModule
+    NzSelectModule,
+    MatButtonModule,
   ],
   standalone: true,
 })
@@ -64,20 +65,22 @@ export class UserEditComponent implements OnInit {
   isShowModal: boolean = false;
   searchValue: string = ''; //搜索部门内容
   unitTypes: Array<any> = [];
-  userJson: any = { //user编辑数据
-    email:'',
-    phone:'',
-    name:'',
-    username:'',
-  }
-  profileJson: any = { //身份编辑数据
-    identity:'',
-    telephone:'',
-    province:'',
-    departmentName:'',
-    postName:'',
-    majorSubject:''
-  }
+  userJson: any = {
+    //user编辑数据
+    email: '',
+    phone: '',
+    name: '',
+    username: '',
+  };
+  profileJson: any = {
+    //身份编辑数据
+    identity: '',
+    telephone: '',
+    province: '',
+    departmentName: '',
+    postName: '',
+    majorSubject: '',
+  };
   userType: Array<string> = ['教师', '评审专家', '高校联系人', '工作联系人'];
   provinces: Array<string> = provinces.options; //省份
 
@@ -87,15 +90,19 @@ export class UserEditComponent implements OnInit {
     private router: Router,
     private route: ActivatedRoute,
     private message: NzMessageService,
-    private nzImageService: NzImageService
+    private nzImageService: NzImageService,
+    private modal: NzModalService
   ) {}
 
-  goUserList(){
-    this.router.navigate(["/nav-admin/manage/user"],{
-      queryParams:{page:this.route.snapshot.queryParamMap.get("page")}
-    })
+  goUserList() {
+    this.router.navigate(['/nav-admin/manage/user'], {
+      queryParams: { page: this.route.snapshot.queryParamMap.get('page') },
+    });
   }
   ngOnInit() {
+    // window.onbeforeunload = (event) => {
+    //   (event || window.event).returnValue = '还未保存是否离开';
+    // };
     this.activeRoute.paramMap.subscribe(async (params) => {
       let id = params.get('id');
       console.log(id);
@@ -109,6 +116,7 @@ export class UserEditComponent implements OnInit {
         queryProfile.equalTo('user', id);
         this.profile = await queryProfile.first();
         this.profileJson = this.profile.toJSON();
+        this.userJson.email = this.profileJson.email
         this.userDataJson = {
           companyType: this.profile?.get('companyType'),
           department: this.user.get('department'),
@@ -118,7 +126,9 @@ export class UserEditComponent implements OnInit {
       let arr = ['教师', '评审专家', '高校联系人'];
       if (this.tbookSer.profile.identity == '国家级管理员') {
         this.edit = true;
-      } else if (this.tbookSer.profile.identity == '工作联系人' && arr.includes(this.profile.get('identity'))
+      } else if (
+        this.tbookSer.profile.identity == '工作联系人' &&
+        arr.includes(this.profile.get('identity'))
       ) {
         this.userType = ['教师', '评审专家', '工作联系人'];
         this.edit = true;
@@ -162,7 +172,7 @@ export class UserEditComponent implements OnInit {
       this.message.warning('同级身份暂无权限操作');
       return;
     }
-    this.password = this.password.trim();
+    this.password = this.password?.trim();
     if (!this.password) {
       this.message.warning('密码格式错误');
       return;
@@ -177,8 +187,8 @@ export class UserEditComponent implements OnInit {
     this.isVisible = false;
   }
   //切换单位类型
-  onChangeType(){
-    this.userDataJson.department = null
+  onChangeType() {
+    this.userDataJson.department = null;
   }
   //选择部门
   async showModalDepart() {
@@ -301,8 +311,160 @@ export class UserEditComponent implements OnInit {
       this.nzImageService.preview(images, { nzZoom: 1.5, nzRotate: 0 });
     }
   }
+  /* 修改账号 */
+  loading: boolean = false;
+  submitForm(type: string) {
+    if (this.loading) return;
+    this.loading = true;
+    if (type == 'save') {
+      this.updateUserJson();
+    } else {
+      this.userJson = this.user.toJSON();
+      this.profileJson = this.profile.toJSON();
+      this.userDataJson = {
+        companyType: this.profile?.get('companyType'),
+        department: this.user.get('department'),
+      };
+      this.loading = false;
+    }
+  }
+  async updateUserJson() {
+    //修改用户数据
+    console.log(this.userJson);
+    console.log(this.profileJson);
+    this.userJson.username = this.userJson?.username?.trim();
+    this.userJson.email = this.userJson?.email?.trim();
+    this.userJson.phone = this.userJson?.phone?.trim();
+    this.userJson.name = this.userJson?.name?.trim();
+    if (!(await this.authVrifly())) {
+      this.loading = false;
+      return;
+    }
+    try {
+      this.user?.set('username', this.userJson?.username);
+      this.user?.set('name', this.userJson?.name);
+      this.user?.set('phone', this.userJson?.phone);
+      this.userJson?.email && this.user?.set('email', this.userJson?.email);
+      await this.user.save();
+
+      this.profile?.set('companyType', this.userDataJson.companyType);
+      this.profile?.set('email', this.userJson.email);
+      this.profile?.set('identity', this.profileJson.identity);
+
+      this.profile?.set('telephone', this.profileJson.telephone);
+      this.profile?.set('province', this.profileJson.province);
+      this.profile?.set('departmentName', this.profileJson.departmentName);
+      this.profile?.set('postName', this.profileJson.postName);
+      this.profile?.set('majorSubject', this.profileJson.majorSubject);
+
+      await this.profile?.save();
+      this.loading = false;
+      this.modal.success({
+        nzTitle: '修改成功',
+        nzContent: '',
+        nzOnOk: () => {},
+      });
+    } catch (err: any) {
+      console.warn('添加用户错误', err);
+      this.loading = false;
+      this.message.error(
+        err?.Error || '错误:请检查用户或邮箱及手机号是否已存在'
+      );
+      return;
+    }
+  }
 
-  submitForm(type:string){
-    this.message.warning('权限暂未开放')
+  async authVrifly(): Promise<boolean | undefined> {
+    this.userJson.username = this.userJson?.username?.trim();
+    this.userJson.email = this.userJson?.email?.trim();
+    this.userJson.phone = this.userJson?.phone?.trim();
+    this.userJson.name = this.userJson?.name?.trim();
+    if (
+      !this.userJson?.username ||
+      !this.userJson?.name ||
+      !this.userJson.phone ||
+      !this.userJson?.email
+    ) {
+      this.message.warning('请填写必填项');
+      return;
+    }
+    if (!this.userDataJson?.department) {
+      this.message.error('请选择所属部门');
+      return;
+    }
+    if (!this.profileJson.identity) {
+      this.message.error('请选择人员类型');
+      return;
+    }
+    let a = /^(?:(?:\+|00)86)?1[3-9]\d{9}$/;
+    if (this.userJson.phone && !String(this.userJson.phone).match(a)) {
+      this.message.error('请填写正确手机号');
+      return;
+    }
+    let m =
+      /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+    if (!String(this.userJson.email).match(m)) {
+      this.message.error('邮箱格式有误');
+      return;
+    }
+    if (
+      this.userJson.phone != this.user.get('phone') &&
+      !(await this.tbookSer.userFind(this.userJson.phone))
+    ) {
+      this.message.error('手机号已存在');
+      return;
+    }
+    return true;
+  }
+  //页面数据变化时
+  vrifly: boolean = false;
+  moduleChange(): Observable<boolean> {
+    let a =
+      this.userJson.username != this.user.get('username') ||
+      this.userJson.name != this.user.get('name') ||
+      this.userJson.email != this.profile.get('email') ||
+      this.userJson.phone != this.user.get('phone');
+    let b =
+      this.profileJson.identity != this.profile.get('identity') ||
+      this.profileJson.telephone != this.profile.get('telephone') ||
+      this.profileJson.province != this.profile.get('province') ||
+      this.profileJson.departmentName != this.profile.get('departmentName') ||
+      this.profileJson.postName != this.profile.get('postName') ||
+      this.profileJson.majorSubject != this.profile.get('majorSubject');
+    console.log(a, b);
+    if (
+      a ||
+      b ||
+      this.userDataJson.companyType != this.profile?.get('companyType')
+    ) {
+      if (this.vrifly) return of(this.vrifly);
+      this.updateCanDeActivate();
+      return of(false);
+    }
+    return of(true);
+  }
+  //提示保存
+  updateCanDeActivate() {
+    new Promise((result) => {
+      this.modal.confirm({
+        nzTitle: '离开当前页面?',
+        nzContent: '<p>当前编辑未保存,是否保存?</p>',
+        nzOkText: '保存',
+        nzOkType: 'primary',
+        nzOkDanger: true,
+        nzClosable: false,
+        nzMaskClosable: false,
+        nzOnOk: async () => {
+          await this.updateUserJson();
+          this.goUserList();
+          result(true);
+        },
+        nzCancelText: '取消',
+        nzOnCancel: () => {
+          this.vrifly = true;
+          this.goUserList();
+        },
+      });
+    });
   }
 }

+ 4 - 1
projects/textbook/src/modules/nav-author/components/attachment/attachment.component.ts

@@ -208,7 +208,10 @@ export class AttachmentComponent implements OnInit {
       this.msg.create('warning', '请返回选择适用课程性质')
       return true
     }
-
+    if(this.eduTextbook?.get('accept')!='本人自愿参加此次申报,已认真填写并检查以上材料,保证内容真实。'){
+      this.msg.create('warning', '请返回输入诚信承诺')
+      return true
+    }
     let eduColumn = eduTextBook.EduTextbook.fields
     let ignoreFiled = [
       'typeNumber', 'code', 'editionNumber', 'importantProjectOther',

+ 4 - 4
projects/textbook/src/modules/nav-author/components/basic-in/basic-in.component.html

@@ -204,7 +204,7 @@
             <nz-input-group style="width: 100px; margin-left: 20px" [nzSuffix]="suffixTemplateInfo">
               <input type="number" formControlName="editionNumber" nz-input placeholder="输入版次" />
             </nz-input-group>
-            <ng-template #suffixTemplateInfo>  </ng-template>
+            <ng-template #suffixTemplateInfo>  </ng-template>
           </div>
         </nz-input-group>
       </nz-form-control>
@@ -214,11 +214,11 @@
       <nz-form-control nzErrorTip="请输入完整内容" [nzSm]="12" [nzXs]="12">
         <nz-input-group>
           <div class="basic-row">
-            <nz-date-picker style="flex: 1" formControlName="printDate"  [nzDisabledDate]="disabledEditionDate"></nz-date-picker>
-            <nz-input-group style="width: 100px; margin-left: 20px" [nzSuffix]="suffixTemplateInfo">
+            <nz-date-picker nzMode="month" style="flex: 1" formControlName="printDate"  [nzDisabledDate]="disabledEditionDate"></nz-date-picker>
+            <nz-input-group style="width: 100px; margin-left: 20px" [nzSuffix]="suffixTemplateInfo02">
               <input type="number" formControlName="printNumber" nz-input placeholder="输入印次" />
             </nz-input-group>
-            <ng-template #suffixTemplateInfo> 次 </ng-template>
+            <ng-template #suffixTemplateInfo02> 次 </ng-template>
           </div>
         </nz-input-group>
       </nz-form-control>

+ 21 - 4
projects/textbook/src/modules/nav-author/components/faith/faith.component.html

@@ -25,7 +25,18 @@
         </nz-form-control>
       </nz-form-item>
     </div> -->
-  <form nz-form [formGroup]="validateForm" nzLayout="vertical">
+
+
+    <div class="author-content">
+      <div class="nav"><b>教材作者诚信承诺</b></div>
+      <p>输入诚信承诺:本人自愿参加此次申报,已认真填写并检查以上材料,保证内容真实。</p>
+      <input [(ngModel)]="value" (ngModelChange)="changeAccept()" nz-input placeholder="请输入承诺内容" />
+
+    </div>
+
+
+
+  <!-- <form nz-form [formGroup]="validateForm" nzLayout="vertical">
     <div class="author-content">
       <div class="nav"><b>教材作者诚信承诺</b></div>
       <p>输入诚信承诺:本人自愿参加此次申报,已认真填写并检查以上材料,保证内容真实。</p>
@@ -35,7 +46,7 @@
         </nz-form-control>
       </nz-form-item>
     </div>
-    <!-- <div class="author-content">
+    <div class="author-content">
       <div class="nav"><b>申报单位承诺意见</b></div>
       <div class="text">
         高校主管领导输入以下承诺:已对教材有关信息及填报的内容进行核实,保证真实性。经对该教材评审评价,同意该教材申报。并在导出函报文件后签字加盖高校公章;
@@ -49,9 +60,15 @@
           </nz-textarea-count>
         </nz-form-control>
       </nz-form-item>
-    </div> -->
-  </form>
+    </div>
+  </form> -->
 </div>
+
+
+
+
+
+
 <div class="footer">
   <button nz-button nzType="default" style="margin-right: 20px" (click)="submitForm('save')">
     保存本页

+ 70 - 55
projects/textbook/src/modules/nav-author/components/faith/faith.component.ts

@@ -72,19 +72,27 @@ export class FaithComponent  implements OnInit {
   ) { }
   ngOnInit() {
     if (this.eduTextbook.id) {
-      this.validateForm = this.fb.group({
-        unitMaterial: [this.eduTextbook.get('unitMaterial')?.text||'' , [Validators.maxLength(200)]],
-        accept: [this.eduTextbook.get('accept') || '', [Validators.required]],
-      });
+
+      this.value = this.eduTextbook.get('accept') || ''
+
+
+      // this.validateForm = this.fb.group({
+      //   // unitMaterial: [this.eduTextbook.get('unitMaterial')?.text||'' , [Validators.maxLength(200)]],
+      //   accept: [this.eduTextbook.get('accept') || '', [Validators.required]],
+      // });
     }
   }
   value:string=''
 
 
   async submitForm(event?: string): Promise<void> {
-
-    let params: any = this.validateForm.value;
-    console.log(params)
+    if(this.value!='本人自愿参加此次申报,已认真填写并检查以上材料,保证内容真实。'){
+      this.msg.error('诚信承诺输入错误,请正确输入');
+      // return
+    }
+    // let params: any = this.validateForm.value;
+    // console.log(params)
+    let params = {accept:this.value}
     await this.saveEduTextbook(params);
 
     if (event == 'pre') {//上一步
@@ -107,6 +115,7 @@ export class FaithComponent  implements OnInit {
   }
 
   async saveEduTextbook(params: any) {
+    
     if (!this.eduTextbook) {
       this.msg.error('请先创建教材');
       return;
@@ -117,59 +126,65 @@ export class FaithComponent  implements OnInit {
       className: 'Company',
       objectId: this.tbookSer.company,
     });
-    params.unitMaterial &&
-      this.eduTextbook?.set('unitMaterial',{text:params.unitMaterial} );
+    // params.unitMaterial &&
+    //   this.eduTextbook?.set('unitMaterial',{text:params.unitMaterial} );
       params.accept &&
       this.eduTextbook?.set('accept', params.accept);
     await this.eduTextbook?.save();
     return;
   }
-  upload(e: any, type: string, index?: any) {
-    let file = e[(e?.length - 1) || 0];
-    if(type=='unitMaterial'){
-      this[type].url = file?.url
-      this[type].name = file?.name
+  // upload(e: any, type: string, index?: any) {
+  //   let file = e[(e?.length - 1) || 0];
+  //   if(type=='unitMaterial'){
+  //     this[type].url = file?.url
+  //     this[type].name = file?.name
+  //   }
+  // }
+
+
+
+  // /**获取文件名 */
+  // getFileName(url: string) {
+  //   if (!url) return ''
+  //   let str = url?.split('/')[5]
+  //   let index = str?.indexOf('-')
+  //   let result = decodeURIComponent(str?.substring(index + 1))
+  //   return result || '未知文件名'
+  // }
+
+  // downloadFile(fileName: string) {
+  //   // let fileName = '十四五”普通高等教育本科国家级规划教材第一次遴选推荐申报表.docx'
+  //   const fileUrl = `../../../../../public/file/${fileName}`;
+  //   this.http.get(fileUrl, { responseType: 'blob' }).subscribe((blob) => {
+  //     const url = window.URL.createObjectURL(blob);
+  //     const a = document.createElement('a');
+  //     a.href = url;
+  //     a.download = fileName;
+  //     document.body.appendChild(a);
+  //     a.click();
+  //     document.body.removeChild(a);
+  //     window.URL.revokeObjectURL(url);
+  //   })
+  // }
+  // openFile(url: string) {
+  //   console.log(url);
+  //   window.open(url)
+  // }
+
+
+  // validateForm: FormGroup<{
+  //   // unitMaterial: FormControl<string | null>;
+  //   accept: FormControl<string | null>;
+  // }> = this.formBuilder.group({
+  //   // unitMaterial: ['', [Validators.maxLength(200)]],
+  //   accept: ['', [Validators.maxLength(100)]]
+
+  // });
+  changeAccept(){
+    console.log(this.value)
+    let str = '本人自愿参加此次申报,已认真填写并检查以上材料,保证内容真实。'
+    if(str.indexOf(this.value)==-1){
+      this.msg.create('warning','请正确输入内容')
     }
   }
-
-
-
-  /**获取文件名 */
-  getFileName(url: string) {
-    if (!url) return ''
-    let str = url?.split('/')[5]
-    let index = str?.indexOf('-')
-    let result = decodeURIComponent(str?.substring(index + 1))
-    return result || '未知文件名'
-  }
-
-  downloadFile(fileName: string) {
-    // let fileName = '十四五”普通高等教育本科国家级规划教材第一次遴选推荐申报表.docx'
-    const fileUrl = `../../../../../public/file/${fileName}`;
-    this.http.get(fileUrl, { responseType: 'blob' }).subscribe((blob) => {
-      const url = window.URL.createObjectURL(blob);
-      const a = document.createElement('a');
-      a.href = url;
-      a.download = fileName;
-      document.body.appendChild(a);
-      a.click();
-      document.body.removeChild(a);
-      window.URL.revokeObjectURL(url);
-    })
-  }
-  openFile(url: string) {
-    console.log(url);
-    window.open(url)
-  }
-
-
-  validateForm: FormGroup<{
-    unitMaterial: FormControl<string | null>;
-    accept: FormControl<string | null>;
-  }> = this.formBuilder.group({
-    unitMaterial: ['', [Validators.maxLength(200)]],
-    accept: ['', [Validators.maxLength(100)]]
-
-  });
-
 }

+ 2 - 2
projects/textbook/src/modules/nav-author/components/textbook-pertain/textbook-pertain.component.ts

@@ -314,7 +314,7 @@ export class TextbookPertainComponent implements OnInit {
         this.authorList.splice(idx + 1, 0, {
           name: '',
           unit: '',
-          birth: '',
+          birth: new Date('December 1, 1975 00:00:00'),
           nationality: '',
           job: '',
           title: '',
@@ -347,7 +347,7 @@ export class TextbookPertainComponent implements OnInit {
             {
               name: '',
               unit: '',
-              birth: '',
+              birth: new Date('December 1, 1975 00:00:00'),
               nationality: '',
               job: '',
               title: '',

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

@@ -8,6 +8,7 @@ import Parse from 'parse';
 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';
+import { textbookServer } from '../../../services/textbook';
 @Component({
   selector: 'app-page-process',
   templateUrl: './page-process.component.html',
@@ -19,11 +20,11 @@ import { TextbookComponent } from '../../../app/textbook/textbook.component';
     NzTabsModule,
     ProcessCreateComponent,
     CompTableListComponent,
-    TextbookComponent
+    TextbookComponent,
   ],
   standalone: true,
 })
-export class PageProcessComponent  implements OnInit {
+export class PageProcessComponent implements OnInit {
   active: number = 0;
   eduProcess: Parse.Object | undefined;
 
@@ -32,29 +33,30 @@ export class PageProcessComponent  implements OnInit {
   beforeFilterObj: any = {
     showMore: true, //显示更多字段
     isCheck: true,
-    noStared:true,
-    status: ['200','201','400'],
+    noStared: true,
+    status: ['200'],
     btns: {
-      reject: true, //退回教材
-      star: true, //移除推荐
-      export:true
+      // reject: true, //退回教材
+      // star: true, //移除推荐
+      export: true,
     },
   };
   //已加入推荐
   afterFilterObj: any = {
     showMore: true, //显示更多字段
     isCheck: true,
-    status: ['200','201','400'],
+    status: ['200', '201', '400'],
     btns: {
-      verify:true,
-      remove: true, //移除推荐
-      export:true
+      // verify:true,
+      // remove: true, //移除推荐
+      export: true,
     },
   };
 
   constructor(
-    private activeRoute:ActivatedRoute,
-    private router: Router,
+    private activeRoute: ActivatedRoute,
+    public tbookSer: textbookServer,
+    private router: Router
   ) {
     this.user = Parse.User.current();
   }
@@ -66,12 +68,33 @@ export class PageProcessComponent  implements OnInit {
         let query = new Parse.Query('EduProcess');
         query.include('branch', 'department');
         query.equalTo('objectId', id);
-        this.eduProcess = await query.first();
+        let res = await query.first();
+        if (res?.id) {
+          let vrifly = await this.tbookSer.getEduProcess(
+            res.get('department').id
+          );
+          if (vrifly) {
+            this.beforeFilterObj.btns = {
+              reject: true, //退回教材
+              star: true, //移除推荐
+              export: true,
+            };
+            this.afterFilterObj.btns = {
+              verify: true,
+              remove: true, //移除推荐
+              export: true,
+            };
+          }
+        }
+        this.eduProcess = res;
       }
-    })
+    });
   }
 
-  onCreateProcess(){
-    this.router.navigate(['/nav-admin/manage/process/create',{cid:this.eduProcess?.id}])
+  onCreateProcess() {
+    this.router.navigate([
+      '/nav-admin/manage/process/create',
+      { cid: this.eduProcess?.id },
+    ]);
   }
 }

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

@@ -49,22 +49,22 @@ export class PageTextbookComponent implements OnInit {
     noStared: true,
     status: ['200'],
     btns: {
-      reject: true, //退回教材
-      star: true, //移除推荐
-      export:true
+      // reject: true, //退回教材
+      // star: true, //移除推荐
+      export: true,
     },
   };
   //已加入推荐
   afterFilterObj: any = {
     showMore: true, //显示更多字段
     isCheck: true,
-    status: ['200','201','400'],
+    status: ['200', '201', '400'],
     btns: {
-      remove: true, //移除推荐
-      export:true
+      // remove: true, //移除推荐
+      export: true,
     },
   };
-  eduProcess?:Parse.Object
+  eduProcess?: Parse.Object;
 
   constructor(
     public tbookSer: textbookServer,
@@ -86,9 +86,9 @@ export class PageTextbookComponent implements OnInit {
   }
 
   ngOnInit(): void {
-    this.getProcess()
+    this.getProcess();
   }
-  async getProcess(){
+  async getProcess() {
     let parentMap = await this.tbookSer.formatNode(
       this.tbookSer?.profile?.user?.department?.objectId
     );
@@ -100,7 +100,19 @@ export class PageTextbookComponent implements OnInit {
     query.notEqualTo('isDeleted', true);
     // query.notEqualTo('status', '100');
     let res = await query.first();
-    this.eduProcess = res
+    let vrifly = await this.tbookSer.getEduProcess(parentMap[1]?.key);
+    if (vrifly) {
+      this.beforeFilterObj.btns = {
+        reject: true, //退回教材
+        star: true, //移除推荐
+        export: true,
+      };
+      this.afterFilterObj.btns = {
+        remove: true, //移除推荐
+        export: true,
+      };
+    }
+    this.eduProcess = res;
   }
   toUrl(url: string, params?: object) {
     if (params) {
@@ -111,10 +123,12 @@ export class PageTextbookComponent implements OnInit {
   }
   //报送
   async submitted() {
-    if(this.eduProcess?.get('status') == '400'){
-      this.message.warning('已提交报送,无需重复提交')
-      this.toUrl(`/nav-province-contact/manage/submitted/${this.eduProcess?.id}`)
-      return
+    if (this.eduProcess?.get('status') == '400') {
+      this.message.warning('已提交报送,无需重复提交');
+      this.toUrl(
+        `/nav-province-contact/manage/submitted/${this.eduProcess?.id}`
+      );
+      return;
     }
     this.eduProcess?.set('status', '400');
     this.eduProcess?.set('releaseDate', new Date());
@@ -132,7 +146,7 @@ export class PageTextbookComponent implements OnInit {
     ]);
     let count = await query.count();
     if (count > this.eduProcess?.get('num')) {
-      this.message.warning('当前推荐教材数量已超额')
+      this.message.warning('当前推荐教材数量已超额');
       return;
     }
     await this.eduProcess?.save();
@@ -141,7 +155,7 @@ export class PageTextbookComponent implements OnInit {
       item.set('status', '400');
       await item.save();
     }
-    this.message.success('提交成功')
-    this.toUrl(`/nav-province-contact/manage/submitted/${this.eduProcess?.id}`)
+    this.message.success('提交成功');
+    this.toUrl(`/nav-province-contact/manage/submitted/${this.eduProcess?.id}`);
   }
 }

+ 2 - 2
projects/textbook/src/modules/nav-province-contact/submitted/export-file/export-file.component.html

@@ -17,11 +17,11 @@
   <div class="left">
     <div class="row">
       <div class="lable">推荐教材</div>
-      <div class="val">{{allCount}}</div>
+      <div class="val">{{otherCount}}</div>
     </div>
     <div class="row">
       <div class="lable">申报限额外推荐教材</div>
-      <div class="val">{{otherCount}}</div>
+      <div class="val">{{allCount - otherCount}}</div>
     </div>
     <div class="row">
       <div class="lable">推荐表总份数</div>

+ 1 - 0
projects/textbook/src/services/languages.map.ts

@@ -4,6 +4,7 @@ export const languages = {
     { lang: 'en', name: '英文' },
     { lang: 'or', name: '其他外国语' },
     { lang: 'min', name: '中国少数民族语言' },
+    { lang: 'man', name: '盲文' },
     // { lang: 'es', name: '西班牙语' },
     // { lang: 'fr', name: '法语' },
     // { lang: 'de', name: '德语' },

+ 76 - 0
projects/textbook/src/services/route-reuse.service.ts

@@ -0,0 +1,76 @@
+import {
+  ActivatedRouteSnapshot,
+  DetachedRouteHandle,
+  RouteReuseStrategy,
+} from '@angular/router';
+
+export class ReuseService implements RouteReuseStrategy {
+  storedRouteHandles = new Map<string, DetachedRouteHandle>();
+  //用来判断跳转时是否需要存储页面
+  from = '';
+  to = '';
+  //用来判断跳转时是否要读取之前存储的页面
+  reuseFrom = '';
+  reuseTo = '';
+
+  shouldReuseRoute(
+    from: ActivatedRouteSnapshot,
+    to: ActivatedRouteSnapshot
+  ): boolean {
+    if (from.routeConfig) {
+      this.from = this.getPath(from);
+    }
+    if (to.routeConfig) {
+      this.to = this.getPath(to);
+    }
+    return from.routeConfig === to.routeConfig;
+  }
+
+  shouldDetach(route: ActivatedRouteSnapshot): boolean {
+    console.log(this.from);
+    console.log(this.to);
+    
+    // 判断是否执行store
+    const f =
+      (this.from === 'nav-admin/manage/user' && this.to === 'nav-admin/manage/user/edit') ||
+      (this.from === 'b' && this.to === 'c');
+    if (f) {
+      this.reuseFrom = this.to;
+      this.reuseTo = this.from;
+    }
+    return f;
+  }
+
+  store(
+    route: ActivatedRouteSnapshot,
+    detachedTree: DetachedRouteHandle
+  ): void {
+    // 进行路由复用存储
+    this.storedRouteHandles.set(this.getPath(route), detachedTree);
+  }
+
+  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
+    if (this.from === this.reuseFrom && this.to === this.reuseTo) {
+      // 读取路由复用
+      return this.storedRouteHandles.get(
+        this.getPath(route)
+      ) as DetachedRouteHandle;
+    } else {
+      return null;
+    }
+  }
+
+  shouldAttach(route: ActivatedRouteSnapshot): boolean {
+    if (this.reuseFrom && this.reuseTo && this.from && this.to) {
+      return this.from === this.reuseFrom && this.to === this.reuseTo;
+    } else {
+      return false;
+    }
+  }
+
+  private getPath(route: ActivatedRouteSnapshot | any): string {
+    // 截取路由地址中最小子节点
+    let url = route['_routerState'].url.split('/');
+    return url[url.length - 1].split('?')[0];
+  }
+}

+ 113 - 104
projects/textbook/src/services/textbook.ts

@@ -9,9 +9,7 @@ export class textbookServer {
   company: string = localStorage.getItem('company')!;
   theme: boolean = false; //深色主题模式
   profile: any = JSON.parse(localStorage.getItem('profile')!);
-  constructor(
-    private http:HttpClient
-  ) {}
+  constructor(private http: HttpClient) {}
   authMobile(mobile: string): boolean {
     let a = /^1[3456789]\d{9}$/;
     if (!String(mobile).match(a)) {
@@ -59,14 +57,14 @@ export class textbookServer {
   //格式化链
   async formatNode(id: string): Promise<Array<any>> {
     let query = new Parse.Query('Department');
-    query.select('name', 'parent', 'hasChildren','type','branch');
+    query.select('name', 'parent', 'hasChildren', 'type', 'branch');
     let r = await query.get(id);
     let arr = [
       {
         title: r.get('name'),
         key: r.id,
         hasChildren: r.get('hasChildren'), //是否是最下级
-        type:r.get('type'),
+        type: r.get('type'),
         branch: r?.get('branch'),
         parent: r?.get('parent')?.id, //上级
       },
@@ -77,37 +75,39 @@ export class textbookServer {
     return arr;
   }
   //获取下级所有部门
-  async getChild(id:string):Promise<Array<string>>{
+  async getChild(id: string): Promise<Array<string>> {
     console.log(id);
-    let arr:Array<string> = [id]
-    let query = new Parse.Query('Department')
-    query.equalTo('parent',id)
-    query.notEqualTo('isDeleted',true)
-    query.select('id','hasChildren')
-    query.limit(200)
-    let r = await query.find()
+    let arr: Array<string> = [id];
+    let query = new Parse.Query('Department');
+    query.equalTo('parent', id);
+    query.notEqualTo('isDeleted', true);
+    query.select('id', 'hasChildren');
+    query.limit(200);
+    let r = await query.find();
     for (let index = 0; index < r.length; index++) {
-      if(r[index].get('hasChildren')){
-        let child:Array<string> = await this.getChild(r[index].id)
-        arr.push(...child)
-      }else{
-        arr.push(r[index].id)
+      if (r[index].get('hasChildren')) {
+        let child: Array<string> = await this.getChild(r[index].id);
+        arr.push(...child);
+      } else {
+        arr.push(r[index].id);
       }
     }
-    return Array.from(new Set([...arr]))
+    return Array.from(new Set([...arr]));
   }
-  userFind(phone:string){
-    return new Promise((res)=>{
-      Parse.Cloud.run('userFind',{mobile:phone}).then(data=>{
-        if(data){
-          res(false)
-        }else{
-          res(true)
-        }
-      }).catch(()=> res(true))
-    })
+  userFind(phone: string) {
+    return new Promise((res) => {
+      Parse.Cloud.run('userFind', { mobile: phone })
+        .then((data) => {
+          if (data) {
+            res(false);
+          } else {
+            res(true);
+          }
+        })
+        .catch(() => res(true));
+    });
   }
-  
+
   /* 批量预设(临时) */
   async saveProcess() {
     // let count = 0;
@@ -123,87 +123,96 @@ export class textbookServer {
     //   count++
     //   console.log(count);
     // }
-  //   let query = new Parse.Query('Department')
-  //   query.equalTo('parent',null)
-  //   query.equalTo('name','省级教育行政部门')
-  //   let r = await query.find()
-  //   for (let index = 0; index < r.length; index++) {
-  //     const element = r[index];
-  //     let queryPareet = new Parse.Query('Department')
-  //     queryPareet.equalTo('parent', element.id)
-  //     queryPareet.limit(2000)
-  //     let prents = await queryPareet.find()
-  //     for (let index = 0; index < prents.length; index++) {
-  //       let item = prents[index];
-  //       let obj = Parse.Object.extend('EduProcess');
-  //       let eduProcess = new obj()
-  //       eduProcess?.set('company', {
-  //         __type: 'Pointer',
-  //         className: 'Company',
-  //         objectId: 'RbIKpmuaMC',
-  //       });
-  //       eduProcess?.set('branch', {
-  //         __type: 'Pointer',
-  //         className: 'Department',
-  //         objectId:element.id,
-  //       });
-  //       eduProcess?.set('department', {
-  //         __type: 'Pointer',
-  //         className: 'Department',
-  //         objectId: item.id,
-  //       });
-  //       eduProcess?.set('name', item.get('name'));
-  //       eduProcess?.set('desc', item.get('name') + '流程');
-  //       eduProcess?.set('code', item.get('code') || item.id);
-  //       if(element.get('name') == '全国出版单位') {
-  //         eduProcess?.set('startDate', new Date('2024-07-20 18:00'));
-  //         eduProcess?.set('deadline', new Date('2024-09-20 18:00'));
-  //       }
-  //       await eduProcess?.save();
-  //       count ++
-  //       console.log(count);
-  //     }
-  //   }
-}
-async tbookExportReport(options:{processId?:string,bookList?:any[]}){
-
-  let url = Parse.serverURL + "/api/tbook/export"
-  // console.log(url)
-  let response = await fetch(url, {
-    method: 'POST',
-    headers: {
-        'Content-Type': 'application/json',
-        'X-Parse-Application-Id': 'edu-textbook'
-    },
-    body: JSON.stringify(options)
-  })
-  let result = await response.json()
-  let zipUrl = result?.result?.zipUrl;
-  if(result?.code==200){
-    zipUrl = zipUrl.replaceAll("http://","https://");
-    const a = document.createElement('a'); // 创建一个&lt;a&gt;元素
-    a.href = zipUrl; // 设置链接的href属性为要下载的文件的URL
-    a.download = '报送流程'; // 设置下载文件的名称
-    document.body.appendChild(a); // 将&lt;a&gt;元素添加到文档中
-    a.click(); // 模拟点击&lt;a&gt;元素
-    document.body.removeChild(a); // 下载后移除&lt;a&gt;元素
+    //   let query = new Parse.Query('Department')
+    //   query.equalTo('parent',null)
+    //   query.equalTo('name','省级教育行政部门')
+    //   let r = await query.find()
+    //   for (let index = 0; index < r.length; index++) {
+    //     const element = r[index];
+    //     let queryPareet = new Parse.Query('Department')
+    //     queryPareet.equalTo('parent', element.id)
+    //     queryPareet.limit(2000)
+    //     let prents = await queryPareet.find()
+    //     for (let index = 0; index < prents.length; index++) {
+    //       let item = prents[index];
+    //       let obj = Parse.Object.extend('EduProcess');
+    //       let eduProcess = new obj()
+    //       eduProcess?.set('company', {
+    //         __type: 'Pointer',
+    //         className: 'Company',
+    //         objectId: 'RbIKpmuaMC',
+    //       });
+    //       eduProcess?.set('branch', {
+    //         __type: 'Pointer',
+    //         className: 'Department',
+    //         objectId:element.id,
+    //       });
+    //       eduProcess?.set('department', {
+    //         __type: 'Pointer',
+    //         className: 'Department',
+    //         objectId: item.id,
+    //       });
+    //       eduProcess?.set('name', item.get('name'));
+    //       eduProcess?.set('desc', item.get('name') + '流程');
+    //       eduProcess?.set('code', item.get('code') || item.id);
+    //       if(element.get('name') == '全国出版单位') {
+    //         eduProcess?.set('startDate', new Date('2024-07-20 18:00'));
+    //         eduProcess?.set('deadline', new Date('2024-09-20 18:00'));
+    //       }
+    //       await eduProcess?.save();
+    //       count ++
+    //       console.log(count);
+    //     }
+    //   }
   }
-  // console.log(result)
-  return result
- 
-  
-  Parse.Cloud.run('tbookExportReport', options).then(
-    (data) => {
+  async tbookExportReport(options: { processId?: string; bookList?: any[] }) {
+    let url = Parse.serverURL + '/api/tbook/export';
+    // console.log(url)
+    let response = await fetch(url, {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json',
+        'X-Parse-Application-Id': 'edu-textbook',
+      },
+      body: JSON.stringify(options),
+    });
+    let result = await response.json();
+    let zipUrl = result?.result?.zipUrl;
+    if (result?.code == 200) {
+      zipUrl = zipUrl.replaceAll('http://', 'https://');
+      const a = document.createElement('a'); // 创建一个&lt;a&gt;元素
+      a.href = zipUrl; // 设置链接的href属性为要下载的文件的URL
+      a.download = '报送流程'; // 设置下载文件的名称
+      document.body.appendChild(a); // 将&lt;a&gt;元素添加到文档中
+      a.click(); // 模拟点击&lt;a&gt;元素
+      document.body.removeChild(a); // 下载后移除&lt;a&gt;元素
+    }
+    // console.log(result)
+    return result;
+
+    Parse.Cloud.run('tbookExportReport', options).then((data) => {
       console.log(data);
       let url = data.zipUrl;
-      url = url.replaceAll("http://","https://");
+      url = url.replaceAll('http://', 'https://');
       const a = document.createElement('a'); // 创建一个&lt;a&gt;元素
       a.href = url; // 设置链接的href属性为要下载的文件的URL
       a.download = '报送流程'; // 设置下载文件的名称
       document.body.appendChild(a); // 将&lt;a&gt;元素添加到文档中
       a.click(); // 模拟点击&lt;a&gt;元素
       document.body.removeChild(a); // 下载后移除&lt;a&gt;元素
-    }
-  );
-}
+    });
+  }
+
+  async getEduProcess(id: string): Promise<string | undefined> {
+    if (!id) return;
+    let query = new Parse.Query('EduProcess');
+    query.equalTo('department', id);
+    query.lessThanOrEqualTo('startDate', new Date());
+    query.greaterThan('deadline', new Date());
+    query.notEqualTo('isDeleted', true);
+    query.containedIn('status', ['200', '300']);
+    query.select('objectId');
+    let res = await query.first();
+    return res?.id;
+  }
 }