BUG527:エラーの共通処理追加

This commit is contained in:
xiaozhe.ma
2024-07-31 18:28:25 +09:00
parent 96722d9c2f
commit b6a68198f5
23 changed files with 345 additions and 123 deletions

View File

@@ -1 +1,68 @@
@import 'bootstrap/scss/bootstrap';
// @import 'bootstrap/scss/bootstrap';
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/root";
.bs-scope{
// Required
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
@import "bootstrap/scss/images";
@import "bootstrap/scss/containers";
@import "bootstrap/scss/grid";
// @import "bootstrap/scss/tables";
// @import "bootstrap/scss/forms";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/transitions";
@import "bootstrap/scss/dropdown";
// @import "bootstrap/scss/button-group";
// @import "bootstrap/scss/nav";
// @import "bootstrap/scss/navbar"; // Requires nav
@import "bootstrap/scss/card";
// @import "bootstrap/scss/breadcrumb";
// @import "bootstrap/scss/accordion";
// @import "bootstrap/scss/pagination";
// @import "bootstrap/scss/badge";
// @import "bootstrap/scss/alert";
// @import "bootstrap/scss/progress";
// @import "bootstrap/scss/list-group";
@import "bootstrap/scss/close";
// @import "bootstrap/scss/toasts";
@import "bootstrap/scss/modal"; // Requires transitions
// @import "bootstrap/scss/tooltip";
@import "bootstrap/scss/popover";
// @import "bootstrap/scss/carousel";
@import "bootstrap/scss/spinners";
@import "bootstrap/scss/offcanvas"; // Requires transitions
// @import "bootstrap/scss/placeholders";
// Helpers
// @import "bootstrap/scss/helpers";
// Utilities
@import "bootstrap/scss/utilities/api";
}
.modal-backdrop {
--bs-backdrop-zindex: 1050;
--bs-backdrop-bg: #000;
--bs-backdrop-opacity: .5;
position: fixed;
top: 0;
left: 0;
z-index: var(--bs-backdrop-zindex);
width: 100vw;
height: 100vh;
background-color: var(--bs-backdrop-bg)
}
.modal-backdrop.fade {
opacity: 0
}
.modal-backdrop.show {
opacity: var(--bs-backdrop-opacity)
}

View File

