328 lines
9.7 KiB
JavaScript
328 lines
9.7 KiB
JavaScript
import { Config } from '../conf/config';
|
|
|
|
export function openTaskSocket(taskId, onMessage) {
|
|
try {
|
|
const base = Config.API_URL || window.location.origin;
|
|
const wsBase = base.replace(/^http/i, 'ws');
|
|
const url = `${wsBase}/ws/tasks/${taskId}`;
|
|
const ws = new WebSocket(url);
|
|
ws.onmessage = (evt) => {
|
|
try {
|
|
onMessage && onMessage(JSON.parse(evt.data));
|
|
} catch (error) {
|
|
console.error('Ошибка подключения', error);
|
|
}
|
|
};
|
|
return ws;
|
|
} catch (error) {
|
|
console.error(error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export const connectToTable = (tableId, userId, options = {}) => {
|
|
const { onError, onClose } = options;
|
|
|
|
const baseURL = Config.API_URL.replace('http://', 'ws://').replace(
|
|
'https://',
|
|
'wss://',
|
|
);
|
|
const wsURL = `${baseURL}/api/v1/ws/${tableId}?user_id=${userId}`;
|
|
|
|
const ws = new WebSocket(wsURL);
|
|
|
|
const eventHandlers = {
|
|
cell_edit_start: [],
|
|
cell_edit_end: [],
|
|
cell_updated: [],
|
|
row_added: [],
|
|
row_deleted: [],
|
|
formula_updated: [],
|
|
formula_manual: [],
|
|
formula_recalculate: [],
|
|
};
|
|
|
|
ws.onerror = (error) => {
|
|
console.error('Ошибка WebSocket:', error);
|
|
if (onError) {
|
|
onError(error);
|
|
}
|
|
};
|
|
|
|
ws.onclose = (event) => {
|
|
console.log(
|
|
`Отключено от таблицы ${tableId}. Код: ${event.code}, причина: ${event.reason}`,
|
|
);
|
|
if (onClose) {
|
|
onClose(event);
|
|
}
|
|
};
|
|
|
|
ws.onmessage = (event) => {
|
|
const raw = event.data;
|
|
let message;
|
|
|
|
try {
|
|
message = JSON.parse(raw);
|
|
} catch (_err) {
|
|
try {
|
|
let fixed = raw
|
|
.replace(/'/g, '"')
|
|
.replace(/\bNone\b/g, 'null')
|
|
.replace(/\bTrue\b/g, 'true')
|
|
.replace(/\bFalse\b/g, 'false');
|
|
|
|
if (fixed.includes('BasicFormulaDependancy')) {
|
|
fixed = fixed.replace(
|
|
/"dependancies"\s*:\s*\[\[[\s\S]*?\]\]/,
|
|
'"dependancies":[[]]',
|
|
);
|
|
}
|
|
|
|
message = JSON.parse(fixed);
|
|
} catch (error) {
|
|
console.error('Ошибка парсинга сообщения WebSocket:', error, raw);
|
|
return;
|
|
}
|
|
}
|
|
|
|
const { event: eventName, data, error, result } = message;
|
|
if (eventHandlers[eventName]) {
|
|
const base = data || {};
|
|
const payload = {
|
|
...base,
|
|
...(result !== undefined ? { result } : {}),
|
|
...(error !== undefined ? { error } : {}),
|
|
};
|
|
eventHandlers[eventName].forEach((handler) => handler(payload));
|
|
}
|
|
};
|
|
|
|
return {
|
|
ws,
|
|
disconnect: () => {
|
|
ws.close();
|
|
},
|
|
|
|
// Начало редактирования ячейки
|
|
startEditCell: (cellKey) => {
|
|
if (ws.readyState === WebSocket.OPEN) {
|
|
const message = JSON.stringify({
|
|
event: 'cell_edit_start',
|
|
data: {
|
|
cell_key: cellKey,
|
|
user_id: userId,
|
|
},
|
|
});
|
|
ws.send(message);
|
|
}
|
|
},
|
|
|
|
// Завершение редактирования ячейки
|
|
endEditCell: (cellKey) => {
|
|
if (ws.readyState === WebSocket.OPEN) {
|
|
const message = JSON.stringify({
|
|
event: 'cell_edit_end',
|
|
data: {
|
|
cell_key: cellKey,
|
|
user_id: userId,
|
|
},
|
|
});
|
|
ws.send(message);
|
|
}
|
|
},
|
|
|
|
// Подписка на событие начала редактирования ячейки другим пользователем
|
|
onCellEditStart: (callback) => {
|
|
eventHandlers.cell_edit_start.push(callback);
|
|
},
|
|
offCellEditStart: (callback) => {
|
|
eventHandlers.cell_edit_start = eventHandlers.cell_edit_start.filter(
|
|
(cb) => cb !== callback,
|
|
);
|
|
},
|
|
|
|
// Подписка на событие завершения редактирования ячейки другим пользователем
|
|
onCellEditEnd: (callback) => {
|
|
eventHandlers.cell_edit_end.push(callback);
|
|
},
|
|
offCellEditEnd: (callback) => {
|
|
eventHandlers.cell_edit_end = eventHandlers.cell_edit_end.filter(
|
|
(cb) => cb !== callback,
|
|
);
|
|
},
|
|
|
|
// Обновление значения ячейки (отправка нового значения другим пользователям)
|
|
updateCellValue: (cellKey, newValue, cellType, cellColor) => {
|
|
const [columnId, rowId] = cellKey.split('_');
|
|
if (ws.readyState === WebSocket.OPEN) {
|
|
const message = JSON.stringify({
|
|
event: 'cell_updated',
|
|
data: {
|
|
row: Number(rowId) + 1,
|
|
header_id: Number(columnId),
|
|
cell_key: cellKey,
|
|
color: cellColor,
|
|
value: newValue,
|
|
type: cellType,
|
|
},
|
|
});
|
|
ws.send(message);
|
|
}
|
|
},
|
|
|
|
// Подписка на событие обновления значения ячейки другим пользователем
|
|
onCellValueUpdated: (callback) => {
|
|
eventHandlers.cell_updated.push(callback);
|
|
},
|
|
offCellValueUpdated: (callback) => {
|
|
eventHandlers.cell_updated = eventHandlers.cell_updated.filter(
|
|
(cb) => cb !== callback,
|
|
);
|
|
},
|
|
|
|
// Добавление строки (отправка события другим пользователям)
|
|
addRow: (rowIndex) => {
|
|
if (ws.readyState === WebSocket.OPEN) {
|
|
const message = JSON.stringify({
|
|
event: 'row_added',
|
|
data: {
|
|
row_index: rowIndex,
|
|
user_id: userId,
|
|
},
|
|
});
|
|
ws.send(message);
|
|
}
|
|
},
|
|
|
|
// Подписка на событие добавления строки другим пользователем
|
|
onRowAdded: (callback) => {
|
|
eventHandlers.row_added.push(callback);
|
|
},
|
|
offRowAdded: (callback) => {
|
|
eventHandlers.row_added = eventHandlers.row_added.filter(
|
|
(cb) => cb !== callback,
|
|
);
|
|
},
|
|
|
|
// Удаление строки (отправка события другим пользователям)
|
|
deleteRow: (rowIndex) => {
|
|
if (ws.readyState === WebSocket.OPEN) {
|
|
const message = JSON.stringify({
|
|
event: 'row_deleted',
|
|
data: {
|
|
row_index: rowIndex,
|
|
user_id: userId,
|
|
},
|
|
});
|
|
ws.send(message);
|
|
}
|
|
},
|
|
|
|
// Подписка на событие удаления строки другим пользователем
|
|
onRowDeleted: (callback) => {
|
|
eventHandlers.row_deleted.push(callback);
|
|
},
|
|
offRowDeleted: (callback) => {
|
|
eventHandlers.row_deleted = eventHandlers.row_deleted.filter(
|
|
(cb) => cb !== callback,
|
|
);
|
|
},
|
|
|
|
// Обновление цвета ячейки
|
|
updateCellColor: (cellKey, color, cellType, cellValue) => {
|
|
const [columnId, rowId] = cellKey.split('_');
|
|
if (ws.readyState === WebSocket.OPEN) {
|
|
const message = JSON.stringify({
|
|
event: 'cell_updated',
|
|
data: {
|
|
row: Number(rowId) + 1,
|
|
header_id: Number(columnId),
|
|
cell_key: cellKey,
|
|
color,
|
|
type: cellType,
|
|
value: cellValue,
|
|
},
|
|
});
|
|
ws.send(message);
|
|
}
|
|
},
|
|
|
|
// Добавление/обновление формулы (отправка события другим пользователям)
|
|
updateFormula: (cellKey, type, value, formula) => {
|
|
const [columnId, rowId] = cellKey.split('_');
|
|
if (ws.readyState === WebSocket.OPEN) {
|
|
const message = JSON.stringify({
|
|
event: 'formula_updated',
|
|
data: {
|
|
cell_key: cellKey,
|
|
row: Number(rowId),
|
|
header_id: Number(columnId),
|
|
type,
|
|
value,
|
|
formula,
|
|
user_id: userId,
|
|
},
|
|
});
|
|
ws.send(message);
|
|
}
|
|
},
|
|
|
|
// Подписка на событие добавления/обновления формулы другим пользователем
|
|
onFormulaUpdated: (callback) => {
|
|
eventHandlers.formula_updated.push(callback);
|
|
},
|
|
offFormulaUpdated: (callback) => {
|
|
eventHandlers.formula_updated = eventHandlers.formula_updated.filter(
|
|
(cb) => cb !== callback,
|
|
);
|
|
},
|
|
|
|
// Ручное добавление формулы (отправка события другим пользователям)
|
|
formulaManual: (formulaDatas) => {
|
|
if (ws.readyState === WebSocket.OPEN) {
|
|
const message = JSON.stringify({
|
|
event: 'formula_manual',
|
|
data: {
|
|
formula_datas: formulaDatas,
|
|
},
|
|
});
|
|
ws.send(message);
|
|
}
|
|
},
|
|
|
|
// Подписка на результат ручного добавления формулы
|
|
onFormulaManual: (callback) => {
|
|
eventHandlers.formula_manual.push(callback);
|
|
},
|
|
offFormulaManual: (callback) => {
|
|
eventHandlers.formula_manual = eventHandlers.formula_manual.filter(
|
|
(cb) => cb !== callback,
|
|
);
|
|
},
|
|
|
|
// Пересчёт формул (отправка события другим пользователям / на бэкенд)
|
|
formulaRecalculate: (formulaDatas, cells) => {
|
|
if (ws.readyState === WebSocket.OPEN) {
|
|
const message = JSON.stringify({
|
|
event: 'formula_recalculate',
|
|
data: {
|
|
formula_datas: formulaDatas,
|
|
cells,
|
|
},
|
|
});
|
|
ws.send(message);
|
|
}
|
|
},
|
|
|
|
// Подписка на результат пересчёта формул
|
|
onFormulaRecalculate: (callback) => {
|
|
eventHandlers.formula_recalculate.push(callback);
|
|
},
|
|
offFormulaRecalculate: (callback) => {
|
|
eventHandlers.formula_recalculate =
|
|
eventHandlers.formula_recalculate.filter((cb) => cb !== callback);
|
|
},
|
|
};
|
|
};
|