Merge branch 'main' of https://g.wace.me/jskim/vexplor_dev
Some checks failed
Build and Push Images / build-and-push (push) Failing after 56s
Some checks failed
Build and Push Images / build-and-push (push) Failing after 56s
This commit is contained in:
@@ -7,9 +7,8 @@ import { query, queryOne } from "../database/db";
|
||||
import { logger } from "../utils/logger";
|
||||
import { encryptionService } from "../services/encryptionService";
|
||||
import {
|
||||
runScheduleNow,
|
||||
sendSmartFactoryLog,
|
||||
getTodayPlanStatus,
|
||||
planDailySends,
|
||||
} from "../utils/smartFactoryLog";
|
||||
|
||||
/**
|
||||
@@ -254,7 +253,7 @@ export const upsertSchedule = async (
|
||||
res: Response
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const { companyCode, isActive, timeStart, timeEnd, excludeWeekend, excludeHolidays } = req.body;
|
||||
const { companyCode, isActive, timeStart, timeEnd, excludeWeekend, excludeHolidays, dailyCount } = req.body;
|
||||
|
||||
if (!companyCode) {
|
||||
res.status(400).json({ success: false, message: "회사코드는 필수입니다." });
|
||||
@@ -262,11 +261,11 @@ export const upsertSchedule = async (
|
||||
}
|
||||
|
||||
await query(
|
||||
`INSERT INTO smart_factory_schedule (company_code, is_active, time_start, time_end, exclude_weekend, exclude_holidays, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, NOW())
|
||||
`INSERT INTO smart_factory_schedule (company_code, is_active, time_start, time_end, exclude_weekend, exclude_holidays, daily_count, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, NOW())
|
||||
ON CONFLICT (company_code) DO UPDATE SET
|
||||
is_active = $2, time_start = $3, time_end = $4,
|
||||
exclude_weekend = $5, exclude_holidays = $6, updated_at = NOW()`,
|
||||
exclude_weekend = $5, exclude_holidays = $6, daily_count = $7, updated_at = NOW()`,
|
||||
[
|
||||
companyCode,
|
||||
isActive ?? false,
|
||||
@@ -274,13 +273,12 @@ export const upsertSchedule = async (
|
||||
timeEnd || "17:30",
|
||||
excludeWeekend ?? true,
|
||||
excludeHolidays ?? true,
|
||||
Math.max(1, Math.min(3, dailyCount || 1)),
|
||||
]
|
||||
);
|
||||
|
||||
// 스케줄 변경 시 오늘 계획 재생성
|
||||
await planDailySends();
|
||||
|
||||
res.json({ success: true, message: "스케줄이 저장되었습니다." });
|
||||
// 계획은 매일 00:05에만 생성 (즉시 재생성하면 지난 시각 소급 전송 위험)
|
||||
res.json({ success: true, message: "스케줄이 저장되었습니다. 내일 00:05부터 적용됩니다." });
|
||||
} catch (error) {
|
||||
logger.error("스케줄 저장 실패:", error);
|
||||
res.status(500).json({ success: false, message: "스케줄 저장 실패" });
|
||||
@@ -307,23 +305,6 @@ export const deleteSchedule = async (
|
||||
/**
|
||||
* POST /api/admin/smart-factory-log/schedules/:companyCode/run-now
|
||||
*/
|
||||
export const runScheduleNowHandler = async (
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const { companyCode } = req.params;
|
||||
const result = await runScheduleNow(companyCode);
|
||||
res.json({ success: true, data: result });
|
||||
} catch (error) {
|
||||
logger.error("즉시 실행 실패:", error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : "즉시 실행 실패",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* GET /api/admin/smart-factory-log/schedules/today-plan
|
||||
*/
|
||||
@@ -502,3 +483,92 @@ export const deleteApiKey = async (
|
||||
res.status(500).json({ success: false, message: "API 키 삭제 실패" });
|
||||
}
|
||||
};
|
||||
|
||||
// ─── 즉시 전송 ───
|
||||
|
||||
/**
|
||||
* GET /api/admin/smart-factory-log/users/:companyCode
|
||||
* 회사별 사용자 목록 조회 (즉시 전송 대상 선택용)
|
||||
*/
|
||||
export const getCompanyUsers = async (
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const { companyCode } = req.params;
|
||||
|
||||
const users = await query<any>(
|
||||
`SELECT user_id, user_name, dept_name
|
||||
FROM user_info
|
||||
WHERE company_code = $1 AND (status = 'active' OR status IS NULL)
|
||||
ORDER BY user_name`,
|
||||
[companyCode]
|
||||
);
|
||||
|
||||
res.json({ success: true, data: users });
|
||||
} catch (error) {
|
||||
logger.error("사용자 목록 조회 실패:", error);
|
||||
res.status(500).json({ success: false, message: "사용자 목록 조회 실패" });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* POST /api/admin/smart-factory-log/send-now
|
||||
* 선택한 사용자 즉시 전송
|
||||
* body: { companyCode, userIds: string[], timeStart?, timeEnd? }
|
||||
*/
|
||||
export const sendNow = async (
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const { companyCode, userIds } = req.body;
|
||||
|
||||
logger.info(`=== 즉시 전송 API 호출 === companyCode=${companyCode}, userIds=${JSON.stringify(userIds)}`);
|
||||
|
||||
if (!companyCode || !userIds || userIds.length === 0) {
|
||||
res.status(400).json({ success: false, message: "회사코드와 사용자를 선택해주세요." });
|
||||
return;
|
||||
}
|
||||
|
||||
// 사용자 정보 조회
|
||||
const users = await query<{ user_id: string; user_name: string }>(
|
||||
`SELECT user_id, user_name FROM user_info WHERE company_code = $1 AND user_id = ANY($2)`,
|
||||
[companyCode, userIds]
|
||||
);
|
||||
|
||||
logger.info(`즉시 전송 대상: ${users.length}명 (조회된 사용자: ${users.map(u => u.user_id).join(", ")})`);
|
||||
|
||||
// 현재 시간으로 즉시 전송
|
||||
let success = 0;
|
||||
let fail = 0;
|
||||
const remoteAddr = req.ip || "127.0.0.1";
|
||||
|
||||
for (const user of users) {
|
||||
try {
|
||||
logger.info(`즉시 전송 시작: ${user.user_id}`);
|
||||
await sendSmartFactoryLog({
|
||||
userId: user.user_id,
|
||||
userName: user.user_name,
|
||||
remoteAddr,
|
||||
useType: "접속",
|
||||
companyCode,
|
||||
});
|
||||
success++;
|
||||
logger.info(`즉시 전송 성공: ${user.user_id}`);
|
||||
} catch (e) {
|
||||
fail++;
|
||||
logger.error(`즉시 전송 실패: ${user.user_id}`, e);
|
||||
}
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: { total: users.length, success, fail },
|
||||
message: `${success}명 전송 완료${fail > 0 ? `, ${fail}명 실패` : ""}`,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error("즉시 전송 실패:", error);
|
||||
res.status(500).json({ success: false, message: "즉시 전송 실패" });
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user