# π ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ ΠΏΠΎ ΡΠ΅ΡΠ°ΠΊΡΠΎΡΠΈΠ½Π³Ρ HomePage.vue
## π― ΠΠ±Π·ΠΎΡ
HomePage.vue - Π³Π»Π°Π²Π½ΡΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ Π΄Π»Ρ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΈΠ³ΡΠΎΠ²ΡΠΌ ΡΠΈΡΠΎΠΌ. ΠΡΠΎΡΠ΅Π» ΠΏΠΎΠ»Π½ΡΠΉ ΡΠ΅ΡΠ°ΠΊΡΠΎΡΠΈΠ½Π³ ΠΎΡ ΠΌΠΎΠ½ΠΎΠ»ΠΈΡΠ½ΠΎΠ³ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ° (2456 ΡΡΡΠΎΠΊ) Π΄ΠΎ ΠΌΠΎΠ΄ΡΠ»ΡΠ½ΠΎΠΉ Π°ΡΡ
ΠΈΡΠ΅ΠΊΡΡΡΡ Π½Π° Vue 3 Composition API.
## π ΠΠ΅ΡΡΠΈΠΊΠΈ ΡΠ΅ΡΠ°ΠΊΡΠΎΡΠΈΠ½Π³Π°
| ΠΠ΅ΡΡΠΈΠΊΠ° | ΠΠΎ ΡΠ΅ΡΠ°ΠΊΡΠΎΡΠΈΠ½Π³Π° | ΠΠΎΡΠ»Π΅ ΡΠ΅ΡΠ°ΠΊΡΠΎΡΠΈΠ½Π³Π° | Π£Π»ΡΡΡΠ΅Π½ΠΈΠ΅ |
|---------|----------------|-------------------|-----------|
| **Π Π°Π·ΠΌΠ΅Ρ ΡΠ°ΠΉΠ»Π°** | 2456 ΡΡΡΠΎΠΊ | ~600 ΡΡΡΠΎΠΊ | **-75%** |
| **ΠΡΡ
ΠΈΡΠ΅ΠΊΡΡΡΠ°** | ΠΠΎΠ½ΠΎΠ»ΠΈΡ | ΠΠΎΠ΄ΡΠ»ΡΠ½Π°Ρ | β
|
| **ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΠΎΡΡΡ** | Π‘Π»ΠΎΠΆΠ½Π°Ρ | ΠΠ΅Π³ΠΊΠ°Ρ | β
|
| **Π’Π΅ΡΡΠΈΡΡΠ΅ΠΌΠΎΡΡΡ** | ΠΠΈΠ·ΠΊΠ°Ρ | ΠΡΡΠΎΠΊΠ°Ρ | β
|
| **ΠΠ΅ΡΠ΅ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅** | ΠΡΡΡΡΡΡΠ²ΡΠ΅Ρ | ΠΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΠΎΠ΅ | β
|
## ποΈ ΠΠΎΠ²Π°Ρ Π°ΡΡ
ΠΈΡΠ΅ΠΊΡΡΡΠ°
### Π‘ΡΡΡΠΊΡΡΡΠ° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ²
```
HomePage.vue (Π³Π»Π°Π²Π½ΡΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ, ~600 ΡΡΡΠΎΠΊ)
βββ Layout ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ
β βββ AppHeader.vue
β βββ AppMain.vue
β βββ AppFooter.vue
βββ UI ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ
β βββ IconButton.vue
β βββ PlayPauseButton.vue
β βββ ConfirmDialog.vue
β βββ ThemeToggle.vue
β βββ BurgerMenu.vue
β βββ TimeSemicircle.vue
βββ ΠΠ³ΡΠΎΠ²ΡΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ
β βββ GamePorts.vue
β βββ GamePort.vue
βββ ΠΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ ΡΠΌΠ΅Π½
βββ ShiftModal.vue
βββ ShiftCloseModal.vue
βββ ShiftForm/
βββ FinancialSection.vue
βββ ToysSection.vue
βββ SalarySection.vue
```
### Composables architecture
```
composables/
βββ useAuth.js // ΠΡΡΠ΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΡ ΠΈ Π°Π²ΡΠΎΡΠΈΠ·Π°ΡΠΈΡ
βββ game/
β βββ useGamePorts.js // Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΈΠ³ΡΠΎΠ²ΡΠΌΠΈ ΠΏΠΎΡΡΠ°ΠΌΠΈ
β βββ useGameControl.js // ΠΠ°ΡΠ·Π°/Π²ΠΎΡΠΏΡΠΎΠΈΠ·Π²Π΅Π΄Π΅Π½ΠΈΠ΅
β βββ useTime.js // Π Π°Π±ΠΎΡΠ° ΡΠΎ Π²ΡΠ΅ΠΌΠ΅Π½Π΅ΠΌ
βββ shift/
β βββ useShifts.js // Π‘ΡΠ°ΡΡΡ ΡΠΌΠ΅Π½
β βββ useShiftOperations.js // ΠΠΏΠ΅ΡΠ°ΡΠΈΠΈ ΡΠΎ ΡΠΌΠ΅Π½Π°ΠΌΠΈ
β βββ useShiftForm.js // ΠΠ°Π»ΠΈΠ΄Π°ΡΠΈΡ ΡΠΎΡΠΌ ΡΠΌΠ΅Π½
βββ ui/
βββ useModals.js // Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΌΠΎΠ΄Π°Π»ΡΠ½ΡΠΌΠΈ ΠΎΠΊΠ½Π°ΠΌΠΈ
βββ useConfirm.js // ΠΠΈΠ°Π»ΠΎΠ³ΠΈ ΠΏΠΎΠ΄ΡΠ²Π΅ΡΠΆΠ΄Π΅Π½ΠΈΡ
βββ useBurgerMenu.js // ΠΡΡΠ³Π΅Ρ ΠΌΠ΅Π½Ρ
```
## π§ Π’Π΅Ρ
Π½ΠΈΡΠ΅ΡΠΊΠΈΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΡ
### 1. Composition API Ρ `
```
### 2. Π Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΎΡΠ²Π΅ΡΡΡΠ²Π΅Π½Π½ΠΎΡΡΠΈ
**HomePage.vue ΡΠ΅ΠΏΠ΅ΡΡ ΠΎΡΠ²Π΅ΡΠ°Π΅Ρ ΡΠΎΠ»ΡΠΊΠΎ Π·Π°:**
- ΠΠΎΠΌΠΏΠΎΠ½ΠΎΠ²ΠΊΡ layout
- ΠΠΎΠΎΡΠ΄ΠΈΠ½Π°ΡΠΈΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ°ΠΌΠΈ
- ΠΠ±ΡΠ°Π±ΠΎΡΠΊΡ ΠΎΡΠ½ΠΎΠ²Π½ΡΡ
ΡΠΎΠ±ΡΡΠΈΠΉ
- Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ Π³Π»ΠΎΠ±Π°Π»ΡΠ½ΡΠΌ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ΠΌ
**ΠΠΎΠ³ΠΈΠΊΠ° Π²ΡΠ½Π΅ΡΠ΅Π½Π° Π²:**
- Composables Π΄Π»Ρ Π±ΠΈΠ·Π½Π΅Ρ-Π»ΠΎΠ³ΠΈΠΊΠΈ
- ΠΡΠ΄Π΅Π»ΡΠ½ΡΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ Π΄Π»Ρ UI
- Π‘Π΅ΡΠ²ΠΈΡΡ Π΄Π»Ρ ΡΠ°Π±ΠΎΡΡ Ρ API
### 3. Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ΠΌ
**ΠΠ»ΠΎΠ±Π°Π»ΡΠ½ΠΎΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅:**
```javascript
// useAuth.js - ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ Π°ΡΡΠ΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΈΠΈ
const user = ref(null)
const isAuthenticated = computed(() => !!user.value)
// useShiftOperations.js - ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ ΡΠΌΠ΅Π½
const shiftStatus = ref({
regularShift: null,
techShift: null
})
// useModals.js - ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ ΠΌΠΎΠ΄Π°Π»ΡΠ½ΡΡ
ΠΎΠΊΠΎΠ½
const showShiftModal = ref(false)
const showCloseShiftModal = ref(false)
```
**ΠΠΎΠΊΠ°Π»ΡΠ½ΠΎΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅:**
```javascript
// HomePage.vue - ΡΠΎΠ»ΡΠΊΠΎ ΡΠΏΠ΅ΡΠΈΡΠΈΡΠ½ΠΎΠ΅ Π΄Π»Ρ ΡΡΡΠ°Π½ΠΈΡΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅
const isPaused = ref(false)
const closeShiftForm = ref({
money_konv: 0,
money_razm_closed: 0,
toys: [0, 0, 0, 0, 0]
})
```
### 4. ΠΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ½Π°Ρ ΡΠΈΡΡΠ΅ΠΌΠ°
**UI ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ - ΠΏΠ΅ΡΠ΅ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΠ΅:**
```vue
```
**ΠΠΈΠ·Π½Π΅Ρ-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ - ΠΏΡΠ΅Π΄ΠΌΠ΅ΡΠ½ΠΎ-ΠΎΡΠΈΠ΅Π½ΡΠΈΡΠΎΠ²Π°Π½Π½ΡΠ΅:**
```vue
```
## π ΠΡΠ΅ΠΈΠΌΡΡΠ΅ΡΡΠ²Π° Π½ΠΎΠ²ΠΎΠΉ Π°ΡΡ
ΠΈΡΠ΅ΠΊΡΡΡΡ
### 1. ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΠΎΡΡΡ
- **Π§Π΅ΡΠΊΠ°Ρ ΡΡΡΡΠΊΡΡΡΠ°** - ΠΊΠ°ΠΆΠ΄ΡΠΉ ΡΠ°ΠΉΠ» ΠΈΠΌΠ΅Π΅Ρ ΡΠ²ΠΎΡ Π·ΠΎΠ½Ρ ΠΎΡΠ²Π΅ΡΡΡΠ²Π΅Π½Π½ΠΎΡΡΠΈ
- **ΠΠ΅Π³ΠΊΠ°Ρ Π½Π°Π²ΠΈΠ³Π°ΡΠΈΡ** - Π»ΠΎΠ³ΠΈΠΊΠ° ΡΠ³ΡΡΠΏΠΏΠΈΡΠΎΠ²Π°Π½Π° ΠΏΠΎ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΡΡΠΈ
- **Π‘Π°ΠΌΠΎΠ΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠΈΡΡΠ΅ΠΌΡΠΉ ΠΊΠΎΠ΄** - Π½Π°Π·Π²Π°Π½ΠΈΡ composables ΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ² Π³ΠΎΠ²ΠΎΡΡΡ ΠΎ ΠΈΡ
Π½Π°Π·Π½Π°ΡΠ΅Π½ΠΈΠΈ
### 2. Π’Π΅ΡΡΠΈΡΡΠ΅ΠΌΠΎΡΡΡ
- **ΠΠ·ΠΎΠ»ΠΈΡΠΎΠ²Π°Π½Π½ΡΠ΅ Π΅Π΄ΠΈΠ½ΠΈΡΡ** - ΠΊΠ°ΠΆΠ΄ΡΠΉ composable ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°ΡΡ ΠΎΡΠ΄Π΅Π»ΡΠ½ΠΎ
- **ΠΠΎΠΊΠΈ ΠΈ Π·Π°Π³Π»ΡΡΠΊΠΈ** - Π»Π΅Π³ΠΊΠ°Ρ ΠΏΠΎΠ΄ΠΌΠ΅Π½Π° Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠ΅ΠΉ
- **ΠΠΎΠΊΡΡΡΠΈΠ΅ ΠΊΠΎΠ΄Π°** - ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°ΡΡ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΡΡ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΡΡΡ
### 3. ΠΠ΅ΡΠ΅ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅
- **UI ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ** - ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡΡΡ Π²ΠΎ Π²ΡΠ΅ΠΌ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ
- **Composables** - Π±ΠΈΠ·Π½Π΅Ρ-Π»ΠΎΠ³ΠΈΠΊΠ° Π΄ΠΎΡΡΡΠΏΠ½Π° Π² ΡΠ°Π·Π½ΡΡ
ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ°Ρ
- **ΠΠΈΠΊΡΠΈΠ½Ρ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΡΡΠΈ** - ΠΌΠΎΠΆΠ½ΠΎ ΠΊΠΎΠΌΠ±ΠΈΠ½ΠΈΡΠΎΠ²Π°ΡΡ ΡΠ°Π·Π½ΡΠ΅ composables
### 4. ΠΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ
- **ΠΠ΅Π½ΠΈΠ²Π°Ρ Π·Π°Π³ΡΡΠ·ΠΊΠ°** - ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ ΠΏΠΎΠ΄Π³ΡΡΠΆΠ°ΡΡΡΡ ΠΏΠΎ ΠΌΠ΅ΡΠ΅ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎΡΡΠΈ
- **ΠΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°** - ΠΌΠ΅Π»ΠΊΠΈΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ Π»ΡΡΡΠ΅ ΠΎΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΡΡΡΡΡ Vue
- **ΠΠ΅Π½ΡΡΠΈΠΉ Π±Π°Π½Π΄Π»** - ΠΊΠΎΠ΄ ΡΠ°Π·Π΄Π΅Π»ΡΠ΅ΡΡΡ Π½Π° ΡΠ°Π½ΠΊΠΈ
## π Π ΡΠΊΠΎΠ²ΠΎΠ΄ΡΡΠ²ΠΎ ΠΏΠΎ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠ΅
### ΠΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Π½ΠΎΠ²ΠΎΠΉ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΡΡΠΈ
1. **Π‘ΠΎΠ·Π΄Π°ΠΉΡΠ΅ composable Π΄Π»Ρ Π±ΠΈΠ·Π½Π΅Ρ-Π»ΠΎΠ³ΠΈΠΊΠΈ:**
```javascript
// composables/game/useNewFeature.js
export function useNewFeature() {
const state = ref(null)
const doSomething = () => {
// Π»ΠΎΠ³ΠΈΠΊΠ°
}
return { state, doSomething }
}
```
2. **Π‘ΠΎΠ·Π΄Π°ΠΉΡΠ΅ UI ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ ΠΏΡΠΈ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎΡΡΠΈ:**
```vue
```
3. **ΠΠ½ΡΠ΅Π³ΡΠΈΡΡΠΉΡΠ΅ Π² HomePage.vue:**
```vue
```
### ΠΠΎΠ΄ΠΈΡΠΈΠΊΠ°ΡΠΈΡ ΡΡΡΠ΅ΡΡΠ²ΡΡΡΠ΅ΠΉ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΡΡΠΈ
1. **ΠΠ°ΠΉΠ΄ΠΈΡΠ΅ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΠΈΠΉ composable**
2. **ΠΠ·ΠΌΠ΅Π½ΠΈΡΠ΅ Π»ΠΎΠ³ΠΈΠΊΡ Π² composable**
3. **ΠΠ±Π½ΠΎΠ²ΠΈΡΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ ΠΏΡΠΈ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎΡΡΠΈ**
4. **ΠΡΠΎΡΠ΅ΡΡΠΈΡΡΠΉΡΠ΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ**
### ΠΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Π½ΠΎΠ²ΠΎΠ³ΠΎ UI ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ°
1. **Π‘ΠΎΠ·Π΄Π°ΠΉΡΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ Π² ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΠ΅ΠΉ ΠΏΠ°ΠΏΠΊΠ΅:**
- `components/ui/` - ΠΎΠ±ΡΠΈΠ΅ UI ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ
- `components/game/` - ΠΈΠ³ΡΠΎΠ²ΡΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ
- `components/shift/` - ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΡ ΡΠΌΠ΅Π½
2. **Π‘Π΄Π΅Π»Π°ΠΉΡΠ΅ Π΅Π³ΠΎ ΠΏΠ΅ΡΠ΅ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΠΌ:**
```vue
```
3. **ΠΠΎΠ±Π°Π²ΡΡΠ΅ Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ ΠΈ ΠΏΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ**
## π§ͺ Π’Π΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅
### Π’Π΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ composables
```javascript
// tests/composables/useGamePorts.spec.js
import { useGamePorts } from '@/composables/game/useGamePorts'
describe('useGamePorts', () => {
it('Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΠΏΠΎΡΡΡ', () => {
const { gamePorts } = useGamePorts()
expect(gamePorts.value).toHaveLength(6)
})
it('Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°ΡΡ ΠΊΠ»ΠΈΠΊ ΠΏΠΎ ΠΏΠΎΡΡΡ', () => {
const { handlePortClick } = useGamePorts()
const consoleSpy = vi.spyOn(console, 'log')
handlePortClick(1)
expect(consoleSpy).toHaveBeenCalledWith('ΠΠ»ΠΈΠΊ ΠΏΠΎ ΠΏΠΎΡΡΡ:', 1)
})
})
```
### Π’Π΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ²
```javascript
// tests/components/GamePort.spec.js
import { mount } from '@vue/test-utils'
import GamePort from '@/components/game/GamePort.vue'
describe('GamePort', () => {
it('Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ°ΡΡ Π½ΠΎΠΌΠ΅Ρ ΠΏΠΎΡΡΠ°', () => {
const port = { id: 1, active: false, occupied: false }
const wrapper = mount(GamePort, { props: { port } })
expect(wrapper.find('.port-number').text()).toBe('1')
})
it('Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΠΌΠ΅ΡΡ ΠΏΡΠ°Π²ΠΈΠ»ΡΠ½ΡΠ΅ ΠΊΠ»Π°ΡΡΡ Π΄Π»Ρ Π°ΠΊΡΠΈΠ²Π½ΠΎΠ³ΠΎ ΠΏΠΎΡΡΠ°', () => {
const port = { id: 1, active: true, occupied: false }
const wrapper = mount(GamePort, { props: { port } })
expect(wrapper.classes()).toContain('active')
})
})
```
## π Best Practices
### 1. Π‘ΡΡΡΠΊΡΡΡΠ° composables
```javascript
// β
Π₯ΠΎΡΠΎΡΠΎ
export function useShiftOperations() {
// Π‘ΠΎΡΡΠΎΡΠ½ΠΈΠ΅
const shiftStatus = ref(null)
// ΠΠ΅ΡΠΎΠ΄Ρ
const openShift = async () => {
// Π»ΠΎΠ³ΠΈΠΊΠ°
}
const closeShift = async () => {
// Π»ΠΎΠ³ΠΈΠΊΠ°
}
// ΠΠΎΠ·Π²ΡΠ°ΡΠ°Π΅ΠΌ ΡΠΎΠ»ΡΠΊΠΎ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎΠ΅
return {
shiftStatus,
openShift,
closeShift
}
}
```
### 2. ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΠΎΡΠΈΠ±ΠΎΠΊ
```javascript
// β
Π₯ΠΎΡΠΎΡΠΎ
const openShift = async () => {
try {
const response = await api.openShift()
return { success: true, data: response }
} catch (error) {
console.error('ΠΡΠΈΠ±ΠΊΠ° ΠΎΡΠΊΡΡΡΠΈΡ ΡΠΌΠ΅Π½Ρ:', error)
return { success: false, error: error.message }
}
}
```
### 3. ΠΠ°Π»ΠΈΠ΄Π°ΡΠΈΡ props
```javascript
// β
Π₯ΠΎΡΠΎΡΠΎ
const props = defineProps({
variant: {
type: String,
default: 'default',
validator: (value) => ['default', 'danger', 'warning'].includes(value)
},
size: {
type: String,
default: 'md',
validator: (value) => ['sm', 'md', 'lg'].includes(value)
}
})
```
### 4. ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ computed ΡΠ²ΠΎΠΉΡΡΠ²
```javascript
// β
Π₯ΠΎΡΠΎΡΠΎ
const canManageShift = computed(() => {
return user.value?.group === 3 ||
user.value?.taccess === 'operators' ||
user.value?.taccess === 'admins'
})
```
## π¨ ΠΠ·Π²Π΅ΡΡΠ½ΡΠ΅ ΠΏΡΠΎΠ±Π»Π΅ΠΌΡ ΠΈ ΡΠ΅ΡΠ΅Π½ΠΈΡ
### ΠΡΠΎΠ±Π»Π΅ΠΌΠ° 1: Π‘Π»ΠΎΠΆΠ½ΠΎΡΡΡ ΠΎΡΠ»Π°Π΄ΠΊΠΈ WebSocket
**Π Π΅ΡΠ΅Π½ΠΈΠ΅:** Π‘ΠΎΠ·Π΄Π°ΠΉΡΠ΅ ΠΎΡΠ΄Π΅Π»ΡΠ½ΡΠΉ composable Π΄Π»Ρ Π»ΠΎΠ³ΠΈΡΠΎΠ²Π°Π½ΠΈΡ:
```javascript
// composables/debug/useWebSocketLogger.js
export function useWebSocketLogger() {
const logMessage = (message, direction = 'send') => {
console.log(`[${direction.toUpperCase()}]`, new Date().toISOString(), message)
}
return { logMessage }
}
```
### ΠΡΠΎΠ±Π»Π΅ΠΌΠ° 2: Π‘ΠΈΠ½Ρ
ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠ°ΠΌΠΈ
**Π Π΅ΡΠ΅Π½ΠΈΠ΅:** ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ reactive ΠΎΠ±ΡΠ΅ΠΊΡΡ Π² composables:
```javascript
// composables/shared/useGameState.js
const gameState = reactive({
isPaused: false,
activePorts: [],
currentShift: null
})
export function useGameState() {
return { gameState }
}
```
### ΠΡΠΎΠ±Π»Π΅ΠΌΠ° 3: ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΠΌΠ½ΠΎΠΆΠ΅ΡΡΠ²Π΅Π½Π½ΡΡ
Π°ΡΠΈΠ½Ρ
ΡΠΎΠ½Π½ΡΡ
ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ
**Π Π΅ΡΠ΅Π½ΠΈΠ΅:** ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ Promise.all ΠΈΠ»ΠΈ async/await Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΎΠΉ ΠΎΡΠΈΠ±ΠΎΠΊ:
```javascript
const initializeApp = async () => {
try {
const [authResult, shiftStatus, portsStatus] = await Promise.all([
checkAuth(),
getShiftsStatus(),
getPortsStatus()
])
return { success: true, data: { authResult, shiftStatus, portsStatus } }
} catch (error) {
return { success: false, error: error.message }
}
}
```
## π ΠΠ»Π°Π½ Π΄Π°Π»ΡΠ½Π΅ΠΉΡΠΈΡ
ΡΠ»ΡΡΡΠ΅Π½ΠΈΠΉ
### ΠΡΠ°ΡΠΊΠΎΡΡΠΎΡΠ½ΡΠ΅ ΡΠ΅Π»ΠΈ (1-2 Π½Π΅Π΄Π΅Π»ΠΈ)
1. **ΠΠΎΠ±Π°Π²ΠΈΡΡ TypeScript** Π΄Π»Ρ ΡΠΈΠΏΠΎΠ±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡΠΈ
2. **ΠΠ°ΠΏΠΈΡΠ°ΡΡ unit ΡΠ΅ΡΡΡ** Π΄Π»Ρ ΠΎΡΠ½ΠΎΠ²Π½ΡΡ
composables
3. **ΠΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ** Ρ ΠΏΠΎΠΌΠΎΡΡΡ lazy loading
4. **Π£Π»ΡΡΡΠΈΡΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΡ ΠΎΡΠΈΠ±ΠΎΠΊ** ΠΈ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΠΉ ΠΎΠΏΡΡ
### Π‘ΡΠ΅Π΄Π½Π΅ΡΡΠΎΡΠ½ΡΠ΅ ΡΠ΅Π»ΠΈ (1-2 ΠΌΠ΅ΡΡΡΠ°)
1. **Π‘ΠΎΠ·Π΄Π°ΡΡ Storybook** Π΄Π»Ρ Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ²
2. **ΠΠΎΠ±Π°Π²ΠΈΡΡ E2E ΡΠ΅ΡΡΡ** Π΄Π»Ρ ΠΊΠ»ΡΡΠ΅Π²ΡΡ
ΡΡΠ΅Π½Π°ΡΠΈΠ΅Π²
3. **Π Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°ΡΡ ΠΊΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅** Π΄Π»Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ Π·Π°ΠΏΡΠΎΡΠΎΠ²
4. **Π£Π»ΡΡΡΠΈΡΡ ΠΌΠΎΠ±ΠΈΠ»ΡΠ½ΡΡ Π²Π΅ΡΡΠΈΡ**
### ΠΠΎΠ»Π³ΠΎΡΡΠΎΡΠ½ΡΠ΅ ΡΠ΅Π»ΠΈ (3-6 ΠΌΠ΅ΡΡΡΠ΅Π²)
1. **ΠΠΈΠ³ΡΠ°ΡΠΈΡ Π½Π° Pinia** Π΄Π»Ρ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅ΠΌ
2. **ΠΠΎΠ±Π°Π²ΠΈΡΡ PWA** ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΡΡΡ
3. **ΠΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ Π±Π°Π½Π΄Π»** ΠΈ Π²ΡΠ΅ΠΌΡ Π·Π°Π³ΡΡΠ·ΠΊΠΈ
4. **Π Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°ΡΡ ΡΠ΅ΠΌΡ ΠΎΡΠΎΡΠΌΠ»Π΅Π½ΠΈΡ**
## π ΠΠΎΠ»Π΅Π·Π½ΡΠ΅ ΡΠ΅ΡΡΡΡΡ
### ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ
- [Vue 3 Composition API](https://vuejs.org/guide/extras/composition-api-faq.html)
- [Vue Router](https://router.vuejs.org/)
- [Vite](https://vitejs.dev/)
### ΠΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ
- [Vue DevTools](https://devtools.vuejs.org/)
- [Vitest](https://vitest.dev/) Π΄Π»Ρ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ
- [ESLint](https://eslint.org/) Π΄Π»Ρ ΠΊΠ°ΡΠ΅ΡΡΠ²Π° ΠΊΠΎΠ΄Π°
- [Prettier](https://prettier.io/) Π΄Π»Ρ ΡΠΎΡΠΌΠ°ΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ
### ΠΠ°ΡΡΠ΅ΡΠ½Ρ ΠΈ Π»ΡΡΡΠΈΠ΅ ΠΏΡΠ°ΠΊΡΠΈΠΊΠΈ
- [Vue Style Guide](https://v2.vuejs.org/v2/style-guide/)
- [Composition API Patterns](https://vueuse.org/)
- [Vue 3 Best Practices](https://learnvue.co/articles/vue-3-best-practices)
---
## π ΠΠ°ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅
Π Π΅ΡΠ°ΠΊΡΠΎΡΠΈΠ½Π³ HomePage.vue Π·Π½Π°ΡΠΈΡΠ΅Π»ΡΠ½ΠΎ ΡΠ»ΡΡΡΠΈΠ» Π°ΡΡ
ΠΈΡΠ΅ΠΊΡΡΡΡ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ:
- **Π£ΠΌΠ΅Π½ΡΡΠ΅Π½ ΡΠ°Π·ΠΌΠ΅Ρ ΠΊΠΎΠ΄Π°** Π½Π° 75%
- **ΠΠΎΠ²ΡΡΠ΅Π½Π° ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΠΎΡΡΡ** ΡΠ΅ΡΠ΅Π· ΠΌΠΎΠ΄ΡΠ»ΡΠ½ΡΡ ΡΡΡΡΠΊΡΡΡΡ
- **Π£Π»ΡΡΡΠ΅Π½Π° ΡΠ΅ΡΡΠΈΡΡΠ΅ΠΌΠΎΡΡΡ** ΡΠ΅ΡΠ΅Π· ΠΈΠ·ΠΎΠ»ΠΈΡΠΎΠ²Π°Π½Π½ΡΠ΅ composables
- **Π£Π²Π΅Π»ΠΈΡΠ΅Π½ΠΎ ΠΏΠ΅ΡΠ΅ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅** ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ² ΠΈ Π»ΠΎΠ³ΠΈΠΊΠΈ
ΠΡΠΎΠ΅ΠΊΡ ΡΠ΅ΠΏΠ΅ΡΡ ΡΠ»Π΅Π΄ΡΠ΅Ρ ΡΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΡΠΌ ΠΏΡΠ°ΠΊΡΠΈΠΊΠ°ΠΌ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠΈ Π½Π° Vue 3 ΠΈ Π³ΠΎΡΠΎΠ² ΠΊ Π΄Π°Π»ΡΠ½Π΅ΠΉΡΠ΅ΠΌΡ ΠΌΠ°ΡΡΡΠ°Π±ΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΈ ΡΠ°Π·Π²ΠΈΡΠΈΡ.
---
*ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Π°: {{ new Date().toLocaleDateString('ru-RU') }}*
Β§