import { IAction, IActionResult, IActionNode, IActionProperty, IContext, IField, } from "../types/ActionTypes"; import { actionAddins } from "."; import type { Record} from "@kintone/rest-api-client/lib/src/client/types"; import { KintoneAllRecordsError, KintoneRestAPIClient} from "@kintone/rest-api-client"; import "./auto-lookup.scss"; import "bootstrap/js/dist/modal"; // import "bootstrap/js/dist/spinner"; import {Modal} from "bootstrap" import $ from "jquery"; interface IAutoLookUpProps { displayName: string; lookupField: LookupField; condition: Condition; } interface Condition { queryString: string; index: number; type: string; children: Child[]; parent: null; logicalOperator: string; } interface Child { index: number; type: string; parent: string; object: any; operator: string; value: string; } interface LookupField { app: App; fields: Field[]; } interface Field { name: string; type: string; code: string; label: string; noLabel: boolean; required: boolean; lookup: Lookup; } interface Lookup { relatedApp: RelatedApp; relatedKeyField: string; fieldMappings: FieldMapping[]; lookupPickerFields: any[]; filterCond: string; sort: string; } interface FieldMapping { field: string; relatedField: string; } interface RelatedApp { app: string; code: string; } interface App { id: string; name: string; description: string; createdate: string; } export class AutoLookUpAction implements IAction { name: string; actionProps: IActionProperty[]; props: IAutoLookUpProps; constructor() { this.name = "ルックアップ更新"; this.actionProps = []; this.props = {} as IAutoLookUpProps; this.register(); } /*** * アクセスのメインの処理関数 */ async process( actionNode: IActionNode, event: any, context: IContext ): Promise { this.actionProps = actionNode.actionProps; this.props = { ...actionNode.ActionValue, condition: JSON.parse((actionNode.ActionValue as any).condition), } as IAutoLookUpProps; // console.log(context); let result = { canNext: true, result: "", } as IActionResult; try { const lookUpFields = this.props.lookupField.fields.filter( (f) => f.lookup && f.lookup.relatedApp.app === String(kintone.app.getId()) ); if (!lookUpFields || lookUpFields.length===0) { throw new Error( `ルックアップの設定は不正です。${this.props.lookupField.fields[0].label} ` ); } const lookUpField = this.props.lookupField.fields[0]; const key = event.record[lookUpField.lookup.relatedKeyField].value; const targetRecords = await this.getUpdateRecords(lookUpField, key); //更新対象がない時にスキップ if(targetRecords.length===0){ return result; } const updateRecords = this.convertForLookup(targetRecords,lookUpField,key); console.log("updateRecords", updateRecords); this.showSpinnerModel(this.props.lookupField.app,lookUpField); const updateResult = await this.updateLookupTarget(updateRecords); if(updateResult){ this.showResult(this.props.lookupField.app,lookUpField,updateRecords.length); } } catch (error) { this.closeDialog(); context.errors.handleError(error,actionNode,"ルックアップ更新中例外が発生しました"); result.canNext = false; } return result; } /** * REST API用クエリ作成 * TODO:共通関数として作成 * @param lookUpField * @param key * @returns */ makeQuery=(lookUpField:Field,key:any)=>{ let query =""; if(typeof key==='number'){ query = `${lookUpField.code} = ${key}` } if(typeof key==='string'){ query = `${lookUpField.code} = "${key}"` } if(this.props.condition.queryString!==''){ query = `${query} and (${this.props.condition.queryString})` } return query; } /** * 更新対象のレコードを取得する */ getUpdateRecords = async (lookUpField:Field,key:any):Promise< Record[]>=>{ const client=new KintoneRestAPIClient(); const resp = await client.record.getAllRecords({ app:this.props.lookupField.app.id, fields:["$id"], condition:this.makeQuery(lookUpField,key) }); return resp; } /** * ルックアップ更新用レコードに変換する * @param targetRecords 更新対象レコード * @param lookUpField ルックアップフィールド * @param key ルックアップフィールドの値 * @returns */ convertForLookup = (targetRecords:Record[],lookUpField:Field,key:any):Array=>{ return targetRecords.map((r) => ({ id: Number(r["$id"].value), record: { [lookUpField.code]: { value: key } }, })); } /** * ルックアップ先を更新する * @param updateRecords */ updateLookupTarget = async (updateRecords:Array):Promise=>{ if (updateRecords && updateRecords.length > 0) { try{ const client=new KintoneRestAPIClient(); const result = await client.record.updateAllRecords({ app:this.props.lookupField.app.id, records:updateRecords }); return true; }catch(error ){ if(error instanceof KintoneAllRecordsError){ this.showError(this.props.lookupField.app, this.props.lookupField.fields[0], error as KintoneAllRecordsError,updateRecords.length); return false; }else{ throw error; } } // await kintone.api(kintone.api.url("/k/v1/records.json", true), "PUT", { // app: this.props.lookupField.app.id, // records: updateRecords // }); } return false; } /** * 更新中のダイアログ表示 * @param app */ showSpinnerModel = (app:App,lookup:Field) => { let dialog = $("#alcLookupModal"); if(dialog.length===0){ const modalHTML = `
`; $(modalHTML).appendTo("body"); dialog = $("#alcLookupModal"); dialog.get()[0].addEventListener('hidden.bs.modal',(ev)=>{ Modal.getOrCreateInstance(dialog.get()[0]).dispose(); $("#alcLookupModal").parent().remove(); }); }else{ const dialogBody=$("#alcLookupModal .modal-body"); const htmlrow=`
${app.name}
`; dialogBody.append(htmlrow); } Modal.getOrCreateInstance(dialog.get()[0]).show(); } /** * 更新結果を表示する * @param app  更新先アプリ情報 * @param count 更新件数 */ showResult=(app:App,lookup:Field,count:number)=>{ const dialogBody=$(`#alcLookupModal .modal-body #app${app.id}_${lookup.code}`); const html=`
${app.name}
更新件数:${count}件
`; dialogBody.html(html); } /** * 更新結果を表示する * @param app  更新先アプリ情報 * @param count 更新件数 */ showError=(app:App,lookup:Field,error:KintoneAllRecordsError,allCount:Number)=>{ const message=error.error.message; const proRecords = error.numOfProcessedRecords; const allRecords=error.numOfAllRecords; const dialogBody=$(`#alcLookupModal .modal-body #app${app.id}_${lookup.code}`); const html=`
${app.name}
更新件数:${proRecords}/${allRecords}
${message}
`; dialogBody.html(html); } /** * ダイアログ画面を閉じる */ closeDialog=()=>{ const dialog = $("#alcLookupModal"); Modal.getOrCreateInstance(dialog.get()[0]).dispose(); $("#alcLookupModal").parent().remove(); } register(): void { actionAddins[this.name] = this; } } new AutoLookUpAction();