Browse Source

合同档案

chenc 3 years ago
parent
commit
53d8a77293

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

@@ -65,6 +65,8 @@ export class ContractFile extends Page {
 	salesmanId?:string;
 	/**销售人员名称*/
 	salesmanName?:string;
+	/**汇款金额 */
+	received?:number;
 
 	 //显示
 	 /**客户名称 */

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

@@ -1,9 +1,13 @@
 <nz-tabset nzTabPosition="left">
   <nz-tab nzTitle="合同基本信息">
-    <app-contract-management-contract-file-add-essential-information #essentialInformation></app-contract-management-contract-file-add-essential-information>
+    <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="收款计划">Content of Tab Pane 3</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>

+ 69 - 9
src/app/routes/contract-management/contract-file/add/add.component.ts

@@ -9,6 +9,11 @@ import { PersonnelService } from 'app/services/basedata/personnel.service';
 import { recursiveQuery } from '@shared';
 import { ContractManagementContractFileAddProductModuleComponent } from './product-module/product-module.component';
 import { ContractFile } from 'app/entity/contract-management/contract-file';
+import { ContractManagementContractFileAddCollectionPlanComponent } from './collection-plan/collection-plan.component';
+import { BaseArchivesCollectionLine } from 'app/entity/basedata/base-archives-collection-line';
+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';
 
 @Component({
   selector: 'app-contract-management-contract-file-add',
@@ -19,14 +24,25 @@ export class ContractManagementContractFileAddComponent implements OnInit {
     private baseArchivesProjectApprovalService: BaseArchivesProjectApprovalService,
     private dictService: DictService,
     private personnelService: PersonnelService,
+    private baseArchivesCollectionLineService: BaseArchivesCollectionLineService,
+    private baseArchivesMilestoneService:BaseArchivesMilestoneService
   ) {}
 
   ngOnInit(): void {
-    this.getDictList().then(() => {
-      return this.getProList();
-    }).then(()=>{
-      return this.getSalesStaffTree();
-    });
+    this.getDictList()
+      .then(() => {
+        return this.getProList();
+      })
+      .then(() => {
+        return this.getSalesStaffTree();
+      })
+      .then(() => {
+        //计划类型
+        return this.getPlanType();
+      })
+      .then(() => {
+        //里程碑
+      });
   }
   //基本信息组件
   @ViewChild('essentialInformation')
@@ -34,6 +50,9 @@ export class ContractManagementContractFileAddComponent implements OnInit {
   //产品与模块组件
   @ViewChild('productModule')
   productModule: ContractManagementContractFileAddProductModuleComponent;
+  //收款计划
+  @ViewChild('collectionPlan')
+  collectionPlan: ContractManagementContractFileAddCollectionPlanComponent;
 
   /**
    * 查询项目立项
@@ -56,7 +75,11 @@ export class ContractManagementContractFileAddComponent implements OnInit {
     return new Promise(resolve => {
       this.dictService.getByDictCode('business_type').then(response => {
         this.essentialInformation.businessTypeDictList = JSON.parse(JSON.stringify(response.result));
-        resolve();
+        //里程碑类型
+        this.dictService.getByDictCode('base_archives_milestone_type').then(response => {
+          this.essentialInformation.milestoneList = response.result;
+          resolve();
+        });
       });
     });
   }
@@ -77,10 +100,47 @@ export class ContractManagementContractFileAddComponent implements OnInit {
   /**
    * 产品与模块改变数据传值到其他页面
    */
-  contractFileObject(contractFile:ContractFile){
-    console.log(contractFile)
+  contractFileObject(contractFile: ContractFile) {
+    console.log(contractFile);
     //产品中计算的标准报价总和传入基本信息
-    this.essentialInformation.contractFile.standardQuotation=contractFile.standardQuotation;
+    this.essentialInformation.contractFile.standardQuotation = contractFile.standardQuotation;
+    //计算折扣率
+    this.essentialInformation.calculation()
+  }
+
+  /**
+   * 计划类型查询
+   */
+  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));
+      }
+    });
   }
 
   close() {}

