@7365admin1/layer-common 1.11.2 → 1.11.6

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.
@@ -289,6 +289,7 @@
289
289
 
290
290
  <script setup lang="ts">
291
291
  import useBuildingUnit from '../composables/useBuildingUnit';
292
+ import useWebUsb from '../composables/useWebUsb';
292
293
 
293
294
 
294
295
  const prop = defineProps({
@@ -322,7 +323,8 @@ const { requiredRule, debounce, UTCToLocalTIme } = useUtils();
322
323
  const { getSiteById, getSiteLevels, getSiteUnits } = useSiteSettings();
323
324
  const { createVisitor, typeFieldMap, contractorTypes, getVisitors, updateVisitor } = useVisitor();
324
325
  const { getBySiteId: getEntryPassSettingsBySiteId } = useSiteEntryPassSettings();
325
- const { createVisitorPass } = useAccessManagement();
326
+ const { createVisitorPass, signQr } = useAccessManagement();
327
+ const { testConnection } = useWebUsb();
326
328
  const { findPersonByNRIC, findPersonByContact, searchCompanyList, findUsersByPlateNumber } = usePeople()
327
329
  const { getById: getUnitDataById } = useBuildingUnit()
328
330
 
@@ -353,7 +355,7 @@ const visitor = reactive<Partial<TVisitorPayload>>({
353
355
  members: [],
354
356
  });
355
357
 
356
- const passType = ref("");
358
+ const passType = ref<string | null>(null);
357
359
  const passQuantity = ref<number | null>(1);
358
360
  const passCards = ref<{ _id: string; cardNo: string }[]>([]);
359
361
 
@@ -655,15 +657,9 @@ function handleAutofillDataViaVehicleNumber(item: TPeople) {
655
657
  const {
656
658
  data: entryPassSettings,
657
659
  pending: entryPassSettingsPending,
658
- refresh: refreshEntryPassSettings,
659
- } = useLazyAsyncData(`fetch-entrypass-settings-${prop.site}`, () => {
660
- if (contractorStep.value !== 2) return Promise.resolve(null);
661
- return getEntryPassSettingsBySiteId(prop.site);
662
- });
663
-
664
- watch(contractorStep, (step) => {
665
- if (step === 2) refreshEntryPassSettings();
666
- });
660
+ } = useLazyAsyncData(`fetch-entrypass-settings-${prop.site}`, () =>
661
+ getEntryPassSettingsBySiteId(prop.site)
662
+ );
667
663
 
668
664
  const {
669
665
  data: siteData,
@@ -908,10 +904,13 @@ async function submit() {
908
904
  const res = await createVisitor(payload);
909
905
  if (res) {
910
906
  if (prop.type === "contractor" && passType.value) {
911
- const visitorId = res?._id;
912
- const acmUrl = entryPassSettings.value?.data?.settings?.acm_url;
907
+ const visitorId = res as unknown as string;
908
+ const rawUrl = entryPassSettings.value?.data?.settings?.url;
909
+ const { encrypted: acmUrl } = await $fetch<{ encrypted: string }>(
910
+ `/api/encrypt-acm-url${rawUrl ? `?url=${encodeURIComponent(rawUrl)}` : ""}`
911
+ );
913
912
  if (visitorId && acmUrl) {
914
- await createVisitorPass({
913
+ const passRes = await createVisitorPass({
915
914
  site: prop.site,
916
915
  unitId: visitor.unit!,
917
916
  quantity: passQuantity.value ?? 1,
@@ -920,6 +919,37 @@ async function submit() {
920
919
  acm_url: acmUrl,
921
920
  visitorId,
922
921
  });
922
+
923
+ if (passType.value === "QR") {
924
+ const accessCards: any[] = (passRes as any)?.accessCards ?? [];
925
+ const printer = entryPassSettings.value?.data?.settings?.printer;
926
+ if (printer?.vendorId && printer?.productId && accessCards.length) {
927
+ const vendorId = parseInt(printer.vendorId);
928
+ const productId = parseInt(printer.productId);
929
+ const companyName = visitor.company || "";
930
+ const blockLabel = blocksArray.value.find((b: any) => b.value === visitor.block)?.title || "";
931
+ const levelLabel = levelsArray.value.find((l: any) => l.value === visitor.level)?.title || "";
932
+ const unitLabel = unitsArray.value.find((u: any) => u.value === visitor.unit)?.title || "";
933
+ const address = [blockLabel, levelLabel, unitLabel].filter(Boolean).join("/");
934
+
935
+ await nextTick();
936
+ for (const qrCode of accessCards) {
937
+ const signed = await signQr({ cardId: qrCode._id, purpose: "vms" });
938
+ const qrData = signed?.data;
939
+ if (!qrData) continue;
940
+ await testConnection(
941
+ vendorId,
942
+ productId,
943
+ true,
944
+ qrData,
945
+ qrCode.accessLevel,
946
+ qrCode.liftAccessLevel,
947
+ companyName,
948
+ address,
949
+ );
950
+ }
951
+ }
952
+ }
923
953
  }
924
954
  }
925
955
  if (createMore.value) {
@@ -279,6 +279,16 @@ export default function useAccessManagement() {
279
279
  );
280
280
  }
281
281
 
282
+ function signQr(payload: { cardId: string; purpose: string }) {
283
+ return useNuxtApp().$api<{ message: string; data: string }>(
284
+ `/api/access-management/sign-qr`,
285
+ {
286
+ method: "POST",
287
+ body: payload,
288
+ }
289
+ );
290
+ }
291
+
282
292
  return {
283
293
  getDoorAccessLevels,
284
294
  getLiftAccessLevels,
@@ -299,5 +309,6 @@ export default function useAccessManagement() {
299
309
  getAvailableContractorCards,
300
310
  generateQrVms,
301
311
  createVisitorPass,
312
+ signQr,
302
313
  };
303
314
  }
@@ -5,6 +5,7 @@ export default function useAreas() {
5
5
  page = 1,
6
6
  limit = 10,
7
7
  type = "",
8
+ serviceType = "",
8
9
  } = {}) {
9
10
  return useNuxtApp().$api<Record<string, any>>(
10
11
  `/api/hygiene-areas/site/${site}`,
@@ -15,6 +16,7 @@ export default function useAreas() {
15
16
  page,
16
17
  limit,
17
18
  type,
19
+ serviceType,
18
20
  },
19
21
  },
20
22
  );
@@ -30,6 +32,7 @@ export default function useAreas() {
30
32
  set: payload.set,
31
33
  type: payload.type,
32
34
  units: payload.units,
35
+ serviceType: payload.serviceType,
33
36
  },
34
37
  },
35
38
  );
@@ -46,7 +46,7 @@ export default function useComment() {
46
46
  "/api/comments/v1",
47
47
  {
48
48
  method: "POST",
49
- body: payload,
49
+ body: JSON.stringify(payload),
50
50
  }
51
51
  );
52
52
  }
@@ -0,0 +1,140 @@
1
+ export default function(){
2
+
3
+ function generateTimeSlots(
4
+ intervalHours: number,
5
+ startTime?: string | null,
6
+ endTime?: string | null
7
+ ): TTimeSlotOption[] {
8
+ if (!intervalHours || intervalHours <= 0) {
9
+ throw new Error("Interval must be greater than 0");
10
+ }
11
+
12
+ const intervalMinutes = intervalHours * 60;
13
+ const startMinutes = toMinutes(startTime ?? "00:00");
14
+ const endMinutes = toMinutes(endTime ?? "24:00");
15
+
16
+ const slots: TTimeSlotOption[] = [];
17
+ let key = 1;
18
+
19
+ let current = startMinutes + intervalMinutes;
20
+
21
+ for (; current <= endMinutes; current += intervalMinutes) {
22
+ slots.push({
23
+ key: key++,
24
+ time: toTimeString(current),
25
+ disabled: false
26
+ });
27
+ }
28
+
29
+ return slots;
30
+ }
31
+
32
+ const toMinutes = (time: string): number => {
33
+ const [h, m] = time.split(":").map(Number);
34
+ return h * 60 + m;
35
+ };
36
+
37
+ const toTimeString = (minutes: number): string => {
38
+ const hours = Math.floor(minutes / 60);
39
+ const mins = minutes % 60;
40
+ return `${hours.toString().padStart(2, "0")}:${mins.toString().padStart(2, "0")}`;
41
+ };
42
+
43
+ function generateTimeSlotsFromStart(
44
+ intervalHours: number,
45
+ startTime?: string | null,
46
+ endTime?: string | null
47
+ ): TTimeSlotOption[] {
48
+ if (!intervalHours || intervalHours <= 0) {
49
+ throw new Error("Interval must be greater than 0");
50
+ }
51
+
52
+ const intervalMinutes = intervalHours * 60;
53
+ const startMinutes = toMinutes(startTime ?? "00:00");
54
+ const endMinutes = toMinutes(endTime ?? "24:00");
55
+
56
+ const slots: TTimeSlotOption[] = [];
57
+ let key = 1;
58
+
59
+ let current = startMinutes
60
+
61
+ for (; current <= endMinutes; current += intervalMinutes) {
62
+ slots.push({
63
+ key: key++,
64
+ time: toTimeString(current),
65
+ disabled: false
66
+ });
67
+ }
68
+
69
+ return slots;
70
+ }
71
+
72
+ // 11/24/2025, 09:05 format
73
+ function toLocalTimeNumeric(utcString: string) {
74
+ return new Date(utcString).toLocaleString("en-US", {
75
+ year: "numeric",
76
+ month: "2-digit",
77
+ day: "2-digit",
78
+ hour: "2-digit",
79
+ minute: "2-digit",
80
+ hour12: false,
81
+ })
82
+ }
83
+
84
+
85
+
86
+ const monthlyOptions = [
87
+ { value: 1, title: "1st" },
88
+ { value: 2, title: "2nd" },
89
+ { value: 3, title: "3rd" },
90
+ { value: 4, title: "4th" },
91
+ { value: 5, title: "5th" },
92
+ { value: 6, title: "6th" },
93
+ { value: 7, title: "7th" },
94
+ { value: 8, title: "8th" },
95
+ { value: 9, title: "9th" },
96
+ { value: 10, title: "10th" },
97
+ { value: 11, title: "11th" },
98
+ { value: 12, title: "12th" },
99
+ { value: 13, title: "13th" },
100
+ { value: 14, title: "14th" },
101
+ { value: 15, title: "15th" },
102
+ { value: 16, title: "16th" },
103
+ { value: 17, title: "17th" },
104
+ { value: 18, title: "18th" },
105
+ { value: 19, title: "19th" },
106
+ { value: 20, title: "20th" },
107
+ { value: 21, title: "21st" },
108
+ { value: 22, title: "22nd" },
109
+ { value: 23, title: "23rd" },
110
+ { value: 24, title: "24th" },
111
+ { value: 25, title: "25th" },
112
+ { value: 26, title: "26th" },
113
+ { value: 27, title: "27th" },
114
+ { value: 28, title: "28th" },
115
+ { value: "Last Day", title: "Last Day" }
116
+ ];
117
+
118
+
119
+ function defaultCurrencyObject (){
120
+
121
+ return {
122
+ symbol: "S$",
123
+ code: "SGD",
124
+ taxType: "GST",
125
+ }
126
+ }
127
+
128
+
129
+ return {
130
+ generateTimeSlots,
131
+ toMinutes,
132
+ toTimeString,
133
+ generateTimeSlotsFromStart,
134
+ monthlyOptions,
135
+ toLocalTimeNumeric,
136
+ defaultCurrencyObject
137
+
138
+ }
139
+
140
+ }
@@ -82,7 +82,7 @@ export default function useFeedback() {
82
82
  dateTo?: any;
83
83
  date?: any;
84
84
  status?: string;
85
- provider?: string;
85
+ provider?: string | any;
86
86
  service?: string;
87
87
  userId?: string;
88
88
  } = {}) {
@@ -24,6 +24,7 @@ export default function useLocalAuth() {
24
24
  role: "",
25
25
  primaryPhone: "",
26
26
  mobilePhone: "",
27
+ serviceProviders: [],
27
28
  };
28
29
 
29
30
  const currentUser = useState(
@@ -0,0 +1,78 @@
1
+ export default function () {
2
+
3
+ type GetOvernightParkingRequestsParams = {
4
+ page?: number
5
+ limit?: number
6
+ order?: "asc" | "desc"
7
+ site?: string
8
+ status?: string
9
+ }
10
+
11
+ async function getOvernightParkingRequests({
12
+ page = 1,
13
+ limit = 10,
14
+ order = "desc",
15
+ site = "",
16
+ status = "",
17
+ }: GetOvernightParkingRequestsParams = {}) {
18
+ return await useNuxtApp().$api<Record<string, any>>(
19
+ "/api/overnight-parking-requests",
20
+ {
21
+ method: "GET",
22
+ query: {
23
+ page,
24
+ limit,
25
+ order,
26
+ site,
27
+ status,
28
+ },
29
+ }
30
+ );
31
+ }
32
+
33
+ async function getOvernightParkingRequestById(_id: string) {
34
+ return await useNuxtApp().$api<TOvernightParkingRequest>(
35
+ `/api/overnight-parking-requests/id/${_id}`,
36
+ {
37
+ method: "GET",
38
+ }
39
+ );
40
+ }
41
+
42
+ async function createOvernightParkingRequest(payload: Partial<TOvernightParkingRequest>) {
43
+ return await useNuxtApp().$api<TOvernightParkingRequest>(
44
+ "/api/overnight-parking-requests",
45
+ {
46
+ method: "POST",
47
+ body: payload,
48
+ }
49
+ );
50
+ }
51
+
52
+ async function updateOvernightParkingRequest(_id: string, payload: Partial<TOvernightParkingRequest>) {
53
+ return await useNuxtApp().$api<TOvernightParkingRequest>(
54
+ `/api/overnight-parking-requests/id/${_id}`,
55
+ {
56
+ method: "PUT",
57
+ body: payload,
58
+ }
59
+ );
60
+ }
61
+
62
+ async function deleteOvernightParkingRequest(_id: string) {
63
+ return await useNuxtApp().$api<Record<string, any>>(
64
+ `/api/overnight-parking-requests/id/${_id}`,
65
+ {
66
+ method: "DELETE",
67
+ }
68
+ );
69
+ }
70
+
71
+ return {
72
+ getOvernightParkingRequests,
73
+ getOvernightParkingRequestById,
74
+ createOvernightParkingRequest,
75
+ updateOvernightParkingRequest,
76
+ deleteOvernightParkingRequest,
77
+ };
78
+ }
@@ -108,6 +108,25 @@ export default function () {
108
108
  );
109
109
  }
110
110
 
111
+ async function getOvernightParkingAvailability(siteId: string): Promise<{ data: TOvernightParkingAvailability }> {
112
+ return await useNuxtApp().$api<TOvernightParkingAvailability>(
113
+ `/api/overnight-parking-approval-settings/site/${siteId}`,
114
+ {
115
+ method: "GET",
116
+ }
117
+ );
118
+ }
119
+
120
+ async function updateOvernightParkingAvailability(siteId: string, payload: TOvernightParkingAvailability) {
121
+ return await useNuxtApp().$api<Record<string, any>>(
122
+ `/api/overnight-parking-approval-settings/site/${siteId}`,
123
+ {
124
+ method: "PUT",
125
+ body: JSON.stringify(payload),
126
+ }
127
+ );
128
+ }
129
+
111
130
  return {
112
131
  getSiteById,
113
132
  getSiteLevels,
@@ -119,5 +138,7 @@ export default function () {
119
138
  updateSiteCamera,
120
139
  deleteSiteCameraById,
121
140
  updateSitebyId,
141
+ getOvernightParkingAvailability,
142
+ updateOvernightParkingAvailability
122
143
  };
123
144
  }
@@ -4,6 +4,7 @@ export default function useUnits() {
4
4
  search = "",
5
5
  page = 1,
6
6
  limit = 10,
7
+ serviceType = "",
7
8
  } = {}) {
8
9
  return useNuxtApp().$api<Record<string, any>>(
9
10
  `/api/hygiene-units/site/${site}`,
@@ -13,20 +14,22 @@ export default function useUnits() {
13
14
  search,
14
15
  page,
15
16
  limit,
17
+ serviceType,
16
18
  },
17
- },
19
+ }
18
20
  );
19
21
  }
20
22
 
21
- function createUnit(name: string, site: string) {
23
+ function createUnit(name: string, site: string, serviceType: string) {
22
24
  return useNuxtApp().$api<Record<string, any>>(
23
25
  `/api/hygiene-units/site/${site}`,
24
26
  {
25
27
  method: "POST",
26
28
  body: {
27
29
  name,
30
+ serviceType,
28
31
  },
29
- },
32
+ }
30
33
  );
31
34
  }
32
35
 
@@ -38,7 +41,7 @@ export default function useUnits() {
38
41
  body: {
39
42
  name,
40
43
  },
41
- },
44
+ }
42
45
  );
