Files
DevelopmentHistory/Plugin.php
2026-02-23 17:23:48 +08:00

1371 lines
45 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
/**
* 发展历史插件
*
* @package DevelopmentHistory
* @author 石头厝
* @version 1.1.0
* @link https://www.shitoucuo.com/
*/
class DevelopmentHistory_Plugin implements Typecho_Plugin_Interface
{
/**
* 激活插件
*
* @return string
* @throws Typecho_Plugin_Exception
*/
public static function activate()
{
// 创建数据表
$db = Typecho_Db::get();
$prefix = $db->getPrefix();
$tableName = $prefix . 'development_history';
// 检查主表是否存在
$tables = $db->fetchAll($db->query("SHOW TABLES LIKE '{$tableName}'"));
if (empty($tables)) {
// 表不存在创建新表不带title字段
$sql = "CREATE TABLE `{$tableName}` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`content` TEXT NOT NULL COMMENT '内容',
`event_date` DATE NOT NULL COMMENT '事件日期',
`post_cids` VARCHAR(255) DEFAULT '' COMMENT '关联文章CID多个用逗号分隔',
`created` DATETIME NOT NULL COMMENT '创建时间',
`modified` DATETIME NOT NULL COMMENT '修改时间',
`status` TINYINT(1) DEFAULT 1 COMMENT '状态1正常'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发展历史记录表';";
try {
$db->query($sql);
} catch (Typecho_Db_Exception $e) {
throw new Typecho_Plugin_Exception('创建数据表失败: ' . $e->getMessage());
}
} else {
// 表已存在检查是否有title字段如果有则删除
$columns = $db->fetchAll($db->query("SHOW COLUMNS FROM `{$tableName}`"));
$hasTitle = false;
foreach ($columns as $column) {
if ($column['Field'] == 'title') {
$hasTitle = true;
break;
}
}
if ($hasTitle) {
// 删除title字段
try {
$db->query("ALTER TABLE `{$tableName}` DROP COLUMN `title`");
} catch (Typecho_Db_Exception $e) {
// 如果删除字段失败,可能是表结构问题,继续执行
}
}
// 检查是否有post_cids字段如果没有则添加
$hasPostCids = false;
foreach ($columns as $column) {
if ($column['Field'] == 'post_cids') {
$hasPostCids = true;
break;
}
}
if (!$hasPostCids) {
try {
$db->query("ALTER TABLE `{$tableName}` ADD `post_cids` VARCHAR(255) DEFAULT '' COMMENT '关联文章CID多个用逗号分隔' AFTER `event_date`");
} catch (Typecho_Db_Exception $e) {
// 如果添加字段失败,继续执行
}
}
}
// 添加管理菜单
Helper::addPanel(3, 'DevelopmentHistory/manage-panel.php', '发展历史', '发展历史管理', 'administrator');
return _t('发展历史插件已激活,请到插件设置中进行配置');
}
/**
* 禁用插件
*
* @return string
*/
public static function deactivate()
{
Helper::removePanel(3, 'DevelopmentHistory/manage-panel.php');
return _t('发展历史插件已禁用');
}
/**
* 插件配置面板
*
* @param Typecho_Widget_Helper_Form $form
*/
public static function config(Typecho_Widget_Helper_Form $form)
{
echo '<h2>发展历史插件配置</h2>';
echo '<p>版本1.1.0 | 作者:您的名字 | <a href="https://您的网站.com" target="_blank">访问官网</a></p>';
echo '<hr>';
// 每页显示数量
$perPage = new Typecho_Widget_Helper_Form_Element_Text(
'perPage',
NULL,
'10',
_t('后台每页显示数量'),
_t('后台管理页面每页显示的历史记录数量默认10')
);
$perPage->input->setAttribute('class', 'mini');
$form->addInput($perPage->addRule('isInteger', _t('请输入整数')));
// 前端每页显示数量
$frontPerPage = new Typecho_Widget_Helper_Form_Element_Text(
'frontPerPage',
NULL,
'20',
_t('主题调用每页显示数量'),
_t('在主题中调用时每页显示的历史记录数量默认20')
);
$frontPerPage->input->setAttribute('class', 'mini');
$form->addInput($frontPerPage->addRule('isInteger', _t('请输入整数')));
// 时间格式
$dateFormat = new Typecho_Widget_Helper_Form_Element_Text(
'dateFormat',
NULL,
'Y.m.d',
_t('日期显示格式'),
_t('PHP日期格式Y.m.d、Y-m-d、Y年m月d日等')
);
$form->addInput($dateFormat);
// 是否显示关联文章
$showRelatedPosts = new Typecho_Widget_Helper_Form_Element_Radio(
'showRelatedPosts',
array(
'1' => _t('显示'),
'0' => _t('不显示')
),
'1',
_t('显示关联文章'),
_t('是否在历史记录下方显示关联的文章链接')
);
$form->addInput($showRelatedPosts);
// 关联文章标题
$relatedPostsTitle = new Typecho_Widget_Helper_Form_Element_Text(
'relatedPostsTitle',
NULL,
'相关文章',
_t('关联文章标题'),
_t('关联文章部分的标题文本')
);
$form->addInput($relatedPostsTitle);
}
/**
* 个人用户配置
*
* @param Typecho_Widget_Helper_Form $form
*/
public static function personalConfig(Typecho_Widget_Helper_Form $form)
{
// 个人配置(如果需要)
}
/**
* 插件配置面板
*
* @param string $panel
*/
public static function configPanel($panel)
{
// 配置面板
}
/**
* 渲染方法(用于在主题模板中调用)
*/
public static function render()
{
// 获取配置
$options = Typecho_Widget::widget('Widget_Options');
$config = $options->plugin('DevelopmentHistory');
// 数据库操作
$db = Typecho_Db::get();
$prefix = $db->getPrefix();
// 获取当前页面文件名
$currentFile = basename($_SERVER['PHP_SELF']);
// 统一使用 'y' 参数
$selectedYear = 0;
$currentPage = 1;
$searchKeyword = '';
// 读取 'y' 参数
if (isset($_GET['y']) && is_numeric($_GET['y'])) {
$selectedYear = intval($_GET['y']);
}
// 保持向后兼容:如果旧链接使用了 'year' 参数,也支持
if ($selectedYear == 0 && isset($_GET['year']) && is_numeric($_GET['year'])) {
$selectedYear = intval($_GET['year']);
}
if (isset($_GET['page']) && is_numeric($_GET['page']) && $_GET['page'] > 0) {
$currentPage = intval($_GET['page']);
}
// 读取搜索关键词参数 - 正确处理URL编码
if (isset($_GET['search']) && !empty($_GET['search'])) {
$searchKeyword = trim($_GET['search']);
// 解码URL编码的参数
$searchKeyword = urldecode($searchKeyword);
}
// URL构建函数 - 正确处理编码
function buildUrl($year = 0, $page = 1, $search = '') {
$currentFile = basename($_SERVER['PHP_SELF']);
$params = array();
if ($page > 1) {
$params['page'] = $page;
}
if ($year > 0) {
$params['y'] = $year;
}
if (!empty($search)) {
// 这里使用原始搜索词http_build_query会自动编码
$params['search'] = $search;
}
if (empty($params)) {
return $currentFile;
}
return $currentFile . '?' . http_build_query($params);
}
// 年份筛选URL
function buildYearUrl($year, $search = '') {
return buildUrl($year, 1, $search);
}
$perPage = isset($config->frontPerPage) ? intval($config->frontPerPage) : 20;
$offset = ($currentPage - 1) * $perPage;
// 构建查询条件
$where = 'status = ?';
$whereParams = array(1);
if ($selectedYear > 0) {
$where .= ' AND YEAR(event_date) = ?';
$whereParams[] = $selectedYear;
}
if (!empty($searchKeyword)) {
$where .= ' AND content LIKE ?';
$whereParams[] = '%' . $searchKeyword . '%';
}
// 查询数据
$query = $db->select()
->from($prefix . 'development_history')
->where($where, ...$whereParams)
->order('id', Typecho_Db::SORT_DESC)
->limit($perPage)
->offset($offset);
$histories = $db->fetchAll($query);
// 为每条记录获取关联的文章信息 - 修复URL生成
foreach ($histories as &$history) {
if (!empty($history['post_cids'])) {
$cids = array_filter(array_map('trim', explode(',', $history['post_cids'])));
$posts = array();
foreach ($cids as $cid) {
if (is_numeric($cid)) {
$postQuery = $db->select('cid, title, slug, created')
->from($prefix . 'contents')
->where('cid = ?', intval($cid))
->where('type = ?', 'post')
->where('status = ?', 'publish')
->limit(1);
$post = $db->fetchRow($postQuery);
if ($post) {
// 修复直接使用slug变量值
if (!empty($post['slug'])) {
$post['url'] = Typecho_Common::url($post['slug'] . '.html', $options->index);
} else {
$post['url'] = Typecho_Common::url('archives/' . $post['cid'], $options->index);
}
$posts[] = $post;
}
}
}
$history['posts'] = $posts;
} else {
$history['posts'] = array();
}
}
// 获取总数
$countQuery = $db->select('COUNT(*) as count')
->from($prefix . 'development_history')
->where($where, ...$whereParams);
$totalResult = $db->fetchRow($countQuery);
$total = $totalResult['count'];
$totalPages = ceil($total / $perPage);
// 获取所有年份及记录数(考虑搜索条件)
$yearsWhere = 'status = ?';
$yearsParams = array(1);
if (!empty($searchKeyword)) {
$yearsWhere .= ' AND content LIKE ?';
$yearsParams[] = '%' . $searchKeyword . '%';
}
$yearsQuery = $db->select('YEAR(event_date) as year, COUNT(*) as count')
->from($prefix . 'development_history')
->where($yearsWhere, ...$yearsParams)
->group('YEAR(event_date)')
->order('year', Typecho_Db::SORT_DESC);
$yearsData = $db->fetchAll($yearsQuery);
// 获取全部记录数(考虑搜索条件)
$totalAllWhere = 'status = ?';
$totalAllParams = array(1);
if (!empty($searchKeyword)) {
$totalAllWhere .= ' AND content LIKE ?';
$totalAllParams[] = '%' . $searchKeyword . '%';
}
$totalAllQuery = $db->select('COUNT(*) as count')
->from($prefix . 'development_history')
->where($totalAllWhere, ...$totalAllParams);
$totalAllResult = $db->fetchRow($totalAllQuery);
$totalAll = $totalAllResult['count'];
// 输出内容
if (empty($histories) && empty($searchKeyword) && $selectedYear == 0) {
echo '<div class="development-history-empty">暂无发展历史记录</div>';
return;
}
?>
<!-- 关联文章样式 -->
<style>
.related-posts {
margin-top: 15px;
padding: 12px 15px;
background: #f8f9fa;
border-radius: 6px;
border-left: 3px solid #007bff;
}
.related-posts-title {
font-size: 13px;
font-weight: 600;
color: #495057;
margin-bottom: 8px;
display: flex;
align-items: center;
gap: 6px;
}
.related-posts ul li{
list-style: none;
}
.related-posts-list {
list-style: none;
padding: 0;
margin: 0;
}
.related-posts ul{
padding-left: 0px!important;
}
.related-post-item {
margin-bottom: 6px;
padding: 6px 10px;
background: white;
border-radius: 4px;
border: 1px solid #dee2e6;
transition: all 0.2s ease;
}
.related-post-item:last-child {
margin-bottom: 0;
}
.related-post-item:hover {
background-color: #e9ecef;
border-color: #ced4da;
}
.related-post-link {
display: flex;
align-items: center;
gap: 8px;
text-decoration: none;
color: #495057;
font-size: 13px;
}
.related-post-link:hover {
color: #007bff;
text-decoration: none;
}
/* 深色模式适配 */
.dark .related-posts {
background: #2d2d2d;
border-left-color: #dc2626;
}
.dark .related-posts-title {
color: #b0b0b0;
}
.dark .related-post-item {
background: #1e1e1e;
border-color: #444;
}
.dark .related-post-item:hover {
background-color: #3d3d3d;
border-color: #555;
}
.dark .related-post-link {
color: #b0b0b0;
}
.dark .related-post-link:hover {
color: #dc2626;
}
.dark .related-post-link:before {
color: #888;
}
</style>
<!-- 搜索框样式 - 同步优化版 -->
<style>
/* 搜索框样式 - 优化版 */
.history-search-box {
margin: 0 auto 20px;
}
.search-form {
display: flex;
flex-direction: column;
gap: 18px;
max-width: 400px;
margin: 0 auto;
}
.search-input-row {
display: flex;
gap: 10px;
width: 100%;
}
.search-input {
flex-grow: 1;
padding: 12px 16px;
border: 1px solid #dee2e6;
border-radius: 6px;
font-size: 15px;
transition: all 0.3s ease;
background: white;
color: #333;
}
.search-input:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
}
.search-input::placeholder {
color: #6c757d;
opacity: 0.8;
}
.search-button-row {
display: flex;
justify-content: center;
gap: 10px;
width: 100%;
}
.search-button {
padding: 8px 30px;
background: linear-gradient(135deg, #007bff, #0056b3);
color: white;
border: none;
border-radius: 10px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
white-space: nowrap;
}
.search-button:hover {
background: linear-gradient(135deg, #0056b3, #004494);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 123, 255, 0.3);
}
.search-button:active {
transform: translateY(0);
box-shadow: 0 1px 2px rgba(0, 123, 255, 0.2);
}
.clear-search-link {
padding: 12px 25px;
background: linear-gradient(135deg, #6c757d, #545b62);
color: white;
text-decoration: none;
border-radius: 6px;
font-size: 15px;
font-weight: 500;
transition: all 0.3s ease;
white-space: nowrap;
box-shadow: 0 2px 4px rgba(108, 117, 125, 0.2);
}
.clear-search-link:hover {
background: linear-gradient(135deg, #545b62, #3d4246);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(108, 117, 125, 0.3);
color: white;
text-decoration: none;
}
.clear-search-link:active {
transform: translateY(0);
box-shadow: 0 1px 2px rgba(108, 117, 125, 0.2);
}
.search-results-info {
margin-top: 15px;
text-align: center;
font-size: 14px;
color: #495057;
padding: 8px 12px;
background: rgba(0, 123, 255, 0.05);
border-radius: 4px;
border-left: 3px solid #007bff;
}
.search-results-info strong {
color: #0056b3;
font-weight: 600;
}
/* 深色模式适配 */
.dark .search-input {
background: #1e1e1e;
color: #000;
border-color: #444;
}
.dark .search-input:focus {
border-color: #dc2626;
box-shadow: 0 0 0 3px rgba(77, 171, 247, 0.1);
}
.dark .search-input::placeholder {
color: #aaa;
}
.dark .search-button {
background: linear-gradient(135deg, #dc2626, #1c7ed6);
}
.dark .search-button:hover {
background: linear-gradient(135deg, #1c7ed6, #1864ab);
}
.dark .clear-search-link {
background: linear-gradient(135deg, #6c757d, #545b62);
box-shadow: 0 2px 4px rgba(108, 117, 125, 0.2);
}
.dark .clear-search-link:hover {
background: linear-gradient(135deg, #545b62, #3d4246);
box-shadow: 0 4px 8px rgba(108, 117, 125, 0.3);
}
.dark .search-results-info {
color: #e0e0e0;
background: rgba(77, 171, 247, 0.05);
border-left-color: #dc2626;
}
.dark .search-results-info strong {
color: #dc2626;
}
@media (max-width: 768px) {
.search-input-row {
flex-direction: column;
}
.search-button-row {
flex-direction: column;
align-items: stretch;
}
.search-button,
.clear-search-link {
width: 100%;
text-align: center;
}
.search-form {
gap: 15px;
}
}
@media (min-width: 769px) {
.search-button-row {
justify-content: center;
}
}
</style>
<!-- 主CSS样式 - 同步优化版 -->
<style>
.development-history-widget {
max-width: 100%;
background: #fff;
border-radius: 8px;
}
.dark .development-history-widget h3{
margin-top:0px;
}
.widget-title {
text-align: center;
margin-bottom: 20px;
color: #333;
font-size: 20px;
padding-bottom: 10px;
border-bottom: 2px solid #007bff;
transition: all 0.3s ease;
}
.dark .year-list li+li{margin-top:0em;}
.year-list li+li{margin-top:0em;}
.dark .year-filter ul{padding-left:0rem;margin-bottom:0px;}
.year-filter ul{padding-left:0rem;margin-bottom:0px;}
.year-filter {
margin:10px auto;
padding: 15px;
background: #f8f9fa;
border-radius: 6px;
border: 1px solid #e9ecef;
}
.year-filter-title {
font-size: 16px;
font-weight: 600;
color: #495057;
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 8px;
}
.year-filter-title:before {
content: "📅";
font-size: 14px;
}
.year-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 0;
padding: 0;
justify-content: center;
list-style: none;
}
.year-item {
display: inline-block;
}
.year-link {
display: inline-block;
padding: 6px 14px;
background-color: #fff;
color: #495057;
text-decoration: none;
border-radius: 10px;
border: 1px solid #dee2e6;
font-size: 13px;
font-weight: 500;
transition: all 0.2s ease;
cursor: pointer;
}
.year-link:hover {
background-color: #e9ecef;
border-color: #ced4da;
transform: translateY(-1px);
}
.year-link.active {
background-color: #007bff;
color: white;
border-color: #007bff;
font-weight: 600;
}
.year-count {
margin-left: 4px;
font-size: 11px;
opacity: 0.8;
font-weight: normal;
}
.history-list {
list-style: none;
padding: 0;
margin: 0;
}
.history-item {
padding: 12px 12px;
display: flex;
align-items: flex-start;
border-radius: 10px;
transition: background-color 0.3s ease;
}
.history-item:first-child {
border-bottom: none;
margin-top: 20px;
}
.history-content p{margin-bottom:0px;}
.dark .history-content p{margin-bottom:0px;}
.history-date {
font-weight: bold;
color: #007bff;
font-size: 14px;
min-width: 90px;
flex-shrink: 0;
text-align: right;
transition: all 0.3s ease;
}
.history-content {
color: #555;
line-height: 1.6;
font-size: 14px;
word-wrap: break-word;
flex-grow: 1;
}
.history-content p {
margin: 0;
}
.history-date::after {
content: "";
color: #666;
font-weight: normal;
padding-left: 2px;
}
.development-history-empty {
text-align: center;
padding: 30px;
color: #999;
font-size: 14px;
border: 1px dashed #ddd;
border-radius: 8px;
background-color: #fafafa;
}
.history-item:last-child{margin-bottom:10px;}
.history-pagination {
text-align: center;
padding-top: 40px;
transition: all 0.3s ease;
border-top:1px solid #333;
padding-bottom:20px;
}
.pagination-container {
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 8px;
}
.pagination-info {
font-size: 13px;
color: #666;
margin: 0 10px;
flex-shrink: 0;
}
.pagination-nav {
display: flex;
align-items: center;
gap: 5px;
}
.pagination-page {
display: flex;
align-items: center;
gap: 8px;
}
.pagination-link {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 36px;
height: 36px;
padding: 0 10px;
background: #fff;
color: #333;
text-decoration: none;
border: 1px solid #ddd;
border-radius: 50px;
font-size: 14px;
transition: all 0.2s ease;
line-height: 1;
}
.pagination-link:hover {
background: #007bff;
color: white;
border-color: #007bff;
transform: translateY(-1px);
}
.pagination-link.active {
background: #007bff;
color: white;
border-color: #007bff;
font-weight: 600;
}
.pagination-link.disabled {
color: #999;
background: #f5f5f5;
border-color: #ddd;
cursor: not-allowed;
opacity: 0.6;
}
.pagination-link.disabled:hover {
background: #f5f5f5;
color: #999;
border-color: #ddd;
transform: none;
}
.pagination-ellipsis {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 36px;
height: 36px;
padding: 0 10px;
color: #666;
font-size: 14px;
}
/* 深色模式适配 */
.dark .development-history-widget {
background: #1e1e1e;
}
.dark .development-history-widget h2 {
margin-top:0px;
border-bottom-width: 0px;
}
.development-history-widget h2 {
margin-top:0px;
}
.dark .widget-title {
color: #e0e0e0;
border-bottom-color: #dc2626;
}
.dark .year-filter {
background: #2d2d2d;
border-color: #333;
}
.dark .year-filter-title {
color: #e0e0e0;
}
.dark .year-link {
background-color: #2d2d2d;
color: #e0e0e0;
border-color: #444;
}
.dark .year-link:hover {
background-color: #3d3d3d;
border-color: #555;
}
.dark .year-link.active {
background-color: #dc2626;
color: #fff;
border-color: #dc2626;
}
.dark .history-item {
border-bottom-color: #333;
}
.dark .history-item:hover {
background-color: #2d2d2d;
}
.dark .history-date {
color: #dc2626;
}
.dark .history-content {
color: #b0b0b0;
}
.dark .history-date::after {
color: #888;
}
.dark .development-history-empty {
color: #888;
border-color: #444;
background-color: #2d2d2d;
}
.dark .history-pagination {
border-top: 1px solid #333;
}
.dark .pagination-info {
color: #aaa;
}
.dark .pagination-link {
background: #2d2d2d;
color: #e0e0e0;
border-color: #444;
}
.dark .pagination-link:hover {
background: #dc2626;
color: #fff;
border-color: #dc2626;
}
.dark .pagination-link.active {
background: #dc2626;
color: #fff;
border-color: #dc2626;
}
.dark .pagination-link.disabled {
color: #666;
background: #2d2d2d;
border-color: #444;
}
.dark .pagination-link.disabled:hover {
background: #2d2d2d;
color: #666;
border-color: #444;
}
.dark .pagination-ellipsis {
color: #888;
}
@media (max-width: 768px) {
.development-history-widget {
padding: 12px;
}
.widget-title {
font-size: 18px;
}
.history-item {
padding: 10px 0;
flex-direction: column;
}
.history-date {
min-width: auto;
text-align: left;
margin-bottom: 5px;
width: 100%;
}
.history-date::after {
content: "";
}
.pagination-container {
flex-direction: column;
gap: 10px;
}
.pagination-nav {
width: 100%;
justify-content: center;
}
.pagination-page {
flex-wrap: wrap;
justify-content: center;
margin: 5px 0;
}
.year-list {
justify-content: center;
}
}
@media (max-width: 480px) {
.pagination-link {
min-width: 32px;
height: 32px;
padding: 0 8px;
font-size: 13px;
}
.pagination-ellipsis {
min-width: 32px;
height: 32px;
font-size: 13px;
}
.year-link {
padding: 5px 10px;
font-size: 12px;
}
}
</style>
<div class="development-history-widget">
<h2 class="widget-title">网站发展历史</h2>
<!-- 搜索框 -->
<div class="history-search-box">
<form method="get" action="<?php echo $currentFile; ?>" class="search-form">
<!-- 隐藏字段,保持当前年份筛选 -->
<?php if ($selectedYear > 0): ?>
<input type="hidden" name="y" value="<?php echo $selectedYear; ?>">
<?php endif; ?>
<div class="search-input-row">
<input type="text"
name="search"
class="search-input"
placeholder="输入关键词搜索历史记录..."
value="<?php echo htmlspecialchars($searchKeyword); ?>"
maxlength="100"
aria-label="搜索历史记录">
</div>
<div class="search-button-row">
<button type="submit" class="search-button">
搜索
</button>
<?php if (!empty($searchKeyword) || $selectedYear > 0): ?>
<a href="<?php echo $currentFile; ?>" class="clear-search-link">
✕ 清除筛选
</a>
<?php endif; ?>
</div>
</form>
<?php if (!empty($searchKeyword)): ?>
<div class="search-results-info">
搜索 "<strong><?php echo htmlspecialchars($searchKeyword); ?></strong>" 找到 <?php echo $total; ?> 条记录
<?php if ($selectedYear > 0): ?>
(在 <?php echo $selectedYear; ?> 年中)
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<!-- 年份筛选器 -->
<?php if (!empty($yearsData)): ?>
<div class="year-filter">
<ul class="year-list">
<!-- 全部年份 -->
<li class="year-item">
<a href="<?php echo buildYearUrl(0, $searchKeyword); ?>"
class="year-link <?php echo $selectedYear == 0 ? 'active' : ''; ?>">
全部
<span class="year-count">(<?php echo $totalAll; ?>)</span>
</a>
</li>
<!-- 各年份 -->
<?php foreach ($yearsData as $yearData): ?>
<li class="year-item">
<?php
$year = $yearData['year'];
$hasData = $yearData['count'] > 0;
$url = buildYearUrl($year, $searchKeyword);
?>
<a href="<?php echo $url; ?>"
class="year-link <?php echo $selectedYear == $year ? 'active' : ''; ?>"
<?php if (!$hasData): ?>style="opacity:0.5; cursor:not-allowed;" onclick="return false;"<?php endif; ?>
title="<?php echo $hasData ? "查看{$year}年记录" : "{$year}年暂无记录"; ?>">
<?php echo $year; ?>
<span class="year-count">(<?php echo $yearData['count']; ?>)</span>
</a>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<!-- 当前筛选信息 -->
<?php if ($selectedYear > 0 && empty($searchKeyword)): ?>
<div style="text-align:center;margin-bottom: 15px; padding: 8px 12px; background: #e7f3ff; border-radius: 4px; ">
<span style="font-size: 13px; color: #0066cc;">
当前筛选:<strong><?php echo $selectedYear; ?></strong> 年
<small>(<?php echo $total; ?> 条记录)</small>
<a href="<?php echo buildYearUrl(0, $searchKeyword); ?>" style="margin-left: 10px; font-size: 12px; color: #666; text-decoration: none;">
清除筛选
</a>
</span>
</div>
<?php endif; ?>
<!-- 搜索结果为空提示 -->
<?php if (empty($histories) && (!empty($searchKeyword) || $selectedYear > 0)): ?>
<div class="development-history-empty">
<?php if (!empty($searchKeyword) && $selectedYear > 0): ?>
未找到包含 "<strong><?php echo htmlspecialchars($searchKeyword); ?></strong>" 的 <?php echo $selectedYear; ?> 年历史记录
<?php elseif (!empty($searchKeyword)): ?>
未找到包含 "<strong><?php echo htmlspecialchars($searchKeyword); ?></strong>" 的历史记录
<?php elseif ($selectedYear > 0): ?>
<?php echo $selectedYear; ?> 年暂无历史记录
<?php endif; ?>
<div style="margin-top: 10px;">
<a href="<?php echo $currentFile; ?>" style="color: #007bff; text-decoration: none;">查看全部记录</a>
</div>
</div>
<?php endif; ?>
<!-- 历史记录列表 -->
<?php if (!empty($histories)): ?>
<div class="history-list">
<?php foreach ($histories as $history): ?>
<div class="history-item">
<div class="history-date">
<?php echo date(isset($config->dateFormat) ? $config->dateFormat : 'Y.m.d', strtotime($history['event_date'])); ?>
</div>
<div class="history-content">
<p>
<?php
$content = htmlspecialchars($history['content']);
// 如果有关键词,高亮显示
if (!empty($searchKeyword)) {
$content = preg_replace(
'/(' . preg_quote($searchKeyword, '/') . ')/i',
'<mark style="background-color: #fff3cd;color:#000; padding: 1px 3px; border-radius: 2px;">$1</mark>',
$content
);
}
echo nl2br($content);
?>
</p>
<?php
// 显示关联文章
if (isset($config->showRelatedPosts) && $config->showRelatedPosts == 1 && !empty($history['posts'])):
?>
<div class="related-posts">
<div class="related-posts-title">
<?php echo isset($config->relatedPostsTitle) ? $config->relatedPostsTitle : '相关文章'; ?>
</div>
<ul class="related-posts-list">
<?php foreach ($history['posts'] as $post): ?>
<li class="related-post-item">
<a href="<?php echo $post['url']; ?>" class="related-post-link" target="_blank">
<?php echo htmlspecialchars($post['title']); ?>
</a>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
<?php if ($totalPages > 1): ?>
<div class="history-pagination">
<div class="pagination-container">
<!--<div class="pagination-info">
第 <?php echo $currentPage; ?> / <?php echo $totalPages; ?> 页
</div>-->
<div class="pagination-nav">
<?php if ($currentPage > 1): ?>
<!--<a href="<?php echo buildUrl($selectedYear, 1, $searchKeyword); ?>"
class="pagination-link" title="第一页">
首页
</a>-->
<a href="<?php echo buildUrl($selectedYear, $currentPage-1, $searchKeyword); ?>"
class="pagination-link" title="上一页">
上一页
</a>
<?php else: ?>
<!--<span class="pagination-link disabled" title="第一页">首页</span>-->
<span class="pagination-link disabled" title="上一页">上一页</span>
<?php endif; ?>
</div>
<div class="pagination-page">
<?php
// 显示页码逻辑
$start = max(1, $currentPage - 2);
$end = min($totalPages, $currentPage + 2);
// 显示第一页和省略号
if ($start > 1) {
echo '<a href="' . buildUrl($selectedYear, 1, $searchKeyword) . '" class="pagination-link">1</a>';
if ($start > 2) {
echo '<span class="pagination-ellipsis">...</span>';
}
}
// 显示页码
for ($i = $start; $i <= $end; $i++) {
if ($i == $currentPage) {
echo '<span class="pagination-link active">' . $i . '</span>';
} else {
echo '<a href="' . buildUrl($selectedYear, $i, $searchKeyword) . '" class="pagination-link">' . $i . '</a>';
}
}
// 显示最后页和省略号
if ($end < $totalPages) {
if ($end < $totalPages - 1) {
echo '<span class="pagination-ellipsis">...</span>';
}
echo '<a href="' . buildUrl($selectedYear, $totalPages, $searchKeyword) . '" class="pagination-link">' . $totalPages . '</a>';
}
?>
</div>
<div class="pagination-nav">
<?php if ($currentPage < $totalPages): ?>
<a href="<?php echo buildUrl($selectedYear, $currentPage+1, $searchKeyword); ?>"
class="pagination-link" title="下一页">
下一页
</a>
<!--<a href="<?php echo buildUrl($selectedYear, $totalPages, $searchKeyword); ?>"
class="pagination-link" title="最后一页">
末页
</a>-->
<?php else: ?>
<span class="pagination-link disabled" title="下一页">下一页</span>
<!--<span class="pagination-link disabled" title="最后一页">末页</span>-->
<?php endif; ?>
</div>
</div>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
<script>
// 调试信息
console.log('当前URL:', window.location.href);
console.log('当前年份参数 (y):', <?php echo $selectedYear; ?>);
console.log('搜索关键词 (原始):', '<?php echo $searchKeyword; ?>');
console.log('搜索关键词 (编码):', '<?php echo urlencode($searchKeyword); ?>');
// 自动聚焦搜索框
document.addEventListener('DOMContentLoaded', function() {
var searchInput = document.querySelector('.search-input');
if (searchInput && !searchInput.value) {
searchInput.focus();
}
});
// 搜索表单提交时验证
var searchForm = document.querySelector('.search-form');
if (searchForm) {
searchForm.addEventListener('submit', function(e) {
var searchInput = this.querySelector('.search-input');
if (searchInput.value.trim() === '') {
e.preventDefault();
// 如果已经有年份筛选,保留年份参数
var yearParam = <?php echo $selectedYear > 0 ? "'?y=" . $selectedYear . "'" : "''"; ?>;
window.location.href = '<?php echo $currentFile; ?>' + yearParam;
}
});
}
// 确保年份链接正确传递搜索参数
document.addEventListener('DOMContentLoaded', function() {
var searchKeyword = '<?php echo $searchKeyword; ?>';
var yearLinks = document.querySelectorAll('.year-link[href]');
yearLinks.forEach(function(link) {
var href = link.getAttribute('href');
if (searchKeyword && href.indexOf('search=') === -1) {
// 如果链接中没有搜索参数,但当前有搜索关键词,需要添加
var separator = href.indexOf('?') === -1 ? '?' : '&';
var newHref = href + separator + 'search=' + encodeURIComponent(searchKeyword);
link.setAttribute('href', newHref);
}
});
});
// 搜索框动画效果
document.addEventListener('DOMContentLoaded', function() {
var searchInput = document.querySelector('.search-input');
if (searchInput) {
searchInput.addEventListener('focus', function() {
this.parentElement.style.transform = 'scale(1.02)';
});
searchInput.addEventListener('blur', function() {
this.parentElement.style.transform = 'scale(1)';
});
}
});
</script>
<?php
}
}