@7365admin1/layer-common 1.10.3 → 1.10.5
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/AccessCardDeleteDialog.vue +109 -0
- package/components/AccessCardHistoryDialog.vue +133 -0
- package/components/AccessCardPreviewDialog.vue +308 -0
- package/components/AccessCardQrTagging.vue +183 -0
- package/components/AccessCardReplaceForm.vue +179 -0
- package/components/AccessManagement.vue +61 -251
- package/components/AreaChecklistHistoryLogs.vue +1 -1
- package/components/BuildingManagement/units.vue +33 -2
- package/components/BuildingUnitFormAdd.vue +45 -99
- package/components/BuildingUnitFormEdit.vue +59 -148
- package/components/BulletinBoardManagement.vue +6 -1
- package/components/BulletinBoardView.vue +2 -2
- package/components/Button/Close.vue +3 -1
- package/components/CleaningScheduleMain.vue +20 -9
- package/components/IncidentReport/IncidentInformation.vue +45 -6
- package/components/IncidentReport/affectedEntities.vue +29 -0
- package/components/PeopleForm.vue +1 -1
- package/components/PlateNumberDisplay.vue +45 -0
- package/components/ScheduleAreaMain.vue +5 -2
- package/components/ScheduleTaskForm.vue +59 -114
- package/components/ScheduleTaskMain.vue +19 -15
- package/components/VehicleAddSelection.vue +58 -0
- package/components/VehicleForm.vue +600 -0
- package/components/VehicleManagement.vue +298 -0
- package/components/VisitorForm.vue +1 -1
- package/composables/useAccessManagement.ts +16 -0
- package/composables/useBulletin.ts +11 -9
- package/composables/useCard.ts +14 -0
- package/composables/useScheduleTask.ts +4 -8
- package/composables/useVehicle.ts +114 -0
- package/package.json +1 -1
- package/types/bulletin-board.d.ts +1 -1
- package/types/checkout-item.d.ts +1 -0
- package/types/cleaner-schedule.d.ts +1 -1
- package/types/people.d.ts +1 -1
- package/types/vehicle.d.ts +43 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @iservice365/layer-common
|
|
2
2
|
|
|
3
|
+
## 1.10.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- eaec446: Update changes for March 6, 2024
|
|
8
|
+
|
|
9
|
+
## 1.10.4
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- a78dff9: Update Layer-common Changes for March 4, 2026
|
|
14
|
+
|
|
3
15
|
## 1.10.3
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-dialog :model-value="modelValue" width="450" persistent>
|
|
3
|
+
<v-card width="100%">
|
|
4
|
+
<v-toolbar density="compact" class="pl-4">
|
|
5
|
+
<span class="font-weight-medium text-h5">Delete Card</span>
|
|
6
|
+
</v-toolbar>
|
|
7
|
+
|
|
8
|
+
<v-card-text>
|
|
9
|
+
<p class="text-subtitle-2 text-center mb-4">
|
|
10
|
+
Are you sure you want to delete this card? This action cannot be
|
|
11
|
+
undone.
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<v-form v-model="validForm" :disabled="loading">
|
|
15
|
+
<InputLabel class="text-capitalize font-weight-bold" title="Remarks" required />
|
|
16
|
+
<v-textarea
|
|
17
|
+
v-model="remarks"
|
|
18
|
+
placeholder="Enter remarks..."
|
|
19
|
+
persistent-placeholder
|
|
20
|
+
rows="3"
|
|
21
|
+
auto-grow
|
|
22
|
+
hide-details="auto"
|
|
23
|
+
:rules="[requiredRule]"
|
|
24
|
+
/>
|
|
25
|
+
</v-form>
|
|
26
|
+
|
|
27
|
+
<v-row v-if="error" no-gutters justify="center" class="mt-3">
|
|
28
|
+
<span class="text-caption text-error text-center">{{ error }}</span>
|
|
29
|
+
</v-row>
|
|
30
|
+
</v-card-text>
|
|
31
|
+
|
|
32
|
+
<v-toolbar density="compact">
|
|
33
|
+
<v-row no-gutters>
|
|
34
|
+
<v-col cols="6">
|
|
35
|
+
<v-btn
|
|
36
|
+
tile
|
|
37
|
+
block
|
|
38
|
+
size="48"
|
|
39
|
+
variant="text"
|
|
40
|
+
class="text-none"
|
|
41
|
+
:disabled="loading"
|
|
42
|
+
@click="handleClose"
|
|
43
|
+
>
|
|
44
|
+
Close
|
|
45
|
+
</v-btn>
|
|
46
|
+
</v-col>
|
|
47
|
+
<v-col cols="6">
|
|
48
|
+
<v-btn
|
|
49
|
+
tile
|
|
50
|
+
block
|
|
51
|
+
size="48"
|
|
52
|
+
color="black"
|
|
53
|
+
variant="flat"
|
|
54
|
+
class="text-none"
|
|
55
|
+
:loading="loading"
|
|
56
|
+
:disabled="!validForm || loading"
|
|
57
|
+
@click="handleConfirm"
|
|
58
|
+
>
|
|
59
|
+
Delete Card
|
|
60
|
+
</v-btn>
|
|
61
|
+
</v-col>
|
|
62
|
+
</v-row>
|
|
63
|
+
</v-toolbar>
|
|
64
|
+
</v-card>
|
|
65
|
+
</v-dialog>
|
|
66
|
+
</template>
|
|
67
|
+
|
|
68
|
+
<script setup lang="ts">
|
|
69
|
+
const props = defineProps({
|
|
70
|
+
modelValue: {
|
|
71
|
+
type: Boolean,
|
|
72
|
+
default: false,
|
|
73
|
+
},
|
|
74
|
+
loading: {
|
|
75
|
+
type: Boolean,
|
|
76
|
+
default: false,
|
|
77
|
+
},
|
|
78
|
+
error: {
|
|
79
|
+
type: String,
|
|
80
|
+
default: "",
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const emit = defineEmits<{
|
|
85
|
+
"update:modelValue": [value: boolean];
|
|
86
|
+
confirm: [remarks: string];
|
|
87
|
+
}>();
|
|
88
|
+
|
|
89
|
+
const { requiredRule } = useUtils();
|
|
90
|
+
|
|
91
|
+
const validForm = ref(false);
|
|
92
|
+
const remarks = ref("");
|
|
93
|
+
|
|
94
|
+
watch(
|
|
95
|
+
() => props.modelValue,
|
|
96
|
+
(val) => {
|
|
97
|
+
if (val) remarks.value = "";
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
function handleClose() {
|
|
102
|
+
emit("update:modelValue", false);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function handleConfirm() {
|
|
106
|
+
if (!validForm.value) return;
|
|
107
|
+
emit("confirm", remarks.value.trim());
|
|
108
|
+
}
|
|
109
|
+
</script>
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-dialog :model-value="modelValue" width="480" persistent>
|
|
3
|
+
<v-card width="100%">
|
|
4
|
+
<v-toolbar density="compact" color="black">
|
|
5
|
+
<v-toolbar-title class="text-subtitle-1 font-weight-medium">
|
|
6
|
+
Card History — {{ card?.cardNo ?? "N/A" }}
|
|
7
|
+
</v-toolbar-title>
|
|
8
|
+
<v-btn icon @click="emit('update:modelValue', false)">
|
|
9
|
+
<v-icon>mdi-close</v-icon>
|
|
10
|
+
</v-btn>
|
|
11
|
+
</v-toolbar>
|
|
12
|
+
|
|
13
|
+
<v-card-text style="max-height: 70vh; overflow-y: auto" class="pa-4">
|
|
14
|
+
<div v-if="pending" class="d-flex justify-center align-center py-8">
|
|
15
|
+
<v-progress-circular indeterminate color="black" />
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div v-else-if="!history.length" class="text-center text-grey py-8">
|
|
19
|
+
No history available.
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<v-timeline v-else side="end" density="compact" truncate-line="both">
|
|
23
|
+
<v-timeline-item
|
|
24
|
+
v-for="(item, index) in history"
|
|
25
|
+
:key="index"
|
|
26
|
+
:dot-color="actionColor(item.action)"
|
|
27
|
+
size="small"
|
|
28
|
+
>
|
|
29
|
+
<template #icon>
|
|
30
|
+
<v-icon size="14" color="white">{{ actionIcon(item.action) }}</v-icon>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<div class="mb-4">
|
|
34
|
+
<div class="d-flex align-center ga-2 mb-1">
|
|
35
|
+
<v-chip
|
|
36
|
+
:color="actionColor(item.action)"
|
|
37
|
+
variant="flat"
|
|
38
|
+
size="x-small"
|
|
39
|
+
class="text-capitalize font-weight-medium"
|
|
40
|
+
>
|
|
41
|
+
{{ actionLabel(item.action) }}
|
|
42
|
+
</v-chip>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="text-body-2">{{ item.performedBy?.name ?? "N/A" }}</div>
|
|
45
|
+
<div class="text-caption text-grey">{{ formatDate(item.date) }}</div>
|
|
46
|
+
</div>
|
|
47
|
+
</v-timeline-item>
|
|
48
|
+
</v-timeline>
|
|
49
|
+
</v-card-text>
|
|
50
|
+
</v-card>
|
|
51
|
+
</v-dialog>
|
|
52
|
+
</template>
|
|
53
|
+
|
|
54
|
+
<script setup lang="ts">
|
|
55
|
+
const props = defineProps({
|
|
56
|
+
modelValue: {
|
|
57
|
+
type: Boolean,
|
|
58
|
+
default: false,
|
|
59
|
+
},
|
|
60
|
+
card: {
|
|
61
|
+
type: Object as PropType<Record<string, any> | null>,
|
|
62
|
+
default: null,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const emit = defineEmits<{
|
|
67
|
+
"update:modelValue": [value: boolean];
|
|
68
|
+
}>();
|
|
69
|
+
|
|
70
|
+
const { getCardHistory } = useAccessManagement();
|
|
71
|
+
|
|
72
|
+
const history = ref<Record<string, any>[]>([]);
|
|
73
|
+
const pending = ref(false);
|
|
74
|
+
|
|
75
|
+
watch(
|
|
76
|
+
() => props.modelValue,
|
|
77
|
+
async (val) => {
|
|
78
|
+
if (val && props.card?._id) {
|
|
79
|
+
pending.value = true;
|
|
80
|
+
try {
|
|
81
|
+
const data = await getCardHistory(props.card._id);
|
|
82
|
+
history.value = Array.isArray(data) ? data : [];
|
|
83
|
+
} finally {
|
|
84
|
+
pending.value = false;
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
history.value = [];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
function actionLabel(action: string) {
|
|
93
|
+
const map: Record<string, string> = {
|
|
94
|
+
available: "Created",
|
|
95
|
+
assign: "Assigned",
|
|
96
|
+
replace: "Replaced",
|
|
97
|
+
deleted: "Deleted",
|
|
98
|
+
};
|
|
99
|
+
return map[action] ?? action;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function actionColor(action: string) {
|
|
103
|
+
const map: Record<string, string> = {
|
|
104
|
+
available: "success",
|
|
105
|
+
assign: "primary",
|
|
106
|
+
replace: "orange",
|
|
107
|
+
deleted: "error",
|
|
108
|
+
};
|
|
109
|
+
return map[action] ?? "grey";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function actionIcon(action: string) {
|
|
113
|
+
const map: Record<string, string> = {
|
|
114
|
+
available: "mdi-plus",
|
|
115
|
+
assign: "mdi-account-check",
|
|
116
|
+
replace: "mdi-swap-horizontal",
|
|
117
|
+
deleted: "mdi-delete",
|
|
118
|
+
};
|
|
119
|
+
return map[action] ?? "mdi-circle-small";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function formatDate(date: string) {
|
|
123
|
+
if (!date) return "N/A";
|
|
124
|
+
return new Intl.DateTimeFormat("en-GB", {
|
|
125
|
+
day: "2-digit",
|
|
126
|
+
month: "short",
|
|
127
|
+
year: "numeric",
|
|
128
|
+
hour: "2-digit",
|
|
129
|
+
minute: "2-digit",
|
|
130
|
+
hour12: true,
|
|
131
|
+
}).format(new Date(date));
|
|
132
|
+
}
|
|
133
|
+
</script>
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<AccessCardHistoryDialog
|
|
3
|
+
v-model="historyDialog"
|
|
4
|
+
:card="selectedCardInUnit"
|
|
5
|
+
/>
|
|
6
|
+
|
|
7
|
+
<v-dialog :model-value="modelValue" width="450" persistent>
|
|
8
|
+
<v-card width="100%">
|
|
9
|
+
<v-card-text style="max-height: 100vh; overflow-y: auto" class="pb-0">
|
|
10
|
+
<v-row no-gutters class="mb-4">
|
|
11
|
+
<v-col cols="12">
|
|
12
|
+
<strong>Building:</strong> {{ unit?.block?.name ?? "N/A" }}
|
|
13
|
+
</v-col>
|
|
14
|
+
<v-col cols="12">
|
|
15
|
+
<strong>Level:</strong> {{ unit?.level?.level ?? "N/A" }}
|
|
16
|
+
</v-col>
|
|
17
|
+
<v-col cols="12">
|
|
18
|
+
<strong>Unit:</strong> {{ unit?.name ?? "N/A" }}
|
|
19
|
+
</v-col>
|
|
20
|
+
|
|
21
|
+
<!-- Available Physical -->
|
|
22
|
+
<v-col cols="12" class="mt-3">
|
|
23
|
+
<strong>Available Physical</strong>
|
|
24
|
+
<div v-if="unit?.available?.physical?.length" class="mt-1">
|
|
25
|
+
<v-chip
|
|
26
|
+
v-for="card in unit.available.physical"
|
|
27
|
+
:key="card._id"
|
|
28
|
+
size="small"
|
|
29
|
+
class="mr-1 mb-1"
|
|
30
|
+
:color="selectedCardInUnit?._id === card._id ? 'primary' : undefined"
|
|
31
|
+
:variant="selectedCardInUnit?._id === card._id ? 'flat' : 'tonal'"
|
|
32
|
+
style="cursor: pointer"
|
|
33
|
+
@click="toggleCard(card)"
|
|
34
|
+
>
|
|
35
|
+
{{ card.cardNo }}
|
|
36
|
+
</v-chip>
|
|
37
|
+
</div>
|
|
38
|
+
<span v-else class="text-caption text-grey ml-1">None</span>
|
|
39
|
+
</v-col>
|
|
40
|
+
|
|
41
|
+
<!-- Available Non-Physical -->
|
|
42
|
+
<v-col cols="12" class="mt-2">
|
|
43
|
+
<strong>Available Non-Physical</strong>
|
|
44
|
+
<div v-if="unit?.available?.non_physical?.length" class="mt-1">
|
|
45
|
+
<v-chip
|
|
46
|
+
v-for="card in unit.available.non_physical"
|
|
47
|
+
:key="card._id"
|
|
48
|
+
size="small"
|
|
49
|
+
class="mr-1 mb-1"
|
|
50
|
+
:color="selectedCardInUnit?._id === card._id ? 'primary' : undefined"
|
|
51
|
+
:variant="selectedCardInUnit?._id === card._id ? 'flat' : 'tonal'"
|
|
52
|
+
style="cursor: pointer"
|
|
53
|
+
@click="toggleCard(card)"
|
|
54
|
+
>
|
|
55
|
+
{{ card.cardNo }}
|
|
56
|
+
</v-chip>
|
|
57
|
+
</div>
|
|
58
|
+
<span v-else class="text-caption text-grey ml-1">None</span>
|
|
59
|
+
</v-col>
|
|
60
|
+
|
|
61
|
+
<!-- Assigned Physical -->
|
|
62
|
+
<v-col cols="12" class="mt-2">
|
|
63
|
+
<strong>Assigned Physical</strong>
|
|
64
|
+
<div v-if="unit?.assigned?.physical?.length" class="mt-1">
|
|
65
|
+
<v-chip
|
|
66
|
+
v-for="card in unit.assigned.physical"
|
|
67
|
+
:key="card._id"
|
|
68
|
+
size="small"
|
|
69
|
+
class="mr-1 mb-1"
|
|
70
|
+
:color="selectedCardInUnit?._id === card._id ? 'primary' : undefined"
|
|
71
|
+
:variant="selectedCardInUnit?._id === card._id ? 'flat' : 'tonal'"
|
|
72
|
+
style="cursor: pointer"
|
|
73
|
+
@click="toggleCard(card)"
|
|
74
|
+
>
|
|
75
|
+
{{ card.cardNo }}
|
|
76
|
+
</v-chip>
|
|
77
|
+
</div>
|
|
78
|
+
<span v-else class="text-caption text-grey ml-1">None</span>
|
|
79
|
+
</v-col>
|
|
80
|
+
|
|
81
|
+
<!-- Assigned Non-Physical -->
|
|
82
|
+
<v-col cols="12" class="mt-2">
|
|
83
|
+
<strong>Assigned Non-Physical</strong>
|
|
84
|
+
<div v-if="unit?.assigned?.non_physical?.length" class="mt-1">
|
|
85
|
+
<v-chip
|
|
86
|
+
v-for="card in unit.assigned.non_physical"
|
|
87
|
+
:key="card._id"
|
|
88
|
+
size="small"
|
|
89
|
+
class="mr-1 mb-1"
|
|
90
|
+
:color="selectedCardInUnit?._id === card._id ? 'primary' : undefined"
|
|
91
|
+
:variant="selectedCardInUnit?._id === card._id ? 'flat' : 'tonal'"
|
|
92
|
+
style="cursor: pointer"
|
|
93
|
+
@click="toggleCard(card)"
|
|
94
|
+
>
|
|
95
|
+
{{ card.cardNo }}
|
|
96
|
+
</v-chip>
|
|
97
|
+
</div>
|
|
98
|
+
<span v-else class="text-caption text-grey ml-1">None</span>
|
|
99
|
+
</v-col>
|
|
100
|
+
|
|
101
|
+
<!-- Replaced Physical -->
|
|
102
|
+
<v-col cols="12" class="mt-2">
|
|
103
|
+
<strong>Replaced Physical</strong>
|
|
104
|
+
<div v-if="unit?.replaced?.physical?.length" class="mt-1">
|
|
105
|
+
<v-chip
|
|
106
|
+
v-for="card in unit.replaced.physical"
|
|
107
|
+
:key="card._id"
|
|
108
|
+
size="small"
|
|
109
|
+
class="mr-1 mb-1"
|
|
110
|
+
:color="selectedCardInUnit?._id === card._id ? 'orange' : 'orange'"
|
|
111
|
+
:variant="selectedCardInUnit?._id === card._id ? 'flat' : 'tonal'"
|
|
112
|
+
style="cursor: pointer"
|
|
113
|
+
@click="toggleCard(card)"
|
|
114
|
+
>
|
|
115
|
+
{{ card.cardNo }}
|
|
116
|
+
</v-chip>
|
|
117
|
+
</div>
|
|
118
|
+
<span v-else class="text-caption text-grey ml-1">None</span>
|
|
119
|
+
</v-col>
|
|
120
|
+
|
|
121
|
+
<!-- Replaced Non-Physical -->
|
|
122
|
+
<v-col cols="12" class="mt-2">
|
|
123
|
+
<strong>Replaced Non-Physical</strong>
|
|
124
|
+
<div v-if="unit?.replaced?.non_physical?.length" class="mt-1">
|
|
125
|
+
<v-chip
|
|
126
|
+
v-for="card in unit.replaced.non_physical"
|
|
127
|
+
:key="card._id"
|
|
128
|
+
size="small"
|
|
129
|
+
class="mr-1 mb-1"
|
|
130
|
+
:color="selectedCardInUnit?._id === card._id ? 'orange' : 'orange'"
|
|
131
|
+
:variant="selectedCardInUnit?._id === card._id ? 'flat' : 'tonal'"
|
|
132
|
+
style="cursor: pointer"
|
|
133
|
+
@click="toggleCard(card)"
|
|
134
|
+
>
|
|
135
|
+
{{ card.cardNo }}
|
|
136
|
+
</v-chip>
|
|
137
|
+
</div>
|
|
138
|
+
<span v-else class="text-caption text-grey ml-1">None</span>
|
|
139
|
+
</v-col>
|
|
140
|
+
|
|
141
|
+
<!-- Deleted Physical -->
|
|
142
|
+
<v-col cols="12" class="mt-2">
|
|
143
|
+
<strong>Deleted Physical</strong>
|
|
144
|
+
<div v-if="unit?.deleted?.physical?.length" class="mt-1">
|
|
145
|
+
<v-chip
|
|
146
|
+
v-for="card in unit.deleted.physical"
|
|
147
|
+
:key="card._id"
|
|
148
|
+
size="small"
|
|
149
|
+
class="mr-1 mb-1"
|
|
150
|
+
:color="selectedCardInUnit?._id === card._id ? 'red' : 'red'"
|
|
151
|
+
:variant="selectedCardInUnit?._id === card._id ? 'flat' : 'tonal'"
|
|
152
|
+
style="cursor: pointer"
|
|
153
|
+
@click="toggleCard(card)"
|
|
154
|
+
>
|
|
155
|
+
{{ card.cardNo }}
|
|
156
|
+
</v-chip>
|
|
157
|
+
</div>
|
|
158
|
+
<span v-else class="text-caption text-grey ml-1">None</span>
|
|
159
|
+
</v-col>
|
|
160
|
+
|
|
161
|
+
<!-- Deleted Non-Physical -->
|
|
162
|
+
<v-col cols="12" class="mt-2">
|
|
163
|
+
<strong>Deleted Non-Physical</strong>
|
|
164
|
+
<div v-if="unit?.deleted?.non_physical?.length" class="mt-1">
|
|
165
|
+
<v-chip
|
|
166
|
+
v-for="card in unit.deleted.non_physical"
|
|
167
|
+
:key="card._id"
|
|
168
|
+
size="small"
|
|
169
|
+
class="mr-1 mb-1"
|
|
170
|
+
:color="selectedCardInUnit?._id === card._id ? 'red' : 'red'"
|
|
171
|
+
:variant="selectedCardInUnit?._id === card._id ? 'flat' : 'tonal'"
|
|
172
|
+
style="cursor: pointer"
|
|
173
|
+
@click="toggleCard(card)"
|
|
174
|
+
>
|
|
175
|
+
{{ card.cardNo }}
|
|
176
|
+
</v-chip>
|
|
177
|
+
</div>
|
|
178
|
+
<span v-else class="text-caption text-grey ml-1">None</span>
|
|
179
|
+
</v-col>
|
|
180
|
+
</v-row>
|
|
181
|
+
</v-card-text>
|
|
182
|
+
|
|
183
|
+
<v-toolbar class="pa-0" density="compact">
|
|
184
|
+
<v-row no-gutters>
|
|
185
|
+
<v-col cols="6" class="pa-0">
|
|
186
|
+
<v-btn
|
|
187
|
+
block
|
|
188
|
+
variant="text"
|
|
189
|
+
class="text-none"
|
|
190
|
+
size="large"
|
|
191
|
+
height="48"
|
|
192
|
+
@click="emit('update:modelValue', false)"
|
|
193
|
+
>
|
|
194
|
+
Close
|
|
195
|
+
</v-btn>
|
|
196
|
+
</v-col>
|
|
197
|
+
<v-col cols="6" class="pa-0" v-if="canUpdate">
|
|
198
|
+
<v-menu>
|
|
199
|
+
<template #activator="{ props }">
|
|
200
|
+
<v-btn
|
|
201
|
+
block
|
|
202
|
+
variant="flat"
|
|
203
|
+
color="black"
|
|
204
|
+
class="text-none"
|
|
205
|
+
height="48"
|
|
206
|
+
v-bind="props"
|
|
207
|
+
tile
|
|
208
|
+
>
|
|
209
|
+
More actions
|
|
210
|
+
</v-btn>
|
|
211
|
+
</template>
|
|
212
|
+
<v-list class="pa-0">
|
|
213
|
+
<v-list-item
|
|
214
|
+
:disabled="!isSelectedCardAssignedPhysical"
|
|
215
|
+
@click="emit('replace')"
|
|
216
|
+
v-if="canReplaceAccessCard && isSelectedCardAssignedPhysical"
|
|
217
|
+
>
|
|
218
|
+
<v-list-item-title class="text-subtitle-2">
|
|
219
|
+
Replace Card
|
|
220
|
+
</v-list-item-title>
|
|
221
|
+
</v-list-item>
|
|
222
|
+
<v-list-item :disabled="!isSelectedCardPhysical" @click="historyDialog = true">
|
|
223
|
+
<v-list-item-title class="text-subtitle-2 cursor-pointer">
|
|
224
|
+
Card History
|
|
225
|
+
</v-list-item-title>
|
|
226
|
+
</v-list-item>
|
|
227
|
+
<v-list-item
|
|
228
|
+
@click="emit('delete')"
|
|
229
|
+
class="text-red"
|
|
230
|
+
:disabled="!isSelectedCardDeletable"
|
|
231
|
+
v-if="canDeleteAccessCard"
|
|
232
|
+
>
|
|
233
|
+
<v-list-item-title class="text-subtitle-2">
|
|
234
|
+
Delete Card
|
|
235
|
+
</v-list-item-title>
|
|
236
|
+
</v-list-item>
|
|
237
|
+
</v-list>
|
|
238
|
+
</v-menu>
|
|
239
|
+
</v-col>
|
|
240
|
+
</v-row>
|
|
241
|
+
</v-toolbar>
|
|
242
|
+
</v-card>
|
|
243
|
+
</v-dialog>
|
|
244
|
+
</template>
|
|
245
|
+
|
|
246
|
+
<script setup lang="ts">
|
|
247
|
+
const props = defineProps({
|
|
248
|
+
modelValue: {
|
|
249
|
+
type: Boolean,
|
|
250
|
+
default: false,
|
|
251
|
+
},
|
|
252
|
+
unit: {
|
|
253
|
+
type: Object as PropType<Record<string, any>>,
|
|
254
|
+
default: () => ({}),
|
|
255
|
+
},
|
|
256
|
+
selectedCardInUnit: {
|
|
257
|
+
type: Object as PropType<Record<string, any> | null>,
|
|
258
|
+
default: null,
|
|
259
|
+
},
|
|
260
|
+
canUpdate: {
|
|
261
|
+
type: Boolean,
|
|
262
|
+
default: true,
|
|
263
|
+
},
|
|
264
|
+
canReplaceAccessCard: {
|
|
265
|
+
type: Boolean,
|
|
266
|
+
default: true,
|
|
267
|
+
},
|
|
268
|
+
canDeleteAccessCard: {
|
|
269
|
+
type: Boolean,
|
|
270
|
+
default: true,
|
|
271
|
+
},
|
|
272
|
+
isSelectedCardAssignedPhysical: {
|
|
273
|
+
type: Boolean,
|
|
274
|
+
default: false,
|
|
275
|
+
},
|
|
276
|
+
isSelectedCardPhysical: {
|
|
277
|
+
type: Boolean,
|
|
278
|
+
default: false,
|
|
279
|
+
},
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
const emit = defineEmits<{
|
|
283
|
+
"update:modelValue": [value: boolean];
|
|
284
|
+
"update:selectedCardInUnit": [value: Record<string, any> | null];
|
|
285
|
+
replace: [];
|
|
286
|
+
delete: [];
|
|
287
|
+
}>();
|
|
288
|
+
|
|
289
|
+
const historyDialog = ref(false);
|
|
290
|
+
|
|
291
|
+
const isSelectedCardDeletable = computed(() => {
|
|
292
|
+
if (!props.selectedCardInUnit?._id) return false;
|
|
293
|
+
const id = props.selectedCardInUnit._id;
|
|
294
|
+
return [
|
|
295
|
+
...(props.unit?.available?.physical ?? []),
|
|
296
|
+
...(props.unit?.available?.non_physical ?? []),
|
|
297
|
+
...(props.unit?.assigned?.physical ?? []),
|
|
298
|
+
...(props.unit?.assigned?.non_physical ?? []),
|
|
299
|
+
].some((c) => c._id === id);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
function toggleCard(card: Record<string, any>) {
|
|
303
|
+
emit(
|
|
304
|
+
"update:selectedCardInUnit",
|
|
305
|
+
props.selectedCardInUnit?._id === card._id ? null : card
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
</script>
|