<?php
// 功能：流量统计文件
// 作者：启肯科技
// Q Q：328493711
// 微信：13738373177（同手机）
// 官网：http://www.qiken.com
// 说明：QKCMS-轻量级AI智能内容管理建站系统
// 版权：© 2025 温州启肯网络有限公司 保留所有权利，盗版必究。

function counter_token($value)
{
    $value = trim((string)$value);
    if ($value === '') return '';
    return substr(md5($value), 0, 16);
}

function counter_list_items($list)
{
    $items = array_filter(explode(',', (string)$list));
    return array_values(array_unique($items));
}

function counter_list_has($list, $token)
{
    if ($token === '') return false;
    return in_array($token, counter_list_items($list), true);
}

function counter_list_add($list, $token, $max = 1000)
{
    if ($token === '') return (string)$list;
    $items = counter_list_items($list);
    if (!in_array($token, $items, true)) $items[] = $token;
    if (count($items) > $max) {
        $items = array_slice($items, count($items) - $max);
    }
    return implode(',', $items);
}

function counter_list_remove($list, $token)
{
    if ($token === '') return (string)$list;
    $items = counter_list_items($list);
    $items = array_values(array_filter($items, function ($item) use ($token) {
        return $item !== $token;
    }));
    return implode(',', $items);
}

function counter_is_spider($ua)
{
    $ua = strtolower((string)$ua);
    if ($ua === '') return false;
    return preg_match('/bot|spider|crawl|slurp|bingpreview|mediapartners-google|facebookexternalhit|python-requests|curl|wget/', $ua) === 1;
}

function counter_should_skip_tracking()
{
    if (session_status() === PHP_SESSION_NONE) {
        @session_start();
    }
    return isset($_SESSION['user_id']) && intval($_SESSION['user_id']) === 1;
}

function ensure_counter_table($conn)
{
    if (!$conn || !is_object($conn)) return false;
    $exists = $conn->query("SHOW TABLES LIKE 'counter'");
    if (!$exists) return false;
    $table_exists = $exists->num_rows > 0;
    $exists->close();
    return $table_exists;
}

function cleanup_counter_history($conn, $days = 7)
{
    if (!$conn || !is_object($conn)) return false;
    $days = (int)$days;
    if ($days < 1) $days = 7;
    $cache_file = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'qkcms_counter_clean_' . date('Ymd');
    if (is_file($cache_file)) return true;
    if (!ensure_counter_table($conn)) return false;
    $expire_date = date('Y-m-d', strtotime('-' . $days . ' days'));
    $result = execute_non_query($conn, "DELETE FROM `counter` WHERE `stat_date` < ?", array($expire_date));
    if ($result !== false) {
        @file_put_contents($cache_file, '1');
        return true;
    }
    return false;
}

function counter_parse_selected_ids($value)
{
    $ids = array();
    foreach (explode(',', (string)$value) as $item) {
        $id = intval(trim($item));
        if ($id > 0) $ids[] = $id;
    }
    return array_values(array_unique($ids));
}

function update_counter_stats($conn, $payload)
{
    if (!$conn || !is_object($conn) || !is_array($payload)) return false;
    if (!ensure_counter_table($conn)) return false;

    $action = isset($payload['action']) ? trim((string)$payload['action']) : '';
    if ($action !== 'view' && $action !== 'leave') return false;

    $title = isset($payload['title']) ? mb_substr(trim((string)$payload['title']), 0, 255) : '';
    $url = isset($payload['url']) ? mb_substr(trim((string)$payload['url']), 0, 255) : '/';
    $entry_url = isset($payload['entry_url']) ? mb_substr(trim((string)$payload['entry_url']), 0, 255) : '';
    $os_name = isset($payload['os_name']) ? mb_substr(trim((string)$payload['os_name']), 0, 60) : '';
    $browser = isset($payload['browser']) ? mb_substr(trim((string)$payload['browser']), 0, 80) : '';
    if ($browser === '' && isset($payload['browser_name'])) $browser = mb_substr(trim((string)$payload['browser_name']), 0, 80);
    $language = isset($payload['language']) ? mb_substr(trim((string)$payload['language']), 0, 20) : '';
    $timezone = isset($payload['timezone']) ? mb_substr(trim((string)$payload['timezone']), 0, 80) : '';
    $resolution = isset($payload['resolution']) ? mb_substr(trim((string)$payload['resolution']), 0, 40) : '';
    if ($resolution === '' && isset($payload['screen_resolution'])) $resolution = mb_substr(trim((string)$payload['screen_resolution']), 0, 40);
    if ($url === '') $url = '/';
    $stat_date = date('Y-m-d');
    $ua = isset($_SERVER['HTTP_USER_AGENT']) ? (string)$_SERVER['HTTP_USER_AGENT'] : '';
    $ip = isset($_SERVER['REMOTE_ADDR']) ? (string)$_SERVER['REMOTE_ADDR'] : '';
    $visitor_token = counter_token(isset($payload['visitor_id']) ? $payload['visitor_id'] : '');
    $session_token = counter_token(isset($payload['session_id']) ? $payload['session_id'] : '');
    $ip_token = counter_token($ip);
    $is_spider = counter_is_spider($ua) ? 1 : 0;

    $row = get_single_row($conn, "SELECT * FROM `counter` WHERE `stat_date`=? AND `page_url`=? LIMIT 1", array($stat_date, $url));
    if (!$row) {
        $row = array(
            'pv' => 0,
            'uv' => 0,
            'ip_count' => 0,
            'spider_count' => 0,
            'entry_url' => '',
            'os_name' => '',
            'browser' => '',
            'language' => '',
            'timezone' => '',
            'resolution' => '',
            'sum_speed_ms' => 0,
            'sum_time_ms' => 0,
            'speed_ms' => 0,
            'avg_time_ms' => 0,
            'bounce_rate' => 0,
            'bounce_count' => 0,
            'session_count' => 0,
            'uv_keys' => '',
            'ip_keys' => '',
            'session_keys' => '',
            'bounce_keys' => ''
        );
    }

    $pv = (int)$row['pv'];
    $uv = (int)$row['uv'];
    $ip_count = (int)$row['ip_count'];
    $spider_count = (int)$row['spider_count'];
    $sum_speed_ms = (float)$row['sum_speed_ms'];
    $sum_time_ms = (float)$row['sum_time_ms'];
    $bounce_count = (int)$row['bounce_count'];
    $session_count = (int)$row['session_count'];
    $uv_keys = (string)$row['uv_keys'];
    $ip_keys = (string)$row['ip_keys'];
    $session_keys = (string)$row['session_keys'];
    $bounce_keys = (string)$row['bounce_keys'];
    if ($entry_url === '') $entry_url = (string)$row['entry_url'];
    if ($os_name === '') $os_name = (string)$row['os_name'];
    if ($browser === '') $browser = isset($row['browser']) ? (string)$row['browser'] : (isset($row['browser_name']) ? (string)$row['browser_name'] : '');
    if ($language === '') $language = (string)$row['language'];
    if ($timezone === '') $timezone = (string)$row['timezone'];
    if ($resolution === '') $resolution = isset($row['resolution']) ? (string)$row['resolution'] : (isset($row['screen_resolution']) ? (string)$row['screen_resolution'] : '');

    if ($action === 'view') {
        $pv += 1;
        $speed_ms = isset($payload['speed_ms']) ? max(0, (float)$payload['speed_ms']) : 0;
        $sum_speed_ms += $speed_ms;
        if ($is_spider === 1) $spider_count += 1;

        if ($visitor_token !== '' && !counter_list_has($uv_keys, $visitor_token)) {
            $uv += 1;
            $uv_keys = counter_list_add($uv_keys, $visitor_token);
        }
        if ($ip_token !== '' && !counter_list_has($ip_keys, $ip_token)) {
            $ip_count += 1;
            $ip_keys = counter_list_add($ip_keys, $ip_token);
        }
        if ($session_token !== '' && !counter_list_has($session_keys, $session_token)) {
            $session_count += 1;
            $session_keys = counter_list_add($session_keys, $session_token);
            $is_entry = isset($payload['is_entry']) ? (int)$payload['is_entry'] : 0;
            if ($is_entry === 1 && !counter_list_has($bounce_keys, $session_token)) {
                $bounce_count += 1;
                $bounce_keys = counter_list_add($bounce_keys, $session_token);
            }
        }
    } else {
        $stay_ms = isset($payload['stay_ms']) ? max(0, (float)$payload['stay_ms']) : 0;
        $sum_time_ms += $stay_ms;
        $is_bounce = isset($payload['is_bounce']) ? (int)$payload['is_bounce'] : 0;

        if ($session_token !== '') {
            if (!counter_list_has($session_keys, $session_token)) {
                $session_count += 1;
                $session_keys = counter_list_add($session_keys, $session_token);
                if ($is_bounce === 1 && !counter_list_has($bounce_keys, $session_token)) {
                    $bounce_count += 1;
                    $bounce_keys = counter_list_add($bounce_keys, $session_token);
                }
            } elseif ($is_bounce === 0 && counter_list_has($bounce_keys, $session_token)) {
                $bounce_keys = counter_list_remove($bounce_keys, $session_token);
                if ($bounce_count > 0) $bounce_count -= 1;
            }
        }
    }

    $speed_ms = $pv > 0 ? round($sum_speed_ms / $pv, 2) : 0;
    $avg_time_ms = $pv > 0 ? round($sum_time_ms / $pv, 2) : 0;
    $bounce_rate = $session_count > 0 ? round(($bounce_count / $session_count) * 100, 2) : 0;

    $upsert_sql = "INSERT INTO `counter`
        (`stat_date`,`page_title`,`page_url`,`entry_url`,`os_name`,`browser`,`language`,`timezone`,`resolution`,`pv`,`uv`,`ip_count`,`spider_count`,`sum_speed_ms`,`sum_time_ms`,`speed_ms`,`avg_time_ms`,`bounce_rate`,`bounce_count`,`session_count`,`uv_keys`,`ip_keys`,`session_keys`,`bounce_keys`)
        VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
        ON DUPLICATE KEY UPDATE
        `page_title`=VALUES(`page_title`),
        `entry_url`=VALUES(`entry_url`),
        `os_name`=VALUES(`os_name`),
        `browser`=VALUES(`browser`),
        `language`=VALUES(`language`),
        `timezone`=VALUES(`timezone`),
        `resolution`=VALUES(`resolution`),
        `pv`=VALUES(`pv`),
        `uv`=VALUES(`uv`),
        `ip_count`=VALUES(`ip_count`),
        `spider_count`=VALUES(`spider_count`),
        `sum_speed_ms`=VALUES(`sum_speed_ms`),
        `sum_time_ms`=VALUES(`sum_time_ms`),
        `speed_ms`=VALUES(`speed_ms`),
        `avg_time_ms`=VALUES(`avg_time_ms`),
        `bounce_rate`=VALUES(`bounce_rate`),
        `bounce_count`=VALUES(`bounce_count`),
        `session_count`=VALUES(`session_count`),
        `uv_keys`=VALUES(`uv_keys`),
        `ip_keys`=VALUES(`ip_keys`),
        `session_keys`=VALUES(`session_keys`),
        `bounce_keys`=VALUES(`bounce_keys`)";

    $params = array(
        $stat_date,
        $title,
        $url,
        $entry_url,
        $os_name,
        $browser,
        $language,
        $timezone,
        $resolution,
        $pv,
        $uv,
        $ip_count,
        $spider_count,
        $sum_speed_ms,
        $sum_time_ms,
        $speed_ms,
        $avg_time_ms,
        $bounce_rate,
        $bounce_count,
        $session_count,
        $uv_keys,
        $ip_keys,
        $session_keys,
        $bounce_keys
    );
    $result = execute_non_query($conn, $upsert_sql, $params);
    return $result !== false;
}

