DB連動実装
This commit is contained in:
@@ -3,6 +3,7 @@ from app.db import Base,engine
|
||||
from app.db.session import get_db
|
||||
from app.db.crud import *
|
||||
from app.db.schemas import *
|
||||
from typing import List
|
||||
|
||||
platform_router = r = APIRouter()
|
||||
|
||||
@@ -91,7 +92,21 @@ async def flow_details(
|
||||
):
|
||||
app = get_flow(db, flowid)
|
||||
return app
|
||||
|
||||
|
||||
|
||||
@r.get(
|
||||
"/flows/{appid}",
|
||||
response_model=List[Flow],
|
||||
response_model_exclude_none=True,
|
||||
)
|
||||
async def flow_list(
|
||||
request: Request,
|
||||
appid: str,
|
||||
db=Depends(get_db),
|
||||
):
|
||||
flows = get_flows_by_app(db, appid)
|
||||
return flows
|
||||
|
||||
|
||||
@r.post("/flow", response_model=Flow, response_model_exclude_none=True)
|
||||
async def flow_create(
|
||||
|
||||
@@ -173,4 +173,10 @@ def get_flow(db: Session, flowid: str):
|
||||
flow = db.query(models.Flow).filter(models.Flow.flowid == flowid).first()
|
||||
if not flow:
|
||||
raise HTTPException(status_code=404, detail="Data not found")
|
||||
return flow
|
||||
return flow
|
||||
|
||||
def get_flows_by_app(db: Session, appid: str):
|
||||
flows = db.query(models.Flow).filter(models.Flow.appid == appid).all()
|
||||
if not flows:
|
||||
raise HTTPException(status_code=404, detail="Data not found")
|
||||
return flows
|
||||
BIN
document/kintone開発自動化ツール UIデザイン案.pptx
Normal file
BIN
document/kintone開発自動化ツール UIデザイン案.pptx
Normal file
Binary file not shown.
@@ -1,6 +1,12 @@
|
||||
<template>
|
||||
<div class="q-pa-md">
|
||||
<q-table :title="name+'一覧'" row-key="name" :selection="type" v-model:selected="selected" :columns="columns" :rows="rows" />
|
||||
<q-table row-key="name" :selection="type" v-model:selected="selected" :columns="columns" :rows="rows"
|
||||
class="action-table"
|
||||
flat bordered
|
||||
virtual-scroll
|
||||
:pagination="pagination"
|
||||
:rows-per-page-options="[0]"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@@ -17,11 +23,11 @@ export default {
|
||||
const columns = [
|
||||
{ name: 'name', required: true,label: 'アクション名',align: 'left',field: 'name',sortable: true},
|
||||
{ name: 'desc', align: 'left', label: '説明', field: 'desc', sortable: true },
|
||||
{ name: 'content', label: '内容', field: 'content', sortable: true }
|
||||
// { name: 'content', label: '内容', field: 'content', sortable: true }
|
||||
]
|
||||
const rows = reactive([])
|
||||
onMounted(async () => {
|
||||
await api.get('http://127.0.0.1:8000/api/kintone/2').then(res =>{
|
||||
await api.get('http://127.0.0.1:8000/api/kintone/1').then(res =>{
|
||||
res.data.forEach((item) =>
|
||||
{
|
||||
rows.push({name:item.name,desc:item.desc,content:item.content});
|
||||
@@ -33,8 +39,16 @@ export default {
|
||||
columns,
|
||||
rows,
|
||||
selected: ref([]),
|
||||
pagination:ref({
|
||||
rowsPerPage:0
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.action-table{
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
50
frontend/src/components/left/AppSelector.vue
Normal file
50
frontend/src/components/left/AppSelector.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<div
|
||||
class="row"
|
||||
style="
|
||||
border-radius: 2px;
|
||||
box-shadow: rgba(255, 255, 255, 0.1) 0px 0px 0px 1px inset,
|
||||
rgba(0, 0, 0, 0.3) 0px 0px 0px 1px;
|
||||
">
|
||||
<q-icon
|
||||
class="self-center q-ma-sm"
|
||||
name="widgets"
|
||||
color="grey-9"
|
||||
style="font-size: 2em"
|
||||
/>
|
||||
|
||||
<div class="col-7 self-center ellipsis">
|
||||
{{ selectedApp.name }}
|
||||
</div>
|
||||
|
||||
<div class="self-center">
|
||||
<q-btn
|
||||
outline
|
||||
dense
|
||||
label="変 更"
|
||||
padding="none sm"
|
||||
color="primary"
|
||||
></q-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent,ref } from 'vue';
|
||||
import {AppInfo} from '../../types/ActionTypes'
|
||||
export default defineComponent({
|
||||
name: 'AppSelector',
|
||||
emits:[
|
||||
"appSelected"
|
||||
],
|
||||
setup(props, context) {
|
||||
const selectedApp =ref<AppInfo>({
|
||||
appId:"",
|
||||
name:"",
|
||||
});
|
||||
return {
|
||||
selectedApp
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
72
frontend/src/components/left/EventTree.vue
Normal file
72
frontend/src/components/left/EventTree.vue
Normal file
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div class="q-pa-md q-gutter-sm">
|
||||
<q-tree
|
||||
:nodes="eventTree.screens"
|
||||
node-key="label"
|
||||
children-key="events"
|
||||
no-connectors
|
||||
v-model:expanded="expanded"
|
||||
:dense="true"
|
||||
>
|
||||
<template v-slot:default-header="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"
|
||||
:color="prop.node.hasFlow?'green':'grey'"
|
||||
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>
|
||||
</div>
|
||||
</template>
|
||||
</q-tree>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, ref } from 'vue';
|
||||
import { kintoneEvents,KintoneEvent } from '../../types/KintoneEvents';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||
export default defineComponent({
|
||||
name: 'EventTree',
|
||||
setup(props, context) {
|
||||
const store = useFlowEditorStore();
|
||||
const eventTree=ref(kintoneEvents);
|
||||
const selectedFlow = store.currentFlow;
|
||||
|
||||
const expanded=ref([
|
||||
selectedFlow?.getRoot()?.title
|
||||
]);
|
||||
const selectedEvent = ref<KintoneEvent|null>(null);
|
||||
const onSelected=(node:KintoneEvent)=>{
|
||||
if(!node.eventId){
|
||||
return;
|
||||
}
|
||||
selectedEvent.value=node;
|
||||
}
|
||||
return {
|
||||
eventTree,
|
||||
expanded,
|
||||
onSelected,
|
||||
selectedEvent,
|
||||
store
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.nowrap{
|
||||
flex-wrap:nowarp;
|
||||
text-wrap:nowarp;
|
||||
}
|
||||
.event-node{
|
||||
cursor:pointer;
|
||||
}
|
||||
.selected-node{
|
||||
color: $primary;
|
||||
font-weight: bolder;
|
||||
}
|
||||
.event-node:hover{
|
||||
background-color: $light-blue-1;
|
||||
}
|
||||
</style>
|
||||
@@ -1,8 +1,23 @@
|
||||
import { api } from 'boot/axios';
|
||||
import { ActionFlow } from 'src/types/ActionTypes';
|
||||
|
||||
export class FlowCtrl
|
||||
{
|
||||
|
||||
async getFlows(appId:string):Promise<ActionFlow[]>
|
||||
{
|
||||
const result = await api.get(`http://127.0.0.1:8000/api/flows/${appId}`);
|
||||
//console.info(result.data);
|
||||
if(!result.data || !Array.isArray(result.data)){
|
||||
return [];
|
||||
}
|
||||
const flows:ActionFlow[]=[];
|
||||
for(const flow of result.data){
|
||||
flows.push(ActionFlow.fromJSON(flow.content));
|
||||
}
|
||||
return flows;
|
||||
}
|
||||
|
||||
async SaveFlow(jsonData:any):Promise<boolean>
|
||||
{
|
||||
const result = await api.post('http://127.0.0.1:8000/api/flow',jsonData);
|
||||
|
||||
165
frontend/src/pages/FlowChart.vue
Normal file
165
frontend/src/pages/FlowChart.vue
Normal file
@@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<div class="q-pa-md q-gutter-sm event-tree">
|
||||
<q-drawer
|
||||
side="left"
|
||||
overlay
|
||||
bordered
|
||||
v-model="drawerLeft"
|
||||
:show-if-above="false"
|
||||
elevated
|
||||
>
|
||||
<!-- <q-card class="column full-height" style="width: 300px">
|
||||
<q-card-section> -->
|
||||
|
||||
<div class="flex-center fixd-top" >
|
||||
<AppSelector />
|
||||
</div>
|
||||
|
||||
<!-- </q-card-section> -->
|
||||
<q-separator />
|
||||
<!-- <q-card-section> -->
|
||||
<div class="flex-center">
|
||||
<EventTree />
|
||||
</div>
|
||||
<!-- </q-card-section> -->
|
||||
<!-- </q-card> -->
|
||||
</q-drawer>
|
||||
</div>
|
||||
|
||||
<q-page>
|
||||
<div class="q-pa-md q-gutter-sm">
|
||||
<!-- <q-layout
|
||||
container
|
||||
class="flow-container shadow-2 rounded-borders"
|
||||
> -->
|
||||
|
||||
<div class="flowchart" v-if="store.currentFlow">
|
||||
<node-item v-for="(node,) in store.currentFlow.actionNodes" :key="node.id"
|
||||
:isSelected="node===state.activeNode" :actionNode="node"
|
||||
@addNode="addNode"
|
||||
@nodeSelected="onNodeSelected"
|
||||
@nodeEdit="onNodeEdit"
|
||||
@deleteNode="onDeleteNode"
|
||||
@deleteAllNextNodes="onDeleteAllNextNodes"
|
||||
></node-item>
|
||||
</div>
|
||||
<!-- </q-layout> -->
|
||||
</div>
|
||||
</q-page>
|
||||
<PropertyPanel :actionNode="state.activeNode" v-model:drawerRight="drawerRight"></PropertyPanel>
|
||||
<show-dialog v-model:visible="showAddAction" name="アクション" @close="closeDg">
|
||||
<action-select ref="appDg" name="アクション" type="single"></action-select>
|
||||
</show-dialog>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref,reactive,computed,onMounted} from 'vue';
|
||||
import {IActionNode, ActionNode, IActionFlow, ActionFlow,RootAction, IActionProperty } from 'src/types/ActionTypes';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||
import NodeItem from 'src/components/main/NodeItem.vue';
|
||||
import ShowDialog from 'components/ShowDialog.vue';
|
||||
import ActionSelect from 'components/ActionSelect.vue';
|
||||
import PropertyPanel from 'components/right/PropertyPanel.vue';
|
||||
import AppSelector from 'components/left/AppSelector.vue';
|
||||
import EventTree from 'components/left/EventTree.vue';
|
||||
import {FlowCtrl } from '../control/flowctrl'
|
||||
const drawerLeft = ref(true);
|
||||
|
||||
const store = useFlowEditorStore();
|
||||
// ref関数を使ってtemplateとバインド
|
||||
const state=reactive({
|
||||
activeNode:{
|
||||
id:""
|
||||
},
|
||||
})
|
||||
const appDg = ref();
|
||||
const prevNodeIfo=ref({
|
||||
prevNode:{},
|
||||
inputPoint:""
|
||||
});
|
||||
const refFlow = ref<ActionFlow|null>(null);
|
||||
const showAddAction=ref(false);
|
||||
const drawerRight=ref(false);
|
||||
|
||||
const addActionNode=(action:IActionNode)=>{
|
||||
// refFlow.value?.actionNodes.push(action);
|
||||
store.currentFlow?.actionNodes.push(action);
|
||||
}
|
||||
|
||||
const addNode=(node:IActionNode,inputPoint:string)=>{
|
||||
showAddAction.value=true;
|
||||
prevNodeIfo.value.prevNode=node;
|
||||
prevNodeIfo.value.inputPoint=inputPoint;
|
||||
}
|
||||
|
||||
const onNodeSelected=(node:IActionNode)=>{
|
||||
//右パネルが開いている場合、自動閉じる
|
||||
if(drawerRight.value && state.activeNode.id!==node.id){
|
||||
drawerRight.value=false;
|
||||
}
|
||||
state.activeNode = node;
|
||||
}
|
||||
|
||||
const onNodeEdit=(node:IActionNode)=>{
|
||||
state.activeNode = node;
|
||||
drawerRight.value=true;
|
||||
}
|
||||
|
||||
const onDeleteNode=(node:IActionNode)=>{
|
||||
if(!store.currentFlow) return;
|
||||
store.currentFlow?.removeNode(node);
|
||||
}
|
||||
|
||||
const onDeleteAllNextNodes=(node:IActionNode)=>{
|
||||
if(!store.currentFlow) return;
|
||||
store.currentFlow?.removeAllNext(node.id);
|
||||
}
|
||||
const closeDg=(val :any)=>{
|
||||
console.log("Dialog closed->",val);
|
||||
if (val == 'OK') {
|
||||
const data = appDg.value.selected[0];
|
||||
const actionProps=JSON.parse(data.content);
|
||||
const action = new ActionNode(data.name,data.desc,"",[],actionProps);
|
||||
store.currentFlow?.addNode(action, prevNodeIfo.value.prevNode,prevNodeIfo.value.inputPoint);
|
||||
}
|
||||
}
|
||||
|
||||
const fetchData= async ()=>{
|
||||
const flowCtrl = new FlowCtrl();
|
||||
const actionFlows = await flowCtrl.getFlows("1");
|
||||
if(actionFlows && actionFlows.length>0){
|
||||
store.setFlows(actionFlows);
|
||||
}
|
||||
if(actionFlows && actionFlows.length==1){
|
||||
store.selectFlow(actionFlows[0]);
|
||||
}
|
||||
refFlow.value=actionFlows[0];
|
||||
const root =refFlow.value.getRoot();
|
||||
if(root){
|
||||
state.activeNode=root;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.flowchart{
|
||||
padding-top: 10px;
|
||||
}
|
||||
.flow-toolbar{
|
||||
opacity: 50%;
|
||||
}
|
||||
.flow-container{
|
||||
height: 91.5dvb;
|
||||
overflow: hidden;
|
||||
}
|
||||
.event-tree .q-drawer {
|
||||
top:50px;
|
||||
z-index: 999;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<q-page>
|
||||
|
||||
<div class="flowchart">
|
||||
<node-item v-for="(node,) in refFlow.actionNodes" :key="node.id"
|
||||
:isSelected="node===state.activeNode" :actionNode="node"
|
||||
@@ -46,7 +47,6 @@ const saibanProps:IActionProperty[]=[{
|
||||
}
|
||||
}];
|
||||
|
||||
|
||||
actionFlow.addNode(new ActionNode('自動採番','文書番号を自動採番する','',[],saibanProps));
|
||||
actionFlow.addNode(new ActionNode('入力データ取得','電話番号を取得する',''));
|
||||
const branchNode = actionFlow.addNode(new ActionNode('条件分岐','電話番号入力形式チャック','',['はい','いいえ'] ));
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<div class="q-mt-lg q-pa-sm">
|
||||
<q-card-section>
|
||||
<div class="flex-center">
|
||||
<ItemSelector :actName="actName" />
|
||||
<ItemSelector />
|
||||
</div>
|
||||
</q-card-section>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,8 @@ const routes: RouteRecordRaw[] = [
|
||||
{ path: 'flow', component: () => import('pages/testFlow.vue') },
|
||||
{ path: 'flowchart', component: () => import('pages/FlowChartTest.vue') },
|
||||
{ path: 'flowEditor', component: () => import('pages/FlowEditorPage.vue') },
|
||||
{ path: 'flowEditor2', component: () => import('pages/FlowEditorPage2.vue') },
|
||||
{ path: 'flowEditor2', component: () => import('pages/FlowChart.vue') },
|
||||
{ path: 'flowChart2', component: () => import('pages/FlowEditorPage2.vue') },
|
||||
{ path: 'right', component: () => import('pages/testRight.vue') },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,25 +1,33 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ActionFlow,AppInfo } from 'src/types/ActionTypes';
|
||||
|
||||
export const useFlowEditorStore = defineStore('flowEditor', {
|
||||
state: () => ({
|
||||
counter: 0,
|
||||
flowNames: [],
|
||||
flowNames1: ''
|
||||
}),
|
||||
export interface FlowEditorState{
|
||||
flowNames1:string;
|
||||
appInfo?:AppInfo;
|
||||
flows?:ActionFlow[];
|
||||
selectedFlow?:ActionFlow|undefined;
|
||||
}
|
||||
|
||||
export const useFlowEditorStore = defineStore("flowEditor",{
|
||||
state: ():FlowEditorState => ({
|
||||
flowNames1: '',
|
||||
appInfo:undefined,
|
||||
flows:undefined,
|
||||
selectedFlow:undefined
|
||||
}),
|
||||
getters: {
|
||||
doubleCount(state) {
|
||||
return state.counter * 2;
|
||||
currentFlow():ActionFlow|undefined{
|
||||
return this.selectedFlow;
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
increment() {
|
||||
this.counter++;
|
||||
setFlows(flows:ActionFlow[]){
|
||||
this.flows=flows;
|
||||
},
|
||||
|
||||
setDefaultFlow() {
|
||||
this.counter++
|
||||
selectFlow(flow:ActionFlow){
|
||||
this.selectedFlow=flow;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
/**
|
||||
* アプリ情報
|
||||
*/
|
||||
export interface AppInfo {
|
||||
appId:string;
|
||||
code?:string;
|
||||
name:string;
|
||||
description?:string;
|
||||
}
|
||||
|
||||
/**
|
||||
* アクションのプロパティ定義
|
||||
@@ -41,6 +49,7 @@ export interface IActionNode{
|
||||
* アクションフローの定義
|
||||
*/
|
||||
export interface IActionFlow {
|
||||
id:string;
|
||||
actionNodes:Array<IActionNode>
|
||||
}
|
||||
|
||||
@@ -112,7 +121,7 @@ export class ActionNode implements IActionNode {
|
||||
title:string,
|
||||
inputPoint:string,
|
||||
outputPoint: Array<string> = [],
|
||||
actionProps: Array<IActionProperty> =[ActionProperty.defaultProperty()]
|
||||
actionProps: Array<IActionProperty> =[ActionProperty.defaultProperty()],
|
||||
) {
|
||||
this.id=uuidv4();
|
||||
this.name = name;
|
||||
@@ -168,7 +177,7 @@ export class RootAction implements IActionNode {
|
||||
* アクションフローの定義
|
||||
*/
|
||||
export class ActionFlow implements IActionFlow {
|
||||
|
||||
id:string;
|
||||
actionNodes:Array<IActionNode>;
|
||||
constructor(actionNodes:Array<IActionNode>|RootAction){
|
||||
if(actionNodes instanceof Array){
|
||||
@@ -176,6 +185,7 @@ export class ActionFlow implements IActionFlow {
|
||||
}else{
|
||||
this.actionNodes=[actionNodes];
|
||||
}
|
||||
this.id=uuidv4();
|
||||
}
|
||||
/**
|
||||
* ノードを追加する
|
||||
@@ -354,5 +364,38 @@ reconnectOrRemoveNextNodes(targetNode: IActionNode): void {
|
||||
return this.actionNodes.find((node) => node.id === id);
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
id:this.id,
|
||||
actionNodes: this.actionNodes.map(node => {
|
||||
const { nextNodeIds, ...rest } = node;
|
||||
return {
|
||||
...rest,
|
||||
nextNodeIds: Array.from(nextNodeIds.entries())
|
||||
};
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
getRoot():IActionNode|undefined{
|
||||
return this.actionNodes.find(node=>node.isRoot)
|
||||
}
|
||||
|
||||
static fromJSON(json: string): ActionFlow {
|
||||
const parsedObject = JSON.parse(json);
|
||||
|
||||
const actionNodes = parsedObject.actionNodes.map((node: any) => {
|
||||
const nodeClass = !node.isRoot? new ActionNode(node.name,node.title,node.inputPoint,node.outputPoint,node.actionProps)
|
||||
:new RootAction(node.name,node.title,node.subTitle);
|
||||
nodeClass.nextNodeIds=new Map(node.nextNodeIds);
|
||||
nodeClass.prevNodeId=node.prevNodeId;
|
||||
return nodeClass;
|
||||
});
|
||||
const actionFlow = new ActionFlow(actionNodes);
|
||||
actionFlow.id=parsedObject.id;
|
||||
return actionFlow;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
138
frontend/src/types/KintoneEvents.ts
Normal file
138
frontend/src/types/KintoneEvents.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
import {IActionFlow} from './ActionTypes';
|
||||
export interface TreeNode {
|
||||
label: string;
|
||||
}
|
||||
|
||||
export interface KintoneEvent extends TreeNode {
|
||||
eventId: string;
|
||||
hasFlow: boolean;
|
||||
flowData?: IActionFlow;
|
||||
}
|
||||
|
||||
export interface KintoneScreen extends TreeNode {
|
||||
label: string;
|
||||
events: KintoneEvent[];
|
||||
}
|
||||
|
||||
|
||||
export class KintoneEventManager {
|
||||
public screens: KintoneScreen[];
|
||||
|
||||
constructor(screens: KintoneScreen[]) {
|
||||
this.screens = screens;
|
||||
}
|
||||
|
||||
public findEventById(eventId: string): KintoneEvent | null {
|
||||
for (const screen of this.screens) {
|
||||
for (const event of screen.events) {
|
||||
if (event.eventId === eventId) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export const kintoneEvents:KintoneEventManager = new KintoneEventManager([
|
||||
{
|
||||
label:"レコード追加画面",
|
||||
events:[
|
||||
{
|
||||
label:"レコード追加画面を表示した後",
|
||||
eventId:"app.record.create.show",
|
||||
hasFlow:false
|
||||
},
|
||||
{
|
||||
label:"保存をクリックしたとき",
|
||||
eventId:"app.record.create.submit",
|
||||
hasFlow:true
|
||||
},
|
||||
{
|
||||
label:"保存が成功したとき",
|
||||
eventId:"app.record.create.submit.success ",
|
||||
hasFlow:false
|
||||
},
|
||||
{
|
||||
label:"フィールドの値を変更したとき",
|
||||
eventId:"app.record.create.change",
|
||||
hasFlow:false
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label:"レコード詳細画面",
|
||||
events:[
|
||||
{
|
||||
label:"レコード詳細画面を表示した後",
|
||||
eventId:"app.record.detail.show",
|
||||
hasFlow:false
|
||||
},
|
||||
{
|
||||
label:"レコードを削除するとき",
|
||||
eventId:"app.record.detail.delete.submit",
|
||||
hasFlow:false
|
||||
},
|
||||
{
|
||||
label:"プロセス管理のアクションを実行したとき",
|
||||
eventId:"app.record.detail.process.proceed",
|
||||
hasFlow:false
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label:"レコード編集画面",
|
||||
events:[
|
||||
{
|
||||
label:"レコード編集画面を表示した後",
|
||||
eventId:"app.record.edit.show",
|
||||
hasFlow:false
|
||||
},
|
||||
{
|
||||
label:"保存をクリックしたとき",
|
||||
eventId:"app.record.edit.submit",
|
||||
hasFlow:false
|
||||
},
|
||||
{
|
||||
label:"保存が成功したとき",
|
||||
eventId:"app.record.edit.submit.success",
|
||||
hasFlow:false
|
||||
},
|
||||
{
|
||||
label:"フィールドの値を変更したとき",
|
||||
eventId:"app.record.edit.change",
|
||||
hasFlow:false
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label:"レコード一覧画面",
|
||||
events:[
|
||||
{
|
||||
label:"一覧画面を表示した後",
|
||||
eventId:"app.record.index.show",
|
||||
hasFlow:false
|
||||
},
|
||||
{
|
||||
label:"インライン編集を開始したとき",
|
||||
eventId:"app.record.index.edit.show",
|
||||
hasFlow:false
|
||||
},
|
||||
{
|
||||
label:"インライン編集のフィールド値を変更したとき",
|
||||
eventId:"app.record.index.edit.change",
|
||||
hasFlow:false
|
||||
},
|
||||
{
|
||||
label:"インライン編集の【保存】をクリックしたとき",
|
||||
eventId:"app.record.index.edit.submit",
|
||||
hasFlow:false
|
||||
},
|
||||
{
|
||||
label:"インライン編集の保存が成功したとき",
|
||||
eventId:"app.record.index.edit.submit.success",
|
||||
hasFlow:false
|
||||
},
|
||||
]
|
||||
}
|
||||
]);
|
||||
137
sample.json
Normal file
137
sample.json
Normal file
@@ -0,0 +1,137 @@
|
||||
{
|
||||
"actionNodes": [
|
||||
{
|
||||
"id": "c9fa2f6a-a05b-4a2b-af8b-00addae2de6f",
|
||||
"name": "app.record.create.submit",
|
||||
"title": "レコード追加画面",
|
||||
"subTitle": "保存するとき",
|
||||
"inputPoint": "",
|
||||
"outputPoints": [],
|
||||
"isRoot": true,
|
||||
"actionProps": [],
|
||||
"ActionValue": {},
|
||||
"nextNodeIds": [
|
||||
[
|
||||
"",
|
||||
"4b39f388-f7f2-4ccd-ace2-995e60893fd3"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "4b39f388-f7f2-4ccd-ace2-995e60893fd3",
|
||||
"name": "自動採番",
|
||||
"title": "文書番号を自動採番する",
|
||||
"inputPoint": "",
|
||||
"outputPoints": [],
|
||||
"actionProps": [
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"name": "displayName",
|
||||
"displayName": "文書番号を自動採番する",
|
||||
"placeholder": "表示を入力してください",
|
||||
"modelValue": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"displayName": "フォーマット",
|
||||
"modelValue": "",
|
||||
"name": "format",
|
||||
"placeholder": "フォーマットを入力してください"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "FieldInput",
|
||||
"props": {
|
||||
"displayName": "採番項目",
|
||||
"modelValue": "",
|
||||
"name": "field",
|
||||
"placeholder": "採番項目を選択してください"
|
||||
}
|
||||
}
|
||||
],
|
||||
"prevNodeId": "c9fa2f6a-a05b-4a2b-af8b-00addae2de6f",
|
||||
"nextNodeIds": [
|
||||
[
|
||||
"",
|
||||
"22cac85a-005b-434a-8ef6-25eb536e0ad3"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "22cac85a-005b-434a-8ef6-25eb536e0ad3",
|
||||
"name": "入力データ取得",
|
||||
"title": "電話番号を取得する",
|
||||
"inputPoint": "",
|
||||
"outputPoints": [],
|
||||
"actionProps": [
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"name": "displayName",
|
||||
"displayName": "表示名",
|
||||
"placeholder": "表示を入力してください",
|
||||
"modelValue": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"prevNodeId": "4b39f388-f7f2-4ccd-ace2-995e60893fd3",
|
||||
"nextNodeIds": [
|
||||
[
|
||||
"",
|
||||
"c39e6d90-0063-4fdb-b3b6-9db396e402fe"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "c39e6d90-0063-4fdb-b3b6-9db396e402fe",
|
||||
"name": "条件分岐",
|
||||
"title": "電話番号入力形式チャック",
|
||||
"inputPoint": "",
|
||||
"outputPoints": [
|
||||
"はい",
|
||||
"いいえ"
|
||||
],
|
||||
"actionProps": [
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"name": "displayName",
|
||||
"displayName": "表示名",
|
||||
"placeholder": "表示を入力してください",
|
||||
"modelValue": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"prevNodeId": "22cac85a-005b-434a-8ef6-25eb536e0ad3",
|
||||
"nextNodeIds": [
|
||||
[
|
||||
"いいえ",
|
||||
"e5464858-b536-4cb0-be08-396daf5092f5"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "e5464858-b536-4cb0-be08-396daf5092f5",
|
||||
"name": "エラー表示",
|
||||
"title": "エラー表示して保存しない",
|
||||
"inputPoint": "いいえ",
|
||||
"outputPoints": [],
|
||||
"actionProps": [
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"name": "displayName",
|
||||
"displayName": "表示名",
|
||||
"placeholder": "表示を入力してください",
|
||||
"modelValue": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"prevNodeId": "c39e6d90-0063-4fdb-b3b6-9db396e402fe",
|
||||
"nextNodeIds": []
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user