@7365admin1/layer-common 3.1.2 → 3.1.3-staging.40

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.
Files changed (31) hide show
  1. package/.github/workflows/publish-staging.yml +11 -0
  2. package/components/AddEqupmentForm.vue +52 -1
  3. package/components/CameraMain.vue +17 -9
  4. package/components/DashboardMain.vue +231 -87
  5. package/components/EquipmentManagementMain.vue +56 -0
  6. package/components/InvitationMain.vue +4 -3
  7. package/components/ManageChecklistMain.vue +44 -38
  8. package/components/Nfc/NFCPatrolReportMain.vue +146 -38
  9. package/components/Nfc/PatrolReport/DailyReportTab.vue +10 -6
  10. package/components/Nfc/PatrolReport/MonthlyReportTab.vue +19 -9
  11. package/components/Nfc/PatrolReport/MonthlyReportTable.vue +69 -0
  12. package/components/Nfc/PatrolReport/PatrolActivityTable.vue +20 -0
  13. package/components/Nfc/PatrolReport/PatrolReportTab.vue +5 -3
  14. package/components/Nfc/PatrolReport/ReportDatePicker.vue +61 -0
  15. package/components/Nfc/PatrolReport/ReportFilters.vue +52 -20
  16. package/components/Nfc/PatrolReport/SummaryReportTable.vue +22 -0
  17. package/components/PhotoUpload.vue +19 -4
  18. package/components/ServiceProviderMain.vue +59 -25
  19. package/components/VisitorForm.vue +78 -18
  20. package/components/VisitorManagement.vue +12 -16
  21. package/composables/useCleaningSchedulePermission.ts +16 -51
  22. package/composables/useEquipment.ts +2 -0
  23. package/composables/useLocalAuth.ts +1 -1
  24. package/composables/useNFCPatrolDailyReport.ts +3 -4
  25. package/composables/useNFCPatrolMonthlyReport.ts +62 -30
  26. package/composables/useNFCPatrolReport.ts +2 -0
  27. package/composables/useServiceProvider.ts +21 -0
  28. package/package.json +1 -1
  29. package/types/customer.d.ts +2 -1
  30. package/types/equipment.d.ts +5 -1
  31. package/types/nfc-patrol-report.ts +19 -1
@@ -36,10 +36,17 @@
36
36
  </template>
37
37
 
38
38
  <v-list v-if="nricSearchResults.length" class="pa-1 phone-search-results">
39
- <v-list-item v-for="(item, index) in nricSearchResults" :key="item._id || index"
40
- @click="selectNricSearchResult(item)" class="cursor-pointer nric-search-item">
41
- <VisitorSearchResultSummary :item="item" />
42
- </v-list-item>
39
+ <div class="search-results-scroll">
40
+ <v-list-item v-for="(item, index) in nricSearchResults" :key="item._id || index"
41
+ @click="selectNricSearchResult(item)" class="cursor-pointer nric-search-item">
42
+ <VisitorSearchResultSummary :item="item" />
43
+ </v-list-item>
44
+ </div>
45
+ <div class="search-results-close pa-1">
46
+ <v-btn block variant="flat" color="red" @click.stop="closeAutofillSearchResults('nric')">
47
+ Close
48
+ </v-btn>
49
+ </div>
43
50
  </v-list>
44
51
  </v-menu>
45
52
  </v-col>
@@ -58,10 +65,17 @@
58
65
  </template>
59
66
 
60
67
  <v-list v-if="phoneSearchResults.length" class="pa-1 phone-search-results">
61
- <v-list-item v-for="(item, index) in phoneSearchResults" :key="item._id || index"
62
- @click="selectPhoneNumberSearchResult(item)" class="cursor-pointer nric-search-item">
63
- <VisitorSearchResultSummary :item="item" />
64
- </v-list-item>
68
+ <div class="search-results-scroll">
69
+ <v-list-item v-for="(item, index) in phoneSearchResults" :key="item._id || index"
70
+ @click="selectPhoneNumberSearchResult(item)" class="cursor-pointer nric-search-item">
71
+ <VisitorSearchResultSummary :item="item" />
72
+ </v-list-item>
73
+ </div>
74
+ <div class="search-results-close pa-1">
75
+ <v-btn block variant="flat" color="red" @click.stop="closeAutofillSearchResults('contact')">
76
+ Close
77
+ </v-btn>
78
+ </div>
65
79
  </v-list>
