0.0.8 • Published 4 years ago

@gsp-fund/ui v0.0.8

Weekly downloads
6
License
MIT
Repository
-
Last release
4 years ago

@gsp-fund/ui - BatchResultModule 批量结果弹窗模块

项目地址

gitlab npm 离线包 \\10.100.1.163\产品服务器\待测库\TM_Cloud\内部使用\资金内部node_modules\@gsp-fund

使用

  1. 表单设计器引用(打开表单后直接点击代码编辑器,拖到最后添加以下代码) image.png
        "isComposedFrm": true,
        "extraImports": [
            {
                "path": "@gsp-fund/ui",
                "name": "BatchResultModule"
            }
        ]
  1. 注入BatchResultService弹窗服务

BatchResultService弹窗服务

open方法

根据传入的结果及列配置打开弹窗(存在失败)或弹出右下角成功提示(全部为成功),若存在待确认,支持选择,返回选择的数组流

参数类型备注
actionstring操作名称,用于标题
actionResultActionResult[]动作结果数组
formLoadingServiceFormLoadingService平台formLoading服务
formNotifyServiceFormNotifyService平台formNotifyService服务
columns{field: string,title: string,type?: ColumnType,width?: number}[]列配置数组,可选

返回Subject<string[]> 表示待确认列表选择的id数组流 若弹窗正常结束或关闭,返回空数组

ActionResult类结构

属性类型备注
idstring主键,由于平台farris-grid限制,必填
dataany数据,用于open方法中的columnsfield取值
stateActionState动作结果的枚举,也可为对应枚举的number值
messagestring提示信息

枚举ActionState

枚举备注
Success1成功
ToBeConfirmed2待确认
Failed-1失败

columns参数详情

属性类型备注
fieldstring字段属性名,若为多级结构用.连接,列表取数时取ActionResultdata属性的对应值
titlestring列标题
typeColumnType列数据类型枚举,封装了常用类型的平台列配置
widthnumber列宽

ColumnType枚举

枚举备注
String0字符串,靠左,无格式特殊处理
AccountNo1账号,靠左,四位空格分隔
Amount2金额,靠右,数字格式化

默认配置为

  [ 
    {
      field: 'code',
      type: ColumnType.String,
      width: 200,
      title: '单据编号'
    }
  ]

所有配置最后内部添加message的配置,无需手工处理

   {
      field: 'message',
      width: 800,
      title: '原因',
      dataType: 'string',
      align: 'left',
      halign: 'left',
      readonly: true,
      visible: true,
   }

option窗口配置参数详情

枚举默认值备注
showButtontrue显示底部按钮(存在待确认结果时设为false无效)
width800宽度
height600高度
title参数action的值标题

用法举例

  1. 后端组装基本的List<ActionResult>响应结构返回给前端

可使用或参考类com.inspur.gs.tm.tmfnd.tmpub.common.pojo.http.ActionResult

import lombok.Getter;
import lombok.Setter;

/**
 * 动作结果
 * @author lifeiyue
 */
@Getter
@Setter
public class ActionResult {
    /**
     * 单据id
     */
    private String id;
   /**
     * 单据数据 (可在前端完成赋值)
     */
    private Object data;
    /**
     * 结果状态
     */
    private ActionState state = ActionState.Success;
    /**
     * 提示信息
     */
    private String message;
}
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;

/**
 * 结果状态枚举
 * @author lifeiyue
 */
public enum ActionState {

    /**
     * 成功
     */
    Success(1),
    /**
     * 待确认
     */
    ToBeConfirmed(2),
    /**
     * 失败
     */
    Failed(-1);

    private int value;
    @JsonCreator
    ActionState(int value) {
        this.value = value;
    }
    @JsonValue
    public int getValue() {
        return this.value;
    }

}
  1. 前端配置弹窗的展示列配置
  import {ActionResult, ActionState, BatchResultService, ColumnType} from '@gsp-fund/ui';

 /**
   * 批量结果弹窗列配置
   */
  private readonly dialogConfig: { field: string, title: string, type?: ColumnType, width?: number }[];
  private template: ServiceTemplate;

  constructor(
    private frameContext: FrameContext,
    private loadingService: FormLoadingService,
    private notifyService: FormNotifyService,
    private messageService: FormMessageService,
    private navigationService: NavigationService,
    private navigationMiddlewareService: NavigationMiddlewareService,
    private translateService: TranslateService,
    private batchResultService: BatchResultService,
    private printService: PrintService
  ) {
    this.template = new ServiceTemplate(frameContext, loadingService, notifyService, messageService);
    // 建议在构造器内或调用方法内初始化列配置,而非直接在类级别直接初始化。否则可能导致国际化服务translateService拿不到
    this.dialogConfig = [
      {
        field: 'docNo',
        title: this.translateService.instant('gridField_8debd649-bec7-41e8-a400-61340cc353e8_docNo')
      }
    ];
  }
  1. 组装弹窗需要的结果入参(若后端已赋值data,可跳过)
       // 转换响应结果
      map(response => {
        const responseResult = response as ActionResult[];
        // 赋值请求结果data字段
        responseResult.forEach(r => r.data = this.frameContext.repository.entityCollection.getEntityById(r.id));
        return responseResult;
      }),
  1. 调用弹窗服务并处理弹窗结果
       // 调用弹窗服务
      switchMap((result: ActionResult[]) =>
        this.batchResultService.open(
          this.translateService.instant('withdraw'), result, this.loadingService, this.notifyService, this.dialogConfig)
      ),
      // 重新加载数据
      tap(() => this.frameContext.viewModel['Load1']())

