Browse Source

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

cehn 7 months ago
parent
commit
451b78944c

+ 77 - 3
projects/textbook/src/modules/nav-province-contact/activity/activity.component.html

@@ -4,18 +4,92 @@
       <span nz-icon nzType="left" nzTheme="outline"></span>返回
     </div>
   </nz-breadcrumb>
-  <nz-page-header-title
-    >{{ eduProcess?.get("name") }}评委活动
+  <nz-page-header-title>{{activity?.get('name')?activity?.get('name'):'创建评委活动'}}
   </nz-page-header-title>
 </nz-page-header>
 <div class="edit-content">
   <nz-tabset [(nzSelectedIndex)]="active">
     <nz-tab nzTitle="活动规则设置">
       @if (active == 0) {
+      <div class="basic">
+        <div class="title">基本信息</div>
+        <ul nz-row nzJustify="space-between">
+          <li nz-col nzSpan="11">
+            <p>评审活动名称<span>*</span></p>
+            <input nz-input placeholder="请输入评审活动名称" [(ngModel)]="name" type="text" />
+          </li>
+          <li nz-col nzSpan="11">
+            <p>开始时间<span></span></p>
+            <nz-date-picker nzShowTime nzFormat="yyyy-MM-dd HH:mm:ss" [(ngModel)]="startDate"></nz-date-picker>
+          </li>
+          <li nz-col nzSpan="11">
+            <p>结束时间<span></span></p>
+            <nz-date-picker nzShowTime nzFormat="yyyy-MM-dd HH:mm:ss" [(ngModel)]="deadline"></nz-date-picker>
+          </li>
+        </ul>
+
+        <button (click)="save()" class="btn save" nz-button nzType="primary">保存</button>
+        <button (click)="reset()" class="btn replay" nz-button nzType="primary">重置</button>
+        <div class="title">评审规则</div>
+        <ul nz-row nzJustify="space-between">
+          <li nz-col nzSpan="11">
+            <p>总分值计算方式<span>*</span></p>
+            <nz-radio-group [(ngModel)]="calculation" (ngModelChange)="changeCalculation()">
+              <label nz-radio nzValue="mean">平均数</label>
+              <label nz-radio nzValue="truncatedMean">截尾平均数</label>
+            </nz-radio-group>
+          </li>
+          <li nz-col nzSpan="11">
+            <p>评审细则</p>
+            @if(reviewDetails?.url){
+            <a target="_blank" [href]="reviewDetails?.url">
+              <span nz-icon nzType="file" nzTheme="outline"></span>
+              {{reviewDetails?.name}}
+            </a>
+            }
+
+            <div class="uploadBtn">
+              <app-comp-upload [type]="'pdf'" (change)="upload($event)" title="上传评审细则文件"></app-comp-upload>
+            </div>
+
+          </li>
+        </ul>
+        <div class="title">
+          评审组
+          <button (click)="creatReviewGroup()" class="btn replay" nz-button nzType="primary">创建评审组</button>
+        </div>
+        @if (expertGroupList.length>0) {
+        <ul class="reviewGroup" >
+          @for (item of expertGroupList; track $index) {
+          <li>
+            <div>
+              <div>{{item?.get('name')||'未命名'}}</div>
+              <p>更新时间:{{item?.get('updatedAt')|date:'yyyy-MM-dd HH:mm:ss'}}</p>
+            </div>
+            <div>
+              <button class="btn replay" nz-button nzType="primary">编辑</button><br>
+              <button (click)="deleteGroup($index)" nz-button nzType="text" nzDanger>删除</button>
+            </div>
+          </li>
+          }
+
+        </ul>
+        }@else {
+        <nz-empty class="empty" nzNotFoundImage="simple" nzNotFoundContent="还没有评审组"></nz-empty>
+        }
+
+
+      </div>
+
+
       }
     </nz-tab>
     <nz-tab nzTitle="评审明细">
-      
+
     </nz-tab>
   </nz-tabset>
