@7365admin1/layer-common 3.0.19 → 3.0.21

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.
@@ -55,18 +55,19 @@
55
55
 
56
56
  <v-dialog v-model="dialogShowMoreActions" width="400" persistent>
57
57
  <HygieneUpdateMoreAction
58
- :title="selectedSupply?.name"
58
+ title="Preview"
59
59
  :canDelete="false"
60
60
  :canUpdate="false"
61
61
  :canApprove="false"
62
62
  :canDisapprove="false"
63
63
  :disabled="true"
64
+ :showMoreActions="false"
64
65
  @close="dialogShowMoreActions = false"
65
66
  >
66
67
  <template #content>
67
68
  <v-row no-gutters>
68
69
  <v-col v-if="selectedSupply" cols="12" class="mb-2">
69
- <v-row
70
+ <!-- <v-row
70
71
  no-gutters
71
72
  class="mb-3"
72
73
  v-if="
@@ -81,8 +82,8 @@
81
82
  >
82
83
  <v-img
83
84
  :src="getFileUrl(selectedSupply.attachment[0])"
84
- height="180"
85
- cover
85
+ height="350"
86
+ contain
86
87
  class="rounded-lg"
87
88
  @click="viewAttachment(selectedSupply.attachment[0])"
88
89
  >
@@ -101,35 +102,56 @@
101
102
  </v-img>
102
103
  </v-sheet>
103
104
  </v-col>
104
- </v-row>
105
+ </v-row> -->
105
106
 
106
107
  <v-row
107
108
  no-gutters
108
109
  class="mb-3"
109
110
  v-if="
110
- selectedSupply.attachment &&
111
- selectedSupply.attachment.length > 1
111
+ selectedSupply.attachment && selectedSupply.attachment.length
112
112
  "
113
113
  >
114
114
  <v-col cols="12">
115
- <v-row no-gutters>
115
+ <v-row
116
+ no-gutters
117
+ :class="
118
+ selectedSupply.attachment.length > 1
119
+ ? 'flex-wrap'
120
+ : 'justify-center'
121
+ "
122
+ >
116
123
  <v-col
117
- v-for="(attId, i) in selectedSupply.attachment.slice(1)"
118
- :key="attId + '-' + i"
119
- cols="auto"
124
+ v-for="(attId, i) in selectedSupply.attachment"
125
+ :key="i"
126
+ cols="6"
120
127
  class="pa-1"
121
128
  >
122
129
  <v-sheet
123
130
  rounded="sm"
124
- style="
125
- width: 72px;
126
- height: 56px;
127
- overflow: hidden;
128
- cursor: pointer;
129
- "
130
- @click="viewAttachment(attId)"
131
+ class="border-md pa-1"
132
+ style="overflow: hidden; cursor: pointer"
131
133
  >
132
- <v-img :src="getFileUrl(attId)" height="56" cover />
134
+ <v-img
135
+ :src="getFileUrl(attId)"
136
+ :height="
137
+ selectedSupply.attachment.length > 1 ? 100 : '100%'
138
+ "
139
+ contain
140
+ @click="viewAttachment(attId)"
141
+ >
142
+ <template v-slot:placeholder>
143
+ <v-row
144
+ class="fill-height ma-0"
145
+ align="center"
146
+ justify="center"
147
+ >
148
+ <v-progress-circular
149
+ indeterminate
150
+ color="grey-lighten-4"
151
+ />
152
+ </v-row>
153
+ </template>
154
+ </v-img>
133
155
  </v-sheet>
134
156
  </v-col>
135
157
  </v-row>
@@ -137,37 +159,37 @@
137
159
  </v-row>
138
160
 
139
161
  <v-row no-gutters class="mb-2">
140
- <v-col cols="5" class="text-subtitle-2 font-weight-bold">
162
+ <v-col cols="6" class="text-subtitle-2 font-weight-bold">
141
163
  Name:
142
164
  </v-col>
143
- <v-col cols="7" class="text-subtitle-2">
165
+ <v-col cols="6" class="text-subtitle-2">
144
166
  {{ selectedSupply.supplyName || "N/A" }}
145
167
  </v-col>
146
168
  </v-row>
147
169
 
148
170
  <v-row no-gutters class="mb-2">
149
- <v-col cols="5" class="text-subtitle-2 font-weight-bold">
150
- Equipment Quantity:
171
+ <v-col cols="6" class="text-subtitle-2 font-weight-bold">
172
+ Checkout Quantity:
151
173
  </v-col>
152
- <v-col cols="7" class="text-subtitle-2">
174
+ <v-col cols="6" class="text-subtitle-2">
153
175
  {{ selectedSupply.qty || "N/A" }}
