This commit is contained in:
211
src/js/helper.ts
Normal file
211
src/js/helper.ts
Normal file
@@ -0,0 +1,211 @@
|
||||
import type { FieldsInfo, FieldsJoinMapping, JoinTable, WhereCondition } from '@/types/model';
|
||||
import {
|
||||
client,
|
||||
isType,
|
||||
type FieldType,
|
||||
type App,
|
||||
type Layout,
|
||||
type OneOf,
|
||||
type Properties,
|
||||
} from './kintone-rest-api-client';
|
||||
import type { ComboboxItem, DropdownItem } from 'kintone-ui-component';
|
||||
import { isSpecialType, type SpecialType } from './join';
|
||||
|
||||
export const EMPTY_OPTION = {
|
||||
value: '',
|
||||
label: '--------',
|
||||
} as DropdownItem;
|
||||
|
||||
export function generateId(): string {
|
||||
const timestamp = new Date().getTime().toString(36);
|
||||
const randomNum = Math.random().toString(36).substring(2, 11);
|
||||
return `${timestamp}-${randomNum}`;
|
||||
}
|
||||
|
||||
export function search(list: Array<WhereCondition | FieldsJoinMapping>, id: string) {
|
||||
if (!list) return;
|
||||
return list.find((item) => item.id === id);
|
||||
}
|
||||
|
||||
export const getEmptyWhereCondition = () =>
|
||||
({ field: '', condition: '', data: '', id: generateId() }) as WhereCondition;
|
||||
export const getEmptyOnCondition = () => ({ leftField: '', rightField: '', id: generateId() }) as FieldsJoinMapping;
|
||||
export const getEmptyFieldsMapping = () => ({ leftField: '', rightField: '', id: generateId() }) as FieldsJoinMapping;
|
||||
|
||||
export function createEmptyJoinTable(id = generateId()) {
|
||||
return resetTable({ id, app: '' } as JoinTable);
|
||||
}
|
||||
|
||||
export function resetTable(table: JoinTable) {
|
||||
table.table = '';
|
||||
return resetConditions(table);
|
||||
}
|
||||
|
||||
export function resetConditions(table: JoinTable) {
|
||||
table.onConditions = [getEmptyOnCondition()];
|
||||
table.fieldsMapping = [getEmptyFieldsMapping()];
|
||||
table.whereConditions = [getEmptyWhereCondition()];
|
||||
return table;
|
||||
}
|
||||
|
||||
const LIMIT = 100; // 毎回請求の最大値
|
||||
export const loadApps = async (offset = 0, _apps: DropdownItem[] = []): Promise<DropdownItem[]> => {
|
||||
const { apps } = await client.app.getApps({ limit: LIMIT, offset });
|
||||
const allApps: DropdownItem[] = [
|
||||
..._apps,
|
||||
...apps.map((app: App) => ({ value: app.appId, label: app.name + '(ID: ' + app.appId + ')' })),
|
||||
];
|
||||
if (apps.length === LIMIT) {
|
||||
return loadApps(offset + LIMIT, allApps);
|
||||
}
|
||||
allApps.sort((a, b) => Number(b.value) - Number(a.value));
|
||||
allApps.unshift(EMPTY_OPTION);
|
||||
return allApps;
|
||||
};
|
||||
|
||||
export const loadAppFieldsAndLayout = async (appId: string | number = kintone.app.getId() as number) => {
|
||||
const fields = (await client.app.getFormFields({ app: appId })).properties;
|
||||
return {
|
||||
fields: flatFields(fields),
|
||||
layout: (await client.app.getFormLayout({ app: appId })).layout,
|
||||
} as FieldsInfo;
|
||||
};
|
||||
|
||||
function flatFields(fields: Properties) {
|
||||
const subtableFields = {} as Properties;
|
||||
Object.values(fields).forEach((field) => {
|
||||
if (isType.SUBTABLE(field)) {
|
||||
Object.values(field.fields).forEach((subField) => {
|
||||
const copy = JSON.parse(JSON.stringify(subField)) as typeof subField & {originLabel:string, tableCode:string};
|
||||
copy.label = '[' + field.label + '].' + subField.label;
|
||||
copy.originLabel = subField.label;
|
||||
copy.tableCode = field.code;
|
||||
subtableFields[subField.code] = copy;
|
||||
});
|
||||
}
|
||||
});
|
||||
return { ...fields, ...subtableFields };
|
||||
}
|
||||
|
||||
type FilterType = Array<FieldType | SpecialType>;
|
||||
type Param = {
|
||||
subTableCode: string | undefined;
|
||||
filterType?: FilterType;
|
||||
baseFilter: FieldType[] | undefined;
|
||||
dependFilterField?: OneOf;
|
||||
defaultLabel?: string;
|
||||
defaultDisableCallback?: (field: OneOf) => boolean;
|
||||
needAllSubTableField?: boolean;
|
||||
};
|
||||
export const getFieldsDropdownItems = (
|
||||
{ fields, layout }: FieldsInfo,
|
||||
{
|
||||
subTableCode, // specified subTable
|
||||
baseFilter, // set not allowed items hidden, undefined means no filter
|
||||
defaultLabel, // label shown (default '--------')
|
||||
filterType, // set not allowed items disabled, undefined and [] means no filter
|
||||
dependFilterField, // used for filterType
|
||||
defaultDisableCallback, // callback to control disabled items, like filterType
|
||||
needAllSubTableField = false, // show all subtable fields
|
||||
}: Param,
|
||||
) => {
|
||||
// get used field codes
|
||||
const fieldOrder = extractFields(layout, baseFilter, !!needAllSubTableField, subTableCode);
|
||||
const fieldMap = fields;
|
||||
|
||||
// create labels
|
||||
const labels: ComboboxItem[] = [
|
||||
{
|
||||
value: EMPTY_OPTION.value,
|
||||
label: defaultLabel || EMPTY_OPTION.label,
|
||||
},
|
||||
];
|
||||
return fieldOrder.reduce((acc, fieldCode) => {
|
||||
const field = fieldMap[fieldCode];
|
||||
if (!fieldCode) return acc;
|
||||
acc.push({
|
||||
value: fieldCode,
|
||||
label: field.label + '(FC: ' + fieldCode + ')',
|
||||
disabled:
|
||||
(defaultDisableCallback && defaultDisableCallback(field)) ||
|
||||
(filterType && !checkFilterType(field, dependFilterField, filterType)),
|
||||
});
|
||||
return acc;
|
||||
}, labels);
|
||||
};
|
||||
|
||||
const checkFilterType = (field: OneOf, dependFilterField: OneOf | undefined, filterType: FilterType) => {
|
||||
if (!filterType.length) return true; // [] means no filter
|
||||
return !!filterType.find((type) => {
|
||||
if (isSpecialType(type)) {
|
||||
return type.check(field, dependFilterField);
|
||||
}
|
||||
return isType[type](field);
|
||||
});
|
||||
};
|
||||
|
||||
export const getTableFieldsDropdownItems = ({ fields }: FieldsInfo, filterType?: FieldType) => {
|
||||
return Object.keys(fields).reduce(
|
||||
(acc, fieldCode) => {
|
||||
const field = fields[fieldCode];
|
||||
if (filterType && !isType[filterType](field)) return acc;
|
||||
acc.push({
|
||||
value: fieldCode,
|
||||
label: field.label + '(FC: ' + fieldCode + ')',
|
||||
});
|
||||
return acc;
|
||||
},
|
||||
[EMPTY_OPTION],
|
||||
);
|
||||
};
|
||||
|
||||
const extractFields = (layout: Layout, baseFilter: FieldType[] | undefined, needAllSubTableField: boolean, subTableCode?: string) => {
|
||||
return layout.reduce((acc, each) => {
|
||||
if (each.type === 'GROUP') {
|
||||
acc.push(...extractFields(each.layout, baseFilter, needAllSubTableField, subTableCode));
|
||||
} else if (each.type === 'ROW' || (!needAllSubTableField && each.code === subTableCode) || (needAllSubTableField && each.type === 'SUBTABLE')) {
|
||||
acc.push(
|
||||
...each.fields.map((field) => {
|
||||
if (!('code' in field)) return '';
|
||||
if (!baseFilter) return field.code;
|
||||
return baseFilter.find((t) => t === field.type) ? field?.code || '' : '';
|
||||
}),
|
||||
);
|
||||
}
|
||||
return acc;
|
||||
}, [] as string[]);
|
||||
};
|
||||
|
||||
export function getFieldObj(fieldCode: string, { fields }: FieldsInfo, subTableCode?: string) {
|
||||
const meta = getMeta(fields, subTableCode);
|
||||
return meta[fieldCode];
|
||||
}
|
||||
|
||||
export function getMeta(fields: Properties, subTableCode?: string, withNoSubTableField = true) {
|
||||
if (!fields || !subTableCode) {
|
||||
return fields;
|
||||
}
|
||||
let meta = fields;
|
||||
const table = meta[subTableCode];
|
||||
if (isType.SUBTABLE(table)) {
|
||||
const subFields = table.fields;
|
||||
Object.values(subFields).forEach((field) => {
|
||||
if (typeof field === 'object' && field !== null) {
|
||||
(field as Record<string, any>).subField = true;
|
||||
}
|
||||
});
|
||||
if (withNoSubTableField) {
|
||||
meta = { ...fields, ...subFields };
|
||||
} else {
|
||||
meta = subFields;
|
||||
}
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
|
||||
export const isStringArray = (value: any) => {
|
||||
if (Array.isArray(value) && value.every((x) => typeof x === 'string')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
Reference in New Issue
Block a user