false, 'message' => 'not_logged_in'], JSON_UNESCAPED_UNICODE); exit; } try { $pdo = db_conn(); $onboardingGroups = [ 'CA200O01', 'CA200O02', 'CA200O03', 'CA200O04', 'CA200O05', 'CA200O06', 'CA200O07', 'CA200O08', 'CA200O09', 'CA200O10', ]; $placeholders = implode(',', array_fill(0, count($onboardingGroups), '?')); $categoryMap = [ 'CA200O01' => ['pieceId' => 1, 'group' => 3, 'area' => 'value'], 'CA200O02' => ['pieceId' => 2, 'group' => 2, 'area' => 'hanmac'], 'CA200O03' => ['pieceId' => 3, 'group' => 2, 'area' => 'hanmac'], 'CA200O04' => ['pieceId' => 4, 'group' => 2, 'area' => 'hanmac'], 'CA200O05' => ['pieceId' => 5, 'group' => 2, 'area' => 'hanmac'], 'CA200O06' => ['pieceId' => 6, 'group' => 3, 'area' => 'value'], 'CA200O07' => ['pieceId' => 7, 'group' => 4, 'area' => 'company'], 'CA200O08' => ['pieceId' => 8, 'group' => 4, 'area' => 'company'], 'CA200O09' => ['pieceId' => 9, 'group' => 1, 'area' => 'family'], 'CA200O10' => ['pieceId' => 10, 'group' => 1, 'area' => 'family'], ]; $chapterNameMap = []; try { $stmtCodes = $pdo->prepare("\n SELECT base_code, code_name\n FROM edu_codes\n WHERE group_code = 'CA200'\n AND base_code IN ('CA200O01','CA200O02','CA200O03','CA200O04','CA200O05','CA200O06','CA200O07','CA200O08','CA200O09','CA200O10')\n ORDER BY base_code\n "); $stmtCodes->execute(); foreach (($stmtCodes->fetchAll(PDO::FETCH_ASSOC) ?: []) as $codeRow) { $baseCode = (string)($codeRow['base_code'] ?? ''); $codeName = trim((string)($codeRow['code_name'] ?? '')); if ($baseCode !== '' && $codeName !== '') { $chapterNameMap[$baseCode] = $codeName; } } } catch (Throwable $e) { // 코드명 조회 실패 시 콘텐츠 제목으로 폴백한다. } $useContentHistories = true; try { $checkTable = $pdo->query("SHOW TABLES LIKE 'edu_content_histories'"); if (!$checkTable || $checkTable->rowCount() === 0) { $useContentHistories = false; } } catch (Throwable $e) { $useContentHistories = false; } if ($useContentHistories) { try { $stmt = $pdo->prepare("\n SELECT\n c.*,\n COALESCE(lh.watch_tm, 0) AS watch_tm,\n COALESCE(lh.content_tm, 0) AS content_tm,\n lh.completed_at AS lh_completed_at,\n CASE\n WHEN ch.content_id IS NULL THEN 'none'\n WHEN ch.completed_at IS NOT NULL THEN 'completed'\n ELSE 'in_progress'\n END AS learning_status\n FROM edu_contents c\n LEFT JOIN edu_learning_histories lh\n ON lh.content_id = c.content_id\n AND lh.member_id = ?\n AND lh.sys_comp_code = ?\n LEFT JOIN edu_content_histories ch\n ON ch.content_id = c.content_id\n AND ch.member_id = ?\n AND ch.sys_comp_code = ?\n WHERE c.category_group IN ($placeholders)\n ORDER BY FIELD(c.category_group, 'CA200O01','CA200O02','CA200O03','CA200O04','CA200O05','CA200O06','CA200O07','CA200O08','CA200O09','CA200O10'), COALESCE(NULLIF(c.sort_order, 0), 9999), c.content_id\n "); $stmt->execute(array_merge([$memberId, $sysCompCode, $memberId, $sysCompCode], $onboardingGroups)); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: []; } catch (Throwable $e) { $useContentHistories = false; } } if (!$useContentHistories) { $stmt = $pdo->prepare("\n SELECT\n c.*,\n COALESCE(lh.watch_tm, 0) AS watch_tm,\n COALESCE(lh.content_tm, 0) AS content_tm,\n lh.completed_at AS lh_completed_at,\n CASE\n WHEN lh.content_id IS NULL THEN 'none'\n WHEN lh.completed_at IS NOT NULL THEN 'completed'\n ELSE 'in_progress'\n END AS learning_status\n FROM edu_contents c\n LEFT JOIN edu_learning_histories lh\n ON lh.content_id = c.content_id\n AND lh.member_id = ?\n AND lh.sys_comp_code = ?\n WHERE c.category_group IN ($placeholders)\n ORDER BY FIELD(c.category_group, 'CA200O01','CA200O02','CA200O03','CA200O04','CA200O05','CA200O06','CA200O07','CA200O08','CA200O09','CA200O10'), COALESCE(NULLIF(c.sort_order, 0), 9999), c.content_id\n "); $stmt->execute(array_merge([$memberId, $sysCompCode], $onboardingGroups)); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: []; } $chapterMap = []; foreach ($rows as $index => $row) { $categoryGroup = (string)($row['category_group'] ?? ''); if ($categoryGroup === '') { continue; } $mapped = $categoryMap[$categoryGroup] ?? null; $description = trim((string)($row['description'] ?? $row['description1'] ?? $row['description_1'] ?? $row['content_desc'] ?? $row['content_desc1'] ?? $row['content_description'] ?? $row['content_description1'] ?? '')); $description2 = trim((string)($row['description2'] ?? $row['description_2'] ?? $row['content_desc2'] ?? $row['content_description2'] ?? '')); if (!isset($chapterMap[$categoryGroup])) { $chapterMap[$categoryGroup] = [ 'id' => 0, 'name' => $chapterNameMap[$categoryGroup] ?? str_replace('[온보딩] ', '', (string)($row['title'] ?? '')), 'pieceId' => (int)($mapped['pieceId'] ?? ($index + 1)), 'type' => 'youtube', 'group' => (int)($mapped['group'] ?? 1), 'category_group' => $categoryGroup, 'area' => (string)($mapped['area'] ?? 'family'), 'lessons' => [], ]; } $learningStatus = (string)($row['learning_status'] ?? 'none'); $chapterMap[$categoryGroup]['lessons'][] = [ 'content_id' => (string)($row['content_id'] ?? ''), 'bookmark_content_id' => (string)($row['content_id'] ?? ''), 'comment_content_id' => (string)($row['content_id'] ?? ''), 'title' => (string)($row['title'] ?? ''), 'label' => str_replace('[온보딩] ', '', (string)($row['title'] ?? '')), 'description' => $description, 'description2' => $description2, 'url' => (string)($row['content_url'] ?? ''), 'completed' => ($learningStatus === 'completed'), 'learning_status' => $learningStatus, 'watch_tm' => (int)($row['watch_tm'] ?? 0), 'content_tm' => (int)($row['content_tm'] ?? 0), 'sort_order' => (int)($row['sort_order'] ?? 0), 'is_bookmarked' => false, ]; } $bookmarkIds = []; foreach ($chapterMap as $chapterItem) { foreach (($chapterItem['lessons'] ?? []) as $lessonItem) { $bookmarkId = trim((string)($lessonItem['bookmark_content_id'] ?? '')); if ($bookmarkId !== '') { $bookmarkIds[] = $bookmarkId; } } } $bookmarkIds = array_values(array_unique($bookmarkIds)); $wishlistMap = []; if (!empty($bookmarkIds)) { $wishlistPlaceholders = implode(',', array_fill(0, count($bookmarkIds), '?')); $stmtWishlist = $pdo->prepare( "SELECT content_id, is_active\n FROM edu_content_wishlist\n WHERE member_id = ?\n AND sys_comp_code = ?\n AND content_id IN ($wishlistPlaceholders)" ); $stmtWishlist->execute(array_merge([$memberId, $sysCompCode], $bookmarkIds)); foreach (($stmtWishlist->fetchAll(PDO::FETCH_ASSOC) ?: []) as $wishlistRow) { $wishlistMap[(string)$wishlistRow['content_id']] = ((string)($wishlistRow['is_active'] ?? '0') === '1'); } } $chapters = []; foreach ($onboardingGroups as $groupCode) { if (!isset($chapterMap[$groupCode])) { continue; } $chapter = $chapterMap[$groupCode]; usort($chapter['lessons'], static function ($left, $right) { $sortDiff = (int)($left['sort_order'] ?? 0) <=> (int)($right['sort_order'] ?? 0); if ($sortDiff !== 0) { return $sortDiff; } return strcmp((string)($left['content_id'] ?? ''), (string)($right['content_id'] ?? '')); }); $chapter['id'] = count($chapters) + 1; $chapter['lessons'] = array_map(static function ($lesson) use ($wishlistMap) { $bookmarkId = trim((string)($lesson['bookmark_content_id'] ?? '')); $lesson['is_bookmarked'] = ($bookmarkId !== '' && !empty($wishlistMap[$bookmarkId])); unset($lesson['sort_order']); return $lesson; }, $chapter['lessons']); $chapters[] = $chapter; } echo json_encode([ 'success' => true, 'chapters' => $chapters, ], JSON_UNESCAPED_UNICODE); } catch (Throwable $e) { http_response_code(500); echo json_encode([ 'success' => false, 'message' => 'server_error', ], JSON_UNESCAPED_UNICODE); }