This commit is contained in:
2023-09-08 20:04:34 +09:00
parent 40cd9998d0
commit ff03490209
3 changed files with 133 additions and 78 deletions

View File

@@ -1,107 +1,141 @@
<template> <template>
<div class="row justify-center" :style="{marginLeft:node.inputPoint!==''?'240px':''}"> <div class="row justify-center" :style="{ marginLeft: node.inputPoint !== '' ? '240px' : '' }" @click="onNodeClick">
<div class="row"> <div class="row">
<q-card class="action-node" :class="{'root-node':node.isRoot,'text-white':node.isRoot}" :square="false"> <q-card class="action-node" :class="nodeStyle" :square="false" >
<q-card-section> <q-card-section>
<div class="text-h6">{{ node.title }}</div> <div class="text-h6">{{ node.title }}</div>
<div class="text-subtitle2">{{ node.subTitle }}</div> <div class="text-subtitle2">{{ node.subTitle }}</div>
</q-card-section> </q-card-section>
<template v-if="hasBranch"> <template v-if="hasBranch">
<q-separator /> <q-separator />
<q-card-actions align="around"> <q-card-actions align="around">
<q-btn flat v-for="(point,index) in node.outputPoints" :key="index"> <q-btn flat v-for="(point, index) in node.outputPoints" :key="index">
{{ point }} {{ point }}
</q-btn> </q-btn>
</q-card-actions> </q-card-actions>
</template> </template>
</q-card> </q-card>
</div> </div>
</div> </div>
<template v-if="hasBranch"> <template v-if="hasBranch">
<div class="row justify-center" :style="{marginLeft:node.inputPoint!==''?'240px':''}"> <div class="row justify-center" :style="{ marginLeft: node.inputPoint !== '' ? '240px' : '' }">
<div v-for="(point,index) in node.outputPoints" :key="index"> <div v-for="(point, index) in node.outputPoints" :key="index">
<node-line :action-node="node" :mode="getMode(point)" @addNode="addNode" :input-point="point" ></node-line> <node-line :action-node="node" :mode="getMode(point)" @addNode="addNode" :input-point="point"></node-line>
</div> </div>
</div> </div>
</template> </template>
<template v-if="!hasBranch"> <template v-if="!hasBranch">
<div class="row justify-center" :style="{marginLeft:node.inputPoint!==''?'240px':''}"> <div class="row justify-center" :style="{ marginLeft: node.inputPoint !== '' ? '240px' : '' }">
<node-line :action-node="node" :mode="getMode('')" @addNode="addNode" input-point=""></node-line> <node-line :action-node="node" :mode="getMode('')" @addNode="addNode" input-point=""></node-line>
</div> </div>
</template> </template>
</template> </template>
<script lang="ts"> <script lang="ts">
import {defineComponent,computed} from 'vue'; import { defineComponent, computed, ref } from 'vue';
import {IActionNode } from '../../types/ActionTypes'; import { IActionNode } from '../../types/ActionTypes';
import NodeLine,{Direction} from '../main/NodeLine.vue'; import NodeLine, { Direction } from '../main/NodeLine.vue';
export default defineComponent({ export default defineComponent({
name: 'NodeItem', name: 'NodeItem',
components: { components: {
NodeLine NodeLine
}, },
props: { props: {
actionNode:{ actionNode: {
type:Object as ()=>IActionNode, type: Object as () => IActionNode,
required:true required: true
},
isSelected: {
type: Boolean
}
},
emits: [
'addNode',
"nodeSelected"
],
setup(props, context) {
const hasBranch = computed(() => props.actionNode.outputPoints.length > 0);
const nodeStyle = computed(() => {
return {
'root-node': props.actionNode.isRoot,
'text-white': props.actionNode.isRoot,
'selected': props.isSelected && !props.actionNode.isRoot
};
});
const getMode = (point: string) => {
if (point === '' || props.actionNode.outputPoints.length === 0) {
return Direction.Default;
}
if (point === props.actionNode.outputPoints[0]) {
if (props.actionNode.nextNodes.get(point)) {
return Direction.Left;
} else {
return Direction.LeftNotNext;
} }
}, } else {
emits: [ if (props.actionNode.nextNodes.get(point)) {
'addNode' return Direction.Right;
], } else {
setup(props,context){ return Direction.RightNotNext;
const hasBranch = computed(() => props.actionNode.outputPoints.length > 0);
const getMode =(point:string)=>{
if(point==='' || props.actionNode.outputPoints.length===0){
return Direction.Default;
}
if(point===props.actionNode.outputPoints[0]){
if(props.actionNode.nextNodes.get(point)){
return Direction.Left;
}else{
return Direction.LeftNotNext;
}
}else{
if(props.actionNode.nextNodes.get(point)){
return Direction.Right;
}else{
return Direction.RightNotNext;
}
}
}
const addNode=(point:string)=>{
context.emit('addNode',props.actionNode,point);
}
return {
node:props.actionNode,
hasBranch,
isRoot:props.actionNode.isRoot,
getMode,
addNode
} }
} }
}); }
/**
* アクションノード追加イベントを
* @param point 入力ポイント
*/
const addNode = (point: string) => {
context.emit('addNode', props.actionNode, point);
}
/**
* ノード選択状態
*/
const onNodeClick = () => {
context.emit('nodeSelected', props.actionNode);
}
return {
node: props.actionNode,
isRoot: props.actionNode.isRoot,
hasBranch,
nodeStyle,
getMode,
addNode,
onNodeClick
}
}
});
</script> </script>
<style lang="scss"> <style lang="scss">
.action-node{ .action-node {
min-width:250px !important; min-width: 250px !important;
} }
.line{
height:20px; .line {
height: 20px;
} }
.line:after{
content:''; .line:after {
background-color:$blue-7; content: '';
display:block; background-color: $blue-7;
width:3px; display: block;
width: 3px;
} }
.add-icon{
.add-icon {
font-size: 2em; font-size: 2em;
color:$blue-7; color: $blue-7;
} }
.root-node{
background-color:$blue-7; .root-node {
background-color: $blue-7;
border-radius: 20px; border-radius: 20px;
} }
.action-node:not(.root-node):hover{
background-color: $light-blue-1;
}
.selected{
background-color: $light-blue-1;
}
</style> </style>

