Jelajahi Sumber

update 教材资源收集

warrior 1 Minggu lalu
induk
melakukan
5a61277c5d

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

@@ -177,6 +177,13 @@ export class CompManageComponent implements OnInit {
 
   ngOnInit() {
     console.log(this.tbookSer.profile.identity);
+    if (this.tbookSer.profile.identity == '工作联系人') {
+      this.optionsMap['工作联系人'][0].child.push({
+        name: '本社教材源文件',
+        path: '/nav-province-contact/manage/collect',
+        id: '1-3',
+      });
+    }
     if (localStorage.getItem('active')) return;
     if (this.optionsMap[this.tbookSer.profile.identity][0]?.child) {
       this.active = '1-1';

+ 267 - 0
projects/textbook/src/modules/nav-admin/components/collect-textbook/collect-textbook.component.html

@@ -0,0 +1,267 @@
+<div class="textbook-table">
+  <div class="tool">
+    <div class="search">
+      <nz-input-group style="width: 280px" [nzPrefix]="prefixTemplateUser">
+        <input
+          type="text"
+          nz-input
+          placeholder="输入教材名称 / ISBN / 申报编号"
+          [(ngModel)]="searchValue"
+          (ngModelChange)="onSearch($event)"
+        />
+      </nz-input-group>
+      <ng-template #prefixTemplateUser
+        ><span nz-icon nzType="search"></span
+      ></ng-template>
+    </div>
+    <!-- <div class="sbt" (click)="export()">导出评审明细</div> -->
+  </div>
+  <nz-table
+    #tableData
+    [nzData]="textbookList"
+    [nzTotal]="count"
+    [(nzPageSize)]="limit"
+    [nzPageIndex]="pageIndex"
+    style="margin: 10px 0"
+    [nzLoading]="loading"
+    nzSize="middle"
+    [nzFrontPagination]="false"
+    [nzScroll]="{ x: (maxWidth || '800') + 'px', y: '580px' }"
+    nzTableLayout="fixed"
+    [nzPageSizeOptions]="[10, 20, 30, 40, 50]"
+    nzShowSizeChanger
+    (nzPageIndexChange)="pageIndexChange($event)"
+    (nzPageSizeChange)="onPageSizeChange($event)"
+  >
+    <thead>
+      <tr>
+        <th nzEllipsis nzWidth="120px" nzLeft>教材名称</th>
+        <th nzEllipsis nzWidth="120px">申报编号</th>
+        <th nzEllipsis nzWidth="120px">ISBN</th>
+        <th nzEllipsis nzWidth="120px">出版单位</th>
+        <th nzEllipsis nzWidth="120px">出版单位联系人</th>
+        <th nzEllipsis nzWidth="80px" nzAlign="center">文件状态</th>
+        <th nzEllipsis nzWidth="80px" nzAlign="center" nzRight>操作</th>
+      </tr>
+    </thead>
+    @if (textbookList.length > 0) {
+    <tbody>
+      @for (data of textbookList; track data.id) {
+      <tr>
+        <td
+          nzEllipsis
+          class="activeTd"
+          (click)="
+            toUrl('/common/textbook/details/' + data?.get('eduTextbook')?.id)
+          "
+          nz-popover
+          [nzPopoverContent]="contentTemplatetitle"
+        >
+          {{ data?.get("title") || "-" }}
+          <ng-template #contentTemplatetitle>
+            <div style="max-width: 400px">
+              {{ data?.get("title") || "-" }}
+            </div>
+          </ng-template>
+        </td>
+        <td nzEllipsis>
+          {{ data?.get("code") ?? "-" }}
+        </td>
+        <td
+          nzEllipsis
+          nz-popover
+          [nzPopoverContent]="contentTemplateISBN"
+          #ISBN
+        >
+          {{ fromatFiled(data?.get("childrens"), "ISBN") }}
+          <ng-template #contentTemplateISBN>
+            <div style="max-width: 400px">
+              {{ ISBN.innerText }}
+            </div>
+          </ng-template>
+        </td>
+        <td
+          nzEllipsis
+          nz-popover
+          [nzPopoverContent]="contentTemplateeditionUnit"
+          #editionUnit
+        >
+          {{ fromatFiled(data?.get("childrens"), "editionUnit") }}
+          <ng-template #contentTemplateeditionUnit>
+            <div style="max-width: 400px">
+              {{ editionUnit.innerText }}
+            </div>
+          </ng-template>
+        </td>
+
+        <td
+          nzEllipsis
+          nz-popover
+          [nzPopoverContent]="contentTemplateChild"
+          #childrens
+        >
+          @for (n of formatMapProfile(data?.get('childrens')); track n) {
+          {{ n }}
+          }
+          <ng-template #contentTemplateChild>
+            <div style="max-width: 400px">
+              {{ childrens.innerText }}
+            </div>
+          </ng-template>
+        </td>
+        <td nzEllipsis nzAlign="center">未上传</td>
+        <td nzEllipsis nzRight nzAlign="center">
+          <a nz-button nzType="link">查看</a>
+        </td>
+      </tr>
+      }
+    </tbody>
+    }
+  </nz-table>
+  @if (textbookList.length == 0) {
+  <nz-empty nzNotFoundImage="/img/group-empty.png"></nz-empty>
+  }
+
+  <div class="loading" [hidden]="!showLoading">
+    <nz-spin nzSimple [nzSize]="'large'"></nz-spin>
+  </div>
+</div>
+
+<nz-modal
+  [(nzVisible)]="showModal"
+  nzTitle="收集教材源文件"
+  (nzOnCancel)="handleCancel()"
+  nzWidth="600px"
+>
+  <ng-container *nzModalContent>
+    <div nz-row class="depart-modal">
+      <div nz-col nzSpan="24">
+        <div class="row">
+          <div class="label">
+            开始时间 <span style="color: #e8353e">*</span>
+          </div>
+          <div class="value">
+            <nz-date-picker
+              nzFormat="yyyy-MM-dd HH:mm:ss"
+              [(ngModel)]="collectStartData"
+              [nzShowTime]="{ nzDefaultOpenValue: timeDefaultValue }"
+            ></nz-date-picker>
+          </div>
+        </div>
+        <div class="row">
+          <div class="label">
+            截止时间 <span style="color: #e8353e">*</span>
+          </div>
+          <div class="value">
+            <nz-date-picker
+              nzFormat="yyyy-MM-dd HH:mm:ss"
+              [(ngModel)]="collectEndData"
+              [nzStatus]="collectEndData < collectStartData ? 'error' : ''"
+              [nzShowTime]="{ nzDefaultOpenValue: timeDefaultValue }"
+            ></nz-date-picker>
+          </div>
+        </div>
+        <div class="row" style="align-items: start">
+          <div class="label">收集教材</div>
+          <div class="value">
+            <nz-table
+              #tableData
+              [nzData]="textbookList"
+              [nzTotal]="count"
+              [(nzPageSize)]="limit"
+              [nzPageIndex]="pageIndex"
+              [nzLoading]="loading"
+              nzSize="middle"
+              [nzFrontPagination]="false"
+              [nzScroll]="{ x: (maxWidth || '400') + 'px', y: '580px' }"
+              nzTableLayout="fixed"
+              [nzPageSizeOptions]="[10, 20, 30, 40, 50]"
+              nzShowSizeChanger
+              (nzPageIndexChange)="pageIndexChange($event)"
+              (nzPageSizeChange)="onPageSizeChange($event)"
+            >
+              <thead>
+                <tr>
+                  <th nzEllipsis nzWidth="120px" nzLeft>教材名称</th>
+                  <th nzEllipsis nzWidth="120px">申报编号</th>
+                  <th nzEllipsis nzWidth="80px">ISBN</th>
+                  <th nzEllipsis nzWidth="120px">出版单位</th>
+                </tr>
+              </thead>
+              @if (textbookList.length > 0) {
+              <tbody>
+                @for (data of textbookList; track data.id) {
+                <tr>
+                  <td
+                    nzEllipsis
+                    class="activeTd"
+                    (click)="
+                      toUrl(
+                        '/common/textbook/details/' +
+                          data?.get('eduTextbook')?.id
+                      )
+                    "
+                    nz-popover
+                    [nzPopoverContent]="contentTemplatetitle"
+                  >
+                    {{ data?.get("title") || "-" }}
+                    <ng-template #contentTemplatetitle>
+                      <div style="max-width: 400px">
+                        {{ data?.get("title") || "-" }}
+                      </div>
+                    </ng-template>
+                  </td>
+                  <td nzEllipsis>
+                    {{ data?.get("code") ?? "-" }}
+                  </td>
+                  <td
+                    nzEllipsis
+                    nz-popover
+                    [nzPopoverContent]="contentTemplateISBN"
+                    #ISBN
+                  >
+                    {{ fromatFiled(data?.get("childrens"), "ISBN") }}
+                    <ng-template #contentTemplateISBN>
+                      <div style="max-width: 400px">
+                        {{ ISBN.innerText }}
+                      </div>
+                    </ng-template>
+                  </td>
+                  <td
+                    nzEllipsis
+                    nz-popover
+                    [nzPopoverContent]="contentTemplateeditionUnit"
+                    #editionUnit
+                  >
+                    {{ fromatFiled(data?.get("childrens"), "editionUnit") }}
+                    <ng-template #contentTemplateeditionUnit>
+                      <div style="max-width: 400px">
+                        {{ editionUnit.innerText }}
+                      </div>
+                    </ng-template>
+                  </td>
+                </tr>
+                }
+              </tbody>
+              }
+            </nz-table>
+            @if (textbookList.length == 0) {
+            <nz-empty nzNotFoundImage="/img/group-empty.png"></nz-empty>
+            }
+          </div>
+        </div>
+      </div>
+    </div>
+  </ng-container>
+  <div *nzModalFooter>
+    <button nz-button nzType="default" (click)="handleCancel()">取消</button>
+    <button
+      nz-button
+      nzType="primary"
+      [disabled]="!this.collectStartData || !this.collectEndData"
+      (click)="editCollect()"
+    >
+      收集
+    </button>
+  </div>
+</nz-modal>

+ 102 - 0
projects/textbook/src/modules/nav-admin/components/collect-textbook/collect-textbook.component.scss

@@ -0,0 +1,102 @@
+.activeTd{
+  cursor: pointer;
+}
+.tool{
+  display: flex;
+  justify-content: space-between;
+  .sbt{
+    padding: 6px 10px;
+    background: #E8F5FC;
+    font-family: PingFang SC;
+    font-size: 14px;
+    font-weight: 400;
+    /* line-height: 20px; */
+    text-align: center;
+    color: #0054C3;
+    border-radius: 4px;
+    cursor: pointer;
+  }
+}
+.activeTd{
+  color: #c6233f;
+}
+// 选中,批量操作区域
+.batch-toolbar-modal{
+  position: fixed;
+  display: flex;
+  justify-content: center;
+  bottom: 80px;
+  // left: calc(50% - 134px);
+  left: calc(50% - 328px);
+  -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;
+}
+
+.loading{
+  position: fixed;
+  z-index: 99;
+  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%);
+}
+::ng-deep .nz-table-hide-scrollbar{
+  scrollbar-color: auto;
+}
+.row{
+  width: 100%;
+  margin-bottom: 20px;
+  display: flex;
+  align-items: center;
+  .label{
+    width: 100px;
+  }
+}

+ 24 - 0
projects/textbook/src/modules/nav-admin/components/collect-textbook/collect-textbook.component.spec.ts

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

+ 236 - 0
projects/textbook/src/modules/nav-admin/components/collect-textbook/collect-textbook.component.ts

@@ -0,0 +1,236 @@
+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 { ActivatedRoute, Router } from '@angular/router';
+import { NzMessageModule } from 'ng-zorro-antd/message';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import Parse from 'parse';
+// import { textbookServer } from '../../../../services/textbook';
+import { NzModalService } from 'ng-zorro-antd/modal';
+import { MatDialog } from '@angular/material/dialog';
+import { NzEmptyModule } from 'ng-zorro-antd/empty';
+import { DatePipe } from '@angular/common';
+import { NzPopoverModule } from 'ng-zorro-antd/popover';
+import { setHours } from 'date-fns';
+import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
+@Component({
+  selector: 'app-collect-textbook',
+  templateUrl: './collect-textbook.component.html',
+  styleUrls: ['./collect-textbook.component.scss'],
+  imports: [
+    CommonModule,
+    NzSpaceModule,
+    CommonCompModule,
+    NzMessageModule,
+    NzEmptyModule,
+    NzPopoverModule,
+    NzDatePickerModule
+  ],
+  providers: [DatePipe],
+  standalone: true,
+})
+export class CollectTextbookComponent implements OnInit {
+  textbookList: Array<Parse.Object> = [];
+  count: number = 0;
+  timeDefaultValue = setHours(new Date(), 0);
+
+  @Input('limit') limit: number = 10;
+  pageIndex: number = 1;
+  loading: boolean = false;
+  @Input('maxWidth') maxWidth: any; //最大宽度
+  @Input('eduProcess') eduProcess?: Parse.Object; //流程id
+
+  // @Input('filterObj') filterObj: any = {
+  //   contained: [],
+  // };
+
+  showModal: boolean = false;
+  textBookList: Array<Parse.Object> = []; //流程教材列表(推荐)
+  collectStartData: any;
+  collectEndData: any;
+
+  searchValue: string = '';
+  time: any;
+  showLoading: boolean = false; //全局
+  /* 格式化拓展表字段 */
+  fromatFiled(list: Array<Parse.Object>, filed: string): string {
+    let arr: Array<string | null> = [];
+    let isDate = false;
+    list.forEach((item: Parse.Object) => {
+      if (
+        isDate ||
+        Object.prototype.toString.call(item.get(filed)).indexOf('Date') != -1
+      ) {
+        arr.push(this.datePipe.transform(item.get(filed), 'yyyy-MM'));
+        isDate = true;
+      } else {
+        arr.push(item.get(filed));
+      }
+    });
+    let j = Array.from(arr).join(',');
+    if (!isDate) {
+      j = Array.from(new Set(arr)).join(' ');
+    }
+    return j || '-';
+  }
+  manageProfiles:any = {}
+
+  formatMapProfile(list:Array<Parse.Object>):Array<string>{
+    let arr:Array<string> = []
+    list.forEach(item=>{
+      arr.push(this.manageProfiles[item?.get('editionUnit')]) 
+    })
+    return [...new Set(arr)]
+  }
+
+  constructor(
+    // private activeRoute: ActivatedRoute,
+    // public tbookSer: textbookServer,
+    private msg: NzMessageService,
+    public dialog: MatDialog,
+    private route: Router,
+    private datePipe: DatePipe,
+    private modal: NzModalService
+  ) {}
+
+  ngOnInit() {
+    this.getTextbook();
+  }
+  async getTextbook(val?: string, review?: boolean): Promise<any[] | void> {
+    if (this.loading) return;
+    this.loading = true;
+    try {
+      let queryParams: any = {
+        where: {
+          $or: [
+            {
+              title: { $regex: `.*${val || ''}.*` },
+              code: { $regex: `.*${val || ''}.*` },
+            },
+            {
+              childrens: {
+                $inQuery: {
+                  where: {
+                    $or: [
+                      {
+                        ISBN: { $regex: `.*${val || ''}.*` },
+                      },
+                      // {
+                      //   author: { $regex: `.*${val || ''}.*` },
+                      // },
+                    ],
+                  },
+                  className: 'EduTextbookVolume',
+                },
+              },
+            },
+          ],
+        },
+      };
+      let query = Parse.Query.fromJSON('EduTextbook', queryParams);
+      query.equalTo('eduProcess', this.eduProcess?.id);
+      query.descending('updatedAt');
+      query.notEqualTo('isDeleted', true);
+      query.equalTo('status', '400');
+      query.equalTo('recommend', true);
+      query.notEqualTo('discard', true);
+      // query.exists('score');
+      // query.equalTo('verify', true);
+      query.include('childrens');
+      this.count = await query.count();
+      query.limit(this.limit);
+      query.skip(this.limit * (this.pageIndex - 1));
+      // if (exported) {
+      //   query.limit(1000);
+      //   let r = await query.find();
+      //   this.loading = false;
+      //   return r;
+      // }
+      this.textbookList = await query.find();
+      //获取对应出版单位管理员
+      if(!review && this.textbookList.length > 0){
+        let contains:Array<string> = []
+        this.textbookList.forEach((childs:any)=>{
+          childs.get('childrens').forEach((item:Parse.Object)=> contains.push(item.get('editionUnit')))
+        })
+        let queryProcess = new Parse.Query('EduProcess')
+        queryProcess.notEqualTo('isDeleted',true)
+        queryProcess.containedIn('name',[...new Set(contains)])
+        queryProcess.include('profileSubmitted.user')
+        queryProcess.select('profileSubmitted.user.name','name')
+        let processList = await queryProcess.find()
+        console.log(processList);
+        processList.forEach(i=>{
+          this.manageProfiles[i?.get('name')] = i?.get('profileSubmitted')?.get('user')?.get('name')
+        })
+      }
+      console.log(this.textbookList);
+      this.loading = false;
+    } catch (err) {
+      console.warn(err);
+      this.msg.error('获取超时');
+    }
+    this.loading = false;
+  }
+  onSearch(e: string) {
+    this.pageIndex = 1;
+    console.log(e);
+    if (this.time) clearTimeout(this.time);
+    this.time = setTimeout(() => {
+      this.getTextbook(e);
+    }, 500);
+  }
+  //分页切换
+  pageIndexChange(e: any) {
+    console.log(e);
+    this.pageIndex = e;
+    this.getTextbook(this.searchValue);
+  }
+  //切换分页条数
+  onPageSizeChange($event: any): void {
+    console.log(this.limit);
+    // this.onAllChecked(false)
+    this.pageIndex = 1;
+    this.getTextbook();
+  }
+
+  toUrl(url: string, param?: Object) {
+    console.log(url);
+    if (param) {
+      this.route.navigate([url, param]);
+      return;
+    }
+    this.route.navigate([url]);
+  }
+
+  //打开编辑收集文件弹窗
+  async openEditCollect() {
+    this.collectStartData = this.eduProcess?.get('collectStartData');
+    this.collectEndData = this.eduProcess?.get('collectEndData');
+    this.pageIndex = 1;
+    this.searchValue = ''
+    this.getTextbook();
+
+    this.showModal = true;
+  }
+  handleCancel(): void {
+    this.showModal = false
+  }
+  //保存收集文件设置
+  async editCollect() {
+    if (
+      !this.collectStartData ||
+      !this.collectEndData ||
+      this.collectStartData > this.collectEndData
+    ) {
+      this.msg.warning('请设置正确的开始和截止时间');
+      return;
+    }
+    this.eduProcess?.set('collectStartData', this.collectStartData);
+    this.eduProcess?.set('collectEndData', this.collectEndData);
+    await this.eduProcess?.save();
+    this.msg.success('设置成功');
+    this.showModal = false;
+  }
+}

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

@@ -1,15 +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-item
+      ><a>{{
+        eduProcess?.get("department")?.get("name") || "未选择申报单位"
+      }}</a></nz-breadcrumb-item
+    >
   </nz-breadcrumb>
   <nz-page-header-title
-    >{{eduProcess?.get('department')?.get('name') || '未选择申报单位'}}
+    >{{ eduProcess?.get("department")?.get("name") || "未选择申报单位" }}
     <br />
     <div class="subtitle">
       在流程中邀请作者、高校联系人、评审员登录系统,创建并提交教材,由工作联系人评审、提交推荐教材完成流程工作
     </div>
   </nz-page-header-title>
+  @if (active == 2) {
+  <nz-page-header-extra>
+    <nz-space>
+      <button
+        style="background: #3e49b3; border: 1px #3e49b3"
+        *nzSpaceItem
+        nz-button
+        nzType="primary"
+        (click)="collect.openEditCollect()"
+      >
+        收集教材源文件
+      </button>
+    </nz-space>
+  </nz-page-header-extra>
+  }
 </nz-page-header>
 <div class="edit-content">
   <nz-tabset [(nzSelectedIndex)]="active">
@@ -20,15 +39,19 @@
     </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> -->
-      <app-textbook [filterObj]="filterObj" [eduProcess]="eduProcess"></app-textbook>
+      <app-textbook
+        [filterObj]="filterObj"
+        [eduProcess]="eduProcess"
+      ></app-textbook>
+      }
+    </nz-tab>
+
+    <nz-tab nzTitle="教材文件">
+      @if (active == 2) {
+      <app-collect-textbook
+        #collect
+        [eduProcess]="eduProcess"
+      ></app-collect-textbook>
       }
     </nz-tab>
   </nz-tabset>

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

@@ -1,15 +1,14 @@
-import { Component, Input, OnInit } from '@angular/core';
+import { Component, Input, OnInit, ViewChild } 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';
 import { TextbookComponent } from '../../../app/textbook/textbook.component';
-
+import { CollectTextbookComponent } from '../components/collect-textbook/collect-textbook.component';
 @Component({
   selector: 'app-page-process',
   templateUrl: './page-process.component.html',
@@ -22,18 +21,17 @@ import { TextbookComponent } from '../../../app/textbook/textbook.component';
     ProcessCreateComponent,
     CompTableListComponent,
     TextbookComponent,
+    CollectTextbookComponent
   ],
   standalone: true,
 })
 export class PageProcessComponent  implements OnInit {
+  @ViewChild('collect') collect: CollectTextbookComponent | any;
+
   active: number = 0;
   eduProcess: Parse.Object | undefined;
 
-  EduTextbook = EduTextbook;
   user: Parse.User | undefined;
-  className: string | undefined;
-  queryParams: any | undefined;
-  fieldsArray: Array<any> | undefined;
   filterObj: any = {
     showMore: true, //显示更多字段
     isCheck: false,
@@ -45,21 +43,11 @@ export class PageProcessComponent  implements OnInit {
     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');
-      this.queryParams.where['department'] = id
       if (id) {
         let query = new Parse.Query('EduProcess');
         query.include('branch', 'department');
@@ -68,8 +56,4 @@ export class PageProcessComponent  implements OnInit {
       }
     })
   }
-
-  onCreateProcess(){
-    this.router.navigate(['/nav-admin/manage/process/create',{cid:this.eduProcess?.id}])
-  }
 }

