feat: 챗봇 신고 페이지 AI 백엔드 추가 및 기타 개선

- ai-service: 챗봇 분석/요약 엔드포인트 추가 (chatbot.py, chatbot_service.py)
- tkreport: 챗봇 신고 페이지 (chat-report.html/js/css), nginx ai-api 프록시
- tkreport: 이미지 업로드 서비스 개선, M-Project 연동 신고자 정보 전달
- system1: TBM 작업보고서 UI 개선
- TKQC: 관리함/수신함 기능 개선

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-09 14:11:00 +09:00
parent 5aeda43605
commit d42380ff63
16 changed files with 1522 additions and 59 deletions

View File

@@ -392,12 +392,16 @@ function openNewTbmModal() {
sessionDateDisplay.textContent = `${year}${parseInt(month)}${parseInt(day)}일 (${dayName})`;
}
// 입력자 자동 설정 (readonly)
// 입력자 자동 설정
if (currentUser && currentUser.user_id) {
const worker = allWorkers.find(w => w.user_id === currentUser.user_id);
if (worker) {
document.getElementById('leaderName').textContent = worker.worker_name;
document.getElementById('leaderId').value = worker.user_id;
} else {
// 어드민: 작업자 목록에 없음 → 이름 표시, leaderId 비움
document.getElementById('leaderName').textContent = currentUser.name || '관리자';
document.getElementById('leaderId').value = '';
}
} else if (currentUser && currentUser.name) {
document.getElementById('leaderName').textContent = currentUser.name;
@@ -534,20 +538,15 @@ function populateLeaderSelect() {
if (!leaderSelect) return;
// 로그인한 사용자가 작업자와 연결되어 있는지 확인
if (currentUser && currentUser.user_id) {
const isWorker = currentUser && currentUser.user_id && allWorkers.find(w => w.user_id === currentUser.user_id);
if (isWorker) {
// 작업자와 연결된 경우: 자동으로 선택하고 비활성화
const worker = allWorkers.find(w => w.user_id === currentUser.user_id);
if (worker) {
const jobTypeText = worker.job_type ? ` (${escapeHtml(worker.job_type)})` : '';
leaderSelect.innerHTML = `<option value="${escapeHtml(worker.user_id)}" selected>${escapeHtml(worker.worker_name)}${jobTypeText}</option>`;
leaderSelect.disabled = true;
} else {
// 작업자를 찾을 수 없는 경우
leaderSelect.innerHTML = '<option value="">입력자를 찾을 수 없습니다</option>';
leaderSelect.disabled = true;
}
const worker = isWorker;
const jobTypeText = worker.job_type ? ` (${escapeHtml(worker.job_type)})` : '';
leaderSelect.innerHTML = `<option value="${escapeHtml(worker.user_id)}" selected>${escapeHtml(worker.worker_name)}${jobTypeText}</option>`;
leaderSelect.disabled = true;
} else {
// 관리자 계정 (user_id가 없음): 드롭다운으로 선택 가능
// 관리자 또는 작업자 목록에 없는 계정: 드롭다운으로 선택 가능
const leaders = allWorkers.filter(w =>
w.job_type === 'leader' || w.job_type === '그룹장' || w.job_type === 'admin'
);
@@ -638,13 +637,8 @@ async function saveTbmSession() {
let leaderId = parseInt(document.getElementById('leaderId').value);
if (!leaderId || isNaN(leaderId)) {
if (!currentUser.user_id) {
leaderId = null;
} else {
console.error(' 입력자 설정 오류');
showToast('입력자 정보가 올바르지 않습니다.', 'error');
return;
}
// 어드민이거나 작업자 목록에 없는 사용자: leaderId null로 저장 가능
leaderId = null;
}
const sessionData = {