障害対応

This commit is contained in:
2025-02-04 10:29:56 +09:00
parent a3595b1368
commit 4761f416f4
11 changed files with 316 additions and 23 deletions

View File

@@ -7,7 +7,9 @@ export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
CellInput: typeof import('./src/components/basic/conditions/CellInput.vue')['default']
Config: typeof import('./src/components/Config.vue')['default']
ErrorDialog: typeof import('./src/components/basic/ErrorDialog.vue')['default']
PluginDropdown: typeof import('./src/components/basic/PluginDropdown.vue')['default']
PluginInput: typeof import('./src/components/basic/PluginInput.vue')['default']
PluginLabel: typeof import('./src/components/basic/PluginLabel.vue')['default']
@@ -21,5 +23,6 @@ declare module 'vue' {
TableCondition: typeof import('./src/components/basic/conditions/TableCondition.vue')['default']
TableConditionValue: typeof import('./src/components/basic/conditions/TableConditionValue.vue')['default']
TableConditionValueDateTime: typeof import('./src/components/basic/conditions/TableConditionValueDateTime.vue')['default']
TableConditionValueMultiInput: typeof import('./src/components/basic/conditions/TableConditionValueMultiInput.vue')['default']
}
}

View File

@@ -3,7 +3,7 @@
<p class="kintoneplugin-desc">{{ $t('config.desc') }}</p>
<plugin-row class="header-row border">
<plugin-input v-model="data.buttonName" placeholder="集約" label="集約ボタン名" />
<plugin-input v-model="data.buttonName" placeholder="ボタン名を入力してください" label="集約ボタン名" />
</plugin-row>
<div id="main-area" ref="mainArea">
@@ -16,6 +16,7 @@
</plugin-row>
<kuc-spinner :container="mainArea" ref="spinner"></kuc-spinner>
<error-dialog :message="errMessage" :show="showError" @update:show="(value) => showError = value"></error-dialog>
</template>
<script setup lang="ts">
import {
@@ -39,6 +40,8 @@ const data: SavedData = reactive({
buttonName: '',
joinTables: [createEmptyJoinTable()],
});
const showError = ref(false);
const errMessage = ref("");
const cachedData: CachedData = reactive({
apps: [EMPTY_OPTION],
@@ -62,7 +65,9 @@ onMounted(async () => {
cachedData.apps = await loadApps();
cachedData.currentAppFields = await loadAppFieldsAndLayout();
if (savedData?.joinTablesForConfig) {
data.joinTables = JSON.parse(savedData.joinTablesForConfig);
const newJoinTables = JSON.parse(savedData.joinTablesForConfig);
data.joinTables.length = 0;
data.joinTables.push(...newJoinTables);
}
data.buttonName = savedData?.buttonName || '集約';
loading.value = false;
@@ -83,7 +88,42 @@ watch(
},
);
/**
* 保存データのバリデーション関数
*/
function validate(data: SavedData<string>): boolean {
// ボタン名が空の場合、エラーを表示
if (!data.buttonName.trim()) {
errMessage.value = 'ボタン名を入力してください。';
return false;
}
for (const joinTable of data.joinTables) {
// 取得元アプリが空の場合、エラーを表示
if (!joinTable.app.trim()) {
errMessage.value = '取得元アプリを指定してください。';
return false;
}
// 取得フィールドのマッピングが1つ未満の場合、エラーを表示
if (
joinTable.fieldsMapping.length < 1 ||
!joinTable.fieldsMapping[0].leftField?.trim() ||
!joinTable.fieldsMapping[0].rightField?.trim()
) {
errMessage.value = '取得フィールドを1つ以上設定してください。';
return false;
}
}
return true;
}
function save() {
if(!validate(data)){
showError.value=true;
return;
}
const currentAppMeta = cachedData.currentAppFields.fields;
const convertJoinTables = JSON.parse(JSON.stringify(data.joinTables)) as JoinTable<OneOf | string>[];
convertJoinTables.forEach((item) => {

View File

@@ -0,0 +1,79 @@
<template>
<div ref="dialogContainer">
</div>
</template>
<script setup lang="ts">
import { Button, Dialog } from "kintone-ui-component";
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
const props = defineProps<{
message: string;
show: boolean;
}>();
const isDialogVisible = ref(props.show);
watch(
() => props.message,
(newMessage) => {
if (dialog.value) {
dialog.value.content=newMessage;
}
}
);
watch(
() => props.show,
(newValue) => {
if (dialog.value) {
if (newValue) {
dialog.value.open();
} else {
dialog.value.close();
}
}
}
);
const emit = defineEmits(["update:show"]);
const dialog = ref<Dialog | null>(null);
const dialogContainer = ref<HTMLDivElement | null>(null);
const closeDialog = () => {
if (dialog.value) {
dialog.value.close();
}
emit("update:show", false);
}
onMounted(() => {
if (!dialogContainer.value) return;
const okButton = new Button({ text: "OK", type: "normal" });
okButton.addEventListener("click", closeDialog);
const footerDiv = document.createElement("div");
footerDiv.className="dialog-action-bar";
footerDiv.appendChild(okButton);
// 创建 Dialog 实例
dialog.value = new Dialog({
header: "エラー情報",
content: props.message,
icon: "error",
container: dialogContainer.value,
footer: footerDiv,
footerVisible:true
});
if (props.show) {
dialog.value.open();
}
});
</script>

View File

@@ -24,7 +24,8 @@
</plugin-row>
<plugin-row class="flex-row">
<plugin-label label="絞込条件" />
<plugin-table-condition-row :modelValue="table.whereConditions"/>
<plugin-table-condition-row :modelValue="table.whereConditions" :table="table"
@update:modelValue="(newData:any) => table.whereConditions = newData"/>
</plugin-row>
</div>
<div class="table-action-area">

View File

@@ -1,10 +1,13 @@
<template>
<kuc-table className='plugin-kuc-table condition-table' :columns="columns" :data="modelValue" />
<kuc-table className='plugin-kuc-table condition-table'
:columns="columns"
:data="modelValue"
/>
</template>
<script setup lang="ts">
import type { CachedData, CachedSelectedAppData, SavedData, WhereCondition } from '@/types/model';
import { defineProps, inject, computed, render, h, reactive } from 'vue';
import type { CachedData, CachedSelectedAppData, JoinTable, SavedData, WhereCondition } from '@/types/model';
import { defineProps, inject, computed, render, h, reactive, watch } from 'vue';
import TableCombobox from './TableCombobox.vue';
import { generateId, getFieldsDropdownItems, search } from '@/js/helper';
import TableCondition from './conditions/TableCondition.vue';
@@ -12,6 +15,11 @@ import TableConditionValue from './conditions/TableConditionValue.vue';
const props = defineProps<{
modelValue: WhereCondition[];
table:JoinTable;
}>();
const emit = defineEmits<{
(event: 'update:modelValue', value: WhereCondition[]): void;
}>();
const savedData = inject<SavedData>('savedData') as SavedData;
@@ -21,6 +29,17 @@ const selectedAppData = inject<CachedSelectedAppData>('selectedAppData') as Cach
const canSave = inject<(canSave: boolean) => void>('canSave') as (canSave: boolean) => void;
watch(
()=>props.modelValue,
(newValue,oldValue)=>{
console.log(newValue);
console.log(oldValue);
},{
deep:true,
immediate:true
}
)
const columns = reactive([
{
title: '取得元アプリのフィールド',
@@ -85,7 +104,13 @@ const columns = reactive([
id: rowData.id,
whereConditions: props.modelValue,
'onUpdate:modelValue': ({obj, value}) => {
obj && (obj.data = value);
if(obj){
obj.data = value;
const newData = props.modelValue.map((item) =>
item.id === obj.id ? { ...item, data: value } : item
);
emit('update:modelValue', newData);
}
},
});
render(vnode, container);

View File

@@ -92,6 +92,7 @@ const columns = reactive([
filterType: filterFunc[props.type].right(dependFilterField),
dependFilterField,
defaultDisableCallback: props.type === 'connect' ? isRightJoinForceDisable : undefined,
needSubTableField:false
});
}),
modelValue: computed(() => (search(props.modelValue, rowData.id) as FieldsJoinMapping)?.rightField || ''),

View File

@@ -0,0 +1,22 @@
<template>
<kuc-text className="kuc-text-input" :value="modelValue" @change="updateValue" />
</template>
<script setup lang="ts">
import type { KucEvent } from '@/types/my-kintone';
import type { TextInputEventDetail } from 'kintone-ui-component';
import { defineProps, defineEmits, type Ref } from 'vue';
const props = defineProps<{
modelValue: string;
}>();
const emit = defineEmits<{
(e: 'update:modelValue', value: string): void;
}>();
const updateValue = ({ detail }: KucEvent<TextInputEventDetail>) => {
emit('update:modelValue', detail.value || '');
};
</script>

View File

@@ -1,6 +1,6 @@
<template>
<kuc-text
v-if="type === 'kuc-text'"
v-if="valueType === 'kuc-text'"
:value="modelValue.value"
@change="updateValue"
:className="needPlaceholderWidthClass"
@@ -8,32 +8,38 @@
:disabled="selectedAppData.loading == undefined ? false : selectedAppData.loading"
/>
<kuc-combobox
v-else-if="type === 'kuc-combobox'"
v-else-if="valueType === 'kuc-combobox'"
:value="modelValue.value"
@change="updateValue"
:disabled="selectedAppData.loading == undefined ? false : selectedAppData.loading"
/>
<kuc-time-picker
v-else-if="type === 'kuc-time'"
v-else-if="valueType === 'kuc-time'"
:value="modelValue.value"
@change="updateValue"
:disabled="selectedAppData.loading == undefined ? false : selectedAppData.loading"
/>
<table-condition-value-date-time
v-else-if="type === 'datetime' || type === 'date'"
:time="type === 'datetime'"
v-else-if="valueType === 'datetime' || valueType === 'date'"
:time="valueType === 'datetime'"
:value="modelValue.value as string"
@change="updateValue"
:disabled="selectedAppData.loading == undefined ? false : selectedAppData.loading"
/>
<kuc-multi-choice
v-else-if="type=== 'kuc-multichoice'"
v-else-if="valueType=== 'kuc-multichoice'"
:value = "muiltValue"
:items = "multiChoiceItems"
:requiredIcon = "true"
@change="updateMuiltValue"
:disabled="selectedAppData.loading == undefined ? false : selectedAppData.loading"
></kuc-multi-choice>
<table-condition-value-multi-input
v-else-if = "valueType ==='multi-input'"
:value="muiltInput"
@change="updateTableValue"
:disabled="selectedAppData.loading == undefined ? false : selectedAppData.loading"
/>
</template>
@@ -43,7 +49,7 @@ import { getFieldObj, isStringArray, search } from '@/js/helper';
import { isType } from '@/js/kintone-rest-api-client';
import type { CachedSelectedAppData, StringValue, WhereCondition } from '@/types/model';
import type { KucEvent } from '@/types/my-kintone';
import type { ComboboxChangeEventDetail, TextInputEventDetail,MultiChoiceChangeEventDetail } from 'kintone-ui-component';
import type { ComboboxChangeEventDetail, TextInputEventDetail,MultiChoiceChangeEventDetail, TableChangeEventDetail } from 'kintone-ui-component';
import { defineProps, defineEmits, computed, type Ref, inject, provide, ref, watch, watchEffect } from 'vue';
const props = defineProps<{
@@ -91,10 +97,10 @@ const multiChoiceItems = computed(()=>{
return items;
});
const type = computed(() => {
const valueType = computed(() => {
const field = getFieldObj(whereCondition.value?.field || '', props.selectedAppData.appFields, '');
const type = getComponent(whereCondition.value?.condition || '', field)
return type;
const vtype = getComponent(whereCondition.value?.condition || '', field)
return vtype;
});
type EmitData = {
@@ -111,11 +117,24 @@ const updateValue = (event: KucEvent<ComboboxChangeEventDetail | TextInputEventD
};
const muiltValue = ref(isStringArray(props.modelValue.value) ? props.modelValue.value : []);
watch(
()=>props.modelValue,
()=>{
const field = getFieldObj(whereCondition.value ?.field || '', props.selectedAppData.appFields, '');
const vType = valueType.value;
const moduleValue = props.modelValue.value;
if(field && "options" in field && (vType==='kuc-multichoice' )){
muiltValue.value = isStringArray(moduleValue) ? moduleValue : [];
}
});
const muiltInput = ref(isStringArray(props.modelValue.value) ? props.modelValue.value as string[] : ["",""]);
watchEffect(()=>{
const field = getFieldObj(whereCondition.value ?.field || '', props.selectedAppData.appFields, '');
const valueType = type.value;
if(field && "options" in field && valueType==='kuc-multichoice'){
muiltValue.value = isStringArray(props.modelValue.value) ? props.modelValue.value : [];
const vType = valueType.value;
const moduleValue = props.modelValue.value;
if( vType==='multi-input'){
muiltInput.value = isStringArray(moduleValue) ? moduleValue as string[] : ["",""];
}
});
@@ -123,4 +142,10 @@ const updateMuiltValue = (event: KucEvent<MultiChoiceChangeEventDetail>) => {
let value = event.detail.value || [];
emit('update:modelValue',{ obj: whereCondition.value, value: event.detail.value ||[] } );
};
const updateTableValue =(event: KucEvent<string[]>)=>{
let value = event.detail || ["",""];
muiltInput.value = value;
emit('update:modelValue',{ obj: whereCondition.value, value: value } );
}
</script>

View File

@@ -0,0 +1,85 @@
<template>
<!-- <kuc-table className='table-option'
:columns="columns"
:data="data"
@change="updateValue"
:headerVisible="false"
ref="table"/> -->
<div ref="tableContainer"></div>
</template>
<script setup lang="ts">
import { dateFuncList, dateFuncMap, getComponent, getDateFuncList, type DateFuncKey } from '@/js/conditions';
import { getFieldObj, isStringArray, search } from '@/js/helper';
import type { CachedSelectedAppData, StringValue, WhereCondition } from '@/types/model';
import type { KucEvent } from '@/types/my-kintone';
import { Table, Text, type ComboboxChangeEventDetail, type TableChangeEventDetail, type TextInputEventDetail } from 'kintone-ui-component';
import { defineProps, defineEmits, computed, ref, watch, inject, type Ref, onMounted, reactive, watchEffect,h, render, onUnmounted } from 'vue';
interface MuiltItem{
value:string
}
const props = defineProps<{
value: string[];
}>();
const tableContainer = ref<HTMLDivElement>();
const table = ref<Table | null>(null);
const data = ref<MuiltItem[]>((props.value || ['', '']).map(x => ({ value: x })));
watch(
() => props.value,
(newValue)=>{
data.value =(newValue || ['', '']).map((x) => ({ value: x }));
if (table.value) {
table.value.data = data.value; // 更新 Table 数据
}
},
{
deep:true,immediate:true
});
const emit = defineEmits<{
(e: 'change', data: KucEvent<string[]>): void;
(e: 'update:modelValue', value: string[]): void;
}>();
const updateValue=(event:KucEvent<TableChangeEventDetail<MuiltItem>>)=>{
data.value = event.detail.data||[{value:''},{value:''}];
if (table.value) {
table.value.data = data.value;
}
const muiltData = event.detail.data ? event.detail.data.map(x=>x.value) :[];
emit('change', { detail: [...muiltData] });
// emit('update:modelValue', [...muiltData] );
// emit('change', muiltData);
}
onMounted(()=>{
table.value = new Table({
className:'table-option',
headerVisible:false,
actionButton:true,
columns:[
{
field:"value",
render:(cellData:any)=>{
const text = new Text({value:cellData});
return text;
}
},
],
data:data.value
});
table.value.addEventListener('change', updateValue);
tableContainer.value?.appendChild(table.value);
});
onUnmounted(() => {
if (table.value) {
table.value.removeEventListener('change', updateValue);
}
});
</script>

View File

@@ -238,4 +238,12 @@
}
.from-today-input.input.error {
margin-bottom: 20px;
}
.table-option td {
padding: 1px;
margin: 0;
border: none;
}
.dialog-action-bar{
text-align: right;
}

View File

@@ -31,7 +31,7 @@ export const conditionList: ConditionItem[] = [
{ value: 'like', label: '次のキーワードを含む', type: 'input' },
{ value: 'not like', label: '次のキーワードを含まない', type: 'input' },
{ value: 'in', label: '次のいずれかを含む', type: (field)=>MultiChoiceComponent[field.type] || 'input' },
{ value: 'not in', label: '次のいずれも含まない', type: (field)=>MultiChoiceComponent[field.type] || 'input' },
{ value: 'not in', label: '次のいずれも含まない', type: (field)=>MultiChoiceComponent[field.type] || 'input' },
];
// search from conditionList
@@ -95,7 +95,8 @@ const component = {
time: 'kuc-time',
date: 'date',
datetime: 'datetime',
multiChoice:'kuc-multichoice'
multiChoice:'kuc-multichoice',
multiInput :"multi-input"
};
export const isDateTimeType = (field: OneOf) => {
@@ -114,9 +115,12 @@ const MultiChoiceComponent:Partial<Record<FieldType, ComponentType>> = {
CHECK_BOX: 'multiChoice',
DROP_DOWN: 'multiChoice',
RADIO_BUTTON: 'multiChoice',
MULTI_SELECT: 'multiChoice'
MULTI_SELECT: 'multiChoice',
SINGLE_LINE_TEXT : 'multiInput',
LINK : 'multiInput'
};
export type ComponentType = keyof typeof component;
export const getComponent = (value: ConditionValue, fieldObj: OneOf) => {
if (!value || !fieldObj) return;