281 lines
7.0 KiB
TypeScript
281 lines
7.0 KiB
TypeScript
import {
|
|
IAction,
|
|
IActionResult,
|
|
IActionNode,
|
|
IActionProperty,
|
|
IContext,
|
|
} from "../types/ActionTypes";
|
|
import { actionAddins } from ".";
|
|
|
|
|
|
type DataProcessingProps = {
|
|
app: {
|
|
id: string;
|
|
name: string;
|
|
};
|
|
conditionsQuery: string;
|
|
propcessing: {
|
|
varRootName: string;
|
|
fields: Field[];
|
|
};
|
|
};
|
|
|
|
type Field = {
|
|
name: string;
|
|
code: string;
|
|
type: string;
|
|
varName: string;
|
|
operator: string;
|
|
};
|
|
|
|
export class DataProcessingAction implements IAction {
|
|
name: string;
|
|
actionProps: IActionProperty[];
|
|
dataProcessingProps: DataProcessingProps | null;
|
|
constructor() {
|
|
this.name = "データ処理";
|
|
this.actionProps = [];
|
|
this.dataProcessingProps = null;
|
|
this.register();
|
|
}
|
|
|
|
async process(
|
|
nodes: IActionNode,event: any,context: IContext
|
|
): Promise<IActionResult> {
|
|
this.initActionProps(nodes);
|
|
this.initTypedActionProps();
|
|
let result = {
|
|
canNext: true,
|
|
result: "",
|
|
} as IActionResult;
|
|
try {
|
|
if (!this.dataProcessingProps) {
|
|
return result;
|
|
}
|
|
|
|
const data = await selectData(this.dataProcessingProps.conditionsQuery);
|
|
console.log("data ", data);
|
|
|
|
context.variables[this.dataProcessingProps.propcessing.varRootName] =
|
|
this.dataProcessingProps.propcessing.fields.reduce((acc, f) => {
|
|
const v = calc(f, data);
|
|
if (v) {
|
|
acc[f.varName] = calc(f, data);
|
|
}
|
|
return acc;
|
|
}, {} as Var);
|
|
|
|
console.log("context ", context);
|
|
return result;
|
|
} catch (error) {
|
|
console.error(error);
|
|
event.error=error;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
register(): void {
|
|
actionAddins[this.name] = this;
|
|
}
|
|
|
|
private initActionProps(nodes: IActionNode) {
|
|
this.actionProps = nodes.actionProps;
|
|
}
|
|
|
|
private initTypedActionProps() {
|
|
this.dataProcessingProps = {
|
|
app: {
|
|
id: "",
|
|
name: "",
|
|
},
|
|
conditionsQuery: "",
|
|
propcessing: {
|
|
varRootName: "",
|
|
fields: [],
|
|
},
|
|
};
|
|
for (const action of this.actionProps) {
|
|
if (action.component === "AppFieldSelect") {
|
|
this.dataProcessingProps.app.id = action.props.modelValue.app.id;
|
|
this.dataProcessingProps.app.name = action.props.modelValue.app.name;
|
|
} else if (action.component === "DataProcessing") {
|
|
this.dataProcessingProps.propcessing.varRootName =
|
|
action.props.modelValue.name;
|
|
for (const f of action.props.modelValue.vars) {
|
|
this.dataProcessingProps.propcessing.fields.push({
|
|
name: f.field.name,
|
|
code: f.field.code,
|
|
type: f.field.type,
|
|
varName: f.vName,
|
|
operator: f.logicalOperator.operator,
|
|
});
|
|
}
|
|
} else if (action.component === "ConditionInput") {
|
|
this.dataProcessingProps.conditionsQuery = JSON.parse(
|
|
action.props.modelValue
|
|
).queryString;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
new DataProcessingAction();
|
|
|
|
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 = {
|
|
[key: string]: {
|
|
type: string;
|
|
value: any[];
|
|
};
|
|
};
|
|
|
|
type Var = {
|
|
[key: string]: any;
|
|
};
|
|
|
|
const ERROR_TYPE = "ERROR_TYPE";
|
|
|
|
const calc = (field: Field, result: Result) => {
|
|
const type = typeCheck(field.type);
|
|
if (!type) {
|
|
return ERROR_TYPE;
|
|
}
|
|
|
|
const fun =
|
|
calcFunc[`${type}_${Operator[field.operator as keyof typeof Operator]}`];
|
|
if (!fun) {
|
|
return ERROR_TYPE;
|
|
}
|
|
const values = result[field.code].value;
|
|
if (!values) {
|
|
return null;
|
|
}
|
|
return fun(values);
|
|
};
|
|
|
|
const typeCheck = (type: string) => {
|
|
switch (type) {
|
|
case "RECORD_NUMBER":
|
|
case "NUMBER":
|
|
return CalcType.NUMBER;
|
|
case "SINGLE_LINE_TEXT":
|
|
case "MULTI_LINE_TEXT":
|
|
case "RICH_TEXT":
|
|
return CalcType.STRING;
|
|
case "DATE":
|
|
return CalcType.DATE;
|
|
case "TIME":
|
|
return CalcType.TIME;
|
|
case "DATETIME":
|
|
case "UPDATED_TIME":
|
|
return CalcType.DATETIME;
|
|
default:
|
|
return null;
|
|
}
|
|
};
|
|
|
|
enum Operator {
|
|
SUM = "SUM",
|
|
AVG = "AVG",
|
|
MAX = "MAX",
|
|
MIN = "MIN",
|
|
COUNT = "COUNT",
|
|
FIRST = "FIRST"
|
|
}
|
|
|
|
enum CalcType {
|
|
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];
|
|
}
|
|
};
|