0) ? (int)round(($watchTm / $contentTm) * 100) : 0; $gauge = max(0, min(100, $gauge)); $raw = trim((string)($row['content_url'] ?? '')); if (preg_match('/(?:v=|youtu\.be\/)([A-Za-z0-9_-]{11})/', $raw, $m)) { $videoId = $m[1]; } elseif (preg_match('/^[A-Za-z0-9_-]{11}$/', $raw)) { $videoId = $raw; } else { $videoId = ''; } $thumbFromDb = trim((string)($row['thumbnail_url'] ?? '')); $url = $videoId !== '' ? "https://www.youtube.com/watch?v={$videoId}" : $raw; $thumbnail = $thumbFromDb !== '' ? $thumbFromDb : ($videoId !== '' ? "https://img.youtube.com/vi/{$videoId}/sddefault.jpg" : '/img/video/img_thumb_01.png'); return [ 'content_id' => $row['content_id'] ?? '', 'category_code' => $row['category_code'] ?? '', 'category_name' => $catMap[$row['category_code'] ?? ''] ?? ($row['category_code'] ?? ''), 'title' => $row['title'] ?? '', 'url' => $url, 'thumbnail' => $thumbnail, 'watch_tm' => (int)($row['watch_tm'] ?? 0), 'content_tm' => (int)($row['content_tm'] ?? 0), 'gauge' => $gauge, 'is_bookmarked' => !empty($row['is_bookmarked']), 'keywords' => $keywords, ]; } function category_tag_class(string $categoryCode): string { $map = [ 'CA10001' => 'myclass', 'CA10002' => 'onboarding', 'CA10003' => 'legal', 'CA10004' => 'leader', 'CA10005' => 'insight', 'CA10006' => 'biz', ]; return $map[$categoryCode] ?? 'etc'; } try { $pdo = db_conn(); $pdo->exec("SET NAMES 'utf8mb4'"); $tab = trim((string)($_GET['tab'] ?? 'watching')); $page = max(1, (int)($_GET['page'] ?? 1)); $limit = max(1, (int)($_GET['limit'] ?? 12)); $offset = ($page - 1) * $limit; $CATEGORY_MAP = [ 'CA10001' => '마이클래스', 'CA10002' => '온보딩', 'CA10003' => '법정교육', 'CA10004' => '리더십', 'CA10005' => '인사이트', 'CA10006' => '비즈트렌드', ]; $stmtCode = $pdo->prepare(" SELECT base_code, code_name FROM edu_codes WHERE group_code = 'CA100' AND is_active = '1' ORDER BY code "); $stmtCode->execute(); foreach ($stmtCode->fetchAll(PDO::FETCH_ASSOC) as $row) { $CATEGORY_MAP[$row['base_code']] = $row['code_name']; } // 탭 카운트 $stmtCountWatching = $pdo->prepare(" SELECT COUNT(*) FROM edu_learning_histories WHERE member_id = :member_id AND sys_comp_code = :sys_comp_code AND watch_tm < content_tm "); $stmtCountWatching->execute([ ':member_id' => $memberId, ':sys_comp_code' => $sysCompCode, ]); $countWatching = (int)$stmtCountWatching->fetchColumn(); $stmtCountCompleted = $pdo->prepare(" SELECT COUNT(*) FROM edu_learning_histories WHERE member_id = :member_id AND sys_comp_code = :sys_comp_code AND watch_tm >= content_tm "); $stmtCountCompleted->execute([ ':member_id' => $memberId, ':sys_comp_code' => $sysCompCode, ]); $countCompleted = (int)$stmtCountCompleted->fetchColumn(); $stmtCountSaved = $pdo->prepare(" SELECT COUNT(*) FROM edu_content_wishlist WHERE member_id = :member_id AND sys_comp_code = :sys_comp_code AND is_active = '1' "); $stmtCountSaved->execute([ ':member_id' => $memberId, ':sys_comp_code' => $sysCompCode, ]); $countSaved = (int)$stmtCountSaved->fetchColumn(); if ($tab === 'saved') { $countTotal = $countSaved; $sql = " SELECT c.content_id, c.category_code, c.title, c.content_url, c.thumbnail_url, lh.watch_tm, lh.content_tm, 1 AS is_bookmarked, GROUP_CONCAT(DISTINCT ck.keyword_code ORDER BY ck.keyword_code SEPARATOR ',') AS keywords FROM edu_content_wishlist cw INNER JOIN edu_contents c ON c.content_id = cw.content_id LEFT JOIN edu_learning_histories lh ON lh.content_id = c.content_id AND lh.member_id = cw.member_id AND lh.sys_comp_code = cw.sys_comp_code LEFT JOIN edu_content_keywords ck ON ck.content_id = c.content_id WHERE cw.member_id = :member_id AND cw.sys_comp_code = :sys_comp_code AND cw.is_active = '1' GROUP BY c.content_id ORDER BY COALESCE(cw.favorited_at, cw.updated_at) DESC LIMIT :limit OFFSET :offset "; } elseif ($tab === 'completed') { $countTotal = $countCompleted; $sql = " SELECT c.content_id, c.category_code, c.title, c.content_url, c.thumbnail_url, lh.watch_tm, lh.content_tm, CASE WHEN cw.content_id IS NOT NULL THEN 1 ELSE 0 END AS is_bookmarked, GROUP_CONCAT(DISTINCT ck.keyword_code ORDER BY ck.keyword_code SEPARATOR ',') AS keywords FROM edu_learning_histories lh INNER JOIN edu_contents c ON c.content_id = lh.content_id LEFT JOIN edu_content_wishlist cw ON cw.content_id = c.content_id AND cw.member_id = lh.member_id AND cw.sys_comp_code = lh.sys_comp_code AND cw.is_active = '1' LEFT JOIN edu_content_keywords ck ON ck.content_id = c.content_id WHERE lh.member_id = :member_id AND lh.sys_comp_code = :sys_comp_code AND lh.watch_tm >= lh.content_tm GROUP BY c.content_id ORDER BY COALESCE(lh.completed_at, lh.last_viewed_at) DESC LIMIT :limit OFFSET :offset "; } else { $tab = 'watching'; $countTotal = $countWatching; $sql = " SELECT c.content_id, c.category_code, c.title, c.content_url, c.thumbnail_url, lh.watch_tm, lh.content_tm, CASE WHEN cw.content_id IS NOT NULL THEN 1 ELSE 0 END AS is_bookmarked, GROUP_CONCAT(DISTINCT ck.keyword_code ORDER BY ck.keyword_code SEPARATOR ',') AS keywords FROM edu_learning_histories lh INNER JOIN edu_contents c ON c.content_id = lh.content_id LEFT JOIN edu_content_wishlist cw ON cw.content_id = c.content_id AND cw.member_id = lh.member_id AND cw.sys_comp_code = lh.sys_comp_code AND cw.is_active = '1' LEFT JOIN edu_content_keywords ck ON ck.content_id = c.content_id WHERE lh.member_id = :member_id AND lh.sys_comp_code = :sys_comp_code AND lh.watch_tm < lh.content_tm GROUP BY c.content_id ORDER BY lh.last_viewed_at DESC LIMIT :limit OFFSET :offset "; } $stmt = $pdo->prepare($sql); $stmt->bindValue(':member_id', $memberId, PDO::PARAM_STR); $stmt->bindValue(':sys_comp_code', $sysCompCode, PDO::PARAM_STR); $stmt->bindValue(':limit', $limit, PDO::PARAM_INT); $stmt->bindValue(':offset', $offset, PDO::PARAM_INT); $stmt->execute(); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); ob_start(); foreach ($rows as $row) { $item = map_content_row($row, $CATEGORY_MAP); $tagClass = category_tag_class($item['category_code']); ?>