0.0.8 • Published 4 years ago
@gsp-fund/ui v0.0.8
@gsp-fund/ui - BatchResultModule 批量结果弹窗模块
项目地址
gitlab
npm
离线包 \\10.100.1.163\产品服务器\待测库\TM_Cloud\内部使用\资金内部node_modules\@gsp-fund
使用
- 表单设计器引用(打开表单后直接点击代码编辑器,拖到最后添加以下代码)
"isComposedFrm": true,
"extraImports": [
{
"path": "@gsp-fund/ui",
"name": "BatchResultModule"
}
]
- 注入
BatchResultService
弹窗服务
BatchResultService
弹窗服务
open
方法
根据传入的结果及列配置打开弹窗(存在失败)或弹出右下角成功提示(全部为成功),若存在待确认,支持选择,返回选择的数组流
参数 | 类型 | 备注 |
---|---|---|
action | string | 操作名称,用于标题 |
actionResult | ActionResult[] | 动作结果数组 |
formLoadingService | FormLoadingService | 平台formLoading服务 |
formNotifyService | FormNotifyService | 平台formNotifyService服务 |
columns | {field: string,title: string,type?: ColumnType,width?: number}[] | 列配置数组,可选 |
返回Subject<string[]>
表示待确认列表选择的id数组流
若弹窗正常结束或关闭,返回空数组
ActionResult
类结构
属性 | 类型 | 备注 |
---|---|---|
id | string | 主键,由于平台farris-grid限制,必填 |
data | any | 数据,用于open 方法中的columns 的field 取值 |
state | ActionState | 动作结果的枚举,也可为对应枚举的number值 |
message | string | 提示信息 |
枚举ActionState
枚举 | 值 | 备注 |
---|---|---|
Success | 1 | 成功 |
ToBeConfirmed | 2 | 待确认 |
Failed | -1 | 失败 |
columns
参数详情
属性 | 类型 | 备注 |
---|---|---|
field | string | 字段属性名,若为多级结构用. 连接,列表取数时取ActionResult 中data 属性的对应值 |
title | string | 列标题 |
type | ColumnType | 列数据类型枚举,封装了常用类型的平台列配置 |
width | number | 列宽 |
ColumnType
枚举
枚举 | 值 | 备注 |
---|---|---|
String | 0 | 字符串,靠左,无格式特殊处理 |
AccountNo | 1 | 账号,靠左,四位空格分隔 |
Amount | 2 | 金额,靠右,数字格式化 |
默认配置为
[
{
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
窗口配置参数详情
枚举 | 默认值 | 备注 |
---|---|---|
showButton | true | 显示底部按钮(存在待确认结果时设为false无效) |
width | 800 | 宽度 |
height | 600 | 高度 |
title | 参数action的值 | 标题 |
用法举例
- 后端组装基本的
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;
}
}
- 前端配置弹窗的展示列配置
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')
}
];
}
- 组装弹窗需要的结果入参(若后端已赋值
data
,可跳过)
// 转换响应结果
map(response => {
const responseResult = response as ActionResult[];
// 赋值请求结果data字段
responseResult.forEach(r => r.data = this.frameContext.repository.entityCollection.getEntityById(r.id));
return responseResult;
}),
- 调用弹窗服务并处理弹窗结果
// 调用弹窗服务
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
使用
- 表单设计器引用(打开表单后直接点击代码编辑器,拖到最后添加以下代码)
"isComposedFrm": true,
"extraImports": [
{
"path": "@gsp-fund/ui",
"name": "SimpleDialogModule"
}
]
- 注入
SimpleDialogService
弹窗服务
SimpleDialogService
服务
open
方法
根据传入的结果及列配置打开弹窗(存在失败)或弹出右下角成功提示(全部为成功),若存在待确认,支持选择,返回选择的数组流
参数 | 类型 | 备注 |
---|---|---|
title | string | 标题 |
controls | 数组 | 控件及相关配置 |
option | {width?: number,height?: number,controlInline?:boolean,validateCallback:(value:any)=>boolean} | 窗口相关配置,可选, |
返回Subject<any>
,其中key为controls中的key,值为对应数据框的值
控件配置数组结构
属性 | 类型 | 备注 |
---|---|---|
key | string | 必传,用于结果key的组装 |
label | string | 控件label,可选 |
type | 'string' | 'number'| 'checkbox' | 'date' | 'dateRange' | 'radioGroup' | 'textArea' | 字符串,对应为控件类型,可选,默认为string |
groupConfig | {value: string, label: strin }[] | 用于radioGroup控件类型的配置,radioGroup类型时必传,label为radio的label,value为对应值 |
窗口配置参数
属性 | 类型 | 备注 |
---|---|---|
width | number | 宽度,默认340 |
height | number | 高度,默认根据控件数量及类型计算 |
controlInline | number | label与控件同行,默认为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);
})