Merge commit '26a685b872daa65a069ad8c39ef4b973c8e25022' into feature-data-mapping
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -217,7 +217,9 @@ def deoployappfromkintone(app:str,revision:str,c:config.KINTONE_ENV):
|
||||
data = {"apps":[{"app":app,"revision":revision}],"revert": False}
|
||||
r = httpx.post(url,headers=headers,data=json.dumps(data))
|
||||
return r.json
|
||||
|
||||
|
||||
# 既定項目に含めるアプリのフィールドのみ取得する
|
||||
# スペース、枠線、ラベルを含まない
|
||||
def getfieldsfromkintone(app:str,c:config.KINTONE_ENV):
|
||||
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||
params = {"app":app}
|
||||
@@ -225,6 +227,44 @@ def getfieldsfromkintone(app:str,c:config.KINTONE_ENV):
|
||||
r = httpx.get(url,headers=headers,params=params)
|
||||
return r.json()
|
||||
|
||||
# フォームに配置するフィールドのみ取得する
|
||||
# スペース、枠線、ラベルも含める
|
||||
def getformfromkintone(app:str,c:config.KINTONE_ENV):
|
||||
headers={config.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||
params = {"app":app}
|
||||
url = f"{c.BASE_URL}{config.API_V1_STR}/form.json"
|
||||
r = httpx.get(url,headers=headers,params=params)
|
||||
return r.json()
|
||||
|
||||
|
||||
def merge_kintone_fields(fields_response: dict, form_response: dict) -> dict:
|
||||
fields_properties = fields_response.get('properties', {})
|
||||
form_properties = form_response.get('properties', [])
|
||||
|
||||
merged_properties = {k: v for k, v in fields_properties.items()}
|
||||
|
||||
for index, form_field in enumerate(form_properties):
|
||||
code = form_field.get('code')
|
||||
if code:
|
||||
if code and code not in merged_properties:
|
||||
merged_properties[code] = form_field
|
||||
else:
|
||||
element_id = form_field.get('elementId')
|
||||
if element_id:
|
||||
key = element_id
|
||||
form_field['code']=element_id
|
||||
form_field['label']=form_field.get('type')
|
||||
# else:
|
||||
# key = f"{form_field.get('type')}_{index}"
|
||||
merged_properties[key] = form_field
|
||||
|
||||
merged_response = {
|
||||
'revision': fields_response.get('revision', ''),
|
||||
'properties': merged_properties
|
||||
}
|
||||
|
||||
return merged_response
|
||||
|
||||
def analysefields(excel,kintone):
|
||||
updatefields={}
|
||||
addfields={}
|
||||
@@ -482,6 +522,15 @@ async def appfields(request:Request,app:str,env = Depends(getkintoneenv)):
|
||||
except Exception as e:
|
||||
raise APIException('kintone:appfields',request.url._url, f"Error occurred while get app fileds({env.DOMAIN_NAM}->{app}):",e)
|
||||
|
||||
@r.get("/allfields")
|
||||
async def allfields(request:Request,app:str,env = Depends(getkintoneenv)):
|
||||
try:
|
||||
field_resp = getfieldsfromkintone(app,env)
|
||||
form_resp = getformfromkintone(app,env)
|
||||
return merge_kintone_fields(field_resp,form_resp)
|
||||
except Exception as e:
|
||||
raise APIException('kintone:allfields',request.url._url, f"Error occurred while get form fileds({env.DOMAIN_NAM}->{app}):",e)
|
||||
|
||||
@r.get("/appprocess")
|
||||
async def appprocess(request:Request,app:str,env = Depends(getkintoneenv)):
|
||||
try:
|
||||
|
||||
@@ -13,14 +13,14 @@ API_V1_AUTH_KEY = "X-Cybozu-Authorization"
|
||||
DEPLOY_MODE = "DEV" #DEV,PROD
|
||||
|
||||
DEPLOY_JS_URL = "https://ka-addin.azurewebsites.net/alc_runtime.js"
|
||||
#DEPLOY_JS_URL = "https://e84c-133-139-70-142.ngrok-free.app/alc_runtime.js"
|
||||
#DEPLOY_JS_URL = "https://ce1c-133-139-70-194.ngrok-free.app/alc_runtime.js"
|
||||
|
||||
KINTONE_FIELD_TYPE=["GROUP","GROUP_SELECT","CHECK_BOX","SUBTABLE","DROP_DOWN","USER_SELECT","RADIO_BUTTON","RICH_TEXT","LINK","REFERENCE_TABLE","CALC","TIME","NUMBER","ORGANIZATION_SELECT","FILE","DATETIME","DATE","MULTI_SELECT","SINGLE_LINE_TEXT","MULTI_LINE_TEXT"]
|
||||
|
||||
KINTONE_FIELD_PROPERTY=['label','code','type','required','unique','maxValue','minValue','maxLength','minLength','defaultValue','defaultNowValue','options','expression','hideExpression','digit','protocol','displayScale','unit','unitPosition']
|
||||
|
||||
class KINTONE_ENV:
|
||||
|
||||
|
||||
BASE_URL = ""
|
||||
|
||||
API_V1_AUTH_VALUE = ""
|
||||
|
||||
@@ -24,4 +24,8 @@ python -m venv env
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
|
||||
```
|
||||
```
|
||||
4. backend 起動
|
||||
```bash
|
||||
uvicorn app.main:app --reload
|
||||
```
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
KAB_BACKEND_URL="https://kab-backend.azurewebsites.net/"
|
||||
#KAB_BACKEND_URL="http://127.0.0.1:8000/"
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
import { ref, onMounted, reactive, watchEffect } from 'vue'
|
||||
import { api } from 'boot/axios';
|
||||
|
||||
|
||||
export default {
|
||||
name: 'fieldSelect',
|
||||
props: {
|
||||
@@ -28,8 +29,9 @@ export default {
|
||||
type:Array,
|
||||
default:()=>[]
|
||||
},
|
||||
updateSelects: {
|
||||
type: Function
|
||||
fieldTypes:{
|
||||
type:Array,
|
||||
default:()=>[]
|
||||
},
|
||||
filter: String,
|
||||
},
|
||||
@@ -43,29 +45,26 @@ export default {
|
||||
const pageSetting = ref({
|
||||
sortBy: 'desc',
|
||||
descending: false,
|
||||
page: 2,
|
||||
page: 1,
|
||||
rowsPerPage: props.not_page ? 0 : 5
|
||||
// rowsNumber: xx if getting data from a server
|
||||
});
|
||||
const rows = reactive([]);
|
||||
const selected = ref(props.selectedFields && props.selectedFields.length>0?props.selectedFields:[]);
|
||||
|
||||
watchEffect(() => {
|
||||
props.updateSelects(selected);
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
const res = await api.get('api/v1/appfields', {
|
||||
const url = props.fieldTypes.includes('SPACER')?'api/v1/allfields':'api/v1/appfields';
|
||||
const res = await api.get(url, {
|
||||
params: {
|
||||
app: props.appId
|
||||
}
|
||||
});
|
||||
let fields = res.data.properties;
|
||||
console.log(fields);
|
||||
Object.keys(fields).forEach((key) => {
|
||||
const fld = fields[key];
|
||||
// rows.push({name:fields[key].label,code:fields[key].code,type:fields[key].type});
|
||||
rows.push({ name: fld.label, ...fld });
|
||||
if(props.fieldTypes.length===0 || props.fieldTypes.includes(fld.type)){
|
||||
rows.push({ name: fld.label || fld.code, ...fld });
|
||||
}
|
||||
});
|
||||
isLoaded.value = true;
|
||||
});
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
<q-tree :nodes="store.eventTree.screens" node-key="eventId" children-key="events" no-connectors
|
||||
v-model:expanded="store.expandedScreen" :dense="true" :ref="tree">
|
||||
<template v-slot:header-EVENT="prop">
|
||||
<div :ref="prop.node.eventId" class="row col items-center no-wrap event-node">
|
||||
<div :ref="prop.node.eventId" class="row col items-center no-wrap event-node" @click="onSelected(prop.node)">
|
||||
<q-icon v-if="prop.node.eventId" name="play_circle" :color="prop.node.hasFlow ? 'green' : 'grey'" size="16px"
|
||||
class="q-mr-sm">
|
||||
</q-icon>
|
||||
<div class="no-wrap" @click="onSelected(prop.node)"
|
||||
<div class="no-wrap"
|
||||
:class="selectedEvent && prop.node.eventId === selectedEvent.eventId ? 'selected-node' : ''">{{
|
||||
prop.node.label }}</div>
|
||||
<q-space></q-space>
|
||||
@@ -15,25 +15,21 @@
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:header-CHANGE="prop">
|
||||
<div class="row col items-center no-wrap event-node">
|
||||
<div class="no-wrap">{{ prop.node.label }}</div>
|
||||
<div class="row col items-start no-wrap event-node">
|
||||
<div class="no-wrap"
|
||||
:class="selectedEvent && prop.node.eventId === selectedEvent.eventId ? 'selected-node' : ''"
|
||||
>{{ prop.node.label }}</div>
|
||||
<q-space></q-space>
|
||||
<q-icon name="add_circle" color="primary" size="16px" class="q-mr-sm"
|
||||
@click="addChangeEvent(prop.node)"></q-icon>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:header-DELETABLE="prop">
|
||||
<div class="row col items-center event-node">
|
||||
<div class="row col items-center" @click="onSelected(prop.node)">
|
||||
<q-icon v-if="prop.node.eventId" name="play_circle" :color="prop.node.hasFlow ? 'green' : 'grey'" size="16px"
|
||||
class="q-mr-sm">
|
||||
</q-icon>
|
||||
<div>{{ prop.node.label }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<q-btn class="q-mr-sm delete-btn" flat fab-mini icon="delete_forever" padding="none" color="negative"
|
||||
@click="deleteEvent(prop.node)"></q-btn>
|
||||
</div>
|
||||
<div class="row col items-start event-node" @click="onSelected(prop.node)">
|
||||
<q-icon v-if="prop.node.eventId" name="play_circle" :color="prop.node.hasFlow ? 'green' : 'grey'" size="16px" class="q-mr-sm" />
|
||||
<div class="no-wrap" :class="selectedEvent && prop.node.eventId === selectedEvent.eventId ? 'selected-node' : ''" >{{ prop.node.label }}</div>
|
||||
<q-space></q-space>
|
||||
<q-icon name="delete_forever" color="negative" size="16px" @click="deleteEvent(prop.node)"></q-icon>
|
||||
</div>
|
||||
</template>
|
||||
</q-tree>
|
||||
|
||||
@@ -61,12 +61,12 @@ export default defineComponent({
|
||||
if(store.eventTree.findEventById(addEventId)){
|
||||
return;
|
||||
}
|
||||
customEvents.events.push(
|
||||
new kintoneEvent(
|
||||
displayName,
|
||||
addEventId,
|
||||
customButtonId)
|
||||
);
|
||||
customEvents.events.push({
|
||||
eventId: addEventId,
|
||||
label: displayName,
|
||||
parentId: customButtonId,
|
||||
header: 'DELETABLE'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
{{ selectedField.name }}
|
||||
</q-chip>
|
||||
</template>
|
||||
<!-- <template v-slot:hint v-if="isSelected">
|
||||
<div> 項目コード:<q-chip size="sm" outline color="secondary" text-color="white">{{selectedField.code}}</q-chip></div>
|
||||
</template> -->
|
||||
<template v-slot:hint v-if="!isSelected">
|
||||
{{ placeholder }}
|
||||
</template>
|
||||
@@ -19,7 +16,7 @@
|
||||
</template>
|
||||
</q-field>
|
||||
<show-dialog v-model:visible="show" name="フィールド一覧" @close="closeDg" widht="400px">
|
||||
<field-select ref="appDg" name="フィールド" type="single" :appId="store.appInfo?.appId"></field-select>
|
||||
<field-select ref="appDg" name="フィールド" :type="selectType" :appId="store.appInfo?.appId" :fieldTypes="fieldTypes"></field-select>
|
||||
</show-dialog>
|
||||
</div>
|
||||
</template>
|
||||
@@ -54,6 +51,14 @@ export default defineComponent({
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
selectType:{
|
||||
type:String,
|
||||
default:'single'
|
||||
},
|
||||
fieldTypes:{
|
||||
type:Array,
|
||||
default:()=>[]
|
||||
},
|
||||
hint: {
|
||||
type: String,
|
||||
default: '',
|
||||
|
||||
@@ -33,6 +33,10 @@ export default defineComponent({
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
fieldTypes:{
|
||||
type:Array,
|
||||
default:()=>[]
|
||||
},
|
||||
hint: {
|
||||
type: String,
|
||||
default: '',
|
||||
|
||||
@@ -29,7 +29,7 @@ export default defineComponent({
|
||||
default:'',
|
||||
},
|
||||
modelValue: {
|
||||
type: Object,
|
||||
type: [Array,String],
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -113,19 +113,19 @@ export const useFlowEditorStore = defineStore('flowEditor', {
|
||||
},
|
||||
|
||||
|
||||
deleteEvent(event: IKintoneEvent) {
|
||||
async deleteEvent(event: IKintoneEvent) {
|
||||
const store = useFlowEditorStore();
|
||||
if (event.flowData) {
|
||||
const flow = event.flowData;
|
||||
if (flow.id === '') {
|
||||
return;
|
||||
if (flow.id !== '') {
|
||||
await flowCtrl.DeleteFlow(flow.id)
|
||||
if (this.flows) {
|
||||
this.flows = this.flows.filter((f) => f.id !== flow.id);
|
||||
}
|
||||
}
|
||||
flowCtrl.DeleteFlow(flow.id)
|
||||
eventTree.deleteEvent(event, store);
|
||||
if(this.flows){
|
||||
this.flows = this.flows.filter((f) => f.id !== flow.id);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
eventTree.deleteEvent(event, store);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -95,10 +95,7 @@ export class KintoneEventManager {
|
||||
const lastIndex = eventId.lastIndexOf('.');
|
||||
const groupId = eventId.substring(0, lastIndex);
|
||||
const eventNode = this.findEventById(groupId);
|
||||
if (
|
||||
eventNode &&
|
||||
(eventNode.header === 'EVENTGROUP' || eventNode.header === 'CHANGE')
|
||||
) {
|
||||
if (eventNode && (eventNode.header === 'EVENTGROUP' || eventNode.header === 'CHANGE')) {
|
||||
const groupEvent = eventNode as kintoneEventGroup;
|
||||
|
||||
const newEvent = {
|
||||
|
||||
6
node_modules/.package-lock.json
generated
vendored
Normal file
6
node_modules/.package-lock.json
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "App Builder for kintone",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
10
node_modules/.yarn-integrity
generated
vendored
Normal file
10
node_modules/.yarn-integrity
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"systemParams": "win32-x64-115",
|
||||
"modulesFolders": [],
|
||||
"flags": [],
|
||||
"linkedModules": [],
|
||||
"topLevelPatterns": [],
|
||||
"lockfileEntries": {},
|
||||
"files": [],
|
||||
"artifacts": {}
|
||||
}
|
||||
16
plugin/kintone-addins/package-lock.json
generated
16
plugin/kintone-addins/package-lock.json
generated
@@ -8,7 +8,8 @@
|
||||
"name": "kintone-addins",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"jquery": "^3.7.1"
|
||||
"jquery": "^3.7.1",
|
||||
"yarn": "^1.22.22"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jquery": "^3.5.24",
|
||||
@@ -795,6 +796,19 @@
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/yarn": {
|
||||
"version": "1.22.22",
|
||||
"resolved": "https://registry.npmjs.org/yarn/-/yarn-1.22.22.tgz",
|
||||
"integrity": "sha512-prL3kGtyG7o9Z9Sv8IPfBNrWTDmXB4Qbes8A9rEzt6wkJV8mUvoirjU0Mp3GGAU06Y0XQyA3/2/RQFVuK7MTfg==",
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"yarn": "bin/yarn.js",
|
||||
"yarnpkg": "bin/yarn.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"jquery": "^3.7.1",
|
||||
"vite-plugin-css-injected-by-js": "^3.5.1"
|
||||
"vite-plugin-css-injected-by-js": "^3.5.1",
|
||||
"yarn": "^1.22.22"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
.alc-button-normal {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
padding: 0 16px;
|
||||
margin-left: 16px;
|
||||
margin-top: 8px;
|
||||
min-width: 100px;
|
||||
outline: none;
|
||||
border: 1px solid #e3e7e8;
|
||||
background-color: #f7f9fa;
|
||||
box-shadow: 1px 1px 1px #fff inset;
|
||||
color: #3498db;
|
||||
text-align: center;
|
||||
line-height: 32px;
|
||||
}
|
||||
.alc-button-normal:hover {
|
||||
background-color: #c8d6dd;
|
||||
box-shadow: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.alc-button-normal:active {
|
||||
color: #f7f9fa;
|
||||
background-color: #54b8eb;
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
|
||||
import { actionAddins } from ".";
|
||||
import { IField, IAction,IActionResult, IActionNode, IActionProperty, IContext } from "../types/ActionTypes";
|
||||
import { IField, IAction,IActionResult, IActionNode, IActionProperty, IContext, IVarName } from "../types/ActionTypes";
|
||||
import { Formatter } from "../util/format";
|
||||
import "./auto-numbering.css";
|
||||
|
||||
declare global {
|
||||
interface Window { $format: any; }
|
||||
@@ -14,7 +13,7 @@ interface IAutoNumberingProps{
|
||||
format:string;
|
||||
prefix:string;
|
||||
suffix:string;
|
||||
verName:string;
|
||||
verName:IVarName;
|
||||
}
|
||||
|
||||
export class AutoNumbering implements IAction{
|
||||
@@ -30,7 +29,7 @@ export class AutoNumbering implements IAction{
|
||||
format:'',
|
||||
prefix:'',
|
||||
suffix:'',
|
||||
verName:''
|
||||
verName:{name:''}
|
||||
}
|
||||
globalThis.window.$format=this.format;
|
||||
this.register();
|
||||
@@ -57,8 +56,8 @@ export class AutoNumbering implements IAction{
|
||||
const docNum = await this.createNumber(this.props);
|
||||
record[this.props.field.code].value=docNum;
|
||||
//変数設定
|
||||
if(this.props.verName){
|
||||
context.variables[this.props.verName]=docNum;
|
||||
if(this.props.verName && this.props.verName.name!==''){
|
||||
context.variables[this.props.verName.name]=docNum;
|
||||
}
|
||||
result= {
|
||||
canNext:true,
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
.alc-button-normal {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
padding: 0 16px;
|
||||
margin-left: 16px;
|
||||
margin-top: 8px;
|
||||
min-width: 100px;
|
||||
outline: none;
|
||||
border: 1px solid #e3e7e8;
|
||||
background-color: #f7f9fa;
|
||||
box-shadow: 1px 1px 1px #fff inset;
|
||||
color: #3498db;
|
||||
text-align: center;
|
||||
line-height: 32px;
|
||||
}
|
||||
.alc-button-normal:hover {
|
||||
background-color: #c8d6dd;
|
||||
box-shadow: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.alc-button-normal:active {
|
||||
color: #f7f9fa;
|
||||
background-color: #54b8eb;
|
||||
}
|
||||
@@ -10,12 +10,18 @@ import "./button-add.css";
|
||||
interface IButtonAddProps {
|
||||
//ボタン表示名
|
||||
buttonName: string;
|
||||
space?:ISpace;
|
||||
//配置位置
|
||||
position: string;
|
||||
//イベント名
|
||||
eventName:string
|
||||
}
|
||||
|
||||
interface ISpace{
|
||||
type:string,
|
||||
elementId:string
|
||||
}
|
||||
|
||||
export class ButtonAddAction implements IAction {
|
||||
name: string;
|
||||
actionProps: IActionProperty[];
|
||||
@@ -49,20 +55,19 @@ export class ButtonAddAction implements IAction {
|
||||
}
|
||||
this.props = actionNode.ActionValue as IButtonAddProps;
|
||||
//ボタンを配置する
|
||||
const menuSpace = kintone.app.record.getHeaderMenuSpaceElement();
|
||||
if(!menuSpace) return result;
|
||||
if($("style#alc-button-add").length===0){
|
||||
const css=`
|
||||
`;
|
||||
const style = $("<style id='alc-button-add'>/<style>");
|
||||
style.text(css);
|
||||
$("head").append(style);
|
||||
let buttonSpace;
|
||||
if(this.props.space && this.props.space.elementId){
|
||||
buttonSpace = kintone.app.record.getSpaceElement(this.props.space.elementId);
|
||||
}else{
|
||||
buttonSpace = kintone.app.record.getHeaderMenuSpaceElement();
|
||||
}
|
||||
if(!buttonSpace) return result;
|
||||
|
||||
const button =$(`<button id='${this.props.eventName}' class='alc-button-normal' >${this.props.buttonName}</button>`);
|
||||
if(this.props.position==="一番左に追加する"){
|
||||
$(menuSpace).prepend(button);
|
||||
$(buttonSpace).prepend(button);
|
||||
}else{
|
||||
$(menuSpace).append(button);
|
||||
$(buttonSpace).append(button);
|
||||
}
|
||||
const clickEventName = `${event.type}.customButtonClick.${this.props.eventName}`;
|
||||
button.on("click",()=>{
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
|
||||
import { actionAddins } from ".";
|
||||
import { IAction,IActionResult, IActionNode, IActionProperty, IContext } from "../types/ActionTypes";
|
||||
import { IAction,IActionResult, IActionNode, IActionProperty, IContext, IVarName } from "../types/ActionTypes";
|
||||
import { ConditionTree } from '../types/Conditions';
|
||||
/**
|
||||
* アクションの属性定義
|
||||
*/
|
||||
interface ICondition{
|
||||
condition:string;
|
||||
verName:string;
|
||||
verName:IVarName;
|
||||
}
|
||||
/**
|
||||
* 条件分岐アクション
|
||||
@@ -21,7 +21,7 @@ export class ConditionAction implements IAction{
|
||||
this.actionProps=[];
|
||||
this.props={
|
||||
condition:'',
|
||||
verName:''
|
||||
verName:{name:''}
|
||||
}
|
||||
//アクションを登録する
|
||||
this.register();
|
||||
@@ -58,8 +58,8 @@ export class ConditionAction implements IAction{
|
||||
result:'いいえ'
|
||||
}
|
||||
}
|
||||
if(this.props.verName){
|
||||
context.variables[this.props.verName]=result.result;
|
||||
if(this.props.verName && this.props.verName.name!==''){
|
||||
context.variables[this.props.verName.name]=result.result;
|
||||
}
|
||||
return result;
|
||||
}catch(error){
|
||||
|
||||
75
plugin/kintone-addins/src/actions/counter-check.ts
Normal file
75
plugin/kintone-addins/src/actions/counter-check.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { actionAddins } from ".";
|
||||
import { IAction,IActionResult, IActionNode, IActionProperty, IField} from "../types/ActionTypes";
|
||||
/**
|
||||
* アクションの属性定義
|
||||
*/
|
||||
interface IStrCountCheckProps{
|
||||
field:IField;//チェックするフィールドの対象
|
||||
message:string;//エラーメッセージ
|
||||
maxLength:number;//
|
||||
}
|
||||
/**
|
||||
* 正規表現チェックアクション
|
||||
*/
|
||||
export class StrCountCheckAciton implements IAction{
|
||||
name: string;
|
||||
actionProps: IActionProperty[];
|
||||
props:IStrCountCheckProps;
|
||||
constructor(){
|
||||
this.name="文字数チェック";
|
||||
this.actionProps=[];
|
||||
this.props={
|
||||
field:{code:''},
|
||||
message:'',
|
||||
maxLength:0
|
||||
}
|
||||
//アクションを登録する
|
||||
this.register();
|
||||
}
|
||||
/**
|
||||
* アクションの実行を呼び出す
|
||||
* @param actionNode
|
||||
* @param event
|
||||
* @returns
|
||||
*/
|
||||
async process(actionNode:IActionNode,event:any):Promise<IActionResult> {
|
||||
let result={
|
||||
canNext:true,
|
||||
result:false
|
||||
};
|
||||
try{
|
||||
//属性設定を取得する
|
||||
this.actionProps=actionNode.actionProps;
|
||||
if (!('field' in actionNode.ActionValue) && !('message' in actionNode.ActionValue) && !('strExpression'in actionNode.ActionValue)) {
|
||||
return result
|
||||
}
|
||||
|
||||
this.props = actionNode.ActionValue as IStrCountCheckProps;
|
||||
//条件式の計算結果を取得
|
||||
const record = event.record;
|
||||
const value = record[this.props.field.code].value;
|
||||
const maxLength = this.props.maxLength;
|
||||
if(value === undefined || value === '' ){
|
||||
return result;
|
||||
}else if(maxLength < value.length){
|
||||
record[this.props.field.code].error = this.props.message;
|
||||
}else{
|
||||
result= {
|
||||
canNext:true,
|
||||
result:true
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}catch(error){
|
||||
event.error=error;
|
||||
console.error(error);
|
||||
result.canNext=false;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
register(): void {
|
||||
actionAddins[this.name]=this;
|
||||
}
|
||||
|
||||
}
|
||||
new StrCountCheckAciton();
|
||||
66
plugin/kintone-addins/src/actions/datetime-getter.ts
Normal file
66
plugin/kintone-addins/src/actions/datetime-getter.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { actionAddins } from ".";
|
||||
import { IAction, IActionResult, IActionNode, IActionProperty, IField ,IContext, IVarName} from "../types/ActionTypes";
|
||||
/**
|
||||
* アクションの属性定義
|
||||
*/
|
||||
interface IDatetimeGetterProps {
|
||||
/**変数の名前 */
|
||||
verName:IVarName;
|
||||
}
|
||||
/**
|
||||
* 現在日時を取得するアクション
|
||||
*/
|
||||
export class DatetimeGetterAction implements IAction {
|
||||
name: string;
|
||||
actionProps: IActionProperty[];
|
||||
props: IDatetimeGetterProps;
|
||||
constructor() {
|
||||
this.name = "現在日時";
|
||||
this.actionProps = [];
|
||||
this.props = {
|
||||
verName:{name:''}
|
||||
}
|
||||
this.register();
|
||||
}
|
||||
/**
|
||||
* アクションの実行を呼び出す
|
||||
* @param actionNode
|
||||
* @param event
|
||||
* @returns
|
||||
*/
|
||||
async process(actionNode: IActionNode, event: any,context:IContext): Promise<IActionResult> {
|
||||
let result = {
|
||||
canNext: true,
|
||||
result: false
|
||||
};
|
||||
|
||||
try {
|
||||
//属性設定を取得する
|
||||
this.actionProps = actionNode.actionProps;
|
||||
|
||||
if (!('verName' in actionNode.ActionValue) ) {
|
||||
return result
|
||||
}
|
||||
this.props = actionNode.ActionValue as IDatetimeGetterProps;
|
||||
|
||||
let today = new Date();
|
||||
|
||||
if(this.props.verName && this.props.verName.name!==''){
|
||||
context.variables[this.props.verName.name]=today.toISOString();
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} catch (error) {
|
||||
event.error = error;
|
||||
console.error(error);
|
||||
result.canNext = false;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
register(): void {
|
||||
actionAddins[this.name] = this;
|
||||
}
|
||||
|
||||
}
|
||||
new DatetimeGetterAction();
|
||||
@@ -56,8 +56,8 @@ export class FieldShownAction implements IAction{
|
||||
}
|
||||
}
|
||||
result= {
|
||||
canNext:true,
|
||||
result:true
|
||||
canNext:true,
|
||||
result:true
|
||||
}
|
||||
return result;
|
||||
}catch(error){
|
||||
@@ -69,9 +69,9 @@ export class FieldShownAction implements IAction{
|
||||
|
||||
}
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param context 条件式を実行する
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
getConditionResult(context:any):boolean{
|
||||
const tree =this.getCondition(this.props.condition);
|
||||
@@ -84,7 +84,7 @@ export class FieldShownAction implements IAction{
|
||||
|
||||
/**
|
||||
* @param condition 条件式ツリーを取得する
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
getCondition(condition:string):ConditionTree|null{
|
||||
try{
|
||||
@@ -93,7 +93,7 @@ export class FieldShownAction implements IAction{
|
||||
if(tree.getConditions(tree.root).length>0){
|
||||
return tree;
|
||||
}else{
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
}catch(error){
|
||||
return null;
|
||||
@@ -103,6 +103,5 @@ export class FieldShownAction implements IAction{
|
||||
register(): void {
|
||||
actionAddins[this.name]=this;
|
||||
}
|
||||
|
||||
}
|
||||
new FieldShownAction();
|
||||
507
plugin/kintone-addins/src/actions/insert-value.ts
Normal file
507
plugin/kintone-addins/src/actions/insert-value.ts
Normal file
@@ -0,0 +1,507 @@
|
||||
|
||||
|
||||
import { actionAddins } from ".";
|
||||
import { IAction,IActionResult, IActionNode, IActionProperty, IField, IContext } from "../types/ActionTypes";
|
||||
import { ConditionTree } from '../types/Conditions';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* アクションの属性定義
|
||||
*/
|
||||
interface IInsertValueProps{
|
||||
field:IField;
|
||||
condition:string;
|
||||
value:string;
|
||||
show:string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export class InsertValueAction implements IAction{
|
||||
name: string;
|
||||
actionProps: IActionProperty[];
|
||||
props:IInsertValueProps;
|
||||
constructor(){
|
||||
this.name="値を挿入する";// DBに登録したアクション名
|
||||
this.actionProps=[];
|
||||
//プロパティ属性の初期化
|
||||
this.props={
|
||||
field:{code:''},
|
||||
condition:'',
|
||||
value:'',
|
||||
show:''
|
||||
}
|
||||
//アクションを登録する
|
||||
this.register();
|
||||
}
|
||||
|
||||
/**
|
||||
* 空白文字を空白文字が非対応のフィールドに挿入しようとしていないか、必須項目フィールドに挿入しようとしていないかチェックする
|
||||
* @param {string} inputValue - 挿入する値
|
||||
* @return {boolean} -入力値が有効な日付形式の場合はtrueを返し、そうでない場合は例外を発生させる
|
||||
*/
|
||||
checkInputBlank(fieldType :string | undefined,inputValue :string,fieldCode :string,fieldRequired :boolean | undefined,event :any): boolean{
|
||||
//正規表現チェック
|
||||
let blankCheck= inputValue.match(/^(\s| )+?$/);//半角スペース・タブ文字・改行・改ページ・全角スペース
|
||||
|
||||
if(blankCheck !== null){
|
||||
//空白文字を空白文字が非対応のフィールドに挿入しようとしている場合、例外を発生させる
|
||||
if(fieldType === "NUMBER" || fieldType === "DATE" || fieldType === "DATETIME" || fieldType === "TIME" || fieldType === "USER_SELECT"
|
||||
|| fieldType === "ORGANIZATION_SELECT" || fieldType === "GROUP_SELECT" || fieldType === "RADIO_BUTTON" || fieldType === "DROP_DOWN" || fieldType === "CHECK_BOX" || fieldType === "MULTI_SELECT"){
|
||||
event.record[fieldCode]['error'] = "「"+fieldCode+"」"+"フィールドには、空白文字は挿入できません。"; //レコードにエラーを表示
|
||||
throw new Error("「"+fieldCode+"」"+"フィールドには、空白文字は挿入できません。「値を挿入する」コンポーネントの処理を中断しました。");
|
||||
|
||||
//空白文字を必須項目フィールドに挿入しようとしている場合、例外を発生させる
|
||||
}else if(fieldRequired){
|
||||
event.record[fieldCode]['error'] = "「"+fieldCode+"」"+"フィールドは必須項目のため、空白文字は挿入できません。"; //レコードにエラーを表示
|
||||
throw new Error("「"+fieldCode+"」"+"フィールドは必須項目のため、空白文字は挿入できません。「値を挿入する」コンポーネントの処理を中断しました。");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 入力値が半角数字かチェックする関数
|
||||
* @param {string} inputValue - 挿入する値
|
||||
* @return {boolean} -入力値が有効な数値の場合はtrueを返し、そうでない場合は例外を発生させる
|
||||
*/
|
||||
checkInputNumber(inputValue :string,fieldCode :string,event :any): boolean{
|
||||
let inputNumberValue = Number(inputValue);//数値型に変換
|
||||
|
||||
//有限数かどうか判定s
|
||||
if(!isFinite(inputNumberValue)){
|
||||
event.record[fieldCode]['error'] = "「"+fieldCode+"」"+"フィールドに入れようとした値は、無効な日付形式です。"; //レコードにエラーを表示
|
||||
throw new Error("「"+fieldCode+"」"+"フィールドに入れようとした値は、有効な数値ではありません。「値を挿入する」コンポーネントの処理を中断しました。");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 入力値が有効な日付形式かチェックする関数
|
||||
* @param {string} inputValue - 挿入する値
|
||||
* @return {boolean} -入力値が有効な日付形式の場合はtrueを返し、そうでない場合は例外を発生させる
|
||||
*/
|
||||
checkInputDate(inputValue :string,fieldCode :string,event :any): boolean{
|
||||
//正規表現チェック
|
||||
let twoDigitMonthDay = inputValue.match(/(\d{4})-(\d{2})-(\d{2})$/);//4桁の数字-2桁の数字-2桁の数字
|
||||
let singleDigitMonthDay = inputValue.match(/(\d{4})-(\d{1})-(\d{1})$/);//4桁の数字-1桁の数字-2桁の数字
|
||||
let singleDigitMonth = inputValue.match(/(\d{4})-(\d{1})-(\d{2})$/);//4桁の数字-1桁の数字-2桁の数字
|
||||
let singleDigitDay = inputValue.match(/(\d{4})-(\d{2})-(\d{1})$/);//4桁の数字-2桁の数字-1桁の数字
|
||||
let dateTime = inputValue.match(/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).000Z/);//時刻入りのUTCの日付形式
|
||||
let date;
|
||||
//date型に変換
|
||||
date = new Date(inputValue);
|
||||
|
||||
//date型変換できたか確認
|
||||
if(date !== undefined && !isNaN(date.getDate())){
|
||||
//正規表現チェック確認
|
||||
if(twoDigitMonthDay === null && singleDigitMonth === null && singleDigitDay === null && singleDigitMonthDay === null && dateTime === null){
|
||||
event.record[fieldCode]['error'] = "「"+fieldCode+"」"+"フィールドに入れようとした値は、無効な日付形式です。"; //レコードにエラーを表示
|
||||
throw new Error("「"+fieldCode+"」"+"フィールドに入れようとした値は、無効な日付形式です。「値を挿入する」コンポーネントの処理を中断しました。");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 入力値が有効な時刻形式かチェックする関数
|
||||
* @param {string} inputValue - 挿入する値
|
||||
* @return {boolean} -入力値が有効な日付形式の場合はtrueを返し、そうでない場合は例外を発生させる
|
||||
*/
|
||||
checkInputTime(inputValue :string,fieldCode :string,event :any): boolean{
|
||||
//正規表現チェック
|
||||
let timeFormat =inputValue.match(/^([0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/);
|
||||
|
||||
//正規表現チェック確認
|
||||
if(timeFormat === null){
|
||||
event.record[fieldCode]['error'] = "「"+fieldCode+"」"+"フィールドに入れようとした値は、無効な時刻形式です。"; //レコードにエラーを表示
|
||||
throw new Error("「"+fieldCode+"」"+"フィールドに入れようとした値は、無効な時刻形式です。「値を挿入する」コンポーネントの処理を中断しました。");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 入力値のフィールドタイプがDATETIMEであれば、時刻ありの日付形式変換し、DATEであれば時刻なしの日付形式変換する関数
|
||||
* @param {string} inputValue -挿入する値
|
||||
* @param {string} fieldType -フィールドタイプ
|
||||
* @return {string} -入力値が日付形式に変換できた場合は文字列を返し、そうでない場合は例外を発生させる
|
||||
*/
|
||||
changeDateFormat(inputValue :string, fieldType :string,fieldCode :string,event :any): string{
|
||||
let dateTime;
|
||||
let date;
|
||||
|
||||
//挿入する値をdate型に変換
|
||||
date = new Date(inputValue);
|
||||
//date型変換できたか確認
|
||||
if(date !== undefined && !isNaN(date.getDate())){
|
||||
|
||||
//日時フィールドの場合、時刻ありの日付形式変換
|
||||
if(fieldType === "DATETIME"){
|
||||
dateTime =date.toISOString();
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
//日付フィールドの場合、時刻なしの日付形式変換
|
||||
let dateArray=inputValue.match(/(\d{4})-(\d{1,2})-(\d{1,2})$/);//4桁の数字-1~2桁の数字-1~2桁の数字
|
||||
if(dateArray !== null){
|
||||
let yearIndex = 1;
|
||||
let monthIndex = 2;
|
||||
let dayIndex = 3;
|
||||
let dateFormatted=`${dateArray[yearIndex]}-${dateArray[monthIndex]}-${dateArray[dayIndex]}`
|
||||
return dateFormatted;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
event.record[fieldCode]['error'] = "「"+fieldCode+"」"+"フィールドに入れようとした値は、無効な日付形式です。"; //レコードにエラーを表示
|
||||
throw new Error("「"+fieldCode+"」"+"フィールドに入れようとした値は、無効な日付形式です。「値を挿入する」コンポーネントの処理を中断しました。");
|
||||
}
|
||||
|
||||
/**
|
||||
* 入力値がフィールドタイプ(ラジオボタン・ドロップダウン・複数選択・ドロップダウン)の選択肢に存在する値かチェックする関数
|
||||
* @param {string} inputValue - 挿入する値
|
||||
* @return {boolean} -入力値が有効な値の場合はtrueを返し、そうでない場合は例外を発生させる
|
||||
*/
|
||||
checkInputOption(inputValue :string,fieldOptions :string | undefined,fieldCode :string,event :any): boolean {
|
||||
|
||||
//入力値が選択肢に存在する値かチェックし、存在したらtrueを返す
|
||||
if(fieldOptions !== undefined){
|
||||
let options = Object.keys(fieldOptions);
|
||||
for(var optionsIndex in options){
|
||||
if(options[optionsIndex] === inputValue){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event.record[fieldCode]['error']="「"+fieldCode+"」"+"には、存在しない値を挿入しようとしたため、処理を中断しました。";
|
||||
throw new Error("「"+fieldCode+"」"+"には、存在しない値を挿入しようとしたため、処理を中断しました。「値を挿入する」コンポーネントの処理を中断しました。");
|
||||
}
|
||||
|
||||
/**
|
||||
* 入力値がフィールドタイプ(ユーザー選択)で、ユーザー情報に存在する値かチェックする関数
|
||||
* @param {string} inputValue - 挿入する値
|
||||
* @return {string | boolean} 入力値が登録されているユーザー情報から見つかった場合、trueを返し、見つからなかった場合、falseを返す
|
||||
*/
|
||||
async setInputUser(inputValue :string): Promise<string | boolean>{
|
||||
|
||||
//ユーザー名を格納する変数
|
||||
let usersName;
|
||||
const usersInfoColumnIndex=0;
|
||||
|
||||
try{
|
||||
//APIでユーザー情報を取得する
|
||||
const resp =await kintone.api(kintone.api.url('/v1/users', true), 'GET', {codes:[inputValue ]})
|
||||
|
||||
//入力されたログイン名(メールアドレス)がユーザー情報に登録されている場合、そのユーザー名を取得する
|
||||
if (resp.users[usersInfoColumnIndex].code === inputValue) {
|
||||
usersName=resp.users[usersInfoColumnIndex].name;
|
||||
}
|
||||
|
||||
//ユーザー名が取得できた場合、ログイン名とユーザー名をフィールドにセットする
|
||||
if(usersName === undefined){
|
||||
throw new Error();
|
||||
}
|
||||
}catch{
|
||||
return false;
|
||||
}
|
||||
|
||||
return usersName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 入力値がフィールドタイプ(組織選択)で、組織情報に存在する値かチェックする関数
|
||||
* @param {string} inputValue - 挿入する値
|
||||
* @return {string | boolean} 入力値が登録されている組織情報から見つかった場合、trueを返し、見つからなかった場合、falseを返す
|
||||
*/
|
||||
async setInputOrganization(inputValue :string): Promise<string | boolean>{
|
||||
|
||||
//組織名を格納する変数
|
||||
let organizationName;
|
||||
const organizationsInfoColumnIndex=0;
|
||||
|
||||
try{
|
||||
//APIで組織情報を取得する
|
||||
const resp =await kintone.api(kintone.api.url('/v1/organizations.json', true), 'GET', {codes:[inputValue ]})
|
||||
|
||||
//入力された組織コードが組織情報に登録されている場合、その組織名を取得する
|
||||
if (resp.organizations[organizationsInfoColumnIndex].code === inputValue) {
|
||||
organizationName=resp.organizations[organizationsInfoColumnIndex].name;
|
||||
}
|
||||
|
||||
//組織名が取得できた場合、組織コードと組織名をフィールドにセットする
|
||||
if(organizationName === undefined){
|
||||
throw new Error();
|
||||
}
|
||||
}catch{
|
||||
return false;
|
||||
}
|
||||
|
||||
return organizationName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 入力値がフィールドタイプ(グループ選択)で、グループ情報に存在する値かチェックする関数
|
||||
* @param {string} inputValue - 挿入する値
|
||||
* @return {string | boolean} 入力値が登録されているグループ情報から見つかった場合、trueを返し、見つからなかった場合、falseを返す
|
||||
*/
|
||||
async setInputGroup(inputValue :string): Promise<string | boolean>{
|
||||
|
||||
//グループ名を格納する変数
|
||||
let groupsName;
|
||||
const groupsInfoColumnIndex=0;
|
||||
|
||||
try{
|
||||
//APIでグループ情報を取得する
|
||||
const resp =await kintone.api(kintone.api.url('/v1/groups.json', true), 'GET', {codes:[inputValue ]})
|
||||
|
||||
//入力されたグループコードがグループ情報に登録されている場合、そのグループ名を取得する
|
||||
if (resp.groups[groupsInfoColumnIndex].code === inputValue) {
|
||||
groupsName=resp.groups[groupsInfoColumnIndex].name;
|
||||
}
|
||||
|
||||
//グループ名が取得できた場合、グループコードとグループ名をフィールドにセットする
|
||||
if(groupsName === undefined){
|
||||
throw new Error();
|
||||
}
|
||||
}catch{
|
||||
return false;
|
||||
}
|
||||
|
||||
return groupsName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* アクションの実行を呼び出す
|
||||
* @param actionNode
|
||||
* @param event
|
||||
* @returns
|
||||
*/
|
||||
async process(actionNode:IActionNode,event:any,context:IContext):Promise<IActionResult> {
|
||||
|
||||
let result={
|
||||
canNext:true,
|
||||
result:false
|
||||
};
|
||||
try{
|
||||
//属性設定を取得する
|
||||
this.actionProps = actionNode.actionProps;
|
||||
if (!('field' in actionNode.ActionValue) && !('value' in actionNode.ActionValue)) {
|
||||
return result
|
||||
}
|
||||
|
||||
const fieldColumnIndex=1;
|
||||
const valueColumnIndex=3;
|
||||
|
||||
//プロパティで選択されたフィールド
|
||||
const field=this.actionProps[fieldColumnIndex].props.modelValue.type;
|
||||
//プロパティの挿入する値
|
||||
const value=this.actionProps[valueColumnIndex].props.modelValue;
|
||||
|
||||
//条件式の結果を取得
|
||||
const conditionResult = this.getConditionResult(context);
|
||||
if(!conditionResult){
|
||||
return result;
|
||||
}
|
||||
|
||||
//プロパティの値を挿入するフィールドが未選択の場合、例外を発生させる
|
||||
if(field === null){
|
||||
throw new Error("「値を挿入する」コンポーネントで、値を挿入するフィールドが指定されていなかったため、処理が中断されました。");
|
||||
}
|
||||
|
||||
//プロパティの値を挿入するフィールドが非対応フィールドの場合、例外を発生させる
|
||||
//添付ファイル・テーブル・カテゴリー・ステータス・作成者・更新者・作業者・リビジョン番号・レコード番号・レコードID・計算・作成日時・更新日時フィールドが選択されている場合、例外を発生させる
|
||||
if(field === "FILE" || field === "SUBTABLE" || field === "CATEGORY" || field === "STATUS"
|
||||
|| field === "STATUS_ASSIGNEE" || field === "CREATOR" || field === "MODIFIER" || field === "__REVISION__"
|
||||
|| field === "RECORD_NUMBER"|| field === "__ID__" || field ==="CALC" || field === "CREATED_TIME" || field === "UPDATED_TIME" ){
|
||||
throw new Error("「値を挿入する」コンポーネントで、選択されたフィールドは、値を挿入するコンポーネントでは非対応のフィールドのため、処理を中断しました。");
|
||||
}
|
||||
|
||||
//プロパティの挿入する値が未入力の場合、例外を発生させる
|
||||
if(value === ""){
|
||||
throw new Error("「値を挿入する」コンポーネントで、フィールドに挿入する値が指定されていなかったため、処理が中断されました。");
|
||||
}
|
||||
|
||||
//既定のプロパティのインターフェースへ変換する
|
||||
this.props = actionNode.ActionValue as IInsertValueProps;
|
||||
|
||||
//挿入する値を取得
|
||||
let fieldValue = this.props.value;
|
||||
//フィールドの種類を取得
|
||||
const fieldType = this.props.field.type;
|
||||
//フィールドが必須項目なのか取得
|
||||
const fieldRequired=this.props.field.required;
|
||||
//挿入するフィールドのコードを取得
|
||||
const fieldCode=this.props.field.code;
|
||||
//挿入する値の形式(手入力か変数)を取得
|
||||
const insertValueType=this.props.show;
|
||||
//ラジオボタン・チェックボックス・複数選択・ドロップダウンの選択肢を取得
|
||||
let fieldOptions =this.props.field.options;
|
||||
//変数の値を格納する
|
||||
let variableValue;
|
||||
|
||||
//変数の場合、値が取得できるかチェック
|
||||
if(insertValueType === "変数" && conditionResult){
|
||||
variableValue = context.variables[fieldValue];
|
||||
|
||||
if(variableValue === undefined){
|
||||
throw new Error("「"+fieldCode+"」"+"フィールドに入れようとした変数は、無効な入力形式です。");
|
||||
}
|
||||
fieldValue = variableValue;
|
||||
}
|
||||
|
||||
//入力値チェック後、形式変換、型変換した値を格納する変数
|
||||
let correctFormattedValue;
|
||||
//入力値チェック後、形式変換、型変換した値を格納する配列
|
||||
let correctValues :string[] = [];
|
||||
//入力エラー(空白文字の混入)がないことをチェック
|
||||
let notInputError=this.checkInputBlank(fieldType,fieldValue,fieldCode,fieldRequired,event);
|
||||
|
||||
//条件式の結果がtrue、入力エラー(空白文字の混入)がない場合、挿入する値をフィールドタイプ別にチェックする
|
||||
if(conditionResult && notInputError){
|
||||
|
||||
//文字列型のフィールドに挿入しようとしている値が適切の場合、correctFormattedValueに代入する
|
||||
if(fieldType === "SINGLE_LINE_TEXT" || fieldType === "MULTI_LINE_TEXT" || fieldType === "RICH_TEXT" || fieldType === "LINK" ){
|
||||
correctFormattedValue = fieldValue;
|
||||
|
||||
//数値型のフィールドに挿入しようとしている値が適切の場合、数値型に型変換してcorrectFormattedValueに代入する
|
||||
}else if(fieldType === "NUMBER" ){
|
||||
if(this.checkInputNumber(fieldValue,fieldCode,event)){//入力値チェック
|
||||
correctFormattedValue = Number(fieldValue);//型変換
|
||||
}
|
||||
|
||||
//日付・日時型のフィールドに挿入しようとしている値が適切の場合、指定の日付・日時に形式変換してcorrectFormattedValueに代入する
|
||||
}else if(fieldType === "DATE" || fieldType === "DATETIME" ){
|
||||
if(this.checkInputDate(fieldValue,fieldCode,event)){//入力値チェック
|
||||
let formattedDate = this.changeDateFormat(fieldValue,fieldType,fieldCode,event)
|
||||
if(formattedDate){
|
||||
correctFormattedValue = formattedDate
|
||||
}
|
||||
}
|
||||
|
||||
//時刻フィールドに挿入しようとしている値が適切の場合、correctFormattedValueに代入する
|
||||
}else if(fieldType === "TIME"){
|
||||
if(this.checkInputTime(fieldValue,fieldCode,event)){//入力値チェック
|
||||
correctFormattedValue = fieldValue;
|
||||
}
|
||||
|
||||
//ラジオボタン・ドロップダウンのフィールドの選択肢と入力値が一致した場合、correctFormattedValueに代入する
|
||||
}else if(fieldType === "RADIO_BUTTON" || fieldType === "DROP_DOWN"){
|
||||
if(this.checkInputOption(fieldValue,fieldOptions,fieldCode,event)){//入力値チェック
|
||||
correctFormattedValue = fieldValue;
|
||||
}
|
||||
|
||||
//チェックボックス・複数選択のフィールドの選択肢と入力値が一致した場合、correctValuesの配列に代入する
|
||||
}else if(fieldType === "CHECK_BOX" || fieldType === "MULTI_SELECT" ){
|
||||
if(this.checkInputOption(fieldValue,fieldOptions,fieldCode,event)){//入力値チェック
|
||||
correctValues[0] = fieldValue;
|
||||
}
|
||||
|
||||
//ユーザー情報フィードに挿入しようとした値が適切な場合、correctFormattedValueに代入する
|
||||
}else if(fieldType === "USER_SELECT"){
|
||||
//挿入する値がユーザー情報から見つかれば、ユーザー名を格納
|
||||
let users=await this.setInputUser(fieldValue);
|
||||
|
||||
//ユーザー名が格納できている場合、ログイン名とユーザー名をcorrectFormattedValueに代入する
|
||||
if(!users){
|
||||
event.record[fieldCode]['error']="ユーザー選択に、挿入しようとしたユーザー情報は見つかりませんでした。「値を挿入する」コンポーネントの処理を中断しました。";
|
||||
throw new Error("ユーザー選択に、挿入しようとしたユーザー情報は見つかりませんでした。「値を挿入する」コンポーネントの処理を中断しました。");
|
||||
}else{
|
||||
correctFormattedValue=[{ code: fieldValue, name: users }];
|
||||
}
|
||||
|
||||
//組織情報フィードに挿入しようとした値が適切な場合、correctFormattedValueに代入する
|
||||
}else if(fieldType === "ORGANIZATION_SELECT"){
|
||||
//挿入する値が組織情報から見つかれば、組織名を格納
|
||||
let organizations=await this.setInputOrganization(fieldValue);
|
||||
|
||||
//組織名が格納できている場合、組織コードと組織名をcorrectFormattedValueに代入する
|
||||
if(!organizations){
|
||||
event.record[fieldCode]['error']="組織選択フィールドに、挿入しようとした組織情報は見つかりませんでした。「値を挿入する」コンポーネントの処理を中断しました。";
|
||||
throw new Error("組織選択フィールドに、挿入しようとした組織情報は見つかりませんでした。「値を挿入する」コンポーネントの処理を中断しました。");
|
||||
}else{
|
||||
correctFormattedValue=[{ code: fieldValue, name: organizations}];
|
||||
}
|
||||
|
||||
//グループ情報フィードに挿入しようとした値が適切な場合、correctFormattedValueに代入する
|
||||
}else if(fieldType === "GROUP_SELECT"){
|
||||
//挿入する値がグループ情報から見つかれば、グループ名を格納
|
||||
let groups=await this.setInputGroup(fieldValue);
|
||||
|
||||
//グループ名が格納できている場合、グループコードとグループ名をcorrectFormattedValueに代入する
|
||||
if(!groups){
|
||||
event.record[fieldCode]['error']="グループ選択フィールドに、挿入しようとしたグループ情報は見つかりませんでした。「値を挿入する」コンポーネントの処理を中断しました。";
|
||||
throw new Error("グループ選択フィールドに、挿入しようとしたグループ情報は見つかりませんでした。「値を挿入する」コンポーネントの処理を中断しました。");
|
||||
}else{
|
||||
correctFormattedValue=[{ code: fieldValue, name: groups}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//条件式の結果がtrueかつ挿入する値が変換できた場合、フィールド(ラジオボタン・ドロップダウン・チェックボックス・複数選択・文字列一行・文字列複数行・リッチエディタ・数値・日付・日時・時刻)にセット
|
||||
if(conditionResult && (correctFormattedValue || correctValues)){
|
||||
//条件式の結果がtureかつ、値を正しい形式に変換できた場合、フィールドに値をセットする
|
||||
if(correctFormattedValue){
|
||||
event.record[fieldCode].value = correctFormattedValue;
|
||||
//条件式の結果がtureかつ、値を正しい形式(配列)に変換できた場合、フィールドに値(配列)をセットする
|
||||
}else if(correctValues.length > 0){
|
||||
event.record[fieldCode].value = correctValues;
|
||||
}
|
||||
}
|
||||
|
||||
result= {
|
||||
canNext:true,
|
||||
result:true
|
||||
}
|
||||
return result;
|
||||
}catch(error:any){
|
||||
event.record;
|
||||
event.error=error.message;
|
||||
console.error(error);
|
||||
result.canNext=true;//次のノードは処理を続ける
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param context 条件式を実行する
|
||||
* @returns
|
||||
*/
|
||||
getConditionResult(context:any):boolean{
|
||||
//プロパティ`condition`から条件ツリーを取得する
|
||||
const tree =this.getCondition(this.props.condition);
|
||||
if(!tree){
|
||||
//条件を設定されていません
|
||||
return true;
|
||||
}
|
||||
return tree.evaluate(tree.root,context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param condition 条件式ツリーを取得する
|
||||
* @returns
|
||||
*/
|
||||
getCondition(condition:string):ConditionTree|null{
|
||||
try{
|
||||
const tree = new ConditionTree();
|
||||
tree.fromJson(condition);
|
||||
if(tree.getConditions(tree.root).length>0){
|
||||
return tree;
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}catch(error){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
register(): void {
|
||||
actionAddins[this.name]=this;
|
||||
}
|
||||
|
||||
}
|
||||
new InsertValueAction();
|
||||
80
plugin/kintone-addins/src/actions/mail-check.ts
Normal file
80
plugin/kintone-addins/src/actions/mail-check.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { actionAddins } from ".";
|
||||
import { IAction, IActionResult, IActionNode, IActionProperty, IField } from "../types/ActionTypes";
|
||||
/**
|
||||
* アクションの属性定義
|
||||
*/
|
||||
interface IMailCheckProps {
|
||||
field: IField;//チェックするフィールドの対象
|
||||
message: string;//エラーメッセージ
|
||||
emailCheck:string;
|
||||
}
|
||||
/**
|
||||
* メールアドレスチェックアクション
|
||||
*/
|
||||
export class MailCheckAction implements IAction {
|
||||
name: string;
|
||||
actionProps: IActionProperty[];
|
||||
props: IMailCheckProps;
|
||||
constructor() {
|
||||
this.name = "メールアドレスチェック";
|
||||
this.actionProps = [];
|
||||
this.props = {
|
||||
field: { code: '' },
|
||||
message: '',
|
||||
emailCheck:''
|
||||
}
|
||||
//アクションを登録する
|
||||
this.register();
|
||||
}
|
||||
/**
|
||||
* アクションの実行を呼び出す
|
||||
* @param actionNode
|
||||
* @param event
|
||||
* @returns
|
||||
*/
|
||||
async process(actionNode: IActionNode, event: any): Promise<IActionResult> {
|
||||
let result = {
|
||||
canNext: true,
|
||||
result: false
|
||||
};
|
||||
|
||||
try {
|
||||
//属性設定を取得する
|
||||
this.actionProps = actionNode.actionProps;
|
||||
|
||||
if (!('field' in actionNode.ActionValue) && !('message' in actionNode.ActionValue) && !('emailCheck' in actionNode.ActionValue)) {
|
||||
return result
|
||||
}
|
||||
this.props = actionNode.ActionValue as IMailCheckProps;
|
||||
//条件式の計算結果を取得
|
||||
const record = event.record;
|
||||
const value = record[this.props.field.code].value;
|
||||
|
||||
if (this.props.emailCheck === '厳格') {
|
||||
if (!/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(value)) {
|
||||
record[this.props.field.code].error = this.props.message;
|
||||
}
|
||||
} else if (this.props.emailCheck === 'ゆるめ') {
|
||||
if (!/^[^@]+@[^@]+$/.test(value)) {
|
||||
record[this.props.field.code].error = this.props.message;
|
||||
}
|
||||
} else {
|
||||
result = {
|
||||
canNext: true,
|
||||
result: true
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
event.error = error;
|
||||
console.error(error);
|
||||
result.canNext = false;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
register(): void {
|
||||
actionAddins[this.name] = this;
|
||||
}
|
||||
|
||||
}
|
||||
new MailCheckAction();
|
||||
72
plugin/kintone-addins/src/actions/regular-check.ts
Normal file
72
plugin/kintone-addins/src/actions/regular-check.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { actionAddins } from ".";
|
||||
import { IAction,IActionResult, IActionNode, IActionProperty, IField} from "../types/ActionTypes";
|
||||
/**
|
||||
* アクションの属性定義
|
||||
*/
|
||||
interface IRegularCheckProps{
|
||||
field:IField;//チェックするフィールドの対象
|
||||
message:string;//エラーメッセージ
|
||||
regExpression:string;//正規表現式
|
||||
}
|
||||
/**
|
||||
* 正規表現チェックアクション
|
||||
*/
|
||||
export class RegularCheckAction implements IAction{
|
||||
name: string;
|
||||
actionProps: IActionProperty[];
|
||||
props:IRegularCheckProps;
|
||||
constructor(){
|
||||
this.name="正規表現チェック";
|
||||
this.actionProps=[];
|
||||
this.props={
|
||||
field:{code:''},
|
||||
message:'',
|
||||
regExpression:''
|
||||
}
|
||||
//アクションを登録する
|
||||
this.register();
|
||||
}
|
||||
/**
|
||||
* アクションの実行を呼び出す
|
||||
* @param actionNode
|
||||
* @param event
|
||||
* @returns
|
||||
*/
|
||||
async process(actionNode:IActionNode,event:any):Promise<IActionResult> {
|
||||
let result={
|
||||
canNext:true,
|
||||
result:false
|
||||
};
|
||||
try{
|
||||
//属性設定を取得する
|
||||
this.actionProps=actionNode.actionProps;
|
||||
if (!('field' in actionNode.ActionValue) && !('message' in actionNode.ActionValue) && !('regExpression'in actionNode.ActionValue)) {
|
||||
return result
|
||||
}
|
||||
this.props = actionNode.ActionValue as IRegularCheckProps;
|
||||
//条件式の計算結果を取得
|
||||
const record = event.record;
|
||||
const value = record[this.props.field.code].value;
|
||||
const regex = new RegExp(this.props.regExpression);
|
||||
if(!regex.test(value)){
|
||||
record[this.props.field.code].error=this.props.message;
|
||||
}else{
|
||||
result= {
|
||||
canNext:true,
|
||||
result:true
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}catch(error){
|
||||
event.error=error;
|
||||
console.error(error);
|
||||
result.canNext=false;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
register(): void {
|
||||
actionAddins[this.name]=this;
|
||||
}
|
||||
|
||||
}
|
||||
new RegularCheckAction();
|
||||
211
plugin/kintone-addins/src/actions/string-join.ts
Normal file
211
plugin/kintone-addins/src/actions/string-join.ts
Normal file
@@ -0,0 +1,211 @@
|
||||
import { actionAddins } from ".";
|
||||
import { IField, IAction,IActionResult, IActionNode, IActionProperty } from "../types/ActionTypes";
|
||||
import { Formatter } from "../util/format";
|
||||
|
||||
//右UI画面propertyのname:型:
|
||||
interface IStringJoinProps{
|
||||
//保存先フィールド
|
||||
saveField:IField;
|
||||
//結合元フィールド1
|
||||
joinField1:IField;
|
||||
//結合元フィールド2
|
||||
joinField2:IField;
|
||||
//区切り文字
|
||||
delimiter:string;
|
||||
}
|
||||
|
||||
//IActionインタフェースを実装する新しいクラスActionを作成:
|
||||
export class StringJoinAction implements IAction{
|
||||
name: string;
|
||||
//importから導入顕示定義
|
||||
actionProps: IActionProperty[];
|
||||
//上方のinterface Propsから、props受ける属性を定義:
|
||||
props:IStringJoinProps;
|
||||
//関数定義に必要な類名を構築:
|
||||
constructor(){
|
||||
//pgAdminDBに登録したアクション名(name/subtitle)一致する必要がある:
|
||||
this.name="文字結合";
|
||||
this.actionProps=[];
|
||||
this.register();
|
||||
//プロパティ属性初期化:
|
||||
this.props={
|
||||
saveField:{code:''},
|
||||
joinField1:{code:''},
|
||||
joinField2:{code:''},
|
||||
delimiter:''
|
||||
}
|
||||
//リセット上記登録表:
|
||||
this.register();
|
||||
}
|
||||
/**
|
||||
* アクションの処理を実装する
|
||||
* @param actionNode アクションノード
|
||||
* @param event Kintoneのイベント
|
||||
* @param context コンテキスト(レコード、変数情報を持っている)
|
||||
* @returns
|
||||
*/
|
||||
//非同期処理ある関数下のある属性:
|
||||
async process(actionNode:IActionNode,event:any):Promise<IActionResult> {
|
||||
let result={
|
||||
//後継処理不可:
|
||||
canNext:false,
|
||||
result:false
|
||||
};
|
||||
try{
|
||||
//属性設定を取得する:
|
||||
this.actionProps=actionNode.actionProps;
|
||||
//プロパティ設定のデータ型は必要な情報含めますか?全部不存在時return:
|
||||
if (!('saveField' in actionNode.ActionValue) && !('joinField1' in actionNode.ActionValue) && !('joinField2' in actionNode.ActionValue)) {
|
||||
return result
|
||||
}
|
||||
|
||||
//既定のプロパティのインタフェースへ変換:
|
||||
this.props = actionNode.ActionValue as IStringJoinProps;
|
||||
const record = event.record;
|
||||
|
||||
//kintoneフィールドタイプ取得:
|
||||
const joinField1type=this.props.joinField1.type;
|
||||
const joinField2type=this.props.joinField2.type;
|
||||
const saveFieldtype=this.props.saveField.type;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// //保存先フィールドは文字列フィールドではない場合、エラー発生:
|
||||
if(!(saveFieldtype==='SINGLE_LINE_TEXT'||saveFieldtype==='MULTI_LINE_TEXT'||saveFieldtype==='RICH_TEXT')){
|
||||
event.error='[エラーメッセージ]:結合保存先対応不可。結合しません';
|
||||
if (event.type.includes('success')){
|
||||
window.alert("[windows alert]:"+event.error);
|
||||
}
|
||||
result = {
|
||||
canNext: false,
|
||||
result: false
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//値取得方法定義:
|
||||
function getValue(value:string,type:string|undefined,fieldCode:string,event:any){
|
||||
if(event.record[fieldCode]?.value===undefined||event.record[fieldCode]?.value===null){
|
||||
event.record[fieldCode].value='';
|
||||
}
|
||||
//作成者、更新者:
|
||||
if(type==='CREATOR'||type==='MODIFIER'){
|
||||
value = event.record[fieldCode]?.value.name;
|
||||
//日時、作成日時、更新日時:
|
||||
}else if(type==='DATETIME'||type==='CREATED_TIME'||type==='UPDATED_TIME'){
|
||||
if(event.record[fieldCode]?.value!==undefined && event.record[fieldCode]?.value!==''){
|
||||
value = Formatter.dateFormat(new Date(event.record[fieldCode]?.value),'yyyy-MM-dd HH:mm');
|
||||
}else{
|
||||
value=event.record[fieldCode]?.value;
|
||||
}
|
||||
//ユーザ選択、組織選択、グループ選択、添付ファイル名、作業者、カテゴリー:
|
||||
}else if(type==='USER_SELECT'||type==='ORGANIZATION_SELECT'||type==='GROUP_SELECT'||type==='FILE'||type==='STATUS_ASSIGNEE'){
|
||||
if(event.record[fieldCode]?.value===undefined || event.record[fieldCode]?.value===''){
|
||||
value = event.record[fieldCode]?.value;
|
||||
}else{
|
||||
const mototext=event.record[fieldCode]?.value;
|
||||
let arr=[];
|
||||
for(let i=0;i<mototext.length;i++){
|
||||
arr.push(mototext[i].name);
|
||||
}
|
||||
//配列要素を,で連結して文字列を作成:
|
||||
value=arr.join();
|
||||
}
|
||||
//カテゴリー、チェックボックス、複数選択:
|
||||
}else if(type==='CATEGORY'||type==='CHECK_BOX'||type==='MULTI_SELECT'){
|
||||
if(event.record[fieldCode]?.value===undefined || event.record[fieldCode]?.value===''){
|
||||
value = event.record[fieldCode]?.value;
|
||||
}else{
|
||||
const mototext=event.record[fieldCode]?.value;
|
||||
let arr=[];
|
||||
for(let i=0;i<mototext.length;i++){
|
||||
arr.push(mototext[i]);
|
||||
}
|
||||
//配列要素を,で連結して文字列を作成:
|
||||
value=arr.join();
|
||||
}
|
||||
//詳細画面プロセス実行後のステータス:
|
||||
}else if(type==='STATUS'&&event.type.includes('process')){
|
||||
value = event.nextStatus.value;
|
||||
}else{
|
||||
value = event.record[fieldCode]?.value;
|
||||
}
|
||||
if (value===undefined || value===null){
|
||||
value='';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//値取得方法呼出:
|
||||
let joinValue1:string='';
|
||||
joinValue1=getValue(joinValue1,joinField1type,this.props.joinField1.code,event);
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
let joinValue2:string='';
|
||||
joinValue2=getValue(joinValue2,joinField2type,this.props.joinField2.code,event);
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
const conString = this.props.delimiter;
|
||||
let saveValue:string='';
|
||||
//前後結合元が空白なら区切り文字も空白にする(例:1-8の8無いなら1。1-8の1無いなら8。1空白8の8無いなら1。結合元全部空白なら全部空白):
|
||||
if(joinValue1===''&&joinValue2===''){
|
||||
saveValue='';
|
||||
}else if(joinValue1===''&&joinValue2!==''){
|
||||
saveValue=joinValue2;
|
||||
}else if(joinValue2===''&&joinValue1!==''){
|
||||
saveValue=joinValue1;
|
||||
}else if(joinValue1!==''&&joinValue2!==''){
|
||||
saveValue=`${joinValue1}${conString}${joinValue2}`
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//新規/更新/一覧保存成功後の以外のeventでPUT使用しない:
|
||||
if (!event.type.includes('success')){
|
||||
//保存先フィールドに値セット:
|
||||
record[this.props.saveField.code].value=saveValue;
|
||||
window.alert("文字結合行いました。"+this.props.joinField1.name+":"+joinValue1+","+this.props.joinField2.name+":"+joinValue2+"。");
|
||||
}else{
|
||||
const params={
|
||||
"app":event.appId,
|
||||
"id":event.recordId,
|
||||
"record":{[this.props.saveField.code]:{"value":saveValue}}
|
||||
};
|
||||
return await kintone.api(kintone.api.url('/k/v1/record',true),'PUT',params).then((resp) => {
|
||||
//kintone保存先フィールド存在確認:
|
||||
record[this.props.saveField.code].value=saveValue;
|
||||
if (event.type.includes('index')){
|
||||
window.alert("文字結合行いました。"+this.props.joinField1.name+":"+joinValue1+","+this.props.joinField2.name+":"+joinValue2+"。一覧画面更新成功後自動リロードしません。必要に応じて手動リロードください。");
|
||||
}else{
|
||||
window.alert("文字結合行いました。"+this.props.joinField1.name+":"+joinValue1+","+this.props.joinField2.name+":"+joinValue2+"。");
|
||||
}
|
||||
//一覧画面更新成功後リロード:
|
||||
// if (event.type.includes('index')){
|
||||
// event.url = location.href.endsWith('/') || location.href.endsWith('&') ?
|
||||
// location.href.slice(0, -1) :
|
||||
// location.href + (location.href.includes('?') ? '&' : '/');
|
||||
// }
|
||||
}).catch((error) => {
|
||||
event.error = 'エラーが発生しました。結合しません。システム管理者へお問合せください';
|
||||
window.alert(event.error+"error message:"+error);
|
||||
return event;
|
||||
});
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
result= {
|
||||
canNext:true,
|
||||
result:true
|
||||
}
|
||||
return result;
|
||||
}catch(error){;
|
||||
if (event.type.includes('success')){
|
||||
window.alert("[windows alert]:処理中異常が発生しました。結合しません。システム担当者へお問合せください。errorメッセージ:"+error)
|
||||
}
|
||||
event.error="[エラーメッセージ]:処理中異常が発生しました。結合しません。システム担当者へお問合せください。errorメッセージ:"+error;
|
||||
return {
|
||||
canNext:false,
|
||||
result:false
|
||||
}
|
||||
}
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
register(): void {
|
||||
actionAddins[this.name]=this;
|
||||
}
|
||||
}
|
||||
new StringJoinAction();
|
||||
96
plugin/kintone-addins/src/actions/validation-fullwidth.ts
Normal file
96
plugin/kintone-addins/src/actions/validation-fullwidth.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { actionAddins } from ".";
|
||||
import { IAction,IActionResult, IActionNode, IActionProperty, IField, IContext } from "../types/ActionTypes";
|
||||
|
||||
//クラス名を設計書に揃える
|
||||
/**
|
||||
* アクションの属性定義
|
||||
*/
|
||||
interface FullWidthProps{
|
||||
//checkOption:Array<string>,
|
||||
field:IField
|
||||
}
|
||||
/**
|
||||
* 全角チェックアクション
|
||||
*/
|
||||
export class FullWidthAction implements IAction{
|
||||
name: string;
|
||||
actionProps: IActionProperty[];
|
||||
props:FullWidthProps;
|
||||
constructor(){
|
||||
this.name="全角チェック"; /* pgadminのnameと同様 */
|
||||
this.actionProps=[];
|
||||
this.props={
|
||||
//checkOption:[],
|
||||
field:{code:''}
|
||||
}
|
||||
//アクションを登録する
|
||||
this.register();
|
||||
}
|
||||
/**
|
||||
* アクションの実行を呼び出す
|
||||
* @param actionNode
|
||||
* @param event
|
||||
* @returns
|
||||
*/
|
||||
async process(actionNode:IActionNode,event:any,context:IContext):Promise<IActionResult> {
|
||||
let result={
|
||||
canNext:true,
|
||||
result:false
|
||||
};
|
||||
try{
|
||||
//属性設定を取得する
|
||||
this.actionProps=actionNode.actionProps;
|
||||
if (!('field' in actionNode.ActionValue) ) {
|
||||
return result
|
||||
}
|
||||
this.props = actionNode.ActionValue as FullWidthProps;
|
||||
//条件式の計算結果を取得
|
||||
const record = event.record;
|
||||
const value = record[this.props.field.code]?.value;
|
||||
//条件分岐
|
||||
//未入力時は何も処理をせず終了
|
||||
if(value===undefined || value===''){
|
||||
return result;
|
||||
}
|
||||
//半角が含まれていた場合resultがfalse
|
||||
if(!this.containsFullWidthChars(value)){
|
||||
//エラー時に出力される文字設定
|
||||
record[this.props.field.code].error="半角が含まれています";
|
||||
//次の処理を中止する値設定
|
||||
result.canNext=false;
|
||||
return result;
|
||||
}
|
||||
//resultプロパティ指定
|
||||
result= {
|
||||
canNext:true,
|
||||
result:true
|
||||
}
|
||||
return result;
|
||||
|
||||
//例外処理
|
||||
}catch(error){
|
||||
event.error=error;
|
||||
console.error(error);
|
||||
result.canNext=false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// 全て全角の文字列の場合はtrue、そうでない場合はfalse
|
||||
containsFullWidthChars(text: string): boolean {
|
||||
|
||||
// 半角英数字カナ記号を除外
|
||||
const checkRegex="^[^\x01-\x7E\uFF61-\uFF9F]+$";
|
||||
|
||||
//正規表現オブジェクト生成
|
||||
const fullWidthRegex = new RegExp(checkRegex);
|
||||
|
||||
//正規表現チェック
|
||||
return fullWidthRegex.test(text);
|
||||
}
|
||||
|
||||
//戻り値を持たないためvoid型
|
||||
register(): void {
|
||||
actionAddins[this.name]=this;
|
||||
}
|
||||
}
|
||||
new FullWidthAction();
|
||||
90
plugin/kintone-addins/src/actions/validation-halfwidth.ts
Normal file
90
plugin/kintone-addins/src/actions/validation-halfwidth.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { actionAddins } from ".";
|
||||
import { IAction,IActionResult, IActionNode, IActionProperty, IField, IContext } from "../types/ActionTypes";
|
||||
|
||||
/**
|
||||
* アクションの属性定義
|
||||
*/
|
||||
interface HalfWidthProps{
|
||||
field:IField
|
||||
}
|
||||
/**
|
||||
* 半角チェックアクション
|
||||
*/
|
||||
export class HalfWidthAction implements IAction{
|
||||
name: string;
|
||||
actionProps: IActionProperty[];
|
||||
props:HalfWidthProps;
|
||||
constructor(){
|
||||
this.name="半角チェック"; /* pgadminのnameと同様 */
|
||||
this.actionProps=[];
|
||||
this.props={
|
||||
field:{code:''}
|
||||
}
|
||||
//アクションを登録する
|
||||
this.register();
|
||||
}
|
||||
/**
|
||||
* アクションの実行を呼び出す
|
||||
* @param actionNode
|
||||
* @param event
|
||||
* @returns
|
||||
*/
|
||||
async process(actionNode:IActionNode,event:any,context:IContext):Promise<IActionResult> {
|
||||
let result={
|
||||
canNext:true,
|
||||
result:false
|
||||
};
|
||||
try{
|
||||
//属性設定を取得する
|
||||
this.actionProps=actionNode.actionProps;
|
||||
if (!('field' in actionNode.ActionValue) ) {
|
||||
return result
|
||||
}
|
||||
this.props = actionNode.ActionValue as HalfWidthProps;
|
||||
//条件式の計算結果を取得
|
||||
const record = event.record;
|
||||
const value = record[this.props.field.code]?.value;
|
||||
//条件分岐
|
||||
//未入力時は何も処理をせず終了
|
||||
if(value===undefined || value===''){
|
||||
return result;
|
||||
}
|
||||
//全角が含まれていた場合保存処理中止(エラー処理)
|
||||
if(!this.containsHalfWidthChars(value)){
|
||||
//エラー時に出力される文字設定
|
||||
record[this.props.field.code].error="全角が含まれています";
|
||||
//次の処理を中止する値設定
|
||||
result.canNext=false;
|
||||
return result;
|
||||
}
|
||||
//半角の場合問題なく実行
|
||||
//resultプロパティ指定
|
||||
result= {
|
||||
canNext:true,
|
||||
result:true
|
||||
}
|
||||
return result;
|
||||
//例外処理
|
||||
}catch(error){
|
||||
event.error=error;
|
||||
console.error(error);
|
||||
result.canNext=false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// 全て全角の文字列の場合はtrue、そうでない場合はfalse
|
||||
containsHalfWidthChars(text: string): boolean {
|
||||
|
||||
const checkRegex = "^[\x01-\x7E\uFF61-\uFF9F]+$";
|
||||
//正規表現オブジェクト生成
|
||||
const halfWidthRegex = new RegExp(checkRegex);
|
||||
|
||||
//正規表現チェック
|
||||
return halfWidthRegex.test(text);
|
||||
}
|
||||
//戻り値を持たないためvoid型
|
||||
register(): void {
|
||||
actionAddins[this.name]=this;
|
||||
}
|
||||
}
|
||||
new HalfWidthAction();
|
||||
70
plugin/kintone-addins/src/actions/value-getter.ts
Normal file
70
plugin/kintone-addins/src/actions/value-getter.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { actionAddins } from ".";
|
||||
import { IAction,IActionResult, IActionNode, IActionProperty, IField, IContext, IVarName} from "../types/ActionTypes";
|
||||
/**
|
||||
* アクションの属性定義
|
||||
*/
|
||||
interface IGetValueProps{
|
||||
field:IField;//チェックするフィールドの対象
|
||||
verName:IVarName;
|
||||
}
|
||||
/**
|
||||
* 正規表現チェックアクション
|
||||
*/
|
||||
export class GetValueAciton implements IAction{
|
||||
name: string;
|
||||
actionProps: IActionProperty[];
|
||||
props:IGetValueProps;
|
||||
constructor(){
|
||||
this.name="値を取得する";
|
||||
this.actionProps=[];
|
||||
this.props={
|
||||
field:{code:''},
|
||||
verName:{name:''}
|
||||
}
|
||||
//アクションを登録する
|
||||
this.register();
|
||||
}
|
||||
/**
|
||||
* アクションの実行を呼び出す
|
||||
* @param actionNode
|
||||
* @param event
|
||||
* @returns
|
||||
*/
|
||||
async process(actionNode:IActionNode,event:any,context:IContext):Promise<IActionResult> {
|
||||
let result={
|
||||
canNext:true,
|
||||
result:false
|
||||
};
|
||||
try{
|
||||
//属性設定を取得する
|
||||
this.actionProps=actionNode.actionProps;
|
||||
if (!('field' in actionNode.ActionValue) && !('verName' in actionNode.ActionValue)) {
|
||||
return result
|
||||
}
|
||||
|
||||
this.props = actionNode.ActionValue as IGetValueProps;
|
||||
//条件式の計算結果を取得
|
||||
const record = event.record;
|
||||
const value = record[this.props.field.code].value;
|
||||
if(this.props.verName && this.props.verName.name!==''){
|
||||
context.variables[this.props.verName.name] = value;
|
||||
}
|
||||
result = {
|
||||
canNext:true,
|
||||
result:true
|
||||
}
|
||||
|
||||
return result;
|
||||
}catch(error){
|
||||
event.error=error;
|
||||
console.error(error);
|
||||
result.canNext=false;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
register(): void {
|
||||
actionAddins[this.name]=this;
|
||||
}
|
||||
|
||||
}
|
||||
new GetValueAciton();
|
||||
@@ -1,9 +1,3 @@
|
||||
// export const sum = (a: number, b: number) => {
|
||||
// if ('development' === process.env.NODE_ENV) {
|
||||
// console.log('boop');
|
||||
// }
|
||||
// return a + b;
|
||||
// };
|
||||
import $ from 'jquery';
|
||||
import { ActionProcess } from './types/action-process';
|
||||
import { ActionFlow } from './types/ActionTypes';
|
||||
|
||||
@@ -89,6 +89,13 @@ export interface IField{
|
||||
name?:string;
|
||||
code:string;
|
||||
type?:string;
|
||||
required?:boolean;
|
||||
options?:string;
|
||||
}
|
||||
//変数のインターフェース
|
||||
export interface IVarName{
|
||||
name:string;
|
||||
fields?:IVarName[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,6 +9,16 @@ import '../actions/condition-action';
|
||||
import '../actions/data-processing';
|
||||
import '../actions/data-mapping';
|
||||
import '../actions/current-field-get';
|
||||
import '../actions/regular-check';
|
||||
import '../actions/mail-check';
|
||||
import '../actions/counter-check';
|
||||
import '../actions/datetime-getter';
|
||||
import '../actions/insert-value';
|
||||
import '../actions/value-getter';
|
||||
import '../actions/string-join';
|
||||
import '../actions/validation-fullwidth';
|
||||
import '../actions/validation-halfwidth';
|
||||
|
||||
import { ActionFlow,IActionFlow, IActionResult,IContext } from "./ActionTypes";
|
||||
|
||||
export class ActionProcess{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
73
sample2.json
73
sample2.json
@@ -1,55 +1,22 @@
|
||||
[
|
||||
{
|
||||
"component": "InputText",
|
||||
"props": {
|
||||
"displayName": "文字入力",
|
||||
"modelValue": "",
|
||||
"name": "str",
|
||||
"placeholder": "文字を入力してください",
|
||||
"maxLength":"20",
|
||||
"hint":"文字列入力<br>入力ルール指定可能。ルールの設定例:[val=>!!val||'必須入力です']",
|
||||
"rules":"[val=>!!val||'必須入力です']"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "AppFieldSelect",
|
||||
"props": {
|
||||
"displayName": "フィールド選択(複数)",
|
||||
"modelValue": {},
|
||||
"name": "selectFields",
|
||||
"placeholder": "アプリ選択後、フィールドを選んでください",
|
||||
"selectType":"multiple"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "AppFieldSelect",
|
||||
"props": {
|
||||
"displayName": "フィールド選択(単一)",
|
||||
"modelValue": {},
|
||||
"name": "selectField",
|
||||
"placeholder": "アプリ選択後、フィールドを選んでください",
|
||||
"selectType":"single"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "ColorPicker",
|
||||
"props": {
|
||||
"displayName": "色選択",
|
||||
"modelValue": "",
|
||||
"name": "color",
|
||||
"placeholder": "カラーを選択してください"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "NumInput",
|
||||
"props": {
|
||||
"displayName": "数値入力フィールド",
|
||||
"modelValue": "",
|
||||
"name": "num",
|
||||
"max":100,
|
||||
"min":0,
|
||||
"placeholder": "数値を入力してください",
|
||||
"rules":"[val=>!!val ||'数値を入力してください',val=>val<=100 && val>=1 || '1-100の範囲内の数値を入力してください']"
|
||||
}
|
||||
{
|
||||
"component": "FieldInput",
|
||||
"props": {
|
||||
"displayName": "フィールド",
|
||||
"modelValue": {},
|
||||
"name": "field",
|
||||
"placeholder": "対象項目を選択してください"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "SelectBox",
|
||||
"props": {
|
||||
"displayName": "チェックする全角文字",
|
||||
"modelValue": null,
|
||||
"name": "options",
|
||||
"placeholder": "チェックしたい全角文字を選択する",
|
||||
"selectType":"multiple",
|
||||
"options":["全角記号および句読点","ひらがな","カタカナ","全角英数字","常用漢字","拡張漢字"]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user