+</div>
+
+<div class="loading" [hidden]="!saveLoading">
+  <nz-spin nzSimple [nzSize]="'large'"></nz-spin>
 </div>

+ 103 - 7
projects/textbook/src/modules/nav-province-contact/activity/activity.component.scss

@@ -6,31 +6,127 @@
   text-align: left;
   cursor: pointer;
 }
+
 .edit-content {
   margin: 0 0 20px;
   padding: 0 24px;
   height: calc(100vh - 250px);
-  .title {
-    font-family: PingFang SC;
-    font-size: 20px;
-    font-weight: 500;
-    line-height: 32px;
-    text-align: left;
-    margin-bottom: 16px;
+
+  .basic {
+    .title {
+      width: 100%;
+      font-family: PingFang SC;
+      font-size: 20px;
+      font-weight: bold;
+      line-height: 32px;
+      text-align: left;
+      margin-top: 30px;
+      margin-bottom: 20px;
+      display: flex;
+      justify-content: space-between;
+    }
+
+    ul {
+      margin: 0;
+      padding: 0;
+      li {
+        list-style: none;
+        margin: 10px 0;
+        p {
+          color: rgb(109, 108, 108);
+
+          span {
+            color: red;
+            margin-left: 5px;
+          }
+        }
+        .uploadBtn{
+          width: 150px;
+          text-wrap: nowrap;
+          padding: 5px 10px;
+          border-radius: 5px;
+          background: #EAE6E6;
+          color: gray;
+        }
+      }
+    }
+    .btn{
+      margin-right: 15px;
+      margin-top: 20px;
+      background: #3E49B3;
+      border: none;
+    }
+    .replay{
+      background:#EAE6E6;
+      color: black;
+    }
+    .empty{
+      color: #86909C; 
+      background: whitesmoke;
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      align-items: center;
+    }
+    .reviewGroup{
+      background: whitesmoke;
+      padding: 20px;
+      margin-bottom: 20px;
+      border-radius: 2px;
+      >li{
+      border-radius: 2px;
+        background: white;
+        padding: 20px;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        >div>div{
+          font-size: 18px;
+          font-weight: bold;
+        }
+        p{
+          margin: 10px 0;
+        }
+      }
+    }
   }
+
 }
+.loading{
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100vw;
+  text-align: center;
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: rgb(0 0 0 / 30%);
+  z-index: 99;
+}
+
+
+
+
+
+
 ::ng-deep .ant-page-header-heading-title {
   white-space: normal;
 }
+
 ::ng-deep .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn {
   color: #c6233f;
 }
+
 ::ng-deep .ant-tabs-ink-bar {
   background: #c6233f;
 }
+
 ::ng-deep .ant-tabs-tab:hover {
   color: #e97488;
 }
+
 ::ng-deep .ant-tabs-tab-btn:active {
   color: #e97488;
 }

+ 174 - 2
projects/textbook/src/modules/nav-province-contact/activity/activity.component.ts

@@ -7,6 +7,23 @@ import { ActivatedRoute, Router } from '@angular/router';
 import Parse from 'parse';
 import { TextbookComponent } from '../../../app/textbook/textbook.component';
 import { textbookServer } from '../../../services/textbook';
+
+import { NzInputModule } from 'ng-zorro-antd/input';
+import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
+import { NzButtonModule } from 'ng-zorro-antd/button';
+import { NzGridModule } from 'ng-zorro-antd/grid';
+import { NzMessageModule } from 'ng-zorro-antd/message';
+import { NzMessageService } from 'ng-zorro-antd/message';
+import { NzRadioModule } from 'ng-zorro-antd/radio';
+import { NzEmptyModule } from 'ng-zorro-antd/empty';
+import { CompUploadComponent } from '../../../app/comp-upload/comp-upload.component';
+import { MatDialog, MatDialogModule } from '@angular/material/dialog';
+import { NzIconModule } from 'ng-zorro-antd/icon';
+import { FormsModule } from '@angular/forms';
+import { NzSpinModule } from 'ng-zorro-antd/spin';
+import { MatDialogRef } from '@angular/material/dialog';
+import { DatePipe } from '@angular/common';
+
 @Component({
   selector: 'app-activity',
   templateUrl: './activity.component.html',
@@ -17,18 +34,33 @@ import { textbookServer } from '../../../services/textbook';
     CommonCompModule,
     NzTabsModule,
     TextbookComponent,
+    NzInputModule,
+    NzDatePickerModule,
+    NzButtonModule,
+    NzGridModule,
+    NzMessageModule,
+    NzRadioModule,
+    NzEmptyModule,
+    CompUploadComponent,
+    MatDialogModule,
+    NzSpinModule,
   ],
+  providers: [DatePipe],
+
   standalone: true,
 })