+ 219 - 0
src/app/routes/contract-management/contract-file/add/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/add/collection-plan/collection-plan.component.spec.ts

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

+ 230 - 0
src/app/routes/contract-management/contract-file/add/collection-plan/collection-plan.component.ts

@@ -0,0 +1,230 @@
+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-add-collection-plan',
+  templateUrl: './collection-plan.component.html',
+})
+export class ContractManagementContractFileAddCollectionPlanComponent 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);
+  }
+
+  ngOnInit(): void {}
+
+  close() {}
+}

+ 40 - 13
src/app/routes/contract-management/contract-file/add/essential-information/essential-information.component.html

@@ -56,8 +56,24 @@
       </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]="24">
+      <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">
@@ -180,7 +196,7 @@
         <nz-form-item>
           <nz-form-label [nzSpan]="'vertical' ? 24 : null">成交金额</nz-form-label>
           <nz-form-explain>
-            <nz-input-number [(ngModel)]="contractFile.transactionAmount" formControlName="transactionAmount"
+            <nz-input-number [(ngModel)]="contractFile.transactionAmount" (nzBlur)="transactionAmountBlur()" formControlName="transactionAmount"
               id="transactionAmount" [nzMin]="0" [nzFormatter]="formatterDollar" [nzParser]="parserDollar">
             </nz-input-number>
           </nz-form-explain>
@@ -192,7 +208,7 @@
           <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]="formatterDollar" [nzParser]="parserDollar">
+              [nzMin]="0" [nzFormatter]="formatterDollar2" [nzParser]="parserDollar2" [nzDisabled]="true">
             </nz-input-number>
           </nz-form-explain>
         </nz-form-item>
@@ -214,7 +230,7 @@
           <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">
+              [nzFormatter]="formatterDollar" [nzParser]="parserDollar" (nzBlur)="costBlur()">
             </nz-input-number>
           </nz-form-explain>
         </nz-form-item>
@@ -225,7 +241,7 @@
           <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">
+              [nzMin]="0" [nzFormatter]="formatterDollar" [nzParser]="parserDollar" (nzBlur)="contractCostBlur()">
             </nz-input-number>
           </nz-form-explain>
         </nz-form-item>
@@ -238,7 +254,18 @@
           <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" [nzFormatter]="formatterDollar" [nzParser]="parserDollar">
+              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>
@@ -248,7 +275,7 @@
         <nz-form-item>
           <nz-form-label [nzSpan]="'vertical' ? 24 : null">应收款账</nz-form-label>
           <nz-form-explain>
-            <nz-input-number [(ngModel)]="contractFile.accountsReceivable" formControlName="accountsReceivable"
+            <nz-input-number [nzDisabled]="true" [(ngModel)]="contractFile.accountsReceivable" formControlName="accountsReceivable"
               id="accountsReceivable" [nzMin]="0" [nzFormatter]="formatterDollar" [nzParser]="parserDollar">
             </nz-input-number>
           </nz-form-explain>
@@ -261,7 +288,7 @@
           <nz-form-explain>
             <nz-input-number [(ngModel)]="contractFile.performanceCalculationRate"
               formControlName="performanceCalculationRate" id="performanceCalculationRate" [nzMin]="0"
-              [nzFormatter]="formatterDollar" [nzParser]="parserDollar">
+              [nzFormatter]="formatterDollar2" [nzParser]="parserDollar2">
             </nz-input-number>
           </nz-form-explain>
         </nz-form-item>
@@ -275,16 +302,16 @@
         <nz-form-item>
           <nz-form-label [nzSpan]="'vertical' ? 24 : null">制单人</nz-form-label>
           <nz-form-explain>