附:前后端代码 后端视图动作

    public void execute() {
        final ArrayList<Object> results = new ArrayList<>();
        if (data != null && data.length > 0) {
            IStandardLcp lcp = getLcp();
            for (EnableUnitStruct item : data) {
                //调用平台原子性动作执行以保证事务
                lcp.atomicallyInvoke(() -> {
                    try {
                        //业务逻辑略...
                        lcp.save();
                        //传回前端的id仍为unitID,因为未启用时,voID就是unitID
                        results.add(new ActionResult() {{
                            setId(item.getUnit());
                        }});
                    } catch (Exception e) {
                        lcp.cleanUp();//清空变更集、锁、缓存
                        String bizErrorInException = ExceptionUtil.getBizErrorInException(e);
                        results.add(new ActionResult() {{
                            setId(item.getUnit());
                            setState(ActionState.Failed);
                            setMessage(bizErrorInException);
                        }});
                    }
                });
            }
        }
        setResult(results);//返回前端的数据
    }
/**
 * 异常工具类
 * @author lifeiyue
 */
public class ExceptionUtil {
    /**
     * 获取捕获异常中的业务信息
     * 在内部存在RPC调用时,扔出的异常会套两层“RPC调用异常”,不可直接拿外层的message。单独的web api请求可能前端处理了此种情况
     * @param e 捕获的异常
     * @return Message
     */
    public static String getBizErrorInException(Exception e){
        String message = e.getMessage();
        Throwable newE = e;
        while(newE.getCause() != null){
            newE = newE.getCause();
            message = newE.getMessage();
        }
        return message;
    }
}

前端调用弹窗方法

        //enableUnit()方法操作的后续操作是,调用平台ListDataService的load动作
	enableUnit() {
		const params: data[] = this['context'].results.getDataToEnable;
		const listData = this.repository.entityCollection;
		this.formLoadingService.show();
                //启用请求
		return this.proxy.EnableUnit(params).pipe(
			concatMap((responseData: ActionResult[]) => {
				if (responseData && responseData.length) {
					const data = responseData.map((item) => {
						item.data = listData.getEntityById(item.id);
						return item;
					});
                                        //调用弹窗
					return this.batchResultService.open(
						this.translate.instant('form_title'),
						data.slice(),
						this.formLoadingService,
						this.formNotifyService,
						this.dialogConfig
					);
				} else {
					this.formLoadingService.clearAll();
					return EMPTY;
				}
			})
		);
    }

附:一种有待确认情况的前端调用

 /**
   * 提交
   */
  submit() {
    const selected = this.template.getFrameContext('data-grid-component').uiState['ids'] as string[];
    if (!selected || !selected.length) {
      this.notifyService.warning(this.translateService.instant('Service_NoSelectData'));
      return EMPTY;
    }
    // 待提交结果
    const submitIds = [];
    // 前端校验结果
    const validResult: ActionResult[] = [];
    // 组装首次提交参数
    selected.forEach(id => {
      const entity = this.frameContext.repository.entityCollection.getEntityById(id) as FundAllocationEntity;
      // 校验单据状态,只有待办理、审批退回、复核退回才能执行
      if (!FundAllocationHandleFrmActionService.canHandleOrSubmit(entity)) {
        validResult.push({
          id,
          data: entity,
          state: ActionState.Failed,
          message: this.translateService.instant('Service_SubmitWithWrongState')
        });
      } else if (!entity.allocationAccount.allocationAccount) { // 下拨账户为空
        validResult.push({
          id,
          data: entity,
          state: ActionState.Failed,
          message: this.translateService.instant('Service_AllocAccountIsNull')
        });
      } else if (!entity.summary) { // 摘要为空
        validResult.push({
          id,
          data: entity,
          state: ActionState.Failed,
          message: this.translateService.instant('Service_SummaryIsNull')
        });
      } else {
        submitIds.push({id, confirmOverBalance: false});
      }
    });
    // 待提交数组流
    const toBeSubmit$ = new Subject<any[]>();
    toBeSubmit$.pipe(
      // 加签
      switchMap(params => this.getMessageAndSign(params)),
      // 若有待提交,执行请求,否则返回空数组
      switchMap(toBeSubmit => {
        if (toBeSubmit.length) {
          this.loadingService.show();
          return this.template.http('/service/submit', 'PUT', {params: toBeSubmit});
        } else {
          return of([]);
        }
      }),
      // 转换响应结果
      map(response => {
        const responseResult = response as ActionResult[];
        // 赋值请求结果data字段
        responseResult.forEach(r => r.data = this.frameContext.repository.entityCollection.getEntityById(r.id));
        // 合并已有的校验结果
        responseResult.push(...validResult);
        return responseResult;
      }),
      // 若有结果,调用弹窗服务,否则抛出空数组
      switchMap((result: ActionResult[]) => {
          if (result.length) {
            return this.batchResultService.open(
              this.translateService.instant('submit'), result, this.loadingService, this.notifyService, this.dialogConfig);
          } else {
            return of([]);
          }
        }
      ),
      // 获取弹窗返回的待确认选择项,若有确认的,进行下一次循环,否则结束
      tap(dialogResult => {
        if (dialogResult.length) {
          // 清空前端的校验结果,不再第二次提示
          validResult.length = 0;
          // 清空提交项,组装下一次提交参数,确认参数改为true
          submitIds.length = 0;
          dialogResult.forEach(result => submitIds.push({id: result, confirmOverBalance: true}));
          // 执行下一次循环
          toBeSubmit$.next(submitIds);
        } else {
          toBeSubmit$.complete();
        }
      })
    ).subscribe({
      // 若有成功提交的,重新加载数据
      complete: () => this.frameContext.viewModel['Load1']()
    });
    // 执行提交
    toBeSubmit$.next(submitIds);
  }

