Browse Source

实施、开发、服务日志 实施里程碑

chenc 4 years ago
parent
commit
884b116c28
38 changed files with 2596 additions and 21 deletions
  1. 2 0
      src/app/entity/project-work/pro-work-logic-content.ts
  2. 40 0
      src/app/entity/project-work/pro-work-milestone.ts
  3. 1 0
      src/app/routes/project-manage-archives/add/add.component.ts
  4. 2 2
      src/app/routes/project-manage-archives/update/development/development.component.html
  5. 2 2
      src/app/routes/project-manage-archives/update/implementation/implementation.component.html
  6. 2 2
      src/app/routes/project-manage-archives/update/serviceta/serviceta.component.html
  7. 109 0
      src/app/routes/project-work/development-log/add/add.component.html
  8. 24 0
      src/app/routes/project-work/development-log/add/add.component.spec.ts
  9. 287 0
      src/app/routes/project-work/development-log/add/add.component.ts
  10. 64 0
      src/app/routes/project-work/development-log/development-log.component.html
  11. 24 0
      src/app/routes/project-work/development-log/development-log.component.spec.ts
  12. 126 0
      src/app/routes/project-work/development-log/development-log.component.ts
  13. 110 0
      src/app/routes/project-work/development-log/update/update.component.html
  14. 24 0
      src/app/routes/project-work/development-log/update/update.component.spec.ts
  15. 311 0
      src/app/routes/project-work/development-log/update/update.component.ts
  16. 2 2
      src/app/routes/project-work/implementation-log/add/add.component.html
  17. 2 1
      src/app/routes/project-work/implementation-log/add/add.component.ts
  18. 32 5
      src/app/routes/project-work/implementation-log/implementation-log.component.html
  19. 2 2
      src/app/routes/project-work/implementation-log/update/update.component.html
  20. 3 2
      src/app/routes/project-work/implementation-log/update/update.component.ts
  21. 53 0
      src/app/routes/project-work/implementation-milestone-confirm/add/add.component.html
  22. 24 0
      src/app/routes/project-work/implementation-milestone-confirm/add/add.component.spec.ts
  23. 47 0
      src/app/routes/project-work/implementation-milestone-confirm/add/add.component.ts
  24. 65 0
      src/app/routes/project-work/implementation-milestone-confirm/implementation-milestone-confirm.component.html
  25. 24 0
      src/app/routes/project-work/implementation-milestone-confirm/implementation-milestone-confirm.component.spec.ts
  26. 88 0
      src/app/routes/project-work/implementation-milestone-confirm/implementation-milestone-confirm.component.ts
  27. 7 1
      src/app/routes/project-work/project-work-routing.module.ts
  28. 18 2
      src/app/routes/project-work/project-work.module.ts
  29. 109 0
      src/app/routes/project-work/service-log/add/add.component.html
  30. 24 0
      src/app/routes/project-work/service-log/add/add.component.spec.ts
  31. 287 0
      src/app/routes/project-work/service-log/add/add.component.ts
  32. 64 0
      src/app/routes/project-work/service-log/service-log.component.html
  33. 24 0
      src/app/routes/project-work/service-log/service-log.component.spec.ts
  34. 126 0
      src/app/routes/project-work/service-log/service-log.component.ts
  35. 110 0
      src/app/routes/project-work/service-log/update/update.component.html
  36. 24 0
      src/app/routes/project-work/service-log/update/update.component.spec.ts
  37. 310 0
      src/app/routes/project-work/service-log/update/update.component.ts
  38. 23 0
      src/app/services/project-work/pro-work-milestone.service.ts

+ 2 - 0
src/app/entity/project-work/pro-work-logic-content.ts

@@ -6,6 +6,8 @@ export class ProWorkLogicContent extends Page{
     id?:string;
 	//日志id
 	logicId?:string;
+	//计划id
+	proPlanId?:string;
 	//项目档案id
 	proArchivesId?:string;
 	//项目档案里程碑

+ 40 - 0
src/app/entity/project-work/pro-work-milestone.ts

@@ -0,0 +1,40 @@
+import { Page } from '../page';
+/**
+ * 里程碑确认单
+ */
+export class ProWorkMilestone extends Page{
+    id?:string;
+	//单据编号
+	billcode?:string;
+	//1.开发 2.实施 3.服务
+	type?:string;
+	//项目档案id
+	proId?:string;
+	//项目档案编码
+	proCode?:string;
+	//项目档案名称
+	proName?:string;
+	//客户档案id
+	cusId?:string;
+	//客户编码
+    cusCode?:string;
+    //客户名称
+    cusName?:string;
+	//里程碑id
+	mileId?:string;
+	//里程碑(计划)
+	mileName?:string;
+	//里程碑确认(0,未确认 1,确认)
+	mileConfirm?:number;
+	//确认时间
+	confirmTime?:string;
+	//工作内容
+	content?:string;
+	//工作时长
+	duration?:number;
+	//填写人(当前用户)
+	currentUser?:string;
+	//组织
+	pkOrg?:string;
+
+}

+ 1 - 0
src/app/routes/project-manage-archives/add/add.component.ts

@@ -282,6 +282,7 @@ export class ProjectManageArchivesAddComponent implements OnInit {
             });
           });
         }
+        element.muilesId = element.id;
         element.muilesName = element.name;
         element.keyId = element.key;
         element.executor = names;

+ 2 - 2
src/app/routes/project-manage-archives/update/development/development.component.html

@@ -96,10 +96,10 @@
                   (nzExpandChange)="collapse(mapOfExpandedData[data.key], item, $event)">
                 </td>
                 <td>
-                  <ng-container *ngIf="item.id">
+                  <ng-container *ngIf="item.muilesId">
                     {{ item.muilesName }}
                   </ng-container>
-                  <ng-container *ngIf="!item.id">
+                  <ng-container *ngIf="!item.muilesId">
                     <input nz-input [(ngModel)]="item.muilesName" />
                   </ng-container>
                 </td>

+ 2 - 2
src/app/routes/project-manage-archives/update/implementation/implementation.component.html

@@ -96,10 +96,10 @@
                   (nzExpandChange)="collapse(mapOfExpandedData[data.key], item, $event)">
                 </td>
                 <td>
-                  <ng-container *ngIf="item.id">
+                  <ng-container *ngIf="item.muilesId">
                     {{ item.muilesName }}
                   </ng-container>
-                  <ng-container *ngIf="!item.id">
+                  <ng-container *ngIf="!item.muilesId">
                     <input nz-input [(ngModel)]="item.muilesName" />
                   </ng-container>
                 </td>

+ 2 - 2
src/app/routes/project-manage-archives/update/serviceta/serviceta.component.html

@@ -96,10 +96,10 @@
                   (nzExpandChange)="collapse(mapOfExpandedData[data.key], item, $event)">
                 </td>
                 <td>
-                  <ng-container *ngIf="item.id">
+                  <ng-container *ngIf="item.muilesId">
                     {{ item.muilesName }}
                   </ng-container>
-                  <ng-container *ngIf="!item.id">
+                  <ng-container *ngIf="!item.muilesId">
                     <input nz-input [(ngModel)]="item.muilesName" />
                   </ng-container>
                 </td>

+ 109 - 0
src/app/routes/project-work/development-log/add/add.component.html

@@ -0,0 +1,109 @@
+<nz-spin [nzSpinning]="isLoadingSave">
+  <form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="code">单据编码</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <input placeholder="自动生成" nz-input formControlName="billcode" id="billcode"
+              [(ngModel)]="proWorkLogic.billcode" [disabled]="true" />
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>项目名称</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <nz-select style="widows: 100%;" nzShowSearch nzAllowClear formControlName="proId" id="proId"
+              [(ngModel)]="proWorkLogic.proId" nzPlaceHolder="请选择" (ngModelChange)="proChange($event)">
+              <nz-option *ngFor="let i of proList" [nzValue]="i.id" [nzLabel]="i.proName"></nz-option>
+            </nz-select>
+            <nz-form-explain *ngIf="validateForm.get('proId')?.dirty && validateForm.get('proId')?.errors">
+              请选择项目名称
+            </nz-form-explain>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>汇报人</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <nz-tree-select style="width: 100%" [nzNodes]="personnelList" nzShowSearch [nzMultiple]="false"
+              formControlName="reporterId" id="reporterId" nzPlaceHolder="请选择" [(ngModel)]="proWorkLogic.reporterId"
+              [nzMaxTagCount]="3" [nzAllowClear]="true">
+            </nz-tree-select>
+            <nz-form-explain *ngIf="validateForm.get('proId')?.dirty && validateForm.get('proId')?.errors">
+              请选择汇报人
+            </nz-form-explain>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>开始时间</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <nz-range-picker [nzShowTime]="true" formControlName="date" id="date" [(ngModel)]="date"></nz-range-picker>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+  </form>
+  <nz-card>
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="24">
+        <!-- 新增按钮 -->
+        <button (click)="addRow()" nz-button nzType="primary">{{ 'button.add' | translate }}</button>
+      </div>
+    </div>
+
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="24">
+        <nz-table style="padding-top: 5px;" nzSize="small" class="tableTdPadding" #basicTable [nzData]="itemList"
+          [nzFrontPagination]="false" [nzShowPagination]="false">
+          <thead>
+            <tr>
+              <th nzAlign="center" style="width: 5%;">序号</th>
+              <th style="width: 30%;">里程碑</th>
+              <th style="width: 50%;">工作内容</th>
+              <th style="width: 5%;">工作用时</th>
+              <th style="width: 10%;">操作</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr *ngFor="let data of basicTable.data;let i =index">
+              <td nzAlign="center">{{i+1}}</td>
+              <td>
+                <nz-tree-select style="width: 100%" [nzNodes]="mieList" nzShowSearch [nzMultiple]="false"
+                  nzPlaceHolder="请选择" [(ngModel)]="data.proArchivesId" [nzMaxTagCount]="3" [nzAllowClear]="true" (ngModelChange)="proArchivesIdChange(data)">
+                </nz-tree-select >
+              </td>
+              <td>
+                <textarea rows="1" nz-input [(ngModel)]="data.content"></textarea>
+              </td>
+              <td style="width: 10%;">
+                <nz-input-number [(ngModel)]="data.duration" [nzMin]="0" [nzStep]="1"></nz-input-number>
+              </td>
+              <td>
+                <a nz-popconfirm nzTitle="是否删除?" (nzOnConfirm)="deleteRow(data.sort)">{{'table.delete'|translate}}</a>
+              </td>
+            </tr>
+          </tbody>
+        </nz-table>
+      </div>
+    </div>
+  </nz-card>
+</nz-spin>
+<!-- 按钮 -->
+<div class="base">
+  <strong>填写人:</strong>{{proWorkLogic.currentUser}} <strong>填写时间:</strong>{{proWorkLogic.createTime}}
+  <!-- 关闭按钮 -->
+  <a nz-popconfirm nzTitle="{{'pm.contract.contract.add.button.cancel'|translate}}" (nzOnConfirm)="close()"
+    style="padding-right: 8px">
+    <button nz-button>{{'pm.quotation.cancel'|translate}}</button>
+  </a>
+  <!-- 保存按钮 -->
+  <button nz-button nzType="primary" class="ant-btn ant-btn-primary" (click)="submitForm()"
+    [nzLoading]="isLoadingSave"><span>{{'pm.finish' | translate}}</span></button>
+</div>

+ 24 - 0
src/app/routes/project-work/development-log/add/add.component.spec.ts

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

+ 287 - 0
src/app/routes/project-work/development-log/add/add.component.ts

