refactor: TBM/작업보고 코드 통합 및 API 쿼리 버그 수정

- 공통 유틸리티 추출 (common/utils.js, common/base-state.js)
- TBM 모바일 인라인 JS/CSS 외부 파일로 분리 (tbm-mobile.js, tbm-mobile.css)
- 미사용 코드 삭제 (index.js, work-report-*.js 등 5개 파일)
- TBM/작업보고 state.js, utils.js를 공통 모듈 기반으로 전환
- 작업보고서 SSO 인증 호환 수정 (token/user 함수)
- tbmModel.js: incomplete-reports 쿼리에서 users→sso_users 조인 수정, leader_name 조인 추가
- docker-compose.yml: system1-web 볼륨 마운트 추가
- 모바일 인계(handover) 기능 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-05 07:51:24 +09:00
parent 22a37ac4d9
commit 4388628788
89 changed files with 5296 additions and 5046 deletions

View File

@@ -10,7 +10,7 @@
* 5. 현재 연도 연차 잔액 초기화 (workers.annual_leave 사용)
*/
const bcrypt = require('bcryptjs');
const bcrypt = require('bcrypt');
const { generateUniqueUsername } = require('../../utils/hangulToRoman');
exports.up = async function(knex) {

View File

@@ -0,0 +1,40 @@
/**
* users 테이블에 department_id 컬럼 추가
* 사용자-부서 직접 연결을 위한 마이그레이션
*/
exports.up = async function(knex) {
const hasColumn = await knex.schema.hasColumn('users', 'department_id');
if (!hasColumn) {
await knex.schema.table('users', (table) => {
table.integer('department_id').unsigned().defaultTo(null).after('worker_id')
.comment('소속 부서 ID');
table.foreign('department_id').references('department_id').inTable('departments')
.onDelete('SET NULL');
});
// 기존 데이터 backfill: 작업자가 연결된 사용자는 해당 작업자의 department_id를 복사
await knex.raw(`
UPDATE users u
INNER JOIN workers w ON u.worker_id = w.worker_id
SET u.department_id = w.department_id
WHERE u.worker_id IS NOT NULL AND w.department_id IS NOT NULL
`);
console.log('✅ users.department_id 컬럼 추가 및 기존 데이터 backfill 완료');
} else {
console.log('⏭️ users.department_id 컬럼이 이미 존재합니다');
}
};
exports.down = async function(knex) {
const hasColumn = await knex.schema.hasColumn('users', 'department_id');
if (hasColumn) {
await knex.schema.table('users', (table) => {
table.dropForeign('department_id');
table.dropColumn('department_id');
});
}
};

View File

@@ -1,26 +0,0 @@
/**
* TBM 팀 배정에 근태 유형 컬럼 추가
* - attendance_type: 근태유형 (overtime/regular/annual/half/quarter/early)
* - attendance_hours: 추가시간(overtime) 또는 실제근무시간(early)
*
* @since 2026-02-24
*/
exports.up = function(knex) {
return knex.raw(`
ALTER TABLE tbm_team_assignments
ADD COLUMN attendance_type ENUM('overtime','regular','annual','half','quarter','early')
DEFAULT NULL
COMMENT '근태유형',
ADD COLUMN attendance_hours DECIMAL(4,1) DEFAULT NULL
COMMENT '추가시간(overtime) 또는 실제근무시간(early)'
`);
};
exports.down = function(knex) {
return knex.raw(`
ALTER TABLE tbm_team_assignments
DROP COLUMN attendance_type,
DROP COLUMN attendance_hours
`);
};

View File

@@ -1,43 +0,0 @@
// 20260225000003_add_split_seq.js
// 같은 작업자가 같은 세션에서 여러 분할 항목을 가질 수 있도록 split_seq 추가
exports.up = function(knex) {
return knex.raw(`
ALTER TABLE tbm_team_assignments
ADD COLUMN split_seq INT UNSIGNED DEFAULT 0 AFTER work_hours
`).then(() => {
return knex.raw(`
ALTER TABLE tbm_team_assignments
DROP INDEX tbm_team_assignments_session_id_worker_id_unique
`);
}).then(() => {
return knex.raw(`
ALTER TABLE tbm_team_assignments
ADD UNIQUE INDEX uniq_session_worker_seq (session_id, worker_id, split_seq)
`);
});
};
exports.down = function(knex) {
return knex.raw(`
ALTER TABLE tbm_team_assignments
DROP INDEX uniq_session_worker_seq
`).then(() => {
return knex.raw(`
DELETE t1 FROM tbm_team_assignments t1
INNER JOIN tbm_team_assignments t2
WHERE t1.assignment_id > t2.assignment_id
AND t1.session_id = t2.session_id
AND t1.worker_id = t2.worker_id
`);
}).then(() => {
return knex.raw(`
ALTER TABLE tbm_team_assignments
ADD UNIQUE INDEX tbm_team_assignments_session_id_worker_id_unique (session_id, worker_id)
`);
}).then(() => {
return knex.raw(`
ALTER TABLE tbm_team_assignments DROP COLUMN split_seq
`);
});
};