feat: Add report cell value management functionality
- Introduced a new controller for managing custom input values in report cells, allowing users to retrieve and upsert values associated with specific reports and targets. - Implemented API routes for fetching and saving report cell values, ensuring proper authentication and data handling. - Enhanced the frontend components to support the new report cell input functionality, including the ability to edit and save input values in a modal. - Updated inventory and equipment management pages to include new features for handling missing items and managing warehouse locations effectively.
This commit is contained in:
@@ -157,6 +157,7 @@ import shippingOrderRoutes from "./routes/shippingOrderRoutes"; // 출하지시
|
||||
import workInstructionRoutes from "./routes/workInstructionRoutes"; // 작업지시 관리
|
||||
import salesReportRoutes from "./routes/salesReportRoutes"; // 영업 리포트
|
||||
import reportPresetRoutes from "./routes/reportPresetRoutes"; // 리포트 프리셋 저장 (회사별/리포트별)
|
||||
import reportCellValueRoutes from "./routes/reportCellValueRoutes"; // 리포트 셀 커스텀 입력값 (input 셀)
|
||||
import analyticsReportRoutes from "./routes/analyticsReportRoutes"; // 분석 리포트 (생산/재고/구매/품질/설비/금형)
|
||||
import systemNoticeRoutes from "./routes/systemNoticeRoutes"; // 시스템 공지
|
||||
import designRoutes from "./routes/designRoutes"; // 설계 모듈 (DR/ECR/프로젝트/ECN)
|
||||
@@ -381,6 +382,7 @@ app.use("/api/shipping-order", shippingOrderRoutes); // 출하지시 관리
|
||||
app.use("/api/work-instruction", workInstructionRoutes); // 작업지시 관리
|
||||
app.use("/api/sales-report", salesReportRoutes); // 영업 리포트
|
||||
app.use("/api/report-presets", reportPresetRoutes); // 리포트 프리셋 (회사별/리포트별 저장)
|
||||
app.use("/api/report-cell-values", reportCellValueRoutes); // 리포트 셀 커스텀 입력값
|
||||
app.use("/api/system-notice", systemNoticeRoutes); // 시스템 공지
|
||||
app.use("/api/report", analyticsReportRoutes); // 분석 리포트 (생산/재고/구매/품질/설비/금형)
|
||||
app.use("/api/design", designRoutes); // 설계 모듈
|
||||
|
||||
93
backend-node/src/controllers/reportCellValueController.ts
Normal file
93
backend-node/src/controllers/reportCellValueController.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* 리포트 셀 커스텀 입력값 컨트롤러
|
||||
*
|
||||
* 리포트 디자이너에서 cellType="input"으로 지정한 셀에 대해
|
||||
* 각 대상 레코드(quote 등)별로 사용자가 입력한 값을 관리
|
||||
*/
|
||||
|
||||
import type { Response } from "express";
|
||||
import { getPool } from "../database/db";
|
||||
import type { AuthenticatedRequest } from "../types/auth";
|
||||
import { logger } from "../utils/logger";
|
||||
|
||||
// 목록 조회: 특정 리포트 + 타겟에 대한 모든 셀 값
|
||||
export async function getList(req: AuthenticatedRequest, res: Response) {
|
||||
try {
|
||||
const companyCode = req.user!.companyCode;
|
||||
const { report_id, target_type, target_id } = req.query;
|
||||
|
||||
if (!report_id || !target_type || !target_id) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "report_id, target_type, target_id는 필수입니다.",
|
||||
});
|
||||
}
|
||||
|
||||
const pool = getPool();
|
||||
const result = await pool.query(
|
||||
`SELECT id, report_id, target_type, target_id, component_id, cell_id, value
|
||||
FROM report_cell_values
|
||||
WHERE company_code = $1 AND report_id = $2 AND target_type = $3 AND target_id = $4`,
|
||||
[companyCode, report_id, target_type, target_id],
|
||||
);
|
||||
|
||||
return res.json({ success: true, data: result.rows });
|
||||
} catch (error: any) {
|
||||
logger.error("리포트 셀 값 조회 실패", { error: error.message });
|
||||
return res.status(500).json({ success: false, message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
// UPSERT 단건: 같은 (report_id, target_type, target_id, component_id, cell_id)면 UPDATE, 아니면 INSERT
|
||||
export async function upsert(req: AuthenticatedRequest, res: Response) {
|
||||
try {
|
||||
const companyCode = req.user!.companyCode;
|
||||
const userId = req.user!.userId;
|
||||
const { report_id, target_type, target_id, component_id, cell_id, value } =
|
||||
req.body;
|
||||
|
||||
if (!report_id || !target_type || !target_id || !component_id || !cell_id) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "필수 필드 누락",
|
||||
});
|
||||
}
|
||||
|
||||
const pool = getPool();
|
||||
|
||||
// value가 빈 문자열이면 DELETE (오버라이드 해제)
|
||||
if (value === "" || value === null || value === undefined) {
|
||||
await pool.query(
|
||||
`DELETE FROM report_cell_values
|
||||
WHERE company_code = $1 AND report_id = $2 AND target_type = $3
|
||||
AND target_id = $4 AND component_id = $5 AND cell_id = $6`,
|
||||
[companyCode, report_id, target_type, target_id, component_id, cell_id],
|
||||
);
|
||||
return res.json({ success: true, data: null });
|
||||
}
|
||||
|
||||
const result = await pool.query(
|
||||
`INSERT INTO report_cell_values
|
||||
(id, company_code, report_id, target_type, target_id, component_id, cell_id, value, created_by, updated_by)
|
||||
VALUES (gen_random_uuid()::text, $1, $2, $3, $4, $5, $6, $7, $8, $8)
|
||||
ON CONFLICT (company_code, report_id, target_type, target_id, component_id, cell_id)
|
||||
DO UPDATE SET value = EXCLUDED.value, updated_at = CURRENT_TIMESTAMP, updated_by = EXCLUDED.updated_by
|
||||
RETURNING *`,
|
||||
[
|
||||
companyCode,
|
||||
report_id,
|
||||
target_type,
|
||||
target_id,
|
||||
component_id,
|
||||
cell_id,
|
||||
value,
|
||||
userId,
|
||||
],
|
||||
);
|
||||
|
||||
return res.json({ success: true, data: result.rows[0] });
|
||||
} catch (error: any) {
|
||||
logger.error("리포트 셀 값 저장 실패", { error: error.message });
|
||||
return res.status(500).json({ success: false, message: error.message });
|
||||
}
|
||||
}
|
||||
12
backend-node/src/routes/reportCellValueRoutes.ts
Normal file
12
backend-node/src/routes/reportCellValueRoutes.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Router } from "express";
|
||||
import { authenticateToken } from "../middleware/authMiddleware";
|
||||
import * as controller from "../controllers/reportCellValueController";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.use(authenticateToken);
|
||||
|
||||
router.get("/", controller.getList);
|
||||
router.post("/", controller.upsert);
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user