+ 5 - 6
projects/textbook/src/modules/nav-admin/page-process/process-list/process-list.component.html

@@ -1,5 +1,4 @@
 <nz-page-header>
-  <!--title-->
   <nz-page-header-title
     >申报流程
     <br />
@@ -7,8 +6,6 @@
       统一管理各类教材推荐流程和限额,设置各个流程开始和结束时间、查看各流程工作进度
     </div>
   </nz-page-header-title>
-
-  <!--extra-->
   <nz-page-header-extra>
     <nz-space>
       <button
@@ -418,10 +415,12 @@
             ></nz-date-picker>
           </div>
         </div>
-        <div class="row">
+        <div class="row" style="align-items: start;">
           <div class="label">收集教材</div>
           <div class="value">
-            12
+            @for (item of textBookList; track $index) {
+              <span>{{item?.get('title')}}; </span>
+            }
           </div>
         </div>
       </div>
@@ -435,7 +434,7 @@
       [disabled]="!this.collectStartData || !this.collectEndData"
       (click)="editCollect()"
     >
-      确定
+      收集
     </button>
   </div>
 </nz-modal>

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

@@ -544,10 +544,19 @@ export class ProcessListComponent implements OnInit {
   }
 
   //打开编辑收集文件弹窗
-  openEditCollect(data:Parse.Object){
+  async openEditCollect(data:Parse.Object){
     this.eduProcess = data
     this.collectStartData = this.eduProcess?.get('collectStartData')
     this.collectEndData = this.eduProcess?.get('collectEndData')
+    let query = new Parse.Query('EduTextbook')
+    query.equalTo('eduProcess',this.eduProcess?.id)
+    query.notEqualTo('isDeleted',true)
+    query.equalTo('status','400')
+    query.equalTo('recommend', true);
+    query.notEqualTo('discard', true);
+    query.select('title')
+    let r = await query.find()
+    this.textBookList = r
     this.showModal = true
   }
   //保存收集文件设置

+ 133 - 0
projects/textbook/src/modules/nav-province-contact/collect-file/collect-file.component.html

@@ -0,0 +1,133 @@
+<nz-page-header>
+  <nz-page-header-title
+    >本社教材源文件
+    <br />
+    <div class="subtitle">
+      将本社出版社的教材源文件PDF或数字资源链接提交至申报系统,以供评审使用
+    </div>
+  </nz-page-header-title>
+</nz-page-header>
+<div class="textbook-table">
+  <div class="tool">
+    <div class="search">
+      <nz-input-group style="width: 280px" [nzPrefix]="prefixTemplateUser">
+        <input
+          type="text"
+          nz-input
+          placeholder="输入教材名称 / ISBN / 申报编号"
+          [(ngModel)]="searchValue"
+          (ngModelChange)="onSearch($event)"
+        />
+      </nz-input-group>
+      <ng-template #prefixTemplateUser
+        ><span nz-icon nzType="search"></span
+      ></ng-template>
+    </div>
+  </div>
+  <nz-table
+    #tableData
+    [nzData]="textbookList"
+    [nzTotal]="count"
+    [(nzPageSize)]="limit"
+    [nzPageIndex]="pageIndex"
+    style="margin: 10px 0"
+    [nzLoading]="loading"
+    nzSize="middle"
+    [nzFrontPagination]="false"
+    [nzScroll]="{ x: (maxWidth || '800') + 'px', y: '580px' }"
+    nzTableLayout="fixed"
+    [nzPageSizeOptions]="[10, 20, 30, 40, 50]"
+    nzShowSizeChanger
+    (nzPageIndexChange)="pageIndexChange($event)"
+    (nzPageSizeChange)="onPageSizeChange($event)"
+  >
+    <thead>
+      <tr>
+        <th nzEllipsis nzWidth="120px" nzLeft>教材名称</th>
+        <th nzEllipsis nzWidth="120px">申报编号</th>
+        <th nzEllipsis nzWidth="120px">ISBN</th>
+        <th nzEllipsis nzWidth="120px">出版单位</th>
+        <th nzEllipsis nzWidth="120px">出版单位联系人</th>
+        <th nzEllipsis nzWidth="80px" nzAlign="center">文件状态</th>
+        <th nzEllipsis nzWidth="80px" nzAlign="center" nzRight>操作</th>
+      </tr>
+    </thead>
+    @if (textbookList.length > 0) {
+    <tbody>
+      @for (data of textbookList; track data.id) {
+      <tr>
+        <td
+          nzEllipsis
+          class="activeTd"
+          (click)="
+            toUrl('/common/textbook/details/' + data?.get('eduTextbook')?.id)
+          "
+          nz-popover
+          [nzPopoverContent]="contentTemplatetitle"
+        >
+          {{ data?.get("title") || "-" }}
+          <ng-template #contentTemplatetitle>
+            <div style="max-width: 400px">
+              {{ data?.get("title") || "-" }}
+            </div>
+          </ng-template>
+        </td>
+        <td nzEllipsis>
+          {{ data?.get("code") ?? "-" }}
+        </td>
+        <td
+          nzEllipsis
+          nz-popover
+          [nzPopoverContent]="contentTemplateISBN"
+          #ISBN
+        >
+          {{ fromatFiled(data?.get("childrens"), "ISBN") }}
+          <ng-template #contentTemplateISBN>
+            <div style="max-width: 400px">
+              {{ ISBN.innerText }}
+            </div>
+          </ng-template>
+        </td>
+        <td
+          nzEllipsis
+          nz-popover
+          [nzPopoverContent]="contentTemplateeditionUnit"
+          #editionUnit
+        >
+          {{ fromatFiled(data?.get("childrens"), "editionUnit") }}
+          <ng-template #contentTemplateeditionUnit>
+            <div style="max-width: 400px">
+              {{ editionUnit.innerText }}
+            </div>
+          </ng-template>
+        </td>
+
+        <td
+          nzEllipsis
+          nz-popover
+          [nzPopoverContent]="contentTemplateChild"
+          #childrens
+        >
+          <ng-template #contentTemplateChild>
+            <div style="max-width: 400px">
+              {{ childrens.innerText }}
+            </div>
+          </ng-template>
+        </td>
+        <td nzEllipsis nzAlign="center">未上传</td>
+        <td nzEllipsis nzRight nzAlign="center">
+          <a nz-button nzType="link">查看</a>
+        </td>
+      </tr>
+      }
+    </tbody>
+    }
+  </nz-table>
+  @if (textbookList.length == 0) {
+  <nz-empty nzNotFoundImage="/img/group-empty.png"></nz-empty>
+  }
+
+  <div class="loading" [hidden]="!showLoading">
+    <nz-spin nzSimple [nzSize]="'large'"></nz-spin>
+  </div>
+</div>

+ 63 - 0
projects/textbook/src/modules/nav-province-contact/collect-file/collect-file.component.scss

@@ -0,0 +1,63 @@
+.subtitle {
+  margin-right: 12px;
+  color: #00000073;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 1.5715;
+  // overflow: hidden;
+  // white-space: nowrap;
+  // text-overflow: ellipsis;
+}
+.textbook-table {
+  margin: 0 0 20px;
+  padding: 0 24px;
+  height: calc(100vh - 192px);
+  min-width: 800px;
+  .activeTd {
+    cursor: pointer;
+  }
+  .tool {
+    display: flex;
+    justify-content: space-between;
+    .sbt {
+      padding: 6px 10px;
+      background: #e8f5fc;
+      font-family: PingFang SC;
+      font-size: 14px;
+      font-weight: 400;
+      /* line-height: 20px; */
+      text-align: center;
+      color: #0054c3;
+      border-radius: 4px;
+      cursor: pointer;
+    }
+  }
+  .activeTd {
+    color: #c6233f;
+  }
+}
+.loading {
+  position: fixed;
+  z-index: 99;
+  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%);
+}
+::ng-deep .nz-table-hide-scrollbar {
+  scrollbar-color: auto;
+}
+.row {
+  width: 100%;
+  margin-bottom: 20px;
+  display: flex;
+  align-items: center;
+  .label {
+    width: 100px;
+  }
+}

