chenc 3 سال پیش
والد
کامیت
11a982a255
28فایلهای تغییر یافته به همراه2555 افزوده شده و 63 حذف شده
  1. 2 0
      src/app/entity/basedata/base-material-file-modular.ts
  2. 2 0
      src/app/entity/contract-management/contract-file-modular.ts
  3. 8 0
      src/app/entity/contract-management/contract-file-product.ts
  4. 27 12
      src/app/routes/contract-management/contract-file/add/add.component.html
  5. 75 8
      src/app/routes/contract-management/contract-file/add/add.component.ts
  6. 43 25
      src/app/routes/contract-management/contract-file/add/essential-information/essential-information.component.html
  7. 9 1
      src/app/routes/contract-management/contract-file/add/essential-information/essential-information.component.ts
  8. 13 7
      src/app/routes/contract-management/contract-file/add/product-module/product-module.component.html
  9. 97 5
      src/app/routes/contract-management/contract-file/add/product-module/product-module.component.ts
  10. 59 2
      src/app/routes/contract-management/contract-file/contract-file.component.html
  11. 85 2
      src/app/routes/contract-management/contract-file/contract-file.component.ts
  12. 219 0
      src/app/routes/contract-management/contract-file/update/collection-plan/collection-plan.component.html
  13. 24 0
      src/app/routes/contract-management/contract-file/update/collection-plan/collection-plan.component.spec.ts
  14. 240 0
      src/app/routes/contract-management/contract-file/update/collection-plan/collection-plan.component.ts
  15. 358 0
      src/app/routes/contract-management/contract-file/update/essential-information/essential-information.component.html
  16. 24 0
      src/app/routes/contract-management/contract-file/update/essential-information/essential-information.component.spec.ts
  17. 319 0
      src/app/routes/contract-management/contract-file/update/essential-information/essential-information.component.ts
  18. 138 0
      src/app/routes/contract-management/contract-file/update/product-module/product-module.component.html
  19. 24 0
      src/app/routes/contract-management/contract-file/update/product-module/product-module.component.spec.ts
  20. 255 0
      src/app/routes/contract-management/contract-file/update/product-module/product-module.component.ts
  21. 28 0
      src/app/routes/contract-management/contract-file/update/update.component.html
  22. 24 0
      src/app/routes/contract-management/contract-file/update/update.component.spec.ts
  23. 270 0
      src/app/routes/contract-management/contract-file/update/update.component.ts
  24. 9 1
      src/app/routes/contract-management/contract-management.module.ts
  25. 44 0
      src/app/services/contract-management/contract-file-and-business.service.ts
  26. 45 0
      src/app/services/contract-management/contract-file-modular.service.ts
  27. 45 0
      src/app/services/contract-management/contract-file-product.service.ts
  28. 69 0
      src/app/services/contract-management/contract-file.service.ts

+ 2 - 0
src/app/entity/basedata/base-material-file-modular.ts

@@ -14,4 +14,6 @@ export class BaseMaterialFileModular extends Page {
 	standardQuotation?:number;
 	/**组织*/
 	 pkOrg?:string;
+	 /**产品id */
+	 baseMaterialFileProductId?:string
 }

+ 2 - 0
src/app/entity/contract-management/contract-file-modular.ts

@@ -21,4 +21,6 @@ export class ContractFileModular extends Page {
 	sort?:number;
 	/**主表id*/
 	contractFileId?:string;
+	/**物料档案模块id */
+	baseMaterialFileModularId?:string;
 }

+ 8 - 0
src/app/entity/contract-management/contract-file-product.ts

@@ -44,4 +44,12 @@ export class ContractFileProduct extends Page {
 	discountRate?:number;
 	/**合同产品模块子表*/
 	contractFileModularList?:ContractFileModular[];
+
+
+
+
+
+
+	/**页面需要零食属性 */
+	modularListSelect?:any[];//模块下拉数据集合
 }

+ 27 - 12
src/app/routes/contract-management/contract-file/add/add.component.html

@@ -1,13 +1,28 @@
-<nz-tabset nzTabPosition="left">
-  <nz-tab nzTitle="合同基本信息">
-    <app-contract-management-contract-file-add-essential-information #essentialInformation (milestone)="milestone($event)"></app-contract-management-contract-file-add-essential-information>
-  </nz-tab>
-  <nz-tab nzTitle="产品与模块">
-    <app-contract-management-contract-file-add-product-module #productModule (contractFileObject)="contractFileObject($event)"></app-contract-management-contract-file-add-product-module>
-  </nz-tab>
-  <nz-tab nzTitle="收款计划">
-    <app-contract-management-contract-file-add-collection-plan #collectionPlan>
+<nz-spin [nzSpinning]="isLoadingSave">
+  <nz-tabset nzTabPosition="left">
+    <nz-tab nzTitle="合同基本信息">
+      <app-contract-management-contract-file-add-essential-information #essentialInformation
+        (milestone)="milestone($event)"></app-contract-management-contract-file-add-essential-information>
+    </nz-tab>
+    <nz-tab nzTitle="产品与模块">
+      <app-contract-management-contract-file-add-product-module #productModule
+        (contractFileObject)="contractFileObject($event)"></app-contract-management-contract-file-add-product-module>
+    </nz-tab>
+    <nz-tab nzTitle="收款计划">
+      <app-contract-management-contract-file-add-collection-plan #collectionPlan>
 
-    </app-contract-management-contract-file-add-collection-plan>
-  </nz-tab>
-</nz-tabset>
+      </app-contract-management-contract-file-add-collection-plan>
+    </nz-tab>
+  </nz-tabset>
+</nz-spin>
+<!-- 按钮 -->
+<div class="base">
+  <!-- 关闭按钮 -->
+  <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)="save()"
+    [nzLoading]="isLoadingSave"><span>{{'pm.finish' | translate}}</span></button>
+</div>

+ 75 - 8
src/app/routes/contract-management/contract-file/add/add.component.ts

@@ -1,5 +1,5 @@
 import { Component, OnInit, ViewChild } from '@angular/core';
-import { NzModalRef, NzMessageService } from 'ng-zorro-antd';
+import { NzModalRef, NzMessageService, NzDrawerRef, NzNotificationService } from 'ng-zorro-antd';
 import { _HttpClient } from '@delon/theme';
 import { BaseArchivesProjectApprovalService } from 'app/services/basedata/base-archives-project-approval.service';
 import { DictService } from 'app/services/dict.service';
@@ -14,10 +14,28 @@ import { BaseArchivesCollectionLine } from 'app/entity/basedata/base-archives-co
 import { BaseArchivesCollectionLineService } from 'app/services/basedata/base-archives-collection-line.service';
 import { BaseArchivesMilestone } from 'app/entity/basedata/base-archives-milestone';
 import { BaseArchivesMilestoneService } from 'app/services/basedata/base-archives-milestone.service';
