643 lines
20 KiB
PHP
643 lines
20 KiB
PHP
<?php
|
||
/**
|
||
* 定期报告生成脚本
|
||
*
|
||
* 此脚本生成任务报告并保存到服务器
|
||
* 可以通过群晖的计划任务定期执行
|
||
*/
|
||
|
||
// 设置错误报告
|
||
ini_set('display_errors', 1);
|
||
error_reporting(E_ALL);
|
||
|
||
// 启用网页输出模式
|
||
header('Content-Type: text/html; charset=utf-8');
|
||
|
||
// 配置信息
|
||
$config = [
|
||
// 数据库配置
|
||
'db_host' => '192.168.2.4',
|
||
'db_port' => 3307,
|
||
'db_name' => 'task_reporter',
|
||
'db_user' => 'task_reporter',
|
||
'db_pass' => 'Pass12349ers!',
|
||
|
||
// 报告生成选项
|
||
'author' => 'CGNICO Task Reporter', // 报告作者
|
||
|
||
// 报告配置
|
||
'report_days' => 7, // 报告包含的天数(例如:7表示过去一周)
|
||
'report_title' => 'CGNICO工具使用报告', // 报告标题
|
||
];
|
||
|
||
// 根据报告天数设置标题
|
||
if (isset($_GET['days'])) {
|
||
$config['report_days'] = intval($_GET['days']);
|
||
|
||
// 根据天数调整报告标题
|
||
if ($config['report_days'] == 7) {
|
||
$config['report_title'] = 'CGNICO工具使用周报';
|
||
} elseif ($config['report_days'] == 30) {
|
||
$config['report_title'] = 'CGNICO工具使用月报';
|
||
} elseif ($config['report_days'] == 90) {
|
||
$config['report_title'] = 'CGNICO工具使用季报';
|
||
} elseif ($config['report_days'] == 365) {
|
||
$config['report_title'] = 'CGNICO工具使用年报';
|
||
}
|
||
}
|
||
|
||
// 创建数据库连接
|
||
try {
|
||
$pdo = new PDO(
|
||
"mysql:host={$config['db_host']};port={$config['db_port']};dbname={$config['db_name']}",
|
||
$config['db_user'],
|
||
$config['db_pass']
|
||
);
|
||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||
$pdo->exec("SET NAMES utf8");
|
||
} catch (PDOException $e) {
|
||
die("数据库连接失败: " . $e->getMessage());
|
||
}
|
||
|
||
// 生成报告
|
||
function generate_report($pdo, $days) {
|
||
$report = [];
|
||
|
||
// 获取日期范围
|
||
$end_date = date('Y-m-d');
|
||
$start_date = date('Y-m-d', strtotime("-{$days} days"));
|
||
|
||
// 1. 总体统计
|
||
$stmt = $pdo->prepare("
|
||
SELECT
|
||
COUNT(*) as total_tasks,
|
||
SUM(time_saved) as total_time_saved,
|
||
COUNT(DISTINCT username) as total_users,
|
||
COUNT(DISTINCT tool_name) as total_tools
|
||
FROM task
|
||
WHERE timestamp BETWEEN :start_date AND :end_date
|
||
AND tool_name NOT LIKE '%(Debug)%'
|
||
");
|
||
$stmt->bindParam(':start_date', $start_date);
|
||
$stmt->bindParam(':end_date', $end_date);
|
||
$stmt->execute();
|
||
$report['summary'] = $stmt->fetch(PDO::FETCH_ASSOC);
|
||
|
||
// 2. 工具使用统计
|
||
$stmt = $pdo->prepare("
|
||
SELECT
|
||
tool_name,
|
||
COUNT(*) as usage_count,
|
||
SUM(time_saved) as time_saved
|
||
FROM task
|
||
WHERE timestamp BETWEEN :start_date AND :end_date
|
||
AND tool_name NOT LIKE '%(Debug)%'
|
||
GROUP BY tool_name
|
||
ORDER BY usage_count DESC
|
||
LIMIT 10
|
||
");
|
||
$stmt->bindParam(':start_date', $start_date);
|
||
$stmt->bindParam(':end_date', $end_date);
|
||
$stmt->execute();
|
||
$report['tools'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||
|
||
// 3. 用户使用统计
|
||
$stmt = $pdo->prepare("
|
||
SELECT
|
||
username,
|
||
COUNT(*) as usage_count,
|
||
SUM(time_saved) as time_saved
|
||
FROM task
|
||
WHERE timestamp BETWEEN :start_date AND :end_date
|
||
AND tool_name NOT LIKE '%(Debug)%'
|
||
GROUP BY username
|
||
ORDER BY usage_count DESC
|
||
LIMIT 10
|
||
");
|
||
$stmt->bindParam(':start_date', $start_date);
|
||
$stmt->bindParam(':end_date', $end_date);
|
||
$stmt->execute();
|
||
$report['users'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||
|
||
// 4. 每日使用趋势
|
||
$stmt = $pdo->prepare("
|
||
SELECT
|
||
DATE(timestamp) as date,
|
||
COUNT(*) as usage_count,
|
||
SUM(time_saved) as time_saved
|
||
FROM task
|
||
WHERE timestamp BETWEEN :start_date AND :end_date
|
||
AND tool_name NOT LIKE '%(Debug)%'
|
||
GROUP BY DATE(timestamp)
|
||
ORDER BY date
|
||
");
|
||
$stmt->bindParam(':start_date', $start_date);
|
||
$stmt->bindParam(':end_date', $end_date);
|
||
$stmt->execute();
|
||
$report['daily'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||
|
||
return [
|
||
'report' => $report,
|
||
'start_date' => $start_date,
|
||
'end_date' => $end_date
|
||
];
|
||
}
|
||
|
||
// 生成HTML报告
|
||
function generate_html_report($report_data) {
|
||
$report = $report_data['report'];
|
||
$start_date = $report_data['start_date'];
|
||
$end_date = $report_data['end_date'];
|
||
|
||
$html = '
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>CGNICO工具使用报告</title>
|
||
<style>
|
||
body {
|
||
font-family: Arial, sans-serif;
|
||
line-height: 1.6;
|
||
color: #333;
|
||
max-width: 800px;
|
||
margin: 0 auto;
|
||
padding: 20px;
|
||
}
|
||
h1, h2, h3 {
|
||
color: #0066cc;
|
||
}
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin: 20px 0;
|
||
}
|
||
th, td {
|
||
padding: 10px;
|
||
border: 1px solid #ddd;
|
||
text-align: left;
|
||
}
|
||
th {
|
||
background-color: #f2f2f2;
|
||
}
|
||
tr:nth-child(even) {
|
||
background-color: #f9f9f9;
|
||
}
|
||
.summary {
|
||
background-color: #f0f7ff;
|
||
padding: 15px;
|
||
border-radius: 5px;
|
||
margin-bottom: 20px;
|
||
}
|
||
.highlight {
|
||
color: #0066cc;
|
||
font-weight: bold;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<h1>CGNICO工具使用报告</h1>
|
||
<p>报告时间范围: ' . $start_date . ' 至 ' . $end_date . '</p>
|
||
|
||
<div class="summary">
|
||
<h2>总体统计</h2>
|
||
<p>在过去的 ' . round((strtotime($end_date) - strtotime($start_date)) / 86400) . ' 天中:</p>
|
||
<ul>
|
||
<li>总任务数: <span class="highlight">' . number_format($report['summary']['total_tasks']) . '</span></li>
|
||
<li>总节省时间: <span class="highlight">' . number_format($report['summary']['total_time_saved'], 2) . ' 小时</span></li>
|
||
<li>活跃用户数: <span class="highlight">' . $report['summary']['total_users'] . '</span></li>
|
||
<li>使用的工具数: <span class="highlight">' . $report['summary']['total_tools'] . '</span></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<h2>工具使用排名</h2>
|
||
<table>
|
||
<tr>
|
||
<th>排名</th>
|
||
<th>工具名称</th>
|
||
<th>使用次数</th>
|
||
<th>节省时间 (小时)</th>
|
||
</tr>';
|
||
|
||
$rank = 1;
|
||
foreach ($report['tools'] as $tool) {
|
||
$html .= '
|
||
<tr>
|
||
<td>' . $rank++ . '</td>
|
||
<td>' . htmlspecialchars($tool['tool_name']) . '</td>
|
||
<td>' . number_format($tool['usage_count']) . '</td>
|
||
<td>' . number_format($tool['time_saved'], 2) . '</td>
|
||
</tr>';
|
||
}
|
||
|
||
$html .= '
|
||
</table>
|
||
|
||
<h2>用户使用排名</h2>
|
||
<table>
|
||
<tr>
|
||
<th>排名</th>
|
||
<th>用户名</th>
|
||
<th>使用次数</th>
|
||
<th>节省时间 (小时)</th>
|
||
</tr>';
|
||
|
||
$rank = 1;
|
||
foreach ($report['users'] as $user) {
|
||
$html .= '
|
||
<tr>
|
||
<td>' . $rank++ . '</td>
|
||
<td>' . htmlspecialchars($user['username']) . '</td>
|
||
<td>' . number_format($user['usage_count']) . '</td>
|
||
<td>' . number_format($user['time_saved'], 2) . '</td>
|
||
</tr>';
|
||
}
|
||
|
||
$html .= '
|
||
</table>
|
||
|
||
<h2>每日使用趋势</h2>
|
||
<table>
|
||
<tr>
|
||
<th>日期</th>
|
||
<th>使用次数</th>
|
||
<th>节省时间 (小时)</th>
|
||
</tr>';
|
||
|
||
foreach ($report['daily'] as $day) {
|
||
$html .= '
|
||
<tr>
|
||
<td>' . $day['date'] . '</td>
|
||
<td>' . number_format($day['usage_count']) . '</td>
|
||
<td>' . number_format($day['time_saved'], 2) . '</td>
|
||
</tr>';
|
||
}
|
||
|
||
$html .= '
|
||
</table>
|
||
|
||
<div style="margin-top: 30px; color: #666; font-size: 12px; text-align: center;">
|
||
<p>此报告由CGNICO Task Reporter自动生成于 ' . date('Y-m-d H:i:s') . '</p>
|
||
</div>
|
||
</body>
|
||
</html>';
|
||
|
||
return $html;
|
||
}
|
||
|
||
// 记录日志
|
||
function log_message($message) {
|
||
$log_dir = __DIR__ . '/logs';
|
||
if (!is_dir($log_dir)) {
|
||
mkdir($log_dir, 0755, true);
|
||
}
|
||
|
||
$log_file = $log_dir . '/report_' . date('Y-m-d') . '.log';
|
||
$time = date('Y-m-d H:i:s');
|
||
file_put_contents($log_file, "[$time] $message\n", FILE_APPEND);
|
||
}
|
||
|
||
// 主程序
|
||
try {
|
||
// 创建报告目录(如果不存在)
|
||
$report_dir = __DIR__ . '/reports/';
|
||
if (!is_dir($report_dir)) {
|
||
mkdir($report_dir, 0755, true);
|
||
}
|
||
|
||
// 检查是否需要生成新报告
|
||
$generate_new_report = false;
|
||
$report_file = $report_dir . 'report_' . date('Y-m-d') . '.html';
|
||
|
||
if (isset($_GET['generate']) && $_GET['generate'] == '1') {
|
||
$generate_new_report = true;
|
||
} elseif (!file_exists($report_file)) {
|
||
// 如果今天的报告不存在,自动生成
|
||
$generate_new_report = true;
|
||
}
|
||
|
||
if ($generate_new_report) {
|
||
log_message('===== 开始执行报告生成脚本 =====');
|
||
|
||
// 生成报告数据
|
||
log_message('开始生成报告数据...');
|
||
$days = $config['report_days'];
|
||
$report_data = generate_report($pdo, $days);
|
||
log_message('报告数据生成完成');
|
||
|
||
// 生成HTML报告
|
||
log_message('生成HTML报告...');
|
||
$html_report = generate_html_report($report_data);
|
||
log_message('HTML报告生成完成');
|
||
|
||
// 保存报告到文件
|
||
file_put_contents($report_file, $html_report);
|
||
log_message('报告已保存到: ' . $report_file);
|
||
}
|
||
|
||
// 开始HTML输出
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>CGNICO工具使用报告生成器</title>
|
||
<style>
|
||
body {
|
||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||
margin: 0;
|
||
padding: 20px;
|
||
background-color: #f5f5f5;
|
||
color: #333;
|
||
}
|
||
|
||
.container {
|
||
max-width: 1000px;
|
||
margin: 0 auto;
|
||
background-color: #fff;
|
||
padding: 20px;
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
h1 {
|
||
color: #ff8c00;
|
||
text-align: center;
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
h3 {
|
||
color: #555;
|
||
margin-top: 0;
|
||
}
|
||
|
||
.success-message {
|
||
background-color: #dff0d8;
|
||
border: 1px solid #d6e9c6;
|
||
color: #3c763d;
|
||
border-radius: 4px;
|
||
padding: 15px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.action-buttons {
|
||
display: flex;
|
||
gap: 10px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.btn {
|
||
display: inline-block;
|
||
padding: 10px 15px;
|
||
text-decoration: none;
|
||
border-radius: 4px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
border: none;
|
||
transition: background-color 0.3s;
|
||
}
|
||
|
||
.btn-primary {
|
||
background-color: #337ab7;
|
||
color: white;
|
||
}
|
||
|
||
.btn-primary:hover {
|
||
background-color: #286090;
|
||
}
|
||
|
||
.btn-success {
|
||
background-color: #4CAF50;
|
||
color: white;
|
||
}
|
||
|
||
.btn-success:hover {
|
||
background-color: #3d8b40;
|
||
}
|
||
|
||
.btn-secondary {
|
||
background-color: #6c757d;
|
||
color: white;
|
||
}
|
||
|
||
.btn-secondary:hover {
|
||
background-color: #5a6268;
|
||
}
|
||
|
||
.panel {
|
||
background-color: #f5f5f5;
|
||
border: 1px solid #e3e3e3;
|
||
border-radius: 4px;
|
||
padding: 15px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
label {
|
||
display: inline-block;
|
||
margin-bottom: 5px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
select {
|
||
padding: 8px 12px;
|
||
border: 1px solid #ccc;
|
||
border-radius: 4px;
|
||
width: 100%;
|
||
max-width: 300px;
|
||
}
|
||
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
th, td {
|
||
padding: 10px;
|
||
border: 1px solid #ddd;
|
||
text-align: left;
|
||
}
|
||
|
||
th {
|
||
background-color: #f0f0f0;
|
||
font-weight: bold;
|
||
}
|
||
|
||
tr:nth-child(even) {
|
||
background-color: #f9f9f9;
|
||
}
|
||
|
||
tr:hover {
|
||
background-color: #f1f1f1;
|
||
}
|
||
|
||
.table-actions {
|
||
text-align: center;
|
||
}
|
||
|
||
.footer {
|
||
text-align: center;
|
||
margin-top: 30px;
|
||
padding-top: 15px;
|
||
border-top: 1px solid #eee;
|
||
color: #777;
|
||
font-size: 0.9em;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1>CGNICO工具使用报告生成器</h1>
|
||
|
||
<?php if ($generate_new_report): ?>
|
||
<div class="success-message">
|
||
<p><strong>报告已生成成功!</strong></p>
|
||
<p>报告时间范围: 过去<?php echo $config['report_days']; ?>天 (<?php echo date('Y-m-d', strtotime("-{$config['report_days']} days")); ?> 至 <?php echo date('Y-m-d'); ?>)</p>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<div class="action-buttons">
|
||
<a href="reports/report_<?php echo date('Y-m-d'); ?>.html" target="_blank" class="btn btn-primary">查看最新报告</a>
|
||
<a href="reports/report_<?php echo date('Y-m-d'); ?>.html" download class="btn btn-success">下载最新报告</a>
|
||
<a href="index.php" class="btn btn-secondary">返回首页</a>
|
||
</div>
|
||
|
||
<div class="panel">
|
||
<h3>生成新报告</h3>
|
||
<form method="get" action="">
|
||
<div class="form-group">
|
||
<label for="days">报告时间范围:</label>
|
||
<select name="days" id="days">
|
||
<option value="7" <?php echo ($config['report_days'] == 7) ? 'selected' : ''; ?>>过去7天 (一周)</option>
|
||
<option value="30" <?php echo ($config['report_days'] == 30) ? 'selected' : ''; ?>>过去30天 (一个月)</option>
|
||
<option value="90" <?php echo ($config['report_days'] == 90) ? 'selected' : ''; ?>>过去90天 (一季度)</option>
|
||
<option value="365" <?php echo ($config['report_days'] == 365) ? 'selected' : ''; ?>>过去365天 (一年)</option>
|
||
</select>
|
||
</div>
|
||
<input type="hidden" name="generate" value="1">
|
||
<button type="submit" class="btn btn-primary">生成报告</button>
|
||
</form>
|
||
</div>
|
||
|
||
<?php
|
||
// 历史报告列表
|
||
$reports_dir = __DIR__ . '/reports/';
|
||
if (is_dir($reports_dir)) {
|
||
$reports = glob($reports_dir . 'report_*.html');
|
||
if (!empty($reports)) {
|
||
echo "<div class=\"panel\">\n";
|
||
echo "<h3>历史报告</h3>\n";
|
||
echo "<table>\n";
|
||
echo "<tr>\n";
|
||
echo "<th>报告日期</th>\n";
|
||
echo "<th>报告类型</th>\n";
|
||
echo "<th>操作</th>\n";
|
||
echo "</tr>\n";
|
||
|
||
rsort($reports); // 按日期降序排序
|
||
|
||
foreach (array_slice($reports, 0, 10) as $report) { // 只显示最近10个
|
||
$filename = basename($report);
|
||
$date = substr($filename, 7, 10); // 从 report_YYYY-MM-DD.html 提取日期
|
||
|
||
// 尝试确定报告类型
|
||
$report_type = "常规报告";
|
||
$file_content = file_get_contents($report);
|
||
if (strpos($file_content, "工具使用周报") !== false) {
|
||
$report_type = "周报";
|
||
} elseif (strpos($file_content, "工具使用月报") !== false) {
|
||
$report_type = "月报";
|
||
} elseif (strpos($file_content, "工具使用季报") !== false) {
|
||
$report_type = "季报";
|
||
} elseif (strpos($file_content, "工具使用年报") !== false) {
|
||
$report_type = "年报";
|
||
}
|
||
|
||
echo "<tr>\n";
|
||
echo "<td>{$date}</td>\n";
|
||
echo "<td>{$report_type}</td>\n";
|
||
echo "<td class=\"table-actions\">\n";
|
||
echo "<a href='reports/{$filename}' target='_blank' class='btn btn-primary' style='padding: 5px 10px; margin-right: 5px;'>查看</a>\n";
|
||
echo "<a href='reports/{$filename}' download class='btn btn-success' style='padding: 5px 10px;'>下载</a>\n";
|
||
echo "</td>\n";
|
||
echo "</tr>\n";
|
||
}
|
||
|
||
echo "</table>\n";
|
||
echo "</div>\n";
|
||
}
|
||
}
|
||
?>
|
||
|
||
<div class="footer">
|
||
<p>CGNICO Task Report System © <?php echo date('Y'); ?> | 联系方式: <a href="mailto:jeffreytsai1004@gmail.com">jeffreytsai1004@gmail.com</a></p>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
<?php
|
||
} catch (Exception $e) {
|
||
log_message('错误: ' . $e->getMessage());
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>错误 - CGNICO工具使用报告生成器</title>
|
||
<style>
|
||
body {
|
||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||
margin: 0;
|
||
padding: 20px;
|
||
background-color: #f5f5f5;
|
||
color: #333;
|
||
}
|
||
.container {
|
||
max-width: 800px;
|
||
margin: 0 auto;
|
||
background-color: #fff;
|
||
padding: 20px;
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||
}
|
||
h1 {
|
||
color: #d9534f;
|
||
}
|
||
.error-message {
|
||
background-color: #f2dede;
|
||
border: 1px solid #ebccd1;
|
||
color: #a94442;
|
||
padding: 15px;
|
||
border-radius: 4px;
|
||
margin-bottom: 20px;
|
||
}
|
||
.btn {
|
||
display: inline-block;
|
||
padding: 10px 15px;
|
||
background-color: #6c757d;
|
||
color: white;
|
||
text-decoration: none;
|
||
border-radius: 4px;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1>发生错误</h1>
|
||
<div class="error-message">
|
||
<p><strong>错误:</strong> <?php echo $e->getMessage(); ?></p>
|
||
</div>
|
||
<a href="index.php" class="btn">返回首页</a>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
<?php
|
||
}
|
||
?>
|