Gogs 3 hafta önce
ebeveyn
işleme
cf7c4971b5
1 değiştirilmiş dosya ile 799 ekleme ve 0 silme
  1. 799 0
      vue/app/shared/FormValidator/README.md

+ 799 - 0
vue/app/shared/FormValidator/README.md

@@ -0,0 +1,799 @@
+# Компонент FormValidator - Полная документация
+
+## Назначение компонента
+
+`FormValidator` - компонент для валидации форм с поддержкой различных типов полей, кастомных правил валидации, асинхронной проверки и многоязычных сообщений об ошибках. Интегрируется с мультиязычной системой приложения.
+
+## Импорт и регистрация
+
+```coffee
+# В основном файле приложения (app/temp.coffee)
+components:
+    'form-validator': require 'app/shared/FormValidator'
+```
+
+## Базовое использование
+
+```pug
+//- Минимальное использование
+form-validator(:rules="rules" v-slot="{ validate, errors }")
+    input(v-model="email" @blur="validate('email')")
+    div(v-if="errors.email") {{ errors.email }}
+
+//- С автоматической валидацией
+form-validator(:rules="rules" :values="formData" v-slot="{ validate, errors, isValid }")
+    form(@submit.prevent="isValid && submitForm()")
+        input(v-model="formData.email" @blur="validate('email')")
+        span(v-if="errors.email" class="error") {{ errors.email }}
+        button(:disabled="!isValid") Отправить
+```
+
+## Полный список props
+
+### `rules` (обязательный)
+- **Тип:** `Object`
+- **Описание:** Объект с правилами валидации для каждого поля
+- **Пример:**
+  ```pug
+  form-validator(:rules="validationRules")
+  ```
+
+### `values` (опциональный)
+- **Тип:** `Object`
+- **По умолчанию:** `{}`
+- **Описание:** Объект с текущими значениями полей
+- **Пример:**
+  ```pug
+  form-validator(:rules="rules" :values="formData")
+  ```
+
+### `validateOn` (опциональный)
+- **Тип:** `String | Array`
+- **По умолчанию:** `'blur'`
+- **Допустимые значения:** `'input'`, `'blur'`, `'change'`, `'submit'`
+- **Описание:** События для автоматической валидации
+- **Пример:**
+  ```pug
+  form-validator(validateOn="input")
+  form-validator(:validateOn="['blur', 'change']")
+  ```
+
+### `mode` (опциональный)
+- **Тип:** `String`
+- **По умолчанию:** `'aggressive'`
+- **Допустимые значения:** `'aggressive'`, `'lazy'`, `'passive'`
+- **Описание:** Режим валидации
+- **Пример:**
+  ```pug
+  form-validator(mode="lazy")
+  ```
+
+### `locale` (опциональный)
+- **Тип:** `String`
+- **По умолчанию:** `'ru'`
+- **Описание:** Локаль для сообщений об ошибках
+- **Пример:**
+  ```pug
+  form-validator(locale="en")
+  ```
+
+### `showErrors` (опциональный)
+- **Тип:** `Boolean`
+- **По умолчанию:** `true`
+- **Описание:** Показывать сообщения об ошибках
+- **Пример:**
+  ```pug
+  form-validator(:showErrors="false")
+  ```
+
+### `scrollToError` (опциональный)
+- **Тип:** `Boolean`
+- **По умолчанию:** `true`
+- **Описание:** Прокручивать к первой ошибке
+- **Пример:**
+  ```pug
+  form-validator(:scrollToError="false")
+  ```
+
+### `class` (опциональный)
+- **Тип:** `String | Object | Array`
+- **По умолчанию:** `''`
+- **Описание:** CSS классы для контейнера
+- **Пример:**
+  ```pug
+  form-validator(class="space-y-4")
+  ```
+
+## События (Events)
+
+### `@valid`
+- **Описание:** Форма стала валидной
+- **Payload:** `{ values: Object, errors: Object }`
+- **Пример:**
+  ```pug
+  form-validator(@valid="onFormValid")
+  ```
+
+### `@invalid`
+- **Описание:** Форма стала невалидной
+- **Payload:** `{ values: Object, errors: Object }`
+- **Пример:**
+  ```pug
+  form-validator(@invalid="onFormInvalid")
+  ```
+
+### `@validate`
+- **Описание:** Произошла валидация поля
+- **Payload:** `{ field: String, isValid: Boolean, error: String }`
+- **Пример:**
+  ```pug
+  form-validator(@validate="onFieldValidate")
+  ```
+
+### `@error`
+- **Описание:** Появилась ошибка валидации
+- **Payload:** `{ field: String, error: String }`
+- **Пример:**
+  ```pug
+  form-validator(@error="onValidationError")
+  ```
+
+### `@success`
+- **Описание:** Ошибка валидации исправлена
+- **Payload:** `{ field: String }`
+- **Пример:**
+  ```pug
+  form-validator(@success="onValidationSuccess")
+  ```
+
+## Слоты (Slots)
+
+### `[body]` (основной слот)
+- **Описание:** Содержимое формы
+- **Scope:** `{ validate: Function, errors: Object, isValid: Boolean, isDirty: Boolean, reset: Function, fields: Object }`
+- **Пример:**
+  ```pug
+  form-validator(:rules="rules" v-slot="{ validate, errors, isValid }")
+      form
+          input(@blur="validate('email')")
+          div(v-if="errors.email") {{ errors.email }}
+  ```
+
+### `[error]`
+- **Описание:** Кастомное отображение ошибки
+- **Scope:** `{ field: String, error: String }`
+- **Пример:**
+  ```pug
+  form-validator(:rules="rules" v-slot="{ errors }")
+      form
+          input
+          template([error]="{ field: 'email', error: errors.email }")
+              div(v-if="error" class="custom-error") {{ error }}
+  ```
+
+### `[success]`
+- **Описание:** Отображение при успешной валидации
+- **Scope:** `{ field: String }`
+- **Пример:**
+  ```pug
+  form-validator(:rules="rules" v-slot="{}")
+      form
+          input
+          template([success]="{ field: 'email' }")
+              div(class="success-icon") ✓
+  ```
+
+## Правила валидации
+
+### Базовые правила
+```coffee
+validationRules =
+    email:
+        required: true
+        email: true
+        maxLength: 255
+    
+    password:
+        required: true
+        minLength: 8
+        contains: ['uppercase', 'lowercase', 'number']
+    
+    phone:
+        required: true
+        pattern: /^\+?[1-9]\d{1,14}$/
+    
+    name:
+        required: true
+        minLength: 2
+        maxLength: 50
+```
+
+### Все доступные правила
+
+#### `required`
+- **Тип:** `Boolean`
+- **Описание:** Поле обязательно для заполнения
+- **Пример:**
+  ```coffee
+  required: true
+  ```
+
+#### `email`
+- **Тип:** `Boolean`
+- **Описание:** Проверка email формата
+- **Пример:**
+  ```coffee
+  email: true
+  ```
+
+#### `url`
+- **Тип:** `Boolean`
+- **Описание:** Проверка URL формата
+- **Пример:**
+  ```coffee
+  url: true
+  ```
+
+#### `minLength`
+- **Тип:** `Number`
+- **Описание:** Минимальная длина значения
+- **Пример:**
+  ```coffee
+  minLength: 3
+  ```
+
+#### `maxLength`
+- **Тип:** `Number`
+- **Описание:** Максимальная длина значения
+- **Пример:**
+  ```coffee
+  maxLength: 255
+  ```
+
+#### `min`
+- **Тип:** `Number`
+- **Описание:** Минимальное числовое значение
+- **Пример:**
+  ```coffee
+  min: 0
+  ```
+
+#### `max`
+- **Тип:** `Number`
+- **Описание:** Максимальное числовое значение
+- **Пример:**
+  ```coffee
+  max: 100
+  ```
+
+#### `pattern`
+- **Тип:** `RegExp | String`
+- **Описание:** Регулярное выражение для проверки
+- **Пример:**
+  ```coffee
+  pattern: /^[a-zA-Z]+$/
+  pattern: '^[a-zA-Z]+$'  # Строка также поддерживается
+  ```
+
+#### `equals`
+- **Тип:** `String | Number | Function`
+- **Описание:** Значение должно совпадать с указанным
+- **Пример:**
+  ```coffee
+  equals: 'password'
+  equals: (value, values) -> value == values.password
+  ```
+
+#### `contains`
+- **Тип:** `Array | String`
+- **Описание:** Должен содержать указанные символы/типы
+- **Пример:**
+  ```coffee
+  contains: ['uppercase', 'lowercase', 'number', 'special']
+  contains: 'abc'
+  ```
+
+#### `custom`
+- **Тип:** `Function`
+- **Описание:** Кастомная функция валидации
+- **Пример:**
+  ```coffee
+  custom: (value, values) ->
+      if value.length < 5
+          return 'Минимум 5 символов'
+      return true
+  ```
+
+#### `async`
+- **Тип:** `Function`
+- **Описание:** Асинхронная функция валидации
+- **Пример:**
+  ```coffee
+  async: (value) ->
+      try
+          response = await fetch('/api/check-email?email='+value)
+          data = await response.json()
+          return data.available or 'Email уже используется'
+      catch error
+          return 'Ошибка проверки'
+  ```
+
+## Примеры использования
+
+### 1. Базовая форма регистрации
+```pug
+form-validator(
+    :rules="registerRules" 
+    :values="formData"
+    v-slot="{ validate, errors, isValid, isDirty }"
+)
+    form(@submit.prevent="isValid && register()" class="space-y-4")
+        div
+            label(for="email" class="block text-sm font-medium") Email
+            input(
+                id="email"
+                v-model="formData.email"
+                @blur="validate('email')"
+                @input="validateOn === 'input' && validate('email')"
+                type="email"
+                class="w-full p-2 border rounded"
+                :class="{ 'border-red-500': errors.email }"
+            )
+            div(v-if="errors.email" class="text-red-500 text-sm mt-1") {{ errors.email }}
+
+        div
+            label(for="password" class="block text-sm font-medium") Пароль
+            input(
+                id="password"
+                v-model="formData.password"
+                @blur="validate('password')"
+                type="password"
+                class="w-full p-2 border rounded"
+                :class="{ 'border-red-500': errors.password }"
+            )
+            div(v-if="errors.password" class="text-red-500 text-sm mt-1") {{ errors.password }}
+
+        div
+            label(for="confirmPassword" class="block text-sm font-medium") Подтверждение пароля
+            input(
+                id="confirmPassword"
+                v-model="formData.confirmPassword"
+                @blur="validate('confirmPassword')"
+                type="password"
+                class="w-full p-2 border rounded"
+                :class="{ 'border-red-500': errors.confirmPassword }"
+            )
+            div(v-if="errors.confirmPassword" class="text-red-500 text-sm mt-1") {{ errors.confirmPassword }}
+
+        button(
+            type="submit"
+            class="w-full bg-blue-500 text-white p-2 rounded disabled:bg-gray-400"
+            :disabled="!isValid || !isDirty"
+        ) Зарегистрироваться
+
+//- В компоненте
+data: ->
+    formData:
+        email: ''
+        password: ''
+        confirmPassword: ''
+    
+    registerRules:
+        email:
+            required: true
+            email: true
+            maxLength: 255
+            async: @checkEmailAvailability
+        
+        password:
+            required: true
+            minLength: 8
+            contains: ['uppercase', 'lowercase', 'number']
+        
+        confirmPassword:
+            required: true
+            equals: (value, values) -> value == values.password
+
+methods:
+    checkEmailAvailability: async (email) ->
+        if !email or email.length < 3
+            return true
+        
+        try
+            response = await fetch('/api/check-email?email='+encodeURIComponent(email))
+            data = await response.json()
+            return data.available or 'Этот email уже используется'
+        catch error
+            return 'Ошибка проверки email'
+    
+    register: ->
+        # Логика регистрации
+```
+
+### 2. Форма с кастомными сообщениями об ошибках
+```pug
+form-validator(
+    :rules="rules"
+    :values="formData"
+    v-slot="{ validate, errors }"
+)
+    form(class="space-y-4")
+        div
+            label Имя
+            input(
+                v-model="formData.name"
+                @blur="validate('name')"
+                :class="{ 'error-border': errors.name }"
+            )
+            template([error]="{ field: 'name', error: errors.name }")
+                div(v-if="error" class="custom-error-message")
+                    icon(name="warning")
+                    span {{ error }}
+
+        div
+            label Телефон
+            input(
+                v-model="formData.phone"
+                @blur="validate('phone')"
+                :class="{ 'error-border': errors.phone }"
+            )
+            template([success]="{ field: 'phone' }")
+                div(class="success-message")
+                    icon(name="check")
+                    span Телефон корректен
+
+//- Правила с кастомными сообщениями
+rules:
+    name:
+        required: [true, 'Пожалуйста, укажите ваше имя']
+        minLength: [2, 'Имя должно содержать минимум 2 символа']
+        maxLength: [50, 'Имя не должно превышать 50 символов']
+    
+    phone:
+        required: [true, 'Телефон обязателен для заполнения']
+        pattern: [/^\+?[1-9]\d{1,14}$/, 'Введите корректный номер телефона']
+```
+
+### 3. Форма с условной валидацией
+```pug
+form-validator(
+    :rules="conditionalRules"
+    :values="formData"
+    v-slot="{ validate, errors, isValid }"
+)
+    form
+        div
+            label Тип пользователя
+            select(v-model="formData.userType" @change="validate()")
+                option(value="individual") Физическое лицо
+                option(value="company") Юридическое лицо
+
+        div(v-if="formData.userType === 'company'")
+            label Название компании
+            input(
+                v-model="formData.companyName"
+                @blur="validate('companyName')"
+            )
+            div(v-if="errors.companyName") {{ errors.companyName }}
+
+        div(v-if="formData.userType === 'company'")
+            label ИНН
+            input(
+                v-model="formData.inn"
+                @blur="validate('inn')"
+            )
+            div(v-if="errors.inn") {{ errors.inn }}
+
+//- Условные правила
+conditionalRules:
+    userType:
+        required: true
+    
+    companyName:
+        required: (value, values) -> values.userType == 'company'
+        minLength: (value, values) -> 
+            if values.userType == 'company' then 2 else true
+    
+    inn:
+        required: (value, values) -> values.userType == 'company'
+        pattern: (value, values) ->
+            if values.userType == 'company'
+                return /^\d{10,12}$/
+            return true
+```
+
+### 4. Форма с асинхронной валидацией
+```pug
+form-validator(
+    :rules="asyncRules"
+    :values="formData"
+    v-slot="{ validate, errors, isValid, isPending }"
+)
+    form
+        div
+            label Имя пользователя
+            input(
+                v-model="formData.username"
+                @blur="validate('username')"
+                :class="{ 'validating': isPending.username }"
+            )
+            div(v-if="errors.username") {{ errors.username }}
+            div(v-if="isPending.username" class="loading") Проверка...
+
+        button(:disabled="!isValid || isPending.username") Сохранить
+
+//- Асинхронные правила
+asyncRules:
+    username:
+        required: true
+        minLength: 3
+        maxLength: 20
+        pattern: /^[a-zA-Z0-9_]+$/
+        async: @checkUsername
+```
+
+### 5. Форма с групповой валидацией
+```pug
+form-validator(
+    :rules="groupRules"
+    :values="formData"
+    v-slot="{ validate, errors, validateField, validateGroup }"
+)
+    form
+        fieldset
+            legend Контактная информация
+            div
+                label Email
+                input(v-model="formData.email" @blur="validateField('email')")
+                div(v-if="errors.email") {{ errors.email }}
+            
+            div
+                label Телефон
+                input(v-model="formData.phone" @blur="validateField('phone')")
+                div(v-if="errors.phone") {{ errors.phone }}
+
+        button(@click="validateGroup('contact')" type="button") Проверить контакты
+```
+
+## Методы API
+
+### `validate(field?: string)`
+- **Описание:** Валидирует поле или всю форму
+- **Параметры:** `field` - опциональное имя поля
+- **Возвращает:** `Promise<boolean>`
+- **Пример:**
+  ```coffee
+  isValid = await validate('email')
+  allValid = await validate()
+  ```
+
+### `validateField(field: string)`
+- **Описание:** Валидирует конкретное поле
+- **Параметры:** `field` - имя поля
+- **Возвращает:** `Promise<boolean>`
+- **Пример:**
+  ```coffee
+  isValid = await validateField('email')
+  ```
+
+### `validateGroup(group: string)`
+- **Описание:** Валидирует группу полей
+- **Параметры:** `group` - имя группы
+- **Возвращает:** `Promise<boolean>`
+- **Пример:**
+  ```coffee
+  isValid = await validateGroup('contact')
+  ```
+
+### `reset()`
+- **Описание:** Сбрасывает состояние валидации
+- **Пример:**
+  ```coffee
+  reset()
+  ```
+
+### `setErrors(errors: Object)`
+- **Описание:** Устанавливает ошибки вручную
+- **Параметры:** `errors` - объект с ошибками
+- **Пример:**
+  ```coffee
+  setErrors({ email: 'Email уже существует' })
+  ```
+
+### `clearErrors(field?: string)`
+- **Описание:** Очищает ошибки поля или все ошибки
+- **Параметры:** `field` - опциональное имя поля
+- **Пример:**
+  ```coffee
+  clearErrors('email')
+  clearErrors()
+  ```
+
+### `getValues()`
+- **Описание:** Возвращает текущие значения
+- **Возвращает:** `Object`
+- **Пример:**
+  ```coffee
+  values = getValues()
+  ```
+
+### `isValid()`
+- **Описание:** Проверяет валидность всей формы
+- **Возвращает:** `boolean`
+- **Пример:**
+  ```coffee
+  if isValid()
+      submitForm()
+  ```
+
+## Состояния слота
+
+### `errors`
+- **Тип:** `Object`
+- **Описание:** Объект с ошибками валидации
+- **Пример:**
+  ```pug
+  span(v-if="errors.email") {{ errors.email }}
+  ```
+
+### `isValid`
+- **Тип:** `Boolean`
+- **Описание:** Вся форма валидна
+- **Пример:**
+  ```pug
+  button(:disabled="!isValid") Отправить
+  ```
+
+### `isDirty`
+- **Тип:** `Boolean`
+- **Описание:** Форма была изменена
+- **Пример:**
+  ```pug
+  button(:disabled="!isDirty") Сохранить изменения
+  ```
+
+### `isPending`
+- **Тип:** `Object`
+- **Описание:** Объект с состояниями асинхронной валидации
+- **Пример:**
+  ```pug
+  div(v-if="isPending.email") Проверка email...
+  ```
+
+### `validate`
+- **Тип:** `Function`
+- **Описание:** Функция для запуска валидации
+- **Пример:**
+  ```pug
+  input(@blur="validate('email')")
+  ```
+
+### `reset`
+- **Тип:** `Function`
+- **Описание:** Функция сброса состояния
+- **Пример:**
+  ```pug
+  button(@click="reset") Сбросить
+  ```
+
+## Интеграция с мультиязычной системой
+
+### Мультиязычные сообщения об ошибках
+```coffee
+# В основном приложении
+validationMessages =
+    ru:
+        required: 'Поле обязательно для заполнения'
+        email: 'Введите корректный email адрес'
+        minLength: 'Минимум {0} символов'
+        # ... другие сообщения
+    
+    en:
+        required: 'Field is required'
+        email: 'Enter a valid email address'
+        minLength: 'Minimum {0} characters'
+```
+
+### Кастомные сообщения в правилах
+```coffee
+rules:
+    email:
+        required: [true, 'Пожалуйста, укажите email']
+        email: [true, 'Это не похоже на email']
+    
+    password:
+        minLength: [8, 'Пароль должен содержать минимум {0} символов']
+```
+
+## Кастомные валидаторы
+
+### Создание кастомного валидатора
+```coffee
+# Глобальная регистрация
+FormValidator.addValidator('phone', (value, params) ->
+    phoneRegex = /^\+?[1-9]\d{1,14}$/
+    if !phoneRegex.test(value)
+        return 'Введите корректный номер телефона'
+    return true
+)
+
+# Использование
+rules:
+    phone:
+        phone: true
+```
+
+### Валидатор с параметрами
+```coffee
+FormValidator.addValidator('fileSize', (value, params) ->
+    if value && value.size > params.maxSize
+        return "Файл слишком большой. Максимум: #{params.maxSize} bytes"
+    return true
+)
+
+# Использование
+rules:
+    avatar:
+        fileSize: { maxSize: 5 * 1024 * 1024 } # 5MB
+```
+
+## Best Practices
+
+### 1. Используйте соответствующие события валидации
+```pug
+//- Для мгновенной обратной связи
+input(@input="validateOn === 'input' && validate('email')")
+
+//- Для окончательной проверки
+input(@blur="validate('email')")
+```
+
+### 2. Группируйте связанные поля
+```coffee
+rules:
+    contact:
+        group: ['email', 'phone']
+        validator: (values) ->
+            if !values.email && !values.phone
+                return 'Укажите email или телефон'
+            return true
+```
+
+### 3. Используйте асинхронную валидацию для проверок на сервере
+```coffee
+async: async (value) ->
+    try
+        available = await checkAvailability(value)
+        return available || 'Уже занято'
+    catch error
+        return 'Ошибка проверки'
+```
+
+### 4. Предоставляйте понятные сообщения об ошибках
+```coffee
+password:
+    minLength: [8, 'Пароль должен содержать не менее 8 символов']
+    contains: [
+        ['uppercase', 'Хотя бы одна заглавная буква'],
+        ['number', 'Хотя бы одна цифра']
+    ]
+```
+
+### 5. Тестируйте валидацию
+```coffee
+describe('FormValidator', ->
+    it('should validate email correctly', ->
+        validator = new FormValidator(rules: email: email: true)
+        
+        result = await validator.validateField('email', 'invalid-email')
+        expect(result).toBe(false)
+        expect(validator.errors.email).toBe('Введите корректный email')
+        
+        result = await validator.validateField('email', 'test@example.com')
+        expect(result).toBe(true)
+        expect(validator.errors.email).toBeNull()
+    )
+)
+```
+
+Компонент FormValidator предоставляет мощную и гибкую систему валидации форм с поддержкой различных типов правил, асинхронной проверки, мультиязычности и кастомизации.