191 lines
8.0 KiB
TypeScript
Executable File
191 lines
8.0 KiB
TypeScript
Executable File
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;
|
||
},
|
||
};
|