-export class ActivityComponent  implements OnInit {
+export class ActivityComponent implements OnInit {
   active: number = 0;
   eduProcess: Parse.Object | undefined;
   constructor(
     private activeRoute: ActivatedRoute,
     public tbookSer: textbookServer,
-    private router: Router
+    private router: Router,
+    private msg: NzMessageService,
+    public dialog: MatDialog
   ) { }
 
+  saveLoading = true
   ngOnInit() {
     this.activeRoute.paramMap.subscribe(async (params) => {
       let id = params.get('id');
@@ -44,6 +76,8 @@ export class ActivityComponent  implements OnInit {
           );
         }
         this.eduProcess = res;
+        this.refersh()
+
       }
     });
   }
@@ -53,4 +87,142 @@ export class ActivityComponent  implements OnInit {
     //   queryParams: { page: this.activeRoute.snapshot.queryParamMap.get('page') },
     // });
   }
+
+
+  async refersh() {
+    this.getActivity()
+    this.getExpertGroup()
+  }
+  company: string = localStorage.getItem('company')!
+  /**评审活动 */
+  activity?: Parse.Object
+  /**获取评审活动 */
+  async getActivity() {
+    console.log(this.eduProcess?.id, this.company)
+    let query = new Parse.Query('Activity')
+    query.notEqualTo('isDeleted', true)
+    query.equalTo('eduProcess', this.eduProcess?.id)
+    query.equalTo('company', this.company)
+    this.activity = await query.first()
+    console.log(this.activity)
+    if (this.activity?.id) {
+      this.name = this.activity?.get('name') || ''
+      this.startDate = this.activity?.get('startDate') || new Date()
+      this.deadline = this.activity?.get('deadline') || null
+      this.calculation = this.activity?.get('calculation') || 'mean'
+      this.reviewDetails = this.activity?.get('reviewDetails') || {}
+      this.saveLoading = false
+    } else {
+      let Activity = Parse.Object.extend('Activity')
+      this.activity = new Activity()
+    }
+  }
+  /**活动名称 */
+  name: string = ''
+  startDate?: any
+  deadline?: any
+  reset() {
+    this.name = ''
+    this.startDate = null
+    this.deadline = null
+  }
+  /**保存活动 */
+  async save() {
+    if (this.name == '' && !this.name) {
+      this.msg.create('warning', '评审活动名称不能为空')
+      return
+    }
+    if (!this.activity?.id) {
+      this.activity?.set('company', { __type: 'Pointer', className: 'Company', objectId: this.company })
+      this.activity?.set('eduProcess', { __type: 'Pointer', className: 'EduProcess', objectId: this.eduProcess?.id })
+    }
+    this.activity?.set('name', this.name)
+    this.activity?.set('startDate', this.startDate)
+    this.activity?.set('deadline', this.deadline)
+    this.activity?.set('calculation', this.calculation || 'mean')
+    this.activity?.set('reviewDetails', this.reviewDetails || {})
+    this.activity = await this.activity?.save()
+    this.msg.create('success', '保存成功')
+
+  }
+  /**计算方式 mean:平均数 truncatedMean:截尾平均数 */
+  calculation: 'truncatedMean' | 'mean' = 'mean'
+  async changeCalculation() {
+    console.log(this.calculation)
+    this.save()
+  }
+  /**评审细则 */
+  reviewDetails: any
+  async upload(e: any) {
+    console.log(e)
+    let file = e[0]
+    this.reviewDetails = file
+    console.log(this.reviewDetails)
+    if (this.reviewDetails?.url) {
+      this.save()
+    }
+  }
+
+  /**评审组 */
+  expertGroupList: Array<Parse.Object> = []
+  async getExpertGroup() {
+    let query = new Parse.Query('ExpertGroup')
+    query.equalTo('eduProcess', this.eduProcess?.id)
+    query.notEqualTo('isDeleted', true)
+    query.descending('createdAt')//大到小
+    this.expertGroupList = await query.find()
+    console.log(this.expertGroupList)
+  }
+  async deleteGroup(index: number) {
+    this.expertGroupList[index].set('isDeleted', true)
+    await this.expertGroupList[index].save()
+    this.expertGroupList.splice(index, 1)
+    
+  }
+  /**创建评审组弹框 */
+  creatReviewGroup() {
+    const dialogRef = this.dialog.open(CreateReviewGroupContent, {
+      width: '400px'
+    });
+    let that = this
+    dialogRef.afterClosed().subscribe(async (result) => {
+      let name = result
+      if (result = '' || !result) {
+        that.msg.create('warning', '评审组名称未填写')
+        return
+      }
+      console.log(name)
+      let ExpertGroup = Parse.Object.extend('ExpertGroup')
+      let expertGroup = new ExpertGroup()
+      expertGroup.set('eduProcess', { __type: 'Pointer', className: 'EduProcess', objectId: that.eduProcess?.id })
+      expertGroup.set('name', name)
+      await expertGroup.save()
+      that.getExpertGroup()
+      that.msg.create('success', '创建成功')
+
+    });
+  }
+}
+
+
+
+@Component({
+  selector: 'create_review',
+  templateUrl: 'create_review.html',
+  standalone: true,
+  imports: [
+    MatDialogModule,
+    NzIconModule,
+    CommonModule,
+    FormsModule,
+    NzInputModule,
+    NzButtonModule,
+  ],
+})
+export class CreateReviewGroupContent {
+  constructor(private dialogRef: MatDialogRef<CreateReviewGroupContent>) { }
+  name: string = ''
+  onConfirm() {
+    this.dialogRef.close(this.name)
+  }
 }