43
46
  }
44
47
 
@@ -47,7 +50,7 @@ export default function useUnits() {
47
50
  `/api/hygiene-units/id/${id}`,
48
51
  {
49
52
  method: "DELETE",
50
- },
53
+ }
51
54
  );
52
55
  }
53
56
 
@@ -60,7 +63,7 @@ export default function useUnits() {
60
63
  {
61
64
  method: "POST",
62
65
  body: formData,
63
- },
66
+ }
64
67
  );
65
68
  }
66
69
 
@@ -9,6 +9,7 @@ export default function useWorkOrder() {
9
9
  status?: string;
10
10
  assignee?: string | TUser;
11
11
  assigneeName?: string;
12
+ assigneeInfo?: Record<string, any>;
12
13
  attachments?: string[];
13
14
  createdBy?: string | TUser;
14
15
  createdByName?: string;
@@ -66,33 +67,63 @@ export default function useWorkOrder() {
66
67
 
67
68
  async function getWorkOrders({
68
69
  page = 1,
69
- site = "",
70
- status = "to-do",
71
- search = "",
72
70
  limit = 10,
73
- category = "",
71
+ organization,
72
+ provider,
73
+ providerService,
74
+ site,
75
+ status,
76
+ startDate = "",
77
+ endDate = "",
78
+ date,
79
+ search = "",
80
+ }: {
81
+ page?: number;
82
+ limit?: number;
83
+ search?: string;
84
+ startDate?: any;
85
+ endDate?: any;
86
+ date?: any;
87
+ status?: string;
88
+ organization?: string;
89
+ site?: string;
90
+ provider?: string | any;
91
+ providerService?: string;
92
+ service?: string;
74
93
  } = {}) {
75
- try {
76
- return useNuxtApp().$api<Record<string, any>>(
77
- `/api/work-orders/site/${site}/status/${status}`,
78
- {
79
- method: "GET",
80
- query: { page, search, limit, category },
81
- }
82
- );
83
- } catch (err) {
84
- console.error(err);
85
- }
94
+ return useNuxtApp().$api<Record<string, any>[]>("/api/work-orders2/v1", {
95
+ method: "GET",
96
+ query: {
97
+ page,
98
+ limit,
99
+ search,
100
+ status,
101
+ startDate,
102
+ endDate,
103
+ date,
104
+ organization,
105
+ site,
106
+ provider,
107
+ providerService,
108
+ },
109
+ });
86
110
  }
87
111
 
88
112
  function getWorkOrderById(id: string) {
89
- return useNuxtApp().$api<TWorkOrder>(`/api/work-orders/${id}`, {
113
+ return useNuxtApp().$api<TWorkOrder>(`/api/work-orders2/v1/id/${id}`, {
90
114
  method: "GET",
91
115
  });
92
116
  }
93
117
 
94
- function createWorkOrder(payload: TWorkOrderCreate) {
95
- return useNuxtApp().$api<Record<string, any>>("/api/work-orders", {
118
+ function createWorkOrder(payload: any) {
119
+ return useNuxtApp().$api<Record<string, any>>("/api/work-orders2/v1", {
120
+ method: "POST",
121
+ body: payload,
122
+ });
123
+ }
124
+
125
+ function updateStatusWorkOrder(payload: any) {
126
+ return useNuxtApp().$api("/api/work-orders2/status-update", {
96
127
  method: "POST",
97
128
  body: payload,
98
129
  });
@@ -140,6 +171,7 @@ export default function useWorkOrder() {
140
171
  pages,
141
172
  pageRange,
142
173
  createWorkOrder,
174
+ updateStatusWorkOrder,
143
175
  getWorkOrders,
144
176
  getWorkOrderById,
145
177
  updateWorkOrder,
package/nuxt.config.ts CHANGED
@@ -17,7 +17,7 @@ export default defineNuxtConfig({
17
17
  APP: (process.env.APP as string) ?? "App",
18
18
  API_DO_STORAGE_ENDPOINT:
19
19
  (process.env.API_DO_STORAGE_ENDPOINT as string) ?? "",
20
- API_DO_STORAGE_ENDPOINT_ANPR:
20
+ API_DO_STORAGE_ENDPOINT_ANPR:
21
21
  (process.env.API_DO_STORAGE_ENDPOINT_ANPR as string) ?? "",
22
22
  APP_NAME: (process.env.APP_NAME as string) ?? "App",
23
23
  APP_NAME_ROUTE: (process.env.APP_NAME_ROUTE as string) ?? "index",
@@ -47,6 +47,7 @@ export default defineNuxtConfig({
47
47
  config.plugins.push(vuetify({ autoImport: true }));
48
48
  });
49
49
  },
50
+ "nuxt-signature-pad",
50
51
  ],
51
52
 
52
53
  vite: {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@7365admin1/layer-common",
3
3
  "license": "MIT",
4
4
  "type": "module",
5
- "version": "1.11.2",
5
+ "version": "1.11.6",
6
6
  "author": "7365admin1",
7
7
  "main": "./nuxt.config.ts",
8
8
  "publishConfig": {
@@ -31,7 +31,7 @@ definePageMeta({
31
31
  layout: "plain",
32
32
  });
33
33
 
34
- const { APP_ACCOUNT, APP_NAME, APP_ORG } = useRuntimeConfig().public;
34
+ const { APP_ACCOUNT, APP_NAME, APP_ORG, APP } = useRuntimeConfig().public;
35
35
 
36
36
  function goToAccount() {
37
37
  window.location.href = `${APP_ACCOUNT}/home`;
@@ -39,9 +39,9 @@ function goToAccount() {
39
39
 
40
40
  function createOrg() {
41
41
  if (APP_NAME.toLowerCase() === "org") {
42
- navigateTo({ name: "organizations-create" });
42
+ navigateTo({ name: "organizations-create", query: { app: APP as string ?? "" } });
43
43
  } else {
44
- window.location.href = `${APP_ORG}/organizations/create`;
44
+ window.location.href = `${APP_ORG}/organizations/create?app=${APP as string ?? ""}`;
45
45
  }
46
46
  }
47
47
  </script>
package/types/area.d.ts CHANGED
@@ -19,4 +19,5 @@ declare type TAreaCreate = {
19
19
  unit: string;
20
20
  name: string;
21
21
  }>;
22
+ serviceType: string;
22
23
  };
@@ -17,11 +17,22 @@ declare type TCustomerCreate = Pick<
17
17
  declare type TCustomerSite = {
18
18
  name: string;
19
19
  site?: string;
20
- siteOrg: string;
21
- siteOrgName: string;
20
+ siteOrg?: string;
21
+ siteOrgName?: string;
22
22
  org: string;
23
23
  status?: string;
24
24
  createdAt?: string;
25
25
  updatedAt?: string;
26
26
  deletedAt?: string;
27
+ category?: TSiteCategory | string;
28
+ address: {
29
+ line1: string;
30
+ line2: string;
31
+ city: string;
32
+ state: string;
33
+ country: string;
34
+ postalCode: string;
35
+ }
27
36
  };
37
+
38
+ declare type TSiteCategory = "residential" | "commercial" | "industrial" | "institutional" | "mixed_development" | "infrastructure" | "hospitality"
@@ -1,10 +1,11 @@
1
1
  declare type TDashboardValues = "today" | "thisWeek" | "thisMonth";
2
2
 
3
-
4
3
  declare type TDashboardCardValue = {
5
4
  key: string;
6
- periodKey: keyof TPeriodState;
5
+ periodKey: string;
7
6
  title: string;
8
7
  icon: string;
9
8
  color: string;
10
- };
9
+ };
10
+
11
+