199 lines
5.6 KiB
Vue
199 lines
5.6 KiB
Vue
<template>
|
|
<div class="row justify-center" :style="{ marginLeft: node.inputPoint !== '' ? '240px' : '' }" >
|
|
<div class="row">
|
|
<q-card class="action-node" :class="nodeStyle" :square="false" @click="onNodeClick" >
|
|
<q-toolbar class="col" >
|
|
<div class="text-subtitle2">{{ node.subTitle }}</div>
|
|
<q-space></q-space>
|
|
<q-btn flat round dense icon="more_horiz" size="sm" >
|
|
<q-menu auto-close anchor="top right">
|
|
<q-list>
|
|
<q-item clickable v-if="!isRoot" @click="onEditNode">
|
|
<q-item-section avatar><q-icon name="edit" ></q-icon></q-item-section>
|
|
<q-item-section >編集する</q-item-section>
|
|
</q-item>
|
|
<q-item clickable v-if="!isRoot" @click="onDeleteNode">
|
|
<q-item-section avatar><q-icon name="delete" ></q-icon></q-item-section>
|
|
<q-item-section>削除する</q-item-section>
|
|
</q-item>
|
|
<q-item clickable @click="onDeleteAllNode">
|
|
<q-item-section avatar><q-icon name="delete_sweep" ></q-icon></q-item-section>
|
|
<q-item-section >以下すべて削除する</q-item-section>
|
|
</q-item>
|
|
</q-list>
|
|
</q-menu>
|
|
</q-btn>
|
|
</q-toolbar>
|
|
<q-separator />
|
|
<q-card-section>
|
|
<div class="row">
|
|
<span class="text-h7">{{ node.title }}</span>
|
|
<q-space></q-space>
|
|
<q-chip color="info" text-color="white" size="0.70rem" v-if="varName(node)" clickable>{{ varName(node) }}</q-chip>
|
|
</div>
|
|
</q-card-section>
|
|
<template v-if="hasBranch">
|
|
<q-separator />
|
|
<q-card-actions align="around">
|
|
<q-btn flat v-for="(point, index) in node.outputPoints" :key="index">
|
|
{{ point }}
|
|
</q-btn>
|
|
</q-card-actions>
|
|
</template>
|
|
</q-card>
|
|
</div>
|
|
</div>
|
|
<template v-if="hasBranch">
|
|
<div class="row justify-center" :style="{ marginLeft: node.inputPoint !== '' ? '240px' : '' }">
|
|
<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>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template v-if="!hasBranch">
|
|
<div class="row justify-center" :style="{ marginLeft: node.inputPoint !== '' ? '240px' : '' }">
|
|
<node-line :action-node="node" :mode="getMode('')" @addNode="addNode" input-point=""></node-line>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { defineComponent, computed, ref } from 'vue';
|
|
import { IActionNode } from '../../types/ActionTypes';
|
|
import NodeLine, { Direction } from '../main/NodeLine.vue';
|
|
export default defineComponent({
|
|
name: 'NodeItem',
|
|
components: {
|
|
NodeLine
|
|
},
|
|
props: {
|
|
actionNode: {
|
|
type: Object as () => IActionNode,
|
|
required: true
|
|
},
|
|
isSelected: {
|
|
type: Boolean
|
|
}
|
|
},
|
|
emits: [
|
|
'addNode',
|
|
"nodeSelected",
|
|
"nodeEdit",
|
|
"deleteNode",
|
|
"deleteAllNextNodes",
|
|
],
|
|
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.nextNodeIds.get(point)) {
|
|
return Direction.Left;
|
|
} else {
|
|
return Direction.LeftNotNext;
|
|
}
|
|
} else {
|
|
if (props.actionNode.nextNodeIds.get(point)) {
|
|
return Direction.Right;
|
|
} else {
|
|
return Direction.RightNotNext;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* アクションノード追加イベントを
|
|
* @param point 入力ポイント
|
|
*/
|
|
const addNode = (point: string) => {
|
|
context.emit('addNode', props.actionNode, point);
|
|
}
|
|
/**
|
|
* ノード選択状態
|
|
*/
|
|
const onNodeClick = () => {
|
|
context.emit('nodeSelected', props.actionNode);
|
|
}
|
|
|
|
const onEditNode=()=>{
|
|
context.emit('nodeEdit', props.actionNode);
|
|
}
|
|
/**
|
|
* ノードを削除する
|
|
*/
|
|
const onDeleteNode=()=>{
|
|
context.emit('deleteNode', props.actionNode);
|
|
}
|
|
|
|
/**
|
|
* ノードの以下すべて削除する
|
|
*/
|
|
const onDeleteAllNode=()=>{
|
|
context.emit('deleteAllNextNodes', props.actionNode);
|
|
};
|
|
/**
|
|
* 変数名取得
|
|
*/
|
|
const varName =(node:IActionNode)=>{
|
|
const prop = node.actionProps.find((prop) => prop.props.name === "verName");
|
|
return prop?.props.modelValue;
|
|
};
|
|
return {
|
|
node: props.actionNode,
|
|
isRoot: props.actionNode.isRoot,
|
|
hasBranch,
|
|
nodeStyle,
|
|
getMode,
|
|
addNode,
|
|
onNodeClick,
|
|
onEditNode,
|
|
onDeleteNode,
|
|
onDeleteAllNode,
|
|
varName
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
<style lang="scss">
|
|
.action-node {
|
|
min-width: 300px !important;
|
|
}
|
|
|
|
.line {
|
|
height: 20px;
|
|
}
|
|
|
|
.line:after {
|
|
content: '';
|
|
background-color: $blue-7;
|
|
display: block;
|
|
width: 3px;
|
|
}
|
|
|
|
.add-icon {
|
|
font-size: 2em;
|
|
color: $blue-7;
|
|
}
|
|
|
|
.root-node {
|
|
background-color: $blue-7;
|
|
border-radius: 20px;
|
|
}
|
|
|
|
.action-node:not(.root-node):hover{
|
|
background-color: $light-blue-1;
|
|
}
|
|
|
|
.selected{
|
|
background-color: $yellow-1;
|
|
}
|
|
</style>
|