+ 24 - 0
projects/textbook/src/modules/nav-province-contact/activity/create_review.html

@@ -0,0 +1,24 @@
+<div style="height: 250px;background: white;">
+    <div style="padding: 20px;display: flex;justify-content: space-between;border-bottom: 1px solid rgb(221, 221, 221);">
+        <span style="font-family: PingFang SC;font-size: 18px;font-weight: bold;">创建评审组</span>
+        <span mat-dialog-close nz-icon nzType="close" nzTheme="outline"></span>
+    </div>
+    <ul style="margin: 0;padding: 15px;">
+        <li style="list-style: none;margin: 0;padding: 0;">
+            <p style="color: gray;">评审组名称<span style="color: red;padding-left: 10px;">*</span></p>
+            <input nz-input placeholder="请输入评审组的名称" [(ngModel)]="name" type="text" />
+        </li>
+    </ul>
+    <div style="width: 100%;display: flex;justify-content: end;">
+        <button style="margin-right: 15px;
+        margin-top: 20px;
+        background: #EAE6E6;
+        border: none;color: black;" mat-dialog-close nz-button nzType="primary">取消</button>
+        <button style="margin-right: 15px;
+        margin-top: 20px;
+        background: #3E49B3;
+        border: none;" nz-button nzType="primary"
+        (click)="onConfirm()">创建</button>
+    </div>
+   
+</div>