feat: TBM 중복 배정 방지, 설비 배치도 좌표계 통일, 구역 상세 CSS 수정
- TBM 팀원 추가 시 중복 배정 검증 및 409 에러 처리 (tbmController, tbmModel, tbm-create.js, tbm.js, tbm/api.js) - tkuser/tkfb 설비 배치도 좌표계를 좌상단 기준으로 통일 (CSS left/top 방식) - tkuser 설비 배치도에 드래그 이동, 코너 리사이즈, 배치 버튼 추가 - 대분류 지도 영역 수정 버튼 추가 (workplace-layout-map.js, tkuser-layout-map.js) - tkfb workplace-status 캔버스 maxWidth 800 통일 - zone-detail.css object-fit:contain 제거 → height:auto로 마커 위치 정확도 개선 - imageUploadService 업로드 경로 Docker 볼륨 마운트 경로로 수정 - repair-management 카테고리 필터 nonconformity → facility 수정 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -194,6 +194,32 @@ const TbmController = {
|
||||
return res.status(400).json({ success: false, message: '팀원 목록이 필요합니다.' });
|
||||
}
|
||||
|
||||
// 중복 배정 검증
|
||||
const sessionRows = await TbmModel.getSessionById(sessionId);
|
||||
if (sessionRows.length > 0) {
|
||||
const sessionDate = sessionRows[0].session_date;
|
||||
let dateStr;
|
||||
if (sessionDate instanceof Date) {
|
||||
dateStr = sessionDate.toISOString().split('T')[0];
|
||||
} else if (typeof sessionDate === 'string') {
|
||||
dateStr = sessionDate.split('T')[0];
|
||||
} else {
|
||||
dateStr = new Date(sessionDate).toISOString().split('T')[0];
|
||||
}
|
||||
|
||||
const userIds = members.map(m => m.user_id);
|
||||
const duplicates = await TbmModel.checkDuplicateAssignments(dateStr, userIds, sessionId);
|
||||
|
||||
if (duplicates.length > 0) {
|
||||
const names = duplicates.map(d => d.worker_name).join(', ');
|
||||
return res.status(409).json({
|
||||
success: false,
|
||||
message: `다음 작업자가 이미 다른 TBM에 배정되어 있습니다: ${names}`,
|
||||
duplicates: duplicates
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await TbmModel.addTeamMembers(sessionId, members);
|
||||
res.json({
|
||||
success: true,
|
||||
|
||||
@@ -848,6 +848,27 @@ const TbmModel = {
|
||||
[checkId]
|
||||
);
|
||||
return { affectedRows: result.affectedRows };
|
||||
},
|
||||
|
||||
// ==================== 중복 배정 검증 ====================
|
||||
|
||||
checkDuplicateAssignments: async (date, userIds, excludeSessionId) => {
|
||||
if (!userIds || userIds.length === 0) return [];
|
||||
const db = await getDb();
|
||||
const placeholders = userIds.map(() => '?').join(',');
|
||||
const [rows] = await db.query(
|
||||
`SELECT ta.user_id, w.worker_name, lw.worker_name AS leader_name
|
||||
FROM tbm_team_assignments ta
|
||||
INNER JOIN tbm_sessions s ON ta.session_id = s.session_id
|
||||
INNER JOIN workers w ON ta.user_id = w.user_id
|
||||
LEFT JOIN workers lw ON s.leader_user_id = lw.user_id
|
||||
WHERE s.session_date = ?
|
||||
AND ta.session_id != ?
|
||||
AND ta.user_id IN (${placeholders})
|
||||
GROUP BY ta.user_id`,
|
||||
[date, excludeSessionId, ...userIds]
|
||||
);
|
||||
return rows;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ try {
|
||||
console.warn('이미지 최적화를 위해 npm install sharp 를 실행하세요.');
|
||||
}
|
||||
|
||||
// 업로드 디렉토리 설정
|
||||
// 업로드 디렉토리 설정 (Docker 볼륨 마운트: /usr/src/app/uploads)
|
||||
const UPLOAD_DIRS = {
|
||||
issues: path.join(__dirname, '../public/uploads/issues'),
|
||||
equipments: path.join(__dirname, '../public/uploads/equipments')
|
||||
issues: path.join(__dirname, '../uploads/issues'),
|
||||
equipments: path.join(__dirname, '../uploads/equipments')
|
||||
};
|
||||
const UPLOAD_DIR = UPLOAD_DIRS.issues; // 기존 호환성 유지
|
||||
const MAX_SIZE = { width: 1920, height: 1920 };
|
||||
|
||||
Reference in New Issue
Block a user