@7365admin1/layer-common 1.10.8 → 1.10.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/components/AccessCardAddForm.vue +1 -1
- package/components/AccessCardAssignToUnitForm.vue +1 -1
- package/components/AccessManagement.vue +1 -1
- package/components/Carousel.vue +474 -0
- package/components/DrawImage.vue +172 -0
- package/components/EntryPassInformation.vue +36 -10
- package/components/EquipmentItemMain.vue +9 -4
- package/components/Feedback/Form.vue +4 -4
- package/components/FeedbackMain.vue +748 -145
- package/components/FileInput.vue +289 -0
- package/components/StockCard.vue +11 -7
- package/components/VisitorForm.vue +129 -44
- package/composables/useAccessManagement.ts +41 -18
- package/composables/useEquipmentManagement.ts +63 -0
- package/composables/useFeedback.ts +53 -21
- package/composables/useLocalAuth.ts +29 -1
- package/composables/useUploadFiles.ts +94 -0
- package/composables/useUtils.ts +152 -53
- package/composables/useVisitor.ts +6 -4
- package/package.json +2 -1
- package/types/feedback.d.ts +5 -2
- package/types/user.d.ts +1 -0
|
@@ -46,12 +46,19 @@
|
|
|
46
46
|
No printer is configured in the settings. QR Pass may not print.
|
|
47
47
|
</v-alert>
|
|
48
48
|
<template v-else>
|
|
49
|
-
<
|
|
49
|
+
<div class="d-flex align-center justify-space-between mt-3">
|
|
50
|
+
<InputLabel title="Quantity" />
|
|
51
|
+
<span v-if="availableCount !== null" class="text-caption text-grey">
|
|
52
|
+
{{ availableCount }} available
|
|
53
|
+
</span>
|
|
54
|
+
<v-progress-circular v-else-if="cardsLoading" size="14" width="2" indeterminate color="grey" />
|
|
55
|
+
</div>
|
|
50
56
|
<v-text-field
|
|
51
57
|
v-model.number="quantity"
|
|
52
58
|
type="number"
|
|
53
59
|
density="comfortable"
|
|
54
60
|
:min="1"
|
|
61
|
+
:max="availableCount ?? undefined"
|
|
55
62
|
hide-details
|
|
56
63
|
/>
|
|
57
64
|
</template>
|
|
@@ -65,7 +72,7 @@
|
|
|
65
72
|
v-model="selectedCards"
|
|
66
73
|
:items="cardItems"
|
|
67
74
|
:loading="cardsLoading"
|
|
68
|
-
item-title="
|
|
75
|
+
item-title="cardNo"
|
|
69
76
|
item-value="_id"
|
|
70
77
|
density="comfortable"
|
|
71
78
|
multiple
|
|
@@ -78,7 +85,7 @@
|
|
|
78
85
|
<template #item="{ props: itemProps, item }">
|
|
79
86
|
<v-list-item v-bind="itemProps">
|
|
80
87
|
<template #subtitle>
|
|
81
|
-
<span class="text-caption text-grey">{{ item.raw.
|
|
88
|
+
<span class="text-caption text-grey">{{ item.raw.cardNo }}</span>
|
|
82
89
|
</template>
|
|
83
90
|
</v-list-item>
|
|
84
91
|
</template>
|
|
@@ -207,11 +214,19 @@ const props = defineProps({
|
|
|
207
214
|
type: Array as PropType<any[]>,
|
|
208
215
|
default: () => [],
|
|
209
216
|
},
|
|
217
|
+
siteId: {
|
|
218
|
+
type: String as PropType<string | null>,
|
|
219
|
+
default: null,
|
|
220
|
+
},
|
|
221
|
+
unitId: {
|
|
222
|
+
type: String as PropType<string | null>,
|
|
223
|
+
default: null,
|
|
224
|
+
},
|
|
210
225
|
});
|
|
211
226
|
|
|
212
227
|
const emit = defineEmits(["update:modelValue", "update:quantity", "update:cards"]);
|
|
213
228
|
|
|
214
|
-
const {
|
|
229
|
+
const { getAvailableContractorCards } = useAccessManagement();
|
|
215
230
|
|
|
216
231
|
const nfcEnabled = computed(() => props.settings?.data?.settings?.nfcPass ?? false);
|
|
217
232
|
const printer = computed(() => props.settings?.data?.settings?.printer ?? { vendorId: null, productId: null });
|
|
@@ -238,12 +253,19 @@ const selectedCards = computed({
|
|
|
238
253
|
// ─── Card fetching ────────────────────────────────────────────────
|
|
239
254
|
const cardItems = ref<any[]>([]);
|
|
240
255
|
const cardsLoading = ref(false);
|
|
256
|
+
const availableCount = ref<number | null>(null);
|
|
241
257
|
|
|
242
|
-
async function fetchCards() {
|
|
258
|
+
async function fetchCards(type: "NFC" | "QRCODE" = "NFC") {
|
|
259
|
+
if (!props.siteId || !props.unitId) return;
|
|
243
260
|
cardsLoading.value = true;
|
|
244
261
|
try {
|
|
245
|
-
const res = await
|
|
246
|
-
|
|
262
|
+
const res = await getAvailableContractorCards({
|
|
263
|
+
type,
|
|
264
|
+
siteId: props.siteId,
|
|
265
|
+
unitId: props.unitId,
|
|
266
|
+
});
|
|
267
|
+
cardItems.value = res?.data?.[0]?.items ?? [];
|
|
268
|
+
availableCount.value = (res?.data?.[2] as any)?.count ?? cardItems.value.length;
|
|
247
269
|
} finally {
|
|
248
270
|
cardsLoading.value = false;
|
|
249
271
|
}
|
|
@@ -268,7 +290,7 @@ const toggleBarcodeScanning = () => {
|
|
|
268
290
|
};
|
|
269
291
|
|
|
270
292
|
const validateScannedBarcode = (scannedCode: string) => {
|
|
271
|
-
const card = cardItems.value.find((c) => c.
|
|
293
|
+
const card = cardItems.value.find((c) => c.cardNo === scannedCode);
|
|
272
294
|
if (card) addCard(card);
|
|
273
295
|
barcodeBuffer.value = "";
|
|
274
296
|
};
|
|
@@ -360,7 +382,7 @@ const scanFrame = async () => {
|
|
|
360
382
|
try {
|
|
361
383
|
const barcodes = await barcodeDetector.detect(canvas);
|
|
362
384
|
for (const barcode of barcodes) {
|
|
363
|
-
const card = cardItems.value.find((c) => c.
|
|
385
|
+
const card = cardItems.value.find((c) => c.cardNo === barcode.rawValue);
|
|
364
386
|
if (card) {
|
|
365
387
|
addCard(card);
|
|
366
388
|
closeCameraDialog();
|
|
@@ -390,9 +412,13 @@ watch(
|
|
|
390
412
|
() => passType.value,
|
|
391
413
|
(val) => {
|
|
392
414
|
if (val === "NFC") {
|
|
393
|
-
fetchCards();
|
|
415
|
+
fetchCards("NFC");
|
|
394
416
|
window.addEventListener("keydown", handleBarcodeInput);
|
|
417
|
+
} else if (val === "QR") {
|
|
418
|
+
availableCount.value = null;
|
|
419
|
+
fetchCards("QRCODE");
|
|
395
420
|
} else {
|
|
421
|
+
availableCount.value = null;
|
|
396
422
|
isBarcodeScanningActive.value = false;
|
|
397
423
|
barcodeBuffer.value = "";
|
|
398
424
|
if (barcodeTimeout.value) clearTimeout(barcodeTimeout.value);
|
|
@@ -283,7 +283,9 @@
|
|
|
283
283
|
>mdi-delete-outline</v-icon
|
|
284
284
|
>
|
|
285
285
|
</template>
|
|
286
|
-
<v-list-item-title
|
|
286
|
+
<v-list-item-title
|
|
287
|
+
>Remove Equipment</v-list-item-title
|
|
288
|
+
>
|
|
287
289
|
</v-list-item>
|
|
288
290
|
</v-list>
|
|
289
291
|
</v-menu>
|
|
@@ -440,7 +442,8 @@
|
|
|
440
442
|
<script setup lang="ts">
|
|
441
443
|
import useEquipmentItem from "../composables/useEquipmentItem";
|
|
442
444
|
import { useEquipmentItemPermission } from "../composables/useEquipmentItemPermission";
|
|
443
|
-
import
|
|
445
|
+
import useEquipmentManagement from "../composables/useEquipmentManagement";
|
|
446
|
+
import useFile from "../composables/useFile";
|
|
444
447
|
import useUtils from "../composables/useUtils";
|
|
445
448
|
|
|
446
449
|
const props = defineProps({
|
|
@@ -546,7 +549,7 @@ watchEffect(() => {
|
|
|
546
549
|
}
|
|
547
550
|
});
|
|
548
551
|
|
|
549
|
-
const { getSupplies } =
|
|
552
|
+
const { getSupplies } = useEquipmentManagement();
|
|
550
553
|
|
|
551
554
|
const { data: getSuppliesReq } = await useLazyAsyncData(
|
|
552
555
|
"get-supplies-for-equipment-item",
|
|
@@ -568,7 +571,9 @@ watchEffect(() => {
|
|
|
568
571
|
}
|
|
569
572
|
});
|
|
570
573
|
|
|
571
|
-
const supplyItems = ref<
|
|
574
|
+
const supplyItems = ref<
|
|
575
|
+
Array<{ name: string; value: string; stockQty: number }>
|
|
576
|
+
>([]);
|
|
572
577
|
const selectedSupplyForAdd = ref<string>("");
|
|
573
578
|
const equipmentItems = ref<TEquipmentItem[]>([]);
|
|
574
579
|
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<template #label> Subject <span class="text-red">*</span> </template>
|
|
32
32
|
</v-autocomplete>
|
|
33
33
|
|
|
34
|
-
<v-autocomplete
|
|
34
|
+
<!-- <v-autocomplete
|
|
35
35
|
v-model="localFeedback.category"
|
|
36
36
|
:items="categories"
|
|
37
37
|
item-title="title"
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
:rules="[requiredRule]"
|
|
46
46
|
>
|
|
47
47
|
<template #label> Category <span class="text-red">*</span> </template>
|
|
48
|
-
</v-autocomplete>
|
|
48
|
+
</v-autocomplete> -->
|
|
49
49
|
|
|
50
50
|
<v-text-field
|
|
51
51
|
label="Location"
|
|
@@ -91,7 +91,7 @@ const props = defineProps<{
|
|
|
91
91
|
feedback: TFeedbackCreate;
|
|
92
92
|
isEditMode: boolean;
|
|
93
93
|
loading: boolean;
|
|
94
|
-
categories: { title: string; value: string }[];
|
|
94
|
+
// categories: { title: string; value: string }[];
|
|
95
95
|
erroredImages?: string[];
|
|
96
96
|
maxFiles?: number;
|
|
97
97
|
}>();
|
|
@@ -133,7 +133,7 @@ const { requiredRule } = useUtils();
|
|
|
133
133
|
const isFormValid = computed(() => {
|
|
134
134
|
return (
|
|
135
135
|
localFeedback.value.subject &&
|
|
136
|
-
localFeedback.value.category &&
|
|
136
|
+
// localFeedback.value.category &&
|
|
137
137
|
localFeedback.value.location &&
|
|
138
138
|
localFeedback.value.description
|
|
139
139
|
);
|