// Базовый URL API (берётся из внешнего config.js) const API_BASE = window.APP_CONFIG?.API_BASE || '' // Формирование полного URL (добавляет домен к относительным путям) export const getFullUrl = (url) => { if (!url) return '' if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith('data:')) { return url } return API_BASE + url } // Базовая функция запроса const request = async (endpoint, options = {}) => { const res = await fetch(`${API_BASE}${endpoint}`, options) return res.json() } // ==================== AUTH ==================== export const authApi = { login: (username, password) => request('/api/user', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'auth_login', username, password }) }), check: () => request('/api/user', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'check_session' }) }), logout: () => request('/api/user', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'logout' }) }) } // ==================== PROJECTS ==================== export const projectsApi = { // active: ID проекта для загрузки данных (опционально) getAll: (active = null) => { let url = '/api/project' if (active) url += `?active=${active}` return request(url, { credentials: 'include' }) }, // Получение данных проекта (проект + колонки + отделы) — один запрос вместо трёх getData: (id_project) => request('/api/project', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'get_project_data', id_project }) }), create: (data) => request('/api/project', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'create', ...data }) }), update: (data) => request('/api/project', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'update', ...data }) }), delete: (id) => request('/api/project', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'delete', id }) }), setReadyColumn: (id_project, column_id) => request('/api/project', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'set_ready_column', id_project, column_id }) }) } // ==================== CARDS ==================== export const cardsApi = { // id_project: ID проекта (обязательный) // archive: 0 = неархивные (по умолчанию), 1 = архивные, 'all' = все getAll: (id_project, archive = 0) => { let url = `/api/task?id_project=${id_project}` if (archive !== 0) url += `&archive=${archive}` return request(url, { credentials: 'include' }) }, updateOrder: (id, column_id, to_index) => request('/api/task', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'update_order', id, column_id, to_index }) }), create: (data) => request('/api/task', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'create', ...data }) }), update: (data) => request('/api/task', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'update', ...data }) }), delete: (id) => request('/api/task', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'delete', id }) }), setArchive: (id, archive = 1) => request('/api/task', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'set_archive', id, archive }) }) } // ==================== TASK IMAGES ==================== export const taskImageApi = { upload: (task_id, file_data, file_name) => request('/api/task', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'upload_image', task_id, file_data, file_name }) }), // Принимает строку (один файл) или массив (несколько файлов) delete: (task_id, file_names) => request('/api/task', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'delete_image', task_id, file_names }) }) } // ==================== USERS ==================== export const usersApi = { getAll: () => request('/api/user', { credentials: 'include' }) }