@7365admin1/layer-common 3.0.6 → 3.0.7
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/CHANGELOG.md +6 -0
- package/components/BulletinBoardForm.vue +423 -333
- package/components/DashboardMain.vue +168 -74
- package/components/OnlineFormConfigurationForm.vue +2 -2
- package/components/OnlineFormFill.vue +193 -51
- package/components/VehicleManagement.vue +6 -2
- package/components/VisitorManagement.vue +1 -1
- package/composables/useDashboard.ts +25 -1
- package/composables/useOnlineForm.ts +25 -13
- package/composables/useOnlineFormPages.ts +2 -2
- package/package.json +1 -1
- package/types/dashboard.d.ts +1 -1
|
@@ -14,6 +14,21 @@
|
|
|
14
14
|
</v-row>
|
|
15
15
|
</v-toolbar>
|
|
16
16
|
|
|
17
|
+
<!-- Submission metadata bar (readonly only) -->
|
|
18
|
+
<div
|
|
19
|
+
v-if="readonly && (submissionStatus)"
|
|
20
|
+
class="px-6 py-2 d-flex align-center ga-4"
|
|
21
|
+
style="background: #f5f5f5; border-bottom: 1px solid #e0e0e0; flex-wrap: wrap"
|
|
22
|
+
>
|
|
23
|
+
<v-chip
|
|
24
|
+
v-if="submissionStatus"
|
|
25
|
+
:color="submissionStatusColor"
|
|
26
|
+
variant="flat"
|
|
27
|
+
size="x-small"
|
|
28
|
+
class="text-capitalize"
|
|
29
|
+
>{{ submissionStatus }}</v-chip>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
17
32
|
<!-- Scrollable body -->
|
|
18
33
|
<v-card-text
|
|
19
34
|
style="max-height: 76vh; overflow-y: auto"
|
|
@@ -31,12 +46,12 @@
|
|
|
31
46
|
<v-row no-gutters>
|
|
32
47
|
<v-col cols="5">
|
|
33
48
|
<span class="text-body-2">
|
|
34
|
-
<strong>Date : </strong>{{ todayDate }}
|
|
49
|
+
<strong>Date : </strong>{{ (initialValues as any).formDate || submissionDate || todayDate }}
|
|
35
50
|
</span>
|
|
36
51
|
</v-col>
|
|
37
52
|
<v-col cols="7">
|
|
38
53
|
<span class="text-body-2">
|
|
39
|
-
<strong>To : </strong>{{ resolveText(block.to) }}
|
|
54
|
+
<strong>To : </strong>{{ (initialValues as any).formTo || resolveText(block.to) }}
|
|
40
55
|
</span>
|
|
41
56
|
</v-col>
|
|
42
57
|
</v-row>
|
|
@@ -220,12 +235,28 @@
|
|
|
220
235
|
</div>
|
|
221
236
|
<div
|
|
222
237
|
v-else-if="block.type === 'signature-row' && readonly"
|
|
223
|
-
class="mt-
|
|
238
|
+
class="mt-3 mb-5"
|
|
224
239
|
>
|
|
240
|
+
<span class="text-caption text-medium-emphasis d-block mb-1">{{ block.label }}</span>
|
|
241
|
+
<div
|
|
242
|
+
v-if="initialValues[block.key]"
|
|
243
|
+
style="
|
|
244
|
+
display: inline-block;
|
|
245
|
+
border-radius: 8px;
|
|
246
|
+
background: #111111;
|
|
247
|
+
padding: 8px;
|
|
248
|
+
max-width: 100%;
|
|
249
|
+
"
|
|
250
|
+
>
|
|
251
|
+
<img
|
|
252
|
+
:src="initialValues[block.key]"
|
|
253
|
+
style="display: block; max-width: 100%; max-height: 130px; object-fit: contain;"
|
|
254
|
+
/>
|
|
255
|
+
</div>
|
|
225
256
|
<div
|
|
257
|
+
v-else
|
|
226
258
|
style="border-bottom: 1px dashed #bbb; height: 56px; background: #fafafa; border-radius: 4px"
|
|
227
259
|
/>
|
|
228
|
-
<span class="text-caption text-medium-emphasis">{{ block.label }}</span>
|
|
229
260
|
</div>
|
|
230
261
|
|
|
231
262
|
<!-- ACKNOWLEDGEMENT -->
|
|
@@ -237,27 +268,38 @@
|
|
|
237
268
|
<span class="text-body-2 font-weight-medium">{{ resolveText(block.text) }}</span>
|
|
238
269
|
</div>
|
|
239
270
|
|
|
240
|
-
<!-- MANAGEMENT USE
|
|
271
|
+
<!-- MANAGEMENT USE -->
|
|
241
272
|
<div
|
|
242
273
|
v-else-if="block.type === 'management-use'"
|
|
243
274
|
class="pa-4 mt-2"
|
|
244
|
-
style="
|
|
275
|
+
:style="approvalMode && selectedAction === 'approved'
|
|
276
|
+
? 'background: #e8f5e9; border-radius: 6px; border: 1px solid #a5d6a7'
|
|
277
|
+
: 'background: #f0f0f0; border-radius: 6px; opacity: 0.75'"
|
|
245
278
|
>
|
|
246
279
|
<v-row no-gutters class="mb-2">
|
|
247
280
|
<span class="text-caption font-weight-bold text-medium-emphasis">
|
|
248
281
|
FOR MANAGEMENT USE ONLY
|
|
249
282
|
</span>
|
|
250
283
|
</v-row>
|
|
251
|
-
<v-row no-gutters style="gap: 16px">
|
|
284
|
+
<v-row no-gutters style="gap: 16px; flex-wrap: wrap">
|
|
252
285
|
<div
|
|
253
286
|
v-for="(item, idx) in block.items"
|
|
254
287
|
:key="idx"
|
|
255
|
-
style="min-width: 160px"
|
|
288
|
+
style="min-width: 160px; flex: 1"
|
|
256
289
|
>
|
|
257
290
|
<div class="text-caption text-medium-emphasis mb-1">{{ item }}</div>
|
|
258
|
-
<
|
|
259
|
-
|
|
291
|
+
<v-text-field
|
|
292
|
+
v-if="approvalMode && selectedAction === 'approved'"
|
|
293
|
+
v-model="managementValues[item]"
|
|
294
|
+
density="compact"
|
|
295
|
+
variant="underlined"
|
|
296
|
+
:error="!(managementValues[item] ?? '').trim()"
|
|
297
|
+
:error-messages="!(managementValues[item] ?? '').trim() ? 'Required' : ''"
|
|
260
298
|
/>
|
|
299
|
+
<div
|
|
300
|
+
v-else
|
|
301
|
+
style="border-bottom: 1px solid #aaa; min-width: 120px; height: 22px; font-size: 13px; padding-top: 2px"
|
|
302
|
+
>{{ managementValues[item] || '' }}</div>
|
|
261
303
|
</div>
|
|
262
304
|
</v-row>
|
|
263
305
|
</div>
|
|
@@ -271,53 +313,70 @@
|
|
|
271
313
|
</v-form>
|
|
272
314
|
</v-card-text>
|
|
273
315
|
|
|
274
|
-
<!--
|
|
275
|
-
<
|
|
316
|
+
<!-- Approval action panel -->
|
|
317
|
+
<div
|
|
318
|
+
v-if="readonly && approvalMode"
|
|
319
|
+
style="border-top: 1px solid #e0e0e0; padding: 12px 16px; background: #fafafa; display: flex; flex-direction: column; gap: 10px"
|
|
320
|
+
>
|
|
321
|
+
<v-text-field
|
|
322
|
+
v-model="adminRemarks"
|
|
323
|
+
label="Remarks"
|
|
324
|
+
density="compact"
|
|
325
|
+
variant="outlined"
|
|
326
|
+
:hide-details="adminRemarks.trim().length > 0"
|
|
327
|
+
:error="remarksRequired && adminRemarks.trim().length === 0"
|
|
328
|
+
:error-messages="remarksRequired && adminRemarks.trim().length === 0 ? 'Remarks are required' : ''"
|
|
329
|
+
/>
|
|
330
|
+
<div class="d-flex align-center ga-2 justify-end">
|
|
331
|
+
<v-btn variant="text" class="text-none" size="small" @click="emit('cancel')">Close</v-btn>
|
|
332
|
+
<v-btn
|
|
333
|
+
:variant="selectedAction === 'resubmission' ? 'flat' : 'tonal'"
|
|
334
|
+
color="orange-darken-1"
|
|
335
|
+
class="text-none"
|
|
336
|
+
size="small"
|
|
337
|
+
@click="selectAction('resubmission')"
|
|
338
|
+
>Resubmit</v-btn>
|
|
339
|
+
<v-btn
|
|
340
|
+
:variant="selectedAction === 'rejected' ? 'flat' : 'tonal'"
|
|
341
|
+
color="red"
|
|
342
|
+
class="text-none"
|
|
343
|
+
size="small"
|
|
344
|
+
@click="selectAction('rejected')"
|
|
345
|
+
>Reject</v-btn>
|
|
346
|
+
<v-btn
|
|
347
|
+
:variant="selectedAction === 'approved' ? 'flat' : 'tonal'"
|
|
348
|
+
color="green"
|
|
349
|
+
class="text-none"
|
|
350
|
+
size="small"
|
|
351
|
+
@click="selectAction('approved')"
|
|
352
|
+
>Approve</v-btn>
|
|
353
|
+
<v-btn
|
|
354
|
+
v-if="selectedAction"
|
|
355
|
+
variant="flat"
|
|
356
|
+
color="grey-darken-3"
|
|
357
|
+
class="text-none"
|
|
358
|
+
size="small"
|
|
359
|
+
:disabled="!canConfirm"
|
|
360
|
+
:loading="updatingStatus"
|
|
361
|
+
@click="confirmStatusUpdate"
|
|
362
|
+
>Confirm</v-btn>
|
|
363
|
+
</div>
|
|
364
|
+
</div>
|
|
365
|
+
|
|
366
|
+
<!-- Normal action bar -->
|
|
367
|
+
<v-toolbar v-else density="compact">
|
|
276
368
|
<v-row no-gutters>
|
|
277
|
-
<!-- Readonly: single Close button -->
|
|
278
369
|
<template v-if="readonly">
|
|
279
370
|
<v-col cols="12">
|
|
280
|
-
<v-btn
|
|
281
|
-
tile
|
|
282
|
-
block
|
|
283
|
-
variant="text"
|
|
284
|
-
class="text-none"
|
|
285
|
-
size="48"
|
|
286
|
-
@click="emit('cancel')"
|
|
287
|
-
>
|
|
288
|
-
Close
|
|
289
|
-
</v-btn>
|
|
371
|
+
<v-btn tile block variant="text" class="text-none" size="48" @click="emit('cancel')">Close</v-btn>
|
|
290
372
|
</v-col>
|
|
291
373
|
</template>
|
|
292
|
-
<!-- Interactive: Cancel + Submit -->
|
|
293
374
|
<template v-else>
|
|
294
375
|
<v-col cols="6">
|
|
295
|
-
<v-btn
|
|
296
|
-
tile
|
|
297
|
-
block
|
|
298
|
-
variant="text"
|
|
299
|
-
class="text-none"
|
|
300
|
-
size="48"
|
|
301
|
-
:disabled="submitting"
|
|
302
|
-
@click="emit('cancel')"
|
|
303
|
-
>
|
|
304
|
-
Cancel
|
|
305
|
-
</v-btn>
|
|
376
|
+
<v-btn tile block variant="text" class="text-none" size="48" :disabled="submitting" @click="emit('cancel')">Cancel</v-btn>
|
|
306
377
|
</v-col>
|
|
307
378
|
<v-col cols="6">
|
|
308
|
-
<v-btn
|
|
309
|
-
tile
|
|
310
|
-
block
|
|
311
|
-
variant="flat"
|
|
312
|
-
color="black"
|
|
313
|
-
class="text-none"
|
|
314
|
-
size="48"
|
|
315
|
-
:disabled="!validForm || submitting"
|
|
316
|
-
:loading="submitting"
|
|
317
|
-
@click="submit"
|
|
318
|
-
>
|
|
319
|
-
Submit
|
|
320
|
-
</v-btn>
|
|
379
|
+
<v-btn tile block variant="flat" color="black" class="text-none" size="48" :disabled="!validForm || submitting" :loading="submitting" @click="submit">Submit</v-btn>
|
|
321
380
|
</v-col>
|
|
322
381
|
</template>
|
|
323
382
|
</v-row>
|
|
@@ -339,6 +398,12 @@ const props = defineProps({
|
|
|
339
398
|
orgId: { type: String, required: true },
|
|
340
399
|
siteName: { type: String, default: "" },
|
|
341
400
|
readonly: { type: Boolean, default: false },
|
|
401
|
+
initialValues: { type: Object as PropType<Record<string, any>>, default: () => ({}) },
|
|
402
|
+
submissionDate: { type: String, default: "" },
|
|
403
|
+
submissionStatus: { type: String, default: "" },
|
|
404
|
+
submissionUnit: { type: String, default: "" },
|
|
405
|
+
approvalMode: { type: Boolean, default: false },
|
|
406
|
+
initialManagementValues: { type: Object as PropType<Record<string, string>>, default: () => ({}) },
|
|
342
407
|
/** Optional custom submit handler. Receives the collected form values.
|
|
343
408
|
* If omitted the component submits to /api/online-forms automatically. */
|
|
344
409
|
submitFn: {
|
|
@@ -347,7 +412,7 @@ const props = defineProps({
|
|
|
347
412
|
},
|
|
348
413
|
});
|
|
349
414
|
|
|
350
|
-
const emit = defineEmits(["cancel", "success"]);
|
|
415
|
+
const emit = defineEmits(["cancel", "success", "update-status"]);
|
|
351
416
|
|
|
352
417
|
function resolveText(text: string): string {
|
|
353
418
|
return text.replace(/\{siteName\}/g, props.siteName || "the Management");
|
|
@@ -361,8 +426,85 @@ const submitting = ref(false);
|
|
|
361
426
|
const message = ref("");
|
|
362
427
|
const values = ref<Record<string, any>>({});
|
|
363
428
|
|
|
429
|
+
const selectedAction = ref("");
|
|
430
|
+
const adminRemarks = ref("");
|
|
431
|
+
const updatingStatus = ref(false);
|
|
432
|
+
const managementValues = ref<Record<string, string>>({});
|
|
433
|
+
|
|
434
|
+
const managementUseItems = computed<string[]>(() => {
|
|
435
|
+
const result: string[] = [];
|
|
436
|
+
for (const block of props.definition.blocks) {
|
|
437
|
+
if (block.type === "management-use") result.push(...block.items);
|
|
438
|
+
}
|
|
439
|
+
return result;
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
// Load previously saved management values (saved keys have colons stripped; remap to match item labels)
|
|
443
|
+
watch(() => props.initialManagementValues, (saved) => {
|
|
444
|
+
if (!saved || !Object.keys(saved).length) return;
|
|
445
|
+
const loaded: Record<string, string> = {};
|
|
446
|
+
for (const item of managementUseItems.value) {
|
|
447
|
+
const stripped = item.replace(/:+\s*$/, "").trim();
|
|
448
|
+
const value = saved[stripped] ?? saved[item] ?? "";
|
|
449
|
+
if (value) loaded[item] = value;
|
|
450
|
+
}
|
|
451
|
+
managementValues.value = { ...loaded, ...managementValues.value };
|
|
452
|
+
}, { immediate: true });
|
|
453
|
+
|
|
454
|
+
const remarksRequired = computed(() => !!selectedAction.value);
|
|
455
|
+
|
|
456
|
+
const managementComplete = computed(() => {
|
|
457
|
+
if (selectedAction.value !== "approved") return true;
|
|
458
|
+
return managementUseItems.value.every(item => (managementValues.value[item] ?? "").trim().length > 0);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
const canConfirm = computed(() =>
|
|
462
|
+
!!selectedAction.value &&
|
|
463
|
+
adminRemarks.value.trim().length > 0 &&
|
|
464
|
+
managementComplete.value
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
function prePopulateManagement() {
|
|
468
|
+
const today = new Date().toLocaleDateString("en-SG", { day: "2-digit", month: "short", year: "numeric" });
|
|
469
|
+
const userName = currentUser.value?.name ?? "";
|
|
470
|
+
for (const item of managementUseItems.value) {
|
|
471
|
+
if (managementValues.value[item]) continue;
|
|
472
|
+
const lower = item.toLowerCase();
|
|
473
|
+
if (lower.includes("by:") || lower.endsWith(" by")) {
|
|
474
|
+
managementValues.value[item] = userName;
|
|
475
|
+
} else if (lower.includes("date")) {
|
|
476
|
+
managementValues.value[item] = today;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function selectAction(action: string) {
|
|
482
|
+
selectedAction.value = selectedAction.value === action ? "" : action;
|
|
483
|
+
if (selectedAction.value === "approved") prePopulateManagement();
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function confirmStatusUpdate() {
|
|
487
|
+
if (!canConfirm.value) return;
|
|
488
|
+
updatingStatus.value = true;
|
|
489
|
+
emit("update-status", {
|
|
490
|
+
status: selectedAction.value,
|
|
491
|
+
remarks: adminRemarks.value,
|
|
492
|
+
managementValues: managementValues.value,
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
|
|
364
496
|
const requiredRule = (v: any) => (v !== null && v !== undefined && v !== "") || "This field is required";
|
|
365
497
|
|
|
498
|
+
const submissionStatusColor = computed(() => {
|
|
499
|
+
switch (props.submissionStatus?.toLowerCase()) {
|
|
500
|
+
case "approved": return "green";
|
|
501
|
+
case "pending": return "orange";
|
|
502
|
+
case "resubmission": return "orange";
|
|
503
|
+
case "rejected": return "red";
|
|
504
|
+
default: return "grey";
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
|
|
366
508
|
// Today's date formatted DD MMM YYYY
|
|
367
509
|
const todayDate = computed(() => {
|
|
368
510
|
const d = new Date();
|
|
@@ -390,7 +532,7 @@ function initValues(def: FormDefinition) {
|
|
|
390
532
|
return init;
|
|
391
533
|
}
|
|
392
534
|
|
|
393
|
-
values.value = initValues(props.definition);
|
|
535
|
+
values.value = { ...initValues(props.definition), ...props.initialValues };
|
|
394
536
|
|
|
395
537
|
const NAME_LABELS = new Set([
|
|
396
538
|
"name",
|
|
@@ -421,7 +563,7 @@ function prePopulate(u: any) {
|
|
|
421
563
|
}
|
|
422
564
|
}
|
|
423
565
|
|
|
424
|
-
watch(currentUser, (u) => { if (u) prePopulate(u); }, { immediate: true });
|
|
566
|
+
watch(currentUser, (u) => { if (u && !props.readonly) prePopulate(u); }, { immediate: true });
|
|
425
567
|
|
|
426
568
|
async function submit() {
|
|
427
569
|
submitting.value = true;
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
{{ value ? `Blk ${value}` : "" }}
|
|
19
19
|
</template>
|
|
20
20
|
<template #item.nric="{ value }">
|
|
21
|
-
|
|
21
|
+
<span v-if="value" v-tooltip:top="value">{{ maskNRIC(value) }}</span>
|
|
22
|
+
<span v-else>{{ maskNRIC(value) }}</span>
|
|
22
23
|
</template>
|
|
23
24
|
|
|
24
25
|
<template #item.plates="{ value, item }">
|
|
@@ -59,7 +60,10 @@
|
|
|
59
60
|
<template v-for="(label, key) in formattedFields" :key="key">
|
|
60
61
|
|
|
61
62
|
<v-col v-if="key === 'nric' && selectedVehicleObject['nric']" cols="12">
|
|
62
|
-
<span class="d-flex ga-3 align-center"
|
|
63
|
+
<span class="d-flex ga-3 align-center">
|
|
64
|
+
<strong>{{ label }}:</strong>
|
|
65
|
+
<span v-tooltip:top="selectedVehicleObject[key]">{{ maskNRIC(selectedVehicleObject[key]) }}</span>
|
|
66
|
+
</span>
|
|
63
67
|
</v-col>
|
|
64
68
|
|
|
65
69
|
<v-col v-else-if="key === 'plates'" class="d-flex flex-column ga-2">
|
|
@@ -343,7 +343,7 @@
|
|
|
343
343
|
<span v-else-if="
|
|
344
344
|
key === 'nric' && selectedVisitorObject['nric']" class="d-flex align-center">
|
|
345
345
|
<strong>{{ label }}:</strong>
|
|
346
|
-
<span class="ml-2">{{ maskNRIC(selectedVisitorObject[key]) }}</span>
|
|
346
|
+
<span v-tooltip:top="selectedVisitorObject[key]" class="ml-2">{{ maskNRIC(selectedVisitorObject[key]) }}</span>
|
|
347
347
|
</span>
|
|
348
348
|
<span v-else-if="key === 'attachments' && selectedVisitorObject?.[key]?.length > 0"
|
|
349
349
|
class="d-flex flex-column">
|
|
@@ -17,12 +17,16 @@ export default function () {
|
|
|
17
17
|
|
|
18
18
|
function getDashboardHygieneWeeklyActivity(
|
|
19
19
|
site = "",
|
|
20
|
-
serviceType: TServiceType = "cleaning_services"
|
|
20
|
+
serviceType: TServiceType = "cleaning_services",
|
|
21
|
+
period?: TDashboardValues
|
|
21
22
|
) {
|
|
22
23
|
return useNuxtApp().$api<THygieneWeeklyActivityItem[]>(
|
|
23
24
|
`/api/dashboard/serviceType/${serviceType}/site/${site}/weekly-activity`,
|
|
24
25
|
{
|
|
25
26
|
method: "GET",
|
|
27
|
+
query: {
|
|
28
|
+
period,
|
|
29
|
+
},
|
|
26
30
|
}
|
|
27
31
|
);
|
|
28
32
|
}
|
|
@@ -80,11 +84,31 @@ export default function () {
|
|
|
80
84
|
);
|
|
81
85
|
}
|
|
82
86
|
|
|
87
|
+
function getDashboardPropertyManagement(
|
|
88
|
+
site = "",
|
|
89
|
+
period: TDashboardValues = "today",
|
|
90
|
+
type = "",
|
|
91
|
+
facility = ""
|
|
92
|
+
) {
|
|
93
|
+
return useNuxtApp().$api<Record<string, any>>(
|
|
94
|
+
`/api/dashboard/serviceType/property_management_agency/site/${site}`,
|
|
95
|
+
{
|
|
96
|
+
method: "GET",
|
|
97
|
+
query: {
|
|
98
|
+
period,
|
|
99
|
+
...(type ? { type } : {}),
|
|
100
|
+
...(facility ? { facility } : {}),
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
83
106
|
return {
|
|
84
107
|
getDashboardHygiene,
|
|
85
108
|
getDashboardHygieneWeeklyActivity,
|
|
86
109
|
getDashboardHygieneTaskSchedule,
|
|
87
110
|
getDashboardHygieneAttendance,
|
|
88
111
|
getDashboardHygieneFeedbacks,
|
|
112
|
+
getDashboardPropertyManagement,
|
|
89
113
|
};
|
|
90
114
|
}
|
|
@@ -46,22 +46,32 @@ export default function useOnlineForm() {
|
|
|
46
46
|
query: { id },
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
|
+
function getFormEntryById(id: string) {
|
|
50
|
+
return useNuxtApp().$api<Record<string, any>>(`/api/form-entries/id/${id}`, {
|
|
51
|
+
method: "GET",
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function updateFormEntryById(id: string, value: any) {
|
|
55
|
+
return useNuxtApp().$api<Record<string, any>>(`/api/form-entries/id/${id}`, {
|
|
56
|
+
method: "PUT",
|
|
57
|
+
body: value,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
49
60
|
function getAllBySiteId(
|
|
50
61
|
siteId: string,
|
|
51
|
-
{ page = 1, search = "", limit = 10, status = "
|
|
62
|
+
{ page = 1, search = "", limit = 10, status = "", org = "" } = {}
|
|
52
63
|
) {
|
|
53
|
-
return useNuxtApp().$api<Record<string, any>>(
|
|
54
|
-
|
|
55
|
-
{
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
);
|
|
64
|
+
return useNuxtApp().$api<Record<string, any>>(`/api/form-entries`, {
|
|
65
|
+
method: "GET",
|
|
66
|
+
query: {
|
|
67
|
+
page,
|
|
68
|
+
search,
|
|
69
|
+
limit,
|
|
70
|
+
status,
|
|
71
|
+
org,
|
|
72
|
+
site: siteId,
|
|
73
|
+
},
|
|
74
|
+
});
|
|
65
75
|
}
|
|
66
76
|
return {
|
|
67
77
|
getAll,
|
|
@@ -70,5 +80,7 @@ export default function useOnlineForm() {
|
|
|
70
80
|
updateOnlineFormById,
|
|
71
81
|
deleteOnlineFormById,
|
|
72
82
|
getAllBySiteId,
|
|
83
|
+
getFormEntryById,
|
|
84
|
+
updateFormEntryById,
|
|
73
85
|
};
|
|
74
86
|
}
|
|
@@ -17,7 +17,7 @@ export type FormBlock =
|
|
|
17
17
|
| { type: "address"; to: string }
|
|
18
18
|
| { type: "row"; fields: FormFieldDef[] }
|
|
19
19
|
| { type: "field"; field: FormFieldDef }
|
|
20
|
-
| { type: "checkbox-group"; title?: string; items: CheckboxItemDef[] }
|
|
20
|
+
| { type: "checkbox-group"; title?: string; single?: boolean; items: CheckboxItemDef[] }
|
|
21
21
|
| { type: "paragraph"; text: string }
|
|
22
22
|
| { type: "section-header"; text: string }
|
|
23
23
|
| { type: "divider" }
|
|
@@ -506,7 +506,7 @@ const formPages: Record<string, FormDefinition> = {
|
|
|
506
506
|
},
|
|
507
507
|
|
|
508
508
|
"Application for Booking of Rooftop Bar/Dining": {
|
|
509
|
-
title: "APPLICATION FOR BOOKING OF ROOFTOP BAR/
|
|
509
|
+
title: "APPLICATION FOR BOOKING OF ROOFTOP BAR/DINING",
|
|
510
510
|
blocks: [
|
|
511
511
|
{ type: "address", to: "{siteName}" },
|
|
512
512
|
{ type: "row", fields: [
|
package/package.json
CHANGED
package/types/dashboard.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ declare type TDashboardMetric = {
|
|
|
30
30
|
outOfStock?: number;
|
|
31
31
|
completed?: number;
|
|
32
32
|
total?: number;
|
|
33
|
+
items?: { name: string; qty: number }[];
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
declare type THygieneDashboardData = {
|
|
@@ -74,4 +75,3 @@ declare type THygienePaginatedResponse<T> = {
|
|
|
74
75
|
pages: number;
|
|
75
76
|
pageRange: string;
|
|
76
77
|
};
|
|
77
|
-
|