+ 24 - 0
projects/textbook/src/modules/nav-province-contact/collect-file/collect-file.component.spec.ts

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

+ 185 - 0
projects/textbook/src/modules/nav-province-contact/collect-file/collect-file.component.ts

@@ -0,0 +1,185 @@
+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 { ActivatedRoute, Router } from '@angular/router';
+import { NzMessageModule } from 'ng-zorro-antd/message';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import Parse from 'parse';
+// import { textbookServer } from '../../../../services/textbook';
+import { NzModalService } from 'ng-zorro-antd/modal';
+import { MatDialog } from '@angular/material/dialog';
+import { NzEmptyModule } from 'ng-zorro-antd/empty';
+import { DatePipe } from '@angular/common';
+import { NzPopoverModule } from 'ng-zorro-antd/popover';
+import { setHours } from 'date-fns';
+import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
+@Component({
+  selector: 'app-collect-file',
+  templateUrl: './collect-file.component.html',
+  styleUrls: ['./collect-file.component.scss'],
+  imports: [
+    CommonModule,
+    NzSpaceModule,
+    CommonCompModule,
+    NzMessageModule,
+    NzEmptyModule,
+    NzPopoverModule,
+    NzDatePickerModule,
+  ],
+  providers: [DatePipe],
+  standalone: true,
+})
+export class CollectFileComponent implements OnInit {
+  textbookList: Array<Parse.Object> = [];
+  count: number = 0;
+  timeDefaultValue = setHours(new Date(), 0);
+
+  @Input('limit') limit: number = 10;
+  pageIndex: number = 1;
+  loading: boolean = false;
+  @Input('maxWidth') maxWidth: any; //最大宽度
+  @Input('eduProcess') eduProcess?: Parse.Object; //流程id
+  showModal: boolean = false;
+
+  searchValue: string = '';
+  time: any;
+  showLoading: boolean = false; //全局
+  /* 格式化拓展表字段 */
+  fromatFiled(list: Array<Parse.Object>, filed: string): string {
+    let arr: Array<string | null> = [];
+    let isDate = false;
+    list.forEach((item: Parse.Object) => {
+      if (
+        isDate ||
+        Object.prototype.toString.call(item.get(filed)).indexOf('Date') != -1
+      ) {
+        arr.push(this.datePipe.transform(item.get(filed), 'yyyy-MM'));
+        isDate = true;
+      } else {
+        arr.push(item.get(filed));
+      }
+    });
+    let j = Array.from(arr).join(',');
+    if (!isDate) {
+      j = Array.from(new Set(arr)).join(' ');
+    }
+    return j || '-';
+  }
+  constructor(
+    private msg: NzMessageService,
+    public dialog: MatDialog,
+    private route: Router,
+    private datePipe: DatePipe,
+    private modal: NzModalService
+  ) {}
+
+  ngOnInit() {}
+
+  async getTextbook(val?: string, review?: boolean): Promise<any[] | void> {
+    if (this.loading) return;
+    this.loading = true;
+    try {
+      let queryParams: any = {
+        where: {
+          $or: [
+            {
+              title: { $regex: `.*${val || ''}.*` },
+              code: { $regex: `.*${val || ''}.*` },
+            },
+            {
+              childrens: {
+                $inQuery: {
+                  where: {
+                    $or: [
+                      {
+                        ISBN: { $regex: `.*${val || ''}.*` },
+                      },
+                      // {
+                      //   author: { $regex: `.*${val || ''}.*` },
+                      // },
+                    ],
+                  },
+                  className: 'EduTextbookVolume',
+                },
+              },
+            },
+          ],
+        },
+      };
+      let query = Parse.Query.fromJSON('EduTextbook', queryParams);
+      query.equalTo('eduProcess', this.eduProcess?.id);
+      query.descending('updatedAt');
+      query.notEqualTo('isDeleted', true);
+      query.equalTo('status', '400');
+      query.equalTo('recommend', true);
+      query.notEqualTo('discard', true);
+      // query.exists('score');
+      // query.equalTo('verify', true);
+      query.include('childrens');
+      this.count = await query.count();
+      query.limit(this.limit);
+      query.skip(this.limit * (this.pageIndex - 1));
+      // if (exported) {
+      //   query.limit(1000);
+      //   let r = await query.find();
+      //   this.loading = false;
+      //   return r;
+      // }
+      this.textbookList = await query.find();
+      //获取对应出版单位管理员
+      // if(!review && this.textbookList.length > 0){
+      //   let contains:Array<string> = []
+      //   this.textbookList.forEach((childs:any)=>{
+      //     childs.get('childrens').forEach((item:Parse.Object)=> contains.push(item.get('editionUnit')))
+      //   })
+      //   let queryProcess = new Parse.Query('EduProcess')
+      //   queryProcess.notEqualTo('isDeleted',true)
+      //   queryProcess.containedIn('name',[...new Set(contains)])
+      //   queryProcess.include('profileSubmitted.user')
+      //   queryProcess.select('profileSubmitted.user.name','name')
+      //   let processList = await queryProcess.find()
+      //   console.log(processList);
+      //   processList.forEach(i=>{
+      //     this.manageProfiles[i?.get('name')] = i?.get('profileSubmitted')?.get('user')?.get('name')
+      //   })
+      // }
+      console.log(this.textbookList);
+      this.loading = false;
+    } catch (err) {
+      console.warn(err);
+      this.msg.error('获取超时');
+    }
+    this.loading = false;
+  }
+  onSearch(e: string) {
+    this.pageIndex = 1;
+    console.log(e);
+    if (this.time) clearTimeout(this.time);
+    this.time = setTimeout(() => {
+      this.getTextbook(e);
+    }, 500);
+  }
+  //分页切换
+  pageIndexChange(e: any) {
+    console.log(e);
+    this.pageIndex = e;
+    this.getTextbook(this.searchValue);
+  }
+  //切换分页条数
+  onPageSizeChange($event: any): void {
+    console.log(this.limit);
+    // this.onAllChecked(false)
+    this.pageIndex = 1;
+    this.getTextbook();
+  }
+
+  toUrl(url: string, param?: Object) {
+    console.log(url);
+    if (param) {
+      this.route.navigate([url, param]);
+      return;
+    }
+    this.route.navigate([url]);
+  }
+}

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

@@ -10,6 +10,7 @@ import { SubmittedComponent } from "./submitted/submitted.component";
 import { AuthGuard } from "./auth.guard";
 import { ActivityComponent } from "./activity/activity.component";
 import { ReviewEditComponent } from "./activity/review-edit/review-edit.component";
+import { CollectFileComponent } from "./collect-file/collect-file.component";
 
 const routes: Routes = [
   {
@@ -57,6 +58,11 @@ const routes: Routes = [
         path: 'review-edit/:id', //评审活动
         component: ReviewEditComponent,
       },
+      
+      {
+        path: 'collect', //本社教材源文件
+        component: CollectFileComponent,
+      },
     ]
   }
 ];