269 lines
9.1 KiB
PHP
269 lines
9.1 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
|
|
if (session_status() === PHP_SESSION_NONE) {
|
|
session_start();
|
|
}
|
|
|
|
require_once __DIR__ . '/../db_conn.php';
|
|
|
|
function json_exit(array $payload, int $status = 200): void {
|
|
http_response_code($status);
|
|
echo json_encode($payload, JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
function resolve_member_and_company(PDO $pdo): array {
|
|
$sessionMemberId = trim((string)($_SESSION['ss_mb_id'] ?? $_SESSION['member_id'] ?? ''));
|
|
$memberId = $sessionMemberId !== '' ? $sessionMemberId : 'U001';
|
|
|
|
$stmtUser = $pdo->prepare('SELECT sys_comp_code FROM edu_users WHERE member_id = ? ORDER BY sys_comp_code LIMIT 1');
|
|
$stmtUser->execute([$memberId]);
|
|
$sysCompCode = (string)($stmtUser->fetchColumn() ?: '');
|
|
|
|
if ($sysCompCode === '') {
|
|
json_exit([
|
|
'success' => false,
|
|
'message' => 'edu_users에 회원 정보가 없어 마이클래스 상태를 조회할 수 없습니다.',
|
|
'data' => ['member_id' => $memberId],
|
|
], 400);
|
|
}
|
|
|
|
return [$memberId, $sysCompCode];
|
|
}
|
|
|
|
function ensure_goal_contents(PDO $pdo, string $goalCode, string $quarter, string $actor): int {
|
|
$stmtCnt = $pdo->prepare("SELECT COUNT(*) FROM edu_goal_contents WHERE goal_code = ? AND (is_active = '1' OR is_active IS NULL)");
|
|
$stmtCnt->execute([$goalCode]);
|
|
$existing = (int)$stmtCnt->fetchColumn();
|
|
if ($existing >= 6) {
|
|
return $existing;
|
|
}
|
|
|
|
$stmtCandidates = $pdo->prepare(
|
|
"SELECT c.content_id
|
|
FROM edu_contents c
|
|
WHERE (c.is_active = '1' OR c.is_active IS NULL)
|
|
AND (c.goal_code = :goal_code OR c.category_group = :quarter)
|
|
ORDER BY
|
|
CASE WHEN c.sort_order IS NULL THEN 1 ELSE 0 END,
|
|
c.sort_order ASC,
|
|
c.content_id ASC
|
|
LIMIT 6"
|
|
);
|
|
$stmtCandidates->execute([
|
|
':goal_code' => $goalCode,
|
|
':quarter' => $quarter,
|
|
]);
|
|
$candidateIds = $stmtCandidates->fetchAll(PDO::FETCH_COLUMN);
|
|
|
|
if (count($candidateIds) < 6) {
|
|
$stmtFallback = $pdo->prepare(
|
|
"SELECT c.content_id
|
|
FROM edu_contents c
|
|
WHERE (c.is_active = '1' OR c.is_active IS NULL)
|
|
ORDER BY
|
|
CASE WHEN c.sort_order IS NULL THEN 1 ELSE 0 END,
|
|
c.sort_order ASC,
|
|
c.content_id ASC
|
|
LIMIT 6"
|
|
);
|
|
$stmtFallback->execute();
|
|
$candidateIds = $stmtFallback->fetchAll(PDO::FETCH_COLUMN);
|
|
}
|
|
|
|
$candidateIds = array_values(array_unique(array_filter(array_map('strval', $candidateIds))));
|
|
|
|
$stmtUpsert = $pdo->prepare(
|
|
"INSERT INTO edu_goal_contents
|
|
(goal_code, content_id, index_id, is_active, sort_order, created_by, created_at, updated_by, updated_at)
|
|
VALUES
|
|
(?, ?, ?, '1', ?, ?, NOW(), ?, NOW())
|
|
ON DUPLICATE KEY UPDATE
|
|
is_active = VALUES(is_active),
|
|
sort_order = VALUES(sort_order),
|
|
updated_by = VALUES(updated_by),
|
|
updated_at = NOW()"
|
|
);
|
|
|
|
foreach ($candidateIds as $idx => $contentId) {
|
|
$order = $idx + 1;
|
|
$stmtUpsert->execute([$goalCode, $contentId, $order, $order, $actor, $actor]);
|
|
}
|
|
|
|
$stmtCnt->execute([$goalCode]);
|
|
return (int)$stmtCnt->fetchColumn();
|
|
}
|
|
|
|
try {
|
|
$pdo = db_conn();
|
|
[$memberId, $sysCompCode] = resolve_member_and_company($pdo);
|
|
|
|
$stmtGoals = $pdo->query(
|
|
"SELECT goal_code, title, quarter, goal_no, sort_order
|
|
FROM edu_learning_goals
|
|
WHERE (is_active = '1' OR is_active IS NULL)
|
|
ORDER BY base_year DESC, quarter ASC, goal_no ASC, goal_code ASC"
|
|
);
|
|
$goals = $stmtGoals->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
if (!$goals) {
|
|
json_exit(['success' => true, 'data' => ['goals' => [], 'videos' => []]]);
|
|
}
|
|
|
|
$stmtSelected = $pdo->prepare(
|
|
"SELECT ug.goal_code, ug.quarter, ug.completed_date, ug.updated_at, lg.title
|
|
FROM edu_user_learning_goals ug
|
|
LEFT JOIN edu_learning_goals lg ON lg.goal_code = ug.goal_code
|
|
WHERE ug.member_id = ?
|
|
AND ug.sys_comp_code = ?
|
|
AND (ug.is_active = '1' OR ug.is_active IS NULL)
|
|
ORDER BY ug.updated_at DESC, ug.goal_code DESC"
|
|
);
|
|
$stmtSelected->execute([$memberId, $sysCompCode]);
|
|
$selectedGoals = $stmtSelected->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
$requestedGoalCode = trim((string)($_GET['goal_code'] ?? ''));
|
|
$activeGoalCode = $requestedGoalCode;
|
|
if ($activeGoalCode === '' && !empty($selectedGoals)) {
|
|
$activeGoalCode = (string)$selectedGoals[0]['goal_code'];
|
|
}
|
|
if ($activeGoalCode === '') {
|
|
$activeGoalCode = (string)$goals[0]['goal_code'];
|
|
}
|
|
|
|
$goalIndex = [];
|
|
foreach ($goals as $g) {
|
|
$goalIndex[(string)$g['goal_code']] = $g;
|
|
}
|
|
|
|
if (!isset($goalIndex[$activeGoalCode])) {
|
|
$activeGoalCode = (string)$goals[0]['goal_code'];
|
|
}
|
|
|
|
$activeQuarter = (string)($goalIndex[$activeGoalCode]['quarter'] ?? '');
|
|
ensure_goal_contents($pdo, $activeGoalCode, $activeQuarter, $memberId);
|
|
|
|
$stmtVideos = $pdo->prepare(
|
|
"SELECT
|
|
gc.goal_code,
|
|
gc.content_id,
|
|
gc.sort_order,
|
|
gc.index_id,
|
|
c.title,
|
|
c.description,
|
|
c.description2,
|
|
c.content_url,
|
|
c.thumbnail_url,
|
|
c.category_code,
|
|
c.category_group,
|
|
lh.watch_tm,
|
|
lh.content_tm,
|
|
lh.completed_at
|
|
FROM edu_goal_contents gc
|
|
JOIN edu_contents c ON c.content_id = gc.content_id
|
|
LEFT JOIN edu_learning_histories lh
|
|
ON lh.member_id = ?
|
|
AND lh.sys_comp_code = ?
|
|
AND lh.content_id = gc.content_id
|
|
WHERE gc.goal_code = ?
|
|
AND (gc.is_active = '1' OR gc.is_active IS NULL)
|
|
ORDER BY
|
|
CASE WHEN gc.sort_order IS NULL THEN 1 ELSE 0 END,
|
|
gc.sort_order ASC,
|
|
CASE WHEN gc.index_id IS NULL THEN 1 ELSE 0 END,
|
|
gc.index_id ASC,
|
|
gc.content_id ASC
|
|
LIMIT 6"
|
|
);
|
|
$stmtVideos->execute([$memberId, $sysCompCode, $activeGoalCode]);
|
|
$videos = $stmtVideos->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
$contentIds = array_values(array_unique(array_filter(array_map(static function ($r) {
|
|
return (string)($r['content_id'] ?? '');
|
|
}, $videos))));
|
|
|
|
$memoMap = [];
|
|
if (!empty($contentIds)) {
|
|
$in = implode(',', array_fill(0, count($contentIds), '?'));
|
|
$stmtMemo = $pdo->prepare(
|
|
"SELECT content_id, seq, title
|
|
FROM edu_content_memos
|
|
WHERE content_id IN ($in)
|
|
AND (is_active = '1' OR is_active IS NULL)
|
|
ORDER BY content_id ASC, seq ASC"
|
|
);
|
|
$stmtMemo->execute($contentIds);
|
|
$memoRows = $stmtMemo->fetchAll(PDO::FETCH_ASSOC);
|
|
foreach ($memoRows as $m) {
|
|
$cid = (string)$m['content_id'];
|
|
if (!isset($memoMap[$cid])) {
|
|
$memoMap[$cid] = [];
|
|
}
|
|
$memoTitle = trim((string)($m['title'] ?? ''));
|
|
if ($memoTitle !== '') {
|
|
$memoMap[$cid][] = $memoTitle;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($videos as $idx => $video) {
|
|
$cid = (string)$video['content_id'];
|
|
$videos[$idx]['memos'] = $memoMap[$cid] ?? [];
|
|
$videos[$idx]['is_completed'] = !empty($video['completed_at']);
|
|
$videos[$idx]['slot_no'] = $idx + 1;
|
|
}
|
|
|
|
$stmtProgress = $pdo->prepare(
|
|
"SELECT
|
|
ug.goal_code,
|
|
COUNT(gc.content_id) AS total_count,
|
|
SUM(CASE WHEN lh.completed_at IS NOT NULL THEN 1 ELSE 0 END) AS completed_count
|
|
FROM edu_user_learning_goals ug
|
|
LEFT JOIN edu_goal_contents gc
|
|
ON gc.goal_code = ug.goal_code
|
|
AND (gc.is_active = '1' OR gc.is_active IS NULL)
|
|
LEFT JOIN edu_learning_histories lh
|
|
ON lh.member_id = ug.member_id
|
|
AND lh.sys_comp_code = ug.sys_comp_code
|
|
AND lh.content_id = gc.content_id
|
|
WHERE ug.member_id = ?
|
|
AND ug.sys_comp_code = ?
|
|
AND (ug.is_active = '1' OR ug.is_active IS NULL)
|
|
GROUP BY ug.goal_code"
|
|
);
|
|
$stmtProgress->execute([$memberId, $sysCompCode]);
|
|
$progressRows = $stmtProgress->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
$goalProgress = [];
|
|
foreach ($progressRows as $row) {
|
|
$total = (int)($row['total_count'] ?? 0);
|
|
$completed = (int)($row['completed_count'] ?? 0);
|
|
$goalProgress[(string)$row['goal_code']] = [
|
|
'total_count' => $total,
|
|
'completed_count' => $completed,
|
|
'is_completed' => $total > 0 && $completed >= $total,
|
|
];
|
|
}
|
|
|
|
json_exit([
|
|
'success' => true,
|
|
'data' => [
|
|
'member_id' => $memberId,
|
|
'sys_comp_code' => $sysCompCode,
|
|
'active_goal_code' => $activeGoalCode,
|
|
'goals' => $goals,
|
|
'selected_goals' => $selectedGoals,
|
|
'goal_progress' => $goalProgress,
|
|
'videos' => $videos,
|
|
],
|
|
]);
|
|
} catch (Throwable $e) {
|
|
json_exit([
|
|
'success' => false,
|
|
'message' => $e->getMessage(),
|
|
], 500);
|
|
}
|