if (!defined('ADMIN_LOADED')) {
    require_once dirname(__DIR__) . '/common.php';
    start_admin_session();
    global $conn;
    $action = isset($_GET['action']) ? trim((string)$_GET['action']) : '';
    if ($action === 'script') {
        header('Content-Type: application/javascript; charset=utf-8');
        if (counter_should_skip_tracking()) {
            echo '(function(){window.__qkCounterLoaded=true;})();';
            exit;
        }
        $js = <<<'JS'
(function () {
  if (window.__qkCounterLoaded) return;
  window.__qkCounterLoaded = true;
  function r(p) { return p + "_" + Math.random().toString(36).slice(2) + Date.now().toString(36); }
  function cget(k) {
    var m = document.cookie.match(new RegExp("(?:^|; )" + k.replace(/([.$?*|{}()\[\]\\\/\+^])/g, "\\$1") + "=([^;]*)"));
    return m ? decodeURIComponent(m[1]) : "";
  }
  function cset(k, v, d) {
    var e = "";
    if (d > 0) {
      var t = new Date();
      t.setTime(t.getTime() + d * 24 * 60 * 60 * 1000);
      e = "; expires=" + t.toUTCString();
    }
    document.cookie = k + "=" + encodeURIComponent(v) + e + "; path=/; SameSite=Lax";
  }
  function vid() {
    var k = "qk_counter_vid";
    var v = cget(k);
    if (!v) {
      v = r("vid");
      cset(k, v, 365);
    }
    return v;
  }
  function sid() {
    var k = "qk_counter_sid";
    var s = "";
    try {
      s = sessionStorage.getItem(k) || "";
      if (!s) {
        s = r("sid");
        sessionStorage.setItem(k, s);
      }
    } catch (e) {
      s = r("sid");
    }
    return s;
  }
  function scount() {
    var n = 1;
    try {
      var k = "qk_counter_page_count";
      var c = parseInt(sessionStorage.getItem(k) || "0", 10);
      if (isNaN(c)) c = 0;
      n = c + 1;
      sessionStorage.setItem(k, String(n));
    } catch (e) {
      n = 1;
    }
    return n;
  }
  function perf() {
    var speed = 0;
    var list = performance.getEntriesByType ? performance.getEntriesByType("navigation") : [];
    if (list && list.length > 0) {
      var nav = list[0];
      speed = Math.max(0, Math.round(nav.loadEventEnd > 0 ? nav.loadEventEnd : nav.duration));
      return speed;
    }
    if (performance.timing) {
      var t = performance.timing;
      speed = Math.max(0, (t.loadEventEnd || Date.now()) - t.navigationStart);
    }
    return speed;
  }
  function meta() {
    var ua = navigator.userAgent || "";
    var os = "Unknown";
    if (/Windows NT/i.test(ua)) os = "Windows";
    else if (/Mac OS X/i.test(ua)) os = "macOS";
    else if (/Android/i.test(ua)) os = "Android";
    else if (/iPhone|iPad|iPod/i.test(ua)) os = "iOS";
    else if (/Linux/i.test(ua)) os = "Linux";
    var browser = "Unknown";
    if (/Edg\//i.test(ua)) browser = "Edge";
    else if (/Chrome\//i.test(ua) && !/Edg\//i.test(ua)) browser = "Chrome";
    else if (/Firefox\//i.test(ua)) browser = "Firefox";
    else if (/Safari\//i.test(ua) && !/Chrome\//i.test(ua) && !/Edg\//i.test(ua)) browser = "Safari";
    else if (/MSIE|Trident/i.test(ua)) browser = "IE";
    var language = (navigator.language || navigator.userLanguage || "").slice(0, 20);
    var timezone = "";
    try { timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || ""; } catch (e) {}
    timezone = String(timezone || "").slice(0, 80);
    var sw = window.screen && window.screen.width ? window.screen.width : 0;
    var sh = window.screen && window.screen.height ? window.screen.height : 0;
    var resolution = sw > 0 && sh > 0 ? (sw + "x" + sh) : "";
    var entryUrl = "";
    try {
      var ek = "qk_counter_entry_url";
      entryUrl = sessionStorage.getItem(ek) || "";
      if (!entryUrl) {
        entryUrl = (window.location.pathname || "/") + (window.location.search || "");
        sessionStorage.setItem(ek, entryUrl);
      }
    } catch (e) {
      entryUrl = (window.location.pathname || "/") + (window.location.search || "");
    }
    return {
      os_name: String(os).slice(0, 60),
      browser: String(browser).slice(0, 80),
      language: String(language).slice(0, 20),
      timezone: String(timezone).slice(0, 80),
      resolution: String(resolution).slice(0, 40),
      entry_url: String(entryUrl).slice(0, 255)
    };
  }
  function post(body) {
    var url = "/admin/counter.php?action=track";
    var m = meta();
    body.os_name = m.os_name;
    body.browser = m.browser;
    body.language = m.language;
    body.timezone = m.timezone;
    body.resolution = m.resolution;
    body.entry_url = m.entry_url;
    var text = JSON.stringify(body);
    try {
      if (navigator.sendBeacon) {
        navigator.sendBeacon(url, new Blob([text], { type: "application/json" }));
        return;
      }
    } catch (e) {}
    try {
      fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: text, keepalive: true });
    } catch (e) {}
  }
  var visitorId = vid();
  var sessionId = sid();
  var pageCount = scount();
  var startAt = Date.now();
  var sent = false;
  function view() {
    post({
      action: "view",
      title: document.title || "",
      url: window.location.pathname || "/",
      speed_ms: perf(),
      is_entry: pageCount === 1 ? 1 : 0,
      visitor_id: visitorId,
      session_id: sessionId
    });
  }
  function leave() {
    if (sent) return;
    sent = true;
    var stay = Date.now() - startAt;
    if (stay < 0) stay = 0;
    post({
      action: "leave",
      title: document.title || "",
      url: window.location.pathname || "/",
      stay_ms: stay,
      is_bounce: pageCount === 1 ? 1 : 0,
      visitor_id: visitorId,
      session_id: sessionId
    });
  }
  window.addEventListener("load", function () { setTimeout(view, 0); });
  window.addEventListener("pagehide", leave);
})();
JS;
        echo $js;
        exit;
    }
    if ($action === 'track') {
        header('Content-Type: application/json; charset=utf-8');
        if (counter_should_skip_tracking()) {
            echo json_encode(array('success' => 1, 'skip' => 1), JSON_UNESCAPED_UNICODE);
            exit;
        }
        if (!ensure_counter_table($conn)) {
            echo json_encode(array('success' => 0, 'message' => 'counter表不存在'), JSON_UNESCAPED_UNICODE);
            exit;
        }
        @cleanup_counter_history($conn, 7);
        $raw = file_get_contents('php://input');
        $payload = json_decode($raw, true);
        if (!is_array($payload)) {
            $payload = $_POST;
        }
        $ok = update_counter_stats($conn, $payload);
        echo json_encode(array('success' => $ok ? 1 : 0), JSON_UNESCAPED_UNICODE);
        exit;
    }
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'delete_selected_counter') {
        define('ADMIN_LOADED', true);
    } else {
        header('HTTP/1.1 403 Forbidden');
        exit('Access Denied');
    }
}

global $conn;
$table_ready = ensure_counter_table($conn);
if ($table_ready) {
    @cleanup_counter_history($conn, 7);
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'delete_selected_counter') {
    header('Content-Type: application/json; charset=utf-8');
    if (!$table_ready) {
        echo json_encode(array('success' => 0, 'message' => 'counter表不存在'), JSON_UNESCAPED_UNICODE);
        exit;
    }
    $ids = counter_parse_selected_ids($_POST['counter_ids'] ?? '');
    if (empty($ids)) {
        echo json_encode(array('success' => 0, 'message' => '请先选择要删除的统计记录'), JSON_UNESCAPED_UNICODE);
        exit;
    }
    $placeholders = implode(',', array_fill(0, count($ids), '?'));
    $result = execute_non_query($conn, "DELETE FROM `counter` WHERE `id` IN ($placeholders)", $ids);
    $affected_rows = isset($result['affected_rows']) ? intval($result['affected_rows']) : 0;
    if ($result !== false && $affected_rows > 0) {
        echo json_encode(array('success' => 1, 'message' => '成功删除 ' . $affected_rows . ' 条统计记录', 'deleted_ids' => $ids), JSON_UNESCAPED_UNICODE);
        exit;
    }
    echo json_encode(array('success' => 0, 'message' => '删除失败或所选记录不存在'), JSON_UNESCAPED_UNICODE);
    exit;
}
$search = isset($_GET['search']) ? trim((string)$_GET['search']) : '';
$current_page = isset($current_page) ? max(1, (int)$current_page) : 1;
$posts_per_page = isset($posts_per_page) ? max(1, min(1000, (int)$posts_per_page)) : 30;
$date_range = isset($_GET['date_range']) ? trim((string)$_GET['date_range']) : '7days';
if (!in_array($date_range, array('today', 'yesterday', '7days'), true)) {
    $date_range = '7days';
}
$sort = isset($_GET['sort']) ? trim((string)$_GET['sort']) : 'date';
$order = isset($_GET['order']) ? strtolower(trim((string)$_GET['order'])) : 'desc';
$sort_map = array(
    'date' => 'stat_date',
    'pv' => 'pv',
    'uv' => 'uv',
    'ip' => 'ip_count'
);
if (!isset($sort_map[$sort])) $sort = 'date';
if ($order !== 'asc' && $order !== 'desc') $order = 'desc';
$sort_field_sql = $sort_map[$sort];
$sort_order_sql = $order === 'asc' ? 'ASC' : 'DESC';
$build_sort_link = function ($field) use ($search, $date_range, $sort, $order) {
    $next_order = ($sort === $field && $order === 'desc') ? 'asc' : 'desc';
    $query = array(
        'tab' => 'counter',
        'date_range' => $date_range,
        'sort' => $field,
        'order' => $next_order
    );
    if ($search !== '') $query['search'] = $search;
    return '/admin?' . http_build_query($query);
};
$sort_indicator = function ($field) use ($sort, $order) {
    $arrow = '';
    if ($sort === $field) {
        $arrow = $order === 'asc' ? '▲' : '▼';
    }
    return '<span class="counter-sort-indicator">' . $arrow . '</span>';
};
$build_date_link = function ($range) use ($search, $sort, $order) {
    $query = array(
        'tab' => 'counter',
        'date_range' => $range,
        'sort' => $sort,
        'order' => $order
    );
    if ($search !== '') $query['search'] = $search;
    return '/admin?' . http_build_query($query);
};
$date_range_labels = array(
    'today' => '今天',
    'yesterday' => '昨天',
    '7days' => '7天内'
);
$date_range_text = isset($date_range_labels[$date_range]) ? $date_range_labels[$date_range] : '7天内';
$today = date('Y-m-d');
if ($date_range === 'today') {
    $date_start = $today;
    $date_end = $today;
} elseif ($date_range === 'yesterday') {
    $date_start = date('Y-m-d', strtotime('-1 day'));
    $date_end = $date_start;
} else {
    $date_start = date('Y-m-d', strtotime('-6 days'));
    $date_end = $today;
}
$rows = array();
$total_count = 0;
$total_pages = 1;
if ($table_ready) {
    $where = " WHERE stat_date BETWEEN ? AND ? ";
    $params = array($date_start, $date_end);
    if ($search !== '') {
        $where .= " AND (page_title LIKE ? OR page_url LIKE ?) ";
        $like = '%' . $search . '%';
        $params[] = $like;
        $params[] = $like;
    }
    $count_row = get_single_row($conn, "SELECT COUNT(*) AS c FROM counter {$where}", $params);
    $total_count = isset($count_row['c']) ? (int)$count_row['c'] : 0;
    $total_pages = max(1, (int)ceil($total_count / $posts_per_page));
    if ($current_page > $total_pages) $current_page = $total_pages;
    $offset = ($current_page - 1) * $posts_per_page;
    $order_by_sql = "{$sort_field_sql} {$sort_order_sql}, stat_date DESC, pv DESC";
    $list_sql = "SELECT `id`,`stat_date`,`page_title`,`page_url`,`entry_url`,`os_name`,`browser`,`language`,`timezone`,`resolution`,`pv`,`uv`,`ip_count`,`spider_count`,`speed_ms`,`avg_time_ms`,`bounce_rate`,`session_count` FROM counter {$where} ORDER BY {$order_by_sql} LIMIT ?, ?";
    $list_params = $params;
    $list_params[] = $offset;
    $list_params[] = $posts_per_page;
    $list_result = execute_query($conn, $list_sql, $list_params);
    if ($list_result) {
        while ($row = $list_result->fetch_assoc()) {
            $rows[] = $row;
        }
        $list_result->close();
    }
}
?>
<style>
    .admin-table.counter-manage {
        width: 100%;
        min-width: 1120px;
        table-layout: auto
    }

    .counter-default-hidden {
        display: none
    }

    .admin-table.counter-manage th,
    .admin-table.counter-manage td {
        vertical-align: middle !important;
        padding: 10px 14px !important;
        line-height: 1.45 !important;
        overflow: visible !important;
        text-overflow: clip !important
    }

    .admin-table.counter-manage th {
        white-space: nowrap !important;
        word-break: normal;
        overflow: visible !important
    }

    .admin-table.counter-manage .counter-date {
        width: 140px !important;
        min-width: 140px !important;
        max-width: 140px !important
    }

    .admin-table.counter-manage .counter-title {
        width: 260px !important;
        min-width: 260px !important;
        max-width: 260px !important;
        white-space: nowrap !important;
        overflow: hidden;
        text-overflow: ellipsis
    }

    .admin-table.counter-manage .counter-title .counter-link {
        white-space: nowrap !important;
        overflow: hidden;
        text-overflow: ellipsis;
        word-break: normal !important;
        display: block
    }

    .admin-table.counter-manage .counter-url {
        width: 170px !important;
        min-width: 170px !important;
        max-width: 170px !important
    }

    .admin-table.counter-manage .counter-num {
        width: 72px !important;
        min-width: 72px;
        max-width: 72px;
        white-space: nowrap !important;
        word-break: normal
    }

    .admin-table.counter-manage th.counter-date {
        overflow: visible !important;
        position: relative;
        z-index: 2
    }

    .admin-table.counter-manage .counter-date-head-wrap {
        position: relative;
        width: auto;
        height: auto;
        display: inline-flex;
        align-items: center;
        overflow: visible;
        z-index: 2
    }

    .admin-table.counter-manage th.counter-num {
        position: relative;
        z-index: 6
    }

    #counter-date-header.counter-date-header-trigger,
    #counter-date-dropdown-menu {
        pointer-events: auto
    }

    #counter-date-header.counter-date-header-trigger {
        display: inline-flex;
        align-items: center;
        position: relative;
        padding-right: 30px;
        gap: 0;
        font-weight: 600;
        cursor: pointer
    }

    #counter-date-header.counter-date-header-trigger::after {
        content: '';
        position: absolute;
        right: 6px;
        top: 50%;
        transform: translateY(-50%);
        width: 16px;
        height: 16px;
        background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23666' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M3 6l5 5 5-5'/%3E%3C/svg%3E");
        background-repeat: no-repeat;
        background-position: center;
        background-size: 16px;
        pointer-events: none;
    }

    #counter-date-dropdown-menu {
        border: 1px solid #ddd;
        border-radius: 0px;
        background-color: #fff;
        box-shadow: none;
        max-height: 360px;
        overflow-y: auto;
        padding: 0;
        width: 125px;
    }

    #counter-date-dropdown-menu .counter-date-dropdown-item {
        height: 30px;
        line-height: 30px;
        padding: 0 10px;
        font-size: 14px;
        cursor: pointer;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        color: #333
    }

    #counter-date-dropdown-menu .counter-date-dropdown-item:hover {
        background-color: var(--primary-color);
        color: #fff
    }

    .admin-table.counter-manage .counter-sort-link {
        text-decoration: none;
        color: inherit;
        display: inline-flex;
        align-items: center;
        position: relative;
        z-index: 20;
        pointer-events: auto;
        white-space: nowrap;
        width: 100%
    }

    .admin-table.counter-manage .counter-sort-link:hover {
        color: var(--primary-color)
    }

    .admin-table.counter-manage .counter-sort-indicator {
        display: inline-block;
        width: 14px;
        text-align: left
    }

    .admin-table.counter-manage .counter-link {
        display: block;
        width: 100%;
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
        word-break: break-all;
        color: inherit;
        text-decoration: none
    }

    .admin-table.counter-manage .counter-link:hover {
        color: var(--primary-color);
        text-decoration: underline
    }

    .counter-empty {
        text-align: center !important;
        height: 75px;
        line-height: 75px;
        font-size: 16px;
        color: #64748b
    }

    .counter-alert {
        background: #fff7ed;
        border: 1px solid #fdba74;
        color: #9a3412;
        border-radius: 10px;
        padding: 12px
    }

    .counter-table-wrapper {
        position: relative
    }

    .counter-custom-scrollbar-container {
        position: relative;
        width: 100%;
        display: flex;
        justify-content: center
    }

 

    .admin-table.counter-manage tr:hover th.counter-last-col,
    .admin-table.counter-manage tr:hover td.counter-last-col {
        background-color: #f9fafb !important;
        box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08), -2px 0 4px rgba(0, 0, 0, 0.1);
        z-index: 100;
    }

    .counter-header-actions {
        margin-left: auto;
        position: relative;
        display: flex;
        align-items: center;
        gap: 10px
    }

    #counter-batch-delete-btn {
        display: none !important;
        margin-right: 0
    }

    #counter-column-setting-btn {
        margin-left: 0 !important;
        margin-right: 0 !important;
    }

    #counter-batch-delete-btn.is-active {
        display: inline-flex !important
    }

    .counter-select-col {
        width: 52px !important;
        min-width: 52px !important;
        max-width: 52px !important;
        text-align: center
    }

    @media (max-width: 768px) {
        #counter-batch-delete-btn,
        #counter-column-setting-btn {
            width: 38px !important;
            height: 38px !important;
            min-width: 38px !important;
            padding: 0 !important;
            margin-left: 6px !important;
            line-height: 38px !important;
        }
        #counter-batch-delete-btn .add-category-btn-text,
        #counter-column-setting-text {
            display: none !important;
        }
        #counter-batch-delete-btn .add-category-btn-icon,
        #counter-column-setting-btn svg {
            margin-right: 0 !important;
        }
    }

    #counter-column-setting-menu.counter-column-menu {
        position: absolute;
        right: 0;
        top: calc(100% + 8px);
        width: 270px;
        max-height: 360px;
        overflow: hidden;
        scrollbar-gutter: stable;
        background: #fff;
        border: 1px solid #e5e7eb;
        border-radius: 0;
        box-shadow: 0 10px 22px rgba(15, 23, 42, .16);
        z-index: 1001;
        display: none;
        padding: 0
    }

    #counter-column-setting-menu.counter-column-menu.show {
        display: block
    }

    .counter-column-item {
        display: flex;
        align-items: center;
        gap: 10px;
        height: 42px;
        padding: 0 10px;
        border-radius: 0;
        border-left: 2px solid transparent;
        cursor: pointer;
        user-select: none;
        font-size: 13px;
        color: #1e293b;
        transition: background-color .18s ease, border-color .18s ease, color .18s ease
    }

    .counter-column-item:not(:last-child) {
        border-bottom: 1px solid #e5e7eb
    }

    .counter-column-item:hover {
        background: #f3f7ff;
        border-left-color: var(--primary-color);
        color: var(--primary-color)
    }

    .counter-column-item input[type="checkbox"] {
        appearance: none;
        -webkit-appearance: none;
        width: 16px;
        height: 16px;
        margin: 0;
        border: 1px solid #94a3b8;
        border-radius: 0;
        background: #fff;
        display: inline-grid;
        place-content: center;
        transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease
    }

    .counter-column-item input[type="checkbox"]::before {
        content: '';
        width: 9px;
        height: 9px;
        transform: scale(0);
        transition: transform .12s ease-out;
        background: linear-gradient(180deg, var(--primary-light, var(--primary-color)) 0%, var(--primary-color) 100%)
    }

    .counter-column-item input[type="checkbox"]:checked {
        border-color: var(--primary-color);
        box-shadow: 0 0 0 1px rgba(59, 130, 246, .15)
    }

    .counter-column-item input[type="checkbox"]:checked::before {
        transform: scale(1)
    }

    .counter-column-item input[type="checkbox"]:focus-visible {
        outline: 0;
        box-shadow: 0 0 0 2px rgba(59, 130, 246, .25)
    }

    .counter-column-field {
        font-family: Consolas, "Courier New", monospace;
        color: #64748b
    }

    .counter-column-name {
        color: #0f172a
    }