66
80
  </v-menu>
67
81
  </v-col>
@@ -77,15 +91,23 @@
77
91
  <v-menu v-model="vehicleSearchMenu" location="bottom" offset-y :close-on-content-click="false">
78
92
  <template #activator="{ props }">
79
93
  <InputVehicleNumber v-bind="props" v-model="visitor.plateNumber" density="comfortable"
80
- @update:model-value="handleUpdateVehicleNumber" @focus="isPlateNumberFieldFocused = true"
94
+ @update:model-value="handleUpdateVehicleNumber" @focus="handleFocusPlateNumber"
81
95
  @blur="isPlateNumberFieldFocused = false" />
82
96
  </template>
83
97
 
84
98
  <v-list v-if="vehicleSearchResults.length" class="pa-1 phone-search-results">
85
- <v-list-item v-for="(item, index) in vehicleSearchResults" :key="item._id || index"
86
- @click="selectPlateNumberSearchResult(item)" class="cursor-pointer nric-search-item">
87
- <VisitorSearchResultSummary :item="item" />
88
- </v-list-item>
99
+ <div class="search-results-scroll">
100
+ <v-list-item v-for="(item, index) in vehicleSearchResults" :key="item._id || index"
101
+ @click="selectPlateNumberSearchResult(item)" class="cursor-pointer nric-search-item">
102
+ <VisitorSearchResultSummary :item="item" />
103
+ </v-list-item>
104
+ </div>
105
+ <div class="search-results-close pa-1">
106
+ <v-btn block variant="flat" color="red"
107
+ @click.stop="closeAutofillSearchResults('vehicleNumber')">
108
+ Close
109
+ </v-btn>
110
+ </div>
89
111
  </v-list>
90
112
  </v-menu>
91
113
  </v-col>
@@ -308,10 +330,10 @@
308
330
 
309
331
  <div class="nric-selected-person d-flex align-center justify-space-between ga-3 mb-5">
310
332
  <span>{{ selectedNricSearchResult.name || "Unknown" }}</span>
311
- <span class="text-no-wrap">NRIC: {{ selectedNricSearchResult.nric || "N/A" }}</span>
333
+ <span v-if="!visitor.nric || currentAutofillSource === 'nric'" class="text-no-wrap">NRIC: {{ selectedNricSearchResult.nric || "N/A" }}</span>
312
334
  </div>
313
335
 
314
- <template v-if="!visitor.contact && selectedNricContactOptions.length >= 1">
336
+ <template v-if="(!visitor.contact || currentAutofillSource === 'contact') && selectedNricContactOptions.length >= 1">
315
337
  <h3 class="nric-options-section-title font-weight-bold mb-2">Contact</h3>
316
338
  <v-radio-group v-model="selectedNricContact" hide-details color="success" class="nric-option-group">
317
339
  <v-radio v-for="contact in selectedNricContactOptions" :key="contact" :label="contact" :value="contact"
@@ -319,7 +341,7 @@
319
341
  </v-radio-group>
320
342
  </template>
321
343
 
322
- <template v-if="!visitor.plateNumber && selectedNricPlateOptions.length >= 1">
344
+ <template v-if="(!visitor.plateNumber || currentAutofillSource === 'vehicleNumber') && selectedNricPlateOptions.length >= 1">
323
345
  <h3 class="nric-options-section-title font-weight-bold mb-2 mt-5">Vehicle</h3>
324
346
  <v-radio-group v-model="selectedNricPlate" hide-details color="success" class="nric-option-group">
325
347
  <v-radio v-for="plate in selectedNricPlateOptions" :key="plate" :label="plate" :value="plate"
