fix bug editor block
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 = {};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Generated
+586
-1056
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"}
|
||||
Reference in New Issue
Block a user