</style>

<script>
    (function() {
        var ALL_COLS = ['id', 'stat_date', 'page_title', 'page_url', 'pv', 'uv', 'ip_count', 'bounce_rate', 'session_count', 'spider_count', 'speed_ms', 'avg_time_ms', 'os_name', 'browser', 'language', 'timezone', 'resolution'];
        var DEFAULTS = ['id', 'stat_date', 'page_title', 'page_url', 'pv', 'uv', 'ip_count', 'bounce_rate', 'session_count'];
        var selected = DEFAULTS.slice();

        try {
            var raw = localStorage.getItem('qk_counter_visible_columns_v1');
            if (raw) {
                var parsed = JSON.parse(raw);
                if (Array.isArray(parsed) && parsed.length) {
                    var allowed = {};
                    ALL_COLS.forEach(function(k) {
                        allowed[k] = true;
                    });
                    var valid = parsed.filter(function(k) {
                        return !!allowed[k];
                    });
                    if (valid.length) selected = valid;
                }
            }
        } catch (e) {}

        window.__counterPreColumns = selected;

        var selectedMap = {};
        selected.forEach(function(k) {
            selectedMap[k] = true;
        });

        var css = ALL_COLS.map(function(k) {
            return '[data-col="' + k + '"]{display:' + (selectedMap[k] ? 'table-cell' : 'none') + ';}';
        }).join('');

        var style = document.createElement('style');
        style.id = 'counter-prestyle';
        style.textContent = css;
        document.head.appendChild(style);
    })();
