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

1426 lines
44 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
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
/**
* 发展历史插件后台管理面板
*/
// 获取配置
$options = Typecho_Widget::widget('Widget_Options');
$config = $options->plugin('DevelopmentHistory');
// 引入Action类
require_once __DIR__ . '/Action.php';
$action = new DevelopmentHistory_Action();
// 获取当前页码
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
$perPage = isset($config->perPage) ? intval($config->perPage) : 10;
// 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 处理新增 - 关键:处理完后不重定向,刷新当前页面
// 在manage-panel.php中修改发布处理部分第29-38行
// 处理新增
if (!empty($_POST['content'])) {
try {
$action->addHistory(array(
'content' => $_POST['content'],
'event_date' => $_POST['event_date'],
'post_cids' => isset($_POST['post_cids']) ? $_POST['post_cids'] : ''
));
$successMsg = '记录添加成功!';
// 添加滚动到列表的锚点
header('Location: ' . $_SERVER['PHP_SELF'] . '?panel=DevelopmentHistory/manage-panel.php&page=' . $page . '#history-list-anchor');
exit;
} catch (Exception $e) {
// 如果数据已保存但出现错误,只显示警告
$successMsg = '记录已添加,但出现警告:' . htmlspecialchars($e->getMessage());
}
}
// 处理批量删除
if (!empty($_POST['delete_ids']) && is_array($_POST['delete_ids'])) {
$action->deleteHistories($_POST['delete_ids']);
$successMsg = '删除成功!';
// 添加滚动到列表的锚点
header('Location: ' . $_SERVER['PHP_SELF'] . '?panel=DevelopmentHistory/manage-panel.php&page=' . $page . '#history-list-anchor');
exit;
}
// 处理编辑
if (!empty($_POST['edit_id'])) {
$action->updateHistory(array(
'edit_id' => $_POST['edit_id'],
'edit_content' => $_POST['edit_content'],
'edit_event_date' => $_POST['edit_event_date'],
'edit_post_cids' => isset($_POST['edit_post_cids']) ? $_POST['edit_post_cids'] : ''
));
$successMsg = '记录更新成功!';
// 添加滚动到列表的锚点
header('Location: ' . $_SERVER['PHP_SELF'] . '?panel=DevelopmentHistory/manage-panel.php&page=' . $page . '#history-list-anchor');
exit;
}
// 处理导出
if (isset($_POST['export'])) {
$exportContent = $action->exportData();
$filename = 'development_history_' . date('Ymd_His') . '.txt';
header('Content-Type: text/plain');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Length: ' . strlen($exportContent));
echo $exportContent;
exit;
}
// 处理导入
if (isset($_POST['import']) && !empty($_FILES['import_file']['tmp_name'])) {
$fileContent = file_get_contents($_FILES['import_file']['tmp_name']);
$result = $action->importData($fileContent);
if ($result['imported'] > 0) {
$successMsg = '导入成功!成功导入 ' . $result['imported'] . ' 条记录';
if ($result['failed'] > 0) {
$successMsg .= ',失败 ' . $result['failed'] . ' 条记录';
// 显示失败原因限制显示前10条
if (!empty($result['fail_reasons'])) {
$errorDetails = '<strong>失败原因:</strong><br>';
$displayCount = min(10, count($result['fail_reasons']));
for ($i = 0; $i < $displayCount; $i++) {
$errorDetails .= htmlspecialchars($result['fail_reasons'][$i]) . '<br>';
}
if (count($result['fail_reasons']) > 10) {
$errorDetails .= '...还有 ' . (count($result['fail_reasons']) - 10) . ' 条失败记录';
}
$errorMsg = $errorDetails;
}
}
} else {
$errorMsg = '导入失败!未找到可导入的记录或格式不正确';
if (!empty($result['fail_reasons'])) {
$errorMsg .= '<br><strong>失败原因:</strong><br>';
$displayCount = min(10, count($result['fail_reasons']));
for ($i = 0; $i < $displayCount; $i++) {
$errorMsg .= htmlspecialchars($result['fail_reasons'][$i]) . '<br>';
}
}
}
}
}
// 获取记录
$histories = $action->getHistories($page, $perPage);
$total = $action->getTotalCount();
$totalPages = ceil($total / $perPage);
?>
<?php include 'header.php'; ?>
<?php include 'menu.php'; ?>
<style>
/* 基础重置 */
* {
box-sizing: border-box;
}
/* 浮动消息提示 */
.floating-message {
position: fixed;
top: 20px;
right: 20px;
z-index: 9999;
max-width: 350px;
opacity: 0;
transform: translateY(-20px);
transition: opacity 0.3s, transform 0.3s;
padding: 14px 20px;
border-radius: 6px;
border: 1px solid transparent;
font-size: 14px;
}
.floating-message.show {
opacity: 1;
transform: translateY(0);
}
.floating-message.success {
color: #0f5132;
background-color: #d1e7dd;
border-color: #badbcc;
}
.floating-message.error {
color: #842029;
background-color: #f8d7da;
border-color: #f5c2c7;
}
/* 表格样式 */
.data-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
margin: 0px 0;
font-size: 14px;
background-color: #fff;
border-radius: 6px;
overflow: hidden;
table-layout: fixed;
}
.data-table th,
.data-table td {
padding: 14px 12px;
border-bottom: 1px solid #f0f0f0;
text-align: left;
vertical-align: middle;
line-height: 1.4;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.data-table th {
background-color: #fafbfc;
font-weight: 600;
color: #333;
border-bottom: 2px solid #e0e0e0;
font-size: 14px;
}
.data-table tbody tr:hover {
background-color: #f8f9fa;
}
.data-table tbody tr:last-child td {
border-bottom: none;
}
/* 复选框列 */
.data-table th:first-child,
.data-table td:first-child {
text-align: center;
width: 50px;
min-width: 50px;
max-width: 50px;
padding: 14px 8px;
}
.data-table th:first-child input[type="checkbox"],
.data-table td:first-child input[type="checkbox"] {
margin: 0;
vertical-align: middle;
width: 16px;
height: 16px;
cursor: pointer;
}
/* ID列样式 - 固定宽度 */
.data-table th:nth-child(2),
.data-table td:nth-child(2) {
text-align: center;
width: 70px;
min-width: 70px;
max-width: 70px;
font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
font-size: 13px;
color: #666;
white-space: nowrap;
}
/* 内容列 - 最大宽度,不换行 */
.data-table th:nth-child(3),
.data-table td:nth-child(3) {
width: auto;
min-width: 250px;
max-width: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* 事件时间列 - 固定宽度,不换行 */
.data-table th:nth-child(4),
.data-table td:nth-child(4) {
text-align: center;
width: 110px;
min-width: 110px;
max-width: 110px;
font-size: 13px;
white-space: nowrap;
}
/* 发布时间列 - 固定宽度,不换行 - 修复:改为黑色 */
.data-table th:nth-child(5),
.data-table td:nth-child(5) {
text-align: center;
width: 110px;
min-width: 110px;
max-width: 110px;
font-size: 13px;
white-space: nowrap;
color: #000; /* 改为黑色 */
}
/* 文章关联列 - 固定宽度 */
.data-table th:nth-child(6),
.data-table td:nth-child(6) {
text-align: left; /* 改为左对齐以便显示多个CID */
width: 180px; /* 增加宽度以便显示多个CID */
min-width: 180px;
max-width: 180px;
font-size: 13px;
white-space: normal; /* 允许多行显示 */
overflow: visible; /* 允许内容溢出 */
}
/* 操作列样式 */
.data-table th:last-child,
.data-table td:last-child {
text-align: center;
width: 80px;
min-width: 80px;
max-width: 80px;
padding: 14px 8px;
white-space: nowrap;
}
/* 日期样式 */
.date-badge {
display: inline-block;
background-color: #f0f7ff;
color: #0066cc;
padding: 4px 10px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
white-space: nowrap;
}
/* 发布时间样式 - 修复:改为普通黑色文字 */
.publish-time {
color: #000;
font-size: 13px;
}
/* CID徽章样式 */
.cid-badge {
display: inline-block;
background-color: #e8f5e8;
color: #2e7d32;
padding: 3px 8px;
margin: 2px;
border-radius: 3px;
font-size: 11px;
font-weight: 500;
font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
white-space: nowrap;
border: 1px solid #c8e6c9;
line-height: 1;
}
.cid-container {
display: flex;
flex-wrap: wrap; /* 允许多行显示 */
gap: 3px;
max-height: 60px;
overflow-y: auto;
}
.no-cid {
color: #999;
font-size: 12px;
font-style: italic;
}
/* 批量操作区域 */
.bulk-actions-header, .bulk-actions-footer {
padding: 15px;
background-color: #f8f9fa;
border: 1px solid #e0e0e0;
display: flex;
justify-content: space-between;
align-items: center;
}
.bulk-actions-footer {
border-top: none;
border-bottom: 2px solid #e0e0e0;
}
/* 模态框样式 */
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
}
.modal-content {
background-color: #fff;
margin: 8% auto;
padding: 0;
border-radius: 8px;
width: 85%;
max-width: 500px;
box-shadow: 0 5px 25px rgba(0,0,0,0.15);
position: relative;
}
.close {
position: absolute;
right: 20px;
top: 18px;
font-size: 22px;
cursor: pointer;
color: #999;
background: none;
border: none;
padding: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
}
.close:hover {
color: #333;
background-color: #f5f5f5;
}
.modal-header {
margin: 0;
padding: 20px 25px;
border-bottom: 1px solid #e0e0e0;
background-color: #fafbfc;
border-radius: 8px 8px 0 0;
}
.modal-header h3 {
margin: 0;
color: #333;
font-size: 16px;
font-weight: 600;
}
.modal-content form {
padding: 25px;
}
/* 分页样式 */
.pagination {
margin-top: 25px;
margin-bottom:25px;
text-align: center;
}
.pagination ul {
list-style: none;
padding: 0;
margin: 0;
display: inline-flex;
gap: 4px;
}
.pagination li {
display: inline;
}
.pagination a, .pagination span {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 8px 12px;
background-color: #fff;
color: #495057;
text-decoration: none;
border-radius: 4px;
border: 1px solid #dee2e6;
min-width: 36px;
height: 36px;
font-size: 13px;
}
.pagination a:hover {
background-color: #f8f9fa;
border-color: #dee2e6;
}
.pagination .active a, .pagination .active span {
background-color: #007bff;
color: white;
border-color: #007bff;
}
/* 消息提示 */
.message {
padding: 14px 20px;
margin: 18px 0;
border-radius: 6px;
border: 1px solid transparent;
font-size: 14px;
}
.message.success {
color: #0f5132;
background-color: #d1e7dd;
border-color: #badbcc;
}
.message.error {
color: #842029;
background-color: #f8d7da;
border-color: #f5c2c7;
}
/* 表单样式 */
.form-section {
background: #fff;
padding: 25px;
margin-bottom: 22px;
border-radius: 8px;
border: 1px solid #e0e0e0;
}
.form-section h2 {
margin-top: 0;
margin-bottom: 22px;
padding-bottom: 16px;
border-bottom: 1px solid #f0f0f0;
color: #333;
font-size: 18px;
font-weight: 600;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #555;
font-size: 14px;
}
.form-control {
width: 100%;
padding: 10px 14px;
border: 1px solid #ced4da;
border-radius: 4px;
font-size: 14px;
color: #333;
background-color: #fff;
}
.form-control:focus {
outline: none;
border-color: #80bdff;
box-shadow: 0 0 0 0.2rem rgba(0,123,255,.15);
}
textarea.form-control {
resize: vertical;
min-height: 100px;
}
.description {
font-size: 12px;
color: #6c757d;
margin-top: 6px;
}
/* 文章关联输入框样式 */
.post-cids-input-wrapper {
position: relative;
}
.post-cids-input {
width: 100%;
padding: 10px 12px;
border: 1px solid #ced4da;
border-radius: 4px;
font-size: 14px;
color: #333;
background-color: #fff;
}
.post-cids-input:focus {
outline: none;
border-color: #80bdff;
box-shadow: 0 0 0 0.2rem rgba(0,123,255,.15);
}
.post-cids-display {
margin-top: 8px;
font-size: 12px;
color: #6c757d;
}
/* 按钮样式 */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 10px 18px;
font-size: 14px;
font-weight: 500;
text-align: center;
cursor: pointer;
border: 1px solid transparent;
border-radius: 4px;
height: 40px;
min-width: 80px;
}
.btn-primary {
color: #fff;
background-color: #007bff;
border-color: #007bff;
}
.btn-primary:hover {
background-color: #0069d9;
border-color: #0062cc;
}
.btn-secondary {
color: #fff;
background-color: #6c757d;
border-color: #6c757d;
}
.btn-secondary:hover {
background-color: #5a6268;
border-color: #545b62;
}
.btn-danger {
color: #fff;
background-color: #dc3545;
border-color: #dc3545;
}
.btn-danger:hover {
background-color: #c82333;
border-color: #bd2130;
}
.btn-success {
color: #fff;
background-color: #28a745;
border-color: #28a745;
}
.btn-success:hover {
background-color: #218838;
border-color: #1e7e34;
}
.btn-info {
color: #fff;
background-color: #17a2b8;
border-color: #17a2b8;
}
.btn-info:hover {
background-color: #138496;
border-color: #117a8b;
}
.btn-sm {
padding: 6px 12px;
font-size: 12px;
height: 32px;
min-width: 60px;
}
.btn-group {
display: flex;
gap: 10px;
}
/* 主容器样式 */
.main {
padding: 25px 0;
min-height: calc(100vh - 60px);
}
.body.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.typecho-page-title {
margin-bottom: 25px;
padding-bottom: 18px;
border-bottom: 1px solid #e0e0e0;
}
.typecho-page-title h1 {
margin: 0;
color: #333;
font-size: 24px;
font-weight: 600;
}
/* 全宽布局 */
.typecho-page-main {
display: block;
width: 100%;
}
.table-section {
background: #fff;
padding: 0;
border-radius: 8px;
border: 1px solid #e0e0e0;
margin-bottom: 22px;
overflow: hidden;
}
.table-section h2 {
margin: 0;
padding: 20px 25px;
border-bottom: 1px solid #f0f0f0;
color: #333;
font-size: 18px;
font-weight: 600;
}
/* 统计信息盒子 */
.stats-box {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
padding: 22px;
border-radius: 8px;
margin-bottom: 22px;
border: 1px solid #dee2e6;
}
.stats-box h3 {
margin-top: 0;
margin-bottom: 18px;
color: #495057;
font-size: 16px;
font-weight: 600;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
}
.stat-item {
background: white;
padding: 18px;
border-radius: 6px;
border-left: 4px solid #007bff;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
.stat-item .label {
font-size: 12px;
color: #6c757d;
margin-bottom: 6px;
text-transform: uppercase;
letter-spacing: 0.5px;
font-weight: 500;
}
.stat-item .value {
font-size: 20px;
font-weight: 600;
color: #343a40;
}
/* 导入导出样式 */
.import-export-section {
margin-bottom: 22px;
border-radius: 8px;
}
.import-export-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 22px;
margin-bottom: 22px;
}
.import-box, .export-box {
background: #f8f9fa;
padding: 22px;
border-radius: 6px;
border: 1px solid #dee2e6;
}
.import-box h4, .export-box h4 {
margin-top: 0;
margin-bottom: 16px;
color: #495057;
font-size: 15px;
font-weight: 600;
}
.format-example {
background: #fff;
padding: 16px;
border-radius: 6px;
border-left: 3px solid #007bff;
margin-top: 18px;
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
font-size: 13px;
}
.format-example pre {
margin: 0;
white-space: pre-wrap;
font-size: 12px;
}
.format-example code {
color: #e83e8c;
font-family: inherit;
font-size: 12px;
}
.format-example strong {
color: #333;
font-weight: 600;
margin-bottom: 8px;
display: block;
}
/* 锚点定位样式 */
.anchor-target {
scroll-margin-top: 20px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.body.container {
padding: 0 15px;
}
.import-export-grid {
grid-template-columns: 1fr;
}
.bulk-actions-header, .bulk-actions-footer {
flex-direction: column;
gap: 10px;
}
.floating-message {
left: 20px;
right: 20px;
max-width: none;
}
/* 响应式调整关联文章列 */
.data-table th:nth-child(6),
.data-table td:nth-child(6) {
width: 140px;
min-width: 140px;
max-width: 140px;
}
}
</style>
<div class="main">
<div class="body container">
<!-- 浮动消息提示 -->
<?php if (isset($successMsg)): ?>
<div id="floatingMessage" class="floating-message success show">
<div style="display: flex; justify-content: space-between; align-items: flex-start;">
<div style="flex-grow: 1;">
<strong>✓ 成功</strong>
<div style="margin-top: 5px;"><?php echo $successMsg; ?></div>
</div>
<button type="button" onclick="hideMessage()" style="background: none; border: none; color: inherit; font-size: 18px; cursor: pointer; margin-left: 10px; padding: 0 5px;">&times;</button>
</div>
</div>
<?php endif; ?>
<?php if (isset($errorMsg)): ?>
<div id="floatingMessage" class="floating-message error show">
<div style="display: flex; justify-content: space-between; align-items: flex-start;">
<div style="flex-grow: 1;">
<strong>✗ 错误</strong>
<div style="margin-top: 5px;"><?php echo $errorMsg; ?></div>
</div>
<button type="button" onclick="hideMessage()" style="background: none; border: none; color: inherit; font-size: 18px; cursor: pointer; margin-left: 10px; padding: 0 5px;">&times;</button>
</div>
</div>
<?php endif; ?>
<div class="typecho-page-main" role="main">
<!-- 统计信息 -->
<div class="stats-box">
<div class="stats-grid">
<div class="stat-item">
<div class="label">总记录数</div>
<div class="value"><?php echo $total; ?> 条</div>
</div>
<div class="stat-item">
<div class="label">当前页数</div>
<div class="value"><?php echo $page; ?> / <?php echo $totalPages; ?></div>
</div>
<div class="stat-item">
<div class="label">每页显示</div>
<div class="value"><?php echo $perPage; ?> 条</div>
</div>
</div>
</div>
<!-- 导入导出功能 -->
<div class="import-export-section">
<div class="import-export-grid">
<!-- 导出功能 -->
<div class="export-box">
<h4>导出数据</h4>
<p style="margin-bottom: 15px;color:#000;">导出所有历史记录为文本文件格式</p>
<form method="post" action="">
<input type="hidden" name="action" value="development-history">
<button type="submit" name="export" class="btn btn-success">
导出为 TXT 文件
</button>
</form>
<div class="format-example">
<strong>导出格式示例:</strong>
<pre>2025.12.21 网站正式上线
2025.12.25 新增用户注册功能
2025.12.28 优化了网站性能</pre>
</div>
</div>
<!-- 导入功能 -->
<div class="import-box">
<h4>导入数据</h4>
<p style="margin-bottom: 15px;color:#000;">从文本文件导入历史记录</p>
<form method="post" action="" enctype="multipart/form-data">
<input type="hidden" name="action" value="development-history">
<div class="form-group" style="margin-bottom: 15px;">
<label for="import_file">选择文件</label>
<input type="file" id="import_file" name="import_file" class="form-control" required accept=".txt,.text">
<p class="description">支持 .txt 文本文件格式</p>
</div>
<button type="submit" name="import" class="btn btn-info">
导入 TXT 文件
</button>
</form>
<div class="format-example">
<strong>导入格式要求:</strong>
<pre>每行一条记录,格式为:<code>日期 内容</code>
日期格式YYYY.M[M].D[D](支持单数字月份和日期)
例如:<code>2023.12.9 网站更新</code>
例如:<code>2023.8.8 新功能上线</code></pre>
<p style="margin-top: 10px; font-size: 12px; color: #666;">
提示:请确保文件编码为 UTF-8每行一条记录
</p>
</div>
</div>
</div>
</div>
<!-- 发布表单 -->
<div class="form-section">
<h2>发布新历史</h2>
<!-- 修复表单action设为空字符串提交到当前页面 -->
<form method="post" action="" id="publishForm">
<div class="form-group">
<label for="content">内容 *</label>
<textarea id="content" name="content" class="form-control" rows="4" required
placeholder="请输入详细网站发展历史内容"></textarea>
</div>
<div class="form-group">
<label for="event_date">日期 *</label>
<div class="btn-group">
<input type="date" id="event_date" name="event_date" class="form-control"
value="<?php echo date('Y-m-d'); ?>" required>
<button type="button" class="btn btn-secondary" onclick="document.getElementById('event_date').value = '<?php echo date('Y-m-d'); ?>'">
今天
</button>
</div>
</div>
<div class="form-group">
<label for="post_cids">关联文章CID可选</label>
<div class="post-cids-input-wrapper">
<input type="text" id="post_cids" name="post_cids" class="form-control post-cids-input"
placeholder="输入文章CID多个用逗号分隔123,456">
</div>
<p class="description post-cids-display">
可关联多个文章输入文章CID用逗号分隔
</p>
</div>
<div style="text-align: center;">
<button type="reset" class="btn btn-secondary" style="margin-right: 10px;">重置</button>
<button type="submit" class="btn btn-primary" id="publishBtn">发布</button>
</div>
</form>
</div>
<!-- 锚点目标,用于滚动定位 -->
<div id="history-list-anchor" class="anchor-target"></div>
<!-- 历史记录列表 -->
<div class="table-section">
<h2>历史记录列表</h2>
<?php if (empty($histories)): ?>
<div class="message info" style="text-align: center; padding: 30px;">
暂无历史记录,请先添加记录
</div>
<?php else: ?>
<form method="post" action="" id="mainForm">
<!-- 表头多选操作栏 -->
<div class="bulk-actions-header">
<div style="display: flex; align-items: center; gap: 15px;">
<div style="display: flex; align-items: center;">
<input type="checkbox" id="header-select-all" style="margin: 0; width: 16px; height: 16px;">
<label for="header-select-all" style="color:#000;margin-left: 8px; font-weight: 500; font-size: 14px;">
全选本页
</label>
</div>
<div class="selected-info">
<span class="description">
已选择 <strong id="selected-count-text">0</strong> 条记录
</span>
</div>
</div>
<div>
<button type="button" id="header-delete-btn" class="btn btn-danger btn-sm">
删除选中
</button>
</div>
</div>
<table class="data-table">
<thead>
<tr>
<th>
<input type="checkbox" id="thead-select-all" title="全选/全不选">
</th>
<th>ID</th>
<th>内容</th>
<th>历史时间</th>
<th>发布时间</th>
<th>文章关联</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php foreach ($histories as $history):
$cids = !empty($history['post_cids']) ? explode(',', $history['post_cids']) : array();
?>
<tr>
<td>
<input type="checkbox" name="delete_ids[]" value="<?php echo $history['id']; ?>" class="row-checkbox">
</td>
<td>
<span class="history-id">#<?php echo $history['id']; ?></span>
</td>
<td title="<?php echo htmlspecialchars($history['content']); ?>">
<div style="font-size: 13px; color: #333; line-height: 1.4; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
<?php echo htmlspecialchars($history['content']); ?>
</div>
</td>
<td>
<span class="date-badge">
<?php echo date('Y-m-d', strtotime($history['event_date'])); ?>
</span>
</td>
<td>
<!-- 修复:发布时间改为黑色普通文字 -->
<span class="publish-time">
<?php echo date('Y-m-d', strtotime($history['created'])); ?>
</span>
</td>
<td>
<?php if (!empty($cids)): ?>
<div class="cid-container">
<?php foreach ($cids as $cid):
$cid = trim($cid);
if (!empty($cid)): ?>
<span class="cid-badge" title="文章CID: <?php echo $cid; ?>">
<?php echo $cid; ?>
</span>
<?php endif; ?>
<?php endforeach; ?>
</div>
<?php else: ?>
<span class="no-cid">-</span>
<?php endif; ?>
</td>
<td>
<button type="button" class="btn btn-sm btn-primary edit-btn"
data-history='<?php echo htmlspecialchars(json_encode($history), ENT_QUOTES, 'UTF-8'); ?>'
style="padding: 4px 10px; font-size: 12px;">
编辑
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<!-- 表尾多选操作栏 -->
<div class="bulk-actions-footer">
<div style="display: flex; align-items: center; gap: 15px;">
<div style="display: flex; align-items: center;">
<input type="checkbox" id="footer-select-all" style="margin: 0; width: 16px; height: 16px;">
<label for="footer-select-all" style="color:#000;margin-left: 8px; font-weight: 500; font-size: 14px;">
全选本页
</label>
</div>
<div class="selected-info">
<span class="description">
已选择 <strong id="footer-selected-count">0</strong> 条记录
</span>
</div>
</div>
<div>
<button type="button" id="footer-delete-btn" class="btn btn-danger btn-sm">
删除选中
</button>
</div>
</div>
<!-- 隐藏的提交按钮 -->
<input type="submit" id="hidden-submit" style="display: none;">
</form>
<!-- 分页 -->
<?php if ($totalPages > 1): ?>
<div class="pagination">
<ul>
<?php if ($page > 1): ?>
<li><a href="?panel=DevelopmentHistory/manage-panel.php&page=<?php echo $page-1; ?>#history-list-anchor">&laquo; 上一页</a></li>
<?php endif; ?>
<?php
$start = max(1, $page - 2);
$end = min($totalPages, $page + 2);
if ($start > 1) {
echo '<li><a href="?panel=DevelopmentHistory/manage-panel.php&page=1#history-list-anchor">1</a></li>';
if ($start > 2) echo '<li><span>...</span></li>';
}
for ($i = $start; $i <= $end; $i++): ?>
<li <?php if ($i == $page) echo 'class="active"'; ?>>
<a href="?panel=DevelopmentHistory/manage-panel.php&page=<?php echo $i; ?>#history-list-anchor"><?php echo $i; ?></a>
</li>
<?php endfor; ?>
<?php if ($end < $totalPages): ?>
<?php if ($end < $totalPages - 1): ?>
<li><span>...</span></li>
<?php endif; ?>
<li><a href="?panel=DevelopmentHistory/manage-panel.php&page=<?php echo $totalPages; ?>#history-list-anchor"><?php echo $totalPages; ?></a></li>
<?php endif; ?>
<?php if ($page < $totalPages): ?>
<li><a href="?panel=DevelopmentHistory/manage-panel.php&page=<?php echo $page+1; ?>#history-list-anchor">下一页 &raquo;</a></li>
<?php endif; ?>
</ul>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
</div>
</div>
<!-- 编辑模态框 -->
<div id="editModal" class="modal" style="display:none;">
<div class="modal-content">
<button type="button" class="close" onclick="closeModal()">&times;</button>
<div class="modal-header">
<h3>编辑历史记录</h3>
</div>
<form id="editForm" method="post" action="">
<div class="form-group">
<label for="edit_content">内容 *</label>
<textarea id="edit_content" name="edit_content" class="form-control" rows="5" required></textarea>
</div>
<div class="form-group">
<label for="edit_event_date">日期 *</label>
<input type="date" id="edit_event_date" name="edit_event_date" class="form-control" required>
</div>
<div class="form-group">
<label for="edit_post_cids">关联文章CID可选</label>
<div class="post-cids-input-wrapper">
<input type="text" id="edit_post_cids" name="edit_post_cids" class="form-control post-cids-input"
placeholder="输入文章CID多个用逗号分隔123,456">
</div>
<p class="description post-cids-display">
可关联多个文章输入文章CID用逗号分隔
</p>
</div>
<input type="hidden" name="edit_id" id="edit_id">
<div style="text-align:right;margin-top:20px; padding-top: 15px; border-top: 1px solid #eee;">
<button type="button" class="btn btn-secondary" onclick="closeModal()" style="margin-right:10px;">
取消
</button>
<button type="submit" class="btn btn-primary">保存修改</button>
</div>
</form>
</div>
</div>
<script>
// 页面加载后自动滚动到锚点
document.addEventListener('DOMContentLoaded', function() {
if (window.location.hash === '#history-list-anchor') {
setTimeout(function() {
var anchor = document.getElementById('history-list-anchor');
if (anchor) {
anchor.scrollIntoView({ behavior: 'smooth' });
}
}, 100);
}
// 自动隐藏浮动消息
var floatingMessage = document.getElementById('floatingMessage');
if (floatingMessage) {
setTimeout(function() {
hideMessage();
}, 5000);
}
});
// 隐藏浮动消息
function hideMessage() {
var message = document.getElementById('floatingMessage');
if (message) {
message.classList.remove('show');
setTimeout(function() {
if (message.parentNode) {
message.parentNode.removeChild(message);
}
}, 300);
}
}
// 更新选中数量函数
function updateSelectedCount() {
var checkboxes = document.querySelectorAll('.row-checkbox:checked');
var count = checkboxes.length;
document.getElementById('selected-count-text').textContent = count;
document.getElementById('footer-selected-count').textContent = count;
var headerBtn = document.getElementById('header-delete-btn');
var footerBtn = document.getElementById('footer-delete-btn');
if (count > 0) {
headerBtn.textContent = '删除选中(' + count + ')';
footerBtn.textContent = '删除选中(' + count + ')';
} else {
headerBtn.textContent = '删除选中';
footerBtn.textContent = '删除选中';
}
var allCheckboxes = document.querySelectorAll('.row-checkbox');
var headerCheckboxes = document.querySelectorAll('#header-select-all, #thead-select-all, #footer-select-all');
if (allCheckboxes.length > 0) {
var allChecked = count === allCheckboxes.length;
var someChecked = count > 0 && count < allCheckboxes.length;
headerCheckboxes.forEach(function(checkbox) {
checkbox.checked = allChecked;
checkbox.indeterminate = someChecked;
});
}
return count;
}
// 全选/全不选功能
function setupSelectAll(selector, targetSelector) {
var selectAll = document.querySelector(selector);
if (selectAll) {
selectAll.addEventListener('change', function(e) {
var checkboxes = document.querySelectorAll(targetSelector);
checkboxes.forEach(function(checkbox) {
checkbox.checked = e.target.checked;
});
updateSelectedCount();
});
}
}
// 为行复选框添加事件监听
function setupRowCheckboxes() {
var checkboxes = document.querySelectorAll('.row-checkbox');
checkboxes.forEach(function(checkbox) {
checkbox.addEventListener('change', updateSelectedCount);
});
}
// 统一的删除确认函数
function confirmDelete() {
var checkboxes = document.querySelectorAll('.row-checkbox:checked');
var count = checkboxes.length;
if (count === 0) {
alert('请先选择要删除的记录!');
return false;
}
var confirmMsg = '确定要删除选中的 ' + count + ' 条记录吗?此操作不可恢复!';
if (!confirm(confirmMsg)) {
return false;
}
document.getElementById('hidden-submit').click();
return true;
}
// 初始化选择功能
document.addEventListener('DOMContentLoaded', function() {
setupSelectAll('#header-select-all', '.row-checkbox');
setupSelectAll('#thead-select-all', '.row-checkbox');
setupSelectAll('#footer-select-all', '.row-checkbox');
setupRowCheckboxes();
var headerDeleteBtn = document.getElementById('header-delete-btn');
var footerDeleteBtn = document.getElementById('footer-delete-btn');
if (headerDeleteBtn) {
headerDeleteBtn.addEventListener('click', function(e) {
e.preventDefault();
confirmDelete();
});
}
if (footerDeleteBtn) {
footerDeleteBtn.addEventListener('click', function(e) {
e.preventDefault();
confirmDelete();
});
}
updateSelectedCount();
});
// 编辑历史记录
document.addEventListener('DOMContentLoaded', function() {
var editButtons = document.querySelectorAll('.edit-btn');
editButtons.forEach(function(button) {
button.addEventListener('click', function() {
try {
var historyData = JSON.parse(this.getAttribute('data-history'));
editHistory(historyData);
} catch (e) {
console.error('解析历史记录数据失败:', e);
alert('编辑失败:数据格式错误');
}
});
});
});
function editHistory(history) {
document.getElementById('edit_id').value = history.id;
document.getElementById('edit_content').value = history.content;
var eventDate = new Date(history.event_date);
var year = eventDate.getFullYear();
var month = (eventDate.getMonth() + 1).toString().padStart(2, '0');
var day = eventDate.getDate().toString().padStart(2, '0');
document.getElementById('edit_event_date').value = year + '-' + month + '-' + day;
document.getElementById('edit_post_cids').value = history.post_cids || '';
document.getElementById('editModal').style.display = 'block';
}
// 关闭模态框
function closeModal() {
document.getElementById('editModal').style.display = 'none';
}
// 点击模态框外部关闭
window.onclick = function(event) {
var modal = document.getElementById('editModal');
if (event.target == modal) {
closeModal();
}
}
// 表单验证
document.querySelectorAll('form').forEach(function(form) {
if (form.querySelector('button[name="export"]')) return;
form.addEventListener('submit', function(e) {
var requiredFields = form.querySelectorAll('[required]');
var valid = true;
requiredFields.forEach(function(field) {
if (!field.value.trim()) {
valid = false;
field.style.borderColor = '#dc3545';
field.style.boxShadow = '0 0 0 0.2rem rgba(220,53,69,.25)';
} else {
field.style.borderColor = '#ced4da';
field.style.boxShadow = 'none';
}
});
if (!valid) {
e.preventDefault();
alert('请填写所有必填字段!');
}
});
});
// 导入文件验证
var importForm = document.querySelector('form[enctype="multipart/form-data"]');
if (importForm) {
importForm.addEventListener('submit', function(e) {
var fileInput = document.getElementById('import_file');
if (fileInput.files.length === 0) {
e.preventDefault();
alert('请选择要导入的文件!');
return;
}
var file = fileInput.files[0];
if (file.size > 5 * 1024 * 1024) {
e.preventDefault();
alert('文件大小不能超过5MB');
return;
}
if (!file.name.toLowerCase().endsWith('.txt')) {
if (!confirm('文件不是.txt格式确定要导入吗')) {
e.preventDefault();
}
}
});
}
</script>
<?php include 'footer.php'; ?>