Compare commits
19 Commits
feature-au
...
feature/da
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f70c27d814 | ||
|
|
432e52d322 | ||
|
|
f3893c2500 | ||
|
|
e726843189 | ||
|
|
183abeba41 | ||
|
|
70d2513cd7 | ||
|
|
0fda3d143c | ||
|
|
a85a3683f2 | ||
|
|
14287b6948 | ||
|
|
0443257f86 | ||
|
|
18b97c249a | ||
|
|
4ac4c9e9f4 | ||
|
|
24a70aed2e | ||
|
|
79e38ba6dd | ||
|
|
303a3ffc23 | ||
|
|
af86edd3e2 | ||
|
|
c87cff4181 | ||
|
|
05db5a0522 | ||
|
|
bac7020c15 |
File diff suppressed because one or more lines are too long
@@ -13,7 +13,6 @@ API_V1_AUTH_KEY = "X-Cybozu-Authorization"
|
|||||||
DEPLOY_MODE = "PROD" #DEV,PROD
|
DEPLOY_MODE = "PROD" #DEV,PROD
|
||||||
|
|
||||||
DEPLOY_JS_URL = "https://ka-addin.azurewebsites.net/alc_runtime.js"
|
DEPLOY_JS_URL = "https://ka-addin.azurewebsites.net/alc_runtime.js"
|
||||||
#DEPLOY_JS_URL = "https://ce1c-133-139-70-194.ngrok-free.app/alc_runtime.js"
|
|
||||||
|
|
||||||
KINTONE_FIELD_TYPE=["GROUP","GROUP_SELECT","CHECK_BOX","SUBTABLE","DROP_DOWN","USER_SELECT","RADIO_BUTTON","RICH_TEXT","LINK","REFERENCE_TABLE","CALC","TIME","NUMBER","ORGANIZATION_SELECT","FILE","DATETIME","DATE","MULTI_SELECT","SINGLE_LINE_TEXT","MULTI_LINE_TEXT"]
|
KINTONE_FIELD_TYPE=["GROUP","GROUP_SELECT","CHECK_BOX","SUBTABLE","DROP_DOWN","USER_SELECT","RADIO_BUTTON","RICH_TEXT","LINK","REFERENCE_TABLE","CALC","TIME","NUMBER","ORGANIZATION_SELECT","FILE","DATETIME","DATE","MULTI_SELECT","SINGLE_LINE_TEXT","MULTI_LINE_TEXT"]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#開発環境
|
#開発環境
|
||||||
#KAB_BACKEND_URL="https://kab-backend.azurewebsites.net/"
|
KAB_BACKEND_URL="https://kab-backend.azurewebsites.net/"
|
||||||
#単体テスト環境
|
#単体テスト環境
|
||||||
#KAB_BACKEND_URL="https://kab-backend-unittest.azurewebsites.net/"
|
#KAB_BACKEND_URL="https://kab-backend-unittest.azurewebsites.net/"
|
||||||
#ローカル開発環境
|
#ローカル開発環境
|
||||||
KAB_BACKEND_URL="http://127.0.0.1:8000/"
|
#KAB_BACKEND_URL="http://127.0.0.1:8000/"
|
||||||
|
|||||||
@@ -1,32 +1,35 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-field labelColor="primary" class="condition-object" :clearable="isSelected" stack-label :dense="true"
|
<div class="q-pa-sm">
|
||||||
:outlined="true">
|
<q-field labelColor="primary" class="condition-object" dense outlined :label="label" :disable="disabled"
|
||||||
<template v-slot:control>
|
:clearable="isSelected">
|
||||||
<!-- <q-chip color="primary" text-color="white" v-if="isSelected && selectedObject.objectType==='field'" :dense="true" class="selected-obj">
|
<template v-slot:control>
|
||||||
{{ selectedObject.name }}
|
<q-chip color="primary" text-color="white" v-if="isSelected && selectedObject.objectType==='field'" :dense="true" class="selected-obj">
|
||||||
</q-chip>
|
{{ selectedObject.name }}
|
||||||
<q-chip color="info" text-color="white" v-if="isSelected && selectedObject.objectType==='variable'" :dense="true" class="selected-obj">
|
</q-chip>
|
||||||
{{ selectedObject.name.name }}
|
<q-chip color="info" text-color="white" v-if="isSelected && selectedObject.objectType==='variable'" :dense="true" class="selected-obj">
|
||||||
</q-chip> -->
|
{{ selectedObject.name.name }}
|
||||||
{{ selectedObject?.sharedText }}
|
</q-chip>
|
||||||
</template>
|
<div v-if="isSelected && selectedObject.objectType==='text'">{{ selectedObject?.sharedText }}</div>
|
||||||
<template v-slot:append>
|
</template>
|
||||||
<q-icon name="search" class="cursor-pointer" @click="showDg" />
|
<template v-slot:append>
|
||||||
</template>
|
<q-icon name="search" class="cursor-pointer" @click="showDg" />
|
||||||
</q-field>
|
</template>
|
||||||
<show-dialog v-model:visible="show" name="設定項目" @close="closeDg" min-width="400px">
|
</q-field>
|
||||||
<!-- <template v-slot:toolbar>
|
<show-dialog v-model:visible="show" name="設定項目" @close="closeDg" min-width="400px">
|
||||||
<q-input dense debounce="200" v-model="filter" placeholder="検索" clearable>
|
<!-- <template v-slot:toolbar>
|
||||||
<template v-slot:before>
|
<q-input dense debounce="200" v-model="filter" placeholder="検索" clearable>
|
||||||
<q-icon name="search" />
|
<template v-slot:before>
|
||||||
</template>
|
<q-icon name="search" />
|
||||||
</q-input>
|
</template>
|
||||||
</template>
|
</q-input>
|
||||||
<condition-objects ref="appDg" name="フィールド" type="single" :filter="filter" :appId="store.appInfo?.appId" :vars="vars"></condition-objects>
|
</template>
|
||||||
-->
|
<condition-objects ref="appDg" name="フィールド" type="single" :filter="filter" :appId="store.appInfo?.appId" :vars="vars"></condition-objects>
|
||||||
<DynamicItemInput v-model:selectedObject="selectedObject" :canInput="config.canInput"
|
-->
|
||||||
:buttonsConfig="config.buttonsConfig" :appId="store.appInfo?.appId" />
|
<DynamicItemInput v-model:selectedObject="selectedObject" :canInput="config.canInput"
|
||||||
|
:buttonsConfig="config.buttonsConfig" :appId="store.appInfo?.appId" />
|
||||||
|
|
||||||
</show-dialog>
|
</show-dialog>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -36,6 +39,7 @@ import ShowDialog from '../ShowDialog.vue';
|
|||||||
import DynamicItemInput from '../DynamicItemInput/DynamicItemInput.vue';
|
import DynamicItemInput from '../DynamicItemInput/DynamicItemInput.vue';
|
||||||
import { useFlowEditorStore } from '../../stores/flowEditor';
|
import { useFlowEditorStore } from '../../stores/flowEditor';
|
||||||
import { IActionFlow, IActionNode, IActionVariable } from '../../types/ActionTypes';
|
import { IActionFlow, IActionNode, IActionVariable } from '../../types/ActionTypes';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ConditionObject',
|
name: 'ConditionObject',
|
||||||
components: {
|
components: {
|
||||||
@@ -44,6 +48,14 @@ export default defineComponent({
|
|||||||
// ConditionObjects
|
// ConditionObjects
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
config: {
|
config: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {
|
default: () => {
|
||||||
@@ -68,7 +80,7 @@ export default defineComponent({
|
|||||||
const store = useFlowEditorStore();
|
const store = useFlowEditorStore();
|
||||||
// const sharedText = ref(''); // 共享的文本状态
|
// const sharedText = ref(''); // 共享的文本状态
|
||||||
const isSelected = computed(() => {
|
const isSelected = computed(() => {
|
||||||
return selectedObject?.value?.sharedText !== '';
|
return selectedObject.value?.sharedText !== '';
|
||||||
});
|
});
|
||||||
// const isSelected = computed(()=>{
|
// const isSelected = computed(()=>{
|
||||||
// return selectedObject.value!==null && typeof selectedObject.value === 'object' && ('name' in selectedObject.value)
|
// return selectedObject.value!==null && typeof selectedObject.value === 'object' && ('name' in selectedObject.value)
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
<div @click.stop @keypress.stop v-else >
|
<div @click.stop @keypress.stop v-else >
|
||||||
<div class="row no-wrap items-center q-my-xs">
|
<div class="row no-wrap items-center q-my-xs">
|
||||||
<ConditionObject v-bind="prop.node" v-model="prop.node.object" :config="leftDynamicItemConfig" class="col-4"/>
|
<ConditionObject v-bind="prop.node" v-model="prop.node.object" :config="leftDynamicItemConfig" class="col-4"/>
|
||||||
<q-select v-model="prop.node.operator" :options="operators" class="operator" :outlined="true" :dense="true"></q-select>
|
<q-select v-model="prop.node.operator" :options="operators" class="operator" :outlined="true" :dense="true"></q-select>
|
||||||
<ConditionObject v-bind="prop.node" v-model="prop.node.value" :config="rightDynamicItemConfig" class="col-4"/>
|
<ConditionObject v-bind="prop.node" v-model="prop.node.value" :config="rightDynamicItemConfig" class="col-4"/>
|
||||||
<!-- <ConditionObject v-bind="prop.node" v-model="prop.node.object" class="col-4"/> -->
|
<!-- <ConditionObject v-bind="prop.node" v-model="prop.node.object" class="col-4"/> -->
|
||||||
<!-- <q-input v-if="!prop.node.object || !('options' in prop.node.object)"
|
<!-- <q-input v-if="!prop.node.object || !('options' in prop.node.object)"
|
||||||
@@ -263,7 +263,8 @@ export default defineComponent( {
|
|||||||
.operator{
|
.operator{
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
max-height: 40px;
|
max-height: 40px;
|
||||||
margin: 0 2px;
|
margin-left: 12px;
|
||||||
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 12pt;
|
font-size: 12pt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<!-- <q-card> -->
|
<!-- <q-card> -->
|
||||||
<div class="q-mb-md">
|
<div class="q-mb-md">
|
||||||
<q-input ref="inputRef" outlined dense debounce="200" @update:model-value="updateSharedText"
|
<q-input ref="inputRef" outlined dense debounce="200" @update:model-value="updateSharedText"
|
||||||
v-model="sharedText" :readonly="!canInput">
|
v-model="sharedText" :readonly="!canInput" autogrow>
|
||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
<q-btn flat round padding="none" icon="cancel" @click="clearSharedText" color="grey-6" />
|
<q-btn flat round padding="none" icon="cancel" @click="clearSharedText" color="grey-6" />
|
||||||
</template>
|
</template>
|
||||||
@@ -94,7 +94,7 @@ export default defineComponent({
|
|||||||
dialogVisible.value = false;
|
dialogVisible.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelect = (value) => {
|
const handleSelect = (value:any) => {
|
||||||
// 获取当前光标位置
|
// 获取当前光标位置
|
||||||
// const cursorPosition = inputRef.value.getNativeElement().selectionStart;
|
// const cursorPosition = inputRef.value.getNativeElement().selectionStart;
|
||||||
// if (cursorPosition === undefined || cursorPosition === 0) {
|
// if (cursorPosition === undefined || cursorPosition === 0) {
|
||||||
@@ -104,7 +104,7 @@ export default defineComponent({
|
|||||||
// const textAfter = sharedText.value.substring(cursorPosition);
|
// const textAfter = sharedText.value.substring(cursorPosition);
|
||||||
// sharedText.value = `${textBefore}${value._t}${textAfter}`;
|
// sharedText.value = `${textBefore}${value._t}${textAfter}`;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (value && value._t && (value._t as string).length > 0) {
|
if (value && value._t && (value._t as string).length > 0) {
|
||||||
canInput.value = editable.value;
|
canInput.value = editable.value;
|
||||||
}
|
}
|
||||||
@@ -117,9 +117,9 @@ export default defineComponent({
|
|||||||
canInput.value = true;
|
canInput.value = true;
|
||||||
emit('update:selectedObject', {});
|
emit('update:selectedObject', {});
|
||||||
}
|
}
|
||||||
const updateSharedText = (value) => {
|
const updateSharedText = (value:string) => {
|
||||||
sharedText.value = value;
|
sharedText.value = value;
|
||||||
emit('update:selectedObject', { ...props.selectedObject, sharedText: value });
|
emit('update:selectedObject', { ...props.selectedObject, sharedText: value,objectType:'text' });
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -138,4 +138,4 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ export interface IApp {
|
|||||||
export interface IField {
|
export interface IField {
|
||||||
name: string,
|
name: string,
|
||||||
code: string,
|
code: string,
|
||||||
type: string
|
type: string,
|
||||||
|
label?:string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAppFields {
|
export interface IAppFields {
|
||||||
|
|||||||
@@ -16,52 +16,62 @@
|
|||||||
</q-card>
|
</q-card>
|
||||||
</template>
|
</template>
|
||||||
</q-field>
|
</q-field>
|
||||||
<show-dialog v-model:visible="dgIsShow" name="データマッピング" @close="closeDg" min-width="50vw" min-height="60vh">
|
<show-dialog v-model:visible="dgIsShow" name="データマッピング" @close="closeDg" min-width="55vw" min-height="60vh">
|
||||||
|
|
||||||
<div class="q-mx-md">
|
<div class="">
|
||||||
<div class="row q-col-gutter-x-xs flex-center">
|
<div class="row q-col-gutter-x-xs flex-center">
|
||||||
<div class="col-6">
|
<div class="col-5">
|
||||||
<div class="q-mx-xs">ソース</div>
|
<div class="q-mx-xs">ソース</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="col-1">
|
<!-- <div class="col-1">
|
||||||
</div> -->
|
</div> -->
|
||||||
<div class="col-6">
|
<div class="col-5">
|
||||||
<div class="q-mx-xs">目標</div>
|
<div class="row justify-between q-mr-md">
|
||||||
|
<div class="">{{ sourceApp?.name }}</div>
|
||||||
|
<q-btn outline color="primary" size="xs" label="最新のフィールドを取得する"
|
||||||
|
@click="() => updateFields(sourceAppId!)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-1 q-pl-sm">
|
||||||
|
キー
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="col-1"><q-btn flat round dense icon="add" size="sm" @click="addMappingObject" /> -->
|
|
||||||
<!-- </div> -->
|
|
||||||
</div>
|
</div>
|
||||||
<q-virtual-scroll style="max-height: 75vh;" :items="mappingProps" separator v-slot="{ item, index }">
|
<q-virtual-scroll style="max-height: 60vh;" :items="mappingProps" separator v-slot="{ item, index }">
|
||||||
<!-- <div class="q-my-sm" v-for="(item, index) in mappingProps" :key="item.id"> -->
|
<!-- <div class="q-my-sm" v-for="(item, index) in mappingProps" :key="item.id"> -->
|
||||||
<div class="row q-my-md q-col-gutter-x-md flex-center">
|
<div class="row q-pa-sm q-col-gutter-x-md flex-center">
|
||||||
<div class="col-6">
|
<div class="col-5">
|
||||||
<ConditionObject :config="config" v-model="item.from" />
|
<ConditionObject :config="config" v-model="item.from" :disabled="item.disabled"
|
||||||
|
:label="item.disabled ? '「Lookup」によってロックされる' : undefined" />
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="col-1">
|
<!-- <div class="col-1">
|
||||||
</div> -->
|
</div> -->
|
||||||
<div class="col-6">
|
<div class="col-5">
|
||||||
<q-field v-model="item.vName" type="text" outlined dense>
|
<q-field v-model="item.vName" type="text" outlined dense :disable="item.disabled" >
|
||||||
<!-- <template v-slot:append>
|
<!-- <template v-slot:append>
|
||||||
<q-icon name="search" class="cursor-pointer"
|
<q-icon name="search" class="cursor-pointer"
|
||||||
@click="() => { mappingProps[index].to.isDialogVisible = true }" />
|
@click="() => { mappingProps[index].to.isDialogVisible = true }" />
|
||||||
</template> -->
|
</template> -->
|
||||||
<template v-slot:control>
|
<template v-slot:control>
|
||||||
<div class="self-center full-width no-outline" tabindex="0"
|
<div class="self-center full-width no-outline" tabindex="0"
|
||||||
v-if="item.to.app?.name && item.to.fields?.length > 0 && item.to.fields[0].label">
|
v-if="item.to.app?.name && item.to.fields?.length > 0 && item.to.fields[0].label">
|
||||||
{{ `${item.to.fields[0].label}` }}
|
{{ `${item.to.fields[0].label}` }}
|
||||||
<q-tooltip>
|
<span class="text-red" v-if="item.to.fields[0].required">*</span>
|
||||||
|
<q-tooltip class="bg-yellow-2 text-black shadow-4" >
|
||||||
<div>アプリ : {{ item.to.app.name }}</div>
|
<div>アプリ : {{ item.to.app.name }}</div>
|
||||||
<div>フィールドのコード : {{ item.to.fields[0].code }}</div>
|
<div>フィールドのコード : {{ item.to.fields[0].code }}</div>
|
||||||
<div>フィールドのタイプ : {{ item.to.fields[0].type }}</div>
|
<div>フィールドのタイプ : {{ item.to.fields[0].type }}</div>
|
||||||
<div>フィールド : {{ item.to.fields[0] }}</div>
|
<div v-if="item.to.fields[0].required">必須項目</div>
|
||||||
|
<!-- <div>フィールド : {{ item.to.fields[0] }}</div>
|
||||||
|
<div>フィールド : {{ item.isKey }}</div> -->
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</q-field>
|
</q-field>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="col-1">
|
<div class="col-1">
|
||||||
<q-btn flat round dense icon="delete" size="sm" @click="() => deleteMappingObject(index)" />
|
<q-checkbox size="sm" v-model="item.isKey" :disable="item.disabled" />
|
||||||
</div> -->
|
<!-- <q-btn flat round dense icon="delete" size="sm" @click="() => deleteMappingObject(index)" /> -->
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<show-dialog v-model:visible="mappingProps[index].to.isDialogVisible" name="フィールド一覧"
|
<show-dialog v-model:visible="mappingProps[index].to.isDialogVisible" name="フィールド一覧"
|
||||||
@@ -74,6 +84,10 @@
|
|||||||
</show-dialog>
|
</show-dialog>
|
||||||
<!-- </div> -->
|
<!-- </div> -->
|
||||||
</q-virtual-scroll>
|
</q-virtual-scroll>
|
||||||
|
|
||||||
|
<div class="q-mt-lg q-ml-md row ">
|
||||||
|
<q-checkbox size="sm" v-model="createWithNull" label="キーが存在しない場合は新規に作成され、存在する場合はデータが更新されます。" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</show-dialog>
|
</show-dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -86,10 +100,10 @@ import ConditionObject from '../ConditionEditor/ConditionObject.vue';
|
|||||||
import ShowDialog from '../ShowDialog.vue';
|
import ShowDialog from '../ShowDialog.vue';
|
||||||
import AppFieldSelectBox from '../AppFieldSelectBox.vue';
|
import AppFieldSelectBox from '../AppFieldSelectBox.vue';
|
||||||
import FieldSelect from '../FieldSelect.vue';
|
import FieldSelect from '../FieldSelect.vue';
|
||||||
import IAppFields from './AppFieldSelect.vue';
|
import { IApp, IField } from './AppFieldSelect.vue';
|
||||||
import { api } from 'boot/axios';
|
import { api } from 'boot/axios';
|
||||||
|
|
||||||
type Props = {
|
type ContextProps = {
|
||||||
props?: {
|
props?: {
|
||||||
name: string;
|
name: string;
|
||||||
modelValue?: {
|
modelValue?: {
|
||||||
@@ -100,14 +114,25 @@ type Props = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
type ValueType = {
|
|
||||||
id: string;
|
type CurrentModelValueType = {
|
||||||
from: object;
|
data: MappingValueType[];
|
||||||
to: typeof IAppFields & {
|
createWithNull: boolean;
|
||||||
isDialogVisible: boolean;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MappingValueType = {
|
||||||
|
id: string;
|
||||||
|
from: { sharedText?: string };
|
||||||
|
to: {
|
||||||
|
app?: IApp,
|
||||||
|
fields: IField[],
|
||||||
|
isDialogVisible: boolean;
|
||||||
|
};
|
||||||
|
isKey: boolean;
|
||||||
|
disabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const blackListLabelName = ['レコード番号', '作業者', '更新者', '更新日時', '作成日時', '作成者']
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'DataMapping',
|
name: 'DataMapping',
|
||||||
@@ -120,7 +145,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
context: {
|
context: {
|
||||||
type: Array<Props>,
|
type: Array<ContextProps>,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
displayName: {
|
displayName: {
|
||||||
@@ -132,7 +157,7 @@ export default defineComponent({
|
|||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Object as () => ValueType[],
|
type: Object as () => CurrentModelValueType,
|
||||||
},
|
},
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -141,7 +166,11 @@ export default defineComponent({
|
|||||||
onlySourceSelect: {
|
onlySourceSelect: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
}
|
},
|
||||||
|
fieldTypes:{
|
||||||
|
type:Array,
|
||||||
|
default:()=>[]
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
@@ -152,58 +181,62 @@ export default defineComponent({
|
|||||||
const sourceAppId = computed(() => sourceApp.value?.id);
|
const sourceAppId = computed(() => sourceApp.value?.id);
|
||||||
|
|
||||||
const closeDg = () => {
|
const closeDg = () => {
|
||||||
emit('update:modelValue', mappingProps.value
|
emit('update:modelValue', { data: mappingProps.value, createWithNull: createWithNull.value });
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeToDg = () => {
|
const closeToDg = () => {
|
||||||
emit('update:modelValue', mappingProps.value
|
emit('update:modelValue', { data: mappingProps.value, createWithNull: createWithNull.value });
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mappingProps = computed(() => props.modelValue ?? []);
|
const mappingProps = ref(props.modelValue?.data ?? []);
|
||||||
|
|
||||||
watch(() => sourceAppId.value, async (newId, oldId) => {
|
const createWithNull = ref(props.modelValue?.createWithNull ?? false)
|
||||||
|
|
||||||
|
// 外部ソースコンポーネントの appid をリッスンし、変更されたときに現在のコンポーネントを更新します
|
||||||
|
watch(() => sourceAppId.value, async (newId,) => {
|
||||||
if (!newId) return;
|
if (!newId) return;
|
||||||
const a = await api.get('api/v1/appfields', {
|
updateFields(newId)
|
||||||
|
})
|
||||||
|
|
||||||
|
const updateFields = async (sourceAppId: string) => {
|
||||||
|
const ktAppFields = await api.get('api/v1/appfields', {
|
||||||
params: {
|
params: {
|
||||||
app: newId
|
app: sourceAppId
|
||||||
}
|
}
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
return Object.values(res.data.properties)
|
return Object.values(res.data.properties)
|
||||||
|
// kintoneのデフォルトの非表示フィールドフィルタリング
|
||||||
|
.filter(f => !blackListLabelName.find(label => f.label === label))
|
||||||
.map(f => ({ name: f.label, objectType: 'field', ...f }))
|
.map(f => ({ name: f.label, objectType: 'field', ...f }))
|
||||||
.map(f => {
|
.map(f => {
|
||||||
|
// 更新前の値を求める
|
||||||
|
const beforeData = mappingProps.value.find(m => m.to.fields[0].code === f.code)
|
||||||
return {
|
return {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
from: {},
|
from: beforeData?.from ?? {}, // 以前のデータを入力します
|
||||||
to: {
|
to: {
|
||||||
app: sourceApp.value,
|
app: sourceApp.value,
|
||||||
fields: [f],
|
fields: [f],
|
||||||
isDialogVisible: false
|
isDialogVisible: false
|
||||||
}
|
},
|
||||||
|
isKey: beforeData?.isKey ?? false, // 以前のデータを入力します
|
||||||
|
disabled: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
const modelValue = props.modelValue ?? [];
|
|
||||||
|
|
||||||
if (modelValue.length === 0 || newId !== oldId) {
|
// 「ルックアップ」によってロックされているフィールドを検索する
|
||||||
emit('update:modelValue', a);
|
const lookupFixedField = ktAppFields
|
||||||
return;
|
.filter(field => field.to.fields[0].lookup !== undefined)
|
||||||
|
.flatMap(field => field.to.fields[0].lookup.fieldMappings.map((m) => m.field))
|
||||||
|
|
||||||
|
// 「ルックアップ」でロックされたビューコンポーネントを非対話型に設定します
|
||||||
|
if (lookupFixedField.length > 0) {
|
||||||
|
ktAppFields.filter(f => lookupFixedField.includes(f.to.fields[0].code)).forEach(f => f.disabled = true)
|
||||||
}
|
}
|
||||||
const modelValueFieldNames = modelValue.map(item => item.to.fields[0].name);
|
|
||||||
|
|
||||||
const newFields = a.filter(field => !modelValueFieldNames.includes(field.to.fields[0].name));
|
mappingProps.value = ktAppFields
|
||||||
|
}
|
||||||
const updatedModelValue = [...modelValue, ...newFields];
|
|
||||||
|
|
||||||
emit('update:modelValue', updatedModelValue);
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log(mappingProps.value);
|
|
||||||
|
|
||||||
// const deleteMappingObject = (index: number) => mappingProps.length === 1
|
|
||||||
// ? mappingProps.splice(0, mappingProps.length, defaultMappingProp())
|
|
||||||
// : mappingProps.splice(index, 1);
|
|
||||||
|
|
||||||
const mappingObjectsInputDisplay = computed(() =>
|
const mappingObjectsInputDisplay = computed(() =>
|
||||||
(mappingProps.value && Array.isArray(mappingProps.value)) ?
|
(mappingProps.value && Array.isArray(mappingProps.value)) ?
|
||||||
@@ -215,15 +248,12 @@ export default defineComponent({
|
|||||||
: []
|
: []
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const btnDisable = computed(() => props.onlySourceSelect ? !(source?.props?.modelValue?.app?.id) : false);
|
const btnDisable = computed(() => props.onlySourceSelect ? !(source?.props?.modelValue?.app?.id) : false);
|
||||||
|
|
||||||
//集計処理方法
|
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
emit('update:modelValue', mappingProps.value);
|
emit('update:modelValue', { data: mappingProps.value, createWithNull: createWithNull.value });
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uuidv4,
|
uuidv4,
|
||||||
dgIsShow: ref(false),
|
dgIsShow: ref(false),
|
||||||
@@ -231,6 +261,8 @@ export default defineComponent({
|
|||||||
toDgIsShow: ref(false),
|
toDgIsShow: ref(false),
|
||||||
closeToDg,
|
closeToDg,
|
||||||
mappingProps,
|
mappingProps,
|
||||||
|
createWithNull,
|
||||||
|
updateFields,
|
||||||
// addMappingObject: () => mappingProps.push(defaultMappingProp()),
|
// addMappingObject: () => mappingProps.push(defaultMappingProp()),
|
||||||
// deleteMappingObject,
|
// deleteMappingObject,
|
||||||
mappingObjectsInputDisplay,
|
mappingObjectsInputDisplay,
|
||||||
@@ -240,11 +272,13 @@ export default defineComponent({
|
|||||||
config: {
|
config: {
|
||||||
canInput: false,
|
canInput: false,
|
||||||
buttonsConfig: [
|
buttonsConfig: [
|
||||||
{ label: '変数', color: 'green', type: 'VariableAdd',editable:false },
|
{ label: 'フィールド', color: 'primary', type: 'FieldAdd' },
|
||||||
|
{ label: '変数', color: 'green', type: 'VariableAdd', editable: false },
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss"></style>
|
<style lang="scss"></style>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
<div class="col-5">
|
<div class="col-5">
|
||||||
<ConditionObject v-model="item.field" />
|
<ConditionObject v-model="item.field" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2">
|
<div class="col-2 q-pa-sm">
|
||||||
<q-select v-model="item.logicalOperator" :options="logicalOperators" outlined dense></q-select>
|
<q-select v-model="item.logicalOperator" :options="logicalOperators" outlined dense></q-select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
@@ -78,14 +78,8 @@ type Props = {
|
|||||||
|
|
||||||
type ProcessingObjectType = {
|
type ProcessingObjectType = {
|
||||||
field?: {
|
field?: {
|
||||||
name: string | {
|
sharedText: string;
|
||||||
name: string;
|
objectType: 'field';
|
||||||
};
|
|
||||||
objectType: string;
|
|
||||||
type: string;
|
|
||||||
code: string;
|
|
||||||
label: string;
|
|
||||||
noLabel: boolean;
|
|
||||||
};
|
};
|
||||||
logicalOperator?: string;
|
logicalOperator?: string;
|
||||||
vName?: string;
|
vName?: string;
|
||||||
@@ -145,34 +139,54 @@ export default defineComponent({
|
|||||||
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
|
const processingProps: ValueType = props.modelValue && props.modelValue.vars
|
||||||
? props.modelValue
|
? reactive(props.modelValue)
|
||||||
: reactive({
|
: reactive({
|
||||||
name: '',
|
name: '',
|
||||||
actionName: actionName?.props?.modelValue as string,
|
actionName: actionName?.props?.modelValue as string,
|
||||||
displayName: '結果(戻り値)',
|
displayName: '結果(戻り値)',
|
||||||
vars: [{ id: uuidv4() }]
|
vars: [
|
||||||
|
{
|
||||||
|
id: uuidv4(),
|
||||||
|
field:{
|
||||||
|
objectType:'field',
|
||||||
|
sharedText:''
|
||||||
|
}
|
||||||
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
const closeDg = () => {
|
const closeDg = () => {
|
||||||
emit('update:modelValue', processingProps
|
emit('update:modelValue', processingProps);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const processingObjects = processingProps.vars;
|
const processingObjects = processingProps.vars;
|
||||||
|
|
||||||
const deleteProcessingObject = (index: number) => processingObjects.length === 1
|
const deleteProcessingObject = (index: number) => {
|
||||||
? processingObjects.splice(0, processingObjects.length, { id: uuidv4() })
|
if(processingObjects.length >0){
|
||||||
: processingObjects.splice(index, 1);
|
processingObjects.splice(index, 1);
|
||||||
|
}
|
||||||
|
if(processingObjects.length===0){
|
||||||
|
addProcessingObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
const processingObjectsInputDisplay = computed(() =>
|
const processingObjectsInputDisplay = computed(() =>
|
||||||
processingObjects ?
|
processingObjects ?
|
||||||
processingObjects
|
processingObjects
|
||||||
.filter(item => item.field && item.logicalOperator && item.vName)
|
.filter(item => item.field && item.logicalOperator && item.vName)
|
||||||
.map(item => {
|
.map(item => {
|
||||||
return`var(${processingProps.name}.${item.vName}) = ${item.field.sharedText}`
|
return`var(${processingProps.name}.${item.vName}) = ${item.field?.sharedText}`
|
||||||
})
|
})
|
||||||
: []
|
: []
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const addProcessingObject=()=>{
|
||||||
|
processingObjects.push({
|
||||||
|
id: uuidv4(),
|
||||||
|
field:{
|
||||||
|
objectType:'field',
|
||||||
|
sharedText:''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
//集計処理方法
|
//集計処理方法
|
||||||
const logicalOperators = ref([
|
const logicalOperators = ref([
|
||||||
{
|
{
|
||||||
@@ -214,7 +228,7 @@ export default defineComponent({
|
|||||||
closeDg,
|
closeDg,
|
||||||
processingObjects,
|
processingObjects,
|
||||||
processingProps,
|
processingProps,
|
||||||
addProcessingObject: () => processingObjects.push({ id: uuidv4() }),
|
addProcessingObject,
|
||||||
deleteProcessingObject,
|
deleteProcessingObject,
|
||||||
logicalOperators,
|
logicalOperators,
|
||||||
processingObjectsInputDisplay,
|
processingObjectsInputDisplay,
|
||||||
|
|||||||
@@ -26,15 +26,13 @@
|
|||||||
"sass": "^1.69.5",
|
"sass": "^1.69.5",
|
||||||
"typescript": "^5.0.2",
|
"typescript": "^5.0.2",
|
||||||
"vite": "^4.4.5",
|
"vite": "^4.4.5",
|
||||||
"vite-plugin-checker": "^0.6.4",
|
"vite-plugin-checker": "^0.6.4"
|
||||||
"vite-plugin-lib-inject-css": "^2.1.1"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kintone/rest-api-client": "^5.5.2",
|
"@kintone/rest-api-client": "^5.5.2",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"@types/bootstrap": "^5.2.10",
|
"@types/bootstrap": "^5.2.10",
|
||||||
"bootstrap": "^5.3.3",
|
"bootstrap": "^5.3.3",
|
||||||
"jquery": "^3.7.1",
|
"jquery": "^3.7.1"
|
||||||
"vite-plugin-css-injected-by-js": "^3.5.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ interface Field {
|
|||||||
noLabel: boolean;
|
noLabel: boolean;
|
||||||
required: boolean;
|
required: boolean;
|
||||||
lookup: Lookup;
|
lookup: Lookup;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Lookup {
|
interface Lookup {
|
||||||
relatedApp: RelatedApp;
|
relatedApp: RelatedApp;
|
||||||
|
|||||||
@@ -1,166 +0,0 @@
|
|||||||
import {
|
|
||||||
IAction,
|
|
||||||
IActionResult,
|
|
||||||
IActionNode,
|
|
||||||
IActionProperty,
|
|
||||||
IContext,
|
|
||||||
} from "../types/ActionTypes";
|
|
||||||
import { actionAddins } from ".";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
displayName: string;
|
|
||||||
sources: Sources;
|
|
||||||
dataMapping: DataMapping[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DataMapping {
|
|
||||||
id: string;
|
|
||||||
from: From;
|
|
||||||
to: To;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface To {
|
|
||||||
app: App;
|
|
||||||
fields: Field[];
|
|
||||||
isDialogVisible: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Field {
|
|
||||||
name: string;
|
|
||||||
type: string;
|
|
||||||
code: string;
|
|
||||||
label: string;
|
|
||||||
noLabel: boolean;
|
|
||||||
required: boolean;
|
|
||||||
minLength: string;
|
|
||||||
maxLength: string;
|
|
||||||
expression: string;
|
|
||||||
hideExpression: boolean;
|
|
||||||
unique: boolean;
|
|
||||||
defaultValue: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface From {
|
|
||||||
sharedText: string;
|
|
||||||
_t: string;
|
|
||||||
id: string;
|
|
||||||
objectType: string;
|
|
||||||
name: Name;
|
|
||||||
actionName: string;
|
|
||||||
displayName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Name {
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Sources {
|
|
||||||
app: App;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface App {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
description: string;
|
|
||||||
createdate: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DataMappingAction implements IAction {
|
|
||||||
name: string;
|
|
||||||
actionProps: IActionProperty[];
|
|
||||||
dataMappingProps: Props;
|
|
||||||
constructor() {
|
|
||||||
this.name = "データマッピング";
|
|
||||||
this.actionProps = [];
|
|
||||||
this.dataMappingProps = {} as Props;
|
|
||||||
this.register();
|
|
||||||
}
|
|
||||||
|
|
||||||
async process(
|
|
||||||
prop: IActionNode,
|
|
||||||
event: any,
|
|
||||||
context: IContext
|
|
||||||
): Promise<IActionResult> {
|
|
||||||
this.actionProps = prop.actionProps;
|
|
||||||
this.dataMappingProps = prop.ActionValue as Props;
|
|
||||||
console.log(prop.ActionValue);
|
|
||||||
|
|
||||||
// this.initTypedActionProps();
|
|
||||||
let result = {
|
|
||||||
canNext: true,
|
|
||||||
result: "",
|
|
||||||
} as IActionResult;
|
|
||||||
try {
|
|
||||||
const record = this.dataMappingProps.dataMapping
|
|
||||||
.filter(
|
|
||||||
(item) =>
|
|
||||||
item.from.objectType === "variable" &&
|
|
||||||
item.from.name.name &&
|
|
||||||
item.to.app &&
|
|
||||||
item.to.fields &&
|
|
||||||
item.to.fields.length > 0
|
|
||||||
)
|
|
||||||
.reduce((accumulator, item) => {
|
|
||||||
return {...accumulator, [item.to.fields[0].code]: {
|
|
||||||
value: getValueByPath(context.variables, item.from.name.name),
|
|
||||||
}};
|
|
||||||
}, {});
|
|
||||||
if (record && Object.keys(record).length > 0) {
|
|
||||||
await kintone.api(kintone.api.url("/k/v1/record.json", true), "POST", {
|
|
||||||
app: this.dataMappingProps.sources.app.id,
|
|
||||||
record: record,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("DataMappingAction error", error);
|
|
||||||
result.canNext = false;
|
|
||||||
}
|
|
||||||
console.log("dataMappingProps", this.dataMappingProps);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
register(): void {
|
|
||||||
actionAddins[this.name] = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new DataMappingAction();
|
|
||||||
|
|
||||||
const getValueByPath = (obj: any, path: string) => {
|
|
||||||
return path.split(".").reduce((o, k) => (o || {})[k], obj);
|
|
||||||
};
|
|
||||||
|
|
||||||
type Resp = { records: RespRecordType[] };
|
|
||||||
|
|
||||||
type RespRecordType = {
|
|
||||||
[key: string]: {
|
|
||||||
type: string;
|
|
||||||
value: any;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
type Result = {
|
|
||||||
type: string;
|
|
||||||
value: any[];
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectData = async (appid: string, field: string): Promise<Result> => {
|
|
||||||
return kintone
|
|
||||||
.api(kintone.api.url("/k/v1/records", true), "GET", {
|
|
||||||
app: appid ?? kintone.app.getId(),
|
|
||||||
fields: [field],
|
|
||||||
})
|
|
||||||
.then((resp: Resp) => {
|
|
||||||
const result: Result = { type: "", value: [] };
|
|
||||||
resp.records.forEach((element) => {
|
|
||||||
for (const [key, value] of Object.entries(element)) {
|
|
||||||
if (result.type === "") {
|
|
||||||
result.type = value.type;
|
|
||||||
}
|
|
||||||
result.value.push(value.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -6,67 +6,19 @@ import {
|
|||||||
IContext,
|
IContext,
|
||||||
} from "../types/ActionTypes";
|
} from "../types/ActionTypes";
|
||||||
import { actionAddins } from ".";
|
import { actionAddins } from ".";
|
||||||
|
import {KintoneRestAPIClient} from '@kintone/rest-api-client';
|
||||||
|
import { Aggregator,Operator} from '../util/aggregates';
|
||||||
|
import { FieldForm } from "../types/FieldLayout";
|
||||||
|
|
||||||
interface Props {
|
interface IDataProcessingProps {
|
||||||
displayName: string;
|
displayName: string;
|
||||||
sources: Sources;
|
sources: Sources;
|
||||||
condition: string;
|
condition: string;
|
||||||
conditionO: Condition;
|
verName?: VerName;
|
||||||
verName: VerName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Condition {
|
interface Condition {
|
||||||
queryString: string;
|
queryString: string;
|
||||||
index: number;
|
|
||||||
type: string;
|
|
||||||
children: Child[];
|
|
||||||
parent: null;
|
|
||||||
logicalOperator: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Child {
|
|
||||||
index: number;
|
|
||||||
type: string;
|
|
||||||
parent: string;
|
|
||||||
object: Object;
|
|
||||||
operator: ChildOperator;
|
|
||||||
value: Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Value {
|
|
||||||
sharedText: string;
|
|
||||||
_t: string;
|
|
||||||
objectType: string;
|
|
||||||
actionName: string;
|
|
||||||
displayName: string;
|
|
||||||
name: Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Name {
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ChildOperator {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Object {
|
|
||||||
sharedText: string;
|
|
||||||
_t: string;
|
|
||||||
name: string;
|
|
||||||
objectType: string;
|
|
||||||
type: string;
|
|
||||||
code: string;
|
|
||||||
label: string;
|
|
||||||
noLabel: boolean;
|
|
||||||
required: boolean;
|
|
||||||
minLength: string;
|
|
||||||
maxLength: string;
|
|
||||||
expression: string;
|
|
||||||
hideExpression: boolean;
|
|
||||||
unique: boolean;
|
|
||||||
defaultValue: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface VerName {
|
interface VerName {
|
||||||
@@ -78,170 +30,26 @@ interface VerName {
|
|||||||
|
|
||||||
interface Var {
|
interface Var {
|
||||||
id: string;
|
id: string;
|
||||||
field: Field2;
|
field: FieldForm;
|
||||||
logicalOperator: LogicalOperator;
|
logicalOperator: CalcOperator;
|
||||||
vName: string;
|
vName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LogicalOperator {
|
interface CalcOperator {
|
||||||
operator: string;
|
operator: Operator;
|
||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Field2 {
|
|
||||||
sharedText: string;
|
|
||||||
_t: string;
|
|
||||||
name: string;
|
|
||||||
objectType: string;
|
|
||||||
type: string;
|
|
||||||
code: string;
|
|
||||||
label: string;
|
|
||||||
noLabel: boolean;
|
|
||||||
required: boolean;
|
|
||||||
minLength: string;
|
|
||||||
maxLength: string;
|
|
||||||
expression: string;
|
|
||||||
hideExpression: boolean;
|
|
||||||
unique: boolean;
|
|
||||||
defaultValue: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Sources {
|
interface Sources {
|
||||||
app: App;
|
app: App;
|
||||||
fields: Field[];
|
fields: FieldForm[];
|
||||||
}
|
|
||||||
|
|
||||||
interface Field {
|
|
||||||
name: string;
|
|
||||||
type: string;
|
|
||||||
code: string;
|
|
||||||
label: string;
|
|
||||||
noLabel: boolean;
|
|
||||||
required: boolean;
|
|
||||||
minLength: string;
|
|
||||||
maxLength: string;
|
|
||||||
expression: string;
|
|
||||||
hideExpression: boolean;
|
|
||||||
unique: boolean;
|
|
||||||
defaultValue: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface App {
|
interface App {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name?: string;
|
||||||
description: string;
|
|
||||||
createdate: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DataProcessingAction implements IAction {
|
|
||||||
name: string;
|
|
||||||
actionProps: IActionProperty[];
|
|
||||||
dataProcessingProps: Props | null;
|
|
||||||
constructor() {
|
|
||||||
this.name = "データ処理";
|
|
||||||
this.actionProps = [];
|
|
||||||
this.dataProcessingProps = null;
|
|
||||||
this.register();
|
|
||||||
}
|
|
||||||
|
|
||||||
async process(
|
|
||||||
nodes: IActionNode,
|
|
||||||
event: any,
|
|
||||||
context: IContext
|
|
||||||
): Promise<IActionResult> {
|
|
||||||
this.actionProps = nodes.actionProps;
|
|
||||||
this.dataProcessingProps = nodes.ActionValue as Props;
|
|
||||||
this.dataProcessingProps.conditionO = JSON.parse(
|
|
||||||
this.dataProcessingProps.condition
|
|
||||||
);
|
|
||||||
let result = {
|
|
||||||
canNext: true,
|
|
||||||
result: "",
|
|
||||||
} as IActionResult;
|
|
||||||
try {
|
|
||||||
if (!this.dataProcessingProps) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await selectData(
|
|
||||||
varGet(
|
|
||||||
this.dataProcessingProps.conditionO.queryString,
|
|
||||||
context.variables
|
|
||||||
)
|
|
||||||
);
|
|
||||||
console.log("data ", data);
|
|
||||||
|
|
||||||
context.variables[this.dataProcessingProps.verName.name] =
|
|
||||||
this.dataProcessingProps.verName.vars.reduce((acc, f) => {
|
|
||||||
const v = calc(f, data);
|
|
||||||
if (v) {
|
|
||||||
acc[f.vName] = calc(f, data);
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, {} as AnyObject);
|
|
||||||
|
|
||||||
console.log("context ", context);
|
|
||||||
return result;
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
event.error = error;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
register(): void {
|
|
||||||
actionAddins[this.name] = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new DataProcessingAction();
|
|
||||||
|
|
||||||
const varGet = (str: string, vars: any) => {
|
|
||||||
console.log(str);
|
|
||||||
|
|
||||||
const regex = /var\((.*?)\)/g;
|
|
||||||
let match;
|
|
||||||
while ((match = regex.exec(str)) !== null) {
|
|
||||||
const varName = match[1];
|
|
||||||
if (varName in vars) {
|
|
||||||
str = str.replace(match[0], vars[varName]);
|
|
||||||
} else {
|
|
||||||
throw new Error(`変数${varName}が見つかりません`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log(str);
|
|
||||||
return str;
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectData = async (query?: string) => {
|
|
||||||
return kintone
|
|
||||||
.api(kintone.api.url("/k/v1/records", true), "GET", {
|
|
||||||
app: kintone.app.getId(),
|
|
||||||
query: query,
|
|
||||||
})
|
|
||||||
.then((resp: Resp) => {
|
|
||||||
const result: Result = {};
|
|
||||||
resp.records.forEach((element) => {
|
|
||||||
for (const [key, value] of Object.entries(element)) {
|
|
||||||
if (!result[key]) {
|
|
||||||
result[key] = { type: value.type, value: [] };
|
|
||||||
}
|
|
||||||
result[key].value.push(value.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
type Resp = { records: RespRecordType[] };
|
|
||||||
|
|
||||||
type RespRecordType = {
|
|
||||||
[key: string]: {
|
|
||||||
type: string;
|
|
||||||
value: any;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
type Result = {
|
type Result = {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
type: string;
|
type: string;
|
||||||
@@ -253,122 +61,125 @@ type AnyObject = {
|
|||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ERROR_TYPE = "ERROR_TYPE";
|
export class DataProcessingAction implements IAction {
|
||||||
|
name: string;
|
||||||
|
actionProps: IActionProperty[];
|
||||||
|
props: IDataProcessingProps ;
|
||||||
|
|
||||||
const calc = (f: Var, result: Result) => {
|
constructor() {
|
||||||
const type = typeCheck(f.field.type);
|
this.name = "データ処理";
|
||||||
if (!type) {
|
this.actionProps = [];
|
||||||
return ERROR_TYPE;
|
this.props = {
|
||||||
|
displayName:'',
|
||||||
|
condition:'',
|
||||||
|
sources:{
|
||||||
|
app:{
|
||||||
|
id:""
|
||||||
|
},
|
||||||
|
fields:[]
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this.register();
|
||||||
}
|
}
|
||||||
|
|
||||||
const fun =
|
async process(
|
||||||
calcFunc[
|
nodes: IActionNode,
|
||||||
`${type}_${Operator[f.logicalOperator.operator as keyof typeof Operator]}`
|
event: any,
|
||||||
];
|
context: IContext
|
||||||
if (!fun) {
|
): Promise<IActionResult> {
|
||||||
return ERROR_TYPE;
|
this.actionProps = nodes.actionProps;
|
||||||
}
|
|
||||||
const values = result[f.field.code].value;
|
|
||||||
if (!values) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return fun(values);
|
|
||||||
};
|
|
||||||
|
|
||||||
const typeCheck = (type: string) => {
|
this.props = nodes.ActionValue as IDataProcessingProps;
|
||||||
switch (type) {
|
const condition = JSON.parse(this.props.condition) as Condition;
|
||||||
case "RECORD_NUMBER":
|
let result = {
|
||||||
case "NUMBER":
|
canNext: true,
|
||||||
return CalcType.NUMBER;
|
result: "",
|
||||||
case "SINGLE_LINE_TEXT":
|
} as IActionResult;
|
||||||
case "MULTI_LINE_TEXT":
|
try {
|
||||||
case "RICH_TEXT":
|
if (!this.props) {
|
||||||
return CalcType.STRING;
|
return result;
|
||||||
case "DATE":
|
}
|
||||||
return CalcType.DATE;
|
|
||||||
case "TIME":
|
|
||||||
return CalcType.TIME;
|
|
||||||
case "DATETIME":
|
|
||||||
case "UPDATED_TIME":
|
|
||||||
return CalcType.DATETIME;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Operator {
|
const query = this.getQuery(condition.queryString,context.variables);
|
||||||
SUM = "SUM",
|
const data = await this.selectData(query);
|
||||||
AVG = "AVG",
|
|
||||||
MAX = "MAX",
|
console.log("data ", data);
|
||||||
MIN = "MIN",
|
|
||||||
COUNT = "COUNT",
|
if(this.props.verName){
|
||||||
FIRST = "FIRST",
|
const varValues= this.props.verName.vars.reduce((acc, f) => {
|
||||||
|
const datas=data[f.field.code].value;
|
||||||
|
const agg = new Aggregator(datas,f.field);
|
||||||
|
const result = agg.calculate(f.logicalOperator.operator)
|
||||||
|
acc[f.vName]=result;
|
||||||
|
return acc;
|
||||||
|
}, {} as AnyObject);
|
||||||
|
context.variables[this.props.verName.name]=varValues;
|
||||||
|
console.log("context ", context);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("データ集計中例外が発生しました。", error);
|
||||||
|
if(error instanceof Error){
|
||||||
|
event.error = `データ集計中例外が発生しました。 ${error.message}`;
|
||||||
|
}else{
|
||||||
|
event.error = "データ集計中例外が発生しました。";
|
||||||
|
}
|
||||||
|
result.canNext = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param str
|
||||||
|
* @param vars
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
getQuery = (str: string, vars: any) => {
|
||||||
|
console.log(str);
|
||||||
|
const regex = /var\((.*?)\)/g;
|
||||||
|
let match;
|
||||||
|
while ((match = regex.exec(str)) !== null) {
|
||||||
|
const varName = match[1];
|
||||||
|
if (varName in vars) {
|
||||||
|
str = str.replace(match[0], vars[varName]);
|
||||||
|
} else {
|
||||||
|
throw new Error(`変数${varName}が見つかりません`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(str);
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* データを取得する
|
||||||
|
* @param query
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
selectData = async ( query?: string) => {
|
||||||
|
const api = new KintoneRestAPIClient();
|
||||||
|
const fields = this.props.sources.fields.map((field)=>field.code);
|
||||||
|
const resp = await api.record.getAllRecords({
|
||||||
|
app: this.props.sources.app.id,
|
||||||
|
fields:fields,
|
||||||
|
condition:query
|
||||||
|
});
|
||||||
|
const result: Result = {};
|
||||||
|
resp.forEach((element) => {
|
||||||
|
for (const [key, value] of Object.entries(element)) {
|
||||||
|
if (!result[key]) {
|
||||||
|
result[key] = { type: value.type, value: [] };
|
||||||
|
}
|
||||||
|
result[key].value.push(value.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
register(): void {
|
||||||
|
actionAddins[this.name] = this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CalcType {
|
new DataProcessingAction();
|
||||||
NUMBER = "number",
|
|
||||||
STRING = "string",
|
|
||||||
DATE = "date",
|
|
||||||
TIME = "time",
|
|
||||||
DATETIME = "datetime",
|
|
||||||
}
|
|
||||||
|
|
||||||
const calcFunc: Record<string, (value: string[]) => string | null> = {
|
|
||||||
[`${CalcType.NUMBER}_${Operator.COUNT}`]: (value: string[]) =>
|
|
||||||
value.length.toString(),
|
|
||||||
[`${CalcType.STRING}_${Operator.COUNT}`]: (value: string[]) =>
|
|
||||||
value.length.toString(),
|
|
||||||
[`${CalcType.DATE}_${Operator.COUNT}`]: (value: string[]) =>
|
|
||||||
value.length.toString(),
|
|
||||||
[`${CalcType.TIME}_${Operator.COUNT}`]: (value: string[]) =>
|
|
||||||
value.length.toString(),
|
|
||||||
[`${CalcType.DATETIME}_${Operator.COUNT}`]: (value: string[]) =>
|
|
||||||
value.length.toString(),
|
|
||||||
|
|
||||||
[`${CalcType.NUMBER}_${Operator.SUM}`]: (value: string[]) =>
|
|
||||||
value.reduce((acc, v) => acc + Number(v), 0).toString(),
|
|
||||||
[`${CalcType.NUMBER}_${Operator.AVG}`]: (value: string[]) =>
|
|
||||||
(value.reduce((acc, v) => acc + Number(v), 0) / value.length).toString(),
|
|
||||||
[`${CalcType.NUMBER}_${Operator.MAX}`]: (value: string[]) =>
|
|
||||||
Math.max(...value.map(Number)).toString(),
|
|
||||||
[`${CalcType.NUMBER}_${Operator.MIN}`]: (value: string[]) =>
|
|
||||||
Math.min(...value.map(Number)).toString(),
|
|
||||||
|
|
||||||
[`${CalcType.STRING}_${Operator.SUM}`]: (value: string[]) => value.join(" "),
|
|
||||||
|
|
||||||
[`${CalcType.DATE}_${Operator.MAX}`]: (value: string[]) =>
|
|
||||||
value.reduce((maxDate, currentDate) =>
|
|
||||||
maxDate > currentDate ? maxDate : currentDate
|
|
||||||
),
|
|
||||||
|
|
||||||
[`${CalcType.DATE}_${Operator.MIN}`]: (value: string[]) =>
|
|
||||||
value.reduce((minDate, currentDate) =>
|
|
||||||
minDate < currentDate ? minDate : currentDate
|
|
||||||
),
|
|
||||||
|
|
||||||
[`${CalcType.TIME}_${Operator.MAX}`]: (value: string[]) =>
|
|
||||||
value.reduce((maxTime, currentTime) =>
|
|
||||||
maxTime > currentTime ? maxTime : currentTime
|
|
||||||
),
|
|
||||||
[`${CalcType.TIME}_${Operator.MIN}`]: (value: string[]) =>
|
|
||||||
value.reduce((minTime, currentTime) =>
|
|
||||||
minTime < currentTime ? minTime : currentTime
|
|
||||||
),
|
|
||||||
|
|
||||||
[`${CalcType.DATETIME}_${Operator.MAX}`]: (value: string[]) =>
|
|
||||||
value.reduce((maxDateTime, currentDateTime) =>
|
|
||||||
new Date(maxDateTime) > new Date(currentDateTime)
|
|
||||||
? maxDateTime
|
|
||||||
: currentDateTime
|
|
||||||
),
|
|
||||||
|
|
||||||
[`${CalcType.DATETIME}_${Operator.MIN}`]: (value: string[]) =>
|
|
||||||
value.reduce((minDateTime, currentDateTime) =>
|
|
||||||
new Date(minDateTime) < new Date(currentDateTime)
|
|
||||||
? minDateTime
|
|
||||||
: currentDateTime
|
|
||||||
),
|
|
||||||
[`${CalcType.STRING}_${Operator.FIRST}`]: (value: string[]) => {
|
|
||||||
return value[0];
|
|
||||||
},
|
|
||||||
};
|
|
||||||
334
plugin/kintone-addins/src/actions/data-update.ts
Normal file
334
plugin/kintone-addins/src/actions/data-update.ts
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
import {
|
||||||
|
IAction,
|
||||||
|
IActionResult,
|
||||||
|
IActionNode,
|
||||||
|
IActionProperty,
|
||||||
|
IContext,
|
||||||
|
} from "../types/ActionTypes";
|
||||||
|
import { actionAddins } from ".";
|
||||||
|
import { KintoneRestAPIClient } from "@kintone/rest-api-client";
|
||||||
|
import { Lookup } from "@kintone/rest-api-client/lib/src/KintoneFields/types/property";
|
||||||
|
import { FieldForm, FieldType } from "../types/FieldLayout";
|
||||||
|
interface Props {
|
||||||
|
displayName: string;
|
||||||
|
sources: Sources;
|
||||||
|
dataMapping: DataMapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DataMapping {
|
||||||
|
data: Mapping[];
|
||||||
|
createWithNull: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Mapping {
|
||||||
|
id: string;
|
||||||
|
from: From;
|
||||||
|
to: To;
|
||||||
|
isKey: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
interface To {
|
||||||
|
app: App;
|
||||||
|
fields:FieldForm[];
|
||||||
|
isDialogVisible: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface From {
|
||||||
|
sharedText: string;
|
||||||
|
id: string;
|
||||||
|
objectType: 'variable'|'field'|'text';
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IVar extends From{
|
||||||
|
name:{
|
||||||
|
name:string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IFromField extends From,FieldForm{
|
||||||
|
|
||||||
|
}
|
||||||
|
interface Sources {
|
||||||
|
app: App;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface App {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
createdate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DataUpdateAction implements IAction {
|
||||||
|
name: string;
|
||||||
|
actionProps: IActionProperty[];
|
||||||
|
dataMappingProps: Props;
|
||||||
|
constructor() {
|
||||||
|
this.name = "データ更新";
|
||||||
|
this.actionProps = [];
|
||||||
|
this.dataMappingProps = {} as Props;
|
||||||
|
this.register();
|
||||||
|
}
|
||||||
|
|
||||||
|
async process(
|
||||||
|
prop: IActionNode,
|
||||||
|
event: any,
|
||||||
|
context: IContext
|
||||||
|
): Promise<IActionResult> {
|
||||||
|
this.actionProps = prop.actionProps;
|
||||||
|
this.dataMappingProps = prop.ActionValue as Props;
|
||||||
|
console.log(context);
|
||||||
|
let result = {
|
||||||
|
canNext: true,
|
||||||
|
result: "",
|
||||||
|
} as IActionResult;
|
||||||
|
try {
|
||||||
|
const lookupFixedFieldCodes = await getLookupFixedFieldCodes(
|
||||||
|
this.dataMappingProps.sources.app.id
|
||||||
|
);
|
||||||
|
|
||||||
|
// createWithNull が有効な場合は、4 番目のパラメーターを true にして doUpdate 関数ブランチを実行します。
|
||||||
|
if (this.dataMappingProps.dataMapping.createWithNull) {
|
||||||
|
await doUpdate(
|
||||||
|
this.dataMappingProps.dataMapping.data,
|
||||||
|
this.dataMappingProps.sources.app.id,
|
||||||
|
context,
|
||||||
|
true, // キーがない場合、またはキーでターゲットが見つからない場合に、マッピング条件によって新しいレコードを作成するかどうかを決定するために使用されます。
|
||||||
|
lookupFixedFieldCodes
|
||||||
|
);
|
||||||
|
} else if (
|
||||||
|
// キーがないと更新対象を取得できないため、この時点でのみ更新が行われます。 doUpdate 関数の 4 番目のパラメーターは false です。
|
||||||
|
this.dataMappingProps.dataMapping.data
|
||||||
|
.map((m) => m.isKey)
|
||||||
|
.find((isKey) => isKey === true)
|
||||||
|
) {
|
||||||
|
await doUpdate(
|
||||||
|
this.dataMappingProps.dataMapping.data,
|
||||||
|
this.dataMappingProps.sources.app.id,
|
||||||
|
context,
|
||||||
|
false,
|
||||||
|
lookupFixedFieldCodes
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await doCreate(
|
||||||
|
this.dataMappingProps.dataMapping.data,
|
||||||
|
this.dataMappingProps.sources.app.id,
|
||||||
|
context,
|
||||||
|
lookupFixedFieldCodes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("DataMappingAction error", error);
|
||||||
|
result.canNext = false;
|
||||||
|
}
|
||||||
|
console.log("dataMappingProps", this.dataMappingProps);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
register(): void {
|
||||||
|
actionAddins[this.name] = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new DataUpdateAction();
|
||||||
|
|
||||||
|
const getContextVarByPath = (obj: any, path: string) => {
|
||||||
|
return path.split(".").reduce((o, k) => (o || {})[k], obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface UpdateRecord {
|
||||||
|
id: string;
|
||||||
|
record: {
|
||||||
|
[key: string]: {
|
||||||
|
value: any;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = new KintoneRestAPIClient();
|
||||||
|
|
||||||
|
const getFromValue=(item:Mapping,context:IContext)=>{
|
||||||
|
if (item.from.objectType === "variable") {
|
||||||
|
const rfrom =item.from as IVar;
|
||||||
|
return getContextVarByPath(context.variables,rfrom.name.name);
|
||||||
|
}else if(item.from.objectType === "field"){
|
||||||
|
const field = item.from as IFromField;
|
||||||
|
return context.record[field.code].value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return item.from.sharedText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const doUpdate = async (
|
||||||
|
mappingData: Mapping[],
|
||||||
|
appId: string,
|
||||||
|
context: IContext,
|
||||||
|
needCreate: boolean,
|
||||||
|
lookupFixedFieldCodes: string[]
|
||||||
|
) => {
|
||||||
|
const targetField = await findUpdateField(mappingData, appId, context);
|
||||||
|
console.log(targetField);
|
||||||
|
if (targetField.records.length === 0 && needCreate) {
|
||||||
|
await doCreate(mappingData, appId, context, lookupFixedFieldCodes);
|
||||||
|
} else {
|
||||||
|
// マッピングデータを単純なオブジェクトに処理し、ソース値が変数の場合は変数を置き換えます。
|
||||||
|
const mappingRules = mappingData
|
||||||
|
.filter(
|
||||||
|
(m) =>
|
||||||
|
Object.keys(m.from).length > 0 &&
|
||||||
|
!lookupFixedFieldCodes.includes(m.to.fields[0].code)
|
||||||
|
)
|
||||||
|
.map((m) => {
|
||||||
|
if (m.from.objectType === "variable") {
|
||||||
|
const rfrom =m.from as IVar;
|
||||||
|
return {
|
||||||
|
value: getContextVarByPath(context.variables,rfrom.name.name),
|
||||||
|
code: m.to.fields[0].code,
|
||||||
|
};
|
||||||
|
}else if(m.from.objectType === "field"){
|
||||||
|
const field = m.from as IFromField;
|
||||||
|
return {
|
||||||
|
value: context.record[field.code].value,
|
||||||
|
code: m.to.fields[0].code,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return {
|
||||||
|
value: m.from.sharedText,
|
||||||
|
code: m.to.fields[0].code,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateRecords: UpdateRecord[] = targetField.records.map(
|
||||||
|
(targetRecord) => {
|
||||||
|
const updateRecord: UpdateRecord["record"] = {};
|
||||||
|
|
||||||
|
// マッピング内のルールにヒットしたフィールドのみが更新されます。
|
||||||
|
for (const mapping of mappingRules) {
|
||||||
|
if (targetRecord[mapping.code]) {
|
||||||
|
updateRecord[mapping.code] = {
|
||||||
|
value: mapping.value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: targetRecord.$id.value as string,
|
||||||
|
record: updateRecord,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(updateRecords);
|
||||||
|
await client.record.updateRecords({
|
||||||
|
app: appId,
|
||||||
|
records: updateRecords,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const makeQuery=(field:FieldForm,key:any)=>{
|
||||||
|
if(field.type===FieldType.NUMBER || field.type===FieldType.RECORD_NUMBER){
|
||||||
|
return `${field.code} = ${Number(key)}`
|
||||||
|
}
|
||||||
|
if(typeof key==='string'){
|
||||||
|
return `${field.code} = "${key}"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const findUpdateField = async (
|
||||||
|
mappingData: Mapping[],
|
||||||
|
appId: string,
|
||||||
|
context: IContext
|
||||||
|
) => {
|
||||||
|
const queryStr = mappingData
|
||||||
|
.filter((m) => m.to.app && m.to.fields && m.to.fields.length > 0 && m.isKey)
|
||||||
|
.map((m) => {
|
||||||
|
if (m.from.objectType === "variable") {
|
||||||
|
const vfrom = m.from as IVar;
|
||||||
|
return makeQuery(m.to.fields[0],getContextVarByPath(context.variables , vfrom.name.name));
|
||||||
|
}
|
||||||
|
else if(m.from.objectType === "field"){
|
||||||
|
const field = m.from as IFromField;
|
||||||
|
return makeQuery(m.to.fields[0],context.record[field.code].value);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return makeQuery(m.to.fields[0],m.from.sharedText);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.join("&");
|
||||||
|
// 検索条件が空の場合は全レコードを返すため、検索対象が見つからない場合は検索は行われません。
|
||||||
|
if (queryStr.length === 0) {
|
||||||
|
return {
|
||||||
|
records: [],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return await client.record.getRecords({
|
||||||
|
app: appId,
|
||||||
|
// query: undefined
|
||||||
|
query: queryStr,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const doCreate = async (
|
||||||
|
mappingData: Mapping[],
|
||||||
|
appId: string,
|
||||||
|
context: IContext,
|
||||||
|
lookupFixedFieldCodes: string[]
|
||||||
|
) => {
|
||||||
|
const filterHandler = (item:Mapping)=>{
|
||||||
|
if(!item.to.fields || item.to.fields.length===0){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(item.from.objectType === "variable" && (item.from as IVar).name.name ){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(item.from.objectType === "field" && (item.from as IFromField).code){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(item.from.objectType === "text" && item.from.sharedText!==null){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const record = mappingData
|
||||||
|
.filter(filterHandler)
|
||||||
|
.filter((item) => !lookupFixedFieldCodes.includes(item.to.fields[0].code))
|
||||||
|
.reduce((accumulator, item) => {
|
||||||
|
return {
|
||||||
|
...accumulator,
|
||||||
|
[item.to.fields[0].code]: {
|
||||||
|
value: getFromValue(item,context),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}, {});
|
||||||
|
if (record && Object.keys(record).length > 0) {
|
||||||
|
console.log(record);
|
||||||
|
await client.record.addRecord({
|
||||||
|
app:appId,
|
||||||
|
record:record
|
||||||
|
});
|
||||||
|
// await kintone.api(kintone.api.url("/k/v1/record.json", true), "POST", {
|
||||||
|
// app: appId,
|
||||||
|
// record: record,
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getLookupFixedFieldCodes = async (appId: string) => {
|
||||||
|
return await client.app
|
||||||
|
.getFormFields({ app: appId })
|
||||||
|
.then((resp) =>
|
||||||
|
Object.values(resp.properties)
|
||||||
|
.filter((f) => (f as Lookup).lookup !== undefined)
|
||||||
|
.flatMap((f) => (f as Lookup).lookup.fieldMappings.map((m) => m.field))
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -51,13 +51,19 @@ export class MailCheckAction implements IAction {
|
|||||||
const value = record[this.props.field.code].value;
|
const value = record[this.props.field.code].value;
|
||||||
|
|
||||||
if (this.props.emailCheck === '厳格') {
|
if (this.props.emailCheck === '厳格') {
|
||||||
if (!/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(value)) {
|
if (!/^[a-zA-Z0-9_-¥.]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(value)) {
|
||||||
record[this.props.field.code].error = this.props.message;
|
record[this.props.field.code].error = this.props.message;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
record[this.props.field.code].error = null;
|
||||||
|
}
|
||||||
} else if (this.props.emailCheck === 'ゆるめ') {
|
} else if (this.props.emailCheck === 'ゆるめ') {
|
||||||
if (!/^[^@]+@[^@]+$/.test(value)) {
|
if (!/^[^@]+@[^@]+$/.test(value)) {
|
||||||
record[this.props.field.code].error = this.props.message;
|
record[this.props.field.code].error = this.props.message;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
record[this.props.field.code].error = null;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
result = {
|
result = {
|
||||||
canNext: true,
|
canNext: true,
|
||||||
|
|||||||
@@ -42,7 +42,12 @@ $(function (){
|
|||||||
const flow=ActionFlow.fromJSON(flowinfo.content);
|
const flow=ActionFlow.fromJSON(flowinfo.content);
|
||||||
if(flow!==undefined){
|
if(flow!==undefined){
|
||||||
const process = new ActionProcess(event.type,flow,event);
|
const process = new ActionProcess(event.type,flow,event);
|
||||||
process.exec();
|
process.exec().then((res)=>{
|
||||||
|
const record = event.record;
|
||||||
|
kintone.app.record.set({record});
|
||||||
|
}).catch((err)=>{
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return event;
|
return event;
|
||||||
});
|
});
|
||||||
@@ -58,7 +63,7 @@ $(function (){
|
|||||||
await process.exec();
|
await process.exec();
|
||||||
}
|
}
|
||||||
const record = event.record;
|
const record = event.record;
|
||||||
kintone.app.record.set({record})
|
kintone.app.record.set({record});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -347,6 +347,9 @@ export class ConditionTree {
|
|||||||
if(!object || typeof object!=="object"){
|
if(!object || typeof object!=="object"){
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
if("sharedText" in object){
|
||||||
|
return object.sharedText;
|
||||||
|
}
|
||||||
if("label" in object){
|
if("label" in object){
|
||||||
return object.label;
|
return object.label;
|
||||||
}
|
}
|
||||||
|
|||||||
240
plugin/kintone-addins/src/types/FieldLayout.ts
Normal file
240
plugin/kintone-addins/src/types/FieldLayout.ts
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
// src/types/field.d.ts
|
||||||
|
|
||||||
|
export enum FieldType {
|
||||||
|
CALC = "CALC",
|
||||||
|
CATEGORY = "CATEGORY",
|
||||||
|
CHECK_BOX = "CHECK_BOX",
|
||||||
|
CREATED_TIME = "CREATED_TIME",
|
||||||
|
CREATOR = "CREATOR",
|
||||||
|
DATE = "DATE",
|
||||||
|
DATETIME = "DATETIME",
|
||||||
|
DROP_DOWN = "DROP_DOWN",
|
||||||
|
FILE = "FILE",
|
||||||
|
GROUP = "GROUP",
|
||||||
|
GROUP_SELECT = "GROUP_SELECT",
|
||||||
|
LINK = "LINK",
|
||||||
|
MODIFIER = "MODIFIER",
|
||||||
|
MULTI_LINE_TEXT = "MULTI_LINE_TEXT",
|
||||||
|
MULTI_SELECT = "MULTI_SELECT",
|
||||||
|
NUMBER = "NUMBER",
|
||||||
|
ORGANIZATION_SELECT = "ORGANIZATION_SELECT",
|
||||||
|
RADIO_BUTTON = "RADIO_BUTTON",
|
||||||
|
RECORD_NUMBER = "RECORD_NUMBER",
|
||||||
|
REFERENCE_TABLE = "REFERENCE_TABLE",
|
||||||
|
RICH_TEXT = "RICH_TEXT",
|
||||||
|
SINGLE_LINE_TEXT = "SINGLE_LINE_TEXT",
|
||||||
|
STATUS = "STATUS",
|
||||||
|
STATUS_ASSIGNEE = "STATUS_ASSIGNEE",
|
||||||
|
SUBTABLE = "SUBTABLE",
|
||||||
|
TIME = "TIME",
|
||||||
|
UPDATED_TIME = "UPDATED_TIME",
|
||||||
|
USER_SELECT = "USER_SELECT"
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum CalcFormat{
|
||||||
|
NUMBER = "NUMBER",
|
||||||
|
NUMBER_DIGIT = "NUMBER_DIGIT",
|
||||||
|
DATETIME = "DATETIME",
|
||||||
|
DATE = "DATE",
|
||||||
|
TIME = "TIME",
|
||||||
|
HOUR_MINUTE= "HOUR_MINUTE",
|
||||||
|
DAY_HOUR_MINUTE= "DAY_HOUR_MINUTE"
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FieldForm {
|
||||||
|
code: string;
|
||||||
|
type: FieldType;
|
||||||
|
required?: boolean;
|
||||||
|
noLabel?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OptionForm{
|
||||||
|
index: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EntityForm {
|
||||||
|
code: string;
|
||||||
|
type: 'USER' | 'ORGANIZATION' | 'GROUP' | 'FUNCTION';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CalcFieldForm extends FieldForm {
|
||||||
|
unit?: string;
|
||||||
|
expression?: string;
|
||||||
|
format?:CalcFormat;
|
||||||
|
unitPosition?: 'BEFORE' | 'AFTER';
|
||||||
|
displayScale?: string;
|
||||||
|
hideExpression?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CategoryFieldForm extends FieldForm {
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DateFieldForm extends FieldForm {
|
||||||
|
defaultValue?: string;
|
||||||
|
unique?: boolean;
|
||||||
|
defaultNowValue?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DatetimeFieldForm extends FieldForm {
|
||||||
|
defaultValue?: string;
|
||||||
|
unique?: boolean;
|
||||||
|
defaultNowValue?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DecimalFieldForm extends FieldForm {
|
||||||
|
maxValue?: string;
|
||||||
|
defaultValue?: string;
|
||||||
|
unitPosition?: 'BEFORE' | 'AFTER';
|
||||||
|
minValue?: string;
|
||||||
|
unit?: string;
|
||||||
|
unique?: boolean;
|
||||||
|
displayScale?: string;
|
||||||
|
digit?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EditorFieldForm extends FieldForm {
|
||||||
|
defaultValue?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EntityForm {
|
||||||
|
code: string;
|
||||||
|
type: 'USER' | 'ORGANIZATION' | 'GROUP' | 'FUNCTION';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FieldMappingForm {
|
||||||
|
relatedField: string;
|
||||||
|
field: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileFieldForm extends FieldForm {
|
||||||
|
thumbnailSize?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GroupFieldForm extends FieldForm {
|
||||||
|
openGroup?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GroupSelectFieldForm extends FieldForm {
|
||||||
|
entities: EntityForm[];
|
||||||
|
defaultValue?: EntityForm[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LinkFieldForm extends FieldForm {
|
||||||
|
protocol?: 'WEB' | 'CALL' | 'MAIL';
|
||||||
|
defaultValue?: string;
|
||||||
|
minLength?: string;
|
||||||
|
unique?: boolean;
|
||||||
|
maxLength?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LookupFieldForm extends FieldForm {
|
||||||
|
lookup: {
|
||||||
|
lookupPickerFields: string[];
|
||||||
|
relatedKeyField: string;
|
||||||
|
relatedApp: {
|
||||||
|
app: string;
|
||||||
|
code: string;
|
||||||
|
};
|
||||||
|
fieldMappings: FieldMappingForm[];
|
||||||
|
sort?: string;
|
||||||
|
filterCond?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ModifiedAtFieldForm extends FieldForm {}
|
||||||
|
|
||||||
|
export interface ModifierFieldForm extends FieldForm {}
|
||||||
|
|
||||||
|
export interface MultipleCheckFieldForm extends FieldForm {
|
||||||
|
defaultValue?: string[];
|
||||||
|
options: {
|
||||||
|
[key: string]: OptionForm;
|
||||||
|
};
|
||||||
|
align?: 'HORIZONTAL' | 'VERTICAL';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MultipleLineTextFieldForm extends FieldForm {
|
||||||
|
defaultValue?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MultipleSelectFieldForm extends FieldForm {
|
||||||
|
defaultValue?: string[];
|
||||||
|
options: {
|
||||||
|
[key: string]: OptionForm;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface OrganizationSelectFieldForm extends FieldForm {
|
||||||
|
entities: EntityForm[];
|
||||||
|
defaultValue?: EntityForm[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RecordIdFieldForm extends FieldForm {}
|
||||||
|
|
||||||
|
export interface ReferenceTableFieldForm extends FieldForm {
|
||||||
|
referenceTable: {
|
||||||
|
condition: {
|
||||||
|
relatedField: string;
|
||||||
|
field: string;
|
||||||
|
};
|
||||||
|
size?: string;
|
||||||
|
relatedApp: {
|
||||||
|
app: string;
|
||||||
|
code: string;
|
||||||
|
};
|
||||||
|
sort?: string;
|
||||||
|
filterCond?: string;
|
||||||
|
displayFields: string[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SingleCheckFieldForm extends FieldForm {
|
||||||
|
defaultValue?: string;
|
||||||
|
options: {
|
||||||
|
[key: string]: OptionForm;
|
||||||
|
};
|
||||||
|
align?: 'HORIZONTAL' | 'VERTICAL';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SingleLineTextFieldForm extends FieldForm {
|
||||||
|
expression?: string;
|
||||||
|
defaultValue?: string;
|
||||||
|
minLength?: string;
|
||||||
|
unique?: boolean;
|
||||||
|
maxLength?: string;
|
||||||
|
hideExpression?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SingleSelectFieldForm extends FieldForm {
|
||||||
|
defaultValue?: string;
|
||||||
|
options: {
|
||||||
|
[key: string]: OptionForm;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StatusAssigneeFieldForm extends FieldForm {
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StatusFieldForm extends FieldForm {
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TableForm extends FieldForm {
|
||||||
|
fields: {
|
||||||
|
[key: string]: CalcFieldForm | CategoryFieldForm | DateFieldForm | DatetimeFieldForm | DecimalFieldForm | EditorFieldForm | FileFieldForm | GroupFieldForm | GroupSelectFieldForm | LinkFieldForm | LookupFieldForm | ModifiedAtFieldForm | ModifierFieldForm | MultipleCheckFieldForm | MultipleLineTextFieldForm | MultipleSelectFieldForm | OrganizationSelectFieldForm | RecordIdFieldForm | ReferenceTableFieldForm | SingleCheckFieldForm | SingleLineTextFieldForm | SingleSelectFieldForm | StatusAssigneeFieldForm | StatusFieldForm | TableForm | TimeFieldForm | UserSelectFieldForm;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimeFieldForm extends FieldForm {
|
||||||
|
defaultValue?: string;
|
||||||
|
defaultNowValue?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserSelectFieldForm extends FieldForm {
|
||||||
|
entities: EntityForm[];
|
||||||
|
defaultValue?: EntityForm[];
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ import '../actions/error-show';
|
|||||||
import '../actions/button-add';
|
import '../actions/button-add';
|
||||||
import '../actions/condition-action';
|
import '../actions/condition-action';
|
||||||
import '../actions/data-processing';
|
import '../actions/data-processing';
|
||||||
import '../actions/data-mapping';
|
import '../actions/data-update';
|
||||||
import '../actions/current-field-get';
|
import '../actions/current-field-get';
|
||||||
import '../actions/regular-check';
|
import '../actions/regular-check';
|
||||||
import '../actions/mail-check';
|
import '../actions/mail-check';
|
||||||
|
|||||||
121
plugin/kintone-addins/src/util/aggregates.ts
Normal file
121
plugin/kintone-addins/src/util/aggregates.ts
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
import { FieldForm,CalcFieldForm,FieldType, CalcFormat} from "../types/FieldLayout";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集計操作子
|
||||||
|
*/
|
||||||
|
export enum Operator {
|
||||||
|
SUM = "SUM",
|
||||||
|
AVG = "AVG",
|
||||||
|
MAX = "MAX",
|
||||||
|
MIN = "MIN",
|
||||||
|
COUNT = "COUNT",
|
||||||
|
FIRST = "FIRST",
|
||||||
|
LAST = "LAST"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 集計関数
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class Aggregator {
|
||||||
|
private data: string[];
|
||||||
|
private field: FieldForm;
|
||||||
|
|
||||||
|
constructor(data: string[], field: FieldForm) {
|
||||||
|
this.data = data;
|
||||||
|
this.field = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
private toNumberArray(): number[] {
|
||||||
|
const numberArray = this.data.map(item => {
|
||||||
|
const num = Number(item);
|
||||||
|
if (isNaN(num)) {
|
||||||
|
throw new Error(`フィールド「${this.field.code} 」は数値に変換できないため、計算を実行できません。`);
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
});
|
||||||
|
|
||||||
|
return numberArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
private sum(): number | null {
|
||||||
|
if (this.data.length === 0) return null;
|
||||||
|
const numberArray = this.toNumberArray();
|
||||||
|
return numberArray.reduce((acc, val) => acc + val, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private avg(): number | null {
|
||||||
|
if (this.data.length === 0) return null;
|
||||||
|
const numberArray = this.toNumberArray();
|
||||||
|
const total = numberArray.reduce((acc, val) => acc + val, 0);
|
||||||
|
return total / numberArray.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private max(): number | string | null {
|
||||||
|
if (this.data.length === 0) return null;
|
||||||
|
if (this.field.type === FieldType.NUMBER ) {
|
||||||
|
const numberArray = this.toNumberArray();
|
||||||
|
return Math.max(...numberArray);
|
||||||
|
}
|
||||||
|
if(this.field.type===FieldType.CALC){
|
||||||
|
const calcField = this.field as CalcFieldForm;
|
||||||
|
if(calcField.format===CalcFormat.NUMBER || calcField.format===CalcFormat.NUMBER_DIGIT){
|
||||||
|
const numberArray = this.toNumberArray();
|
||||||
|
return Math.max(...numberArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.data.reduce((max, item) => (item > max ? item : max), this.data[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private min(): number | string | null {
|
||||||
|
if (this.data.length === 0) return null;
|
||||||
|
if (this.field.type === FieldType.NUMBER ) {
|
||||||
|
const numberArray = this.toNumberArray();
|
||||||
|
return Math.min(...numberArray);
|
||||||
|
}
|
||||||
|
if(this.field.type===FieldType.CALC){
|
||||||
|
const calcField = this.field as CalcFieldForm;
|
||||||
|
if(calcField.format===CalcFormat.NUMBER || calcField.format===CalcFormat.NUMBER_DIGIT){
|
||||||
|
const numberArray = this.toNumberArray();
|
||||||
|
return Math.min(...numberArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(this.data===null || this.data.length===0){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.data.reduce((min, item) => (item < min ? item : min), this.data[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private count(): number {
|
||||||
|
return this.data.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private first(): string | null {
|
||||||
|
return this.data.length ? this.data[0] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private last(): string | null {
|
||||||
|
return this.data.length ? this.data[this.data.length - 1] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public calculate(operator: Operator): number | string | null {
|
||||||
|
switch (operator) {
|
||||||
|
case Operator.SUM:
|
||||||
|
return this.sum();
|
||||||
|
case Operator.AVG:
|
||||||
|
return this.avg();
|
||||||
|
case Operator.MAX:
|
||||||
|
return this.max();
|
||||||
|
case Operator.MIN:
|
||||||
|
return this.min();
|
||||||
|
case Operator.COUNT:
|
||||||
|
return this.count();
|
||||||
|
case Operator.FIRST:
|
||||||
|
return this.first();
|
||||||
|
case Operator.LAST:
|
||||||
|
return this.last();
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// vite.config.js
|
// vite.config.js
|
||||||
import { defineConfig, loadEnv } from "vite";
|
import { defineConfig, loadEnv } from "vite";
|
||||||
import checker from "vite-plugin-checker";
|
import checker from "vite-plugin-checker";
|
||||||
import { libInjectCss } from 'vite-plugin-lib-inject-css';
|
// import { libInjectCss } from 'vite-plugin-lib-inject-css';
|
||||||
|
|
||||||
export default ({ mode }) => {
|
export default ({ mode }) => {
|
||||||
process.env = { ...process.env, ...loadEnv(mode, process.cwd()) };
|
process.env = { ...process.env, ...loadEnv(mode, process.cwd()) };
|
||||||
@@ -12,7 +12,7 @@ export default ({ mode }) => {
|
|||||||
checker({
|
checker({
|
||||||
typescript: true,
|
typescript: true,
|
||||||
}),
|
}),
|
||||||
libInjectCss(),
|
// libInjectCss(),
|
||||||
],
|
],
|
||||||
build: {
|
build: {
|
||||||
cssCodeSplit: false,
|
cssCodeSplit: false,
|
||||||
|
|||||||
@@ -2,60 +2,6 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
"@ast-grep/napi-darwin-arm64@0.22.6":
|
|
||||||
version "0.22.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/@ast-grep/napi-darwin-arm64/-/napi-darwin-arm64-0.22.6.tgz#34e9146234de6a7c965ed45335d67863ad96ca95"
|
|
||||||
integrity sha512-L9rEGJ8fNi5LxbZj860wbXxjX7DLNV799zcTaPOSzYadvNyhMY3LWvDXd45Vtx6Dh8QRtCoEMQmw8KaRCEjm9A==
|
|
||||||
|
|
||||||
"@ast-grep/napi-darwin-x64@0.22.6":
|
|
||||||
version "0.22.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/@ast-grep/napi-darwin-x64/-/napi-darwin-x64-0.22.6.tgz#521470adf988e1f64e5912ec41afad3f958fc9ff"
|
|
||||||
integrity sha512-0iuM6iDJNhcPd6a/JJr64AallR7ttGW/MvUujfQdvJEZY5p9LK35xm23dULznW0tIMgwtMKPRaprgk8LPondKg==
|
|
||||||
|
|
||||||
"@ast-grep/napi-linux-arm64-gnu@0.22.6":
|
|
||||||
version "0.22.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/@ast-grep/napi-linux-arm64-gnu/-/napi-linux-arm64-gnu-0.22.6.tgz#808008fd5952733e589558d5ac4a5746b84a1d55"
|
|
||||||
integrity sha512-9PAqNJlAQfFm1RW0DVCM/S4gFHdppxUTWacB3qEeJZXgdLnoH0KGQa4z3Xo559SPYDKZy0VnY02mZ3XJ+v6/Vw==
|
|
||||||
|
|
||||||
"@ast-grep/napi-linux-x64-gnu@0.22.6":
|
|
||||||
version "0.22.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/@ast-grep/napi-linux-x64-gnu/-/napi-linux-x64-gnu-0.22.6.tgz#3f087687560b33ad9a5b232ff4e6780cc8367339"
|
|
||||||
integrity sha512-nZf+gxXVrZqvP1LN6HwzOMA4brF3umBXfMequQzv8S6HeJ4c34P23F0Tw8mHtQpVYP9PQWJUvt3LJQ8Xvd5Hiw==
|
|
||||||
|
|
||||||
"@ast-grep/napi-linux-x64-musl@0.22.6":
|
|
||||||
version "0.22.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/@ast-grep/napi-linux-x64-musl/-/napi-linux-x64-musl-0.22.6.tgz#dfa09e6e947f266084b30080476e8a1e25aefc73"
|
|
||||||
integrity sha512-gcJeBMgJQf2pZZo0lgH0Vg4ycyujM7Am8VlomXhavC/dPpkddA1tiHSIC4fCNneLU1EqHITy3ALSmM4GLdsjBw==
|
|
||||||
|
|
||||||
"@ast-grep/napi-win32-arm64-msvc@0.22.6":
|
|
||||||
version "0.22.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/@ast-grep/napi-win32-arm64-msvc/-/napi-win32-arm64-msvc-0.22.6.tgz#ac0f092c0dad39a05b8cb10430cdc99eb87eebfc"
|
|
||||||
integrity sha512-YDDzvPIyl4ti8xZfjvGSGVCX9JJjMQjyWPlXcwRpiLRnHThtHTDL8PyE2yq+gAPuZ28QbrygMkP9EKXIyYFVcQ==
|
|
||||||
|
|
||||||
"@ast-grep/napi-win32-ia32-msvc@0.22.6":
|
|
||||||
version "0.22.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/@ast-grep/napi-win32-ia32-msvc/-/napi-win32-ia32-msvc-0.22.6.tgz#d4ca06d33a59760aa3870baffa296720ffb01b19"
|
|
||||||
integrity sha512-w5P0MDcBD3bifC2K9nCDEFYacy8HQnXdf6fX6cIE/7xL8XEDs6D1lQjGewrZDcMAXVXUQfupj4P27ZsJRmuIoQ==
|
|
||||||
|
|
||||||
"@ast-grep/napi-win32-x64-msvc@0.22.6":
|
|
||||||
version "0.22.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/@ast-grep/napi-win32-x64-msvc/-/napi-win32-x64-msvc-0.22.6.tgz#82c3a7557336c0aa9809ac8ccd5ec573b907b727"
|
|
||||||
integrity sha512-1aaHvgsCBwUP0tDf4HXPMpUV/nUwsOWgRCiBc2zIJjdEjT9TTk795EIX9Z1Nc0OMCrxVEceyiKcYTofXa0Fpxw==
|
|
||||||
|
|
||||||
"@ast-grep/napi@^0.22.3":
|
|
||||||
version "0.22.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/@ast-grep/napi/-/napi-0.22.6.tgz#473c4398fbafb39277c99b298f08d342f507eabe"
|
|
||||||
integrity sha512-kNF87HiI4omHC7VzyBZSvqOAXtMlSDRF2YX+O5ya0XKv/7/GYms1opLQ+BQ9twLLDj0WsSFX4MYg0TrinZTxTg==
|
|
||||||
optionalDependencies:
|
|
||||||
"@ast-grep/napi-darwin-arm64" "0.22.6"
|
|
||||||
"@ast-grep/napi-darwin-x64" "0.22.6"
|
|
||||||
"@ast-grep/napi-linux-arm64-gnu" "0.22.6"
|
|
||||||
"@ast-grep/napi-linux-x64-gnu" "0.22.6"
|
|
||||||
"@ast-grep/napi-linux-x64-musl" "0.22.6"
|
|
||||||
"@ast-grep/napi-win32-arm64-msvc" "0.22.6"
|
|
||||||
"@ast-grep/napi-win32-ia32-msvc" "0.22.6"
|
|
||||||
"@ast-grep/napi-win32-x64-msvc" "0.22.6"
|
|
||||||
|
|
||||||
"@babel/code-frame@^7.12.13":
|
"@babel/code-frame@^7.12.13":
|
||||||
version "7.24.7"
|
version "7.24.7"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465"
|
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465"
|
||||||
@@ -189,11 +135,6 @@
|
|||||||
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz"
|
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz"
|
||||||
integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==
|
integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==
|
||||||
|
|
||||||
"@jridgewell/sourcemap-codec@^1.4.15":
|
|
||||||
version "1.4.15"
|
|
||||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
|
|
||||||
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
|
|
||||||
|
|
||||||
"@kintone/rest-api-client@^5.5.2":
|
"@kintone/rest-api-client@^5.5.2":
|
||||||
version "5.5.2"
|
version "5.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/@kintone/rest-api-client/-/rest-api-client-5.5.2.tgz#501cd72dcfe51cd84c1a65fb1e2fdd4a92933e5b"
|
resolved "https://registry.yarnpkg.com/@kintone/rest-api-client/-/rest-api-client-5.5.2.tgz#501cd72dcfe51cd84c1a65fb1e2fdd4a92933e5b"
|
||||||
@@ -719,13 +660,6 @@ jsonfile@^6.0.1:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
graceful-fs "^4.1.6"
|
graceful-fs "^4.1.6"
|
||||||
|
|
||||||
magic-string@^0.30.10:
|
|
||||||
version "0.30.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.10.tgz#123d9c41a0cb5640c892b041d4cfb3bd0aa4b39e"
|
|
||||||
integrity sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==
|
|
||||||
dependencies:
|
|
||||||
"@jridgewell/sourcemap-codec" "^1.4.15"
|
|
||||||
|
|
||||||
memorystream@^0.3.1:
|
memorystream@^0.3.1:
|
||||||
version "0.3.1"
|
version "0.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
|
resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
|
||||||
@@ -1027,20 +961,6 @@ vite-plugin-checker@^0.6.4:
|
|||||||
vscode-languageserver-textdocument "^1.0.1"
|
vscode-languageserver-textdocument "^1.0.1"
|
||||||
vscode-uri "^3.0.2"
|
vscode-uri "^3.0.2"
|
||||||
|
|
||||||
vite-plugin-css-injected-by-js@^3.5.1:
|
|
||||||
version "3.5.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.5.1.tgz#b9c568c21b131d08e31aa6d368ee39c9d6c1b6c1"
|
|
||||||
integrity sha512-9ioqwDuEBxW55gNoWFEDhfLTrVKXEEZgl5adhWmmqa88EQGKfTmexy4v1Rh0pAS6RhKQs2bUYQArprB32JpUZQ==
|
|
||||||
|
|
||||||
vite-plugin-lib-inject-css@^2.1.1:
|
|
||||||
version "2.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/vite-plugin-lib-inject-css/-/vite-plugin-lib-inject-css-2.1.1.tgz#39c5bb30dbb40c70e0d41a334097ce9b77e8e740"
|
|
||||||
integrity sha512-RIMeVnqBK/8I0E9nnQWzws6pdj5ilRMPJSnXYb6nWxNR4EmDPnksnb/ACoR5Fy7QfzULqS4gtQMrjwnNCC9zoA==
|
|
||||||
dependencies:
|
|
||||||
"@ast-grep/napi" "^0.22.3"
|
|
||||||
magic-string "^0.30.10"
|
|
||||||
picocolors "^1.0.0"
|
|
||||||
|
|
||||||
vite@^4.4.5:
|
vite@^4.4.5:
|
||||||
version "4.5.0"
|
version "4.5.0"
|
||||||
resolved "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz"
|
resolved "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz"
|
||||||
|
|||||||
Reference in New Issue
Block a user