</script>

<div class="counter-page">
    <div class="section-header">
        <h2>流量统计</h2>
        <div class="counter-header-actions">
            <button type="button" id="counter-batch-delete-btn" class="btn btn-danger action-button section-header-mobile-btn" style="flex: none; width: 120px; align-items: center; justify-content: center; white-space: nowrap;">
                <svg class="add-category-btn-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">
                    <circle cx="12" cy="12" r="10"></circle>
                    <line x1="15" y1="9" x2="9" y2="15"></line>
                    <line x1="9" y1="9" x2="15" y2="15"></line>
                </svg>
                <span class="add-category-btn-text">删除选择</span>
            </button>
            <a href="#" id="counter-column-setting-btn" class="btn btn-primary action-button section-header-mobile-btn" style="display: inline-flex; align-items: center; justify-content: center; position: relative; overflow: visible;">
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 6px;">
                    <circle cx="12" cy="12" r="3"></circle>
                    <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
                </svg>
                <span id="counter-column-setting-text">列数设置</span>
                <span id="counter-column-count-badge" class="counter-column-count-badge" style="position: absolute; top: -6px; right: -6px; min-width: 18px; height: 18px; padding: 0 5px; background: #dc3545; color: #fff; font-size: 11px; font-weight: 500; border-radius: 50%; display: flex; align-items: center; justify-content: center; line-height: 1; z-index: 20; box-shadow: 0 1px 3px rgba(0,0,0,0.1);"></span>
            </a>
            <div id="counter-column-setting-menu" class="counter-column-menu"></div>
        </div>
    </div>

    <?php if (!$table_ready): ?>
        <div class="counter-alert">未检测到 counter 数据表，请先执行安装或补表后再使用统计功能。</div>
    <?php endif; ?>

    <div class="admin-card">
        <div class="table-container">
            <div class="counter-table-wrapper">
                <div class="counter-table-scroll">
                    <table class="admin-table counter-manage">
                        <thead>
                            <tr>
                                <th class="counter-select-col"><input type="checkbox" id="select-all-counter" class="form-checkbox" style="width:18px;height:18px;"></th>
                                <th class="counter-num" data-col="id">ID</th>
                                <th class="counter-date" data-col="stat_date">
                                    <span id="counter-date-header" class="counter-date-header-trigger" onclick="toggleCounterDateMenu()">时间</span>
                                </th>
                                <th data-col="page_title">页面标题</th>
                                <th data-col="page_url">URL</th>
                                <th class="counter-num" data-col="pv"><a class="counter-sort-link" href="<?php echo htmlspecialchars($build_sort_link('pv')); ?>">PV<?php echo $sort_indicator('pv'); ?></a></th>
                                <th class="counter-num" data-col="uv"><a class="counter-sort-link" href="<?php echo htmlspecialchars($build_sort_link('uv')); ?>">UV<?php echo $sort_indicator('uv'); ?></a></th>
                                <th class="counter-num" data-col="ip_count"><a class="counter-sort-link" href="<?php echo htmlspecialchars($build_sort_link('ip')); ?>">IP<?php echo $sort_indicator('ip'); ?></a></th>
                                <th class="counter-num" data-col="bounce_rate">跳出率(%)</th>
                                <th class="counter-num" data-col="session_count">会话数</th>
                                <th class="counter-num" data-col="spider_count">蜘蛛</th>
                                <th class="counter-num" data-col="speed_ms">平均速度(ms)</th>
                                <th class="counter-num" data-col="avg_time_ms">平均停留(ms)</th>
                                <th class="counter-num" data-col="os_name">系统</th>
                                <th class="counter-num" data-col="browser">浏览器</th>
                                <th class="counter-num" data-col="language">语言</th>
                                <th class="counter-num" data-col="timezone">时区</th>
                                <th class="counter-num" data-col="resolution">分辨率</th>
                            </tr>
                        </thead>
                        <tbody id="counter-list-body">
                            <?php if (empty($rows)): ?>
                                <tr class="counter-empty-row">
                                    <td colspan="18" class="counter-empty">暂无统计数据</td>
                                </tr>
                            <?php else: ?>
                                <?php foreach ($rows as $item): ?>
                                    <tr>
                                        <td class="counter-select-col"><input type="checkbox" class="counter-row-checkbox" value="<?php echo (int)$item['id']; ?>" style="width:18px;height:18px;"></td>
                                        <td class="counter-num" data-col="id"><?php echo (int)$item['id']; ?></td>
                                        <td class="counter-date" data-col="stat_date"><?php echo htmlspecialchars($item['stat_date']); ?></td>
                                        <td class="counter-title" data-col="page_title"><a class="counter-link" data-qk-tip="<?php echo htmlspecialchars($item['page_title']); ?>" href="<?php echo htmlspecialchars($item['page_url']); ?>" target="_blank" rel="noopener noreferrer"><?php echo htmlspecialchars($item['page_title']); ?></a></td>
                                        <td class="counter-url" data-col="page_url"><a class="counter-link" href="<?php echo htmlspecialchars($item['page_url']); ?>" target="_blank" rel="noopener noreferrer"><?php echo htmlspecialchars($item['page_url']); ?></a></td>
                                        <td class="counter-num" data-col="pv"><?php echo (int)$item['pv']; ?></td>
                                        <td class="counter-num" data-col="uv"><?php echo (int)$item['uv']; ?></td>
                                        <td class="counter-num" data-col="ip_count"><?php echo (int)$item['ip_count']; ?></td>
                                        <td class="counter-num" data-col="bounce_rate"><?php echo round((float)$item['bounce_rate'], 2); ?></td>
                                        <td class="counter-num" data-col="session_count"><?php echo (int)$item['session_count']; ?></td>
                                        <td class="counter-num" data-col="spider_count"><?php echo (int)$item['spider_count']; ?></td>
                                        <td class="counter-num" data-col="speed_ms"><?php echo round((float)$item['speed_ms'], 2); ?></td>
                                        <td class="counter-num" data-col="avg_time_ms"><?php echo round((float)$item['avg_time_ms'], 2); ?></td>
                                        <td class="counter-num" data-col="os_name"><?php echo htmlspecialchars($item['os_name']); ?></td>
                                        <td class="counter-num" data-col="browser"><?php echo htmlspecialchars($item['browser']); ?></td>
                                        <td class="counter-num" data-col="language"><?php echo htmlspecialchars($item['language']); ?></td>
                                        <td class="counter-num" data-col="timezone"><?php echo htmlspecialchars($item['timezone']); ?></td>
                                        <td class="counter-num" data-col="resolution"><?php echo htmlspecialchars($item['resolution']); ?></td>
                                    </tr>
                                <?php endforeach; ?>
                            <?php endif; ?>
                        </tbody>
                    </table>
                </div>
                <div class="counter-custom-scrollbar-container">
                    <div class="counter-custom-scrollbar-track">
                        <div class="counter-custom-scrollbar-thumb"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<div id="counter-date-dropdown-menu" style="display: none;">
    <div class="counter-date-dropdown-item" onclick="filterCounterDate('<?php echo htmlspecialchars($build_date_link('today'), ENT_QUOTES); ?>')">今天</div>
    <div class="counter-date-dropdown-item" onclick="filterCounterDate('<?php echo htmlspecialchars($build_date_link('yesterday'), ENT_QUOTES); ?>')">昨天</div>
    <div class="counter-date-dropdown-item" onclick="filterCounterDate('<?php echo htmlspecialchars($build_date_link('7days'), ENT_QUOTES); ?>')">7天内</div>
