@7365admin1/layer-common 3.0.21 → 3.0.23
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 +12 -0
- package/components/DashboardMain.vue +211 -58
- package/components/InvitationMain.vue +32 -3
- package/components/MemberMain.vue +1 -1
- package/components/Nfc/NFCPatrolReportMain.vue +48 -541
- package/components/Nfc/PatrolReport/DailyReportTab.vue +59 -0
- package/components/Nfc/PatrolReport/MonthlyReportTab.vue +59 -0
- package/components/Nfc/PatrolReport/PatrolActivityTable.vue +81 -0
- package/components/Nfc/PatrolReport/PatrolReportTab.vue +73 -0
- package/components/Nfc/PatrolReport/PatrolRouteSummary.vue +63 -0
- package/components/Nfc/PatrolReport/RemarksDialog.vue +37 -0
- package/components/Nfc/PatrolReport/ReportEmptyState.vue +24 -0
- package/components/Nfc/PatrolReport/ReportFilters.vue +88 -0
- package/components/Nfc/PatrolReport/ReportLocationHeader.vue +17 -0
- package/components/Nfc/PatrolReport/SummaryReportTable.vue +51 -0
- package/components/ScheduleTaskMain.vue +47 -12
- package/components/ServiceProviderMain.vue +182 -184
- package/components/UnitMain.vue +8 -1
- package/components/VisitorForm.vue +2 -0
- package/components/VisitorManagement.vue +31 -0
- package/components/VisitorSocketPopUp.vue +292 -0
- package/composables/useNFCPatrolDailyReport.ts +27 -0
- package/composables/useNFCPatrolMonthlyReport.ts +27 -0
- package/composables/useNFCPatrolReport.ts +38 -0
- package/composables/useNFCPatrolReportExport.ts +31 -0
- package/composables/useNFCPatrolReportFilters.ts +39 -0
- package/composables/useVisitor.ts +3 -0
- package/composables/useVisitorSocket.ts +25 -0
- package/package.json +2 -1
- package/services/nfcPatrolReport.ts +172 -0
- package/types/nfc-patrol-report.ts +73 -0
- package/types/verification.d.ts +6 -1
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<!-- <h1>Live Monitoring</h1>
|
|
4
|
+
|
|
5
|
+
Connection Status Indicator
|
|
6
|
+
<div :class="['status-badge', status]">Status: {{ status }}</div>
|
|
7
|
+
<pre>
|
|
8
|
+
path: {{ path }}
|
|
9
|
+
</pre>
|
|
10
|
+
<pre>visitorData: {{ visitorSocketData }}</pre>
|
|
11
|
+
<pre>socketTrigger:{{ socketUnregisteredVisitorTrigger }}</pre>
|
|
12
|
+
|
|
13
|
+
<section v-if="newVisitor">
|
|
14
|
+
<h3>New Plate Detected!</h3>
|
|
15
|
+
<div class="visitor-card">
|
|
16
|
+
<p>
|
|
17
|
+
<strong>Plate Number:</strong>
|
|
18
|
+
{{ newVisitor.plateNumber || "Unknown" }}
|
|
19
|
+
</p>
|
|
20
|
+
<p><strong>Site ID:</strong> {{ newVisitor.site }}</p>
|
|
21
|
+
<p><strong>Time:</strong> {{ new Date().toLocaleTimeString() }}</p>
|
|
22
|
+
</div>
|
|
23
|
+
</section>
|
|
24
|
+
|
|
25
|
+
<section v-if="visitorList.length > 0">
|
|
26
|
+
<h3>Recent History</h3>
|
|
27
|
+
<ul>
|
|
28
|
+
<li v-for="(v, index) in visitorList" :key="index">
|
|
29
|
+
{{ v?.plateNumber }} — {{ new Date().toLocaleTimeString() }}
|
|
30
|
+
</li>
|
|
31
|
+
</ul>
|
|
32
|
+
</section> -->
|
|
33
|
+
|
|
34
|
+
<v-snackbar
|
|
35
|
+
v-if="!isUnregisteredVisitorRoute"
|
|
36
|
+
v-model="snackBarMessage.modal"
|
|
37
|
+
:color="snackBarMessage.color"
|
|
38
|
+
:timeout="snackBarMessage.timeout"
|
|
39
|
+
location="bottom center"
|
|
40
|
+
class="rounded-xl"
|
|
41
|
+
multi-line
|
|
42
|
+
:z-index="100000000"
|
|
43
|
+
>
|
|
44
|
+
<div class="d-flex flex-column align-start ga-2">
|
|
45
|
+
<div class="d-flex align-center ga-2">
|
|
46
|
+
<span class="text-1-4rem mr-2">{{ snackBarMessage.text }}</span>
|
|
47
|
+
</div>
|
|
48
|
+
<v-btn
|
|
49
|
+
v-if="snackBarMessage.isUnregistered"
|
|
50
|
+
rounded="md"
|
|
51
|
+
variant="text"
|
|
52
|
+
color="baseButton"
|
|
53
|
+
class="text-truncate text-decoration-underline px-0"
|
|
54
|
+
@click="goToUnregistered"
|
|
55
|
+
>
|
|
56
|
+
Go to Unregistered
|
|
57
|
+
</v-btn>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<template #actions>
|
|
61
|
+
<v-btn
|
|
62
|
+
icon="mdi-close"
|
|
63
|
+
variant="text"
|
|
64
|
+
@click="handleCloseSnackbar"
|
|
65
|
+
/>
|
|
66
|
+
</template>
|
|
67
|
+
</v-snackbar>
|
|
68
|
+
|
|
69
|
+
<v-dialog v-model="permanentMessageDialog.modal" max-width="480" persistent>
|
|
70
|
+
<v-card>
|
|
71
|
+
<v-card-title class="text-h6">Notice</v-card-title>
|
|
72
|
+
<v-card-text>{{ permanentMessageDialog.text }}</v-card-text>
|
|
73
|
+
<v-card-actions>
|
|
74
|
+
<v-spacer />
|
|
75
|
+
<v-btn
|
|
76
|
+
color="primary"
|
|
77
|
+
variant="elevated"
|
|
78
|
+
@click="permanentMessageDialog.modal = false"
|
|
79
|
+
>
|
|
80
|
+
Close
|
|
81
|
+
</v-btn>
|
|
82
|
+
</v-card-actions>
|
|
83
|
+
</v-card>
|
|
84
|
+
</v-dialog>
|
|
85
|
+
</div>
|
|
86
|
+
</template>
|
|
87
|
+
|
|
88
|
+
<script setup lang="ts">
|
|
89
|
+
import { io, type Socket } from "socket.io-client";
|
|
90
|
+
import type { TVisitorSocketData } from "../composables/useVisitorSocket";
|
|
91
|
+
|
|
92
|
+
const props = defineProps({
|
|
93
|
+
siteId: {
|
|
94
|
+
type: String,
|
|
95
|
+
default: "",
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const config = useRuntimeConfig();
|
|
100
|
+
const publicConfig = config.public as Record<string, string | undefined>;
|
|
101
|
+
const route = useRoute();
|
|
102
|
+
const { tab } = useVisitor();
|
|
103
|
+
const { socketUnregisteredVisitorTrigger, visitorSocketData } =
|
|
104
|
+
useVisitorSocket();
|
|
105
|
+
|
|
106
|
+
const APP_NAME = publicConfig.APP || "";
|
|
107
|
+
|
|
108
|
+
const socket = shallowRef<Socket | null>(null);
|
|
109
|
+
const status = ref("disconnected");
|
|
110
|
+
const newVisitor = ref<TVisitorSocketData | null>(null);
|
|
111
|
+
const visitorList = ref<TVisitorSocketData[]>([]);
|
|
112
|
+
const lastPlateNumber = ref("");
|
|
113
|
+
|
|
114
|
+
const snackBarMessage = reactive({
|
|
115
|
+
timeout: 3000,
|
|
116
|
+
text: "",
|
|
117
|
+
color: "",
|
|
118
|
+
modal: false,
|
|
119
|
+
isUnregistered: false,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const permanentMessageDialog = reactive({
|
|
123
|
+
modal: false,
|
|
124
|
+
text: "",
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const path = computed(() => route.path);
|
|
128
|
+
const isVisitorManagementPath = (path: string) =>
|
|
129
|
+
path.includes("/visitor-management");
|
|
130
|
+
|
|
131
|
+
const isVisitorRoute = computed(
|
|
132
|
+
() =>
|
|
133
|
+
path.value === "/visitors" ||
|
|
134
|
+
isVisitorManagementPath(path.value)
|
|
135
|
+
);
|
|
136
|
+
const isUnregisteredVisitorRoute = computed(
|
|
137
|
+
() => isVisitorRoute.value && route.query.tab === "unregistered"
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const socketBaseUrl = computed(
|
|
141
|
+
() => publicConfig.socketUrl || publicConfig.API_CORE || ""
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const formatDateQuery = (date: Date) => date.toISOString().slice(0, 10);
|
|
145
|
+
|
|
146
|
+
const getDefaultDateQuery = () => {
|
|
147
|
+
const dateTo = new Date();
|
|
148
|
+
const dateFrom = new Date(dateTo);
|
|
149
|
+
dateFrom.setMonth(dateFrom.getMonth() - 1);
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
dateFrom: formatDateQuery(dateFrom),
|
|
153
|
+
dateTo: formatDateQuery(dateTo),
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const handleCloseSnackbar = () => {
|
|
158
|
+
snackBarMessage.modal = false;
|
|
159
|
+
socketUnregisteredVisitorTrigger.value = false;
|
|
160
|
+
newVisitor.value = null;
|
|
161
|
+
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const showTransientMessage = (
|
|
165
|
+
text: string,
|
|
166
|
+
color: string,
|
|
167
|
+
isUnregistered = false
|
|
168
|
+
) => {
|
|
169
|
+
snackBarMessage.text = text;
|
|
170
|
+
snackBarMessage.color = color;
|
|
171
|
+
snackBarMessage.modal = true;
|
|
172
|
+
snackBarMessage.timeout = 20000;
|
|
173
|
+
snackBarMessage.isUnregistered = isUnregistered;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const connectSocket = () => {
|
|
177
|
+
if (!props.siteId || !socketBaseUrl.value || socket.value) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const namespace = `/site-${props.siteId}`;
|
|
182
|
+
socket.value = io(`${socketBaseUrl.value}${namespace}`, {
|
|
183
|
+
path: "/socket.io",
|
|
184
|
+
transports: ["websocket"],
|
|
185
|
+
reconnectionAttempts: 5,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
socket.value.on("connect", () => {
|
|
189
|
+
status.value = "connected";
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
socket.value.on("anpr-messages", (data: TVisitorSocketData) => {
|
|
193
|
+
const plateNumber = data?.plateNumber?.trim() || "";
|
|
194
|
+
const isCheckIn = Boolean(plateNumber);
|
|
195
|
+
const isPlateNumberChanging =
|
|
196
|
+
Boolean(lastPlateNumber.value) && lastPlateNumber.value !== plateNumber;
|
|
197
|
+
|
|
198
|
+
socketUnregisteredVisitorTrigger.value = false;
|
|
199
|
+
visitorSocketData.value = null;
|
|
200
|
+
visitorSocketData.value = data;
|
|
201
|
+
newVisitor.value = data;
|
|
202
|
+
|
|
203
|
+
if (isCheckIn) {
|
|
204
|
+
showTransientMessage(
|
|
205
|
+
`New plate detected: ${plateNumber}`,
|
|
206
|
+
"info",
|
|
207
|
+
true
|
|
208
|
+
);
|
|
209
|
+
lastPlateNumber.value = plateNumber;
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
if (data?.message) {
|
|
215
|
+
showTransientMessage(data.message, "error");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (data?.messagePermanent) {
|
|
219
|
+
permanentMessageDialog.text = data.messagePermanent;
|
|
220
|
+
permanentMessageDialog.modal = true;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
visitorList.value.unshift(data);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
socket.value.on("connect_error", () => {
|
|
227
|
+
status.value = "disconnected";
|
|
228
|
+
});
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const disconnectSocket = () => {
|
|
232
|
+
if (socket.value) {
|
|
233
|
+
socket.value.disconnect();
|
|
234
|
+
socket.value = null;
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const goToUnregistered = async () => {
|
|
239
|
+
tab.value = "unregistered";
|
|
240
|
+
socketUnregisteredVisitorTrigger.value = true;
|
|
241
|
+
snackBarMessage.modal = false;
|
|
242
|
+
|
|
243
|
+
if (route.params.org && route.params.site) {
|
|
244
|
+
const defaultDateQuery = getDefaultDateQuery();
|
|
245
|
+
|
|
246
|
+
if(!APP_NAME) return;
|
|
247
|
+
|
|
248
|
+
await navigateTo({
|
|
249
|
+
path: `/${route.params.org}/${route.params.site}/${APP_NAME === "security_agency" ? "visitor-management" : APP_NAME === "property_management_agency" ? "visitor-mgmt" : "visitor-management"}`,
|
|
250
|
+
query: {
|
|
251
|
+
tab: "unregistered",
|
|
252
|
+
dateFrom: route.query.dateFrom || defaultDateQuery.dateFrom,
|
|
253
|
+
dateTo: route.query.dateTo || defaultDateQuery.dateTo,
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
await navigateTo({
|
|
260
|
+
name: "visitors",
|
|
261
|
+
query: {
|
|
262
|
+
tab: "unregistered",
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
watch(
|
|
268
|
+
() => props.siteId,
|
|
269
|
+
() => {
|
|
270
|
+
disconnectSocket();
|
|
271
|
+
connectSocket();
|
|
272
|
+
},
|
|
273
|
+
{ immediate: true, deep: true }
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
watch(
|
|
277
|
+
() => route.fullPath,
|
|
278
|
+
() => {
|
|
279
|
+
if (isUnregisteredVisitorRoute.value) {
|
|
280
|
+
snackBarMessage.modal = false;
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
{ immediate: true }
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
onUnmounted(() => {
|
|
287
|
+
disconnectSocket();
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
</script>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NFCPatrolReportFilters,
|
|
3
|
+
NFCPatrolSummaryReport,
|
|
4
|
+
} from "../types/nfc-patrol-report";
|
|
5
|
+
import { useNFCPatrolReportService } from "../services/nfcPatrolReport";
|
|
6
|
+
|
|
7
|
+
export function useNFCPatrolDailyReport(filters: NFCPatrolReportFilters) {
|
|
8
|
+
const reportService = useNFCPatrolReportService();
|
|
9
|
+
const report = ref<NFCPatrolSummaryReport | null>(null);
|
|
10
|
+
const loading = ref(false);
|
|
11
|
+
|
|
12
|
+
async function fetchReport() {
|
|
13
|
+
loading.value = true;
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
report.value = await reportService.getDailyReport(filters);
|
|
17
|
+
} finally {
|
|
18
|
+
loading.value = false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
report,
|
|
24
|
+
loading,
|
|
25
|
+
fetchReport,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NFCPatrolReportFilters,
|
|
3
|
+
NFCPatrolSummaryReport,
|
|
4
|
+
} from "../types/nfc-patrol-report";
|
|
5
|
+
import { useNFCPatrolReportService } from "../services/nfcPatrolReport";
|
|
6
|
+
|
|
7
|
+
export function useNFCPatrolMonthlyReport(filters: NFCPatrolReportFilters) {
|
|
8
|
+
const reportService = useNFCPatrolReportService();
|
|
9
|
+
const report = ref<NFCPatrolSummaryReport | null>(null);
|
|
10
|
+
const loading = ref(false);
|
|
11
|
+
|
|
12
|
+
async function fetchReport() {
|
|
13
|
+
loading.value = true;
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
report.value = await reportService.getMonthlyReport(filters);
|
|
17
|
+
} finally {
|
|
18
|
+
loading.value = false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
report,
|
|
24
|
+
loading,
|
|
25
|
+
fetchReport,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NFCPatrolActivity,
|
|
3
|
+
NFCPatrolReport,
|
|
4
|
+
NFCPatrolReportFilters,
|
|
5
|
+
} from "../types/nfc-patrol-report";
|
|
6
|
+
import { useNFCPatrolReportService } from "../services/nfcPatrolReport";
|
|
7
|
+
|
|
8
|
+
export function useNFCPatrolReport(filters: NFCPatrolReportFilters) {
|
|
9
|
+
const reportService = useNFCPatrolReportService();
|
|
10
|
+
const report = ref<NFCPatrolReport | null>(null);
|
|
11
|
+
const loading = ref(false);
|
|
12
|
+
const selectedActivityRemarks = ref("");
|
|
13
|
+
const dialogRemarks = ref(false);
|
|
14
|
+
|
|
15
|
+
async function fetchReport() {
|
|
16
|
+
loading.value = true;
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
report.value = await reportService.getPatrolReport(filters);
|
|
20
|
+
} finally {
|
|
21
|
+
loading.value = false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function openRemarksDialog(activity: NFCPatrolActivity) {
|
|
26
|
+
selectedActivityRemarks.value = activity.remarks || "No remarks provided";
|
|
27
|
+
dialogRemarks.value = true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
report,
|
|
32
|
+
loading,
|
|
33
|
+
selectedActivityRemarks,
|
|
34
|
+
dialogRemarks,
|
|
35
|
+
fetchReport,
|
|
36
|
+
openRemarksDialog,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NFCPatrolReportExportRequest,
|
|
3
|
+
NFCPatrolReportFilters,
|
|
4
|
+
NFCPatrolReportTab,
|
|
5
|
+
} from "../types/nfc-patrol-report";
|
|
6
|
+
import { useNFCPatrolReportService } from "../services/nfcPatrolReport";
|
|
7
|
+
|
|
8
|
+
export function useNFCPatrolReportExport() {
|
|
9
|
+
const reportService = useNFCPatrolReportService();
|
|
10
|
+
const loading = ref(false);
|
|
11
|
+
|
|
12
|
+
async function exportReport(tab: NFCPatrolReportTab, filters: NFCPatrolReportFilters) {
|
|
13
|
+
loading.value = true;
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const request: NFCPatrolReportExportRequest = {
|
|
17
|
+
tab,
|
|
18
|
+
filters,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
await reportService.exportReport(request);
|
|
22
|
+
} finally {
|
|
23
|
+
loading.value = false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
loading,
|
|
29
|
+
exportReport,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NFCPatrolReportFilterOptions,
|
|
3
|
+
NFCPatrolReportFilters,
|
|
4
|
+
} from "../types/nfc-patrol-report";
|
|
5
|
+
import { useNFCPatrolReportService } from "../services/nfcPatrolReport";
|
|
6
|
+
|
|
7
|
+
export function useNFCPatrolReportFilters(site: string) {
|
|
8
|
+
const reportService = useNFCPatrolReportService();
|
|
9
|
+
|
|
10
|
+
const filters = reactive<NFCPatrolReportFilters>({
|
|
11
|
+
route: "WH01 Patrol Route",
|
|
12
|
+
timeRange: "15:00 - 17:00",
|
|
13
|
+
date: "2025-11-27",
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const options = ref<NFCPatrolReportFilterOptions>({
|
|
17
|
+
routes: [],
|
|
18
|
+
timeRanges: [],
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const loading = ref(false);
|
|
22
|
+
|
|
23
|
+
async function fetchOptions() {
|
|
24
|
+
loading.value = true;
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
options.value = await reportService.getFilterOptions(site);
|
|
28
|
+
} finally {
|
|
29
|
+
loading.value = false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
filters,
|
|
35
|
+
options,
|
|
36
|
+
loading,
|
|
37
|
+
fetchOptions,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -94,6 +94,8 @@ export default function () {
|
|
|
94
94
|
tab?: string;
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
+
const tab = useState("visitorsTab", () => "visitor");
|
|
98
|
+
|
|
97
99
|
async function getVisitors({
|
|
98
100
|
page = 1,
|
|
99
101
|
limit = 10,
|
|
@@ -190,6 +192,7 @@ export default function () {
|
|
|
190
192
|
}
|
|
191
193
|
|
|
192
194
|
return {
|
|
195
|
+
tab,
|
|
193
196
|
typeFieldMap,
|
|
194
197
|
visitorSelection,
|
|
195
198
|
contractorTypes,
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type TVisitorSocketData = {
|
|
2
|
+
_id: string;
|
|
3
|
+
site: string;
|
|
4
|
+
plateNumber: string;
|
|
5
|
+
message?: string;
|
|
6
|
+
messagePermanent?: string;
|
|
7
|
+
reload?: boolean;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const useVisitorSocket = () => {
|
|
11
|
+
const socketUnregisteredVisitorTrigger = useState(
|
|
12
|
+
"socketUnregisteredVisitorTrigger",
|
|
13
|
+
() => false,
|
|
14
|
+
);
|
|
15
|
+
const visitorSocketData = useState(
|
|
16
|
+
"visitorSocketData",
|
|
17
|
+
(): TVisitorSocketData | null => null,
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
socketUnregisteredVisitorTrigger,
|
|
23
|
+
visitorSocketData,
|
|
24
|
+
};
|
|
25
|
+
};
|
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.0.
|
|
5
|
+
"version": "3.0.23",
|
|
6
6
|
"author": "7365admin1",
|
|
7
7
|
"main": "./nuxt.config.ts",
|
|
8
8
|
"publishConfig": {
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"qrcode": "^1.5.4",
|
|
41
41
|
"qrcode.vue": "^3.4.1",
|
|
42
42
|
"sass": "^1.80.6",
|
|
43
|
+
"socket.io-client": "^4.8.3",
|
|
43
44
|
"vue-draggable-next": "^2.3.0",
|
|
44
45
|
"vue3-signature": "^0.2.4",
|
|
45
46
|
"vuetify-pro-tiptap": "^2.8.2",
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NFCPatrolReport,
|
|
3
|
+
NFCPatrolReportExportRequest,
|
|
4
|
+
NFCPatrolReportFilterOptions,
|
|
5
|
+
NFCPatrolReportFilters,
|
|
6
|
+
NFCPatrolSummaryReport,
|
|
7
|
+
} from "../types/nfc-patrol-report";
|
|
8
|
+
|
|
9
|
+
const filterOptions: NFCPatrolReportFilterOptions = {
|
|
10
|
+
routes: ["WH01 Patrol Route", "WH02 Patrol Route", "WH03 Patrol Route"],
|
|
11
|
+
timeRanges: ["15:00 - 17:00", "08:00 - 10:00", "13:00 - 15:00", "18:00 - 20:00"],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const location = {
|
|
15
|
+
name: "Winsland Homes",
|
|
16
|
+
address: "221A Upper Thomson Road THOMSON RIDGE ESTATE",
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function useNFCPatrolReportService() {
|
|
20
|
+
async function getFilterOptions(_site: string): Promise<NFCPatrolReportFilterOptions> {
|
|
21
|
+
return filterOptions;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function getPatrolReport(filters: NFCPatrolReportFilters): Promise<NFCPatrolReport> {
|
|
25
|
+
return {
|
|
26
|
+
location,
|
|
27
|
+
routeSummary: {
|
|
28
|
+
routeName: filters.route,
|
|
29
|
+
tolerance: 30,
|
|
30
|
+
schedule: {
|
|
31
|
+
start: "14:00",
|
|
32
|
+
end: "15:00",
|
|
33
|
+
totalTime: "25 mins",
|
|
34
|
+
},
|
|
35
|
+
actual: {
|
|
36
|
+
start: "14:01",
|
|
37
|
+
end: "14:16",
|
|
38
|
+
totalTime: "15 mins",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
activities: [
|
|
42
|
+
{
|
|
43
|
+
id: "1",
|
|
44
|
+
checkpoint: "Point 1 WH01",
|
|
45
|
+
startTime: "14:01",
|
|
46
|
+
endTime: "14:04",
|
|
47
|
+
actualTime: "3:00 mins",
|
|
48
|
+
expectedTime: "5:00 mins",
|
|
49
|
+
status: "Skipped",
|
|
50
|
+
remarks: "Raining",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: "2",
|
|
54
|
+
checkpoint: "Point 2 WH02",
|
|
55
|
+
startTime: "14:04",
|
|
56
|
+
endTime: "14:07",
|
|
57
|
+
actualTime: "3:00 mins",
|
|
58
|
+
expectedTime: "5:00 mins",
|
|
59
|
+
status: "Completed",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "3",
|
|
63
|
+
checkpoint: "Point 3 WH03",
|
|
64
|
+
startTime: "14:07",
|
|
65
|
+
endTime: "15:10",
|
|
66
|
+
actualTime: "3:00 mins",
|
|
67
|
+
expectedTime: "5:00 mins",
|
|
68
|
+
status: "Completed",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "4",
|
|
72
|
+
checkpoint: "Point 4 WH04",
|
|
73
|
+
startTime: "14:10",
|
|
74
|
+
endTime: "14:13",
|
|
75
|
+
actualTime: "3:00 mins",
|
|
76
|
+
expectedTime: "5:00 mins",
|
|
77
|
+
status: "Completed",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: "5",
|
|
81
|
+
checkpoint: "Point 5 WH05",
|
|
82
|
+
startTime: "14:13",
|
|
83
|
+
endTime: "14:16",
|
|
84
|
+
actualTime: "3:00 mins",
|
|
85
|
+
expectedTime: "5:00 mins",
|
|
86
|
+
status: "Completed",
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function getDailyReport(
|
|
93
|
+
filters: NFCPatrolReportFilters,
|
|
94
|
+
): Promise<NFCPatrolSummaryReport> {
|
|
95
|
+
return getSummaryReport(`Patrol Route Summary: ${filters.route}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function getMonthlyReport(
|
|
99
|
+
filters: NFCPatrolReportFilters,
|
|
100
|
+
): Promise<NFCPatrolSummaryReport> {
|
|
101
|
+
return getSummaryReport(`Patrol Route Summary: ${filters.route}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function exportReport(_request: NFCPatrolReportExportRequest): Promise<void> {
|
|
105
|
+
return Promise.resolve();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function getSummaryReport(title: string): NFCPatrolSummaryReport {
|
|
109
|
+
return {
|
|
110
|
+
location,
|
|
111
|
+
title,
|
|
112
|
+
rows: [
|
|
113
|
+
{
|
|
114
|
+
id: "1",
|
|
115
|
+
routeName: "1. WH01",
|
|
116
|
+
securityCheckSchedule: "14:00",
|
|
117
|
+
checked: 22,
|
|
118
|
+
missed: 0,
|
|
119
|
+
status: "Completed",
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: "2",
|
|
123
|
+
routeName: "2. WH01",
|
|
124
|
+
securityCheckSchedule: "15:00",
|
|
125
|
+
checked: 18,
|
|
126
|
+
missed: 3,
|
|
127
|
+
status: "Completed",
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: "3",
|
|
131
|
+
routeName: "3. WH01",
|
|
132
|
+
securityCheckSchedule: "16:00",
|
|
133
|
+
checked: 22,
|
|
134
|
+
missed: 0,
|
|
135
|
+
status: "Completed",
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
id: "4",
|
|
139
|
+
routeName: "4. WH01",
|
|
140
|
+
securityCheckSchedule: "17:00",
|
|
141
|
+
checked: 22,
|
|
142
|
+
missed: 0,
|
|
143
|
+
status: "Completed",
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
id: "5",
|
|
147
|
+
routeName: "5. WH01",
|
|
148
|
+
securityCheckSchedule: "18:00",
|
|
149
|
+
checked: 22,
|
|
150
|
+
missed: 0,
|
|
151
|
+
status: "Completed",
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
id: "6",
|
|
155
|
+
routeName: "6. WH01",
|
|
156
|
+
securityCheckSchedule: "19:00",
|
|
157
|
+
checked: 22,
|
|
158
|
+
missed: 0,
|
|
159
|
+
status: "Completed",
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
getFilterOptions,
|
|
167
|
+
getPatrolReport,
|
|
168
|
+
getDailyReport,
|
|
169
|
+
getMonthlyReport,
|
|
170
|
+
exportReport,
|
|
171
|
+
};
|
|
172
|
+
}
|