自動採番アクション追加・ドメイン追加
This commit is contained in:
132
plugin/kintone-addins/src/actions/auto-numbering.ts
Normal file
132
plugin/kintone-addins/src/actions/auto-numbering.ts
Normal 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();
|
||||
@@ -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= {
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* アクションのプロパティ定義に基づいたクラス
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
71
plugin/kintone-addins/src/util/format.ts
Normal file
71
plugin/kintone-addins/src/util/format.ts
Normal 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;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user