ボタンクリックイベント対応
This commit is contained in:
1
backend/.gitignore
vendored
1
backend/.gitignore
vendored
@@ -56,6 +56,7 @@ coverage.xml
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
*.log.*
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -12,7 +12,8 @@ API_V1_AUTH_KEY = "X-Cybozu-Authorization"
|
||||
|
||||
DEPLOY_MODE = "DEV" #DEV,PROD
|
||||
|
||||
DEPLOY_JS_URL = "https://ka-addin.azurewebsites.net/alc_runtime.js"
|
||||
#DEPLOY_JS_URL = "https://ka-addin.azurewebsites.net/alc_runtime.js"
|
||||
DEPLOY_JS_URL = "https://b9c9-133-139-70-187.ngrok-free.app/alc_runtime.js"
|
||||
|
||||
KINTONE_FIELD_TYPE=["GROUP","GROUP_SELECT","CHECK_BOX","SUBTABLE","DROP_DOWN","USER_SELECT","RADIO_BUTTON","RICH_TEXT","LINK","REFERENCE_TABLE","CALC","TIME","NUMBER","ORGANIZATION_SELECT","FILE","DATETIME","DATE","MULTI_SELECT","SINGLE_LINE_TEXT","MULTI_LINE_TEXT"]
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
97
document/AI-OCRシステム概要図.drawio
Normal file
97
document/AI-OCRシステム概要図.drawio
Normal file
@@ -0,0 +1,97 @@
|
||||
<mxfile host="app.diagrams.net" modified="2024-02-28T04:38:57.047Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" etag="OcG1GMfhziVI7M4sfXsS" version="23.1.5" type="device">
|
||||
<diagram name="Page-1" id="12e1b939-464a-85fe-373e-61e167be1490">
|
||||
<mxGraphModel dx="1434" dy="820" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1.5" pageWidth="1169" pageHeight="826" background="none" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="60da8b9f42644d3a-2" value="" style="whiteSpace=wrap;html=1;rounded=1;shadow=0;strokeWidth=8;fontSize=20;align=center;fillColor=#7EA6E0;strokeColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="316" y="405" width="280" height="430" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-3" value="AI-OCRフォーム認識" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;shadow=0;fontSize=27;fontColor=#FFFFFF;fontStyle=1" parent="1" vertex="1">
|
||||
<mxGeometry x="316" y="425" width="280" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-4" value="AI-OCRのフォーム認識機能で<br>フォーマット情報を抽出する" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;shadow=0;fontSize=14;fontColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="316" y="725" width="280" height="90" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-6" value="" style="line;strokeWidth=2;html=1;rounded=0;shadow=0;fontSize=27;align=center;fillColor=none;strokeColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="336" y="485" width="240" height="10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-7" value="" style="line;strokeWidth=2;html=1;rounded=0;shadow=0;fontSize=27;align=center;fillColor=none;strokeColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="336" y="705" width="240" height="10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-8" value="PDFや<br>画像ファイル<br>レイアウト" style="ellipse;whiteSpace=wrap;html=1;rounded=0;shadow=0;strokeWidth=6;fontSize=14;align=center;fillColor=#BFB4A9;strokeColor=#FFFFFF;fontColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="259" y="545" width="115" height="115" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-9" value="" style="html=1;shadow=0;dashed=0;align=center;verticalAlign=middle;shape=mxgraph.arrows2.stylisedArrow;dy=0.6;dx=40;notch=15;feather=0.4;rounded=0;strokeWidth=1;fontSize=27;strokeColor=none;fillColor=#fff2cc;" parent="1" vertex="1">
|
||||
<mxGeometry x="406" y="573" width="100" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-17" value="" style="whiteSpace=wrap;html=1;rounded=1;shadow=0;strokeWidth=8;fontSize=20;align=center;fillColor=#FFC001;strokeColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="596" y="405" width="280" height="430" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-18" value="WEBフォーマット<br>変換" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;shadow=0;fontSize=27;fontColor=#FFFFFF;fontStyle=1" parent="1" vertex="1">
|
||||
<mxGeometry x="596" y="425" width="280" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-19" value="必要な注文情報項目、フォームレイアウト<br>データ種別等確認し、<br>入力フォームを自動変換する" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;shadow=0;fontSize=14;fontColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="596" y="725" width="280" height="90" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-20" value="" style="line;strokeWidth=2;html=1;rounded=0;shadow=0;fontSize=27;align=center;fillColor=none;strokeColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="616" y="485" width="240" height="10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-21" value="" style="line;strokeWidth=2;html=1;rounded=0;shadow=0;fontSize=27;align=center;fillColor=none;strokeColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="616" y="705" width="240" height="10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-22" value="フォーマット<br>確認" style="ellipse;whiteSpace=wrap;html=1;rounded=0;shadow=0;strokeWidth=6;fontSize=14;align=center;fillColor=#397DAA;strokeColor=#FFFFFF;fontColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="539" y="545" width="115" height="115" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-23" value="" style="html=1;shadow=0;dashed=0;align=center;verticalAlign=middle;shape=mxgraph.arrows2.stylisedArrow;dy=0.6;dx=40;notch=15;feather=0.4;rounded=0;strokeWidth=1;fontSize=27;strokeColor=none;fillColor=#fff2cc;" parent="1" vertex="1">
|
||||
<mxGeometry x="686" y="573" width="100" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-24" value="" style="whiteSpace=wrap;html=1;rounded=1;shadow=0;strokeWidth=8;fontSize=20;align=center;fillColor=#60a917;strokeColor=#2D7600;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="876" y="405" width="280" height="430" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-25" value="ユーザーの注文" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;shadow=0;fontSize=27;fontColor=#FFFFFF;fontStyle=1" parent="1" vertex="1">
|
||||
<mxGeometry x="876" y="425" width="280" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-26" value="ユーザーがWeb入力フォームから<br>注文データを入力する" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;shadow=0;fontSize=14;fontColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="876" y="725" width="280" height="90" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-27" value="" style="line;strokeWidth=2;html=1;rounded=0;shadow=0;fontSize=27;align=center;fillColor=none;strokeColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="896" y="485" width="240" height="10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-28" value="" style="line;strokeWidth=2;html=1;rounded=0;shadow=0;fontSize=27;align=center;fillColor=none;strokeColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="896" y="705" width="240" height="10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-29" value="注文フォーム<br>公開" style="ellipse;whiteSpace=wrap;html=1;rounded=0;shadow=0;strokeWidth=6;fontSize=14;align=center;fillColor=#EF9353;strokeColor=#FFFFFF;fontColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="819" y="545" width="115" height="115" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-30" value="" style="html=1;shadow=0;dashed=0;align=center;verticalAlign=middle;shape=mxgraph.arrows2.stylisedArrow;dy=0.6;dx=40;notch=15;feather=0.4;rounded=0;strokeWidth=1;fontSize=27;strokeColor=none;fillColor=#fff2cc;" parent="1" vertex="1">
|
||||
<mxGeometry x="966" y="573" width="100" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-31" value="" style="whiteSpace=wrap;html=1;rounded=1;shadow=0;strokeWidth=8;fontSize=20;align=center;fillColor=#a20025;strokeColor=#6F0000;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="1156" y="405" width="280" height="430" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-32" value="データ管理" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;shadow=0;fontSize=27;fontColor=#FFFFFF;fontStyle=1" parent="1" vertex="1">
|
||||
<mxGeometry x="1156" y="425" width="280" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-33" value="注文データをDBに保管し、<br>注文データの 確認やCSV抽出など<br>管理する" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;shadow=0;fontSize=14;fontColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="1156" y="725" width="280" height="90" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-34" value="" style="line;strokeWidth=2;html=1;rounded=0;shadow=0;fontSize=27;align=center;fillColor=none;strokeColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="1176" y="485" width="240" height="10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-35" value="" style="line;strokeWidth=2;html=1;rounded=0;shadow=0;fontSize=27;align=center;fillColor=none;strokeColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="1176" y="705" width="240" height="10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-36" value="メール自動送信" style="ellipse;whiteSpace=wrap;html=1;rounded=0;shadow=0;strokeWidth=6;fontSize=14;align=center;fillColor=#68B85C;strokeColor=#FFFFFF;fontColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="1099" y="545" width="115" height="115" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-37" value="" style="html=1;shadow=0;dashed=0;align=center;verticalAlign=middle;shape=mxgraph.arrows2.stylisedArrow;dy=0.6;dx=40;notch=15;feather=0.4;rounded=0;strokeWidth=1;fontSize=27;strokeColor=none;fillColor=#fff2cc;" parent="1" vertex="1">
|
||||
<mxGeometry x="1246" y="573" width="100" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="60da8b9f42644d3a-38" value="CSV出力<br>データ連携" style="ellipse;whiteSpace=wrap;html=1;rounded=0;shadow=0;strokeWidth=6;fontSize=14;align=center;fillColor=#BF639A;strokeColor=#FFFFFF;fontColor=#FFFFFF;" parent="1" vertex="1">
|
||||
<mxGeometry x="1379" y="545" width="115" height="115" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
@@ -2,13 +2,14 @@
|
||||
<!-- <div class="q-pa-md q-gutter-sm"> -->
|
||||
<q-tree
|
||||
:nodes="store.eventTree.screens"
|
||||
node-key="label"
|
||||
node-key="eventId"
|
||||
children-key="events"
|
||||
no-connectors
|
||||
v-model:expanded="store.expandedScreen"
|
||||
:dense="true"
|
||||
:ref="tree"
|
||||
>
|
||||
<template v-slot:default-header="prop">
|
||||
<template v-slot:header-EVENT="prop">
|
||||
<div class="row col items-start no-wrap event-node" @click="onSelected(prop.node)">
|
||||
<q-icon v-if="prop.node.eventId"
|
||||
name="play_circle"
|
||||
@@ -16,27 +17,78 @@
|
||||
size="16px" class="q-mr-sm">
|
||||
</q-icon>
|
||||
<div class="no-wrap" :class="selectedEvent && prop.node.eventId===selectedEvent.eventId?'selected-node':''">{{ prop.node.label }}</div>
|
||||
<q-space></q-space>
|
||||
<!-- <q-icon v-if="prop.node.hasFlow" name="delete" color="negative" size="16px" class="q-mr-sm"></q-icon> -->
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:header-CHANGE="prop" >
|
||||
<div class="row col items-start no-wrap event-node" >
|
||||
<div class="no-wrap">{{ prop.node.label }}</div>
|
||||
<q-space></q-space>
|
||||
<q-icon name="add_circle" color="primary" size="16px" class="q-mr-sm" @click="addChangeEvent(prop.node)"></q-icon>
|
||||
</div>
|
||||
</template>
|
||||
</q-tree>
|
||||
<!-- </div> -->
|
||||
<show-dialog v-model:visible="showDialog" name="フィールド選択" @close="closeDg" widht="400px">
|
||||
<field-select ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></field-select>
|
||||
</show-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, ref } from 'vue';
|
||||
import { IKintoneEvent } from '../../types/KintoneEvents';
|
||||
import { IKintoneEvent ,IKintoneEventGroup, IKintoneEventNode, kintoneEvent} from '../../types/KintoneEvents';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||
import { ActionFlow, ActionNode, RootAction } from 'src/types/ActionTypes';
|
||||
import ShowDialog from '../ShowDialog.vue';
|
||||
import FieldSelect from '../FieldSelect.vue';
|
||||
import { QTree } from 'quasar';
|
||||
export default defineComponent({
|
||||
name: 'EventTree',
|
||||
components: {
|
||||
ShowDialog,
|
||||
FieldSelect,
|
||||
},
|
||||
setup(props, context) {
|
||||
const appDg = ref();
|
||||
const store = useFlowEditorStore();
|
||||
const showDialog = ref(false);
|
||||
const tree = ref<QTree>();
|
||||
// const eventTree=ref(kintoneEvents);
|
||||
// const selectedFlow = store.currentFlow;
|
||||
|
||||
// const expanded=ref();
|
||||
const selectedEvent = ref<IKintoneEvent|null>(null);
|
||||
const selectedChangeEvent=ref<IKintoneEventGroup|null>(null);
|
||||
const isFieldChange = (node:IKintoneEventNode)=>{
|
||||
return node.header=='EVENT' && node.eventId.indexOf(".change.")>-1;
|
||||
}
|
||||
//フィールド値変更イベント追加
|
||||
const closeDg = (val:string) => {
|
||||
if (val == 'OK') {
|
||||
if(!selectedChangeEvent.value){return;}
|
||||
const field = appDg.value.selected[0];
|
||||
const eventid = `${selectedChangeEvent.value.eventId}.${field.code}`;
|
||||
if(store.eventTree.findEventById(eventid)){
|
||||
return;
|
||||
}
|
||||
selectedChangeEvent.value?.events.push(
|
||||
new kintoneEvent(
|
||||
field.label,
|
||||
eventid,
|
||||
selectedChangeEvent.value.eventId)
|
||||
);
|
||||
tree.value?.expanded?.push(selectedChangeEvent.value.eventId);
|
||||
tree.value?.expandAll();
|
||||
}
|
||||
};
|
||||
const addChangeEvent=(node:IKintoneEventGroup)=>{
|
||||
if(store.appInfo===undefined){
|
||||
return;
|
||||
}
|
||||
selectedChangeEvent.value=node;
|
||||
showDialog.value=true;
|
||||
}
|
||||
const onSelected=(node:IKintoneEvent)=>{
|
||||
if(!node.eventId){
|
||||
return;
|
||||
@@ -45,24 +97,35 @@ export default defineComponent({
|
||||
if(store.appInfo===undefined){
|
||||
return;
|
||||
}
|
||||
const screen = store.eventTree.findScreen(node.eventId);
|
||||
const screen = store.eventTree.findEventById(node.parentId);
|
||||
let flow =store.findFlowByEventId(node.eventId);
|
||||
const screenName=screen!==null?screen.label:"";
|
||||
let screenName=screen!==null?screen.label:"";
|
||||
let nodeLabel = node.label;
|
||||
// if(isFieldChange(node)){
|
||||
// screenName=nodeLabel;
|
||||
// nodeLabel=`${node.label}の値を変更したとき`;
|
||||
// }
|
||||
if(flow!==undefined && flow!==null ){
|
||||
store.selectFlow(flow);
|
||||
}else{
|
||||
const root = new RootAction(node.eventId,screenName,node.label)
|
||||
const root = new RootAction(node.eventId,screenName,nodeLabel)
|
||||
const flow =new ActionFlow(root);
|
||||
store.flows?.push(flow);
|
||||
store.selectFlow(flow);
|
||||
selectedEvent.value.flowData=flow;
|
||||
}
|
||||
}
|
||||
};
|
||||
return {
|
||||
// eventTree,
|
||||
// expanded,
|
||||
appDg,
|
||||
tree,
|
||||
showDialog,
|
||||
isFieldChange,
|
||||
onSelected,
|
||||
selectedEvent,
|
||||
addChangeEvent,
|
||||
closeDg,
|
||||
store
|
||||
}
|
||||
}
|
||||
@@ -83,4 +146,6 @@ export default defineComponent({
|
||||
.event-node:hover{
|
||||
background-color: $light-blue-1;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-for="(item, index) in componentData" :key="index">
|
||||
<component :is="item.component" v-bind="item.props" v-model="item.props.modelValue"></component>
|
||||
<component :is="item.component" v-bind="item.props" :connectProps="connectProps" v-model="item.props.modelValue"></component>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { defineComponent,computed } from 'vue';
|
||||
import InputText from '../right/InputText.vue';
|
||||
import SelectBox from '../right/SelectBox.vue';
|
||||
import DatePicker from '../right/DatePicker.vue';
|
||||
import FieldInput from '../right/FieldInput.vue';
|
||||
|
||||
import EventSetter from '../right/EventSetter.vue';
|
||||
import { IActionProperty, IProp } from 'src/types/ActionTypes';
|
||||
export default defineComponent({
|
||||
name: 'ActionProperty',
|
||||
components: {
|
||||
InputText,
|
||||
SelectBox,
|
||||
DatePicker,
|
||||
FieldInput
|
||||
FieldInput,
|
||||
EventSetter
|
||||
},
|
||||
props: {
|
||||
jsonData: {
|
||||
@@ -31,27 +33,43 @@ export default defineComponent({
|
||||
required: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
componentData() {
|
||||
return this.jsonData.elements.map((element: any) => {
|
||||
if(this.jsonValue != undefined )
|
||||
setup(props){
|
||||
const componentData=computed<Array<IActionProperty>>(()=>{
|
||||
return props.jsonData.elements.map((element: any) => {
|
||||
if(props.jsonValue != undefined )
|
||||
{
|
||||
if(this.jsonValue.hasOwnProperty(element.props.name))
|
||||
if(props.jsonValue.hasOwnProperty(element.props.name))
|
||||
{
|
||||
element.props.modelValue = this.jsonValue[element.props.name];
|
||||
element.props.modelValue = props.jsonValue[element.props.name];
|
||||
}
|
||||
else
|
||||
{
|
||||
element.props.modelValue = '';
|
||||
}
|
||||
|
||||
}
|
||||
return {
|
||||
component: element.component,
|
||||
props: element.props,
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
const connectProps=(props:IProp)=>{
|
||||
const connProps:any={};
|
||||
if(props && "connectProps" in props && props.connectProps!=undefined){
|
||||
for(let connProp of props.connectProps){
|
||||
let targetProp = componentData.value.find((prop)=>prop.props.name===connProp.propName);
|
||||
if(targetProp){
|
||||
connProps[connProp.key]=targetProp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return connProps;
|
||||
}
|
||||
|
||||
return{
|
||||
componentData,
|
||||
connectProps
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
80
frontend/src/components/right/EventSetter.vue
Normal file
80
frontend/src/components/right/EventSetter.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<q-input :label="displayName" v-model="inputValue" label-color="primary" :placeholder="placeholder" stack-label>
|
||||
<template v-slot:append>
|
||||
<q-btn round dense flat icon="add" @click="addButtonEvent()" />
|
||||
</template>
|
||||
</q-input>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent,ref,watchEffect } from 'vue';
|
||||
import { useFlowEditorStore } from '../../stores/flowEditor';
|
||||
import { IKintoneEventGroup,kintoneEvent } from 'src/types/KintoneEvents';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'EventSetter',
|
||||
props: {
|
||||
displayName:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
name:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
hint:{
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
connectProps:{
|
||||
type:Object,
|
||||
default:undefined
|
||||
}
|
||||
},
|
||||
|
||||
setup(props , { emit }) {
|
||||
const inputValue = ref(props.modelValue);
|
||||
const store = useFlowEditorStore();
|
||||
const addButtonEvent=()=>{
|
||||
const eventId =store.currentFlow?.getRoot()?.name;
|
||||
if(eventId===undefined){return;}
|
||||
let displayName = inputValue.value;
|
||||
if(props.connectProps!==undefined && "displayName" in props.connectProps){
|
||||
displayName =props.connectProps["displayName"].props.modelValue;
|
||||
}
|
||||
const customButtonId=`${eventId}.customButtonClick`;
|
||||
const findedEvent = store.eventTree.findEventById(customButtonId);
|
||||
if(findedEvent && "events" in findedEvent){
|
||||
const customEvents = findedEvent as IKintoneEventGroup;
|
||||
const addEventId = customButtonId+"." + inputValue.value;
|
||||
if(store.eventTree.findEventById(addEventId)){
|
||||
return;
|
||||
}
|
||||
customEvents.events.push(
|
||||
new kintoneEvent(
|
||||
displayName,
|
||||
addEventId,
|
||||
customButtonId)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
emit('update:modelValue', inputValue.value);
|
||||
});
|
||||
|
||||
return {
|
||||
inputValue,
|
||||
addButtonEvent
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-for="(item, index) in properties" :key="index" >
|
||||
<component :is="item.component" v-bind="item.props" v-model="item.props.modelValue"></component>
|
||||
<component :is="item.component" v-bind="item.props" :connectProps="connectProps(item.props)" v-model="item.props.modelValue"></component>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -17,7 +17,8 @@ import DatePicker from '../right/DatePicker.vue';
|
||||
import FieldInput from '../right/FieldInput.vue';
|
||||
import MuiltInputText from '../right/MuiltInputText.vue';
|
||||
import ConditionInput from '../right/ConditionInput.vue';
|
||||
import { IActionNode,IActionProperty } from 'src/types/ActionTypes';
|
||||
import EventSetter from '../right/EventSetter.vue';
|
||||
import { IActionNode,IActionProperty,IProp } from 'src/types/ActionTypes';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PropertyList',
|
||||
@@ -27,7 +28,8 @@ export default defineComponent({
|
||||
DatePicker,
|
||||
FieldInput,
|
||||
MuiltInputText,
|
||||
ConditionInput
|
||||
ConditionInput,
|
||||
EventSetter
|
||||
},
|
||||
props: {
|
||||
nodeProps: {
|
||||
@@ -40,9 +42,22 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
setup(props, context) {
|
||||
const properties=ref(props.nodeProps)
|
||||
const properties=ref(props.nodeProps);
|
||||
const connectProps=(props:IProp)=>{
|
||||
const connProps:any={};
|
||||
if(props && "connectProps" in props && props.connectProps!=undefined){
|
||||
for(let connProp of props.connectProps){
|
||||
let targetProp = properties.value.find((prop)=>prop.props.name===connProp.propName);
|
||||
if(targetProp){
|
||||
connProps[connProp.key]=targetProp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return connProps;
|
||||
}
|
||||
return {
|
||||
properties
|
||||
properties,
|
||||
connectProps
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { AppInfo ,IActionFlow, IActionNode} from 'src/types/ActionTypes';
|
||||
import { kintoneEvents,IKintoneEvent,KintoneEventManager } from 'src/types/KintoneEvents';
|
||||
import { IKintoneEvent,KintoneEventManager } from 'src/types/KintoneEvents';
|
||||
import {FlowCtrl } from '../control/flowctrl';
|
||||
|
||||
export interface FlowEditorState{
|
||||
@@ -14,6 +14,7 @@ export interface FlowEditorState{
|
||||
expandedScreen:any[];
|
||||
}
|
||||
const flowCtrl=new FlowCtrl();
|
||||
const eventTree = new KintoneEventManager();
|
||||
export const useFlowEditorStore = defineStore("flowEditor",{
|
||||
state: ():FlowEditorState => ({
|
||||
flowNames1: '',
|
||||
@@ -21,7 +22,7 @@ export const useFlowEditorStore = defineStore("flowEditor",{
|
||||
flows:[],
|
||||
selectedFlow:undefined,
|
||||
activeNode:undefined,
|
||||
eventTree:kintoneEvents,
|
||||
eventTree:eventTree,
|
||||
selectedEvent:undefined,
|
||||
expandedScreen:[]
|
||||
}),
|
||||
|
||||
@@ -26,6 +26,8 @@ export interface IProp{
|
||||
placeholder: string;
|
||||
//入力提示・説明
|
||||
hint:string;
|
||||
//関連属性リスト
|
||||
connectProps:[{key:string,propName:string}]|undefined;
|
||||
//プロパティ設定値
|
||||
modelValue: any;
|
||||
}
|
||||
@@ -109,6 +111,7 @@ class ActionProperty implements IActionProperty {
|
||||
displayName: displayName,
|
||||
placeholder: placeholder,
|
||||
hint:hint,
|
||||
connectProps:undefined,
|
||||
modelValue: modelValue
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,112 +1,197 @@
|
||||
import { publicDecrypt } from 'crypto';
|
||||
import {IActionFlow} from './ActionTypes';
|
||||
export interface TreeNode {
|
||||
export interface IKintoneEventNode {
|
||||
label: string;
|
||||
header:string;
|
||||
eventId:string;
|
||||
parentId:string;
|
||||
}
|
||||
|
||||
export interface IKintoneEvent extends TreeNode {
|
||||
eventId: string;
|
||||
export interface IKintoneEvent extends IKintoneEventNode {
|
||||
hasFlow: boolean;
|
||||
flowData?: IActionFlow;
|
||||
}
|
||||
|
||||
export interface IKintoneScreen extends TreeNode {
|
||||
label: string;
|
||||
events: IKintoneEvent[];
|
||||
export interface IKintoneEventGroup extends IKintoneEventNode {
|
||||
events: IKintoneEventNode[];
|
||||
}
|
||||
|
||||
|
||||
export class kintoneEvent implements IKintoneEvent{
|
||||
eventId: string;
|
||||
get hasFlow(): boolean{
|
||||
parentId:string;
|
||||
get hasFlow(): boolean{
|
||||
return this.flowData!==undefined && this.flowData.actionNodes.length>1
|
||||
};
|
||||
flowData?: IActionFlow | undefined;
|
||||
label: string;
|
||||
constructor({eventId,label}:{eventId:string,label:string}){
|
||||
get header():string{
|
||||
return "EVENT";
|
||||
}
|
||||
constructor(label:string,eventId:string,parentId:string){
|
||||
this.eventId=eventId;
|
||||
this.label=label;
|
||||
|
||||
this.parentId=parentId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class KintoneEventManager {
|
||||
public screens: IKintoneScreen[];
|
||||
export class kintoneEventGroup implements IKintoneEventGroup{
|
||||
eventId: string;
|
||||
parentId:string;
|
||||
label: string;
|
||||
events: IKintoneEventNode[];
|
||||
get header():string{
|
||||
return "EVENTGROUP";
|
||||
}
|
||||
constructor(eventId:string,label:string,events:IKintoneEventNode[],parentId:string){
|
||||
this.eventId=eventId;
|
||||
this.label=label;
|
||||
this.events=events;
|
||||
this.parentId=parentId;
|
||||
}
|
||||
}
|
||||
|
||||
constructor(screens: IKintoneScreen[]) {
|
||||
this.screens = screens;
|
||||
|
||||
export class kintoneEventForChange implements IKintoneEventGroup{
|
||||
eventId: string;
|
||||
parentId:string;
|
||||
label: string;
|
||||
events: IKintoneEventNode[];
|
||||
get header():string{
|
||||
return "CHANGE";
|
||||
}
|
||||
constructor(eventId:string,label:string,events:IKintoneEventNode[],parentId:string){
|
||||
this.eventId=eventId;
|
||||
this.label=label;
|
||||
this.events=events;
|
||||
this.parentId=parentId;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export class KintoneEventManager {
|
||||
public screens: IKintoneEventGroup[];
|
||||
|
||||
constructor() {
|
||||
this.screens = this.getKintoneEvents();
|
||||
}
|
||||
|
||||
public bindFlows(flows:IActionFlow[]){
|
||||
for (const screen of this.screens) {
|
||||
screen.events.forEach((ev)=>ev.flowData=undefined);
|
||||
}
|
||||
this.screens=this.getKintoneEvents();
|
||||
for (const flow of flows){
|
||||
const eventId =flow.getRoot()?.name;
|
||||
if(eventId!==undefined){
|
||||
const event = this.findEventById(eventId);
|
||||
if(event!==null){
|
||||
const eventNode = this.findEventById(eventId);
|
||||
if(eventNode!==null && eventNode.header==="EVENT"){
|
||||
const event =eventNode as kintoneEvent;
|
||||
event.flowData=flow;
|
||||
}else{
|
||||
//EventGroupのIDを取得
|
||||
const lastIndex = eventId.lastIndexOf(".");
|
||||
const groupId=eventId.substring(0,lastIndex);
|
||||
const eventNode = this.findEventById(groupId);
|
||||
if(eventNode && (eventNode.header==="EVENTGROUP" || eventNode.header==="CHANGE")){
|
||||
const groupEvent=eventNode as kintoneEventGroup;
|
||||
const newEvent =new kintoneEvent(
|
||||
flow.getRoot()?.subTitle || "",
|
||||
eventId,
|
||||
groupEvent.parentId
|
||||
);
|
||||
newEvent.flowData=flow;
|
||||
groupEvent.events.push(newEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public findEventById(eventId: string): IKintoneEvent | null {
|
||||
public findEventById(eventId: string): IKintoneEventNode | null {
|
||||
const screen=this.findScreen(eventId);
|
||||
if(screen) {return screen;}
|
||||
for (const screen of this.screens) {
|
||||
for (const event of screen.events) {
|
||||
if (event.eventId === eventId) {
|
||||
return event;
|
||||
}
|
||||
if (event.eventId === eventId) {
|
||||
return event;
|
||||
}
|
||||
if(event.header==="EVENTGROUP"||event.header==="CHANGE"){
|
||||
const eventGroup = event as IKintoneEventGroup;
|
||||
const targetEvent = eventGroup.events.find((ev)=>{
|
||||
return ev.eventId===eventId;
|
||||
})
|
||||
if(targetEvent){
|
||||
return targetEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public findScreen(eventId:string):IKintoneScreen|null{
|
||||
for (const screen of this.screens) {
|
||||
if(screen.events.some((ev:IKintoneEvent)=>ev.eventId===eventId)){
|
||||
return screen;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
public findScreen(eventId:string):IKintoneEventGroup|undefined{
|
||||
return this.screens.find(screen=>screen.eventId==eventId);
|
||||
}
|
||||
|
||||
public getKintoneEvents():IKintoneEventGroup[]{
|
||||
return [
|
||||
new kintoneEventGroup("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 kintoneEventForChange('app.record.create.change','フィールドの値を変更したとき',[],"app.record.create"),
|
||||
new kintoneEventGroup('app.record.create.show.customButtonClick','ボタンをクリックした時',[],"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"),
|
||||
],"")
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export const kintoneEvents:KintoneEventManager = new KintoneEventManager([
|
||||
{
|
||||
label:'レコード追加画面',
|
||||
events:[
|
||||
new kintoneEvent({label:'レコード追加画面を表示した後',eventId:'app.record.create.show'}),
|
||||
new kintoneEvent({label:'保存をクリックしたとき',eventId:'app.record.create.submit'}),
|
||||
new kintoneEvent({label:'保存が成功したとき',eventId:'app.record.create.submit.success'}),
|
||||
new kintoneEvent({label:'フィールドの値を変更したとき',eventId:'app.record.create.change'}),
|
||||
]
|
||||
},
|
||||
{
|
||||
label:'レコード詳細画面',
|
||||
events:[
|
||||
new kintoneEvent({label:'レコード詳細画面を表示した後',eventId:'app.record.detail.show'}),
|
||||
new kintoneEvent({label:'レコードを削除するとき',eventId:'app.record.detail.delete.submit'}),
|
||||
new kintoneEvent({label:'プロセス管理のアクションを実行したとき',eventId:'app.record.detail.process.proceed'}),
|
||||
]
|
||||
},
|
||||
{
|
||||
label:'レコード編集画面',
|
||||
events:[new kintoneEvent({label:'レコード編集画面を表示した後',eventId:'app.record.edit.show'}),
|
||||
new kintoneEvent({label:'保存をクリックしたとき',eventId:'app.record.edit.submit'}),
|
||||
new kintoneEvent({label:'保存が成功したとき',eventId:'app.record.edit.submit.success'}),
|
||||
new kintoneEvent({label:'フィールドの値を変更したとき',eventId:'app.record.edit.change'}),
|
||||
]
|
||||
},
|
||||
{
|
||||
label:'レコード一覧画面',
|
||||
events:[
|
||||
new kintoneEvent({label:'一覧画面を表示した後', eventId:'app.record.index.show'}),
|
||||
new kintoneEvent({label:'インライン編集を開始したとき',eventId:'app.record.index.edit.show'}),
|
||||
new kintoneEvent({label:'インライン編集のフィールド値を変更したとき', eventId:'app.record.index.edit.change'}),
|
||||
new kintoneEvent({label:'インライン編集の【保存】をクリックしたとき',eventId:'app.record.index.edit.submit'}),
|
||||
new kintoneEvent({label:'インライン編集の保存が成功したとき', eventId:'app.record.index.edit.submit.success'}),
|
||||
]
|
||||
}
|
||||
]);
|
||||
// export const kintoneEvents:KintoneEventManager = new KintoneEventManager([
|
||||
// new kintoneEventGroup("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 kintoneEventForChange('app.record.create.change','フィールドの値を変更したとき',[],"app.record.create"),
|
||||
// new kintoneEventGroup('app.record.create.customButtonClick','ボタンをクリックした時',[],"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.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.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.customButtonClick','ボタンをクリックした時',[],"app.record.index"),
|
||||
// ],"")
|
||||
// ]);
|
||||
|
||||
107
plugin/kintone-addins/src/actions/button-add.ts
Normal file
107
plugin/kintone-addins/src/actions/button-add.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
|
||||
import { actionAddins } from ".";
|
||||
import $ from 'jquery';
|
||||
import { IAction, IActionProperty, IActionNode, IActionResult } from "../types/ActionTypes";
|
||||
/**
|
||||
* ボタン配置属性定義
|
||||
*/
|
||||
interface IButtonAddProps {
|
||||
//ボタン表示名
|
||||
buttonName: string;
|
||||
//配置位置
|
||||
position: string;
|
||||
//イベント名
|
||||
eventName:string
|
||||
}
|
||||
|
||||
export class ButtonAddAction implements IAction {
|
||||
name: string;
|
||||
actionProps: IActionProperty[];
|
||||
props: IButtonAddProps;
|
||||
constructor() {
|
||||
this.name = "ボタンの配置";
|
||||
this.actionProps = [];
|
||||
this.props = {
|
||||
buttonName: '',
|
||||
position: '',
|
||||
eventName:''
|
||||
}
|
||||
this.register();
|
||||
}
|
||||
|
||||
/**
|
||||
* アクションの実行を呼び出す
|
||||
* @param actionNode
|
||||
* @param event
|
||||
* @returns
|
||||
*/
|
||||
async process(actionNode: IActionNode, event: any): Promise<IActionResult> {
|
||||
let result = {
|
||||
canNext: true,
|
||||
result: false
|
||||
};
|
||||
try {
|
||||
this.actionProps = actionNode.actionProps;
|
||||
if (!('buttonName' in actionNode.ActionValue) && !('position' in actionNode.ActionValue)) {
|
||||
return result
|
||||
}
|
||||
this.props = actionNode.ActionValue as IButtonAddProps;
|
||||
//ボタンを配置する
|
||||
const menuSpace = kintone.app.record.getHeaderMenuSpaceElement();
|
||||
if(!menuSpace) return result;
|
||||
if($("style#alc-button-add").length===0){
|
||||
const css=`
|
||||
.alc-button-normal {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
padding: 0 16px;
|
||||
margin-left: 16px;
|
||||
margin-top: 8px;
|
||||
min-width: 100px;
|
||||
outline: none;
|
||||
border: 1px solid #e3e7e8;
|
||||
background-color: #f7f9fa;
|
||||
box-shadow: 1px 1px 1px #fff inset;
|
||||
color: #3498db;
|
||||
text-align: center;
|
||||
line-height: 32px;
|
||||
}
|
||||
.alc-button-normal:hover {
|
||||
background-color: #c8d6dd;
|
||||
box-shadow: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.alc-button-normal:active {
|
||||
color: #f7f9fa;
|
||||
background-color: #54b8eb;
|
||||
}`;
|
||||
const style = $("<style id='alc-button-add'>/<style>");
|
||||
style.text(css);
|
||||
$("head").append(style);
|
||||
}
|
||||
const button =$(`<button id='${this.props.eventName}' class='alc-button-normal' >${this.props.buttonName}</button>`);
|
||||
if(this.props.position==="一番左に追加する"){
|
||||
$(menuSpace).prepend(button);
|
||||
}else{
|
||||
$(menuSpace).append(button);
|
||||
}
|
||||
const clickEventName = `${event.type}.customButtonClick.${this.props.eventName}`;
|
||||
button.on("click",()=>{
|
||||
$(document).trigger(clickEventName,event);
|
||||
});
|
||||
return result;
|
||||
} catch (error) {
|
||||
event.error = error;
|
||||
console.error(error);
|
||||
result.canNext = false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
register(): void {
|
||||
actionAddins[this.name] = this;
|
||||
}
|
||||
|
||||
}
|
||||
new ButtonAddAction();
|
||||
@@ -31,7 +31,7 @@ export class ErrorShowAction implements IAction {
|
||||
* @returns
|
||||
*/
|
||||
async process(actionNode: IActionNode, event: any, context: IContext): Promise<IActionResult> { //异步处理某函数下的:xx属性
|
||||
let result = { //定义一个能否继续往下实行的开关
|
||||
let result = {
|
||||
canNext: true,
|
||||
result: false
|
||||
};
|
||||
@@ -40,10 +40,10 @@ export class ErrorShowAction implements IAction {
|
||||
if (!('message' in actionNode.ActionValue) && !('condition' in actionNode.ActionValue)) { //如果message以及condition两者都不存在的情况下return
|
||||
return result
|
||||
}
|
||||
this.props = actionNode.ActionValue as IErrorShowProps; //将TS的action.actionvalue as转换为interface需要且定义的js部分
|
||||
this.props = actionNode.ActionValue as IErrorShowProps;
|
||||
const conditionResult = this.getConditionResult(context);
|
||||
if (conditionResult) {
|
||||
event.error = this.props.message
|
||||
event.error = this.props.message;
|
||||
} else {
|
||||
result = {
|
||||
canNext: false,
|
||||
|
||||
@@ -14,14 +14,58 @@ declare const alcflow : {
|
||||
};
|
||||
|
||||
$(function (){
|
||||
const getChangeEvents=(events:string[])=>{
|
||||
return events.filter((event)=>event.includes(".change."));
|
||||
}
|
||||
const getClickEvents=(events:string[])=>{
|
||||
return events.filter((event)=>event.includes(".customButtonClick."));
|
||||
}
|
||||
const getKintoneEvents=(events:string[])=>{
|
||||
return events.filter((event)=>{
|
||||
return !event.includes(".customButtonClick.") && !event.includes(".change.")
|
||||
});
|
||||
}
|
||||
const events=Object.keys(alcflow);
|
||||
kintone.events.on(events,async (event:any)=>{
|
||||
const flowinfo = alcflow[event.type];
|
||||
const flow=ActionFlow.fromJSON(flowinfo.content);
|
||||
if(flow!==undefined){
|
||||
const process = new ActionProcess(event.type,flow,event);
|
||||
await process.exec();
|
||||
}
|
||||
return event;
|
||||
});
|
||||
const changeEvents = getChangeEvents(events);
|
||||
const clickEvents = getClickEvents(events);
|
||||
const kintoneEvents = getKintoneEvents(events);
|
||||
if(kintoneEvents.length>0 ){
|
||||
//通常Kintoneイベントをバンド
|
||||
kintone.events.on(kintoneEvents,async (event:any)=>{
|
||||
const flowinfo = alcflow[event.type];
|
||||
const flow=ActionFlow.fromJSON(flowinfo.content);
|
||||
if(flow!==undefined){
|
||||
const process = new ActionProcess(event.type,flow,event);
|
||||
await process.exec();
|
||||
}
|
||||
return event;
|
||||
});
|
||||
}
|
||||
if(changeEvents.length>0){
|
||||
//値変更イベントをバンドする
|
||||
kintone.events.on(changeEvents,(event:any)=>{
|
||||
const flowinfo = alcflow[event.type];
|
||||
const flow=ActionFlow.fromJSON(flowinfo.content);
|
||||
if(flow!==undefined){
|
||||
const process = new ActionProcess(event.type,flow,event);
|
||||
process.exec();
|
||||
}
|
||||
return event;
|
||||
});
|
||||
}
|
||||
if(clickEvents.length>0){
|
||||
clickEvents.forEach((eventName:string)=>{
|
||||
$(document).on(eventName,async ()=>{
|
||||
const event=kintone.app.record.get();
|
||||
const flowinfo = alcflow[eventName];
|
||||
const flow=ActionFlow.fromJSON(flowinfo.content);
|
||||
if(flow!==undefined){
|
||||
const process = new ActionProcess(eventName,flow,event);
|
||||
await process.exec();
|
||||
}
|
||||
const record = event.record;
|
||||
kintone.app.record.set({record})
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -257,7 +257,7 @@ export class ActionFlow implements IActionFlow {
|
||||
const actionNodes = parsedObject.actionNodes.map((node: any) => {
|
||||
const nodeClass = !node.isRoot ? new ActionNode(node)
|
||||
: new RootAction(node);
|
||||
nodeClass.nextNodeIds = new Map(node.nextNodeIds);
|
||||
nodeClass.nextNodeIds = new Map<string,string>(Object.entries(node.nextNodeIds));
|
||||
nodeClass.prevNodeId = node.prevNodeId;
|
||||
nodeClass.id = node.id;
|
||||
return nodeClass;
|
||||
|
||||
@@ -324,7 +324,7 @@ export class ConditionTree {
|
||||
*/
|
||||
getObjectValue(object:any,context:IContext){
|
||||
if(!object || typeof object!=="object" || !("objectType" in object)){
|
||||
return object;
|
||||
return undefined;
|
||||
}
|
||||
if(object.objectType==='field'){
|
||||
const fieldValue = context.record[object.code];
|
||||
@@ -402,6 +402,12 @@ export class ConditionTree {
|
||||
*/
|
||||
compare(operator: Operator, targetValue: any, value: any): boolean {
|
||||
// targetValue は日期时,value も日期に変換して比較する
|
||||
if(targetValue===undefined || targetValue===null||targetValue===''){
|
||||
if(value===undefined || value===null||value===''){
|
||||
targetValue='';
|
||||
value='';
|
||||
}
|
||||
}
|
||||
if (targetValue instanceof Date) {
|
||||
const dateValue = new Date(value);
|
||||
if (!isNaN(dateValue.getTime())) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import '../actions/must-input';
|
||||
import '../actions/auto-numbering';
|
||||
import '../actions/field-shown';
|
||||
import '../actions/error-show';
|
||||
import '../actions/button-add';
|
||||
import { ActionFlow,IActionFlow, IActionResult,IContext } from "./ActionTypes";
|
||||
|
||||
export class ActionProcess{
|
||||
|
||||
202
sample2.json
202
sample2.json
@@ -1,167 +1,37 @@
|
||||
{
|
||||
"id": "e4929dfe-32bb-448a-bd66-83c19dad9c79",
|
||||
"actionNodes": [
|
||||
{
|
||||
"id": "06388b74-ef56-4ba2-9fba-2dbde999c34d",
|
||||
"name": "app.record.create.submit",
|
||||
"title": "レコード追加画面",
|
||||
"subTitle": "保存をクリックしたとき",
|
||||
"inputPoint": "",
|
||||
"outputPoints": [],
|
||||
"isRoot": true,
|
||||
"actionProps": [],
|
||||
"ActionValue": {},
|
||||
"nextNodeIds": {
|
||||
"": "5963b63a-bfea-49d0-9a8e-b57abe99e2a7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "5963b63a-bfea-49d0-9a8e-b57abe99e2a7",
|
||||
"name": "自動採番する",
|
||||
"inputPoint": "",
|
||||
"outputPoints": [],
|
||||
"actionProps": [
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"name": "displayName",
|
||||
"displayName": "表示名",
|
||||
"placeholder": "表示を入力してください",
|
||||
"hint": "",
|
||||
"modelValue": "文書番号を自動採番する"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "FieldInput",
|
||||
"props": {
|
||||
"displayName": "採番項目",
|
||||
"modelValue": {},
|
||||
"name": "field",
|
||||
"placeholder": "採番項目を選択してください"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"displayName": "フォーマット",
|
||||
"modelValue": "000000",
|
||||
"name": "format",
|
||||
"placeholder": "数値書式文字列を指定します"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"displayName": "前につける文字列",
|
||||
"modelValue": "",
|
||||
"name": "prefix",
|
||||
"placeholder": "前につける文字列を入力してください"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"displayName": "後ろにつける文字列",
|
||||
"modelValue": "",
|
||||
"name": "suffix",
|
||||
"placeholder": "後ろにつける文字列を入力してください"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"displayName": "結果(戻り値)",
|
||||
"modelValue": "DocumentNo",
|
||||
"name": "verName",
|
||||
"placeholder": "変数名を入力してください"
|
||||
}
|
||||
}
|
||||
],
|
||||
"prevNodeId": "06388b74-ef56-4ba2-9fba-2dbde999c34d",
|
||||
"nextNodeIds": {
|
||||
"": "f1fb6e7c-540c-4fcc-8d30-bd22aed7f923"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "f1fb6e7c-540c-4fcc-8d30-bd22aed7f923",
|
||||
"name": "条件式",
|
||||
"inputPoint": "",
|
||||
"outputPoints": [
|
||||
"はい",
|
||||
"いいえ"
|
||||
],
|
||||
"actionProps": [
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"name": "displayName",
|
||||
"displayName": "表示名",
|
||||
"placeholder": "表示を入力してください",
|
||||
"hint": "",
|
||||
"modelValue": "条件式を設定する"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "ConditionInput",
|
||||
"props": {
|
||||
"displayName": "条件",
|
||||
"modelValue": "{\"index\":0,\"type\":\"root\",\"children\":[{\"index\":1,\"type\":\"condition\",\"parent\":\"root\",\"object\":{\"name\":\"ステータス\",\"objectType\":\"field\",\"type\":\"STATUS\",\"code\":\"ステータス\",\"label\":\"ステータス\",\"enabled\":true},\"operator\":\"=\",\"value\":\"作成中\"},{\"index\":2,\"type\":\"condition\",\"parent\":\"root\",\"object\":{\"name\":\"部署\",\"objectType\":\"field\",\"type\":\"DROP_DOWN\",\"code\":\"ドロップダウン\",\"label\":\"部署\",\"noLabel\":false,\"required\":false,\"options\":{\"総務\":{\"label\":\"総務\",\"index\":\"2\"},\"サポート\":{\"label\":\"サポート\",\"index\":\"3\"},\"マーケティング\":{\"label\":\"マーケティング\",\"index\":\"1\"},\"営業\":{\"label\":\"営業\",\"index\":\"0\"},\"開発\":{\"label\":\"開発\",\"index\":\"4\"}},\"defaultValue\":\"\"},\"operator\":\"!=\",\"value\":\"\"},{\"index\":4,\"type\":\"condition\",\"parent\":\"root\",\"object\":{\"objectType\":\"variable\",\"actionName\":\"自動採番する\",\"displayName\":\"結果(戻り値)\",\"name\":\"DocumentNo\"},\"operator\":\"=\",\"value\":\"\"}],\"parent\":null,\"logicalOperator\":\"AND\"}",
|
||||
"name": "condition",
|
||||
"placeholder": "条件式を設定してください"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"displayName": "結果(戻り値)",
|
||||
"modelValue": "conditionValue",
|
||||
"name": "verName",
|
||||
"placeholder": "変数名を入力してください"
|
||||
}
|
||||
}
|
||||
],
|
||||
"prevNodeId": "5963b63a-bfea-49d0-9a8e-b57abe99e2a7",
|
||||
"nextNodeIds": {
|
||||
"いいえ": "81987177-746f-44f2-8cd5-acf52ebb83bb"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "81987177-746f-44f2-8cd5-acf52ebb83bb",
|
||||
"name": "エラー表示",
|
||||
"inputPoint": "いいえ",
|
||||
"outputPoints": [],
|
||||
"actionProps": [
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"name": "displayName",
|
||||
"displayName": "表示名",
|
||||
"placeholder": "表示を入力してください",
|
||||
"hint": "",
|
||||
"modelValue": "入力した内容が不適切な場合"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "ConditionInput",
|
||||
"props": {
|
||||
"displayName": "条件",
|
||||
"modelValue": "{\"index\":0,\"type\":\"root\",\"children\":[{\"index\":1,\"type\":\"condition\",\"parent\":\"root\",\"object\":{\"objectType\":\"variable\",\"actionName\":\"条件式\",\"displayName\":\"結果(戻り値)\",\"name\":\"conditionValue\"},\"operator\":\"=\",\"value\":\"いいえ\"}],\"parent\":null,\"logicalOperator\":\"AND\"}",
|
||||
"name": "condition",
|
||||
"placeholder": "条件を選択または入力してください"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "MuiltInputText",
|
||||
"props": {
|
||||
"displayName": "エラーメッセージ",
|
||||
"modelValue": "",
|
||||
"name": "message",
|
||||
"placeholder": "エラーメッセージを入力してください"
|
||||
}
|
||||
}
|
||||
],
|
||||
"prevNodeId": "f1fb6e7c-540c-4fcc-8d30-bd22aed7f923",
|
||||
"nextNodeIds": {}
|
||||
[
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"displayName": "ボタン名",
|
||||
"modelValue": "",
|
||||
"name": "buttonName",
|
||||
"placeholder": "ボタンのラベルを入力してください"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "SelectBox",
|
||||
"props": {
|
||||
"displayName": "追加位置",
|
||||
"modelValue": "",
|
||||
"name": "position",
|
||||
"options":[
|
||||
"一番右に追加する",
|
||||
"一番左に追加する"
|
||||
],
|
||||
"placeholder": "追加位置を選択してください"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "EventSetter",
|
||||
"props": {
|
||||
"displayName": "イベント名",
|
||||
"modelValue": "",
|
||||
"name": "eventName",
|
||||
"connectProps":[{
|
||||
"key":"displayName",
|
||||
"propName":"buttonName"
|
||||
}],
|
||||
"placeholder": "イベント名を入力してください"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user