</div>

<script>
    const counterDateMenu = document.getElementById('counter-date-dropdown-menu');
    if (counterDateMenu && counterDateMenu.parentElement !== document.body) {
        document.body.appendChild(counterDateMenu);
    }

    var COUNTER_COLUMN_KEY = 'qk_counter_visible_columns_v1';
    var COUNTER_COLUMNS = [{
            key: 'id',
            label: 'ID',
            defaultVisible: true
        },
        {
            key: 'stat_date',
            label: '时间',
            defaultVisible: true
        },
        {
            key: 'page_title',
            label: '标题',
            defaultVisible: true
        },
        {
            key: 'page_url',
            label: 'URL',
            defaultVisible: true
        },
        {
            key: 'pv',
            label: 'PV',
            defaultVisible: true
        },
        {
            key: 'uv',
            label: 'UV',
            defaultVisible: true
        },
        {
            key: 'ip_count',
            label: 'IP',
            defaultVisible: true
        },
        {
            key: 'bounce_rate',
            label: '跳出率',
            defaultVisible: true
        },
        {
            key: 'session_count',
            label: '会话',
            defaultVisible: true
        },
        {
            key: 'spider_count',
            label: '蜘蛛',
            defaultVisible: false
        },
        {
            key: 'speed_ms',
            label: '平均速度',
            defaultVisible: false
        },
        {
            key: 'avg_time_ms',
            label: '停留',
            defaultVisible: false
        },
        {
            key: 'os_name',
            label: '系统',
            defaultVisible: false
        },
        {
            key: 'browser',
            label: '浏览器',
            defaultVisible: false
        },
        {
            key: 'language',
            label: '语言',
            defaultVisible: false
        },
        {
            key: 'timezone',
            label: '时区',
            defaultVisible: false
        },
        {
            key: 'resolution',
            label: '分辨率',
            defaultVisible: false
        }
    ];
    var counterVisibleColumns = [];

    (function() {
        if (typeof hideLoading === 'function') hideLoading();
        var spinner = document.getElementById('loading-spinner');
        if (spinner) spinner.classList.remove('show');
    })();

    function initCounterCustomScrollbar() {
        if (!window.AdminScrollbar || typeof window.AdminScrollbar.initHorizontal !== 'function') return;
        window.AdminScrollbar.initHorizontal({
            scrollContainer: '.counter-table-scroll',
            track: '.counter-custom-scrollbar-track',
            thumb: '.counter-custom-scrollbar-thumb',
            updateHookName: '_counterUpdateScrollbarThumb'
        });
    }

    function renderCounterList(data) {
        var tbody = document.getElementById('counter-list-body');
        if (!tbody) return;
        var list = data && Array.isArray(data.rows) ? data.rows : [];
        if (!list.length) {
            tbody.innerHTML = '<tr class="counter-empty-row"><td colspan="18" class="counter-empty">暂无统计数据</td></tr>';
            applyCounterColumnVisibility();
            updateCounterBatchDeleteButton();
            return;
        }
        tbody.innerHTML = list.map(function(item) {
            var date = item.stat_date || '';
            var title = item.page_title || '';
            var url = item.page_url || '';
            var osName = item.os_name || '';
            var browser = item.browser || '';
            var language = item.language || '';
            var timezone = item.timezone || '';
            var resolution = item.resolution || '';
            var pv = parseInt(item.pv || 0, 10);
            var uv = parseInt(item.uv || 0, 10);
            var ip = parseInt(item.ip_count || 0, 10);
            var spider = parseInt(item.spider_count || 0, 10);
            var speed = Number(item.speed_ms || 0).toFixed(2);
            var time = Number(item.avg_time_ms || 0).toFixed(2);
            var bounceRate = Number(item.bounce_rate || 0).toFixed(2);
            var session = parseInt(item.session_count || 0, 10);
            var id = parseInt(item.id || 0, 10);
            return '<tr>' +
                '<td class="counter-select-col"><input type="checkbox" class="counter-row-checkbox" value="' + id + '" style="width:18px;height:18px;"></td>' +
                '<td class="counter-num" data-col="id">' + id + '</td>' +
                '<td class="counter-date" data-col="stat_date">' + qkCounterEscapeHtml(date) + '</td>' +
                '<td class="counter-title" data-col="page_title"><a class="counter-link" data-qk-tip="' + qkCounterEscapeHtml(title) + '" href="' + qkCounterEscapeHtml(url) + '" target="_blank" rel="noopener noreferrer">' + qkCounterEscapeHtml(title) + '</a></td>' +
                '<td class="counter-url" data-col="page_url"><a class="counter-link" href="' + qkCounterEscapeHtml(url) + '" target="_blank" rel="noopener noreferrer">' + qkCounterEscapeHtml(url) + '</a></td>' +
                '<td class="counter-num" data-col="pv">' + pv + '</td>' +
                '<td class="counter-num" data-col="uv">' + uv + '</td>' +
                '<td class="counter-num" data-col="ip_count">' + ip + '</td>' +
                '<td class="counter-num" data-col="bounce_rate">' + bounceRate + '</td>' +
                '<td class="counter-num" data-col="session_count">' + session + '</td>' +
                '<td class="counter-num" data-col="spider_count">' + spider + '</td>' +
                '<td class="counter-num" data-col="speed_ms">' + speed + '</td>' +
                '<td class="counter-num" data-col="avg_time_ms">' + time + '</td>' +
                '<td class="counter-num" data-col="os_name">' + qkCounterEscapeHtml(osName) + '</td>' +
                '<td class="counter-num" data-col="browser">' + qkCounterEscapeHtml(browser) + '</td>' +
                '<td class="counter-num" data-col="language">' + qkCounterEscapeHtml(language) + '</td>' +
                '<td class="counter-num" data-col="timezone">' + qkCounterEscapeHtml(timezone) + '</td>' +
                '<td class="counter-num" data-col="resolution">' + qkCounterEscapeHtml(resolution) + '</td>' +
                '</tr>';
        }).join('');
        applyCounterColumnVisibility();
        bindCounterRowSelection();
        updateCounterBatchDeleteButton();
    }

    function qkCounterEscapeHtml(value) {
        var map = {
            '&': '&amp;',
            '<': '&lt;',
            '>': '&gt;',
            '"': '&quot;',
            "'": '&#39;'
        };
        return String(value == null ? '' : value).replace(/[&<>"']/g, function(ch) {
            return map[ch];
        });
    }

    document.addEventListener('DOMContentLoaded', function() {
        initCounterDateMenuScrollbar();
        initCounterColumnSettings();
        initCounterCustomScrollbar();
        bindCounterRowSelection();
        updateCounterBatchDeleteButton();
        var scrollContainer = document.querySelector('.counter-table-scroll');
        if (scrollContainer && typeof scrollContainer._counterUpdateScrollbarThumb === 'function') {
            window.requestAnimationFrame(scrollContainer._counterUpdateScrollbarThumb);
        }
        window.addEventListener('resize', function() {
            var scrollContainer = document.querySelector('.counter-table-scroll');
            if (scrollContainer && typeof scrollContainer._counterUpdateScrollbarThumb === 'function') {
                window.requestAnimationFrame(scrollContainer._counterUpdateScrollbarThumb);
            }
        });
        document.addEventListener('click', function(e) {
            var header = document.getElementById('counter-date-header');
            var menu = document.getElementById('counter-date-dropdown-menu');
            var colBtn = document.getElementById('counter-column-setting-btn');
            var colMenu = document.getElementById('counter-column-setting-menu');
            if (!header || !menu) return;
            if (!header.contains(e.target) && !menu.contains(e.target)) {
                menu.style.display = 'none';
            }
            if (colBtn && colMenu && !colBtn.contains(e.target) && !colMenu.contains(e.target)) {
                colMenu.classList.remove('show');
            }
        });
    });

    function getDefaultCounterColumns() {
        return COUNTER_COLUMNS.filter(function(c) {
            return !!c.defaultVisible;
        }).map(function(c) {
            return c.key;
        });
    }

    function readCounterColumns() {
        var defaults = getDefaultCounterColumns();
        try {
            var raw = localStorage.getItem(COUNTER_COLUMN_KEY);
            if (!raw) return defaults;
            var parsed = JSON.parse(raw);
            if (!Array.isArray(parsed)) return defaults;
            var map = {};
            COUNTER_COLUMNS.forEach(function(c) {
                map[c.key] = true;
            });
            var valid = parsed.filter(function(k) {
                return !!map[k];
            });
            return valid.length ? valid : defaults;
        } catch (e) {
            return defaults;
        }
    }

    function saveCounterColumns(keys) {
        localStorage.setItem(COUNTER_COLUMN_KEY, JSON.stringify(keys));
    }

    function getCounterColumnWidthConfig(key) {
        if (key === 'page_title') return {
            min: 220,
            weight: 2.2
        };
        if (key === 'page_url') return {
            min: 220,
            weight: 2.2
        };
        if (key === 'entry_url') return {
            min: 220,
            weight: 2
        };
        if (key === 'browser') return {
            min: 140,
            weight: 1.3
        };
        if (key === 'timezone') return {
            min: 160,
            weight: 1.4
        };
        if (key === 'stat_date') return {
            min: 140,
            weight: 1.2
        };
        return {
            min: 96,
            weight: 1
        };
    }

    function autoAdjustCounterColumnWidths() {
        var table = document.querySelector('.admin-table.counter-manage');
        var scrollContainer = document.querySelector('.counter-table-scroll');
        if (!table || !scrollContainer) return;
        if (!counterVisibleColumns.length) counterVisibleColumns = getDefaultCounterColumns();
        var visibleColumns = COUNTER_COLUMNS.filter(function(col) {
            return counterVisibleColumns.indexOf(col.key) !== -1;
        });
        if (!visibleColumns.length) return;
        var viewportWidth = Math.max(0, scrollContainer.clientWidth);
        var minTotal = 0;
        var totalWeight = 0;
        var base = {};
        visibleColumns.forEach(function(col) {
            var conf = getCounterColumnWidthConfig(col.key);
            base[col.key] = conf;
            minTotal += conf.min;
            totalWeight += conf.weight;
        });
        var targetTotal = Math.max(viewportWidth, minTotal);
        var remaining = Math.max(0, targetTotal - minTotal);
        visibleColumns.forEach(function(col) {
            var conf = base[col.key];
            var extra = totalWeight > 0 ? (remaining * conf.weight / totalWeight) : 0;
            var finalWidth = Math.round(conf.min + extra);
            document.querySelectorAll('[data-col="' + col.key + '"]').forEach(function(el) {
                el.style.setProperty('width', finalWidth + 'px', 'important');
                el.style.setProperty('min-width', finalWidth + 'px', 'important');
                el.style.setProperty('max-width', finalWidth + 'px', 'important');
            });
        });
        table.style.setProperty('min-width', targetTotal + 'px');
        if (typeof scrollContainer._counterUpdateScrollbarThumb === 'function') {
            window.requestAnimationFrame(scrollContainer._counterUpdateScrollbarThumb);
        }
    }

    function applyCounterColumnVisibility() {
        var pre = document.getElementById('counter-prestyle');
        if (pre && pre.parentNode) pre.parentNode.removeChild(pre);
        if (!counterVisibleColumns.length) counterVisibleColumns = getDefaultCounterColumns();
        var visibleMap = {};
        counterVisibleColumns.forEach(function(k) {
            visibleMap[k] = true;
        });
        var runtimeStyle = document.getElementById('counter-runtime-style');
        if (!runtimeStyle) {
            runtimeStyle = document.createElement('style');
            runtimeStyle.id = 'counter-runtime-style';
            document.head.appendChild(runtimeStyle);
        }
        runtimeStyle.textContent = COUNTER_COLUMNS.map(function(col) {
            return '[data-col="' + col.key + '"]{display:' + (visibleMap[col.key] ? 'table-cell' : 'none') + ' !important;}';
        }).join('');

        document.querySelectorAll('.counter-last-col').forEach(function(el) {
            el.classList.remove('counter-last-col');
        });
        var lastVisibleCol = counterVisibleColumns.length > 0 ? counterVisibleColumns[counterVisibleColumns.length - 1] : null;
        if (lastVisibleCol) {
            document.querySelectorAll('[data-col="' + lastVisibleCol + '"]').forEach(function(el) {
                el.classList.add('counter-last-col');
            });
        }
        var visibleCount = counterVisibleColumns.length;
        var emptyTd = document.querySelector('#counter-list-body .counter-empty-row td');
        if (emptyTd) emptyTd.colSpan = Math.max(1, visibleCount + 1);
        var btnText = document.getElementById('counter-column-setting-text');
        if (btnText) btnText.textContent = '列数设置';
        var countBadge = document.getElementById('counter-column-count-badge');
        if (countBadge) countBadge.textContent = visibleCount;
    }

    function initCounterColumnSettings() {
        var btn = document.getElementById('counter-column-setting-btn');
        var menu = document.getElementById('counter-column-setting-menu');
        if (!btn || !menu) return;
        if (window.__counterPreColumns && Array.isArray(window.__counterPreColumns) && window.__counterPreColumns.length) {
            counterVisibleColumns = window.__counterPreColumns.slice();
        } else {
            counterVisibleColumns = readCounterColumns();
        }
        var menuItemsHtml = COUNTER_COLUMNS.map(function(col) {
            var checked = counterVisibleColumns.indexOf(col.key) !== -1 ? ' checked' : '';
            return '<label class="counter-column-item"><input type="checkbox" data-col-key="' + qkCounterEscapeHtml(col.key) + '"' + checked + '><span class="counter-column-name">' + qkCounterEscapeHtml(col.label) + '</span><span class="counter-column-field">（' + qkCounterEscapeHtml(col.key) + '）</span></label>';
        }).join('');
        menu.innerHTML = '<div class="counter-column-menu-content">' + menuItemsHtml + '</div><div class="counter-column-menu-vscroll"><div class="counter-column-menu-vthumb"></div></div>';
        initCounterColumnMenuScrollbar(menu);
        var visibleCount = counterVisibleColumns.length;
        var emptyTd = document.querySelector('#counter-list-body .counter-empty-row td');
        if (emptyTd) emptyTd.colSpan = Math.max(1, visibleCount + 1);
        var countBadge = document.getElementById('counter-column-count-badge');
        if (countBadge) countBadge.textContent = visibleCount;
        btn.addEventListener('click', function(e) {
            e.preventDefault();
            menu.classList.toggle('show');
            if (menu.classList.contains('show') && typeof menu._counterMenuScrollbarUpdate === 'function') {
                window.requestAnimationFrame(menu._counterMenuScrollbarUpdate);
            }
        });
        menu.addEventListener('click', function(e) {
            e.stopPropagation();
        });

        menu.addEventListener('change', function(e) {
            var input = e.target && e.target.matches('input[type="checkbox"][data-col-key]') ? e.target : null;
            if (!input) return;
            var selected = Array.from(menu.querySelectorAll('input[data-col-key]:checked')).map(function(node) {
                return node.getAttribute('data-col-key');
            });
            if (!selected.length) {
                input.checked = true;
                return;
            }
            counterVisibleColumns = selected;
            saveCounterColumns(counterVisibleColumns);
            applyCounterColumnVisibility();
        });
    }

    function initCounterColumnMenuScrollbar(menu) {
        if (!window.AdminScrollbar || typeof window.AdminScrollbar.initVerticalMenu !== 'function') return;
        window.AdminScrollbar.initVerticalMenu({
            menu: menu,
            contentSelector: '.counter-column-menu-content',
            trackSelector: '.counter-column-menu-vscroll',
            thumbSelector: '.counter-column-menu-vthumb',
            thumbHeight: 80,
            updateHookName: '_counterMenuScrollbarUpdate'
        });
    }

    function initCounterDateMenuScrollbar() {
        var menu = document.getElementById('counter-date-dropdown-menu');
        if (!menu) return;
        if (!window.AdminScrollbar || typeof window.AdminScrollbar.initVerticalMenu !== 'function') return;
        window.AdminScrollbar.initVerticalMenu({
            menu: menu,
            contentSelector: '.counter-column-menu-content',
            trackSelector: '.counter-column-menu-vscroll',
            thumbSelector: '.counter-column-menu-vthumb',
            thumbHeight: 80,
            updateHookName: '_counterDateMenuScrollbarUpdate'
        });
    }

    function closeAllCounterMenus() {
        const menu = document.getElementById('counter-date-dropdown-menu');
        if (menu) {
            menu.style.display = 'none';
        }
    }

    window.addEventListener('scroll', function() {
        closeAllCounterMenus();
    }, { passive: true });

    function toggleCounterDateMenu() {
        const header = document.getElementById('counter-date-header');
        const menu = document.getElementById('counter-date-dropdown-menu');
        if (!header || !menu) return;

        const isOpen = menu.style.display === 'block';
        if (isOpen) {
            menu.style.display = 'none';
            return;
        }

        const rect = header.getBoundingClientRect();
        menu.style.position = 'fixed';
        menu.style.top = (rect.bottom - 23) + 'px';
        menu.style.left = rect.left + 'px';
        menu.style.zIndex = '2147483647';
        menu.style.display = 'block';
    }

    function filterCounterDate(url) {
        const menu = document.getElementById('counter-date-dropdown-menu');
        if (menu) menu.style.display = 'none';
        if (!url) return;
        window.location.href = url;
    }

    function getSelectedCounterIds() {
        return Array.from(document.querySelectorAll('.counter-row-checkbox:checked')).map(function(node) {
            return node.value;
        });
    }

    function updateCounterBatchDeleteButton() {
        var btn = document.getElementById('counter-batch-delete-btn');
        if (!btn) return;
        var count = getSelectedCounterIds().length;
        if (count > 0) btn.classList.add('is-active');
        else btn.classList.remove('is-active');
    }

    function syncCounterSelectAllState() {
        var all = document.querySelectorAll('.counter-row-checkbox');
        var checked = document.querySelectorAll('.counter-row-checkbox:checked');
        var selectAll = document.getElementById('select-all-counter');
        if (!selectAll) return;
        if (!all.length) {
            selectAll.checked = false;
            selectAll.indeterminate = false;
            return;
        }
        selectAll.checked = checked.length === all.length;
        selectAll.indeterminate = checked.length > 0 && checked.length < all.length;
    }

    function bindCounterRowSelection() {
        var selectAll = document.getElementById('select-all-counter');
        if (selectAll && !selectAll.dataset.bound) {
            selectAll.dataset.bound = '1';
            selectAll.addEventListener('change', function() {
                var isChecked = this.checked;
                document.querySelectorAll('.counter-row-checkbox').forEach(function(node) {
                    node.checked = isChecked;
                });
                syncCounterSelectAllState();
                updateCounterBatchDeleteButton();
            });
        }
        document.querySelectorAll('.counter-row-checkbox').forEach(function(node) {
            if (node.dataset.bound === '1') return;
            node.dataset.bound = '1';
            node.addEventListener('change', function() {
                syncCounterSelectAllState();
                updateCounterBatchDeleteButton();
            });
        });
        syncCounterSelectAllState();
    }

    function deleteSelectedCounters() {
        var ids = getSelectedCounterIds();
        if (!ids.length) {
            if (typeof showToast === 'function') showToast('请先选择要删除的统计记录', 'warning');
            return;
        }

        var doDelete = function() {
            fetch('/admin/counter.php', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                    'X-Requested-With': 'XMLHttpRequest'
                },
                credentials: 'include',
                body: 'action=delete_selected_counter&counter_ids=' + encodeURIComponent(ids.join(','))
            }).then(function(response) {
                return response.json();
            }).then(function(data) {
                if (data && data.success) {
                    ids.forEach(function(id) {
                        var checkbox = document.querySelector('.counter-row-checkbox[value="' + id + '"]');
                        if (checkbox) {
                            var tr = checkbox.closest('tr');
                            if (tr) tr.remove();
                        }
                    });
                    var tbody = document.getElementById('counter-list-body');
                    if (tbody && !tbody.querySelector('tr')) {
                        tbody.innerHTML = '<tr class="counter-empty-row"><td colspan="18" class="counter-empty">暂无统计数据</td></tr>';
                    }
                    syncCounterSelectAllState();
                    updateCounterBatchDeleteButton();
                    if (typeof showToast === 'function') showToast(data.message || '删除成功', 'success');
                } else {
                    if (typeof showToast === 'function') showToast((data && data.message) ? data.message : '删除失败', 'error');
                }
            }).catch(function() {
                if (typeof showToast === 'function') showToast('网络错误，请稍后重试', 'error');
            });
        };

        doDelete();
    }

    document.addEventListener('DOMContentLoaded', function() {
        var batchDeleteBtn = document.getElementById('counter-batch-delete-btn');
        if (batchDeleteBtn) {
            batchDeleteBtn.addEventListener('click', function(e) {
                e.preventDefault();
                deleteSelectedCounters();
            });
        }
    });
</script>
