@7365admin1/layer-common 1.11.21 → 1.11.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/AddPassKeyToVisitor.vue +9 -9
- package/components/AreaMain.vue +10 -8
- package/components/AttendanceMain.vue +6 -6
- package/components/CleaningScheduleMain.vue +8 -7
- package/components/ManageChecklistMain.vue +4 -3
- package/components/MemberInformation.vue +49 -13
- package/components/MyAttendanceMain.vue +6 -3
- package/components/PassInformation.vue +197 -144
- package/components/ScanVisitorQRCode.vue +47 -12
- package/components/ScheduleAreaMain.vue +6 -3
- package/components/ScheduleTaskMain.vue +11 -8
- package/components/UnitMain.vue +10 -8
- package/components/VisitorDataFromScannedQRCodeForm.vue +262 -0
- package/components/VisitorForm.vue +1 -1
- package/components/VisitorManagement.vue +80 -2
- package/components/VisitorPassKeyQRScanner.vue +138 -0
- package/composables/useVisitor.ts +98 -25
- package/package.json +2 -1
- package/types/visitor.d.ts +45 -15
|
@@ -1,171 +1,224 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
</v-
|
|
40
|
-
|
|
2
|
+
<v-row no-gutters class="w-100">
|
|
3
|
+
<v-card class="w-100">
|
|
4
|
+
<v-card-text>
|
|
5
|
+
<v-btn
|
|
6
|
+
block
|
|
7
|
+
color="primary-button"
|
|
8
|
+
:height="40"
|
|
9
|
+
text="Scan QR Code"
|
|
10
|
+
class="text-capitalize"
|
|
11
|
+
disabled
|
|
12
|
+
prepend-icon="mdi-qrcode"
|
|
13
|
+
/>
|
|
14
|
+
<v-autocomplete
|
|
15
|
+
v-model="selectedPass"
|
|
16
|
+
v-model:search="passInput"
|
|
17
|
+
:hide-no-data="false"
|
|
18
|
+
class="mt-3"
|
|
19
|
+
:items="passItems"
|
|
20
|
+
:rules="props.passRules"
|
|
21
|
+
item-title="prefixAndName"
|
|
22
|
+
item-value="_id"
|
|
23
|
+
label="Pass"
|
|
24
|
+
variant="outlined"
|
|
25
|
+
hide-details
|
|
26
|
+
density="compact"
|
|
27
|
+
persistent-hint
|
|
28
|
+
small-chips
|
|
29
|
+
:clearable="props.clearable"
|
|
30
|
+
>
|
|
31
|
+
<template v-slot:chip="{ props, item }">
|
|
32
|
+
<v-chip
|
|
33
|
+
v-if="selectedPass"
|
|
34
|
+
v-bind="props"
|
|
35
|
+
prepend-icon="mdi-card-bulleted-outline"
|
|
36
|
+
:text="item.raw?.prefixAndName"
|
|
37
|
+
></v-chip>
|
|
38
|
+
</template>
|
|
39
|
+
</v-autocomplete>
|
|
40
|
+
|
|
41
|
+
<template v-if="!props.hideKeys">
|
|
42
|
+
<v-autocomplete
|
|
43
|
+
v-model="selectedKeys"
|
|
44
|
+
v-model:search="keyInput"
|
|
45
|
+
:hide-no-data="false"
|
|
46
|
+
class="mt-3"
|
|
47
|
+
:items="keyItems"
|
|
48
|
+
:rules="props.passRules"
|
|
49
|
+
item-title="prefixAndName"
|
|
50
|
+
item-value="_id"
|
|
51
|
+
label="Keys"
|
|
52
|
+
multiple
|
|
53
|
+
variant="outlined"
|
|
54
|
+
hide-details
|
|
55
|
+
density="compact"
|
|
56
|
+
persistent-hint
|
|
57
|
+
small-chips
|
|
58
|
+
:clearable="props.clearable"
|
|
59
|
+
>
|
|
60
|
+
<template v-slot:chip="{ props, item }">
|
|
61
|
+
<v-chip
|
|
62
|
+
v-if="selectedKeys.length > 0"
|
|
63
|
+
v-bind="props"
|
|
64
|
+
prepend-icon="mdi-key"
|
|
65
|
+
:text="item.raw?.prefixAndName"
|
|
66
|
+
></v-chip>
|
|
67
|
+
</template>
|
|
68
|
+
</v-autocomplete>
|
|
69
|
+
</template>
|
|
70
|
+
|
|
71
|
+
<v-divider class="my-4 w-100" />
|
|
72
|
+
|
|
73
|
+
<template v-if="selectedType">
|
|
74
|
+
<v-number-input
|
|
75
|
+
v-model="count"
|
|
76
|
+
variant="outlined"
|
|
77
|
+
:min="1"
|
|
78
|
+
:precision="0"
|
|
79
|
+
density="compact"
|
|
80
|
+
:rules="countRules"
|
|
81
|
+
/>
|
|
82
|
+
</template>
|
|
83
|
+
</v-card-text>
|
|
84
|
+
</v-card>
|
|
85
|
+
</v-row>
|
|
41
86
|
</template>
|
|
42
87
|
|
|
43
88
|
<script setup lang="ts">
|
|
44
|
-
import type { PropType } from
|
|
45
|
-
import type { ValidationRule } from
|
|
46
|
-
import usePassKey from
|
|
47
|
-
import useKey from
|
|
89
|
+
import type { PropType } from "vue";
|
|
90
|
+
import type { ValidationRule } from "vuetify/lib/types.mjs";
|
|
91
|
+
import usePassKey from "../composables/usePassKey";
|
|
92
|
+
import useKey from "../composables/useKey";
|
|
48
93
|
|
|
49
94
|
const props = defineProps({
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
const
|
|
95
|
+
passRules: {
|
|
96
|
+
type: Array as PropType<ValidationRule[]>,
|
|
97
|
+
default: [],
|
|
98
|
+
},
|
|
99
|
+
countRules: {
|
|
100
|
+
type: Array as PropType<ValidationRule[]>,
|
|
101
|
+
default: [],
|
|
102
|
+
},
|
|
103
|
+
site: {
|
|
104
|
+
type: String,
|
|
105
|
+
required: true,
|
|
106
|
+
},
|
|
107
|
+
type: {
|
|
108
|
+
type: String as PropType<TVisitorType>,
|
|
109
|
+
required: true,
|
|
110
|
+
},
|
|
111
|
+
contractorType: {
|
|
112
|
+
type: String,
|
|
113
|
+
default: "",
|
|
114
|
+
},
|
|
115
|
+
hideKeys: {
|
|
116
|
+
type: Boolean,
|
|
117
|
+
default: false,
|
|
118
|
+
},
|
|
119
|
+
clearable: {
|
|
120
|
+
type: Boolean,
|
|
121
|
+
default: false,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const pass = defineModel<TPassKeyPayload[]>("pass", { default: [] });
|
|
126
|
+
const keys = defineModel<TPassKeyPayload[]>("keys", { default: [] });
|
|
127
|
+
const selectedPass = ref<string>("");
|
|
128
|
+
const selectedKeys = ref<string[]>([]);
|
|
129
|
+
const passInput = ref("");
|
|
130
|
+
const keyInput = ref("");
|
|
131
|
+
const passItems = ref<TPassKey[]>([]);
|
|
132
|
+
const keyItems = ref<any[]>([]);
|
|
133
|
+
const selectedType = ref<"qr-pass" | "nfc-card">();
|
|
134
|
+
const count = ref(1);
|
|
135
|
+
|
|
136
|
+
const { getPassKeysByPageSearch } = usePassKey();
|
|
88
137
|
|
|
89
138
|
const typeItems = [
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
]
|
|
139
|
+
{
|
|
140
|
+
label: "QR Pass",
|
|
141
|
+
value: "qr-pass",
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
label: "NFC Card",
|
|
145
|
+
value: "nfc-card",
|
|
146
|
+
},
|
|
147
|
+
];
|
|
99
148
|
|
|
100
149
|
const passTypesComputed = computed(() => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
} else {
|
|
105
|
-
return ["contractor-pass"]
|
|
106
|
-
}
|
|
150
|
+
if (props.type === "contractor") {
|
|
151
|
+
if (props.contractorType === "property-agent") {
|
|
152
|
+
return ["agent-pass"];
|
|
107
153
|
} else {
|
|
108
|
-
|
|
154
|
+
return ["contractor-pass"];
|
|
109
155
|
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
156
|
+
} else {
|
|
157
|
+
return ["visitor-pass"];
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const {
|
|
162
|
+
data: passesData,
|
|
163
|
+
refresh: refreshPassesData,
|
|
164
|
+
pending: fetchPassesPending,
|
|
165
|
+
} = await useLazyAsyncData("get-pass-keys", () => {
|
|
166
|
+
return getPassKeysByPageSearch({
|
|
167
|
+
search: passInput.value,
|
|
168
|
+
page: 1,
|
|
169
|
+
limit: 500,
|
|
170
|
+
passTypes: passTypesComputed.value,
|
|
171
|
+
sites: [props.site],
|
|
172
|
+
statuses: ["Available"],
|
|
173
|
+
});
|
|
174
|
+
});
|
|
122
175
|
|
|
123
176
|
watch(passesData, (data: any) => {
|
|
124
|
-
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
const {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
177
|
+
passItems.value = data?.items || [];
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const {
|
|
181
|
+
data: keysData,
|
|
182
|
+
refresh: refreshKeysData,
|
|
183
|
+
pending: fetchKeysPending,
|
|
184
|
+
} = await useLazyAsyncData("get-keys", () => {
|
|
185
|
+
return getPassKeysByPageSearch({
|
|
186
|
+
search: keyInput.value,
|
|
187
|
+
statuses: ["Available"],
|
|
188
|
+
passTypes: ["pass-key"],
|
|
189
|
+
page: 1,
|
|
190
|
+
limit: 500,
|
|
191
|
+
sites: [props.site],
|
|
192
|
+
});
|
|
193
|
+
});
|
|
137
194
|
|
|
138
195
|
watch(keysData, (data: any) => {
|
|
139
|
-
|
|
140
|
-
})
|
|
196
|
+
keyItems.value = data?.items || [];
|
|
197
|
+
});
|
|
141
198
|
|
|
142
199
|
watch(selectedPass, (newVal) => {
|
|
143
|
-
|
|
144
|
-
})
|
|
200
|
+
pass.value = [{ keyId: newVal }];
|
|
201
|
+
});
|
|
145
202
|
|
|
146
203
|
watch(selectedKeys, (newVal) => {
|
|
147
|
-
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
204
|
+
keys.value = newVal.map((key) => ({ keyId: key }));
|
|
205
|
+
});
|
|
152
206
|
|
|
153
207
|
//prevent negative value;
|
|
154
208
|
watch(count, (newCount) => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
})
|
|
209
|
+
if (newCount < 1) {
|
|
210
|
+
count.value = 1;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
159
213
|
|
|
160
214
|
onMounted(() => {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
})
|
|
168
|
-
|
|
215
|
+
if (pass.value.length > 0) {
|
|
216
|
+
selectedPass.value = pass.value[0].keyId;
|
|
217
|
+
}
|
|
218
|
+
if (keys.value.length > 0) {
|
|
219
|
+
selectedKeys.value = keys.value.map((k) => k.keyId);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
169
222
|
</script>
|
|
170
223
|
|
|
171
|
-
<style scoped></style>
|
|
224
|
+
<style scoped></style>
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<!-- This is where the QR code scanner will be displayed -->
|
|
33
33
|
</div>
|
|
34
34
|
<!-- Show Error Messages -->
|
|
35
|
-
<div v-if="showNotFoundMessage" class="text-error mt-
|
|
35
|
+
<div v-if="showNotFoundMessage" class="text-error mt-4">
|
|
36
36
|
<p>{{ errorMessage }}</p>
|
|
37
37
|
</div>
|
|
38
38
|
<!-- Switch camera button inside the reader box -->
|
|
@@ -52,9 +52,18 @@ const props = defineProps({
|
|
|
52
52
|
type: Boolean,
|
|
53
53
|
default: false,
|
|
54
54
|
},
|
|
55
|
+
site: {
|
|
56
|
+
type: String,
|
|
57
|
+
default: null,
|
|
58
|
+
},
|
|
55
59
|
});
|
|
56
60
|
|
|
57
|
-
const
|
|
61
|
+
const { validateVisitorQrCode } = useVisitor();
|
|
62
|
+
|
|
63
|
+
const emits = defineEmits([
|
|
64
|
+
"closeDialog",
|
|
65
|
+
"openVisitorDataFromScannedQrCodeDialog",
|
|
66
|
+
]);
|
|
58
67
|
|
|
59
68
|
const message = ref("");
|
|
60
69
|
const messageColor = ref("");
|
|
@@ -86,31 +95,57 @@ const handleScanVisitorQRCode = async () => {
|
|
|
86
95
|
showNotFoundMessage.value = false;
|
|
87
96
|
// Automatically navigate to the scanned URL if it's a valid link
|
|
88
97
|
if (isValidUrl(qrCodeMessage)) {
|
|
89
|
-
console.log(
|
|
90
|
-
|
|
98
|
+
console.log("QR Code value", qrCodeMessage);
|
|
99
|
+
console.log("Last _id", qrCodeMessage.split("/").pop());
|
|
100
|
+
// get the last _id in the url
|
|
101
|
+
const id = qrCodeMessage.split("/").pop();
|
|
102
|
+
// check if it's a valid mongodb _id
|
|
103
|
+
if (/^[0-9a-fA-F]{24}$/.test(id as string)) {
|
|
104
|
+
// validate visitor's QR code
|
|
105
|
+
const response = await validateVisitorQrCode(
|
|
106
|
+
props.site as string,
|
|
107
|
+
id as string
|
|
108
|
+
);
|
|
109
|
+
console.log("validateVisitorQrCode", response);
|
|
110
|
+
if (response.errorMessage) {
|
|
111
|
+
showNotFoundMessage.value = true;
|
|
112
|
+
errorMessage.value = response.errorMessage;
|
|
113
|
+
showMessage(errorMessage.value, "error");
|
|
114
|
+
} else {
|
|
115
|
+
emits("openVisitorDataFromScannedQrCodeDialog", response);
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
showNotFoundMessage.value = true;
|
|
119
|
+
errorMessage.value = "Invalid mongodb _id.";
|
|
120
|
+
showMessage(errorMessage.value, "error");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// window.location.href = qrCodeMessage;
|
|
91
124
|
} else {
|
|
92
125
|
showNotFoundMessage.value = true;
|
|
93
|
-
errorMessage.value = "Invalid url";
|
|
94
|
-
showMessage(
|
|
126
|
+
errorMessage.value = "Invalid url.";
|
|
127
|
+
showMessage(errorMessage.value, "error");
|
|
95
128
|
}
|
|
96
129
|
},
|
|
97
130
|
(msg: string) => {
|
|
98
|
-
if (msg === "QR Code no longer in front") {
|
|
131
|
+
if (msg === "QR Code no longer in front.") {
|
|
99
132
|
showNotFoundMessage.value = true;
|
|
100
133
|
errorMessage.value = msg;
|
|
101
|
-
showMessage(
|
|
134
|
+
showMessage(errorMessage.value, "error");
|
|
102
135
|
}
|
|
103
136
|
}
|
|
104
137
|
)
|
|
105
138
|
.catch((err: any) => {
|
|
139
|
+
closeDialog();
|
|
106
140
|
showMessage(`Unable to start scanning, error: ${err}`, "error");
|
|
107
141
|
});
|
|
108
142
|
};
|
|
109
143
|
|
|
110
|
-
const isValidUrl = (
|
|
144
|
+
const isValidUrl = (url: string) => {
|
|
111
145
|
try {
|
|
112
|
-
|
|
113
|
-
|
|
146
|
+
if (typeof url == "string") {
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
114
149
|
} catch (_) {
|
|
115
150
|
return false;
|
|
116
151
|
}
|
|
@@ -130,7 +165,7 @@ const switchCamera = async () => {
|
|
|
130
165
|
};
|
|
131
166
|
|
|
132
167
|
const closeDialog = () => {
|
|
133
|
-
|
|
168
|
+
emits("closeDialog");
|
|
134
169
|
stopScanner();
|
|
135
170
|
};
|
|
136
171
|
|
|
@@ -163,7 +163,6 @@
|
|
|
163
163
|
</template>
|
|
164
164
|
|
|
165
165
|
<script setup lang="ts">
|
|
166
|
-
import { useCleaningSchedulePermission } from "../composables/useCleaningSchedulePermission";
|
|
167
166
|
import useCleaningSchedules from "../composables/useCleaningSchedules";
|
|
168
167
|
import useUtils from "../composables/useUtils";
|
|
169
168
|
|
|
@@ -174,6 +173,9 @@ const props = defineProps({
|
|
|
174
173
|
type: { type: String, required: true, default: "cleaner" },
|
|
175
174
|
serviceType: { type: String, default: "" },
|
|
176
175
|
scheduleRoute: { type: String, default: "cleaning-schedule" },
|
|
176
|
+
canGenerateChecklist: { type: Boolean, default: false },
|
|
177
|
+
canViewHistory: { type: Boolean, default: true },
|
|
178
|
+
canManageScheduleTasks: { type: Boolean, default: false },
|
|
177
179
|
});
|
|
178
180
|
|
|
179
181
|
const submitting = ref(false);
|
|
@@ -195,8 +197,9 @@ const headers = [
|
|
|
195
197
|
|
|
196
198
|
const { formatDate, back } = useUtils();
|
|
197
199
|
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
+
const canGenerateChecklist = computed(() => props.canGenerateChecklist);
|
|
201
|
+
const canViewHistory = computed(() => props.canViewHistory);
|
|
202
|
+
const canManageScheduleTasks = computed(() => props.canManageScheduleTasks);
|
|
200
203
|
|
|
201
204
|
const selectedScheduleStatus = useState<string>(
|
|
202
205
|
"selectedScheduleStatus",
|
|
@@ -257,24 +257,27 @@
|
|
|
257
257
|
|
|
258
258
|
<script lang="ts" setup>
|
|
259
259
|
import useScheduleTask from "../composables/useScheduleTask";
|
|
260
|
-
import useScheduleTaskPermission from "../composables/useScheduleTaskPermission";
|
|
261
260
|
|
|
262
261
|
const props = defineProps({
|
|
263
262
|
orgId: { type: String, required: true },
|
|
264
263
|
site: { type: String, required: true },
|
|
265
264
|
type: { type: String, default: "toilet" },
|
|
266
265
|
serviceType: { type: String, default: "" },
|
|
266
|
+
canViewScheduleTasks: { type: Boolean, default: true },
|
|
267
|
+
canCreateScheduleTask: { type: Boolean, default: false },
|
|
268
|
+
canUpdateScheduleTask: { type: Boolean, default: false },
|
|
269
|
+
canDeleteScheduleTask: { type: Boolean, default: false },
|
|
270
|
+
canViewScheduleTaskDetails: { type: Boolean, default: true },
|
|
267
271
|
});
|
|
268
272
|
|
|
269
273
|
const { formatDate, debounce } = useUtils();
|
|
270
274
|
const { getScheduleTasks, getScheduleTaskById, deleteScheduleTask } = useScheduleTask();
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
} = useScheduleTaskPermission();
|
|
275
|
+
|
|
276
|
+
const canViewScheduleTasks = computed(() => props.canViewScheduleTasks);
|
|
277
|
+
const canCreateScheduleTask = computed(() => props.canCreateScheduleTask);
|
|
278
|
+
const canUpdateScheduleTask = computed(() => props.canUpdateScheduleTask);
|
|
279
|
+
const canDeleteScheduleTask = computed(() => props.canDeleteScheduleTask);
|
|
280
|
+
const canViewScheduleTaskDetails = computed(() => props.canViewScheduleTaskDetails);
|
|
278
281
|
|
|
279
282
|
const page = ref(1);
|
|
280
283
|
const pages = ref(0);
|
package/components/UnitMain.vue
CHANGED
|
@@ -209,7 +209,6 @@
|
|
|
209
209
|
</template>
|
|
210
210
|
|
|
211
211
|
<script setup lang="ts">
|
|
212
|
-
import { useUnitPermission } from "../composables/useUnitPermission";
|
|
213
212
|
import useUnits from "../composables/useUnits";
|
|
214
213
|
import useUtils from "../composables/useUtils";
|
|
215
214
|
|
|
@@ -217,6 +216,11 @@ const props = defineProps({
|
|
|
217
216
|
orgId: { type: String, default: "" },
|
|
218
217
|
site: { type: String, default: "" },
|
|
219
218
|
serviceType: { type: String, default: "", required: true },
|
|
219
|
+
canViewUnits: { type: Boolean, default: true },
|
|
220
|
+
canCreateUnit: { type: Boolean, default: false },
|
|
221
|
+
canUpdateUnit: { type: Boolean, default: false },
|
|
222
|
+
canDeleteUnit: { type: Boolean, default: false },
|
|
223
|
+
canImportUnit: { type: Boolean, default: false },
|
|
220
224
|
});
|
|
221
225
|
|
|
222
226
|
const items = ref<Array<Record<string, any>>>([]);
|
|
@@ -299,13 +303,11 @@ function showMessage(msg: string, color: string = "error") {
|
|
|
299
303
|
messageSnackbar.value = true;
|
|
300
304
|
}
|
|
301
305
|
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
canImportUnit,
|
|
308
|
-
} = useUnitPermission();
|
|
306
|
+
const canViewUnits = computed(() => props.canViewUnits);
|
|
307
|
+
const canCreateUnit = computed(() => props.canCreateUnit);
|
|
308
|
+
const canUpdateUnit = computed(() => props.canUpdateUnit);
|
|
309
|
+
const canDeleteUnit = computed(() => props.canDeleteUnit);
|
|
310
|
+
const canImportUnit = computed(() => props.canImportUnit);
|
|
309
311
|
|
|
310
312
|
async function handleDownloadExcel() {
|
|
311
313
|
try {
|