@@ -96,14 +96,14 @@ export class AutoLookUpAction implements IAction {
* アクセスのメインの処理関数
*/
async process(
prop: IActionNode,
actionNode: IActionNode,
event: any,
context: IContext
): Promise<IActionResult> {
this.actionProps = prop.actionProps;
this.actionProps = actionNode.actionProps;
this.props = {
...prop.ActionValue,
condition: JSON.parse((prop.ActionValue as any).condition),
...actionNode.ActionValue,
condition: JSON.parse((actionNode.ActionValue as any).condition),
} as Props;
// console.log(context);
@@ -133,15 +133,9 @@ export class AutoLookUpAction implements IAction {
await this.updateLookupTarget(updateRecords);
this.showResult(this.props.lookupField.app,updateRecords.length);
} catch (error) {
console.error("ルックアップ更新中例外が発生しました。", error);
if(error instanceof Error){
event.error = error.message;
}else{
event.error = "ルックアップ更新中例外が発生しました。";
}
context.errors.handleError(error,actionNode,"ルックアップ更新中例外が発生しました");
result.canNext = false;
}
console.log("autoLookupProps", this.props);
return result;
}
@@ -213,7 +207,7 @@ export class AutoLookUpAction implements IAction {
showSpinnerModel = (app:App) => {
let dialog = $("#alcLookupModal");
if(dialog.length===0){
const modalHTML = `
const modalHTML = `<div class="bs-scope">
<div class="modal" id="alcLookupModal" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog-centered">
<div class="modal-dialog modal-content">
@@ -230,13 +224,12 @@ export class AutoLookUpAction implements IAction {
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">OK</button>
</div>
</div>
</div>
</div>`;
dialog = $(modalHTML).appendTo("body");
</div></div></div></div>`;
$(modalHTML).appendTo("body");
dialog = $("#alcLookupModal");
dialog.get()[0].addEventListener('hidden.bs.modal',(ev)=>{
Modal.getOrCreateInstance(dialog.get()[0]).dispose();
$("#alcLookupModal").remove();
$("#alcLookupModal").parent().remove();
});
}else{
const dialogBody=$("#alcLookupModal .modal-body");
@@ -248,7 +241,7 @@ export class AutoLookUpAction implements IAction {
<div>`;
dialogBody.append(htmlrow);
}
Modal.getOrCreateInstance(dialog.get()[0]).show();
Modal.getOrCreateInstance(dialog.get()[0]).show();
}
/**

View File

@@ -65,8 +65,7 @@ export class AutoNumbering implements IAction{
}
return result;
}catch(error){
console.error(error);
event.error="処理中異常が発生しました。";
context.errors.handleError(error,actionNode);
return {
canNext:false,
result:false

View File

@@ -1,7 +1,7 @@
import { actionAddins } from ".";
import $ from 'jquery';
import { IAction, IActionProperty, IActionNode, IActionResult } from "../types/ActionTypes";
import { IAction, IActionProperty, IActionNode, IActionResult, IContext } from "../types/ActionTypes";
import "./button-add.css";
/**
@@ -43,7 +43,7 @@ export class ButtonAddAction implements IAction {
* @param event
* @returns
*/
async process(actionNode: IActionNode, event: any): Promise<IActionResult> {
async process(actionNode: IActionNode, event: any,context:IContext): Promise<IActionResult> {
let result = {
canNext: true,
result: false
@@ -75,8 +75,7 @@ export class ButtonAddAction implements IAction {
});
return result;
} catch (error) {
event.error = error;
console.error(error);
context.errors.handleError(error,actionNode);
result.canNext = false;
return result;
}

View File

@@ -63,8 +63,7 @@ export class ConditionAction implements IAction{
}
return result;
}catch(error){
event.error=error;
console.error(error);
context.errors.handleError(error,actionNode);
result.canNext=false;
return result;
}

View File

@@ -1,5 +1,5 @@
import { actionAddins } from ".";
import { IAction,IActionResult, IActionNode, IActionProperty, IField} from "../types/ActionTypes";
import { IAction,IActionResult, IActionNode, IActionProperty, IField, IContext} from "../types/ActionTypes";
/**
* アクションの属性定義
*/
@@ -32,7 +32,7 @@ export class StrCountCheckAciton implements IAction{
* @param event
* @returns
*/
async process(actionNode:IActionNode,event:any):Promise<IActionResult> {
async process(actionNode:IActionNode,event:any,context:IContext):Promise<IActionResult> {
let result={
canNext:true,
result:false
@@ -61,8 +61,7 @@ export class StrCountCheckAciton implements IAction{
}
return result;
}catch(error){
event.error=error;
console.error(error);
context.errors.handleError(error,actionNode);
result.canNext=false;
return result;
}

View File

@@ -4,13 +4,14 @@ import {
IActionNode,
IActionProperty,
IContext,
IField,
} from "../types/ActionTypes";
import { actionAddins } from ".";
interface Props {
interface ICurrentFieldGetProps {
displayName: string;
field: Field;
field: IField;
verName: VerName;
}
@@ -18,49 +19,43 @@ interface VerName {
name: string;
}
interface Field {
name: string;
type: string;
code: string;
label: string;
noLabel: boolean;
required: boolean;
minLength: string;
maxLength: string;
expression: string;
hideExpression: boolean;
unique: boolean;
defaultValue: string;
}
export class CurrentFieldGetAction implements IAction {
name: string;
actionProps: IActionProperty[];
currentFieldGetProps: Props;
props: ICurrentFieldGetProps;
constructor() {
this.name = "フィールドの値を取得する";
this.actionProps = [];
this.currentFieldGetProps = {} as Props;
this.props = {} as ICurrentFieldGetProps;
this.register();
}
async process(
prop: IActionNode,
actionNode: IActionNode,
event: any,
context: IContext
): Promise<IActionResult> {
this.currentFieldGetProps = prop.ActionValue as Props;
this.actionProps = prop.actionProps;
this.props = actionNode.ActionValue as ICurrentFieldGetProps;
this.actionProps = actionNode.actionProps;
let result = {
canNext: true,
result: "",
result: '',
} as IActionResult;
try {
context.variables[this.currentFieldGetProps.verName.name] = context.record[this.currentFieldGetProps.field.code].value;
} catch (error) {
console.error("CurrentFieldGetAction error", error);
const record = event.record;
if(!(this.props.field.code in record)){
throw new Error(`フィールド[${this.props.field.code}]が見つかりませんでした。`);
}
//変数設定
if(this.props.verName && this.props.verName.name!==''){
context.variables[this.props.verName.name]=record[this.props.field.code].value;
}
}
catch (error) {
context.errors.handleError(error,actionNode);
result.canNext = false;
}
return result;

View File

@@ -83,13 +83,13 @@ export class DataProcessingAction implements IAction {
}
async process(
nodes: IActionNode,
actionNode: IActionNode,
event: any,
context: IContext
): Promise<IActionResult> {
this.actionProps = nodes.actionProps;
this.actionProps = actionNode.actionProps;
this.props = nodes.ActionValue as IDataProcessingProps;
this.props = actionNode.ActionValue as IDataProcessingProps;
const condition = JSON.parse(this.props.condition) as Condition;
let result = {
canNext: true,
@@ -118,12 +118,7 @@ export class DataProcessingAction implements IAction {
}
return result;
} catch (error) {
console.error("データ集計中例外が発生しました。", error);
if(error instanceof Error){
event.error = `データ集計中例外が発生しました。 ${error.message}`;
}else{
event.error = "データ集計中例外が発生しました。";
}
context.errors.handleError(error,actionNode);
result.canNext = false;
return result;
}

View File

@@ -74,12 +74,12 @@ export class DataUpdateAction implements IAction {
}
async process(
prop: IActionNode,
actionNode: IActionNode,
event: any,
context: IContext
): Promise<IActionResult> {
this.actionProps = prop.actionProps;
this.dataMappingProps = prop.ActionValue as Props;
this.actionProps = actionNode.actionProps;
this.dataMappingProps = actionNode.ActionValue as Props;
console.log(context);
let result = {
canNext: true,
@@ -121,7 +121,7 @@ export class DataUpdateAction implements IAction {
);
}
} catch (error) {
console.error("DataMappingAction error", error);
context.errors.handleError(error,actionNode);
result.canNext = false;
}
console.log("dataMappingProps", this.dataMappingProps);

View File

@@ -52,8 +52,7 @@ export class DatetimeGetterAction implements IAction {
return result;
} catch (error) {
event.error = error;
console.error(error);
context.errors.handleError(error,actionNode);
result.canNext = false;
return result;
}

View File

@@ -30,12 +30,12 @@ export class ErrorShowAction implements IAction {
* @param event
* @returns
*/
async process(actionNode: IActionNode, event: any, context: IContext): Promise<IActionResult> { //异步处理某函数下的xx属性
async process(actionNode: IActionNode, event: any, context: IContext): Promise<IActionResult> {
let result = {
canNext: true,
result: false
};
try { //尝试执行以下代码部分
try {
this.actionProps = actionNode.actionProps;
if (!('message' in actionNode.ActionValue) && !('condition' in actionNode.ActionValue)) { //如果message以及condition两者都不存在的情况下return
return result
@@ -52,8 +52,7 @@ export class ErrorShowAction implements IAction {
}
return result;
} catch (error) {
event.error = error;
console.error(error);
context.errors.handleError(error,actionNode);
result.canNext = false;
return result;
}

View File

@@ -0,0 +1,112 @@
import { actionAddins } from ".";
import { IAction,IActionResult, IActionNode, IActionProperty, IField, IContext } from "../types/ActionTypes";
import { ConditionTree } from '../types/Conditions';
/**
* アクションの属性定義
*/
interface IDisableProps{
//対象フィールド
field:IField;
//編集可/不可設定
editable:'編集可'|'編集不可'|'';
condition:string;
}
/**
* 編集可/不可アクション
*/
export class FieldDisableAction implements IAction{
name: string;
actionProps: IActionProperty[];
props:IDisableProps;
constructor(){
this.name="編集可/不可";
this.actionProps=[];
this.props={
field:{code:''},
editable:'',
condition:''
}
//アクションを登録する
this.register();
}
/**
* アクションの実行を呼び出す
* @param actionNode
* @param event
* @returns
*/
async process(actionNode:IActionNode,event:any,context:IContext):Promise<IActionResult> {
let result={
canNext:true,
result:false
};
try{
//属性設定を取得する
this.actionProps=actionNode.actionProps;
if (!('field' in actionNode.ActionValue) && !('editable' in actionNode.ActionValue)) {
return result
}
this.props = actionNode.ActionValue as IDisableProps;
//条件式の計算結果を取得
const conditionResult = this.getConditionResult(context);
const record = event.record;
if(!(this.props.field.code in record)){
throw new Error(`フィールド「${this.props.field.code}」が見つかりません。`);
}
if(conditionResult){
if(this.props.editable==='編集可'){
record[this.props.field.code].disabled=false;
}else if (this.props.editable==='編集不可'){
record[this.props.field.code].disabled=true;
}
}
result= {
canNext:true,
result:true
}
return result;
}catch(error){
context.errors.handleError(error,actionNode);
result.canNext=false;
return result;
}
}
/**
*
* @param context 条件式を実行する
* @returns
*/
getConditionResult(context:any):boolean{
const tree =this.getCondition(this.props.condition);
if(!tree){
//条件を設定されていません
return true;
}
return tree.evaluate(tree.root,context);
}
/**
* @param condition 条件式ツリーを取得する
* @returns
*/
getCondition(condition:string):ConditionTree|null{
try{
const tree = new ConditionTree();
tree.fromJson(condition);
if(tree.getConditions(tree.root).length>0){
return tree;
}else{
return null;
}
}catch(error){
return null;
}
}
register(): void {
actionAddins[this.name]=this;
}
}
new FieldDisableAction();

View File

@@ -61,8 +61,7 @@ export class FieldShownAction implements IAction{
}
return result;
}catch(error){
event.error=error;
console.error(error);
context.errors.handleError(error,actionNode);
result.canNext=false;
return result;
}

View File

@@ -512,13 +512,10 @@ export class InsertValueAction implements IAction{
}
return result;
}catch(error:any){
event.record;
event.error=error.message;
console.error(error);
context.errors.handleError(error,actionNode);
result.canNext=true;//次のノードは処理を続ける
return result;
}
}
/**

View File

@@ -61,7 +61,7 @@ export class LoginUserGetterAction implements IAction{
return result;
//////////////////////////////////////////////////////////////////////////////////////
}catch(error:any){;
event.error=error.message;
context.errors.handleError(error,actionNode);
return {
canNext:false,
result:false

View File

@@ -1,5 +1,5 @@
import { actionAddins } from ".";
import { IAction, IActionResult, IActionNode, IActionProperty, IField } from "../types/ActionTypes";
import { IAction, IActionResult, IActionNode, IActionProperty, IField, IContext } from "../types/ActionTypes";
/**
* アクションの属性定義
*/
@@ -32,7 +32,7 @@ export class MailCheckAction implements IAction {
* @param event
* @returns
*/
async process(actionNode: IActionNode, event: any): Promise<IActionResult> {
async process(actionNode: IActionNode, event: any,context:IContext): Promise<IActionResult> {
let result = {
canNext: true,
result: false
@@ -46,8 +46,11 @@ export class MailCheckAction implements IAction {
return result
}
this.props = actionNode.ActionValue as IMailCheckProps;
//条件式の計算結果を取得
const record = event.record;
//対象フィールドの存在チェック
if(!(this.props.field.code in record)){
throw new Error(`フィールド[${this.props.field.code}]が見つかりませんでした。`);
}
const value = record[this.props.field.code].value;
if (this.props.emailCheck === '厳格') {
@@ -56,13 +59,15 @@ export class MailCheckAction implements IAction {
}
else {
record[this.props.field.code].error = null;
result.result=true;
}
} else if (this.props.emailCheck === 'ゆるめ') {
if (!/^[^@]+@[^@]+$/.test(value)) {
record[this.props.field.code].error = this.props.message;
}
else {
record[this.props.field.code].error = null;
record[this.props.field.code].error = null;
result.result=true;
}
} else {
result = {
@@ -72,8 +77,7 @@ export class MailCheckAction implements IAction {
}
return result;
} catch (error) {
event.error = error;
console.error(error);
context.errors.handleError(error,actionNode);
result.canNext = false;
return result;
}

View File

@@ -1,6 +1,6 @@
import { actionAddins } from ".";
import { IAction,IActionResult, IActionNode, IActionProperty, IField } from "../types/ActionTypes";
import { IAction,IActionResult, IActionNode, IActionProperty, IField, IContext } from "../types/ActionTypes";
interface IMustInputProps{
field:IField;
@@ -22,25 +22,33 @@ export class MustInputAction implements IAction{
this.register();
}
async process(actionNode:IActionNode,event:any):Promise<IActionResult> {
async process(actionNode:IActionNode,event:any,context:IContext):Promise<IActionResult> {
let result={
canNext:true,
result:false
};
this.actionProps=actionNode.actionProps;
if (!('field' in actionNode.ActionValue) && !('message' in actionNode.ActionValue)) {
return result
}
this.props = actionNode.ActionValue as IMustInputProps;
const record = event.record;
const value = record[this.props.field.code]?.value;
if(value===undefined || value===''){
record[this.props.field.code].error=this.props.message;
return result;
}
result= {
canNext:true,
result:true
try{
this.actionProps=actionNode.actionProps;
if (!('field' in actionNode.ActionValue) && !('message' in actionNode.ActionValue)) {
return result
}
this.props = actionNode.ActionValue as IMustInputProps;
const record = event.record;
if(!(this.props.field.code in record)){
throw new Error(`フィールド[${this.props.field.code}]が見つかりませんでした。`);
}
const value = record[this.props.field.code].value;
if(value===undefined || value===''){
record[this.props.field.code].error=this.props.message;
return result;
}
result= {
canNext:true,
result:true
}
}catch(error){
context.errors.handleError(error,actionNode);
result.canNext=false;
}
return result;
}

View File

@@ -1,5 +1,5 @@
import { actionAddins } from ".";
import { IAction,IActionResult, IActionNode, IActionProperty, IField} from "../types/ActionTypes";
import { IAction,IActionResult, IActionNode, IActionProperty, IField, IContext} from "../types/ActionTypes";
/**
* アクションの属性定義
*/
@@ -32,7 +32,7 @@ export class RegularCheckAction implements IAction{
* @param event
* @returns
*/
async process(actionNode:IActionNode,event:any):Promise<IActionResult> {
async process(actionNode:IActionNode,event:any,context:IContext):Promise<IActionResult> {
let result={
canNext:true,
result:false
@@ -60,8 +60,7 @@ export class RegularCheckAction implements IAction{
}
return result;
}catch(error){
event.error=error;
console.error(error);
context.errors.handleError(error,actionNode);
result.canNext=false;
return result;
}

View File

@@ -68,8 +68,9 @@ export class FullWidthAction implements IAction{
//例外処理
}catch(error){
event.error=error;
console.error(error);
// event.error=error;
// console.error(error);
context.errors.handleError(error,actionNode);
result.canNext=false;
return result;
}

View File

@@ -68,8 +68,9 @@ export class HalfWidthAction implements IAction{
return result;
//例外処理
}catch(error){
event.error=error;
console.error(error);
// event.error=error;
// console.error(error);
context.errors.handleError(error,actionNode);
result.canNext=false;
return result;
}

View File

@@ -56,8 +56,9 @@ export class GetValueAciton implements IAction{
return result;
}catch(error){
event.error=error;
console.error(error);
// event.error=error;
// console.error(error);
context.errors.handleError(error,actionNode);
result.canNext=false;
return result;
}

View File

@@ -1,4 +1,3 @@
/**
* アプリ情報
*/
@@ -67,7 +66,8 @@ export interface IActionResult{
*/
export interface IContext{
record:any,
variables:any
variables:any,
errors:ErrorManager
}
/**
@@ -85,6 +85,7 @@ export interface IAction{
}
export interface IField{
name?:string;
code:string;
@@ -275,3 +276,46 @@ export class ActionFlow implements IActionFlow {
}
}
export interface IActionError{
action: IActionNode,
error:string
}
export class ErrorManager{
private errors:IActionError[]=[];
public get hasError():boolean{
return this.errors.length>0;
}
public handleError(err:any,action:IActionNode,defaultMessage?:string){
const defMsg = defaultMessage ? defaultMessage : '';
let error = err instanceof Error? `${defMsg} ${err.message}` : defMsg ;
console.error(`${action.name}」処理中例外発生しました。`,err);
this.errors.push({error,action});
}
public setEvent(event:any){
const messages = this.errors.map((err)=>{
return `${err.action.name}」処理中例外発生しました。詳細:${err.error}`;
});
event.error=messages.join('\n');
}
public showError(){
const msg =this.errors.map((err)=>{
return `${err.action.name}」処理中例外発生しました。\n詳細:${err.error}`;
});
window.alert(msg);
// const html=
// `<div id="myalert" class="notifier-cybozu notifier-error-cybozu" style="left: 50%; top: 0px;">
// <div class="notifier-header-cybozu"><div class="notifier-title-cybozu">エラー</div>
// <ul class="notifier-body-cybozu"><li>${msg}</li></ul></div>
// <a class="notifier-remove-cybozu" href="javascript:void(0)"></a></div>`
// const alert = $(html).appendTo("body");
// alert.children("#myalert .notifier-remove-cybozu").on("click",(ev)=>{
// $("myalert").slideUp().remove();
// });
}
}

View File

@@ -20,21 +20,28 @@ import '../actions/validation-fullwidth';
import '../actions/validation-halfwidth';
import '../actions/login-user-getter';
import '../actions/auto-lookup';
import { ActionFlow,IActionFlow, IActionResult,IContext } from "./ActionTypes";
import '../actions/field-disable';
import { ActionFlow,ErrorManager,IActionFlow, IActionResult,IContext } from "./ActionTypes";
const ShowErrorEvents:string[] = [
"app.record.create.submit.success",
"app.record.edit.submit.success",
"app.record.index.edit.submit.success",
];
export class ActionProcess{
eventId:string;
flow:IActionFlow;
event:any;
context:IContext;
constructor(eventId:string,flow:ActionFlow,event:any){
constructor(eventId:string,flow:ActionFlow,event:any){
this.eventId=eventId;
this.flow=flow;
this.event=event;
const errormanager = new ErrorManager();
this.context={
record:this.event.record,
variables:{}
variables:{},
errors:errormanager
};
}
async exec(){
@@ -59,9 +66,14 @@ export class ActionProcess{
nextInput = result.result||'';
}
id=nextAction.nextNodeIds.get(nextInput);
if(id===undefined) return;
if(id===undefined) break;
nextAction = this.flow.findNodeById(id);
}
if(this.context.errors.hasError){
this.context.errors.setEvent(this.event);
if(ShowErrorEvents.includes(this.event.type)){
this.context.errors.showError();
}
}
}
}