Merge branch 'maxz-real-impl' into mvp_step2_dev
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.session import get_db
|
||||||
from app.db.crud import *
|
from app.db.crud import *
|
||||||
from app.db.schemas import *
|
from app.db.schemas import *
|
||||||
|
from typing import List
|
||||||
|
|
||||||
platform_router = r = APIRouter()
|
platform_router = r = APIRouter()
|
||||||
|
|
||||||
@@ -93,6 +94,20 @@ async def flow_details(
|
|||||||
return app
|
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)
|
@r.post("/flow", response_model=Flow, response_model_exclude_none=True)
|
||||||
async def flow_create(
|
async def flow_create(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
|||||||
@@ -174,3 +174,9 @@ def get_flow(db: Session, flowid: str):
|
|||||||
if not flow:
|
if not flow:
|
||||||
raise HTTPException(status_code=404, detail="Data not found")
|
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.
53
frontend/package-lock.json
generated
53
frontend/package-lock.json
generated
@@ -10,6 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/extras": "^1.16.4",
|
"@quasar/extras": "^1.16.4",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
|
"pinia": "^2.1.6",
|
||||||
"quasar": "^2.6.0",
|
"quasar": "^2.6.0",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"vue": "^3.0.0",
|
"vue": "^3.0.0",
|
||||||
@@ -4079,6 +4080,56 @@
|
|||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pinia": {
|
||||||
|
"version": "2.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.6.tgz",
|
||||||
|
"integrity": "sha512-bIU6QuE5qZviMmct5XwCesXelb5VavdOWKWaB17ggk++NUwQWWbP5YnsONTk3b752QkW9sACiR81rorpeOMSvQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@vue/devtools-api": "^6.5.0",
|
||||||
|
"vue-demi": ">=0.14.5"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/posva"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@vue/composition-api": "^1.4.0",
|
||||||
|
"typescript": ">=4.4.4",
|
||||||
|
"vue": "^2.6.14 || ^3.3.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@vue/composition-api": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pinia/node_modules/vue-demi": {
|
||||||
|
"version": "0.14.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz",
|
||||||
|
"integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"bin": {
|
||||||
|
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||||
|
"vue-demi-switch": "bin/vue-demi-switch.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/antfu"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@vue/composition-api": "^1.0.0-rc.1",
|
||||||
|
"vue": "^3.0.0-0 || ^2.6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@vue/composition-api": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.25",
|
"version": "8.4.25",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.25.tgz",
|
||||||
@@ -4955,7 +5006,7 @@
|
|||||||
"version": "4.9.5",
|
"version": "4.9.5",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/extras": "^1.16.4",
|
"@quasar/extras": "^1.16.4",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
|
"pinia": "^2.1.6",
|
||||||
"quasar": "^2.6.0",
|
"quasar": "^2.6.0",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"vue": "^3.0.0",
|
"vue": "^3.0.0",
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="q-pa-md">
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
@@ -17,11 +23,11 @@ export default {
|
|||||||
const columns = [
|
const columns = [
|
||||||
{ name: 'name', required: true,label: 'アクション名',align: 'left',field: 'name',sortable: true},
|
{ name: 'name', required: true,label: 'アクション名',align: 'left',field: 'name',sortable: true},
|
||||||
{ name: 'desc', align: 'left', label: '説明', field: 'desc', 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([])
|
const rows = reactive([])
|
||||||
onMounted(async () => {
|
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) =>
|
res.data.forEach((item) =>
|
||||||
{
|
{
|
||||||
rows.push({name:item.name,desc:item.desc,content:item.content});
|
rows.push({name:item.name,desc:item.desc,content:item.content});
|
||||||
@@ -33,8 +39,16 @@ export default {
|
|||||||
columns,
|
columns,
|
||||||
rows,
|
rows,
|
||||||
selected: ref([]),
|
selected: ref([]),
|
||||||
|
pagination:ref({
|
||||||
|
rowsPerPage:0
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.action-table{
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { ref,onMounted,reactive } from 'vue'
|
|||||||
import { api } from 'boot/axios';
|
import { api } from 'boot/axios';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'appSelect',
|
name: 'AppSelect',
|
||||||
props: {
|
props: {
|
||||||
name: String,
|
name: String,
|
||||||
type: String
|
type: String
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
<script>
|
<script>
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'showDialog',
|
name: 'ShowDialog',
|
||||||
props: {
|
props: {
|
||||||
name:String,
|
name:String,
|
||||||
visible: Boolean,
|
visible: Boolean,
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="q-py-md">
|
|
||||||
<q-list>
|
|
||||||
<q-expansion-item
|
|
||||||
group="somegroup"
|
|
||||||
label="レコードを追加画面"
|
|
||||||
default-opened
|
|
||||||
>
|
|
||||||
<q-card-section>
|
|
||||||
<q-checkbox v-model="setting.v1" label="追加画面表示した時" />
|
|
||||||
<q-checkbox v-model="setting.v2" label="保存をクリックした時" />
|
|
||||||
<q-checkbox v-model="setting.v3" label="保存成功した時" />
|
|
||||||
</q-card-section>
|
|
||||||
</q-expansion-item>
|
|
||||||
|
|
||||||
<q-expansion-item group="somegroup" label="レコード編集画面">
|
|
||||||
<q-card>
|
|
||||||
<q-card-section>
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quidem,
|
|
||||||
eius reprehenderit eos corrupti commodi magni quaerat ex numquam,
|
|
||||||
dolorum officiis modi facere maiores architecto suscipit iste
|
|
||||||
eveniet doloribus ullam aliquid.
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
</q-expansion-item>
|
|
||||||
|
|
||||||
<q-expansion-item group="somegroup" label="レコード詳細画面">
|
|
||||||
<q-card>
|
|
||||||
<q-card-section>
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quidem,
|
|
||||||
eius reprehenderit eos corrupti commodi magni quaerat ex numquam,
|
|
||||||
dolorum officiis modi facere maiores architecto suscipit iste
|
|
||||||
eveniet doloribus ullam aliquid.
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
</q-expansion-item>
|
|
||||||
|
|
||||||
<q-expansion-item group="somegroup" label="レコード一覧画面">
|
|
||||||
<q-card class="bg-teal-2">
|
|
||||||
<q-card-section>
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quidem,
|
|
||||||
eius reprehenderit eos corrupti commodi magni quaerat ex numquam,
|
|
||||||
dolorum officiis modi facere maiores architecto suscipit iste
|
|
||||||
eveniet doloribus ullam aliquid.
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
</q-expansion-item>
|
|
||||||
</q-list>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<q-btn @click="clear" label="clear"/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, Ref } from 'vue';
|
|
||||||
interface Setting {
|
|
||||||
v1: boolean;
|
|
||||||
v2: boolean;
|
|
||||||
v3: boolean;
|
|
||||||
}
|
|
||||||
const setting: Ref<Setting> = ref({
|
|
||||||
v1: true,
|
|
||||||
v2: true,
|
|
||||||
v3: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
let clear = () => {
|
|
||||||
setting.value.v1 = false
|
|
||||||
setting.value.v2 = false
|
|
||||||
setting.value.v3 = false
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="q-py-md">
|
<div class="q-py-md">
|
||||||
<q-tree :nodes="LeftDataBus.root" node-key="label">
|
<q-tree
|
||||||
<template #header-rg="p">
|
no-connectors
|
||||||
<ControlPanelTreeRadio
|
selected-color="primary"
|
||||||
:node="p.node"
|
default-expand-all
|
||||||
:dataBus="LeftDataBus"
|
:nodes="LeftDataBus.root"
|
||||||
></ControlPanelTreeRadio>
|
v-model:selected="flowNames1"
|
||||||
</template>
|
node-key="label"
|
||||||
|
>
|
||||||
</q-tree>
|
</q-tree>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -16,9 +17,13 @@ import {
|
|||||||
LeftDataBus,
|
LeftDataBus,
|
||||||
setControlPanelE,
|
setControlPanelE,
|
||||||
} from 'components/flowEditor/left/DataBus';
|
} from 'components/flowEditor/left/DataBus';
|
||||||
import ControlPanelTreeRadio from './ControlPanelTreeRadio.vue';
|
import { ref } from 'vue';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
|
|
||||||
// 应该在page中用网络请求获取值并初始化组件
|
// 应该在page中用网络请求获取值并初始化组件
|
||||||
// 然后在page中执行setControlPane设置databus
|
// 然后在page中执行setControlPane设置databus
|
||||||
|
const store = useFlowEditorStore();
|
||||||
|
const { flowNames1 } = storeToRefs(store);
|
||||||
setControlPanelE();
|
setControlPanelE();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
<template>
|
|
||||||
<q-radio v-model="model" :val="node.value" :label="node.label" />
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { computed } from 'vue';
|
|
||||||
import { LeftData, ControlPanelData } from 'components/flowEditor/left/DataBus';
|
|
||||||
|
|
||||||
const props = defineProps(['node', 'dataBus']);
|
|
||||||
|
|
||||||
const node = computed(() => props.node as ControlPanelData);
|
|
||||||
|
|
||||||
const model = computed({
|
|
||||||
get() {
|
|
||||||
return (props.dataBus as LeftData).data?.get(node.value.group ?? 'n');
|
|
||||||
},
|
|
||||||
set(newValue) {
|
|
||||||
(props.dataBus as LeftData).data?.set(
|
|
||||||
node.value.group ?? 'n',
|
|
||||||
newValue ?? ''
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@@ -1,36 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="ItemSelector q-pa-sm">
|
<div
|
||||||
<div class="row">
|
class="row"
|
||||||
<div class="col-auto">
|
style="
|
||||||
<q-icon name="widgets" color="primary" size="2.5em" />
|
border-radius: 2px;
|
||||||
</div>
|
box-shadow: rgba(255, 255, 255, 0.1) 0px 0px 0px 1px inset,
|
||||||
<div class="col flex">
|
rgba(0, 0, 0, 0.3) 0px 0px 0px 1px;
|
||||||
<div class="q-pa-sm flex" style="align-items: center">{{title}}</div>
|
"
|
||||||
</div>
|
>
|
||||||
<div class="col-auto flex">
|
<q-icon
|
||||||
<div class="flex" style="align-items: center">
|
class="self-center q-ma-sm"
|
||||||
<q-btn
|
name="widgets"
|
||||||
class="q-px-sm"
|
color="grey-9"
|
||||||
color="white"
|
style="font-size: 2em"
|
||||||
size="sm"
|
/>
|
||||||
text-color="black"
|
|
||||||
label="変 更"
|
<div class="col-7 self-center ellipsis">
|
||||||
dense
|
{{ actName }}
|
||||||
/>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
<div class="self-center">
|
||||||
|
<q-btn
|
||||||
|
outline
|
||||||
|
dense
|
||||||
|
label="変 更"
|
||||||
|
padding="none sm"
|
||||||
|
color="primary"
|
||||||
|
></q-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script>
|
||||||
import { ref } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
const title = ref('勤怠管理')
|
export default {
|
||||||
|
props: ['actName'],
|
||||||
|
setup(props) {
|
||||||
|
const actName = computed(() => props.actName);
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="sass">
|
|
||||||
.ItemSelector
|
|
||||||
border: 0.15em solid rgba(#999, .4)
|
|
||||||
border-radius: 0.4em
|
|
||||||
</style>
|
|
||||||
|
|||||||
85
frontend/src/components/left/AppSelector.vue
Normal file
85
frontend/src/components/left/AppSelector.vue
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<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"
|
||||||
|
@click="showAppDialog"
|
||||||
|
></q-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ShowDialog v-model:visible="showSelectApp" name="アプリ" @close="closeDg">
|
||||||
|
<AppSelect ref="appDg" name="アプリ" type="single"></AppSelect>
|
||||||
|
</ShowDialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent,ref } from 'vue';
|
||||||
|
import {AppInfo} from '../../types/ActionTypes'
|
||||||
|
import ShowDialog from '../../components/ShowDialog.vue';
|
||||||
|
import AppSelect from '../../components/AppSelect.vue';
|
||||||
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'AppSelector',
|
||||||
|
emits:[
|
||||||
|
"appSelected"
|
||||||
|
],
|
||||||
|
components:{
|
||||||
|
AppSelect,
|
||||||
|
ShowDialog
|
||||||
|
},
|
||||||
|
setup(props, context) {
|
||||||
|
|
||||||
|
const store = useFlowEditorStore();
|
||||||
|
const appDg = ref();
|
||||||
|
const showSelectApp=ref(false);
|
||||||
|
const selectedApp =ref<AppInfo>({
|
||||||
|
appId:"",
|
||||||
|
name:"",
|
||||||
|
});
|
||||||
|
const closeDg=(val :any)=>{
|
||||||
|
showSelectApp.value=false;
|
||||||
|
console.log("Dialog closed->",val);
|
||||||
|
if (val == 'OK') {
|
||||||
|
const data = appDg.value.selected[0];
|
||||||
|
console.log(data);
|
||||||
|
selectedApp.value={
|
||||||
|
appId:data.id ,
|
||||||
|
name:data.name
|
||||||
|
};
|
||||||
|
store.setApp(selectedApp.value);
|
||||||
|
store.setFlow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const showAppDialog=()=>{
|
||||||
|
showSelectApp.value=true;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
store,
|
||||||
|
selectedApp,
|
||||||
|
showSelectApp,
|
||||||
|
showAppDialog,
|
||||||
|
closeDg,
|
||||||
|
appDg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</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>
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
<show-dialog v-model:visible="show" name="フィールド一覧" @close="closeDg">
|
<show-dialog v-model:visible="show" name="フィールド一覧" @close="closeDg">
|
||||||
<field-select ref="appDg" name="フィールド" type="single" :appId="1"></field-select>
|
<field-select ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></field-select>
|
||||||
</show-dialog>
|
</show-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
import { defineComponent, ref ,watchEffect} from 'vue';
|
import { defineComponent, ref ,watchEffect} from 'vue';
|
||||||
import ShowDialog from '../ShowDialog.vue';
|
import ShowDialog from '../ShowDialog.vue';
|
||||||
import FieldSelect from '../FieldSelect.vue';
|
import FieldSelect from '../FieldSelect.vue';
|
||||||
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'FieldInput',
|
name: 'FieldInput',
|
||||||
components: {
|
components: {
|
||||||
@@ -35,6 +35,7 @@ export default defineComponent({
|
|||||||
const appDg = ref();
|
const appDg = ref();
|
||||||
const show = ref(false);
|
const show = ref(false);
|
||||||
const selectedField = ref(props.modelValue);
|
const selectedField = ref(props.modelValue);
|
||||||
|
const store = useFlowEditorStore();
|
||||||
|
|
||||||
const showDg = () => {
|
const showDg = () => {
|
||||||
show.value = true;
|
show.value = true;
|
||||||
@@ -51,6 +52,7 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
store,
|
||||||
appDg,
|
appDg,
|
||||||
show,
|
show,
|
||||||
showDg,
|
showDg,
|
||||||
|
|||||||
37
frontend/src/control/flowctrl.ts
Normal file
37
frontend/src/control/flowctrl.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
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);
|
||||||
|
console.info(result.data)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async UpdateFlow(jsonData:any):Promise<boolean>
|
||||||
|
{
|
||||||
|
const result = await api.put('http://127.0.0.1:8000/api/flow/' + jsonData.flowid,jsonData);
|
||||||
|
console.info(result.data)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ const essentialLinks: EssentialLinkProps[] = [
|
|||||||
title: 'フローエディター',
|
title: 'フローエディター',
|
||||||
caption: 'flowChart',
|
caption: 'flowChart',
|
||||||
icon: 'account_tree',
|
icon: 'account_tree',
|
||||||
link: '/#/flowChart',
|
link: '/#/flowEditor2',
|
||||||
target:'_self'
|
target:'_self'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
160
frontend/src/pages/FlowChart.vue
Normal file
160
frontend/src/pages/FlowChart.vue
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
<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">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
|
<PropertyPanel :actionNode="state.activeNode" v-model:drawerRight="drawerRight"></PropertyPanel>
|
||||||
|
<ShowDialog v-model:visible="showAddAction" name="アクション" @close="closeDg">
|
||||||
|
<action-select ref="appDg" name="model" type="single"></action-select>
|
||||||
|
</ShowDialog>
|
||||||
|
|
||||||
|
</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:{} as IActionNode,
|
||||||
|
inputPoint:""
|
||||||
|
});
|
||||||
|
const refFlow = ref<ActionFlow|null>(null);
|
||||||
|
const showAddAction=ref(false);
|
||||||
|
const drawerRight=ref(false);
|
||||||
|
const model=ref("");
|
||||||
|
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();
|
||||||
|
if(store.appInfo===undefined) return;
|
||||||
|
const actionFlows = await flowCtrl.getFlows(store.appInfo?.appId);
|
||||||
|
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>
|
<template>
|
||||||
<q-page>
|
<q-page>
|
||||||
|
|
||||||
<div class="flowchart">
|
<div class="flowchart">
|
||||||
<node-item v-for="(node,) in refFlow.actionNodes" :key="node.id"
|
<node-item v-for="(node,) in refFlow.actionNodes" :key="node.id"
|
||||||
:isSelected="node===state.activeNode" :actionNode="node"
|
:isSelected="node===state.activeNode" :actionNode="node"
|
||||||
@@ -46,11 +47,10 @@ const saibanProps:IActionProperty[]=[{
|
|||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
|
||||||
actionFlow.addNode(new ActionNode('自動採番','文書番号を自動採番する','',[],saibanProps));
|
actionFlow.addNode(new ActionNode('自動採番','文書番号を自動採番する','',[],saibanProps));
|
||||||
actionFlow.addNode(new ActionNode('入力データ取得','電話番号を取得する',''));
|
actionFlow.addNode(new ActionNode('入力データ取得','電話番号を取得する',''));
|
||||||
const branchNode = actionFlow.addNode(new ActionNode('条件分岐','電話番号入力形式チャック','',['はい','いいえ'] ));
|
const branchNode = actionFlow.addNode(new ActionNode('条件分岐','電話番号入力形式チャック','',['はい','いいえ'] ));
|
||||||
actionFlow.addNode(new ActionNode('入力データ取得','住所を取得する',''),branchNode,'はい');
|
// actionFlow.addNode(new ActionNode('入力データ取得','住所を取得する',''),branchNode,'はい');
|
||||||
actionFlow.addNode(new ActionNode('エラー表示','エラー表示して保存しない',''),branchNode,'いいえ' );
|
actionFlow.addNode(new ActionNode('エラー表示','エラー表示して保存しない',''),branchNode,'いいえ' );
|
||||||
|
|
||||||
// ref関数を使ってtemplateとバインド
|
// ref関数を使ってtemplateとバインド
|
||||||
@@ -88,7 +88,7 @@ const onDeleteNode=(node:IActionNode)=>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onDeleteAllNextNodes=(node:IActionNode)=>{
|
const onDeleteAllNextNodes=(node:IActionNode)=>{
|
||||||
refFlow.value.removeNode(node);
|
refFlow.value.removeAllNext(node.id);
|
||||||
}
|
}
|
||||||
const closeDg=(val :any)=>{
|
const closeDg=(val :any)=>{
|
||||||
console.log("Dialog closed->",val);
|
console.log("Dialog closed->",val);
|
||||||
|
|||||||
@@ -1,37 +1,122 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page>
|
<div>
|
||||||
<div class="q-pa-md">
|
<div class="q-ma-md">
|
||||||
<div class="q-gutter-sm row items-start">
|
<div class="q-gutter-xs row items-start">
|
||||||
<q-breadcrumbs>
|
<q-breadcrumbs class="q-pt-xs q-mr-sm" active-color="black">
|
||||||
<q-breadcrumbs-el icon="home" to="/" />
|
<q-breadcrumbs-el icon="home" />
|
||||||
<q-breadcrumbs-el :label="title" icon="rule" />
|
<q-breadcrumbs-el :label="actName" />
|
||||||
</q-breadcrumbs>
|
<q-breadcrumbs-el
|
||||||
</div>
|
v-for="flowName in flowNames"
|
||||||
<div class="q-pa-md">
|
:key="flowName"
|
||||||
<div class="row">
|
:label="flowName"
|
||||||
<div class="col-2 column">
|
/>
|
||||||
<ItemSelector />
|
|
||||||
<div class="col-auto"><ControlPanel /></div>
|
|
||||||
</div>
|
|
||||||
<!-- <div class="col">
|
|
||||||
|
|
||||||
</div> -->
|
<q-breadcrumbs-el :label="flowNames1" />
|
||||||
</div>
|
</q-breadcrumbs>
|
||||||
|
<q-separator vertical class="q-mr-xs" />
|
||||||
|
<q-btn
|
||||||
|
unelevated
|
||||||
|
class="q-py-sm"
|
||||||
|
padding="none md none sm"
|
||||||
|
color="blue-1"
|
||||||
|
text-color="primary"
|
||||||
|
size="md"
|
||||||
|
@click="drawerLeft = !drawerLeft"
|
||||||
|
label="変 更"
|
||||||
|
icon="expand_more"
|
||||||
|
dense
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-space />
|
||||||
|
<q-btn
|
||||||
|
class="q-px-sm q-mr-sm"
|
||||||
|
color="white"
|
||||||
|
size="sm"
|
||||||
|
text-color="black"
|
||||||
|
label="キャンセル"
|
||||||
|
dense
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
class="q-px-sm"
|
||||||
|
color="primary"
|
||||||
|
size="sm"
|
||||||
|
label="保存する"
|
||||||
|
dense
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-page>
|
<q-layout
|
||||||
|
container
|
||||||
|
style="height: 91.5dvb"
|
||||||
|
class="shadow-2 rounded-borders"
|
||||||
|
>
|
||||||
|
<q-drawer side="left" overlay bordered v-model="drawerLeft">
|
||||||
|
<div class="q-pa-sm fixed-right">
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
color="primary"
|
||||||
|
icon="close"
|
||||||
|
@click="drawerLeft = !drawerLeft"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="q-mt-lg q-pa-sm">
|
||||||
|
<q-card-section>
|
||||||
|
<div class="flex-center">
|
||||||
|
<div class="row q-pl-md">
|
||||||
|
<p class="text-h6">アクション選択</p>
|
||||||
|
</div>
|
||||||
|
<ItemSelector :actName="actName" />
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
</div>
|
||||||
|
<q-separator />
|
||||||
|
<div class="q-mt-md q-pa-sm">
|
||||||
|
<q-card-section>
|
||||||
|
<p class="text-h6 q-pl-md q-mb-none">フロー選択</p>
|
||||||
|
<ControlPanel />
|
||||||
|
</q-card-section>
|
||||||
|
</div>
|
||||||
|
<q-separator />
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<div class="q-pa-sm">
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
color="primary"
|
||||||
|
size="md"
|
||||||
|
@click="drawerLeft = !drawerLeft"
|
||||||
|
label="ジャンプ"
|
||||||
|
dense
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-drawer>
|
||||||
|
|
||||||
|
<FlowChartTest />
|
||||||
|
</q-layout>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ItemSelector from 'components/flowEditor/left/ItemSelector.vue';
|
import FlowChartTest from 'pages/FlowChartTest.vue';
|
||||||
import ControlPanel from 'components/flowEditor/left/ControlPanelC.vue';
|
import ControlPanel from 'components/flowEditor/left/ControlPanelC.vue';
|
||||||
interface FlowEditorPageProps {
|
import ItemSelector from 'components/flowEditor/left/ItemSelector.vue';
|
||||||
title: string;
|
import { ref } from 'vue';
|
||||||
}
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
|
|
||||||
|
const actName = ref('勤怠管理 - 4');
|
||||||
|
const flowNames = ref(['レコードを追加画面', '保存をクリックした時']);
|
||||||
|
|
||||||
|
const drawerLeft = ref(false);
|
||||||
|
const store = useFlowEditorStore();
|
||||||
|
const { flowNames1 } = storeToRefs(store);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<FlowEditorPageProps>(), {
|
|
||||||
title: 'FlowEditor',
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="sass"></style>
|
<style lang="sass"></style>
|
||||||
|
|||||||
117
frontend/src/pages/FlowEditorPage2.vue
Normal file
117
frontend/src/pages/FlowEditorPage2.vue
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<template>
|
||||||
|
<div >
|
||||||
|
<div class="q-ma-md">
|
||||||
|
<div class="q-gutter-xs row items-start">
|
||||||
|
<q-btn
|
||||||
|
size="md"
|
||||||
|
@click="drawerLeft = !drawerLeft"
|
||||||
|
icon="keyboard_double_arrow_right"
|
||||||
|
round
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-space />
|
||||||
|
<q-btn
|
||||||
|
color="white"
|
||||||
|
size="sm"
|
||||||
|
text-color="black"
|
||||||
|
label="キャンセル"
|
||||||
|
dense
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
class="q-px-sm"
|
||||||
|
color="primary"
|
||||||
|
size="sm"
|
||||||
|
label="保存する"
|
||||||
|
@click="save()"
|
||||||
|
dense
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<q-layout
|
||||||
|
container
|
||||||
|
class="flow-container shadow-2 rounded-borders"
|
||||||
|
>
|
||||||
|
<q-drawer side="left" overlay bordered v-model="drawerLeft">
|
||||||
|
<div class="q-pa-sm fixed-right">
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
round
|
||||||
|
color="primary"
|
||||||
|
icon="close"
|
||||||
|
@click="drawerLeft = !drawerLeft"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="q-mt-lg q-pa-sm">
|
||||||
|
<q-card-section>
|
||||||
|
<div class="flex-center">
|
||||||
|
<ItemSelector />
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
</div>
|
||||||
|
<q-separator />
|
||||||
|
<div class="q-mt-md q-pa-sm">
|
||||||
|
<q-card-section>
|
||||||
|
<ControlPanel />
|
||||||
|
</q-card-section>
|
||||||
|
</div>
|
||||||
|
<q-separator />
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<div class="q-pa-sm">
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
color="primary"
|
||||||
|
size="md"
|
||||||
|
@click="drawerLeft = !drawerLeft"
|
||||||
|
label="ジャンプ"
|
||||||
|
dense
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-drawer>
|
||||||
|
|
||||||
|
<FlowChartTest />
|
||||||
|
</q-layout>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import FlowChartTest from 'pages/FlowChartTest.vue';
|
||||||
|
import ControlPanel from 'components/flowEditor/left/ControlPanelC.vue';
|
||||||
|
import ItemSelector from 'components/flowEditor/left/ItemSelector.vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
|
import { FlowCtrl } from '../control/flowctrl'
|
||||||
|
|
||||||
|
const flowCtrl = new FlowCtrl();
|
||||||
|
const actName = ref('勤怠管理 - 4');
|
||||||
|
|
||||||
|
const drawerLeft = ref(false);
|
||||||
|
const store = useFlowEditorStore();
|
||||||
|
const { flowNames1 } = storeToRefs(store);
|
||||||
|
let isNew = ref(true);
|
||||||
|
|
||||||
|
const save = () =>{
|
||||||
|
|
||||||
|
if(isNew.value)
|
||||||
|
{
|
||||||
|
flowCtrl.SaveFlow({appid:'1',flowid:'flow123',eventid:'event123',name:'test',content:'[]'});
|
||||||
|
isNew.value = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flowCtrl.UpdateFlow({appid:'1',flowid:'flow123',eventid:'event123',name:'test',content:'[{"a":"b"}]'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.flow-toolbar{
|
||||||
|
opacity: 50%;
|
||||||
|
}
|
||||||
|
.flow-container{
|
||||||
|
height: calc(91.5dvb - 50px);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -11,6 +11,8 @@ const routes: RouteRecordRaw[] = [
|
|||||||
{ path: 'flow', component: () => import('pages/testFlow.vue') },
|
{ path: 'flow', component: () => import('pages/testFlow.vue') },
|
||||||
{ path: 'flowchart', component: () => import('pages/FlowChartTest.vue') },
|
{ path: 'flowchart', component: () => import('pages/FlowChartTest.vue') },
|
||||||
{ path: 'flowEditor', component: () => import('pages/FlowEditorPage.vue') },
|
{ path: 'flowEditor', component: () => import('pages/FlowEditorPage.vue') },
|
||||||
|
{ path: 'flowEditor2', component: () => import('pages/FlowChart.vue') },
|
||||||
|
{ path: 'flowChart2', component: () => import('pages/FlowEditorPage2.vue') },
|
||||||
{ path: 'right', component: () => import('pages/testRight.vue') },
|
{ path: 'right', component: () => import('pages/testRight.vue') },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
47
frontend/src/stores/flowEditor.ts
Normal file
47
frontend/src/stores/flowEditor.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { ActionFlow,AppInfo } from 'src/types/ActionTypes';
|
||||||
|
import {FlowCtrl } from '../control/flowCtrl';
|
||||||
|
|
||||||
|
export interface FlowEditorState{
|
||||||
|
flowNames1:string;
|
||||||
|
appInfo?:AppInfo;
|
||||||
|
flows?:ActionFlow[];
|
||||||
|
selectedFlow?:ActionFlow|undefined;
|
||||||
|
}
|
||||||
|
const flowCtrl=new FlowCtrl();
|
||||||
|
export const useFlowEditorStore = defineStore("flowEditor",{
|
||||||
|
state: ():FlowEditorState => ({
|
||||||
|
flowNames1: '',
|
||||||
|
appInfo:undefined,
|
||||||
|
flows:undefined,
|
||||||
|
selectedFlow:undefined
|
||||||
|
}),
|
||||||
|
getters: {
|
||||||
|
currentFlow():ActionFlow|undefined{
|
||||||
|
return this.selectedFlow;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
setFlows(flows:ActionFlow[]){
|
||||||
|
this.flows=flows;
|
||||||
|
},
|
||||||
|
selectFlow(flow:ActionFlow){
|
||||||
|
this.selectedFlow=flow;
|
||||||
|
},
|
||||||
|
setApp(app:AppInfo){
|
||||||
|
this.appInfo=app;
|
||||||
|
},
|
||||||
|
async setFlow(){
|
||||||
|
if(this.appInfo===undefined) return;
|
||||||
|
const actionFlows = await flowCtrl.getFlows(this.appInfo?.appId);
|
||||||
|
if(actionFlows && actionFlows.length>0){
|
||||||
|
this.setFlows(actionFlows);
|
||||||
|
}
|
||||||
|
if(actionFlows && actionFlows.length==1){
|
||||||
|
this.selectFlow(actionFlows[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
32
frontend/src/stores/index.ts
Normal file
32
frontend/src/stores/index.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { store } from 'quasar/wrappers'
|
||||||
|
import { createPinia } from 'pinia'
|
||||||
|
import { Router } from 'vue-router';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When adding new properties to stores, you should also
|
||||||
|
* extend the `PiniaCustomProperties` interface.
|
||||||
|
* @see https://pinia.vuejs.org/core-concepts/plugins.html#typing-new-store-properties
|
||||||
|
*/
|
||||||
|
declare module 'pinia' {
|
||||||
|
export interface PiniaCustomProperties {
|
||||||
|
readonly router: Router;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If not building with SSR mode, you can
|
||||||
|
* directly export the Store instantiation;
|
||||||
|
*
|
||||||
|
* The function below can be async too; either use
|
||||||
|
* async/await or return a Promise which resolves
|
||||||
|
* with the Store instance.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default store((/* { ssrContext } */) => {
|
||||||
|
const pinia = createPinia()
|
||||||
|
|
||||||
|
// You can add Pinia plugins here
|
||||||
|
// pinia.use(SomePiniaPlugin)
|
||||||
|
|
||||||
|
return pinia
|
||||||
|
})
|
||||||
10
frontend/src/stores/store-flag.d.ts
vendored
Normal file
10
frontend/src/stores/store-flag.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
|
||||||
|
// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
|
||||||
|
import "quasar/dist/types/feature-flag";
|
||||||
|
|
||||||
|
declare module "quasar/dist/types/feature-flag" {
|
||||||
|
interface QuasarFeatureFlags {
|
||||||
|
store: true;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
frontend/src/stores/testStore.ts
Normal file
19
frontend/src/stores/testStore.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
|
export const useCounterStore = defineStore('counter', {
|
||||||
|
state: () => ({
|
||||||
|
counter: 0
|
||||||
|
}),
|
||||||
|
|
||||||
|
getters: {
|
||||||
|
doubleCount (state) {
|
||||||
|
return state.counter * 2;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
increment () {
|
||||||
|
this.counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -1,5 +1,13 @@
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
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 {
|
export interface IActionFlow {
|
||||||
|
id:string;
|
||||||
actionNodes:Array<IActionNode>
|
actionNodes:Array<IActionNode>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,8 +87,6 @@ class ActionProperty implements IActionProperty {
|
|||||||
modelValue: modelValue
|
modelValue: modelValue
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -114,7 +121,7 @@ export class ActionNode implements IActionNode {
|
|||||||
title:string,
|
title:string,
|
||||||
inputPoint:string,
|
inputPoint:string,
|
||||||
outputPoint: Array<string> = [],
|
outputPoint: Array<string> = [],
|
||||||
actionProps: Array<IActionProperty> =[ActionProperty.defaultProperty()]
|
actionProps: Array<IActionProperty> =[ActionProperty.defaultProperty()],
|
||||||
) {
|
) {
|
||||||
this.id=uuidv4();
|
this.id=uuidv4();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@@ -170,13 +177,15 @@ export class RootAction implements IActionNode {
|
|||||||
* アクションフローの定義
|
* アクションフローの定義
|
||||||
*/
|
*/
|
||||||
export class ActionFlow implements IActionFlow {
|
export class ActionFlow implements IActionFlow {
|
||||||
actionNodes:Array<IActionNode>;
|
id:string;
|
||||||
|
actionNodes:Array<IActionNode>;
|
||||||
constructor(actionNodes:Array<IActionNode>|RootAction){
|
constructor(actionNodes:Array<IActionNode>|RootAction){
|
||||||
if(actionNodes instanceof Array){
|
if(actionNodes instanceof Array){
|
||||||
this.actionNodes=actionNodes;
|
this.actionNodes=actionNodes;
|
||||||
}else{
|
}else{
|
||||||
this.actionNodes=[actionNodes];
|
this.actionNodes=[actionNodes];
|
||||||
}
|
}
|
||||||
|
this.id=uuidv4();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* ノードを追加する
|
* ノードを追加する
|
||||||
@@ -195,13 +204,18 @@ export class ActionFlow implements IActionFlow {
|
|||||||
if(inputPoint!==undefined){
|
if(inputPoint!==undefined){
|
||||||
newNode.inputPoint=inputPoint;
|
newNode.inputPoint=inputPoint;
|
||||||
}
|
}
|
||||||
if(prevNode){
|
if(prevNode!==undefined){
|
||||||
this.resetNodeRelation(prevNode,newNode,inputPoint);
|
this.connectNodes(prevNode,newNode,inputPoint||'');
|
||||||
}else{
|
}else{
|
||||||
prevNode=this.actionNodes[this.actionNodes.length-1];
|
prevNode=this.actionNodes[this.actionNodes.length-1];
|
||||||
this.resetNodeRelation(prevNode,newNode,inputPoint);
|
this.connectNodes(prevNode,newNode,inputPoint||'');
|
||||||
|
}
|
||||||
|
const index=this.actionNodes.findIndex(node=>node.id===prevNode?.id)
|
||||||
|
if(index>=0){
|
||||||
|
this.actionNodes.splice(index+1,0,newNode);
|
||||||
|
}else{
|
||||||
|
this.actionNodes.push(newNode);
|
||||||
}
|
}
|
||||||
this.actionNodes.push(newNode);
|
|
||||||
return newNode;
|
return newNode;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -291,7 +305,9 @@ reconnectOrRemoveNextNodes(targetNode: IActionNode): void {
|
|||||||
}
|
}
|
||||||
//二つ以上の場合
|
//二つ以上の場合
|
||||||
for(const [point,nextid] of nextNodeIds){
|
for(const [point,nextid] of nextNodeIds){
|
||||||
if(!this.connectNodes(prevNode,nextid,point)){
|
const nextNode = this.findNodeById(nextid);
|
||||||
|
if(!nextNode) return;
|
||||||
|
if(!this.connectNodes(prevNode,nextNode,point)){
|
||||||
this.removeAllNext(nextid);
|
this.removeAllNext(nextid);
|
||||||
this.removeFromActionNodes(nextid);
|
this.removeFromActionNodes(nextid);
|
||||||
}
|
}
|
||||||
@@ -305,13 +321,12 @@ reconnectOrRemoveNextNodes(targetNode: IActionNode): void {
|
|||||||
* @param point
|
* @param point
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
connectNodes(prevNode:IActionNode,nextNodeId:string,point:string):boolean{
|
connectNodes(prevNode:IActionNode,nextNode:IActionNode,point:string):boolean{
|
||||||
if(!prevNode || !nextNodeId){
|
if(!prevNode || !nextNode){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const nextNode = this.findNodeById(nextNodeId);
|
if(!nextNode) return false;
|
||||||
if(!nextNode) return false;
|
prevNode.nextNodeIds.set(point,nextNode.id);
|
||||||
prevNode.nextNodeIds.set(point,nextNodeId);
|
|
||||||
nextNode.prevNodeId=prevNode.id;
|
nextNode.prevNodeId=prevNode.id;
|
||||||
nextNode.inputPoint=point;
|
nextNode.inputPoint=point;
|
||||||
return true;
|
return true;
|
||||||
@@ -354,5 +369,38 @@ reconnectOrRemoveNextNodes(targetNode: IActionNode): void {
|
|||||||
return this.actionNodes.find((node) => node.id === id);
|
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
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
@@ -2149,6 +2149,14 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1:
|
|||||||
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
|
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
|
||||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||||
|
|
||||||
|
pinia@^2.0.0, pinia@^2.1.6:
|
||||||
|
version "2.1.6"
|
||||||
|
resolved "https://registry.npmjs.org/pinia/-/pinia-2.1.6.tgz"
|
||||||
|
integrity sha512-bIU6QuE5qZviMmct5XwCesXelb5VavdOWKWaB17ggk++NUwQWWbP5YnsONTk3b752QkW9sACiR81rorpeOMSvQ==
|
||||||
|
dependencies:
|
||||||
|
"@vue/devtools-api" "^6.5.0"
|
||||||
|
vue-demi ">=0.14.5"
|
||||||
|
|
||||||
postcss-selector-parser@^6.0.9:
|
postcss-selector-parser@^6.0.9:
|
||||||
version "6.0.13"
|
version "6.0.13"
|
||||||
resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz"
|
resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz"
|
||||||
@@ -2662,7 +2670,7 @@ type-is@~1.6.18:
|
|||||||
media-typer "0.3.0"
|
media-typer "0.3.0"
|
||||||
mime-types "~2.1.24"
|
mime-types "~2.1.24"
|
||||||
|
|
||||||
typescript@^4.5.4, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta":
|
typescript@^4.5.4, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", typescript@>=4.4.4:
|
||||||
version "4.9.5"
|
version "4.9.5"
|
||||||
resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz"
|
resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz"
|
||||||
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
|
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
|
||||||
@@ -2734,6 +2742,11 @@ vary@~1.1.2:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
|
vue-demi@>=0.14.5:
|
||||||
|
version "0.14.6"
|
||||||
|
resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz"
|
||||||
|
integrity sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==
|
||||||
|
|
||||||
vue-eslint-parser@^9.3.0:
|
vue-eslint-parser@^9.3.0:
|
||||||
version "9.3.1"
|
version "9.3.1"
|
||||||
resolved "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz"
|
resolved "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz"
|
||||||
@@ -2754,7 +2767,7 @@ vue-router@^4.0.0, vue-router@^4.0.12:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@vue/devtools-api" "^6.5.0"
|
"@vue/devtools-api" "^6.5.0"
|
||||||
|
|
||||||
vue@^3.0.0, vue@^3.2.0, vue@^3.2.25, vue@^3.2.29, vue@3.3.4:
|
"vue@^2.6.14 || ^3.3.0", vue@^3.0.0, "vue@^3.0.0-0 || ^2.6.0", vue@^3.2.0, vue@^3.2.25, vue@^3.2.29, vue@3.3.4:
|
||||||
version "3.3.4"
|
version "3.3.4"
|
||||||
resolved "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz"
|
resolved "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz"
|
||||||
integrity sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==
|
integrity sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==
|
||||||
|
|||||||
138
sample.json
Normal file
138
sample.json
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
{
|
||||||
|
"id": "681ecde3-4439-4210-9fdf-424c6af98f09",
|
||||||
|
"actionNodes": [
|
||||||
|
{
|
||||||
|
"id": "34dfd32e-ba1a-440f-bb46-a8a1999109cd",
|
||||||
|
"name": "app.record.create.submit",
|
||||||
|
"title": "レコード追加画面",
|
||||||
|
"subTitle": "保存するとき",
|
||||||
|
"inputPoint": "",
|
||||||
|
"outputPoints": [],
|
||||||
|
"isRoot": true,
|
||||||
|
"actionProps": [],
|
||||||
|
"ActionValue": {},
|
||||||
|
"nextNodeIds": [
|
||||||
|
[
|
||||||
|
"",
|
||||||
|
"ce07775d-9729-4516-a88c-78ee8f2f851e"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ce07775d-9729-4516-a88c-78ee8f2f851e",
|
||||||
|
"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": "34dfd32e-ba1a-440f-bb46-a8a1999109cd",
|
||||||
|
"nextNodeIds": [
|
||||||
|
[
|
||||||
|
"",
|
||||||
|
"0d18c3c9-abee-44e5-83eb-82074316219b"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "0d18c3c9-abee-44e5-83eb-82074316219b",
|
||||||
|
"name": "入力データ取得",
|
||||||
|
"title": "電話番号を取得する",
|
||||||
|
"inputPoint": "",
|
||||||
|
"outputPoints": [],
|
||||||
|
"actionProps": [
|
||||||
|
{
|
||||||
|
"component": "InputText",
|
||||||
|
"props": {
|
||||||
|
"name": "displayName",
|
||||||
|
"displayName": "表示名",
|
||||||
|
"placeholder": "表示を入力してください",
|
||||||
|
"modelValue": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"prevNodeId": "ce07775d-9729-4516-a88c-78ee8f2f851e",
|
||||||
|
"nextNodeIds": [
|
||||||
|
[
|
||||||
|
"",
|
||||||
|
"399d7c04-5345-4bf6-8da3-d745df554524"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "399d7c04-5345-4bf6-8da3-d745df554524",
|
||||||
|
"name": "条件分岐",
|
||||||
|
"title": "電話番号入力形式チャック",
|
||||||
|
"inputPoint": "",
|
||||||
|
"outputPoints": [
|
||||||
|
"はい",
|
||||||
|
"いいえ"
|
||||||
|
],
|
||||||
|
"actionProps": [
|
||||||
|
{
|
||||||
|
"component": "InputText",
|
||||||
|
"props": {
|
||||||
|
"name": "displayName",
|
||||||
|
"displayName": "表示名",
|
||||||
|
"placeholder": "表示を入力してください",
|
||||||
|
"modelValue": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"prevNodeId": "0d18c3c9-abee-44e5-83eb-82074316219b",
|
||||||
|
"nextNodeIds": [
|
||||||
|
[
|
||||||
|
"いいえ",
|
||||||
|
"8173e6bc-3fa2-4403-b973-9368884e2dfa"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8173e6bc-3fa2-4403-b973-9368884e2dfa",
|
||||||
|
"name": "エラー表示",
|
||||||
|
"title": "エラー表示して保存しない",
|
||||||
|
"inputPoint": "いいえ",
|
||||||
|
"outputPoints": [],
|
||||||
|
"actionProps": [
|
||||||
|
{
|
||||||
|
"component": "InputText",
|
||||||
|
"props": {
|
||||||
|
"name": "displayName",
|
||||||
|
"displayName": "表示名",
|
||||||
|
"placeholder": "表示を入力してください",
|
||||||
|
"modelValue": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"prevNodeId": "399d7c04-5345-4bf6-8da3-d745df554524",
|
||||||
|
"nextNodeIds": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user