@ozdao/martyrs 0.2.473 → 0.2.475

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.
Files changed (235) hide show
  1. package/dist/{Media-DW8RLbfM.js → Media-_vz04tII.js} +1 -1
  2. package/dist/{Media-y_TX6us_.mjs → Media-sGk7Bp9b.mjs} +1 -1
  3. package/dist/auth.server.js +6 -2
  4. package/dist/auth.server.mjs +6 -2
  5. package/dist/authJwt-CELQKF2s.js +82 -0
  6. package/dist/authJwt-DnXu3BFq.mjs +83 -0
  7. package/dist/builder.js +7 -4
  8. package/dist/builder.mjs +7 -4
  9. package/dist/chats.server.js +1 -1
  10. package/dist/chats.server.mjs +1 -1
  11. package/dist/community.server.js +4 -4
  12. package/dist/community.server.mjs +4 -4
  13. package/dist/events.server.js +4 -4
  14. package/dist/events.server.mjs +4 -4
  15. package/dist/files.server.js +1 -1
  16. package/dist/files.server.mjs +1 -1
  17. package/dist/gallery.server.js +3 -3
  18. package/dist/gallery.server.mjs +3 -3
  19. package/dist/{globals.abac-DT0VjfaZ.js → globals.abac-Bn-4tbX8.js} +110 -16
  20. package/dist/{globals.abac-CvmZM8XG.mjs → globals.abac-DZpTRxKR.mjs} +110 -16
  21. package/dist/globals.server.js +70 -10
  22. package/dist/globals.server.mjs +70 -10
  23. package/dist/{globals.verifier-C_VZYebB.mjs → globals.verifier-BdJxc8-8.mjs} +34 -0
  24. package/dist/{globals.verifier-ChDpCdy_.js → globals.verifier-CKYpYfQl.js} +34 -0
  25. package/dist/{index-CVXl1rB5.js → index-BOmxJQ5W.js} +7 -86
  26. package/dist/{index-Df8vtZx7.mjs → index-C_Fw0Umg.mjs} +7 -86
  27. package/dist/{main-CgmHzhq5.mjs → main-CqMtW7Hq.mjs} +274 -276
  28. package/dist/{main-CCfQH-Dd.js → main-CsGkbSyK.js} +2 -2
  29. package/dist/martyrs/src/components/Block/Block.vue.cjs +1 -1
  30. package/dist/martyrs/src/components/Block/Block.vue.js +1 -1
  31. package/dist/martyrs/src/components/Button/Button.vue2.cjs +1 -1
  32. package/dist/martyrs/src/components/Button/Button.vue2.js +1 -1
  33. package/dist/martyrs/src/components/Chips/{Chips.vue2.cjs → Chips.vue.cjs} +2 -2
  34. package/dist/martyrs/src/components/Chips/Chips.vue.cjs.map +1 -0
  35. package/dist/martyrs/src/components/Chips/{Chips.vue2.js → Chips.vue.js} +2 -2
  36. package/dist/martyrs/src/components/Chips/Chips.vue.js.map +1 -0
  37. package/dist/martyrs/src/components/Dropdown/{Dropdown.vue.cjs → Dropdown.vue2.cjs} +2 -2
  38. package/dist/martyrs/src/components/Dropdown/Dropdown.vue2.cjs.map +1 -0
  39. package/dist/martyrs/src/components/Dropdown/{Dropdown.vue.js → Dropdown.vue2.js} +2 -2
  40. package/dist/martyrs/src/components/Dropdown/{Dropdown.vue.cjs.map → Dropdown.vue2.js.map} +1 -1
  41. package/dist/martyrs/src/components/Feed/Feed.vue.cjs +2 -2
  42. package/dist/martyrs/src/components/Feed/Feed.vue.js +2 -2
  43. package/dist/martyrs/src/components/Loader/{Loader.vue2.cjs → Loader.vue.cjs} +2 -2
  44. package/dist/martyrs/src/components/Loader/{Loader.vue2.js.map → Loader.vue.cjs.map} +1 -1
  45. package/dist/martyrs/src/components/Loader/{Loader.vue2.js → Loader.vue.js} +2 -2
  46. package/dist/martyrs/src/components/Loader/Loader.vue.js.map +1 -0
  47. package/dist/martyrs/src/components/LocationMarker/LocationMarker.vue2.cjs +1 -1
  48. package/dist/martyrs/src/components/LocationMarker/LocationMarker.vue2.js +1 -1
  49. package/dist/martyrs/src/components/Select/Select.vue.cjs +4 -4
  50. package/dist/martyrs/src/components/Select/Select.vue.cjs.map +1 -1
  51. package/dist/martyrs/src/components/Select/Select.vue.js +4 -4
  52. package/dist/martyrs/src/components/Select/Select.vue.js.map +1 -1
  53. package/dist/martyrs/src/components/Slider/Slider.native.vue.cjs +1 -1
  54. package/dist/martyrs/src/components/Slider/Slider.native.vue.js +1 -1
  55. package/dist/martyrs/src/components/Tooltip/{Tooltip.vue2.cjs → Tooltip.vue.cjs} +2 -2
  56. package/dist/martyrs/src/components/Tooltip/{Tooltip.vue2.js.map → Tooltip.vue.cjs.map} +1 -1
  57. package/dist/martyrs/src/components/Tooltip/{Tooltip.vue2.js → Tooltip.vue.js} +2 -2
  58. package/dist/martyrs/src/components/Tooltip/Tooltip.vue.js.map +1 -0
  59. package/dist/martyrs/src/components/UploadImageMultiple/UploadImageMultiple.vue.cjs +1 -1
  60. package/dist/martyrs/src/components/UploadImageMultiple/UploadImageMultiple.vue.js +1 -1
  61. package/dist/martyrs/src/modules/auth/views/components/layouts/Auth.vue.cjs +1 -1
  62. package/dist/martyrs/src/modules/auth/views/components/layouts/Auth.vue.js +1 -1
  63. package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.cjs +2 -2
  64. package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js +2 -2
  65. package/dist/martyrs/src/modules/community/community.client.js +27 -27
  66. package/dist/martyrs/src/modules/community/community.client.js.map +1 -1
  67. package/dist/martyrs/src/modules/community/components/blocks/CardBlogpost.vue.cjs +1 -1
  68. package/dist/martyrs/src/modules/community/components/blocks/CardBlogpost.vue.js +1 -1
  69. package/dist/martyrs/src/modules/community/components/pages/BlogPost.vue.cjs +2 -2
  70. package/dist/martyrs/src/modules/community/components/pages/BlogPost.vue.js +2 -2
  71. package/dist/martyrs/src/modules/community/components/sections/HotPosts.vue.cjs +4 -5
  72. package/dist/martyrs/src/modules/community/components/sections/HotPosts.vue.cjs.map +1 -1
  73. package/dist/martyrs/src/modules/community/components/sections/HotPosts.vue.js +4 -5
  74. package/dist/martyrs/src/modules/community/components/sections/HotPosts.vue.js.map +1 -1
  75. package/dist/martyrs/src/modules/events/components/blocks/CardEvent.vue.cjs +1 -1
  76. package/dist/martyrs/src/modules/events/components/blocks/CardEvent.vue.js +1 -1
  77. package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.cjs +1 -1
  78. package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.js +1 -1
  79. package/dist/martyrs/src/modules/events/components/pages/Event.vue.cjs +2 -2
  80. package/dist/martyrs/src/modules/events/components/pages/Event.vue.js +2 -2
  81. package/dist/martyrs/src/modules/events/components/sections/EventsHot.vue.cjs +2 -2
  82. package/dist/martyrs/src/modules/events/components/sections/EventsHot.vue.js +2 -2
  83. package/dist/martyrs/src/modules/events/components/sections/Feed.vue.cjs +1 -1
  84. package/dist/martyrs/src/modules/events/components/sections/Feed.vue.js +1 -1
  85. package/dist/martyrs/src/modules/events/components/sections/List.vue.cjs +1 -1
  86. package/dist/martyrs/src/modules/events/components/sections/List.vue.js +1 -1
  87. package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.cjs +1 -1
  88. package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.js +1 -1
  89. package/dist/martyrs/src/modules/globals/views/components/blocks/CardHeader.vue.cjs +3 -3
  90. package/dist/martyrs/src/modules/globals/views/components/blocks/CardHeader.vue.js +3 -3
  91. package/dist/martyrs/src/modules/globals/views/components/blocks/PopupDateSelector.vue.cjs +1 -1
  92. package/dist/martyrs/src/modules/globals/views/components/blocks/PopupDateSelector.vue.js +1 -1
  93. package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.cjs +1 -1
  94. package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.js +1 -1
  95. package/dist/martyrs/src/modules/globals/views/components/partials/Navigation.vue.cjs +1 -1
  96. package/dist/martyrs/src/modules/globals/views/components/partials/Navigation.vue.js +1 -1
  97. package/dist/martyrs/src/modules/marketplace/views/components/sections/SectionMenu.vue.cjs +1 -1
  98. package/dist/martyrs/src/modules/marketplace/views/components/sections/SectionMenu.vue.js +1 -1
  99. package/dist/martyrs/src/modules/orders/components/blocks/CardOrderUser.vue.cjs +1 -1
  100. package/dist/martyrs/src/modules/orders/components/blocks/CardOrderUser.vue.js +1 -1
  101. package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.cjs +1 -1
  102. package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js +1 -1
  103. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.cjs +88 -27
  104. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.cjs.map +1 -1
  105. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js +89 -28
  106. package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js.map +1 -1
  107. package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.cjs +2 -2
  108. package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js +2 -2
  109. package/dist/martyrs/src/modules/orders/store/shopcart.cjs +1 -0
  110. package/dist/martyrs/src/modules/orders/store/shopcart.cjs.map +1 -1
  111. package/dist/martyrs/src/modules/orders/store/shopcart.js +1 -0
  112. package/dist/martyrs/src/modules/orders/store/shopcart.js.map +1 -1
  113. package/dist/martyrs/src/modules/organizations/components/blocks/CardOrganization.vue.cjs +1 -1
  114. package/dist/martyrs/src/modules/organizations/components/blocks/CardOrganization.vue.js +1 -1
  115. package/dist/martyrs/src/modules/organizations/components/pages/DepartmentEdit.vue.cjs +1 -1
  116. package/dist/martyrs/src/modules/organizations/components/pages/DepartmentEdit.vue.js +1 -1
  117. package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.cjs +1 -1
  118. package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.js +1 -1
  119. package/dist/martyrs/src/modules/organizations/components/sections/DetailsTabSection.vue.cjs +2 -2
  120. package/dist/martyrs/src/modules/organizations/components/sections/DetailsTabSection.vue.js +2 -2
  121. package/dist/martyrs/src/modules/organizations/components/sections/Documents.vue.cjs +1 -1
  122. package/dist/martyrs/src/modules/organizations/components/sections/Documents.vue.js +1 -1
  123. package/dist/martyrs/src/modules/organizations/components/sections/Organizations.vue.cjs +1 -1
  124. package/dist/martyrs/src/modules/organizations/components/sections/Organizations.vue.js +1 -1
  125. package/dist/martyrs/src/modules/pages/views/components/blocks/CardPage.vue.cjs +1 -1
  126. package/dist/martyrs/src/modules/pages/views/components/blocks/CardPage.vue.js +1 -1
  127. package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.cjs +1 -1
  128. package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.js +1 -1
  129. package/dist/martyrs/src/modules/products/components/blocks/Images360.vue.cjs +1 -1
  130. package/dist/martyrs/src/modules/products/components/blocks/Images360.vue.js +1 -1
  131. package/dist/martyrs/src/modules/products/components/pages/Categories.vue.cjs +1 -1
  132. package/dist/martyrs/src/modules/products/components/pages/Categories.vue.js +1 -1
  133. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.cjs +21 -2
  134. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.cjs.map +1 -1
  135. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js +21 -2
  136. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js.map +1 -1
  137. package/dist/martyrs/src/modules/products/components/pages/Product.vue.cjs +1 -0
  138. package/dist/martyrs/src/modules/products/components/pages/Product.vue.cjs.map +1 -1
  139. package/dist/martyrs/src/modules/products/components/pages/Product.vue.js +1 -0
  140. package/dist/martyrs/src/modules/products/components/pages/Product.vue.js.map +1 -1
  141. package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.cjs +2 -2
  142. package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.cjs.map +1 -1
  143. package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js +2 -2
  144. package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js.map +1 -1
  145. package/dist/martyrs/src/modules/products/components/pages/ProductRecommmendation.vue.cjs +1 -1
  146. package/dist/martyrs/src/modules/products/components/pages/ProductRecommmendation.vue.js +1 -1
  147. package/dist/martyrs/src/modules/products/components/sections/EditProductInfo.vue.cjs +1 -1
  148. package/dist/martyrs/src/modules/products/components/sections/EditProductInfo.vue.js +1 -1
  149. package/dist/martyrs/src/modules/products/components/sections/PopularProducts.vue.cjs +1 -1
  150. package/dist/martyrs/src/modules/products/components/sections/PopularProducts.vue.js +1 -1
  151. package/dist/martyrs/src/modules/products/store/categories.cjs +2 -0
  152. package/dist/martyrs/src/modules/products/store/categories.cjs.map +1 -1
  153. package/dist/martyrs/src/modules/products/store/categories.js +2 -0
  154. package/dist/martyrs/src/modules/products/store/categories.js.map +1 -1
  155. package/dist/martyrs/src/modules/spots/components/blocks/CardSpot.vue.cjs +1 -1
  156. package/dist/martyrs/src/modules/spots/components/blocks/CardSpot.vue.js +1 -1
  157. package/dist/martyrs/src/modules/spots/components/layouts/Spots.vue.cjs +1 -1
  158. package/dist/martyrs/src/modules/spots/components/layouts/Spots.vue.js +1 -1
  159. package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.cjs +31 -24
  160. package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.cjs.map +1 -1
  161. package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.js +31 -24
  162. package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.js.map +1 -1
  163. package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.cjs +807 -0
  164. package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.cjs.map +1 -0
  165. package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.js +807 -0
  166. package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.js.map +1 -0
  167. package/dist/martyrs/src/modules/spots/store/spots.cjs +4 -1
  168. package/dist/martyrs/src/modules/spots/store/spots.cjs.map +1 -1
  169. package/dist/martyrs/src/modules/spots/store/spots.js +4 -1
  170. package/dist/martyrs/src/modules/spots/store/spots.js.map +1 -1
  171. package/dist/martyrs.cjs.js +1 -1
  172. package/dist/martyrs.css +1 -1
  173. package/dist/martyrs.es.js +1 -1
  174. package/dist/notifications.server.js +1 -1
  175. package/dist/notifications.server.mjs +1 -1
  176. package/dist/orders.server.js +5 -4
  177. package/dist/orders.server.mjs +5 -4
  178. package/dist/organizations.server.js +120 -47
  179. package/dist/organizations.server.mjs +120 -47
  180. package/dist/{ownership.schema-C0w02Vw1.mjs → ownership.schema-CNCotD3D.mjs} +10 -4
  181. package/dist/{ownership.schema-Ck2H9clB.js → ownership.schema-MxfJlPtq.js} +10 -4
  182. package/dist/products.server.js +415 -149
  183. package/dist/products.server.mjs +415 -149
  184. package/dist/{profile.schema-h61hhB2w.js → profile.schema-BLSuV_VC.js} +0 -4
  185. package/dist/{profile.schema-kP_zKXNt.mjs → profile.schema-BRuvQ7QV.mjs} +0 -4
  186. package/dist/{queryProcessor-CWnMIe2U.mjs → queryProcessor-CVKI651_.mjs} +62 -8
  187. package/dist/{queryProcessor-D6GuKfTV.js → queryProcessor-DSUqSk3I.js} +62 -8
  188. package/dist/rents.server.js +4 -4
  189. package/dist/rents.server.mjs +4 -4
  190. package/dist/spots.server.js +162 -8
  191. package/dist/spots.server.mjs +162 -8
  192. package/dist/style.css +27 -4
  193. package/dist/wallet.server.js +2 -2
  194. package/dist/wallet.server.mjs +2 -2
  195. package/package.json +1 -1
  196. package/src/builder/rspack/rspack.config.base.js +1 -1
  197. package/src/builder/rspack/rspack.config.client.js +13 -5
  198. package/src/components/Select/Select.vue +4 -2
  199. package/src/modules/auth/models/user.model.js +4 -1
  200. package/src/modules/community/components/sections/HotPosts.vue +1 -1
  201. package/src/modules/globals/controllers/classes/globals.abac.js +148 -23
  202. package/src/modules/globals/controllers/classes/globals.validator.js +37 -0
  203. package/src/modules/globals/controllers/classes/globals.verifier.js +2 -0
  204. package/src/modules/globals/controllers/policies/globals.policies.js +91 -74
  205. package/src/modules/globals/controllers/utils/queryProcessor.js +59 -11
  206. package/src/modules/globals/models/schemas/ownership.schema.js +11 -6
  207. package/src/modules/globals/models/schemas/profile.schema.js +0 -4
  208. package/src/modules/music/components/layouts/MusicLayout.vue +10 -58
  209. package/src/modules/music/components/pages/MusicHome.vue +5 -5
  210. package/src/modules/orders/components/pages/OrderCreate.vue +84 -12
  211. package/src/modules/orders/controllers/orders.controller.js +3 -0
  212. package/src/modules/orders/store/shopcart.js +1 -0
  213. package/src/modules/organizations/models/schemas/accesses.schema.js +18 -0
  214. package/src/modules/organizations/policies/organizations.policies.js +117 -61
  215. package/src/modules/products/components/pages/CategoryEdit.vue +27 -2
  216. package/src/modules/products/components/pages/Product.vue +1 -0
  217. package/src/modules/products/components/pages/ProductEdit.vue +2 -2
  218. package/src/modules/products/controllers/categories.controller.js +297 -133
  219. package/src/modules/products/middlewares/categories.verifier.js +177 -0
  220. package/src/modules/products/models/category.model.js +12 -14
  221. package/src/modules/products/routes/categories.routes.js +50 -11
  222. package/src/modules/products/store/categories.js +2 -0
  223. package/src/modules/spots/components/pages/SpotEdit.vue +21 -17
  224. package/src/modules/spots/components/sections/WorktimeEdit.vue +840 -0
  225. package/src/modules/spots/controllers/queries/getIsOpenNowStage.js +109 -0
  226. package/src/modules/spots/controllers/spots.controller.js +2 -1
  227. package/src/modules/spots/models/spot.model.js +59 -13
  228. package/src/modules/spots/store/spots.js +4 -1
  229. package/dist/martyrs/src/components/Chips/Chips.vue2.cjs.map +0 -1
  230. package/dist/martyrs/src/components/Chips/Chips.vue2.js.map +0 -1
  231. package/dist/martyrs/src/components/Dropdown/Dropdown.vue.js.map +0 -1
  232. package/dist/martyrs/src/components/Loader/Loader.vue2.cjs.map +0 -1
  233. package/dist/martyrs/src/components/Tooltip/Tooltip.vue2.cjs.map +0 -1
  234. package/src/modules/products/middlewares/index.js +0 -11
  235. package/src/modules/products/middlewares/verifyCategory.js +0 -25
