Ingen beskrivning

Gogs 2e604181de -- 3 veckor sedan
assets d100bd6170 -- 3 veckor sedan
pug 06219819b6 -- 3 veckor sedan
scripts 2e604181de -- 3 veckor sedan
vue 2ea2b002fa -- 3 veckor sedan
.gitignore 06219819b6 -- 3 veckor sedan
README.md 2e604181de -- 3 veckor sedan
doc.json 80710f8924 -- 3 veckor sedan
lzma.coffee c0e0a044f2 -- 3 veckor sedan

README.md

Текущая ззадача

доработай seed-events.coffee, для удаления старых версий документов, и создай новые тестовые документы для сайта. минимум 6 постов и мероприятий, также 6 сладеров

файл с правилами

https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/README.md

применяй правила:

оформление ссылок

a(href="[ссылка]") - не правильно router-link(to="[ссылка]") - не правильно app-link(to="[ссылка]") - правильно (должен быть подключен компанент: 'app-link': require 'app/shared/AppLink')

Корневой каталог и мета данные

Важно: мета данные добавляются через app/temp.coffe базовым тегоьм для vuejs является body, app/index.pug начинается с div, теги html, head, body ЗАПРЕЩЕНО использовать.

пример кода app/temp.coffee

# обязательно подключение глобальных массивов
globalThis.renderFns = require 'pug.json'
globalThis.stylFns   = require 'styl.json'

# подключение мета информации (строго в данном фиде)
document.head.insertAdjacentHTML 'beforeend','<meta charset="UTF-8">'
document.head.insertAdjacentHTML 'beforeend','<meta name="viewport" content="width=device-width, initial-scale=1.0">'
document.head.insertAdjacentHTML('beforeend','<title> Кохи Борбад - Концертный зал Душанбе</title>')

# Настройка tailwind
tailwind.config = require 'tailwind.config.js'

# подключение основных стилей
## tailwind
document.head.insertAdjacentHTML('beforeend','<style  type="text/tailwindcss"  page="main">'+stylFns['main.css']+'</style>')
## базовой стиль приложения
document.head.insertAdjacentHTML('beforeend','<style  type="text/tailwindcss"  page="root">'+stylFns['app/temp.styl']+'</style>')

# Маршруты
routes = [
  { path: '/', component: require 'app/pages/Home' }
  { path: '/events', component: require 'app/pages/Events' }
  { path: '/about', component: require 'app/pages/About' }
  { path: '/contacts', component: require 'app/pages/Contacts' }
]

# Глобальное определение vuejs приложения
app = Vue.createApp
  name: 'app'
  data: ()->
        return  {
            
            appState:
                events: []
                featuredEvents: []
                sliderEvents: []
                loading: true
                error: null
            modalState:           #управление модальными окнами
                isVisible: false
                component: null
                props: {}
            couchDBService: new CouchDBService()
        }
  beforeMount: ()->
        debug.log "start beforeMount"
        # определение контекста vuejs приложения как глобальной переменной _
        globalThis._ = @
        # все глобальные переменные необходимые для работы определяем в data
        # и получаем доступ через _.*
  render: (new Function '_ctx', '_cache', renderFns['app/temp.pug'])()
  mounted: ->{}
  methods: {}
  components:
      'themetoggle':    require 'app/shared/ThemeToggle'
      'multilevelmenu': require 'app/shared/MultiLevelMenu'
      'imageslider':    require 'app/shared/ImageSlider'
app.use(VueRouter.createRouter({
  routes: routes
  history: VueRouter.createWebHistory()
  scrollBehavior: (to, from, savedPosition) ->
    if savedPosition
      return savedPosition
    else
      return { x: 0, y: 0 }
}))

# подключаем в body ОБЯЗАТЕЛЬНО!!!
app.mount('body')

Привер кода index.coffee для компанентов/страниц

# Важно загрузка стилей компонента/страницы
document.head.insertAdjacentHTML('beforeend','<style type="text/tailwindcss"  page="Blog">'+stylFns['app/pages/Blog/index.styl']+'</style>')

