index.coffee 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. document.head.insertAdjacentHTML('beforeend','<style type="text/tailwindcss">'+stylFns['app/pages/Admin/index.styl']+'</style>')
  2. PouchDB = require 'app/utils/pouch'
  3. # Иконки для меню (упрощенные компоненты)
  4. MenuIcons =
  5. SliderIcon:
  6. template: """
  7. <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
  8. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8h16M4 16h16"></path>
  9. </svg>
  10. """
  11. ProductsIcon:
  12. template: """
  13. <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
  14. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"></path>
  15. </svg>
  16. """
  17. ClientsIcon:
  18. template: """
  19. <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
  20. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path>
  21. </svg>
  22. """
  23. BlogIcon:
  24. template: """
  25. <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
  26. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
  27. </svg>
  28. """
  29. RoutesIcon:
  30. template: """
  31. <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
  32. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"></path>
  33. </svg>
  34. """
  35. SettingsIcon:
  36. template: """
  37. <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
  38. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>
  39. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
  40. </svg>
  41. """
  42. module.exports =
  43. name: 'AdminPanel'
  44. components: MenuIcons
  45. render: (new Function '_ctx', '_cache', renderFns['app/pages/Admin/index.pug'])()
  46. data: ->
  47. return {
  48. currentDomain: window.location.hostname
  49. theme: localStorage.getItem('theme') || 'light'
  50. mobileMenuOpen: false
  51. sidebarCollapsed: false
  52. notificationsOpen: false
  53. currentDomainSettings: null
  54. user: null
  55. mainMenuItems: [
  56. {
  57. id: 'slider'
  58. name: 'Слайдер'
  59. path: '/admin/slider'
  60. icon: 'SliderIcon'
  61. }
  62. {
  63. id: 'products'
  64. name: 'Товары'
  65. path: '/admin/products'
  66. icon: 'ProductsIcon'
  67. }
  68. {
  69. id: 'clients'
  70. name: 'Клиенты'
  71. path: '/admin/clients'
  72. icon: 'ClientsIcon'
  73. }
  74. ]
  75. contentMenuItems: [
  76. {
  77. id: 'blog'
  78. name: 'Блог'
  79. path: '/admin/blog'
  80. icon: 'BlogIcon'
  81. }
  82. {
  83. id: 'routes'
  84. name: 'Маршруты'
  85. path: '/admin/routes'
  86. icon: 'RoutesIcon'
  87. }
  88. ]
  89. systemMenuItems: [
  90. {
  91. id: 'settings'
  92. name: 'Настройки'
  93. path: '/admin/settings'
  94. icon: 'SettingsIcon'
  95. }
  96. ]
  97. breadcrumbs: []
  98. notifications: []
  99. unreadNotifications: 0
  100. }
  101. computed:
  102. currentRoute: ->
  103. @$route.path.split('/').pop() || 'settings'
  104. userInitials: ->
  105. return 'АД' unless @user?.name
  106. names = @user.name.split(' ')
  107. if names.length >= 2
  108. (names[0][0] + names[1][0]).toUpperCase()
  109. else
  110. @user.name.substring(0, 2).toUpperCase()
  111. methods:
  112. navigateTo: (path) ->
  113. @mobileMenuOpen = false
  114. @$router.push(path)
  115. getMenuItemClass: (item) ->
  116. baseClass = 'admin__nav-item'
  117. isActive = @currentRoute == item.id
  118. if isActive
  119. return "#{baseClass} admin__nav-item--active"
  120. else
  121. return "#{baseClass} admin__nav-item--inactive"
  122. toggleTheme: ->
  123. @theme = if @theme == 'light' then 'dark' else 'light'
  124. localStorage.setItem 'theme', @theme
  125. document.documentElement.classList.toggle 'dark'
  126. @$root.theme = @theme
  127. refreshData: ->
  128. @showNotification 'Данные обновлены'
  129. markAsRead: (notificationId) ->
  130. notification = @notifications.find (n) -> n.id == notificationId
  131. if notification && !notification.read
  132. notification.read = true
  133. @unreadNotifications -= 1
  134. logout: ->
  135. localStorage.removeItem 'user'
  136. @user = null
  137. @$router.push('/')
  138. @showNotification 'Вы успешно вышли из системы'
  139. loadDomainSettings: ->
  140. PouchDB.getDocument("domain_settings:#{@currentDomain}")
  141. .then (settings) =>
  142. @currentDomainSettings = settings
  143. .catch (error) =>
  144. debug.log 'Настройки домена не найдены, используются значения по умолчанию'
  145. @currentDomainSettings = null
  146. loadUserData: ->
  147. userData = localStorage.getItem 'user'
  148. if userData
  149. try
  150. @user = JSON.parse userData
  151. catch
  152. @user = null
  153. else
  154. # Заглушка для демонстрации
  155. @user = { name: 'Администратор Системы', role: 'admin' }
  156. updateBreadcrumbs: ->
  157. routeName = @currentRoute
  158. breadcrumbMap =
  159. slider: { title: 'Слайдер' }
  160. products: { title: 'Товары' }
  161. clients: { title: 'Клиенты' }
  162. blog: { title: 'Блог' }
  163. routes: { title: 'Маршруты' }
  164. settings: { title: 'Настройки' }
  165. current = breadcrumbMap[routeName]
  166. if current
  167. @breadcrumbs = [
  168. { title: 'Главная', path: '/admin' }
  169. { title: current.title }
  170. ]
  171. else
  172. @breadcrumbs = [{ title: 'Главная' }]
  173. showNotification: (message, type = 'success') ->
  174. @$root.showNotification?(message, type) || debug.log("#{type}: #{message}")
  175. watch:
  176. currentRoute:
  177. immediate: true
  178. handler: ->
  179. @updateBreadcrumbs()
  180. mounted: ->
  181. @loadDomainSettings()
  182. @loadUserData()
  183. # Инициализация темы
  184. if @theme == 'dark'
  185. document.documentElement.classList.add 'dark'
  186. # Заглушка для уведомлений
  187. @notifications = [
  188. {
  189. id: 1
  190. title: 'Новый заказ получен'
  191. time: '5 мин назад'
  192. read: false
  193. icon: 'SettingsIcon'
  194. }
  195. {
  196. id: 2
  197. title: 'Обновление системы'
  198. time: '1 час назад'
  199. read: false
  200. icon: 'SettingsIcon'
  201. }
  202. ]
  203. @unreadNotifications = @notifications.filter((n) -> !n.read).length