Browse Source

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

xll 7 months ago
parent
commit
7107ff42de

+ 1 - 1
README.md

@@ -20,7 +20,7 @@ npm run start
 
 ``` bash
 npx vite build
-cp .\dist\server\server.js temp-server.js
+cp ./dist/server/server.js temp-server.js
 node temp-server.js --local
 ```
 

+ 1 - 1
docker-front

@@ -1 +1 @@
-Subproject commit 4ce99679dd15b479ee2c74abe019e8e3474bc558
+Subproject commit f2aa87dcdcbea31ac16b3a7e5a2aa858de9f5aff

+ 1 - 0
projects/textbook/src/app/comp-manage/comp-manage.component.scss

@@ -32,6 +32,7 @@
     flex: 1;
     background-color: white;
     border-radius: 10px;
+    position: relative;
   }
 }
 

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

@@ -124,7 +124,7 @@ export class CompManageComponent implements OnInit {
       },
       {
         id:'2',
-        name:'用户过来',
+        name:'用户管理',
         child:[
           {
             id:'2-1',

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

@@ -32,6 +32,7 @@
     [nzFrontPagination]="false"
     [nzScroll]="{ x: (maxWidth || '1200') + 'px' }"
     nzTableLayout="fixed"
+    (nzPageIndexChange)="pageIndexChange($event)"
   >
     <thead>
       <tr>

+ 105 - 2
projects/textbook/src/app/textbook/textbook.component.ts

@@ -59,7 +59,7 @@ export class TextbookComponent implements OnInit {
   setOfCheckedId = new Set<string>();
   searchValue: string = '';
   manage: boolean = false;
-  eduProcessId:any = '' //流程id,verify存在时需要
+  eduProcessId: any = ''; //流程id,verify存在时需要
   constructor(
     public tbookSer: textbookServer,
     private route: Router,
@@ -77,7 +77,7 @@ export class TextbookComponent implements OnInit {
       }
     });
   }
-  async getTextbook(val?: string) {
+  async getTextbook(val?: string, exported?: boolean): Promise<any[] | void> {
     this.loading = true;
     let query = new Parse.Query('EduTextbook');
     if (val) {
@@ -124,6 +124,11 @@ export class TextbookComponent implements OnInit {
     } else {
       query.notEqualTo('discard', true);
     }
+    if (exported) {
+      let r = await query.find();
+      this.loading = false;
+      return r;
+    }
     // query.include('department');
     this.count = await query.count();
     query.limit(this.limit);
@@ -136,6 +141,12 @@ export class TextbookComponent implements OnInit {
     console.log(e);
     this.getTextbook(e);
   }
+  //分页切换
+  pageIndexChange(e: any) {
+    console.log(e);
+    this.pageSize = e;
+    this.getTextbook(this.searchValue);
+  }
   //全选
   onAllChecked(checked: boolean) {
     console.log(checked);
@@ -303,4 +314,96 @@ export class TextbookComponent implements OnInit {
     }
     this.route.navigate([url]);
   }
+
+  //导出
+  async export() {
+    let data: any = await this.getTextbook('',true);
+    let table = `<table border="1px" cellspacing="0" cellpadding="0">
+        <thead>
+          <tr>
+            <th>申报编号</th>
+            <th>教材名称</th>
+            <th>册数</th>
+            <th>第一主编/作者</th>
+            <th>所属单位</th>
+            <th>所属本科专业</th>
+            <th>主要语种类型</th>
+            <th>ISBN</th>
+            <th>出版单位</th>
+          </tr>
+        </thead>
+        <tbody>
+        `;
+    let _body = '';
+    for (var row = 0; row < data.length; row++) {
+      _body += '<tr>';
+      _body += '<td>';
+      _body += `${row + 1}`;
+      _body += '</td>';
+
+      _body += '<td>';
+      _body += ` &nbsp;${data[row].get('title') || '-'}`;
+      _body += '</td>';
+
+      _body += '<td>';
+      _body += `${
+        data[row]?.get('type') == '单册'
+          ? '单册'
+          : data[row]?.get('typeNumber') || '-'
+      }`;
+      _body += '</td>';
+
+      _body += '<td>';
+      _body += `${data[row]?.get('author') || '-'}`;
+      _body += '</td>';
+
+      _body += '<td>';
+      _body += `${data[row]?.get('unit') || '-'}`;
+      _body += '</td>';
+
+      _body += '<td>';
+      _body += `${data[row]?.get('major').name || '-'}`;
+      _body += '</td>';
+
+      _body += '<td>';
+      _body += `${data[row]?.get('lang') || '-'}`;
+      _body += '</td>';
+
+      _body += '<td>';
+      _body += `${data[row]?.get('ISBN') || '-'}`;
+      _body += '</td>';
+
+      _body += '<td>';
+      _body += `${data[row]?.get('editionUnit') || '-'}`;
+      _body += '</td>';
+      _body += '</tr>';
+    }
+    table += _body;
+    table += '</tbody>';
+    table += '</table>';
+    let title = '申报流程列表';
+    this.excel(table, `${title}.xls`);
+  }
+  excel(data: any, filename: string) {
+    let html =
+      "<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:x='urn:schemas-microsoft-com:office:excel' xmlns='http://www.w3.org/TR/REC-html40'>";
+    html +=
+      '<meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8">';
+    html += '<meta http-equiv="content-type" content="application/vnd.ms-excel';
+    html += '; charset=UTF-8">';
+    html += '<head>';
+    html += '</head>';
+    html += '<body>';
+    html += data;
+    html += '</body>';
+    html += '</html>';
+    let uri =
+      'data:application/vnd.ms-excel;charset=utf-8,' + encodeURIComponent(html);
+    let link = document.createElement('a');
+    link.href = uri;
+    link.download = `${filename}`;
+    document.body.appendChild(link);
+    link.click();
+    document.body.removeChild(link);
+  }
 }

+ 6 - 10
projects/textbook/src/modules/nav-province-contact/submitted/complete/complete.component.html

@@ -1,15 +1,11 @@
 <div class="manage">
-  <nz-empty [nzNotFoundContent]="deadline+ '后可完成报送'"></nz-empty>
+  <nz-empty [nzNotFoundContent]="deadline + '后可完成报送'"></nz-empty>
 </div>
 
 <div class="footer">
-  <button nz-button disabled="true" nzType="default" style="margin-right: 20px">
-  </button>
-  <button
-    nz-button
-    nzType="primary"
-    disabled="true"
-  >
-    完成报送
-  </button>
+  <div class="tips">共 36 册(套)推荐报送教材</div>
+  <div class="btns">
+  <button nz-button disabled="true" nzType="default" style="margin-right: 20px">撤销公示</button>
+    <button nz-button nzType="primary" disabled="true">完成报送</button>
+  </div>
 </div>

+ 20 - 8
projects/textbook/src/modules/nav-province-contact/submitted/complete/complete.component.scss

@@ -8,14 +8,26 @@
   // justify-content: center;
 }
 .footer{
-  position: fixed;
-  bottom: 50px;
-  right: 10px;
+  position: absolute;
+  bottom: 10px;
+  width: 100%;
+  right: 0;
   display: flex;
-  margin: 10px auto;
   align-items: center;
-  justify-content: space-evenly;
-  // width: 200px;
-  justify-content: end;
-  padding-right: 100px;
+  justify-content: space-between;
+  padding: 0 10px;
+  .tips{
+    font-family: PingFang SC;
+    font-size: 16px;
+    font-weight: 400;
+    line-height: 24px;
+    text-align: left;
+    color: #231C1F99;
+  }
+  .btns{
+    display: flex;
+    align-items: center;
+    justify-content: space-evenly;
+    justify-content: end;
+  }
 }

+ 1 - 1
projects/textbook/src/modules/nav-province-contact/submitted/complete/complete.component.ts

@@ -10,7 +10,7 @@ import { NzEmptyModule } from 'ng-zorro-antd/empty';
   standalone: true,
 })
 export class CompleteComponent implements OnInit {
-  date: Date = new Date('2024/7/21');
+  date: Date = new Date('2024/7/31');
   t: any;
   deadline: string = '';
   time() {

+ 6 - 8
projects/textbook/src/modules/nav-province-contact/submitted/export-file/export-file.component.scss

@@ -22,14 +22,12 @@
   }
 }
 .footer{
-  position: fixed;
-  bottom: 50px;
-  right: 10px;
+  position: absolute;
+  bottom: 10px;
+  width: 100%;
+  right: 0;
   display: flex;
-  margin: 10px auto;
   align-items: center;
-  justify-content: space-evenly;
-  // width: 200px;
-  justify-content: end;
-  padding-right: 100px;
+  justify-content: flex-end;
+  padding: 0 10px;
 }

+ 28 - 6
projects/textbook/src/modules/nav-province-contact/submitted/export-list/export-list.component.html

@@ -1,11 +1,33 @@
 <div class="manage">
-  <div class="title">北京市“十四五”普通高等教育本科国家级规划教材第一次遴选推荐名单</div>
-  <app-textbook [filterObj]="filterObj"></app-textbook>
+  <div class="title">
+    {{
+      eduProcess?.get("name")
+    }}“十四五”普通高等教育本科国家级规划教材第一次遴选推荐名单
+  </div>
+  <app-textbook #textbook [filterObj]="filterObj"></app-textbook>
 </div>
 
-
 <div class="footer">
-  <button nz-button nzType="default"  style="margin-right: 20px">下载公示列表</button>
-  <button nz-button nzType="default" (click)="onChange('pre')" style="margin-right: 20px">上一页</button>
-  <button nz-button nzType="primary" (click)="onChange('next')" style="background: #3e49b3; border: 1px #3e49b3">下一步</button>
+  <div class="tips">共 36 册(套)推荐报送教材</div>
+  <div class="btns">
+    <button nz-button (click)="textbook.export()" nzType="default" style="margin-right: 20px">
+      下载公示列表
+    </button>
+    <button
+      nz-button
+      nzType="default"
+      (click)="onChange('pre')"
+      style="margin-right: 20px"
+    >
+      上一页
+    </button>
+    <button
+      nz-button
+      nzType="primary"
+      (click)="onChange('next')"
+      style="background: #3e49b3; border: 1px #3e49b3"
+    >
+      下一步
+    </button>
+  </div>
 </div>

+ 20 - 8
projects/textbook/src/modules/nav-province-contact/submitted/export-list/export-list.component.scss

@@ -8,14 +8,26 @@
   margin-bottom: 18px;
 }
 .footer{
-  position: fixed;
-  bottom: 50px;
-  right: 10px;
+  position: absolute;
+  bottom: 10px;
+  width: 100%;
+  right: 0;
   display: flex;
-  margin: 10px auto;
   align-items: center;
-  justify-content: space-evenly;
-  // width: 200px;
-  justify-content: end;
-  padding-right: 100px;
+  justify-content: space-between;
+  padding: 0 10px;
+  .tips{
+    font-family: PingFang SC;
+    font-size: 16px;
+    font-weight: 400;
+    line-height: 24px;
+    text-align: left;
+    color: #231C1F99;
+  }
+  .btns{
+    display: flex;
+    align-items: center;
+    justify-content: space-evenly;
+    justify-content: end;
+  }
 }