module.exports =
    name: 'BlogPage'
    # ВАЖНО загрузка шаблона через рендер функцию
    render: (new Function '_ctx', '_cache', renderFns['app/pages/Blog/index.pug'])()
    data: ->
        posts: []
        loading: true
        error: null
    
    beforeMount: ->
        @loadBlogPosts()
    
    methods:
        loadBlogPosts: ->
            try
                @loading = true
                @posts = await AppDB.getBlogPosts(limit: 10)
                @loading = false
            catch error
                @error = "Ошибка загрузки постов: "+error
                @loading = false
    

определение функций в _deing документе

при обновлении документа учитывай версионность

    # Design документ для блог постов
    blog_posts:
        version: "1.1"
        views:
            # Все опубликованные блог посты
            published:
                map: ((doc) ->
                    if doc.type is 'blog_post' and doc.status is 'published'
                        emit(doc.created_at, doc)).toString()

определение шаблонов для слотов

template(#body) - не правильно template(v-slot:body) - не правильно template([body]) - правильно

async в методах

async loadData: -> - не правильно loadData: -> - правильно

Радота с кодом

всегда приводи полный листинг файлов при форматировании кода для отделения логических блоков используй 4 пробела (" ") следи за строгим соблюдением синтаксиса используемых языков (coffeescript, pug, stylus) в pug не используй многострочные вычисляемые атрибуты

работа с консолью и текстовыми константами/переменными используй конкатенацию (СТРОГО! ВАЖНО!)

используй для вывода в консоль debug.log console.log "переменная temp = #{temp}" - не правильно debug.log "переменная temp = "+temp - правильно

shareUrl = "https://twitter.com/intent/tweet?text=#{text}" - не правильно shareUrl = "https://twitter.com/intent/tweet?text="+text - правильно

"#{@baseUrl}/#{@dbName}/_all_docs?include_docs=true" - не правильно @baseUrl+"/"+@dbName+"/_all_docs?include_docs=true" - правильно

Цвета и управление темами

во всех *.styl файлах используй цвета в виде переменных, определённых в файле tailwind.config.js

Стили

все глобальный настройки стилей, пиши в app/temp.styl в остальных файлах, строго стили необходимые только для данного компаонента

Расположение статических файлов/изображений

img(src="/images/hall-interior.jpg") - не правильно img(src="/assets/[domenName]/hall-interior.jpg") - правильно

стиль написания классов

.container.mx-auto.px-4 - не правильно div(class="container.mx-auto px-4") - правильно

не используй вызовы

Vue = require 'vue' VueRouter = require 'vue-router'

  • Подключение осуществлено глобально через файл doc.json

git ВАЖНО

для анализа кода бери версии файлов СТРОГО из репозитария: https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/src/master , корневой каталог vue/ от него идут пути к файлам пример: в коде -> app/temp.coffee, в репозитарии -> vue/app/temp.coffee

Общее описание

Универсаньная CMS для работы с couchdb как бекендом. CMS мультидоменная и мультиязычная. мультидоменность во все view через поле domain

общая структура проекта

app/ ├── tailwind.config.js (настройка тем и Tailwind CSS) ├── temp.pug (основной layout) ├── temp.coffee (инициализация Vue и роутера) ├── temp.styl (стили которые сложно или не удобно сделать на Tailwind CSS или стили к однотипным элементам на stylus) ├── core/ - Каталог для хранения coffee файлов частей ядра системы, для улучшения чтения temp.coffee | ├── CouchdbClass.coffee | ... ├── page/ | ├── Home/ (главная страница) | | ├── index.coffee | | ├── index.pug | | ├── index.styl | ├── [другие_страницы]/ | ├── index.coffee | ├── index.pug | ├── index.styl └── shared/

 ├── ThemeToggle/
 |      ├── index.coffee
 |      ├── index.pug
 |      ├── index.styl
 ├── MultiLevelMenu/
 |      ├── index.coffee
 |      ├── index.pug
 |      ├── index.styl
 ├── ImageSlider/
 |      ├── index.coffee
 |      ├── index.pug
 |      ├── index.styl
 ├── ModalWindow/
 |      ├── index.coffee
 |      ├── index.pug
 |      ├── index.styl
 ├── FormValidator/
 |      ├── index.coffee
 |      ├── index.pug
 |      ├── index.styl
 ├── FilterSort/
        ├── index.coffee
        ├── index.pug
        ├── index.styl

Структура хранимых данных

Описание всех хранимых объектов с мультиязычностью

  1. Настройки домена (domain_settings) coffee { _id: String # Уникальный идентификатор (domainsettings[domain]) type: 'domain_settings' # Тип документа domain: String # Доменное имя (borbad.s5l.ru) name: String # Название сайта description: String # Описание сайта active: Boolean # Активен ли домен priority: Number # Приоритет домена theme: String # Тема оформления languages: Array[String] # Поддерживаемые языки ['ru', 'en', 'tj'] default_language: String # Язык по умолчанию timezone: String # Часовой пояс currency: String # Валюта по умолчанию settings: Object # Дополнительные настройки created_at: ISOString # Дата создания updated_at: ISOString # Дата обновления }
  2. Запись блога (blog_post) с мультиязычностью coffee { _id: String # Уникальный идентификатор type: 'blog_post' # Тип записи domain: String # Домен language: String # Язык контента ('ru', 'en', 'tj') translation_of: String # ID исходного документа для переводов translation_status: String # Статус перевода ('draft', 'review', 'published') title: String # Заголовок content: String # Основной текст в Markdown excerpt: String # Краткое описание image: String # Главное изображение tags: Array[String] # Теги для категоризации category_id: String # ID категории author: String # Автор записи status: 'published' | 'draft' # Статус публикации meta_title: String # SEO заголовок meta_description: String # SEO описание featured: Boolean # Избранная запись created_at: ISOString # Дата создания updated_at: ISOString # Дата обновления published_at: ISOString # Дата публикации views: Number # Количество просмотров }
  3. Мероприятие (event) с мультиязычностью coffee { _id: String # Уникальный идентификатор type: 'event' # Тип документа domain: String # Домен language: String # Язык контента translation_of: String # ID исходного документа translation_status: String # Статус перевода title: String # Заголовок мероприятия content: String # Markdown описание мероприятия event_date: ISOString # Дата и время мероприятия end_date: ISOString # Дата и время окончания location: String # Место проведения venue_id: String # ID места проведения price: Number # Стоимость билета currency: String # Валюта (TJS, USD, etc.) available_tickets: Number # Количество доступных билетов total_tickets: Number # Общее количество билетов image: String # Изображение мероприятия gallery: Array[String] # Галерея изображений tags: Array[String] # Теги (концерт, выставка, etc.) category_id: String # ID категории status: 'upcoming' | 'ongoing' | 'completed' | 'cancelled' registration_required: Boolean # Требуется ли регистрация max_attendees: Number # Максимальное количество участников age_restriction: String # Возрастные ограничения created_at: ISOString # Дата создания updated_at: ISOString # Дата обновления }
  4. Слайд (slide) с мультиязычностью coffee { _id: String # Уникальный идентификатор type: 'slide' # Тип документа domain: String # Домен language: String # Язык контента translation_of: String # ID исходного документа translation_status: String # Статус перевода title: String # Заголовок слайда content: String # Markdown контент image: String # Фоновое изображение order: Number # Порядок отображения active: Boolean # Активен ли слайд button_text: String # Текст кнопки button_link: String # Ссылка кнопки text_color: String # Цвет текста overlay: Boolean # Наложение на изображение created_at: ISOString # Дата создания updated_at: ISOString # Дата обновления }
  5. Товар (product) с мультиязычностью coffee { _id: String # Уникальный идентификатор type: 'product' # Тип документа domain: String # Домен language: String # Язык контента translation_of: String # ID исходного документа translation_status: String # Статус перевода title: String # Название товара content: String # Markdown описание excerpt: String # Краткое описание image: String # Главное изображение gallery: Array[String] # Галерея изображений price: Number # Цена currency: String # Валюта compare_price: Number # Старая цена (для акций) category_id: String # ID категории tags: Array[String] # Теги attributes: Object # Атрибуты товара inventory: Number # Количество на складе sku: String # Артикул status: 'available' | 'out_of_stock' | 'discontinued' featured: Boolean # Рекомендуемый товар weight: Number # Вес dimensions: Object # Размеры created_at: ISOString # Дата создания updated_at: ISOString # Дата обновления }
  6. Категория (category) с мультиязычностью coffee { _id: String # Уникальный идентификатор type: 'category' # Тип документа domain: String # Домен language: String # Язык контента translation_of: String # ID исходного документа translation_status: String # Статус перевода name: String # Название категории slug: String # URL-адрес description: String # Описание категории image: String # Изображение категории parent_id: String # ID родительской категории order: Number # Порядок отображения meta_title: String # SEO заголовок meta_description: String # SEO описание active: Boolean # Активна ли категория created_at: ISOString # Дата создания updated_at: ISOString # Дата обновления }
  7. Тема (theme) с мультиязычностью coffee { _id: String # Уникальный идентификатор type: 'theme' # Тип документа domain: String # Домен language: String # Язык контента translation_of: String # ID исходного документа translation_status: String # Статус перевода name: String # Название темы slug: String # URL-адрес description: String # Описание темы color: String # Цвет темы image: String # Изображение темы order: Number # Порядок отображения active: Boolean # Активна ли тема created_at: ISOString # Дата создания updated_at: ISOString # Дата обновления }
  8. Страница (page) с мультиязычностью coffee { _id: String # Уникальный идентификатор type: 'page' # Тип документа domain: String # Домен language: String # Язык контента translation_of: String # ID исходного документа translation_status: String # Статус перевода title: String # Заголовок страницы slug: String # URL-адрес content: String # Markdown контент excerpt: String # Краткое описание image: String # Изображение страницы parent_id: String # ID родительской страницы order: Number # Порядок отображения template: String # Шаблон страницы meta_title: String # SEO заголовок meta_description: String # SEO описание status: 'published' | 'draft' # Статус публикации protected: Boolean # Защищенная страница created_at: ISOString # Дата создания updated_at: ISOString # Дата обновления }
  9. Меню (menu) с мультиязычностью coffee { _id: String # Уникальный идентификатор type: 'menu' # Тип документа domain: String # Домен language: String # Язык контента translation_of: String # ID исходного документа translation_status: String # Статус перевода name: String # Название меню location: String # Расположение (header, footer, etc.) active: Boolean # Активно ли меню items: Array[Object] # Элементы меню created_at: ISOString # Дата создания updated_at: ISOString # Дата обновления }
  10. Пользователь (user) coffee { _id: String # Уникальный идентификатор type: 'user' # Тип документа email: String # Email пользователя name: String # Имя пользователя role: String # Роль (admin, editor, user) active: Boolean # Активен ли пользователь permissions: Array[String] # Права доступа profile: Object # Профиль пользователя preferences: Object # Настройки пользователя language: String # Предпочитаемый язык created_at: ISOString # Дата создания updated_at: ISOString # Дата обновления last_login: ISOString # Дата последнего входа }
  11. Заказ (order) coffee { _id: String # Уникальный идентификатор type: 'order' # Тип документа domain: String # Домен language: String # Язык заказа user_id: String # ID пользователя status: String # Статус заказа total: Number # Общая сумма currency: String # Валюта items: Array[Object] # Элементы заказа customer_info: Object # Информация о клиенте payment_info: Object # Информация об оплате shipping_info: Object # Информация о доставке created_at: ISOString # Дата создания updated_at: ISOString # Дата обновления }
  12. Настройка (setting) coffee { _id: String # Уникальный идентификатор type: 'setting' # Тип документа domain: String # Домен language: String # Язык настройки key: String # Ключ настройки value: Object # Значение настройки is_global: Boolean # Глобальная настройка description: String # Описание настройки created_at: ISOString # Дата создания updated_at: ISOString # Дата обновления }
  13. Аудит (audit_log) coffee { _id: String # Уникальный идентификатор type: 'audit_log' # Тип документа user_id: String # ID пользователя action: String # Действие resource_type: String # Тип ресурса resource_id: String # ID ресурса description: String # Описание действия ip_address: String # IP адрес user_agent: String # User Agent language: String # Язык действия created_at: ISOString # Дата создания }

Пример документа настроек домена

domainSettingsExample =

_id: "domain_settings_borbad_s5l_ru"
type: "domain_settings"
domain: "borbad.s5l.ru"
name: "Кохи Борбад - Концертный зал Душанбе"
description: "Официальный сайт концертного зала Борбад"
active: true
priority: 1
theme: "borbad"
languages: ["ru", "en", "tj"]
default_language: "ru"
timezone: "Asia/Dushanbe"
currency: "TJS"
settings:
    seo:
        title_template: "{page} - Кохи Борбад"
        description: "Концертный зал Борбад - культурный центр Душанбе"
        keywords: ["концерты", "мероприятия", "Душанбе", "культура"]
    social:
        facebook: "https://facebook.com/borbad"
        instagram: "https://instagram.com/borbad"
        twitter: "https://twitter.com/borbad"
    contact:
        address: "г. Душанбе, пр. Рудаки 22"
        phone: "+992 37 123-45-67"
        email: "info@borbad.s5l.ru"
created_at: new Date().toISOString()
updated_at: new Date().toISOString()

Пример документа страницы

pageExample =

_id: "page_about_borbad"
type: "page"
domain: "borbad.s5l.ru"
title: "О нас - Кохи Борбад"
slug: "about"
content: "# О концертном зале Борбад\n\nИстория и описание нашего зала..."
excerpt: "Информация о концертном зале Борбад в Душанбе"
image: "/assets/borbad.s5l.ru/about.jpg"
meta_title: "О нас - Концертный зал Борбад"
meta_description: "Узнайте больше о концертном зале Борбад в Душанбе"
status: "published"
order: 2
template: "default"
created_at: new Date().toISOString()
updated_at: new Date().toISOString()

Пример документа меню

menuExample =

_id: "menu_main_borbad"
type: "menu"
domain: "borbad.s5l.ru"
name: "Главное меню"
location: "header"
active: true
items: [
    {
        title: "Главная"
        url: "/"
        order: 1
        target: "_self"
    }
    {
        title: "Мероприятия"
        url: "/events"
        order: 2
        target: "_self"
    }
    {
        title: "О нас"
        url: "/about"
        order: 3
        target: "_self"
    }
    {
        title: "Контакты"
        url: "/contacts"
        order: 4
        target: "_self"
    }
]
created_at: new Date().toISOString()
updated_at: new Date().toISOString()

Пример документа пользователя

userExample =

_id: "user_admin_1"
type: "user"
email: "admin@borbad.s5l.ru"
name: "Администратор"
role: "admin"
active: true
permissions: [
    "read"
    "write"
    "delete"
    "admin"
]
profile:
    avatar: "/assets/borbad.s5l.ru/avatars/admin.jpg"
    phone: "+992 37 123-45-67"
    position: "Системный администратор"
settings:
    language: "ru"
    notifications: true
created_at: new Date().toISOString()
updated_at: new Date().toISOString()
last_login: new Date().toISOString()

Пример документа заказа

orderExample =

_id: "order_2024_001"
type: "order"
domain: "borbad.s5l.ru"
user_id: "user_customer_1"
status: "completed"
total: 1500
currency: "TJS"
items: [
    {
        product_id: "event_ticket_1"
        name: "Билет на симфонический концерт"
        quantity: 2
        price: 500
        total: 1000
    }
    {
        product_id: "product_1"
        name: "Футболка с логотипом"
        quantity: 1
        price: 500
        total: 500
    }
]
customer_info:
    name: "Иван Иванов"
    email: "ivan@example.com"
    phone: "+992 123-45-67"
payment_info:
    method: "card"
    transaction_id: "txn_123456"
    status: "paid"
created_at: new Date().toISOString()
updated_at: new Date().toISOString()

Пример документа аудита

auditExample =

_id: "audit_2024_001"
type: "audit_log"
user_id: "user_admin_1"
action: "create"
resource_type: "blog_post"
resource_id: "blog_post_1"
description: "Создана новая запись блога"
ip_address: "192.168.1.1"
user_agent: "Mozilla/5.0..."
created_at: new Date().toISOString()

_desing документ для работы с данными

https://gogs.osvoj.ru/s5l.ru/borbad.s5l.ru/raw/master/scripts/design-documents.coffee