Files
minicrm/doc-endpoints.js
2026-01-26 22:55:51 +05:00

953 lines
44 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// doc-endpoints.js
const express = require('express');
const router = express.Router();
const multer = require('multer');
const path = require('path');
const fs = require('fs');
// Middleware для проверки авторизации
const requireAuth = (req, res, next) => {
if (!req.session.user) {
return res.status(401).json({ error: 'Требуется аутентификация' });
}
next();
};
// Настройка загрузки файлов для документов
const storage = multer.diskStorage({
destination: (req, file, cb) => {
const uploadDir = path.join(__dirname, 'data', 'uploads', 'documents');
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}
cb(null, uploadDir);
},
filename: (req, file, cb) => {
const uniqueName = `${Date.now()}-${Math.round(Math.random() * 1E9)}${path.extname(file.originalname)}`;
cb(null, uniqueName);
}
});
const upload = multer({
storage: storage,
limits: { fileSize: 50 * 1024 * 1024 }, // 50MB
fileFilter: (req, file, cb) => {
const allowedTypes = ['.doc', '.docx', '.pdf', '.txt', '.rtf', '.xls', '.xlsx', '.ppt', '.pptx', '.jpg', '.jpeg', '.png'];
const ext = path.extname(file.originalname).toLowerCase();
if (allowedTypes.includes(ext)) {
cb(null, true);
} else {
cb(new Error('Недопустимый тип файла'));
}
}
});
// Вспомогательная функция для логирования действий с документами
function logDocumentActivity(db, documentId, userId, action, changes = '') {
db.run(
"INSERT INTO document_history (document_id, user_id, action, changes) VALUES (?, ?, ?, ?)",
[documentId, userId, action, changes]
);
}
// Получение доступных типов документов для создания
router.get('/api/doc/types', requireAuth, async (req, res) => {
try {
const { getDb } = require('./database');
const db = getDb();
const query = `
SELECT dt.*,
COUNT(DISTINCT a.id) as stages_count
FROM document_types dt
LEFT JOIN approval_stages a ON dt.id = a.document_type_id
GROUP BY dt.id
ORDER BY dt.name
`;
db.all(query, [], (err, types) => {
if (err) {
console.error('Ошибка получения типов документов:', err);
return res.status(500).json({ error: 'Ошибка сервера' });
}
res.json(types);
});
} catch (error) {
console.error('Ошибка:', error);
res.status(500).json({ error: 'Ошибка сервера' });
}
});
// Создание нового документа
router.post('/api/documents', requireAuth, upload.single('file'), async (req, res) => {
try {
const { getDb } = require('./database');
const db = getDb();
const { title, description, document_type_id } = req.body;
const userId = req.session.user.id;
if (!title || !document_type_id) {
return res.status(400).json({ error: 'Название и тип документа обязательны' });
}
if (!req.file) {
return res.status(400).json({ error: 'Файл документа обязателен' });
}
// Проверяем существование типа документа
db.get("SELECT id FROM document_types WHERE id = ?", [document_type_id], (err, docType) => {
if (err || !docType) {
return res.status(400).json({ error: 'Тип документа не найден' });
}
db.serialize(() => {
// Создаем документ
db.run(
`INSERT INTO documents
(title, description, document_type_id, status, created_by,
file_path, file_name, file_size)
VALUES (?, ?, ?, 'draft', ?, ?, ?, ?)`,
[
title,
description || '',
document_type_id,
userId,
req.file.path,
req.file.originalname,
req.file.size
],
function(err) {
if (err) {
console.error('Ошибка создания документа:', err);
return res.status(500).json({ error: 'Ошибка сервера' });
}
const documentId = this.lastID;
// Логируем создание
logDocumentActivity(db, documentId, userId, 'DOCUMENT_CREATED', `Создан документ: ${title}`);
// Получаем этапы согласования для этого типа документа
db.all(
"SELECT * FROM approval_stages WHERE document_type_id = ? ORDER BY stage_number",
[document_type_id],
(err, stages) => {
if (err) {
console.error('Ошибка получения этапов согласования:', err);
return res.status(500).json({ error: 'Ошибка сервера' });
}
// Создаем записи для согласования
if (stages && stages.length > 0) {
stages.forEach(stage => {
// Определяем пользователя для согласования
let approverUserId = stage.approver_user_id;
// Если указана роль, находим пользователя с этой ролью
if (stage.approver_role && !approverUserId) {
db.get(
"SELECT id FROM users WHERE role = ? LIMIT 1",
[stage.approver_role],
(err, user) => {
if (user) {
approverUserId = user.id;
}
createApprovalRecord();
}
);
} else {
createApprovalRecord();
}
function createApprovalRecord() {
if (!approverUserId) {
console.log('⚠️ Не указан согласующий для этапа:', stage.stage_name);
return;
}
// Устанавливаем дедлайн, если указано
let deadline = null;
if (stage.deadline_days) {
deadline = new Date();
deadline.setDate(deadline.getDate() + stage.deadline_days);
}
db.run(
`INSERT INTO document_approvals
(document_id, stage_id, approver_user_id, deadline)
VALUES (?, ?, ?, ?)`,
[documentId, stage.id, approverUserId, deadline]
);
}
});
}
res.json({
success: true,
message: 'Документ создан',
documentId: documentId
});
}
);
}
);
});
});
} catch (error) {
console.error('Ошибка:', error);
res.status(500).json({ error: 'Ошибка сервера' });
}
});
// Получение списка документов пользователя
router.get('/api/documents', requireAuth, async (req, res) => {
try {
const { getDb } = require('./database');
const db = getDb();
const userId = req.session.user.id;
const { status, type, search } = req.query;
let query = `
SELECT DISTINCT d.*,
u.name as author_name,
dt.name as type_name,
dt.id as type_id,
(SELECT COUNT(*) FROM document_approvals da
WHERE da.document_id = d.id AND da.approver_user_id = ? AND da.status = 'pending') as pending_for_me
FROM documents d
LEFT JOIN users u ON d.created_by = u.id
LEFT JOIN document_types dt ON d.document_type_id = dt.id
LEFT JOIN document_approvals da ON d.id = da.document_id
WHERE 1=1
`;
const params = [userId];
// Фильтр по статусу
if (status && status !== 'all') {
query += ` AND d.status = ?`;
params.push(status);
}
// Фильтр по типу
if (type && type !== 'all') {
query += ` AND d.document_type_id = ?`;
params.push(type);
}
// Поиск
if (search) {
query += ` AND (d.title LIKE ? OR d.description LIKE ?)`;
const searchPattern = `%${search}%`;
params.push(searchPattern, searchPattern);
}
// Показываем документы, которые создал пользователь или которые ему нужно согласовать
query += ` AND (d.created_by = ? OR da.approver_user_id = ?)`;
params.push(userId, userId);
query += ` GROUP BY d.id ORDER BY d.created_at DESC`;
db.all(query, params, async (err, documents) => {
if (err) {
console.error('Ошибка получения документов:', err);
return res.status(500).json({ error: 'Ошибка сервера' });
}
// Добавляем информацию о согласовании
const documentsWithApprovals = await Promise.all(documents.map(async (doc) => {
const approvals = await new Promise((resolve) => {
db.all(`
SELECT da.*, a.stage_number, a.stage_name,
u.name as approver_name, u.login as approver_login
FROM document_approvals da
LEFT JOIN approval_stages a ON da.stage_id = a.id
LEFT JOIN users u ON da.approver_user_id = u.id
WHERE da.document_id = ?
ORDER BY a.stage_number
`, [doc.id], (err, rows) => {
resolve(rows || []);
});
});
return {
...doc,
approvals
};
}));
res.json(documentsWithApprovals);
});
} catch (error) {
console.error('Ошибка:', error);
res.status(500).json({ error: 'Ошибка сервера' });
}
});
// Получение информации о конкретном документе
router.get('/api/documents/:id', requireAuth, async (req, res) => {
try {
const { getDb } = require('./database');
const db = getDb();
const documentId = req.params.id;
const userId = req.session.user.id;
// Проверяем доступ к документу
db.get(`
SELECT 1 FROM documents d
LEFT JOIN document_approvals da ON d.id = da.document_id
WHERE d.id = ? AND (d.created_by = ? OR da.approver_user_id = ?)
LIMIT 1
`, [documentId, userId, userId], (err, hasAccess) => {
if (err || !hasAccess) {
return res.status(403).json({ error: 'Доступ к документу запрещен' });
}
// Получаем информацию о документе
db.get(`
SELECT d.*,
u.name as author_name, u.login as author_login,
dt.name as type_name, dt.description as type_description,
au.name as approver_name, ru.name as rejector_name
FROM documents d
LEFT JOIN users u ON d.created_by = u.id
LEFT JOIN document_types dt ON d.document_type_id = dt.id
LEFT JOIN users au ON d.approved_by = au.id
LEFT JOIN users ru ON d.rejected_by = ru.id
WHERE d.id = ?
`, [documentId], async (err, document) => {
if (err || !document) {
return res.status(404).json({ error: 'Документ не найден' });
}
// Получаем этапы согласования
const approvals = await new Promise((resolve) => {
db.all(`
SELECT da.*, a.stage_number, a.stage_name, a.can_edit, a.can_comment,
u.name as approver_name, u.login as approver_login,
CASE
WHEN da.approver_user_id = ? THEN 'current'
WHEN da.status = 'pending' AND a.stage_number < (
SELECT MIN(a2.stage_number)
FROM document_approvals da2
LEFT JOIN approval_stages a2 ON da2.stage_id = a2.id
WHERE da2.document_id = ? AND da2.status = 'pending'
) THEN 'completed'
ELSE 'future'
END as user_relation
FROM document_approvals da
LEFT JOIN approval_stages a ON da.stage_id = a.id
LEFT JOIN users u ON da.approver_user_id = u.id
WHERE da.document_id = ?
ORDER BY a.stage_number
`, [userId, documentId, documentId], (err, rows) => {
resolve(rows || []);
});
});
// Получаем комментарии
const comments = await new Promise((resolve) => {
db.all(`
SELECT dc.*, u.name as user_name, u.login as user_login
FROM document_comments dc
LEFT JOIN users u ON dc.user_id = u.id
WHERE dc.document_id = ?
ORDER BY dc.created_at DESC
`, [documentId], (err, rows) => {
resolve(rows || []);
});
});
// Получаем историю
const history = await new Promise((resolve) => {
db.all(`
SELECT dh.*, u.name as user_name
FROM document_history dh
LEFT JOIN users u ON dh.user_id = u.id
WHERE dh.document_id = ?
ORDER BY dh.created_at DESC
LIMIT 20
`, [documentId], (err, rows) => {
resolve(rows || []);
});
});
// Определяем текущий этап для пользователя
let currentStage = null;
if (document.status === 'in_review') {
currentStage = approvals.find(a =>
a.approver_user_id === userId && a.status === 'pending'
);
}
// Проверяем права на редактирование
let canEdit = false;
let canApprove = false;
let canComment = true;
if (document.created_by === userId && document.status === 'draft') {
canEdit = true;
}
if (currentStage) {
const stageInfo = approvals.find(a => a.id === currentStage.id);
canEdit = stageInfo?.can_edit || false;
canApprove = true;
canComment = stageInfo?.can_comment || true;
}
res.json({
document,
approvals,
comments,
history,
permissions: {
canEdit,
canApprove,
canComment,
canDownload: true,
canDelete: document.created_by === userId && document.status === 'draft'
},
currentStage
});
});
});
} catch (error) {
console.error('Ошибка:', error);
res.status(500).json({ error: 'Ошибка сервера' });
}
});
// Скачивание документа
router.get('/api/documents/:id/download', requireAuth, async (req, res) => {
try {
const { getDb } = require('./database');
const db = getDb();
const documentId = req.params.id;
const userId = req.session.user.id;
// Проверяем доступ к документу
db.get(`
SELECT 1 FROM documents d
LEFT JOIN document_approvals da ON d.id = da.document_id
WHERE d.id = ? AND (d.created_by = ? OR da.approver_user_id = ?)
LIMIT 1
`, [documentId, userId, userId], (err, hasAccess) => {
if (err || !hasAccess) {
return res.status(403).json({ error: 'Доступ к документу запрещен' });
}
// Получаем информацию о файле
db.get("SELECT file_path, file_name FROM documents WHERE id = ?", [documentId], (err, doc) => {
if (err || !doc) {
return res.status(404).json({ error: 'Документ не найден' });
}
if (!fs.existsSync(doc.file_path)) {
return res.status(404).json({ error: 'Файл не найден' });
}
// Устанавливаем заголовки для скачивания
const encodedFileName = encodeURIComponent(doc.file_name);
res.setHeader('Content-Disposition', `attachment; filename*=UTF-8''${encodedFileName}`);
res.setHeader('Content-Type', 'application/octet-stream');
// Отправляем файл
res.sendFile(doc.file_path);
});
});
} catch (error) {
console.error('Ошибка:', error);
res.status(500).json({ error: 'Ошибка сервера' });
}
});
// Отправка документа на согласование
router.post('/api/documents/:id/submit', requireAuth, async (req, res) => {
try {
const { getDb } = require('./database');
const db = getDb();
const documentId = req.params.id;
const userId = req.session.user.id;
// Проверяем, что документ принадлежит пользователю и имеет статус черновика
db.get("SELECT status, created_by FROM documents WHERE id = ?", [documentId], (err, document) => {
if (err || !document) {
return res.status(404).json({ error: 'Документ не найден' });
}
if (document.created_by !== userId) {
return res.status(403).json({ error: 'Недостаточно прав' });
}
if (document.status !== 'draft') {
return res.status(400).json({ error: 'Документ уже отправлен на согласование' });
}
db.serialize(() => {
// Обновляем статус документа
db.run(
"UPDATE documents SET status = 'in_review', updated_at = CURRENT_TIMESTAMP WHERE id = ?",
[documentId],
function(err) {
if (err) {
console.error('Ошибка обновления статуса:', err);
return res.status(500).json({ error: 'Ошибка сервера' });
}
// Логируем действие
logDocumentActivity(db, documentId, userId, 'DOCUMENT_SUBMITTED', 'Документ отправлен на согласование');
// Отправляем уведомления согласующим первого этапа
db.all(`
SELECT da.approver_user_id, u.email, u.name
FROM document_approvals da
LEFT JOIN users u ON da.approver_user_id = u.id
WHERE da.document_id = ? AND da.status = 'pending'
ORDER BY (
SELECT stage_number FROM approval_stages WHERE id = da.stage_id
) LIMIT 1
`, [documentId], (err, approvers) => {
if (!err && approvers && approvers.length > 0) {
// Здесь можно добавить отправку email уведомлений
console.log(`📄 Документ ${documentId} отправлен на согласование`);
approvers.forEach(approver => {
console.log(` 👤 Уведомить: ${approver.name} (${approver.email})`);
});
}
});
res.json({ success: true, message: 'Документ отправлен на согласование' });
}
);
});
});
} catch (error) {
console.error('Ошибка:', error);
res.status(500).json({ error: 'Ошибка сервера' });
}
});
// Согласование документа
router.post('/api/documents/:id/approve', requireAuth, async (req, res) => {
try {
const { getDb } = require('./database');
const db = getDb();
const documentId = req.params.id;
const userId = req.session.user.id;
const { comments } = req.body;
// Проверяем, что пользователь является текущим согласующим
db.get(`
SELECT da.*, a.stage_number
FROM document_approvals da
LEFT JOIN approval_stages a ON da.stage_id = a.id
WHERE da.document_id = ? AND da.approver_user_id = ? AND da.status = 'pending'
ORDER BY a.stage_number
LIMIT 1
`, [documentId, userId], (err, approval) => {
if (err || !approval) {
return res.status(403).json({ error: 'Вы не являетесь текущим согласующим' });
}
db.serialize(() => {
// Обновляем запись согласования
db.run(
`UPDATE document_approvals
SET status = 'approved', comments = ?, approved_at = CURRENT_TIMESTAMP,
updated_at = CURRENT_TIMESTAMP
WHERE id = ?`,
[comments || '', approval.id],
function(err) {
if (err) {
console.error('Ошибка обновления согласования:', err);
return res.status(500).json({ error: 'Ошибка сервера' });
}
// Логируем действие
logDocumentActivity(db, documentId, userId, 'STAGE_APPROVED',
`Этап ${approval.stage_number} согласован`);
// Добавляем комментарий, если он есть
if (comments) {
db.run(
`INSERT INTO document_comments (document_id, user_id, comment, is_internal)
VALUES (?, ?, ?, 0)`,
[documentId, userId, comments]
);
}
// Проверяем, остались ли этапы для согласования
db.get(`
SELECT COUNT(*) as pending_count
FROM document_approvals
WHERE document_id = ? AND status = 'pending'
`, [documentId], (err, result) => {
if (err) {
console.error('Ошибка проверки оставшихся этапов:', err);
return res.status(500).json({ error: 'Ошибка сервера' });
}
if (result.pending_count === 0) {
// Все этапы согласованы
db.run(
`UPDATE documents
SET status = 'approved', approved_at = CURRENT_TIMESTAMP,
approved_by = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ?`,
[userId, documentId],
function(err) {
if (err) {
console.error('Ошибка обновления статуса документа:', err);
return res.status(500).json({ error: 'Ошибка сервера' });
}
logDocumentActivity(db, documentId, userId, 'DOCUMENT_APPROVED',
'Документ полностью согласован');
res.json({
success: true,
message: 'Документ полностью согласован',
documentStatus: 'approved'
});
}
);
} else {
// Переходим к следующему этапу
db.get(`
SELECT da.approver_user_id, u.email, u.name
FROM document_approvals da
LEFT JOIN users u ON da.approver_user_id = u.id
WHERE da.document_id = ? AND da.status = 'pending'
ORDER BY (
SELECT stage_number FROM approval_stages WHERE id = da.stage_id
) LIMIT 1
`, [documentId], (err, nextApprover) => {
if (!err && nextApprover) {
// Здесь можно добавить отправку уведомления следующему согласующему
console.log(`📄 Переход к следующему согласующему: ${nextApprover.name}`);
}
res.json({
success: true,
message: 'Этап согласован',
documentStatus: 'in_review'
});
});
}
});
}
);
});
});
} catch (error) {
console.error('Ошибка:', error);
res.status(500).json({ error: 'Ошибка сервера' });
}
});
// Отклонение документа
router.post('/api/documents/:id/reject', requireAuth, async (req, res) => {
try {
const { getDb } = require('./database');
const db = getDb();
const documentId = req.params.id;
const userId = req.session.user.id;
const { reason } = req.body;
if (!reason) {
return res.status(400).json({ error: 'Укажите причину отклонения' });
}
// Проверяем, что пользователь является текущим согласующим или создателем
db.get(`
SELECT d.created_by, da.*, a.stage_number
FROM documents d
LEFT JOIN document_approvals da ON d.id = da.document_id AND da.approver_user_id = ? AND da.status = 'pending'
LEFT JOIN approval_stages a ON da.stage_id = a.id
WHERE d.id = ?
`, [userId, documentId], (err, result) => {
if (err) {
console.error('Ошибка проверки прав:', err);
return res.status(500).json({ error: 'Ошибка сервера' });
}
const canReject = result?.created_by === userId || result?.id; // Создатель или текущий согласующий
if (!canReject) {
return res.status(403).json({ error: 'Недостаточно прав для отклонения документа' });
}
db.serialize(() => {
// Если отклоняет согласующий, отмечаем его этап
if (result.id) {
db.run(
`UPDATE document_approvals
SET status = 'rejected', comments = ?, rejected_at = CURRENT_TIMESTAMP,
updated_at = CURRENT_TIMESTAMP
WHERE id = ?`,
[reason, result.id]
);
logDocumentActivity(db, documentId, userId, 'STAGE_REJECTED',
`Этап ${result.stage_number} отклонен: ${reason}`);
}
// Обновляем статус документа
db.run(
`UPDATE documents
SET status = 'rejected', rejected_at = CURRENT_TIMESTAMP,
rejected_by = ?, rejection_reason = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ?`,
[userId, reason, documentId],
function(err) {
if (err) {
console.error('Ошибка обновления статуса документа:', err);
return res.status(500).json({ error: 'Ошибка сервера' });
}
// Добавляем комментарий
db.run(
`INSERT INTO document_comments (document_id, user_id, comment, is_internal)
VALUES (?, ?, ?, 0)`,
[documentId, userId, `Документ отклонен: ${reason}`]
);
logDocumentActivity(db, documentId, userId, 'DOCUMENT_REJECTED',
`Документ отклонен: ${reason}`);
res.json({ success: true, message: 'Документ отклонен' });
}
);
});
});
} catch (error) {
console.error('Ошибка:', error);
res.status(500).json({ error: 'Ошибка сервера' });
}
});
// Добавление комментария к документу
router.post('/api/documents/:id/comments', requireAuth, async (req, res) => {
try {
const { getDb } = require('./database');
const db = getDb();
const documentId = req.params.id;
const userId = req.session.user.id;
const { comment, is_internal = false } = req.body;
if (!comment) {
return res.status(400).json({ error: 'Комментарий обязателен' });
}
// Проверяем доступ к документу
db.get(`
SELECT 1 FROM documents d
LEFT JOIN document_approvals da ON d.id = da.document_id
WHERE d.id = ? AND (d.created_by = ? OR da.approver_user_id = ?)
LIMIT 1
`, [documentId, userId, userId], (err, hasAccess) => {
if (err || !hasAccess) {
return res.status(403).json({ error: 'Доступ к документу запрещен' });
}
db.run(
`INSERT INTO document_comments (document_id, user_id, comment, is_internal)
VALUES (?, ?, ?, ?)`,
[documentId, userId, comment, is_internal ? 1 : 0],
function(err) {
if (err) {
console.error('Ошибка добавления комментария:', err);
return res.status(500).json({ error: 'Ошибка сервера' });
}
logDocumentActivity(db, documentId, userId, 'COMMENT_ADDED', 'Добавлен комментарий');
res.json({ success: true, message: 'Комментарий добавлен' });
}
);
});
} catch (error) {
console.error('Ошибка:', error);
res.status(500).json({ error: 'Ошибка сервера' });
}
});
// Обновление документа (новая версия)
router.put('/api/documents/:id', requireAuth, upload.single('file'), async (req, res) => {
try {
const { getDb } = require('./database');
const db = getDb();
const documentId = req.params.id;
const userId = req.session.user.id;
const { title, description } = req.body;
// Проверяем права на редактирование
db.get(`
SELECT d.*, da.id as approval_id, a.can_edit
FROM documents d
LEFT JOIN document_approvals da ON d.id = da.document_id AND da.approver_user_id = ? AND da.status = 'pending'
LEFT JOIN approval_stages a ON da.stage_id = a.id
WHERE d.id = ?
`, [userId, documentId], (err, document) => {
if (err || !document) {
return res.status(404).json({ error: 'Документ не найден' });
}
const canEdit = (document.created_by === userId && document.status === 'draft') ||
(document.approval_id && document.can_edit);
if (!canEdit) {
return res.status(403).json({ error: 'Недостаточно прав для редактирования' });
}
db.serialize(() => {
// Создаем новую версию документа
const newVersion = document.version + 1;
const updateFields = [
'updated_at = CURRENT_TIMESTAMP',
'version = ?'
];
const params = [newVersion];
if (title) {
updateFields.push('title = ?');
params.push(title);
}
if (description) {
updateFields.push('description = ?');
params.push(description);
}
if (req.file) {
// Удаляем старый файл, если он существует
if (document.file_path && fs.existsSync(document.file_path)) {
fs.unlinkSync(document.file_path);
}
updateFields.push('file_path = ?', 'file_name = ?', 'file_size = ?');
params.push(req.file.path, req.file.originalname, req.file.size);
}
params.push(documentId);
db.run(
`UPDATE documents SET ${updateFields.join(', ')} WHERE id = ?`,
params,
function(err) {
if (err) {
console.error('Ошибка обновления документа:', err);
return res.status(500).json({ error: 'Ошибка сервера' });
}
// Логируем действие
const changes = [];
if (title && title !== document.title) changes.push(`Название: "${document.title}" -> "${title}"`);
if (description && description !== document.description) changes.push('Описание изменено');
if (req.file) changes.push('Файл обновлен');
logDocumentActivity(db, documentId, userId, 'DOCUMENT_UPDATED',
`Версия ${newVersion}: ${changes.join(', ')}`);
res.json({ success: true, message: 'Документ обновлен', version: newVersion });
}
);
});
});
} catch (error) {
console.error('Ошибка:', error);
res.status(500).json({ error: 'Ошибка сервера' });
}
});
// Удаление документа
router.delete('/api/documents/:id', requireAuth, async (req, res) => {
try {
const { getDb } = require('./database');
const db = getDb();
const documentId = req.params.id;
const userId = req.session.user.id;
// Проверяем, что документ принадлежит пользователю и имеет статус черновика
db.get("SELECT status, created_by, file_path FROM documents WHERE id = ?", [documentId], (err, document) => {
if (err || !document) {
return res.status(404).json({ error: 'Документ не найден' });
}
if (document.created_by !== userId) {
return res.status(403).json({ error: 'Недостаточно прав' });
}
if (document.status !== 'draft') {
return res.status(400).json({ error: 'Можно удалять только черновики' });
}
db.serialize(() => {
// Удаляем связанные записи
db.run("DELETE FROM document_approvals WHERE document_id = ?", [documentId]);
db.run("DELETE FROM document_comments WHERE document_id = ?", [documentId]);
db.run("DELETE FROM document_history WHERE document_id = ?", [documentId]);
// Удаляем файл
if (document.file_path && fs.existsSync(document.file_path)) {
fs.unlinkSync(document.file_path);
}
// Удаляем документ
db.run("DELETE FROM documents WHERE id = ?", [documentId], function(err) {
if (err) {
console.error('Ошибка удаления документа:', err);
return res.status(500).json({ error: 'Ошибка сервера' });
}
res.json({ success: true, message: 'Документ удален' });
});
});
});
} catch (error) {
console.error('Ошибка:', error);
res.status(500).json({ error: 'Ошибка сервера' });
}
});
// Получение документов, ожидающих согласования пользователем
router.get('/api/documents/pending', requireAuth, async (req, res) => {
try {
const { getDb } = require('./database');
const db = getDb();
const userId = req.session.user.id;
const query = `
SELECT d.*,
u.name as author_name,
dt.name as type_name,
a.stage_number, a.stage_name,
da.deadline,
julianday(da.deadline) - julianday('now') as days_until_deadline
FROM document_approvals da
LEFT JOIN documents d ON da.document_id = d.id
LEFT JOIN users u ON d.created_by = u.id
LEFT JOIN document_types dt ON d.document_type_id = dt.id
LEFT JOIN approval_stages a ON da.stage_id = a.id
WHERE da.approver_user_id = ?
AND da.status = 'pending'
AND d.status = 'in_review'
ORDER BY da.deadline ASC, d.created_at DESC
`;
db.all(query, [userId], (err, documents) => {
if (err) {
console.error('Ошибка получения документов:', err);
return res.status(500).json({ error: 'Ошибка сервера' });
}
res.json(documents);
});
} catch (error) {
console.error('Ошибка:', error);
res.status(500).json({ error: 'Ошибка сервера' });
}
});
module.exports = router;