-            xxx
+            {{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-label [nzSpan]="'vertical' ? 24 : null">制单时间</nz-form-label>
           <nz-form-explain>
-            xxx
+            {{contractFile.createTime}}
           </nz-form-explain>
         </nz-form-item>
       </div>
@@ -295,7 +322,7 @@
         <nz-form-item>
           <nz-form-label [nzSpan]="'vertical' ? 24 : null">修改人</nz-form-label>
           <nz-form-explain>
-            xxx
+            {{contractFile.updateBy}}
           </nz-form-explain>
         </nz-form-item>
       </div>
@@ -304,7 +331,7 @@
         <nz-form-item>
           <nz-form-label [nzSpan]="'vertical' ? 24 : null">修改时间</nz-form-label>
           <nz-form-explain>
-            xxx
+            {{contractFile.updateTime}}
           </nz-form-explain>
         </nz-form-item>
       </div>

+ 183 - 63
src/app/routes/contract-management/contract-file/add/essential-information/essential-information.component.ts

@@ -1,6 +1,6 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit, Output, EventEmitter } from '@angular/core';
 import { NzModalRef, NzMessageService, NzModalService } from 'ng-zorro-antd';
-import { _HttpClient } from '@delon/theme';
+import { _HttpClient, SettingsService } from '@delon/theme';
 import { FormGroup, Validators, FormBuilder } from '@angular/forms';
 import { ContractFile } from 'app/entity/contract-management/contract-file';
 import { BaseArchivesProjectApproval } from 'app/entity/basedata/base-archives-project-approval';
@@ -8,14 +8,20 @@ import { BaseArchivesProjectApprovalService } from 'app/services/basedata/base-a
 import { DictService } from 'app/services/dict.service';
 import { BasedataCustomerModalTableComponent } from 'app/routes/basedata/customer/modal-table/modal-table.component';
 import { CustomerService } from 'app/services/basedata/customer.service';
+import { DatePipe } from '@angular/common';
 
 @Component({
   selector: 'app-contract-management-contract-file-add-essential-information',
   templateUrl: './essential-information.component.html',
 })
 export class ContractManagementContractFileAddEssentialInformationComponent implements OnInit {
-  constructor(private fb: FormBuilder, private modalService: NzModalService,
-    private customerService:CustomerService) {}
+  constructor(
+    private fb: FormBuilder,
+    private modalService: NzModalService,
+    private customerService: CustomerService,
+    private settingsService: SettingsService,
+    private datePipe:DatePipe
+  ) {}
 
   validateForm!: FormGroup;
   ngOnInit(): void {
@@ -24,41 +30,49 @@ export class ContractManagementContractFileAddEssentialInformationComponent impl
       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:[]
+      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: [],
     });
   }