+import { ContractFileService } from 'app/services/contract-management/contract-file.service';
+import { I18NService } from '@core';
+import { DatePipe } from '@angular/common';
 
 @Component({
   selector: 'app-contract-management-contract-file-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 ContractManagementContractFileAddComponent implements OnInit {
   constructor(
@@ -25,7 +43,12 @@ export class ContractManagementContractFileAddComponent implements OnInit {
     private dictService: DictService,
     private personnelService: PersonnelService,
     private baseArchivesCollectionLineService: BaseArchivesCollectionLineService,
-    private baseArchivesMilestoneService:BaseArchivesMilestoneService
+    private baseArchivesMilestoneService: BaseArchivesMilestoneService,
+    private drawerRef: NzDrawerRef,
+    private contractFileService: ContractFileService,
+    private nzNotificationService: NzNotificationService,
+    private i18NService: I18NService,
+    private datePipe: DatePipe,
   ) {}
 
   ngOnInit(): void {
@@ -101,11 +124,18 @@ export class ContractManagementContractFileAddComponent implements OnInit {
    * 产品与模块改变数据传值到其他页面
    */
   contractFileObject(contractFile: ContractFile) {
-    console.log(contractFile);
-    //产品中计算的标准报价总和传入基本信息
-    this.essentialInformation.contractFile.standardQuotation = contractFile.standardQuotation;
-    //计算折扣率
-    this.essentialInformation.calculation()
+    if (contractFile.standardQuotation) {
+      //产品中计算的标准报价总和传入基本信息标准报价
+      this.essentialInformation.contractFile.standardQuotation = contractFile.standardQuotation;
+      //计算折扣率
+      this.essentialInformation.calculation();
+    }
+    if (contractFile.transactionAmount) {
+      //产品中计算的折扣后单价总和传入基本信息成交金额
+      this.essentialInformation.contractFile.transactionAmount = contractFile.transactionAmount;
+      //触发成交金额的改变事件计算
+      this.essentialInformation.transactionAmountBlur();
+    }
   }
 
   /**
@@ -143,5 +173,42 @@ export class ContractManagementContractFileAddComponent implements OnInit {
     });
   }
 
-  close() {}
+  isLoadingSave = false; //保存按钮加载属性
+  save() {
+    return new Promise(resolve => {
+      if (this.essentialInformation.submitForm()) {
+        this.isLoadingSave = true;
+        let contractFile = new ContractFile();
+        contractFile = JSON.parse(JSON.stringify(this.essentialInformation.contractFile)); //获取基本信息的合同对象
+        //时间处理
+        contractFile.freeAfterSalesStart = this.datePipe.transform(contractFile.freeAfterSalesStart, 'yyyy-MM-dd');
+        contractFile.freeAfterSalesEnd = this.datePipe.transform(contractFile.freeAfterSalesEnd, 'yyyy-MM-dd');
+        contractFile.contractDate = this.datePipe.transform(contractFile.contractDate, 'yyyy-MM-dd');
+        contractFile.pkOrg = sessionStorage.getItem('pkOrg'); //组织id
+        contractFile.contractFileProductList = this.productModule.productList; //产品以及模块数据
+        //收款计划与回款计划
+        let contractFileAndBusinessList = this.collectionPlan.collectionPlanList.concat(
+          this.collectionPlan.paymentCollectionList,
+        );
+        contractFile.contractFileAndBusinessList = contractFileAndBusinessList;
+        this.contractFileService.saveMainAndChild(contractFile).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'), '');
+          }
+        });
+      }
+    });
+  }
+
+  close() {
+    this.drawerRef.close();
+  }
 }

+ 43 - 25
src/app/routes/contract-management/contract-file/add/essential-information/essential-information.component.html

@@ -26,6 +26,37 @@
           </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>
+            <nz-date-picker nzFormat="yyyy-MM-dd" formControlName="contractDate" id="contractDate"
+              [(ngModel)]="contractFile.contractDate"></nz-date-picker>
+            <nz-form-explain
+              *ngIf="validateForm.get('contractDate')?.dirty && validateForm.get('contractDate')?.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" [nzXs]="24" nzRequired>里程碑类型</nz-form-label>
+          <nz-form-control [nzSm]="24" [nzXs]="24">
+            <nz-select style="widows: 100%;" nzShowSearch nzAllowClear formControlName="milestoneId" id="milestoneId"
+              [(ngModel)]="contractFile.milestoneId" nzPlaceHolder="请选择" (ngModelChange)="milestoneChange($event)">
+              <nz-option *ngFor="let i of milestoneList" [nzValue]="i.value" [nzLabel]="i.text"></nz-option>
+            </nz-select>
+            <nz-form-explain *ngIf="validateForm.get('milestoneId')?.dirty && validateForm.get('milestoneId')?.errors">
+              请选择里程碑
+            </nz-form-explain>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+    <div nz-row [nzGutter]="24">
       <!-- 免费售后起始 -->
       <div nz-col [nzSpan]="6">
         <nz-form-item>
@@ -54,26 +85,9 @@
           </nz-form-explain>
         </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" [nzXs]="24" nzRequired>里程碑类型</nz-form-label>
-          <nz-form-control [nzSm]="24" [nzXs]="24">
-            <nz-select style="widows: 100%;" nzShowSearch nzAllowClear formControlName="milestoneId" id="milestoneId"
-              [(ngModel)]="contractFile.milestoneId" nzPlaceHolder="请选择"
-              (ngModelChange)="milestoneChange($event)">
-              <nz-option *ngFor="let i of milestoneList" [nzValue]="i.value" [nzLabel]="i.text"></nz-option>
-            </nz-select>
-            <nz-form-explain *ngIf="validateForm.get('milestoneId')?.dirty && validateForm.get('milestoneId')?.errors">
-              请选择里程碑
-            </nz-form-explain>
-          </nz-form-control>
-        </nz-form-item>
-      </div>
+
       <!-- 合同概述 -->
-      <div nz-col [nzSpan]="18">
+      <div nz-col [nzSpan]="12">
         <nz-form-item>
           <nz-form-label [nzSpan]="'vertical' ? 24 : null">合同概述</nz-form-label>
           <nz-form-control [nzSm]="24" [nzXs]="24">
@@ -186,7 +200,8 @@
           <nz-form-label [nzSpan]="'vertical' ? 24 : null">标准报价</nz-form-label>
           <nz-form-explain>
             <nz-input-number [(ngModel)]="contractFile.standardQuotation" formControlName="standardQuotation"
-              id="standardQuotation" [nzDisabled]="true" [nzMin]="0" [nzFormatter]="formatterDollar" [nzParser]="parserDollar">
+              id="standardQuotation" [nzDisabled]="true" [nzMin]="0" [nzFormatter]="formatterDollar"
+              [nzParser]="parserDollar">
             </nz-input-number>
           </nz-form-explain>
         </nz-form-item>
@@ -196,8 +211,9 @@
         <nz-form-item>
           <nz-form-label [nzSpan]="'vertical' ? 24 : null">成交金额</nz-form-label>
           <nz-form-explain>
-            <nz-input-number [(ngModel)]="contractFile.transactionAmount" (nzBlur)="transactionAmountBlur()" formControlName="transactionAmount"
-              id="transactionAmount" [nzMin]="0" [nzFormatter]="formatterDollar" [nzParser]="parserDollar">
+            <nz-input-number [(ngModel)]="contractFile.transactionAmount" [nzDisabled]="true"
+              (nzBlur)="transactionAmountBlur()" formControlName="transactionAmount" id="transactionAmount" [nzMin]="0"
+              [nzFormatter]="formatterDollar" [nzParser]="parserDollar">
             </nz-input-number>
           </nz-form-explain>
         </nz-form-item>
@@ -254,7 +270,8 @@
           <nz-form-label [nzSpan]="'vertical' ? 24 : null">合同利润</nz-form-label>
           <nz-form-explain>
             <nz-input-number [(ngModel)]="contractFile.contractProfit" formControlName="contractProfit"
-              id="contractProfit" [nzMin]="0" [nzDisabled]="true" [nzFormatter]="formatterDollar" [nzParser]="parserDollar">
+              id="contractProfit" [nzMin]="0" [nzDisabled]="true" [nzFormatter]="formatterDollar"
+              [nzParser]="parserDollar">
             </nz-input-number>
           </nz-form-explain>
         </nz-form-item>
@@ -275,8 +292,9 @@
         <nz-form-item>
           <nz-form-label [nzSpan]="'vertical' ? 24 : null">应收款账</nz-form-label>
           <nz-form-explain>
-            <nz-input-number [nzDisabled]="true" [(ngModel)]="contractFile.accountsReceivable" formControlName="accountsReceivable"
-              id="accountsReceivable" [nzMin]="0" [nzFormatter]="formatterDollar" [nzParser]="parserDollar">
+            <nz-input-number [nzDisabled]="true" [(ngModel)]="contractFile.accountsReceivable"
+              formControlName="accountsReceivable" id="accountsReceivable" [nzMin]="0" [nzFormatter]="formatterDollar"
+              [nzParser]="parserDollar">
             </nz-input-number>
           </nz-form-explain>
         </nz-form-item>

+ 9 - 1
src/app/routes/contract-management/contract-file/add/essential-information/essential-information.component.ts

@@ -49,6 +49,7 @@ export class ContractManagementContractFileAddEssentialInformationComponent impl
       performanceCalculationRate: [],
       milestoneId: [],
       received: [],
+      contractDate:[null, [Validators.required]]
     });
   }
   user=this.settingsService.user//当前登录用户信息
@@ -309,7 +310,14 @@ export class ContractManagementContractFileAddEssentialInformationComponent impl
     }
   }
 
-  submitForm() {}
+  submitForm() {
+    for (const i in this.validateForm.controls) {
+      this.validateForm.controls[i].markAsDirty();
+      this.validateForm.controls[i].updateValueAndValidity();
+    }
+    let valid = this.validateForm.valid;
+    return valid;
+  }
 
   close() {}
 }

+ 13 - 7
src/app/routes/contract-management/contract-file/add/product-module/product-module.component.html

@@ -28,7 +28,7 @@
         </thead>
         <tbody>
           <tr *ngFor="let data of productRowTable.data" class="editable-row">
-            <td><input type="text" nz-input [(ngModel)]="data.code" /></td>
+            <td><input type="text" nz-input [(ngModel)]="data.code" disabled="true" /></td>
             <td>
               <nz-input-group nzSearch [nzAddOnAfter]="suffixIconButton">
                 <input type="text" [(ngModel)]="data.name" nz-input
@@ -42,14 +42,14 @@
               </ng-template>
             </td>
             <td>
-              <nz-input-number [nzMin]="0" [(ngModel)]="data.discountRate"></nz-input-number>
+              <nz-input-number [nzMin]="0" [(ngModel)]="data.discountRate" [nzFormatter]="formatterDollar2" [nzParser]="parserDollar2"></nz-input-number>
             </td>
             <td>
               <nz-input-number [nzMin]="0" [nzDisabled]="true" [(ngModel)]="data.standardQuotation"
                 [nzFormatter]="formatterDollar" [nzParser]="parserDollar"></nz-input-number>
             </td>
             <td>
-              <nz-input-number [nzMin]="0" [(ngModel)]="data.unitPriceAfterDiscount" [nzFormatter]="formatterDollar"
+              <nz-input-number [nzMin]="0" [(ngModel)]="data.unitPriceAfterDiscount" (nzBlur)="unitPriceAfterDiscountBlur(data)" [nzFormatter]="formatterDollar"
                 [nzParser]="parserDollar"></nz-input-number>
             </td>
             <td>
@@ -107,14 +107,20 @@
             </thead>
             <tbody>
               <tr *ngFor="let data of moduleRowTable.data" class="editable-row">
-                <td><input type="text" nz-input [(ngModel)]="data.code" /></td>
-                <td><input type="text" nz-input [(ngModel)]="data.name" /></td>
+                <td><input disabled="true" type="text" nz-input [(ngModel)]="data.code" /></td>
                 <td>
-                  <nz-input-number [nzMin]="0" [(ngModel)]="data.standardQuotation" [nzFormatter]="formatterDollar"
+                  <nz-select style="width:100%" nzShowSearch nzAllowClear [(ngModel)]="data.baseMaterialFileModularId"
+                    nzPlaceHolder="请选择" (ngModelChange)="baseMaterialFileModularIdChange(product,data,$event)">
+                    <nz-option *ngFor="let i of product.modularListSelect" [nzValue]="i.id" [nzLabel]="i.name">
+                    </nz-option>
+                  </nz-select>
+                </td>
+                <td>
+                  <nz-input-number [nzMin]="0" [nzDisabled]="true" [(ngModel)]="data.standardQuotation" [nzFormatter]="formatterDollar"
                     [nzParser]="parserDollar" (ngModelChange)="standardQuotationModuleKeyUp(product)"></nz-input-number>
                 </td>
                 <td>
-                  <nz-input-number [nzMin]="0" [(ngModel)]="data.purchasePrice" [nzFormatter]="formatterDollar"
+                  <nz-input-number [nzMin]="0" [(ngModel)]="data.purchasePrice"  [nzFormatter]="formatterDollar"
                     [nzParser]="parserDollar"></nz-input-number>
                 </td>
                 <td>

+ 97 - 5
src/app/routes/contract-management/contract-file/add/product-module/product-module.component.ts

@@ -5,6 +5,9 @@ import { ContractFileProduct } from 'app/entity/contract-management/contract-fil
 import { ContractFileModular } from 'app/entity/contract-management/contract-file-modular';
 import { ContractFile } from 'app/entity/contract-management/contract-file';
 import { RoutesSharedModalProdutSelectComponent } from 'app/routes/shared/modal/produt-select/produt-select.component';
+import { ContractFileModularService } from 'app/services/contract-management/contract-file-modular.service';
+import { BaseMaterialFileModular } from 'app/entity/basedata/base-material-file-modular';
+import { BaseMaterialFileModularService } from 'app/services/basedata/base-material-file-modular.service';
 
 @Component({
   selector: 'app-contract-management-contract-file-add-product-module',
@@ -12,7 +15,8 @@ import { RoutesSharedModalProdutSelectComponent } from 'app/routes/shared/modal/
 })
 export class ContractManagementContractFileAddProductModuleComponent implements OnInit {
   constructor(
-    private modalService:NzModalService
+    private modalService:NzModalService,
+    private baseMaterialFileModularService:BaseMaterialFileModularService
   ) {}
   ngOnInit(): void {}
 
@@ -20,6 +24,8 @@ export class ContractManagementContractFileAddProductModuleComponent implements
   // moduleList:ContractFileModular[]=[];//模块数据
   formatterDollar = (value: number): string => `¥ ${value}`;
   parserDollar = (value: string): string => value.replace('¥ ', '');
+  formatterDollar2 = (value: number): string => `${value}%`;
+  parserDollar2 = (value: string): string => value.replace('%', '');
 
   /**
    * 产品新增行
@@ -133,7 +139,7 @@ export class ContractManagementContractFileAddProductModuleComponent implements
   /**
    * 选择产品事件
    */
-  selectProdutModal(data) {
+  selectProdutModal(product) {
     const modalRef = this.modalService.create({
       nzTitle: '选择产品',
       nzContent: RoutesSharedModalProdutSelectComponent,
@@ -151,9 +157,11 @@ export class ContractManagementContractFileAddProductModuleComponent implements
           type: 'primary',
           onClick: addModel => {
             addModel.save().then(()=>{
-              data.code=addModel.selectObj[0].code
-              data.name=addModel.selectObj[0].name
-              data.baseMaterialFileProductId=addModel.selectObj[0].id
+              product.code=addModel.selectObj[0].code
+              product.name=addModel.selectObj[0].name
+              product.baseMaterialFileProductId=addModel.selectObj[0].id
+              //获取产品下的模块数据下拉供模块表格选择
+              this.getModuleListByPid(product);
             });
           },
         },
@@ -161,5 +169,89 @@ export class ContractManagementContractFileAddProductModuleComponent implements
     });
   }
 
+  /**
+   * 根据产品id查询所属模块集合(供模块表格下拉选择)
+   */
+  getModuleListByPid(product){
+      return new Promise((resolve)=>{
+        let baseMaterialFileModular=new BaseMaterialFileModular();
+        baseMaterialFileModular.baseMaterialFileProductId=product.baseMaterialFileProductId;
+        //查询当前选择产品的模块
+        this.baseMaterialFileModularService.list(baseMaterialFileModular).then((response)=>{
+          //放入产品对象中
+          if(response.success){
+            product.modularListSelect=JSON.parse(JSON.stringify(response.result.records))
+          }
+          resolve();
+        })
+      })
+  }
+
+  /**
+   * 模块选择触发事件
+   * 获取编码和名称
+   */
+  baseMaterialFileModularIdChange(product,data,event){
+    if(event){
+      product.modularListSelect.forEach(element => {
+        if(event==element.id){
+          data.code=element.code;
+          data.name=element.name;
+          data.standardQuotation=element.standardQuotation;
+        }
+      });
+    }else{
+      data.code="";
+      data.name="";
+    }
+    //计算标准报价
+    this.standardQuotationModuleKeyUp(product)
+  }
+
+  /**
+   * 折扣后单价改变事件
+   */
+  unitPriceAfterDiscountBlur(data){
+    //标准报价
+    let standardQuotation=this.getIsNaN("standardQuotation",data);
+    //折扣后单价
+    let unitPriceAfterDiscount=this.getIsNaN("unitPriceAfterDiscount",data);
+    //折扣率
+    if (unitPriceAfterDiscount > 0.0 && standardQuotation > 0.0) {
+      //(成交金额/标准报价)100
+      let discountRate = Number(((unitPriceAfterDiscount / standardQuotation) * 100).toFixed(2));
+      data.discountRate = discountRate;
+    }
+    //计算折扣单价总和
+    this.getUnitPriceAfterDiscountTotal();
+  }
+
+/**
+ * 计算折扣单价总和
+ */
+  getUnitPriceAfterDiscountTotal(){
+    //折扣后单价总和
+    let unitPriceAfterDiscountTotal=0.0;
+    if(this.productList){
+      this.productList.forEach(element => {
+        unitPriceAfterDiscountTotal=unitPriceAfterDiscountTotal+Number(element.unitPriceAfterDiscount);
+      });
+      //放到主对象中
+      this.contractFile.transactionAmount=unitPriceAfterDiscountTotal;
+      //传给父级页面
+      this.outContractFileObject();
+    }
+  }
+
+  /**
+   * 验证是否数字
+   */
+  getIsNaN(name,data) {
+    if (!isNaN(Number(data[name]))) {
+      return Number(data[name]);
+    } else {
+      return 0.0;
+    }
+  }
   close() {}
 }

+ 59 - 2
src/app/routes/contract-management/contract-file/contract-file.component.html

@@ -4,6 +4,63 @@
   </ng-template>
 </page-header>
 <nz-card>
-  <sf mode="search" [schema]="searchSchema" (formSubmit)="st.reset($event)" (formReset)="st.reset($event)"></sf>
-  <st #st [data]="url" [columns]="columns"></st>
+   <!-- 查询条件 -->
+   <form nz-form>
+    <div nz-row [nzGutter]="24">
+      <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)]="contractFile.code" />
+          </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]="24">
+    <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.code }}</td>
+            <td>{{ data.proName }}</td>
+            <td>{{ data.proName }}</td>
+            <td>{{ data.proName }}</td>
+            <td>{{ data.proName }}</td>
+            <td>{{ data.proName }}</td>
+            <td>{{ data.proName }}</td>
+            <td>
+              <a (click)="view(data.id)" >详情</a>
+              <nz-divider nzType="vertical" ></nz-divider>
+              <a (click)="update(data.id)" >修改</a>
+              <nz-divider nzType="vertical" ></nz-divider>
+              <a (click)="delete(data.id)" >删除</a>
+            </td>
+          </tr>
+        </tbody>
+      </nz-table>
+    </div>
+  </div>
 </nz-card>

