feat:データ集計処理作成

This commit is contained in:
2024-05-24 09:20:19 +09:00
parent 7fb3d08ccb
commit 53aadfcaaa
7 changed files with 212 additions and 165 deletions

View File

@@ -2,7 +2,6 @@
<html lang="ja-jp">
<head>
<title><%= productName %></title>
<meta charset="utf-8">
<meta name="description" content="<%= productDescription %>">
<meta name="format-detection" content="telephone=no">

View File

@@ -4,6 +4,7 @@ import { Router } from 'vue-router';
import { App } from 'vue';
export default boot(({ app, router }: { app: App<Element>; router: Router }) => {
document.documentElement.lang="ja-JP";
app.config.errorHandler = (err: any, instance: any, info: string) => {
if (err.response && err.response.status === 401) {
// 認証エラーの場合再ログインする

View File

@@ -1,5 +1,5 @@
<template>
<show-dialog v-model:visible="showflg" name="条件エディタ" @close="closeDg" min-width="60vw" min-height="60vh">
<show-dialog v-model:visible="showflg" name="条件エディタ" @close="closeDg" min-width="50vw" min-height="60vh">
<template v-slot:toolbar>
<q-btn flat round dense icon="more_vert" >
<q-menu auto-close anchor="bottom start">

View File

@@ -13,14 +13,14 @@
<q-icon name="search" class="cursor-pointer" @click="showDg"/>
</template>
</q-field>
<show-dialog v-model:visible="show" name="条件設定項目一覧" @close="closeDg" width="600px">
<show-dialog v-model:visible="show" name="設定項目一覧" @close="closeDg" min-width="400px">
<template v-slot:toolbar>
<q-input dense debounce="200" v-model="filter" placeholder="検索" clearable>
<template v-slot:before>
<q-icon name="search" />
</template>
</q-input>
</template>
</template>
<condition-objects ref="appDg" name="フィールド" type="single" :filter="filter" :appId="store.appInfo?.appId" :vars="vars"></condition-objects>
</show-dialog>
</template>

View File

@@ -1,7 +1,7 @@
<template>
<!-- <div class="q-pa-md q-gutter-sm" > -->
<q-dialog :model-value="visible" persistent bordered >
<q-card :style="cardStyle" style=" min-width: 40vw; max-width: 80vw; max-height: 95vh;">
<q-card style="min-width: 40vw; max-width: 80vw; max-height: 95vh;" :style="cardStyle">
<q-toolbar class="bg-grey-4">
<q-toolbar-title>{{ name }}</q-toolbar-title>
<q-space></q-space>

View File

@@ -1,59 +1,60 @@
<template>
<div>
<q-field :label="displayName" labelColor="primary" stack-label>
<template v-slot:control>
<q-card flat class="full-width">
<q-card-actions vertical>
<q-btn color="grey-3" text-color="black" @click="() => { dgIsShow = true }">クリックで設定</q-btn>
</q-card-actions>
<q-card-section class="text-caption">
<div v-for="(item) in processingObjectsInputDisplay" :key="item">{{ item }}</div>
</q-card-section>
</q-card>
</template>
</q-field>
<show-dialog v-model:visible="dgIsShow" name="条件エディタ" @close="closeDg" min-width="60vw" min-height="60vh">
<div class="q-mx-md q-mb-md">
<q-input v-model="processingProps.name" type="text" label-color="primary" label="変数名を入力してください"
placeholder="varName" />
<div>
<q-field :label="displayName" labelColor="primary" stack-label>
<template v-slot:control>
<q-card flat class="full-width">
<q-card-actions vertical>
<q-btn color="grey-3" text-color="black" @click="() => { dgIsShow = true }">クリックで設定</q-btn>
</q-card-actions>
<q-card-section class="text-caption">
<div v-if="processingObjectsInputDisplay && processingObjectsInputDisplay.length>0">
<div v-for="(item) in processingObjectsInputDisplay" :key="item">{{ item }}</div>
</div>
<div v-else>{{ placeholder }}</div>
</q-card-section>
</q-card>
</template>
</q-field>
<show-dialog v-model:visible="dgIsShow" name="集計処理" @close="closeDg" min-width="50vw" min-height="60vh">
<div class="q-mx-md q-mb-md">
<q-input v-model="processingProps.name" type="text" label-color="primary" label="集計結果の変数名"
placeholder="集計結果を格納する変数名を入力してください" stack-label />
</div>
<div class="q-mx-md">
<div class="row q-col-gutter-x-xs flex-center">
<div class="col-5">
<div class="q-mx-xs">数据源</div>
</div>
<div class="col-2">
<div class="q-mx-xs">运算符</div>
</div>
<div class="col-4">
<div class="q-mx-xs">目标变量</div>
</div>
<div class="col-1"><q-btn flat round dense icon="add" size="sm" @click="addProcessingObject" />
</div>
</div>
<div class="q-my-sm" v-for="(item, index) in processingObjects" :key="item.id">
<div class="row q-col-gutter-x-xs flex-center">
<div class="col-5">
<ConditionObject v-model="item.field" />
</div>
<div class="col-2">
<q-select v-model="item.logicalOperator" :options="logicalOperators" outlined
dense></q-select>
</div>
<div class="col-4">
<q-input v-model="item.vName" type="text" label="Label" outlined dense />
</div>
<div class="col-1">
<q-btn flat round dense icon="delete" size="sm"
@click="() => deleteProcessingObject(index)" />
</div>
</div>
</div>
<div class="q-mx-md">
<div class="row q-col-gutter-x-xs flex-center">
<div class="col-5">
<div class="q-mx-xs">データソース</div>
</div>
<div class="col-2">
<div class="q-mx-xs">集計計算</div>
</div>
<div class="col-4">
<div class="q-mx-xs">集計結果変数名</div>
</div>
<div class="col-1"><q-btn flat round dense icon="add" size="sm" @click="addProcessingObject" />
</div>
</div>
<div class="q-my-sm" v-for="(item, index) in processingObjects" :key="item.id">
<div class="row q-col-gutter-x-xs flex-center">
<div class="col-5">
<ConditionObject v-model="item.field" />
</div>
</show-dialog>
</div>
<div class="col-2">
<q-select v-model="item.logicalOperator" :options="logicalOperators" outlined dense></q-select>
</div>
<div class="col-4">
<q-input v-model="item.vName" type="text" outlined dense />
</div>
<div class="col-1">
<q-btn flat round dense icon="delete" size="sm" @click="() => deleteProcessingObject(index)" />
</div>
</div>
</div>
</div>
</show-dialog>
</div>
</template>
<script lang="ts">
@@ -63,128 +64,166 @@ import ConditionObject from '../ConditionEditor/ConditionObject.vue';
import ShowDialog from '../ShowDialog.vue';
type Props = {
props?: {
name: string;
modelValue?: {
fields: {
type: string;
label: string;
code: string;
}[]
} | string
}
props?: {
name: string;
modelValue?: {
fields: {
type: string;
label: string;
code: string;
}[]
} | string
}
};
type ProcessingObjectType = {
field?: {
name: string | {
name: string;
};
objectType: string;
type: string;
code: string;
label: string;
noLabel: boolean;
field?: {
name: string | {
name: string;
};
logicalOperator?: string;
vName?: string;
id: string;
objectType: string;
type: string;
code: string;
label: string;
noLabel: boolean;
};
logicalOperator?: string;
vName?: string;
id: string;
}
type ValueType = {
name: string;
actionName: string,
displayName: string,
vars: ProcessingObjectType[];
name: string;
actionName: string,
displayName: string,
vars: ProcessingObjectType[];
}
export default defineComponent({
name: 'DataProcessing',
inheritAttrs: false,
components: {
ShowDialog,
ConditionObject,
name: 'DataProcessing',
inheritAttrs: false,
components: {
ShowDialog,
ConditionObject,
},
props: {
context: {
type: Array<Props>,
default: '',
},
props: {
context: {
type: Array<Props>,
default: '',
},
displayName: {
type: String,
default: '',
},
name: {
type: String,
default: '',
},
modelValue: {
type: Object as () => ValueType,
},
displayName: {
type: String,
default: '',
},
name: {
type: String,
default: '',
},
modelValue: {
type: Object as () => ValueType,
},
placeholder: {
type: String,
default: '',
},
},
setup(props, { emit }) {
const source = props.context.find(element => element?.props?.name === 'sources')
setup(props, { emit }) {
const source = props.context.find(element => element?.props?.name === 'sources')
if (source) {
provide('sourceFields', computed(() => {
const modelValue = source.props?.modelValue;
if (modelValue && typeof modelValue !== 'string') {
return modelValue.fields;
}
return null;
}));
if (source) {
provide('sourceFields', computed(() => {
const modelValue = source.props?.modelValue;
if (modelValue && typeof modelValue !== 'string') {
return modelValue.fields;
}
return null;
}));
}
const actionName = props.context.find(element => element?.props?.name === 'displayName')
const actionName = props.context.find(element => element?.props?.name === 'displayName')
const processingProps: ValueType = props.modelValue && props.modelValue.vars
? props.modelValue
: reactive({
name: '',
actionName: actionName?.props?.modelValue as string,
displayName: '結果(戻り値)',
vars: [{ id: uuidv4() }]
});
const processingProps: ValueType = props.modelValue && props.modelValue.vars
? props.modelValue
: reactive({
name: '',
actionName: actionName?.props?.modelValue as string,
displayName: '結果(戻り値)',
vars: [{ id: uuidv4() }]
});
const closeDg = () => {
emit('update:modelValue', processingProps
);
}
const closeDg = () => {
emit('update:modelValue', processingProps
);
}
const processingObjects = processingProps.vars;
const processingObjects = processingProps.vars;
const deleteProcessingObject = (index: number) => processingObjects.length === 1
? processingObjects.splice(0, processingObjects.length, { id: uuidv4() })
: processingObjects.splice(index, 1);
const processingObjectsInputDisplay = computed(() =>
processingObjects ?
processingObjects
.filter(item => item.field && item.logicalOperator && item.vName)
.map(item => {
const name = typeof item.field?.name === 'string'
? item.field.name
: item.field?.name.name;
return `${processingProps.name}.${item.vName} = ${item.logicalOperator}(${name})`
})
: ''
);
const deleteProcessingObject = (index: number) => processingObjects.length === 1
? processingObjects.splice(0, processingObjects.length, { id: uuidv4() })
: processingObjects.splice(index, 1);
watchEffect(() => {
emit('update:modelValue', processingProps);
});
return {
uuidv4,
dgIsShow: ref(false),
closeDg,
processingObjects,
processingProps,
addProcessingObject: () => processingObjects.push({ id: uuidv4() }),
deleteProcessingObject,
logicalOperators: reactive(['MAX', 'SUM']),
processingObjectsInputDisplay,
};
},
const processingObjectsInputDisplay = computed(() =>
processingObjects ?
processingObjects
.filter(item => item.field && item.logicalOperator && item.vName)
.map(item => {
const name = typeof item.field?.name === 'string'
? item.field.name
: item.field?.name.name;
return item.logicalOperator.operator!==''?
`${processingProps.name}.${item.vName} = ${item.logicalOperator.operator}(${name})`
:`${processingProps.name}.${item.vName} = ${name}`
})
: []
);
//集計処理方法
const logicalOperators = ref([
{
"operator": "",
"label": "なし"
},
{
"operator": "SUM",
"label": "合計"
},
{
"operator": "AVG",
"label": "平均"
},
{
"operator": "MAX",
"label": "最大値"
},
{
"operator": "MIN",
"label": "最小値"
},
{
"operator": "COUNT",
"label": "カウント"
},
{
"operator": "FIRST",
"label": "最初の値"
}
]);
watchEffect(() => {
emit('update:modelValue', processingProps);
});
return {
uuidv4,
dgIsShow: ref(false),
closeDg,
processingObjects,
processingProps,
addProcessingObject: () => processingObjects.push({ id: uuidv4() }),
deleteProcessingObject,
logicalOperators,
processingObjectsInputDisplay,
};
},
});
</script>
<style lang="scss"></style>

View File

@@ -1,11 +1,12 @@
<template>
<div v-bind="$attrs">
<q-select v-model="selectedValue" :label="displayName" :options="options"/>
<q-select v-model="selectedValue" :use-chips="multiple" :label="displayName" label-color="primary" :options="options" stack-label
:multiple="multiple"/>
</div>
</template>
<script lang="ts">
import { defineComponent,ref,watchEffect } from 'vue';
import { defineComponent,ref,watchEffect,computed } from 'vue';
export default defineComponent({
name: 'SelectBox',
@@ -23,20 +24,27 @@ export default defineComponent({
type: Array,
required: true,
},
selectType:{
type:String,
default:'',
},
modelValue: {
type: String,
default: '',
type: Object,
default: null,
},
},
setup(props, { emit }) {
const selectedValue = ref(props.modelValue);
const multiple = computed(()=>{
return props.selectType==='multiple'
});
watchEffect(() => {
emit('update:modelValue', selectedValue.value);
});
return {
selectedValue
selectedValue,
multiple
};
},
});