条件エディタ実装
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -25,6 +25,7 @@ api.interceptors.response.use(
|
||||
(error)=>{
|
||||
const orgReq=error.config;
|
||||
if(error.response && error.response.status===401){
|
||||
console.error("401エラー");
|
||||
localStorage.removeItem('token');
|
||||
router.replace({
|
||||
path:"/login",
|
||||
|
||||
@@ -1,13 +1,30 @@
|
||||
<template>
|
||||
<show-dialog v-model:visible="showflg" name="条件エディタ" @close="closeDg" width="60vw" height="60vh">
|
||||
<template v-slot:toolbar>
|
||||
<q-btn flat round dense icon="more_vert" >
|
||||
<q-menu auto-close anchor="bottom start">
|
||||
<q-list>
|
||||
<q-item clickable @click="copyCondition()">
|
||||
<q-item-section avatar><q-icon name="content_copy" ></q-icon></q-item-section>
|
||||
<q-item-section >コピー</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable @click="pasteCondition()">
|
||||
<q-item-section avatar><q-icon name="content_paste" ></q-icon></q-item-section>
|
||||
<q-item-section >貼り付け</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
</template>
|
||||
<NodeCondition v-model:conditionTree="tree"></NodeCondition>
|
||||
</show-dialog>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref ,watchEffect} from 'vue';
|
||||
import ShowDialog from '../../components/ShowDialog.vue';
|
||||
import NodeCondition from './NodeCondition.vue';
|
||||
import { ConditionTree } from '../../types/Conditions';
|
||||
import ShowDialog from '../../components/ShowDialog.vue';
|
||||
import NodeCondition from './NodeCondition.vue';
|
||||
import { ConditionTree } from '../../types/Conditions';
|
||||
import { useQuasar } from 'quasar';
|
||||
export default defineComponent({
|
||||
name: 'ConditionObject',
|
||||
components: {
|
||||
@@ -24,18 +41,55 @@ import { defineComponent, ref ,watchEffect} from 'vue';
|
||||
default:false
|
||||
}
|
||||
},
|
||||
emits:[
|
||||
"closed",
|
||||
"update:conditionTree",
|
||||
"update:show"
|
||||
],
|
||||
setup(props,context) {
|
||||
const appDg = ref();
|
||||
const $q=useQuasar();
|
||||
const tree = ref(props.conditionTree);
|
||||
const closeDg = (val:string) => {
|
||||
if (val == 'OK') {
|
||||
if(tree.value.root.children.length===0){
|
||||
$q.notify({
|
||||
type: 'negative',
|
||||
message: `条件式を設定してください。`
|
||||
});
|
||||
}
|
||||
context.emit("update:conditionTree",tree.value);
|
||||
}
|
||||
showflg.value=false;
|
||||
context.emit("update:show",false);
|
||||
context.emit("closed",val);
|
||||
};
|
||||
const showflg =ref(props.show);
|
||||
|
||||
//条件式をコピーする
|
||||
const copyCondition=()=>{
|
||||
if (navigator.clipboard) {
|
||||
const jsonData=tree.value.toJson();
|
||||
navigator.clipboard.writeText(jsonData).then(() => {
|
||||
console.log('Text successfully copied to clipboard');
|
||||
},
|
||||
(err) => {
|
||||
console.error('Error in copying text: ', err);
|
||||
});
|
||||
} else {
|
||||
console.log('Clipboard API not available');
|
||||
}
|
||||
};
|
||||
//条件式を貼り付ける
|
||||
const pasteCondition=async ()=>{
|
||||
try {
|
||||
const text = await navigator.clipboard.readText();
|
||||
console.log('Text from clipboard:', text);
|
||||
tree.value.fromJson(text);
|
||||
} catch (err) {
|
||||
console.error('Failed to read text from clipboard: ', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
watchEffect(() => {
|
||||
showflg.value=props.show;
|
||||
});
|
||||
@@ -44,7 +98,9 @@ import { defineComponent, ref ,watchEffect} from 'vue';
|
||||
tree,
|
||||
appDg,
|
||||
closeDg,
|
||||
showflg
|
||||
showflg,
|
||||
copyCondition,
|
||||
pasteCondition
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -11,20 +11,20 @@
|
||||
</template>
|
||||
</q-field>
|
||||
<show-dialog v-model:visible="show" name="フィールド一覧" @close="closeDg" widht="400px">
|
||||
<field-select ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></field-select>
|
||||
<condition-objects ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></condition-objects>
|
||||
</show-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref ,watchEffect,computed} from 'vue';
|
||||
import ShowDialog from '../ShowDialog.vue';
|
||||
import FieldSelect from '../FieldSelect.vue';
|
||||
import ConditionObjects from '../ConditionObjects.vue';
|
||||
import { useFlowEditorStore } from '../../stores/flowEditor';
|
||||
export default defineComponent({
|
||||
name: 'ConditionObject',
|
||||
components: {
|
||||
ShowDialog,
|
||||
FieldSelect,
|
||||
ConditionObjects,
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
|
||||
@@ -34,15 +34,6 @@
|
||||
<q-btn flat round dense icon="more_horiz" size="sm" >
|
||||
<q-menu auto-close anchor="top right">
|
||||
<q-list>
|
||||
<q-item clickable @click="addGroup(prop.node, LogicalOperator.AND)">
|
||||
<q-item-section avatar><q-icon name="playlist_add" ></q-icon></q-item-section>
|
||||
<q-item-section >グループ追加</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable @click="addCondition(prop.node)">
|
||||
<q-item-section avatar><q-icon name="add_circle_outline" ></q-icon></q-item-section>
|
||||
<q-item-section >条件式追加</q-item-section>
|
||||
</q-item>
|
||||
<q-separator inset/>
|
||||
<q-item clickable @click="moveUp(prop.node)">
|
||||
<q-item-section avatar><q-icon name="arrow_upward" ></q-icon></q-item-section>
|
||||
<q-item-section >一つ上に移動</q-item-section>
|
||||
@@ -52,6 +43,19 @@
|
||||
<q-item-section >一つ下に移動</q-item-section>
|
||||
</q-item>
|
||||
<q-separator inset/>
|
||||
<q-item clickable @click="addGroup(prop.node, LogicalOperator.AND)">
|
||||
<q-item-section avatar><q-icon name="playlist_add" ></q-icon></q-item-section>
|
||||
<q-item-section >グループ追加</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable @click="addCondition(prop.node)">
|
||||
<q-item-section avatar><q-icon name="add_circle_outline" ></q-icon></q-item-section>
|
||||
<q-item-section >条件式追加</q-item-section>
|
||||
</q-item>
|
||||
<q-separator inset/>
|
||||
<q-item clickable @click="splitGroup(prop.node)">
|
||||
<q-item-section avatar><q-icon name="playlist_remove" color="negative"></q-icon></q-item-section>
|
||||
<q-item-section >グループ化解除</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable @click="removeNode(prop.node)">
|
||||
<q-item-section avatar><q-icon name="delete" color="negative"></q-icon></q-item-section>
|
||||
<q-item-section >削除</q-item-section>
|
||||
@@ -86,6 +90,11 @@
|
||||
<q-item-section >一つ下に移動</q-item-section>
|
||||
</q-item>
|
||||
<q-separator inset/>
|
||||
<q-item clickable @click="groupMerge(prop.node)" v-if="canMerge(prop.node)">
|
||||
<q-item-section avatar><q-icon name="playlist_add"></q-icon></q-item-section>
|
||||
<q-item-section >グループ化</q-item-section>
|
||||
</q-item>
|
||||
<q-separator inset/>
|
||||
<q-item clickable @click="removeNode(prop.node)">
|
||||
<q-item-section avatar><q-icon name="delete" color="negative"></q-icon></q-item-section>
|
||||
<q-item-section>削除</q-item-section>
|
||||
@@ -102,6 +111,7 @@
|
||||
<q-btn @click="getConditionJson()" class="q-mt-md" color="primary" icon="mdi-plus">Show Condtion data</q-btn>
|
||||
<q-btn @click="LoadCondition()" class="q-mt-md" color="primary" icon="mdi-plus">Load Condition</q-btn> -->
|
||||
<q-tooltip anchor="center middle" v-model="showingCondition" no-parent-event>
|
||||
import { finished } from 'stream';
|
||||
{{ conditionString }}
|
||||
</q-tooltip>
|
||||
</div>
|
||||
@@ -160,7 +170,6 @@ export default defineComponent( {
|
||||
return opts;
|
||||
};
|
||||
|
||||
|
||||
const addGroup = (parent:GroupNode, logicOp:LogicalOperator) => {
|
||||
if(!parent){
|
||||
parent=tree.root;
|
||||
@@ -169,7 +178,7 @@ export default defineComponent( {
|
||||
};
|
||||
|
||||
const addCondition = (parent:GroupNode) => {
|
||||
const newNode = new ConditionNode(LogicalOperator.AND,{},Operator.Equal,'',parent);
|
||||
const newNode = new ConditionNode({},Operator.Equal,'',parent);
|
||||
tree.addNode(parent,newNode);
|
||||
};
|
||||
|
||||
@@ -188,10 +197,36 @@ export default defineComponent( {
|
||||
const getConditionJson=()=>{
|
||||
return tree.toJson();
|
||||
}
|
||||
|
||||
//JsonからConditionTreeのインスタンスを作成
|
||||
const LoadCondition=()=>{
|
||||
tree.fromJson(conditionString.value);
|
||||
}
|
||||
//グループ化
|
||||
const groupMerge=(node:INode)=>{
|
||||
const checkedNodes:INode[]=[];
|
||||
const checkedIndexs:number[] = ticked.value;
|
||||
checkedIndexs.forEach(index => {
|
||||
const node = tree.findByIndex(index);
|
||||
if(node){
|
||||
checkedNodes.push(node);
|
||||
}
|
||||
});
|
||||
tree.createGroupNode(node,checkedNodes,LogicalOperator.AND);
|
||||
ticked.value=[];
|
||||
}
|
||||
//グループ化可能かをチェックする
|
||||
const canMerge =(node:INode)=>{
|
||||
const checkedIndexs:number[] = ticked.value;
|
||||
const findNode = checkedIndexs.find(index=>node.index===index);
|
||||
console.log("findNode=>",findNode!==undefined,findNode);
|
||||
return findNode!==undefined;
|
||||
}
|
||||
//グループ化解散
|
||||
const splitGroup=(node:INode)=>{
|
||||
tree.dissolveGroupNode(node as GroupNode);
|
||||
ticked.value=[];
|
||||
}
|
||||
|
||||
|
||||
const expanded=computed(()=>tree.getGroups(tree.root));
|
||||
// addCondition(tree.root);
|
||||
@@ -214,7 +249,10 @@ export default defineComponent( {
|
||||
getConditionJson,
|
||||
LoadCondition,
|
||||
objectValueOptions,
|
||||
expanded
|
||||
expanded,
|
||||
canMerge,
|
||||
groupMerge,
|
||||
splitGroup
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
54
frontend/src/components/ConditionObjects.vue
Normal file
54
frontend/src/components/ConditionObjects.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="q-pa-md">
|
||||
<div v-if="!isLoaded" class="spinner flex flex-center">
|
||||
<q-spinner color="primary" size="3em" />
|
||||
</div>
|
||||
<q-table v-else row-key="name" :selection="type" v-model:selected="selected" :columns="columns" :rows="rows" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { ref,onMounted,reactive } from 'vue'
|
||||
import { api } from 'boot/axios';
|
||||
|
||||
export default {
|
||||
name: 'ConditionObjects',
|
||||
props: {
|
||||
name: String,
|
||||
type: String,
|
||||
appId:Number
|
||||
},
|
||||
setup(props) {
|
||||
const isLoaded=ref(false);
|
||||
const columns = [
|
||||
{ name: 'name', required: true,label: 'フィールド名',align: 'left',field: row=>row.name,sortable: true},
|
||||
{ name: 'code', label: 'フィールドコード', align: 'left',field: 'code', sortable: true },
|
||||
{ name: 'type', label: 'フィールドタイプ', align: 'left',field: 'type', sortable: true }
|
||||
]
|
||||
const rows = reactive([])
|
||||
onMounted( async () => {
|
||||
const res = await api.get('api/v1/appfields', {
|
||||
params:{
|
||||
app: props.appId
|
||||
}
|
||||
});
|
||||
let fields = res.data.properties;
|
||||
console.log(fields);
|
||||
Object.keys(fields).forEach((key) =>
|
||||
{
|
||||
const fld=fields[key];
|
||||
// rows.push({name:fields[key].label,code:fields[key].code,type:fields[key].type});
|
||||
rows.push({name:fld.label,objectType:'field',...fld});
|
||||
});
|
||||
isLoaded.value=true;
|
||||
});
|
||||
|
||||
return {
|
||||
columns,
|
||||
rows,
|
||||
selected: ref([]),
|
||||
isLoaded
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
@@ -2,10 +2,15 @@
|
||||
<!-- <div class="q-pa-md q-gutter-sm" > -->
|
||||
<q-dialog :model-value="visible" persistent bordered>
|
||||
<q-card :style="{minWidth : width}" >
|
||||
<q-toolbar class="bg-grey-4">
|
||||
<q-toolbar-title>{{ name }}</q-toolbar-title>
|
||||
<q-space></q-space>
|
||||
<slot name="toolbar"></slot>
|
||||
<q-btn flat round dense icon="close" @click="CloseDialogue('Cancel')" />
|
||||
</q-toolbar>
|
||||
<q-card-section>
|
||||
<div class="text-h6">{{ name }}</div>
|
||||
<!-- <div class="text-h6">{{ name }}</div> -->
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="q-pt-none" :style="{...(height? {minHeight:height}:{}) }">
|
||||
<slot></slot>
|
||||
</q-card-section>
|
||||
|
||||
@@ -26,7 +26,11 @@
|
||||
</q-toolbar>
|
||||
<q-separator />
|
||||
<q-card-section>
|
||||
<div class="text-h7">{{ node.title }}</div>
|
||||
<div class="row">
|
||||
<span class="text-h7">{{ node.title }}</span>
|
||||
<q-space></q-space>
|
||||
<q-chip color="info" text-color="white" size="0.70rem" v-if="varName(node)" clickable>{{ varName(node) }}</q-chip>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<template v-if="hasBranch">
|
||||
<q-separator />
|
||||
@@ -134,7 +138,14 @@ export default defineComponent({
|
||||
*/
|
||||
const onDeleteAllNode=()=>{
|
||||
context.emit('deleteAllNextNodes', props.actionNode);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 変数名取得
|
||||
*/
|
||||
const varName =(node:IActionNode)=>{
|
||||
const prop = node.actionProps.find((prop) => prop.props.name === "verName");
|
||||
return prop?.props.modelValue;
|
||||
};
|
||||
return {
|
||||
node: props.actionNode,
|
||||
isRoot: props.actionNode.isRoot,
|
||||
@@ -145,7 +156,8 @@ export default defineComponent({
|
||||
onNodeClick,
|
||||
onEditNode,
|
||||
onDeleteNode,
|
||||
onDeleteAllNode
|
||||
onDeleteAllNode,
|
||||
varName
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</q-card>
|
||||
</template>
|
||||
</q-field>
|
||||
<condition-editor v-model:show="show" v-model:conditionTree="tree"></condition-editor>
|
||||
<condition-editor v-model:show="show" v-model:conditionTree="tree" @closed="onClosed"></condition-editor>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -54,7 +54,7 @@
|
||||
if(props.modelValue && props.modelValue!==''){
|
||||
tree.fromJson(props.modelValue);
|
||||
}else{
|
||||
const newNode = new ConditionNode(LogicalOperator.AND,{},Operator.Equal,'',tree.root);
|
||||
const newNode = new ConditionNode({},Operator.Equal,'',tree.root);
|
||||
tree.addNode(tree.root,newNode);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
show.value = true;
|
||||
};
|
||||
|
||||
const closeDg = (val:string) => {
|
||||
const onClosed = (val:string) => {
|
||||
if (val == 'OK') {
|
||||
const conditionJson = tree.toJson();
|
||||
isSetted.value=true;
|
||||
@@ -86,7 +86,7 @@
|
||||
isSetted,
|
||||
show,
|
||||
showDg,
|
||||
closeDg,
|
||||
onClosed,
|
||||
tree,
|
||||
conditionString
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
>
|
||||
<q-card class="column full-height" style="width: 300px">
|
||||
<q-card-section>
|
||||
<div class="text-h6">プロパティ</div>
|
||||
<div class="text-h6">{{ actionNode.subTitle }}:設定</div>
|
||||
</q-card-section>
|
||||
<q-card-section class="col q-pt-none">
|
||||
<property-list :node-props="actionProps" v-if="showPanel" ></property-list>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<q-btn @click="showCondition()" class="q-mt-md" color="primary" icon="mdi-plus">条件エディタ表示</q-btn>
|
||||
</div>
|
||||
<condition-editor v-model:show="show" v-model:conditionTree="tree"></condition-editor>
|
||||
<p>{{conditionString}}</p>
|
||||
<q-code>{{conditionString}}</q-code>
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
@@ -16,7 +16,7 @@ import { ConditionTree,GroupNode,ConditionNode,LogicalOperator,Operator } from '
|
||||
|
||||
const store = useFlowEditorStore();
|
||||
const tree = reactive(new ConditionTree());
|
||||
const newNode = new ConditionNode(LogicalOperator.AND,{},Operator.Equal,'',tree.root);
|
||||
const newNode = new ConditionNode({},Operator.Equal,'',tree.root);
|
||||
tree.addNode(tree.root,newNode);
|
||||
|
||||
const show =ref(false);
|
||||
|
||||
@@ -89,7 +89,7 @@ export class ConditionNode implements INode {
|
||||
return 'generic';
|
||||
}
|
||||
|
||||
constructor(logicOp: LogicalOperator, object: any, operator: Operator, value: any, parent: GroupNode) {
|
||||
constructor(object: any, operator: Operator, value: any, parent: GroupNode) {
|
||||
this.index=0;
|
||||
this.type = NodeType.Condition;
|
||||
this.object = object;
|
||||
@@ -100,7 +100,6 @@ export class ConditionNode implements INode {
|
||||
|
||||
static fromJSON(json: any, parent: GroupNode): ConditionNode {
|
||||
const node= new ConditionNode(
|
||||
json.logicalOperator,
|
||||
json.object,
|
||||
json.operator,
|
||||
json.value,
|
||||
@@ -144,20 +143,38 @@ export class ConditionTree {
|
||||
return this.findChildren(this.root,index);
|
||||
}
|
||||
|
||||
findChildren(parent:GroupNode,index:number):INode|undefined{
|
||||
if(parent.index===index){
|
||||
findChildren(parent: GroupNode, index: number): INode | undefined {
|
||||
if (parent.index === index) {
|
||||
return parent;
|
||||
}
|
||||
return parent.children.findLast((node:INode)=>{
|
||||
if(node.index===index){
|
||||
for (const node of parent.children) {
|
||||
if (node.index === index) {
|
||||
return node;
|
||||
}
|
||||
if(node.type!==NodeType.Condition){
|
||||
return this.findChildren(node as GroupNode,index);
|
||||
if (node.type !== NodeType.Condition) {
|
||||
const foundNode = this.findChildren(node as GroupNode, index);
|
||||
if (foundNode) {
|
||||
return foundNode;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getMaxIndex(node:INode):number{
|
||||
let maxIndex:number=node.index;
|
||||
if(node.type!==NodeType.Condition){
|
||||
const groupNode = node as GroupNode;
|
||||
groupNode.children.forEach((child)=>{
|
||||
const childMax = this.getMaxIndex(child);
|
||||
if(childMax>maxIndex){
|
||||
maxIndex=childMax;
|
||||
}
|
||||
});
|
||||
}
|
||||
return maxIndex;
|
||||
}
|
||||
|
||||
//条件式を表示する
|
||||
buildConditionString(node:INode){
|
||||
if (node.type !== NodeType.Condition) {
|
||||
@@ -176,9 +193,9 @@ export class ConditionTree {
|
||||
return conditionString;
|
||||
} else {
|
||||
const condNode=node as ConditionNode;
|
||||
if (condNode.object && condNode.operator && condNode.value!==null) {
|
||||
if (condNode.object && condNode.operator ) {
|
||||
let value=condNode.value;
|
||||
if(typeof value ==='object' && ('label' in condNode.value)){
|
||||
if(value && typeof value ==='object' && ('label' in value)){
|
||||
value =condNode.value.label;
|
||||
}
|
||||
return `${condNode.object.name} ${condNode.operator} '${value}'`;
|
||||
@@ -230,11 +247,80 @@ export class ConditionTree {
|
||||
return groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件ノードをグループ化
|
||||
* @param nodes 結合ノードを選択する
|
||||
* @param logicOp
|
||||
* @returns
|
||||
*/
|
||||
createGroupNode(firstNode:INode,nodes: INode[], logicOp: LogicalOperator): GroupNode | null {
|
||||
if (nodes.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 最初のノードの親ノードを取得
|
||||
const parent = firstNode.parent as GroupNode;
|
||||
if (!parent) {
|
||||
throw new Error('ルートノードをグループ化できません');
|
||||
}
|
||||
|
||||
// 親ノードを取得
|
||||
const filteredNodes = nodes.filter(node => node.parent === parent);
|
||||
|
||||
// 新しいグループノードを作成
|
||||
const newGroup = new GroupNode(logicOp, parent);
|
||||
this.maxIndex++;
|
||||
newGroup.index = this.maxIndex;
|
||||
|
||||
// 新しいグループノードの挿入位置を取得
|
||||
let firstNodeIndex = parent.children.length;
|
||||
if (filteredNodes.length > 0) {
|
||||
firstNodeIndex = parent.children.indexOf(filteredNodes[0]);
|
||||
}
|
||||
|
||||
filteredNodes.forEach(node => {
|
||||
// 元の親ノードから削除する
|
||||
const nodeIndex = parent.children.indexOf(node);
|
||||
parent.children.splice(nodeIndex, 1);
|
||||
|
||||
// 新しいグループに追加
|
||||
node.parent = newGroup;
|
||||
newGroup.children.push(node);
|
||||
});
|
||||
|
||||
// 新しいGroupNodeを挿入する
|
||||
parent.children.splice(firstNodeIndex, 0, newGroup);
|
||||
return newGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* GroupNodeを解散する
|
||||
* @param groupNode 対象グループノード
|
||||
*/
|
||||
dissolveGroupNode(groupNode: GroupNode): void {
|
||||
if (groupNode.parent === null || groupNode.type !== NodeType.LogicGroup) {
|
||||
throw new Error('ルートノードと非グループノードを解散することができません');
|
||||
}
|
||||
|
||||
// 親ノードを取得
|
||||
const parent = groupNode.parent as GroupNode;
|
||||
const groupIndex = parent.children.indexOf(groupNode);
|
||||
|
||||
// 子ノードをリセットする
|
||||
groupNode.children.forEach(child => {
|
||||
child.parent = parent;
|
||||
parent.children.splice(groupIndex, 0, child);
|
||||
});
|
||||
|
||||
//グループノードを削除する
|
||||
parent.children.splice(groupIndex + groupNode.children.length, 1);
|
||||
}
|
||||
|
||||
// Jsonから復元
|
||||
fromJson(jsonString: string): INode {
|
||||
const json = JSON.parse(jsonString);
|
||||
this.root = GroupNode.fromJSON(json) as GroupNode;
|
||||
this.maxIndex=this.getMaxIndex(this.root);
|
||||
return this.root;
|
||||
}
|
||||
|
||||
@@ -246,4 +332,5 @@ export class ConditionTree {
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
import { actionAddins } from ".";
|
||||
import { IField, IAction,IActionResult, IActionNode, IActionProperty } from "../types/ActionTypes";
|
||||
import { IField, IAction,IActionResult, IActionNode, IActionProperty, IContext } from "../types/ActionTypes";
|
||||
import { Formatter } from "../util/format";
|
||||
|
||||
declare global {
|
||||
@@ -14,7 +14,7 @@ interface IAutoNumberingProps{
|
||||
format:string;
|
||||
prefix:string;
|
||||
suffix:string;
|
||||
|
||||
verName:string;
|
||||
}
|
||||
|
||||
export class AutoNumbering implements IAction{
|
||||
@@ -29,13 +29,14 @@ export class AutoNumbering implements IAction{
|
||||
field:{code:''},
|
||||
format:'',
|
||||
prefix:'',
|
||||
suffix:''
|
||||
suffix:'',
|
||||
verName:''
|
||||
}
|
||||
globalThis.window.$format=this.format;
|
||||
this.register();
|
||||
}
|
||||
|
||||
async process(actionNode:IActionNode,event:any):Promise<IActionResult> {
|
||||
async process(actionNode:IActionNode,event:any,context:IContext):Promise<IActionResult> {
|
||||
let result={
|
||||
canNext:false,
|
||||
result:false
|
||||
@@ -49,6 +50,10 @@ export class AutoNumbering implements IAction{
|
||||
const record = event.record;
|
||||
const docNum = await this.createNumber(this.props);
|
||||
record[this.props.field.code].value=docNum;
|
||||
//変数設定
|
||||
if(this.props.verName){
|
||||
context.variables[this.props.verName]=docNum;
|
||||
}
|
||||
result= {
|
||||
canNext:true,
|
||||
result:true
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
|
||||
import { actionAddins } from ".";
|
||||
import { IAction,IActionResult, IActionNode, IActionProperty, IField } from "../types/ActionTypes";
|
||||
import { IAction,IActionResult, IActionNode, IActionProperty, IField, IContext } from "../types/ActionTypes";
|
||||
import { ConditionTree } from '../types/Conditions';
|
||||
/**
|
||||
* アクションの属性定義
|
||||
*/
|
||||
interface IShownProps{
|
||||
field:IField;
|
||||
show:string;
|
||||
condition:string;
|
||||
}
|
||||
/**
|
||||
* 表示/非表示アクション
|
||||
@@ -18,11 +20,12 @@ export class FieldShownAction implements IAction{
|
||||
constructor(){
|
||||
this.name="表示/非表示";
|
||||
this.actionProps=[];
|
||||
this.register();
|
||||
this.props={
|
||||
this.props={
|
||||
field:{code:''},
|
||||
show:''
|
||||
show:'',
|
||||
condition:''
|
||||
}
|
||||
//アクションを登録する
|
||||
this.register();
|
||||
}
|
||||
/**
|
||||
@@ -31,21 +34,26 @@ export class FieldShownAction 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
|
||||
};
|
||||
try{
|
||||
//属性設定を取得する
|
||||
this.actionProps=actionNode.actionProps;
|
||||
if (!('field' in actionNode.ActionValue) && !('show' in actionNode.ActionValue)) {
|
||||
return result
|
||||
}
|
||||
this.props = actionNode.ActionValue as IShownProps;
|
||||
if(this.props.show==='表示'){
|
||||
kintone.app.record.setFieldShown(this.props.field.code,true);
|
||||
}else if (this.props.show==='非表示'){
|
||||
kintone.app.record.setFieldShown(this.props.field.code,false);
|
||||
//条件式の計算結果を取得
|
||||
const conditionResult = this.getConditionResult(context);
|
||||
if(conditionResult){
|
||||
if(this.props.show==='表示'){
|
||||
kintone.app.record.setFieldShown(this.props.field.code,true);
|
||||
}else if (this.props.show==='非表示'){
|
||||
kintone.app.record.setFieldShown(this.props.field.code,false);
|
||||
}
|
||||
}
|
||||
result= {
|
||||
canNext:true,
|
||||
@@ -60,6 +68,37 @@ export class FieldShownAction implements IAction{
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @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;
|
||||
|
||||
@@ -61,13 +61,30 @@ export interface IActionResult{
|
||||
result?:any;
|
||||
}
|
||||
|
||||
/**
|
||||
* コンテキスト
|
||||
* レコードとフローの変数を持つ
|
||||
*/
|
||||
export interface IContext{
|
||||
record:any,
|
||||
variables:any
|
||||
}
|
||||
|
||||
/**
|
||||
* アクションのインターフェース
|
||||
*/
|
||||
export interface IAction{
|
||||
//アクションの名前(ユーニック名が必要)
|
||||
name:string;
|
||||
//属性設定情報
|
||||
actionProps: Array<IActionProperty>;
|
||||
process(prop:IActionNode,event:any):Promise<IActionResult>;
|
||||
//アクションのプロセス実行関数
|
||||
process(prop:IActionNode,event:any,context:IContext):Promise<IActionResult>;
|
||||
//アクションの登録関数
|
||||
register():void;
|
||||
}
|
||||
|
||||
|
||||
export interface IField{
|
||||
name?:string;
|
||||
code:string;
|
||||
|
||||
473
plugin/kintone-addins/src/types/Conditions.ts
Normal file
473
plugin/kintone-addins/src/types/Conditions.ts
Normal file
@@ -0,0 +1,473 @@
|
||||
import { IContext } from "./ActionTypes";
|
||||
|
||||
//ノード種別
|
||||
export enum NodeType{
|
||||
Root = 'root',
|
||||
LogicGroup ='logicgroup',
|
||||
Condition ='condition'
|
||||
}
|
||||
|
||||
//ロジックオペレーター
|
||||
export enum LogicalOperator{
|
||||
AND = 'AND',
|
||||
OR = 'OR'
|
||||
}
|
||||
|
||||
//条件オペレーター
|
||||
export enum Operator{
|
||||
Equal = '=',
|
||||
NotEqual='!=',
|
||||
Greater = '>',
|
||||
GreaterOrEqual = '>=',
|
||||
Less = '<',
|
||||
LessOrEqual = '<=',
|
||||
Contains = 'contains',
|
||||
NotContains = 'not contains',
|
||||
StartWith = 'start With',
|
||||
EndWith = 'end with',
|
||||
NotStartWith = 'not start with',
|
||||
NotEndWith = 'not end with'
|
||||
}
|
||||
|
||||
|
||||
// INode
|
||||
export interface INode {
|
||||
index:number;
|
||||
type: NodeType;
|
||||
header:string;
|
||||
parent: INode | null;
|
||||
logicalOperator:LogicalOperator
|
||||
}
|
||||
|
||||
// ロジックノード
|
||||
export class GroupNode implements INode {
|
||||
index:number;
|
||||
type: NodeType;
|
||||
children: INode[];
|
||||
parent: INode | null;
|
||||
logicalOperator: LogicalOperator;
|
||||
get label():string{
|
||||
return this.logicalOperator;
|
||||
}
|
||||
get header():string{
|
||||
return this.type===NodeType.Root?'root':'generic';
|
||||
}
|
||||
get expanded():boolean{
|
||||
return this.children.length>0;
|
||||
}
|
||||
constructor(logicOp:LogicalOperator, parent: INode | null) {
|
||||
this.index=0;
|
||||
this.type = parent==null?NodeType.Root: NodeType.LogicGroup;
|
||||
this.logicalOperator = logicOp;
|
||||
this.parent=parent;
|
||||
this.children=[];
|
||||
}
|
||||
|
||||
static fromJSON(json: any, parent: INode | null = null): GroupNode {
|
||||
const node = new GroupNode(json.logicalOperator, parent);
|
||||
node.index=json.index;
|
||||
node.children = json.children.map((childJson: any) => {
|
||||
return childJson.type === NodeType.LogicGroup
|
||||
? GroupNode.fromJSON(childJson, node)
|
||||
: ConditionNode.fromJSON(childJson, node);
|
||||
});
|
||||
return node;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 条件式ノード
|
||||
export class ConditionNode implements INode {
|
||||
index: number;
|
||||
type: NodeType;
|
||||
parent:INode;
|
||||
get logicalOperator(): LogicalOperator{
|
||||
return this.parent.logicalOperator;
|
||||
};
|
||||
object: any; // 比較元
|
||||
operator: Operator; // 比較子
|
||||
value: any;
|
||||
get header():string{
|
||||
return 'generic';
|
||||
}
|
||||
|
||||
constructor(object: any, operator: Operator, value: any, parent: GroupNode) {
|
||||
this.index=0;
|
||||
this.type = NodeType.Condition;
|
||||
this.object = object;
|
||||
this.operator = operator;
|
||||
this.value = value;
|
||||
this.parent=parent;
|
||||
}
|
||||
|
||||
static fromJSON(json: any, parent: GroupNode): ConditionNode {
|
||||
const node= new ConditionNode(
|
||||
json.object,
|
||||
json.operator,
|
||||
json.value,
|
||||
parent
|
||||
);
|
||||
node.index=json.index;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件式の管理クラス
|
||||
*/
|
||||
export class ConditionTree {
|
||||
root: GroupNode;
|
||||
maxIndex:number;
|
||||
|
||||
constructor() {
|
||||
this.maxIndex=0;
|
||||
this.root = new GroupNode(LogicalOperator.AND, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* ノード追加
|
||||
* @param parent
|
||||
* @param node
|
||||
*/
|
||||
addNode(parent: GroupNode, node: INode): void {
|
||||
this.maxIndex++;
|
||||
node.index=this.maxIndex;
|
||||
parent.children.push(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* ノード削除
|
||||
* @param node
|
||||
*/
|
||||
removeNode(node: INode): void {
|
||||
if (node.parent === null) {
|
||||
throw new Error('ルートノード削除できません');
|
||||
} else {
|
||||
const parent = node.parent as GroupNode;
|
||||
const index = parent.children.indexOf(node);
|
||||
if (index > -1) {
|
||||
parent.children.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件ツリーからインディクス値で条件ノードを検索する
|
||||
* @param index
|
||||
* @returns
|
||||
*/
|
||||
findByIndex(index:number):INode|undefined{
|
||||
return this.findChildren(this.root,index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定のノードグループからインディクス値で条件ノードを検索する
|
||||
* @param parent
|
||||
* @param index
|
||||
* @returns
|
||||
*/
|
||||
findChildren(parent: GroupNode, index: number): INode | undefined {
|
||||
if (parent.index === index) {
|
||||
return parent;
|
||||
}
|
||||
for (const node of parent.children) {
|
||||
if (node.index === index) {
|
||||
return node;
|
||||
}
|
||||
if (node.type !== NodeType.Condition) {
|
||||
const foundNode = this.findChildren(node as GroupNode, index);
|
||||
if (foundNode) {
|
||||
return foundNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param node 最大のインディクス値を取得する
|
||||
* @returns
|
||||
*/
|
||||
getMaxIndex(node:INode):number{
|
||||
let maxIndex:number=node.index;
|
||||
if(node.type!==NodeType.Condition){
|
||||
const groupNode = node as GroupNode;
|
||||
groupNode.children.forEach((child)=>{
|
||||
const childMax = this.getMaxIndex(child);
|
||||
if(childMax>maxIndex){
|
||||
maxIndex=childMax;
|
||||
}
|
||||
});
|
||||
}
|
||||
return maxIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件式を表示する
|
||||
* @param node 条件ノード
|
||||
* @returns
|
||||
*/
|
||||
buildConditionString(node:INode){
|
||||
if (node.type !== NodeType.Condition) {
|
||||
let conditionString = '(';
|
||||
const groupNode = node as GroupNode;
|
||||
for (let i = 0; i < groupNode.children.length; i++) {
|
||||
const childConditionString = this.buildConditionString(groupNode.children[i]);
|
||||
if (childConditionString !== '') {
|
||||
conditionString += childConditionString;
|
||||
if (i < groupNode.children.length - 1) {
|
||||
conditionString += ` ${groupNode.logicalOperator} `;
|
||||
}
|
||||
}
|
||||
}
|
||||
conditionString += ')';
|
||||
return conditionString;
|
||||
} else {
|
||||
const condNode=node as ConditionNode;
|
||||
if (condNode.object && condNode.operator ) {
|
||||
let value=condNode.value;
|
||||
if(value && typeof value ==='object' && ('label' in value)){
|
||||
value =condNode.value.label;
|
||||
}
|
||||
return `${condNode.object.name} ${condNode.operator} '${value}'`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* すべて条件式を取得する
|
||||
*/
|
||||
getConditions(parent:GroupNode):ConditionNode[]{
|
||||
const condiNodes:ConditionNode[]=[];
|
||||
parent.children.forEach((node)=>{
|
||||
if(node.type===NodeType.Condition){
|
||||
condiNodes.push(node as ConditionNode);
|
||||
}else{
|
||||
condiNodes.push(...this.getConditions(node as GroupNode));
|
||||
}
|
||||
});
|
||||
return condiNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param parent すべて条件グループを取得する
|
||||
* @returns
|
||||
*/
|
||||
getGroups(parent:GroupNode):number[]{
|
||||
const groups:number[]=[];
|
||||
groups.push(parent.index);
|
||||
parent.children.forEach((node)=>{
|
||||
if(node.type!==NodeType.Condition){
|
||||
groups.push(...this.getGroups(node as GroupNode));
|
||||
}
|
||||
});
|
||||
return groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Jsonから復元
|
||||
* @param jsonString
|
||||
* @returns
|
||||
*/
|
||||
fromJson(jsonString: string): INode {
|
||||
const json = JSON.parse(jsonString);
|
||||
this.root = GroupNode.fromJSON(json) as GroupNode;
|
||||
this.maxIndex=this.getMaxIndex(this.root);
|
||||
return this.root;
|
||||
}
|
||||
/**
|
||||
* JSON文字列に変換する
|
||||
* @returns
|
||||
*/
|
||||
toJson():string{
|
||||
return JSON.stringify(this.root, (key, value) => {
|
||||
if (key === 'parent') {
|
||||
return value ? value.type : null;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件式を計算する
|
||||
* @param node
|
||||
* @param context
|
||||
* @returns
|
||||
*/
|
||||
evaluate(node: INode, context: any): boolean {
|
||||
if (node.type === NodeType.Condition) {
|
||||
return this.evaluateCondition(node as ConditionNode, context);
|
||||
} else if (node.type === NodeType.LogicGroup || node.type === NodeType.Root) {
|
||||
const groupNode = node as GroupNode;
|
||||
const results = groupNode.children.map(child => this.evaluate(child, context));
|
||||
|
||||
if (groupNode.logicalOperator === LogicalOperator.AND) {
|
||||
return results.every(result => result);
|
||||
} else if (groupNode.logicalOperator === LogicalOperator.OR) {
|
||||
return results.some(result => result);
|
||||
} else {
|
||||
throw new Error('Unsupported logical operator');
|
||||
}
|
||||
} else {
|
||||
throw new Error('Unsupported node type');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition objectの値を取得する
|
||||
* @param object
|
||||
* @param context
|
||||
* @returns
|
||||
*/
|
||||
getObjectValue(object:any,context:IContext){
|
||||
if(!object || typeof object!=="object" || !("objectType" in object)){
|
||||
return object;
|
||||
}
|
||||
if(object.objectType==='field'){
|
||||
return context.record[object.code].value;
|
||||
}else if(object.objectType==='var'){
|
||||
return context.variables[object.varName].value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 比較オブジェクトの値を取得
|
||||
* @param object
|
||||
* @returns
|
||||
*/
|
||||
getConditionValue(object:any){
|
||||
if(!object || typeof object!=="object"){
|
||||
return object;
|
||||
}
|
||||
if("label" in object){
|
||||
return object.label;
|
||||
}
|
||||
if("value" in object){
|
||||
return object.value;
|
||||
}
|
||||
if("name" in object){
|
||||
return object.name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件式を計算する
|
||||
* @param condition
|
||||
* @param context
|
||||
* @returns
|
||||
*/
|
||||
evaluateCondition(condition: ConditionNode, context: IContext): boolean {
|
||||
const { object, operator, value } = condition;
|
||||
const targetValue = this.getObjectValue(object,context);
|
||||
const conditionValue = this.getConditionValue(value);
|
||||
switch (operator) {
|
||||
case Operator.Equal:
|
||||
case Operator.NotEqual:
|
||||
case Operator.Greater:
|
||||
case Operator.GreaterOrEqual:
|
||||
case Operator.Less:
|
||||
case Operator.LessOrEqual:
|
||||
return this.compare(operator,targetValue, conditionValue);
|
||||
case Operator.Contains:
|
||||
return this.contains(targetValue,conditionValue);
|
||||
case Operator.NotContains:
|
||||
return !this.contains(targetValue,conditionValue);
|
||||
case Operator.StartWith:
|
||||
return this.startWith(targetValue,conditionValue);
|
||||
case Operator.NotStartWith:
|
||||
return !this.startWith(targetValue,conditionValue);
|
||||
case Operator.EndWith:
|
||||
return this.endsWith(targetValue,conditionValue);
|
||||
case Operator.NotEndWith:
|
||||
return this.endsWith(targetValue,conditionValue);
|
||||
default:
|
||||
throw new Error('Unsupported operator');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 比較を実行する
|
||||
* @param operator
|
||||
* @param targetValue
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
compare(operator: Operator, targetValue: any, value: any): boolean {
|
||||
// targetValue は日期时,value も日期に変換して比較する
|
||||
if (targetValue instanceof Date) {
|
||||
const dateValue = new Date(value);
|
||||
if (!isNaN(dateValue.getTime())) {
|
||||
value = dateValue;
|
||||
}
|
||||
}
|
||||
//targetValueは数値時,value を数値に変換する
|
||||
else if (typeof targetValue === 'number') {
|
||||
const numberValue = Number(value);
|
||||
if (!isNaN(numberValue)) {
|
||||
value = numberValue;
|
||||
}
|
||||
}
|
||||
else if (typeof targetValue === 'string') {
|
||||
value = String(value);
|
||||
}
|
||||
|
||||
switch (operator) {
|
||||
case Operator.Equal:
|
||||
return targetValue === value;
|
||||
case Operator.NotEqual:
|
||||
return targetValue !== value;
|
||||
case Operator.Greater:
|
||||
return targetValue > value;
|
||||
case Operator.GreaterOrEqual:
|
||||
return targetValue >= value;
|
||||
case Operator.Less:
|
||||
return targetValue < value;
|
||||
case Operator.LessOrEqual:
|
||||
return targetValue <= value;
|
||||
default:
|
||||
throw new Error('Unsupported operator for comparison');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 含む計算
|
||||
* @param targetValue
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
contains(targetValue: any, value: any): boolean {
|
||||
if (typeof targetValue === 'string' && typeof value === 'string') {
|
||||
return targetValue.includes(value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* StartWith計算
|
||||
* @param targetValue
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
startWith(targetValue: any, value: any): boolean {
|
||||
if (typeof targetValue === 'string' && typeof value === 'string') {
|
||||
return targetValue.startsWith(value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* EndsWith計算
|
||||
* @param targetValue
|
||||
* @param value
|
||||
* @returns
|
||||
*/
|
||||
endsWith(targetValue: any, value: any): boolean {
|
||||
if (typeof targetValue === 'string' && typeof value === 'string') {
|
||||
return targetValue.endsWith(value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -3,16 +3,21 @@ import { actionAddins } from "../actions";
|
||||
import '../actions/must-input';
|
||||
import '../actions/auto-numbering';
|
||||
import '../actions/field-shown';
|
||||
import { ActionFlow,IActionFlow, IActionResult } from "./ActionTypes";
|
||||
import { ActionFlow,IActionFlow, IActionResult,IContext } from "./ActionTypes";
|
||||
|
||||
export class ActionProcess{
|
||||
eventId:string;
|
||||
flow:IActionFlow;
|
||||
event:any;
|
||||
context:IContext;
|
||||
constructor(eventId:string,flow:ActionFlow,event:any){
|
||||
this.eventId=eventId;
|
||||
this.flow=flow;
|
||||
this.event=event;
|
||||
this.context={
|
||||
record:this.event.record,
|
||||
variables:{}
|
||||
};
|
||||
}
|
||||
async exec(){
|
||||
const root = this.flow.getRoot();
|
||||
@@ -28,7 +33,7 @@ export class ActionProcess{
|
||||
while(nextAction!==undefined && result.canNext){
|
||||
const action = actionAddins[nextAction.name];
|
||||
if(action!==undefined){
|
||||
result = await action.process(nextAction,this.event)
|
||||
result = await action.process(nextAction,this.event,this.context);
|
||||
}
|
||||
const nextInput = nextAction.outputPoints!==undefined?result.result||'':'';
|
||||
id=nextAction.nextNodeIds.get(nextInput);
|
||||
|
||||
11
sample.json
11
sample.json
@@ -12,7 +12,7 @@
|
||||
"component": "SelectBox",
|
||||
"props": {
|
||||
"displayName": "表示/非表示",
|
||||
"options":[
|
||||
"options": [
|
||||
"表示",
|
||||
"非表示"
|
||||
],
|
||||
@@ -20,5 +20,14 @@
|
||||
"name": "show",
|
||||
"placeholder": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "ConditionInput",
|
||||
"props": {
|
||||
"displayName": "条件",
|
||||
"modelValue": "",
|
||||
"name": "condition",
|
||||
"placeholder": "対象項目を選択してください"
|
||||
}
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user