@7365admin1/layer-common 3.2.7 → 3.2.8-staging.201
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/assets/css/primitives.css +1113 -0
- package/assets/css/screens.css +1097 -0
- package/assets/css/shell.css +258 -0
- package/assets/css/tokens.css +236 -0
- package/components/AcceptDialog.vue +17 -18
- package/components/AccessCard/AvailableStats.vue +24 -16
- package/components/AccessCardAddForm.vue +42 -42
- package/components/AccessCardAssignToUnitForm.vue +13 -21
- package/components/AccessCardDeleteDialog.vue +41 -39
- package/components/AccessCardDetailsDialog.vue +125 -79
- package/components/AccessCardPreviewDialog.vue +58 -84
- package/components/AccessCardQrTagging.vue +60 -63
- package/components/AccessCardReplaceForm.vue +27 -23
- package/components/AccessManagement.vue +86 -85
- package/components/AddEqupmentForm.vue +18 -22
- package/components/AddPassKeyToVisitor.vue +95 -73
- package/components/AppButton.vue +62 -0
- package/components/AppCard.vue +20 -0
- package/components/AppDateField.vue +49 -0
- package/components/AppField.vue +76 -0
- package/components/AppKpiTile.vue +65 -0
- package/components/AppSegmented.vue +38 -0
- package/components/AppSelect.vue +247 -0
- package/components/AreaChecklistHistoryLogs.vue +51 -44
- package/components/AreaChecklistHistoryMain.vue +14 -7
- package/components/AreaFormDialog.vue +71 -59
- package/components/AreaMain.vue +73 -107
- package/components/AttachmentsViewer.vue +84 -22
- package/components/AttendanceCheckInOutDialog.vue +85 -88
- package/components/AttendanceDetailsDialog.vue +57 -63
- package/components/AttendanceMain.vue +4 -3
- package/components/AttendanceMapSearchDialog.vue +42 -44
- package/components/AttendanceSettingsDialog.vue +79 -63
- package/components/Avatar/Main.vue +54 -2
- package/components/BillingMain.vue +26 -30
- package/components/BtnUploadFile.vue +53 -11
- package/components/BuildingForm.vue +34 -27
- package/components/BuildingManagement/buildings.vue +39 -39
- package/components/BuildingManagement/units.vue +26 -42
- package/components/BuildingUnitFormAdd.vue +20 -23
- package/components/BuildingUnitFormEdit.vue +8 -4
- package/components/BulletinBoardForm.vue +19 -24
- package/components/BulletinBoardManagement.vue +49 -57
- package/components/BulletinBoardView.vue +9 -6
- package/components/BulletinExpirationChip.vue +13 -4
- package/components/Button/Close.vue +2 -2
- package/components/CameraForm.vue +21 -22
- package/components/CameraMain.vue +50 -49
- package/components/Card/DeleteConfirmation.vue +24 -22
- package/components/Card/MemberInfoSummary.vue +28 -3
- package/components/Card/Toggle.vue +15 -3
- package/components/CardToolbar.vue +37 -0
- package/components/Carousel.vue +56 -36
- package/components/Chat/Bubbles.vue +43 -14
- package/components/Chat/Information.vue +49 -32
- package/components/Chat/ListCard.vue +38 -9
- package/components/Chat/Message.vue +41 -15
- package/components/Chat/Navigation.vue +27 -15
- package/components/Chat/SkeletonLoader.vue +9 -2
- package/components/ChecklistItemRow.vue +25 -1
- package/components/CleaningScheduleMain.vue +44 -49
- package/components/ClientDetailForm.vue +81 -56
- package/components/ClientMain.vue +92 -82
- package/components/ConfirmDialog.vue +14 -8
- package/components/Container/Standard.vue +9 -7
- package/components/CreateSubsciptionPlan.vue +148 -89
- package/components/DashboardEmptyState.vue +48 -3
- package/components/DashboardMain.vue +924 -676
- package/components/DashboardPanel.vue +84 -21
- package/components/DeliveryCompany.vue +34 -20
- package/components/Dialog/DeleteConfirmation.vue +20 -21
- package/components/Dialog/ReplaceAutofillPrompt.vue +19 -26
- package/components/Dialog/ReusablePrompt.vue +30 -29
- package/components/Dialog/UpdateMoreAction.vue +62 -59
- package/components/DocumentForm.vue +14 -21
- package/components/DocumentManagement.vue +162 -108
- package/components/DocumentViewer.vue +29 -12
- package/components/DrawImage.vue +29 -21
- package/components/EntryPass/QrTemplatePreview.vue +27 -16
- package/components/EntryPassInformation.vue +40 -10
- package/components/EntryPassMain.vue +49 -27
- package/components/EquipmentItemMain.vue +84 -97
- package/components/EquipmentManagementMain.vue +81 -103
- package/components/Facility/BookingSetup.vue +43 -52
- package/components/Feedback/Form.vue +26 -12
- package/components/FeedbackMain.vue +35 -49
- package/components/FileInput.vue +75 -58
- package/components/FileInputWithList.vue +59 -12
- package/components/FormDialog.vue +60 -21
- package/components/HidAccessLogDashboard.vue +512 -490
- package/components/HidCameraCaptureDialog.vue +216 -0
- package/components/HidEnabledGate.vue +67 -9
- package/components/HidIntercomManagement.vue +1322 -653
- package/components/HidQrCodeConfiguration.vue +1030 -258
- package/components/HidReaderForm.vue +142 -59
- package/components/HidReaderManagement.vue +211 -323
- package/components/HidServiceSettingsPanel.vue +44 -13
- package/components/HidUserEnrollment.vue +1185 -412
- package/components/HygieneUpdateMoreAction.vue +44 -44
- package/components/IncidentReport/Authorities.vue +30 -18
- package/components/IncidentReport/IncidentInformation.vue +10 -10
- package/components/IncidentReport/IncidentInformationDownload.vue +3 -4
- package/components/IncidentReport/affectedEntities.vue +41 -20
- package/components/Input/Date.vue +3 -0
- package/components/Input/DatePicker.vue +1 -2
- package/components/Input/DateTimePicker.vue +1 -1
- package/components/Input/File.vue +55 -10
- package/components/Input/FileV2.vue +39 -6
- package/components/Input/InputPhoneNumberV2.vue +2 -1
- package/components/Input/ListGroupSelection.vue +56 -8
- package/components/Input/NRICNumber.vue +1 -0
- package/components/Input/NewDate.vue +1 -0
- package/components/Input/Number.vue +1 -0
- package/components/Input/Password.vue +1 -0
- package/components/Input/PhoneNumber.vue +21 -1
- package/components/Input/VehicleNumber.vue +1 -0
- package/components/InputLabel.vue +2 -2
- package/components/InvitationClientForm.vue +21 -19
- package/components/InvitationForm.vue +15 -21
- package/components/InvitationMain.vue +46 -61
- package/components/Layout/Header.vue +263 -36
- package/components/Layout/NavigationDrawer.vue +300 -30
- package/components/ListItem.vue +33 -3
- package/components/LocalPagination.vue +27 -3
- package/components/ManageChecklistMain.vue +136 -86
- package/components/MemberInformation.vue +32 -16
- package/components/MemberMain.vue +113 -93
- package/components/MyAttendanceMain.vue +3 -5
- package/components/NavigationItem.vue +83 -3
- package/components/Nfc/NFCPatrolReportMain.vue +47 -33
- package/components/Nfc/NFCPatrolRouteForm.vue +18 -20
- package/components/Nfc/NFCPatrolRouteMain.vue +116 -103
- package/components/Nfc/NFCPatrolSettings.vue +14 -4
- package/components/Nfc/NFCTagForm.vue +22 -8
- package/components/Nfc/NFCTagMain.vue +41 -43
- package/components/Nfc/PatrolReport/DailyReportTab.vue +8 -1
- package/components/Nfc/PatrolReport/MonthlyReportTab.vue +8 -1
- package/components/Nfc/PatrolReport/MonthlyReportTable.vue +5 -3
- package/components/Nfc/PatrolReport/PatrolActivityTable.vue +26 -6
- package/components/Nfc/PatrolReport/PatrolReportTab.vue +8 -0
- package/components/Nfc/PatrolReport/PatrolRouteSummary.vue +41 -9
- package/components/Nfc/PatrolReport/RemarksDialog.vue +39 -9
- package/components/Nfc/PatrolReport/ReportEmptyState.vue +29 -9
- package/components/Nfc/PatrolReport/ReportFilters.vue +19 -10
- package/components/Nfc/PatrolReport/ReportLocationHeader.vue +32 -6
- package/components/Nfc/PatrolReport/SummaryReportTable.vue +28 -6
- package/components/NotificationSettings.vue +373 -0
- package/components/NumberSettingField.vue +9 -2
- package/components/OnlineFormConfigurationForm.vue +725 -237
- package/components/OnlineFormFill.vue +213 -106
- package/components/OnlineFormRenderPreview.vue +25 -30
- package/components/OnlineFormsConfiguration.vue +113 -109
- package/components/OrgViewDialog.vue +34 -16
- package/components/OvernightParkingAvailability.vue +49 -26
- package/components/OvernightParkingManagement.vue +78 -18
- package/components/PageHeader.vue +43 -0
- package/components/PassInformation.vue +109 -53
- package/components/PasswordConfirmation.vue +44 -26
- package/components/PeopleForm.vue +41 -20
- package/components/PhotoUpload.vue +110 -48
- package/components/PlaceholderComponent.vue +35 -19
- package/components/PlanActionsMenu.vue +12 -2
- package/components/PlanStatusBadge.vue +7 -8
- package/components/PlateNumberDisplay.vue +9 -6
- package/components/QrTemplate/PrintDialog.vue +66 -43
- package/components/RolePermissionFormCreate.vue +104 -79
- package/components/RolePermissionFormPreviewUpdate.vue +111 -109
- package/components/RolePermissionMain.vue +183 -81
- package/components/ScanVisitorQRCode.vue +99 -35
- package/components/ScheduleAreaMain.vue +34 -59
- package/components/ScheduleTaskForm.vue +61 -42
- package/components/ScheduleTaskMain.vue +56 -69
- package/components/SearchVehicleNumberUser.vue +39 -37
- package/components/ServiceProviderFormCreate.vue +29 -20
- package/components/ServiceProviderInvitationPrompt.vue +155 -0
- package/components/ServiceProviderMain.vue +601 -432
- package/components/Signature.vue +40 -34
- package/components/SignaturePad.vue +5 -29
- package/components/SiteSettings.vue +41 -11
- package/components/SiteSettingsWorkOrder.vue +61 -30
- package/components/SlideCardGroup.vue +35 -11
- package/components/Snackbar.vue +36 -3
- package/components/SpecificAttr.vue +18 -8
- package/components/StatusChip.vue +156 -0
- package/components/StockCard.vue +17 -12
- package/components/SubscriptionPlanTable.vue +207 -140
- package/components/SwitchContext.vue +201 -9
- package/components/TableHygiene.vue +36 -46
- package/components/TableList.vue +10 -10
- package/components/TableListSecondary.vue +105 -54
- package/components/TableMain.vue +251 -78
- package/components/TableV3.vue +61 -70
- package/components/TiptapEditor.vue +33 -40
- package/components/TiptapEditorQr.vue +5 -2
- package/components/Tooltip/Info.vue +69 -24
- package/components/UnitMain.vue +40 -60
- package/components/UnitPersonCard.vue +42 -13
- package/components/VehicleAddSelection.vue +48 -32
- package/components/VehicleForm.vue +112 -129
- package/components/VehicleManagement.vue +26 -12
- package/components/VehicleUpdateMoreAction.vue +59 -46
- package/components/VisitorDataFromScannedQRCodeForm.vue +90 -65
- package/components/VisitorForm.vue +774 -210
- package/components/VisitorFormSelection.vue +40 -37
- package/components/VisitorManagement.vue +239 -82
- package/components/VisitorPassKeyQRScanner.vue +65 -18
- package/components/VisitorSearchResultSummary.vue +60 -16
- package/components/VisitorSocketPopUp.vue +22 -14
- package/components/VisitorsReportPreview.vue +44 -29
- package/components/WorkOrder/Create.vue +26 -17
- package/components/WorkOrder/ListView.vue +38 -7
- package/components/WorkOrder/Main.vue +62 -59
- package/composables/useFeedback.ts +3 -3
- package/composables/useHidAmico.ts +269 -0
- package/composables/useHidNavigation.ts +2 -9
- package/composables/useMember.ts +3 -3
- package/composables/useNFCPatrolDailyReport.ts +13 -0
- package/composables/useNFCPatrolMonthlyReport.ts +22 -56
- package/composables/useNFCPatrolReport.ts +13 -0
- package/composables/useNotificationPreference.ts +87 -0
- package/composables/useOnlineFormPages.ts +2 -0
- package/composables/useRole.ts +22 -0
- package/composables/useServiceProvider.ts +3 -3
- package/composables/useServiceProviderInvitation.ts +145 -0
- package/composables/useSipWebPhone.ts +336 -0
- package/composables/useSubscriptionPlan.ts +62 -0
- package/composables/useThemePreference.ts +63 -0
- package/composables/useVisitor.ts +6 -1
- package/composables/useWebUsb.ts +127 -37
- package/composables/useWorkOrder.ts +17 -3
- package/error.vue +30 -6
- package/nuxt.config.ts +36 -0
- package/package.json +25 -4
- package/pages/[org]/[site]/access-mgmt/administrator/index.vue +2 -2
- package/pages/[org]/[site]/access-mgmt/{identity-mapping → hid-cards}/index.vue +2 -2
- package/pages/[org]/[site]/access-mgmt/intercom/index.vue +1 -1
- package/pages/notification-settings.vue +19 -0
- package/pages/payment-method-linked.vue +34 -10
- package/pages/require-customer.vue +48 -10
- package/pages/require-organization-membership.vue +32 -8
- package/pages/unauthorized.vue +29 -4
- package/plugins/secure-member.client.ts +21 -56
- package/plugins/vuetify.ts +69 -2
- package/types/nfc-patrol-report.ts +3 -2
- package/types/site.d.ts +71 -0
- package/types/subscription.ts +18 -11
- package/utils/breadcrumb.test.ts +108 -0
- package/utils/breadcrumb.ts +82 -0
- package/utils/dashboard.test.ts +118 -0
- package/utils/dashboard.ts +53 -0
- package/utils/data.test.ts +95 -0
- package/utils/data.ts +40 -2
- package/utils/hid-discover.test.ts +102 -0
- package/utils/list-page.test.ts +60 -0
- package/utils/list-page.ts +38 -0
- package/utils/materialSymbols.ts +363 -0
- package/utils/nav-sections.test.ts +190 -0
- package/utils/nav-sections.ts +151 -0
- package/utils/nfc-patrol-report.test.ts +130 -0
- package/utils/nfc-patrol-report.ts +101 -0
- package/utils/role.test.ts +69 -0
- package/utils/role.ts +10 -0
- package/utils/route-name.test.ts +85 -0
- package/utils/route-name.ts +24 -0
- package/utils/status.test.ts +110 -0
- package/utils/status.ts +135 -0
- package/utils/table-card.test.ts +84 -0
- package/utils/theme-aa-ledger.ts +148 -0
- package/utils/theme.test.ts +485 -7
- package/utils/theme.ts +295 -110
- package/.changeset/README.md +0 -8
- package/.changeset/config.json +0 -11
- package/.editorconfig +0 -12
- package/.github/workflows/main.yml +0 -17
- package/.github/workflows/publish-staging.yml +0 -47
- package/.github/workflows/publish.yml +0 -39
- package/PUBLISHING.md +0 -269
- package/components/HidIdentityMapping.vue +0 -975
- package/components/ScheduleTaskAreaFormDialog.vue +0 -144
- package/components/ScheduleTaskAreaUpdateMoreAction.vue +0 -109
- package/components/ScheduleTastTicketMain.vue +0 -182
- package/components/TableWithButton.vue +0 -94
- package/test/visitor-socket.test.mjs +0 -36
|
@@ -1,27 +1,48 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The summary a visitor search draws under its result. Every one of the four
|
|
3
|
+
cells was `text-subtitle-1` - Vuetify's 16px/400 Roboto - so the LABEL that
|
|
4
|
+
names a value ("Name:", "NRIC:") was drawn at exactly the same size, weight
|
|
5
|
+
and ink as the value itself, and neither was the product font.
|
|
6
|
+
|
|
7
|
+
DESIGN GAP, STATED: the handoff draws no visitor-search panel. What it does
|
|
8
|
+
draw is a label sitting next to the value it names, at
|
|
9
|
+
`iService365 Redesign.dc.html:659` - `color:var(--muted);font-size:12.5px` -
|
|
10
|
+
inside a row whose own type is 13.5px/600 with the name at 700 (line 658).
|
|
11
|
+
Those are the values below: a muted 12.5px label over a 13.5px/700 value, the
|
|
12
|
+
same label-quieter-than-value relationship `ListItem.vue` already uses.
|
|
13
|
+
|
|
14
|
+
The trailing colons are dropped: the design separates a label from its value
|
|
15
|
+
by weight and ink, not by punctuation.
|
|
16
|
+
-->
|
|
1
17
|
<template>
|
|
2
18
|
<div class="w-100 py-2">
|
|
3
|
-
<div class="d-flex align-center mb-3 justify-space-between ga-4 w-100">
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<div>
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
<div class="d-flex flex-wrap align-center mb-3 justify-space-between ga-4 w-100">
|
|
20
|
+
<!-- These were `<span>` wrappers with `<div>` children - a block inside
|
|
21
|
+
an inline element, which the parser closes early. Now both are
|
|
22
|
+
blocks, which is also what makes the 50% min-width behave. -->
|
|
23
|
+
<div class="visitor-summary__cell">
|
|
24
|
+
<div class="visitor-summary__label">Name</div>
|
|
25
|
+
<div class="visitor-summary__value">{{ displayName }}</div>
|
|
26
|
+
</div>
|
|
27
|
+
<div class="visitor-summary__cell">
|
|
28
|
+
<div class="visitor-summary__label">NRIC</div>
|
|
29
|
+
<div class="visitor-summary__value">{{ item?.nric || "N/A" }}</div>
|
|
30
|
+
</div>
|
|
12
31
|
</div>
|
|
13
32
|
|
|
14
33
|
<div
|
|
15
34
|
v-if="contacts.length < 2 && plateNumbers.length < 2"
|
|
16
|
-
class="d-flex align-center justify-space-between ga-4 w-100"
|
|
35
|
+
class="d-flex flex-wrap align-center justify-space-between ga-4 w-100"
|
|
17
36
|
>
|
|
18
|
-
<div class="
|
|
19
|
-
<div>Contact
|
|
20
|
-
<div>{{ contacts[0] || "N/A" }}</div>
|
|
37
|
+
<div class="visitor-summary__cell">
|
|
38
|
+
<div class="visitor-summary__label">Contact</div>
|
|
39
|
+
<div class="visitor-summary__value">{{ contacts[0] || "N/A" }}</div>
|
|
21
40
|
</div>
|
|
22
|
-
<div class="
|
|
23
|
-
<div>Plate
|
|
24
|
-
<div class="text-uppercase">
|
|
41
|
+
<div class="visitor-summary__cell">
|
|
42
|
+
<div class="visitor-summary__label">Plate</div>
|
|
43
|
+
<div class="visitor-summary__value text-uppercase">
|
|
44
|
+
{{ plateNumbers[0] || "N/A" }}
|
|
45
|
+
</div>
|
|
25
46
|
</div>
|
|
26
47
|
</div>
|
|
27
48
|
</div>
|
|
@@ -84,3 +105,26 @@ const plateNumbers = computed(() => {
|
|
|
84
105
|
);
|
|
85
106
|
});
|
|
86
107
|
</script>
|
|
108
|
+
|
|
109
|
+
<style scoped>
|
|
110
|
+
.visitor-summary__cell {
|
|
111
|
+
min-width: 50%;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.visitor-summary__label {
|
|
115
|
+
font-family: var(--font-sans);
|
|
116
|
+
font-size: 12.5px;
|
|
117
|
+
font-weight: var(--fw-cell);
|
|
118
|
+
letter-spacing: 0;
|
|
119
|
+
color: var(--muted);
|
|
120
|
+
margin-bottom: 2px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.visitor-summary__value {
|
|
124
|
+
font-family: var(--font-sans);
|
|
125
|
+
font-size: var(--fs-cell);
|
|
126
|
+
font-weight: var(--fw-btn);
|
|
127
|
+
letter-spacing: 0;
|
|
128
|
+
color: var(--text);
|
|
129
|
+
}
|
|
130
|
+
</style>
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
v-if="snackBarMessage.isUnregistered"
|
|
50
50
|
rounded="md"
|
|
51
51
|
variant="text"
|
|
52
|
-
color="
|
|
52
|
+
color="primary"
|
|
53
53
|
class="text-truncate text-decoration-underline px-0"
|
|
54
54
|
@click="goToUnregistered"
|
|
55
55
|
>
|
|
@@ -90,19 +90,14 @@
|
|
|
90
90
|
</v-snackbar>
|
|
91
91
|
|
|
92
92
|
<v-dialog v-model="permanentMessageDialog.modal" max-width="480" persistent>
|
|
93
|
-
<v-card>
|
|
94
|
-
<v-card-title
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
@click="permanentMessageDialog.modal = false"
|
|
102
|
-
>
|
|
103
|
-
Close
|
|
104
|
-
</v-btn>
|
|
105
|
-
</v-card-actions>
|
|
93
|
+
<v-card class="screen-modal socket-notice">
|
|
94
|
+
<v-card-title>Notice</v-card-title>
|
|
95
|
+
<div class="screen-modal__body socket-notice__body">
|
|
96
|
+
{{ permanentMessageDialog.text }}
|
|
97
|
+
</div>
|
|
98
|
+
<div class="socket-notice__footer">
|
|
99
|
+
<AppButton @click="permanentMessageDialog.modal = false">Close</AppButton>
|
|
100
|
+
</div>
|
|
106
101
|
</v-card>
|
|
107
102
|
</v-dialog>
|
|
108
103
|
</div>
|
|
@@ -372,3 +367,16 @@ onUnmounted(() => {
|
|
|
372
367
|
|
|
373
368
|
|
|
374
369
|
</script>
|
|
370
|
+
|
|
371
|
+
<style scoped>
|
|
372
|
+
.socket-notice__body {
|
|
373
|
+
padding: 4px 20px 0;
|
|
374
|
+
color: var(--text2);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.socket-notice__footer {
|
|
378
|
+
display: flex;
|
|
379
|
+
justify-content: flex-end;
|
|
380
|
+
padding: 16px 20px 20px;
|
|
381
|
+
}
|
|
382
|
+
</style>
|
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<AppCard class="pa-2 pa-sm-5">
|
|
3
3
|
<v-row no-gutters>
|
|
4
4
|
<v-col cols="12">
|
|
5
5
|
<v-row no-gutters class="d-flex ga-2 justify-space-between align-start mb-3 mb-sm-5 flex-wrap">
|
|
6
6
|
|
|
7
7
|
<div class="d-flex flex-column" style="min-width: 0;">
|
|
8
|
-
<span class="
|
|
8
|
+
<span class="screen-card-title" style="word-break: break-word;">Visitor
|
|
9
9
|
Management - Visitor ({{ items.length }} visitors)</span>
|
|
10
|
-
<span
|
|
10
|
+
<span class="report-meta" style="word-break: break-word;">Date Range: {{
|
|
11
11
|
formatDateDDMMYYYY(dateFrom) }} - {{ formatDateDDMMYYYY(dateTo) ?? "" }}</span>
|
|
12
|
-
<span class="
|
|
12
|
+
<span class="report-meta" style="word-break: break-word;">Site Name: {{ activeSiteName
|
|
13
13
|
}}</span>
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
16
|
</v-row>
|
|
17
|
-
|
|
17
|
+
<!-- `text-black` forced every cell AND the empty-state line to
|
|
18
|
+
literal black, which on the dark theme's card measured
|
|
19
|
+
1.26:1. The table takes the theme's own ink now. -->
|
|
20
|
+
<div class="table-card" style="overflow-x: auto; max-width: 100%;">
|
|
18
21
|
<v-data-table :headers="headers" :items="items" show-header :items-per-page="100"
|
|
19
|
-
hide-default-footer
|
|
22
|
+
hide-default-footer no-data-text="No entries to display">
|
|
20
23
|
|
|
21
24
|
<template v-slot:item.typeCompany="{ item }">
|
|
22
25
|
<span class="d-flex align-center ga-2" style="flex-wrap: wrap;">
|
|
@@ -77,13 +80,13 @@
|
|
|
77
80
|
<template v-slot:item.checkInOutImage="{ item }">
|
|
78
81
|
<div class="d-flex flex-column ga-2">
|
|
79
82
|
<div v-if="item?.snapshotEntryImage" class="d-flex flex-column">
|
|
80
|
-
<span class="
|
|
83
|
+
<span class="snapshot-label snapshot-label--in">Check-In</span>
|
|
81
84
|
<v-img :src="getFileUrlAnpr(`${siteId}/${item.snapshotEntryImage}`)"
|
|
82
85
|
style="max-width: clamp(60px, 10vw, 100px); max-height: clamp(60px, 10vw, 100px);"
|
|
83
86
|
class="border" />
|
|
84
87
|
</div>
|
|
85
88
|
<div v-if="item?.snapshotExitImage" class="d-flex flex-column">
|
|
86
|
-
<span class="
|
|
89
|
+
<span class="snapshot-label snapshot-label--out">Check-Out</span>
|
|
87
90
|
<v-img :src="getFileUrlAnpr(`${siteId}/${item.snapshotExitImage}`)"
|
|
88
91
|
style="max-width: clamp(60px, 10vw, 100px); max-height: clamp(60px, 10vw, 100px);"
|
|
89
92
|
class="border" />
|
|
@@ -101,7 +104,7 @@
|
|
|
101
104
|
</v-col>
|
|
102
105
|
|
|
103
106
|
</v-row>
|
|
104
|
-
</
|
|
107
|
+
</AppCard>
|
|
105
108
|
</template>
|
|
106
109
|
|
|
107
110
|
<script setup lang="ts">
|
|
@@ -311,44 +314,56 @@ onMounted(() => {
|
|
|
311
314
|
box-sizing: border-box;
|
|
312
315
|
}
|
|
313
316
|
|
|
314
|
-
|
|
315
|
-
|
|
317
|
+
/* The handoff names no type for a report's meta lines or a snapshot caption,
|
|
318
|
+
so both take the design's own secondary sizes. The captions were
|
|
319
|
+
`text-blue-darken-1` / `text-red-darken-1` - fixed Vuetify hues that do not
|
|
320
|
+
follow the theme. */
|
|
321
|
+
.report-meta {
|
|
322
|
+
font-family: var(--font-sans);
|
|
323
|
+
font-size: var(--fs-breadcrumb);
|
|
324
|
+
color: var(--text2);
|
|
316
325
|
}
|
|
317
326
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
font-weight:
|
|
327
|
+
.snapshot-label {
|
|
328
|
+
font-family: var(--font-sans);
|
|
329
|
+
font-size: var(--fs-chip);
|
|
330
|
+
font-weight: var(--fw-chip);
|
|
322
331
|
}
|
|
323
332
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
color: white !important;
|
|
327
|
-
border-right: 1px solid rgba(255, 255, 255, 0.2) !important;
|
|
328
|
-
font-size: clamp(11px, 1.2vw, 14px) !important;
|
|
329
|
-
padding: clamp(8px, 1vw, 12px) !important;
|
|
330
|
-
word-break: break-word;
|
|
333
|
+
.snapshot-label--in {
|
|
334
|
+
color: var(--info);
|
|
331
335
|
}
|
|
332
336
|
|
|
333
|
-
|
|
334
|
-
|
|
337
|
+
.snapshot-label--out {
|
|
338
|
+
/* Was `var(--error)`, which is not a token here - the name is `--err`. An
|
|
339
|
+
undefined custom property invalidates the declaration silently, so the
|
|
340
|
+
label inherited instead of turning red. */
|
|
341
|
+
color: var(--err);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
:deep(.v-card) {
|
|
345
|
+
overflow-x: auto;
|
|
335
346
|
}
|
|
336
347
|
|
|
348
|
+
/* The header row was a fixed `#1976d2` fill with white labels and the cell
|
|
349
|
+
rules were a fixed `#e0e0e0`, none of which follows the theme and none of
|
|
350
|
+
which is in the handoff - the design's table head is 11px/800 uppercase in
|
|
351
|
+
`--muted` on `--thead`. Deleted so the shared `.table-card` rule applies;
|
|
352
|
+
only the column rule this report actually needs is kept, on `--border`. */
|
|
353
|
+
:deep(.v-data-table thead tr th),
|
|
337
354
|
:deep(.v-data-table tbody tr td) {
|
|
338
|
-
border-right: 1px solid
|
|
339
|
-
font-size: clamp(10px, 1.1vw, 13px) !important;
|
|
340
|
-
padding: clamp(6px, 0.8vw, 10px) !important;
|
|
355
|
+
border-right: 1px solid var(--border) !important;
|
|
341
356
|
word-break: break-word;
|
|
342
|
-
word-wrap: break-word;
|
|
343
357
|
overflow-wrap: break-word;
|
|
344
358
|
}
|
|
345
359
|
|
|
360
|
+
:deep(.v-data-table thead tr th:last-child),
|
|
346
361
|
:deep(.v-data-table tbody tr td:last-child) {
|
|
347
362
|
border-right: none !important;
|
|
348
363
|
}
|
|
349
364
|
|
|
350
365
|
:deep(.v-data-table tbody tr:last-child td) {
|
|
351
|
-
border-bottom: 1px solid
|
|
366
|
+
border-bottom: 1px solid var(--border) !important;
|
|
352
367
|
}
|
|
353
368
|
|
|
354
369
|
:deep(.v-img) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<FormDialog v-model="dialog" @close="closeDialog">
|
|
3
3
|
<template #title>
|
|
4
|
-
<span class="
|
|
4
|
+
<span class="screen-card-title pt-1 text-capitalize">
|
|
5
5
|
{{ isEditMode ? "Edit Work Order" : "Create Work Order" }}
|
|
6
6
|
</span>
|
|
7
7
|
</template>
|
|
@@ -24,8 +24,7 @@
|
|
|
24
24
|
item-props
|
|
25
25
|
label="Subject"
|
|
26
26
|
variant="outlined"
|
|
27
|
-
|
|
28
|
-
class="mb-2"
|
|
27
|
+
class="filter-field mb-2"
|
|
29
28
|
:clearable="
|
|
30
29
|
props.createdFrom === 'feedback' && workOrder.subject !== ''
|
|
31
30
|
? false
|
|
@@ -39,7 +38,7 @@
|
|
|
39
38
|
:custom-filter="customFilter"
|
|
40
39
|
:rules="[requiredRule]"
|
|
41
40
|
>
|
|
42
|
-
<template #label> Subject <span class="
|
|
41
|
+
<template #label> Subject <span class="form-required">*</span> </template>
|
|
43
42
|
</v-autocomplete>
|
|
44
43
|
|
|
45
44
|
<v-autocomplete
|
|
@@ -50,8 +49,7 @@
|
|
|
50
49
|
item-props
|
|
51
50
|
label="Category"
|
|
52
51
|
variant="outlined"
|
|
53
|
-
|
|
54
|
-
class="mb-2"
|
|
52
|
+
class="filter-field mb-2"
|
|
55
53
|
:clearable="
|
|
56
54
|
props.createdFrom === 'feedback' && workOrder.category !== ''
|
|
57
55
|
? false
|
|
@@ -64,12 +62,12 @@
|
|
|
64
62
|
"
|
|
65
63
|
:rules="[requiredRule]"
|
|
66
64
|
>
|
|
67
|
-
<template #label> Category <span class="
|
|
65
|
+
<template #label> Category <span class="form-required">*</span> </template>
|
|
68
66
|
</v-autocomplete>
|
|
69
67
|
|
|
70
68
|
<v-checkbox v-model="workOrder.highPriority" density="compact" class="ma-0">
|
|
71
69
|
<template #label>
|
|
72
|
-
<span class="
|
|
70
|
+
<span class="form-check-label">
|
|
73
71
|
Set work order as High Priority (Optional)
|
|
74
72
|
</span>
|
|
75
73
|
</template>
|
|
@@ -98,14 +96,13 @@
|
|
|
98
96
|
<v-autocomplete
|
|
99
97
|
label="Unit"
|
|
100
98
|
variant="outlined"
|
|
101
|
-
|
|
99
|
+
class="filter-field mt-1"
|
|
102
100
|
v-model="workOrder.unit"
|
|
103
101
|
:items="units"
|
|
104
|
-
class="mt-1"
|
|
105
102
|
clearable
|
|
106
103
|
:rules="[requiredRule]"
|
|
107
104
|
>
|
|
108
|
-
<template #label> Unit <span class="
|
|
105
|
+
<template #label> Unit <span class="form-required">*</span> </template>
|
|
109
106
|
</v-autocomplete>
|
|
110
107
|
|
|
111
108
|
<!-- <v-text-field
|
|
@@ -125,23 +122,21 @@
|
|
|
125
122
|
<v-textarea
|
|
126
123
|
label="Work Order Description"
|
|
127
124
|
variant="outlined"
|
|
128
|
-
|
|
125
|
+
class="filter-field mt-1"
|
|
129
126
|
v-model="workOrder.description"
|
|
130
|
-
class="mt-1"
|
|
131
127
|
rows="4"
|
|
132
128
|
clearable
|
|
133
129
|
auto-grow
|
|
134
130
|
:rules="[requiredRule]"
|
|
135
131
|
>
|
|
136
|
-
<template #label> Description <span class="
|
|
132
|
+
<template #label> Description <span class="form-required">*</span> </template>
|
|
137
133
|
</v-textarea>
|
|
138
134
|
|
|
139
135
|
<template #footer>
|
|
140
136
|
<v-btn
|
|
141
|
-
|
|
142
|
-
|
|
137
|
+
class="screen-btn-primary mb-4"
|
|
138
|
+
variant="flat"
|
|
143
139
|
block
|
|
144
|
-
height="40"
|
|
145
140
|
:loading="loading"
|
|
146
141
|
:disabled="loading || !isFormValid"
|
|
147
142
|
@click="submitWorkOrder"
|
|
@@ -282,3 +277,17 @@ const customFilter = (value: string, query: string, item: any) => {
|
|
|
282
277
|
return title.includes(search) || subtitle.includes(search);
|
|
283
278
|
};
|
|
284
279
|
</script>
|
|
280
|
+
|
|
281
|
+
<style scoped>
|
|
282
|
+
/* The required star was `text-red`, a Vuetify palette word rather than the
|
|
283
|
+
design's error token. */
|
|
284
|
+
.form-required {
|
|
285
|
+
color: var(--err);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.form-check-label {
|
|
289
|
+
font-family: var(--font-sans);
|
|
290
|
+
font-size: var(--fs-cell);
|
|
291
|
+
color: var(--text);
|
|
292
|
+
}
|
|
293
|
+
</style>
|
|
@@ -13,14 +13,22 @@
|
|
|
13
13
|
@click:create="emit('click:create')"
|
|
14
14
|
:length="pages"
|
|
15
15
|
>
|
|
16
|
+
<!--
|
|
17
|
+
A failed request is not a site with no work orders. Without this the
|
|
18
|
+
table drew its neutral "No data available" for a 500, which reads as
|
|
19
|
+
"there is nothing outstanding" - a statement the server never made.
|
|
20
|
+
-->
|
|
21
|
+
<template v-if="failed" #no-data>
|
|
22
|
+
<DashboardEmptyState error />
|
|
23
|
+
</template>
|
|
24
|
+
|
|
16
25
|
<template #title>
|
|
17
|
-
<span class="
|
|
26
|
+
<span class="screen-card-title">Work Order</span>
|
|
18
27
|
</template>
|
|
19
28
|
<template #action-button>
|
|
20
29
|
<v-btn
|
|
21
|
-
color="primary-button"
|
|
22
30
|
variant="flat"
|
|
23
|
-
class="ml-4
|
|
31
|
+
class="screen-btn-primary ml-4"
|
|
24
32
|
@click="emit('click:create')"
|
|
25
33
|
>
|
|
26
34
|
Work Order
|
|
@@ -53,6 +61,8 @@
|
|
|
53
61
|
</template>
|
|
54
62
|
|
|
55
63
|
<script lang="ts" setup>
|
|
64
|
+
import { readListPage, NO_PAGE_RANGE } from "../../utils/list-page";
|
|
65
|
+
|
|
56
66
|
const emit = defineEmits(["click:create", "update:pagination"]);
|
|
57
67
|
|
|
58
68
|
const { page, pages, pageRange, workOrders, getWorkOrders } = useWorkOrder();
|
|
@@ -62,6 +72,7 @@ const message = ref("");
|
|
|
62
72
|
const messageColor = ref("");
|
|
63
73
|
const messageSnackbar = ref(false);
|
|
64
74
|
const loading = ref(false);
|
|
75
|
+
const failed = ref(false);
|
|
65
76
|
const height = ref("500px");
|
|
66
77
|
const selected = ref<string[]>([]);
|
|
67
78
|
|
|
@@ -73,20 +84,40 @@ const headers = ref([
|
|
|
73
84
|
{ title: "Date", value: "createdAt" },
|
|
74
85
|
]);
|
|
75
86
|
|
|
87
|
+
// `getWorkOrders` RETURNS the reply; nothing was ever reading it. `workOrders`,
|
|
88
|
+
// `pages` and `pageRange` are `useState` cells that no code in this layer or in
|
|
89
|
+
// any of the eleven apps ever assigned, so this table drew zero rows and
|
|
90
|
+
// "-- - -- of --" no matter what the server sent. The reply is now bound
|
|
91
|
+
// through the one helper that knows how a paginated reply is shaped, so the
|
|
92
|
+
// count on screen is the server's count of the whole list - never the number
|
|
93
|
+
// of rows on this page.
|
|
76
94
|
async function _getWorkOrders() {
|
|
77
95
|
loading.value = true;
|
|
96
|
+
failed.value = false;
|
|
78
97
|
|
|
79
98
|
try {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
99
|
+
const listPage = readListPage<TWorkOrder>(
|
|
100
|
+
await getWorkOrders({
|
|
101
|
+
page: page.value,
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
workOrders.value = listPage.items;
|
|
105
|
+
pages.value = listPage.pages;
|
|
106
|
+
pageRange.value = listPage.pageRange;
|
|
83
107
|
|
|
84
108
|
emit("update:pagination", {
|
|
85
109
|
page: page.value,
|
|
86
110
|
pages: pages.value,
|
|
87
111
|
});
|
|
88
112
|
} catch (error) {
|
|
89
|
-
|
|
113
|
+
// Say the request failed rather than presenting it as an empty list. The
|
|
114
|
+
// count goes back to the placeholder for the same reason: a failure is not
|
|
115
|
+
// a zero.
|
|
116
|
+
failed.value = true;
|
|
117
|
+
workOrders.value = [];
|
|
118
|
+
pages.value = 0;
|
|
119
|
+
pageRange.value = NO_PAGE_RANGE;
|
|
120
|
+
console.error("Error fetching work orders:", error);
|
|
90
121
|
} finally {
|
|
91
122
|
loading.value = false;
|
|
92
123
|
}
|
|
@@ -1,58 +1,47 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
>
|
|
2
|
+
<div>
|
|
3
|
+
<!--
|
|
4
|
+
The design's page scaffold. The screen had no heading, its Create button
|
|
5
|
+
sat top-left and the search floated top-right outside the card, with
|
|
6
|
+
refresh and the pager stacked on their own bar above the table. Same
|
|
7
|
+
button, same dialog, same permission, same debounced search, same pager.
|
|
8
|
+
-->
|
|
9
|
+
<PageHeader title="Work Orders">
|
|
10
|
+
<template v-if="canCreateWorkOrder" #actions>
|
|
11
|
+
<AppButton @click="(showCreateDialog = true), (isEditMode = false)">
|
|
13
12
|
Create Work Order
|
|
14
|
-
</
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
variant="outlined"
|
|
20
|
-
density="comfortable"
|
|
21
|
-
clearable
|
|
22
|
-
hide-details
|
|
23
|
-
class="ml-2"
|
|
24
|
-
style="max-width: 250px"
|
|
25
|
-
/>
|
|
26
|
-
</v-row>
|
|
27
|
-
</v-col>
|
|
13
|
+
</AppButton>
|
|
14
|
+
</template>
|
|
15
|
+
</PageHeader>
|
|
16
|
+
|
|
17
|
+
<v-row no-gutters>
|
|
28
18
|
<v-col cols="12">
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
<v-btn fab icon density="comfortable" @click="updatePage(1)">
|
|
39
|
-
<v-icon>mdi-refresh</v-icon>
|
|
40
|
-
</v-btn>
|
|
19
|
+
<AppCard class="table-card">
|
|
20
|
+
<CardToolbar :count="pageRange">
|
|
21
|
+
<template #left>
|
|
22
|
+
<AppButton
|
|
23
|
+
variant="icon"
|
|
24
|
+
icon="mdi-refresh"
|
|
25
|
+
aria-label="Refresh"
|
|
26
|
+
@click="updatePage(1)"
|
|
27
|
+
/>
|
|
41
28
|
</template>
|
|
42
29
|
|
|
43
|
-
<template #
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
30
|
+
<template #right>
|
|
31
|
+
<AppField
|
|
32
|
+
v-model="searchText"
|
|
33
|
+
search
|
|
34
|
+
compact
|
|
35
|
+
placeholder="Search work order..."
|
|
36
|
+
klass="app-toolbar__search"
|
|
37
|
+
/>
|
|
38
|
+
<local-pagination
|
|
39
|
+
v-model="page"
|
|
40
|
+
:length="pages"
|
|
41
|
+
@update:value="updatePage"
|
|
42
|
+
/>
|
|
54
43
|
</template>
|
|
55
|
-
</
|
|
44
|
+
</CardToolbar>
|
|
56
45
|
|
|
57
46
|
<v-data-table
|
|
58
47
|
:headers="headers"
|
|
@@ -62,6 +51,7 @@
|
|
|
62
51
|
fixed-header
|
|
63
52
|
hide-default-footer
|
|
64
53
|
:hide-default-header="false"
|
|
54
|
+
:loading="loading"
|
|
65
55
|
@click:row="tableRowClickHandler"
|
|
66
56
|
style="max-height: calc(100vh - (200px))"
|
|
67
57
|
>
|
|
@@ -69,9 +59,10 @@
|
|
|
69
59
|
{{ formatDateDDMMYYYYLocal(item.createdAt) }}
|
|
70
60
|
</template>
|
|
71
61
|
</v-data-table>
|
|
72
|
-
</
|
|
62
|
+
</AppCard>
|
|
73
63
|
</v-col>
|
|
74
|
-
|
|
64
|
+
</v-row>
|
|
65
|
+
</div>
|
|
75
66
|
|
|
76
67
|
<WorkOrderCreate
|
|
77
68
|
v-model="showCreateDialog"
|
|
@@ -217,6 +208,9 @@
|
|
|
217
208
|
|
|
218
209
|
<script setup lang="ts">
|
|
219
210
|
import { useTheme } from "vuetify";
|
|
211
|
+
// Relative import, never Nuxt auto-import: this layer's `utils/` are auto-imported
|
|
212
|
+
// into the consuming apps but not reliably into the layer's own components.
|
|
213
|
+
import { pickRouteName } from "../../utils/route-name";
|
|
220
214
|
const emit = defineEmits(["click:create", "update:pagination"]);
|
|
221
215
|
|
|
222
216
|
const props = defineProps({
|
|
@@ -372,14 +366,23 @@ function handleRowClick(row: any) {
|
|
|
372
366
|
const org = useRoute().params.org || "defaultOrg";
|
|
373
367
|
const site = useRoute().params.site || "defaultSite";
|
|
374
368
|
const id = row._id;
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
369
|
+
// `work-order-details` is not a route in any consuming app; the detail screen
|
|
370
|
+
// is `pages/[org]/[site]/work-orders/[id].vue` -> `org-site-work-orders-id`.
|
|
371
|
+
const details = pickRouteName(
|
|
372
|
+
useRouter(),
|
|
373
|
+
"org-site-work-orders-id",
|
|
374
|
+
"work-orders-id"
|
|
375
|
+
);
|
|
376
|
+
if (details) {
|
|
377
|
+
useRouter().push({
|
|
378
|
+
name: details,
|
|
379
|
+
params: {
|
|
380
|
+
org,
|
|
381
|
+
site,
|
|
382
|
+
id,
|
|
383
|
+
},
|
|
384
|
+
});
|
|
385
|
+
}
|
|
383
386
|
}
|
|
384
387
|
|
|
385
388
|
function resetWorkOrderForm() {
|
|
@@ -51,9 +51,9 @@ export default function useFeedback() {
|
|
|
51
51
|
|
|
52
52
|
const feedback = useState("feedback", () => new MFeedback());
|
|
53
53
|
const feedbacks = useState("feedbacks", (): TFeedback[] => []);
|
|
54
|
-
const page = useState("
|
|
55
|
-
const pages = useState("
|
|
56
|
-
const pageRange = useState("
|
|
54
|
+
const page = useState("feedbackPage", () => 1);
|
|
55
|
+
const pages = useState("feedbackPages", () => 0);
|
|
56
|
+
const pageRange = useState("feedbackPageRange", () => "-- - -- of --");
|
|
57
57
|
|
|
58
58
|
function setFeedback(data?: TFeedback) {
|
|
59
59
|
feedback.value = data || new MFeedback();
|