1371 lines
45 KiB
PHP
1371 lines
45 KiB
PHP
|
|
<?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
|
|||
|
|
}
|
|||
|
|
}
|