feat: 권한 탭 분리 + 부서 인원 표시 + 다수 시스템 개선
- tkuser: 권한 관리를 별도 탭으로 분리, 부서 클릭 시 소속 인원 목록 표시 - system1: 모바일 UI 개선, nginx 권한 보정, 신고 카테고리 타입 마이그레이션 - system2: 신고 상세/보고서 개선, 내 보고서 페이지 추가 - system3: 이슈 뷰/수신함/관리함 개선 - gateway: 포털 라우팅 수정 - user-management API: 부서별 권한 벌크 설정 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -237,6 +237,7 @@ const createReport = async (reportData, callback) => {
|
||||
visit_request_id = null,
|
||||
issue_category_id,
|
||||
issue_item_id = null,
|
||||
category_type,
|
||||
additional_description = null,
|
||||
photo_path1 = null,
|
||||
photo_path2 = null,
|
||||
@@ -251,11 +252,11 @@ const createReport = async (reportData, callback) => {
|
||||
const [result] = await db.query(
|
||||
`INSERT INTO work_issue_reports
|
||||
(reporter_id, report_date, factory_category_id, workplace_id, project_id, custom_location,
|
||||
tbm_session_id, visit_request_id, issue_category_id, issue_item_id,
|
||||
tbm_session_id, visit_request_id, issue_category_id, issue_item_id, category_type,
|
||||
additional_description, photo_path1, photo_path2, photo_path3, photo_path4, photo_path5)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[reporter_id, reportDate, factory_category_id, workplace_id, project_id, custom_location,
|
||||
tbm_session_id, visit_request_id, issue_category_id, issue_item_id,
|
||||
tbm_session_id, visit_request_id, issue_category_id, issue_item_id, category_type,
|
||||
additional_description, photo_path1, photo_path2, photo_path3, photo_path4, photo_path5]
|
||||
);
|
||||
|
||||
@@ -291,7 +292,7 @@ const getAllReports = async (filters = {}, callback) => {
|
||||
u.username as reporter_name, u.name as reporter_full_name,
|
||||
wc.category_name as factory_name,
|
||||
w.workplace_name,
|
||||
irc.category_type, irc.category_name as issue_category_name,
|
||||
wir.category_type, irc.category_type as original_category_type, irc.category_name as issue_category_name,
|
||||
iri.item_name as issue_item_name, iri.severity,
|
||||
assignee.username as assigned_user_name, assignee.name as assigned_full_name
|
||||
FROM work_issue_reports wir
|
||||
@@ -313,7 +314,7 @@ const getAllReports = async (filters = {}, callback) => {
|
||||
}
|
||||
|
||||
if (filters.category_type) {
|
||||
query += ` AND irc.category_type = ?`;
|
||||
query += ` AND wir.category_type = ?`;
|
||||
params.push(filters.category_type);
|
||||
}
|
||||
|
||||
@@ -394,7 +395,7 @@ const getReportById = async (reportId, callback) => {
|
||||
u.username as reporter_name, u.name as reporter_full_name,
|
||||
wc.category_name as factory_name,
|
||||
w.workplace_name,
|
||||
irc.category_type, irc.category_name as issue_category_name,
|
||||
wir.category_type, irc.category_type as original_category_type, irc.category_name as issue_category_name,
|
||||
iri.item_name as issue_item_name, iri.severity,
|
||||
assignee.username as assigned_user_name, assignee.name as assigned_full_name,
|
||||
assigner.username as assigned_by_name,
|
||||
@@ -783,25 +784,30 @@ const getStatsSummary = async (filters = {}, callback) => {
|
||||
let whereClause = '1=1';
|
||||
const params = [];
|
||||
|
||||
if (filters.category_type) {
|
||||
whereClause += ` AND wir.category_type = ?`;
|
||||
params.push(filters.category_type);
|
||||
}
|
||||
|
||||
if (filters.start_date && filters.end_date) {
|
||||
whereClause += ` AND DATE(report_date) BETWEEN ? AND ?`;
|
||||
whereClause += ` AND DATE(wir.report_date) BETWEEN ? AND ?`;
|
||||
params.push(filters.start_date, filters.end_date);
|
||||
}
|
||||
|
||||
if (filters.factory_category_id) {
|
||||
whereClause += ` AND factory_category_id = ?`;
|
||||
whereClause += ` AND wir.factory_category_id = ?`;
|
||||
params.push(filters.factory_category_id);
|
||||
}
|
||||
|
||||
const [rows] = await db.query(
|
||||
`SELECT
|
||||
COUNT(*) as total,
|
||||
SUM(CASE WHEN status = 'reported' THEN 1 ELSE 0 END) as reported,
|
||||
SUM(CASE WHEN status = 'received' THEN 1 ELSE 0 END) as received,
|
||||
SUM(CASE WHEN status = 'in_progress' THEN 1 ELSE 0 END) as in_progress,
|
||||
SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed,
|
||||
SUM(CASE WHEN status = 'closed' THEN 1 ELSE 0 END) as closed
|
||||
FROM work_issue_reports
|
||||
SUM(CASE WHEN wir.status = 'reported' THEN 1 ELSE 0 END) as reported,
|
||||
SUM(CASE WHEN wir.status = 'received' THEN 1 ELSE 0 END) as received,
|
||||
SUM(CASE WHEN wir.status = 'in_progress' THEN 1 ELSE 0 END) as in_progress,
|
||||
SUM(CASE WHEN wir.status = 'completed' THEN 1 ELSE 0 END) as completed,
|
||||
SUM(CASE WHEN wir.status = 'closed' THEN 1 ELSE 0 END) as closed
|
||||
FROM work_issue_reports wir
|
||||
WHERE ${whereClause}`,
|
||||
params
|
||||
);
|
||||
@@ -885,6 +891,86 @@ const getStatsByWorkplace = async (filters = {}, callback) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 유형 이관 (category_type 변경)
|
||||
*/
|
||||
const transferCategoryType = async (reportId, newCategoryType, userId, callback) => {
|
||||
try {
|
||||
const db = await getDb();
|
||||
|
||||
// 기존 데이터 조회
|
||||
const [existing] = await db.query(
|
||||
`SELECT report_id, category_type, modification_history FROM work_issue_reports WHERE report_id = ?`,
|
||||
[reportId]
|
||||
);
|
||||
|
||||
if (existing.length === 0) {
|
||||
return callback(new Error('신고를 찾을 수 없습니다.'));
|
||||
}
|
||||
|
||||
const current = existing[0];
|
||||
const oldCategoryType = current.category_type;
|
||||
|
||||
if (oldCategoryType === newCategoryType) {
|
||||
return callback(new Error('현재 유형과 동일합니다.'));
|
||||
}
|
||||
|
||||
// 수정 이력 추가
|
||||
const existingHistory = current.modification_history ? JSON.parse(current.modification_history) : [];
|
||||
const now = new Date().toISOString();
|
||||
existingHistory.push({
|
||||
field: 'category_type',
|
||||
old_value: oldCategoryType,
|
||||
new_value: newCategoryType,
|
||||
modified_at: now,
|
||||
modified_by: userId
|
||||
});
|
||||
|
||||
// category_type 업데이트
|
||||
const [result] = await db.query(
|
||||
`UPDATE work_issue_reports
|
||||
SET category_type = ?, modification_history = ?, updated_at = NOW()
|
||||
WHERE report_id = ?`,
|
||||
[newCategoryType, JSON.stringify(existingHistory), reportId]
|
||||
);
|
||||
|
||||
callback(null, result);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 공장/작업장 이름 조회 (System 3 연동용)
|
||||
*/
|
||||
const getLocationNames = async (factoryCategoryId, workplaceId, callback) => {
|
||||
try {
|
||||
const db = await getDb();
|
||||
let factoryName = null;
|
||||
let workplaceName = null;
|
||||
|
||||
if (factoryCategoryId) {
|
||||
const [rows] = await db.query(
|
||||
`SELECT category_name FROM workplace_categories WHERE category_id = ?`,
|
||||
[factoryCategoryId]
|
||||
);
|
||||
if (rows.length > 0) factoryName = rows[0].category_name;
|
||||
}
|
||||
|
||||
if (workplaceId) {
|
||||
const [rows] = await db.query(
|
||||
`SELECT workplace_name FROM workplaces WHERE workplace_id = ?`,
|
||||
[workplaceId]
|
||||
);
|
||||
if (rows.length > 0) workplaceName = rows[0].workplace_name;
|
||||
}
|
||||
|
||||
callback(null, { factory_name: factoryName, workplace_name: workplaceName });
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
// 카테고리
|
||||
getAllCategories,
|
||||
@@ -910,6 +996,10 @@ module.exports = {
|
||||
|
||||
// System 3 연동
|
||||
updateMProjectId,
|
||||
getLocationNames,
|
||||
|
||||
// 유형 이관
|
||||
transferCategoryType,
|
||||
|
||||
// 상태 관리
|
||||
receiveReport,
|
||||
|
||||
Reference in New Issue
Block a user