+ 85 - 2
src/app/routes/contract-management/contract-file/contract-file.component.ts

@@ -5,6 +5,9 @@ import { SFSchema } from '@delon/form';
 import { NzDrawerService } from 'ng-zorro-antd';
 import { ContractManagementContractFileAddComponent } from './add/add.component';
 import { I18NService } from '@core';
+import { ContractFile } from 'app/entity/contract-management/contract-file';
+import { ContractFileService } from 'app/services/contract-management/contract-file.service';
+import { ContractManagementContractFileUpdateComponent } from './update/update.component';
 
 @Component({
   selector: 'app-contract-management-contract-file',
@@ -35,9 +38,89 @@ export class ContractManagementContractFileComponent implements OnInit {
     }
   ];
 
-  constructor(private nzDrawerService:NzDrawerService,private i18NService:I18NService) { }
+  constructor(private nzDrawerService:NzDrawerService,private i18NService:I18NService,
+    private contractFileService:ContractFileService) { }
 
-  ngOnInit() { }
+  ngOnInit() {
+    this.getList()
+   }
+
+  contractFile:ContractFile={}//合同对象
+  listOfData:ContractFile[]=[];//合同对象
+  page = {
+    total: 0,
+    current: 0,
+  }; //页码
+  isSpinning = false;
+
+  /**
+   * 查询按钮
+   */
+  query(){
+    this.contractFile.pageNo = 1;
+    this.getList();
+  }
+
+  //按页码显示数据
+  pageIndexChange(event) {
+    this.contractFile.pageNo = event; //当前页码
+    this.getList();
+  }
+
+  /**
+   * 查询
+   */
+  getList(){
+    return new Promise((resolve)=>{
+      this.isSpinning=true;
+      this.contractFile.pkOrg=sessionStorage.getItem("pkOrg");//组织
+      this.contractFileService.getList(this.contractFile).then((response)=>{
+        if(response.success){
+          this.listOfData=JSON.parse(JSON.stringify((response.result.records)));
+          this.page=JSON.parse(JSON.stringify(response.result))
+          this.isSpinning=false;
+          resolve()
+        }
+      })
+    })
+  }
+
+  /**
+   * 详情
+   */
+  view(id){
+
+  }
+
+  /**
+   * 修改
+   */
+  update(id){
+    const drawerRef = this.nzDrawerService.create({
+      nzTitle: this.i18NService.fanyi("table.update"),//修改标题
+      nzContent: ContractManagementContractFileUpdateComponent,
+      nzWidth: window.innerWidth,
+      nzBodyStyle: { height: 'calc(100% - 55px)', overflow: 'auto', 'padding-bottom': '53px' },
+      nzContentParams: {
+        //合同id
+        id: id
+      }
+    });
+
+    //关闭抽屉的回调
+    drawerRef.afterClose.subscribe((isRefresh) => {
+      if (isRefresh) {//刷新list列表
+        // this.getList();
+      }
+    });
+  }
+
+  /**
+   * 删除
+   */
+  delete(id){
+
+  }
 
   add() {
     const drawerRef = this.nzDrawerService.create({

+ 219 - 0
src/app/routes/contract-management/contract-file/update/collection-plan/collection-plan.component.html

@@ -0,0 +1,219 @@
+<!-- 收款计划 -->
+<nz-card nzTitle="收款计划" nzSize="small">
+  <div nz-row [nzGutter]="24">
+    <div nz-col [nzSpan]="24">
+      <!-- 新增按钮 -->
+      <button (click)="collectionPlanAdd()" 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]="collectionPlanList" [nzFrontPagination]="false" [nzShowPagination]="false" [nzScroll]="{x:'123vw'}">
+        <!-- <thead>
+          <tr>
+            <th>{{ 'customer.contacts.name' | translate }}</th>
+            <th>{{ 'customer.contacts.telephone' | translate }}</th>
+            <th>{{ 'customer.contacts.mail' | translate }}</th>
+            <th>{{ 'customer.is.it.default' | translate }}</th>
+            <th>{{ 'customer.contacts.client.address' | translate }}</th>
+            <th>{{ 'table.operation' | translate }}</th>
+          </tr>
+        </thead> -->
+        <tbody>
+          <tr *ngFor="let data of basicTable.data">
+            <td style="width: 7%;">
+              <nz-select style="width: 100%;" nzShowSearch nzAllowClear [(ngModel)]="data.planId" nzPlaceHolder="请选择"
+                [nzDropdownMatchSelectWidth]="false" (ngModelChange)="planIdChange(data,'1')">
+                <nz-option *ngFor="let i of planList" [nzValue]="i.id" [nzLabel]="i.name"></nz-option>
+              </nz-select>
+            </td>
+            <td style="width: 4%;">第一笔</td>
+            <td style="width: 4%;">
+              <nz-input-number [(ngModel)]="data.price1" [nzMin]="0" [nzStep]="1" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar" [nzMax]=1000000000 (nzBlur)="priceBlur()"></nz-input-number>
+            </td>
+            <td style="width: 5%;">
+              <nz-select style="width: 100%;" nzShowSearch nzAllowClear [(ngModel)]="data.mileId1" nzPlaceHolder="请选择"
+                [nzDropdownMatchSelectWidth]="false" (ngModelChange)="mileIdChange(data)">
+                <nz-option *ngFor="let i of milestoneList" [nzValue]="i.id" [nzLabel]="i.name"></nz-option>
+              </nz-select>
+            </td>
+            <td style="width: 5%;">
+              <input [(ngModel)]="data.desc1" nz-input maxlength=140 (blur)="descChange()"/>
+            </td>
+            <td style="width: 4%;">第二笔</td>
+            <td style="width: 4%;">
+              <nz-input-number [(ngModel)]="data.price2" [nzMin]="0" [nzStep]="1" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar" [nzMax]=1000000000 (nzBlur)="priceBlur()"></nz-input-number>
+            </td>
+            <td style="width: 5%;">
+              <nz-select style="width: 100%;" nzShowSearch nzAllowClear [(ngModel)]="data.mileId2" nzPlaceHolder="请选择"
+                [nzDropdownMatchSelectWidth]="false" (ngModelChange)="mileIdChange(data)">
+                <nz-option *ngFor="let i of milestoneList" [nzValue]="i.id" [nzLabel]="i.name"></nz-option>
+              </nz-select>
+            </td>
+            <td style="width: 5%;">
+              <input [(ngModel)]="data.desc2" nz-input maxlength=140 (blur)="descChange()"/>
+            </td>
+            <td style="width: 4%;">第三笔</td>
+            <td style="width: 4%;">
+              <nz-input-number [(ngModel)]="data.price3" [nzMin]="0" [nzStep]="1" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar" [nzMax]=1000000000 (nzBlur)="priceBlur()"></nz-input-number>
+            </td>
+            <td style="width: 5%;">
+              <nz-select style="width: 100%;" nzShowSearch nzAllowClear [(ngModel)]="data.mileId3" nzPlaceHolder="请选择"
+                [nzDropdownMatchSelectWidth]="false" (ngModelChange)="mileIdChange(data)">
+                <nz-option *ngFor="let i of milestoneList" [nzValue]="i.id" [nzLabel]="i.name"></nz-option>
+              </nz-select>
+            </td>
+            <td style="width: 5%;">
+              <input [(ngModel)]="data.desc3" nz-input maxlength=140 (blur)="descChange()"/>
+            </td>
+            <td style="width: 4%;">第四笔</td>
+            <td style="width: 4%;">
+              <nz-input-number [(ngModel)]="data.price4" [nzMin]="0" [nzStep]="1" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar" [nzMax]=1000000000 (nzBlur)="priceBlur()"></nz-input-number>
+            </td>
+            <td style="width: 5%;">
+              <nz-select style="width: 100%;" nzShowSearch nzAllowClear [(ngModel)]="data.mileId4" nzPlaceHolder="请选择"
+                [nzDropdownMatchSelectWidth]="false" (ngModelChange)="mileIdChange(data)">
+                <nz-option *ngFor="let i of milestoneList" [nzValue]="i.id" [nzLabel]="i.name"></nz-option>
+              </nz-select>
+            </td>
+            <td style="width: 5%;">
+              <input [(ngModel)]="data.desc4" nz-input maxlength=140 (blur)="descChange()"/>
+            </td>
+            <td style="width: 4%;">第五笔</td>
+            <td style="width: 4%;">
+              <nz-input-number [(ngModel)]="data.price5" [nzMin]="0" [nzStep]="1" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar" [nzMax]=1000000000 (nzBlur)="priceBlur()"></nz-input-number>
+            </td>
+            <td style="width: 5%;">
+              <nz-select style="width: 100%;" nzShowSearch nzAllowClear [(ngModel)]="data.mileId5" nzPlaceHolder="请选择"
+                [nzDropdownMatchSelectWidth]="false" (ngModelChange)="mileIdChange(data)">
+                <nz-option *ngFor="let i of milestoneList" [nzValue]="i.id" [nzLabel]="i.name"></nz-option>
+              </nz-select>
+            </td>
+            <td style="width: 5%;">
+              <input [(ngModel)]="data.desc5" nz-input maxlength=140 (blur)="descChange()"/>
+            </td>
+            <td nzRight="0"><a nz-popconfirm nzTitle="是否删除?"
+                (nzOnConfirm)="collectionPlanDelete(data.sort)">{{'table.delete'|translate}}</a></td>
+          </tr>
+        </tbody>
+      </nz-table>
+    </div>
+  </div>
+</nz-card>
+
+
+<!-- 回款情况 -->
+<nz-card nzTitle="回款情况" nzSize="small">
+  <div nz-row [nzGutter]="24">
+    <div nz-col [nzSpan]="24">
+      <!-- 新增按钮 -->
+      <!-- <button (click)="paymentCollectionAdd()" 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" #basicTable2
+        [nzData]="paymentCollectionList" [nzFrontPagination]="false" [nzShowPagination]="false"
+        [nzScroll]="{x:'123vw'}">
+        <!-- <thead>
+          <tr>
+            <th>{{ 'customer.contacts.name' | translate }}</th>
+            <th>{{ 'customer.contacts.telephone' | translate }}</th>
+            <th>{{ 'customer.contacts.mail' | translate }}</th>
+            <th>{{ 'customer.is.it.default' | translate }}</th>
+            <th>{{ 'customer.contacts.client.address' | translate }}</th>
+            <th>{{ 'table.operation' | translate }}</th>
+          </tr>
+        </thead> -->
+        <tbody>
+          <tr *ngFor="let data of basicTable2.data">
+            <td style="width: 7%;">
+              <nz-select style="width: 100%;" nzShowSearch nzAllowClear [(ngModel)]="data.planId" nzPlaceHolder="请选择"
+                [nzDropdownMatchSelectWidth]="false" (ngModelChange)="planIdChange(data,'2')" nzDisabled>
+                <nz-option *ngFor="let i of planList" [nzValue]="i.id" [nzLabel]="i.name"></nz-option>
+              </nz-select>
+            </td>
+            <td style="width: 4%;">第一笔</td>
+            <td style="width: 4%;">
+              <nz-input-number [(ngModel)]="data.price1" [nzMin]="0" [nzStep]="1" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar"  [nzMax]=1000000000 [disabled]="true"></nz-input-number>
+            </td>
+            <td style="width: 5%;">
+              <nz-select style="width: 100%;" nzShowSearch nzAllowClear [(ngModel)]="data.mileId1" nzPlaceHolder="请选择"
+                [nzDropdownMatchSelectWidth]="false" (ngModelChange)="mileChange(data)" nzDisabled>
+                <nz-option *ngFor="let i of milestoneList" [nzValue]="i.id" [nzLabel]="i.name"></nz-option>
+              </nz-select>
+            </td>
+            <td style="width: 5%;">
+              <input [(ngModel)]="data.desc1" nz-input maxlength=140 [disabled]="true"/>
+            </td>
+            <td style="width: 4%;">第二笔</td>
+            <td style="width: 4%;">
+              <nz-input-number [(ngModel)]="data.price2" [nzMin]="0" [nzStep]="1" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar" [nzMax]=1000000000 [disabled]="true"></nz-input-number>
+            </td>
+            <td style="width: 5%;">
+              <nz-select style="width: 100%;" nzShowSearch nzAllowClear [(ngModel)]="data.mileId2" nzPlaceHolder="请选择"
+                [nzDropdownMatchSelectWidth]="false" (ngModelChange)="mileChange(data)" nzDisabled>
+                <nz-option *ngFor="let i of milestoneList" [nzValue]="i.id" [nzLabel]="i.name"></nz-option>
+              </nz-select>
+            </td>
+            <td style="width: 5%;">
+              <input [(ngModel)]="data.desc2" nz-input maxlength=140 [disabled]="true"/>
+            </td>
+            <td style="width: 4%;">第三笔</td>
+            <td style="width: 4%;">
+              <nz-input-number [(ngModel)]="data.price3" [nzMin]="0" [nzStep]="1" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar" [nzMax]=1000000000 [disabled]="true"></nz-input-number>
+            </td>
+            <td style="width: 5%;">
+              <nz-select style="width: 100%;" nzShowSearch nzAllowClear [(ngModel)]="data.mileId3" nzPlaceHolder="请选择"
+                [nzDropdownMatchSelectWidth]="false" (ngModelChange)="mileChange(data)" nzDisabled>
+                <nz-option *ngFor="let i of milestoneList" [nzValue]="i.id" [nzLabel]="i.name"></nz-option>
+              </nz-select>
+            </td>
+            <td style="width: 5%;">
+              <input [(ngModel)]="data.desc3" nz-input maxlength=140 [disabled]="true"/>
+            </td>
+            <td style="width: 4%;">第四笔</td>
+            <td style="width: 4%;">
+              <nz-input-number [(ngModel)]="data.price4" [nzMin]="0" [nzStep]="1" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar" [nzMax]=1000000000 [disabled]="true"></nz-input-number>
+            </td>
+            <td style="width: 5%;">
+              <nz-select style="width: 100%;" nzShowSearch nzAllowClear [(ngModel)]="data.mileId4" nzPlaceHolder="请选择"
+                [nzDropdownMatchSelectWidth]="false" (ngModelChange)="mileChange(data)" nzDisabled>
+                <nz-option *ngFor="let i of milestoneList" [nzValue]="i.id" [nzLabel]="i.name"></nz-option>
+              </nz-select>
+            </td>
+            <td style="width: 5%;">
+              <input [(ngModel)]="data.desc4" nz-input maxlength=140 [disabled]="true"/>
+            </td>
+            <td style="width: 4%;">第五笔</td>
+            <td style="width: 4%;">
+              <nz-input-number [(ngModel)]="data.price5" [nzMin]="0" [nzStep]="1" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar" [nzMax]=1000000000 [disabled]="true"></nz-input-number>
+            </td>
+            <td style="width: 5%;">
+              <nz-select style="width: 100%;" nzShowSearch nzAllowClear [(ngModel)]="data.mileId5" nzPlaceHolder="请选择"
+                [nzDropdownMatchSelectWidth]="false" (ngModelChange)="mileChange(data)" nzDisabled>
+                <nz-option *ngFor="let i of milestoneList" [nzValue]="i.id" [nzLabel]="i.name"></nz-option>
+              </nz-select>
+            </td>
+            <td style="width: 5%;">
+              <input [(ngModel)]="data.desc5" nz-input maxlength=140 [disabled]="true"/>
+            </td>
+            <td nzRight="0"><a nz-popconfirm nzTitle="是否删除?"
+              (nzOnConfirm)="paymentCollectionDelete(data.sort)">{{'table.delete'|translate}}</a></td>
+          </tr>
+        </tbody>
+      </nz-table>
+    </div>
+  </div>
+</nz-card>

+ 24 - 0
src/app/routes/contract-management/contract-file/update/collection-plan/collection-plan.component.spec.ts

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

+ 240 - 0
src/app/routes/contract-management/contract-file/update/collection-plan/collection-plan.component.ts

@@ -0,0 +1,240 @@
+import { Component, OnInit } from '@angular/core';
+import { NzModalRef, NzMessageService } from 'ng-zorro-antd';
+import { _HttpClient } from '@delon/theme';
+
+@Component({
+  selector: 'app-contract-management-contract-file-update-collection-plan',
+  templateUrl: './collection-plan.component.html',
+})
+export class ContractManagementContractFileUpdateCollectionPlanComponent implements OnInit {
+
+  constructor() {}
+
+  collectionPlanList = []; //收款计划数据
+  paymentCollectionList = []; //汇款计划数据
+  planList: any = []; //计划下来集合数据
+  milestoneList: any = []; //里程碑集合数据
+  formatterDollar = (value: number) => {
+    if (value) {
+      return `¥ ${value}`;
+    } else {
+      return `¥ `;
+    }
+  };
+  parserDollar = (value: string) => value.replace('¥ ', '');
+
+  /**
+   * 
+   收款计划新增
+   */
+  collectionPlanSort = 0; //收款计划排序
+  collectionPlanAdd() {
+    this.collectionPlanList = [
+      ...this.collectionPlanList,
+      {
+        price1: 0,
+        price2: 0,
+        price3: 0,
+        price4: 0,
+        price5: 0,
+        sort: this.collectionPlanSort,
+        planType: '1',
+      },
+    ];
+    this.collectionPlanSort++;
+    //回款计划新增
+    this.paymentCollectionAdd();
+  }
+
+  /**
+   * 回款计划新增
+   */
+  paymentCollectionSort = 0; //回款情况排序
+  paymentCollectionAdd() {
+    this.paymentCollectionList = [
+      ...this.paymentCollectionList,
+      {
+        price1: 0,
+        price2: 0,
+        price3: 0,
+        price4: 0,
+        price5: 0,
+        sort: this.paymentCollectionSort,
+        planType: '2',
+      },
+    ];
+    this.paymentCollectionSort++;
+  }
+
+  /**
+   * 类型触发事件
+   */
+  planIdChange(data, type) {
+    //获取类型名称
+    this.getPlanName(data);
+    //同步其他三个表格数据
+    this.getData();
+  }
+
+  /**
+   * 获取类型名称
+   * @param data 计划对象
+   */
+  getPlanName(data) {
+    this.planList.forEach(element => {
+      if (element.id === data.planId) {
+        data.planName = element.name;
+      }
+    });
+  }
+
+  //根据计划收款信息表格数据复制到其他三个表格数据
+  getData() {
+    if (this.collectionPlanList) {
+      this.getAddData(this.collectionPlanList);
+    }
+  }
+
+  /**
+   * 根据计划收款信息表格数据复制到其他三个表格数据
+   *
+   */
+  getAddData(dataList) {
+    this.paymentCollectionList = [];
+    this.paymentCollectionList = [];
+    //循环收款情况
+    dataList.forEach(element => {
+      //回款表格数据
+      let data = {
+        planId: element.planId, //计划条线id
+        planName: element.planName, //计划条线名称
+        price1: element.price1, //金额
+        mileId1: element.mileId1, //里程碑id
+        milestone1: element.milestone1, //里程碑名称
+        price2: element.price2, //金额
+        mileId2: element.mileId2, //里程碑id
+        milestone2: element.milestone2, //里程碑名称
+        price3: element.price3, //金额
+        mileId3: element.mileId3, //里程碑id
+        milestone3: element.milestone3, //里程碑名称
+        price4: element.price4, //金额
+        mileId4: element.mileId4, //里程碑id
+        milestone4: element.milestone4, //里程碑名称
+        price5: element.price5, //金额
+        mileId5: element.mileId5, //里程碑id
+        milestone5: element.milestone5, //里程碑名称
+        sort: element.sort,
+        planType: '2',
+      };
+      //回款情况
+      let data2 = JSON.parse(JSON.stringify(data));
+      data2.planType = '2';
+      this.paymentCollectionList.push(data2);
+    });
+  }
+
+  /**
+   * 金额鼠标离开事件
+   */
+  priceBlur() {
+    this.getData();
+  }
+
+  /**
+   * 获取里程碑名称
+   */
+  getMileName(element) {
+    //判断是否选择里程碑
+    if (element.mileId1) {
+      //循环商务页签中计划表中里程碑下拉数据获取名称
+      this.milestoneList.forEach(mile => {
+        if (mile.id === element.mileId1) {
+          element.milestone1 = mile.name;
+        }
+      });
+    } else {
+      element.milestone1 = '';
+    }
+    //判断是否选择里程碑
+    if (element.mileId2) {
+      //循环商务页签中计划表中里程碑下拉数据获取名称
+      this.milestoneList.forEach(mile => {
+        if (mile.id === element.mileId2) {
+          element.milestone2 = mile.name;
+        }
+      });
+    } else {
+      element.milestone2 = '';
+    }
+    //判断是否选择里程碑
+    if (element.mileId3) {
+      //循环商务页签中计划表中里程碑下拉数据获取名称
+      this.milestoneList.forEach(mile => {
+        if (mile.id === element.mileId3) {
+          element.milestone3 = mile.name;
+        }
+      });
+    } else {
+      element.milestone3 = '';
+    }
+    //判断是否选择里程碑
+    if (element.mileId4) {
+      //循环商务页签中计划表中里程碑下拉数据获取名称
+      this.milestoneList.forEach(mile => {
+        if (mile.id === element.mileId4) {
+          element.milestone4 = mile.name;
+        }
+      });
+    } else {
+      element.milestone4 = '';
+    }
+    //判断是否选择里程碑
+    if (element.mileId5) {
+      //循环商务页签中计划表中里程碑下拉数据获取名称
+      this.milestoneList.forEach(mile => {
+        if (mile.id === element.mileId5) {
+          element.milestone5 = mile.name;
+        }
+      });
+    } else {
+      element.milestone5 = '';
+    }
+  }
+
+  /**
+   * 里程碑选择事件
+   */
+  mileIdChange(data) {
+    //获取里程碑名称
+    this.getMileName(data);
+    //同步其他表格数据
+    this.getData();
+  }
+
+  /**
+   * 描述输入改变事件
+   */
+  descChange() {
+    this.getData();
+  }
+
+  /**
+   * 收款删除按钮
+   */
+  collectionPlanDelete(sort) {
+    this.collectionPlanList = this.collectionPlanList.filter(d => d.sort !== sort);
+    //回款删除
+    this.paymentCollectionDelete(sort);
+  }
+
+  /**
+   * 回款删除
+   */
+  paymentCollectionDelete(sort){
+    this.paymentCollectionList = this.paymentCollectionList.filter(d => d.sort !== sort);
+  }
+
+  ngOnInit(): void {}
+
+  close() {}
+}

+ 358 - 0
src/app/routes/contract-management/contract-file/update/essential-information/essential-information.component.html

@@ -0,0 +1,358 @@
+<!-- 基本信息 -->
+<form nz-form [formGroup]="validateForm" (ngSubmit)="submitForm()">
+  <nz-card>
+    <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">
+            <input nz-input placeholder="自动生成" disabled="true" />
+          </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-tree-select style="width: 100%" [nzNodes]="proList" nzShowSearch [nzMultiple]="false"
+              formControlName="proId" id="proId" nzPlaceHolder="请选择" [(ngModel)]="contractFile.proId"
+              [nzMaxTagCount]="3" [nzAllowClear]="true" (ngModelChange)="proChange($event)">
+            </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 nz-col [nzSpan]="6">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null" nzRequired>合同日期</nz-form-label>
+          <nz-form-control>
+            <nz-date-picker nzFormat="yyyy-MM-dd" formControlName="contractDate" id="contractDate"
+              [(ngModel)]="contractFile.contractDate"></nz-date-picker>
+            <nz-form-explain
+              *ngIf="validateForm.get('contractDate')?.dirty && validateForm.get('contractDate')?.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" [nzXs]="24" nzRequired>里程碑类型</nz-form-label>
+          <nz-form-control [nzSm]="24" [nzXs]="24">
+            <nz-select style="widows: 100%;" nzShowSearch nzAllowClear formControlName="milestoneId" id="milestoneId"
+              [(ngModel)]="contractFile.milestoneId" nzPlaceHolder="请选择" (ngModelChange)="milestoneChange($event)">
+              <nz-option *ngFor="let i of milestoneList" [nzValue]="i.value" [nzLabel]="i.text"></nz-option>
+            </nz-select>
+            <nz-form-explain *ngIf="validateForm.get('milestoneId')?.dirty && validateForm.get('milestoneId')?.errors">
+              请选择里程碑
+            </nz-form-explain>
+          </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>
+            <nz-date-picker nzFormat="yyyy-MM-dd" formControlName="freeAfterSalesStart" id="freeAfterSalesStart"
+              [(ngModel)]="contractFile.freeAfterSalesStart" [nzDisabledDate]="disabledDate"></nz-date-picker>
+            <nz-form-explain
+              *ngIf="validateForm.get('freeAfterSalesStart')?.dirty && validateForm.get('freeAfterSalesStart')?.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-explain>
+            <nz-date-picker nzFormat="yyyy-MM-dd" formControlName="freeAfterSalesEnd" id="freeAfterSalesEnd"
+              [(ngModel)]="contractFile.freeAfterSalesEnd" [nzDisabledDate]="disabledDate2"></nz-date-picker>
+            <nz-form-explain
+              *ngIf="validateForm.get('freeAfterSalesEnd')?.dirty && validateForm.get('freeAfterSalesEnd')?.errors">
+              请选择免费售后截至
+            </nz-form-explain>
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+
+      <!-- 合同概述 -->
+      <div nz-col [nzSpan]="12">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">合同概述</nz-form-label>
+          <nz-form-control [nzSm]="24" [nzXs]="24">
+            <textarea rows="2" formControlName="overview" id="overview" nz-input [(ngModel)]="contractFile.overview"
+              placeholder="请输入合同概述"></textarea>
+          </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">
+            <nz-input-group nzSearch [nzAddOnAfter]="suffixIconButton">
+              <input type="text" [(ngModel)]="contractFile.fdCustomerName" formControlName="fdCustomerName"
+                id="fdCustomerName" nz-input placeholder="{{ 'select.please.choose' | translate }}" disabled="true" />
+            </nz-input-group>
+            <ng-template #suffixIconButton>
+              <!-- 放大镜  勾选列表 -->
+              <button nz-button nzType="primary" nzSearch (click)="modalTable()">
+                <i nz-icon type="search"></i>
+              </button>
+            </ng-template>
+            <nz-form-explain
+              *ngIf="validateForm.get('fdCustomerName')?.dirty && validateForm.get('fdCustomerName')?.errors">
+              请选择客户
+            </nz-form-explain>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+      <div nz-col [nzSpan]="18">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">客户地址</nz-form-label>
+          <nz-form-control [nzSm]="24" [nzXs]="24">
+            <input disabled="true" nz-input [(ngModel)]="contractFile.fdCustomeraddress"
+              formControlName="fdCustomeraddress" id="fdCustomeraddress" placeholder="客户地址" [disabled]="true" />
+          </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>
+            <nz-select style="widows: 100%;" nzShowSearch nzAllowClear formControlName="fdCustomerPersonnelId"
+              id="fdCustomerPersonnelId" [(ngModel)]="contractFile.fdCustomerPersonnelId" nzPlaceHolder="请选择"
+              (ngModelChange)="fdCustomerPersonnelChange($event)">
+              <nz-option *ngFor="let i of fdCustomerPersonnelList" [nzValue]="i.id" [nzLabel]="i.contactPsn">
+              </nz-option>
+            </nz-select>
+            <nz-form-explain
+              *ngIf="validateForm.get('fdCustomerPersonnelId')?.dirty && validateForm.get('fdCustomerPersonnelId')?.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">手机</nz-form-label>
+          <nz-form-control>
+            <input disabled="true" nz-input [(ngModel)]="contractFile.fdCustomerPersonnelTel"
+              formControlName="fdCustomerPersonnelTel" id="fdCustomerPersonnelTel" placeholder="客户地址"
+              [disabled]="true" />
+          </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>
+            <nz-tree-select [nzNodes]="salesStaffList" nzShowSearch formControlName="salesmanId" id="salesmanId"
+              nzAllowClear="false" [(ngModel)]="contractFile.salesmanId" (ngModelChange)="onChangeSalesmanId($event)"
+              nzPlaceHolder="{{ 'select.please.choose' | translate }}"></nz-tree-select>
+            <nz-form-explain *ngIf="validateForm.get('salesmanId')?.dirty && validateForm.get('salesmanId')?.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">业务类型</nz-form-label>
+          <nz-form-control [nzSm]="24" [nzXs]="24">
+            <nz-select style="widows: 100%;" nzShowSearch nzAllowClear formControlName="businessTypeDictId"
+              id="businessTypeDictId" [(ngModel)]="contractFile.businessTypeDictId" nzPlaceHolder="请选择"
+              (ngModelChange)="businessTypeDictIdChange($event)">
+              <nz-option *ngFor="let i of businessTypeDictList" [nzValue]="i.value" [nzLabel]="i.text"></nz-option>
+            </nz-select>
+            <nz-form-explain
+              *ngIf="validateForm.get('businessTypeDictId')?.dirty && validateForm.get('businessTypeDictId')?.errors">
+              请选择业务类型
+            </nz-form-explain>
+          </nz-form-control>
+        </nz-form-item>
+      </div>
+    </div>
+  </nz-card>
+  <nz-card>
+    <div nz-row [nzGutter]="24">
+      <!-- 标准报价 -->
+      <div nz-col [nzSpan]="4">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">标准报价</nz-form-label>
+          <nz-form-explain>
+            <nz-input-number [(ngModel)]="contractFile.standardQuotation" formControlName="standardQuotation"
+              id="standardQuotation" [nzDisabled]="true" [nzMin]="0" [nzFormatter]="formatterDollar"
+              [nzParser]="parserDollar">
+            </nz-input-number>
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+      <!-- 成交金额 -->
+      <div nz-col [nzSpan]="4">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">成交金额</nz-form-label>
+          <nz-form-explain>
+            <nz-input-number [(ngModel)]="contractFile.transactionAmount" [nzDisabled]="true"
+              (nzBlur)="transactionAmountBlur()" formControlName="transactionAmount" id="transactionAmount" [nzMin]="0"
+              [nzFormatter]="formatterDollar" [nzParser]="parserDollar">
+            </nz-input-number>
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+      <!-- 折扣率 -->
+      <div nz-col [nzSpan]="4">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">折扣率</nz-form-label>
+          <nz-form-explain>
+            <nz-input-number [(ngModel)]="contractFile.discountRate" formControlName="discountRate" id="discountRate"
+              [nzMin]="0" [nzFormatter]="formatterDollar2" [nzParser]="parserDollar2" [nzDisabled]="true">
+            </nz-input-number>
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+      <!-- 赠品金额 -->
+      <div nz-col [nzSpan]="4">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">赠品金额</nz-form-label>
+          <nz-form-explain>
+            <nz-input-number [(ngModel)]="contractFile.giftAmount" formControlName="giftAmount" id="giftAmount"
+              [nzMin]="0" [nzFormatter]="formatterDollar" [nzParser]="parserDollar">
+            </nz-input-number>
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+      <!-- 成本 -->
+      <div nz-col [nzSpan]="4">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">成本</nz-form-label>
+          <nz-form-explain>
+            <nz-input-number [(ngModel)]="contractFile.cost" formControlName="cost" id="cost" [nzMin]="0"
+              [nzFormatter]="formatterDollar" [nzParser]="parserDollar" (nzBlur)="costBlur()">
+            </nz-input-number>
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+      <!-- 合同费用 -->
+      <div nz-col [nzSpan]="4">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">合同费用</nz-form-label>
+          <nz-form-explain>
+            <nz-input-number [(ngModel)]="contractFile.contractCost" formControlName="contractCost" id="contractCost"
+              [nzMin]="0" [nzFormatter]="formatterDollar" [nzParser]="parserDollar" (nzBlur)="contractCostBlur()">
+            </nz-input-number>
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+    </div>
+    <div nz-row [nzGutter]="24">
+      <!-- 合同利润 -->
+      <div nz-col [nzSpan]="4">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">合同利润</nz-form-label>
+          <nz-form-explain>
+            <nz-input-number [(ngModel)]="contractFile.contractProfit" formControlName="contractProfit"
+              id="contractProfit" [nzMin]="0" [nzDisabled]="true" [nzFormatter]="formatterDollar"
+              [nzParser]="parserDollar">
+            </nz-input-number>
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+      <!-- 回款金额 -->
+      <div nz-col [nzSpan]="4">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">回款金额</nz-form-label>
+          <nz-form-explain>
+            <nz-input-number [nzDisabled]="true" [(ngModel)]="contractFile.received" formControlName="received"
+              id="received" [nzMin]="0" [nzFormatter]="formatterDollar" [nzParser]="parserDollar">
+            </nz-input-number>
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+      <!-- 应收款账 -->
+      <div nz-col [nzSpan]="4">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">应收款账</nz-form-label>
+          <nz-form-explain>
+            <nz-input-number [nzDisabled]="true" [(ngModel)]="contractFile.accountsReceivable"
+              formControlName="accountsReceivable" id="accountsReceivable" [nzMin]="0" [nzFormatter]="formatterDollar"
+              [nzParser]="parserDollar">
+            </nz-input-number>
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+      <!-- 业绩计算率 -->
+      <div nz-col [nzSpan]="4">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">业绩计算率</nz-form-label>
+          <nz-form-explain>
+            <nz-input-number [(ngModel)]="contractFile.performanceCalculationRate"
+              formControlName="performanceCalculationRate" id="performanceCalculationRate" [nzMin]="0"
+              [nzFormatter]="formatterDollar2" [nzParser]="parserDollar2">
+            </nz-input-number>
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+    </div>
+  </nz-card>
+  <nz-card>
+    <div nz-row [nzGutter]="24">
+      <!-- 制单人 -->
+      <div nz-col [nzSpan]="12">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">制单人</nz-form-label>
+          <nz-form-explain>
+            {{contractFile.createBy}}
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+      <!-- 制单时间 -->
+      <div nz-col [nzSpan]="12">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">制单时间</nz-form-label>
+          <nz-form-explain>
+            {{contractFile.createTime}}
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+    </div>
+    <div nz-row [nzGutter]="24">
+      <!-- 修改人 -->
+      <div nz-col [nzSpan]="12">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">修改人</nz-form-label>
+          <nz-form-explain>
+            {{contractFile.updateBy}}
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+      <!-- 修改时间 -->
+      <div nz-col [nzSpan]="12">
+        <nz-form-item>
+          <nz-form-label [nzSpan]="'vertical' ? 24 : null">修改时间</nz-form-label>
+          <nz-form-explain>
+            {{contractFile.updateTime}}
+          </nz-form-explain>
+        </nz-form-item>
+      </div>
+    </div>
+  </nz-card>
+</form>

+ 24 - 0
src/app/routes/contract-management/contract-file/update/essential-information/essential-information.component.spec.ts

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

+ 319 - 0
src/app/routes/contract-management/contract-file/update/essential-information/essential-information.component.ts

@@ -0,0 +1,319 @@
+import { Component, OnInit, Output, EventEmitter } from '@angular/core';
+import { NzModalRef, NzMessageService, NzModalService } from 'ng-zorro-antd';
+import { _HttpClient, SettingsService } from '@delon/theme';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { CustomerService } from 'app/services/basedata/customer.service';
+import { DatePipe } from '@angular/common';
+import { ContractFile } from 'app/entity/contract-management/contract-file';
+import { RoutesSharedModalCustomerSelectComponent } from 'app/routes/shared/modal/customer-select/customer-select.component';
+
+@Component({
+  selector: 'app-contract-management-contract-file-update-essential-information',
+  templateUrl: './essential-information.component.html',
+})
+export class ContractManagementContractFileUpdateEssentialInformationComponent implements OnInit {
+  constructor(
+    private fb: FormBuilder,
+    private modalService: NzModalService,
+    private customerService: CustomerService,
+    private settingsService: SettingsService,
+    private datePipe:DatePipe
+  ) {}
+
+  validateForm!: FormGroup;
+  ngOnInit(): void {
+    //初始化表单
+    this.validateForm = this.fb.group({
+      proId: [null, [Validators.required]],
+      overview: [],
+      businessTypeDictId: [],
+      fdCustomerName: [null, [Validators.required]],
+      fdCustomerPersonnelId: [null, [Validators.required]],
+      fdCustomeraddress: [],
+      fdCustomerPersonnelTel: [],
+      salesmanId: [null, [Validators.required]],
+      freeAfterSalesStart: [null, [Validators.required]],
+      freeAfterSalesEnd: [null, [Validators.required]],
+      standardQuotation: [],
+      transactionAmount: [],
+      discountRate: [],
+      giftAmount: [],
+      cost: [],
+      contractCost: [],
+      contractProfit: [],
+      accountsReceivable: [],
+      performanceCalculationRate: [],
+      milestoneId: [],
+      received: [],
+      contractDate:[null, [Validators.required]]
+    });
+  }
+  user=this.settingsService.user//当前登录用户信息
+  contractFile: ContractFile = {
+    standardQuotation: 0,
+    transactionAmount: 0,
+    discountRate: 0,
+    giftAmount: 0,
+    cost: 0,
+    contractCost: 0,
+    contractProfit: 0,
+    accountsReceivable: 0,
+    performanceCalculationRate: 0,
+    received: 0,
+    createBy:this.user.realname,
+    createTime:this.datePipe.transform(new Date(), 'yyyy-MM-dd HH:mm:ss')
+  }; //合同对象
+  proList: any = []; //项目下拉集合
+  businessTypeDictList: any = []; //业务类型集合
+  salesStaffList: any = []; //销售人员tree下拉数据
+  formatterDollar = (value: number): string => `¥ ${value}`;
+  parserDollar = (value: string): string => value.replace('¥ ', '');
+  milestoneList: any = []; //里程碑类型
+  formatterDollar2 = (value: number): string => `${value}%`;
+  parserDollar2 = (value: string): string => value.replace('%', '');
+
+  /**
+   * 项目名称下拉款触发事件
+   */
+  proChange(event) {
+    if (!event) {
+      this.contractFile.proId = '';
+    }
+  }
+
+  /**
+   * 客户选择
+   */
+  modalTable() {
+    const modalRef = this.modalService.create({
+      nzTitle: '选择客户',
+      nzContent: RoutesSharedModalCustomerSelectComponent,
+      nzWidth: 1400,
+      nzFooter: [
+        {
+          label: '关闭',
+          type: 'default',
+          onClick: addModel => {
+            addModel.handleCancel();
+          },
+        },
+        {
+          label: '确定',
+          type: 'primary',
+          onClick: addModel => {
+            addModel.handleOk();
+            // addModel.selectObj 包含勾选项的 id 和 name
+            this.contractFile.fdCustomerName = addModel.selectObj[0].name;
+            this.contractFile.fdCustomerId = addModel.selectObj[0].id;
+            //查询客户的联系人
+            this.getLdCustomerPersonnelList();
+          },
+        },
+      ],
+    });
+  }
+
+  /**
+   * 根据客户获取客户人员数据
+   */
+  fdCustomerPersonnelList: any = [];
+  getLdCustomerPersonnelList() {
+    return new Promise(resolve => {
+      this.customerService.getContactsByMainId(this.contractFile.fdCustomerId).then(response => {
+        this.fdCustomerPersonnelList = response.result;
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 客户人员选择事件
+   */
+  fdCustomerPersonnelChange(event) {
+    if (event) {
+      this.fdCustomerPersonnelList.forEach(element => {
+        if (element.id == event) {
+          this.contractFile.fdCustomerPersonnelTel = element.contectTel;
+        }
+      });
+    } else {
+      this.contractFile.fdCustomerPersonnelId = '';
+      this.contractFile.fdCustomerPersonnelTel = '';
+    }
+  }
+
+  /**
+   * 业务类型选择事件
+   */
+  businessTypeDictIdChange(event) {
+    if (!event) {
+      this.contractFile.businessTypeDictId = '';
+    }
+  }
+
+  /**
+   * 销售人员选择时间
+   * @param event
+   */
+  onChangeSalesmanId(event) {
+    if (event) {
+      //获取人员名称
+      this.salesStaffList.forEach(pkOrg => {
+        pkOrg.children.forEach(depart => {
+          depart.children.forEach(personnel => {
+            if (personnel.key === event) {
+              this.contractFile.salesmanName = personnel.name;
+            }
+          });
+        });
+      });
+    } else {
+      this.contractFile.salesmanName = '';
+    }
+  }
+
+  /**
+   * 免费售后起始
+   */
+  disabledDate = (current: Date): boolean => {
+    // Can not select days before today and today
+    if (this.contractFile.freeAfterSalesEnd) {
+      let end = new Date(this.contractFile.freeAfterSalesEnd); //结束时间
+      //开始时间大于结束时间的禁用
+      return current.getTime() > end.getTime();
+    } else {
+      return false;
+    }
+  };
+
+  /**
+   * 免费售后截至
+   */
+  disabledDate2 = (current: Date): boolean => {
+    // Can not select days before today and today
+    if (this.contractFile.freeAfterSalesStart) {
+      let start = new Date(this.contractFile.freeAfterSalesStart); //开始时间
+      //结束时间小于开始时间禁用
+      return current.getTime() < start.getTime();
+    } else {
+      return false;
+    }
+  };
+
+  /**
+   * 里程碑类型选择事件
+   */
+  //回写里程碑类型到其他页签查询明细
+  @Output() milestone = new EventEmitter<{}>();
+  milestoneChange(event) {
+    if (event) {
+      // this.milestoneList.forEach(element => {
+      //   if (element.value === event) {
+      //     this.projectManageArchivesa.milestoneType = element.text;
+      //   }
+      // });
+      this.milestone.emit(this.contractFile);
+    }
+  }
+
+  /**
+   * 成交金额改变事件
+   */
+  transactionAmountBlur() {
+    //计算折扣率
+    this.calculation();
+    //计算应收金额
+    this.calculationAccountsReceivable();
+  }
+
+  /**
+   * 计算折扣率
+   */
+  calculation() {
+    /**计算折扣率*/
+    //标准报价
+    let standardQuotation = this.getIsNaN('standardQuotation');
+    //成交金额
+    let transactionAmount = this.getIsNaN('transactionAmount');
+    //折扣率
+    if (transactionAmount > 0.0 && standardQuotation > 0.0) {
+      //(成交金额/标准报价)100
+      let discountRate = Number(((transactionAmount / standardQuotation) * 100).toFixed(2));
+      this.contractFile.discountRate = discountRate;
+    }
+    //计算合同利润
+    this.calculationContractProfit();
+  }
+
+  /**
+   * 成本改变事件
+   */
+  costBlur() {
+    //计算合同利润
+    this.calculationContractProfit();
+  }
+
+  /**
+   * 合同费用改变事件
+   */
+  contractCostBlur() {
+    //计算合同利润
+    this.calculationContractProfit();
+  }
+
+  /**
+   * 计算合同利润
+   */
+  calculationContractProfit() {
+    //成交金额
+    let transactionAmount = this.getIsNaN('transactionAmount');
+    //成本
+    let cost = this.getIsNaN('cost');
+    //合同费用
+    let contractCost = this.getIsNaN('contractCost');
+    //合同利润
+    if (transactionAmount > 0.0) {
+      //成交金额-成本-合同费用
+      let contractProfit = transactionAmount - cost - contractCost;
+      this.contractFile.contractProfit = contractProfit;
+    }
+  }
+
+  /**
+   * 计算应收款账
+   */
+  calculationAccountsReceivable(){
+    //成交金额
+    let transactionAmount = this.getIsNaN('transactionAmount');
+    //回款金额
+    let received=this.getIsNaN("received");
+    //计算应收金额
+    if(transactionAmount>0.0){
+      //成交金额-回款金额
+      this.contractFile.accountsReceivable=transactionAmount-received;
+    }
+  }
+
+
+  /**
+   * 验证是否数字
+   */
+  getIsNaN(name) {
+    if (!isNaN(Number(this.contractFile[name]))) {
+      return Number(this.contractFile[name]);
+    } else {
+      return 0.0;
+    }
+  }
+
+  submitForm() {
+    for (const i in this.validateForm.controls) {
+      this.validateForm.controls[i].markAsDirty();
+      this.validateForm.controls[i].updateValueAndValidity();
+    }
+    let valid = this.validateForm.valid;
+    return valid;
+  }
+
+  close() {}
+}

+ 138 - 0
src/app/routes/contract-management/contract-file/update/product-module/product-module.component.html

@@ -0,0 +1,138 @@
+<!-- 产品 -->
+<nz-card nzTitle="产品">
+  <!-- 操作按钮 -->
+  <div nz-row [nzGutter]="24">
+    <div nz-col [nzSpan]="24">
+      <button nz-button (click)="productAddRow()" nzType="primary">新增</button>
+      <br />
+      <br />
+    </div>
+  </div>
+  <!-- 表格 -->
+  <div nz-row [nzGutter]="24">
+    <div nz-col [nzSpan]="24">
+      <nz-table #productRowTable nzSize="small" class="tableTdPadding" nzBordered [nzData]="productList">
+        <thead>
+          <tr>
+            <th nzWidth="10%">产品编码</th>
+            <th nzWidth="17%">产品名称</th>
+            <th nzWidth="9%">折扣率</th>
+            <th nzWidth="9%">标准报价</th>
+            <th nzWidth="9%">折扣后单价</th>
+            <th nzWidth="9%">标准金额</th>
+            <th nzWidth="9%">折扣后金额</th>
+            <th nzWidth="9%">成本单价</th>
+            <th nzWidth="9%">成本金额</th>
+            <th nzWidth="10%">操作</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr *ngFor="let data of productRowTable.data" class="editable-row">
+            <td><input type="text" nz-input [(ngModel)]="data.code" disabled="true" /></td>
+            <td>
+              <nz-input-group nzSearch [nzAddOnAfter]="suffixIconButton">
+                <input type="text" [(ngModel)]="data.name" nz-input
+                  placeholder="{{ 'select.please.choose' | translate }}" disabled="true" />
+              </nz-input-group>
+              <ng-template #suffixIconButton>
+                <!-- 放大镜  勾选列表 -->
+                <button nz-button nzType="primary" nzSearch (click)="selectProdutModal(data)">
+                  <i nz-icon type="search"></i>
+                </button>
+              </ng-template>
+            </td>
+            <td>
+              <nz-input-number [nzMin]="0" [(ngModel)]="data.discountRate" [nzFormatter]="formatterDollar2" [nzParser]="parserDollar2"></nz-input-number>
+            </td>
+            <td>
+              <nz-input-number [nzMin]="0" [nzDisabled]="true" [(ngModel)]="data.standardQuotation"
+                [nzFormatter]="formatterDollar" [nzParser]="parserDollar"></nz-input-number>
+            </td>
+            <td>
+              <nz-input-number [nzMin]="0" [(ngModel)]="data.unitPriceAfterDiscount" (nzBlur)="unitPriceAfterDiscountBlur(data)" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar"></nz-input-number>
+            </td>
+            <td>
+              <nz-input-number [nzMin]="0" [(ngModel)]="data.standardAmount" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar"></nz-input-number>
+            </td>
+            <td>
+              <nz-input-number [nzMin]="0" [(ngModel)]="data.amountAfterDiscount" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar"></nz-input-number>
+            </td>
+            <td>
+              <nz-input-number [nzMin]="0" [(ngModel)]="data.costUnitPrice" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar"></nz-input-number>
+            </td>
+            <td>
+              <nz-input-number [nzMin]="0" [(ngModel)]="data.costAmount" [nzFormatter]="formatterDollar"
+                [nzParser]="parserDollar"></nz-input-number>
+            </td>
+            <td>
+              <a nz-popconfirm nzTitle="{{ 'confirm.to.delete' | translate }}?" nzOkText="{{ 'yes' | translate }}"
+                nzCancelText="{{ 'no' | translate }}"
+                (nzOnConfirm)="productDeleteRow(data.id)">{{ 'table.delete' | translate }}</a>
+            </td>
+          </tr>
+        </tbody>
+      </nz-table>
+    </div>
+  </div>
+</nz-card>
+
+<nz-card nzTitle="模块">
+  <nz-tabset>
+    <nz-tab *ngFor="let product of productList" [nzTitle]="product.name">
+      <!-- 操作按钮 -->
+      <div nz-row [nzGutter]="24">
+        <div nz-col [nzSpan]="24">
+          <button nz-button (click)="moduleAddRow(product)" nzType="primary">新增</button>
+          <br />
+          <br />
+        </div>
+      </div>
+      <!-- 表格 -->
+      <div nz-row [nzGutter]="24">
+        <div nz-col [nzSpan]="24">
+          <nz-table #moduleRowTable nzSize="small" class="tableTdPadding" nzBordered
+            [nzData]="product.contractFileModularList">
+            <thead>
+              <tr>
+                <th nzWidth="30%">产品模块编码</th>
+                <th nzWidth="30%">产品模块名称</th>
+                <th nzWidth="10%">标准报价</th>
+                <th nzWidth="10%">采购价格</th>
+                <th nzWidth="20%">操作</th>
+              </tr>
+            </thead>
+            <tbody>
+              <tr *ngFor="let data of moduleRowTable.data" class="editable-row">
+                <td><input disabled="true" type="text" nz-input [(ngModel)]="data.code" /></td>
+                <td>
+                  <nz-select style="width:100%" nzShowSearch nzAllowClear [(ngModel)]="data.baseMaterialFileModularId"
+                    nzPlaceHolder="请选择" (ngModelChange)="baseMaterialFileModularIdChange(product,data,$event)">
+                    <nz-option *ngFor="let i of product.modularListSelect" [nzValue]="i.id" [nzLabel]="i.name">
+                    </nz-option>
+                  </nz-select>
+                </td>
+                <td>
+                  <nz-input-number [nzMin]="0" [nzDisabled]="true" [(ngModel)]="data.standardQuotation" [nzFormatter]="formatterDollar"
+                    [nzParser]="parserDollar" (ngModelChange)="standardQuotationModuleKeyUp(product)"></nz-input-number>
+                </td>
+                <td>
+                  <nz-input-number [nzMin]="0" [(ngModel)]="data.purchasePrice"  [nzFormatter]="formatterDollar"
+                    [nzParser]="parserDollar"></nz-input-number>
+                </td>
+                <td>
+                  <a nz-popconfirm nzTitle="{{ 'confirm.to.delete' | translate }}?" nzOkText="{{ 'yes' | translate }}"
+                    nzCancelText="{{ 'no' | translate }}"
+                    (nzOnConfirm)="moduleDeleteRow(product,data.id)">{{ 'table.delete' | translate }}</a>
+                </td>
+              </tr>
+            </tbody>
+          </nz-table>
+        </div>
+      </div>
+    </nz-tab>
+  </nz-tabset>
+</nz-card>

+ 24 - 0
src/app/routes/contract-management/contract-file/update/product-module/product-module.component.spec.ts

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

+ 255 - 0
src/app/routes/contract-management/contract-file/update/product-module/product-module.component.ts

@@ -0,0 +1,255 @@
+import { Component, OnInit, Output, EventEmitter } from '@angular/core';
+import { NzModalRef, NzMessageService, NzModalService } from 'ng-zorro-antd';
+import { _HttpClient } from '@delon/theme';
+import { BaseMaterialFileModularService } from 'app/services/basedata/base-material-file-modular.service';
+import { ContractFileProduct } from 'app/entity/contract-management/contract-file-product';
+import { ContractFile } from 'app/entity/contract-management/contract-file';
+import { RoutesSharedModalProdutSelectComponent } from 'app/routes/shared/modal/produt-select/produt-select.component';
+import { BaseMaterialFileModular } from 'app/entity/basedata/base-material-file-modular';
+
+@Component({
+  selector: 'app-contract-management-contract-file-update-product-module',
+  templateUrl: './product-module.component.html',
+})
+export class ContractManagementContractFileUpdateProductModuleComponent implements OnInit {
+  constructor(
+    private modalService:NzModalService,
+    private baseMaterialFileModularService:BaseMaterialFileModularService
+  ) {}
+  ngOnInit(): void {}
+
+  productList: ContractFileProduct[] = []; //产品数据
+  // moduleList:ContractFileModular[]=[];//模块数据
+  formatterDollar = (value: number): string => `¥ ${value}`;
+  parserDollar = (value: string): string => value.replace('¥ ', '');
+  formatterDollar2 = (value: number): string => `${value}%`;
+  parserDollar2 = (value: string): string => value.replace('%', '');
+
+  /**
+   * 产品新增行
+   */
+  prouctI = 0;
+  productAddRow() {
+    this.productList = [
+      ...this.productList,
+      {
+        id: `${this.prouctI}`,
+        code: '',
+        name: '',
+        discountRate: 0,
+        standardQuotation: 0,
+        unitPriceAfterDiscount: 0,
+        standardAmount: 0,
+        amountAfterDiscount: 0,
+        costUnitPrice: 0,
+        costAmount: 0,
+        contractFileModularList: [],
+      },
+    ];
+    this.prouctI++;
+  }
+
+  /**
+   * 产品删除行
+   */
+  productDeleteRow(id) {
+    this.productList = this.productList.filter(d => d.id !== id);
+  }
+
+  /**
+   * 模块新增行
+   */
+  moduleI = 0;
+  moduleAddRow(product) {
+    product.contractFileModularList = [
+      ...product.contractFileModularList,
+      {
+        id: `${this.moduleI}`,
+        code: '',
+        name: '',
+        standardQuotation: 0,
+        purchasePrice: 0,
+      },
+    ];
+    this.moduleI++;
+  }
+
+  /**
+   * 模块删除行
+   */
+  moduleDeleteRow(product, id) {
+    product.contractFileModularList = product.contractFileModularList.filter(d => d.id !== id);
+  }
+
+  /**
+   * 模块标准报价键盘弹起事件
+   * @param product 产品对象
+   */
+  standardQuotationModuleKeyUp(product) {
+    //判断当前产品下是否存在模块
+    if (product && product.contractFileModularList) {
+      let standardQuotationTotal = 0.0; //定义模块中标准报价总计
+      //循环模块
+      product.contractFileModularList.forEach(element => {
+        //判断标准报价是否为数字
+        if (!isNaN(Number(element.standardQuotation))) {
+          //累加
+          standardQuotationTotal = standardQuotationTotal + Number(element.standardQuotation);
+        }
+      });
+      //把模块标准报价总和赋值给产品的标准报价
+      product.standardQuotation = standardQuotationTotal;
+      //获取品总标准报价并传入基本信息
+      this.getContractFileStandardQuotationTotal();
+    }
+  }
+
+  /**
+   * 获取合同总共的标准报价
+   */
+
+  getContractFileStandardQuotationTotal() {
+    if (this.productList) {
+      let standardQuotationProductTotal = 0.0; //定义产品中标准报价总计
+      this.productList.forEach(element => {
+        //判断标准报价是否为数字
+        if (!isNaN(Number(element.standardQuotation))) {
+          //累加
+          standardQuotationProductTotal = standardQuotationProductTotal + Number(element.standardQuotation);
+        }
+      });
+      //把产品的总标准报价给合同标准报价
+      this.contractFile.standardQuotation = standardQuotationProductTotal;
+      //传给基本信息
+      this.outContractFileObject();
+    }
+  }
+
+  contractFile: ContractFile = {}; //合同的对象
+  /**
+   * 获取当前页面的相关信息传个父级页面
+   */
+  @Output() contractFileObject = new EventEmitter<{}>();
+  outContractFileObject() {
+    this.contractFileObject.emit(this.contractFile);
+  }
+
+  /**
+   * 选择产品事件
+   */
+  selectProdutModal(product) {
+    const modalRef = this.modalService.create({
+      nzTitle: '选择产品',
+      nzContent: RoutesSharedModalProdutSelectComponent,
+      nzWidth: 1400,
+      nzFooter: [
+        {
+          label: '关闭',
+          type: 'default',
+          onClick: addModel => {
+            addModel.close();
+          },
+        },
+        {
+          label: '确定',
+          type: 'primary',
+          onClick: addModel => {
+            addModel.save().then(()=>{
+              product.code=addModel.selectObj[0].code
+              product.name=addModel.selectObj[0].name
+              product.baseMaterialFileProductId=addModel.selectObj[0].id
+              //获取产品下的模块数据下拉供模块表格选择
+              this.getModuleListByPid(product);
+            });
+          },
+        },
+      ],
+    });
+  }
+
+  /**
+   * 根据产品id查询所属模块集合(供模块表格下拉选择)
+   */
+  getModuleListByPid(product){
+      return new Promise((resolve)=>{
+        let baseMaterialFileModular=new BaseMaterialFileModular();
+        baseMaterialFileModular.baseMaterialFileProductId=product.baseMaterialFileProductId;
+        //查询当前选择产品的模块
+        this.baseMaterialFileModularService.list(baseMaterialFileModular).then((response)=>{
+          //放入产品对象中
+          if(response.success){
+            product.modularListSelect=JSON.parse(JSON.stringify(response.result.records))
+          }
+          resolve();
+        })
+      })
+  }
+
+  /**
+   * 模块选择触发事件
+   * 获取编码和名称
+   */
+  baseMaterialFileModularIdChange(product,data,event){
+    if(event){
+      product.modularListSelect.forEach(element => {
+        if(event==element.id){
+          data.code=element.code;
+          data.name=element.name;
+          data.standardQuotation=element.standardQuotation;
+        }
+      });
+    }else{
+      data.code="";
+      data.name="";
+    }
+    //计算标准报价
+    this.standardQuotationModuleKeyUp(product)
+  }
+
+  /**
+   * 折扣后单价改变事件
+   */
+  unitPriceAfterDiscountBlur(data){
+    //标准报价
+    let standardQuotation=this.getIsNaN("standardQuotation",data);
+    //折扣后单价
+    let unitPriceAfterDiscount=this.getIsNaN("unitPriceAfterDiscount",data);
+    //折扣率
+    if (unitPriceAfterDiscount > 0.0 && standardQuotation > 0.0) {
+      //(成交金额/标准报价)100
+      let discountRate = Number(((unitPriceAfterDiscount / standardQuotation) * 100).toFixed(2));
+      data.discountRate = discountRate;
+    }
+    //计算折扣单价总和
+    this.getUnitPriceAfterDiscountTotal();
+  }
+
+/**
+ * 计算折扣单价总和
+ */
+  getUnitPriceAfterDiscountTotal(){
+    //折扣后单价总和
+    let unitPriceAfterDiscountTotal=0.0;
+    if(this.productList){
+      this.productList.forEach(element => {
+        unitPriceAfterDiscountTotal=unitPriceAfterDiscountTotal+Number(element.unitPriceAfterDiscount);
+      });
+      //放到主对象中
+      this.contractFile.transactionAmount=unitPriceAfterDiscountTotal;
+      //传给父级页面
+      this.outContractFileObject();
+    }
+  }
+
+  /**
+   * 验证是否数字
+   */
+  getIsNaN(name,data) {
+    if (!isNaN(Number(data[name]))) {
+      return Number(data[name]);
+    } else {
+      return 0.0;
+    }
+  }
+  close() {}
+}

+ 28 - 0
src/app/routes/contract-management/contract-file/update/update.component.html

@@ -0,0 +1,28 @@
+<nz-spin [nzSpinning]="isLoadingSave">
+  <nz-tabset nzTabPosition="left">
+    <nz-tab nzTitle="合同基本信息">
+      <app-contract-management-contract-file-update-essential-information #essentialInformation
+        (milestone)="milestone($event)"></app-contract-management-contract-file-update-essential-information>
+    </nz-tab>
+    <nz-tab nzTitle="产品与模块">
+      <app-contract-management-contract-file-update-product-module #productModule
+        (contractFileObject)="contractFileObject($event)"></app-contract-management-contract-file-update-product-module>
+    </nz-tab>
+    <nz-tab nzTitle="收款计划">
+      <app-contract-management-contract-file-update-collection-plan #collectionPlan>
+
+      </app-contract-management-contract-file-update-collection-plan>
+    </nz-tab>
+  </nz-tabset>
+</nz-spin>
+<!-- 按钮 -->
+<div class="base">
+  <!-- 关闭按钮 -->
+  <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)="save()"
+    [nzLoading]="isLoadingSave"><span>{{'pm.finish' | translate}}</span></button>
+</div>

+ 24 - 0
src/app/routes/contract-management/contract-file/update/update.component.spec.ts

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

+ 270 - 0
src/app/routes/contract-management/contract-file/update/update.component.ts

@@ -0,0 +1,270 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { NzModalRef, NzMessageService, NzDrawerRef, NzNotificationService } from 'ng-zorro-antd';
+import { _HttpClient } from '@delon/theme';
+import { ContractManagementContractFileUpdateEssentialInformationComponent } from './essential-information/essential-information.component';
+import { ContractManagementContractFileUpdateProductModuleComponent } from './product-module/product-module.component';
+import { ContractManagementContractFileUpdateCollectionPlanComponent } from './collection-plan/collection-plan.component';
+import { BaseArchivesProjectApprovalService } from 'app/services/basedata/base-archives-project-approval.service';
+import { DictService } from 'app/services/dict.service';
+import { PersonnelService } from 'app/services/basedata/personnel.service';
+import { BaseArchivesCollectionLineService } from 'app/services/basedata/base-archives-collection-line.service';
+import { BaseArchivesMilestoneService } from 'app/services/basedata/base-archives-milestone.service';
+import { ContractFileService } from 'app/services/contract-management/contract-file.service';
+import { I18NService } from '@core';
+import { DatePipe } from '@angular/common';
+import { BaseArchivesProjectApproval } from 'app/entity/basedata/base-archives-project-approval';
+import { recursiveQuery } from '@shared';
+import { ContractFile } from 'app/entity/contract-management/contract-file';
+import { BaseArchivesCollectionLine } from 'app/entity/basedata/base-archives-collection-line';
+import { BaseArchivesMilestone } from 'app/entity/basedata/base-archives-milestone';
+
+@Component({
+  selector: 'app-contract-management-contract-file-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 ContractManagementContractFileUpdateComponent implements OnInit {
+  constructor(
+    private baseArchivesProjectApprovalService: BaseArchivesProjectApprovalService,
+    private dictService: DictService,
+    private personnelService: PersonnelService,
+    private baseArchivesCollectionLineService: BaseArchivesCollectionLineService,
+    private baseArchivesMilestoneService: BaseArchivesMilestoneService,
+    private drawerRef: NzDrawerRef,
+    private contractFileService: ContractFileService,
+    private nzNotificationService: NzNotificationService,
+    private i18NService: I18NService,
+    private datePipe: DatePipe,
+  ) {}
+
+  ngOnInit(): void {
+    this.getDictList()
+      .then(() => {
+        return this.getProList();
+      })
+      .then(() => {
+        return this.getSalesStaffTree();
+      })
+      .then(() => {
+        //计划类型
+        return this.getPlanType();
+      })
+      .then(() => {
+        //里程碑
+        this.getById();
+      });
+  }
+
+  //基本信息组件
+  @ViewChild('essentialInformation')
+  essentialInformation: ContractManagementContractFileUpdateEssentialInformationComponent;
+  //产品与模块组件
+  @ViewChild('productModule')
+  productModule: ContractManagementContractFileUpdateProductModuleComponent;
+  //收款计划
+  @ViewChild('collectionPlan')
+  collectionPlan: ContractManagementContractFileUpdateCollectionPlanComponent;
+
+  id = '';
+  /**
+   * 根据id查询
+   */
+  getById() {
+    return new Promise(resolve => {
+      this.contractFileService.queryMainAndChildById(this.id).then(response => {
+        if (response.success) {
+          let contractFile = JSON.parse(JSON.stringify(response.result));
+          //合同基本信息
+          this.essentialInformation.contractFile = contractFile;
+          //产品数据
+          if (contractFile.contractFileProductList) {
+            this.productModule.productList = contractFile.contractFileProductList;
+            //获取产品子表的最后排序
+            this.productModule.prouctI = contractFile.contractFileProductList.length + 1;
+            //获取模块子表的最后排序
+            let moduleI = 0;
+            contractFile.contractFileProductList.forEach(prod => {
+              if (prod.contractFileModularList) {
+                prod.contractFileModularList.forEach(element => {
+                  moduleI++;
+                });
+              }
+            });
+            this.productModule.moduleI = moduleI;
+          }
+          //收款计划数据
+          if (contractFile.contractFileAndBusinessList) {
+            let collectionPlanList = []; //收款计划
+            let paymentCollectionList = []; //回款计划
+            let collectionPlanSort=0
+            let paymentCollectionSort=0
+            contractFile.contractFileAndBusinessList.forEach(element => {
+              if (element.planType == '1') {
+                element.sort=collectionPlanSort;
+                collectionPlanList.push(element);
+                collectionPlanSort++;
+              }
+              if (element.planType == '2') {
+                element.sort=paymentCollectionSort
+                paymentCollectionList.push(element);
+                paymentCollectionSort++;
+              }
+            });
+            this.collectionPlan.collectionPlanList=collectionPlanList
+            this.collectionPlan.paymentCollectionList=paymentCollectionList
+            this.collectionPlan.collectionPlanSort=collectionPlanSort;
+            this.collectionPlan.paymentCollectionSort=paymentCollectionSort;
+          }
+        }
+      });
+    });
+  }
+  /**
+   * 查询项目立项
+   */
+  getProList() {
+    return new Promise(resolve => {
+      let baseArchivesProjectApproval = new BaseArchivesProjectApproval();
+      baseArchivesProjectApproval.pkOrg = sessionStorage.getItem('pkOrg');
+      this.baseArchivesProjectApprovalService.getTreeList(baseArchivesProjectApproval).then(response => {
+        this.essentialInformation.proList = JSON.parse(JSON.stringify(response.result));
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 获取数据字典数据
+   */
+  getDictList() {
+    return new Promise(resolve => {
+      this.dictService.getByDictCode('business_type').then(response => {
+        this.essentialInformation.businessTypeDictList = JSON.parse(JSON.stringify(response.result));
+        //里程碑类型
+        this.dictService.getByDictCode('base_archives_milestone_type').then(response => {
+          this.essentialInformation.milestoneList = response.result;
+          resolve();
+        });
+      });
+    });
+  }
+
+  /**
+   * 获取销售人员下拉
+   */
+  getSalesStaffTree() {
+    return new Promise(resolve => {
+      this.personnelService.queryApprover(sessionStorage.getItem('pkOrg')).then(res => {
+        this.essentialInformation.salesStaffList = JSON.parse(JSON.stringify(res.result));
+        recursiveQuery(this.essentialInformation.salesStaffList);
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 产品与模块改变数据传值到其他页面
+   */
+  contractFileObject(contractFile: ContractFile) {
+    if (contractFile.standardQuotation) {
+      //产品中计算的标准报价总和传入基本信息标准报价
+      this.essentialInformation.contractFile.standardQuotation = contractFile.standardQuotation;
+      //计算折扣率
+      this.essentialInformation.calculation();
+    }
+    if (contractFile.transactionAmount) {
+      //产品中计算的折扣后单价总和传入基本信息成交金额
+      this.essentialInformation.contractFile.transactionAmount = contractFile.transactionAmount;
+      //触发成交金额的改变事件计算
+      this.essentialInformation.transactionAmountBlur();
+    }
+  }
+
+  /**
+   * 计划类型查询
+   */
+  getPlanType() {
+    return new Promise(resolve => {
+      let baseArchivesCollectionLine = new BaseArchivesCollectionLine();
+      baseArchivesCollectionLine.pageSize = 20000;
+      baseArchivesCollectionLine.pkOrg = sessionStorage.getItem('pkOrg');
+      this.baseArchivesCollectionLineService.getList(baseArchivesCollectionLine).then(response => {
+        if (response.success) {
+          //计划类型
+          this.collectionPlan.planList = response.result.records;
+        }
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * 根据里程碑类型查询收款计划的里程碑下拉数据
+   */
+  milestone(event: ContractFile) {
+    //商务里程碑下拉数据
+    //查询条件
+    let baseArchivesMilestone = new BaseArchivesMilestone();
+    baseArchivesMilestone.parentId = '0';
+    baseArchivesMilestone.typeId = event.milestoneId; //里程碑档案类型
+    //查询数据
+    this.baseArchivesMilestoneService.getAllParent(baseArchivesMilestone).then(response => {
+      if (response.result) {
+        this.collectionPlan.milestoneList = JSON.parse(JSON.stringify(response.result));
+      }
+    });
+  }
+
+  isLoadingSave = false; //保存按钮加载属性
+  save() {
+    return new Promise(resolve => {
+      if (this.essentialInformation.submitForm()) {
+        this.isLoadingSave = true;
+        let contractFile = new ContractFile();
+        contractFile = JSON.parse(JSON.stringify(this.essentialInformation.contractFile)); //获取基本信息的合同对象
+        //时间处理
+        contractFile.freeAfterSalesStart = this.datePipe.transform(contractFile.freeAfterSalesStart, 'yyyy-MM-dd');
+        contractFile.freeAfterSalesEnd = this.datePipe.transform(contractFile.freeAfterSalesEnd, 'yyyy-MM-dd');
+        contractFile.contractDate = this.datePipe.transform(contractFile.contractDate, 'yyyy-MM-dd');
+        contractFile.pkOrg = sessionStorage.getItem('pkOrg'); //组织id
+        contractFile.contractFileProductList = this.productModule.productList; //产品以及模块数据
+        //收款计划与回款计划
+        let contractFileAndBusinessList = this.collectionPlan.collectionPlanList.concat(
+          this.collectionPlan.paymentCollectionList,
+        );
+        contractFile.contractFileAndBusinessList = contractFileAndBusinessList;
+        this.contractFileService.saveMainAndChild(contractFile).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'), '');
+          }
+        });
+      }
+    });
+  }
+
+  close() {
+    this.drawerRef.close();
+  }
+}

+ 9 - 1
src/app/routes/contract-management/contract-management.module.ts

@@ -6,6 +6,10 @@ import { ContractManagementContractFileAddComponent } from './contract-file/add/
 import { ContractManagementContractFileAddEssentialInformationComponent } from './contract-file/add/essential-information/essential-information.component';
 import { ContractManagementContractFileAddProductModuleComponent } from './contract-file/add/product-module/product-module.component';
 import { ContractManagementContractFileAddCollectionPlanComponent } from './contract-file/add/collection-plan/collection-plan.component';
+import { ContractManagementContractFileUpdateComponent } from './contract-file/update/update.component';
+import { ContractManagementContractFileUpdateCollectionPlanComponent } from './contract-file/update/collection-plan/collection-plan.component';
+import { ContractManagementContractFileUpdateEssentialInformationComponent } from './contract-file/update/essential-information/essential-information.component';
+import { ContractManagementContractFileUpdateProductModuleComponent } from './contract-file/update/product-module/product-module.component';
 
 const COMPONENTS = [
   ContractManagementContractFileComponent];
@@ -13,7 +17,11 @@ const COMPONENTS_NOROUNT = [
   ContractManagementContractFileAddComponent,
   ContractManagementContractFileAddEssentialInformationComponent,
   ContractManagementContractFileAddProductModuleComponent,
-  ContractManagementContractFileAddCollectionPlanComponent];
+  ContractManagementContractFileAddCollectionPlanComponent,
+  ContractManagementContractFileUpdateComponent,
+  ContractManagementContractFileUpdateCollectionPlanComponent,
+  ContractManagementContractFileUpdateEssentialInformationComponent,
+  ContractManagementContractFileUpdateProductModuleComponent];
 
 @NgModule({
   imports: [

+ 44 - 0
src/app/services/contract-management/contract-file-and-business.service.ts

@@ -0,0 +1,44 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { BaseResponse } from 'app/entity/baseResponse';
+import { Result } from 'app/entity/Result';
+import { ContractFileAndBusiness } from 'app/entity/contract-management/contract-file-and-business';
+
+@Injectable({
+  providedIn: 'root'
+})
+/**
+ * 收款计划
+ */
+export class ContractFileAndBusinessService {
+
+  constructor(private http:HttpClient) { }
+  //分页查询
+  async getList(body: any): Promise<BaseResponse<Result<any>>> {
+    return await this.http
+      .get<BaseResponse<Result<any>>>('/contract.file/contractFileAndBusiness/list', { params: body })
+      .toPromise();
+  }
+
+  //新增
+  async add(body: ContractFileAndBusiness): Promise<BaseResponse<any>> {
+    return await this.http.post<BaseResponse<any>>('/contract.file/contractFileAndBusiness/add', body).toPromise();
+  }
+
+  //根据id查询
+  async queryById(id: string): Promise<BaseResponse<any>> {
+    return await this.http
+      .get<BaseResponse<any>>('/contract.file/contractFileAndBusiness/queryById', { params: { id: id } })
+      .toPromise();
+  }
+
+  //删除
+  async delete(body:any):Promise<BaseResponse<any>>{
+    return await this.http.delete<BaseResponse<any>>('/contract.file/contractFileAndBusiness/delete',{params:body}).toPromise();
+  }
+
+  //修改
+  async update(body: ContractFileAndBusiness): Promise<BaseResponse<any>> {
+    return await this.http.put<BaseResponse<any>>('/contract.file/contractFileAndBusiness/edit', body).toPromise();
+  }
+}

+ 45 - 0
src/app/services/contract-management/contract-file-modular.service.ts

@@ -0,0 +1,45 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { BaseResponse } from 'app/entity/baseResponse';
+import { Result } from 'app/entity/Result';
+import { ContractFileModular } from 'app/entity/contract-management/contract-file-modular';
+
+@Injectable({
+  providedIn: 'root'
+})
+/**
+ * 合同模块
+ */
+export class ContractFileModularService {
+
+  constructor(private http:HttpClient) { }
+
+  //分页查询
+  async getList(body: any): Promise<BaseResponse<Result<any>>> {
+    return await this.http
+      .get<BaseResponse<Result<any>>>('/contract.file/contractFileModular/list', { params: body })
+      .toPromise();
+  }
+
+  //新增
+  async add(body: ContractFileModular): Promise<BaseResponse<any>> {
+    return await this.http.post<BaseResponse<any>>('/contract.file/contractFileModular/add', body).toPromise();
+  }
+
+  //根据id查询
+  async queryById(id: string): Promise<BaseResponse<any>> {
+    return await this.http
+      .get<BaseResponse<any>>('/contract.file/contractFileModular/queryById', { params: { id: id } })
+      .toPromise();
+  }
+
+  //删除
+  async delete(body:any):Promise<BaseResponse<any>>{
+    return await this.http.delete<BaseResponse<any>>('/contract.file/contractFileModular/delete',{params:body}).toPromise();
+  }
+
+  //修改
+  async update(body: ContractFileModular): Promise<BaseResponse<any>> {
+    return await this.http.put<BaseResponse<any>>('/contract.file/contractFileModular/edit', body).toPromise();
+  }
+}

+ 45 - 0
src/app/services/contract-management/contract-file-product.service.ts

@@ -0,0 +1,45 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { BaseResponse } from 'app/entity/baseResponse';
+import { Result } from 'app/entity/Result';
+import { ContractFileProduct } from 'app/entity/contract-management/contract-file-product';
+
+@Injectable({
+  providedIn: 'root'
+})
+/**
+ * 合同产品
+ */
+export class ContractFileProductService {
+
+  constructor(private http:HttpClient) { }
+
+  //分页查询
+  async getList(body: any): Promise<BaseResponse<Result<any>>> {
+    return await this.http
+      .get<BaseResponse<Result<any>>>('/contract.file/contractFileProduct/list', { params: body })
+      .toPromise();
+  }
+
+  //新增
+  async add(body: ContractFileProduct): Promise<BaseResponse<any>> {
+    return await this.http.post<BaseResponse<any>>('/contract.file/contractFileProduct/add', body).toPromise();
+  }
+
+  //根据id查询
+  async queryById(id: string): Promise<BaseResponse<any>> {
+    return await this.http
+      .get<BaseResponse<any>>('/contract.file/contractFileProduct/queryById', { params: { id: id } })
+      .toPromise();
+  }
+
+  //删除
+  async delete(body:any):Promise<BaseResponse<any>>{
+    return await this.http.delete<BaseResponse<any>>('/contract.file/contractFileProduct/delete',{params:body}).toPromise();
+  }
+
+  //修改
+  async update(body: ContractFileProduct): Promise<BaseResponse<any>> {
+    return await this.http.put<BaseResponse<any>>('/contract.file/contractFileProduct/edit', body).toPromise();
+  }
+}

+ 69 - 0
src/app/services/contract-management/contract-file.service.ts

@@ -0,0 +1,69 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { BaseResponse } from 'app/entity/baseResponse';
+import { Result } from 'app/entity/Result';
+import { ContractFile } from 'app/entity/contract-management/contract-file';
+
+@Injectable({
+  providedIn: 'root'
+})
+/**
+ * 合同主表
+ */
+export class ContractFileService {
+
+  constructor(private http:HttpClient) { }
+
+  //分页查询
+  async getList(body: any): Promise<BaseResponse<Result<any>>> {
+    return await this.http
+      .get<BaseResponse<Result<any>>>('contract.file/contractFile/list', { params: body })
+      .toPromise();
+  }
+
+  //新增
+  async add(body: ContractFile): Promise<BaseResponse<any>> {
+    return await this.http.post<BaseResponse<any>>('contract.file/contractFile/add', body).toPromise();
+  }
+
+   //主表和子表数据一起保存
+   async saveMainAndChild(body: ContractFile): Promise<BaseResponse<any>> {
+    return await this.http.post<BaseResponse<any>>('contract.file/contractFile/saveMainAndChild', body).toPromise();
+  }
+
+  //根据id查询
+  async queryById(id: string): Promise<BaseResponse<any>> {
+    return await this.http
+      .get<BaseResponse<any>>('contract.file/contractFile/queryById', { params: { id: id } })
+      .toPromise();
+  }
+
+  //根据主表id查询主子表数据
+  async queryMainAndChildById(id: string): Promise<BaseResponse<any>> {
+    return await this.http
+      .get<BaseResponse<any>>('contract.file/contractFile/queryMainAndChildById', { params: { id: id } })
+      .toPromise();
+  }
+
+  //删除
+  async delete(body:any):Promise<BaseResponse<any>>{
+    return await this.http.delete<BaseResponse<any>>('contract.file/contractFile/delete',{params:body}).toPromise();
+  }
+
+   //主表与子表一起删除
+   async deleteMainAndChild(body:any):Promise<BaseResponse<any>>{
+    return await this.http.delete<BaseResponse<any>>('contract.file/contractFile/deleteMainAndChild',{params:body}).toPromise();
+  }
+
+  //修改
+  async update(body: ContractFile): Promise<BaseResponse<any>> {
+    return await this.http.put<BaseResponse<any>>('contract.file/contractFile/edit', body).toPromise();
+  }
+  
+
+  //主表和子表一起修改
+  async updateMainAndChild(body: ContractFile): Promise<BaseResponse<any>> {
+    return await this.http.put<BaseResponse<any>>('contract.file/contractFile/updateMainAndChild', body).toPromise();
+  }
+
+}