252 lines
11 KiB
PHP
252 lines
11 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
// auth.php and session are already initialized by skin/index.php before this file is included.
|
|
|
|
$userName = edu_user_field('name', (string) ($_SESSION['member_name'] ?? ''));
|
|
$userRank = (string) ($_SESSION['rank_name'] ?? edu_user_field('rank_name', ''));
|
|
$memberId = edu_current_member_id();
|
|
$sysCompCode = (string) ($_SESSION['sys_comp_code'] ?? '');
|
|
|
|
require_once __DIR__ . '/db_conn.php';
|
|
|
|
// 세션에 누락된 정보 DB에서 보완
|
|
if (($userRank === '' || $sysCompCode === '') && $memberId !== '') {
|
|
try {
|
|
if ($sysCompCode !== '') {
|
|
$__st = db_conn()->prepare(
|
|
'SELECT name, rank_name, sys_comp_code FROM edu_users WHERE member_id = ? AND sys_comp_code = ? LIMIT 1'
|
|
);
|
|
$__st->execute([$memberId, $sysCompCode]);
|
|
} else {
|
|
$__st = db_conn()->prepare(
|
|
'SELECT name, rank_name, sys_comp_code FROM edu_users WHERE member_id = ? ORDER BY sys_comp_code LIMIT 1'
|
|
);
|
|
$__st->execute([$memberId]);
|
|
}
|
|
$__row = $__st->fetch(PDO::FETCH_ASSOC);
|
|
if ($__row) {
|
|
if ($userName === '')
|
|
$userName = (string) ($__row['name'] ?? '');
|
|
if ($userRank === '')
|
|
$userRank = (string) ($__row['rank_name'] ?? '');
|
|
if ($sysCompCode === '')
|
|
$sysCompCode = (string) ($__row['sys_comp_code'] ?? '');
|
|
}
|
|
} catch (Throwable $__e) {
|
|
error_log('[main_data rank fallback] ' . $__e->getMessage());
|
|
}
|
|
}
|
|
$userRank = trim($userRank);
|
|
|
|
// ── 키워드 & 영상 설정 ─────────────────────────────────────────
|
|
$allKeywords = []; // 전체 키워드 목록 (모달 선택용, 21개)
|
|
$adminKeywords = []; // 회사 추천 키워드 (kw-deny)
|
|
$myKeywords = []; // 사용자 선택 키워드 0~3개 (kw-allow)
|
|
$videosJson = '[]';
|
|
$myKwJson = '[]'; // JS fallback용
|
|
$totalMin = 0;
|
|
$avgWatchMin = 0; // 전체 평균 학습시간 (분)
|
|
$mainDataError = ''; // DEBUG용 오류 메시지
|
|
|
|
try {
|
|
$pdo = db_conn();
|
|
$pdo->exec("SET NAMES 'utf8mb4'");
|
|
|
|
// edu_user_keywords 테이블 자동 생성 (권한 없으면 무시)
|
|
try {
|
|
$pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS edu_user_keywords (
|
|
member_id VARCHAR(20) NOT NULL,
|
|
sys_comp_code VARCHAR(20) NOT NULL DEFAULT '',
|
|
keyword_code VARCHAR(20) NOT NULL,
|
|
sort_order INT NOT NULL DEFAULT 0,
|
|
PRIMARY KEY (member_id, sys_comp_code, keyword_code)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
|
");
|
|
} catch (Throwable $__ce) {
|
|
error_log('[main_data] CREATE edu_user_keywords: ' . $__ce->getMessage());
|
|
}
|
|
|
|
// 전체 키워드 (모달 선택용) — sort_order 없는 테이블도 안전하게 base_code만으로 정렬
|
|
$stmtKw = $pdo->query("SELECT base_code AS keyword_code, code_name AS keyword_name FROM edu_codes WHERE group_code = 'KW100' ORDER BY base_code");
|
|
$allKeywords = $stmtKw->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// 회사 추천 키워드: 반드시 edu_recommend_keywords의 코드값을 edu_codes와 한글 매핑해서 사용
|
|
try {
|
|
$stmtAdm = $pdo->prepare("
|
|
SELECT rk.keyword_code, ec.code_name AS keyword_name
|
|
FROM edu_recommend_keywords rk
|
|
JOIN edu_codes ec ON ec.base_code = rk.keyword_code
|
|
WHERE rk.is_active = 1
|
|
AND rk.keyword_code IS NOT NULL
|
|
AND rk.keyword_code <> ''
|
|
AND ec.group_code = 'KW100'
|
|
ORDER BY rk.keyword_code
|
|
LIMIT 2
|
|
");
|
|
$stmtAdm->execute();
|
|
$adminKeywords = $stmtAdm->fetchAll(PDO::FETCH_ASSOC);
|
|
error_log('[main_data] edu_recommend_keywords result: ' . count($adminKeywords) . ' rows');
|
|
} catch (Throwable $__ae) {
|
|
error_log('[main_data] edu_recommend_keywords 쿼리 실패: ' . $__ae->getMessage());
|
|
$adminKeywords = [];
|
|
}
|
|
|
|
// 사용자 선택 키워드 (0~3개)
|
|
// ⚠️ sys_comp_code 없어도 저장되도록 조건 완화 (저장 후 바로 조회 위함)
|
|
// sys_comp_code 조건 추가 : 권오재
|
|
if ($memberId !== '') {
|
|
$stmtMy = $pdo->prepare("
|
|
SELECT uk.keyword_code, ec.code_name AS keyword_name
|
|
FROM edu_user_keywords uk
|
|
JOIN edu_codes ec ON ec.base_code = uk.keyword_code
|
|
WHERE uk.member_id = ?
|
|
AND uk.sys_comp_code = ?
|
|
AND uk.sys_comp_code <> ''
|
|
ORDER BY uk.keyword_code
|
|
LIMIT 3
|
|
");
|
|
$stmtMy->execute([$memberId, $sysCompCode]);
|
|
$myKeywords = $stmtMy->fetchAll(PDO::FETCH_ASSOC);
|
|
error_log('[main_data] myKeywords query: memberId=' . $memberId . ', result_count=' . count($myKeywords));
|
|
}
|
|
|
|
// JS fallback용: 사용자 키워드명 배열 (JSON)
|
|
$myKwJson = json_encode(
|
|
array_column($myKeywords, 'keyword_name'),
|
|
JSON_UNESCAPED_UNICODE | JSON_HEX_TAG
|
|
);
|
|
|
|
// 누적 시청 시간 (게이지): watch_tm 기준
|
|
if ($memberId !== '' && $sysCompCode !== '') {
|
|
$stmtTm = $pdo->prepare(
|
|
'SELECT COALESCE(SUM(watch_tm), 0) FROM edu_learning_histories WHERE member_id = ? AND sys_comp_code = ?'
|
|
);
|
|
$stmtTm->execute([$memberId, $sysCompCode]);
|
|
$totalMin = (int) floor((int) $stmtTm->fetchColumn() / 60);
|
|
}
|
|
|
|
// 전체 평균 학습시간 계산: (모든 member_id의 총 watch_tm 합계) / (학습경험이 있는 사용자 수)
|
|
try {
|
|
$stmtAvg = $pdo->prepare("
|
|
SELECT
|
|
COALESCE(SUM(h.watch_tm), 0) as total_watch_tm,
|
|
COUNT(DISTINCT h.member_id) as unique_members
|
|
FROM edu_learning_histories h
|
|
WHERE h.sys_comp_code = ?
|
|
");
|
|
$stmtAvg->execute([$sysCompCode]);
|
|
$avgRow = $stmtAvg->fetch(PDO::FETCH_ASSOC);
|
|
if ($avgRow) {
|
|
$totalWatchTm = (int) ($avgRow['total_watch_tm'] ?? 0);
|
|
$uniqueMembers = (int) ($avgRow['unique_members'] ?? 0);
|
|
if ($uniqueMembers > 0) {
|
|
$avgWatchMin = (int) floor($totalWatchTm / $uniqueMembers / 60);
|
|
// 최소 50분으로 설정해서 게이지의 maxValue 보장
|
|
$avgWatchMin = max(50, $avgWatchMin);
|
|
error_log('[main_data] avgWatchMin calc: totalWatchTm=' . $totalWatchTm . ', uniqueMembers=' . $uniqueMembers . ', avgWatchMin=' . $avgWatchMin);
|
|
}
|
|
}
|
|
} catch (Throwable $__ae) {
|
|
error_log('[main_data] avgWatchMin 계산 실패: ' . $__ae->getMessage());
|
|
}
|
|
|
|
// ── Pick 영상(추천) + 키워드 영상 5개 조합: 항상 6개 보장 ──
|
|
$videos = [];
|
|
// 1. Pick(추천) 영상: is_offer=1, 본인 제외, 랜덤 1개
|
|
$stmtPick = $pdo->prepare("SELECT * FROM edu_contents WHERE is_offer=1 AND is_active=1 AND issue_type_code = 'IS10003' AND member_id != ? ORDER BY RAND() LIMIT 1");
|
|
$stmtPick->execute([$memberId]);
|
|
$pick = $stmtPick->fetch(PDO::FETCH_ASSOC);
|
|
if ($pick) {
|
|
$pick['is_pick'] = true;
|
|
$videos[] = $pick;
|
|
}
|
|
// 2. 나머지 5개: 실제 사용자 키워드 기반 영상 쿼리로 채움
|
|
$keywordVideos = [];
|
|
$userKeywordCodes = array_column($myKeywords, 'keyword_code');
|
|
if (!empty($userKeywordCodes)) {
|
|
$ph = implode(',', array_fill(0, count($userKeywordCodes), '?'));
|
|
$sql = "SELECT * FROM edu_contents c
|
|
JOIN edu_content_keywords k ON c.content_id = k.content_id AND k.is_active = 1
|
|
WHERE c.is_active=1 AND k.keyword_code IN ($ph)";
|
|
$params = $userKeywordCodes;
|
|
// pick과 중복 제거
|
|
if ($pick && isset($pick['content_id'])) {
|
|
$sql .= " AND c.content_id != ?";
|
|
$params[] = $pick['content_id'];
|
|
}
|
|
$sql .= " GROUP BY c.content_id ORDER BY c.content_id DESC LIMIT 5";
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|
$row['is_pick'] = false;
|
|
$keywordVideos[] = $row;
|
|
}
|
|
}
|
|
// 부족하면 전체 영상에서 추가로 채움
|
|
if (count($keywordVideos) < 5) {
|
|
$already = array_column($keywordVideos, 'content_id');
|
|
if ($pick && isset($pick['content_id']))
|
|
$already[] = $pick['content_id'];
|
|
$ph = implode(',', array_fill(0, count($already), '?'));
|
|
$sql = "SELECT * FROM edu_contents WHERE is_active=1";
|
|
if (!empty($already))
|
|
$sql .= " AND content_id NOT IN ($ph)";
|
|
$sql .= " ORDER BY content_id DESC LIMIT " . (5 - count($keywordVideos));
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($already);
|
|
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
|
$row['is_pick'] = false;
|
|
$keywordVideos[] = $row;
|
|
}
|
|
}
|
|
// 최대 5개만
|
|
$keywordVideos = array_slice($keywordVideos, 0, 5);
|
|
foreach ($keywordVideos as $v) {
|
|
$videos[] = $v;
|
|
}
|
|
// 3. 부족하면 빈 카드로 채움
|
|
while (count($videos) < 6) {
|
|
$videos[] = [
|
|
'content_id' => 'empty_' . count($videos),
|
|
'title' => '',
|
|
'is_pick' => false,
|
|
'img' => '',
|
|
'category' => '',
|
|
'author' => '',
|
|
'keywords' => [],
|
|
];
|
|
}
|
|
|
|
// 카테고리 코드→한글명 매핑 (edu_codes)
|
|
$codeMap = [];
|
|
$normCode = static function (string $code): string {
|
|
return preg_replace('/[^A-Z0-9]/', '', strtoupper(trim($code)));
|
|
};
|
|
try {
|
|
$stmtCm = $pdo->query("SELECT base_code, code_name FROM edu_codes");
|
|
foreach ($stmtCm->fetchAll(PDO::FETCH_ASSOC) as $cr) {
|
|
$baseCode = $normCode((string) ($cr['base_code'] ?? ''));
|
|
if ($baseCode === '')
|
|
continue;
|
|
$codeMap[$baseCode] = $cr['code_name'];
|
|
}
|
|
} catch (Throwable $e) { /* ignore */
|
|
}
|
|
foreach ($videos as &$v) {
|
|
if (!is_array($v) || !isset($v['content_id']) || strpos((string) ($v['content_id'] ?? ''), 'empty_') === 0)
|
|
continue;
|
|
$categoryCode = $normCode((string) ($v['category_code'] ?? ''));
|
|
$groupCode = $normCode((string) ($v['category_group'] ?? ''));
|
|
$v['category'] = $codeMap[$categoryCode] ?? ($v['category_code'] ?? '');
|
|
$v['subcate'] = $codeMap[$groupCode] ?? ($v['category_group'] ?? '');
|
|
}
|
|
unset($v);
|
|
|
|
// 4. JSON 직렬화
|
|
$videosJson = json_encode($videos, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG);
|
|
} catch (Throwable $e) {
|
|
$mainDataError = $e->getMessage();
|
|
error_log('[main_data] ' . $e->getMessage());
|
|
}
|