Compare commits

..

7 Commits

Author SHA1 Message Date
Mouriya
c3b560dbc9 条件付きコンポーネントは'source'でappidを受け取ることができる。 2024-05-25 04:15:09 +09:00
53aadfcaaa feat:データ集計処理作成 2024-05-24 09:20:19 +09:00
Mouriya
7fb3d08ccb 細部の問題の修正 2024-05-20 03:38:27 +09:00
Mouriya
cf4209333d データ処理書き込み完了 2024-05-17 23:32:14 +09:00
Mouriya
61ac281134 verNameのラッピング・オブジェクト 2024-05-17 14:41:15 +09:00
Mouriya
64d2cadd82 2つのデータ計算コンポーネントを追加する 2024-05-13 06:56:44 +09:00
Mouriya
371e2ee073 add vueuse dependencies 2024-05-13 06:56:03 +09:00
24 changed files with 819 additions and 735 deletions

View File

@@ -2,7 +2,6 @@
<html lang="ja-jp"> <html lang="ja-jp">
<head> <head>
<title><%= productName %></title> <title><%= productName %></title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="description" content="<%= productDescription %>"> <meta name="description" content="<%= productDescription %>">
<meta name="format-detection" content="telephone=no"> <meta name="format-detection" content="telephone=no">

View File