@@ -1044,8 +1066,8 @@ function selectAutofillSearchResult(item: Partial<TPeople>, source: Exclude<Auto
1044
1066
  const selectedPlate =
1045
1067
  findMatchingPlateOption(plateOptions, visitor.plateNumber) || plateOptions[0] || "";
1046
1068
 
1047
- const needsContactChoice = !visitor.contact?.trim() && contactOptions.length > 1;
1048
- const needsPlateChoice = !visitor.plateNumber?.trim() && plateOptions.length > 1;
1069
+ const needsContactChoice = (!visitor.contact?.trim() || source === 'contact') && contactOptions.length > 1;
1070
+ const needsPlateChoice = (!visitor.plateNumber?.trim() || source === 'vehicleNumber') && plateOptions.length > 1;
1049
1071
 
1050
1072
  if (needsContactChoice || needsPlateChoice) {
1051
1073
  nricSearchMenu.value = false;
@@ -1066,6 +1088,23 @@ function selectAutofillSearchResult(item: Partial<TPeople>, source: Exclude<Auto
1066
1088
  });
1067
1089
  }
1068
1090
 
1091
+ function closeAutofillSearchResults(source: Exclude<AutofillSource, null>) {
1092
+ if (source === "nric") {
1093
+ nricSearchMenu.value = false;
1094
+ nricSearchResults.value = [];
1095
+ }
1096
+
1097
+ if (source === "contact") {
1098
+ phoneSearchMenu.value = false;
1099
+ phoneSearchResults.value = [];
1100
+ }
1101
+
1102
+ if (source === "vehicleNumber") {
1103
+ vehicleSearchMenu.value = false;
1104
+ vehicleSearchResults.value = [];
1105
+ }
1106
+ }
1107
+
1069
1108
  function closeNricAutofillOptions() {
1070
1109
  dialog.nricAutofillOptions = false;
1071
1110
  selectedNricSearchResult.value = null;
@@ -1503,6 +1542,15 @@ function handleUpdateVehicleNumber() {
1503
1542
  debounceFetchPlateNumber();
1504
1543
  }
1505
1544
 
1545
+ const handleFocusPlateNumber = () => {
1546
+ isPlateNumberFieldFocused.value = true;
1547
+ if (prop.mode === 'register') {
1548
+
1549
+ handleUpdateVehicleNumber();
1550
+ }
1551
+ };
1552
+
1553
+
1506
1554
  function backToSelection() {
1507
1555
  emit("back");
1508
1556
  message.value = "";
@@ -2108,10 +2156,22 @@ onMounted(() => {
2108
2156
  }
2109
2157
 
2110
2158
  .phone-search-results {
2159
+ display: flex;
2160
+ flex-direction: column;
2111
2161
  max-height: 400px;
2162
+ overflow: hidden;
2163
+ }
2164
+
2165
+ .search-results-scroll {
2166
+ flex: 1 1 auto;
2167
+ min-height: 0;
2112
2168
  overflow-y: auto;
2113
2169
  }
2114
2170
 
2171
+ .search-results-close {
2172
+ flex: 0 0 auto;
2173
+ }
2174
+
2115
2175
  .nric-options-card {
2116
2176
  border-radius: 16px !important;
2117
2177
  }
@@ -825,10 +825,8 @@
825
825
  item-title="label"
826
826
  item-value="value"
827
827
  v-model="pass.status"
828
- :disabled="
829
- selectedVisitorObject.checkOut || pass.status == 'Removed'
830
- "
831
- ></v-select>
828
+ :disabled="pass.status == 'Removed'"
829
+ />
832
830
  <v-textarea
833
831
  v-if="pass.status === 'Lost' || pass.status === 'Damaged'"
834
832
  no-resize
@@ -836,8 +834,7 @@
836
834
  class="w-100"
837
835
  density="compact"
838
836
  v-model="pass.remarks"
839
- :disabled="selectedVisitorObject.checkOut"
840
- ></v-textarea>
837
+ />
841
838
  </v-row>
842
839
  </div>
843
840
  <div v-if="keyReturnStatuses.length > 0" class="mb-2">
@@ -864,10 +861,8 @@
864
861
  item-title="label"
865
862
  item-value="value"
866
863
  v-model="key.status"
867
- :disabled="
868
- selectedVisitorObject.checkOut || key.status == 'Removed'
869
- "
870
- ></v-select>
864
+ :disabled="key.status == 'Removed'"
865
+ />
871
866
  <v-textarea
872
867
  v-if="key.status === 'Lost' || key.status === 'Damaged'"
873
868
  no-resize
@@ -875,8 +870,7 @@
875
870
  class="w-100"
876
871
  density="compact"
877
872
  v-model="key.remarks"
878
- :disabled="selectedVisitorObject.checkOut"
879
- ></v-textarea>
873
+ />
880
874
  </v-row>
881
875
  </div>
882
876
 
@@ -886,11 +880,11 @@
886
880
  color="blue"
887
881
  density="comfortable"
888
882
  class="text-capitalize"
889
- :disabled="selectedVisitorObject.checkOut"
890
883
  :loading="loading.updatingPassKeys"
891
884
  @click.stop="handleUpdatePassKeys"
892
- >Update Pass/Keys</v-btn
893
885
  >
886
+ Update Pass/Keys
887
+ </v-btn>
894
888
  </v-row>
895
889
  </v-card-text>
896
890
  <v-toolbar class="pa-0" density="compact">
@@ -900,8 +894,9 @@
900
894
  variant="text"
901
895
  block
902
896
  @click="dialog.returnPassesKeys = false"
903
- >Close</v-btn
904
897
  >
898
+ Close
899
+ </v-btn>
905
900
  </v-col>
906
901
  <v-col cols="6">
907
902
  <v-btn
@@ -915,8 +910,9 @@
915
910
  !canConfirmCheckout || selectedVisitorObject.checkOut
916
911
  "
917
912
  @click="proceedCheckout"
918
- >Confirm Checkout</v-btn
919
913
  >
914
+ Confirm Checkout
915
+ </v-btn>
920
916
  </v-col>
921
917
  </v-row>
922
918
  </v-toolbar>
@@ -1,58 +1,23 @@
1
1
  export function useCleaningSchedulePermission() {
2
- const { hasPermission } = usePermission();
3
- const { permissions } = useCleaningPermission();
4
-
5
2
  const { userAppRole } = useLocalSetup();
6
3
 
7
- const canViewSchedules = computed(() => {
8
- if (!userAppRole.value) return false;
9
- if (userAppRole.value.permissions.includes("*")) return true;
10
- return hasPermission(userAppRole.value, permissions, "cleaning-schedule-mgmt", "see-all-schedules");
11
- });
12
-
13
- const canViewScheduleDetails = computed(() => {
14
- if (!userAppRole.value) return false;
15
- if (userAppRole.value.permissions.includes("*")) return true;
16
- return hasPermission(userAppRole.value, permissions, "cleaning-schedule-mgmt", "see-schedule-details");
17
- });
18
-
19
- const canDownloadSchedule = computed(() => {
20
- if (!userAppRole.value) return false;
21
- if (userAppRole.value.permissions.includes("*")) return true;
22
- return hasPermission(userAppRole.value, permissions, "cleaning-schedule-mgmt", "download-schedule");
23
- });
24
-
25
- const canManageScheduleTasks = computed(() => {
26
- if (!userAppRole.value) return false;
27
- if (userAppRole.value.permissions.includes("*")) return true;
28
- return hasPermission(userAppRole.value, permissions, "cleaning-schedule-mgmt", "manage-schedule-tasks");
29
- });
30
-
31
- const canGenerateChecklist = computed(() => {
32
- if (!userAppRole.value) return false;
33
- if (userAppRole.value.permissions.includes("*")) return true;
34
- return hasPermission(userAppRole.value, permissions, "cleaning-schedule-mgmt", "generate-checklist");
35
- });
36
-
37
- const canViewHistory = computed(() => {
38
- if (!userAppRole.value) return false;
39
- if (userAppRole.value.permissions.includes("*")) return true;
40
- return hasPermission(userAppRole.value, permissions, "cleaning-schedule-mgmt", "view-history");
41
- });
42
-
43
- const canAddRemarks = computed(() => {
44
- if (!userAppRole.value) return false;
45
- if (userAppRole.value.permissions.includes("*")) return true;
46
- return hasPermission(userAppRole.value, permissions, "cleaning-schedule-mgmt", "add-remarks");
47
- });
4
+ const can = (action: string) =>
5
+ computed(() => {
6
+ const permissions = userAppRole.value?.permissions;
7
+ if (!permissions) return false;
8
+ if (permissions.includes("*")) return true;
9
+ return permissions.some((permission) =>
10
+ permission.endsWith(`-schedule-mgmt:${action}`),
11
+ );
12
+ });
48
13
 
49
14
  return {
50
- canViewSchedules,
51
- canViewScheduleDetails,
52
- canDownloadSchedule,
53
- canManageScheduleTasks,
54
- canGenerateChecklist,
55
- canViewHistory,
56
- canAddRemarks,
15
+ canViewSchedules: can("see-all-schedules"),
16
+ canViewScheduleDetails: can("see-schedule-details"),
17
+ canDownloadSchedule: can("download-schedule"),
18
+ canManageScheduleTasks: can("manage-schedule-tasks"),
19
+ canGenerateChecklist: can("generate-checklist"),
20
+ canViewHistory: can("view-history"),
21
+ canAddRemarks: can("add-remarks"),
57
22
  };
58
23
  }
@@ -27,6 +27,7 @@ export default function useEquipment() {
27
27
  name: payload.name,
28
28
  unitOfMeasurement: payload.unitOfMeasurement,
29
29
  serviceType,
30
+ ...(payload.attachment ? { attachment: payload.attachment } : {}),
30
31
  },
31
32
  }
32
33
  );
@@ -40,6 +41,7 @@ export default function useEquipment() {
40
41
  body: {
41
42
  name: payload.name,
42
43
  unitOfMeasurement: payload.unitOfMeasurement,
44
+ ...(payload.attachment ? { attachment: payload.attachment } : {}),
43
45
  },
44
46
  }
45
47
  );
