warrior 9b017f9a0c 教材技术文档 4 tygodni temu
..
Devops.md da240f6101 fix: devops db bak 3 miesięcy temu
README.md 9b017f9a0c 教材技术文档 4 tygodni temu
Schema.md 49f77cba89 feat: schema.md 5 miesięcy temu

README.md

145教材系统技术文档

一、技术语言和框架

数据库和数据表

  • 数据库:PostgreSQL
  • 数据表

    • _User【用户】

      "fields": {
      "avatar": {
          "type": "String"
      },
      "name": {
          "type": "String"
      },
      "mobile": {
          "type": "String"
      },
      // Authing 提供信息
      "phone": {
          "type": "String"
      },
      "lastIP":{
          "type":"String"
      },
      "lastLogin": {
          "type": "Date"
      },
      "userSourceType":{
          "type": "String"
      },
      "loginsCount":{
          "type": "Number"
      }
      }
      
    • Profile 【用户角色】

      "fields": {
      "user": {
      "type": "Pointer",
      "targetClass": "_User",
      "required": false
      },
      "phone": {
      "type": "String"
      },
      "email": {
      "type": "String"
      },
      "telephone": {
      "type": "String"
      },
      "province": {
      "type": "String"
      },
      "companyType": {
      "type": "String"
      },
      "postName": {
      "type": "String"
      },
      "idcard": {
      "type": "String"
      },
      "identity": {
      "type": "String"
      },
      "identityFile": {
      "type": "String"
      },
      "majorSubject": {
      "type": "String"
      }
      },
      
    • Department 【单位部门】

      "fields": {
      "parent": {//上级
      "type": "Pointer",
      "targetClass": "Department",
      "required": false
      },
      "name": {//单位、组织名称
      "type": "String",
      "required": false
      },
      "code": {//标识码
      "type": "String",
      "required": false
      },
      "branch": {//主管部门
      "type": "String",
      "required": false
      },
      "address": {//所在地
      "type": "String",
      "required": false
      },
      "type": { // 单位类型
      "type": "String",
      "required": false
      },
      "hasChildren": {//办学层次
      "type": "Boolean",
      "required": false
      },
      },
      
    • EduTextbook 【教材】

      "fields": {
      "status": {
        /*状态 
        101:待完善资料  
        102:可提交状态 
        103:已提交至高校管理员
        200:已提交遴选中 
        201:公示中 
        300:退回
        400:已报送
        */
        "type": "String",
        "required": false
      },
      "childrens":{//指向所有分册
        "type": "String",
        "required": false
      },
      "user": {
        "type": "Pointer",
        "targetClass":"_User",
        "required": false
      },
      "department": { //所属流程
        "type": "Pointer",
        "targetClass":"Department",
        "required": false
      },
      "render": { //是否提交
        "type": "Boolean",
        "required": false
      },
      "recommend": { //是否推荐
        "type": "Boolean",
        "required": false
      },
      "complete": { //是否填写完整
        "type": "Boolean",
        "required": false
      },
      "isDeleted": {
        "type": "Boolean",
        "required": false
      },
      "discard": { //删除至回收站
        "type": "Boolean",
        "required": false
      },
      "title": {
        "type": "String",
        "required": false
      },
      "ISBN": {
        "type": "String",
        "required": false
      },
      "author": {
        "type": "String",
        "required": false
      },
      "unit": {
        "type": "String",
        "required": false
      },
      "type": {
        "type": "String",
        "required": false
      },
      "typeNumber": {//全册次数
        "type": "Number",
        "required": false
      },
      "majorPoniter": {
        "type": "String",
        "required": false
      },
      "lang": {
        "type": "String",
        "required": false
      },
      "authors": {
        "type": "String",
        "required": false
      },
      "editor": {
        "type": "String",
        "required": false
      },
      "approval": {//是否为重点立项教材
        "type": "String",
        "required": false
      },
      "edition": {
        "type": "String",
        "required": false
      },
      "editionFirst": {
        "type": "Date",
        "required": false
      },
      "carrierShape": {
        "type": "String",
        "required": false
      },
      "editionDate": {
        "type": "Date",
        "required": false
      },
      "editionNumber": {//出版版次
        "type": "Number",
        "required": false
      },
      "printDate": {
        "type": "Date",
        "required": false
      },
      "printNumber": {
        "type": "Number",
        "required": false
      },
      "printSum": {
        "type": "Number",
        "required": false
      },
      "importantProject": {//重点项目
        "type": "Array",
        "required": false
      },
      "importantProjectOther": {//重点项目-其他
        "type": "String",
        "required": false
      },
      "copyright": {
        "type": "Array",
        "required": false
      },
      "CIP": {
        "type": "Array",
        "required": false
      },
      'majors':{//适用专业代码(六位)及名称
        "type":'Number',
        "required": false  
      },
      "period": {
        "type": "Number",
        "required": false
      },
      "lessons": {
        "type": "Array",
        "required": false
      },
      "characteristic": {
        "type": "Array",
        "required": false
      },
      "authorList": {
        "type": "Array",
        "required": false
      },
      "authorDetails": {
        "type": "String",
        "required": false
      },
      "achievementOptions": {
        "type": "Array",
        "required": false
      },
      "courses": {
        "type": "Array",
        "required": false
      },
      "innovateExplain": {
        "type": "String",
        "required": false
      },
      "influence": {
        "type": "String",
        "required": false
      },
      "textbookFiles": {
        "type": "Array",
        "required": false
      },
      "links": {
        "type": "Array",
        "required": false
      },
      "opinions": {
        "type": "Array",
        "required": false
      },
      "selfResults": {
        "type": "Object",
        "required": false
      },
      "expertOpinion": {
        "type": "Object",
        "required": false
      },
      "evidence": {
        "type": "Object",
        "required": false
      },
      "moreMaterial": {
        "type": "Array",
        "required": false
      },
      "authorSign": {
        "type": "Array",
        "required": false
      },
      "unitMaterial": {
        "type": "Object",
        "required": false
      },
      "accept": {//填写承诺书
        "type": "String",
        "required": false
      },
      "approvedImgUrl":{//重点立项教材获批截图            
        "type":'String',
        "required": false
      },
      "eduProcess": {//所属流程
        "type": "Pointer",
        "targetClass":"EduProcess",
        "required": false
      },
      "code":{//编号
        "type":'String',
        "required": false
      },
      'editionUnit':{
        "type":'String',
        "required": false
      },
      'copyrightImgUrl':{
        "type":'String',
        "required": false  
      },
      'CIPImgurl':{
        "type":'String',
        "required": false  
      },
      'examine':{//作者政治审核表
        "type":'Array',
        "required": false  
      },
      'cipProveFile':{//cip相关截图
        "type":'Array',
        "required": false  
      },
      'inviteUnit':{//推荐单位
        "type":'Array',
        "required": false  
      },
      'unitType':{//推荐单位类型
        "type":'Array',
        "required": false  
      },
      'score':{//平均分
        "type":'Number',
        "required": false  
      },
      },
      
    • EduTextbookVolume 【分册】

      "fields": {
      "user": {
        "type": "Pointer",
        "targetClass":"_User",
        "required": false
      },
      "isDeleted": {
        "type": "Boolean",
        "required": false
      },
      "title": {
        "type": "String",
        "required": false
      },
      "ISBN": {
        "type": "String",
        "required": false
      },
      "author": {
        "type": "String",
        "required": false
      },
      "unit": {
        "type": "String",
        "required": false
      },
      "lang": {
        "type": "String",
        "required": false
      },
      "authors": {
        "type": "String",
        "required": false
      },
      "editor": {
        "type": "String",
        "required": false
      },
      "editionFirst": {
        "type": "Date",
        "required": false
      },
      "carrierShape": {
        "type": "String",
        "required": false
      },
      "editionDate": {
        "type": "Date",
        "required": false
      },
      "editionNumber": {//出版版次
        "type": "Number",
        "required": false
      },
      "printDate": {
        "type": "Date",
        "required": false
      },
      "printNumber": {
        "type": "Number",
        "required": false
      },
      "printSum": {
        "type": "Number",
        "required": false
      },
      "importantProject": {//重点项目
        "type": "Array",
        "required": false
      },
      "importantProjectOther": {//重点项目-其他
        "type": "String",
        "required": false
      },
      "authorList": {
        "type": "Array",
        "required": false
      },
      "authorDetails": {
        "type": "String",
        "required": false
      },
      "achievementOptions": {
        "type": "Array",
        "required": false
      },
      "courses": {
        "type": "Array",
        "required": false
      },
      'editionUnit':{
        "type":'String',
        "required": false
      },
      'unitType':{//推荐单位类型
        "type":'Array',
        "required": false  
      },
      "collectFIles": {//纸质教材文件
        "type": "Object",
        "required": false
      },
      "collectDigitFiles":{//纸质数字文件
        "type": "Object",
        "required": false
      },
      "collectCheck":{//教材文件上传类型
        "type": "Object",
        "required": false
      },
      "collectStatus":{//教材文件上传状态
        "type": "Object",
        "required": false
      },
      },
      
    • Activity 【评审活动】

      "fields": {
      "name":{//活动名称
      "type": "String",
      "required": false
      },
      "eduProcess": { //评审教材
      "type": "Pointer",
      "targetClass": "EduProcess",
      "required": false
      },
      "startDate": {//开始时间
      "type": "Date",
      "required": false
      },
      "deadline": {//截止时间
      "type": "Date",
      "required": false
      },
      "status":{//是否开始
      "type": "Number",
      "required": false
      },
      "desc":{//详情说明
      "type": "String",
      "required": false
      },
      },
      
    • Company 【公司】

      "fields": {
      "title": {
        "type": "String"
      },
      },
      
    • EduProcess 【流程】

      "fields": {
      "eduCollection": { //指向报送合集
        "type": "Pointer",
        "targetClass": "EduCollection",
        "required": false
      },
      "branch": { //类别
        "type": "Pointer",
        "targetClass": "Department",
        "required": false
      },
      "department": { //部门/单位
        "type": "Pointer",
        "targetClass": "Department",
        "required": false
      },
      "profileSubmitted": {//流程管理员
        "type": "Pointer",
        "targetClass":"Profile",
        "required": false
      },
      "name": {//流程名称
        "type": "String",
        "required": false
      },
      "num": {//报送名额
        "type": "Number",
        "required": false
      },
      "code": {//流程唯一标识
        "type": "String",
        "required": false
      },
      "startDate": {//开始时间
        "type": "Date",
        "required": false
      },
      "deadline": {//截止时间
        "type": "Date",
        "required": false
      },
      /**@状态
       * 100:暂停
      * 200:已开始
      * 201:评审中
      * 300:已公示
      * 400:已提交(完成)
      */
      "status": {
        "type": "String",
        "required": false
      },
      "releaseDate": {//公示时间
        "type": "Date",
        "required": false
      },
      
      "collectStartData": {//收集文件开始时间
        "type": "Date",
        "required": false
      },
      "collectEndData": {//收集文件结束时间
        "type": "Date",
        "required": false
      },
      },
      
    • EduReview 【评审记录】

      "fields": {
      "eduTextbook": { //评审教材
      "type": "Pointer",
      "targetClass": "EduTextbook",
      "required": false
      },
      "user": {
      "type": "Pointer",
      "targetClass": "_User",
      "required": false
      },
      "profile": { //评审用户
      "type": "Pointer",
      "targetClass": "Profile",
      "required": false
      },
      "score": {//最终分数
      "type": "Number"
      },
      "num":{//预估分
      "type": "Number"
      },
      "verify":{//是否完成
      "type": "Boolean"
      }
      },
      
    • ExpertGroup 【评审组】

      "fields": {
      "name":{//活动名称
      "type": "String",
      "required": false
      },
      "eduProcess": { //评审流程
      "type": "Pointer",
      "targetClass": "EduProcess",
      "required": false
      },
      "textbookList": {//评审教材列表
      "type": "Array",
      "required": false
      },
      "reviewList": {//评审教师列表
      "type": "Array",
      "required": false
      },
      "checkTextbook": {//选择教材类型
      "type": "String",
      "required": false
      },
      "checkReview": {//选择评审专家类型
      "type": "String",
      "required": false
      },
      },
      

