初始化

This commit is contained in:
2026-08-08 18:28:49 +08:00
parent 9bef4420e0
commit f082037a6e
854 changed files with 217171 additions and 11 deletions
+173
View File
@@ -0,0 +1,173 @@
<?php
$activeMenu = 'databaseUpgrade';
include APP_PATH . 'app/views/layouts/admin_header.php';
?>
<style>
.sql-preview {
background: #1e1e1e;
color: #d4d4d4;
font-family: 'Consolas', 'Courier New', monospace;
font-size: 12px;
padding: 10px 15px;
border-radius: 4px;
max-height: 300px;
overflow-y: auto;
white-space: pre-wrap;
word-break: break-all;
line-height: 1.5;
margin: 0;
}
.sql-preview::-webkit-scrollbar { width: 6px; }
.sql-preview::-webkit-scrollbar-track { background: #2d2d2d; }
.sql-preview::-webkit-scrollbar-thumb { background: #555; border-radius: 3px; }
.badge-status { font-size: 12px; }
.btn-execute-all { margin-left: 10px; }
</style>
<?php if (!empty($message)): ?>
<div class="row">
<div class="col-md-12">
<div class="alert alert-<?php echo $messageType; ?> alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<h4><i class="icon fa fa-<?php echo $messageType === 'success' ? 'check' : ($messageType === 'danger' ? 'ban' : 'warning'); ?>"></i> 提示</h4>
<?php echo nl2br(htmlspecialchars($message)); ?>
</div>
</div>
</div>
<?php endif; ?>
<div class="row">
<div class="col-md-12">
<div class="box box-success">
<div class="box-header with-border">
<h3 class="box-title"><i class="fa fa-wrench"></i> 数据库升级/迁移</h3>
<div class="box-tools">
<?php if ($pendingCount > 0): ?>
<span class="badge bg-yellow" style="font-size:13px;"><?php echo $pendingCount; ?> 个待执行</span>
<form method="post" style="display:inline;" class="confirm-form" data-confirm="确定要一键执行所有未执行的迁移脚本吗?此操作将按文件名顺序依次执行所有未执行过的 .sql 文件。">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrfToken); ?>">
<input type="hidden" name="action" value="execute_all">
<button type="submit" class="btn btn-sm btn-success btn-execute-all">
<i class="fa fa-bolt"></i> 一键全部执行
</button>
</form>
<?php else: ?>
<span class="badge bg-green" style="font-size:13px;">全部已执行</span>
<?php endif; ?>
</div>
</div>
<div class="box-body">
<div class="callout callout-info" style="margin-bottom: 15px;">
<h4><i class="icon fa fa-info-circle"></i> 使用说明</h4>
<p style="margin-bottom:0;">
1. 系统会自动扫描 <code>sql/</code> 目录下的所有 <code>.sql</code> 文件。<br>
2. 已执行过的脚本会标记为 <span class="label label-success">已执行</span>,不会重复执行。<br>
3. 每个脚本在事务中执行,失败会自动回滚。<br>
4. 点击文件名可展开查看 SQL 内容预览。
</p>
</div>
<?php if (empty($fileList)): ?>
<div class="text-center" style="padding: 40px;">
<i class="fa fa-inbox" style="font-size: 48px; color: #ccc;"></i>
<p style="color: #999; margin-top: 10px;">sql/ 目录下没有找到 .sql 迁移文件</p>
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th style="width: 40px;">#</th>
<th>文件名</th>
<th style="width: 100px;">状态</th>
<th style="width: 160px;">执行时间</th>
<th style="width: 120px;">操作</th>
</tr>
</thead>
<tbody>
<?php $idx = 1; foreach ($fileList as $file): ?>
<tr>
<td><?php echo $idx++; ?></td>
<td>
<a href="#" class="sql-preview-link" data-preview="preview-<?php echo $idx; ?>" style="font-family: monospace;">
<i class="fa fa-file-code-o"></i> <?php echo htmlspecialchars($file['name']); ?>
</a>
<div id="preview-<?php echo $idx; ?>" class="sql-preview" style="display:none; margin-top:8px;">
<?php echo $file['preview']; ?>
</div>
</td>
<td>
<?php if ($file['is_migrated']): ?>
<?php if ($file['status'] == 1): ?>
<span class="label label-success">已执行</span>
<?php else: ?>
<span class="label label-danger" title="<?php echo htmlspecialchars($file['error_msg']); ?>">执行失败</span>
<?php endif; ?>
<?php else: ?>
<span class="label label-warning">待执行</span>
<?php endif; ?>
</td>
<td>
<?php if ($file['is_migrated'] && $file['executed_at']): ?>
<small><?php echo htmlspecialchars($file['executed_at']); ?></small>
<?php else: ?>
<small style="color:#999;">—</small>
<?php endif; ?>
</td>
<td>
<?php if (!$file['is_migrated'] || $file['status'] == 0): ?>
<form method="post" style="display:inline;" class="confirm-form" data-confirm="确定要执行该迁移脚本吗?">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrfToken); ?>">
<input type="hidden" name="action" value="execute">
<input type="hidden" name="file" value="<?php echo htmlspecialchars($file['name']); ?>">
<button type="submit" class="btn btn-sm btn-primary">
<i class="fa fa-play"></i> 执行
</button>
</form>
<?php else: ?>
<button class="btn btn-sm btn-default" disabled>
<i class="fa fa-check"></i> 已完成
</button>
<?php endif; ?>
<?php if ($file['is_migrated'] && $file['status'] == 0 && !empty($file['error_msg'])): ?>
<br><small class="text-danger" style="display:inline-block;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="<?php echo htmlspecialchars($file['error_msg']); ?>"><?php echo htmlspecialchars($file['error_msg']); ?></small>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
<script nonce="<?php echo csp_nonce(); ?>">
function togglePreview(link, previewId) {
var preview = document.getElementById(previewId);
var icon = link.querySelector('i');
if (preview.style.display === 'none' || preview.style.display === '') {
preview.style.display = 'block';
if (icon) {
icon.className = 'fa fa-file-code-o';
}
} else {
preview.style.display = 'none';
if (icon) {
icon.className = 'fa fa-file-code-o';
}
}
}
// CSP:文件名预览切换改为事件委托(替代内联 onclick / javascript:
document.addEventListener('click', function (e) {
var link = e.target.closest ? e.target.closest('.sql-preview-link') : null;
if (!link) return;
e.preventDefault();
togglePreview(link, link.getAttribute('data-preview'));
});
</script>
<?php include APP_PATH . 'app/views/layouts/admin_footer.php'; ?>