217 lines
9.3 KiB
Markdown
217 lines
9.3 KiB
Markdown
---
|
||
title: Онлайн-консультация в личном кабинете
|
||
---
|
||
|
||
# Онлайн-консультация (cabinet)
|
||
|
||
> Как устроена запись на **онлайн-приём** в `apps/cabinet`: маршруты, MIS/Widget API, оплата и видеоконференция. Связано с [расписанием врачей](./doctor-schedule-sync.md).
|
||
|
||
---
|
||
|
||
## TL;DR
|
||
|
||
| Этап | Где | Внешний ресурс |
|
||
|------|-----|----------------|
|
||
| Список онлайн-врачей | `GET /online-specialists` (нужен login) | PostgreSQL `location_view` (`online_mode=true`) |
|
||
| Слоты | `GET /api/interval?onlineMode=1` | `MIS` → `widget.sovamed.ru` |
|
||
| Запись | `webSDK.scheduleRecReserve({ onlineType: 1 })` | Infoclinica SDK в браузере |
|
||
| Оплата / видео | `/case-history` | `webSDK.loadPaymentView`, `openConference` |
|
||
|
||
Cron `upload:doctors 1` (backend) обновляет **ближайшие даты** для онлайн-локаций, не сами слоты.
|
||
|
||
---
|
||
|
||
## 1. Маршруты
|
||
|
||
| URL | Auth | Назначение |
|
||
|-----|------|------------|
|
||
| `/online-specialists` | `ROLE_USER` | Список врачей с онлайн-локациями |
|
||
| `/specialists` | публичный | Очный приём (`onlineMode=0`) |
|
||
| `/api/interval` | публичный | Прокси расписания в MIS |
|
||
| `/case-history` | `ROLE_USER` | Записи, оплата, «Онлайн приём», возврат |
|
||
| `/refund` | `ROLE_USER` | Форма возврата |
|
||
|
||
Код: [`SpecialistController.php`](../../apps/cabinet/src/Controller/SpecialistController.php), [`PublicAPIController.php`](../../apps/cabinet/src/Controller/PublicAPIController.php), [`SecurityController.php`](../../apps/cabinet/src/Controller/SecurityController.php).
|
||
|
||
---
|
||
|
||
## 2. Поток данных
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant User as Пользователь ЛК
|
||
participant Cab as cabinet
|
||
participant MIS as widget.sovamed.ru
|
||
participant SDK as webSDK браузер
|
||
|
||
User->>Cab: GET /online-specialists
|
||
Cab->>Cab: location_view online_mode=1
|
||
User->>Cab: GET /api/interval onlineMode=1
|
||
Cab->>MIS: /api/reservation/schedule + /intervals
|
||
MIS-->>Cab: intervalsData
|
||
User->>SDK: scheduleRecReserve onlineType=1
|
||
User->>Cab: GET /case-history
|
||
Cab->>SDK: records, payment, conference
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Отличия online vs offline
|
||
|
||
| | Offline | Online |
|
||
|---|---------|--------|
|
||
| Список | `/specialists` | `/online-specialists` + login |
|
||
| `onlineMode` в API | `0` | `1` |
|
||
| Анонимная запись | да (`/api/anonymous-reserve`) | **нет** |
|
||
| Согласия | PD | PD + оферта + ИДС |
|
||
| После записи | `#doctor-success` | `#online` + предупреждение об оплате 5 мин |
|
||
| Оплата / видео | — | `/case-history` |
|
||
|
||
---
|
||
|
||
## 4. Типичные причины поломки
|
||
|
||
### 4.1. Пустой список `/online-specialists`
|
||
|
||
- Нет строк в `location_view` с `online_mode = true` (cron `upload:doctors 1` + `update_location()`).
|
||
- Врач не привязан к MIS (`dcode`, `department`, `filial`).
|
||
|
||
**Проверка:** SQL `SELECT * FROM location_view WHERE online_mode = true;`
|
||
|
||
### 4.2. Нет слотов на карточке
|
||
|
||
- MIS недоступен (`MIS` env, `widget.sovamed.ru`).
|
||
- Неверный `filial`/`department` для онлайн-режима.
|
||
- `GET /api/interval?onlineMode=1` возвращает 5xx.
|
||
|
||
**Проверка:** `curl "https://widget.sovamed.ru/specialists/departments"` и `/api/interval` с prod.
|
||
|
||
### 4.3. Запись создаётся как очная
|
||
|
||
- Баг нормализации `onlineMode` в JS/PHP (исправлено: `OnlineMode`, `onlineMode.js`).
|
||
- В `scheduleRecReserve` уходит `onlineType: 0` вместо `1`.
|
||
|
||
### 4.4. Фильтр на онлайн-странице уводит на `/specialists`
|
||
|
||
- Форма поиска post'ила на `specialist_index` (исправлено → `specialist_online_index`).
|
||
|
||
### 4.5. Оплата / видео не работает
|
||
|
||
- Не загружен SDK (`loader.js` → `widget.sovamed.ru/.../sdk.build.min.js`).
|
||
- Запись не оплачена в течение 5 мин (MIS отменяет).
|
||
- `webSDK.openConference` — вне окна времени приёма.
|
||
|
||
### 4.6. Авторизация внутри iframe (`#iframeProtocol`) — не должна появляться
|
||
|
||
**Симптом:** пользователь уже в ЛК, но в модальном окне «Онлайн приём» или «Оплата» внутри iframe просят войти снова.
|
||
|
||
**Причина:** две независимые сессии:
|
||
|
||
| Сессия | Где хранится | За что отвечает |
|
||
|--------|--------------|-----------------|
|
||
| Symfony (`ROLE_USER`) | cookie `cabinet.sovamed.ru` | `/case-history`, `/online-specialists` |
|
||
| MIS / webSDK | cookie `widget.sovamed.ru` + скрытый iframe `/sdk` | `openConference`, `loadPaymentView`, `scheduleRecReserve` |
|
||
|
||
Symfony может быть активна, а MIS — нет (истёк timeout, другой браузер, блокировка third-party cookies).
|
||
|
||
**Где iframe:**
|
||
|
||
| Действие | Метод SDK | Элемент |
|
||
|----------|-----------|---------|
|
||
| «Онлайн приём» | `openConference()` | `#iframeProtocol` — URL видеоконференции |
|
||
| Вход через Госуслуги | `loadLoginView()` | `#iframeProtocol` — **ожидаемо** показывает login |
|
||
| Оплата | `loadPaymentView()` | виджет ЮKassa в `#popup-body` (не login-iframe) |
|
||
|
||
**Исправление в коде (cabinet):**
|
||
|
||
- `assets/components/misSession.js` — проверка `webSDK.data.user.authenticated` / `isLoggedIn()` перед оплатой и конференцией.
|
||
- `caseHistory_controller.js` — `openConference` **без** `container` (DOM-элемент ломал SDK `eval(container)` и пропускал Guest URL); iframe переносится в popup через `mountConferenceInPopup()`.
|
||
- При протухшей MIS-сессии — popup «Войти снова» → `/logout`, а не форма login внутри iframe.
|
||
|
||
**Проверка в браузере (prod):**
|
||
|
||
```javascript
|
||
// на /case-history, до клика «Онлайн приём»
|
||
window.webSDK?.data?.user?.authenticated // должно быть true
|
||
```
|
||
|
||
```bash
|
||
# Symfony-сессия (smoke-скрипт)
|
||
curl -b cookies.txt https://cabinet.sovamed.ru/api/userInfo
|
||
# → {"data":"<uid>"} — это НЕ гарантия MIS-сессии
|
||
```
|
||
|
||
**Smoke:**
|
||
|
||
```bash
|
||
make local-online-smoke
|
||
# шаги 9–10: UI-маркеры case-history, /api/userInfo, доступность MIS SDK
|
||
```
|
||
|
||
### 4.7. MIS / Infoclinica
|
||
|
||
Env: `MIS=https://widget.sovamed.ru` в [`apps/cabinet/.env`](../../apps/cabinet/.env).
|
||
|
||
Публичный DNS: CNAME `production.infoclinica.ru` → `217.74.42.159` (не путать с внутренними IP вроде `10.34.23.239`).
|
||
|
||
---
|
||
|
||
## 5. Тесты
|
||
|
||
### Shell smoke (Docker local)
|
||
|
||
```bash
|
||
make local-up
|
||
make local-online-smoke
|
||
```
|
||
|
||
Скрипт: [`scripts/online-consultation-smoke.sh`](../../scripts/online-consultation-smoke.sh)
|
||
|
||
### Pytest e2e
|
||
|
||
```bash
|
||
./scripts/run-online-consultation-pytest.sh
|
||
```
|
||
|
||
Каталог: [`tests/e2e/online_consultation/`](../../tests/e2e/online_consultation/)
|
||
|
||
### PHPUnit (cabinet)
|
||
|
||
```bash
|
||
make cabinet-test
|
||
# или
|
||
docker exec php82-local php bin/phpunit tests/Unit tests/Controller
|
||
```
|
||
|
||
- `tests/Unit/Support/OnlineModeTest.php` — нормализация `0/1/true/false`
|
||
- `tests/Controller/OnlineSpecialistsControllerTest.php` — auth на `/online-specialists`
|
||
|
||
---
|
||
|
||
## 6. Чеклист диагностики на prod
|
||
|
||
1. Пользователь залогинен? `/online-specialists` без login → redirect.
|
||
2. Есть онлайн-локации в БД? `location_view.online_mode = true`.
|
||
3. `docker exec php84 php bin/console upload:doctors 1` — без ошибок?
|
||
4. `/api/interval?...&onlineMode=1` — HTTP 200 и `intervalsData`?
|
||
5. В браузере загружен `webSDK`? Console → нет 404 на `sdk.build.min.js`.
|
||
6. `/case-history` — запись с `onlineType`, статус оплаты?
|
||
7. **До «Онлайн приём»:** `window.webSDK.data.user.authenticated === true`? Если `false` — MIS-сессия протухла (см. §4.6).
|
||
8. Iframe `#iframeProtocol`: `src` — URL конференции, а не `/login`?
|
||
|
||
---
|
||
|
||
## 7. Ключевые файлы
|
||
|
||
| Файл | Роль |
|
||
|------|------|
|
||
| `src/Controller/SpecialistController.php` | `/online-specialists` |
|
||
| `src/Controller/PublicAPIController.php` | `/api/interval` |
|
||
| `src/Repository/SpecialistViewRepository.php` | фильтр `onlineMode` |
|
||
| `src/Support/OnlineMode.php` | нормализация флага |
|
||
| `assets/components/record.js` | запись, `onlineType` |
|
||
| `assets/components/misSession.js` | проверка MIS-сессии, mount iframe конференции |
|
||
| `assets/controllers/caseHistory_controller.js` | оплата, конференция |
|
||
| `assets/components/loader.js` | загрузка SDK |
|
||
| `templates/specialist/_item.html.twig` | карточка врача |
|