188 lines
6.8 KiB
TypeScript
188 lines
6.8 KiB
TypeScript
import { Router } from 'express';
|
|
import { requireAuth, requirePermission } from '../auth/authMiddleware.js';
|
|
import { AuthError } from '../auth/authService.js';
|
|
import {
|
|
getTemplates,
|
|
getCategories,
|
|
listReports,
|
|
getReport,
|
|
createReport,
|
|
updateReport,
|
|
deleteReport,
|
|
updateReportSection,
|
|
} from './reportsService.js';
|
|
|
|
const router = Router();
|
|
|
|
// ============================================================
|
|
// GET /api/reports/templates — 템플릿 목록 + 섹션 정의
|
|
// ============================================================
|
|
router.get('/templates', requireAuth, async (_req, res) => {
|
|
try {
|
|
const templates = await getTemplates();
|
|
res.json(templates);
|
|
} catch (err) {
|
|
console.error('[reports] 템플릿 조회 오류:', err);
|
|
res.status(500).json({ error: '템플릿 조회 중 오류가 발생했습니다.' });
|
|
}
|
|
});
|
|
|
|
// ============================================================
|
|
// GET /api/reports/categories — 분석 카테고리 목록 + 섹션 정의
|
|
// ============================================================
|
|
router.get('/categories', requireAuth, async (_req, res) => {
|
|
try {
|
|
const categories = await getCategories();
|
|
res.json(categories);
|
|
} catch (err) {
|
|
console.error('[reports] 카테고리 조회 오류:', err);
|
|
res.status(500).json({ error: '카테고리 조회 중 오류가 발생했습니다.' });
|
|
}
|
|
});
|
|
|
|
// ============================================================
|
|
// GET /api/reports — 보고서 목록
|
|
// ============================================================
|
|
router.get('/', requireAuth, requirePermission('reports', 'READ'), async (req, res) => {
|
|
try {
|
|
const { jrsdCd, tmplCd, sttsCd, search, page, size } = req.query;
|
|
const result = await listReports({
|
|
jrsdCd: jrsdCd as string | undefined,
|
|
tmplCd: tmplCd as string | undefined,
|
|
sttsCd: sttsCd as string | undefined,
|
|
search: search as string | undefined,
|
|
page: page ? parseInt(page as string, 10) : undefined,
|
|
size: size ? parseInt(size as string, 10) : undefined,
|
|
});
|
|
res.json(result);
|
|
} catch (err) {
|
|
console.error('[reports] 목록 조회 오류:', err);
|
|
if (err instanceof AuthError) {
|
|
res.status(err.status).json({ error: err.message });
|
|
} else {
|
|
res.status(500).json({ error: '보고서 목록 조회 중 오류가 발생했습니다.' });
|
|
}
|
|
}
|
|
});
|
|
|
|
// ============================================================
|
|
// GET /api/reports/:sn — 보고서 상세
|
|
// ============================================================
|
|
router.get('/:sn', requireAuth, requirePermission('reports', 'READ'), async (req, res) => {
|
|
try {
|
|
const sn = parseInt(req.params.sn as string, 10);
|
|
if (isNaN(sn)) {
|
|
res.status(400).json({ error: '유효하지 않은 보고서 번호입니다.' });
|
|
return;
|
|
}
|
|
const report = await getReport(sn);
|
|
res.json(report);
|
|
} catch (err) {
|
|
if (err instanceof AuthError) {
|
|
res.status(err.status).json({ error: err.message });
|
|
} else {
|
|
console.error('[reports] 상세 조회 오류:', err);
|
|
res.status(500).json({ error: '보고서 조회 중 오류가 발생했습니다.' });
|
|
}
|
|
}
|
|
});
|
|
|
|
// ============================================================
|
|
// POST /api/reports — 보고서 생성
|
|
// ============================================================
|
|
router.post('/', requireAuth, requirePermission('reports', 'CREATE'), async (req, res) => {
|
|
try {
|
|
const { tmplSn, ctgrSn, acdntSn, title, jrsdCd, sttsCd, sections, step3MapImg, step6MapImg } = req.body;
|
|
const result = await createReport({
|
|
tmplSn,
|
|
ctgrSn,
|
|
acdntSn,
|
|
title,
|
|
jrsdCd,
|
|
sttsCd,
|
|
authorId: req.user!.sub,
|
|
step3MapImg,
|
|
step6MapImg,
|
|
sections,
|
|
});
|
|
res.status(201).json(result);
|
|
} catch (err) {
|
|
if (err instanceof AuthError) {
|
|
res.status(err.status).json({ error: err.message });
|
|
} else {
|
|
console.error('[reports] 생성 오류:', err);
|
|
res.status(500).json({ error: '보고서 생성 중 오류가 발생했습니다.' });
|
|
}
|
|
}
|
|
});
|
|
|
|
// ============================================================
|
|
// POST /api/reports/:sn/update — 보고서 수정
|
|
// ============================================================
|
|
router.post('/:sn/update', requireAuth, requirePermission('reports', 'UPDATE'), async (req, res) => {
|
|
try {
|
|
const sn = parseInt(req.params.sn as string, 10);
|
|
if (isNaN(sn)) {
|
|
res.status(400).json({ error: '유효하지 않은 보고서 번호입니다.' });
|
|
return;
|
|
}
|
|
const { title, jrsdCd, sttsCd, acdntSn, sections, step3MapImg, step6MapImg } = req.body;
|
|
await updateReport(sn, { title, jrsdCd, sttsCd, acdntSn, sections, step3MapImg, step6MapImg }, req.user!.sub);
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
if (err instanceof AuthError) {
|
|
res.status(err.status).json({ error: err.message });
|
|
} else {
|
|
console.error('[reports] 수정 오류:', err);
|
|
res.status(500).json({ error: '보고서 수정 중 오류가 발생했습니다.' });
|
|
}
|
|
}
|
|
});
|
|
|
|
// ============================================================
|
|
// POST /api/reports/:sn/delete — 보고서 삭제 (논리 삭제)
|
|
// ============================================================
|
|
router.post('/:sn/delete', requireAuth, requirePermission('reports', 'DELETE'), async (req, res) => {
|
|
try {
|
|
const sn = parseInt(req.params.sn as string, 10);
|
|
if (isNaN(sn)) {
|
|
res.status(400).json({ error: '유효하지 않은 보고서 번호입니다.' });
|
|
return;
|
|
}
|
|
await deleteReport(sn, req.user!.sub);
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
if (err instanceof AuthError) {
|
|
res.status(err.status).json({ error: err.message });
|
|
} else {
|
|
console.error('[reports] 삭제 오류:', err);
|
|
res.status(500).json({ error: '보고서 삭제 중 오류가 발생했습니다.' });
|
|
}
|
|
}
|
|
});
|
|
|
|
// ============================================================
|
|
// POST /api/reports/:sn/sections/:sectCd — 개별 섹션 수정
|
|
// ============================================================
|
|
router.post('/:sn/sections/:sectCd', requireAuth, requirePermission('reports', 'UPDATE'), async (req, res) => {
|
|
try {
|
|
const sn = parseInt(req.params.sn as string, 10);
|
|
if (isNaN(sn)) {
|
|
res.status(400).json({ error: '유효하지 않은 보고서 번호입니다.' });
|
|
return;
|
|
}
|
|
const { sectData, includeYn } = req.body;
|
|
await updateReportSection(sn, req.params.sectCd as string, sectData, includeYn, req.user!.sub);
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
if (err instanceof AuthError) {
|
|
res.status(err.status).json({ error: err.message });
|
|
} else {
|
|
console.error('[reports] 섹션 수정 오류:', err);
|
|
res.status(500).json({ error: '섹션 수정 중 오류가 발생했습니다.' });
|
|
}
|
|
}
|
|
});
|
|
|
|
export default router;
|