@@ -0,0 +1,287 @@
+import { Component, OnInit } from '@angular/core';
+import { NzModalRef, NzMessageService, NzNotificationService, NzDrawerRef } from 'ng-zorro-antd';
+import { _HttpClient, SettingsService } from '@delon/theme';
+import { FormBuilder, Validators, FormGroup } from '@angular/forms';
+import { DatePipe } from '@angular/common';
+import { ProjectManageArchivesService } from 'app/services/project-manage-archives/project-manage-archives.service';
+import { PersonnelService } from 'app/services/basedata/personnel.service';
+import { ProWorkLogicService } from 'app/services/project-work/pro-work-logic.service';
+import { I18NService } from '@core';
+import { ProWorkLogic } from 'app/entity/project-work/pro-work-logic';
+import { ProjectManageArchives } from 'app/entity/project-manage-archives/project-manage-archives';
+import { recursiveQuery } from '@shared';
+
+@Component({
+  selector: 'app-project-work-development-log-add',
+  templateUrl: './add.component.html',
+  styles: [
+    `
+      .base {
+        position: absolute;
+        bottom: 0px;
+        width: 100%;
+        border-top: 1px solid rgb(232, 232, 232);
+        padding: 6px 16px;
+        text-align: right;
+        left: 0px;
+        background: #fff;
+        z-index: 99;
+      }
+    `,
+  ]
+})
+export class ProjectWorkDevelopmentLogAddComponent implements OnInit {
+  constructor(
+    private fb: FormBuilder,
+    private settingsService: SettingsService,
+    private datePipe: DatePipe,
+    private projectManageArchivesService: ProjectManageArchivesService,
+    private personnelService: PersonnelService,
+    private proWorkLogicService: ProWorkLogicService,
+    private nzNotificationService: NzNotificationService,
+    private i18NService: I18NService,
+    private drawerRef: NzDrawerRef,
+  ) {}
+
+  ngOnInit(): void {
+    //初始化表单
+    this.validateForm = this.fb.group({
+      billcode: [{ value: '', disabled: true }],
+      proId: [null, [Validators.required]],
+      date: [null, [Validators.required]],
+      reporterId: [null, [Validators.required]],
+    });
+    //项目下拉
+    this.isLoadingSave = true;
+    this.getProList()
+      .then(() => {
+        //人员下来数据
+        return this.getPersonnelList();
+      })
+      .then(() => {
+        this.isLoadingSave = false;
+      });
+  }
+
+  isLoadingSave = false;
+  validateForm!: FormGroup;
+  proWorkLogic: ProWorkLogic = {
+    currentUser: this.settingsService.user.realname,
+    createTime: this.datePipe.transform(new Date(), 'yyyy-MM-dd HH:mm:ss'),
+  }; //对象
+  proList = []; //项目下拉数据
+  personnelList = []; //汇报人下拉数据
+  itemList = []; //明细集合
+  mieList = []; //里程碑数据下拉
+  date = null;
+
+  /**
+   * 获取项目下拉数据
+   */
+  getProList() {
+    return new Promise(resolve => {
+      let projectManageArchives = new ProjectManageArchives();
+      projectManageArchives.pageSize = 20000;
+      projectManageArchives.pkOrg = sessionStorage.getItem('pkOrg');
+      this.projectManageArchivesService.getList(projectManageArchives).then(response => {
+        if (response.result.records) {
+          this.proList = response.result.records;
+        }
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 项目下拉选择事件
+   */
+  proChange(event) {
+    this.getMieList(event);
+  }
+
+  /**
+   * 获取汇报人下拉数据
+   */
+  getPersonnelList() {
+    return new Promise(resolve => {
+      this.personnelService.queryApprover(sessionStorage.getItem('pkOrg')).then(response => {
+        if (response.result) {
+          this.personnelList = JSON.parse(JSON.stringify(response.result));
+        }
+        recursiveQuery(this.personnelList);
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 里程碑数据下拉
+   */
+  getMieList(proArchivesId) {
+    return new Promise(resolve => {
+      let plan = { id: proArchivesId, planType: '3' };
+      this.projectManageArchivesService.getPlanListById(plan).then(response => {
+        if (response.result) {
+          this.mieList = response.result;
+        }
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 里程碑选择事件
+   */
+  proArchivesIdChange(data) {
+    console.log(data.proArchivesId);
+    //是否选择里程碑
+    if (data.proArchivesId) {
+      this.getChild(this.mieList, data);
+    } else {
+      data.proArchivesMilestone = '';
+      data.proArchivesId = '';
+    }
+  }
+
+  /**
+   * 递归查询名称
+   */
+  getChild(mieList, data) {
+    mieList.forEach(element => {
+      if (element.key === data.proArchivesId) {
+        data.proArchivesMilestone = element.title;
+        data.proArchivesId = element.key;
+        data.proPlanId=element.id;
+      } else {
+        if (element.children) {
+          this.getChild(element.children, data);
+        }
+      }
+    });
+  }
+
+  /**
+   * 增行按钮
+   */
+  sort = 0;
+  addRow() {
+    this.itemList = [
+      ...this.itemList,
+      {
+        sort: this.sort,
+      },
+    ];
+    this.sort++;
+  }
+
+  /**
+   * 删除行
+   */
+  deleteRow(sort) {
+    this.itemList = this.itemList.filter(d => d.sort !== sort);
+  }
+
+  /**
+   * 保存按钮
+   */
+  submitForm(): any {
+    return new Promise(resolve => {
+      for (const i in this.validateForm.controls) {
+        this.validateForm.controls[i].markAsDirty();
+        this.validateForm.controls[i].updateValueAndValidity();
+      }
+      let valid = this.validateForm.valid;
+      if (valid) {
+        this.isLoadingSave = true;
+        this.proWorkLogic.type = '1'; //开发
+        this.proWorkLogic.pkOrg = sessionStorage.getItem('pkOrg');
+        //项目名称
+        if (this.proWorkLogic.proId) {
+          this.proList.forEach(element => {
+            if (element.id === this.proWorkLogic.proId) {
+              this.proWorkLogic.proName = element.proName;
+            }
+          });
+        } else {
+          this.proWorkLogic.proName = '';
+        }
+        //汇报人名称
+        if (this.proWorkLogic.reporterId) {
+          //循环集合数据获取名称
+          this.personnelList.forEach(pkOrg => {
+            pkOrg.children.forEach(depart => {
+              depart.children.forEach(personnel => {
+                if (personnel.key === this.proWorkLogic.reporterId) {
+                  this.proWorkLogic.reporter = personnel.name;
+                }
+              });
+            });
+          });
+        } else {
+          this.proWorkLogic.reporter = '';
+        }
+        //时间格式化
+        this.proWorkLogic.startDate = this.datePipe.transform(this.date[0], 'yyyy-MM-dd HH:mm:ss');
+        this.proWorkLogic.endDate = this.datePipe.transform(this.date[1], 'yyyy-MM-dd HH:mm:ss');
+        //判断两个时间差的工时是否大于明细总工时
+        if(!this.getHourBoole()){
+          this.nzNotificationService.warning("工作用时不得大于开始时间与结束时间之差","");
+          this.isLoadingSave=false;
+          return;
+        }
+        //子表\
+        //判断是否输入子表数据
+        if (this.itemList && this.itemList.length > 0) {
+          this.proWorkLogic.detailList = this.itemList;
+        } else {
+          this.nzNotificationService.warning('工作内容必填', '');
+          this.isLoadingSave=false;
+          return;
+        }
+        this.proWorkLogicService.add(this.proWorkLogic).then(response => {
+          if (response.success) {
+            //保存成功
+            this.isLoadingSave = false;
+            this.nzNotificationService.success(this.i18NService.fanyi('save.ok'), '');
+            this.drawerRef.close(true);
+            resolve();
+          } else {
+            //保存失败
+            this.isLoadingSave = false;
+            this.nzNotificationService.error(this.i18NService.fanyi('save.not'), '');
+          }
+        });
+      }
+    });
+  }
+
+  /**
+   * 判断两个时间差的工时是否大于明细总工时
+   */
+  getHourBoole():boolean{
+    //明细总工时
+    let itemHour=0;
+    //两个时间差
+    let dateHour=this.getInervalHour(this.date[0], this.date[1]);
+    //循环获取明细的总工时
+    this.itemList.forEach(element => {
+      if(element.duration){
+        itemHour=itemHour+Number(element.duration);
+      }
+    });
+    return dateHour>=itemHour;
+  }
+
+  /**
+   * 获取两个时间差
+   */
+  getInervalHour(startDate, endDate) {
+    var ms = endDate.getTime() - startDate.getTime();
+    if (ms < 0) return 0;
+    return Math.floor(ms / 1000 / 60 / 60);
+  }
+
+  close() {
+    this.drawerRef.close();
+  }
+}

+ 64 - 0
src/app/routes/project-work/development-log/development-log.component.html

@@ -0,0 +1,64 @@
+<page-header [action]="phActionTpl">
+  <ng-template #phActionTpl>
+    <button (click)="add()" nz-button nzType="primary" acl [acl-ability]="'development-log:add'">新建</button>
+  </ng-template>
+</page-header>
+<nz-card>
+  <!-- 查询条件 -->
+  <form nz-form>
+    <div nz-row [nzGutter]="{ xs: 8, sm: 16, md: 24, lg: 32 }">
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24">单据编码</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <input nz-input name="code" [(ngModel)]="proWorkLogic.billcode" />
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="2" [nzXs]="24" [nzNoColon]=true></nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <button nzType="primary" (click)="query()" nz-button><span>查询</span></button>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+  </form>
+   <!-- 表格 -->
+   <div nz-row [nzGutter]="{ xs: 8, sm: 16, md: 24, lg: 32 }">
+    <div nz-col [nzSpan]="24">
+      <nz-table nzSize="small" #basicTable [nzData]="listOfData" [nzFrontPagination]="false" [nzTotal]="page.total"
+        [nzPageIndex]="page.current" (nzPageIndexChange)="pageIndexChange($event)" [nzLoading]="isSpinning">
+        <thead>
+          <tr>
+            <th>单据编码</th>
+            <th>项目名称</th>
+            <th>开始时间</th>
+            <th>结束时间</th>
+            <th>汇报人</th>
+            <th>填写人</th>
+            <th>填写时间</th>
+            <th>操作</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr *ngFor="let data of basicTable.data">
+            <td>{{ data.billcode }}</td>
+            <td>{{ data.proName }}</td>
+            <td>{{ data.startDate }}</td>
+            <td>{{ data.endDate }}</td>
+            <td>{{ data.reporter }}</td>
+            <td>{{ data.currentUser }}</td>
+            <td>{{ data.createTime }}</td>
+            <td>
+              <a (click)="update(data)" acl [acl-ability]="'development-log:update'">修改</a>
+              <nz-divider nzType="vertical" acl [acl-ability]="'development-log:update'"></nz-divider>
+              <a (click)="delete(data.id)" acl [acl-ability]="'development-log:delete'">删除</a>
+            </td>
+          </tr>
+        </tbody>
+      </nz-table>
+    </div>
+  </div>
+</nz-card>

+ 24 - 0
src/app/routes/project-work/development-log/development-log.component.spec.ts

@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ProjectWorkDevelopmentLogComponent } from './development-log.component';
+
+describe('ProjectWorkDevelopmentLogComponent', () => {
+  let component: ProjectWorkDevelopmentLogComponent;
+  let fixture: ComponentFixture<ProjectWorkDevelopmentLogComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ ProjectWorkDevelopmentLogComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ProjectWorkDevelopmentLogComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 126 - 0
src/app/routes/project-work/development-log/development-log.component.ts

@@ -0,0 +1,126 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { _HttpClient, ModalHelper } from '@delon/theme';
+import { STColumn, STComponent } from '@delon/abc';
+import { SFSchema } from '@delon/form';
+import { ProWorkLogicService } from 'app/services/project-work/pro-work-logic.service';
+import { NzDrawerService, NzNotificationService } from 'ng-zorro-antd';
+import { I18NService } from '@core';
+import { ProWorkLogic } from 'app/entity/project-work/pro-work-logic';
+import { ProjectWorkDevelopmentLogAddComponent } from './add/add.component';
+import { ProjectWorkDevelopmentLogUpdateComponent } from './update/update.component';
+
+@Component({
+  selector: 'app-project-work-development-log',
+  templateUrl: './development-log.component.html',
+})
+export class ProjectWorkDevelopmentLogComponent implements OnInit {
+  constructor(
+    private proWorkLogicService:ProWorkLogicService,
+    private nzDrawerService:NzDrawerService,
+    private i18NService:I18NService,
+    private nzNotificationService:NzNotificationService
+  ) {}
+
+  ngOnInit() {
+    this.getList();
+  }
+  listOfData = [];
+  proWorkLogic: ProWorkLogic = {}; //对象
+  page = {
+    total: 0,
+    current: 0,
+  }; //页码
+  isSpinning = false;
+
+  //按页码显示数据
+  pageIndexChange(event) {
+    this.proWorkLogic.pageNo = event; //当前页码
+    this.getList();
+  }
+
+  /**
+   * 查询数据表
+   */
+  getList() {
+    // this.isSpinning=true;
+    this.proWorkLogic.pkOrg = sessionStorage.getItem('pkOrg'); //组织
+    this.proWorkLogic.type="1";
+    this.proWorkLogicService.getList(this.proWorkLogic).then(response => {
+      this.listOfData = response.result.records;
+    });
+  }
+
+  /**
+   * 查询按钮
+   */
+  query() {
+    this.proWorkLogic.pageNo = 1;
+    this.getList();
+  }
+  
+  /**
+   * 新增按钮
+   */
+  add() {
+    const drawerRef = this.nzDrawerService.create<ProjectWorkDevelopmentLogAddComponent, { quotationId: string }, string>({
+      nzTitle: this.i18NService.fanyi("button.add"),//新增标题
+      nzContent: ProjectWorkDevelopmentLogAddComponent,
+      nzWidth: window.innerWidth,
+      nzBodyStyle: { height: 'calc(100% - 55px)', overflow: 'auto', 'padding-bottom': '53px' }
+      // nzContentParams: {
+      //   //模板id
+      //   quotationId: item.id
+      // }
+    });
+
+    //关闭抽屉的回调
+    drawerRef.afterClose.subscribe((isRefresh) => {
+      if (isRefresh) {//刷新list列表
+        this.getList();
+      }
+    });
+  }
+
+  /**
+   * 修改
+   * @param data 修改对象
+   */
+  update(data){
+    const drawerRef = this.nzDrawerService.create<ProjectWorkDevelopmentLogUpdateComponent, { id: string }, string>({
+      nzTitle: this.i18NService.fanyi("table.update"),//新增标题
+      nzContent: ProjectWorkDevelopmentLogUpdateComponent,
+      nzWidth: window.innerWidth,
+      nzBodyStyle: { height: 'calc(100% - 55px)', overflow: 'auto', 'padding-bottom': '53px' },
+      nzContentParams: {
+        //模板id
+        id: data.id
+      }
+    });
+
+    //关闭抽屉的回调
+    drawerRef.afterClose.subscribe((isRefresh) => {
+      if (isRefresh) {//刷新list列表
+        this.getList();
+      }
+    });
+  }
+
+  /**
+   * 删除
+   * @param id 
+   */
+  delete(id){
+    let proWorkLogic=new ProWorkLogic();
+    proWorkLogic.id=id;
+    this.proWorkLogicService.delete(proWorkLogic).then((response)=>{
+      if (response.success) {
+        //删除成功
+        this.nzNotificationService.success(this.i18NService.fanyi('successful.deletion'), '');
+        this.getList();
+      } else {
+        //删除失败
+        this.nzNotificationService.error(this.i18NService.fanyi('delete.failed'), '');
+      }
+    })
+  }
+}

+ 110 - 0
src/app/routes/project-work/development-log/update/update.component.html

@@ -0,0 +1,110 @@
+<nz-spin [nzSpinning]="isLoadingSave">
+  <form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="code">单据编码</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <input placeholder="自动生成" nz-input formControlName="billcode" id="billcode"
+              [(ngModel)]="proWorkLogic.billcode" [disabled]="true" />
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>项目名称</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <nz-select style="widows: 100%;" nzShowSearch nzAllowClear formControlName="proId" id="proId"
+              [(ngModel)]="proWorkLogic.proId" nzPlaceHolder="请选择" (ngModelChange)="proChange($event)">
+              <nz-option *ngFor="let i of proList" [nzValue]="i.id" [nzLabel]="i.proName"></nz-option>
+            </nz-select>
+            <nz-form-explain *ngIf="validateForm.get('proId')?.dirty && validateForm.get('proId')?.errors">
+              请选择项目名称
+            </nz-form-explain>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>汇报人</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <nz-tree-select style="width: 100%" [nzNodes]="personnelList" nzShowSearch [nzMultiple]="false"
+              formControlName="reporterId" id="reporterId" nzPlaceHolder="请选择" [(ngModel)]="proWorkLogic.reporterId"
+              [nzMaxTagCount]="3" [nzAllowClear]="true">
+            </nz-tree-select>
+            <nz-form-explain *ngIf="validateForm.get('proId')?.dirty && validateForm.get('proId')?.errors">
+              请选择汇报人
+            </nz-form-explain>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>开始时间</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <nz-range-picker [nzShowTime]="true" formControlName="date" id="date" [(ngModel)]="date"></nz-range-picker>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+  </form>
+  <nz-card>
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="24">
+        <!-- 新增按钮 -->
+        <button (click)="addRow()" nz-button nzType="primary">{{ 'button.add' | translate }}</button>
+      </div>
+    </div>
+
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="24">
+        <nz-table style="padding-top: 5px;" nzSize="small" class="tableTdPadding" #basicTable [nzData]="itemList"
+          [nzFrontPagination]="false" [nzShowPagination]="false">
+          <thead>
+            <tr>
+              <th nzAlign="center" style="width: 5%;">序号</th>
+              <th style="width: 30%;">里程碑</th>
+              <th style="width: 50%;">工作内容</th>
+              <th style="width: 5%;">工作用时</th>
+              <th style="width: 10%;">操作</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr *ngFor="let data of basicTable.data;let i =index">
+              <td nzAlign="center">{{i+1}}</td>
+              <td>
+                <nz-tree-select style="width: 100%" [nzNodes]="mieList" nzShowSearch [nzMultiple]="false"
+                  nzPlaceHolder="请选择" [(ngModel)]="data.proArchivesId" [nzMaxTagCount]="3" [nzAllowClear]="true"
+                  (ngModelChange)="proArchivesIdChange(data)">
+                </nz-tree-select>
+              </td>
+              <td>
+                <textarea rows="1" nz-input [(ngModel)]="data.content"></textarea>
+              </td>
+              <td style="width: 10%;">
+                <nz-input-number [(ngModel)]="data.duration" [nzMin]="0" [nzStep]="1"></nz-input-number>
+              </td>
+              <td>
+                <a nz-popconfirm nzTitle="是否删除?" (nzOnConfirm)="deleteRow(data.sort)">{{'table.delete'|translate}}</a>
+              </td>
+            </tr>
+          </tbody>
+        </nz-table>
+      </div>
+    </div>
+  </nz-card>
+</nz-spin>
+<!-- 按钮 -->
+<div class="base">
+  <strong>填写人:</strong>{{proWorkLogic.currentUser}} <strong>填写时间:</strong>{{proWorkLogic.createTime}}
+  <!-- 关闭按钮 -->
+  <a nz-popconfirm nzTitle="{{'pm.contract.contract.add.button.cancel'|translate}}" (nzOnConfirm)="close()"
+    style="padding-right: 8px">
+    <button nz-button>{{'pm.quotation.cancel'|translate}}</button>
+  </a>
+  <!-- 保存按钮 -->
+  <button nz-button nzType="primary" class="ant-btn ant-btn-primary" (click)="submitForm()"
+    [nzLoading]="isLoadingSave"><span>{{'pm.finish' | translate}}</span></button>
+</div>

+ 24 - 0
src/app/routes/project-work/development-log/update/update.component.spec.ts

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

+ 311 - 0
src/app/routes/project-work/development-log/update/update.component.ts

@@ -0,0 +1,311 @@
+import { Component, OnInit } from '@angular/core';
+import { NzModalRef, NzMessageService, NzNotificationService, NzDrawerRef } from 'ng-zorro-antd';
+import { _HttpClient, SettingsService } from '@delon/theme';
+import { FormBuilder, Validators, FormGroup } from '@angular/forms';
+import { DatePipe } from '@angular/common';
+import { ProjectManageArchivesService } from 'app/services/project-manage-archives/project-manage-archives.service';
+import { PersonnelService } from 'app/services/basedata/personnel.service';
+import { ProWorkLogicService } from 'app/services/project-work/pro-work-logic.service';
+import { I18NService } from '@core';
+import { ProWorkLogic } from 'app/entity/project-work/pro-work-logic';
+import { ProjectManageArchives } from 'app/entity/project-manage-archives/project-manage-archives';
+import { recursiveQuery } from '@shared';
+
+@Component({
+  selector: 'app-project-work-development-log-update',
+  templateUrl: './update.component.html',
+  styles: [
+    `
+      .base {
+        position: absolute;
+        bottom: 0px;
+        width: 100%;
+        border-top: 1px solid rgb(232, 232, 232);
+        padding: 6px 16px;
+        text-align: right;
+        left: 0px;
+        background: #fff;
+        z-index: 99;
+      }
+    `,
+  ],
+})
+export class ProjectWorkDevelopmentLogUpdateComponent implements OnInit {
+  constructor(
+    private fb: FormBuilder,
+    private settingsService: SettingsService,
+    private datePipe: DatePipe,
+    private projectManageArchivesService: ProjectManageArchivesService,
+    private personnelService: PersonnelService,
+    private proWorkLogicService: ProWorkLogicService,
+    private nzNotificationService: NzNotificationService,
+    private i18NService: I18NService,
+    private drawerRef: NzDrawerRef,
+  ) {}
+
+  ngOnInit(): void {
+    //初始化表单
+    this.validateForm = this.fb.group({
+      billcode: [{ value: '', disabled: true }],
+      proId: [null, [Validators.required]],
+      date: [null, [Validators.required]],
+      reporterId: [null, [Validators.required]],
+    });
+    //项目下拉
+    this.isLoadingSave = true;
+    this.getProList()
+      .then(() => {
+        //人员下来数据
+        return this.getPersonnelList();
+      }).then(()=>{
+        //根据id查询
+        return this.getById();
+      })
+      .then(() => {
+        this.isLoadingSave = false;
+      });
+  }
+
+  isLoadingSave = false;
+  validateForm!: FormGroup;
+  proWorkLogic: ProWorkLogic = {
+  }; //对象
+  proList = []; //项目下拉数据
+  personnelList = []; //汇报人下拉数据
+  itemList = []; //明细集合
+  mieList = []; //里程碑数据下拉
+  date = null;
+  id="";
+
+  /**
+   * 根据id查询
+   */
+  getById(){
+    return new Promise((resolve)=>{
+      this.proWorkLogicService.getListById(this.id).then((response)=>{
+        if(response.result){
+          this.proWorkLogic=response.result;//主表对象
+          this.itemList=response.result.detailList;//明细数组
+          //最大排序
+          if(this.itemList){
+            this.sort=this.itemList.length+1;
+          }
+          //开始时间-结束时间
+          this.date=[new Date(this.proWorkLogic.startDate),new Date(this.proWorkLogic.endDate)]
+        }
+        resolve();
+      })
+    })
+  }
+
+  /**
+   * 获取项目下拉数据
+   */
+  getProList() {
+    return new Promise(resolve => {
+      let projectManageArchives = new ProjectManageArchives();
+      projectManageArchives.pageSize = 20000;
+      projectManageArchives.pkOrg = sessionStorage.getItem('pkOrg');
+      this.projectManageArchivesService.getList(projectManageArchives).then(response => {
+        if (response.result.records) {
+          this.proList = response.result.records;
+        }
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 项目下拉选择事件
+   */
+  proChange(event) {
+    this.getMieList(event);
+  }
+
+  /**
+   * 获取汇报人下拉数据
+   */
+  getPersonnelList() {
+    return new Promise(resolve => {
+      this.personnelService.queryApprover(sessionStorage.getItem('pkOrg')).then(response => {
+        if (response.result) {
+          this.personnelList = JSON.parse(JSON.stringify(response.result));
+        }
+        recursiveQuery(this.personnelList);
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 里程碑数据下拉
+   */
+  getMieList(proArchivesId) {
+    return new Promise(resolve => {
+      let plan = { id: proArchivesId, planType: '3' };
+      this.projectManageArchivesService.getPlanListById(plan).then(response => {
+        if (response.result) {
+          this.mieList = response.result;
+        }
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 里程碑选择事件
+   */
+  proArchivesIdChange(data) {
+    console.log(data.proArchivesId);
+    //是否选择里程碑
+    if (data.proArchivesId) {
+      this.getChild(this.mieList, data);
+    } else {
+      data.proArchivesMilestone = '';
+      data.proArchivesId = '';
+    }
+  }
+
+  /**
+   * 递归查询名称
+   */
+  getChild(mieList, data) {
+    mieList.forEach(element => {
+      if (element.key === data.proArchivesId) {
+        data.proArchivesMilestone = element.title;
+        data.proArchivesId = element.key;
+        data.proPlanId=element.id;
+      } else {
+        if (element.children) {
+          this.getChild(element.children, data);
+        }
+      }
+    });
+  }
+
+  /**
+   * 增行按钮
+   */
+  sort = 0;
+  addRow() {
+    this.itemList = [
+      ...this.itemList,
+      {
+        sort: this.sort,
+      },
+    ];
+    this.sort++;
+  }
+
+  /**
+   * 删除行
+   */
+  deleteRow(sort) {
+    this.itemList = this.itemList.filter(d => d.sort !== sort);
+  }
+
+  /**
+   * 保存按钮
+   */
+  submitForm(): any {
+    return new Promise(resolve => {
+      for (const i in this.validateForm.controls) {
+        this.validateForm.controls[i].markAsDirty();
+        this.validateForm.controls[i].updateValueAndValidity();
+      }
+      let valid = this.validateForm.valid;
+      if (valid) {
+        this.isLoadingSave = true;
+        
+        // this.proWorkLogic.type = '1'; //实施
+        this.proWorkLogic.pkOrg = sessionStorage.getItem('pkOrg');
+        //项目名称
+        if (this.proWorkLogic.proId) {
+          this.proList.forEach(element => {
+            if (element.id === this.proWorkLogic.proId) {
+              this.proWorkLogic.proName = element.proName;
+            }
+          });
+        } else {
+          this.proWorkLogic.proName = '';
+        }
+        //汇报人名称
+        if (this.proWorkLogic.reporterId) {
+          //循环集合数据获取名称
+          this.personnelList.forEach(pkOrg => {
+            pkOrg.children.forEach(depart => {
+              depart.children.forEach(personnel => {
+                if (personnel.key === this.proWorkLogic.reporterId) {
+                  this.proWorkLogic.reporter = personnel.name;
+                }
+              });
+            });
+          });
+        } else {
+          this.proWorkLogic.reporter = '';
+        }
+        //时间格式化
+        this.proWorkLogic.startDate = this.datePipe.transform(this.date[0], 'yyyy-MM-dd HH:mm:ss');
+        this.proWorkLogic.endDate = this.datePipe.transform(this.date[1], 'yyyy-MM-dd HH:mm:ss');
+        //判断两个时间差的工时是否大于明细总工时
+        if (!this.getHourBoole()) {
+          this.nzNotificationService.warning('工作用时不得大于开始时间与结束时间之差', '');
+          this.isLoadingSave = false;
+          return;
+        }
+        //子表\
+        //判断是否输入子表数据
+        if (this.itemList && this.itemList.length > 0) {
+          this.proWorkLogic.detailList = this.itemList;
+        } else {
+          this.nzNotificationService.warning('工作内容必填', '');
+          this.isLoadingSave = false;
+          return;
+        }
+        this.proWorkLogicService.update(this.proWorkLogic).then(response => {
+          if (response.success) {
+            //保存成功
+            this.isLoadingSave = false;
+            this.nzNotificationService.success(this.i18NService.fanyi('save.ok'), '');
+            this.drawerRef.close(true);
+            resolve();
+          } else {
+            //保存失败
+            this.isLoadingSave = false;
+            this.nzNotificationService.error(this.i18NService.fanyi('save.not'), '');
+          }
+        });
+      }
+    });
+  }
+
+  /**
+   * 判断两个时间差的工时是否大于明细总工时
+   */
+  getHourBoole(): boolean {
+    //明细总工时
+    let itemHour = 0;
+    //两个时间差
+    let dateHour = this.getInervalHour(this.date[0], this.date[1]);
+    //循环获取明细的总工时
+    this.itemList.forEach(element => {
+      if (element.duration) {
+        itemHour = itemHour + Number(element.duration);
+      }
+    });
+    return dateHour >= itemHour;
+  }
+
+  /**
+   * 获取两个时间差
+   */
+  getInervalHour(startDate, endDate) {
+    var ms = endDate.getTime() - startDate.getTime();
+    if (ms < 0) return 0;
+    return Math.floor(ms / 1000 / 60 / 60);
+  }
+
+  close() {
+    this.drawerRef.close();
+  }
+}

+ 2 - 2
src/app/routes/project-work/implementation-log/add/add.component.html

@@ -12,14 +12,14 @@
       </div>
       <div nz-col [nzSpan]="8">
         <nz-form-item>
-          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>项目</nz-form-label>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>项目名称</nz-form-label>
           <nz-form-control [nzSm]="14" [nzXs]="24">
             <nz-select style="widows: 100%;" nzShowSearch nzAllowClear formControlName="proId" id="proId"
               [(ngModel)]="proWorkLogic.proId" nzPlaceHolder="请选择" (ngModelChange)="proChange($event)">
               <nz-option *ngFor="let i of proList" [nzValue]="i.id" [nzLabel]="i.proName"></nz-option>
             </nz-select>
             <nz-form-explain *ngIf="validateForm.get('proId')?.dirty && validateForm.get('proId')?.errors">
-              请选择项目
+              请选择项目名称
             </nz-form-explain>
           </nz-form-control>
         </nz-form-item>

+ 2 - 1
src/app/routes/project-work/implementation-log/add/add.component.ts

@@ -150,7 +150,8 @@ export class ProjectWorkImplementationLogAddComponent implements OnInit {
     mieList.forEach(element => {
       if (element.key === data.proArchivesId) {
         data.proArchivesMilestone = element.title;
-        data.proArchivesId = element.id;
+        data.proArchivesId = element.key;
+        data.proPlanId=element.id;
       } else {
         if (element.children) {
           this.getChild(element.children, data);

+ 32 - 5
src/app/routes/project-work/implementation-log/implementation-log.component.html

@@ -1,9 +1,30 @@
 <page-header [action]="phActionTpl">
   <ng-template #phActionTpl>
-    <button (click)="add()" nz-button nzType="primary">新建</button>
+    <button (click)="add()" nz-button nzType="primary" acl [acl-ability]="'url:implementation-log:add'">新建</button>
   </ng-template>
 </page-header>
 <nz-card>
+  <!-- 查询条件 -->
+  <form nz-form>
+    <div nz-row [nzGutter]="{ xs: 8, sm: 16, md: 24, lg: 32 }">
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24">单据编码</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <input nz-input name="code" [(ngModel)]="proWorkLogic.billcode" />
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="2" [nzXs]="24" [nzNoColon]=true></nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <button nzType="primary" (click)="query()" nz-button><span>查询</span></button>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+  </form>
    <!-- 表格 -->
    <div nz-row [nzGutter]="{ xs: 8, sm: 16, md: 24, lg: 32 }">
     <div nz-col [nzSpan]="24">
@@ -12,9 +33,12 @@
         <thead>
           <tr>
             <th>单据编码</th>
-            <th>项目</th>
+            <th>项目名称</th>
             <th>开始时间</th>
             <th>结束时间</th>
+            <th>汇报人</th>
+            <th>填写人</th>
+            <th>填写时间</th>
             <th>操作</th>
           </tr>
         </thead>
@@ -24,10 +48,13 @@
             <td>{{ data.proName }}</td>
             <td>{{ data.startDate }}</td>
             <td>{{ data.endDate }}</td>
+            <td>{{ data.reporter }}</td>
+            <td>{{ data.currentUser }}</td>
+            <td>{{ data.createTime }}</td>
             <td>
-              <a (click)="update(data)" acl [acl-ability]="'base-archives-cost:update'">修改</a>
-              <nz-divider nzType="vertical" acl [acl-ability]="'base-archives-cost:update'"></nz-divider>
-              <a (click)="delete(data.id)" acl [acl-ability]="'base-archives-cost:delete'">删除</a>
+              <a (click)="update(data)" acl [acl-ability]="'implementation-log:update'">修改</a>
+              <nz-divider nzType="vertical" acl [acl-ability]="'implementation-log:update'"></nz-divider>
+              <a (click)="delete(data.id)" acl [acl-ability]="'implementation-log:delete'">删除</a>
             </td>
           </tr>
         </tbody>

+ 2 - 2
src/app/routes/project-work/implementation-log/update/update.component.html

@@ -12,14 +12,14 @@
       </div>
       <div nz-col [nzSpan]="8">
         <nz-form-item>
-          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>项目</nz-form-label>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>项目名称</nz-form-label>
           <nz-form-control [nzSm]="14" [nzXs]="24">
             <nz-select style="widows: 100%;" nzShowSearch nzAllowClear formControlName="proId" id="proId"
               [(ngModel)]="proWorkLogic.proId" nzPlaceHolder="请选择" (ngModelChange)="proChange($event)">
               <nz-option *ngFor="let i of proList" [nzValue]="i.id" [nzLabel]="i.proName"></nz-option>
             </nz-select>
             <nz-form-explain *ngIf="validateForm.get('proId')?.dirty && validateForm.get('proId')?.errors">
-              请选择项目
+              请选择项目名称
             </nz-form-explain>
           </nz-form-control>
         </nz-form-item>

+ 3 - 2
src/app/routes/project-work/implementation-log/update/update.component.ts

@@ -173,7 +173,8 @@ export class ProjectWorkImplementationLogUpdateComponent implements OnInit {
     mieList.forEach(element => {
       if (element.key === data.proArchivesId) {
         data.proArchivesMilestone = element.title;
-        data.proArchivesId = element.id;
+        data.proArchivesId = element.key;
+        data.proPlanId=element.id;
       } else {
         if (element.children) {
           this.getChild(element.children, data);
@@ -215,7 +216,7 @@ export class ProjectWorkImplementationLogUpdateComponent implements OnInit {
       let valid = this.validateForm.valid;
       if (valid) {
         this.isLoadingSave = true;
-        this.proWorkLogic.type = '2'; //实施
+        // this.proWorkLogic.type = '2'; //实施
         this.proWorkLogic.pkOrg = sessionStorage.getItem('pkOrg');
         //项目名称
         if (this.proWorkLogic.proId) {

+ 53 - 0
src/app/routes/project-work/implementation-milestone-confirm/add/add.component.html

@@ -0,0 +1,53 @@
+<!-- 基本信息 -->
+<form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
+  <div nz-row [nzGutter]="24">
+    <div nz-col [nzSpan]="24">
+      <nz-form-item>
+        <nz-form-label [nzSpan]="'vertical' ? 24 : null" nzRequired>单据编码</nz-form-label>
+        <nz-form-control [nzSm]="24" [nzXs]="24">
+          自动生成
+        </nz-form-control>
+      </nz-form-item>
+    </div>
+  </div>
+  <div nz-row [nzGutter]="24">
+    <div nz-col [nzSpan]="6">
+      <nz-form-item>
+        <nz-form-label [nzSpan]="'vertical' ? 24 : null" nzRequired>项目编码</nz-form-label>
+        <nz-form-control [nzSm]="24" [nzXs]="24">
+          {{proWorkMilestone.proCode}}
+        </nz-form-control>
+      </nz-form-item>
+    </div>
+    <div nz-col [nzSpan]="6">
+      <nz-form-item>
+        <nz-form-label [nzSpan]="'vertical' ? 24 : null" nzRequired>项目名称</nz-form-label>
+        <nz-form-control [nzSm]="24" [nzXs]="24">
+          <nz-select style="widows: 100%;" nzShowSearch nzAllowClear formControlName="proId" id="proId"
+              [(ngModel)]="proWorkMilestone.proId" nzPlaceHolder="请选择" (ngModelChange)="proChange($event)">
+              <nz-option *ngFor="let i of proList" [nzValue]="i.id" [nzLabel]="i.proName"></nz-option>
+            </nz-select>
+            <nz-form-explain *ngIf="validateForm.get('proId')?.dirty && validateForm.get('proId')?.errors">
+              请选择项目名称
+            </nz-form-explain>
+        </nz-form-control>
+      </nz-form-item>
+    </div>
+    <div nz-col [nzSpan]="6">
+      <nz-form-item>
+        <nz-form-label [nzSpan]="'vertical' ? 24 : null" nzRequired>客户编码</nz-form-label>
+        <nz-form-control [nzSm]="24" [nzXs]="24">
+          {{proWorkMilestone.cusCode}}
+        </nz-form-control>
+      </nz-form-item>
+    </div>
+    <div nz-col [nzSpan]="6">
+      <nz-form-item>
+        <nz-form-label [nzSpan]="'vertical' ? 24 : null" nzRequired>客户名称</nz-form-label>
+        <nz-form-control [nzSm]="24" [nzXs]="24">
+          {{proWorkMilestone.cusName}}
+        </nz-form-control>
+      </nz-form-item>
+    </div>
+  </div>
+</form>

+ 24 - 0
src/app/routes/project-work/implementation-milestone-confirm/add/add.component.spec.ts

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

+ 47 - 0
src/app/routes/project-work/implementation-milestone-confirm/add/add.component.ts

@@ -0,0 +1,47 @@
+import { Component, OnInit } from '@angular/core';
+import { NzModalRef, NzMessageService } from 'ng-zorro-antd';
+import { _HttpClient } from '@delon/theme';
+import { FormBuilder, Validators, FormGroup } from '@angular/forms';
+import { ProWorkMilestone } from 'app/entity/project-work/pro-work-milestone';
+
+@Component({
+  selector: 'app-project-work-implementation-milestone-confirm-add',
+  templateUrl: './add.component.html',
+})
+export class ProjectWorkImplementationMilestoneConfirmAddComponent implements OnInit {
+  constructor(
+    private fb: FormBuilder
+  ) {}
+
+  ngOnInit(): void {
+    //初始化表单
+    this.validateForm = this.fb.group({
+      proId: [null, [Validators.required]]
+    });
+  }
+
+  validateForm!: FormGroup;
+  proWorkMilestone: ProWorkMilestone = {}; //对象
+  proList=[];//项目下拉列表
+
+  /**
+   * 项目选择事件
+   */
+  proChange(event){
+
+  }
+
+  /**
+   * 保存按钮
+   */
+  submitForm(){
+    for (const i in this.validateForm.controls) {
+      this.validateForm.controls[i].markAsDirty();
+      this.validateForm.controls[i].updateValueAndValidity();
+    }
+    let valid = this.validateForm.valid;
+
+  }
+
+  close() {}
+}

+ 65 - 0
src/app/routes/project-work/implementation-milestone-confirm/implementation-milestone-confirm.component.html

@@ -0,0 +1,65 @@
+<page-header [action]="phActionTpl">
+  <ng-template #phActionTpl>
+    <button (click)="add()" nz-button nzType="primary">新建</button>
+  </ng-template>
+</page-header>
+<nz-card>
+  <!-- 查询条件 -->
+  <form nz-form>
+    <div nz-row [nzGutter]="{ xs: 8, sm: 16, md: 24, lg: 32 }">
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24">单据编码</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <input nz-input name="code" [(ngModel)]="proWorkMilestone.billcode" />
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="2" [nzXs]="24" [nzNoColon]=true></nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <button nzType="primary" (click)="query()" nz-button><span>查询</span></button>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+  </form>
+   <!-- 表格 -->
+   <div nz-row [nzGutter]="{ xs: 8, sm: 16, md: 24, lg: 32 }">
+    <div nz-col [nzSpan]="24">
+      <nz-table nzSize="small" #basicTable [nzData]="listOfData" [nzFrontPagination]="false" [nzTotal]="page.total"
+        [nzPageIndex]="page.current" (nzPageIndexChange)="pageIndexChange($event)" [nzLoading]="isSpinning">
+        <thead>
+          <tr>
+            <th>单据编码</th>
+            <th>项目编码</th>
+            <th>项目名称</th>
+            <th>客户编码</th>
+            <th>客户名称</th>
+            <th>项目里程碑</th>
+            <th>里程碑确认</th>
+            <th>确认时间</th>
+            <th>操作</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr *ngFor="let data of basicTable.data">
+            <td>{{ data.billcode }}</td>
+            <td>{{ data.proCode }}</td>
+            <td>{{ data.proName }}</td>
+            <td>{{ data.cusCode }}</td>
+            <td>{{ data.cusName }}</td>
+            <td>{{ data.mileName }}</td>
+            <td>{{ data.confirmTime }}</td>
+            <td>
+              <a (click)="update(data)" acl [acl-ability]="'implementation-log:update'">修改</a>
+              <nz-divider nzType="vertical" acl [acl-ability]="'implementation-log:update'"></nz-divider>
+              <a (click)="delete(data.id)" acl [acl-ability]="'implementation-log:delete'">删除</a>
+            </td>
+          </tr>
+        </tbody>
+      </nz-table>
+    </div>
+  </div>
+</nz-card>

+ 24 - 0
src/app/routes/project-work/implementation-milestone-confirm/implementation-milestone-confirm.component.spec.ts

@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ProjectWorkImplementationMilestoneConfirmComponent } from './implementation-milestone-confirm.component';
+
+describe('ProjectWorkImplementationMilestoneConfirmComponent', () => {
+  let component: ProjectWorkImplementationMilestoneConfirmComponent;
+  let fixture: ComponentFixture<ProjectWorkImplementationMilestoneConfirmComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ ProjectWorkImplementationMilestoneConfirmComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ProjectWorkImplementationMilestoneConfirmComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 88 - 0
src/app/routes/project-work/implementation-milestone-confirm/implementation-milestone-confirm.component.ts

@@ -0,0 +1,88 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { _HttpClient, ModalHelper } from '@delon/theme';
+import { STColumn, STComponent } from '@delon/abc';
+import { SFSchema } from '@delon/form';
+import { ProWorkMilestone } from 'app/entity/project-work/pro-work-milestone';
+import { ProWorkMilestoneService } from 'app/services/project-work/pro-work-milestone.service';
+import { NzDrawerService } from 'ng-zorro-antd';
+import { ProjectWorkImplementationMilestoneConfirmAddComponent } from './add/add.component';
+import { I18NService } from '@core';
+
+@Component({
+  selector: 'app-project-work-implementation-milestone-confirm',
+  templateUrl: './implementation-milestone-confirm.component.html',
+})
+export class ProjectWorkImplementationMilestoneConfirmComponent implements OnInit {
+  constructor(
+    private proWorkMilestoneService:ProWorkMilestoneService,
+    private nzDrawerService:NzDrawerService,
+    private i18NService:I18NService
+  ) {}
+
+  ngOnInit() {}
+
+  listOfData = [];
+  proWorkMilestone: ProWorkMilestone = {}; //对象
+  page = {
+    total: 0,
+    current: 0,
+  }; //页码
+  isSpinning = false;
+
+  //按页码显示数据
+  pageIndexChange(event) {
+    this.proWorkMilestone.pageNo = event; //当前页码
+    this.getList();
+  }
+
+  /**
+   * 查询数据表
+   */
+  getList() {
+    // this.isSpinning=true;
+    this.proWorkMilestone.pkOrg = sessionStorage.getItem('pkOrg'); //组织
+    this.proWorkMilestone.type = '2';
+    this.proWorkMilestoneService.getList(this.proWorkMilestone).then(response => {
+      this.listOfData = response.result.records;
+    });
+  }
+
+  /**
+   * 查询按钮
+   */
+  query() {
+    this.proWorkMilestone.pageNo = 1;
+    this.getList();
+  }
+
+  /**
+   * 新增按钮
+   */
+  add() {
+    const drawerRef = this.nzDrawerService.create<ProjectWorkImplementationMilestoneConfirmAddComponent, { quotationId: string }, string>({
+      nzTitle: this.i18NService.fanyi("button.add"),//新增标题
+      nzContent: ProjectWorkImplementationMilestoneConfirmAddComponent,
+      nzWidth: window.innerWidth,
+      nzBodyStyle: { height: 'calc(100% - 55px)', overflow: 'auto', 'padding-bottom': '53px' }
+      // nzContentParams: {
+      //   //模板id
+      //   quotationId: item.id
+      // }
+    });
+
+    //关闭抽屉的回调
+    drawerRef.afterClose.subscribe((isRefresh) => {
+      if (isRefresh) {//刷新list列表
+        this.getList();
+      }
+    });
+  }
+
+  update(data){
+
+  }
+
+  delete(id){
+
+  }
+}

+ 7 - 1
src/app/routes/project-work/project-work-routing.module.ts

@@ -1,10 +1,16 @@
 import { NgModule } from '@angular/core';
 import { Routes, RouterModule } from '@angular/router';
 import { ProjectWorkImplementationLogComponent } from './implementation-log/implementation-log.component';
+import { ProjectWorkDevelopmentLogComponent } from './development-log/development-log.component';
+import { ProjectWorkServiceLogComponent } from './service-log/service-log.component';
+import { ProjectWorkImplementationMilestoneConfirmComponent } from './implementation-milestone-confirm/implementation-milestone-confirm.component';
 
 const routes: Routes = [
 
-  { path: 'implementation-log', component: ProjectWorkImplementationLogComponent }];
+  { path: 'implementation-log', component: ProjectWorkImplementationLogComponent },
+  { path: 'development-log', component: ProjectWorkDevelopmentLogComponent },
+  { path: 'service-log', component: ProjectWorkServiceLogComponent },
+  { path: 'implementation-milestone-confirm', component: ProjectWorkImplementationMilestoneConfirmComponent }];
 
 @NgModule({
   imports: [RouterModule.forChild(routes)],

+ 18 - 2
src/app/routes/project-work/project-work.module.ts

@@ -4,12 +4,28 @@ import { ProjectWorkRoutingModule } from './project-work-routing.module';
 import { ProjectWorkImplementationLogComponent } from './implementation-log/implementation-log.component';
 import { ProjectWorkImplementationLogAddComponent } from './implementation-log/add/add.component';
 import { ProjectWorkImplementationLogUpdateComponent } from './implementation-log/update/update.component';
+import { ProjectWorkDevelopmentLogComponent } from './development-log/development-log.component';
+import { ProjectWorkDevelopmentLogAddComponent } from './development-log/add/add.component';
+import { ProjectWorkDevelopmentLogUpdateComponent } from './development-log/update/update.component';
+import { ProjectWorkServiceLogComponent } from './service-log/service-log.component';
+import { ProjectWorkServiceLogAddComponent } from './service-log/add/add.component';
+import { ProjectWorkServiceLogUpdateComponent } from './service-log/update/update.component';
+import { ProjectWorkImplementationMilestoneConfirmComponent } from './implementation-milestone-confirm/implementation-milestone-confirm.component';
+import { ProjectWorkImplementationMilestoneConfirmAddComponent } from './implementation-milestone-confirm/add/add.component';
 
 const COMPONENTS = [
-  ProjectWorkImplementationLogComponent];
+  ProjectWorkImplementationLogComponent,
+  ProjectWorkDevelopmentLogComponent,
+  ProjectWorkServiceLogComponent,
+  ProjectWorkImplementationMilestoneConfirmComponent];
 const COMPONENTS_NOROUNT = [
   ProjectWorkImplementationLogAddComponent,
-  ProjectWorkImplementationLogUpdateComponent];
+  ProjectWorkImplementationLogUpdateComponent,
+  ProjectWorkDevelopmentLogAddComponent,
+  ProjectWorkDevelopmentLogUpdateComponent,
+  ProjectWorkServiceLogAddComponent,
+  ProjectWorkServiceLogUpdateComponent,
+  ProjectWorkImplementationMilestoneConfirmAddComponent];
 
 @NgModule({
   imports: [

+ 109 - 0
src/app/routes/project-work/service-log/add/add.component.html

@@ -0,0 +1,109 @@
+<nz-spin [nzSpinning]="isLoadingSave">
+  <form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="code">单据编码</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <input placeholder="自动生成" nz-input formControlName="billcode" id="billcode"
+              [(ngModel)]="proWorkLogic.billcode" [disabled]="true" />
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>项目名称</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <nz-select style="widows: 100%;" nzShowSearch nzAllowClear formControlName="proId" id="proId"
+              [(ngModel)]="proWorkLogic.proId" nzPlaceHolder="请选择" (ngModelChange)="proChange($event)">
+              <nz-option *ngFor="let i of proList" [nzValue]="i.id" [nzLabel]="i.proName"></nz-option>
+            </nz-select>
+            <nz-form-explain *ngIf="validateForm.get('proId')?.dirty && validateForm.get('proId')?.errors">
+              请选择项目名称
+            </nz-form-explain>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>汇报人</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <nz-tree-select style="width: 100%" [nzNodes]="personnelList" nzShowSearch [nzMultiple]="false"
+              formControlName="reporterId" id="reporterId" nzPlaceHolder="请选择" [(ngModel)]="proWorkLogic.reporterId"
+              [nzMaxTagCount]="3" [nzAllowClear]="true">
+            </nz-tree-select>
+            <nz-form-explain *ngIf="validateForm.get('proId')?.dirty && validateForm.get('proId')?.errors">
+              请选择汇报人
+            </nz-form-explain>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>开始时间</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <nz-range-picker [nzShowTime]="true" formControlName="date" id="date" [(ngModel)]="date"></nz-range-picker>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+  </form>
+  <nz-card>
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="24">
+        <!-- 新增按钮 -->
+        <button (click)="addRow()" nz-button nzType="primary">{{ 'button.add' | translate }}</button>
+      </div>
+    </div>
+
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="24">
+        <nz-table style="padding-top: 5px;" nzSize="small" class="tableTdPadding" #basicTable [nzData]="itemList"
+          [nzFrontPagination]="false" [nzShowPagination]="false">
+          <thead>
+            <tr>
+              <th nzAlign="center" style="width: 5%;">序号</th>
+              <th style="width: 30%;">里程碑</th>
+              <th style="width: 50%;">工作内容</th>
+              <th style="width: 5%;">工作用时</th>
+              <th style="width: 10%;">操作</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr *ngFor="let data of basicTable.data;let i =index">
+              <td nzAlign="center">{{i+1}}</td>
+              <td>
+                <nz-tree-select style="width: 100%" [nzNodes]="mieList" nzShowSearch [nzMultiple]="false"
+                  nzPlaceHolder="请选择" [(ngModel)]="data.proArchivesId" [nzMaxTagCount]="3" [nzAllowClear]="true" (ngModelChange)="proArchivesIdChange(data)">
+                </nz-tree-select >
+              </td>
+              <td>
+                <textarea rows="1" nz-input [(ngModel)]="data.content"></textarea>
+              </td>
+              <td style="width: 10%;">
+                <nz-input-number [(ngModel)]="data.duration" [nzMin]="0" [nzStep]="1"></nz-input-number>
+              </td>
+              <td>
+                <a nz-popconfirm nzTitle="是否删除?" (nzOnConfirm)="deleteRow(data.sort)">{{'table.delete'|translate}}</a>
+              </td>
+            </tr>
+          </tbody>
+        </nz-table>
+      </div>
+    </div>
+  </nz-card>
+</nz-spin>
+<!-- 按钮 -->
+<div class="base">
+  <strong>填写人:</strong>{{proWorkLogic.currentUser}} <strong>填写时间:</strong>{{proWorkLogic.createTime}}
+  <!-- 关闭按钮 -->
+  <a nz-popconfirm nzTitle="{{'pm.contract.contract.add.button.cancel'|translate}}" (nzOnConfirm)="close()"
+    style="padding-right: 8px">
+    <button nz-button>{{'pm.quotation.cancel'|translate}}</button>
+  </a>
+  <!-- 保存按钮 -->
+  <button nz-button nzType="primary" class="ant-btn ant-btn-primary" (click)="submitForm()"
+    [nzLoading]="isLoadingSave"><span>{{'pm.finish' | translate}}</span></button>
+</div>

+ 24 - 0
src/app/routes/project-work/service-log/add/add.component.spec.ts

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

+ 287 - 0
src/app/routes/project-work/service-log/add/add.component.ts

@@ -0,0 +1,287 @@
+import { Component, OnInit } from '@angular/core';
+import { NzModalRef, NzMessageService, NzNotificationService, NzDrawerRef } from 'ng-zorro-antd';
+import { _HttpClient, SettingsService } from '@delon/theme';
+import { FormBuilder, Validators, FormGroup } from '@angular/forms';
+import { DatePipe } from '@angular/common';
+import { ProjectManageArchivesService } from 'app/services/project-manage-archives/project-manage-archives.service';
+import { PersonnelService } from 'app/services/basedata/personnel.service';
+import { ProWorkLogicService } from 'app/services/project-work/pro-work-logic.service';
+import { I18NService } from '@core';
+import { ProWorkLogic } from 'app/entity/project-work/pro-work-logic';
+import { ProjectManageArchives } from 'app/entity/project-manage-archives/project-manage-archives';
+import { recursiveQuery } from '@shared';
+
+@Component({
+  selector: 'app-project-work-service-log-add',
+  templateUrl: './add.component.html',
+  styles: [
+    `
+      .base {
+        position: absolute;
+        bottom: 0px;
+        width: 100%;
+        border-top: 1px solid rgb(232, 232, 232);
+        padding: 6px 16px;
+        text-align: right;
+        left: 0px;
+        background: #fff;
+        z-index: 99;
+      }
+    `,
+  ],
+})
+export class ProjectWorkServiceLogAddComponent implements OnInit {
+  constructor(
+    private fb: FormBuilder,
+    private settingsService: SettingsService,
+    private datePipe: DatePipe,
+    private projectManageArchivesService: ProjectManageArchivesService,
+    private personnelService: PersonnelService,
+    private proWorkLogicService: ProWorkLogicService,
+    private nzNotificationService: NzNotificationService,
+    private i18NService: I18NService,
+    private drawerRef: NzDrawerRef,
+  ) {}
+
+  ngOnInit(): void {
+    //初始化表单
+    this.validateForm = this.fb.group({
+      billcode: [{ value: '', disabled: true }],
+      proId: [null, [Validators.required]],
+      date: [null, [Validators.required]],
+      reporterId: [null, [Validators.required]],
+    });
+    //项目下拉
+    this.isLoadingSave = true;
+    this.getProList()
+      .then(() => {
+        //人员下来数据
+        return this.getPersonnelList();
+      })
+      .then(() => {
+        this.isLoadingSave = false;
+      });
+  }
+
+  isLoadingSave = false;
+  validateForm!: FormGroup;
+  proWorkLogic: ProWorkLogic = {
+    currentUser: this.settingsService.user.realname,
+    createTime: this.datePipe.transform(new Date(), 'yyyy-MM-dd HH:mm:ss'),
+  }; //对象
+  proList = []; //项目下拉数据
+  personnelList = []; //汇报人下拉数据
+  itemList = []; //明细集合
+  mieList = []; //里程碑数据下拉
+  date = null;
+
+  /**
+   * 获取项目下拉数据
+   */
+  getProList() {
+    return new Promise(resolve => {
+      let projectManageArchives = new ProjectManageArchives();
+      projectManageArchives.pageSize = 20000;
+      projectManageArchives.pkOrg = sessionStorage.getItem('pkOrg');
+      this.projectManageArchivesService.getList(projectManageArchives).then(response => {
+        if (response.result.records) {
+          this.proList = response.result.records;
+        }
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 项目下拉选择事件
+   */
+  proChange(event) {
+    this.getMieList(event);
+  }
+
+  /**
+   * 获取汇报人下拉数据
+   */
+  getPersonnelList() {
+    return new Promise(resolve => {
+      this.personnelService.queryApprover(sessionStorage.getItem('pkOrg')).then(response => {
+        if (response.result) {
+          this.personnelList = JSON.parse(JSON.stringify(response.result));
+        }
+        recursiveQuery(this.personnelList);
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 里程碑数据下拉
+   */
+  getMieList(proArchivesId) {
+    return new Promise(resolve => {
+      let plan = { id: proArchivesId, planType: '4' };
+      this.projectManageArchivesService.getPlanListById(plan).then(response => {
+        if (response.result) {
+          this.mieList = response.result;
+        }
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 里程碑选择事件
+   */
+  proArchivesIdChange(data) {
+    console.log(data.proArchivesId);
+    //是否选择里程碑
+    if (data.proArchivesId) {
+      this.getChild(this.mieList, data);
+    } else {
+      data.proArchivesMilestone = '';
+      data.proArchivesId = '';
+    }
+  }
+
+  /**
+   * 递归查询名称
+   */
+  getChild(mieList, data) {
+    mieList.forEach(element => {
+      if (element.key === data.proArchivesId) {
+        data.proArchivesMilestone = element.title;
+        data.proArchivesId = element.key;
+        data.proPlanId=element.id;
+      } else {
+        if (element.children) {
+          this.getChild(element.children, data);
+        }
+      }
+    });
+  }
+
+  /**
+   * 增行按钮
+   */
+  sort = 0;
+  addRow() {
+    this.itemList = [
+      ...this.itemList,
+      {
+        sort: this.sort,
+      },
+    ];
+    this.sort++;
+  }
+
+  /**
+   * 删除行
+   */
+  deleteRow(sort) {
+    this.itemList = this.itemList.filter(d => d.sort !== sort);
+  }
+
+  /**
+   * 保存按钮
+   */
+  submitForm(): any {
+    return new Promise(resolve => {
+      for (const i in this.validateForm.controls) {
+        this.validateForm.controls[i].markAsDirty();
+        this.validateForm.controls[i].updateValueAndValidity();
+      }
+      let valid = this.validateForm.valid;
+      if (valid) {
+        this.isLoadingSave = true;
+        this.proWorkLogic.type = '3'; //实施
+        this.proWorkLogic.pkOrg = sessionStorage.getItem('pkOrg');
+        //项目名称
+        if (this.proWorkLogic.proId) {
+          this.proList.forEach(element => {
+            if (element.id === this.proWorkLogic.proId) {
+              this.proWorkLogic.proName = element.proName;
+            }
+          });
+        } else {
+          this.proWorkLogic.proName = '';
+        }
+        //汇报人名称
+        if (this.proWorkLogic.reporterId) {
+          //循环集合数据获取名称
+          this.personnelList.forEach(pkOrg => {
+            pkOrg.children.forEach(depart => {
+              depart.children.forEach(personnel => {
+                if (personnel.key === this.proWorkLogic.reporterId) {
+                  this.proWorkLogic.reporter = personnel.name;
+                }
+              });
+            });
+          });
+        } else {
+          this.proWorkLogic.reporter = '';
+        }
+        //时间格式化
+        this.proWorkLogic.startDate = this.datePipe.transform(this.date[0], 'yyyy-MM-dd HH:mm:ss');
+        this.proWorkLogic.endDate = this.datePipe.transform(this.date[1], 'yyyy-MM-dd HH:mm:ss');
+        //判断两个时间差的工时是否大于明细总工时
+        if(!this.getHourBoole()){
+          this.nzNotificationService.warning("工作用时不得大于开始时间与结束时间之差","");
+          this.isLoadingSave=false;
+          return;
+        }
+        //子表\
+        //判断是否输入子表数据
+        if (this.itemList && this.itemList.length > 0) {
+          this.proWorkLogic.detailList = this.itemList;
+        } else {
+          this.nzNotificationService.warning('工作内容必填', '');
+          this.isLoadingSave=false;
+          return;
+        }
+        this.proWorkLogicService.add(this.proWorkLogic).then(response => {
+          if (response.success) {
+            //保存成功
+            this.isLoadingSave = false;
+            this.nzNotificationService.success(this.i18NService.fanyi('save.ok'), '');
+            this.drawerRef.close(true);
+            resolve();
+          } else {
+            //保存失败
+            this.isLoadingSave = false;
+            this.nzNotificationService.error(this.i18NService.fanyi('save.not'), '');
+          }
+        });
+      }
+    });
+  }
+
+  /**
+   * 判断两个时间差的工时是否大于明细总工时
+   */
+  getHourBoole():boolean{
+    //明细总工时
+    let itemHour=0;
+    //两个时间差
+    let dateHour=this.getInervalHour(this.date[0], this.date[1]);
+    //循环获取明细的总工时
+    this.itemList.forEach(element => {
+      if(element.duration){
+        itemHour=itemHour+Number(element.duration);
+      }
+    });
+    return dateHour>=itemHour;
+  }
+
+  /**
+   * 获取两个时间差
+   */
+  getInervalHour(startDate, endDate) {
+    var ms = endDate.getTime() - startDate.getTime();
+    if (ms < 0) return 0;
+    return Math.floor(ms / 1000 / 60 / 60);
+  }
+
+  close() {
+    this.drawerRef.close();
+  }
+}

+ 64 - 0
src/app/routes/project-work/service-log/service-log.component.html

@@ -0,0 +1,64 @@
+<page-header [action]="phActionTpl">
+  <ng-template #phActionTpl>
+    <button (click)="add()" nz-button nzType="primary" acl [acl-ability]="'url:service-log:view'">新建</button>
+  </ng-template>
+</page-header>
+<nz-card>
+  <!-- 查询条件 -->
+  <form nz-form>
+    <div nz-row [nzGutter]="{ xs: 8, sm: 16, md: 24, lg: 32 }">
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24">单据编码</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <input nz-input name="code" [(ngModel)]="proWorkLogic.billcode" />
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="2" [nzXs]="24" [nzNoColon]=true></nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <button nzType="primary" (click)="query()" nz-button><span>查询</span></button>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+  </form>
+   <!-- 表格 -->
+   <div nz-row [nzGutter]="{ xs: 8, sm: 16, md: 24, lg: 32 }">
+    <div nz-col [nzSpan]="24">
+      <nz-table nzSize="small" #basicTable [nzData]="listOfData" [nzFrontPagination]="false" [nzTotal]="page.total"
+        [nzPageIndex]="page.current" (nzPageIndexChange)="pageIndexChange($event)" [nzLoading]="isSpinning">
+        <thead>
+          <tr>
+            <th>单据编码</th>
+            <th>项目名称</th>
+            <th>开始时间</th>
+            <th>结束时间</th>
+            <th>汇报人</th>
+            <th>填写人</th>
+            <th>填写时间</th>
+            <th>操作</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr *ngFor="let data of basicTable.data">
+            <td>{{ data.billcode }}</td>
+            <td>{{ data.proName }}</td>
+            <td>{{ data.startDate }}</td>
+            <td>{{ data.endDate }}</td>
+            <td>{{ data.reporter }}</td>
+            <td>{{ data.currentUser }}</td>
+            <td>{{ data.createTime }}</td>
+            <td>
+              <a (click)="update(data)" acl [acl-ability]="'service-log:update'">修改</a>
+              <nz-divider nzType="vertical" acl [acl-ability]="'service-log:update'"></nz-divider>
+              <a (click)="delete(data.id)" acl [acl-ability]="'service-log:delete'">删除</a>
+            </td>
+          </tr>
+        </tbody>
+      </nz-table>
+    </div>
+  </div>
+</nz-card>

+ 24 - 0
src/app/routes/project-work/service-log/service-log.component.spec.ts

@@ -0,0 +1,24 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ProjectWorkServiceLogComponent } from './service-log.component';
+
+describe('ProjectWorkServiceLogComponent', () => {
+  let component: ProjectWorkServiceLogComponent;
+  let fixture: ComponentFixture<ProjectWorkServiceLogComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ ProjectWorkServiceLogComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ProjectWorkServiceLogComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 126 - 0
src/app/routes/project-work/service-log/service-log.component.ts

@@ -0,0 +1,126 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { _HttpClient, ModalHelper } from '@delon/theme';
+import { STColumn, STComponent } from '@delon/abc';
+import { SFSchema } from '@delon/form';
+import { ProWorkLogicService } from 'app/services/project-work/pro-work-logic.service';
+import { NzDrawerService, NzNotificationService } from 'ng-zorro-antd';
+import { I18NService } from '@core';
+import { ProWorkLogic } from 'app/entity/project-work/pro-work-logic';
+import { ProjectWorkServiceLogAddComponent } from './add/add.component';
+import { ProjectWorkServiceLogUpdateComponent } from './update/update.component';
+
+@Component({
+  selector: 'app-project-work-service-log',
+  templateUrl: './service-log.component.html',
+})
+export class ProjectWorkServiceLogComponent implements OnInit {
+  constructor(
+    private proWorkLogicService:ProWorkLogicService,
+    private nzDrawerService:NzDrawerService,
+    private i18NService:I18NService,
+    private nzNotificationService:NzNotificationService
+  ) {}
+
+  ngOnInit() {
+    this.getList();
+  }
+  listOfData = [];
+  proWorkLogic: ProWorkLogic = {}; //对象
+  page = {
+    total: 0,
+    current: 0,
+  }; //页码
+  isSpinning = false;
+
+  //按页码显示数据
+  pageIndexChange(event) {
+    this.proWorkLogic.pageNo = event; //当前页码
+    this.getList();
+  }
+
+  /**
+   * 查询数据表
+   */
+  getList() {
+    // this.isSpinning=true;
+    this.proWorkLogic.pkOrg = sessionStorage.getItem('pkOrg'); //组织
+    this.proWorkLogic.type="3";
+    this.proWorkLogicService.getList(this.proWorkLogic).then(response => {
+      this.listOfData = response.result.records;
+    });
+  }
+
+  /**
+   * 查询按钮
+   */
+  query() {
+    this.proWorkLogic.pageNo = 1;
+    this.getList();
+  }
+  
+  /**
+   * 新增按钮
+   */
+  add() {
+    const drawerRef = this.nzDrawerService.create<ProjectWorkServiceLogAddComponent, { quotationId: string }, string>({
+      nzTitle: this.i18NService.fanyi("button.add"),//新增标题
+      nzContent: ProjectWorkServiceLogAddComponent,
+      nzWidth: window.innerWidth,
+      nzBodyStyle: { height: 'calc(100% - 55px)', overflow: 'auto', 'padding-bottom': '53px' }
+      // nzContentParams: {
+      //   //模板id
+      //   quotationId: item.id
+      // }
+    });
+
+    //关闭抽屉的回调
+    drawerRef.afterClose.subscribe((isRefresh) => {
+      if (isRefresh) {//刷新list列表
+        this.getList();
+      }
+    });
+  }
+
+  /**
+   * 修改
+   * @param data 修改对象
+   */
+  update(data){
+    const drawerRef = this.nzDrawerService.create<ProjectWorkServiceLogUpdateComponent, { id: string }, string>({
+      nzTitle: this.i18NService.fanyi("table.update"),//新增标题
+      nzContent: ProjectWorkServiceLogUpdateComponent,
+      nzWidth: window.innerWidth,
+      nzBodyStyle: { height: 'calc(100% - 55px)', overflow: 'auto', 'padding-bottom': '53px' },
+      nzContentParams: {
+        //模板id
+        id: data.id
+      }
+    });
+
+    //关闭抽屉的回调
+    drawerRef.afterClose.subscribe((isRefresh) => {
+      if (isRefresh) {//刷新list列表
+        this.getList();
+      }
+    });
+  }
+
+  /**
+   * 删除
+   * @param id 
+   */
+  delete(id){
+    let proWorkLogic=new ProWorkLogic();
+    proWorkLogic.id=id;
+    this.proWorkLogicService.delete(proWorkLogic).then((response)=>{
+      if (response.success) {
+        //删除成功
+        this.nzNotificationService.success(this.i18NService.fanyi('successful.deletion'), '');
+        this.getList();
+      } else {
+        //删除失败
+        this.nzNotificationService.error(this.i18NService.fanyi('delete.failed'), '');
+      }
+    })
+  }
+}

+ 110 - 0
src/app/routes/project-work/service-log/update/update.component.html

@@ -0,0 +1,110 @@
+<nz-spin [nzSpinning]="isLoadingSave">
+  <form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired nzFor="code">单据编码</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <input placeholder="自动生成" nz-input formControlName="billcode" id="billcode"
+              [(ngModel)]="proWorkLogic.billcode" [disabled]="true" />
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>项目名称</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <nz-select style="widows: 100%;" nzShowSearch nzAllowClear formControlName="proId" id="proId"
+              [(ngModel)]="proWorkLogic.proId" nzPlaceHolder="请选择" (ngModelChange)="proChange($event)">
+              <nz-option *ngFor="let i of proList" [nzValue]="i.id" [nzLabel]="i.proName"></nz-option>
+            </nz-select>
+            <nz-form-explain *ngIf="validateForm.get('proId')?.dirty && validateForm.get('proId')?.errors">
+              请选择项目名称
+            </nz-form-explain>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>汇报人</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <nz-tree-select style="width: 100%" [nzNodes]="personnelList" nzShowSearch [nzMultiple]="false"
+              formControlName="reporterId" id="reporterId" nzPlaceHolder="请选择" [(ngModel)]="proWorkLogic.reporterId"
+              [nzMaxTagCount]="3" [nzAllowClear]="true">
+            </nz-tree-select>
+            <nz-form-explain *ngIf="validateForm.get('proId')?.dirty && validateForm.get('proId')?.errors">
+              请选择汇报人
+            </nz-form-explain>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="8">
+        <nz-form-item>
+          <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>开始时间</nz-form-label>
+          <nz-form-control [nzSm]="14" [nzXs]="24">
+            <nz-range-picker [nzShowTime]="true" formControlName="date" id="date" [(ngModel)]="date"></nz-range-picker>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+  </form>
+  <nz-card>
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="24">
+        <!-- 新增按钮 -->
+        <button (click)="addRow()" nz-button nzType="primary">{{ 'button.add' | translate }}</button>
+      </div>
+    </div>
+
+    <div nz-row [nzGutter]="24">
+      <div nz-col [nzSpan]="24">
+        <nz-table style="padding-top: 5px;" nzSize="small" class="tableTdPadding" #basicTable [nzData]="itemList"
+          [nzFrontPagination]="false" [nzShowPagination]="false">
+          <thead>
+            <tr>
+              <th nzAlign="center" style="width: 5%;">序号</th>
+              <th style="width: 30%;">里程碑</th>
+              <th style="width: 50%;">工作内容</th>
+              <th style="width: 5%;">工作用时</th>
+              <th style="width: 10%;">操作</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr *ngFor="let data of basicTable.data;let i =index">
+              <td nzAlign="center">{{i+1}}</td>
+              <td>
+                <nz-tree-select style="width: 100%" [nzNodes]="mieList" nzShowSearch [nzMultiple]="false"
+                  nzPlaceHolder="请选择" [(ngModel)]="data.proArchivesId" [nzMaxTagCount]="3" [nzAllowClear]="true"
+                  (ngModelChange)="proArchivesIdChange(data)">
+                </nz-tree-select>
+              </td>
+              <td>
+                <textarea rows="1" nz-input [(ngModel)]="data.content"></textarea>
+              </td>
+              <td style="width: 10%;">
+                <nz-input-number [(ngModel)]="data.duration" [nzMin]="0" [nzStep]="1"></nz-input-number>
+              </td>
+              <td>
+                <a nz-popconfirm nzTitle="是否删除?" (nzOnConfirm)="deleteRow(data.sort)">{{'table.delete'|translate}}</a>
+              </td>
+            </tr>
+          </tbody>
+        </nz-table>
+      </div>
+    </div>
+  </nz-card>
+</nz-spin>
+<!-- 按钮 -->
+<div class="base">
+  <strong>填写人:</strong>{{proWorkLogic.currentUser}} <strong>填写时间:</strong>{{proWorkLogic.createTime}}
+  <!-- 关闭按钮 -->
+  <a nz-popconfirm nzTitle="{{'pm.contract.contract.add.button.cancel'|translate}}" (nzOnConfirm)="close()"
+    style="padding-right: 8px">
+    <button nz-button>{{'pm.quotation.cancel'|translate}}</button>
+  </a>
+  <!-- 保存按钮 -->
+  <button nz-button nzType="primary" class="ant-btn ant-btn-primary" (click)="submitForm()"
+    [nzLoading]="isLoadingSave"><span>{{'pm.finish' | translate}}</span></button>
+</div>

+ 24 - 0
src/app/routes/project-work/service-log/update/update.component.spec.ts

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

+ 310 - 0
src/app/routes/project-work/service-log/update/update.component.ts

@@ -0,0 +1,310 @@
+import { Component, OnInit } from '@angular/core';
+import { NzModalRef, NzMessageService, NzNotificationService, NzDrawerRef } from 'ng-zorro-antd';
+import { _HttpClient, SettingsService } from '@delon/theme';
+import { FormBuilder, Validators, FormGroup } from '@angular/forms';
+import { DatePipe } from '@angular/common';
+import { ProjectManageArchivesService } from 'app/services/project-manage-archives/project-manage-archives.service';
+import { PersonnelService } from 'app/services/basedata/personnel.service';
+import { ProWorkLogicService } from 'app/services/project-work/pro-work-logic.service';
+import { I18NService } from '@core';
+import { ProWorkLogic } from 'app/entity/project-work/pro-work-logic';
+import { ProjectManageArchives } from 'app/entity/project-manage-archives/project-manage-archives';
+import { recursiveQuery } from '@shared';
+
+@Component({
+  selector: 'app-project-work-service-log-update',
+  templateUrl: './update.component.html',
+  styles: [
+    `
+      .base {
+        position: absolute;
+        bottom: 0px;
+        width: 100%;
+        border-top: 1px solid rgb(232, 232, 232);
+        padding: 6px 16px;
+        text-align: right;
+        left: 0px;
+        background: #fff;
+        z-index: 99;
+      }
+    `,
+  ],
+})
+export class ProjectWorkServiceLogUpdateComponent implements OnInit {
+  constructor(
+    private fb: FormBuilder,
+    private settingsService: SettingsService,
+    private datePipe: DatePipe,
+    private projectManageArchivesService: ProjectManageArchivesService,
+    private personnelService: PersonnelService,
+    private proWorkLogicService: ProWorkLogicService,
+    private nzNotificationService: NzNotificationService,
+    private i18NService: I18NService,
+    private drawerRef: NzDrawerRef,
+  ) {}
+
+  ngOnInit(): void {
+    //初始化表单
+    this.validateForm = this.fb.group({
+      billcode: [{ value: '', disabled: true }],
+      proId: [null, [Validators.required]],
+      date: [null, [Validators.required]],
+      reporterId: [null, [Validators.required]],
+    });
+    //项目下拉
+    this.isLoadingSave = true;
+    this.getProList()
+      .then(() => {
+        //人员下来数据
+        return this.getPersonnelList();
+      }).then(()=>{
+        //根据id查询
+        return this.getById();
+      })
+      .then(() => {
+        this.isLoadingSave = false;
+      });
+  }
+
+  isLoadingSave = false;
+  validateForm!: FormGroup;
+  proWorkLogic: ProWorkLogic = {
+  }; //对象
+  proList = []; //项目下拉数据
+  personnelList = []; //汇报人下拉数据
+  itemList = []; //明细集合
+  mieList = []; //里程碑数据下拉
+  date = null;
+  id="";
+
+  /**
+   * 根据id查询
+   */
+  getById(){
+    return new Promise((resolve)=>{
+      this.proWorkLogicService.getListById(this.id).then((response)=>{
+        if(response.result){
+          this.proWorkLogic=response.result;//主表对象
+          this.itemList=response.result.detailList;//明细数组
+          //最大排序
+          if(this.itemList){
+            this.sort=this.itemList.length+1;
+          }
+          //开始时间-结束时间
+          this.date=[new Date(this.proWorkLogic.startDate),new Date(this.proWorkLogic.endDate)]
+        }
+        resolve();
+      })
+    })
+  }
+
+  /**
+   * 获取项目下拉数据
+   */
+  getProList() {
+    return new Promise(resolve => {
+      let projectManageArchives = new ProjectManageArchives();
+      projectManageArchives.pageSize = 20000;
+      projectManageArchives.pkOrg = sessionStorage.getItem('pkOrg');
+      this.projectManageArchivesService.getList(projectManageArchives).then(response => {
+        if (response.result.records) {
+          this.proList = response.result.records;
+        }
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 项目下拉选择事件
+   */
+  proChange(event) {
+    this.getMieList(event);
+  }
+
+  /**
+   * 获取汇报人下拉数据
+   */
+  getPersonnelList() {
+    return new Promise(resolve => {
+      this.personnelService.queryApprover(sessionStorage.getItem('pkOrg')).then(response => {
+        if (response.result) {
+          this.personnelList = JSON.parse(JSON.stringify(response.result));
+        }
+        recursiveQuery(this.personnelList);
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 里程碑数据下拉
+   */
+  getMieList(proArchivesId) {
+    return new Promise(resolve => {
+      let plan = { id: proArchivesId, planType: '4' };
+      this.projectManageArchivesService.getPlanListById(plan).then(response => {
+        if (response.result) {
+          this.mieList = response.result;
+        }
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 里程碑选择事件
+   */
+  proArchivesIdChange(data) {
+    console.log(data.proArchivesId);
+    //是否选择里程碑
+    if (data.proArchivesId) {
+      this.getChild(this.mieList, data);
+    } else {
+      data.proArchivesMilestone = '';
+      data.proArchivesId = '';
+    }
+  }
+
+  /**
+   * 递归查询名称
+   */
+  getChild(mieList, data) {
+    mieList.forEach(element => {
+      if (element.key === data.proArchivesId) {
+        data.proArchivesMilestone = element.title;
+        data.proArchivesId = element.key;
+        data.proPlanId=element.id;
+      } else {
+        if (element.children) {
+          this.getChild(element.children, data);
+        }
+      }
+    });
+  }
+
+  /**
+   * 增行按钮
+   */
+  sort = 0;
+  addRow() {
+    this.itemList = [
+      ...this.itemList,
+      {
+        sort: this.sort,
+      },
+    ];
+    this.sort++;
+  }
+
+  /**
+   * 删除行
+   */
+  deleteRow(sort) {
+    this.itemList = this.itemList.filter(d => d.sort !== sort);
+  }
+
+  /**
+   * 保存按钮
+   */
+  submitForm(): any {
+    return new Promise(resolve => {
+      for (const i in this.validateForm.controls) {
+        this.validateForm.controls[i].markAsDirty();
+        this.validateForm.controls[i].updateValueAndValidity();
+      }
+      let valid = this.validateForm.valid;
+      if (valid) {
+        this.isLoadingSave = true;
+        // this.proWorkLogic.type = '2'; //实施
+        this.proWorkLogic.pkOrg = sessionStorage.getItem('pkOrg');
+        //项目名称
+        if (this.proWorkLogic.proId) {
+          this.proList.forEach(element => {
+            if (element.id === this.proWorkLogic.proId) {
+              this.proWorkLogic.proName = element.proName;
+            }
+          });
+        } else {
+          this.proWorkLogic.proName = '';
+        }
+        //汇报人名称
+        if (this.proWorkLogic.reporterId) {
+          //循环集合数据获取名称
+          this.personnelList.forEach(pkOrg => {
+            pkOrg.children.forEach(depart => {
+              depart.children.forEach(personnel => {
+                if (personnel.key === this.proWorkLogic.reporterId) {
+                  this.proWorkLogic.reporter = personnel.name;
+                }
+              });
+            });
+          });
+        } else {
+          this.proWorkLogic.reporter = '';
+        }
+        //时间格式化
+        this.proWorkLogic.startDate = this.datePipe.transform(this.date[0], 'yyyy-MM-dd HH:mm:ss');
+        this.proWorkLogic.endDate = this.datePipe.transform(this.date[1], 'yyyy-MM-dd HH:mm:ss');
+        //判断两个时间差的工时是否大于明细总工时
+        if (!this.getHourBoole()) {
+          this.nzNotificationService.warning('工作用时不得大于开始时间与结束时间之差', '');
+          this.isLoadingSave = false;
+          return;
+        }
+        //子表\
+        //判断是否输入子表数据
+        if (this.itemList && this.itemList.length > 0) {
+          this.proWorkLogic.detailList = this.itemList;
+        } else {
+          this.nzNotificationService.warning('工作内容必填', '');
+          this.isLoadingSave = false;
+          return;
+        }
+        this.proWorkLogicService.update(this.proWorkLogic).then(response => {
+          if (response.success) {
+            //保存成功
+            this.isLoadingSave = false;
+            this.nzNotificationService.success(this.i18NService.fanyi('save.ok'), '');
+            this.drawerRef.close(true);
+            resolve();
+          } else {
+            //保存失败
+            this.isLoadingSave = false;
+            this.nzNotificationService.error(this.i18NService.fanyi('save.not'), '');
+          }
+        });
+      }
+    });
+  }
+
+  /**
+   * 判断两个时间差的工时是否大于明细总工时
+   */
+  getHourBoole(): boolean {
+    //明细总工时
+    let itemHour = 0;
+    //两个时间差
+    let dateHour = this.getInervalHour(this.date[0], this.date[1]);
+    //循环获取明细的总工时
+    this.itemList.forEach(element => {
+      if (element.duration) {
+        itemHour = itemHour + Number(element.duration);
+      }
+    });
+    return dateHour >= itemHour;
+  }
+
+  /**
+   * 获取两个时间差
+   */
+  getInervalHour(startDate, endDate) {
+    var ms = endDate.getTime() - startDate.getTime();
+    if (ms < 0) return 0;
+    return Math.floor(ms / 1000 / 60 / 60);
+  }
+
+  close() {
+    this.drawerRef.close();
+  }
+}

+ 23 - 0
src/app/services/project-work/pro-work-milestone.service.ts

@@ -0,0 +1,23 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { BaseResponse } from 'app/entity/baseResponse';
+import { Result } from 'app/entity/Result';
+
+@Injectable({
+  providedIn: 'root'
+})
+/**
+ * 里程碑确认单
+ */
+export class ProWorkMilestoneService {
+
+  constructor(private http:HttpClient) { }
+
+   //分页查询
+   async getList(body: any): Promise<BaseResponse<Result<any>>> {
+    return await this.http
+      .get<BaseResponse<Result<any>>>('/prowork/proWorkMilestone/list', { params: body })
+      .toPromise();
+  }
+
+}