@shisyamo4131/air-guard-v2-schemas 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +15 -0
- package/package.json +44 -0
- package/src/Agreement.js +262 -0
- package/src/ArrangementNotification.js +505 -0
- package/src/Billing.js +159 -0
- package/src/Company.js +176 -0
- package/src/Customer.js +98 -0
- package/src/Employee.js +201 -0
- package/src/Operation.js +779 -0
- package/src/OperationBilling.js +193 -0
- package/src/OperationDetail.js +147 -0
- package/src/OperationResult.js +437 -0
- package/src/OperationResultDetail.js +72 -0
- package/src/Outsourcer.js +46 -0
- package/src/RoundSetting.js +123 -0
- package/src/Site.js +192 -0
- package/src/SiteOperationSchedule.js +503 -0
- package/src/SiteOperationScheduleDetail.js +99 -0
- package/src/SiteOrder.js +62 -0
- package/src/Tax.js +39 -0
- package/src/User.js +41 -0
- package/src/WorkingResult.js +297 -0
- package/src/apis/index.js +9 -0
- package/src/constants/arrangement-notification-status.js +68 -0
- package/src/constants/billing-unit-type.js +15 -0
- package/src/constants/contract-status.js +15 -0
- package/src/constants/day-type.js +44 -0
- package/src/constants/employment-status.js +15 -0
- package/src/constants/gender.js +11 -0
- package/src/constants/index.js +9 -0
- package/src/constants/prefectures.js +56 -0
- package/src/constants/shift-type.js +20 -0
- package/src/constants/site-status.js +15 -0
- package/src/parts/accessorDefinitions.js +109 -0
- package/src/parts/fieldDefinitions.js +642 -0
- package/src/utils/ContextualError.js +49 -0
- package/src/utils/CutoffDate.js +223 -0
- package/src/utils/index.js +48 -0
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VALUES as ARRANGEMENT_NOTIFICATION_STATUS_VALUES,
|
|
3
|
+
OPTIONS as ARRANGEMENT_NOTIFICATION_STATUS_OPTIONS,
|
|
4
|
+
} from "../constants/arrangement-notification-status.js";
|
|
5
|
+
import {
|
|
6
|
+
VALUES as CONTRACT_STATUS_VALUES,
|
|
7
|
+
OPTIONS as CONTRACT_STATUS_OPTIONS,
|
|
8
|
+
} from "../constants/contract-status.js";
|
|
9
|
+
import { DAY_TYPE_ARRAY, DAY_TYPE_DEFAULT } from "../constants/day-type.js";
|
|
10
|
+
import {
|
|
11
|
+
VALUES as EMPLOYMENT_STATUS_VALUES,
|
|
12
|
+
OPTIONS as EMPLOYMENT_STATUS_OPTIONS,
|
|
13
|
+
} from "../constants/employment-status.js";
|
|
14
|
+
import { GENDER_ARRAY, GENDER_DEFAULT } from "../constants/gender.js";
|
|
15
|
+
import { PREFECTURES_ARRAY } from "../constants/prefectures.js";
|
|
16
|
+
import {
|
|
17
|
+
SHIFT_TYPE_ARRAY,
|
|
18
|
+
SHIFT_TYPE_DEFAULT,
|
|
19
|
+
} from "../constants/shift-type.js";
|
|
20
|
+
import {
|
|
21
|
+
VALUES as SITE_STATUS_VALUES,
|
|
22
|
+
OPTIONS as SITE_STATUS_OPTIONS,
|
|
23
|
+
} from "../constants/site-status.js";
|
|
24
|
+
|
|
25
|
+
export const DEFAULT_WORKING_MINUTES = 480;
|
|
26
|
+
export const DEFAULT_BREAK_MINUTES = 60;
|
|
27
|
+
export const MINUTES_PER_HOUR = 60;
|
|
28
|
+
export const MINUTES_PER_QUARTER_HOUR = 15;
|
|
29
|
+
export const MAX_SCHEDULED_WORKING_MINUTES = 480; // 8時間 * 60分
|
|
30
|
+
|
|
31
|
+
const defaultDefinition = {
|
|
32
|
+
type: String,
|
|
33
|
+
default: null,
|
|
34
|
+
label: undefined,
|
|
35
|
+
length: undefined,
|
|
36
|
+
required: undefined,
|
|
37
|
+
hidden: undefined,
|
|
38
|
+
component: {
|
|
39
|
+
name: undefined,
|
|
40
|
+
attrs: {},
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/** 汎用パーツ */
|
|
45
|
+
const generalDefinitions = {
|
|
46
|
+
array: {
|
|
47
|
+
...defaultDefinition,
|
|
48
|
+
type: Array,
|
|
49
|
+
default: () => [],
|
|
50
|
+
component: { name: "air-select", attrs: { multiple: true } },
|
|
51
|
+
},
|
|
52
|
+
check: {
|
|
53
|
+
...defaultDefinition,
|
|
54
|
+
type: Boolean,
|
|
55
|
+
default: false,
|
|
56
|
+
component: { name: "air-checkbox", attrs: {} },
|
|
57
|
+
},
|
|
58
|
+
code: {
|
|
59
|
+
...defaultDefinition,
|
|
60
|
+
length: 10,
|
|
61
|
+
component: { name: "air-text-field", attrs: { inputType: "alphanumeric" } },
|
|
62
|
+
},
|
|
63
|
+
// 日付(00時固定としたDateオブジェクトとして使用する)
|
|
64
|
+
dateAt: {
|
|
65
|
+
...defaultDefinition,
|
|
66
|
+
type: Object,
|
|
67
|
+
label: "日付",
|
|
68
|
+
default: () => {
|
|
69
|
+
const date = new Date();
|
|
70
|
+
date.setHours(0, 0, 0, 0);
|
|
71
|
+
return date;
|
|
72
|
+
},
|
|
73
|
+
component: {
|
|
74
|
+
name: "air-date-input",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
// 日時(時刻までを含んだDateオブジェクト)
|
|
78
|
+
dateTimeAt: {
|
|
79
|
+
...defaultDefinition,
|
|
80
|
+
type: Object,
|
|
81
|
+
label: "日時",
|
|
82
|
+
default: null,
|
|
83
|
+
component: { name: "air-date-time-picker-input", attrs: {} },
|
|
84
|
+
},
|
|
85
|
+
multipleLine: {
|
|
86
|
+
...defaultDefinition,
|
|
87
|
+
length: 200,
|
|
88
|
+
component: {
|
|
89
|
+
name: "air-textarea",
|
|
90
|
+
attrs: { counter: true, maxlength: 200 },
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
number: {
|
|
94
|
+
...defaultDefinition,
|
|
95
|
+
type: Number,
|
|
96
|
+
component: {
|
|
97
|
+
name: "air-number-input",
|
|
98
|
+
attrs: {
|
|
99
|
+
controlVariant: "split",
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
object: {
|
|
104
|
+
...defaultDefinition,
|
|
105
|
+
type: Object,
|
|
106
|
+
component: { name: "air-select" }, // `AirTextField` that is used as default ui component could not handle object type.
|
|
107
|
+
},
|
|
108
|
+
oneLine: {
|
|
109
|
+
...defaultDefinition,
|
|
110
|
+
component: { name: "air-text-field", attrs: {} },
|
|
111
|
+
},
|
|
112
|
+
radio: {
|
|
113
|
+
...defaultDefinition,
|
|
114
|
+
component: { name: "air-radio-group", attrs: {} },
|
|
115
|
+
},
|
|
116
|
+
select: {
|
|
117
|
+
...defaultDefinition,
|
|
118
|
+
component: { name: "air-select", attrs: {} },
|
|
119
|
+
},
|
|
120
|
+
// 時刻文字列
|
|
121
|
+
time: {
|
|
122
|
+
...defaultDefinition,
|
|
123
|
+
label: "時刻",
|
|
124
|
+
component: {
|
|
125
|
+
name: "air-time-picker-input",
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/** カスタムパーツ(汎用パーツ含む) */
|
|
131
|
+
export const fieldDefinitions = {
|
|
132
|
+
/** array */
|
|
133
|
+
array: generalDefinitions.array,
|
|
134
|
+
/** check */
|
|
135
|
+
check: generalDefinitions.check,
|
|
136
|
+
isForeigner: {
|
|
137
|
+
...generalDefinitions.check,
|
|
138
|
+
label: "外国籍",
|
|
139
|
+
},
|
|
140
|
+
/** code */
|
|
141
|
+
code: generalDefinitions.code,
|
|
142
|
+
/** dateAt */
|
|
143
|
+
dateAt: generalDefinitions.dateAt,
|
|
144
|
+
/** dateTimeAt */
|
|
145
|
+
dateTimeAt: generalDefinitions.dateTimeAt,
|
|
146
|
+
/** multiple-line */
|
|
147
|
+
multipleLine: generalDefinitions.multipleLine,
|
|
148
|
+
|
|
149
|
+
/** number */
|
|
150
|
+
number: generalDefinitions.number,
|
|
151
|
+
breakMinutes: {
|
|
152
|
+
...generalDefinitions.number,
|
|
153
|
+
label: "休憩時間(分)",
|
|
154
|
+
default: DEFAULT_BREAK_MINUTES,
|
|
155
|
+
validator: (v) => v >= 0,
|
|
156
|
+
component: {
|
|
157
|
+
...generalDefinitions.number.component,
|
|
158
|
+
attrs: {
|
|
159
|
+
...generalDefinitions.number.component.attrs,
|
|
160
|
+
min: 0,
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
overtimeWorkMinutes: {
|
|
165
|
+
...generalDefinitions.number,
|
|
166
|
+
label: "残業時間(分)",
|
|
167
|
+
default: 0,
|
|
168
|
+
validator: (v) => v >= 0,
|
|
169
|
+
component: {
|
|
170
|
+
...generalDefinitions.number.component,
|
|
171
|
+
attrs: {
|
|
172
|
+
...generalDefinitions.number.component.attrs,
|
|
173
|
+
min: 0,
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
regulationWorkMinutes: {
|
|
178
|
+
...generalDefinitions.number,
|
|
179
|
+
label: "規定実働時間(分)",
|
|
180
|
+
default: DEFAULT_WORKING_MINUTES,
|
|
181
|
+
validator: (v) => v >= 0,
|
|
182
|
+
component: {
|
|
183
|
+
...generalDefinitions.number.component,
|
|
184
|
+
attrs: {
|
|
185
|
+
...generalDefinitions.number.component.attrs,
|
|
186
|
+
min: 0,
|
|
187
|
+
persistentHint: true,
|
|
188
|
+
hint: "この時間を超えると残業扱いになります。",
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
price: {
|
|
193
|
+
...generalDefinitions.number,
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
/** one-line */
|
|
197
|
+
oneLine: generalDefinitions.oneLine,
|
|
198
|
+
address: {
|
|
199
|
+
...generalDefinitions.oneLine,
|
|
200
|
+
label: "町域名・番地",
|
|
201
|
+
length: 15,
|
|
202
|
+
},
|
|
203
|
+
building: {
|
|
204
|
+
...generalDefinitions.oneLine,
|
|
205
|
+
label: "建物名・階数",
|
|
206
|
+
length: 30,
|
|
207
|
+
},
|
|
208
|
+
city: {
|
|
209
|
+
...generalDefinitions.oneLine,
|
|
210
|
+
label: "市区町村",
|
|
211
|
+
length: 10,
|
|
212
|
+
},
|
|
213
|
+
displayName: {
|
|
214
|
+
...generalDefinitions.oneLine,
|
|
215
|
+
label: "表示名",
|
|
216
|
+
length: 6,
|
|
217
|
+
},
|
|
218
|
+
email: {
|
|
219
|
+
...generalDefinitions.oneLine,
|
|
220
|
+
label: "email",
|
|
221
|
+
length: 50,
|
|
222
|
+
component: {
|
|
223
|
+
name: generalDefinitions.oneLine.component.name,
|
|
224
|
+
attrs: {
|
|
225
|
+
inputType: "email",
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
fax: {
|
|
230
|
+
...generalDefinitions.oneLine,
|
|
231
|
+
label: "FAX番号",
|
|
232
|
+
length: 13,
|
|
233
|
+
component: {
|
|
234
|
+
name: generalDefinitions.oneLine.component.name,
|
|
235
|
+
attrs: {
|
|
236
|
+
counter: true,
|
|
237
|
+
inputType: "tel",
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
firstName: {
|
|
242
|
+
...generalDefinitions.oneLine,
|
|
243
|
+
label: "名",
|
|
244
|
+
length: 20,
|
|
245
|
+
},
|
|
246
|
+
firstNameKana: {
|
|
247
|
+
...generalDefinitions.oneLine,
|
|
248
|
+
label: "メイ",
|
|
249
|
+
length: 40,
|
|
250
|
+
component: {
|
|
251
|
+
name: generalDefinitions.oneLine.component.name,
|
|
252
|
+
attrs: {
|
|
253
|
+
inputType: "katakana",
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
foreignName: {
|
|
258
|
+
...generalDefinitions.oneLine,
|
|
259
|
+
label: "本名",
|
|
260
|
+
length: 50,
|
|
261
|
+
},
|
|
262
|
+
lastName: {
|
|
263
|
+
...generalDefinitions.oneLine,
|
|
264
|
+
label: "姓",
|
|
265
|
+
length: 20,
|
|
266
|
+
},
|
|
267
|
+
lastNameKana: {
|
|
268
|
+
...generalDefinitions.oneLine,
|
|
269
|
+
label: "セイ",
|
|
270
|
+
length: 40,
|
|
271
|
+
component: {
|
|
272
|
+
name: generalDefinitions.oneLine.component.name,
|
|
273
|
+
attrs: {
|
|
274
|
+
inputType: "katakana",
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
name: {
|
|
279
|
+
...generalDefinitions.oneLine,
|
|
280
|
+
label: "名前",
|
|
281
|
+
length: 20,
|
|
282
|
+
},
|
|
283
|
+
nameKana: {
|
|
284
|
+
...generalDefinitions.oneLine,
|
|
285
|
+
label: "名前(カナ)",
|
|
286
|
+
length: 40,
|
|
287
|
+
component: {
|
|
288
|
+
name: generalDefinitions.oneLine.component.name,
|
|
289
|
+
attrs: {
|
|
290
|
+
inputType: "katakana",
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
nationality: {
|
|
295
|
+
...generalDefinitions.oneLine,
|
|
296
|
+
label: "国籍",
|
|
297
|
+
length: 50,
|
|
298
|
+
},
|
|
299
|
+
siteId: {
|
|
300
|
+
...generalDefinitions.oneLine,
|
|
301
|
+
label: "現場",
|
|
302
|
+
component: {
|
|
303
|
+
name: "air-autocomplete-api",
|
|
304
|
+
attrs: {
|
|
305
|
+
itemValue: "docId",
|
|
306
|
+
itemTitle: "name",
|
|
307
|
+
noFilter: true,
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
tel: {
|
|
312
|
+
...generalDefinitions.oneLine,
|
|
313
|
+
label: "電話番号",
|
|
314
|
+
length: 13,
|
|
315
|
+
component: {
|
|
316
|
+
name: generalDefinitions.oneLine.component.name,
|
|
317
|
+
attrs: {
|
|
318
|
+
counter: true,
|
|
319
|
+
inputType: "tel",
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
workDescription: {
|
|
324
|
+
...generalDefinitions.oneLine,
|
|
325
|
+
label: "作業内容",
|
|
326
|
+
length: 20,
|
|
327
|
+
},
|
|
328
|
+
zipcode: {
|
|
329
|
+
...generalDefinitions.oneLine,
|
|
330
|
+
default: null,
|
|
331
|
+
label: "郵便番号",
|
|
332
|
+
component: {
|
|
333
|
+
name: "air-postal-code",
|
|
334
|
+
attrs: {
|
|
335
|
+
counter: true,
|
|
336
|
+
inputType: "zipcode",
|
|
337
|
+
"onUpdate:address": (item, updater) => {
|
|
338
|
+
return (result) => {
|
|
339
|
+
updater({
|
|
340
|
+
prefCode: result.prefcode,
|
|
341
|
+
prefecture: result.address1,
|
|
342
|
+
city: result.address2,
|
|
343
|
+
address: result.address3,
|
|
344
|
+
});
|
|
345
|
+
};
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
/** object */
|
|
352
|
+
object: generalDefinitions.object,
|
|
353
|
+
|
|
354
|
+
customer: {
|
|
355
|
+
...generalDefinitions.object,
|
|
356
|
+
label: "取引先",
|
|
357
|
+
component: {
|
|
358
|
+
name: "air-autocomplete-api",
|
|
359
|
+
attrs: {
|
|
360
|
+
cacheItems: true,
|
|
361
|
+
clearable: true,
|
|
362
|
+
itemTitle: "name",
|
|
363
|
+
itemValue: "docId",
|
|
364
|
+
returnObject: true,
|
|
365
|
+
},
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
location: {
|
|
369
|
+
...generalDefinitions.object,
|
|
370
|
+
hidden: true,
|
|
371
|
+
},
|
|
372
|
+
|
|
373
|
+
/** radio */
|
|
374
|
+
radio: generalDefinitions.radio,
|
|
375
|
+
|
|
376
|
+
/** select */
|
|
377
|
+
select: generalDefinitions.select,
|
|
378
|
+
arrangementNotificationStatus: {
|
|
379
|
+
...generalDefinitions.select,
|
|
380
|
+
default: ARRANGEMENT_NOTIFICATION_STATUS_VALUES.ARRANGED.value,
|
|
381
|
+
label: "状態",
|
|
382
|
+
component: {
|
|
383
|
+
name: generalDefinitions.select.component.name,
|
|
384
|
+
attrs: {
|
|
385
|
+
items: ARRANGEMENT_NOTIFICATION_STATUS_OPTIONS,
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
// contractStatus -> Used in Customer.js and Outsourcer.js
|
|
390
|
+
contractStatus: {
|
|
391
|
+
...generalDefinitions.select,
|
|
392
|
+
default: CONTRACT_STATUS_VALUES.ACTIVE.value,
|
|
393
|
+
label: "契約状態",
|
|
394
|
+
component: {
|
|
395
|
+
name: generalDefinitions.select.component.name,
|
|
396
|
+
attrs: {
|
|
397
|
+
items: CONTRACT_STATUS_OPTIONS,
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
},
|
|
401
|
+
dayType: {
|
|
402
|
+
...generalDefinitions.select,
|
|
403
|
+
default: DAY_TYPE_DEFAULT,
|
|
404
|
+
label: "曜日区分",
|
|
405
|
+
component: {
|
|
406
|
+
name: generalDefinitions.select.component.name,
|
|
407
|
+
attrs: {
|
|
408
|
+
items: DAY_TYPE_ARRAY,
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
employmentStatus: {
|
|
413
|
+
...generalDefinitions.select,
|
|
414
|
+
default: EMPLOYMENT_STATUS_VALUES.ACTIVE.value,
|
|
415
|
+
label: "雇用状態",
|
|
416
|
+
component: {
|
|
417
|
+
name: generalDefinitions.select.component.name,
|
|
418
|
+
attrs: {
|
|
419
|
+
items: EMPLOYMENT_STATUS_OPTIONS,
|
|
420
|
+
},
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
gender: {
|
|
424
|
+
...generalDefinitions.select,
|
|
425
|
+
default: GENDER_DEFAULT,
|
|
426
|
+
label: "性別",
|
|
427
|
+
component: {
|
|
428
|
+
name: generalDefinitions.select.component.name,
|
|
429
|
+
attrs: {
|
|
430
|
+
items: GENDER_ARRAY,
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
prefCode: {
|
|
435
|
+
...generalDefinitions.select,
|
|
436
|
+
label: "都道府県",
|
|
437
|
+
length: 2,
|
|
438
|
+
component: {
|
|
439
|
+
name: generalDefinitions.select.component.name,
|
|
440
|
+
attrs: {
|
|
441
|
+
items: PREFECTURES_ARRAY,
|
|
442
|
+
},
|
|
443
|
+
},
|
|
444
|
+
},
|
|
445
|
+
shiftType: {
|
|
446
|
+
...generalDefinitions.select,
|
|
447
|
+
default: SHIFT_TYPE_DEFAULT,
|
|
448
|
+
label: "勤務区分",
|
|
449
|
+
component: {
|
|
450
|
+
name: generalDefinitions.select.component.name,
|
|
451
|
+
attrs: {
|
|
452
|
+
items: SHIFT_TYPE_ARRAY,
|
|
453
|
+
},
|
|
454
|
+
},
|
|
455
|
+
},
|
|
456
|
+
siteStatus: {
|
|
457
|
+
...generalDefinitions.select,
|
|
458
|
+
default: SITE_STATUS_VALUES.ACTIVE.value,
|
|
459
|
+
label: "状態",
|
|
460
|
+
component: {
|
|
461
|
+
name: generalDefinitions.select.component.name,
|
|
462
|
+
attrs: {
|
|
463
|
+
items: SITE_STATUS_OPTIONS,
|
|
464
|
+
},
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
|
|
468
|
+
/** time */
|
|
469
|
+
time: {
|
|
470
|
+
...generalDefinitions.time,
|
|
471
|
+
},
|
|
472
|
+
|
|
473
|
+
/** else */
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* FireModel を継承したカスタムクラスの classProps で使用するプロパティ定義です。
|
|
478
|
+
* - 定義されている各種プロパティは一部を除き、Vuetify(AirVuetify) の入力コンポーネントに引き渡される属性として使用されます。
|
|
479
|
+
* - `default`, `label`, `required` は `undefined` を許容します。
|
|
480
|
+
* - `undefined` の場合、当該属性が入力コンポーネントに引き渡されないことを意味します。
|
|
481
|
+
* - `component` プロパティは、`default`, `label`, `required` 以外に入力コンポーネントに引き渡す属性の定義です。
|
|
482
|
+
* - `name` プロパティは使用するコンポーネントの名前です。AirVuetify コンポーネントのみ指定可能です。
|
|
483
|
+
* - `attrs` プロパティにネストされた各プロパティがそのまま入力コンポーネントに引き渡されます。
|
|
484
|
+
*/
|
|
485
|
+
|
|
486
|
+
export const defField = (key, options = {}) => {
|
|
487
|
+
let baseConfigSource = fieldDefinitions[key];
|
|
488
|
+
let isFallback = false;
|
|
489
|
+
const effectiveDefaultDefinition = defaultDefinition;
|
|
490
|
+
|
|
491
|
+
if (!baseConfigSource) {
|
|
492
|
+
console.warn(
|
|
493
|
+
`[parts/fieldDefinitions.js defField] Definition for key "${key}" not found. Using fieldDefinitions.default as base.`
|
|
494
|
+
);
|
|
495
|
+
baseConfigSource = effectiveDefaultDefinition;
|
|
496
|
+
isFallback = true;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// ステップ1: defaultDefinition と baseConfigSource をマージして newConfig の基礎を作成
|
|
500
|
+
// これにより、baseConfigSource にないプロパティは defaultDefinition の値が使われる
|
|
501
|
+
const newConfig = { ...effectiveDefaultDefinition, ...baseConfigSource };
|
|
502
|
+
|
|
503
|
+
// ステップ2: component オブジェクトのディープコピー
|
|
504
|
+
// newConfig.component は baseConfigSource.component または defaultDefinition.component のいずれか (またはそのマージ結果)
|
|
505
|
+
// これを新しいオブジェクトとして確定させる
|
|
506
|
+
// まず、newConfig.component が存在するか確認し、なければ defaultDefinition.component を使う
|
|
507
|
+
const componentSourceForCopy =
|
|
508
|
+
newConfig.component || effectiveDefaultDefinition.component;
|
|
509
|
+
newConfig.component = { ...componentSourceForCopy }; // 新しい component オブジェクトを作成
|
|
510
|
+
|
|
511
|
+
// ステップ3: component.attrs オブジェクトのディープコピー
|
|
512
|
+
// newConfig.component.attrs も同様に新しいオブジェクトにする
|
|
513
|
+
const attrsSourceForCopy =
|
|
514
|
+
newConfig.component.attrs ||
|
|
515
|
+
(effectiveDefaultDefinition.component &&
|
|
516
|
+
effectiveDefaultDefinition.component.attrs);
|
|
517
|
+
newConfig.component.attrs = { ...attrsSourceForCopy }; // 新しい attrs オブジェクトを作成
|
|
518
|
+
|
|
519
|
+
// ステップ4: component.attrs.rules 配列のディープコピー
|
|
520
|
+
// rules が存在し、かつ配列であれば新しい配列としてコピーし、そうでなければ空配列で初期化
|
|
521
|
+
if (
|
|
522
|
+
newConfig.component.attrs.rules &&
|
|
523
|
+
Array.isArray(newConfig.component.attrs.rules)
|
|
524
|
+
) {
|
|
525
|
+
newConfig.component.attrs.rules = [...newConfig.component.attrs.rules];
|
|
526
|
+
} else {
|
|
527
|
+
// rules が存在しないか、配列でない場合は、defaultDefinition の rules を参照 (なければ空配列)
|
|
528
|
+
newConfig.component.attrs.rules =
|
|
529
|
+
effectiveDefaultDefinition.component &&
|
|
530
|
+
effectiveDefaultDefinition.component.attrs &&
|
|
531
|
+
Array.isArray(effectiveDefaultDefinition.component.attrs.rules)
|
|
532
|
+
? [...effectiveDefaultDefinition.component.attrs.rules] // defaultDefinition に rules があればコピー
|
|
533
|
+
: []; // それ以外は空配列
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// フォールバック時(keyが見つからなかった場合)で、かつoptionsでlabelが指定されていない場合、
|
|
537
|
+
// label に key の値を設定 (defaultDefinition.label は undefined のため)
|
|
538
|
+
if (isFallback && !options.hasOwnProperty("label")) {
|
|
539
|
+
newConfig.label = key;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// options のプロパティで newConfig を上書き
|
|
543
|
+
if (options.hasOwnProperty("type")) {
|
|
544
|
+
newConfig.type = options.type;
|
|
545
|
+
}
|
|
546
|
+
if (options.hasOwnProperty("label")) {
|
|
547
|
+
newConfig.label = options.label;
|
|
548
|
+
}
|
|
549
|
+
if (options.hasOwnProperty("default")) {
|
|
550
|
+
newConfig.default = options.default;
|
|
551
|
+
}
|
|
552
|
+
// `required` は options にあればその値、なければ newConfig の値 (baseConfig または defaultDefinition 由来) を維持
|
|
553
|
+
// defaultDefinition.required は undefined なので、指定がなければ undefined のままになる
|
|
554
|
+
if (options.hasOwnProperty("required")) {
|
|
555
|
+
newConfig.required = options.required;
|
|
556
|
+
}
|
|
557
|
+
// `hidden` は options にあればその値、なければ newConfig の値 (baseConfig または defaultDefinition 由来) を維持
|
|
558
|
+
// defaultDefinition.hidden は undefined なので、指定がなければ undefined のままになる
|
|
559
|
+
if (options.hasOwnProperty("hidden")) {
|
|
560
|
+
newConfig.hidden = options.hidden;
|
|
561
|
+
}
|
|
562
|
+
// customClass の処理: options に customClass があれば newConfig に設定
|
|
563
|
+
if (options.hasOwnProperty("customClass")) {
|
|
564
|
+
newConfig.customClass = options.customClass;
|
|
565
|
+
}
|
|
566
|
+
// options.colsDefinition があれば、それを newConfig.colsDefinition に設定
|
|
567
|
+
if (options.hasOwnProperty("colsDefinition")) {
|
|
568
|
+
newConfig.colsDefinition = options.colsDefinition;
|
|
569
|
+
}
|
|
570
|
+
// options.component オブジェクトの処理
|
|
571
|
+
if (typeof options.component === "object" && options.component !== null) {
|
|
572
|
+
// options.component.name があれば newConfig.component.name を上書き
|
|
573
|
+
if (options.component.hasOwnProperty("name")) {
|
|
574
|
+
newConfig.component.name = options.component.name;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// options.component.attrs がオブジェクトであれば、newConfig.component.attrs にマージ
|
|
578
|
+
if (
|
|
579
|
+
typeof options.component.attrs === "object" &&
|
|
580
|
+
options.component.attrs !== null
|
|
581
|
+
) {
|
|
582
|
+
newConfig.component.attrs = {
|
|
583
|
+
...newConfig.component.attrs,
|
|
584
|
+
...options.component.attrs,
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
// options.component.attrs が 'rules' を明示的に配列として提供する場合、
|
|
588
|
+
// それを newConfig.component.attrs.rules として設定(ディープコピー)
|
|
589
|
+
if (
|
|
590
|
+
options.component.attrs.hasOwnProperty("rules") &&
|
|
591
|
+
Array.isArray(options.component.attrs.rules)
|
|
592
|
+
) {
|
|
593
|
+
newConfig.component.attrs.rules = [...options.component.attrs.rules];
|
|
594
|
+
}
|
|
595
|
+
// 注意: options.component.attrs に rules がない、または配列でない場合、
|
|
596
|
+
// この時点での newConfig.component.attrs.rules (ベース定義由来またはステップ4で初期化されたもの) が維持され、
|
|
597
|
+
// 後続の options.length による上書きの対象となります。
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// component.attrs のプロパティの上書き
|
|
602
|
+
if (options.hasOwnProperty("counter")) {
|
|
603
|
+
newConfig.component.attrs.counter = options.counter;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// length の処理: options.length を優先し、なければ newConfig.length (baseConfigSource由来) を使用
|
|
607
|
+
let lengthToUseForRules;
|
|
608
|
+
|
|
609
|
+
if (options.hasOwnProperty("length")) {
|
|
610
|
+
// options.length が明示的に指定されていれば最優先
|
|
611
|
+
lengthToUseForRules = options.length;
|
|
612
|
+
} else if (
|
|
613
|
+
newConfig.hasOwnProperty("length") &&
|
|
614
|
+
newConfig.length !== undefined
|
|
615
|
+
) {
|
|
616
|
+
// options.length がなく、newConfig (baseConfigSource由来) に length があればそれを使用
|
|
617
|
+
lengthToUseForRules = newConfig.length;
|
|
618
|
+
}
|
|
619
|
+
// lengthToUseForRules が undefined のままなら、length に基づくルールは適用しない
|
|
620
|
+
|
|
621
|
+
if (lengthToUseForRules !== undefined) {
|
|
622
|
+
if (typeof lengthToUseForRules === "number" && lengthToUseForRules > 0) {
|
|
623
|
+
const lengthValidationRule = (v) =>
|
|
624
|
+
!v ||
|
|
625
|
+
v.length <= lengthToUseForRules ||
|
|
626
|
+
`${lengthToUseForRules}文字以内で入力してください。`;
|
|
627
|
+
|
|
628
|
+
if (Array.isArray(newConfig.component.attrs.rules)) {
|
|
629
|
+
// 既存のルール配列に新しい長さバリデーションルールを追加
|
|
630
|
+
newConfig.component.attrs.rules.push(lengthValidationRule);
|
|
631
|
+
} else {
|
|
632
|
+
// rules が配列でない(または存在しない)場合は、新しいルール配列を作成
|
|
633
|
+
newConfig.component.attrs.rules = [lengthValidationRule];
|
|
634
|
+
}
|
|
635
|
+
} else if (lengthToUseForRules === null || lengthToUseForRules === 0) {
|
|
636
|
+
// options.length が null または 0 の場合、ルールを意図的に空にする
|
|
637
|
+
newConfig.component.attrs.rules = [];
|
|
638
|
+
}
|
|
639
|
+
// それ以外の場合 (lengthValue が undefined や不正な値) は、既存のルール (コピーされたもの) を維持
|
|
640
|
+
}
|
|
641
|
+
return newConfig;
|
|
642
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* コンテキスト情報付きエラークラス
|
|
3
|
+
* 標準のErrorクラスを拡張し、エラー発生時の詳細情報を保持する
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export class ContextualError extends Error {
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} message - エラーメッセージ
|
|
9
|
+
* @param {Object} context - エラー発生時のコンテキスト情報
|
|
10
|
+
* @param {string} context.method - メソッド名
|
|
11
|
+
* @param {Object} context.arguments - 引数情報
|
|
12
|
+
* @param {string} context.className - クラス名
|
|
13
|
+
* @param {Object} context.error - 元のエラーオブジェクト
|
|
14
|
+
* @param {string} context.timestamp - タイムスタンプ
|
|
15
|
+
* @param {Object} context.state - オブジェクトの状態
|
|
16
|
+
*/
|
|
17
|
+
constructor(message, context = {}) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = "ContextualError";
|
|
20
|
+
this.context = {
|
|
21
|
+
timestamp: new Date().toISOString(),
|
|
22
|
+
...context,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
console.error(this.message, this.context);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* エラー情報を構造化された形式で取得
|
|
30
|
+
*/
|
|
31
|
+
getFormattedContext() {
|
|
32
|
+
return {
|
|
33
|
+
error: this.message,
|
|
34
|
+
name: this.name,
|
|
35
|
+
...this.context,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* デバッグ用の詳細な文字列表現
|
|
41
|
+
*/
|
|
42
|
+
toDetailedString() {
|
|
43
|
+
return `${this.name}: ${this.message}\nContext: ${JSON.stringify(
|
|
44
|
+
this.context,
|
|
45
|
+
null,
|
|
46
|
+
2
|
|
47
|
+
)}`;
|
|
48
|
+
}
|
|
49
|
+
}
|