PyBot/index.php
2026-05-20 00:40:03 +08:00

1279 lines
51 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* 资讯推送Web端 - PHP版本
* 直接从SQLite数据库读取数据并展示
*/
// 设置字符编码
header('Content-Type: text/html; charset=utf-8');
// 数据库路径
$dbPath = __DIR__ . '/resources/db/web.db';
// 检查数据库文件是否存在
if (!file_exists($dbPath)) {
die('<div style="text-align:center;padding:50px;color:#ff6b6b;font-size:1.2em;">❌ 数据库文件不存在!请确认路径正确。</div>');
}
// 获取请求参数
$action = isset($_GET['action']) ? $_GET['action'] : '';
$dateFilter = isset($_GET['date']) ? $_GET['date'] : '';
$limit = isset($_GET['limit']) ? intval($_GET['limit']) : 50;
// 限制最大记录数
if ($limit > 200 || $limit < 1) {
$limit = 50;
}
/**
* 连接SQLite数据库
*/
function getDatabaseConnection($dbPath) {
try {
$db = new PDO("sqlite:" . $dbPath);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
return $db;
} catch (PDOException $e) {
error_log("数据库连接失败: " . $e->getMessage());
return null;
}
}
/**
* 格式化日期显示
*/
function formatDate($dateStr) {
if (empty($dateStr)) return '未知时间';
$timestamp = strtotime($dateStr);
if ($timestamp === false) {
return $dateStr;
}
return date('Y-m-d H:i:s', $timestamp);
}
/**
* 截断文本到指定长度
*/
function truncateText($text, $maxLength = 200) {
if (empty($text)) return '';
if (mb_strlen($text, 'UTF-8') <= $maxLength) return $text;
return mb_substr($text, 0, $maxLength, 'UTF-8') . '...';
}
/**
* 获取安全新闻数据
*/
function getSecNews($db, $dateFilter = '', $limit = 50) {
if ($dateFilter) {
$sql = "SELECT article_title, link, author, description, source, upload_time, category
FROM sec_news
WHERE DATE(upload_time) = :date
ORDER BY upload_time DESC
LIMIT :limit";
$stmt = $db->prepare($sql);
$stmt->bindValue(':date', $dateFilter, PDO::PARAM_STR);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
} else {
$sql = "SELECT article_title, link, author, description, source, upload_time, category
FROM sec_news
ORDER BY upload_time DESC
LIMIT :limit";
$stmt = $db->prepare($sql);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
}
$stmt->execute();
return $stmt->fetchAll();
}
/**
* 获取技术文章数据
*/
function getTechPassage($db, $dateFilter = '', $limit = 50) {
if ($dateFilter) {
$sql = "SELECT article_title, link, author, description, source, upload_time, category
FROM tech_passage
WHERE DATE(upload_time) = :date
ORDER BY upload_time DESC
LIMIT :limit";
$stmt = $db->prepare($sql);
$stmt->bindValue(':date', $dateFilter, PDO::PARAM_STR);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
} else {
$sql = "SELECT article_title, link, author, description, source, upload_time, category
FROM tech_passage
ORDER BY upload_time DESC
LIMIT :limit";
$stmt = $db->prepare($sql);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
}
$stmt->execute();
return $stmt->fetchAll();
}
/**
* 获取百度新闻数据
*/
function getBaiduNews($db, $dateFilter = '', $limit = 50) {
if ($dateFilter) {
$sql = "SELECT article_title, link, description, source, upload_time, keyword
FROM baidu
WHERE DATE(upload_time) = :date
ORDER BY upload_time DESC
LIMIT :limit";
$stmt = $db->prepare($sql);
$stmt->bindValue(':date', $dateFilter, PDO::PARAM_STR);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
} else {
$sql = "SELECT article_title, link, description, source, upload_time, keyword
FROM baidu
ORDER BY upload_time DESC
LIMIT :limit";
$stmt = $db->prepare($sql);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
}
$stmt->execute();
return $stmt->fetchAll();
}
/**
* 获取GitHub动态数据
*/
function getGithubNews($db, $dateFilter = '', $limit = 50) {
if ($dateFilter) {
$sql = "SELECT article_title, link, description, author, upload_time, keyword, language, source
FROM github
WHERE DATE(upload_time) = :date
ORDER BY upload_time DESC
LIMIT :limit";
$stmt = $db->prepare($sql);
$stmt->bindValue(':date', $dateFilter, PDO::PARAM_STR);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
} else {
$sql = "SELECT article_title, link, description, author, upload_time, keyword, language, source
FROM github
ORDER BY upload_time DESC
LIMIT :limit";
$stmt = $db->prepare($sql);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
}
$stmt->execute();
return $stmt->fetchAll();
}
/**
* 获取微信文章数据(搜狗微信)
*/
function getWxNews($db, $dateFilter = '', $limit = 50) {
if ($dateFilter) {
$sql = "SELECT article_title, link, description, upload_time, author, keyword
FROM wx_news
WHERE DATE(upload_time) = :date
ORDER BY upload_time DESC
LIMIT :limit";
$stmt = $db->prepare($sql);
$stmt->bindValue(':date', $dateFilter, PDO::PARAM_STR);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
} else {
$sql = "SELECT article_title, link, description, upload_time, author, keyword
FROM wx_news
ORDER BY upload_time DESC
LIMIT :limit";
$stmt = $db->prepare($sql);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
}
$stmt->execute();
return $stmt->fetchAll();
}
/**
* 获取其他RSS源数据uni_rss表
*/
function getOtherRss($db, $dateFilter = '', $limit = 50) {
if ($dateFilter) {
$sql = "SELECT article_title, link, description, upload_time, author, source
FROM uni_rss
WHERE DATE(upload_time) = :date
ORDER BY upload_time DESC
LIMIT :limit";
$stmt = $db->prepare($sql);
$stmt->bindValue(':date', $dateFilter, PDO::PARAM_STR);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
} else {
$sql = "SELECT article_title, link, description, upload_time, author, source
FROM uni_rss
ORDER BY upload_time DESC
LIMIT :limit";
$stmt = $db->prepare($sql);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
}
$stmt->execute();
return $stmt->fetchAll();
}
/**
* 渲染安全新闻HTML
*/
function renderSecNews($articles) {
if (empty($articles)) {
return '<div class="error-message"><p>❌ 暂无安全新闻数据</p></div>';
}
$html = '';
foreach ($articles as $article) {
$html .= '<div class="article-item">';
$html .= '<h4><a href="' . htmlspecialchars($article['link']) . '" target="_blank">' .
htmlspecialchars($article['article_title']) . '</a></h4>';
$html .= '<div class="article-meta">';
if (!empty($article['author'])) {
$html .= '<span class="meta-item"><strong>作者:</strong>' . htmlspecialchars($article['author']) . '</span>';
}
$html .= '<span class="meta-item"><strong>上传时间:</strong>' . formatDate($article['upload_time']) . '</span>';
if (!empty($article['source'])) {
$html .= '<span class="meta-item"><strong>来源:</strong>' . htmlspecialchars($article['source']) . '</span>';
}
if (!empty($article['category'])) {
$html .= '<span class="meta-item"><strong>类型:</strong>' . htmlspecialchars($article['category']) . '</span>';
}
$html .= '</div>';
if (!empty($article['description'])) {
$html .= '<div class="article-desc">' . htmlspecialchars(truncateText($article['description'], 300)) . '</div>';
}
$html .= '<hr class="article-divider">';
$html .= '</div>';
}
return $html;
}
/**
* 渲染技术文章HTML
*/
function renderTechPassage($articles) {
if (empty($articles)) {
return '<div class="error-message"><p>❌ 暂无技术文章数据</p></div>';
}
$html = '';
foreach ($articles as $article) {
$html .= '<div class="article-item">';
$html .= '<h4><a href="' . htmlspecialchars($article['link']) . '" target="_blank">' .
htmlspecialchars($article['article_title']) . '</a></h4>';
$html .= '<div class="article-meta">';
if (!empty($article['author'])) {
$html .= '<span class="meta-item"><strong>作者:</strong>' . htmlspecialchars($article['author']) . '</span>';
}
$html .= '<span class="meta-item"><strong>上传时间:</strong>' . formatDate($article['upload_time']) . '</span>';
if (!empty($article['source'])) {
$html .= '<span class="meta-item"><strong>来源:</strong>' . htmlspecialchars($article['source']) . '</span>';
}
if (!empty($article['category'])) {
$html .= '<span class="meta-item"><strong>类型:</strong>' . htmlspecialchars($article['category']) . '</span>';
}
$html .= '</div>';
if (!empty($article['description'])) {
$html .= '<div class="article-desc">' . htmlspecialchars(truncateText($article['description'], 300)) . '</div>';
}
$html .= '<hr class="article-divider">';
$html .= '</div>';
}
return $html;
}
/**
* 渲染百度新闻HTML
*/
function renderBaiduNews($articles) {
if (empty($articles)) {
return '<div class="error-message"><p>❌ 暂无百度新闻数据</p></div>';
}
$html = '';
foreach ($articles as $article) {
$html .= '<div class="article-item">';
$html .= '<h4><a href="' . htmlspecialchars($article['link']) . '" target="_blank">' .
htmlspecialchars($article['article_title']) . '</a></h4>';
$html .= '<div class="article-meta">';
$html .= '<span class="meta-item"><strong>上传时间:</strong>' . formatDate($article['upload_time']) . '</span>';
if (!empty($article['source'])) {
$html .= '<span class="meta-item"><strong>来源:</strong>' . htmlspecialchars($article['source']) . '</span>';
}
if (!empty($article['keyword'])) {
$html .= '<span class="meta-item"><strong>关键词:</strong>' . htmlspecialchars($article['keyword']) . '</span>';
}
$html .= '</div>';
if (!empty($article['description'])) {
$html .= '<div class="article-desc">' . htmlspecialchars(truncateText($article['description'], 300)) . '</div>';
}
$html .= '<hr class="article-divider">';
$html .= '</div>';
}
return $html;
}
/**
* 渲染GitHub动态HTML根据source字段区分四种情况
*/
function renderGithubNews($articles) {
if (empty($articles)) {
return '<div class="error-message"><p>❌ 暂无GitHub动态数据</p></div>';
}
$html = '';
foreach ($articles as $article) {
$html .= '<div class="article-item">';
// 获取source字段
$source = isset($article['source']) ? trim($article['source']) : '';
$title = htmlspecialchars($article['article_title']);
$link = htmlspecialchars($article['link']);
// 根据source值判断显示格式
if ($source === 'New project') {
$keyword = !empty($article['keyword']) ? '【' . htmlspecialchars($article['keyword']) . '】' : '';
$html .= '<h4>关键词' . $keyword . '发现新项目:<a href="' . $link . '" target="_blank">' . $title . '</a></h4>';
if (!empty($article['description'])) {
$html .= '<div class="article-meta"><span class="meta-item"><strong>项目描述:</strong>' . htmlspecialchars(truncateText($article['description'], 300)) . '</span></div>';
}
$html .= '<div class="article-meta">';
$html .= '<span class="meta-item"><strong>上传时间:</strong>' . formatDate($article['upload_time']) . '</span>';
if (!empty($article['language'])) {
$html .= '<span class="meta-item"><strong>开发语言:</strong>' . htmlspecialchars($article['language']) . '</span>';
}
if (!empty($article['author'])) {
$html .= '<span class="meta-item"><strong>作者:</strong>' . htmlspecialchars($article['author']) . '</span>';
}
$html .= '</div>';
} elseif ($source === 'Project update') {
$html .= '<h4>项目 <a href="' . $link . '" target="_blank">' . $title . '</a> 存在更新!!!</h4>';
$html .= '<div class="article-meta">';
$html .= '<span class="meta-item"><strong>更新时间:</strong>' . formatDate($article['upload_time']) . '</span>';
if (!empty($article['author'])) {
$html .= '<span class="meta-item"><strong>提交者:</strong>' . htmlspecialchars($article['author']) . '</span>';
}
$html .= '</div>';
if (!empty($article['description'])) {
$html .= '<div class="article-meta"><span class="meta-item"><strong>更新描述:</strong>' . htmlspecialchars(truncateText($article['description'], 300)) . '</span></div>';
}
if (!empty($article['keyword'])) {
$html .= '<div class="article-meta"><span class="meta-item"><a href="' . htmlspecialchars($article['keyword']) . '" target="_blank">点此查看提交详情</a></span></div>';
}
} elseif ($source === 'New tool') {
$author = !empty($article['author']) ? '【' . htmlspecialchars($article['author']) . '】' : '【未知作者】';
$html .= '<h4>大佬' . $author . '上传了一个新工具:<a href="' . $link . '" target="_blank">' . $title . '</a></h4>';
if (!empty($article['description'])) {
$html .= '<div class="article-meta"><span class="meta-item"><strong>项目描述:</strong>' . htmlspecialchars(truncateText($article['description'], 300)) . '</span></div>';
}
$html .= '<div class="article-meta"><span class="meta-item"><strong>上传时间:</strong>' . formatDate($article['upload_time']) . '</span></div>';
} elseif ($source === 'New version') {
$author = !empty($article['author']) ? '【' . htmlspecialchars($article['author']) . '】' : '【未知作者】';
$html .= '<h4>' . $author . '为 <a href="' . $link . '" target="_blank">' . $title . '</a> 发布了新版本,请及时查收!</h4>';
$html .= '<div class="article-meta"><span class="meta-item"><strong>发布时间:</strong>' . formatDate($article['upload_time']) . '</span></div>';
} else {
// 默认格式
$html .= '<h4><a href="' . $link . '" target="_blank">' . $title . '</a></h4>';
$html .= '<div class="article-meta">';
if (!empty($article['author'])) {
$html .= '<span class="meta-item"><strong>作者:</strong>' . htmlspecialchars($article['author']) . '</span>';
}
$html .= '<span class="meta-item"><strong>更新时间:</strong>' . formatDate($article['upload_time']) . '</span>';
if (!empty($article['keyword'])) {
$html .= '<span class="meta-item"><strong>关键词:</strong>' . htmlspecialchars($article['keyword']) . '</span>';
}
if (!empty($article['language'])) {
$html .= '<span class="meta-item"><strong>语言:</strong>' . htmlspecialchars($article['language']) . '</span>';
}
if (!empty($source)) {
$html .= '<span class="meta-item"><strong>类型:</strong>' . htmlspecialchars($source) . '</span>';
}
$html .= '</div>';
if (!empty($article['description'])) {
$html .= '<div class="article-desc">' . htmlspecialchars(truncateText($article['description'], 300)) . '</div>';
}
}
$html .= '<hr class="article-divider">';
$html .= '</div>';
}
return $html;
}
/**
* 渲染微信文章HTML搜狗微信
*/
function renderWxNews($articles) {
if (empty($articles)) {
return '<div class="error-message"><p>❌ 暂无微信文章数据</p></div>';
}
$html = '';
foreach ($articles as $article) {
$html .= '<div class="article-item">';
$keyword = isset($article['keyword']) ? trim($article['keyword']) : '';
$title = htmlspecialchars($article['article_title']);
$link = htmlspecialchars($article['link']);
if (!empty($keyword)) {
$html .= '<h4>关键词【' . htmlspecialchars($keyword) . '】发现新文章:<a href="' . $link . '" target="_blank">' . $title . '</a></h4>';
} else {
$html .= '<h4><a href="' . $link . '" target="_blank">' . $title . '</a></h4>';
}
$html .= '<div class="article-meta">';
if (!empty($article['description'])) {
$html .= '<span class="meta-item"><strong>描述:</strong>' . htmlspecialchars(truncateText($article['description'], 300)) . '</span>';
}
$html .= '<span class="meta-item"><strong>上传时间:</strong>' . formatDate($article['upload_time']) . '</span>';
if (!empty($article['author'])) {
$html .= '<span class="meta-item"><strong>作者:</strong>' . htmlspecialchars($article['author']) . '</span>';
}
$html .= '</div>';
$html .= '<hr class="article-divider">';
$html .= '</div>';
}
return $html;
}
/**
* 渲染其他RSS源HTMLuni_rss
*/
function renderOtherRss($articles) {
if (empty($articles)) {
return '<div class="error-message"><p>❌ 暂无其他RSS源数据</p></div>';
}
$html = '';
foreach ($articles as $article) {
$html .= '<div class="article-item">';
$source = isset($article['source']) ? trim($article['source']) : '';
$title = htmlspecialchars($article['article_title']);
$link = htmlspecialchars($article['link']);
if (!empty($source)) {
$html .= '<h4>【' . htmlspecialchars($source) . '】RSS源发现新文章<a href="' . $link . '" target="_blank">' . $title . '</a></h4>';
} else {
$html .= '<h4><a href="' . $link . '" target="_blank">' . $title . '</a></h4>';
}
$html .= '<div class="article-meta">';
if (!empty($article['description'])) {
$html .= '<span class="meta-item"><strong>描述:</strong>' . htmlspecialchars(truncateText($article['description'], 300)) . '</span>';
}
$html .= '<span class="meta-item"><strong>上传时间:</strong>' . formatDate($article['upload_time']) . '</span>';
if (!empty($article['author'])) {
$html .= '<span class="meta-item"><strong>作者:</strong>' . htmlspecialchars($article['author']) . '</span>';
}
$html .= '</div>';
$html .= '<hr class="article-divider">';
$html .= '</div>';
}
return $html;
}
// 处理AJAX请求
if ($action === 'ajax') {
header('Content-Type: application/json; charset=utf-8');
$type = isset($_GET['type']) ? $_GET['type'] : 'sec-news';
$dateFilter = isset($_GET['date']) ? $_GET['date'] : '';
$limit = isset($_GET['limit']) ? intval($_GET['limit']) : 50;
$db = getDatabaseConnection($dbPath);
if (!$db) {
echo json_encode(['success' => false, 'message' => '数据库连接失败']);
exit;
}
$data = [];
$title = '';
switch ($type) {
case 'sec-news':
$data = getSecNews($db, $dateFilter, $limit);
$title = '🔒 安全新闻';
break;
case 'tech-passage':
$data = getTechPassage($db, $dateFilter, $limit);
$title = '💻 技术文章';
break;
case 'baidu-news':
$data = getBaiduNews($db, $dateFilter, $limit);
$title = '📊 百度新闻';
break;
case 'github-news':
$data = getGithubNews($db, $dateFilter, $limit);
$title = '🐙 GitHub动态';
break;
case 'wx-news':
$data = getWxNews($db, $dateFilter, $limit);
$title = '💬 微信文章';
break;
case 'other-rss':
$data = getOtherRss($db, $dateFilter, $limit);
$title = '📡 其他来源';
break;
default:
echo json_encode(['success' => false, 'message' => '无效的类型']);
exit;
}
echo json_encode([
'success' => true,
'title' => $title,
'count' => count($data),
'data' => $data
]);
exit;
}
// 获取初始数据(默认显示安全新闻)
$db = getDatabaseConnection($dbPath);
$initialData = [];
$initialTitle = '🔒 安全新闻';
if ($db) {
$initialData = getSecNews($db, $dateFilter, $limit);
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>资讯推送Web端</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes">
<link rel="shortcut icon" href="./static/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/layui-src/dist/css/layui.css">
<style>
* {
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 20px;
background-color: #f8f9fa;
line-height: 1.6;
}
.layui-container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 20px;
}
h1 {
color: #333;
font-size: clamp(1.3em, 4vw, 1.8em);
text-align: center;
margin-bottom: 20px;
border-bottom: 2px solid #009688;
padding-bottom: 10px;
}
#content-area {
padding: 15px;
background-color: #fafafa;
border-radius: 4px;
min-height: 400px;
}
#button-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 10px;
margin: 15px 0;
max-width: 900px;
margin-left: auto;
margin-right: auto;
}
#button-container .layui-btn {
margin: 0;
transition: all 0.3s ease;
min-width: 120px;
width: 100%;
}
#sec-news-btn { background-color: #FF5722; }
#tech-passage-btn { background-color: #2196F3; }
#baidu-news-btn { background-color: #2F4F4F; }
#github-news-btn { background-color: #333; }
#wx-news-btn { background-color: #07C160; }
#other-rss-btn { background-color: #9C27B0; }
#button-container .layui-btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
.layui-colla-item {
margin-bottom: 15px;
border-radius: 4px;
overflow: hidden;
}
.layui-colla-title {
background-color: #f2f2f2;
font-weight: 600;
}
.info-text {
text-align: center;
color: #666;
font-size: clamp(0.85em, 2.5vw, 0.9em);
margin: 10px 0 20px;
padding: 10px;
background-color: #f0f8ff;
border-radius: 4px;
}
#back-to-top {
display: none;
position: fixed;
bottom: 20px;
right: 20px;
z-index: 1000;
font-size: 14px;
border: none;
outline: none;
background-color: #009688;
color: white;
cursor: pointer;
padding: 12px 15px;
border-radius: 50%;
box-shadow: 0 2px 10px rgba(0,0,0,0.3);
transition: all 0.3s;
}
#back-to-top:hover {
background-color: #007a6e;
transform: scale(1.1);
}
.article-item {
margin-bottom: 20px;
padding: 15px;
background: white;
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
transition: box-shadow 0.3s;
}
.article-item:hover {
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
.article-item h4 {
margin: 0 0 10px 0;
color: #333;
font-size: clamp(1em, 3vw, 1.1em);
word-wrap: break-word;
overflow-wrap: break-word;
}
.article-item h4 a {
color: #009688;
text-decoration: none;
}
.article-item h4 a:hover {
text-decoration: underline;
}
.article-meta {
margin-bottom: 10px;
font-size: clamp(0.8em, 2vw, 0.9em);
color: #666;
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.meta-item {
display: inline-block;
}
.article-desc {
color: #555;
line-height: 1.8;
margin-top: 10px;
font-size: clamp(0.85em, 2.5vw, 0.95em);
word-wrap: break-word;
overflow-wrap: break-word;
}
.article-divider {
border: none;
border-top: 1px solid #e0e0e0;
margin-top: 15px;
}
.error-message {
text-align: center;
padding: 40px;
color: #ff6b6b;
font-size: 1.1em;
}
.loading {
text-align: center;
padding: 50px;
}
.filter-container {
margin: 15px 0;
padding: 15px;
background-color: #f9f9f9;
border-radius: 4px;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 10px;
}
.filter-container label {
font-weight: 600;
white-space: nowrap;
}
.filter-container input[type="date"] {
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
flex: 1;
min-width: 150px;
max-width: 200px;
}
.filter-container input[type="number"] {
width: 80px;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
}
.filter-container button {
min-width: 100px;
}
@media only screen and (max-width: 1024px) {
body {
padding: 15px;
}
.layui-container {
padding: 18px;
}
#button-container {
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
}
}
@media only screen and (max-width: 768px) {
body {
margin: 0;
padding: 10px;
}
.layui-container {
padding: 12px;
border-radius: 6px;
}
h1 {
margin-bottom: 15px;
padding-bottom: 8px;
}
#content-area {
padding: 10px;
min-height: 300px;
}
#button-container {
grid-template-columns: repeat(2, 1fr);
gap: 8px;
}
#button-container .layui-btn {
font-size: 0.9em;
padding: 8px 12px;
}
.filter-container {
flex-direction: column;
align-items: stretch;
padding: 12px;
}
.filter-container label {
margin-bottom: 5px;
}
.filter-container input[type="date"],
.filter-container input[type="number"] {
width: 100%;
max-width: none;
}
.filter-container button {
width: 100%;
}
.article-item {
padding: 12px;
margin-bottom: 15px;
}
.article-meta {
flex-direction: column;
gap: 5px;
}
#back-to-top {
font-size: 12px;
padding: 10px 12px;
bottom: 15px;
right: 15px;
}
}
@media only screen and (max-width: 480px) {
body {
padding: 8px;
}
.layui-container {
padding: 10px;
}
h1 {
font-size: 1.2em;
}
#button-container {
grid-template-columns: 1fr;
}
.article-item h4 {
font-size: 0.95em;
}
.article-desc {
font-size: 0.85em;
}
}
@media only screen and (max-height: 600px) and (orientation: landscape) {
.layui-container {
padding: 10px;
}
h1 {
margin-bottom: 10px;
font-size: 1.3em;
}
.info-text {
margin: 8px 0 15px;
padding: 8px;
}
#content-area {
min-height: 250px;
}
}
@media only screen and (min-width: 1400px) {
.layui-container {
max-width: 1400px;
}
#button-container {
max-width: 1000px;
}
}
@media print {
#button-container,
.filter-container,
#back-to-top {
display: none !important;
}
.layui-container {
box-shadow: none;
padding: 0;
}
.article-item {
break-inside: avoid;
box-shadow: none;
border: 1px solid #ddd;
}
}
html {
scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
</style>
</head>
<body>
<div class="layui-container">
<h1 class="layui-title" id="page-title"><?php echo htmlspecialchars($initialTitle); ?></h1>
<div class="layui-collapse" lay-accordion>
<div class="layui-colla-item">
<h2 class="layui-colla-title">📋 选择资讯类型</h2>
<div class="layui-colla-content layui-show">
<div id="button-container">
<button id="sec-news-btn" class="layui-btn layui-btn-sm" data-type="sec-news">🔒 安全新闻</button>
<button id="tech-passage-btn" class="layui-btn layui-btn-sm" data-type="tech-passage">💻 技术文章</button>
<button id="baidu-news-btn" class="layui-btn layui-btn-sm" data-type="baidu-news">📊 百度新闻</button>
<button id="github-news-btn" class="layui-btn layui-btn-sm" data-type="github-news">🐙 GitHub动态</button>
<button id="wx-news-btn" class="layui-btn layui-btn-sm" data-type="wx-news">💬 微信文章</button>
<button id="other-rss-btn" class="layui-btn layui-btn-sm" data-type="other-rss">📡 其他来源</button>
</div>
<div class="filter-container">
<label for="date-filter">📅 按日期筛选:</label>
<input type="date" id="date-filter" name="date">
<label for="limit-filter">数量:</label>
<input type="number" id="limit-filter" name="limit" value="<?php echo $limit; ?>" min="1" max="200">
<button id="apply-filter" class="layui-btn layui-btn-sm">应用筛选</button>
<button id="clear-filter" class="layui-btn layui-btn-sm layui-btn-primary">清除筛选</button>
</div>
</div>
</div>
</div>
<div id="content-area">
<?php echo renderSecNews($initialData); ?>
</div>
</div>
<button id="back-to-top" title="返回顶部">
<i class="layui-icon layui-icon-top"></i> 返回顶部
</button>
<script src="https://cdn.jsdelivr.net/npm/layui-src/dist/layui.js"></script>
<script>
layui.use(['layer', 'element'], function(){
var layer = layui.layer;
var element = layui.element;
});
var currentType = 'sec-news';
var currentDateFilter = '';
var currentLimit = <?php echo $limit; ?>;
function fetchContent(type, dateFilter, limit) {
var url = '?action=ajax&type=' + type;
if (dateFilter) {
url += '&date=' + dateFilter;
}
if (limit) {
url += '&limit=' + limit;
}
document.querySelectorAll('#button-container .layui-btn').forEach(function(btn) {
btn.disabled = (btn.dataset.type === type);
btn.style.opacity = (btn.dataset.type === type) ? '0.7' : '1';
});
document.getElementById('content-area').innerHTML =
'<div class="loading"><i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i> 加载中...</div>';
fetch(url)
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('page-title').innerText = data.title;
var html = '';
if (data.data && data.data.length > 0) {
data.data.forEach(function(article) {
html += '<div class="article-item">';
if (currentType === 'github-news') {
var source = (article.source || '').trim();
var title = escapeHtml(article.article_title);
var link = escapeHtml(article.link);
if (source === 'New project') {
var keyword = article.keyword ? '【' + escapeHtml(article.keyword) + '】' : '';
html += '<h4>关键词' + keyword + '发现新项目:<a href="' + link + '" target="_blank">' + title + '</a></h4>';
if (article.description) {
html += '<div class="article-meta"><span class="meta-item"><strong>项目描述:</strong>' + escapeHtml(truncateText(article.description, 300)) + '</span></div>';
}
html += '<div class="article-meta">';
html += '<span class="meta-item"><strong>上传时间:</strong>' + formatDate(article.upload_time) + '</span>';
if (article.language) {
html += '<span class="meta-item"><strong>开发语言:</strong>' + escapeHtml(article.language) + '</span>';
}
if (article.author) {
html += '<span class="meta-item"><strong>作者:</strong>' + escapeHtml(article.author) + '</span>';
}
html += '</div>';
} else if (source === 'Project update') {
html += '<h4>项目 <a href="' + link + '" target="_blank">' + title + '</a> 存在更新!!!</h4>';
html += '<div class="article-meta">';
html += '<span class="meta-item"><strong>更新时间:</strong>' + formatDate(article.upload_time) + '</span>';
if (article.author) {
html += '<span class="meta-item"><strong>提交者:</strong>' + escapeHtml(article.author) + '</span>';
}
html += '</div>';
if (article.description) {
html += '<div class="article-meta"><span class="meta-item"><strong>更新描述:</strong>' + escapeHtml(truncateText(article.description, 300)) + '</span></div>';
}
if (article.keyword) {
html += '<div class="article-meta"><span class="meta-item"><a href="' + escapeHtml(article.keyword) + '" target="_blank">点此查看提交详情</a></span></div>';
}
} else if (source === 'New tool') {
var author = article.author ? '【' + escapeHtml(article.author) + '】' : '【未知作者】';
html += '<h4>大佬' + author + '上传了一个新工具:<a href="' + link + '" target="_blank">' + title + '</a></h4>';
if (article.description) {
html += '<div class="article-meta"><span class="meta-item"><strong>项目描述:</strong>' + escapeHtml(truncateText(article.description, 300)) + '</span></div>';
}
html += '<div class="article-meta"><span class="meta-item"><strong>上传时间:</strong>' + formatDate(article.upload_time) + '</span></div>';
} else if (source === 'New version') {
var author = article.author ? '【' + escapeHtml(article.author) + '】' : '【未知作者】';
html += '<h4>' + author + '为 <a href="' + link + '" target="_blank">' + title + '</a> 发布了新版本,请及时查收!</h4>';
html += '<div class="article-meta"><span class="meta-item"><strong>发布时间:</strong>' + formatDate(article.upload_time) + '</span></div>';
} else {
html += '<h4><a href="' + link + '" target="_blank">' + title + '</a></h4>';
html += '<div class="article-meta">';
if (article.author) {
html += '<span class="meta-item"><strong>作者:</strong>' + escapeHtml(article.author) + '</span>';
}
html += '<span class="meta-item"><strong>更新时间:</strong>' + formatDate(article.upload_time) + '</span>';
if (article.keyword) {
html += '<span class="meta-item"><strong>关键词:</strong>' + escapeHtml(article.keyword) + '</span>';
}
if (article.language) {
html += '<span class="meta-item"><strong>语言:</strong>' + escapeHtml(article.language) + '</span>';
}
if (source) {
html += '<span class="meta-item"><strong>类型:</strong>' + escapeHtml(source) + '</span>';
}
html += '</div>';
if (article.description) {
html += '<div class="article-desc">' + escapeHtml(truncateText(article.description, 300)) + '</div>';
}
}
} else if (currentType === 'wx-news') {
var keyword = (article.keyword || '').trim();
var title = escapeHtml(article.article_title);
var link = escapeHtml(article.link);
if (keyword) {
html += '<h4>关键词【' + escapeHtml(keyword) + '】发现新文章:<a href="' + link + '" target="_blank">' + title + '</a></h4>';
} else {
html += '<h4><a href="' + link + '" target="_blank">' + title + '</a></h4>';
}
html += '<div class="article-meta">';
if (article.description) {
html += '<span class="meta-item"><strong>描述:</strong>' + escapeHtml(truncateText(article.description, 300)) + '</span>';
}
html += '<span class="meta-item"><strong>上传时间:</strong>' + formatDate(article.upload_time) + '</span>';
if (article.author) {
html += '<span class="meta-item"><strong>作者:</strong>' + escapeHtml(article.author) + '</span>';
}
html += '</div>';
} else if (currentType === 'other-rss') {
var source = (article.source || '').trim();
var title = escapeHtml(article.article_title);
var link = escapeHtml(article.link);
if (source) {
html += '<h4>【' + escapeHtml(source) + '】RSS源发现新文章<a href="' + link + '" target="_blank">' + title + '</a></h4>';
} else {
html += '<h4><a href="' + link + '" target="_blank">' + title + '</a></h4>';
}
html += '<div class="article-meta">';
if (article.description) {
html += '<span class="meta-item"><strong>描述:</strong>' + escapeHtml(truncateText(article.description, 300)) + '</span>';
}
html += '<span class="meta-item"><strong>上传时间:</strong>' + formatDate(article.upload_time) + '</span>';
if (article.author) {
html += '<span class="meta-item"><strong>作者:</strong>' + escapeHtml(article.author) + '</span>';
}
html += '</div>';
} else {
html += '<h4><a href="' + escapeHtml(article.link) + '" target="_blank">' +
escapeHtml(article.article_title) + '</a></h4>';
html += '<div class="article-meta">';
if (article.author) {
html += '<span class="meta-item"><strong>作者:</strong>' + escapeHtml(article.author) + '</span>';
}
if (article.upload_time) {
html += '<span class="meta-item"><strong>时间:</strong>' + formatDate(article.upload_time) + '</span>';
}
if (article.source) {
html += '<span class="meta-item"><strong>来源:</strong>' + escapeHtml(article.source) + '</span>';
}
if (article.category) {
html += '<span class="meta-item"><strong>类型:</strong>' + escapeHtml(article.category) + '</span>';
}
if (article.keyword) {
html += '<span class="meta-item"><strong>关键词:</strong>' + escapeHtml(article.keyword) + '</span>';
}
if (article.language) {
html += '<span class="meta-item"><strong>语言:</strong>' + escapeHtml(article.language) + '</span>';
}
html += '</div>';
if (article.description) {
html += '<div class="article-desc">' + escapeHtml(truncateText(article.description, 300)) + '</div>';
}
}
html += '<hr class="article-divider">';
html += '</div>';
});
} else {
html = '<div class="error-message"><p>❌ 暂无数据</p></div>';
}
document.getElementById('content-area').innerHTML = html;
} else {
document.getElementById('content-area').innerHTML =
'<div class="error-message"><p>❌ ' + escapeHtml(data.message || '加载失败') + '</p></div>';
}
})
.catch(error => {
console.error('获取数据失败:', error);
document.getElementById('content-area').innerHTML =
'<div class="error-message"><p>❌ 无法加载数据!</p></div>';
});
}
function escapeHtml(text) {
if (!text) return '';
var div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function formatDate(dateStr) {
if (!dateStr) return '未知时间';
var date = new Date(dateStr);
if (isNaN(date.getTime())) return dateStr;
var year = date.getFullYear();
var month = String(date.getMonth() + 1).padStart(2, '0');
var day = String(date.getDate()).padStart(2, '0');
var hours = String(date.getHours()).padStart(2, '0');
var minutes = String(date.getMinutes()).padStart(2, '0');
var seconds = String(date.getSeconds()).padStart(2, '0');
return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds;
}
function truncateText(text, maxLength) {
if (!text) return '';
if (text.length <= maxLength) return text;
return text.substring(0, maxLength) + '...';
}
document.querySelectorAll('#button-container .layui-btn').forEach(function(btn) {
btn.addEventListener('click', function() {
currentType = this.dataset.type;
fetchContent(currentType, currentDateFilter, currentLimit);
});
});
document.getElementById('apply-filter').addEventListener('click', function() {
var dateValue = document.getElementById('date-filter').value;
var limitValue = parseInt(document.getElementById('limit-filter').value) || 50;
// if (limitValue < 1 || limitValue > 200) {
// limitValue = 50;
// document.getElementById('limit-filter').value = 50;
// }
if (limitValue < 1 || limitValue > 200) {
layer.msg('数量必须在1到200之间', {icon: 2, time: 2000});
return;
}
currentDateFilter = dateValue;
currentLimit = limitValue;
fetchContent(currentType, currentDateFilter, currentLimit);
});
document.getElementById('clear-filter').addEventListener('click', function() {
document.getElementById('date-filter').value = '';
document.getElementById('limit-filter').value = 50;
currentDateFilter = '';
currentLimit = 50;
fetchContent(currentType, currentDateFilter, currentLimit);
});
function scrollFunction() {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var backToTopBtn = document.getElementById("back-to-top");
if (scrollTop > 300) {
backToTopBtn.style.display = "block";
} else {
backToTopBtn.style.display = "none";
}
}
window.onscroll = function() {
scrollFunction();
};
document.getElementById("back-to-top").addEventListener("click", function() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
</script>
</body>
</html>