@@ -183,4 +183,4 @@ export default function useLocalAuth() {
183
183
  updateVerificationStatus,
184
184
  signUp,
185
185
  };
186
- }
186
+ }
@@ -34,6 +34,8 @@ function mapLogToSummaryRow(log: Record<string, any>, index: number): NFCPatrolS
34
34
  id: log._id,
35
35
  routeName: `${index + 1}. ${log.route?.name ?? "-"}`,
36
36
  securityCheckSchedule: log.route?.startTime ?? "-",
37
+ guardName: log.sign?.guardName,
38
+ guardSignatureFileId: log.sign?.guardSignatureFileId,
37
39
  checked,
38
40
  missed,
39
41
  status: missed === 0 ? "Completed" : "Incomplete",
@@ -63,15 +65,12 @@ export function useNFCPatrolDailyReport(
63
65
 
64
66
  try {
65
67
  const [logsRes, siteInfo] = await Promise.all([
66
- getPatrolLogs<NFCPatrolLogListResponse>({
68
+ getPatrolLogs({
67
69
  page: 1,
68
70
  limit: 100,
69
71
  site,
70
72
  date: filters.date,
71
73
  routeId: filters.route,
72
- routeStartTime: filters.timeRange
73
- ? filters.timeRange.split(" - ")[0]
74
- : undefined,
75
74
  }),
76
75
  getSiteById(site),
77
76
  ]);
@@ -2,6 +2,8 @@ import type {
2
2
  NFCPatrolReportFilters,
3
3
  NFCPatrolSummaryReport,
4
4
  NFCPatrolReportSummaryRow,
5
+ NFCPatrolMonthlyReportRow,
6
+ NFCPatrolMonthlyReport,
5
7
  } from "../types/nfc-patrol-report";
6
8
  import useNFCPatrolLog from "./useNFCPatrolLog";
7
9
  import useSite from "./useSite";
@@ -12,6 +14,55 @@ interface NFCPatrolLogListResponse {
12
14
  pageRange?: string;
13
15
  }
14
16
 
17
+ const MONTHS = [
18
+ "January",
19
+ "February",
20
+ "March",
21
+ "April",
22
+ "May",
23
+ "June",
24
+ "July",
25
+ "August",
26
+ "September",
27
+ "October",
28
+ "November",
29
+ "December",
30
+ ];
31
+ function mapLogsToMonthlyRows(
32
+ logs: Record<string, any>[],
33
+ ): NFCPatrolMonthlyReportRow[] {
34
+ const rows = MONTHS.map((month) => ({
35
+ month,
36
+ checked: 0,
37
+ checkedPercentage: 0,
38
+ missed: 0,
39
+ missedPercentage: 0,
40
+ }));
41
+
42
+ logs.forEach((log) => {
43
+ const monthIndex = new Date(log.date).getMonth();
44
+
45
+ for (const checkpoint of log.checkPoints ?? []) {
46
+ if (checkpoint.status === "Completed") {
47
+ rows[monthIndex].checked++;
48
+ } else if (checkpoint.status === "Skipped") {
49
+ rows[monthIndex].missed++;
50
+ }
51
+ }
52
+ });
53
+
54
+ rows.forEach((row) => {
55
+ const total = row.checked + row.missed;
56
+
57
+ if (total > 0) {
58
+ row.checkedPercentage = Math.round((row.checked / total) * 100);
59
+ row.missedPercentage = Math.round((row.missed / total) * 100);
60
+ }
61
+ });
62
+
63
+ return rows;
64
+ }
65
+
15
66
  function buildAddress(address?: Record<string, string>) {
16
67
  if (!address) return undefined;
17
68
 
@@ -27,23 +78,7 @@ function buildAddress(address?: Record<string, string>) {
27
78
  return parts.length ? parts.join(", ") : undefined;
28
79
  }
29
80
 
30
- function mapLogToSummaryRow(
31
- log: Record<string, any>,
32
- index: number,
33
- ): NFCPatrolReportSummaryRow {
34
- const checkpoints: Record<string, any>[] = log.checkPoints ?? [];
35
- const checked = checkpoints.filter((cp) => cp.status === "Completed").length;
36
- const missed = checkpoints.filter((cp) => cp.status === "Skipped").length;
37
81
 
38
- return {
39
- id: log._id,
40
- routeName: `${index + 1}. ${log.route?.name ?? "-"}`,
41
- securityCheckSchedule: log.route?.startTime ?? "-",
42
- checked,
43
- missed,
44
- status: missed === 0 ? "Completed" : "Incomplete",
45
- };
46
- }
47
82
 
48
83
  export function useNFCPatrolMonthlyReport(
49
84
  filters: NFCPatrolReportFilters,
@@ -52,12 +87,12 @@ export function useNFCPatrolMonthlyReport(
52
87
  const { getAll: getPatrolLogs } = useNFCPatrolLog();
53
88
  const { getSiteById } = useSite();
54
89
 
55
- const report = ref<NFCPatrolSummaryReport | null>(null);
90
+ const report = ref<NFCPatrolMonthlyReport | null>(null);
56
91
  const loading = ref(false);
57
92
  const notFound = ref(false);
58
93
 
59
94
  async function fetchReport() {
60
- if (!site || !filters.date || !filters.route) {
95
+ if (!site || !filters.route) {
61
96
  report.value = null;
62
97
  notFound.value = false;
63
98
  return;
@@ -65,19 +100,16 @@ export function useNFCPatrolMonthlyReport(
65
100
 
66
101
  loading.value = true;
67
102
  notFound.value = false;
68
-
103
+ const currentYear = new Date().getFullYear().toString();
69
104
  try {
70
105
  const [logsRes, siteInfo] = await Promise.all([
71
- getPatrolLogs<NFCPatrolLogListResponse>({
72
- page: 1,
73
- limit: 100,
74
- site,
75
- date: filters.date,
76
- routeId: filters.route,
77
- routeStartTime: filters.timeRange
78
- ? filters.timeRange.split(" - ")[0]
79
- : undefined,
80
- type: "month",
106
+ getPatrolLogs({
107
+ page: 1,
108
+ limit: 100,
109
+ site,
110
+ routeId: filters.route,
111
+ date: currentYear,
112
+ type: "month",
81
113
  }),
82
114
  getSiteById(site),
83
115
  ]);
@@ -93,7 +125,7 @@ export function useNFCPatrolMonthlyReport(
93
125
  address: buildAddress(siteInfo.address),
94
126
  },
95
127
  title: `Patrol Route Summary: ${routeName}`,
96
- rows: logs.map(mapLogToSummaryRow),
128
+ rows: mapLogsToMonthlyRows(logs),
97
129
  };
98
130
  } else {
99
131
  report.value = null;
@@ -51,6 +51,8 @@ function mapLogToPatrolReport(
51
51
  const activities: NFCPatrolActivity[] = checkpoints.map((cp) => ({
52
52
  id: cp.nfcTag_id,
53
53
  checkpoint: cp.nfcTag_name,
54
+ guardName: log.sign?.guardName,
55
+ guardSignatureFileId: log.sign?.guardSignatureFileId,
54
56
  startTime: formatTime(cp.startDateTime),
55
57
  endTime: formatTime(cp.endDateTime),
56
58
  actualTime: diffMinutes(cp.startDateTime, cp.endDateTime),
@@ -236,6 +236,26 @@ export default function useServiceProvider() {
236
236
  );
237
237
  }
238
238
 
239
+ async function getByEmail({
240
+ email = "",
241
+ orgId = "",
242
+ siteId = "",
243
+ serviceProviderOrgId = "",
244
+ } = {}) {
245
+ return useNuxtApp().$api<Record<string, any>>(
246
+ "/api/service-providers/email",
247
+ {
248
+ method: "GET",
249
+ query: {
250
+ email,
251
+ ...(orgId ? { orgId } : {}),
252
+ ...(siteId ? { siteId } : {}),
253
+ ...(serviceProviderOrgId ? { serviceProviderOrgId } : {}),
254
+ },
255
+ }
256
+ );
257
+ }
258
+
239
259
  return {
240
260
  serviceProviders,
241
261
  serviceProvider,
@@ -254,5 +274,6 @@ export default function useServiceProvider() {
254
274
  add,
255
275
  addViaInvite,
256
276
  updateStatus,
277
+ getByEmail,
257
278
  };
258
279
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@7365admin1/layer-common",
3
3
  "license": "MIT",
4
4
  "type": "module",
5
- "version": "3.1.2",
5
+ "version": "3.1.3-staging.40",
6
6
  "author": "7365admin1",
7
7
  "main": "./nuxt.config.ts",
8
8
  "publishConfig": {
@@ -41,4 +41,5 @@ type TSiteCategory =
41
41
  | "shopping_mall"
42
42
  | "mix_development"
43
43
  | "industrial"
44
- | "co_working_co_living";
44
+ | "co_working"
45
+ | "co_living";
@@ -6,6 +6,10 @@ declare type TEquipment = {
6
6
  unitOfMeasurement: string;
7
7
  createdAt: string;
8
8
  updatedAt: string;
9
+ attachment?: string;
9
10
  };
10
11
 
11
- declare type TEquipmentCreate = Pick<TEquipment, "name" | "unitOfMeasurement">;
12
+ declare type TEquipmentCreate = Pick<
13
+ TEquipment,
14
+ "name" | "unitOfMeasurement" | "attachment"
15
+ >;
@@ -26,7 +26,7 @@ export interface NFCPatrolReportFilterOptions {
26
26
 
27
27
  export interface NFCPatrolReportLocation {
28
28
  name?: string;
29
- address?: string;
29
+ address?: string;
30
30
  }
31
31
 
32
32
  export interface NFCPatrolRouteSummary {
@@ -47,6 +47,8 @@ export interface NFCPatrolRouteSummary {
47
47
  export interface NFCPatrolActivity {
48
48
  id: string;
49
49
  checkpoint: string;
50
+ guardName?: string;
51
+ guardSignatureFileId?: string;
50
52
  startTime: string;
51
53
  endTime: string;
52
54
  actualTime: string;
@@ -67,6 +69,8 @@ export interface NFCPatrolReportSummaryRow {
67
69
  id: string;
68
70
  routeName: string;
69
71
  securityCheckSchedule: string;
72
+ guardName?: string;
73
+ guardSignatureFileId?: string;
70
74
  checked: number;
71
75
  missed: number;
72
76
  status: NFCPatrolReportSummaryStatus;
@@ -77,3 +81,17 @@ export interface NFCPatrolSummaryReport {
77
81
  title: string;
78
82
  rows: NFCPatrolReportSummaryRow[];
79
83
  }
84
+
85
+ export interface NFCPatrolMonthlyReportRow {
86
+ month: string;
87
+ checked: number;
88
+ checkedPercentage: number;
89
+ missed: number;
90
+ missedPercentage: number;
91
+ }
92
+
93
+ export interface NFCPatrolMonthlyReport {
94
+ location: NFCPatrolReportLocation;
95
+ title: string;
96
+ rows: NFCPatrolMonthlyReportRow[];
97
+ }