View File

@@ -2,7 +2,8 @@
<div> <div>
<svg class="node-line"> <svg class="node-line">
<polyline :points="points.linePoints" class="line" ></polyline> <polyline :points="points.linePoints" class="line" ></polyline>
<text class="add-icon" @click="addNode(node)" :x="points.iconPoint.x" :y="points.iconPoint.y" font-family="Arial" font-size="25" text-anchor="middle" dy=".3em" style="cursor: pointer;" > <text class="add-icon" @click="addNode(node)" :x="points.iconPoint.x" :y="points.iconPoint.y" font-family="Arial" font-size="25"
text-anchor="middle" dy=".3em" style="cursor: pointer;" >
</text> </text>
</svg> </svg>
@@ -69,6 +70,7 @@ export default defineComponent({
const addNode=(prveNode:IActionNode)=>{ const addNode=(prveNode:IActionNode)=>{
context.emit('addNode',props.inputPoint); context.emit('addNode',props.inputPoint);
} }
return { return {
node: props.actionNode, node: props.actionNode,
hasBranch, hasBranch,
@@ -91,9 +93,17 @@ export default defineComponent({
} }
.add-icon { .add-icon {
stroke: $blue-7; stroke: $blue-8;
fill: $blue-7; fill: $blue-8;
font-family: Arial; font-family: Arial;
pointer-events: all; pointer-events: all;
font-size: 2.0em;
}
.add-icon:hover{
stroke: $blue-8;
fill:$blue-8;
font-weight: bold;
font-size: 2.4em;
} }
</style> </style>

View File

@@ -1,7 +1,9 @@
<template> <template>
<q-page> <q-page>
<div class="flowchart"> <div class="flowchart">
<node-item v-for="(node,index) in refFlow.actionNodes" :key="index" :actionNode="node" @addNode="addNode"></node-item> <node-item v-for="(node,index) in refFlow.actionNodes" :key="index"
:isSelected="node===activeNode" :actionNode="node"
@addNode="addNode" @nodeSelected="onNodeSelected"></node-item>
</div> </div>
</q-page> </q-page>
<show-dialog v-model:visible="showAddAction" name="アクション" @close="closeDg"> <show-dialog v-model:visible="showAddAction" name="アクション" @close="closeDg">
@@ -16,8 +18,8 @@ import NodeItem from 'src/components/main/NodeItem.vue';
import ShowDialog from 'components/ShowDialog.vue'; import ShowDialog from 'components/ShowDialog.vue';
import ActionSelect from 'components/ActionSelect.vue'; import ActionSelect from 'components/ActionSelect.vue';
const rootAction:RootAction =new RootAction("app.record.create.submit","レコード追加画面","保存するとき"); const rootNode:RootAction =new RootAction("app.record.create.submit","レコード追加画面","保存するとき");
const actionFlow: ActionFlow = new ActionFlow(rootAction); const actionFlow: ActionFlow = new ActionFlow(rootNode);
actionFlow.addNode(new ActionNode('自動採番','文書番号を自動採番する','')); actionFlow.addNode(new ActionNode('自動採番','文書番号を自動採番する',''));
actionFlow.addNode(new ActionNode('入力データ取得','電話番号を取得する','')); actionFlow.addNode(new ActionNode('入力データ取得','電話番号を取得する',''));
const branchNode = actionFlow.addNode(new ActionNode('条件分岐','電話番号入力形式チャック','',['はい','いいえ'] )); const branchNode = actionFlow.addNode(new ActionNode('条件分岐','電話番号入力形式チャック','',['はい','いいえ'] ));
@@ -26,6 +28,7 @@ actionFlow.addNode(new ActionNode('エラー表示','エラー表示して保存
// ref関数を使ってtemplateとバインド // ref関数を使ってtemplateとバインド
const refFlow = ref(actionFlow); const refFlow = ref(actionFlow);
const showAddAction=ref(false); const showAddAction=ref(false);
const activeNode =ref(rootNode);
const addActionNode=(action:IActionNode)=>{ const addActionNode=(action:IActionNode)=>{
refFlow.value.actionNodes.push(action); refFlow.value.actionNodes.push(action);
@@ -34,6 +37,14 @@ const addActionNode=(action:IActionNode)=>{
const addNode=(node:IActionNode,inputPoint:string)=>{ const addNode=(node:IActionNode,inputPoint:string)=>{
showAddAction.value=true; showAddAction.value=true;
} }
const onNodeSelected=(node:IActionNode)=>{
activeNode.value=node;
}
const closeDg=(val :any)=>{
console.log("Dialog closed->",val);
}
</script> </script>
<style lang="scss"> <style lang="scss">