+ 11 - 2
projects/textbook/src/modules/nav-province-contact/submitted/export-list/export-list.component.ts

@@ -2,6 +2,7 @@ import { Component, EventEmitter, OnInit, Output } from '@angular/core';
 import { Router, ActivatedRoute } from '@angular/router';
 import { TextbookComponent } from '../../../../app/textbook/textbook.component';
 import { CommonCompModule } from '../../../../services/common.modules';
+import Parse from 'parse';
 
 @Component({
   selector: 'app-export-list',
@@ -13,13 +14,21 @@ import { CommonCompModule } from '../../../../services/common.modules';
 export class ExportListComponent implements OnInit {
   @Output() change: EventEmitter<any> = new EventEmitter<any>();
   textBookList: Parse.Object | any;
-
+  eduProcess?:Parse.Object
   filterObj: any = {
     isCheck: false,
   };
   constructor(private router: Router, private activeRoute: ActivatedRoute) {}
 
-  ngOnInit() {}
+  ngOnInit() {
+    this.activeRoute.paramMap.subscribe(async (params) => {
+      let id = params.get('id');
+      let query = new Parse.Query('EduProcess');
+      query.include('department');
+      query.equalTo('objectId', id);
+      this.eduProcess = await query.first();
+    });
+  }
   onChange(type: string) {
     if (type == 'next') {
       this.change.emit('next');

+ 1 - 0
server/cloud/authing/test/test-authing-org-sync.js

@@ -12,4 +12,5 @@ main()
 /**
  * Cloud Code test
  curl -X POST -H "Content-Type: application/json" -H 'X-Parse-Application-Id: edu-textbook' http://8.140.98.43/parse/functions/authingDepartSync
+ curl -X POST -H "Content-Type: application/json" -H 'X-Parse-Application-Id: edu-textbook' http://127.0.0.1:61337/parse/functions/authingDepartSync
  */

+ 13 - 2
server/cloud/authing/trigger-user-save.js

@@ -10,28 +10,39 @@ const managementClient  = new ManagementClient({
 /**
  * 用户创建前,创建用户至Authing
  * @desc 仅同步注册信息及密码,资料在afterSave中同步
+ * @example
+ * 注册:
+ curl -X POST -H "Content-Type: application/json" -H "X-Parse-Application-Id: edu-textbook" -d '{
+  "username": "333",
+  "password": "333"
+ }' http://127.0.0.1:61337/parse/users
+ * 删除:
  */
 export function defineUserBeforeSave(){
     Parse.Cloud.beforeSave("_User", async (request) => {
+        // console.log("UserBeforeSave")
         request.object = appendUserACL(request.object)
         let user = request.object;
         // 仅首次注册/创建用户/修改密码有password属性,同步Authing账号
         let password = user?.get("password");
+        // console.log(password)
         if(password){
             let mobile = user?.get("mobile");
             let email = user?.get("email");
             let username = user?.get("username");
             let externalId = user?.id;
             let authingUserExists = await findUserByMobileEmailUserName(user)
+            // console.log(authingUserExists)
             if(authingUserExists?.statusCode==404){ // 创建用户
                 let newuser = {
                     status:"Activated",
+                    password:password,
                 }
                 if(mobile){newuser.phone = mobile}
                 if(email){newuser.email = email}
                 if(username){newuser.username = username}
                 if(externalId){newuser.externalId = externalId}
-
+                // console.log(newuser)
                 result = await managementClient.createUser(newuser)
             }
             if(authingUserExists?.statusCode==200){
@@ -72,7 +83,7 @@ function appendUserACL(user){
 /**
  * 用户删除前,删除用户从Authing
  */
- export function defineUserBeforeDelete(){
+ export function defineUserAfterDelete(){
     Parse.Cloud.afterDelete("_User", async (request) => {
         let user = request.object;
         // console.log(user.toJSON());

+ 2 - 2
server/server.js

@@ -44,7 +44,7 @@ global.config["LOCAL"] = argv.local || process.env["LOCAL"] || appConfig["LOCAL"
 
 import  {textbookRouter} from "./api/textbook/routes";
 import { defineAliOssSTS } from "./cloud/aliyun"
-import { defineAuthingLogin, defineUserBeforeDelete, defineUserBeforeSave } from "./cloud/authing"
+import { defineAuthingLogin, defineUserAfterDelete, defineUserBeforeSave } from "./cloud/authing"
 import { defineAuthingDepartSync } from "./cloud/authing"
 import { defineUserAfterSave } from "./cloud/authing"
 import { defineTbookISBN } from "./cloud/tbook"
@@ -184,7 +184,7 @@ async function initParseAndDatabase(){
       defineAliOssSTS();
       defineUserAfterSave();
       defineUserBeforeSave();
-      defineUserBeforeDelete();
+      defineUserAfterDelete();
       defineTbookISBN();
     });