自動採番アクション追加・ドメイン追加

This commit is contained in:
2023-11-01 10:47:24 +09:00
parent df593d2ffe
commit cfc416fd14
20 changed files with 529 additions and 56 deletions

View File

@@ -0,0 +1,132 @@
import { actionAddins } from ".";
import { IField, IAction,IActionResult, IActionNode, IActionProperty } from "../types/ActionTypes";
import { Formatter } from "../util/format";
declare global {
interface Window { $format: any; }
}
interface IAutoNumberingProps{
//文書番号を格納する
field:IField;
format:string;
prefix:string;
suffix:string;
}
export class AutoNumbering implements IAction{
name: string;
actionProps: IActionProperty[];
props:IAutoNumberingProps;
constructor(){
this.name="自動採番する";
this.actionProps=[];
this.register();
this.props={
field:{code:''},
format:'',
prefix:'',
suffix:''
}
globalThis.window.$format=this.format;
this.register();
}
async process(actionNode:IActionNode,event:any):Promise<IActionResult> {
let result={
canNext:false,
result:false
};
try{
this.actionProps=actionNode.actionProps;
if (!('field' in actionNode.ActionValue) && !('format' in actionNode.ActionValue)) {
return result
}
this.props = actionNode.ActionValue as IAutoNumberingProps;
const record = event.record;
const docNum = await this.createNumber(this.props);
record[this.props.field.code].value=docNum;
result= {
canNext:true,
result:true
}
return result;
}catch(error){
console.error(error);
event.error="処理中異常が発生しました。";
return {
canNext:false,
result:false
}
}
}
execTemplate(template:string):string{
if(template===undefined) return '';
const regex = /\$\{([^}]+)\}/g;
return template.replace(regex,(match,expr)=>{
return this.execEval(match,expr);
});
}
execEval(match:string,expr:string):string{
console.log(match);
return eval(expr);
}
format(pattern:string):string{
const now=new Date();
return Formatter.dateFormat(now, pattern);
}
async createNumber(props:IAutoNumberingProps){
let number :string='';
let prefix:string='';
let suffix:string='';
let no = await this.fetchNo();
if(props.format!==undefined && props.format!==''){
number=Formatter.numberFormat(no, props.format);
}else{
number=no.toString(10);
}
if(props.prefix!==undefined && props.prefix!==''){
prefix=this.execTemplate(props.prefix);
}
if(props.suffix!==undefined && props.suffix!==''){
suffix=this.execTemplate(props.suffix);
}
return `${prefix}${number}${suffix}`;
}
async fetchNo():Promise<number>{
let recNo=1;
return await new kintone.Promise<number>((resolve,reject)=>{
const appurl = kintone.api.url('/k/v1/records',true);
const params={
app:kintone.app.getId(),
fields:['$id'],
query:'limit 1'
};
return kintone.api(appurl,'GET',params).then((resp)=>{
if(resp.records[0]!==null){
recNo = parseInt(resp.records[0].$id.value,10)+1;
}
resolve(recNo);
}).catch((error)=>{
reject(error);
});
});
}
register(): void {
actionAddins[this.name]=this;
}
}
new AutoNumbering();

View File

