922 lines
42 KiB
PHP
922 lines
42 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../../bbs/auth.php';
|
|
edu_require_login();
|
|
|
|
include_once '../../bbs/db_conn.php';
|
|
include_once 'header.php';
|
|
|
|
// 현재 년도
|
|
$current_year = date('Y');
|
|
$selected_year = $_GET['year'] ?? $current_year;
|
|
$selected_access_comp = $_GET['access_comp'] ?? '';
|
|
$selected_ranking_comp = $_GET['ranking_comp'] ?? '';
|
|
|
|
// 신규 필터 파라미터 (선택된 년도 기준)
|
|
$fr_date = $_GET['fr_date'] ?? "{$selected_year}-01-01";
|
|
$to_date = $_GET['to_date'] ?? "{$selected_year}-12-31";
|
|
$exclude_admin = ($_GET['exclude_admin'] ?? '0') === '1';
|
|
|
|
// 섹션별 별도 날짜가 필요한 경우를 위해 (추후 확장성 고려)
|
|
$rank_fr_date = $_GET['rank_fr_date'] ?? $fr_date;
|
|
$rank_to_date = $_GET['rank_to_date'] ?? $to_date;
|
|
$video_fr_date = $_GET['video_fr_date'] ?? $fr_date;
|
|
$video_to_date = $_GET['video_to_date'] ?? $to_date;
|
|
$stat_fr_date = $_GET['stat_fr_date'] ?? $fr_date;
|
|
$stat_to_date = $_GET['stat_to_date'] ?? $to_date;
|
|
$access_fr_date = $_GET['access_fr_date'] ?? $fr_date;
|
|
$access_to_date = $_GET['access_to_date'] ?? $to_date;
|
|
|
|
|
|
// 현재 년도의 법정의무교육 기간 조회
|
|
$legal_edu_period = '';
|
|
$user_qty = 0;
|
|
try {
|
|
require_once __DIR__ . '/../../bbs/db_conn.php';
|
|
$pdo = db_conn();
|
|
$stmt = $pdo->prepare("
|
|
SELECT start_date, end_date
|
|
FROM edu_contents
|
|
WHERE category_code = 'CA10003'
|
|
AND base_year = ?
|
|
GROUP BY start_date, end_date
|
|
LIMIT 1
|
|
");
|
|
$stmt->execute([$selected_year]);
|
|
$period = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($period && !empty($period['start_date']) && !empty($period['end_date'])) {
|
|
// 날짜 포맷: YYYY.MM.DD
|
|
$start = date('Y.m.d', strtotime($period['start_date']));
|
|
$end = date('Y.m.d', strtotime($period['end_date']));
|
|
$legal_edu_period = "{$start} ~ {$end}";
|
|
|
|
// 전체 학습자 수 표시 퇴사자 제외
|
|
$stmt_qty = $pdo->prepare("
|
|
SELECT COUNT(member_id) as qty
|
|
FROM edu_users
|
|
WHERE (end_date IS NULL OR end_date > CURDATE())
|
|
AND sys_comp_code = working_comp
|
|
");
|
|
$stmt_qty->execute();
|
|
$user_qty = $stmt_qty->fetchColumn();
|
|
|
|
}
|
|
} catch (Exception $e) {
|
|
// 법정의무교육 기간 조회 실패 시 기본값 유지
|
|
}
|
|
|
|
// 법인 리스트 가져오기 (프로시저 사용)
|
|
$pdo = db_conn();
|
|
$stmt_corp = $pdo->query("CALL proc_get_code2_list('CO100')");
|
|
$companies = $stmt_corp->fetchAll(PDO::FETCH_ASSOC);
|
|
while ($stmt_corp->nextRowset()) {
|
|
}
|
|
unset($stmt_corp);
|
|
|
|
// 법인별 학습인원 현황 (재직 중인 인원 수)
|
|
$learner_count_query = $pdo->prepare("
|
|
SELECT c.code_name, COUNT(DISTINCT b.member_id) as learner_count
|
|
FROM edu_codes c
|
|
LEFT JOIN edu_users b ON c.code = b.belong_comp AND b.end_date IS NULL
|
|
WHERE c.group_code = 'CO100' AND c.is_active = '1'
|
|
GROUP BY c.code, c.code_name
|
|
ORDER BY c.code ASC
|
|
");
|
|
$learner_count_query->execute();
|
|
$learner_counts = $learner_count_query->fetchAll();
|
|
|
|
// 법인별 통계 (총 학습시간)
|
|
$total_time_query = $pdo->prepare("
|
|
SELECT
|
|
c.code,
|
|
c.code_name,
|
|
CONCAT(
|
|
LPAD(FLOOR(IFNULL(SUM(CASE WHEN a.completed_at IS NULL THEN a.watch_tm ELSE a.content_tm END), 0) / 3600), 2, '0'), '시간 ',
|
|
LPAD(FLOOR((IFNULL(SUM(CASE WHEN a.completed_at IS NULL THEN a.watch_tm ELSE a.content_tm END), 0) % 3600) / 60), 2, '0'), '분'
|
|
) AS formatted_total_tm
|
|
FROM edu_codes c
|
|
LEFT JOIN edu_users b ON c.code = b.sys_comp_code
|
|
LEFT JOIN edu_learning_histories a ON b.member_id = a.member_id AND b.sys_comp_code = a.sys_comp_code AND a.last_viewed_at BETWEEN ? AND ?
|
|
WHERE c.group_code = 'CO100' AND c.is_active = '1'
|
|
GROUP BY c.code, c.code_name
|
|
ORDER BY c.code ASC
|
|
");
|
|
$total_time_query->execute(["$stat_fr_date 00:00:00", "$stat_to_date 23:59:59"]);
|
|
$total_times = $total_time_query->fetchAll();
|
|
|
|
// 법인별 통계 (평균 학습횟수)
|
|
$avg_count_query = $pdo->prepare("
|
|
SELECT
|
|
c.code,
|
|
c.code_name,
|
|
CONCAT(
|
|
IFNULL(
|
|
ROUND(
|
|
COUNT(a.content_id) ,
|
|
1
|
|
),
|
|
0
|
|
), '회'
|
|
) AS avg_view_count
|
|
FROM edu_codes c
|
|
LEFT JOIN edu_users b ON c.code = b.sys_comp_code
|
|
LEFT JOIN edu_learning_histories a ON b.member_id = a.member_id AND b.sys_comp_code = a.sys_comp_code AND a.last_viewed_at BETWEEN ? AND ?
|
|
WHERE c.group_code = 'CO100' AND c.is_active = '1'
|
|
GROUP BY c.code, c.code_name
|
|
ORDER BY c.code ASC
|
|
");
|
|
$avg_count_query->execute(["$stat_fr_date 00:00:00", "$stat_to_date 23:59:59"]);
|
|
$avg_counts = $avg_count_query->fetchAll();
|
|
|
|
// 법인별 접속 추이 (월별)
|
|
$access_trend_query = $pdo->prepare("
|
|
SELECT
|
|
MONTH(accessed_at) as month,
|
|
COUNT(al.member_id) as access_count
|
|
FROM edu_access_logs al
|
|
WHERE al.accessed_at BETWEEN ? AND ? AND (? = '' OR EXISTS (
|
|
SELECT 1 FROM edu_users u WHERE u.member_id = al.member_id AND u.sys_comp_code = ?
|
|
))
|
|
GROUP BY MONTH(al.accessed_at)
|
|
ORDER BY MONTH(al.accessed_at) ASC
|
|
");
|
|
$access_trend_query->execute(["$access_fr_date 00:00:00", "$access_to_date 23:59:59", $selected_access_comp, $selected_access_comp]);
|
|
$access_trends = $access_trend_query->fetchAll();
|
|
|
|
// 가장 많이 본 영상 (카테고리별 top5)
|
|
$popular_videos_query = $pdo->prepare("
|
|
SELECT
|
|
b.category_code,
|
|
b.title AS content_title,
|
|
COUNT(a.content_id) as view_count
|
|
FROM edu_learning_histories a
|
|
JOIN edu_contents b ON a.content_id = b.content_id
|
|
WHERE a.last_viewed_at BETWEEN ? AND ?
|
|
GROUP BY b.category_code, b.content_id, b.title
|
|
ORDER BY b.category_code, view_count DESC
|
|
");
|
|
$popular_videos_query->execute(["$video_fr_date 00:00:00", "$video_to_date 23:59:59"]);
|
|
$popular_videos = $popular_videos_query->fetchAll();
|
|
|
|
// 배움터 학습 랭킹
|
|
$ranking_sql = "
|
|
SELECT a.sys_comp_code,
|
|
a.name,
|
|
a.dept_name,
|
|
c.code_name as company_name,
|
|
SUM(CASE WHEN b.completed_at IS NULL THEN b.watch_tm ELSE b.content_tm END) / 3600 as total_hours
|
|
FROM edu_users a
|
|
JOIN edu_learning_histories b ON a.member_id = b.member_id AND a.sys_comp_code = b.sys_comp_code
|
|
JOIN edu_codes c ON a.belong_comp = c.code
|
|
WHERE b.last_viewed_at BETWEEN ? AND ? AND c.group_code = 'CO100' AND (? = '' OR a.belong_comp = ?)
|
|
";
|
|
|
|
if ($exclude_admin) {
|
|
$ranking_sql .= " AND a.auth_level NOT IN ('LE10001', 'LE10002') ";
|
|
}
|
|
|
|
$ranking_sql .= "
|
|
GROUP BY a.sys_comp_code, a.member_id, a.name, a.dept_name, c.code_name
|
|
ORDER BY total_hours DESC
|
|
LIMIT 20
|
|
";
|
|
|
|
$ranking_query = $pdo->prepare($ranking_sql);
|
|
$ranking_query->execute(["$rank_fr_date 00:00:00", "$rank_to_date 23:59:59", $selected_ranking_comp, $selected_ranking_comp]);
|
|
$rankings = $ranking_query->fetchAll();
|
|
?>
|
|
<main class="max-w-[1600px] mx-auto p-6">
|
|
<header class="flex flex-col md:flex-row justify-between items-end md:items-center mb-6 gap-4">
|
|
<div>
|
|
<h2 class="text-2xl font-bold text-gray-800 flex items-center">
|
|
전체학습현황
|
|
<span class="ml-4 text-xs font-normal px-2 py-1 bg-gray-200 rounded text-gray-600">전체 학습자 수:
|
|
<?php echo $user_qty; ?>명</span>
|
|
</h2>
|
|
<p class="text-sm text-gray-400 mt-1 italic leading-relaxed">법정의무교육 기간: <?php echo $legal_edu_period; ?></p>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
<div class="flex bg-gray-200 p-1 rounded-md">
|
|
<?php
|
|
$is_prev_selected = $selected_year == ($current_year - 1);
|
|
$is_curr_selected = $selected_year == $current_year;
|
|
?>
|
|
<button class="px-3 py-1 text-sm rounded transition <?php echo $is_prev_selected ? 'bg-[#114b3d] text-white shadow-sm font-bold' : 'text-gray-500 hover:text-gray-800'; ?>"
|
|
onclick="changeYear(<?php echo $current_year - 1; ?>)"><?php echo $current_year - 1; ?>년</button>
|
|
<button class="px-3 py-1 text-sm rounded transition <?php echo $is_curr_selected ? 'bg-[#114b3d] text-white shadow-sm font-bold' : 'text-gray-500 hover:text-gray-800'; ?>"
|
|
onclick="changeYear(<?php echo $current_year; ?>)"><?php echo $current_year; ?>년</button>
|
|
</div>
|
|
<button
|
|
class="px-4 py-2 bg-[#2563eb] text-white rounded-md text-sm font-bold flex items-center hover:bg-blue-700 transition shadow-lg">
|
|
<i class="fa-solid fa-file-invoice mr-2"></i>교육결과보고서
|
|
</button>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- 통계 카드 3개 -->
|
|
<section class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
|
|
|
<!-- 법인별 학습인원 현황 (막대 차트) -->
|
|
<div class="bg-white p-6 rounded-xl border border-gray-200 shadow-sm">
|
|
<h3 class="font-bold text-gray-800 mb-4 flex items-center justify-between text-sm">
|
|
법인별 학습인원 현황
|
|
<i class="fa-solid fa-ellipsis-vertical text-gray-300"></i>
|
|
</h3>
|
|
<?php
|
|
$max_count = 0;
|
|
foreach ($learner_counts as $count) {
|
|
$val = (int) $count['learner_count'];
|
|
if ($val > $max_count)
|
|
$max_count = $val;
|
|
}
|
|
|
|
// 스케일 계산: 데이터가 있으면 500 단위로 올림, 없으면 기본 100
|
|
$y_max = $max_count > 0 ? ceil($max_count / 500) * 500 : 500;
|
|
if ($y_max < 1)
|
|
$y_max = 100;
|
|
|
|
$y_step_count = 4;
|
|
$y_unit = $y_max / $y_step_count;
|
|
$scale = 165 / $y_max;
|
|
$bar_width = 30;
|
|
$gap = 12;
|
|
$start_x = 45;
|
|
?>
|
|
<!-- SVG Bar Chart -->
|
|
<div class="relative w-full" style="height:240px;">
|
|
<svg viewBox="0 0 320 210" class="w-full h-full" xmlns="http://www.w3.org/2000/svg">
|
|
<!-- 격자선 -->
|
|
<?php for ($i = 0; $i <= $y_step_count; $i++):
|
|
$y = 175 - ($i * (165 / $y_step_count));
|
|
?>
|
|
<line x1="42" y1="<?php echo $y; ?>" x2="315" y2="<?php echo $y; ?>" stroke="#e5e7eb"
|
|
stroke-width="<?php echo $i === 0 ? '1' : '0.8'; ?>" <?php echo $i === 0 ? '' : 'stroke-dasharray="4,3"'; ?> />
|
|
<?php endfor; ?>
|
|
|
|
<!-- Y축 레이블 -->
|
|
<?php for ($i = 0; $i <= $y_step_count; $i++):
|
|
$y = 175 - ($i * (165 / $y_step_count));
|
|
$label = $i * $y_unit;
|
|
?>
|
|
<text x="38" y="<?php echo $y + 3; ?>" text-anchor="end" font-size="10"
|
|
fill="#9ca3af"><?php echo number_format($label); ?></text>
|
|
<?php endfor; ?>
|
|
|
|
<!-- Y축 라인 -->
|
|
<line x1="42" y1="8" x2="42" y2="175" stroke="#d1d5db" stroke-width="1" />
|
|
|
|
<?php
|
|
foreach ($learner_counts as $index => $data) {
|
|
if ($index >= 7)
|
|
break; // 차트 공간상 7개까지만 표시
|
|
$val = (int) $data['learner_count'];
|
|
$height = $val * $scale;
|
|
$y = 175 - $height;
|
|
$x = $start_x + $index * ($bar_width + $gap);
|
|
$color = $index < 4 ? '#114b3d' : '#1d6b56';
|
|
echo "<rect x='$x' y='$y' width='$bar_width' height='$height' fill='$color' rx='3'/>\n";
|
|
$text_x = $x + $bar_width / 2;
|
|
$short_name = mb_substr($data['code_name'], 0, 4); // 이름이 길면 자름
|
|
echo "<text x='$text_x' y='194' text-anchor='middle' font-size='9' fill='#6b7280'>{$short_name}</text>\n";
|
|
}
|
|
?>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 법인별 통계 -->
|
|
<div class="bg-white p-6 rounded-xl border border-gray-200 shadow-sm">
|
|
<div class="space-y-2 mb-5">
|
|
<div class="flex justify-between items-center">
|
|
<h3 class="font-bold text-gray-800 italic underline decoration-blue-200 decoration-4 text-sm">법인별 통계</h3>
|
|
<select id="statType" class="text-xs bg-gray-50 border border-gray-100 rounded p-1"
|
|
onchange="changeStatType()">
|
|
<option value="avg">학습횟수</option>
|
|
<option value="total">총 학습시간</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div id="statContent" class="space-y-3">
|
|
<!-- 평균학습 내용 -->
|
|
<div id="avgStats" class="space-y-3">
|
|
<?php foreach ($avg_counts as $data): ?>
|
|
<div
|
|
class="flex justify-between items-center pb-2 border-b border-gray-50 cursor-pointer hover:bg-gray-50 transition"
|
|
onclick="showCorpDetail('<?php echo htmlspecialchars($data['code']); ?>', 'avg', '<?php echo htmlspecialchars($data['code_name']); ?>')">
|
|
<span
|
|
class="text-sm font-medium text-gray-600"><?php echo htmlspecialchars($data['code_name']); ?></span><span
|
|
class="text-sm font-bold text-blue-600"><?php echo htmlspecialchars($data['avg_view_count']); ?></span>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<!-- 총 학습시간 내용 -->
|
|
<div id="totalStats" class="space-y-3" style="display: none;">
|
|
<?php foreach ($total_times as $data): ?>
|
|
<div
|
|
class="flex justify-between items-center pb-2 border-b border-gray-50 cursor-pointer hover:bg-gray-50 transition"
|
|
onclick="showCorpDetail('<?php echo htmlspecialchars($data['code']); ?>', 'total', '<?php echo htmlspecialchars($data['code_name']); ?>')">
|
|
<span
|
|
class="text-sm font-medium text-gray-600"><?php echo htmlspecialchars($data['code_name']); ?></span><span
|
|
class="text-sm font-bold text-blue-600"><?php echo htmlspecialchars($data['formatted_total_tm']); ?></span>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 법인별 접속 추이 (라인 차트) -->
|
|
<div class="bg-white p-6 rounded-xl border border-gray-200 shadow-sm">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h3 class="font-bold text-gray-800 text-sm">법인별 접속 추이(로그인 법인)</h3>
|
|
<div class="flex flex-col gap-1 items-end">
|
|
<select id="accessTrendComp" class="text-xs bg-gray-50 border border-gray-100 rounded p-1 w-24"
|
|
onchange="changeAccessTrendComp()">
|
|
<option value="">전체</option>
|
|
<?php foreach ($companies as $comp): ?>
|
|
<option value="<?php echo htmlspecialchars($comp['code']); ?>" <?php echo $selected_access_comp === $comp['code'] ? 'selected' : ''; ?>><?php echo htmlspecialchars($comp['name']); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<!-- SVG Line Chart -->
|
|
<div class="relative w-full" style="height:240px;">
|
|
<svg viewBox="0 0 320 210" class="w-full h-full" xmlns="http://www.w3.org/2000/svg">
|
|
<?php
|
|
$max_access = 0;
|
|
foreach ($access_trends as $trend) {
|
|
$max_access = max($max_access, $trend['access_count']);
|
|
}
|
|
$target_max_access = ceil($max_access * 1.2);
|
|
if ($target_max_access == 0)
|
|
$target_max_access = 20;
|
|
$y_trend_step_count = 4;
|
|
$y_trend_unit = ceil($target_max_access / $y_trend_step_count);
|
|
$y_trend_max = $y_trend_unit * $y_trend_step_count;
|
|
$scale_y_trend = $y_trend_max > 0 ? 165 / $y_trend_max : 0;
|
|
?>
|
|
<!-- 격자선 -->
|
|
<?php for ($i = 0; $i <= $y_trend_step_count; $i++):
|
|
$y = 175 - ($i * (165 / $y_trend_step_count));
|
|
?>
|
|
<line x1="42" y1="<?php echo $y; ?>" x2="315" y2="<?php echo $y; ?>" stroke="#e5e7eb"
|
|
stroke-width="<?php echo $i === 0 ? '1' : '0.8'; ?>" <?php echo $i === 0 ? '' : 'stroke-dasharray="4,3"'; ?> />
|
|
<?php endfor; ?>
|
|
|
|
<!-- Y축 레이블 -->
|
|
<?php for ($i = 0; $i <= $y_trend_step_count; $i++):
|
|
$y = 175 - ($i * (165 / $y_trend_step_count));
|
|
$label = $i * $y_trend_unit;
|
|
?>
|
|
<text x="38" y="<?php echo $y + 3; ?>" text-anchor="end" font-size="11"
|
|
fill="#9ca3af"><?php echo number_format($label); ?></text>
|
|
<?php endfor; ?>
|
|
|
|
<!-- Y축 라인 -->
|
|
<line x1="42" y1="8" x2="42" y2="175" stroke="#d1d5db" stroke-width="1" />
|
|
|
|
<!-- 라인 경로 -->
|
|
<?php
|
|
$points = [];
|
|
$x_step = 273 / 11; // 12개월
|
|
$x_start = 42;
|
|
foreach ($access_trends as $trend) {
|
|
$month = $trend['month'];
|
|
$count = $trend['access_count'];
|
|
$x = $x_start + ($month - 1) * $x_step;
|
|
$y = 175 - ($count * $scale_y_trend);
|
|
$points[] = "$x,$y";
|
|
}
|
|
$points_str = implode(' ', $points);
|
|
?>
|
|
<polyline points="<?php echo $points_str; ?>" fill="none" stroke="#0d9488" stroke-width="2.5"
|
|
stroke-linejoin="round" />
|
|
|
|
<!-- 데이터 포인트 -->
|
|
<g>
|
|
<?php foreach ($access_trends as $trend):
|
|
$month = $trend['month'];
|
|
$count = $trend['access_count'];
|
|
$x = $x_start + ($month - 1) * $x_step;
|
|
$y = 175 - ($count * $scale_y_trend);
|
|
?>
|
|
<circle cx="<?php echo $x; ?>" cy="<?php echo $y; ?>" r="10" fill="transparent" class="cursor-pointer"
|
|
onclick="showAccessLogs(<?php echo $month; ?>)" />
|
|
<circle cx="<?php echo $x; ?>" cy="<?php echo $y; ?>" r="4.5" fill="white" stroke="#0d9488"
|
|
stroke-width="2.5" class="pointer-events-none" />
|
|
<?php endforeach; ?>
|
|
</g>
|
|
|
|
<!-- X축 레이블 -->
|
|
<?php for ($m = 1; $m <= 12; $m++):
|
|
$x = $x_start + ($m - 1) * $x_step;
|
|
?>
|
|
<text x="<?php echo $x; ?>" y="194" text-anchor="middle" font-size="10"
|
|
fill="#9ca3af"><?php echo $m; ?>월</text>
|
|
<?php endfor; ?>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- 하단: 가장 많이 본 영상 + 배움터 학습 랭킹 -->
|
|
<section class="grid grid-cols-1 lg:grid-cols-2 gap-6 pb-12">
|
|
|
|
<!-- 가장 많이 본 영상 -->
|
|
<div class="bg-white rounded-xl border border-gray-200 shadow-sm overflow-hidden">
|
|
<div class="p-5 border-b border-gray-50 flex justify-between items-center bg-gray-50/50">
|
|
<h3 class="font-bold text-gray-800 flex items-center italic text-sm">
|
|
<i class="fa-solid fa-play-circle text-blue-500 mr-2"></i>가장 많이 본 영상
|
|
</h3>
|
|
<div class="flex flex-col gap-1 items-end">
|
|
<div class="flex gap-1 items-center">
|
|
<input type="date" id="video_fr_date" value="<?php echo $video_fr_date; ?>"
|
|
class="text-xs border border-gray-200 rounded p-1" onchange="updateVideoDate()">
|
|
<span class="text-gray-400">~</span>
|
|
<input type="date" id="video_to_date" value="<?php echo $video_to_date; ?>"
|
|
class="text-xs border border-gray-200 rounded p-1" onchange="updateVideoDate()">
|
|
</div>
|
|
<select id="videoCategory" class="text-xs bg-white border border-gray-200 rounded p-1 w-24"
|
|
onchange="changeVideoCategory()">
|
|
<option value="CA10001">마이클래스</option>
|
|
<option value="CA10002">온보딩</option>
|
|
<option value="CA10003">법정교육</option>
|
|
<option value="CA10004">리더십</option>
|
|
<option value="CA10005">인사이트</option>
|
|
<option value="CA10006">비즈트렌드</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div id="videoContent" class="p-5 space-y-5 overflow-y-auto max-h-[350px]">
|
|
<?php
|
|
$categories = ['CA10001' => '마이클래스', 'CA10002' => '온보딩', 'CA10003' => '법정교육', 'CA10004' => '리더십', 'CA10005' => '인사이트', 'CA10006' => '비즈트렌드'];
|
|
foreach ($categories as $cat_code => $cat_name):
|
|
$videos = array_filter($popular_videos, function ($v) use ($cat_code) {
|
|
return $v['category_code'] == $cat_code;
|
|
});
|
|
usort($videos, function ($a, $b) {
|
|
return $b['view_count'] - $a['view_count'];
|
|
});
|
|
$top5 = array_slice($videos, 0, 20);
|
|
?>
|
|
<div id="videos-<?php echo $cat_code; ?>" class="space-y-5"
|
|
style="display: <?php echo $cat_code == 'CA10001' ? 'block' : 'none'; ?>;">
|
|
<?php foreach ($top5 as $index => $video): ?>
|
|
<div class="flex items-center space-x-3">
|
|
<div class="font-bold text-blue-600 text-lg w-10 flex-shrink-0 text-center"><?php echo $index + 1; ?></div>
|
|
<div
|
|
class="w-24 h-14 bg-slate-200 rounded flex-shrink-0 flex items-center justify-center text-slate-400 text-xs">
|
|
<i class="fa-solid fa-play text-lg"></i>
|
|
</div>
|
|
<div>
|
|
<h4 class="font-bold text-sm leading-tight"><?php echo htmlspecialchars($video['content_title']); ?></h4>
|
|
<p class="text-[11px] text-gray-400 mt-1">시청수: <span
|
|
class="text-gray-700 font-bold"><?php echo htmlspecialchars($video['view_count']); ?>회</span></p>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<!--
|
|
<button class="w-full py-3 bg-slate-50 text-xs text-gray-400 font-medium hover:bg-slate-100 border-t border-gray-100 italic transition">
|
|
<i class="fa-solid fa-comment-dots mr-2"></i>한줄 소감문 보기
|
|
</button>
|
|
-->
|
|
</div>
|
|
|
|
<!-- 배움터 학습 랭킹 -->
|
|
<div class="bg-white rounded-xl border border-gray-200 shadow-sm overflow-hidden">
|
|
<div class="p-5 border-b border-gray-50 flex justify-between items-center bg-gray-50/50">
|
|
<h3 class="font-bold text-gray-800 flex items-center italic text-sm">
|
|
<i class="fa-solid fa-award text-teal-600 mr-2"></i>배움터 학습 랭킹
|
|
</h3>
|
|
<div class="flex flex-col gap-1 items-end">
|
|
<div class="flex gap-1 items-center">
|
|
<input type="date" id="rank_fr_date" value="<?php echo $rank_fr_date; ?>"
|
|
class="text-xs border border-gray-200 rounded p-1" onchange="updateRankingDate()">
|
|
<span class="text-gray-400">~</span>
|
|
<input type="date" id="rank_to_date" value="<?php echo $rank_to_date; ?>"
|
|
class="text-xs border border-gray-200 rounded p-1" onchange="updateRankingDate()">
|
|
</div>
|
|
<div class="flex gap-2 items-center">
|
|
<label class="flex items-center text-xs text-gray-500 cursor-pointer">
|
|
<input type="checkbox" id="excludeAdmin" class="mr-1" <?php echo $exclude_admin ? 'checked' : ''; ?>
|
|
onchange="updateRankingFilter()">
|
|
관리자 제외
|
|
</label>
|
|
<select id="rankingComp" class="text-xs bg-white border border-gray-200 rounded p-1 w-24"
|
|
onchange="changeRankingComp()">
|
|
<option value="">전체</option>
|
|
<?php foreach ($companies as $comp): ?>
|
|
<option value="<?php echo htmlspecialchars($comp['code']); ?>" <?php echo $selected_ranking_comp === $comp['code'] ? 'selected' : ''; ?>>
|
|
|
|
<?php echo htmlspecialchars($comp['name']); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
<div class="p-4 overflow-y-auto max-h-[350px]">
|
|
<table class="w-full text-sm">
|
|
<tbody>
|
|
<?php foreach ($rankings as $index => $rank):
|
|
$level = $rank['total_hours'] >= 40 ? 'Master' : ($rank['total_hours'] >= 20 ? 'Elite' : ($rank['total_hours'] >= 8 ? 'Learner' : 'Rookie'));
|
|
$level_color = $level == 'Master' ? 'purple' : ($level == 'Elite' ? 'blue' : ($level == 'Learner' ? 'green' : 'gray'));
|
|
?>
|
|
<tr class="hover:bg-gray-50 transition <?php echo $index > 0 ? 'border-t border-gray-50' : ''; ?>">
|
|
<td class="p-3 font-bold text-blue-600 text-lg w-10"><?php echo $index + 1; ?></td>
|
|
<td class="p-3">
|
|
<p class="font-bold"><?php echo htmlspecialchars($rank['name']); ?></p>
|
|
<p class="text-[10px] text-gray-400"><?php echo htmlspecialchars($rank['company_name']); ?>
|
|
<?php echo htmlspecialchars($rank['dept_name']); ?>
|
|
</p>
|
|
</td>
|
|
<td class="p-3 text-right">
|
|
<span class="font-bold mr-2"><?php echo number_format($rank['total_hours'], 1); ?>시간</span>
|
|
<span
|
|
class="px-2 py-0.5 bg-<?php echo $level_color; ?>-100 text-<?php echo $level_color; ?>-600 text-[10px] rounded font-bold"><?php echo $level; ?></span>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<!--
|
|
<button class="w-full py-3 bg-slate-50 text-xs text-gray-400 font-medium hover:bg-slate-100 border-t border-gray-100 italic transition">
|
|
<i class="fa-solid fa-thumbs-up mr-2"></i>추천 영상 보기
|
|
</button>
|
|
-->
|
|
</div>
|
|
</section>
|
|
<!-- 접속자 리스트 모달 -->
|
|
<div id="accessListModal" class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 hidden">
|
|
<div class="bg-white rounded-xl shadow-lg w-full max-w-4xl overflow-hidden flex flex-col max-h-[85vh]">
|
|
<div class="px-6 py-4 border-b border-gray-100 flex justify-between items-center bg-gray-50">
|
|
<h3 class="font-bold text-gray-800" id="accessListTitle">법인별 접속자 리스트</h3>
|
|
<button onclick="closeAccessListModal()" class="text-gray-400 hover:text-gray-600 transition">
|
|
<i class="fa-solid fa-xmark text-xl"></i>
|
|
</button>
|
|
</div>
|
|
<div class="px-6 py-4 bg-gray-50/50 flex flex-wrap gap-4 items-center">
|
|
<div class="flex items-center gap-2">
|
|
<span class="text-xs font-bold text-gray-600">조회기간</span>
|
|
<input type="date" id="modal_access_fr_date"
|
|
class="border border-gray-300 rounded px-2 py-1 text-sm bg-white shadow-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
<span class="text-gray-400">~</span>
|
|
<input type="date" id="modal_access_to_date"
|
|
class="border border-gray-300 rounded px-2 py-1 text-sm bg-white shadow-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<span class="text-xs font-bold text-gray-600">기준법인</span>
|
|
<select id="modal_access_comp"
|
|
class="border border-gray-300 rounded px-2 py-1 text-sm bg-white shadow-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
<option value="">전체</option>
|
|
<?php foreach ($companies as $comp): ?>
|
|
|
|
<option value="<?php echo htmlspecialchars($comp['code']); ?>">
|
|
<?php echo htmlspecialchars($comp['name']); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<button onclick="searchAccessLogsInModal()"
|
|
class="px-4 py-1.5 bg-blue-600 text-white rounded font-bold text-sm hover:bg-blue-700 transition flex items-center transform active:scale-95 duration-100">
|
|
<i class="fa-solid fa-magnifying-glass mr-2 text-xs"></i>검색
|
|
</button>
|
|
</div>
|
|
<div class="px-6 pb-6 pt-2 overflow-y-auto max-h-[50vh]">
|
|
<table class="w-full text-sm text-left border-collapse">
|
|
<thead class="bg-gray-100 text-gray-600 sticky top-0 z-10 whitespace-nowrap shadow-[0_1px_0_0_#e5e7eb]">
|
|
<tr>
|
|
<th class="py-2 px-4 font-bold border-b border-gray-200">기준법인</th>
|
|
<th class="py-2 px-4 font-bold border-b border-gray-200">이름</th>
|
|
<th class="py-2 px-4 font-bold border-b border-gray-200">부서명</th>
|
|
<th class="py-2 px-4 font-bold border-b border-gray-200">직위</th>
|
|
<th id="thAccessedAt"
|
|
class="py-2 px-4 font-bold border-b border-gray-200 cursor-pointer select-none hover:bg-gray-200 transition whitespace-nowrap"
|
|
onclick="sortByAccessedAt()">
|
|
접속일시 <span id="sortIcon" class="ml-1 text-gray-400">↕</span>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="accessListBody">
|
|
<!-- 데이터 삽입 영역 -->
|
|
</tbody>
|
|
</table>
|
|
<div id="accessListEmpty" class="text-center py-6 text-gray-500 hidden">
|
|
접속자 데이터가 없습니다.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 법인별 통계 상세 모달 -->
|
|
<div id="corpDetailModal" class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 hidden">
|
|
<div class="bg-white rounded-xl shadow-lg w-full max-w-5xl overflow-hidden flex flex-col max-h-[90vh]">
|
|
<div class="px-6 py-4 border-b border-gray-100 flex justify-between items-center bg-gray-50">
|
|
<h3 class="font-bold text-gray-800" id="corpDetailTitle">법인별 통계 상세 정보</h3>
|
|
<button onclick="closeCorpDetailModal()" class="text-gray-400 hover:text-gray-600 transition">
|
|
<i class="fa-solid fa-xmark text-xl"></i>
|
|
</button>
|
|
</div>
|
|
<div class="px-6 py-4 bg-gray-50/50 flex flex-wrap gap-4 items-center">
|
|
<div class="flex items-center gap-2">
|
|
<span class="text-xs font-bold text-gray-600">조회기간</span>
|
|
<input type="date" id="modal_stat_fr_date"
|
|
class="border border-gray-300 rounded px-2 py-1 text-sm bg-white shadow-sm focus:ring-2 focus:ring-teal-500 outline-none">
|
|
<span class="text-gray-400">~</span>
|
|
<input type="date" id="modal_stat_to_date"
|
|
class="border border-gray-300 rounded px-2 py-1 text-sm bg-white shadow-sm focus:ring-2 focus:ring-teal-500 outline-none">
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<span class="text-xs font-bold text-gray-600">기준법인</span>
|
|
<select id="modal_stat_comp_code"
|
|
class="border border-gray-300 rounded px-2 py-1 text-sm bg-white shadow-sm focus:ring-2 focus:ring-teal-500 outline-none">
|
|
<option value="">전체</option>
|
|
|
|
<?php foreach ($companies as $comp): ?>
|
|
<option value="<?php echo htmlspecialchars($comp['code']); ?>">
|
|
<?php echo htmlspecialchars($comp['name']); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<button onclick="searchCorpDetailInModal()"
|
|
class="px-4 py-1.5 bg-teal-600 text-white rounded font-bold text-sm hover:bg-teal-700 transition flex items-center shadow-md transform active:scale-95 duration-100">
|
|
<i class="fa-solid fa-magnifying-glass mr-2 text-xs"></i>검색
|
|
</button>
|
|
</div>
|
|
<div class="px-6 pb-6 pt-2 overflow-y-auto">
|
|
<table class="w-full text-sm text-left border-collapse">
|
|
<thead class="bg-gray-100 text-gray-600 sticky top-0 z-10 whitespace-nowrap shadow-[0_1px_0_0_#e5e7eb]">
|
|
<tr>
|
|
<th class="py-2 px-4 font-bold border-b border-gray-200 w-[5%] text-center">번호</th>
|
|
<th class="py-2 px-4 font-bold border-b border-gray-200 w-[10%] text-center">사번</th>
|
|
<th class="py-2 px-4 font-bold border-b border-gray-200 w-[12%]">성명</th>
|
|
<th class="py-2 px-4 font-bold border-b border-gray-200 w-[18%]">부서</th>
|
|
<th class="py-2 px-4 font-bold border-b border-gray-200 w-[30%]">과정명</th>
|
|
<th class="py-2 px-4 font-bold border-b border-gray-200 w-[25%] text-center">최종학습일</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="corpDetailBody">
|
|
<!-- 데이터 삽입 영역 -->
|
|
</tbody>
|
|
</table>
|
|
<div id="corpDetailEmpty" class="text-center py-6 text-gray-500 hidden">
|
|
데이터가 없습니다.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
<script>
|
|
function getCommonParams() {
|
|
return {
|
|
ranking_comp: document.getElementById('rankingComp').value,
|
|
rank_fr_date: document.getElementById('rank_fr_date').value,
|
|
rank_to_date: document.getElementById('rank_to_date').value,
|
|
exclude_admin: document.getElementById('excludeAdmin').checked ? '1' : '0',
|
|
|
|
access_comp: document.getElementById('accessTrendComp').value,
|
|
|
|
video_fr_date: document.getElementById('video_fr_date').value,
|
|
video_to_date: document.getElementById('video_to_date').value,
|
|
video_category: document.getElementById('videoCategory').value,
|
|
|
|
fr_date: '<?php echo $fr_date; ?>',
|
|
to_date: '<?php echo $to_date; ?>'
|
|
};
|
|
}
|
|
|
|
function reloadWithParams(params) {
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
for (const [key, value] of Object.entries(params)) {
|
|
urlParams.set(key, value);
|
|
}
|
|
window.location.href = '?' + urlParams.toString();
|
|
}
|
|
|
|
function changeYear(year) {
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
urlParams.set('year', year);
|
|
urlParams.set('fr_date', year + '-01-01');
|
|
urlParams.set('to_date', year + '-12-31');
|
|
|
|
// 섹션별 상세 필터 파라미터가 있다면 제거하여 새 년도 기본값으로 리셋
|
|
const paramsToRemove = [
|
|
'rank_fr_date', 'rank_to_date',
|
|
'video_fr_date', 'video_to_date',
|
|
'stat_fr_date', 'stat_to_date',
|
|
'access_fr_date', 'access_to_date'
|
|
];
|
|
paramsToRemove.forEach(p => urlParams.delete(p));
|
|
|
|
window.location.href = '?' + urlParams.toString();
|
|
}
|
|
|
|
function updateRankingDate() {
|
|
const p = getCommonParams();
|
|
reloadWithParams(p);
|
|
}
|
|
|
|
function updateRankingFilter() {
|
|
const p = getCommonParams();
|
|
reloadWithParams(p);
|
|
}
|
|
|
|
function changeRankingComp() {
|
|
const p = getCommonParams();
|
|
reloadWithParams(p);
|
|
}
|
|
|
|
function updateVideoDate() {
|
|
const p = getCommonParams();
|
|
reloadWithParams(p);
|
|
}
|
|
|
|
function changeAccessTrendComp() {
|
|
const p = getCommonParams();
|
|
reloadWithParams(p);
|
|
}
|
|
|
|
function changeStatType() {
|
|
const type = document.getElementById('statType').value;
|
|
document.getElementById('avgStats').style.display = type === 'avg' ? 'block' : 'none';
|
|
document.getElementById('totalStats').style.display = type === 'total' ? 'block' : 'none';
|
|
}
|
|
|
|
function changeVideoCategory() {
|
|
const category = document.getElementById('videoCategory').value;
|
|
const contents = document.querySelectorAll('#videoContent > div');
|
|
contents.forEach(div => {
|
|
div.style.display = div.id === 'videos-' + category ? 'block' : 'none';
|
|
});
|
|
}
|
|
|
|
// 접속자 리스트 정렬 상태
|
|
let _accessLogData = [];
|
|
let _accessSortDir = 'desc'; // 기본: 최신순
|
|
|
|
function renderAccessLogTable(data) {
|
|
const tbody = document.getElementById('accessListBody');
|
|
tbody.innerHTML = '';
|
|
if (data.length === 0) {
|
|
document.getElementById('accessListEmpty').classList.remove('hidden');
|
|
return;
|
|
}
|
|
document.getElementById('accessListEmpty').classList.add('hidden');
|
|
data.forEach(log => {
|
|
const tr = document.createElement('tr');
|
|
tr.className = 'border-b border-gray-100 hover:bg-gray-50';
|
|
tr.innerHTML = `
|
|
<td class="py-2 px-4 text-gray-700">${log.comp_name || log.sys_comp_code || '-'}</td>
|
|
<td class="py-2 px-4 text-gray-800 font-medium">${log.name || '-'}</td>
|
|
<td class="py-2 px-4 text-gray-600">${log.dept_name || '-'}</td>
|
|
<td class="py-2 px-4 text-gray-600">${log.rank_name || '-'}</td>
|
|
<td class="py-2 px-4 text-gray-500">${log.accessed_at || '-'}</td>
|
|
`;
|
|
tbody.appendChild(tr);
|
|
});
|
|
}
|
|
|
|
function sortByAccessedAt() {
|
|
if (_accessLogData.length === 0) return;
|
|
_accessSortDir = _accessSortDir === 'desc' ? 'asc' : 'desc';
|
|
const icon = document.getElementById('sortIcon');
|
|
if (_accessSortDir === 'asc') {
|
|
icon.textContent = '↑';
|
|
icon.classList.remove('text-gray-400');
|
|
icon.classList.add('text-blue-500');
|
|
} else {
|
|
icon.textContent = '↓';
|
|
icon.classList.remove('text-gray-400');
|
|
icon.classList.add('text-blue-500');
|
|
}
|
|
const sorted = [..._accessLogData].sort((a, b) => {
|
|
const da = new Date(a.accessed_at || 0);
|
|
const db = new Date(b.accessed_at || 0);
|
|
return _accessSortDir === 'asc' ? da - db : db - da;
|
|
});
|
|
renderAccessLogTable(sorted);
|
|
}
|
|
|
|
function showAccessLogs(month) {
|
|
const fr_date = '<?php echo $access_fr_date; ?>';
|
|
const to_date = '<?php echo $access_to_date; ?>';
|
|
const accessComp = document.getElementById('accessTrendComp').value;
|
|
|
|
document.getElementById('modal_access_fr_date').value = fr_date;
|
|
document.getElementById('modal_access_to_date').value = to_date;
|
|
document.getElementById('modal_access_comp').value = accessComp;
|
|
|
|
// 정렬 상태 초기화
|
|
_accessLogData = [];
|
|
_accessSortDir = 'desc';
|
|
const icon = document.getElementById('sortIcon');
|
|
icon.textContent = '↕';
|
|
icon.className = 'ml-1 text-gray-400';
|
|
|
|
document.getElementById('accessListModal').classList.remove('hidden');
|
|
searchAccessLogsInModal(month);
|
|
}
|
|
|
|
function searchAccessLogsInModal(month = '') {
|
|
const fr_date = document.getElementById('modal_access_fr_date').value;
|
|
const to_date = document.getElementById('modal_access_to_date').value;
|
|
const accessComp = document.getElementById('modal_access_comp').value;
|
|
const year = fr_date ? fr_date.split('-')[0] : '<?php echo $selected_year; ?>';
|
|
|
|
document.getElementById('accessListTitle').innerText = accessComp ? `${accessComp} 접속자 리스트 (${fr_date} ~ ${to_date})` : `전체 접속자 리스트 (${fr_date} ~ ${to_date})`;
|
|
document.getElementById('accessListBody').innerHTML = '<tr><td colspan="5" class="text-center py-4 text-gray-500"><i class="fa-solid fa-spinner fa-spin mr-2"></i>로딩 중...</td></tr>';
|
|
document.getElementById('accessListEmpty').classList.add('hidden');
|
|
|
|
fetch(`../bbs/get_access_logs.php?year=${year}&month=${month}&access_comp=${accessComp}&fr_date=${fr_date}&to_date=${to_date}`)
|
|
.then(response => response.json())
|
|
.then(res => {
|
|
if (res.success) {
|
|
_accessLogData = res.data;
|
|
document.getElementById('accessListTitle').innerText += ` - ${_accessLogData.length}회`;
|
|
renderAccessLogTable(_accessLogData);
|
|
} else {
|
|
alert(res.message);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error fetching logs:', error);
|
|
document.getElementById('accessListBody').innerHTML = '<tr><td colspan="5" class="text-center py-4 text-red-500">데이터를 불러오는 중 오류가 발생했습니다.</td></tr>';
|
|
});
|
|
}
|
|
|
|
function closeAccessListModal() {
|
|
document.getElementById('accessListModal').classList.add('hidden');
|
|
}
|
|
|
|
function showCorpDetail(corpCode, type, corpName) {
|
|
const fr_date = '<?php echo $stat_fr_date; ?>';
|
|
const to_date = '<?php echo $stat_to_date; ?>';
|
|
|
|
document.getElementById('modal_stat_fr_date').value = fr_date;
|
|
document.getElementById('modal_stat_to_date').value = to_date;
|
|
document.getElementById('modal_stat_comp_code').value = corpCode;
|
|
document.getElementById('_corp_detail_type') ? null : (window._corp_detail_type = type);
|
|
|
|
document.getElementById('corpDetailModal').classList.remove('hidden');
|
|
searchCorpDetailInModal(type, corpName);
|
|
}
|
|
|
|
function searchCorpDetailInModal(type = window._corp_detail_type, corpName) {
|
|
const corpCode = document.getElementById('modal_stat_comp_code').value;
|
|
const fr_date = document.getElementById('modal_stat_fr_date').value;
|
|
const to_date = document.getElementById('modal_stat_to_date').value;
|
|
|
|
// 모달 타이틀 업데이트 (선택된 법인명 가져오기)
|
|
const select = document.getElementById('modal_stat_comp_code');
|
|
const selectedName = select.options[select.selectedIndex].text;
|
|
|
|
document.getElementById('corpDetailTitle').innerText = corpCode ? `${selectedName} 통계 상세 정보` : `전체 법인 통계 상세 정보`;
|
|
document.getElementById('corpDetailBody').innerHTML = '<tr><td colspan="6" class="text-center py-4 text-gray-500"><i class="fa-solid fa-spinner fa-spin mr-2"></i>로딩 중...</td></tr>';
|
|
document.getElementById('corpDetailEmpty').classList.add('hidden');
|
|
|
|
fetch(`../bbs/get_corp_stats_detail.php?corp_code=${corpCode}&fr_date=${fr_date}&to_date=${to_date}&type=${type}`)
|
|
.then(response => response.json())
|
|
.then(res => {
|
|
if (res.success) {
|
|
const tbody = document.getElementById('corpDetailBody');
|
|
tbody.innerHTML = '';
|
|
if (res.data.length === 0) {
|
|
document.getElementById('corpDetailEmpty').classList.remove('hidden');
|
|
return;
|
|
}
|
|
res.data.forEach((item, index) => {
|
|
const tr = document.createElement('tr');
|
|
tr.className = 'border-b border-gray-100 hover:bg-gray-50';
|
|
tr.innerHTML = `
|
|
<td class="py-2 px-4 text-gray-500 text-center text-xs">${index + 1}</td>
|
|
<td class="py-2 px-4 text-gray-700 text-center">${item.member_id || '-'}</td>
|
|
<td class="py-2 px-4 text-gray-800 font-medium">${item.name || '-'}</td>
|
|
<td class="py-2 px-4 text-gray-600">${item.dept_name || '-'}</td>
|
|
<td class="py-2 px-4 text-gray-600 truncate max-w-0" title="${item.content_title || ''}">${item.content_title || '-'}</td>
|
|
<td class="py-2 px-4 text-gray-500 text-center">${item.last_viewed_at || '-'}</td>
|
|
`;
|
|
tbody.appendChild(tr);
|
|
});
|
|
} else {
|
|
alert(res.message);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error fetching detail:', error);
|
|
document.getElementById('corpDetailBody').innerHTML = '<tr><td colspan="6" class="text-center py-4 text-red-500">데이터를 불러오는 중 오류가 발생했습니다.</td></tr>';
|
|
});
|
|
}
|
|
|
|
function closeCorpDetailModal() {
|
|
document.getElementById('corpDetailModal').classList.add('hidden');
|
|
}
|
|
</script>
|
|
</body>
|
|
|
|
</html>
|