Files
mkd/services/domaService.ts

191 lines
8.0 KiB
TypeScript
Raw Permalink Normal View History

2026-02-04 00:17:04 +05:00
import { DomaApplication, DomaApplicationStatus } from '../types';
import { backendApi } from './apiClient';
import { domaGraphQLClient, DomaTicket } from './domaGraphQLClient';
import { settingsService } from './settingsService';
/**
* Сервис для работы с Doma AI API
* Интегрирует GraphQL API Doma AI для получения заявок
*/
export const domaService = {
/**
* Инициализация подключения к Doma AI
* Выполняет аутентификацию, если токен не сохранен
* Использует настройки из localStorage или переменные окружения как fallback
*/
async initialize(): Promise<boolean> {
// Обновляем настройки в клиенте
domaGraphQLClient.updateSettings();
// Получаем настройки из localStorage
const settings = settingsService.getDomaAISettings();
// Проверяем, настроен ли URL API (из настроек или переменных окружения)
const apiUrl = settings?.apiUrl || import.meta.env.VITE_DOMA_AI_API_URL;
if (!apiUrl) {
console.warn(
'[domaService] URL API Doma AI не настроен. ' +
'Укажите URL в настройках интеграций или в переменных окружения.'
);
return false;
}
// Если в настройках уже есть токен, просто используем его (без health-check запроса)
if (settings?.token) {
domaGraphQLClient.setToken(settings.token);
return true;
}
// Если токен уже есть в клиенте, считаем, что авторизация настроена
if (domaGraphQLClient.hasToken()) {
return true;
}
// Пытаемся получить учетные данные из настроек или переменных окружения
const email = settings?.email || import.meta.env.VITE_DOMA_AI_EMAIL;
const password = settings?.password || import.meta.env.VITE_DOMA_AI_PASSWORD;
const phone = settings?.phone || import.meta.env.VITE_DOMA_AI_PHONE;
if (!email && !phone) {
console.warn(
'[domaService] Учетные данные Doma AI не настроены. ' +
'Укажите email/телефон и пароль в настройках интеграций или в переменных окружения.'
);
return false;
}
if (!password) {
console.warn('[domaService] Пароль Doma AI не настроен. Укажите пароль в настройках интеграций.');
return false;
}
try {
if (email && password) {
await domaGraphQLClient.authenticate(email, password);
} else if (phone && password) {
await domaGraphQLClient.authenticateWithPhone(phone, password);
} else {
return false;
}
return true;
} catch (error) {
console.error('[domaService] Ошибка авторизации в Doma AI:', error);
return false;
}
},
/**
* Преобразует заявку из формата Doma AI в формат приложения
*/
mapDomaTicketToApplication(ticket: DomaTicket): DomaApplication {
// Маппинг статусов Doma AI в статусы приложения
const statusMap: Record<string, DomaApplicationStatus> = {
'new': 'new',
'in_progress': 'in_progress',
'inProgress': 'in_progress',
'done': 'done',
'completed': 'done',
'canceled': 'canceled',
'cancelled': 'canceled',
};
const statusType = ticket.status?.type?.toLowerCase() || ticket.status?.name?.toLowerCase() || 'new';
const mappedStatus = statusMap[statusType] || 'new';
return {
id: parseInt(ticket.id) || Date.now(), // Если ID не число, используем timestamp
number: ticket.number || ticket.id,
status: mappedStatus,
description: ticket.description || ticket.details || 'Без описания',
address: ticket.property?.address || 'Адрес не указан',
apartment: ticket.property?.unitName || '—',
clientName: ticket.client?.name || 'Клиент не указан',
createdAt: ticket.createdAt || new Date().toISOString(),
deadlineAt: ticket.deadline || new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(), // По умолчанию +7 дней
performer: ticket.assignee ? { name: ticket.assignee.name } : undefined,
};
},
/**
* Получает список заявок из Doma AI
* @param filters - Фильтры для запроса заявок
* @returns Массив заявок в формате приложения
*/
async getApplications(filters?: {
status?: DomaApplicationStatus;
limit?: number;
}): Promise<DomaApplication[]> {
console.log('[domaService] Получение заявок из Doma AI...');
// Проверяем и инициализируем подключение, если нужно
if (!domaGraphQLClient.hasToken()) {
const initialized = await this.initialize();
if (!initialized) {
console.warn('[domaService] Не удалось подключиться к Doma AI, используем fallback');
return this.getApplicationsFallback();
}
}
try {
// Преобразуем фильтры для Doma AI
const domaFilters: any = {};
if (filters?.status) {
// Маппинг статусов обратно (упрощенный вариант)
// В реальности нужно знать ID статусов в Doma AI
domaFilters.status = filters.status;
}
// Получаем заявки из Doma AI
const tickets = await domaGraphQLClient.getTickets({
...domaFilters,
limit: filters?.limit || 100,
});
// Преобразуем в формат приложения
const applications = tickets.map(ticket => this.mapDomaTicketToApplication(ticket));
console.log(`[domaService] Получено ${applications.length} заявок из Doma AI`);
return applications;
} catch (error) {
console.error('[domaService] Ошибка при получении заявок из Doma AI:', error);
// Fallback: пробуем получить из бэкенда
return this.getApplicationsFallback();
}
},
/**
* Fallback метод: получает заявки из бэкенда
* Важно: демо-мок-данные больше не используются, чтобы не путать с реальной интеграцией
*/
async getApplicationsFallback(): Promise<DomaApplication[]> {
try {
console.log('[domaService] Попытка получить заявки из бэкенда...');
const apps = await backendApi.getApplications();
return apps;
} catch (error) {
console.warn('[domaService] Бэкенд недоступен, возвращаем пустой список заявок:', error);
return [];
}
},
/**
* Обновление статуса заявки в Doma AI
* @param ticketId - ID заявки в Doma AI
* @param status - Новый статус
*/
async updateApplicationStatus(ticketId: string, status: DomaApplicationStatus): Promise<boolean> {
if (!domaGraphQLClient.hasToken()) {
const initialized = await this.initialize();
if (!initialized) {
throw new Error('Не удалось авторизоваться в Doma AI');
}
}
// TODO: Реализовать мутацию для обновления статуса заявки
// Это зависит от схемы GraphQL в Doma AI
console.warn('[domaService] Обновление статуса заявки в Doma AI пока не реализовано');
return false;
},
};