@@ -17,8 +17,9 @@
}, },
"dependencies": { "dependencies": {
"@quasar/extras": "^1.16.4", "@quasar/extras": "^1.16.4",
"@vueuse/core": "^10.9.0",
"axios": "^1.4.0", "axios": "^1.4.0",
"pinia": "^2.1.6", "pinia": "^2.1.7",
"quasar": "^2.6.0", "quasar": "^2.6.0",
"uuid": "^9.0.0", "uuid": "^9.0.0",
"vue": "^3.0.0", "vue": "^3.0.0",

View File

@@ -4,6 +4,7 @@ import { Router } from 'vue-router';
import { App } from 'vue'; import { App } from 'vue';
export default boot(({ app, router }: { app: App<Element>; router: Router }) => { export default boot(({ app, router }: { app: App<Element>; router: Router }) => {
document.documentElement.lang="ja-JP";
app.config.errorHandler = (err: any, instance: any, info: string) => { app.config.errorHandler = (err: any, instance: any, info: string) => {
if (err.response && err.response.status === 401) { if (err.response && err.response.status === 401) {
// 認証エラーの場合再ログインする // 認証エラーの場合再ログインする

View File

@@ -1,5 +1,5 @@
<template> <template>
<show-dialog v-model:visible="showflg" name="条件エディタ" @close="closeDg" min-width="60vw" min-height="60vh"> <show-dialog v-model:visible="showflg" name="条件エディタ" @close="closeDg" min-width="50vw" min-height="60vh">
<template v-slot:toolbar> <template v-slot:toolbar>
<q-btn flat round dense icon="more_vert" > <q-btn flat round dense icon="more_vert" >
<q-menu auto-close anchor="bottom start"> <q-menu auto-close anchor="bottom start">

View File

@@ -6,14 +6,14 @@
{{ selectedObject.name }} {{ selectedObject.name }}
</q-chip> </q-chip>
<q-chip color="info" text-color="white" v-if="isSelected && selectedObject.objectType==='variable'" :dense="true" class="selected-obj"> <q-chip color="info" text-color="white" v-if="isSelected && selectedObject.objectType==='variable'" :dense="true" class="selected-obj">
{{ selectedObject.name }} {{ selectedObject.name.name }}
</q-chip> </q-chip>
</template> </template>
<template v-slot:append> <template v-slot:append>
<q-icon name="search" class="cursor-pointer" @click="showDg"/> <q-icon name="search" class="cursor-pointer" @click="showDg"/>
</template> </template>
</q-field> </q-field>
<show-dialog v-model:visible="show" name="条件設定項目一覧" @close="closeDg" width="600px"> <show-dialog v-model:visible="show" name="設定項目一覧" @close="closeDg" min-width="400px">
<template v-slot:toolbar> <template v-slot:toolbar>
<q-input dense debounce="200" v-model="filter" placeholder="検索" clearable> <q-input dense debounce="200" v-model="filter" placeholder="検索" clearable>
<template v-slot:before> <template v-slot:before>
@@ -88,9 +88,9 @@
.condition-object{ .condition-object{
min-width: 200px; min-width: 200px;
max-height: 40px; max-height: 40px;
padding: 2px; margin: 0 2px;
} }
.selected-obj{ .selected-obj{
margin: 0px; margin: 0 2px;
} }
</style> </style>

View File

@@ -66,7 +66,7 @@
</div> </div>
<!-- condition --> <!-- condition -->
<div @click.stop @keypress.stop v-else > <div @click.stop @keypress.stop v-else >
<div class="row no-wrap items-center"> <div class="row no-wrap items-center q-my-xs">
<ConditionObject v-bind="prop.node" v-model="prop.node.object" class="col-4"></ConditionObject> <ConditionObject v-bind="prop.node" v-model="prop.node.object" class="col-4"></ConditionObject>
<q-select v-model="prop.node.operator" :options="operators" class="operator" :outlined="true" :dense="true"></q-select> <q-select v-model="prop.node.operator" :options="operators" class="operator" :outlined="true" :dense="true"></q-select>
<q-input v-if="!prop.node.object || !('options' in prop.node.object)" <q-input v-if="!prop.node.object || !('options' in prop.node.object)"
@@ -257,12 +257,12 @@ export default defineComponent( {
.condition-value{ .condition-value{
min-width: 200px; min-width: 200px;
max-height: 40px; max-height: 40px;
padding: 2px; margin: 0 2px;
} }
.operator{ .operator{
min-width: 150px; min-width: 150px;
max-height: 40px; max-height: 40px;
padding: 2px; margin: 0 2px;
text-align: center; text-align: center;
font-size: 12pt; font-size: 12pt;
} }

View File

@@ -19,7 +19,7 @@
<q-tab-panels v-model="tab" animated> <q-tab-panels v-model="tab" animated>
<q-tab-panel name="fields"> <q-tab-panel name="fields">
<field-list v-model="selected" type="single" :filter="filter" :appId="appId"></field-list> <field-list v-model="selected" type="single" :filter="filter" :appId="sourceApp ? sourceApp :appId " :fields="sourceFields"></field-list>
</q-tab-panel> </q-tab-panel>
<q-tab-panel name="vars" > <q-tab-panel name="vars" >
@@ -30,7 +30,7 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { ref, onMounted, reactive } from 'vue' import { ref, onMounted, reactive, inject } from 'vue'
import FieldList from './FieldList.vue'; import FieldList from './FieldList.vue';
import VariableList from './VariableList.vue'; import VariableList from './VariableList.vue';
@@ -48,10 +48,14 @@ export default {
filter:String filter:String
}, },
setup(props) { setup(props) {
const selected = ref([]);
console.log(selected);
return { return {
sourceFields : inject('sourceFields'),
sourceApp : inject('sourceApp'),
tab: ref('fields'), tab: ref('fields'),
selected: ref([]) selected
} }
}, },

View File

@@ -1,19 +1,18 @@
<template> <template>
<div class="q-pa-md"> <div class="q-pa-md">
<q-table flat bordered :loading="!isLoaded" row-key="name" :selection="type" <q-table flat bordered :loading="!isLoaded" row-key="name" :selection="type" :selected="modelValue"
:selected="modelValue" @update:selected="$emit('update:modelValue', $event)" :filter="filter" :columns="columns" :rows="rows" />
@update:selected="$emit('update:modelValue', $event)"
:filter="filter"
:columns="columns" :rows="rows" />
</div> </div>
</template> </template>
<script> <script lang="ts">
import { ref, onMounted, reactive } from 'vue' import { useAsyncState } from '@vueuse/core';
import { api } from 'boot/axios'; import { api } from 'boot/axios';
import { computed } from 'vue';
export default { export default {
name: 'FieldList', name: 'FieldList',
props: { props: {
fields: Array,
name: String, name: String,
type: String, type: String,
appId: Number, appId: Number,
@@ -24,27 +23,28 @@ export default {
'update:modelValue' 'update:modelValue'
], ],
setup(props) { setup(props) {
const isLoaded = ref(false); // const rows = ref([]);
// const isLoaded = ref(false);
const columns = [ const columns = [
{ name: 'name', required: true, label: 'フィールド名', align: 'left', field: row => row.name, sortable: true }, { name: 'name', required: true, label: 'フィールド名', align: 'left', field: 'name', sortable: true },
{ name: 'code', label: 'フィールドコード', align: 'left', field: 'code', sortable: true }, { name: 'code', label: 'フィールドコード', align: 'left', field: 'code', sortable: true },
{ name: 'type', label: 'フィールドタイプ', align: 'left', field: 'type', sortable: true } { name: 'type', label: 'フィールドタイプ', align: 'left', field: 'type', sortable: true }
] ]
const rows = reactive([]);
onMounted(async () => { const { state : rows, isReady: isLoaded, isLoading } = useAsyncState((args) => {
const res = await api.get('api/v1/appfields', { if (props.fields) {
return props.fields.map(f => ({ name: f.label, objectType: 'field', ...f }));
} else {
return api.get('api/v1/appfields', {
params: { params: {
app: props.appId app: props.appId
} }
}).then(res => {
console.log(res);
return Object.values(res.data.properties).map(f => ({ name: f.label, objectType: 'field', ...f }));
}); });
let fields = res.data.properties; }
console.log(fields); }, [{ name: '', objectType: '', type: '', code: '', label: '' }])
Object.keys(fields).forEach((key) => {
const fld = fields[key];
rows.push({ name: fld.label, objectType: 'field', ...fld });
});
isLoaded.value = true;
});
return { return {
columns, columns,

View File

@@ -1,7 +1,7 @@
<template> <template>
<!-- <div class="q-pa-md q-gutter-sm" > --> <!-- <div class="q-pa-md q-gutter-sm" > -->
<q-dialog :model-value="visible" persistent bordered > <q-dialog :model-value="visible" persistent bordered >
<q-card :style="cardStyle" style=" min-width: 40vw; max-width: 80vw; max-height: 95vh;"> <q-card style="min-width: 40vw; max-width: 80vw; max-height: 95vh;" :style="cardStyle">
<q-toolbar class="bg-grey-4"> <q-toolbar class="bg-grey-4">
<q-toolbar-title>{{ name }}</q-toolbar-title> <q-toolbar-title>{{ name }}</q-toolbar-title>
<q-space></q-space> <q-space></q-space>

View File

@@ -1,14 +1,13 @@
<template> <template>
<div class="q-pa-md"> <div class="q-pa-md">
<q-table flat bordered row-key="name" :selection="type" <q-table flat bordered row-key="id" :selection="type" :selected="modelValue"
:selected="modelValue" @update:selected="$emit('update:modelValue', $event)" :columns="columns" :rows="rows" />
@update:selected="$emit('update:modelValue', $event)"
:columns="columns" :rows="rows" />
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { ref, reactive, PropType, compile } from 'vue'; import { PropType, reactive } from 'vue';
import {IActionNode,IActionVariable} from '../types/ActionTypes'; import { IActionVariable } from '../types/ActionTypes';
import { v4 as uuidv4 } from 'uuid';
export default { export default {
name: 'VariableList', name: 'VariableList',
@@ -26,13 +25,30 @@ export default {
'update:modelValue' 'update:modelValue'
], ],
setup(props) { setup(props) {
const variableName = (field) => {
const name = field.name;
return name.name;
}
const columns = [ const columns = [
{ name: 'actionName', label: 'アクション名', align: 'left', field: 'actionName', sortable: true }, { name: 'actionName', label: 'アクション名', align: 'left', field: 'actionName', sortable: true },
{ name: 'displayName', label: '変数表示名', align: 'left', field: 'displayName', sortable: true }, { name: 'displayName', label: '変数表示名', align: 'left', field: 'displayName', sortable: true },
{ name: 'name', label: '変数名', align: 'left',field: 'name',required: true, sortable: true } { name: 'name', label: '変数名', align: 'left', field: variableName, required: true, sortable: true }
]; ];
const rows= props.vars.map((v)=>{
return {objectType:'variable',...v}; const rows = props.vars.flatMap((v) => {
if (v.name.vars && v.name.vars.length > 0) {
return v.name.vars
.filter(o => o.vName && o.logicalOperator && o.field)
.map(o => ({
id: uuidv4(),
objectType: 'variable',
name: { name: `${v.name.name}.${o.vName}` },
actionName: v.name.actionName,
displayName: v.name.displayName
}));
} else {
return [{ objectType: 'variable', ...v }];
}
}); });
return { return {

View File

@@ -1,55 +1,48 @@
<template> <template>
<!-- <div class="q-pa-md q-gutter-sm"> --> <!-- <div class="q-pa-md q-gutter-sm"> -->
<q-tree :nodes="store.eventTree.screens" node-key="eventId" children-key="events" no-connectors <q-tree
v-model:expanded="store.expandedScreen" :dense="true" :ref="tree"> :nodes="store.eventTree.screens"
node-key="eventId"
children-key="events"
no-connectors
v-model:expanded="store.expandedScreen"
:dense="true"
:ref="tree"
>
<template v-slot:header-EVENT="prop"> <template v-slot:header-EVENT="prop">
<div :ref="prop.node.eventId" class="row col items-center no-wrap event-node"> <div class="row col items-start no-wrap event-node" @click="onSelected(prop.node)">
<q-icon v-if="prop.node.eventId" name="play_circle" :color="prop.node.hasFlow ? 'green' : 'grey'" size="16px" <q-icon v-if="prop.node.eventId"
class="q-mr-sm"> name="play_circle"
:color="prop.node.hasFlow?'green':'grey'"
size="16px" class="q-mr-sm">
</q-icon> </q-icon>
<div class="no-wrap" @click="onSelected(prop.node)" <div class="no-wrap" :class="selectedEvent && prop.node.eventId===selectedEvent.eventId?'selected-node':''">{{ prop.node.label }}</div>
:class="selectedEvent && prop.node.eventId === selectedEvent.eventId ? 'selected-node' : ''">{{
prop.node.label }}</div>
<q-space></q-space> <q-space></q-space>
<!-- <q-icon v-if="prop.node.hasFlow" name="delete" color="negative" size="16px" class="q-mr-sm"></q-icon> --> <!-- <q-icon v-if="prop.node.hasFlow" name="delete" color="negative" size="16px" class="q-mr-sm"></q-icon> -->
</div> </div>
</template> </template>
<template v-slot:header-CHANGE="prop" > <template v-slot:header-CHANGE="prop" >
<div class="row col items-center no-wrap event-node"> <div class="row col items-start no-wrap event-node" >
<div class="no-wrap">{{ prop.node.label }}</div> <div class="no-wrap">{{ prop.node.label }}</div>
<q-space></q-space> <q-space></q-space>
<q-icon name="add_circle" color="primary" size="16px" class="q-mr-sm" <q-icon name="add_circle" color="primary" size="16px" class="q-mr-sm" @click="addChangeEvent(prop.node)"></q-icon>
@click="addChangeEvent(prop.node)"></q-icon>
</div>
</template>
<template v-slot:header-DELETABLE="prop">
<div class="row col items-center event-node">
<div class="row col items-center" @click="onSelected(prop.node)">
<q-icon v-if="prop.node.eventId" name="play_circle" :color="prop.node.hasFlow ? 'green' : 'grey'" size="16px"
class="q-mr-sm">
</q-icon>
<div>{{ prop.node.label }}</div>
</div>
<div>
<q-btn class="q-mr-sm delete-btn" flat fab-mini icon="delete_forever" padding="none" color="negative"
@click="deleteEvent(prop.node)"></q-btn>
</div>
</div> </div>
</template> </template>
</q-tree> </q-tree>
<show-dialog v-model:visible="showDialog" name="フィールド選択" @close="closeDg"> <show-dialog v-model:visible="showDialog" name="フィールド選択" @close="closeDg" widht="400px">
<field-select ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></field-select> <field-select ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></field-select>
</show-dialog> </show-dialog>
</template> </template>
<script lang="ts"> <script lang="ts">
import { QTree } from 'quasar'; import { defineComponent, computed, ref } from 'vue';
import { ActionFlow, RootAction } from 'src/types/ActionTypes'; import { IKintoneEvent ,IKintoneEventGroup, IKintoneEventNode, kintoneEvent} from '../../types/KintoneEvents';
import { storeToRefs } from 'pinia';
import { useFlowEditorStore } from 'stores/flowEditor'; import { useFlowEditorStore } from 'stores/flowEditor';
import { defineComponent, ref } from 'vue'; import { ActionFlow, ActionNode, RootAction } from 'src/types/ActionTypes';
import { IKintoneEvent, IKintoneEventGroup, IKintoneEventNode } from '../../types/KintoneEvents';
import FieldSelect from '../FieldSelect.vue';
import ShowDialog from '../ShowDialog.vue'; import ShowDialog from '../ShowDialog.vue';
import FieldSelect from '../FieldSelect.vue';
import { QTree } from 'quasar';
export default defineComponent({ export default defineComponent({
name: 'EventTree', name: 'EventTree',
components: { components: {
@@ -79,12 +72,12 @@ export default defineComponent({
if(store.eventTree.findEventById(eventid)){ if(store.eventTree.findEventById(eventid)){
return; return;
} }
selectedChangeEvent.value?.events.push({ selectedChangeEvent.value?.events.push(
eventId: eventid, new kintoneEvent(
label: field.name, field.label,
parentId: selectedChangeEvent.value.eventId, eventid,
header: 'DELETABLE' selectedChangeEvent.value.eventId)
}); );
tree.value?.expanded?.push(selectedChangeEvent.value.eventId); tree.value?.expanded?.push(selectedChangeEvent.value.eventId);
tree.value?.expandAll(); tree.value?.expandAll();
} }
@@ -96,17 +89,6 @@ export default defineComponent({
selectedChangeEvent.value=node; selectedChangeEvent.value=node;
showDialog.value=true; showDialog.value=true;
} }
const deleteEvent = (node: IKintoneEvent) => {
if (!node.eventId) {
return;
}
store.deleteStoreEventAndFlow(node);
store.selectFlow(undefined)
console.log(store.selectedFlow);
}
const onSelected=(node:IKintoneEvent)=>{ const onSelected=(node:IKintoneEvent)=>{
if(!node.eventId){ if(!node.eventId){
return; return;
@@ -116,7 +98,6 @@ export default defineComponent({
return; return;
} }
const screen = store.eventTree.findEventById(node.parentId); const screen = store.eventTree.findEventById(node.parentId);
let flow =store.findFlowByEventId(node.eventId); let flow =store.findFlowByEventId(node.eventId);
let screenName=screen!==null?screen.label:""; let screenName=screen!==null?screen.label:"";
let nodeLabel = node.label; let nodeLabel = node.label;
@@ -124,7 +105,6 @@ export default defineComponent({
// screenName=nodeLabel; // screenName=nodeLabel;
// nodeLabel=`${node.label}の値を変更したとき`; // nodeLabel=`${node.label}の値を変更したとき`;
// } // }
if(flow!==undefined && flow!==null ){ if(flow!==undefined && flow!==null ){
store.selectFlow(flow); store.selectFlow(flow);
}else{ }else{
@@ -145,7 +125,6 @@ export default defineComponent({
onSelected, onSelected,
selectedEvent, selectedEvent,
addChangeEvent, addChangeEvent,
deleteEvent,
closeDg, closeDg,
store store
} }
@@ -157,21 +136,16 @@ export default defineComponent({
flex-wrap:nowarp; flex-wrap:nowarp;
text-wrap:nowarp; text-wrap:nowarp;
} }
.event-node{ .event-node{
cursor:pointer; cursor:pointer;
} }
.selected-node{ .selected-node{
color: $primary; color: $primary;
font-weight: bolder; font-weight: bolder;
} }
.event-node:hover{ .event-node:hover{
background-color: $light-blue-1; background-color: $light-blue-1;
} }
.delete-btn {
margin-right: 5px;
}
</style> </style>

View File

@@ -205,7 +205,7 @@ export default defineComponent({
*/ */
const varName =(node:IActionNode)=>{ const varName =(node:IActionNode)=>{
const prop = node.actionProps.find((prop) => prop.props.name === "verName"); const prop = node.actionProps.find((prop) => prop.props.name === "verName");
return prop?.props.modelValue; return prop?.props.modelValue.name;
}; };
const copyFlow=()=>{ const copyFlow=()=>{
context.emit('copyFlow', props.actionNode); context.emit('copyFlow', props.actionNode);

View File

@@ -128,7 +128,7 @@ interface IAppFields{
export default defineComponent({ export default defineComponent({
inheritAttrs:false, inheritAttrs:false,
name: 'FieldInput', name: 'AppFieldSelect',
components: { components: {
ShowDialog, ShowDialog,
FieldSelect, FieldSelect,

View File

@@ -17,10 +17,27 @@
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, ref ,watchEffect,computed,reactive} from 'vue'; import { ConditionNode, ConditionTree, Operator } from 'app/src/types/Conditions';
import { ConditionTree,GroupNode,ConditionNode,LogicalOperator,Operator } from 'app/src/types/Conditions'; import { computed, defineComponent, provide, reactive, ref, watchEffect } from 'vue';
import ConditionEditor from '../ConditionEditor/ConditionEditor.vue' import ConditionEditor from '../ConditionEditor/ConditionEditor.vue';
type Props = {
props?: {
name: string;
modelValue?: {
fields: {
type: string;
label: string;
code: string;
}[]
}
}
};
export default defineComponent({ export default defineComponent({
name: 'FieldInput', name: 'FieldInput',
inheritAttrs: false, inheritAttrs: false,
@@ -28,6 +45,10 @@
ConditionEditor ConditionEditor
}, },
props: { props: {
context: {
type: Array<Props>,
default: '',
},
displayName: { displayName: {
type: String, type: String,
default: '', default: '',
@@ -48,9 +69,24 @@
type: String, type: String,
default: null default: null
}, },
sourceType: {
type: String,
default: 'field'
}
}, },
setup(props, { emit }) { setup(props, { emit }) {
const source = props.context.find(element => element?.props?.name === 'sources')
if (source) {
if(props.sourceType === 'field'){
provide('sourceFields', computed( () => source.props?.modelValue?.fields ?? []));
} else if(props.sourceType === 'app'){
console.log('sourceApp', source.props?.modelValue);
provide('sourceApp', computed( () => source.props?.modelValue?.app?.id));
}
}
const appDg = ref(); const appDg = ref();
const show = ref(false); const show = ref(false);
const tree = reactive(new ConditionTree()); const tree = reactive(new ConditionTree());

View File

@@ -0,0 +1,229 @@
<template>
<div>
<q-field :label="displayName" labelColor="primary" stack-label>
<template v-slot:control>
<q-card flat class="full-width">
<q-card-actions vertical>
<q-btn color="grey-3" text-color="black" @click="() => { dgIsShow = true }">クリックで設定</q-btn>
</q-card-actions>
<q-card-section class="text-caption">
<div v-if="processingObjectsInputDisplay && processingObjectsInputDisplay.length>0">
<div v-for="(item) in processingObjectsInputDisplay" :key="item">{{ item }}</div>
</div>
<div v-else>{{ placeholder }}</div>
</q-card-section>
</q-card>
</template>
</q-field>
<show-dialog v-model:visible="dgIsShow" name="集計処理" @close="closeDg" min-width="50vw" min-height="60vh">
<div class="q-mx-md q-mb-md">
<q-input v-model="processingProps.name" type="text" label-color="primary" label="集計結果の変数名"
placeholder="集計結果を格納する変数名を入力してください" stack-label />
</div>
<div class="q-mx-md">
<div class="row q-col-gutter-x-xs flex-center">
<div class="col-5">
<div class="q-mx-xs">データソース</div>
</div>
<div class="col-2">
<div class="q-mx-xs">集計計算</div>
</div>
<div class="col-4">
<div class="q-mx-xs">集計結果変数名</div>
</div>
<div class="col-1"><q-btn flat round dense icon="add" size="sm" @click="addProcessingObject" />
</div>
</div>
<div class="q-my-sm" v-for="(item, index) in processingObjects" :key="item.id">
<div class="row q-col-gutter-x-xs flex-center">
<div class="col-5">
<ConditionObject v-model="item.field" />
</div>
<div class="col-2">
<q-select v-model="item.logicalOperator" :options="logicalOperators" outlined dense></q-select>
</div>
<div class="col-4">
<q-input v-model="item.vName" type="text" outlined dense />
</div>
<div class="col-1">
<q-btn flat round dense icon="delete" size="sm" @click="() => deleteProcessingObject(index)" />
</div>
</div>
</div>
</div>
</show-dialog>
</div>
</template>
<script lang="ts">
import { v4 as uuidv4 } from 'uuid';
import { computed, defineComponent, provide, reactive, ref, watchEffect } from 'vue';
import ConditionObject from '../ConditionEditor/ConditionObject.vue';
import ShowDialog from '../ShowDialog.vue';
type Props = {
props?: {
name: string;
modelValue?: {
fields: {
type: string;
label: string;
code: string;
}[]
} | string
}
};
type ProcessingObjectType = {
field?: {
name: string | {
name: string;
};
objectType: string;
type: string;
code: string;
label: string;
noLabel: boolean;
};
logicalOperator?: string;
vName?: string;
id: string;
}
type ValueType = {
name: string;
actionName: string,
displayName: string,
vars: ProcessingObjectType[];
}
export default defineComponent({
name: 'DataProcessing',
inheritAttrs: false,
components: {
ShowDialog,
ConditionObject,
},
props: {
context: {
type: Array<Props>,
default: '',
},
displayName: {
type: String,
default: '',
},
name: {
type: String,
default: '',
},
modelValue: {
type: Object as () => ValueType,
},
placeholder: {
type: String,
default: '',
},
},
setup(props, { emit }) {
const source = props.context.find(element => element?.props?.name === 'sources')
if (source) {
provide('sourceFields', computed(() => {
const modelValue = source.props?.modelValue;
if (modelValue && typeof modelValue !== 'string') {
return modelValue.fields;
}
return null;
}));
}
const actionName = props.context.find(element => element?.props?.name === 'displayName')
const processingProps: ValueType = props.modelValue && props.modelValue.vars
? props.modelValue
: reactive({
name: '',
actionName: actionName?.props?.modelValue as string,
displayName: '結果(戻り値)',
vars: [{ id: uuidv4() }]
});
const closeDg = () => {
emit('update:modelValue', processingProps
);
}
const processingObjects = processingProps.vars;
const deleteProcessingObject = (index: number) => processingObjects.length === 1
? processingObjects.splice(0, processingObjects.length, { id: uuidv4() })
: processingObjects.splice(index, 1);
const processingObjectsInputDisplay = computed(() =>
processingObjects ?
processingObjects
.filter(item => item.field && item.logicalOperator && item.vName)
.map(item => {
const name = typeof item.field?.name === 'string'
? item.field.name
: item.field?.name.name;
return item.logicalOperator.operator!==''?
`${processingProps.name}.${item.vName} = ${item.logicalOperator.operator}(${name})`
:`${processingProps.name}.${item.vName} = ${name}`
})
: []
);
//集計処理方法
const logicalOperators = ref([
{
"operator": "",
"label": "なし"
},
{
"operator": "SUM",
"label": "合計"
},
{
"operator": "AVG",
"label": "平均"
},
{
"operator": "MAX",
"label": "最大値"
},
{
"operator": "MIN",
"label": "最小値"
},
{
"operator": "COUNT",
"label": "カウント"
},
{
"operator": "FIRST",
"label": "最初の値"
}
]);
watchEffect(() => {
emit('update:modelValue', processingProps);
});
return {
uuidv4,
dgIsShow: ref(false),
closeDg,
processingObjects,
processingProps,
addProcessingObject: () => processingObjects.push({ id: uuidv4() }),
deleteProcessingObject,
logicalOperators,
processingObjectsInputDisplay,
};
},
});
</script>
<style lang="scss"></style>

View File

@@ -1,10 +1,7 @@
<template> <template>
<div v-bind="$attrs"> <div v-bind="$attrs">
<q-input :label="displayName" v-model="inputValue" label-color="primary" <q-input :label="displayName" v-model="inputValue" label-color="primary" :placeholder="placeholder" stack-label
:placeholder="placeholder" stack-label :rules="rulesExp" :maxlength="maxLength">
:rules="rulesExp"
:maxlength="maxLength"
>
<template v-slot:append v-if="hint !== ''"> <template v-slot:append v-if="hint !== ''">
<q-icon name="help" size="22px" color="blue-8"> <q-icon name="help" size="22px" color="blue-8">
<q-tooltip class="bg-yellow-2 text-black shadow-4" anchor="bottom right"> <q-tooltip class="bg-yellow-2 text-black shadow-4" anchor="bottom right">
@@ -18,7 +15,7 @@
<script lang="ts"> <script lang="ts">
import { kMaxLength } from 'buffer'; import { kMaxLength } from 'buffer';
import { defineComponent, ref, watchEffect } from 'vue'; import { defineComponent, ref, watchEffect, computed } from 'vue';
export default defineComponent({ export default defineComponent({
name: 'InputText', name: 'InputText',
@@ -50,17 +47,40 @@ export default defineComponent({
default: undefined default: undefined
}, },
modelValue: { modelValue: {
type: String, // type: Any,
default: '', default: '',
}, },
}, },
setup(props, { emit }) { setup(props, { emit }) {
const inputValue = ref(props.modelValue); const inputValue = computed({
const rulesExp = props.rules===undefined?null : eval(props.rules); get: () => {
watchEffect(() => { if (props.modelValue !== null && typeof props.modelValue === 'object' && 'name' in props.modelValue) {
emit('update:modelValue', inputValue.value); return props.modelValue.name;
} else {
return props.modelValue;
}
},
set: (val) => {
if (props.name === 'verName') {
// return props.modelValue.name;
emit('update:modelValue', { name: val });
} else {
emit('update:modelValue', val);
}
},
}); });
// const inputValue = ref(props.modelValue);
const rulesExp = props.rules === undefined ? null : eval(props.rules);
// const finalValue = computed(() => {
// return props.name !== 'verName' ? inputValue.value : {
// name: inputValue.value,
// };
// });
// watchEffect(() => {
// emit('update:modelValue', finalValue);
// });
return { return {
inputValue, inputValue,

View File

@@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<div v-for="(item, index) in properties" :key="index" > <div v-for="(item, index) in properties" :key="index" >
<component :is="item.component" v-bind="item.props" :connectProps="connectProps(item.props)" v-model="item.props.modelValue"></component> <component :is="item.component" v-bind="item.props" :context="properties" :connectProps="connectProps(item.props)" v-model="item.props.modelValue"></component>
</div> </div>
</div> </div>
</template> </template>
@@ -21,6 +21,7 @@ import ConditionInput from '../right/ConditionInput.vue';
import EventSetter from '../right/EventSetter.vue'; import EventSetter from '../right/EventSetter.vue';
import ColorPicker from './ColorPicker.vue'; import ColorPicker from './ColorPicker.vue';
import NumInput from './NumInput.vue'; import NumInput from './NumInput.vue';
import DataProcessing from './DataProcessing.vue';
import { IActionNode,IActionProperty,IProp } from 'src/types/ActionTypes'; import { IActionNode,IActionProperty,IProp } from 'src/types/ActionTypes';
export default defineComponent({ export default defineComponent({
@@ -35,7 +36,8 @@ export default defineComponent({
ConditionInput, ConditionInput,
EventSetter, EventSetter,
ColorPicker, ColorPicker,
NumInput NumInput,
DataProcessing
}, },
props: { props: {
nodeProps: { nodeProps: {
@@ -50,7 +52,7 @@ export default defineComponent({
setup(props, context) { setup(props, context) {
const properties=ref(props.nodeProps); const properties=ref(props.nodeProps);
const connectProps=(props:IProp)=>{ const connectProps=(props:IProp)=>{
const connProps:any={}; const connProps:any={context:properties};
if(props && "connectProps" in props && props.connectProps!=undefined){ if(props && "connectProps" in props && props.connectProps!=undefined){
for(let connProp of props.connectProps){ for(let connProp of props.connectProps){
let targetProp = properties.value.find((prop)=>prop.props.name===connProp.propName); let targetProp = properties.value.find((prop)=>prop.props.name===connProp.propName);

View File

@@ -1,11 +1,12 @@
<template> <template>
<div v-bind="$attrs"> <div v-bind="$attrs">
<q-select v-model="selectedValue" :label="displayName" :options="options"/> <q-select v-model="selectedValue" :use-chips="multiple" :label="displayName" label-color="primary" :options="options" stack-label
:multiple="multiple"/>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent,ref,watchEffect } from 'vue'; import { defineComponent,ref,watchEffect,computed } from 'vue';
export default defineComponent({ export default defineComponent({
name: 'SelectBox', name: 'SelectBox',
@@ -23,20 +24,27 @@ export default defineComponent({
type: Array, type: Array,
required: true, required: true,
}, },
modelValue: { selectType:{
type:String, type:String,
default:'', default:'',
}, },
modelValue: {
type: Object,
default: null,
},
}, },
setup(props, { emit }) { setup(props, { emit }) {
const selectedValue = ref(props.modelValue); const selectedValue = ref(props.modelValue);
const multiple = computed(()=>{
return props.selectType==='multiple'
});
watchEffect(() => { watchEffect(() => {
emit('update:modelValue', selectedValue.value); emit('update:modelValue', selectedValue.value);
}); });
return { return {
selectedValue selectedValue,
multiple
}; };
}, },
}); });

View File

@@ -1,8 +1,11 @@
import { api } from 'boot/axios'; import { api } from 'boot/axios';
import { ActionFlow } from 'src/types/ActionTypes'; import { ActionFlow } from 'src/types/ActionTypes';
export class FlowCtrl { export class FlowCtrl
async getFlows(appId: string): Promise<ActionFlow[]> { {
async getFlows(appId:string):Promise<ActionFlow[]>
{
const flows:ActionFlow[]=[]; const flows:ActionFlow[]=[];
try{ try{
const result = await api.get(`api/flows/${appId}`); const result = await api.get(`api/flows/${appId}`);
@@ -21,9 +24,10 @@ export class FlowCtrl {
} }
} }
async SaveFlow(jsonData: any): Promise<boolean> { async SaveFlow(jsonData:any):Promise<boolean>
{
const result = await api.post('api/flow',jsonData); const result = await api.post('api/flow',jsonData);
console.info(result.data); console.info(result.data)
return true; return true;
} }
/** /**
@@ -31,19 +35,10 @@ export class FlowCtrl {
* @param jsonData * @param jsonData
* @returns * @returns
*/ */
async UpdateFlow(jsonData: any): Promise<boolean> { async UpdateFlow(jsonData:any):Promise<boolean>
{
const result = await api.put('api/flow/' + jsonData.flowid,jsonData); const result = await api.put('api/flow/' + jsonData.flowid,jsonData);
console.info(result.data); console.info(result.data)
return true;
}
/**
* フローを消去する
* @param flowId
* @returns
*/
async DeleteFlow(flowId: string): Promise<boolean> {
const result = await api.delete('api/flow/' + flowId);
console.info(result.data);
return true; return true;
} }
/** /**
@@ -51,9 +46,12 @@ export class FlowCtrl {
* @param appid * @param appid
* @returns * @returns
*/ */
async depoly(appid: string): Promise<boolean> { async depoly(appid:string):Promise<boolean>
{
const result = await api.post(`api/v1/createjstokintone?app=${appid}`); const result = await api.post(`api/v1/createjstokintone?app=${appid}`);
console.info(result.data); console.info(result.data);
return true; return true;
} }
} }

View File

@@ -20,9 +20,10 @@
</div> </div>
</q-drawer> </q-drawer>
</div> </div>
<q-btn flat dense round :icon="drawerLeft ? 'keyboard_double_arrow_left' : 'keyboard_double_arrow_right'" <q-btn flat dense round
:style="[drawerLeft ? { 'left': '300px' } : { 'left': '0px' }]" @click="drawerLeft = !drawerLeft" :icon="drawerLeft?'keyboard_double_arrow_left':'keyboard_double_arrow_right'"
class="expand" /> :style="[drawerLeft?{'left':'300px'}:{'left':'0px'}]"
@click="drawerLeft=!drawerLeft" class="expand" />
<div class="q-pa-md q-gutter-sm" :style="{minWidth: minPanelWidth}"> <div class="q-pa-md q-gutter-sm" :style="{minWidth: minPanelWidth}">
<div class="flowchart" v-if="store.currentFlow" :style="[drawerLeft?{paddingLeft:'300px'}:{}]"> <div class="flowchart" v-if="store.currentFlow" :style="[drawerLeft?{paddingLeft:'300px'}:{}]">
<node-item v-if="rootNode!==undefined" :key="rootNode.id" :isSelected="rootNode === store.activeNode" <node-item v-if="rootNode!==undefined" :key="rootNode.id" :isSelected="rootNode === store.activeNode"
@@ -194,22 +195,7 @@ const onDeploy = async () => {
const onSaveFlow = async () => { const onSaveFlow = async () => {
const targetFlow = store.selectedFlow; const targetFlow = store.selectedFlow;
const deleteFlows = () => {
$q.notify({
type: 'positive',
caption: "通知",
message: `削除 ${store.deleteFlowIds.length} イベント`
});
store.deletebackendFlow();
}
if (targetFlow === undefined) { if (targetFlow === undefined) {
if (store.deleteFlowIds.length > 0) {
deleteFlows();
return;
}
$q.notify({ $q.notify({
type: 'negative', type: 'negative',
caption: "エラー", caption: "エラー",
@@ -218,9 +204,6 @@ const onSaveFlow = async () => {
return; return;
} }
try { try {
if (store.deleteFlowIds.length > 0) {
deleteFlows();
}
saveLoading.value = true; saveLoading.value = true;
await store.saveFlow(targetFlow); await store.saveFlow(targetFlow);
saveLoading.value = false; saveLoading.value = false;
@@ -282,7 +265,6 @@ onMounted(() => {
top: 50px; top: 50px;
z-index: 999; z-index: 999;
} }
.expand{ .expand{
position: fixed; position: fixed;
left: 0px; left: 0px;

View File

@@ -12,11 +12,10 @@ export interface FlowEditorState {
eventTree:KintoneEventManager; eventTree:KintoneEventManager;
selectedEvent:IKintoneEvent|undefined; selectedEvent:IKintoneEvent|undefined;
expandedScreen:any[]; expandedScreen:any[];
deleteFlowIds: string[];
} }
const flowCtrl=new FlowCtrl(); const flowCtrl=new FlowCtrl();
const eventTree = new KintoneEventManager(); const eventTree = new KintoneEventManager();
export const useFlowEditorStore = defineStore('flowEditor', { export const useFlowEditorStore = defineStore("flowEditor",{
state: ():FlowEditorState => ({ state: ():FlowEditorState => ({
flowNames1: '', flowNames1: '',
appInfo:undefined, appInfo:undefined,
@@ -25,8 +24,7 @@ export const useFlowEditorStore = defineStore('flowEditor', {
activeNode:undefined, activeNode:undefined,
eventTree:eventTree, eventTree:eventTree,
selectedEvent:undefined, selectedEvent:undefined,
expandedScreen: [], expandedScreen:[]
deleteFlowIds: [],
}), }),
getters: { getters: {
/** /**
@@ -45,29 +43,17 @@ export const useFlowEditorStore = defineStore('flowEditor', {
return (eventId:string)=>{ return (eventId:string)=>{
return state.flows?.find((flow)=>{ return state.flows?.find((flow)=>{
const root=flow.getRoot(); const root=flow.getRoot();
return root?.name === eventId; return root?.name===eventId
}); });
}; }
}, }
findEventById(state) {
return (eventId: string) => {
return state.eventTree.findEventById(eventId);
};
},
findEventFrist(state) {
return () => {
return state.eventTree.findEventFrist();
};
},
}, },
actions: { actions: {
setFlows(flows:IActionFlow[]){ setFlows(flows:IActionFlow[]){
this.flows=flows; this.flows=flows;
}, },
selectFlow(flow: IActionFlow | undefined) { selectFlow(flow:IActionFlow){
this.selectedFlow=flow; this.selectedFlow=flow;
}, },
setActiveNode(node:IActionNode){ setActiveNode(node:IActionNode){
@@ -76,12 +62,6 @@ export const useFlowEditorStore = defineStore('flowEditor', {
setApp(app:AppInfo){ setApp(app:AppInfo){
this.appInfo=app; this.appInfo=app;
}, },
addDeleteFlowId(flowId: string) {
this.deleteFlowIds.push(flowId);
},
clearDeleteFlowIds() {
this.deleteFlowIds = [];
},
/** /**
* DBからフルーを保存する * DBからフルーを保存する
* @returns * @returns
@@ -100,7 +80,7 @@ export const useFlowEditorStore = defineStore('flowEditor', {
if(actionFlows && actionFlows.length>0){ if(actionFlows && actionFlows.length>0){
this.selectFlow(actionFlows[0]); this.selectFlow(actionFlows[0]);
} }
const expandNames = actionFlows.map((flow) => flow.getRoot()?.title); const expandNames = actionFlows.map(flow=>flow.getRoot()?.title);
// const expandName =actionFlows[0].getRoot()?.title; // const expandName =actionFlows[0].getRoot()?.title;
this.expandedScreen=expandNames; this.expandedScreen=expandNames;
}, },
@@ -115,8 +95,8 @@ export const useFlowEditorStore = defineStore('flowEditor', {
appid: this.appInfo?.appId, appid: this.appInfo?.appId,
eventid: root?.name, eventid: root?.name,
name: root?.subTitle, name: root?.subTitle,
content: JSON.stringify(flow), content: JSON.stringify(flow)
}; }
if(isNew){ if(isNew){
return await flowCtrl.SaveFlow(jsonData); return await flowCtrl.SaveFlow(jsonData);
@@ -124,33 +104,6 @@ export const useFlowEditorStore = defineStore('flowEditor', {
return await flowCtrl.UpdateFlow(jsonData); return await flowCtrl.UpdateFlow(jsonData);
} }
}, },
async deletebackendFlow() {
const deletePromises = Object.values(this.deleteFlowIds).map((flowId) =>
flowCtrl.DeleteFlow(flowId)
);
await Promise.all(deletePromises);
this.clearDeleteFlowIds();
},
deleteStoreEventAndFlow(event: IKintoneEvent) {
const store = useFlowEditorStore();
if (event.flowData) {
const flow = event.flowData;
if (flow.id === '') {
return;
}
console.log('delete flow', flow);
this.addDeleteFlowId(flow.id);
eventTree.deleteEvent(event, store);
if(this.flows){
this.flows = this.flows.filter((f) => f.id !== flow.id);
}
} else {
eventTree.deleteEvent(event, store);
}
},
/** /**
* デプロイする * デプロイする
*/ */
@@ -159,6 +112,7 @@ export const useFlowEditorStore = defineStore('flowEditor', {
return false; return false;
} }
return await flowCtrl.depoly(this.appInfo?.appId); return await flowCtrl.depoly(this.appInfo?.appId);
}, }
},
}
}); });

View File

@@ -45,7 +45,16 @@ export interface IActionProperty {
export interface IActionVariable{ export interface IActionVariable{
actionName:string; actionName:string;
displayName:string; displayName:string;
name: {
name:string; name:string;
actionName:string;
displayName:string;
vars : {
vName:string;
logicalOperator:string;
field: object;
}[]
};
} }
/** /**
* アクションタイプ定義 * アクションタイプ定義
@@ -448,6 +457,12 @@ export class ActionFlow implements IActionFlow {
getPrevVarNames(prevNode:IActionNode):IActionVariable[]{ getPrevVarNames(prevNode:IActionNode):IActionVariable[]{
let varNames:IActionVariable[]=[]; let varNames:IActionVariable[]=[];
if(prevNode.varName!==undefined && prevNode.varName.modelValue){ if(prevNode.varName!==undefined && prevNode.varName.modelValue){
if(prevNode.varName.modelValue ==='object'){
console.log(prevNode);
}
varNames.unshift({ varNames.unshift({
actionName:prevNode.name, actionName:prevNode.name,
displayName:prevNode.varName.displayName, displayName:prevNode.varName.displayName,

View File

@@ -198,7 +198,7 @@ export class ConditionTree {
if(value && typeof value ==='object' && ('label' in value)){ if(value && typeof value ==='object' && ('label' in value)){
value =condNode.value.label; value =condNode.value.label;
} }
return `${condNode.object.name} ${condNode.operator} '${value}'`; return `${typeof condNode.object.name === 'object' ? condNode.object.name.name : condNode.object.name} ${condNode.operator} '${value}'`;
} else { } else {
return ''; return '';
} }

View File

@@ -1,4 +1,3 @@
import { useFlowEditorStore } from 'src/stores/flowEditor';
import {IActionFlow} from './ActionTypes'; import {IActionFlow} from './ActionTypes';
export interface IKintoneEventNode { export interface IKintoneEventNode {
label: string; label: string;
@@ -16,15 +15,18 @@ export interface IKintoneEventGroup extends IKintoneEventNode {
events: IKintoneEventNode[]; events: IKintoneEventNode[];
} }
export class kintoneEvent implements IKintoneEvent{ export class kintoneEvent implements IKintoneEvent{
eventId: string; eventId: string;
parentId:string; parentId:string;
get hasFlow(): boolean{ get hasFlow(): boolean{
return this.flowData !== undefined && this.flowData.actionNodes.length > 1; return this.flowData!==undefined && this.flowData.actionNodes.length>1
} };
flowData?: IActionFlow | undefined; flowData?: IActionFlow | undefined;
label: string; label: string;
header = 'EVENT'; get header():string{
return "EVENT";
}
constructor(label:string,eventId:string,parentId:string){ constructor(label:string,eventId:string,parentId:string){
this.eventId=eventId; this.eventId=eventId;
this.label=label; this.label=label;
@@ -38,14 +40,9 @@ export class kintoneEventGroup implements IKintoneEventGroup {
label: string; label: string;
events: IKintoneEventNode[]; events: IKintoneEventNode[];
get header():string{ get header():string{
return 'EVENTGROUP'; return "EVENTGROUP";
} }
constructor( constructor(eventId:string,label:string,events:IKintoneEventNode[],parentId:string){
eventId: string,
label: string,
events: IKintoneEventNode[],
parentId: string
) {
this.eventId=eventId; this.eventId=eventId;
this.label=label; this.label=label;
this.events=events; this.events=events;
@@ -53,20 +50,16 @@ export class kintoneEventGroup implements IKintoneEventGroup {
} }
} }
export class kintoneEventForChange implements IKintoneEventGroup{ export class kintoneEventForChange implements IKintoneEventGroup{
eventId: string; eventId: string;
parentId:string; parentId:string;
label: string; label: string;
events: IKintoneEventNode[]; events: IKintoneEventNode[];
get header():string{ get header():string{
return 'CHANGE'; return "CHANGE";
} }
constructor( constructor(eventId:string,label:string,events:IKintoneEventNode[],parentId:string){
eventId: string,
label: string,
events: IKintoneEventNode[],
parentId: string
) {
this.eventId=eventId; this.eventId=eventId;
this.label=label; this.label=label;
this.events=events; this.events=events;
@@ -74,6 +67,8 @@ export class kintoneEventForChange implements IKintoneEventGroup {
} }
} }
export class KintoneEventManager { export class KintoneEventManager {
public screens: IKintoneEventGroup[]; public screens: IKintoneEventGroup[];
@@ -85,38 +80,24 @@ export class KintoneEventManager {
this.screens=this.getKintoneEvents(); this.screens=this.getKintoneEvents();
for (const flow of flows){ for (const flow of flows){
const eventId =flow.getRoot()?.name; const eventId =flow.getRoot()?.name;
console.log('eventId:', eventId);
if(eventId!==undefined){ if(eventId!==undefined){
const eventNode = this.findEventById(eventId); const eventNode = this.findEventById(eventId);
if (eventNode !== null && eventNode.header === 'EVENT') { if(eventNode!==null && eventNode.header==="EVENT"){
const event =eventNode as kintoneEvent; const event =eventNode as kintoneEvent;
event.flowData=flow; event.flowData=flow;
}else{ }else{
//EventGroupのIDを取得 //EventGroupのIDを取得
const lastIndex = eventId.lastIndexOf('.'); const lastIndex = eventId.lastIndexOf(".");
const groupId=eventId.substring(0,lastIndex); const groupId=eventId.substring(0,lastIndex);
const eventNode = this.findEventById(groupId); const eventNode = this.findEventById(groupId);
if ( if(eventNode && (eventNode.header==="EVENTGROUP" || eventNode.header==="CHANGE")){
eventNode &&
(eventNode.header === 'EVENTGROUP' || eventNode.header === 'CHANGE')
) {
const groupEvent=eventNode as kintoneEventGroup; const groupEvent=eventNode as kintoneEventGroup;
console.log('label:', flow.getRoot()?.subTitle); const newEvent =new kintoneEvent(
flow.getRoot()?.subTitle || "",
const newEvent = { eventId,
label: flow.getRoot()?.subTitle || '', groupEvent.parentId
eventId: eventId, );
parentId: groupId, newEvent.flowData=flow;
header: 'DELETABLE',
hasFlow: true,
flowData: flow,
};
// new kintoneEvent(
// flow.getRoot()?.subTitle || '',
// eventId,
// groupEvent.parentId
// );
groupEvent.events.push(newEvent); groupEvent.events.push(newEvent);
} }
} }
@@ -124,25 +105,19 @@ export class KintoneEventManager {
} }
} }
public findEventFrist() {
return this.findEventById('app.record.create.show') as IKintoneEvent;
}
public findEventById(eventId: string): IKintoneEventNode | null { public findEventById(eventId: string): IKintoneEventNode | null {
const screen=this.findScreen(eventId); const screen=this.findScreen(eventId);
if (screen) { if(screen) {return screen;}
return screen;
}
for (const screen of this.screens) { for (const screen of this.screens) {
for (const event of screen.events) { for (const event of screen.events) {
if (event.eventId === eventId) { if (event.eventId === eventId) {
return event; return event;
} }
if (event.header === 'EVENTGROUP' || event.header === 'CHANGE') { if(event.header==="EVENTGROUP"||event.header==="CHANGE"){
const eventGroup = event as IKintoneEventGroup; const eventGroup = event as IKintoneEventGroup;
const targetEvent = eventGroup.events.find((ev)=>{ const targetEvent = eventGroup.events.find((ev)=>{
return ev.eventId===eventId; return ev.eventId===eventId;
}); })
if(targetEvent){ if(targetEvent){
return targetEvent; return targetEvent;
} }
@@ -153,169 +128,39 @@ export class KintoneEventManager {
} }
public findScreen(eventId:string):IKintoneEventGroup|undefined{ public findScreen(eventId:string):IKintoneEventGroup|undefined{
return this.screens.find((screen) => screen.eventId == eventId); return this.screens.find(screen=>screen.eventId==eventId);
}
public deleteEvent(
event: kintoneEvent,
store: ReturnType<typeof useFlowEditorStore>
) {
if (event.header !== 'DELETABLE') {
return;
}
const parent = store.findEventById(event.parentId);
if (parent?.header !== 'CHANGE' && parent?.header !== 'EVENTGROUP') {
return;
}
const realParent = parent as kintoneEventForChange;
const index = realParent.events.findIndex(
(e) => e.eventId === event.eventId
);
if (index !== -1) {
realParent.events.splice(index, 1);
}
} }
public getKintoneEvents():IKintoneEventGroup[]{ public getKintoneEvents():IKintoneEventGroup[]{
return [ return [
new kintoneEventGroup( new kintoneEventGroup("app.record.create","レコード追加画面",[
'app.record.create', new kintoneEvent('レコード追加画面を表示した後','app.record.create.show',"app.record.create"),
'レコード追加画面', new kintoneEvent('保存をクリックしたとき','app.record.create.submit',"app.record.create"),
[ new kintoneEvent('保存が成功したとき','app.record.create.submit.success',"app.record.create"),
new kintoneEvent( new kintoneEventForChange('app.record.create.change','フィールドの値を変更したとき',[],"app.record.create"),
'レコード追加画面を表示した', new kintoneEventGroup('app.record.create.show.customButtonClick','ボタンをクリックした',[],"app.record.create")
'app.record.create.show', ],""),
'app.record.create' new kintoneEventGroup("app.record.detail","レコード詳細画面",[
), new kintoneEvent('レコード詳細画面を表示した後','app.record.detail.show',"app.record.detail"),
new kintoneEvent( new kintoneEvent('レコードを削除するとき','app.record.detail.delete.submit',"app.record.detail"),
'保存をクリックしたとき', new kintoneEvent('プロセス管理のアクションを実行したとき','app.record.detail.process.proceed',"app.record.detail"),
'app.record.create.submit', new kintoneEventGroup('app.record.detail.show.customButtonClick','ボタンをクリックした時',[],"app.record.detail"),
'app.record.create' ],""),
), new kintoneEventGroup("app.record.edit","レコード編集画面",[
new kintoneEvent( new kintoneEvent('レコード編集画面を表示した後','app.record.edit.show',"app.record.edit"),
'保存が成功したとき', new kintoneEvent('保存をクリックしたとき','app.record.edit.submit',"app.record.edit"),
'app.record.create.submit.success', new kintoneEvent('保存が成功したとき','app.record.edit.submit.success',"app.record.edit"),
'app.record.create' new kintoneEventForChange('app.record.edit.change','フィールドの値を変更したとき',[],"app.record.edit"),
), new kintoneEventGroup('app.record.edit.show.customButtonClick','ボタンをクリックした時',[],"app.record.edit"),
new kintoneEventForChange( ],""),
'app.record.create.change', new kintoneEventGroup("app.record.index","レコード一覧画面",[
'フィールドの値を変更したとき', new kintoneEvent('一覧画面を表示した後', 'app.record.index.show',"app.record.index"),
[], new kintoneEvent('インライン編集を開始したとき','app.record.index.edit.show',"app.record.index"),
'app.record.create' new kintoneEvent('インライン編集の【保存】をクリックしたとき','app.record.index.edit.submit',"app.record.index"),
), new kintoneEvent('インライン編集の保存が成功したとき', 'app.record.index.edit.submit.success',"app.record.index"),
new kintoneEventGroup( new kintoneEventForChange('app.record.index.edit.change','インライン編集のフィールド値を変更したとき' ,[],"app.record.index"),
'app.record.create.show.customButtonClick', new kintoneEventGroup('app.record.detail.show.customButtonClick','ボタンをクリックした時',[],"app.record.index"),
'ボタンをクリックした時', ],"")
[],
'app.record.create'
),
],
''
),
new kintoneEventGroup(
'app.record.detail',
'レコード詳細画面',
[
new kintoneEvent(
'レコード詳細画面を表示した後',
'app.record.detail.show',
'app.record.detail'
),
new kintoneEvent(
'レコードを削除するとき',
'app.record.detail.delete.submit',
'app.record.detail'
),
new kintoneEvent(
'プロセス管理のアクションを実行したとき',
'app.record.detail.process.proceed',
'app.record.detail'
),
new kintoneEventGroup(
'app.record.detail.show.customButtonClick',
'ボタンをクリックした時',
[],
'app.record.detail'
),
],
''
),
new kintoneEventGroup(
'app.record.edit',
'レコード編集画面',
[
new kintoneEvent(
'レコード編集画面を表示した後',
'app.record.edit.show',
'app.record.edit'
),
new kintoneEvent(
'保存をクリックしたとき',
'app.record.edit.submit',
'app.record.edit'
),
new kintoneEvent(
'保存が成功したとき',
'app.record.edit.submit.success',
'app.record.edit'
),
new kintoneEventForChange(
'app.record.edit.change',
'フィールドの値を変更したとき',
[],
'app.record.edit'
),
new kintoneEventGroup(
'app.record.edit.show.customButtonClick',
'ボタンをクリックした時',
[],
'app.record.edit'
),
],
''
),
new kintoneEventGroup(
'app.record.index',
'レコード一覧画面',
[
new kintoneEvent(
'一覧画面を表示した後',
'app.record.index.show',
'app.record.index'
),
new kintoneEvent(
'インライン編集を開始したとき',
'app.record.index.edit.show',
'app.record.index'
),
new kintoneEvent(
'インライン編集の【保存】をクリックしたとき',
'app.record.index.edit.submit',
'app.record.index'
),
new kintoneEvent(
'インライン編集の保存が成功したとき',
'app.record.index.edit.submit.success',
'app.record.index'
),
new kintoneEventForChange(
'app.record.index.edit.change',
'インライン編集のフィールド値を変更したとき',
[],
'app.record.index'
),
new kintoneEventGroup(
'app.record.detail.show.customButtonClick',
'ボタンをクリックした時',
[],
'app.record.index'
),
],
''
),
]; ];
} }
} }