You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中如何处理多连锁请求后发起最终POST请求

多分支机构企业创建的异步流程实现方案

需求与现状

需要实现企业+多分支机构的创建流程:

  • 每个分支机构必须先保存地址,拿到后端返回的addressId后才能创建分支机构
  • 现有代码仅支持单个分支机构,需改造为多分支适配,且要借助RxJS操作符实现异步流程控制

现有多分支数据结构:

Enterprise : {
    socialReason: "Apple";
    siren: 1248746392;
    establishment: [
      {
        name: "Apple London";
        siret: "129838";
        addressId: null;
        enterpriseId: null;
      },
      // 更多分支机构...
    ]
}

原单分支保存代码(仅作参考):

public onSave(): void {
this.isLoading = true;

const siren = this.entepriseWithEstablishmentFormGroup.controls.enterpriseFormGroup.controls.siren.value;
const enterprise = this.entepriseWithEstablishmentFormGroup.controls.enterpriseFormGroup.getRawValue();
const establishment = this.entepriseWithEstablishmentFormGroup.controls.establishmentFormGroup.getRawValue();
const siret = `${siren}${establishment.siret}`;
const establishmentRM = new EstablishmentRequestModel(establishment.name, siret, establishment.email, establishment.phone, null, establishment.addressId);
const enterpriseRM = new EnterpriseWithEstablishmentRequestModel(enterprise.name, enterprise.siren, establishmentRM);

this.isLoading = true;

// create enterprise and establishment in a row
this.subscriptions.add(
  this.enterpriseService
    .createEstablishmentAddress(this.addressFormGroup.getRawValue())
    .pipe(
      map((addressId) => addressId),
      catchError((error: HttpErrorResponse) =>
        throwError(() => {
          this.isLoading = false;
          this.toastr.error(this.translatePipe.transform('COMPANY.DIALOGS.CREATE.ERROR-MSG.PERSISTENCE-ERROR'), this.translatePipe.transform('ADDRESS.DIALOGS.CREATE.TITLE'));
        })
      ),
      switchMap((addressId) => {
        enterpriseRM.establishment.addressId = addressId;
        this.entepriseWithEstablishmentFormGroup.controls.establishmentFormGroup.controls.addressId.patchValue(addressId);
        //this.showAddressForm = false;
        return this.enterpriseService.createEnterpriseWithEstablishment(enterpriseRM).pipe(
          map((response) => response),
          catchError((error: HttpErrorResponse) =>
            throwError(() => {
              this.isLoading = false;
              this.toastr.error(this.translatePipe.transform('COMPANY.DIALOGS.CREATE.ERROR-MSG'), this.translatePipe.transform('COMPANY.DIALOGS.CREATE.TITLE'));
            })
          )
        );
      })
    )
    .subscribe((response) => {
      this.isLoading = false;

      if (response !== null) {
        this.dialogRef.close(response);
      }
    })
);

解决方案

核心思路

  1. 并行保存所有分支机构地址:用forkJoin批量发起地址保存请求,地址之间无依赖,并行处理效率更高
  2. 绑定地址ID与分支机构:将forkJoin返回的addressId数组按顺序对应到各分支机构,填充addressId字段
  3. 创建企业及所有分支机构:构建包含所有已填充addressId的分支机构的企业请求模型,调用创建接口

改造后的完整代码(支持批量创建分支)

public onSave(): void {
  this.isLoading = true;

  // 1. 获取表单中的企业与所有分支机构数据
  const enterpriseFormData = this.entepriseWithEstablishmentFormGroup.controls.enterpriseFormGroup.getRawValue();
  const establishmentsFormData = this.entepriseWithEstablishmentFormGroup.controls.establishmentsFormArray.getRawValue(); // 多分支用FormArray存储
  const siren = enterpriseFormData.siren;

  // 2. 准备所有分支机构的地址保存请求
  const addressSaveRequests$ = establishmentsFormData.map((est) => {
    // 替换为获取当前分支机构对应地址表单数据的逻辑
    const addressData = this.getEstablishmentAddressFormData(est); 
    return this.enterpriseService.createEstablishmentAddress(addressData).pipe(
      catchError((error: HttpErrorResponse) => {
        this.isLoading = false;
        this.toastr.error(
          this.translatePipe.transform('COMPANY.DIALOGS.CREATE.ERROR-MSG.PERSISTENCE-ERROR'),
          this.translatePipe.transform('ADDRESS.DIALOGS.CREATE.TITLE')
        );
        return throwError(() => error);
      })
    );
  });

  // 3. 并行处理所有地址保存请求,再创建企业+多分支
  this.subscriptions.add(
    forkJoin(addressSaveRequests$).pipe(
      switchMap((addressIds: string[]) => {
        // 4. 将addressId对应到每个分支机构,构建请求模型
        const establishmentRMs = establishmentsFormData.map((est, index) => {
          const siret = `${siren}${est.siret}`;
          return new EstablishmentRequestModel(
            est.name,
            siret,
            est.email,
            est.phone,
            null,
            addressIds[index] // 绑定对应的addressId
          );
        });

        // 5. 构建包含所有分支机构的企业请求模型
        const enterpriseRM = new EnterpriseWithEstablishmentsRequestModel(
          enterpriseFormData.name,
          enterpriseFormData.siren,
          establishmentRMs // 传入多分支数组
        );

        // 6. 调用企业创建接口(需后端支持一次性创建企业+多分支)
        return this.enterpriseService.createEnterpriseWithEstablishments(enterpriseRM).pipe(
          catchError((error: HttpErrorResponse) => {
            this.isLoading = false;
            this.toastr.error(
              this.translatePipe.transform('COMPANY.DIALOGS.CREATE.ERROR-MSG'),
              this.translatePipe.transform('COMPANY.DIALOGS.CREATE.TITLE')
            );
            return throwError(() => error);
          })
        );
      })
    ).subscribe((response) => {
      this.isLoading = false;
      if (response !== null) {
        this.dialogRef.close(response);
      }
    })
  );
}

// 辅助函数:获取指定分支机构的地址表单数据(需根据实际表单结构调整)
private getEstablishmentAddressFormData(establishment: any): any {
  const index = this.entepriseWithEstablishmentFormGroup.controls.establishmentsFormArray.controls.findIndex(
    ctrl => ctrl.value.siret === establishment.siret
  );
  return this.entepriseWithEstablishmentFormGroup.controls.establishmentsFormArray.controls[index].controls.addressFormGroup.getRawValue();
}

补充:若后端不支持一次性创建多分支机构

如果后端要求先创建企业,再逐个创建分支机构,流程需调整为:

public onSave(): void {
  this.isLoading = true;

  const enterpriseFormData = this.entepriseWithEstablishmentFormGroup.controls.enterpriseFormGroup.getRawValue();
  const establishmentsFormData = this.entepriseWithEstablishmentFormGroup.controls.establishmentsFormArray.getRawValue();
  const siren = enterpriseFormData.siren;

  const addressSaveRequests$ = establishmentsFormData.map((est) => {
    const addressData = this.getEstablishmentAddressFormData(est); 
    return this.enterpriseService.createEstablishmentAddress(addressData).pipe(
      catchError((error: HttpErrorResponse) => {
        this.isLoading = false;
        this.toastr.error(
          this.translatePipe.transform('COMPANY.DIALOGS.CREATE.ERROR-MSG.PERSISTENCE-ERROR'),
          this.translatePipe.transform('ADDRESS.DIALOGS.CREATE.TITLE')
        );
        return throwError(() => error);
      })
    );
  });

  this.subscriptions.add(
    forkJoin(addressSaveRequests$).pipe(
      // 先创建企业,获取enterpriseId
      switchMap((addressIds) => {
        const baseEnterpriseRM = new EnterpriseRequestModel(enterpriseFormData.name, enterpriseFormData.siren);
        return this.enterpriseService.createEnterprise(baseEnterpriseRM).pipe(
          map(enterprise => ({ enterpriseId: enterprise.id, addressIds }))
        );
      }),
      // 批量创建分支机构,绑定enterpriseId和addressId
      switchMap(({ enterpriseId, addressIds }) => {
        const establishmentSaveRequests$ = establishmentsFormData.map((est, index) => {
          const siret = `${siren}${est.siret}`;
          const establishmentRM = new EstablishmentRequestModel(
            est.name,
            siret,
            est.email,
            est.phone,
            enterpriseId,
            addressIds[index]
          );
          return this.enterpriseService.createEstablishment(establishmentRM).pipe(
            catchError(error => {
              this.toastr.error(this.translatePipe.transform('COMPANY.DIALOGS.CREATE.ERROR-MSG.ESTABLISHMENT'), this.translatePipe.transform('COMPANY.DIALOGS.CREATE.TITLE'));
              return throwError(() => error);
            })
          );
        });
        return forkJoin(establishmentSaveRequests$);
      })
    ).subscribe(() => {
      this.isLoading = false;
      this.dialogRef.close(true);
    })
  );
}

关键RxJS操作符说明

  • forkJoin:并行执行多个Observable,所有请求成功完成后返回结果数组,适合无依赖的批量异步操作(如多地址保存、多分支创建)
  • switchMap:将前一个Observable的结果转换为新的Observable,实现流程的顺序控制(如地址保存完成后触发企业创建)

注意事项

  1. 表单结构需适配多分支:将原单分支的establishmentFormGroup改为establishmentsFormArray,每个数组项包含分支机构信息及对应地址表单
  2. 错误处理需覆盖所有异步步骤,确保任何环节失败都能关闭loading并提示用户
  3. 需根据后端接口能力选择对应的流程方案

内容的提问来源于stack exchange,提问作者A G

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 14:25:55