================================================================================ АРХИТЕКТУРНЫЙ СЛЕПОК СИСТЕМЫ ПРИЛОЖЕНИЯ «МОЙ ЖКХ» v3.0 (ДЛЯ ОБНОВЛЕНИЯ КОНТЕКСТА) ================================================================================ 1. СЕТЕВОЙ СЛОЙ (api.ts): - Эндпоинт: http://90.188.226 - Методы RPC: * login(account,password,registerData?) -> POST action:'LOGIN' * getBalance(account) -> POST action:'GET_DATA' * sendMeters(account,meterId,value) -> POST action:'SEND_METERS' * getMonthDetails(account,period) -> POST action:'GET_MONTH_DETAILS' * getReceiptPdf(account,period) -> POST action:'GET_RECEIPT_PDF' 2. АВТОРИЗАЦИЯ, БИОМЕТРИЯ И ФОЛБЭК СЕССИИ (App.tsx): - При старте в checkAutoLogin() заложена задержка 150мс для Android (устраняет Race Condition в .apk), затем асинхронно читается AsyncStorage, а при его пустоте — SecureStore. - При успехе SplashScreen.hideAsync() тушит заставку, затем через 350мс вызывается LocalAuthentication.authenticateAsync со свойствами: disableDeviceFallback: Platform.OS==='ios', fallbackLabel: Platform.OS==='ios'?"":"Использовать код устройства". - В handleLoginSuccess() из-за сбоев Keystore Android приоритет смещен вверх: сначала пишется AsyncStorage, затем изолированным блоком try-catch пишется SecureStore. Метод handleLogout() стирает данные из обоих хранилищ. 3. ИНТЕРФЕЙС И РУЧНАЯ РЕГИСТРАЦИЯ (AuthScreen.tsx): - Ссылка registerToggleBtn переключает стейт showRegisterFields, плавно раскрывая анкету (Фамилия, Имя, Отчество, Телефон). Поле Лицевого счета всегда editable={true}. - Интегрированы типы автозаполнения: autoComplete="username"/"current-password"/"new-password", importantForAutofill="yes", textContentType="username"/"password"/"newPassword". - В функции handleLogin первой строкой вызывается Keyboard.dismiss() для корректного перехвата связки паролей менеджерами Google Autofill и iOS Keychain. 4. ДЕТАЛИЗАЦИЯ И СХЛОПЫВАНИЕ ОДН/СОИ (HomeScreen.tsx): - Стейт баланса: const [balanceData,setBalanceData]=useState<{has_data:boolean;total_charged:string;jkh_charged:string;repair_charged:string;balance_value:string;} | null>(null); - Если has_data===false -> плашка styles.noChargesBanner ("Начисления за текущий месяц еще не сформированы..."). Если true -> раскрывается детальная карточка. Текущий остаток (balance_value) выводится всегда из истории. - Алгоритм группировки (monthDetails.services): парсит строки в числа (replace(',','.')). Если имя содержит 'сои' или 'одн' -> флаг isSoi=true. Очищает baseName от мусора и объединяет дубликаты ГВС, ХВС, Водоотведения. Формирует объект groupedServices: {[baseName]:{name,volume,tariff,cost,soiCost,unit}}. Цена = cost + soiCost. Тариф ГВС скрыт. - Pull-to-Refresh реализован через скрытый . Кастомная капсула лоадера и тост-уведомление зафиксированы вне ScrollView на отметке top: 80 (ниже челки iPhone). 5. СЕРВЕРНАЯ ЛОГИКА 1С (Общий модуль жкх_МобильноеПриложениеСервер): - ПолучитьДанныеЛицевогоСчета(ЛицевойСчет): Поиск в Справочники.КВП_ЛицевыеСчета по "Идентификатор". Запрос по УПЖКХ_Начисления за текущий месяц группирует суммы по ВЫБОР КОГДА Наименование ПОДОБНО "%Капитальный ремонт%" ИЛИ "%Капремонт%" ТОГДА "Капремонт" ИНАЧЕ "Коммунальные" КОНЕЦ. Наполняет total_charged, jkh_charged, repair_charged. Флаг has_data=(ВсегоНачислено>0). Блок Истории: запрос к .Обороты КВП_ВзаиморасчетыПоЛицевымСчетам левым соединением с .Остатки выводит КонечныйОстаток как честное накопительное переходящее сальдо. Верхний balance_value берется из первой строки History.balance. - ПолучитьДетализациюЗаМесяц(ЛицевойСчет,ПериодСтрока): Выбирает строки из УПЖКХ_Начисления, подтягивая Услуга.ЕдиницаИзмерения.Наименование КАК ЕдИзм. Возвращает массив Services (name,volume,tariff,cost,unit). В ЕдинаяТочкаВходаapiPOST ключи переводятся в нижний регистр ("services", "payments"). - СформироватьКвитанциюВPDF(ЛицевойСчетКод,ПериодСтрока): Генерирует ТабличныйДокумент через Отчеты.УПЖКХ_ПлатёжныйДокумент.СформироватьПечатнуюФорму, сохраняет в PDF, считывает в ДвоичныеДанные и возвращает Base64Строка(). ================================================================================