154
176
  </v-col>
155
177
  </v-row>
156
178
 
157
179
  <v-row no-gutters class="mb-2">
158
- <v-col cols="5" class="text-subtitle-2 font-weight-bold">
180
+ <v-col cols="6" class="text-subtitle-2 font-weight-bold">
159
181
  Unit of Measurement:
160
182
  </v-col>
161
- <v-col cols="7" class="text-subtitle-2">
183
+ <v-col cols="6" class="text-subtitle-2">
162
184
  {{ selectedSupply.unitOfMeasurement || "N/A" }}
163
185
  </v-col>
164
186
  </v-row>
165
187
 
166
188
  <v-row no-gutters class="mb-2">
167
- <v-col cols="5" class="text-subtitle-2 font-weight-bold">
168
- Stock Quantity:
189
+ <v-col cols="6" class="text-subtitle-2 font-weight-bold">
190
+ Available Stock Quantity:
169
191
  </v-col>
170
- <v-col cols="7" class="text-subtitle-2">
192
+ <v-col cols="6" class="text-subtitle-2">
171
193
  {{ selectedSupply.stockQty || "N/A" }}
172
194
  </v-col>
173
195
  </v-row>
@@ -246,14 +268,26 @@
246
268
  >
247
269
  <v-text-field
248
270
  v-model.number="item.qty"
249
- :rules="[requiredRule]"
271
+ :rules="
272
+ (item.stockQty ?? 0) === 0
273
+ ? []
274
+ : [
275
+ requiredRule,
276
+ (v) => v > 0 || 'Must be greater than 0',
277
+ (v) =>
278
+ v <= (item.stockQty ?? 0) ||
279
+ 'Exceeds stock limits',
280
+ ]
281
+ "
250
282
  density="compact"
251
283
  variant="outlined"
252
284
  type="number"
253
285
  min="1"
254
- hide-details
255
- style="max-width: 120px"
286
+ :max="item.stockQty ?? 0"
287
+ hide-details="auto"
288
+ style="max-width: 150px"
256
289
  class="mr-2"
290
+ :disabled="(item.stockQty ?? 0) === 0"
257
291
  />
258
292
 
259
293
  <v-menu location="bottom end">
@@ -290,6 +324,15 @@
290
324
  </v-list>
291
325
  </v-menu>
292
326
  </v-col>
327
+
328
+ <v-col
329
+ v-if="item.stockQty == 0"
330
+ cols="12"
331
+ md="4"
332
+ class="d-flex align-center text-error"
333
+ >
334
+ Insufficient stock
335
+ </v-col>
293
336
  </v-row>
294
337
 
295
338
  <!-- Photo Preview -->
@@ -360,7 +403,7 @@
360
403
  :loading="submitting"
361
404
  @click="_equipmentItem()"
362
405
  >
363
- Equipment Item
406
+ Checkout Item
364
407
  </v-btn>
365
408
  </v-col>
366
409
  </v-row>
@@ -437,6 +480,32 @@
437
480
  </v-card-actions>
438
481
  </v-card>
439
482
  </v-dialog>
483
+
484
+ <v-dialog v-model="showAttachmentDialog" max-width="720" persistent>
485
+ <v-card rounded="lg">
486
+ <v-card-title class="d-flex align-center pa-4">
487
+ <div>
488
+ <div class="text-h6 font-weight-bold">Attachment</div>
489
+ </div>
490
+
491
+ <v-spacer />
492
+
493
+ <v-btn
494
+ icon="mdi-close"
495
+ variant="text"
496
+ size="small"
497
+ @click="(showAttachmentDialog = false), (attachmentUrl = '')"
498
+ />
499
+ </v-card-title>
500
+
501
+ <v-divider />
502
+
503
+ <!-- Body -->
504
+ <v-card-text class="pa-6">
505
+ <v-img :src="attachmentUrl" contain />
506
+ </v-card-text>
507
+ </v-card>
508
+ </v-dialog>
440
509
  </template>
441
510
 
442
511
  <script setup lang="ts">
