first commit 2

This commit is contained in:
hmw1001
2026-06-11 18:47:38 +09:00
parent c768729ce6
commit 6f534e33a6
11095 changed files with 1595758 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
<?php
define('G5_IS_ADMIN', true);
define('G5_IS_ADMIN', true);
include_once('../../common.php');
if (!defined('_GNUBOARD_')) exit;
include_once(G5_ADMIN_PATH.'/admin.lib.php');
//if (isset($token)) {
// $token = @htmlspecialchars(strip_tags($token), ENT_QUOTES);
//}
//
//run_event('admin_common');
@@ -0,0 +1,12 @@
<?php
if (!defined('_GNUBOARD_')) exit;
// 710번대 최상위 메뉴 '통계관리'를 정의합니다.
// 💡 [수정] 통계관리 메뉴 링크 수정
$menu['menu720'][] = array('720100', '통계관리', G5_ADMIN_URL . '/statistics/index.php', 'statistics');
$menu['menu720'][] = array('720200', '통계현황', G5_ADMIN_URL . '/statistics/visit_list.php', 'st_visit'); // 상세 통계 페이지로 변경
//$menu['menu720'][] = array('720300', '접속통계', G5_ADMIN_URL . '/statistics/index.php', 'st_visit_summary'); // 요약 페이지
$menu['menu720'][] = array('720400', '광고현황', G5_ADMIN_URL . '/statistics/banner.php', 'st_keyword');
$menu['menu720'][] = array('720500', '개시판통계', G5_ADMIN_URL . '/statistics/board.php', 'st_board');
$menu['menu720'][] = array('720600', '솔루션 설치', G5_ADMIN_URL . '/statistics/install.php', 'install');
?>
+240
View File
@@ -0,0 +1,240 @@
<?php
include_once('./_common.php');
//if (!isset($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest') {
// die(json_encode(['error' => '잘못된 접근입니다.']));
//}
$type = isset($_GET['type']) ? preg_replace('/[^a-z_]/i', '', $_GET['type']) : 'time';
$start_day = isset($_GET['start_day']) ? $_GET['start_day'] : G5_TIME_YMD;
$end_day = isset($_GET['end_day']) ? $_GET['end_day'] : G5_TIME_YMD;
$result = [
'type' => 'bar',
'title' => '',
'labels' => [],
'datasets' => [],
'list' => [],
];
$data = [];
$sql = '';
$sql_common = " from {$g5['visit_table']} ";
$sql_search = " where vi_date between '{$start_day}' and '{$end_day}' ";
// 배너 테이블 존재 여부 확인
$banner_table = 'rb_banner';//isset($g5['banner_table']) ? $g5['banner_table'] : 'g5_shop_banner';
switch($type) {
// --- 접속 통계 (기존 코드 유지) ---
case 'time':
$result['title'] = '시간별 접속 현황';
$sql = " SELECT SUBSTRING(vi_time, 1, 2) as `key`, count(vi_id) as `cnt` {$sql_common} {$sql_search} GROUP BY `key` ORDER BY `key` ";
break;
case 'week':
$result['title'] = '요일별 접속 현황';
$sql = " SELECT WEEKDAY(vi_date) as `key`, count(vi_id) as `cnt` {$sql_common} {$sql_search} GROUP BY `key` ORDER BY `key` ";
break;
case 'date':
$result['title'] = '일별 접속 현황';
$result['type'] = 'line';
$sql = " SELECT vi_date as `key`, count(vi_id) as `cnt` {$sql_common} {$sql_search} GROUP BY `key` ORDER BY `key` ";
break;
case 'month':
$result['title'] = '월별 접속 현황';
$result['type'] = 'line';
$sql = " SELECT SUBSTRING(vi_date, 1, 7) as `key`, count(vi_id) as `cnt` {$sql_common} {$sql_search} GROUP BY `key` ORDER BY `key` ";
break;
case 'domain':
$result['title'] = '접속전 도메인 TOP 50';
$sql = " SELECT vi_referer as `key`, count(vi_id) as `cnt` {$sql_common} {$sql_search} AND vi_referer != '' GROUP BY `key` ORDER BY `cnt` DESC LIMIT 50";
break;
case 'ip':
$result['title'] = '접속 IP TOP 50';
$sql = " SELECT vi_ip as `key`, count(vi_id) as `cnt` {$sql_common} {$sql_search} GROUP BY `key` ORDER BY `cnt` DESC LIMIT 50";
break;
case 'browser':
$result['title'] = '브라우저별 접속 현황';
$result['type'] = 'pie';
$sql = " SELECT vi_browser as `key`, count(vi_id) as `cnt` {$sql_common} {$sql_search} GROUP BY `key` ORDER BY `cnt` DESC LIMIT 20";
break;
case 'os':
$result['title'] = '운영체제별 접속 현황';
$result['type'] = 'pie';
$sql = " SELECT vi_os as `key`, count(vi_id) as `cnt` {$sql_common} {$sql_search} GROUP BY `key` ORDER BY `cnt` DESC LIMIT 20";
break;
// --- 게시물 통계 (수정된 부분) ---
case 'board_view':
$result['title'] = '게시판별 총 조회수';
// 💡 [수정] 모든 게시판을 순회하며 실제 wr_hit 합계 계산 (성능 최적화)
$boards = sql_query("SELECT bo_table, bo_subject FROM {$g5['board_table']} ORDER BY bo_count_write DESC");
$board_stats = [];
while($row = sql_fetch_array($boards)) {
$write_table = $g5['write_prefix'] . $row['bo_table'];
$chk = sql_fetch("SHOW TABLES LIKE '{$write_table}'");
if ($chk) {
$stat = sql_fetch("SELECT SUM(wr_hit) as cnt FROM {$write_table}");
if ($stat['cnt'] > 0) {
$board_stats[] = ['key' => $row['bo_subject'], 'cnt' => $stat['cnt']];
}
}
}
// 조회수 내림차순 정렬
usort($board_stats, function($a, $b) { return $b['cnt'] - $a['cnt']; });
$board_stats = array_slice($board_stats, 0, 20); // 상위 20개만
// SQL 실행 결과를 흉내내어 데이터 처리 로직으로 넘김
$data_source = $board_stats;
break;
case 'board_write':
$result['title'] = '게시판별 총 게시물 수';
$sql = " SELECT bo_subject as `key`, bo_count_write as `cnt` FROM {$g5['board_table']} ORDER BY `cnt` DESC LIMIT 20";
break;
case 'board_comment':
$result['title'] = '게시판별 총 댓글 수';
$sql = " SELECT bo_subject as `key`, bo_count_comment as `cnt` FROM {$g5['board_table']} ORDER BY `cnt` DESC LIMIT 20";
break;
case 'post_view':
$result['title'] = '게시물별 조회수 TOP 20';
// 💡 [수정] 모든 게시판을 순회하며 상위 게시물 수집 (성능 최적화)
$boards = sql_query("SELECT bo_table FROM {$g5['board_table']}");
$all_posts = [];
while($row = sql_fetch_array($boards)) {
$write_table = $g5['write_prefix'] . $row['bo_table'];
$chk = sql_fetch("SHOW TABLES LIKE '{$write_table}'");
if ($chk) {
// 각 게시판에서 상위 20개씩 가져옴
$res = sql_query("SELECT wr_subject as `key`, wr_hit as `cnt` FROM {$write_table} WHERE wr_is_comment = 0 ORDER BY wr_hit DESC LIMIT 20");
while($post = sql_fetch_array($res)) {
$all_posts[] = $post;
}
}
}
// 전체에서 다시 정렬하여 상위 20개 추출
usort($all_posts, function($a, $b) { return $b['cnt'] - $a['cnt']; });
$data_source = array_slice($all_posts, 0, 20);
break;
case 'post_comment':
$result['title'] = '게시물별 댓글 수 TOP 20';
// 💡 [수정] 모든 게시판을 순회하며 상위 게시물 수집
$boards = sql_query("SELECT bo_table FROM {$g5['board_table']}");
$all_posts = [];
while($row = sql_fetch_array($boards)) {
$write_table = $g5['write_prefix'] . $row['bo_table'];
$chk = sql_fetch("SHOW TABLES LIKE '{$write_table}'");
if ($chk) {
$res = sql_query("SELECT wr_subject as `key`, wr_comment as `cnt` FROM {$write_table} WHERE wr_is_comment = 0 ORDER BY wr_comment DESC LIMIT 20");
while($post = sql_fetch_array($res)) {
$all_posts[] = $post;
}
}
}
usort($all_posts, function($a, $b) { return $b['cnt'] - $a['cnt']; });
$data_source = array_slice($all_posts, 0, 20);
break;
// --- 배너 통계 (기존 코드 유지) ---
case 'position':
$result['title'] = '배너 위치별 클릭수';
$result['type'] = 'pie';
$chk = sql_fetch("SHOW TABLES LIKE '{$banner_table}'");
if ($chk) {
$sql = " SELECT bn_position as `key`, SUM(bn_hit) as `cnt` FROM {$banner_table} GROUP BY `key` ORDER BY `cnt` DESC ";
}
break;
case 'each':
$result['title'] = '개별 배너 클릭수 TOP 20';
$chk = sql_fetch("SHOW TABLES LIKE '{$banner_table}'");
if ($chk) {
$sql = " SELECT bn_alt as `key`, bn_hit as `cnt` FROM {$banner_table} ORDER BY `cnt` DESC LIMIT 20";
}
break;
// --- 검색어 통계 (기존 코드 유지) ---
case 'keyword_today':
case 'keyword_yesterday':
case 'keyword_week':
case 'keyword_month':
$result['title'] = '검색어 순위';
$from = $to = '';
if($type === 'keyword_today') { $from = $to = G5_TIME_YMD; }
if($type === 'keyword_yesterday') { $from = $to = date('Y-m-d', strtotime('-1 day')); }
if($type === 'keyword_week') { $from = date('Y-m-d', strtotime('-6 day')); $to = G5_TIME_YMD; }
if($type === 'keyword_month') { $from = date('Y-m-01'); $to = G5_TIME_YMD; }
$sql = " SELECT pp_word as `key`, pp_count as `cnt` FROM {$g5['popular_table']} WHERE pp_date BETWEEN '{$from}' AND '{$to}' GROUP BY pp_word ORDER BY `cnt` DESC LIMIT 50";
break;
}
// 데이터 처리 공통 로직
if (isset($data_source)) {
// PHP 배열로 데이터가 준비된 경우 (게시판 통계 등)
$sum_count = 0;
$max = 0;
foreach($data_source as $row) {
$sum_count += $row['cnt'];
if ($row['cnt'] > $max) $max = $row['cnt'];
}
foreach($data_source as $row) {
$key = $row['key'] ?: '알수없음';
$result['labels'][] = $key;
$data[] = $row['cnt'];
$rate = ($sum_count > 0) ? $row['cnt'] / $sum_count * 100 : 0;
$bar_width = ($max > 0) ? $row['cnt'] / $max * 100 : 0;
$result['list'][] = [
'key' => $key,
'count' => number_format($row['cnt']),
'rate' => number_format($rate, 1),
'bar_width' => $bar_width
];
}
} else if ($sql) {
// SQL 쿼리로 데이터가 준비된 경우 (접속 통계 등)
$res = sql_query($sql, false);
if ($res) {
$sum_count = 0;
$max = 0;
$temp_list = [];
while($row = sql_fetch_array($res)) {
$temp_list[] = $row;
$sum_count += $row['cnt'];
if ($row['cnt'] > $max) $max = $row['cnt'];
}
foreach($temp_list as $row) {
$key = $row['key'] ?: '알수없음';
if ($type == 'week') {
$week_name = ['월', '화', '수', '목', '금', '토', '일'];
$key = isset($week_name[$row['key']]) ? $week_name[$row['key']] : '알수없음';
}
$result['labels'][] = $key;
$data[] = $row['cnt'];
$rate = ($sum_count > 0) ? $row['cnt'] / $sum_count * 100 : 0;
$bar_width = ($max > 0) ? $row['cnt'] / $max * 100 : 0;
$result['list'][] = [
'key' => $key,
'count' => number_format($row['cnt']),
'rate' => number_format($rate, 1),
'bar_width' => $bar_width
];
}
}
}
$dataset_item = ['label' => '수', 'data' => $data];
if (in_array($result['type'], ['pie', 'doughnut', 'radar'])) {
$colors = [
'rgba(255, 99, 132, 0.7)', 'rgba(54, 162, 235, 0.7)', 'rgba(255, 206, 86, 0.7)',
'rgba(75, 192, 192, 0.7)', 'rgba(153, 102, 255, 0.7)', 'rgba(255, 159, 64, 0.7)'
];
$dataset_item['backgroundColor'] = array_slice($colors, 0, count($data));
} else {
$dataset_item['backgroundColor'] = 'rgba(54, 162, 235, 0.5)';
}
$result['datasets'][] = $dataset_item;
echo json_encode($result);
?>
+140
View File
@@ -0,0 +1,140 @@
<?php
$sub_menu = '720400';
include_once('./_common.php');
auth_check_menu($auth, $sub_menu, "r");
$g5['title'] = "배너 통계";
include_once(G5_ADMIN_PATH.'/admin.head.php');
$type = isset($_GET['type']) ? preg_replace('/[^a-z]/i', '', $_GET['type']) : 'position';
?>
<link rel="stylesheet" href="statistics.css?ver=<?php echo G5_CSS_VER; ?>">
<div class="notbox">
<p>위치별, 배너별 노출수와 클릭수를 시각적으로 분석할 수 있습니다.</p>
</div>
<dl class="srchb lnb4_col bg2_col">
<table class="bg_col">
<tbody>
<tr>
<td class="ctlt bno">통계분류</td>
<td class="wbg pl7">
<ul class="List">
<li><a href="./banner.php?type=position" class="<?php echo ($type == 'position') ? 'btn_ov01' : 'btn_ov02'; ?>">위치별 통계</a></li>
<li><a href="./banner.php?type=each" class="<?php echo ($type == 'each') ? 'btn_ov01' : 'btn_ov02'; ?>">개별 배너 통계</a></li>
</ul>
</td>
</tr>
</tbody>
</table>
</dl>
<div class="pt5" style="display: none;">
<dl class="srchb lnb4_col bg2_col">
<form name="statisticsSearchFrm" method="GET" id="statisticsSearchFrm">
<input type="hidden" name="type" value="<?php echo $type; ?>">
<dl class="tc pd7 wbg">
<input name="start_day" type="date" class="frm_input" id="start_day" value="<?php echo date('Y-m-d'); ?>"> ~
<input name="end_day" type="date" class="frm_input" id="end_day" value="<?php echo date('Y-m-d'); ?>">
<a class="btn btn_03 set_day" data-date="today">오늘</a>
<a class="btn btn_03 set_day" data-date="week">이번주</a>
<a class="btn btn_03 set_day" data-date="month">이번달</a>
<a class="btn btn_03 set_day" data-date="7day">1주일</a>
<a class="btn btn_03 set_day" data-date="15day">15일</a>
<a class="btn btn_03 set_day" data-date="30day">1개월</a>
<a class="btn btn_03 set_day" data-date="60day">3개월</a>
<a class="btn btn_03 set_day" data-date="120day">6개월</a>
&nbsp;
<button type="button" id="btn_search" class="btn_submit btn">검색</button>
</dl>
</form>
</dl>
</div>
<div id="chart-type-selector" class="local_sch01 local_sch">
<strong>차트 모양</strong>
<a class="btn btn_03 chart-btn active" data-chart-type="bar">세로막대</a>
<a class="btn btn_03 chart-btn" data-chart-type="horizontalBar">가로막대</a>
<a class="btn btn_03 chart-btn" data-chart-type="line">선그래프</a>
<a class="btn btn_03 chart-btn" data-chart-type="pie">원형</a>
<a class="btn btn_03 chart-btn" data-chart-type="doughnut">도넛</a>
<a class="btn btn_03 chart-btn" data-chart-type="radar">레이더</a>
</div>
<div class="chart-container">
<canvas id="myChart"></canvas>
</div>
<!-- 💡 [핵심 수정] 이미지 경로 수정 -->
<dl class="ntlt lnb_col"><img src="img/bul_10.png" class="t"> 상세 데이터</dl>
<table width="100%" class="access ttlt tf">
<thead>
<tr class="bg">
<th>항목</th>
<th>그래프</th>
<th>클릭수</th>
<th>비율(%)</th>
</tr>
</thead>
<tbody id="data-table-body">
<!-- 데이터가 여기에 동적으로 추가됩니다. -->
</tbody>
</table>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="statistics.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
<script>
$(function(){
$(".hasDatepicker").datepicker({
dateFormat: "yy-mm-dd"
});
$('.set_day').click(function(){
var term = $(this).data('date');
var today = new Date();
var start_day, end_day;
end_day = $.datepicker.formatDate('yy-mm-dd', today);
switch(term) {
case 'today':
start_day = end_day;
break;
case 'week':
today.setDate(today.getDate() - today.getDay() + (today.getDay() === 0 ? -6 : 1));
start_day = $.datepicker.formatDate('yy-mm-dd', today);
break;
case 'month':
start_day = $.datepicker.formatDate('yy-mm-01', today);
break;
default:
var days = parseInt(term.replace('day', ''));
today.setDate(today.getDate() - (days - 1));
start_day = $.datepicker.formatDate('yy-mm-dd', today);
break;
}
$('#start_day').val(start_day);
$('#end_day').val(end_day);
// 💡 [핵심 수정] 선택된 버튼 스타일 적용
$('.set_day').removeClass('active');
$(this).addClass('active');
});
// 차트 종류 변경 버튼 이벤트
$('.chart-btn').click(function(){
var chartType = $(this).data('chart-type');
// createChart(chartType);
$('.chart-btn').removeClass('active');
$(this).addClass('active');
});
});
</script>
<?php
include_once(G5_ADMIN_PATH.'/admin.tail.php');
?>
+145
View File
@@ -0,0 +1,145 @@
<?php
$sub_menu = '720500'; // 💡 [변경] 게시판 통계 메뉴 코드
include_once('./_common.php');
auth_check_menu($auth, $sub_menu, "r");
$g5['title'] = "게시판 통계";
include_once(G5_ADMIN_PATH.'/admin.head.php');
$type = isset($_GET['type']) ? preg_replace('/[^a-z_]/i', '', $_GET['type']) : 'board_view'; // 💡 [변경] 기본값
?>
<!-- 💡 [공통] CSS 파일 로드 -->
<link rel="stylesheet" href="statistics.css?ver=<?php echo G5_CSS_VER; ?>">
<div class="notbox">
<p>게시판별, 게시물별 조회수와 활동 현황을 시각적으로 분석할 수 있습니다.</p>
</div>
<dl class="srchb lnb4_col bg2_col">
<table class="bg_col">
<tbody>
<tr>
<td class="ctlt bno">통계분류</td>
<td class="wbg pl7">
<ul class="List">
<!-- 💡 [변경] 게시판 통계용 탭 메뉴 -->
<li><a href="./board.php?type=board_view" class="<?php echo ($type == 'board_view') ? 'btn_ov01' : 'btn_ov02'; ?>">게시판별 조회수</a></li>
<li><a href="./board.php?type=board_write" class="<?php echo ($type == 'board_write') ? 'btn_ov01' : 'btn_ov02'; ?>">게시판별 게시물 수</a></li>
<li><a href="./board.php?type=board_comment" class="<?php echo ($type == 'board_comment') ? 'btn_ov01' : 'btn_ov02'; ?>">게시판별 댓글 수</a></li>
<li><a href="./board.php?type=post_view" class="<?php echo ($type == 'post_view') ? 'btn_ov01' : 'btn_ov02'; ?>">게시물별 조회수 TOP 20</a></li>
<li><a href="./board.php?type=post_comment" class="<?php echo ($type == 'post_comment') ? 'btn_ov01' : 'btn_ov02'; ?>">게시물별 댓글 수 TOP 20</a></li>
</ul>
</td>
</tr>
</tbody>
</table>
</dl>
<div class="pt5">
<dl class="srchb lnb4_col bg2_col">
<form name="statisticsSearchFrm" method="GET" id="statisticsSearchFrm">
<input type="hidden" name="type" value="<?php echo $type; ?>">
<dl class="tc pd7 wbg">
<input name="start_day" type="date" class="frm_input" id="start_day" value="<?php echo date('Y-m-d'); ?>"> ~
<input name="end_day" type="date" class="frm_input" id="end_day" value="<?php echo date('Y-m-d'); ?>">
<a class="btn btn_03 set_day" data-date="today">오늘</a>
<a class="btn btn_03 set_day" data-date="week">이번주</a>
<a class="btn btn_03 set_day" data-date="month">이번달</a>
<a class="btn btn_03 set_day" data-date="7day">1주일</a>
<a class="btn btn_03 set_day" data-date="15day">15일</a>
<a class="btn btn_03 set_day" data-date="30day">1개월</a>
<a class="btn btn_03 set_day" data-date="60day">3개월</a>
<a class="btn btn_03 set_day" data-date="120day">6개월</a>
&nbsp;
<button type="button" id="btn_search" class="btn_submit btn">검색</button>
</dl>
</form>
</dl>
</div>
<div id="chart-type-selector" class="local_sch01 local_sch">
<strong>차트 모양</strong>
<a class="btn btn_03 chart-btn active" data-chart-type="bar">세로막대</a>
<a class="btn btn_03 chart-btn" data-chart-type="horizontalBar">가로막대</a>
<a class="btn btn_03 chart-btn" data-chart-type="line">선그래프</a>
<a class="btn btn_03 chart-btn" data-chart-type="pie">원형</a>
<a class="btn btn_03 chart-btn" data-chart-type="doughnut">도넛</a>
<a class="btn btn_03 chart-btn" data-chart-type="radar">레이더</a>
</div>
<div class="chart-container">
<canvas id="myChart"></canvas>
</div>
<dl class="ntlt lnb_col"><img src="img/bul_10.png" class="t"> 상세 데이터</dl>
<table width="100%" class="access ttlt tf">
<thead>
<tr class="bg">
<th>항목</th>
<th>그래프</th>
<th>수</th>
<th>비율(%)</th>
</tr>
</thead>
<tbody id="data-table-body">
<!-- 데이터가 여기에 동적으로 추가됩니다. -->
</tbody>
</table>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="statistics.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
<script>
$(function(){
$(".hasDatepicker").datepicker({
dateFormat: "yy-mm-dd"
});
$('.set_day').click(function(){
var term = $(this).data('date');
var today = new Date();
var start_day, end_day;
end_day = $.datepicker.formatDate('yy-mm-dd', today);
switch(term) {
case 'today':
start_day = end_day;
break;
case 'week':
today.setDate(today.getDate() - today.getDay() + (today.getDay() === 0 ? -6 : 1));
start_day = $.datepicker.formatDate('yy-mm-dd', today);
break;
case 'month':
start_day = $.datepicker.formatDate('yy-mm-01', today);
break;
default:
var days = parseInt(term.replace('day', ''));
today.setDate(today.getDate() - (days - 1));
start_day = $.datepicker.formatDate('yy-mm-dd', today);
break;
}
$('#start_day').val(start_day);
$('#end_day').val(end_day);
// 💡 [핵심 수정] 선택된 버튼 스타일 적용
$('.set_day').removeClass('active');
$(this).addClass('active');
});
// 차트 종류 변경 버튼 이벤트
$('.chart-btn').click(function(){
var chartType = $(this).data('chart-type');
// createChart(chartType);
$('.chart-btn').removeClass('active');
$(this).addClass('active');
});
});
</script>
<?php
include_once(G5_ADMIN_PATH.'/admin.tail.php');
?>
Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