@@ -1,9 +1,9 @@
import { actionAddins } from ".";
import { IAction,IActionResult, IActionNode, IActionProperty } from "../types/ActionTypes";
import { IAction,IActionResult, IActionNode, IActionProperty, IField } from "../types/ActionTypes";
interface IMustInputProps{
field:string;
field:IField;
message:string;
}
@@ -16,13 +16,13 @@ export class MustInputAction implements IAction{
this.actionProps=[];
this.register();
this.props={
field:'',
field:{code:''},
message:''
}
this.register();
}
process(actionNode:IActionNode,event:any):IActionResult {
async process(actionNode:IActionNode,event:any):Promise<IActionResult> {
let result={
canNext:true,
result:false
@@ -33,9 +33,9 @@ export class MustInputAction implements IAction{
}
this.props = actionNode.ActionValue as IMustInputProps;
const record = event.record;
const value = record[this.props.field]?.value;
const value = record[this.props.field.code]?.value;
if(value===undefined || value===''){
record[this.props.field].error=this.props.message;
record[this.props.field.code].error=this.props.message;
return result;
}
result= {

View File

@@ -15,12 +15,12 @@ declare const alcflow : {
$(function (){
const events=Object.keys(alcflow);
kintone.events.on(events,(event:any)=>{
kintone.events.on(events,async (event:any)=>{
const flowinfo = alcflow[event.type];
const flow=ActionFlow.fromJSON(flowinfo.content);
if(flow!==undefined){
const process = new ActionProcess(event.type,flow,event);
process.exec();
await process.exec();
}
return event;
});

View File

@@ -64,10 +64,16 @@ export interface IActionResult{
export interface IAction{
name:string;
actionProps: Array<IActionProperty>;
process(prop:IActionNode,event:any):IActionResult;
process(prop:IActionNode,event:any):Promise<IActionResult>;
register():void;
}
export interface IField{
name?:string;
code:string;
type?:string;
}
/**
* アクションのプロパティ定義に基づいたクラス
*/

View File

@@ -1,6 +1,7 @@
import { actionAddins } from "../actions";
import '../actions/must-input';
import '../actions/auto-numbering';
import { ActionFlow,IActionFlow, IActionResult } from "./ActionTypes";
export class ActionProcess{
@@ -12,7 +13,7 @@ export class ActionProcess{
this.flow=flow;
this.event=event;
}
exec(){
async exec(){
const root = this.flow.getRoot();
if(root===undefined || root.nextNodeIds.size===0){
return;
@@ -26,7 +27,7 @@ export class ActionProcess{
while(nextAction!==undefined && result.canNext){
const action = actionAddins[nextAction.name];
if(action!==undefined){
result = action.process(nextAction,this.event)
result = await action.process(nextAction,this.event)
}
const nextInput = nextAction.outputPoints!==undefined?result.result||'':'';
id=nextAction.nextNodeIds.get(nextInput);

View File

@@ -0,0 +1,71 @@
export class Formatter{
static numberFormat(num:number,format:string):string{
let integerPart = Math.floor(Math.abs(num)).toString();
let fractionPart = Math.abs(num).toString().split('.')[1] || '';
let isNegative = num < 0;
let isPercent = format.includes('%');
// %
if (isPercent) {
num *= 100;
integerPart = Math.floor(Math.abs(num)).toString();
fractionPart = Math.abs(num).toString().split('.')[1] || '';
}
// 小数と整数部分の処理
let [integerFormat, fractionFormat] = format.split('.');
integerPart = integerFormat ? integerPart.padStart(integerFormat.replace(/[^0]/g, '').length, '0') : integerPart;
fractionPart = fractionPart.padEnd(fractionFormat ? fractionFormat.length : 0, '0');
// カマ区切
if (/,/.test(integerFormat)) {
const parts = [];
while (integerPart.length) {
parts.unshift(integerPart.slice(-3));
integerPart = integerPart.slice(0, -3);
}
integerPart = parts.join(',');
}
// すべて組合わせ
let result = fractionFormat ? `${integerPart}.${fractionPart}` : integerPart;
result = isNegative ? `-${result}` : result;
return isPercent ? `${result}%` : result;
}
static dateFormat(date: Date, format: string): string {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const hour = date.getHours();
const minute = date.getMinutes();
const second = date.getSeconds();
const millisecond = date.getMilliseconds();
const timeZoneOffset = -date.getTimezoneOffset() / 60;
const replacements = {
'yyyy': year.toString(),
'yy': year.toString().slice(-2),
'MM': month.toString().padStart(2, '0'),
'M': month.toString(),
'dd': day.toString().padStart(2, '0'),
'd': day.toString(),
'HH': hour.toString().padStart(2, '0'),
'H': hour.toString(),
'hh': (hour > 12 ? hour - 12 : hour).toString().padStart(2, '0'),
'h': (hour > 12 ? hour - 12 : hour).toString(),
'mm': minute.toString().padStart(2, '0'),
'm': minute.toString(),
'ss': second.toString().padStart(2, '0'),
's': second.toString(),
'fff': millisecond.toString().padStart(3, '0'),
'zzz': (timeZoneOffset >= 0 ? '+' : '-') + Math.abs(timeZoneOffset).toString().padStart(2, '0') + ':00'
};
return format.replace(/yyyy|yy|MM|M|dd|d|HH|H|hh|h|mm|m|ss|s|fff|zzz/g, (match) => {
return replacements[match as keyof typeof replacements] || match;
});
}
}