@@ -535,7 +604,7 @@ watchEffect(() => {
535
604
  supplyName: getEquipmentItemByIdReq.value.supplyName || "N/A",
536
605
  qty: getEquipmentItemByIdReq.value.qty || 0,
537
606
  unitOfMeasurement:
538
- getEquipmentItemByIdReq.value.supply?.unitOfMeasurement || "N/A",
607
+ getEquipmentItemByIdReq.value.unitOfMeasurement || "N/A",
539
608
  status: getEquipmentItemByIdReq.value.status || "N/A",
540
609
  site: getEquipmentItemByIdReq.value.site || "N/A",
541
610
  supply:
@@ -555,16 +624,17 @@ watchEffect(() => {
555
624
 
556
625
  const { getSupplies } = useEquipmentManagement();
557
626
 
558
- const { data: getSuppliesReq } = await useLazyAsyncData(
559
- "get-supplies-for-equipment-item",
560
- () =>
561
- getSupplies({
562
- site: props.site,
563
- limit: 100,
564
- serviceType: props.serviceType,
565
- }),
566
- {}
567
- );
627
+ const { data: getSuppliesReq, refresh: getSuppliesRefresh } =
628
+ await useLazyAsyncData(
629
+ "get-supplies-for-equipment-item",
630
+ () =>
631
+ getSupplies({
632
+ site: props.site,
633
+ limit: 100,
634
+ serviceType: props.serviceType,
635
+ }),
636
+ {}
637
+ );
568
638
 
569
639
  watchEffect(() => {
570
640
  if (getSuppliesReq.value) {
@@ -658,7 +728,34 @@ async function _equipmentItem() {
658
728
  return;
659
729
  }
660
730
 
661
- const items = equipmentItems.value.map((item) => ({
731
+ const validItems = equipmentItems.value.filter(
732
+ (item) => (item.stockQty ?? 0) > 0
733
+ );
734
+
735
+ if (validItems.length === 0) {
736
+ showMessage("None of the selected equipment has available stock.");
737
+ submitting.value = false;
738
+ return;
739
+ }
740
+
741
+ for (const item of validItems) {
742
+ if (item.qty > (item.stockQty ?? 0)) {
743
+ showMessage(
744
+ `Checkout quantity for ${item.supplyName} exceeds available stock (${
745
+ item.stockQty ?? 0
746
+ }).`
747
+ );
748
+ submitting.value = false;
749
+ return;
750
+ }
751
+ if (!item.qty || item.qty <= 0) {
752
+ showMessage(`Quantity for ${item.supplyName} must be at least 1.`);
753
+ submitting.value = false;
754
+ return;
755
+ }
756
+ }
757
+
758
+ const items = validItems.map((item) => ({
662
759
  supply: item.supply,
663
760
  qty: item.qty,
664
761
  ...(item.photoIds && item.photoIds.length
@@ -666,7 +763,10 @@ async function _equipmentItem() {
666
763
  : {}),
667
764
  }));
668
765
 
669
- await equipmentItemApi(props.site, { items, serviceType: props.serviceType });
766
+ await equipmentItemApi(props.site, {
767
+ items,
768
+ serviceType: props.serviceType,
769
+ });
670
770
 
671
771
  showMessage(
672
772
  `Checked out ${equipmentItems.value.length} item(s).`,
@@ -676,6 +776,7 @@ async function _equipmentItem() {
676
776
  equipmentItems.value = [];
677
777
 
678
778
  await getEquipmentItemsRefresh();
779
+ await getSuppliesRefresh();
679
780
  } catch (error: any) {
680
781
  console.error(error);
681
782
  showMessage(error?.data?.message, "error");
@@ -685,11 +786,14 @@ async function _equipmentItem() {
685
786
  }
686
787
 
687
788
  const { getFileUrl } = useFile();
789
+ const showAttachmentDialog = ref(false);
790
+ const attachmentUrl = ref("");
688
791
 
689
792
  function viewAttachment(attachmentId: string) {
690
793
  if (!attachmentId) return;
691
794
  const url = getFileUrl(attachmentId);
692
- window.open(url, "_blank");
795
+ showAttachmentDialog.value = true;
796
+ attachmentUrl.value = url;
693
797
  }
694
798
 
695
799
  const currentPhotos = computed({
@@ -242,7 +242,11 @@
242
242
  </v-card>
243
243
  </v-dialog>
244
244
 
245
- <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
245
+ <Snackbar
246
+ v-model="messageSnackbar"
247
+ :text="snackbarMessage"
248
+ :color="messageColor"
249
+ />
246
250
  </template>
247
251
  <script setup lang="ts">
248
252
  import useEquipment from "../composables/useEquipment";
@@ -352,8 +356,11 @@ const equipmentUnit = ref("");
352
356
  const stockActionFormRef = ref<any>(null);
353
357
  const stockActionValid = ref(false);
354
358
 
359
+ const snackbarMessage = ref("");
360
+
355
361
  function showMessage(msg: string, color: string = "error") {
356
362
  message.value = msg;
363
+ snackbarMessage.value = msg;
357
364
  messageColor.value = color;
358
365
  messageSnackbar.value = true;
359
366
  }