后端语言及框架

  • 编写语言:JavaScript
  • 技术框架:Node.jsParse Server

    前端语言及框架

  • 编写语言:TypeScript、HTML、SCSS

  • 技术框架:Angular18、Vite、NG-ZORRO

二、客户端前端

用户操作逻辑介绍

graph TB

Start(开始) --> User[用户登录页]
User --> Register[注册]
User --> Login[用户登录]
Register --> Regcomplete[注册成功]
Regcomplete --> User
Login --> Manage[登录成功进入后台]
Manage --> LogOut[退出登录]
LogOut --> End(结束)

身份权限

  • 登录成功时存储本地缓存profile;
  • 通过profile.identity身份判断角色验证
  • 全局采用路由守卫 auth.guard.ts

    页面路由

  • 入口路由文件:projects\textbook\src\app\app.routes.ts

  • 各个身份子路由

    • user/login //默认路由
    • nav-admin //国家级管理员管理平台
    • nav-province-contact //工作联系人:中央部门所属高校联系人、部省合建高校联系人、出版单位联系人、省属高校流程管理员
    • nav-province-school-contact //高校联系人
    • nav-review //教材评审组成员
    • nav-author //作者 / 教师 / 主编

      主组件

  • app-comp-manage【全局组件】:登录成功后跳转后页面显示;包括左侧menu,通过optionsMap身份对应显示身份功能栏

    • 附件下载功能函数:openFile、downloadFile
  • app-comp-nav 【个人信息组件】:页面左下角个人信息,包括退出登录功能

  • app-comp-upload 【文件上传组件】

    • provider-oss-aliyun 引入阿里OSS处理函数等,含公开转私有、私有转公开、临时链接等
    • 重点传入参数
    • @files:回显文件
    • @acl 上传类型,是否加密
    • @type 可上传文件类型

      //映射关系处理
      get accept() {
      let type;
      switch (this.type) {
      case 'image':
        type = 'image/*';
        break;
      case 'pdf':
        type = 'application/pdf';
        break;
      case 'audio':
        type = 'audio/*';
        break;
      case 'video':
        type = 'video/*';
        break;
      default:
        type = 'file';
        break;
      }
      return type;
      }
      
    • 上传成功、失败、删除文件触发回调

    • 函数change,返回fileList

  • app-textbook 【教材列表组件】

    • 重点传入参数
    • @filterObj 相关权限配置
    • @uid 对应用户
    • @eduProcess 流程id,verify存在时需要
    • @discard 是否删除
    • @recommend 是否推荐
    • 重要函数解释
    • getTextbook:获取教材列表重要函数,利用Parse.Query.fromJSON多条件查询,通过设定参数传入接口查询获取教材,满足全平台90%以上页面教材列表管理
    • getDepartment:获取所有单位部门
    • reject: 退回教材
    • del:删除教材
    • updateStatus:加入/移除推荐
    • submit:提交教材
    • beforSubmit:高校联系人提交教材至工作联系人
    • restore:恢复教材
    • exportProcess:导出教材;功能业务:导出推荐汇总表
    • submitted:提交报送跳转,非直接请求报送教材接口

      各身份模块

      用户登录
  • parse-authing.ts 【登录服务类】 应用authing登录回调,返回获取登录结果

    • initLoginModal 初始化登录模块
  • app-login 登录页

    • new ParseAuthing实例化authing登录服务,通过login成功后回调调用AuthServr服务类,profileVerify处理登录成功后函数

      let parseAuthing = new ParseAuthing({
      // 监听事件:登陆成功后,返回用户信息
      login:(user,authClient)=>{
      console.log(user)
      console.log(Parse.User.current());
      Parse.User.current()?.id && this.authServr.profileVerify(this.modal)
      },
      beforeChangeModule:(data:any)=>{
      if(data=='register'){
        this.router.navigate(['/user/account_info'])
      }
      }
      });
      parseAuthing.initLoginModal();
      
  • app-account-info 工作联系人注册

    • 功能说明
    • 访客用户可在登录页点击“账户申请”进入工作联系人账户申请,国家级管理员可查看资料根据情况是否通过,通过条件会自动校验是否存在,如果流程存在该管理员会自动替换
    • 主要函数方法
    • validateForm:基础填写字段
    • identity:注册身份
    • identityFile:单位联系人认证文件
    • 主要参数说明
    • getUnitTypes:获取可选择注册单位
    • provinceChange:根据所选单位类型获取对应单位
    • submitForm:提交注册信息
    • profileSave:提交角色信息
    • authUser:注册基础字段信息校验,判断手机号、邮箱是否合规

      作者/教师/主编
  • 路由模块:NavAuthorRoutingModule

  • 组件(教材创建)

    • app-basic 【填写基本信息】
    • 必填参数
    • 主要函数方法

      • getEduTextbookVolumeList:获取分册表
      • upload:上传附件回调
      • saveEduTextbook:保存教材信息
      • 保存接口中判断是否填写完成
      • 判断各分册填写及获取分册id代码
      • 部分主要代码

        let eduTextbookVolumes = await this.saveEduTextbookVolume(this.eduTextbookId);
        console.log(eduTextbookVolumes?.isVrifly);
        console.log(eduTextbookVolumes.list);
        this.eduTextbook?.set('childrens', eduTextbookVolumes.list);
        this.eduTextbook?.set('typeNumber', eduTextbookVolumes.list.length);
        isComplete = isComplete && eduTextbookVolumes?.isVrifly;
        //如果填写未完整,仅保存,状态修改待完善101
        if (this.eduTextbook.get('status') == '102' && !isComplete) {
        this.eduTextbook?.set('status', '101');
        this.eduTextbook.set('complete', false);
        } else if (!this.eduTextbook.get('status')) {
        this.eduTextbook?.set('status', '101');
        }
        if(isComplete){
        this.eduTextbook.set('complete', true)
        }
        - `saveEduTextbookVolume`:上传分册数据
        - 子组件调用
        - 上传获批截图  
        

        html <app-comp-upload [type]="'pdf'" (change)="upload($event, 'approvedImgUrl')" title="上传教材获批截图"

    • 分册信息

      <app-one #children
      [eduTextbookId]="eduTextbookId"
      [eduTextbookVolumeId]="panel?.id"
      ></app-one>
      - app-textbook-pertain【填写教材适用情况】
      - 必填参数
      - @eduTextbook 教材
      - 主要函数方法
      - `saveEduTextbook`:保存教材信息
      - `saveEduTextbookVolume`:上传分册数据
      - 子组件调用
      - 分册信息
      

      html <app-author #children [eduTextbook]="eduTextbook?.id" [eduTextbookVolume]="panel"

  • app-textbook-content【填写教材内容】

  • 必填参数

  • 主要函数方法

    • saveEduTextbook:保存教材信息
    • saveEduTextbookVolume:上传分册数据
  • 子组件调用

    • 分册信息

      <app-three
      #children
      [eduTextbook]="eduTextbook?.id"
      [eduTextbookVolume]="panel"
      ></app-three>
      
  • app-faith【填写教材内容】

  • 必填参数

  • 主要函数方法

    • saveEduTextbook:保存教材信息
    • saveEduTextbookVolume:上传分册数据
    • verify:校验填写字段是否匹配
  • app-attachment【上传附件材料】

  • 必填参数

  • 主要函数方法

    • saveEduTextbook:保存教材信息
    • saveEduTextbookVolume:上传分册数据
    • examineNull:检查本页必填是否存在空项
    • isIgnoreFiledNull:判断教材所有字段是否必填
    • upload:上传附件回调
  • 子组件调用

    • app-comp-upload 附件上传组件
    • 分册信息

      <app-author-file
      #children
      [eduTextbook]="eduTextbook?.id"
      [eduTextbookVolume]="panel"
      ></app-author-file>
      
  • 个人空间:app-space
  • 调用组件:app-textbook

  • 主要函数:getEduProcess 获取教师所属单位的流程

  • 创建教材:app-apply

  • 组件调用

  • app-basic

  • app-textbook-pertain

  • app-textbook-content

  • app-faith

  • app-attachment

  • 应用代码

    @switch (state) { @case (0) {
    <app-basic
    [eduTextbook]="textBook"
    (state)="changeState($event)"
    (save)="save()"
    ></app-basic>
    } @case (1) {
    <app-textbook-pertain
    [eduTextbook]="textBook"
    (state)="changeState($event)"
    (save)="save()"
    (maxWidth)="(submitComp.style.width)"
    ></app-textbook-pertain>
    } @case (2) {
    <app-textbook-content
    [eduTextbook]="textBook"
    (state)="changeState($event)"
    (save)="save()"
    (maxWidth)="(submitComp.style.width)"
    ></app-textbook-content>
    }@case (3) {
    <app-faith
    [eduTextbook]="textBook"
    (state)="changeState($event)"
    (save)="save()"
    (maxWidth)="(submitComp.style.width)"
    ></app-faith>
    } 
    @case (4) {
    <app-attachment
    [eduTextbook]="textBook"
    (state)="changeState($event)"
    (save)="save()"
    (maxWidth)="(submitComp.style.width)"
    ></app-attachment>
    } }
    
  • 回收站:app-recycle
  • 调用组件:app-textbook

    <app-textbook
    [filterObj]="filterObj"
    [uid]="user?.id"
    path="/nav-author/manage/details"
    [discard]="true"
    ></app-textbook>
    
    国家级管理员管理平台
  • 路由模块:NavAdminRoutingModule

  • 组件

  • app-collect-textbook 【教材文件收集列表】

  • 必填参数

  • 主要函数方法

    • getTextbook:获取教材
    • onEmitMsg:短信提醒,提交状态置为100
    • onReject:退回教材给出版社
  • app-profile 【工作联系人】

  • 必填参数

    • depart:单位,用于查询本单位下注册联系人身份用户列表
  • 主要函数方法

    • getProfile:获取用户角色列表
  • 全部教材:app-page-textbook

  • 功能说明

  • 批量查看已提交至国家级管理员教材、教材文件上传管理

  • 调用组件

  • app-textbook

  • app-collect-textbook

  • 申报流程:app-process-list

  • 功能说明

  • 进入页面通过getDepart方法获取所有一级节点部门

  • 点击左侧流程调用getDepart获取对应一级节点下全部流程,右侧显示流程table

  • table操作栏可对流程进行操作,可操作按钮通过statusMap状态判断

  • 可通过toUrl('/nav-admin/manage/process/create')跳转创建流程页

  • 主要参数说明

  • activeDepart:当前编辑部门

  • eduProcessList:流程列表

  • formatStatus:格式化流程状态

  • formatFileStatus:教材上传状态

  • 主要函数方法

  • getDepart:获取部门单位节点

  • getEduProcess:获取部门列表

  • formatNode:格式化链

  • statusSelected:操作流程,开始、暂停、结束、删除

  • onStatusChange:暂停流程

  • openEditCollect:保存收集文件设置

  • sendNoticeMSG:短信通知

  • 流程详情:app-page-process

  • 功能说明

  • 默认进入报送流程tab栏,可修改流程名称、限额、工作联系人等相关配置信息

  • 教材列表可查看已提交到国家级管理员的所有教材

  • 教材文件功能查看上传教材的状态

  • 调用组件

  • app-process-create:流程管理

  • app-textbook

  • app-collect-textbook

  • 用户列表:app-page-user
  • 功能说明

  • 本页权限通过tbookSer.profile.identity判断给与相应权限,包含国家级管理员、高校联系人管理权限区分;国家级管理员可管理平台所有身份用户,工作联系人可管理所属部门节点及下级节点的部门用户,不包含“工作联系人”身份的用户

  • 统一管理平台所有用户,可创建、删除、修改用户

  • 创建用户:点击addMember弹出创建用户弹窗,填写用户基本信息后点击确定完成请求创建用户,人员类型校验必须选择部门后才能选择

  • 在操作通过认证时,如果该工作联系人对应流程未被绑定,则会自动校验绑定至该单位的流程作为流程管理员(注:每一个流程只能对应一个流程管理员),诺已绑定,则会取消本次绑定事件,但会继续通过身份认证。部分代码逻辑

    //更新工作联系人textbook.ts
    async updateProfileSubmitted(
    pid: string,
    type: string,
    dpid?: string,
    msg?: NzMessageService
    ): Promise<boolean | undefined> {
    console.log(pid, type, dpid);
    let query = new Parse.Query('EduProcess');
    if (!dpid) {
    query.equalTo('profileSubmitted', pid);
    } else {
    query.equalTo('department', dpid);
    }
    query.include('profileSubmitted');
    query.select('objectId', 'profileSubmitted');
    query.notEqualTo('isDeleted', true);
    let res = await query.first();
    if (!res?.id) {
    msg?.warning('所属单位不存在');
    return false;
    }
    if (type == 'del') {
    //删除工作联系人
    res.set('profileSubmitted', null);
    await res.save();
    return true;
    } else {
    //添加工作联系人
    if (res?.get('profileSubmitted')?.get('user')) {
      msg?.warning('该单位已有部门联系人,请先移除后再操作');
      return false;
    }
    res?.set('profileSubmitted', {
      __type: 'Pointer',
      className: 'Profile',
      objectId: pid,
    });
    await res.save();
    return true;
    }
    return false;
    }
    
  • 主要参数说明

  • profiles:用户列表

  • parentList:部门选择

  • filters:筛选条件,用于列表搜索或列表条件查询等

  • 主要函数方法

  • getProfile:获取用户列表

  • updateUrlPageIndex:更新页面,路由返回功能回显作用

  • updateUser:更新用户信息,通过认证或删除操作

  • addMember:添加用户初始化,初始化后通过accountIsVisible设置弹窗弹出用户信息弹出,对其设置

  • getDepart:获取部门信息

  • onCheckedDepart:选择所属类别下级列表

  • accountComplete:添加账号,需通过authVrifly表单信息校验

  • authVrifly:用户信息表单校验,含邮箱格式正则、手机号正则等

  • 用户管理&编辑:app-user-edit

  • 功能说明

  • 路由须携带用户ID

  • 编辑、查看用户信息,含扩展字段,省份、职务等

  • 修改密码:判断是否具有修改权限,如果有可直接在弹出中修改,修改后会直接通过邮箱或短信通知

  • 用户教材:可查看该用户所创建的所有教材,含未提交的,组件传入参数

    submitTextBook = {
    status:['102','103','200','201','300','400'],
    btns:{
    review:true,//查阅
    }
    }
    
  • 调用组件

  • app-textbook

    <app-textbook
    [filterObj]="submitTextBook"
    [uid]="user?.id"
    ></app-textbook>
    
  • 主要参数说明

  • user:用户信息

  • profileJson:身份编辑数据

  • userJson:user编辑数据,用于编辑未保存提示

  • edit:是否可编辑权限

  • profile:用户角色信息

  • 主要函数方法

  • updateUser:操作用户删除、变更用户状态

  • handleOk:变更密码

  • showModalDepart:选择部门

  • getDepart:根据所选单位类型获取对应单位

  • onCheckedDepart:选择部门

  • completeChange:选择部门

  • submitForm:修改账户所属部门单位

  • updateUserJson:更新用户数据

  • moduleChange:判断编辑数据变化

  • updateCanDeActivate:保存提示

  • 申报单位管理:app-page-role
  • 功能说明

  • 通过权限判断获取单位部门getDepart,存储nodes节点,部分代码

    nodes.push({
    title: item.get('name'),
    key: item.id,
    children: [],
    branch: item.get('branch'),
    parent: item.get('parent')?.id, //上级
    isLeaf: !item.get('hasChildren'), //是否是最下级
    type: item.get('type'),
    });
    
  • 点击部门获取用户列表,在左侧用户显示,可对其管理

  • 添加成员:addMember添加选中部门的用户角色,工作联系人管理状态下默认同节点

  • 添加部门:国家级管理员可添加任意节点部门、工作联系人可添加当前单位下的部门

  • 使用nz-tree组件,通过contextmenu函数调用鼠标左击直接操作选中单位可编辑的权限

  • 主要参数说明

  • nodes:部门节点

  • profileLength:用户列表

  • activatedNode:当前选中节点

  • activeDepart:当前编辑部门

  • editObject:编辑部门字段,单项赋值绑定

  • 主要函数方法

  • getDepart:获取部门单位

  • getProfile:获取用户列表

  • contextMenu:鼠标右击事件

  • onDelDepart:删除部门

  • showModalDepart:初始化用户

  • handleOk:保存编辑&新增部门

  • showProfile:变更用户部门

  • accountComplete:添加账号

  • updateProfile:保存更新部门

    工作联系人:中央部门所属高校联系人、部省合建高校联系人、出版单位联系人、省属高校流程管理员
  • 路由模块:NavProContactRoutingModule

  • 组件

  • app-review-details 【评审教材列表】

  • 必填参数

  • 主要函数方法

    • getTextbook:获取教材
    • export:导出表格
  • app-upload-collect 【教材上传列表】

  • 必填参数

  • 主要函数方法

    • upload:上传回调参数处理
    • submitForm:提交教材文件
  • 全部教材:app-page-textbook

  • 功能说明

  • 批量查看已提交至国家级管理员教材、教材文件上传管理

  • 通过textbook?.export()调用app-textbook组件直接下载汇总表

    <app-textbook
    hidden
    #textbook
    [recommend]="true"
    [filterObj]="filterObj"
    [eduProcess]="eduProcess"
    ></app-textbook>
    
  • 调用组件

  • app-textbook

  • 主要参数说明

  • beforeFilterObj:待审核参数

    beforeFilterObj: any = {
    showMore: true, //显示更多字段
    isCheck: true,
    noStared: true,
    status: ['200'],
    btns: {
      export: true,
    },
    };
    
  • afterFilterObj:已加入推荐

    afterFilterObj: any = {
    showMore: true, //显示更多字段
    isCheck: true,
    status: ['200', '201', '400'],
    btns: {
    // remove: true, //移除推荐
    export: true,
    },
    };
    
  • 主要函数方法

  • getProcess:获取流程

  • submitted:报送

  • 申报流程:app-process-list

  • 功能说明

  • 查看本单位申报流程的流程,可点击教材名称进入详情查看

  • 主要参数说明

  • formatStatus:格式化流程状态,收集状态

  • 主要函数方法

  • getEduProcess:获取流程

  • 流程详情:app-page-process

  • 功能说明

  • 流程管理可以查看报送限额、开始及结束时间

  • 评审活动显示评审活动时间

  • 显示所有的已提交的教材列表;

  • 调用组件

  • app-process-create

  • app-textbook

    <div class="title">待评审教材列表</div>
    <app-textbook
    [filterObj]="beforeFilterObj"
    [eduProcess]="eduProcess"
    ></app-textbook>
    <br />
    <div class="title">推荐教材列表</div>
    <app-textbook
    [filterObj]="afterFilterObj"
    [recommend]="true"
    [eduProcess]="eduProcess"
    ></app-textbook>
    
    //待审核
    beforeFilterObj: any = {
    showMore: true, //显示更多字段
    isCheck: true,
    noStared: true,
    status: ['200'],
    btns: {
    export: true,
    },
    };
    //已加入推荐
    afterFilterObj: any = {
    showMore: true, //显示更多字段
    isCheck: true,
    status: ['200', '201', '400'],
    btns: {
    export: true,
    },
    };
    
  • 主要参数说明

  • beforeFilterObj:待审核

  • afterFilterObj:已加入推荐

  • activity:评审活动

  • 主要函数方法

  • getActivity:获取评审活动

  • getExpertGroup:获取评审组

  • startActivity:开始活动

  • onCompute:计算平均分

  • getEduReview:获取评审详情列表

  • 创建&编辑评委活动:app-activity

  • 功能说明

  • 编辑评审活动,name、startDate、deadline;评审端评选打分教材以此时间为准,评审端通过条件判断是否在评审时间段内为评审条件之一

  • 评审规则:平均数mean、截尾平均数truncatedMean用于计算时评审计平均分分

  • 评审组:设置教材可评审的评审人员,教材与评审组关系:n:1

  • 调用组件

  • app-comp-upload

    //上传教材评审文件,在评审端评审时可在弹出的打分中看到该文件
    <app-comp-upload
    [type]="'pdf'"
    (change)="upload($event)"
    title="上传评审细则文件"
    ></app-comp-upload>
    
  • app-review-details

    <app-review-details
    [listOfFilter]="listOfFilter"
    [filterObj]="filterObj"
    ></app-review-details>
    
  • 主要参数说明

  • filterObj:评审明细子组件介绍参数条件;showGroup:显示评审组名称,contained:指定评审组查询,bookMap:教材对应评审组结构{booid:评审组名称}

  • 主要函数方法

  • getActivity:获取评审活动

  • getExpertGroup:评审组

  • deleteGroup:删除评审组

  • 创建&编辑评委组:app-review-edit

  • 功能说明

  • 默认评审教材为全部,可以onchangeTextbook切换手动选中教材,选中手动选中教材后,显示教材列表app-textbook组件,可勾选后确定,在app-textbook组件的回调中获取勾选的教材赋值变量在保存请求

  • 默认评审专家为全部,可手动onchangeReview切换手动选择专家,选择的专家会在右侧

  • 所有设置均有回显类名class="dep-right"元素显示,也会在当前类class="dep-comp"显示选中样式

  • 教材评审明细显示已打分的各个评审专家分数

  • 调用组件

  • app-review-details

    <app-review-details [filterObj]="reviewFilterObj"></app-review-details>
    
  • app-textbook

    //setOfCheckedTextbookAll传入已选择的id
    //updateCheck是组件选中后确认的回调方法,通过@ViewChild获取组件元素服务,直接调用组件方法赋值给页面
    <app-textbook
    [hidden]="radio == 'all'"
    [filterObj]="filterObj"
    [eduProcess]="eduProcess"
    [setOfCheckedId]="setOfCheckedTextbookAll"
    (updateCheck)="updateCheck()"
    #textbook
    >
    
  • 主要参数说明

  • eduProcess:申报流程

  • expertGroup:评审组对象

  • checkProfileListLeng:已选择评审专家人数

  • reviewFilterObj:传入评审组件显示列表参数

  • 主要函数方法

  • refresh:初始化评审组,回显、赋值可编辑信息

  • getTextName:获取展示已选择教材

  • getExpertGroup:获取所有已被其他评审组选择过教材

  • getProfile:获取评委专家

  • updateAllChecked:选中专家改变事件

  • onSave:保存评审设置,评审教材、评审专家

  • 本社教材源文件:app-collect-file

  • 功能说明

  • 本路由权限只有出版社部门节点下的联系人有权限进入,在app-comp-manage初始化组件中做逻辑menu权限判断

  • comp-manage.component.ts相关代码

    if (this.tbookSer.profile.identity == '工作联系人' && this.tbookSer.profile.user?.department?.branch == '出版单位') {
    this.optionsMap['工作联系人'][0].child.push({
      name: '本社教材源文件',
      path: '/nav-province-contact/manage/collect',
      id: '1-3',
    });
    }
    
  • 根据教材分册所选出版社,editionUnit字段是否等于当前出版社单位筛选条件;查询对应教材是否在上传期间条件:EduTextbook.eduProcess.status流程状态需要是已提交至国家级管理员

  • 因为单本教材可能涉及到多个分册,每个分册可能不同出版单位,我们在教材获取下来后在分册中做了本次教材校验,且在上传中只能对应选中本出版单位本册可操作、查看,以下部分代码,通过判断渲染可编辑权限教材

    @for (panel of currentTextbook?.get('childrens'); track panel) { @if
        (panel?.get('editionUnit') == tbookSer.profile.user?.department?.name) {
      <nz-collapse-panel
        #p
        [nzHeader]="title"
        [nzActive]="false"
        nzExpandedIcon="caret-right"
        style="
          background: #f7f7f7;
          border-radius: 4px;
          margin-bottom: 24px;
          border: 0px;
        "
      >
        <ng-template #title>
          <span class="panel-title">{{
            "分册" + ($index + 1) + "-" + currentTextbook?.get("title")
          }}</span>
        </ng-template>
        <div class="">
          <app-upload-collect
            #children
            [eduTextbookVolume]="panel"
          ></app-upload-collect>
        </div>
        <ng-template #expandedIcon let-active>
          {{ active }}
          <span
            nz-icon
            nzType="caret-right"
            class="ant-collapse-arrow"
            [nzRotate]="p.nzActive ? 90 : -90"
          ></span>
        </ng-template>
      </nz-collapse-panel>
      } }
    
  • 管理员可点击列表编辑打开弹出后,进行教材上传

  • 调用组件

  • app-upload-collect

  • 主要参数说明

  • textbookList:教材列表

  • statusMap:任务状态,映射关系:{教材id:{状态,状态色、可操作按钮}}

  • 主要函数方法

  • fromatFiled:格式化拓展表字段

  • getTextbook:获取教材

  • getEduProcess:获取流程

  • onEditModal:上传教材打开上传弹窗

  • saveCollect:保存上传教材

  • saveEduTextbookVolume:保存事件推送上传教材

  • 用户列表:app-page-user 功能同国家级管理员用户列表

  • 申报单位管理: app-page-role 功能同国家级管理员申报单位管理

    高校联系人
  • 路由模块:NavProSchoolRoutingModule

  • 全部教材:app-page-textbook

  • 功能说明

  • 高校联系人只有省级教育行政部门、有关部门(单位)教育司(局)单位下级省局单位下高校有登录权限,当教师属于该单位下时,默认提交到高校联系人,由高校联系人审核后提交至工作联系人

  • 在本页高校联系人可查看对应高校及以下单位的所有教师教材,含未提交

  • 待提交教材可点击提交至工作联系人,代评审教材为未被专家评审或未提交报送的教材

  • 调用组件

  • app-textbook

  • 主要参数说明

  • draftFilterObj:获取草稿传参子组件调教

  • beforeFilterObj:获取待提交教材子组件调教

  • afterFilterObj:获取待评审教材子组件调教

  • 主要函数方法

  • getProcess:获取流程

  • 用户列表:app-page-user 功能同国家级管理员用户列表

  • 申报单位管理: app-page-role 功能同国家级管理员申报单位管理

  • 个人空间:app-space 功能同教师个人空间

  • 回收站:app-recycle 功能同教师回收站

    教材评审专家
  • 路由模块:NavReviewRoutingModule

  • 教材打分:app-approve

  • 功能说明

  • 根据评审组件获取该评审专家对应可打分评审的教材,首先需先确定该流程下的评审活动已开启,是否在评审期间以活动时间为准,以下为权限及获取打分教材部分代码

    //判断是否在获取期间
    get isStart(): boolean {
    return (
      !this.activity?.get('startDate') ||
      this.activity?.get('startDate') > new Date()
    );
    }
    
    <!-- 获取教材列表组件 -->
    <app-textbook
    (markScore)="onMarkScore($event)"
    [filterObj]="beforeFilterObj"
    [scoreMap]="scoreMap"
    #textbook
    ></app-textbook>
    
    //待评分
    beforeFilterObj: any = {
    showMore: true, //显示更多字段
    isCheck: true,
    status: ['200'],
    contained: [],
    btns: {
      eduReivew: true,
      mark: true,
    },
    };
    //已评审
    afterFilterObj: any = {
    showMore: true, //显示更多字段
    isCheck: false,
    status: ['200','201','300','400'],
    contained: [],
    btns: {
      eduReivew: true,
    },
    };
    
  • 点击打分可在可允许打分条件下弹窗,若已过或未开始评审时间,则打分弹窗会被阻止;评审专家可在打分弹窗中打分,可先保存saveScore('save')或提交saveScore('submit')

  • 调用组件

  • app-textbook

  • 主要参数说明

  • eduProcess:流程

  • editTextbook:评分教材

  • eduReview:评审记录

  • scoreMap:教材评审状态

  • 主要函数方法

  • authCompute:校验是否在评审期间

  • isStart:校验评审是否开始

  • isEnd:校验评审是否结束

  • getEduReview:获取评审记录

  • getExpertGroup:获取评审组相关教材,评审专家可对应对各评审组,需把所有评审组中教材获取后传递给渲染组件获取可评审教材

    //部分代码逻辑
    r.forEach((item) => {
    item.get('textbookList')?.forEach((obj: any) => {
    this.beforeFilterObj.contained.push(obj.id || obj.objectId);
    });
    });
    
  • getActivity:获取评审活动

  • onMarkScore:打开评审弹窗

  • saveScore:提交打分

    其他公共模块
  • 教材详情:app-textbook-details

  • 功能说明

  • 展示教材所有基础信息,含附件

  • 联系人或国家级管理员身份可查看评审分数

  • 主要参数说明

  • textBook:教材对象

  • 主要函数方法

  • getExpertGroup:获取评审组

  • getEduReview:获取本教程评分

  • 补充上传教材作者诚信承诺:app-upload-pdf

  • 功能说明

  • 创建时未上传作者签名文件等,可链接本页面填写添加补全

  • 主要参数说明

  • authorSignPDF:上传签名页

  • unitMaterial:申报单位承诺意见

  • 主要函数方法

  • saveEduTextbook:获取教材签名文件是否上传

  • upload:上传文件回调

    项目公共服务类services

  • auth.guard.ts:路由守卫

  • auth.service.ts:用户身份服务

  • compute.ts:科学计算

  • majors.map.ts:教材所属专业类map(6位)

  • majors4.map.ts:教材所属专业类map(4位)

  • shell.ts:定制化导出脚本

  • textbook.ts:教材common服务