-
+  user=this.settingsService.user//当前登录用户信息
   contractFile: ContractFile = {
-    standardQuotation:0,
-    transactionAmount:0,
-    discountRate:0,
-    giftAmount:0,
-    cost:0,
-    contractCost:0,
-    contractProfit:0,
-    accountsReceivable:0,
-    performanceCalculationRate:0
+    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下拉数据
+  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('%', '');
 
   /**
    * 项目名称下拉款触发事件
@@ -73,7 +87,7 @@ export class ContractManagementContractFileAddEssentialInformationComponent impl
    * 客户选择
    */
   modalTable() {
-    this.getLdCustomerPersonnelList("");
+    this.getLdCustomerPersonnelList('');
     const modalRef = this.modalService.create({
       nzTitle: '选择客户',
       nzContent: BasedataCustomerModalTableComponent,
@@ -103,59 +117,59 @@ export class ContractManagementContractFileAddEssentialInformationComponent impl
   /**
    * 根据客户获取客户人员数据
    */
-  fdCustomerPersonnelList:any=[]
-  getLdCustomerPersonnelList(customerId){
-    return new Promise((resolve)=>{
-      this.customerService.getContactsByMainId("4d0df0dc441aff4655d8aa4380b194dc").then((response)=>{
-        this.fdCustomerPersonnelList=response.result
+  fdCustomerPersonnelList: any = [];
+  getLdCustomerPersonnelList(customerId) {
+    return new Promise(resolve => {
+      this.customerService.getContactsByMainId('4d0df0dc441aff4655d8aa4380b194dc').then(response => {
+        this.fdCustomerPersonnelList = response.result;
         resolve();
-      })
-    })
+      });
+    });
   }
 
   /**
    * 客户人员选择事件
    */
-  fdCustomerPersonnelChange(event){
-    if(event){
+  fdCustomerPersonnelChange(event) {
+    if (event) {
       this.fdCustomerPersonnelList.forEach(element => {
-        if(element.id==event){
-          this.contractFile.fdCustomerPersonnelTel=element.contectTel
+        if (element.id == event) {
+          this.contractFile.fdCustomerPersonnelTel = element.contectTel;
         }
       });
-    }else{
-      this.contractFile.fdCustomerPersonnelId=""
-      this.contractFile.fdCustomerPersonnelTel=""
+    } else {
+      this.contractFile.fdCustomerPersonnelId = '';
+      this.contractFile.fdCustomerPersonnelTel = '';
     }
   }
 
   /**
    * 业务类型选择事件
    */
-  businessTypeDictIdChange(event){
-    if(!event){
-      this.contractFile.businessTypeDictId="";
+  businessTypeDictIdChange(event) {
+    if (!event) {
+      this.contractFile.businessTypeDictId = '';
     }
   }
 
   /**
    * 销售人员选择时间
-   * @param event 
+   * @param event
    */
-  onChangeSalesmanId(event){
-    if(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;
+              this.contractFile.salesmanName = personnel.name;
             }
           });
         });
       });
-    }else{
-      this.contractFile.salesmanName=""
+    } else {
+      this.contractFile.salesmanName = '';
     }
   }
 
@@ -164,11 +178,11 @@ export class ContractManagementContractFileAddEssentialInformationComponent impl
    */
   disabledDate = (current: Date): boolean => {
     // Can not select days before today and today
-    if(this.contractFile.freeAfterSalesEnd){
-      let end=new Date(this.contractFile.freeAfterSalesEnd);//结束时间
+    if (this.contractFile.freeAfterSalesEnd) {
+      let end = new Date(this.contractFile.freeAfterSalesEnd); //结束时间
       //开始时间大于结束时间的禁用
-      return current.getTime()>end.getTime();
-    }else{
+      return current.getTime() > end.getTime();
+    } else {
       return false;
     }
   };
@@ -178,15 +192,121 @@ export class ContractManagementContractFileAddEssentialInformationComponent impl
    */
   disabledDate2 = (current: Date): boolean => {
     // Can not select days before today and today
-    if(this.contractFile.freeAfterSalesStart){
-      let start=new Date(this.contractFile.freeAfterSalesStart);//开始时间
+    if (this.contractFile.freeAfterSalesStart) {
+      let start = new Date(this.contractFile.freeAfterSalesStart); //开始时间
       //结束时间小于开始时间禁用
-      return current.getTime()<start.getTime();
-    }else{
+      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() {}
 
   close() {}

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

@@ -5,13 +5,15 @@ import { ContractManagementContractFileComponent } from './contract-file/contrac
 import { ContractManagementContractFileAddComponent } from './contract-file/add/add.component';
 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';
 
 const COMPONENTS = [
   ContractManagementContractFileComponent];
 const COMPONENTS_NOROUNT = [
   ContractManagementContractFileAddComponent,
   ContractManagementContractFileAddEssentialInformationComponent,
-  ContractManagementContractFileAddProductModuleComponent];
+  ContractManagementContractFileAddProductModuleComponent,
+  ContractManagementContractFileAddCollectionPlanComponent];
 
 @NgModule({
   imports: [