@@ -0,0 +1,840 @@
1
+ <template>
2
+ <div class="working-hours-editor w-100">
3
+ <div class="mn-b-small flex flex-nowrap flex-v-center">
4
+ <h4 class="mn-r-auto">{{ t('workingHours.title') }}</h4>
5
+ <Button
6
+ class="bg-main"
7
+ :submit="addRegularDay"
8
+ :showSucces="false"
9
+ :showLoader="false"
10
+ >
11
+ {{ t('workingHours.addRegularDay') }}
12
+ </Button>
13
+ </div>
14
+
15
+ <!-- Таблица для регулярных часов работы -->
16
+ <div class="bg-white radius-small pd-small mn-b-medium">
17
+ <h5 class="mn-b-small">{{ t('workingHours.regularSchedule') }}</h5>
18
+
19
+ <div v-if="worktime.regular && worktime.regular.length > 0" class="regular-schedule mn-b-small">
20
+ <div
21
+ v-for="(day, index) in worktime.regular"
22
+ :key="`regular-${index}`"
23
+ class="schedule-item pd-small mn-b-small flex flex-v-center flex-nowrap"
24
+ :class="index % 2 === 0 ? 'bg-light' : ''"
25
+ >
26
+ <div class="day-info flex-child-1">
27
+ <div class="day-name t-semi">{{ getWeekdayName(day.dayOfWeek) }}</div>
28
+ <div class="day-hours" v-if="day.isOpen && day.periods && day.periods.length > 0">
29
+ <template v-for="(period, pIndex) in day.periods" :key="`period-${pIndex}`">
30
+ <span class="period t-small t-transp">
31
+ {{ period.open }} - {{ period.close }}
32
+ </span>
33
+ <span v-if="pIndex < day.periods.length - 1" class="t-small t-transp">, </span>
34
+ </template>
35
+ </div>
36
+ <div v-else class="day-hours t-small t-transp t-red">
37
+ {{ t('workingHours.closed') }}
38
+ </div>
39
+ </div>
40
+ <div class="day-actions flex-nowrap flex gap-small">
41
+ <Button
42
+ class="pd-micro bg-light"
43
+ :submit="() => editRegularDay(index)"
44
+ :showSucces="false"
45
+ :showLoader="false"
46
+ >
47
+ {{ t('workingHours.edit') }}
48
+ </Button>
49
+ <Button
50
+ class="pd-micro bg-fourth-nano"
51
+ :submit="() => removeRegularDay(index)"
52
+ :showSucces="false"
53
+ :showLoader="false"
54
+ >
55
+ {{ t('workingHours.remove') }}
56
+ </Button>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ <div v-else class="empty-schedule bg-light pd-medium radius-small t-center mn-b-small">
61
+ {{ t('workingHours.noRegularSchedule') }}
62
+ </div>
63
+ </div>
64
+
65
+ <!-- Таблица для особых дней -->
66
+ <div class="bg-white radius-small pd-small mn-b-small">
67
+ <div class="mn-b-small flex flex-nowrap flex-v-center">
68
+ <h5 class="mn-r-auto">{{ t('workingHours.specialDays') }}</h5>
69
+ <Button
70
+ class="bg-light mn-l-small"
71
+ :submit="addSpecialDay"
72
+ :showSucces="false"
73
+ :showLoader="false"
74
+ >
75
+ {{ t('workingHours.addSpecialDay') }}
76
+ </Button>
77
+ </div>
78
+ <div v-if="worktime.special && worktime.special.length > 0" class="special-schedule mn-b-small">
79
+ <div
80
+ v-for="(day, index) in worktime.special"
81
+ :key="`special-${index}`"
82
+ class="schedule-item pd-small mn-b-small flex flex-v-center flex-nowrap"
83
+ :class="index % 2 === 0 ? 'bg-light' : ''"
84
+ >
85
+ <div class="day-info flex-child-1">
86
+ <div class="flex flex-nowrap flex-v-center">
87
+ <div class="day-name t-semi">{{ formatDate(day.date) }}</div>
88
+ <div v-if="day.description" class="t-small t-transp mn-l-small">({{ day.description }})</div>
89
+ </div>
90
+ <div class="day-hours" v-if="day.isOpen && day.periods && day.periods.length > 0">
91
+ <template v-for="(period, pIndex) in day.periods" :key="`special-period-${pIndex}`">
92
+ <span class="period t-small t-transp">
93
+ {{ period.open }} - {{ period.close }}
94
+ </span>
95
+ <span v-if="pIndex < day.periods.length - 1" class="t-small t-transp">, </span>
96
+ </template>
97
+ </div>
98
+ <div v-else class="day-hours t-small t-transp t-red">
99
+ {{ t('workingHours.closed') }}
100
+ </div>
101
+ </div>
102
+ <div class="day-actions flex-nowrap flex gap-small">
103
+ <Button
104
+ class="pd-micro bg-light"
105
+ :submit="() => editSpecialDay(index)"
106
+ :showSucces="false"
107
+ :showLoader="false"
108
+ >
109
+ {{ t('workingHours.edit') }}
110
+ </Button>
111
+ <Button
112
+ class="pd-micro bg-fourth-nano"
113
+ :submit="() => removeSpecialDay(index)"
114
+ :showSucces="false"
115
+ :showLoader="false"
116
+ >
117
+ {{ t('workingHours.remove') }}
118
+ </Button>
119
+ </div>
120
+ </div>
121
+ </div>
122
+ <div v-else class="empty-schedule bg-light pd-medium radius-small t-center">
123
+ {{ t('workingHours.noSpecialDays') }}
124
+ </div>
125
+ </div>
126
+
127
+ <!-- Модальное окно для добавления/редактирования регулярного дня -->
128
+ <Popup
129
+ :isPopupOpen="showRegularDayModal"
130
+ @close-popup="showRegularDayModal = false"
131
+ :title="editingRegularIndex !== null ? t('workingHours.editRegularDay') : t('workingHours.addRegularDay')"
132
+ class="bg-white pd-semi w-m-33r radius-big"
133
+ >
134
+ <div class="schedule-editor">
135
+ <Select
136
+ v-model:select="currentRegularDay.dayOfWeek"
137
+ value="text"
138
+ :options="availableWeekdays"
139
+ property="value"
140
+ class="pos-relative w-100 mn-b-small bg-light radius-small pd-medium"
141
+ />
142
+
143
+ <Checkbox
144
+ :label="t('workingHours.isOpen')"
145
+ name="isOpenRegular"
146
+ :value="true"
147
+ :radio="currentRegularDay.isOpen"
148
+ @update:radio="val => currentRegularDay.isOpen = val"
149
+ class="w-100 mn-b-small bg-light radius-small pd-small"
150
+ />
151
+
152
+ <div v-if="currentRegularDay.isOpen">
153
+ <div class="flex flex-nowrap flex-v-center mn-b-small">
154
+ <h5 class="mn-r-auto">{{ t('workingHours.periods') }}</h5>
155
+ <Button
156
+ class="pd-micro bg-light"
157
+ :submit="addPeriodToRegular"
158
+ :showSucces="false"
159
+ :showLoader="false"
160
+ >
161
+ {{ t('workingHours.addPeriod') }}
162
+ </Button>
163
+ </div>
164
+
165
+ <div v-if="validationErrors.overlappingPeriods" class="error-message mn-b-small pd-small radius-small bg-fourth-nano">
166
+ {{ t('workingHours.errorOverlappingPeriods') }}
167
+ </div>
168
+
169
+ <div
170
+ v-for="(period, pIndex) in currentRegularDay.periods"
171
+ :key="`edit-period-${pIndex}`"
172
+ class="period-row mn-b-small flex flex-nowrap gap-small"
173
+ >
174
+ <div class="flex-child-1 time-inputs cols-2 gap-small">
175
+ <Field
176
+ v-model:field="period.open"
177
+ :label="t('workingHours.opens')"
178
+ type="time"
179
+ class="bg-light radius-small pd-medium"
180
+ @blur="validatePeriods"
181
+ />
182
+ <Field
183
+ v-model:field="period.close"
184
+ :label="t('workingHours.closes')"
185
+ type="time"
186
+ class="bg-light radius-small pd-medium"
187
+ @blur="validatePeriods"
188
+ />
189
+ </div>
190
+ <Button
191
+ v-if="currentRegularDay.periods.length > 1"
192
+ class="pd-micro bg-fourth-nano"
193
+ :submit="() => removeRegularPeriod(pIndex)"
194
+ :showSucces="false"
195
+ :showLoader="false"
196
+ >
197
+ {{ t('workingHours.remove') }}
198
+ </Button>
199
+ </div>
200
+ </div>
201
+
202
+ <div class="button-group flex flex-nowrap gap-small mn-t-medium">
203
+ <Button
204
+ class="w-100 bg-light"
205
+ :submit="() => showRegularDayModal = false"
206
+ :showSucces="false"
207
+ :showLoader="false"
208
+ >
209
+ {{ t('workingHours.cancel') }}
210
+ </Button>
211
+ <Button
212
+ class="w-100 bg-main"
213
+ :submit="saveRegularDay"
214
+ :showSucces="false"
215
+ :disabled="!isValidRegularDay"
216
+ >
217
+ {{ t('workingHours.save') }}
218
+ </Button>
219
+ </div>
220
+ </div>
221
+ </Popup>
222
+
223
+ <!-- Модальное окно для добавления/редактирования особого дня -->
224
+ <Popup
225
+ :isPopupOpen="showSpecialDayModal"
226
+ @close-popup="showSpecialDayModal = false"
227
+ :title="editingSpecialIndex !== null ? t('workingHours.editSpecialDay') : t('workingHours.addSpecialDay')"
228
+ class="bg-white pd-semi w-m-33r radius-big"
229
+ >
230
+ <div class="schedule-editor">
231
+ <Field
232
+ v-model:field="currentSpecialDay.dateInput"
233
+ :label="t('workingHours.date')"
234
+ type="date"
235
+ class="bg-light radius-small pd-medium mn-b-small"
236
+ @blur="validateSpecialDate"
237
+ />
238
+
239
+ <div v-if="validationErrors.duplicateDate" class="error-message mn-b-small pd-small radius-small bg-fourth-nano">
240
+ {{ t('workingHours.errorDuplicateDate') }}
241
+ </div>
242
+
243
+ <Field
244
+ v-model:field="currentSpecialDay.description"
245
+ :label="t('workingHours.description')"
246
+ :placeholder="t('workingHours.descriptionPlaceholder')"
247
+ class="bg-light radius-small pd-medium mn-b-small"
248
+ />
249
+
250
+ <Checkbox
251
+ :label="t('workingHours.isOpen')"
252
+ name="isOpenSpecial"
253
+ :value="true"
254
+ :radio="currentSpecialDay.isOpen"
255
+ @update:radio="val => currentSpecialDay.isOpen = val"
256
+ class="w-100 mn-b-small bg-white radius-small pd-small"
257
+ />
258
+
259
+ <div v-if="currentSpecialDay.isOpen">
260
+ <div class="flex flex-nowrap flex-v-center mn-b-small">
261
+ <h5 class="mn-r-auto">{{ t('workingHours.periods') }}</h5>
262
+ <Button
263
+ class="pd-micro bg-light"
264
+ :submit="addPeriodToSpecial"
265
+ :showSucces="false"
266
+ :showLoader="false"
267
+ >
268
+ {{ t('workingHours.addPeriod') }}
269
+ </Button>
270
+ </div>
271
+
272
+ <div v-if="validationErrors.overlappingPeriods" class="error-message mn-b-small pd-small radius-small bg-fourth-nano">
273
+ {{ t('workingHours.errorOverlappingPeriods') }}
274
+ </div>
275
+
276
+ <div
277
+ v-for="(period, pIndex) in currentSpecialDay.periods"
278
+ :key="`edit-special-period-${pIndex}`"
279
+ class="period-row mn-b-small flex flex-nowrap gap-small"
280
+ >
281
+ <div class="flex-child-1 time-inputs cols-2 gap-small">
282
+ <Field
283
+ v-model:field="period.open"
284
+ :label="t('workingHours.opens')"
285
+ type="time"
286
+ class="bg-light radius-small pd-medium"
287
+ @blur="validatePeriods"
288
+ />
289
+ <Field
290
+ v-model:field="period.close"
291
+ :label="t('workingHours.closes')"
292
+ type="time"
293
+ class="bg-light radius-small pd-medium"
294
+ @blur="validatePeriods"
295
+ />
296
+ </div>
297
+ <Button
298
+ v-if="currentSpecialDay.periods.length > 1"
299
+ class="pd-micro bg-fourth-nano"
300
+ :submit="() => removeSpecialPeriod(pIndex)"
301
+ :showSucces="false"
302
+ :showLoader="false"
303
+ >
304
+ {{ t('workingHours.remove') }}
305
+ </Button>
306
+ </div>
307
+ </div>
308
+
309
+ <div class="button-group flex flex-nowrap gap-small mn-t-medium">
310
+ <Button
311
+ class="w-100 bg-light"
312
+ :submit="() => showSpecialDayModal = false"
313
+ :showSucces="false"
314
+ :showLoader="false"
315
+ >
316
+ {{ t('workingHours.cancel') }}
317
+ </Button>
318
+ <Button
319
+ class="w-100 bg-main"
320
+ :submit="saveSpecialDay"
321
+ :showSucces="false"
322
+ :disabled="!isValidSpecialDay"
323
+ >
324
+ {{ t('workingHours.save') }}
325
+ </Button>
326
+ </div>
327
+ </div>
328
+ </Popup>
329
+ </div>
330
+ </template>
331
+
332
+ <script setup>
333
+ import { ref, computed, watch, onMounted } from 'vue';
334
+ import { useI18n } from 'vue-i18n';
335
+
336
+ import Button from '@martyrs/src/components/Button/Button.vue';
337
+ import Field from '@martyrs/src/components/Field/Field.vue';
338
+ import Select from '@martyrs/src/components/Select/Select.vue';
339
+ import Checkbox from '@martyrs/src/components/Checkbox/Checkbox.vue';
340
+ import Popup from '@martyrs/src/components/Popup/Popup.vue';
341
+
342
+ const worktime = defineModel('worktime')
343
+ const emit = defineEmits(['update:worktime']);
344
+
345
+ // i18n
346
+ const { t, locale } = useI18n({
347
+ messages: {
348
+ en: {
349
+ workingHours: {
350
+ title: 'Working Hours',
351
+ regularSchedule: 'Regular Schedule',
352
+ specialDays: 'Special Days',
353
+ addRegularDay: 'Add Day',
354
+ addSpecialDay: 'Add Day',
355
+ editRegularDay: 'Edit Regular Day',
356
+ editSpecialDay: 'Edit Special Day',
357
+ save: 'Save',
358
+ cancel: 'Cancel',
359
+ edit: 'Edit',
360
+ remove: 'Remove',
361
+ weekday: 'Weekday',
362
+ date: 'Date',
363
+ isOpen: 'Open on this day',
364
+ description: 'Description',
365
+ descriptionPlaceholder: 'Holiday, Special event, etc.',
366
+ periods: 'Operating Hours',
367
+ addPeriod: 'Add Period',
368
+ opens: 'Opens at',
369
+ closes: 'Closes at',
370
+ closed: 'Closed',
371
+ noRegularSchedule: 'No regular schedule set. Add working days to define your regular hours.',
372
+ noSpecialDays: 'No special days set. Add special days for holidays or events.',
373
+ errorDuplicateDate: 'This date already exists in special days.',
374
+ errorOverlappingPeriods: 'Time periods cannot overlap.',
375
+ selectDate: 'Please select a date.',
376
+ errorInvalidPeriod: 'Invalid time period. Closing time must be after opening time.'
377
+ }
378
+ },
379
+ ru: {
380
+ workingHours: {
381
+ title: 'Часы работы',
382
+ regularSchedule: 'Регулярное расписание',
383
+ specialDays: 'Особые дни',
384
+ addRegularDay: 'Добавить день',
385
+ addSpecialDay: 'Добавить особый день',
386
+ editRegularDay: 'Изменить рабочий день',
387
+ editSpecialDay: 'Изменить особый день',
388
+ save: 'Сохранить',
389
+ cancel: 'Отмена',
390
+ edit: 'Изменить',
391
+ remove: 'Удалить',
392
+ weekday: 'День недели',
393
+ date: 'Дата',
394
+ isOpen: 'Открыто в этот день',
395
+ description: 'Описание',
396
+ descriptionPlaceholder: 'Праздник, особое событие и т.д.',
397
+ periods: 'Часы работы',
398
+ addPeriod: 'Добавить период',
399
+ opens: 'Открывается в',
400
+ closes: 'Закрывается в',
401
+ closed: 'Закрыто',
402
+ noRegularSchedule: 'Регулярное расписание не установлено. Добавьте рабочие дни для определения регулярных часов.',
403
+ noSpecialDays: 'Особые дни не установлены. Добавьте особые дни для праздников или событий.',
404
+ errorDuplicateDate: 'Эта дата уже существует в особых днях.',
405
+ errorOverlappingPeriods: 'Временные периоды не могут пересекаться.',
406
+ selectDate: 'Пожалуйста, выберите дату.',
407
+ errorInvalidPeriod: 'Недопустимый временной период. Время закрытия должно быть после времени открытия.'
408
+ }
409
+ }
410
+ }
411
+ });
412
+
413
+ // Форматирование даты с использованием браузерных API
414
+ const formatDate = (date) => {
415
+ if (!date) return '';
416
+ const dateObj = new Date(date);
417
+ return new Intl.DateTimeFormat(locale.value, {
418
+ weekday: 'long',
419
+ year: 'numeric',
420
+ month: 'long',
421
+ day: 'numeric'
422
+ }).format(dateObj);
423
+ };
424
+
425
+ // Получение названия дня недели по номеру
426
+ const getWeekdayName = (dayNumber) => {
427
+ if (dayNumber === undefined || dayNumber === null) return '';
428
+
429
+ // Создаем дату с известным начальным днем недели (1 января 2023 - воскресенье)
430
+ const date = new Date(2023, 0, 1 + dayNumber);
431
+
432
+ return new Intl.DateTimeFormat(locale.value, { weekday: 'long' }).format(date);
433
+ };
434
+
435
+ // Состояние для модальных окон
436
+ const showRegularDayModal = ref(false);
437
+ const showSpecialDayModal = ref(false);
438
+
439
+ // Индексы для редактирования
440
+ const editingRegularIndex = ref(null);
441
+ const editingSpecialIndex = ref(null);
442
+
443
+ // Валидация
444
+ const validationErrors = ref({
445
+ overlappingPeriods: false,
446
+ duplicateDate: false,
447
+ invalidPeriod: false
448
+ });
449
+
450
+ // Текущие значения для редактирования
451
+ const currentRegularDay = ref({
452
+ dayOfWeek: 1, // Понедельник по умолчанию
453
+ isOpen: true,
454
+ periods: [{
455
+ open: '09:00',
456
+ close: '18:00'
457
+ }]
458
+ });
459
+
460
+ const currentSpecialDay = ref({
461
+ dateInput: '', // Для ввода даты в формате YYYY-MM-DD
462
+ date: null,
463
+ description: '',
464
+ isOpen: false,
465
+ periods: [{
466
+ open: '09:00',
467
+ close: '18:00'
468
+ }]
469
+ });
470
+
471
+ // Список доступных дней недели (0-6)
472
+ const weekdays = [0, 1, 2, 3, 4, 5, 6];
473
+
474
+ // Получаем доступные дни недели (исключая те, которые уже добавлены)
475
+ const availableWeekdays = computed(() => {
476
+ const usedDays = new Set((worktime.value?.regular || []).map(d => d.dayOfWeek));
477
+
478
+ // Фильтруем дни, которые еще не добавлены или это текущий редактируемый день
479
+ return weekdays
480
+ .filter(day =>
481
+ !usedDays.has(day) ||
482
+ (editingRegularIndex.value !== null &&
483
+ worktime.value?.regular[editingRegularIndex.value]?.dayOfWeek === day)
484
+ )
485
+ .map(day => ({
486
+ text: getWeekdayName(day),
487
+ value: day
488
+ }));
489
+ });
490
+
491
+ // Проверка валидности текущего состояния
492
+ const isValidRegularDay = computed(() => {
493
+ return !validationErrors.value.overlappingPeriods && !validationErrors.value.invalidPeriod;
494
+ });
495
+
496
+ const isValidSpecialDay = computed(() => {
497
+ return !validationErrors.value.duplicateDate &&
498
+ !validationErrors.value.overlappingPeriods &&
499
+ !validationErrors.value.invalidPeriod &&
500
+ !!currentSpecialDay.value.dateInput;
501
+ });
502
+
503
+ // Функции добавления дней
504
+ const addRegularDay = () => {
505
+ editingRegularIndex.value = null;
506
+ currentRegularDay.value = {
507
+ dayOfWeek: availableWeekdays.value[0]?.value ?? 1,
508
+ isOpen: true,
509
+ periods: [{
510
+ open: '09:00',
511
+ close: '18:00'
512
+ }]
513
+ };
514
+ validationErrors.value = {
515
+ overlappingPeriods: false,
516
+ duplicateDate: false,
517
+ invalidPeriod: false
518
+ };
519
+ showRegularDayModal.value = true;
520
+ };
521
+
522
+ const addSpecialDay = () => {
523
+ editingSpecialIndex.value = null;
524
+ // Устанавливаем текущую дату по умолчанию
525
+ const today = new Date();
526
+ const todayFormatted = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
527
+
528
+ currentSpecialDay.value = {
529
+ dateInput: todayFormatted,
530
+ date: today,
531
+ description: '',
532
+ isOpen: false,
533
+ periods: [{
534
+ open: '09:00',
535
+ close: '18:00'
536
+ }]
537
+ };
538
+
539
+ validationErrors.value = {
540
+ overlappingPeriods: false,
541
+ duplicateDate: false,
542
+ invalidPeriod: false
543
+ };
544
+
545
+ showSpecialDayModal.value = true;
546
+
547
+ // Сразу проверяем на дублирование даты
548
+ validateSpecialDate();
549
+ };
550
+
551
+ // Валидация периодов (проверка на пересечение)
552
+ const validatePeriods = () => {
553
+ const periods = showRegularDayModal.value ?
554
+ currentRegularDay.value.periods :
555
+ currentSpecialDay.value.periods;
556
+
557
+ if (!periods || periods.length <= 1) {
558
+ validationErrors.value.overlappingPeriods = false;
559
+ validationErrors.value.invalidPeriod = false;
560
+ return;
561
+ }
562
+
563
+ // Проверка на недопустимые периоды (конец раньше начала)
564
+ validationErrors.value.invalidPeriod = periods.some(period =>
565
+ period.open >= period.close
566
+ );
567
+
568
+ if (validationErrors.value.invalidPeriod) {
569
+ return;
570
+ }
571
+
572
+ // Сортируем периоды по времени начала
573
+ const sortedPeriods = [...periods].sort((a, b) => a.open.localeCompare(b.open));
574
+
575
+ // Проверяем пересечения
576
+ for (let i = 0; i < sortedPeriods.length - 1; i++) {
577
+ if (sortedPeriods[i].close > sortedPeriods[i + 1].open) {
578
+ validationErrors.value.overlappingPeriods = true;
579
+ return;
580
+ }
581
+ }
582
+
583
+ validationErrors.value.overlappingPeriods = false;
584
+ };
585
+
586
+ // Валидация даты для особого дня (проверка на дублирование)
587
+ const validateSpecialDate = () => {
588
+ if (!currentSpecialDay.value.dateInput) {
589
+ validationErrors.value.duplicateDate = false;
590
+ return;
591
+ }
592
+
593
+ const newDateObj = new Date(currentSpecialDay.value.dateInput);
594
+ newDateObj.setHours(0, 0, 0, 0); // Нормализуем время
595
+
596
+ const isDuplicate = worktime.value.special.some((specialDay, index) => {
597
+ if (editingSpecialIndex.value === index) return false; // Пропускаем текущий редактируемый день
598
+
599
+ const existingDate = new Date(specialDay.date);
600
+ existingDate.setHours(0, 0, 0, 0); // Нормализуем время
601
+
602
+ return existingDate.getTime() === newDateObj.getTime();
603
+ });
604
+
605
+ validationErrors.value.duplicateDate = isDuplicate;
606
+ };
607
+
608
+ // Методы для работы с регулярными днями
609
+ const editRegularDay = (index) => {
610
+ editingRegularIndex.value = index;
611
+ const day = JSON.parse(JSON.stringify(worktime.value.regular[index]));
612
+
613
+ // Если нет периодов, добавляем пустой
614
+ if (!day.periods || day.periods.length === 0) {
615
+ day.periods = [{
616
+ open: '09:00',
617
+ close: '18:00'
618
+ }];
619
+ }
620
+
621
+ currentRegularDay.value = day;
622
+ validationErrors.value = {
623
+ overlappingPeriods: false,
624
+ duplicateDate: false,
625
+ invalidPeriod: false
626
+ };
627
+ showRegularDayModal.value = true;
628
+
629
+ // Валидируем периоды
630
+ validatePeriods();
631
+ };
632
+
633
+ const removeRegularDay = (index) => {
634
+ const updatedWorktime = { ...worktime.value };
635
+ updatedWorktime.regular.splice(index, 1);
636
+ emit('update:worktime', updatedWorktime);
637
+ };
638
+
639
+ const saveRegularDay = () => {
640
+ // Проверяем валидность
641
+ validatePeriods();
642
+ if (!isValidRegularDay.value) {
643
+ return;
644
+ }
645
+
646
+ // Копируем текущее значение модели
647
+ const updatedWorktime = JSON.parse(JSON.stringify(worktime.value));
648
+
649
+ // Убеждаемся, что regular существует
650
+ if (!updatedWorktime.regular) {
651
+ updatedWorktime.regular = [];
652
+ }
653
+
654
+ // Копируем текущий день
655
+ const dayToSave = { ...currentRegularDay.value };
656
+
657
+ // Если день закрыт, удаляем периоды
658
+ if (!dayToSave.isOpen) {
659
+ dayToSave.periods = [];
660
+ }
661
+
662
+ // Обновляем или добавляем
663
+ if (editingRegularIndex.value !== null) {
664
+ updatedWorktime.regular[editingRegularIndex.value] = dayToSave;
665
+ } else {
666
+ updatedWorktime.regular.push(dayToSave);
667
+ }
668
+
669
+ // Сортируем по дням недели
670
+ updatedWorktime.regular.sort((a, b) => a.dayOfWeek - b.dayOfWeek);
671
+
672
+ // Обновляем модель
673
+ worktime.value = updatedWorktime
674
+ emit('update:worktime', updatedWorktime);
675
+ showRegularDayModal.value = false;
676
+ };
677
+
678
+ const addPeriodToRegular = () => {
679
+ currentRegularDay.value.periods.push({
680
+ open: '09:00',
681
+ close: '18:00'
682
+ });
683
+ validatePeriods();
684
+ };
685
+
686
+ const removeRegularPeriod = (index) => {
687
+ currentRegularDay.value.periods.splice(index, 1);
688
+ validatePeriods();
689
+ };
690
+
691
+ // Методы для работы с особыми днями
692
+ const editSpecialDay = (index) => {
693
+ editingSpecialIndex.value = index;
694
+ const day = JSON.parse(JSON.stringify(worktime.value.special[index]));
695
+
696
+ // Форматируем дату для поля ввода
697
+ const date = new Date(day.date);
698
+ const dateForInput = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
699
+
700
+ // Если нет периодов, добавляем пустой
701
+ if (!day.periods || day.periods.length === 0) {
702
+ day.periods = [{
703
+ open: '09:00',
704
+ close: '18:00'
705
+ }];
706
+ }
707
+
708
+ currentSpecialDay.value = {
709
+ ...day,
710
+ dateInput: dateForInput
711
+ };
712
+
713
+ validationErrors.value = {
714
+ overlappingPeriods: false,
715
+ duplicateDate: false,
716
+ invalidPeriod: false
717
+ };
718
+ showSpecialDayModal.value = true;
719
+
720
+ // Валидируем периоды
721
+ validatePeriods();
722
+ };
723
+
724
+ const removeSpecialDay = (index) => {
725
+ const updatedWorktime = { ...worktime.value };
726
+ updatedWorktime.special.splice(index, 1);
727
+ emit('update:worktime', updatedWorktime);
728
+ };
729
+
730
+ const saveSpecialDay = () => {
731
+ // Проверяем валидность
732
+ validateSpecialDate();
733
+ validatePeriods();
734
+
735
+ if (!isValidSpecialDay.value) {
736
+ if (!currentSpecialDay.value.dateInput) {
737
+ alert(t('workingHours.selectDate'));
738
+ }
739
+ return;
740
+ }
741
+
742
+ // Копируем текущее значение модели
743
+ const updatedWorktime = JSON.parse(JSON.stringify(worktime.value));
744
+
745
+ // Убеждаемся, что special существует
746
+ if (!updatedWorktime.special) {
747
+ updatedWorktime.special = [];
748
+ }
749
+
750
+ // Преобразуем дату из input в объект Date
751
+ const dateParts = currentSpecialDay.value.dateInput.split('-');
752
+ const specialDate = new Date(
753
+ parseInt(dateParts[0]),
754
+ parseInt(dateParts[1]) - 1,
755
+ parseInt(dateParts[2])
756
+ );
757
+
758
+ // Копируем текущий день и обновляем дату
759
+ const dayToSave = {
760
+ ...currentSpecialDay.value,
761
+ date: specialDate
762
+ };
763
+
764
+ // Удаляем вспомогательное поле
765
+ delete dayToSave.dateInput;
766
+
767
+ // Если день закрыт, удаляем периоды
768
+ if (!dayToSave.isOpen) {
769
+ dayToSave.periods = [];
770
+ }
771
+
772
+ // Обновляем или добавляем
773
+ if (editingSpecialIndex.value !== null) {
774
+ updatedWorktime.special[editingSpecialIndex.value] = dayToSave;
775
+ } else {
776
+ updatedWorktime.special.push(dayToSave);
777
+ }
778
+
779
+ // Сортируем по датам
780
+ updatedWorktime.special.sort((a, b) => new Date(a.date) - new Date(b.date));
781
+
782
+ // Обновляем модель
783
+ emit('update:worktime', updatedWorktime);
784
+ showSpecialDayModal.value = false;
785
+ };
786
+
787
+ const addPeriodToSpecial = () => {
788
+ currentSpecialDay.value.periods.push({
789
+ open: '09:00',
790
+ close: '18:00'
791
+ });
792
+ validatePeriods();
793
+ };
794
+
795
+ const removeSpecialPeriod = (index) => {
796
+ currentSpecialDay.value.periods.splice(index, 1);
797
+ validatePeriods();
798
+ };
799
+
800
+ // Инициализация значений при монтировании
801
+ onMounted(() => {
802
+ // Проверяем, что начальное значение модели имеет правильную структуру
803
+ if (!worktime.value.regular || !worktime.value.special ) worktime.value = {
804
+ regular: [],
805
+ special: []
806
+ }
807
+ // emit('update:worktime', worktime.value);
808
+ });
809
+ </script>
810
+
811
+ <style scoped>
812
+ .working-hours-editor {
813
+ border-radius: 8px;
814
+ }
815
+
816
+ .schedule-item {
817
+ transition: all 0.3s ease;
818
+ border-bottom: 1px solid rgba(var(--grey), 0.1);
819
+ }
820
+
821
+ .schedule-item:last-child {
822
+ border-bottom: none;
823
+ }
824
+
825
+ .period {
826
+ display: inline-block;
827
+ }
828
+
829
+ .empty-schedule {
830
+ color: rgba(var(--dark), 0.6);
831
+ }
832
+
833
+ .period-row {
834
+ align-items: center;
835
+ }
836
+
837
+ .error-message {
838
+ color: white;
839
+ }
840
+ </style>