条件エディタ実装
This commit is contained in:
@@ -1,13 +1,30 @@
|
||||
<template>
|
||||
<show-dialog v-model:visible="showflg" name="条件エディタ" @close="closeDg" width="60vw" height="60vh">
|
||||
<template v-slot:toolbar>
|
||||
<q-btn flat round dense icon="more_vert" >
|
||||
<q-menu auto-close anchor="bottom start">
|
||||
<q-list>
|
||||
<q-item clickable @click="copyCondition()">
|
||||
<q-item-section avatar><q-icon name="content_copy" ></q-icon></q-item-section>
|
||||
<q-item-section >コピー</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable @click="pasteCondition()">
|
||||
<q-item-section avatar><q-icon name="content_paste" ></q-icon></q-item-section>
|
||||
<q-item-section >貼り付け</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
</template>
|
||||
<NodeCondition v-model:conditionTree="tree"></NodeCondition>
|
||||
</show-dialog>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref ,watchEffect} from 'vue';
|
||||
import ShowDialog from '../../components/ShowDialog.vue';
|
||||
import NodeCondition from './NodeCondition.vue';
|
||||
import { ConditionTree } from '../../types/Conditions';
|
||||
import ShowDialog from '../../components/ShowDialog.vue';
|
||||
import NodeCondition from './NodeCondition.vue';
|
||||
import { ConditionTree } from '../../types/Conditions';
|
||||
import { useQuasar } from 'quasar';
|
||||
export default defineComponent({
|
||||
name: 'ConditionObject',
|
||||
components: {
|
||||
@@ -24,18 +41,55 @@ import { defineComponent, ref ,watchEffect} from 'vue';
|
||||
default:false
|
||||
}
|
||||
},
|
||||
emits:[
|
||||
"closed",
|
||||
"update:conditionTree",
|
||||
"update:show"
|
||||
],
|
||||
setup(props,context) {
|
||||
const appDg = ref();
|
||||
const $q=useQuasar();
|
||||
const tree = ref(props.conditionTree);
|
||||
const closeDg = (val:string) => {
|
||||
if (val == 'OK') {
|
||||
if(tree.value.root.children.length===0){
|
||||
$q.notify({
|
||||
type: 'negative',
|
||||
message: `条件式を設定してください。`
|
||||
});
|
||||
}
|
||||
context.emit("update:conditionTree",tree.value);
|
||||
}
|
||||
showflg.value=false;
|
||||
context.emit("update:show",false);
|
||||
context.emit("closed",val);
|
||||
};
|
||||
const showflg =ref(props.show);
|
||||
|
||||
//条件式をコピーする
|
||||
const copyCondition=()=>{
|
||||
if (navigator.clipboard) {
|
||||
const jsonData=tree.value.toJson();
|
||||
navigator.clipboard.writeText(jsonData).then(() => {
|
||||
console.log('Text successfully copied to clipboard');
|
||||
},
|
||||
(err) => {
|
||||
console.error('Error in copying text: ', err);
|
||||
});
|
||||
} else {
|
||||
console.log('Clipboard API not available');
|
||||
}
|
||||
};
|
||||
//条件式を貼り付ける
|
||||
const pasteCondition=async ()=>{
|
||||
try {
|
||||
const text = await navigator.clipboard.readText();
|
||||
console.log('Text from clipboard:', text);
|
||||
tree.value.fromJson(text);
|
||||
} catch (err) {
|
||||
console.error('Failed to read text from clipboard: ', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
watchEffect(() => {
|
||||
showflg.value=props.show;
|
||||
});
|
||||
@@ -44,7 +98,9 @@ import { defineComponent, ref ,watchEffect} from 'vue';
|
||||
tree,
|
||||
appDg,
|
||||
closeDg,
|
||||
showflg
|
||||
showflg,
|
||||
copyCondition,
|
||||
pasteCondition
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -11,20 +11,20 @@
|
||||
</template>
|
||||
</q-field>
|
||||
<show-dialog v-model:visible="show" name="フィールド一覧" @close="closeDg" widht="400px">
|
||||
<field-select ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></field-select>
|
||||
<condition-objects ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></condition-objects>
|
||||
</show-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref ,watchEffect,computed} from 'vue';
|
||||
import ShowDialog from '../ShowDialog.vue';
|
||||
import FieldSelect from '../FieldSelect.vue';
|
||||
import ConditionObjects from '../ConditionObjects.vue';
|
||||
import { useFlowEditorStore } from '../../stores/flowEditor';
|
||||
export default defineComponent({
|
||||
name: 'ConditionObject',
|
||||
components: {
|
||||
ShowDialog,
|
||||
FieldSelect,
|
||||
ConditionObjects,
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
|
||||
@@ -34,15 +34,6 @@
|
||||
<q-btn flat round dense icon="more_horiz" size="sm" >
|
||||
<q-menu auto-close anchor="top right">
|
||||
<q-list>
|
||||
<q-item clickable @click="addGroup(prop.node, LogicalOperator.AND)">
|
||||
<q-item-section avatar><q-icon name="playlist_add" ></q-icon></q-item-section>
|
||||
<q-item-section >グループ追加</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable @click="addCondition(prop.node)">
|
||||
<q-item-section avatar><q-icon name="add_circle_outline" ></q-icon></q-item-section>
|
||||
<q-item-section >条件式追加</q-item-section>
|
||||
</q-item>
|
||||
<q-separator inset/>
|
||||
<q-item clickable @click="moveUp(prop.node)">
|
||||
<q-item-section avatar><q-icon name="arrow_upward" ></q-icon></q-item-section>
|
||||
<q-item-section >一つ上に移動</q-item-section>
|
||||
@@ -52,6 +43,19 @@
|
||||
<q-item-section >一つ下に移動</q-item-section>
|
||||
</q-item>
|
||||
<q-separator inset/>
|
||||
<q-item clickable @click="addGroup(prop.node, LogicalOperator.AND)">
|
||||
<q-item-section avatar><q-icon name="playlist_add" ></q-icon></q-item-section>
|
||||
<q-item-section >グループ追加</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable @click="addCondition(prop.node)">
|
||||
<q-item-section avatar><q-icon name="add_circle_outline" ></q-icon></q-item-section>
|
||||
<q-item-section >条件式追加</q-item-section>
|
||||
</q-item>
|
||||
<q-separator inset/>
|
||||
<q-item clickable @click="splitGroup(prop.node)">
|
||||
<q-item-section avatar><q-icon name="playlist_remove" color="negative"></q-icon></q-item-section>
|
||||
<q-item-section >グループ化解除</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable @click="removeNode(prop.node)">
|
||||
<q-item-section avatar><q-icon name="delete" color="negative"></q-icon></q-item-section>
|
||||
<q-item-section >削除</q-item-section>
|
||||
@@ -86,6 +90,11 @@
|
||||
<q-item-section >一つ下に移動</q-item-section>
|
||||
</q-item>
|
||||
<q-separator inset/>
|
||||
<q-item clickable @click="groupMerge(prop.node)" v-if="canMerge(prop.node)">
|
||||
<q-item-section avatar><q-icon name="playlist_add"></q-icon></q-item-section>
|
||||
<q-item-section >グループ化</q-item-section>
|
||||
</q-item>
|
||||
<q-separator inset/>
|
||||
<q-item clickable @click="removeNode(prop.node)">
|
||||
<q-item-section avatar><q-icon name="delete" color="negative"></q-icon></q-item-section>
|
||||
<q-item-section>削除</q-item-section>
|
||||
@@ -102,6 +111,7 @@
|
||||
<q-btn @click="getConditionJson()" class="q-mt-md" color="primary" icon="mdi-plus">Show Condtion data</q-btn>
|
||||
<q-btn @click="LoadCondition()" class="q-mt-md" color="primary" icon="mdi-plus">Load Condition</q-btn> -->
|
||||
<q-tooltip anchor="center middle" v-model="showingCondition" no-parent-event>
|
||||
import { finished } from 'stream';
|
||||
{{ conditionString }}
|
||||
</q-tooltip>
|
||||
</div>
|
||||
@@ -160,7 +170,6 @@ export default defineComponent( {
|
||||
return opts;
|
||||
};
|
||||
|
||||
|
||||
const addGroup = (parent:GroupNode, logicOp:LogicalOperator) => {
|
||||
if(!parent){
|
||||
parent=tree.root;
|
||||
@@ -169,7 +178,7 @@ export default defineComponent( {
|
||||
};
|
||||
|
||||
const addCondition = (parent:GroupNode) => {
|
||||
const newNode = new ConditionNode(LogicalOperator.AND,{},Operator.Equal,'',parent);
|
||||
const newNode = new ConditionNode({},Operator.Equal,'',parent);
|
||||
tree.addNode(parent,newNode);
|
||||
};
|
||||
|
||||
@@ -188,10 +197,36 @@ export default defineComponent( {
|
||||
const getConditionJson=()=>{
|
||||
return tree.toJson();
|
||||
}
|
||||
|
||||
//JsonからConditionTreeのインスタンスを作成
|
||||
const LoadCondition=()=>{
|
||||
tree.fromJson(conditionString.value);
|
||||
}
|
||||
//グループ化
|
||||
const groupMerge=(node:INode)=>{
|
||||
const checkedNodes:INode[]=[];
|
||||
const checkedIndexs:number[] = ticked.value;
|
||||
checkedIndexs.forEach(index => {
|
||||
const node = tree.findByIndex(index);
|
||||
if(node){
|
||||
checkedNodes.push(node);
|
||||
}
|
||||
});
|
||||
tree.createGroupNode(node,checkedNodes,LogicalOperator.AND);
|
||||
ticked.value=[];
|
||||
}
|
||||
//グループ化可能かをチェックする
|
||||
const canMerge =(node:INode)=>{
|
||||
const checkedIndexs:number[] = ticked.value;
|
||||
const findNode = checkedIndexs.find(index=>node.index===index);
|
||||
console.log("findNode=>",findNode!==undefined,findNode);
|
||||
return findNode!==undefined;
|
||||
}
|
||||
//グループ化解散
|
||||
const splitGroup=(node:INode)=>{
|
||||
tree.dissolveGroupNode(node as GroupNode);
|
||||
ticked.value=[];
|
||||
}
|
||||
|
||||
|
||||
const expanded=computed(()=>tree.getGroups(tree.root));
|
||||
// addCondition(tree.root);
|
||||
@@ -214,7 +249,10 @@ export default defineComponent( {
|
||||
getConditionJson,
|
||||
LoadCondition,
|
||||
objectValueOptions,
|
||||
expanded
|
||||
expanded,
|
||||
canMerge,
|
||||
groupMerge,
|
||||
splitGroup
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
54
frontend/src/components/ConditionObjects.vue
Normal file
54
frontend/src/components/ConditionObjects.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="q-pa-md">
|
||||
<div v-if="!isLoaded" class="spinner flex flex-center">
|
||||
<q-spinner color="primary" size="3em" />
|
||||
</div>
|
||||
<q-table v-else row-key="name" :selection="type" v-model:selected="selected" :columns="columns" :rows="rows" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { ref,onMounted,reactive } from 'vue'
|
||||
import { api } from 'boot/axios';
|
||||
|
||||
export default {
|
||||
name: 'ConditionObjects',
|
||||
props: {
|
||||
name: String,
|
||||
type: String,
|
||||
appId:Number
|
||||
},
|
||||
setup(props) {
|
||||
const isLoaded=ref(false);
|
||||
const columns = [
|
||||
{ name: 'name', required: true,label: 'フィールド名',align: 'left',field: row=>row.name,sortable: true},
|
||||
{ name: 'code', label: 'フィールドコード', align: 'left',field: 'code', sortable: true },
|
||||
{ name: 'type', label: 'フィールドタイプ', align: 'left',field: 'type', sortable: true }
|
||||
]
|
||||
const rows = reactive([])
|
||||
onMounted( async () => {
|
||||
const res = await api.get('api/v1/appfields', {
|
||||
params:{
|
||||
app: props.appId
|
||||
}
|
||||
});
|
||||
let fields = res.data.properties;
|
||||
console.log(fields);
|
||||
Object.keys(fields).forEach((key) =>
|
||||
{
|
||||
const fld=fields[key];
|
||||
// rows.push({name:fields[key].label,code:fields[key].code,type:fields[key].type});
|
||||
rows.push({name:fld.label,objectType:'field',...fld});
|
||||
});
|
||||
isLoaded.value=true;
|
||||
});
|
||||
|
||||
return {
|
||||
columns,
|
||||
rows,
|
||||
selected: ref([]),
|
||||
isLoaded
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
@@ -2,10 +2,15 @@
|
||||
<!-- <div class="q-pa-md q-gutter-sm" > -->
|
||||
<q-dialog :model-value="visible" persistent bordered>
|
||||
<q-card :style="{minWidth : width}" >
|
||||
<q-toolbar class="bg-grey-4">
|
||||
<q-toolbar-title>{{ name }}</q-toolbar-title>
|
||||
<q-space></q-space>
|
||||
<slot name="toolbar"></slot>
|
||||
<q-btn flat round dense icon="close" @click="CloseDialogue('Cancel')" />
|
||||
</q-toolbar>
|
||||
<q-card-section>
|
||||
<div class="text-h6">{{ name }}</div>
|
||||
<!-- <div class="text-h6">{{ name }}</div> -->
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="q-pt-none" :style="{...(height? {minHeight:height}:{}) }">
|
||||
<slot></slot>
|
||||
</q-card-section>
|
||||
|
||||
@@ -26,7 +26,11 @@
|
||||
</q-toolbar>
|
||||
<q-separator />
|
||||
<q-card-section>
|
||||
<div class="text-h7">{{ node.title }}</div>
|
||||
<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 />
|
||||
@@ -134,7 +138,14 @@ export default defineComponent({
|
||||
*/
|
||||
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,
|
||||
@@ -145,7 +156,8 @@ export default defineComponent({
|
||||
onNodeClick,
|
||||
onEditNode,
|
||||
onDeleteNode,
|
||||
onDeleteAllNode
|
||||
onDeleteAllNode,
|
||||
varName
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</q-card>
|
||||
</template>
|
||||
</q-field>
|
||||
<condition-editor v-model:show="show" v-model:conditionTree="tree"></condition-editor>
|
||||
<condition-editor v-model:show="show" v-model:conditionTree="tree" @closed="onClosed"></condition-editor>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -54,7 +54,7 @@
|
||||
if(props.modelValue && props.modelValue!==''){
|
||||
tree.fromJson(props.modelValue);
|
||||
}else{
|
||||
const newNode = new ConditionNode(LogicalOperator.AND,{},Operator.Equal,'',tree.root);
|
||||
const newNode = new ConditionNode({},Operator.Equal,'',tree.root);
|
||||
tree.addNode(tree.root,newNode);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
show.value = true;
|
||||
};
|
||||
|
||||
const closeDg = (val:string) => {
|
||||
const onClosed = (val:string) => {
|
||||
if (val == 'OK') {
|
||||
const conditionJson = tree.toJson();
|
||||
isSetted.value=true;
|
||||
@@ -86,7 +86,7 @@
|
||||
isSetted,
|
||||
show,
|
||||
showDg,
|
||||
closeDg,
|
||||
onClosed,
|
||||
tree,
|
||||
conditionString
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
>
|
||||
<q-card class="column full-height" style="width: 300px">
|
||||
<q-card-section>
|
||||
<div class="text-h6">プロパティ</div>
|
||||
<div class="text-h6">{{ actionNode.subTitle }}:設定</div>
|
||||
</q-card-section>
|
||||
<q-card-section class="col q-pt-none">
|
||||
<property-list :node-props="actionProps" v-if="showPanel" ></property-list>
|
||||
|
||||
Reference in New Issue
Block a user