+283
View File
@@ -0,0 +1,283 @@
<?php
$sub_menu = '720100';
include_once('./_common.php');
auth_check_menu($auth, $sub_menu, "r");
$g5['title'] = "접속통계";
include_once(G5_ADMIN_PATH.'/admin.head.php');
//--- 데이터 처리 시작 ---//
$type = isset($_GET['type']) ? preg_replace('/[^a-z]/i', '', $_GET['type']) : 'summary';
// 날짜 검색
$start_day = isset($_GET['start_day']) && preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/", $_GET['start_day']) ? $_GET['start_day'] : G5_TIME_YMD;
$end_day = isset($_GET['end_day']) && preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/", $_GET['end_day']) ? $_GET['end_day'] : G5_TIME_YMD;
$list = [];
$sum_count = 0;
$max = 0;
$chart_data = ['labels' => [], 'datasets' => [['data' => []]]];
$page_title = '';
$chart_type = 'bar';
$sql_common = " from {$g5['visit_table']} ";
$sql_search = " where vi_date between '{$start_day}' and '{$end_day}' ";
switch ($type) {
case 'time':
$page_title = '시간별 통계';
$sql = " select SUBSTRING(vi_time, 1, 2) as `key`, count(vi_id) as `cnt` {$sql_common} {$sql_search} group by `key` order by `key` ";
break;
case 'week':
$page_title = '요일별 통계';
$sql = " select weekday(vi_date) as `key`, count(vi_id) as `cnt` {$sql_common} {$sql_search} group by `key` order by `key` ";
break;
case 'date':
$page_title = '일별 통계';
$chart_type = 'line';
$sql = " select vi_date as `key`, count(vi_id) as `cnt` {$sql_common} {$sql_search} group by `key` order by `key` ";
break;
case 'month':
$page_title = '월별 통계';
$chart_type = 'line';
$sql = " select SUBSTRING(vi_date, 1, 7) as `key`, count(vi_id) as `cnt` {$sql_common} {$sql_search} group by `key` order by `key` ";
break;
case 'browser':
$page_title = '접속 브라우저';
$chart_type = 'pie';
$sql = " select vi_browser as `key`, count(vi_id) as `cnt` {$sql_common} {$sql_search} group by `key` order by `cnt` desc limit 10";
break;
case 'os':
$page_title = '접속 OS';
$chart_type = 'pie';
$sql = " select vi_os as `key`, count(vi_id) as `cnt` {$sql_common} {$sql_search} group by `key` order by `cnt` desc limit 10";
break;
// ... (다른 케이스들)
default:
$page_title = '접속통계 요약';
break;
}
if ($type !== 'summary' && $sql) {
$result = sql_query($sql);
while($row = sql_fetch_array($result)) {
$list[] = $row;
$sum_count += $row['cnt'];
if ($row['cnt'] > $max) $max = $row['cnt'];
}
}
//--- 데이터 처리 끝 ---//
?>
<link rel="stylesheet" href="statistics.css?ver=<?php echo G5_CSS_VER; ?>">
<link rel="stylesheet" href="//code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
<div class="notbox">
<p>시간 흐름(시간/일간/월간)에 따른 방문자 현황 등을 한눈에 볼 수 있습니다.<br>
하루 하루 나타나는 데이터를 출력하여 모아 놓으면, 아주 소중한 사이트 운영가이드책이 될 수 있습니다.</p>
</div>
<dl class="srchb lnb4_col bg2_col">
<table class="bg_col">
<tbody><tr>
<td class="ctlt bno">통계분류</td>
<td class="wbg pl7">
<ul class="List">
<li><a href="./" class="<?php echo ($type == 'summary') ? 'btn_ov01' : 'btn_ov02'; ?>">접속통계</a></li>
<li><a href="./?type=time" class="<?php echo ($type == 'time') ? 'btn_ov01' : 'btn_ov02'; ?>">시간별 통계</a></li>
<li><a href="./?type=week" class="<?php echo ($type == 'week') ? 'btn_ov01' : 'btn_ov02'; ?>">요일별 통계</a></li>
<li><a href="./?type=date" class="<?php echo ($type == 'date') ? 'btn_ov01' : 'btn_ov02'; ?>">일별 통계</a></li>
<li><a href="./?type=month" class="<?php echo ($type == 'month') ? 'btn_ov01' : 'btn_ov02'; ?>">월별 통계</a></li>
<li><a href="./?type=domain" class="<?php echo ($type == 'domain') ? 'btn_ov01' : 'btn_ov02'; ?>">접속전 도메인</a></li>
<li><a href="./?type=ip" class="<?php echo ($type == 'ip') ? 'btn_ov01' : 'btn_ov02'; ?>">접속 IP</a></li>
<li><a href="./?type=browser" class="<?php echo ($type == 'browser') ? 'btn_ov01' : 'btn_ov02'; ?>">접속 브라우저</a></li>
<li><a href="./?type=os" class="<?php echo ($type == 'os') ? 'btn_ov01' : 'btn_ov02'; ?>">접속 OS</a></li>
</ul>
</td>
</tr>
</tbody></table>
</dl>
<?php if ($type !== 'summary'): ?>
<div class="pt5">
<dl class="srchb lnb4_col bg2_col">
<form name="statisticsSearchFrm" method="GET" id="statisticsSearchFrm">
<input type="hidden" name="type" value="<?php echo $type; ?>">
<dl class="tc pd7 wbg">
<input name="start_day" type="date" class="frm_input hasDatepicker" id="start_day" value="<?php echo $start_day; ?>"> ~
<input name="end_day" type="date" class="frm_input hasDatepicker" id="end_day" value="<?php echo $end_day; ?>">
<a class="btn btn_03 set_day" data-date="today">오늘</a>
<a class="btn btn_03 set_day" data-date="week">이번주</a>
<a class="btn btn_03 set_day" data-date="month">이번달</a>
<a class="btn btn_03 set_day" data-date="7day">1주일</a>
<a class="btn btn_03 set_day" data-date="15day">15일</a>
<a class="btn btn_03 set_day" data-date="30day">1개월</a>
<a class="btn btn_03 set_day" data-date="60day">3개월</a>
<a class="btn btn_03 set_day" data-date="120day">6개월</a>
&nbsp;
<button type="submit" class="btn_submit btn">검색</button>
<button type="button" class="btn" onclick="$('#statisticsSearchFrm').get(0).reset();">초기화</button>
</dl>
</form>
</dl>
</div>
<!-- 💡 [핵심 추가] 차트 종류 선택 UI -->
<div id="chart-type-selector" class="local_sch01 local_sch">
<strong>차트 모양</strong>
<a class="btn btn_03 chart-btn active" data-chart-type="bar">세로막대</a>
<a class="btn btn_03 chart-btn" data-chart-type="line">선그래프</a>
<a class="btn btn_03 chart-btn" data-chart-type="pie">원형</a>
<a class="btn btn_03 chart-btn" data-chart-type="doughnut">도넛</a>
<a class="btn btn_03 chart-btn" data-chart-type="radar">레이더</a>
</div>
<dl class="ntlt lnb_col"><img src="img/bul_10.png" class="t"> <?php echo $page_title; ?></dl>
<div class="chart-container">
<canvas id="myChart"></canvas>
</div>
<table width="100%" class="access ttlt tf">
<colgroup>
<col width="200">
<col>
<col width="100">
<col width="100">
</colgroup>
<thead>
<tr class="bg">
<th>항목</th>
<th>그래프</th>
<th>방문자수</th>
<th>비율(%)</th>
</tr>
</thead>
<tbody>
<?php
if (count($list)) {
foreach ($list as $row) {
$key = $row['key'] ?: '알수없음';
if ($type == 'week') {
$week_name = ['월', '화', '수', '목', '금', '토', '일'];
$key = isset($week_name[$row['key']]) ? $week_name[$row['key']] : '알수없음';
}
$rate = ($sum_count > 0) ? $row['cnt'] / $sum_count * 100 : 0;
$bar_width = ($max > 0) ? $row['cnt'] / $max * 100 : 0;
$chart_data['labels'][] = $key;
$chart_data['datasets'][0]['data'][] = $row['cnt'];
?>
<tr>
<td class="ct"><?php echo $key; ?></td>
<td><div class="graph"><span class="bar" style="width:<?php echo $bar_width; ?>%"></span></div></td>
<td class="rt"><?php echo number_format($row['cnt']); ?></td>
<td class="rt"><?php echo number_format($rate, 1); ?></td>
</tr>
<?php
}
} else {
echo '<tr><td colspan="4" class="empty_table">데이터가 없습니다.</td></tr>';
}
?>
</tbody>
</table>
<?php endif; ?>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
$(function(){
$(".hasDatepicker").datepicker({
dateFormat: "yy-mm-dd"
});
$('.set_day').click(function(){
var term = $(this).data('date');
var today = new Date();
var start_day, end_day;
end_day = $.datepicker.formatDate('yy-mm-dd', today);
switch(term) {
case 'today':
start_day = end_day;
break;
case 'week':
today.setDate(today.getDate() - today.getDay() + (today.getDay() === 0 ? -6 : 1));
start_day = $.datepicker.formatDate('yy-mm-dd', today);
break;
case 'month':
start_day = $.datepicker.formatDate('yy-mm-01', today);
break;
default:
var days = parseInt(term.replace('day', ''));
today.setDate(today.getDate() - (days - 1));
start_day = $.datepicker.formatDate('yy-mm-dd', today);
break;
}
$('#start_day').val(start_day);
$('#end_day').val(end_day);
// 💡 [핵심 수정] 선택된 버튼 스타일 적용
$('.set_day').removeClass('active');
$(this).addClass('active');
});
// 💡 [핵심 수정] 차트 생성 및 변경 로직
var chartData = <?php echo json_encode($chart_data); ?>;
var defaultChartType = '<?php echo $chart_type; ?>';
var ctx = document.getElementById('myChart');
var myChart;
function createChart(type) {
if (myChart) {
myChart.destroy();
}
if(ctx && chartData.labels.length > 0) {
// 💡 [핵심 수정] 원형/도넛 차트용 색상 배열 생성
if (['pie', 'doughnut', 'radar'].includes(type)) {
const colors = [
'rgba(255, 99, 132, 0.5)', 'rgba(54, 162, 235, 0.5)', 'rgba(255, 206, 86, 0.5)',
'rgba(75, 192, 192, 0.5)', 'rgba(153, 102, 255, 0.5)', 'rgba(255, 159, 64, 0.5)',
'rgba(255, 99, 132, 0.8)', 'rgba(54, 162, 235, 0.8)', 'rgba(255, 206, 86, 0.8)',
'rgba(75, 192, 192, 0.8)'
];
chartData.datasets[0].backgroundColor = colors;
} else {
chartData.datasets[0].backgroundColor = 'rgba(54, 162, 235, 0.5)';
}
myChart = new Chart(ctx, {
type: type,
data: {
labels: chartData.labels,
datasets: chartData.datasets
},
options: {
scales: { y: { beginAtZero: true } }
}
});
}
}
// 초기 차트 생성
createChart('bar');
// 차트 종류 변경 버튼 이벤트
$('.chart-btn').click(function(){
var chartType = $(this).data('chart-type');
createChart(chartType);
$('.chart-btn').removeClass('active');
$(this).addClass('active');
});
});
</script>
<?php
include_once(G5_ADMIN_PATH.'/admin.tail.php');
?>
+115
View File
@@ -0,0 +1,115 @@
<?php
$sub_menu = '850640';
include_once('./_common.php');
//include_once(__DIR__ . '/lib/SchemaManager.class.php');
if (!$is_admin) {
alert('관리자만 접근할 수 있습니다.');
}
$g5['title'] = '통계 솔루션 설치';
include_once(G5_ADMIN_PATH . '/admin.head.php');
$install_result = null;
$delete_result = null;
$action = $_POST['action'] ?? '';
if ($action === 'install') {
check_admin_token();
try {
$menu_msg = create_admin_menu_file();
$install_result = ['menu' => $menu_msg];
} catch (Exception $e) {
$install_result['errors'][] = '설치 중 심각한 오류 발생: ' . $e->getMessage();
}
} else if ($action === 'delete') {
check_admin_token();
$delete_result = ['tables' => [], 'menu' => ''];
$menu_file = G5_ADMIN_PATH . '/admin.menu720.statistics.php';
if (file_exists($menu_file)) {
if (@unlink($menu_file)) {
$delete_result['menu'] = '메뉴 파일 삭제 성공';
} else {
$delete_result['menu'] = '메뉴 파일 삭제 실패 (권한 확인 필요)';
}
}
}
function create_admin_menu_file() {
$source_file = __DIR__ . '/admin.menu720.statistics.php';
$target_file = G5_ADMIN_PATH . '/admin.menu720.statistics.php';
if (!file_exists($source_file)) return "실패 (메뉴 원본 파일 없음)";
if (file_exists($target_file)) return "성공 (이미 존재함)";
if (@copy($source_file, $target_file)) return "성공";
return "실패 (파일 복사 오류)";
}
$menu_file = G5_ADMIN_PATH . '/admin.menu720.statistics.php';
$is_installed = file_exists($menu_file);
?>
<style>
.install-container { max-width: 800px; margin: 20px auto; padding: 20px; background: #fff; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
.install-header { text-align: center; margin-bottom: 30px; padding-bottom: 20px; border-bottom: 2px solid #AA20FF; }
.install-header h1 { color: #AA20FF; margin-bottom: 10px; }
.feature-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin: 30px 0; }
.feature-card { padding: 20px; border: 1px solid #e0e0e0; border-radius: 8px; text-align: center; }
.feature-card i { font-size: 2em; color: #AA20FF; margin-bottom: 10px; }
.status-table { width: 100%; border-collapse: collapse; margin: 20px 0; }
.status-table th, .status-table td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
.status-table th { background-color: #f8f9fa; font-weight: bold; }
.status-ok { color: #28a745; font-weight: bold; }
.status-missing { color: #dc3545; font-weight: bold; }
.install-btn { display: block; width: 200px; margin: 30px auto; padding: 15px 30px; background: #AA20FF; color: white; text-align: center; text-decoration: none; border-radius: 5px; font-size: 16px; font-weight: bold; border: none; cursor: pointer; transition: background-color 0.3s; }
.install-btn:hover { background: #8A1ACC; color: white; }
.install-btn:disabled { background: #ccc; cursor: not-allowed; }
.alert { padding: 15px; margin: 20px 0; border-radius: 5px; }
.alert-success { background-color: #d4edda; border: 1px solid #c3e6cb; color: #155724; }
.alert-info { background-color: #d1ecf1; border: 1px solid #bee5eb; color: #0c5460; }
.alert-danger { background-color: #f8d7da; border: 1px solid #f5c6cb; color: #721c24; }
.btn-secondary { background: #6c757d; color: white; border-color: #6c757d; padding: 5px 10px; border-radius: 4px; text-decoration: none; }
.btn-secondary:hover { background: #5a6268; }
.btn-danger { background: #dc3545; color: white; border: none; padding: 10px 15px; border-radius: 4px; cursor: pointer; }
.btn-danger:hover { background: #c82333; }
.button-group { display: flex; justify-content: center; align-items: center; gap: 10px; }
</style>
<div class="install-container">
<div class="install-header">
<h1><i class="fa fa-calendar-check"></i> 상담 예약 시스템</h1>
<p>전문적인 상담 예약 관리 및 일정 관리 솔루션</p>
</div>
<?php if ($install_result): ?>
<div class="alert alert-success"><h4><i class="fa fa-check-circle"></i> 설치 작업 완료</h4><p>데이터베이스 및 기본 설정 설치가 완료되었습니다.</p><p><a href="./consultant_list.php" class="btn btn-primary">상담 예약 관리로 이동</a></p></div>
<?php elseif ($delete_result): ?>
<div class="alert alert-danger"><h4><i class="fa fa-trash"></i> 삭제 작업 완료</h4><p>솔루션 관련 데이터와 파일이 삭제되었습니다.</p><ul><?php foreach($delete_result['tables'] as $tbl) echo "<li>{$tbl} 테이블 삭제됨</li>"; ?><li><?php echo $delete_result['menu']; ?></li></ul></div>
<?php elseif ($is_installed): ?>
<div class="alert alert-success"><h4><i class="fa fa-check-circle"></i> 설치 완료</h4><p>상담 예약 시스템이 이미 설치되어 있습니다.</p><p><a href="./consultant_list.php" class="btn btn-primary">상담 예약 관리로 이동</a></p></div>
<?php else: ?>
<div class="alert alert-info"><h4><i class="fa fa-info-circle"></i> 설치 필요</h4><p>상담 예약 시스템을 사용하기 위해 설치가 필요합니다.</p></div>
<?php endif; ?>
<h3><i class="fa fa-database"></i> 설치 상태</h3>
<?php if (!$is_installed): ?>
<form method="post" onsubmit="return confirm('솔루션을 설치하시겠습니까?');">
<input type="hidden" name="action" value="install">
<input type="hidden" name="token" value="<?php echo get_token(); ?>">
<button type="submit" class="install-btn"><i class="fa fa-download"></i> 솔루션 설치하기</button>
</form>
<?php endif; ?>
<?php if ($is_installed && !$install_result && !$delete_result): ?>
<div class="button-group" style="text-align: center; margin-top: 20px;">
<form method="post" onsubmit="return confirm('정말로 솔루션을 삭제하시겠습니까? 모든 관련 데이터와 파일이 영구적으로 삭제됩니다.');">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="token" value="<?php echo get_token(); ?>">
<button type="submit" class="btn-danger"><i class="fa fa-trash"></i> 솔루션 삭제하기</button>
</form>
</div>
<?php endif; ?>
</div>
<?php
include_once(G5_ADMIN_PATH . '/admin.tail.php');
?>
+37
View File
@@ -0,0 +1,37 @@
<?php
$sub_menu = '720300';
include_once('./_common.php');
auth_check_menu($auth, $sub_menu, "r");
$g5['title'] = "검색어통계";
include_once(G5_ADMIN_PATH.'/admin.head.php');
?>
<link rel="stylesheet" href="statistics.css?ver=<?php echo G5_CSS_VER; ?>">
<div class="local_sch01 local_sch">
<ul class="List">
<li><a href="./keyword.php?type=today" class="btn_ov01">오늘</a></li>
<li><a href="./keyword.php?type=yesterday" class="btn_ov02">어제</a></li>
<li><a href="./keyword.php?type=week" class="btn_ov02">이번주</a></li>
<li><a href="./keyword.php?type=month" class="btn_ov02">이번달</a></li>
</ul>
</div>
<div id="chart-type-selector" class="local_sch01 local_sch">
<strong class="m-r-10">차트 모양</strong>
<button type="button" class="btn_ov02" data-chart-type="bar">세로막대</button>
<button type="button" class="btn_ov02" data-chart-type="horizontalBar">가로막대</button>
<button type="button" class="btn_ov02" data-chart-type="line">선</button>
</div>
<div class="chart-container">
<canvas id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="statistics.js?ver=<?php echo G5_JS_VER; ?>"></script>
<?php
include_once(G5_ADMIN_PATH.'/admin.tail.php');
?>
+80
View File
@@ -0,0 +1,80 @@
.notbox { border:1px solid #e9e9e9; background:#f7f7f7; padding:10px; text-align:center; margin-bottom:10px; }
.srchb { border:1px solid #e9e9e9; margin-bottom:10px; }
.srchb table { width:100%; }
.srchb td { padding:5px; }
.srchb .ctlt { background:#f7f7f7; text-align:center; font-weight:bold; }
.srchb .wbg { background:#fff; }
/* 💡 [핵심 수정] 통계 분류 탭 메뉴 스타일 복원 */
.srchb .List {
list-style: none;
margin: 0;
padding: 0;
display: flex;
gap: 5px;
flex-wrap: wrap;
}
.srchb .List li a {
display: block;
padding: 5px 10px;
border: 1px solid #ddd;
background: #f8f9fa;
color: #333;
text-decoration: none;
}
.srchb .List li a:hover {
background: #e9ecef;
}
.srchb .List li a.btn_ov01 {
background: #333;
color: #fff;
border-color: #000;
font-weight: bold;
}
/* 날짜 설정 및 차트 종류 버튼 스타일 */
.set_day,
#chart-type-selector .btn_03 {
cursor: pointer !important;
border: 1px solid #ccc;
padding: 5px 10px;
background: #f8f9fa;
border-radius: 4px;
text-decoration: none;
color: #333;
display: inline-block;
}
.set_day:hover,
#chart-type-selector .btn_03:hover {
background: #e9ecef;
}
.set_day.active,
#chart-type-selector .btn_03.active {
background: #333;
color: #fff;
border-color: #000;
font-weight: bold;
}
.ntlt { font-weight:bold; margin:15px 0 5px; }
.ttlt { width:100%; border-collapse:collapse; border-top:2px solid #999; }
.ttlt th, .ttlt td { padding:8px; border:1px solid #e9e9e9; }
.ttlt thead tr { background:#f7f7f7; }
.ttlt .rt { text-align:right; }
.ttlt .ct { text-align:center; }
.graph { background:#eee; width:100%; height:15px; border-radius: 3px; overflow: hidden;}
.graph .bar { display:block; background:#627ab8; height:100%; text-align:right; color:#fff; padding-right:5px; }
.chart-container {
width: 100%;
max-width: 1000px;
margin: 30px auto;
padding: 20px;
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
}
.empty-chart { text-align:center; padding: 50px; }
+142
View File
@@ -0,0 +1,142 @@
document.addEventListener('DOMContentLoaded', function() {
const ctx = document.getElementById('myChart');
if (!ctx) return;
const urlParams = new URLSearchParams(window.location.search);
let type = urlParams.get('type');
const currentPage = window.location.pathname.split('/').pop();
if (!type) {
if (currentPage.includes('visit_list.php')) type = 'time';
else if (currentPage.includes('keyword.php')) type = 'today';
else if (currentPage.includes('board.php')) type = 'board_view';
else if (currentPage.includes('banner.php')) type = 'position';
else type = 'summary';
}
let myChart;
let currentChartData;
function createChart(chartType, chartData) {
if (myChart) {
myChart.destroy();
}
const isHorizontal = chartType === 'horizontalBar';
const finalChartType = isHorizontal ? 'bar' : chartType;
const options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { position: 'top' },
title: { display: true, text: chartData.title }
},
indexAxis: isHorizontal ? 'y' : 'x',
};
if (['pie', 'doughnut', 'radar'].includes(chartType)) {
const colors = [
'rgba(255, 99, 132, 0.5)', 'rgba(54, 162, 235, 0.5)', 'rgba(255, 206, 86, 0.5)',
'rgba(75, 192, 192, 0.5)', 'rgba(153, 102, 255, 0.5)', 'rgba(255, 159, 64, 0.5)',
'rgba(255, 99, 132, 0.8)', 'rgba(54, 162, 235, 0.8)', 'rgba(255, 206, 86, 0.8)',
'rgba(75, 192, 192, 0.8)'
];
chartData.datasets[0].backgroundColor = colors;
} else {
chartData.datasets[0].backgroundColor = 'rgba(54, 162, 235, 0.5)';
}
myChart = new Chart(ctx, {
type: finalChartType,
data: {
labels: chartData.labels,
datasets: chartData.datasets
},
options: options
});
}
function fetchData(newType, startDate, endDate) {
const requestType = newType || type;
let url = `ajax.data.php?type=${requestType}`;
if (startDate) url += `&start_day=${startDate}`;
if (endDate) url += `&end_day=${endDate}`;
fetch(url)
.then(response => response.json())
.then(data => {
const chartContainer = document.querySelector('.chart-container');
const dataTableBody = document.getElementById('data-table-body');
if (data.labels && data.labels.length > 0) {
chartContainer.style.display = 'block';
currentChartData = data;
const initialChartType = data.type || 'bar';
createChart(initialChartType, currentChartData);
// 테이블 데이터 생성
if (dataTableBody) {
let tableHtml = '';
data.list.forEach(item => {
tableHtml += `<tr>
<td class="ct">${item.key}</td>
<td><div class="graph"><span class="bar" style="width:${item.bar_width}%"></span></div></td>
<td class="rt">${item.count}</td>
<td class="rt">${item.rate}</td>
</tr>`;
});
dataTableBody.innerHTML = tableHtml;
}
} else {
if(myChart) myChart.destroy();
chartContainer.innerHTML = '<div class="empty-chart" style="text-align:center; padding: 50px;">표시할 데이터가 없습니다.</div>';
if(dataTableBody) dataTableBody.innerHTML = '<tr><td colspan="4" class="empty_table">데이터가 없습니다.</td></tr>';
}
})
.catch(error => console.error('Error fetching chart data:', error));
}
$('#chart-type-selector').on('click', 'a.chart-btn', function(e) {
e.preventDefault();
const newChartType = $(this).data('chart-type');
if (newChartType && currentChartData) {
createChart(newChartType, currentChartData);
$('.chart-btn').removeClass('active');
$(this).addClass('active');
}
});
function updateData() {
const newType = new URLSearchParams(window.location.search).get('type') || type;
const startDate = $('#start_day').val();
const endDate = $('#end_day').val();
fetchData(newType, startDate, endDate);
}
$('.local_sch a').on('click', function(e) {
e.preventDefault();
const url = new URL(this.href);
const newType = url.searchParams.get('type');
history.pushState({type: newType}, '', this.href);
$('.local_sch a').removeClass('btn_ov01').addClass('btn_ov02');
$(this).removeClass('btn_ov02').addClass('btn_ov01');
$('input[name="type"]').val(newType);
type = newType; // 현재 type 업데이트
updateData();
});
$('#btn_search').on('click', function() {
updateData();
});
// 초기 데이터 로드
if (type !== 'summary') {
updateData();
}
});
+145
View File
@@ -0,0 +1,145 @@
<?php
$sub_menu = '720200';
include_once('./_common.php');
auth_check_menu($auth, $sub_menu, "r");
$g5['title'] = "상세 접속통계";
include_once(G5_ADMIN_PATH.'/admin.head.php');
$type = isset($_GET['type']) ? preg_replace('/[^a-z]/i', '', $_GET['type']) : 'time';
?>
<link rel="stylesheet" href="statistics.css?ver=<?php echo G5_CSS_VER; ?>">
<!--<link rel="stylesheet" href="http://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">-->
<div class="notbox">
<p>차트를 통해 기간별, 유형별 방문자 현황을 시각적으로 분석할 수 있습니다.</p>
</div>
<dl class="srchb lnb4_col bg2_col">
<table class="bg_col">
<tbody><tr>
<td class="ctlt bno">통계분류</td>
<td class="wbg pl7">
<ul class="List">
<li><a href="./" class="btn_ov02">요약</a></li>
<li><a href="./visit_list.php?type=time" class="<?php echo ($type == 'time') ? 'btn_ov01' : 'btn_ov02'; ?>">시간별</a></li>
<li><a href="./visit_list.php?type=week" class="<?php echo ($type == 'week') ? 'btn_ov01' : 'btn_ov02'; ?>">요일별</a></li>
<li><a href="./visit_list.php?type=date" class="<?php echo ($type == 'date') ? 'btn_ov01' : 'btn_ov02'; ?>">일별</a></li>
<li><a href="./visit_list.php?type=month" class="<?php echo ($type == 'month') ? 'btn_ov01' : 'btn_ov02'; ?>">월별</a></li>
<li><a href="./visit_list.php?type=domain" class="<?php echo ($type == 'domain') ? 'btn_ov01' : 'btn_ov02'; ?>">도메인</a></li>
<li><a href="./visit_list.php?type=ip" class="<?php echo ($type == 'ip') ? 'btn_ov01' : 'btn_ov02'; ?>">접속IP</a></li>
<li><a href="./visit_list.php?type=browser" class="<?php echo ($type == 'browser') ? 'btn_ov01' : 'btn_ov02'; ?>">브라우저</a></li>
<li><a href="./visit_list.php?type=os" class="<?php echo ($type == 'os') ? 'btn_ov01' : 'btn_ov02'; ?>">운영체제</a></li>
</ul>
</td>
</tr>
</tbody></table>
</dl>
<div class="pt5">
<dl class="srchb lnb4_col bg2_col">
<form name="statisticsSearchFrm" method="GET" id="statisticsSearchFrm">
<input type="hidden" name="type" value="<?php echo $type; ?>">
<dl class="tc pd7 wbg">
<input name="start_day" type="date" class="frm_input" id="start_day" value="<?php echo date('Y-m-d'); ?>"> ~
<input name="end_day" type="date" class="frm_input" id="end_day" value="<?php echo date('Y-m-d'); ?>">
<a class="btn btn_03 set_day" data-date="today">오늘</a>
<a class="btn btn_03 set_day" data-date="week">이번주</a>
<a class="btn btn_03 set_day" data-date="month">이번달</a>
<a class="btn btn_03 set_day" data-date="7day">1주일</a>
<a class="btn btn_03 set_day" data-date="15day">15일</a>
<a class="btn btn_03 set_day" data-date="30day">1개월</a>
<a class="btn btn_03 set_day" data-date="60day">3개월</a>
<a class="btn btn_03 set_day" data-date="120day">6개월</a>
&nbsp;
<button type="button" id="btn_search" class="btn_submit btn">검색</button>
</dl>
</form>
</dl>
</div>
<div id="chart-type-selector" class="local_sch01 local_sch">
<strong>차트 모양</strong>
<a class="btn btn_03 chart-btn active" data-chart-type="bar">세로막대</a>
<a class="btn btn_03 chart-btn" data-chart-type="line">선그래프</a>
<a class="btn btn_03 chart-btn" data-chart-type="pie">원형</a>
<a class="btn btn_03 chart-btn" data-chart-type="doughnut">도넛</a>
<a class="btn btn_03 chart-btn" data-chart-type="radar">레이더</a>
</div>
<div class="chart-container">
<canvas id="myChart"></canvas>
</div>
<dl class="ntlt lnb_col"><img src="img/bul_10.png" class="t"> 상세 데이터</dl>
<table width="100%" class="access ttlt tf">
<thead>
<tr class="bg">
<th>항목</th>
<th>그래프</th>
<th>방문자수</th>
<th>비율(%)</th>
</tr>
</thead>
<tbody id="data-table-body">
<!-- 데이터가 여기에 동적으로 추가됩니다. -->
</tbody>
</table>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="statistics.js?ver=<?php echo G5_JS_VER; ?>"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
<script>
$(function(){
$(".hasDatepicker").datepicker({
dateFormat: "yy-mm-dd"
});
$('.set_day').click(function(){
var term = $(this).data('date');
var today = new Date();
var start_day, end_day;
end_day = $.datepicker.formatDate('yy-mm-dd', today);
switch(term) {
case 'today':
start_day = end_day;
break;
case 'week':
today.setDate(today.getDate() - today.getDay() + (today.getDay() === 0 ? -6 : 1));
start_day = $.datepicker.formatDate('yy-mm-dd', today);
break;
case 'month':
start_day = $.datepicker.formatDate('yy-mm-01', today);
break;
default:
var days = parseInt(term.replace('day', ''));
today.setDate(today.getDate() - (days - 1));
start_day = $.datepicker.formatDate('yy-mm-dd', today);
break;
}
$('#start_day').val(start_day);
$('#end_day').val(end_day);
// 💡 [핵심 수정] 선택된 버튼 스타일 적용
$('.set_day').removeClass('active');
$(this).addClass('active');
});
// 차트 종류 변경 버튼 이벤트
$('.chart-btn').click(function(){
var chartType = $(this).data('chart-type');
// createChart(chartType);
$('.chart-btn').removeClass('active');
$(this).addClass('active');
});
});
</script>
<?php
include_once(G5_ADMIN_PATH.'/admin.tail.php');
?>