# @gsp-fund/ui - SimpleDialogModule 公共简易表单输入框模块

项目地址

gitlab npm 离线包 \\10.100.1.163\产品服务器\待测库\TM_Cloud\内部使用\资金内部node_modules\@gsp-fund

使用

  1. 表单设计器引用(打开表单后直接点击代码编辑器,拖到最后添加以下代码)
        "isComposedFrm": true,
        "extraImports": [
            {
                "path": "@gsp-fund/ui",
                "name": "SimpleDialogModule"
            }
        ]
  1. 注入SimpleDialogService弹窗服务

SimpleDialogService服务

open方法

根据传入的结果及列配置打开弹窗(存在失败)或弹出右下角成功提示(全部为成功),若存在待确认,支持选择,返回选择的数组流

参数类型备注
titlestring标题
controls数组控件及相关配置
option{width?: number,height?: number,controlInline?:boolean,validateCallback:(value:any)=>boolean}窗口相关配置,可选,

返回Subject<any> ,其中key为controls中的key,值为对应数据框的值

控件配置数组结构

属性类型备注
keystring必传,用于结果key的组装
labelstring控件label,可选
type'string' | 'number'| 'checkbox' | 'date' | 'dateRange' | 'radioGroup' | 'textArea'字符串,对应为控件类型,可选,默认为string
groupConfig{value: string, label: strin }[]用于radioGroup控件类型的配置,radioGroup类型时必传,label为radio的label,value为对应值

窗口配置参数

属性类型备注
widthnumber宽度,默认340
heightnumber高度,默认根据控件数量及类型计算
controlInlinenumberlabel与控件同行,默认为true
validateCallback(value: any) => boolean校验函数回调,传入表单的值,返回boolean,必须传入lambda表达式或变量,避免this指向问题 选填

示例

// 组装参数,自行处理国际化
const config: {
      key: string,
      label?: string,
      type?: 'string' | 'number' | 'checkbox' | 'date' | 'dateRange' | 'radioGroup' | 'textArea',
      groupConfig?: {
        value: string,
        label: string
      }[]
    }[] = [
      {
        key: 'text',
        label: '测试文本'
      },
      {
        key: 'number',
        label: '测试数字',
        type: 'number'
      },
      {
        key: 'date',
        type: 'date'
      },
      {
        key: 'check',
        label: '测试check',
        type: 'checkbox'
      },
      {
        key: 'dateRange',
        label: '测试日期范围',
        type: 'dateRange'
      },
      {
        key: 'textArea',
        label: '说明',
        type: 'textArea'
      },
      {
        key: 'radio',
        label: '测试radio',
        type: 'radioGroup',
        groupConfig: [
          {
           value: 'a',
           label: 'AAAAAAAAAAAA'
          },
          {
            value: 'b',
            label: 'BBBBBBBBBB'
          },
          {
            value: 'c',
            label: 'CCCCCCCCCCC'
          }
        ]
      }
    ];
    const validateFun = (value) => {
      if (!value['text']) {
        alert('测试文本为空');
        return false;
      }
      return true;

    }
    this.simpleDialogService.open('测试弹窗', config, {controlInline: false, validateCallback: validateFun}).subscribe(result => {
      console.log(result);
    })
0.0.8

4 years ago

0.0.7

5 years ago

0.0.5

5 years ago

0.0.4

5 years ago

0.0.3

5 years ago

0.0.2

5 years ago

0.0.1

5 years ago