fix bug editor block

This commit is contained in:
2026-08-09 22:38:14 +03:00
parent 4ba9dd8012
commit b0ee07823e
9 changed files with 710 additions and 1114 deletions
+7 -3
View File
@@ -30,6 +30,10 @@
- [x] 5.5 Удалить react-scripts
## Этап 6: Проверка
- [ ] 6.1 npm install для backend и frontend
- [ ] 6.2 npm run build для frontend
- [ ] 6.3 Запуск backend
- [x] 6.1 npm install для backend и frontend
- [x] 6.2 npm run build для frontend (Vite 8, 503ms)
- [x] 6.3 Запуск backend
## Этап 7: Синхронизация версий Vite (после реструктуризации)
- [x] 7.1 frontend обновлён до Vite 8.2.1 + plugin-react 6.0.5 (совпадение с admin-frontend)
- [x] 7.2 Сборка frontend подтверждена (621 kB, gzip 187 kB, 503ms)
+1
View File
@@ -3,6 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="https://cdn.quilljs.com/1.3.6/quill.snow.css" />
<title>Admin Frontend</title>
</head>
<body>
+44 -38
View File
@@ -1,4 +1,5 @@
import React, { useState, useEffect, useRef, useCallback } from 'react';
import 'quill/dist/quill.snow.css';
import '../App.css';
import DOMPurify from 'dompurify';
@@ -14,7 +15,7 @@ function Editor() {
const [editContent, setEditContent] = useState('');
const [editPreviewContent, setEditPreviewContent] = useState('');
const [showConfirmModal, setShowConfirmModal] = useState(false);
const [csrfToken, setCsrfToken] = useState('');
//const [csrfToken, setCsrfToken] = useState('');
const [notify, setNotify] = useState({ message: '', type: '', show: false });
const editorRef = useRef(null);
@@ -30,14 +31,14 @@ function Editor() {
}, []);
// Fetch CSRF token
useEffect(() => {
fetch('/moders/csrf-token')
.then(res => res.json())
.then(data => {
setCsrfToken(data.csrfToken);
})
.catch(() => {});
}, []);
//useEffect(() => {
// fetch('/moders/csrf-token')
// .then(res => res.json())
// .then(data => {
// setCsrfToken(data.csrfToken);
//})
//.catch(() => {});
//}, []);
// Check session on mount
useEffect(() => {
@@ -53,13 +54,9 @@ function Editor() {
.catch(() => setIsLoggedIn(false));
}, []); // eslint-disable-line react-hooks/exhaustive-deps
const authenticatedFetch = useCallback((url, options = {}) => {
if (!options.headers) options.headers = {};
if (options.method && ['POST', 'PUT', 'DELETE'].includes(options.method.toUpperCase())) {
options.headers['x-csrf-token'] = csrfToken;
}
return fetch(url, options);
}, [csrfToken]);
const authenticatedFetch = useCallback((url, options = {}) => {
return fetch(url, options);
}, []);
const loadBlocks = useCallback(async (tab) => {
try {
@@ -140,32 +137,41 @@ function Editor() {
};
const handleSaveBlock = async (e) => {
e.preventDefault();
const content = DOMPurify.sanitize(editContent.trim());
if (!content || content === '<p><br></p>') return;
e.preventDefault();
const content = DOMPurify.sanitize(editContent.trim());
if (!content || content === '<p><br></p>') return;
try {
if (editingBlockId) {
await authenticatedFetch(`/moders/content/${activeTab}/${editingBlockId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ type: 'text', content })
});
showNotify('Блок обновлён', 'success');
} else {
await authenticatedFetch(`/moders/content/${activeTab}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ type: 'text', content })
});
showNotify('Блок добавлен', 'success');
}
const url = editingBlockId
? `/moders/content/${activeTab}/${editingBlockId}`
: `/moders/content/${activeTab}`;
const method = editingBlockId ? 'PUT' : 'POST';
console.log('➡️ Отправка:', method, url, { type: 'text', content });
try {
const response = await fetch(url, {
method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ type: 'text', content })
});
const data = await response.json();
console.log('⬅️ Ответ сервера:', response.status, data);
if (response.ok) {
showNotify(editingBlockId ? 'Блок обновлён' : 'Блок добавлен', 'success');
setShowEditModal(false);
loadBlocks(activeTab);
} catch (e) {
showNotify('Ошибка сохранения', 'error');
} else {
showNotify(`Ошибка: ${data.message || response.status}`, 'error');
}
};
} catch (e) {
console.error('❌ Ошибка при сохранении:', e);
showNotify('Ошибка сохранения', 'error');
}
};
const handleTryCloseEditModal = () => {
if (editContent !== originalContentRef.current) {
+9 -9
View File
@@ -3,15 +3,15 @@ import '../App.css';
// CSRF token management
let csrfToken = null;
async function fetchCsrfToken() {
try {
const res = await fetch('/moders/csrf-token', { credentials: 'include' });
if (res.ok) {
const data = await res.json();
csrfToken = data.csrfToken;
}
} catch (e) { csrfToken = null; }
}
//async function fetchCsrfToken() {
// try {
// const res = await fetch('/moders/csrf-token', { credentials: 'include' });
// if (res.ok) {
// const data = await res.json();
// csrfToken = data.csrfToken;
// }
//} catch (e) { csrfToken = null; }
//}
async function apiFetch(url, options = {}) {
if (!options.headers) options.headers = {};
+50
View File
@@ -1588,3 +1588,53 @@
[2026-08-09T17:57:08.445Z] [INFO] [LOGIN] Результат сравнения пароля: true
[2026-08-09T17:57:08.446Z] [INFO] [LOGIN] Сессия установлена: {"isModerator":true,"userId":4,"username":"vova"}
[2026-08-09T17:57:08.447Z] [INFO] [LOGIN] Ответ отправлен
[2026-08-09T19:05:03.523Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:05:03.527Z] [INFO] Card logs initialized successfully
[2026-08-09T19:05:12.014Z] [INFO] [DB CHECK] Проверка подключения к MySQL: localhost:3306/rasch_content
[2026-08-09T19:05:12.048Z] [INFO] [DB CHECK] ✅ Успешное подключение к MySQL
[2026-08-09T19:05:12.093Z] [ERROR] [DB CHECK] ❌ Ошибка связи с бэкендом: connect ECONNREFUSED 127.0.0.1:3001; connect ECONNREFUSED ::1:3001
[2026-08-09T19:10:18.966Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:10:18.970Z] [INFO] Card logs initialized successfully
[2026-08-09T19:11:58.219Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:11:58.223Z] [INFO] Card logs initialized successfully
[2026-08-09T19:12:24.042Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:12:24.045Z] [INFO] Card logs initialized successfully
[2026-08-09T19:13:05.537Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:13:05.540Z] [INFO] Card logs initialized successfully
[2026-08-09T19:14:14.837Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:14:14.842Z] [INFO] Card logs initialized successfully
[2026-08-09T19:19:29.874Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:19:29.880Z] [INFO] Card logs initialized successfully
[2026-08-09T19:20:26.539Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:20:26.543Z] [INFO] Card logs initialized successfully
[2026-08-09T19:21:13.450Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:21:13.456Z] [INFO] Card logs initialized successfully
[2026-08-09T19:24:43.343Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:24:43.347Z] [INFO] Card logs initialized successfully
[2026-08-09T19:24:47.081Z] [ERROR] Error: ENOENT: no such file or directory, stat 'D:\rasch\admin-frontend\build\index.html'
[2026-08-09T19:24:47.308Z] [ERROR] Error: ENOENT: no such file or directory, stat 'D:\rasch\admin-frontend\build\index.html'
[2026-08-09T19:25:15.162Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:25:15.167Z] [INFO] Card logs initialized successfully
[2026-08-09T19:25:51.739Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:25:51.743Z] [INFO] Card logs initialized successfully
[2026-08-09T19:26:23.916Z] [INFO] [DB CHECK] Проверка подключения к MySQL: localhost:3306/rasch_content
[2026-08-09T19:26:23.932Z] [INFO] [DB CHECK] ✅ Успешное подключение к MySQL
[2026-08-09T19:26:36.976Z] [INFO] [LOGIN] Попытка входа: vova
[2026-08-09T19:26:36.980Z] [INFO] [LOGIN] Проверка подключения к базе...
[2026-08-09T19:26:36.991Z] [INFO] [LOGIN] Результат поиска пользователя: найден
[2026-08-09T19:26:36.993Z] [INFO] [LOGIN] Сравнение пароля через bcrypt...
[2026-08-09T19:26:37.333Z] [INFO] [LOGIN] Результат сравнения пароля: true
[2026-08-09T19:26:37.335Z] [INFO] [LOGIN] Сессия установлена: {"isModerator":true,"userId":4,"username":"vova"}
[2026-08-09T19:26:37.338Z] [INFO] [LOGIN] Ответ отправлен
[2026-08-09T19:29:13.173Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:29:13.178Z] [INFO] Card logs initialized successfully
[2026-08-09T19:30:13.482Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:30:13.486Z] [INFO] Card logs initialized successfully
[2026-08-09T19:32:50.665Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:32:50.668Z] [INFO] Card logs initialized successfully
[2026-08-09T19:34:06.656Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:34:06.660Z] [INFO] Card logs initialized successfully
[2026-08-09T19:34:39.788Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:34:39.791Z] [INFO] Card logs initialized successfully
[2026-08-09T19:36:51.312Z] [INFO] Server running on http://localhost:3005
[2026-08-09T19:36:51.318Z] [INFO] Card logs initialized successfully
+4
View File
@@ -47,6 +47,10 @@ app.use('/api/health', healthRouter);
app.use('/api/monitoring', monitoringRouter);
app.use('/moders', moderAuthRouter);
app.use('/moders/content', moderContentRouter);
app.use((req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
next();
});
// Initialize card logs
(async () => {
try {
+586 -1056
View File
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -69,13 +69,13 @@
"devDependencies": {
"@types/jest": "^29.5.14",
"@types/node": "^26.2.0",
"@vitejs/plugin-react": "^4.7.0",
"concurrently": "^7.5.0",
"electron": "^37.0.0",
"electron-builder": "^26.15.3",
"electron-rebuild": "^3.2.9",
"vite": "^6.0.0",
"vitest": "^2.1.8",
"wait-on": "^6.0.1"
"@vitejs/plugin-react":"^6.0.5",
"concurrently":"^7.5.0",
"electron":"^37.0.0",
"electron-builder":"^26.15.3",
"electron-rebuild":"^3.2.9",
"vite":"^8.2.1",
"vitest":"^2.1.8",
"wait-on":"^6.0.1"
}
}
+1
View File
@@ -0,0 +1 @@
{"root":["./src/app.test.tsx","./src/app.tsx","./src/config.js","./src/global.d.ts","./src/index.tsx","./src/r5usb.js","./src/r5usb_example.js","./src/react-app-env.d.ts","./src/reportwebvitals.ts","./src/setuptests.ts","./src/components/employeeinfo.tsx","./src/components/guestmode.tsx","./src/components/loginwindow.tsx","./src/components/payslipviewer.tsx","./vite.config.js"],"version":"5.9.3"}