<?php
// 禁止缓存
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Expires: 0');
// 开发环境清除 OPCache 缓存
if (function_exists('opcache_invalidate')) {
opcache_invalidate(__FILE__, true);
}
// 数据库配置
$host = '127.0.0.1';
$dbname = 'db_hk4e_config_gio';
$username = 'root';
$password = 'qq28009618'; // 请根据实际情况修改密码
$dsn = "mysql:host=$host;dbname=$dbname;charset=utf8mb4";
try {
$pdo = new PDO($dsn, $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_PERSISTENT, false);
} catch (PDOException $e) {
die("数据库连接失败: " . htmlspecialchars($e->getMessage()));
}
// 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save'])) {
$allowed_fields = [
'begin_time',
'end_time',
'gacha_up_config',
'gacha_prefab_path',
'gacha_preview_prefab_path',
'title_textmap'
];
foreach ($_POST['rows'] as $key => $data) {
$schedule_id = trim(urldecode($key));
$setParts = [];
$params = [];
foreach ($allowed_fields as $field) {
if (isset($data[$field])) {
$value = trim($data[$field]);
$setParts[] = "`$field` = ?";
$params[] = $value;
}
}
if (!empty($setParts)) {
$params[] = $schedule_id;
$sql = "UPDATE `t_gacha_schedule_config` SET " . implode(', ', $setParts) . " WHERE `schedule_id` = ?";
try {
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
} catch (Exception $ex) {
echo "<div style='color:red;'>更新失败 (ID: $schedule_id): " . htmlspecialchars($ex->getMessage()) . "</div><br>";
}
}
}
// 显示成功提示并自动刷新
echo "<div style='color:green; font-weight:bold;'>✅ 所有更改已成功保存!</div><br>";
// 重新查询最新数据
$stmt = $pdo->query("SELECT schedule_id, begin_time, end_time, gacha_up_config,
gacha_prefab_path, gacha_preview_prefab_path, title_textmap
FROM t_gacha_schedule_config");
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
} else {
try {
$stmt = $pdo->query("SELECT schedule_id, begin_time, end_time, gacha_up_config,
gacha_prefab_path, gacha_preview_prefab_path, title_textmap
FROM t_gacha_schedule_config");
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {
die("<div style='color:red;'>查询失败: " . htmlspecialchars($e->getMessage()) . "</div>");
}
}
// 根据 schedule_id 返回卡池名称
function getPoolName($id) {
switch ((int)$id) {
case 893: return '角色UP1卡池';
case 903: return '角色UP2卡池';
case 913: return '角色常驻卡池';
case 923: return '武器UP1卡池';
case 933: return '武器常驻卡池';
default: return "未知卡池($id)";
}
}
?>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>抽卡活动配置 - 五星/四星UP编辑</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 20px;
background-color: #f9f9f9;
color: #333;
}
h1 {
color: #2c3e50;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
background-color: white;
}
th, td {
border: 1px solid #ddd;
padding: 10px;
text-align: left;
vertical-align: top;
}
th {
background-color: #4CAF50;
color: white;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
input[type="text"], input[type="datetime-local"], textarea {
width: 100%;
padding: 5px;
box-sizing: border-box;
font-family: monospace;
border: 1px solid #ccc;
border-radius: 4px;
}
.action {
text-align: center;
margin-bottom: 20px;
}
button {
padding: 10px 20px;
font-size: 16px;
background-color: #007BFF;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
transition: background-color 0.3s;
}
button:hover {
background-color: #0056b3;
}
.pool-label {
display: inline-block;
padding: 5px 10px;
font-size: 14px;
background-color: #607D8B;
color: white;
border: none;
border-radius: 4px;
margin-right: 10px;
text-align: center;
min-width: 100px;
height: 32px;
line-height: 16px;
vertical-align: middle;
}
.star-btn {
margin-right: 10px;
background-color: #e91e63;
color: white;
padding: 5px 10px;
font-size: 14px;
border: none;
border-radius: 4px;
cursor: pointer;
height: 32px;
line-height: 16px;
vertical-align: middle;
}
.star-btn:hover {
background-color: #c2185b;
}
.modal {
display: none;
position: fixed;
z-index: 2000;
left: 0; top: 0;
width: 100%; height: 100%;
background-color: rgba(0,0,0,0.5);
align-items: center;
justify-content: center;
}
.modal-content {
background-color: #fff;
padding: 25px;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
width: 400px;
max-width: 90%;
text-align: center;
animation: fadeIn 0.3s ease-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: scale(0.9); }
to { opacity: 1; transform: scale(1); }
}
.modal-header {
font-size: 1.4em;
margin-bottom: 15px;
color: #333;
}
.modal-body {
margin: 15px 0;
color: #555;
font-size: 1.1em;
}
.modal-footer {
margin-top: 20px;
display: flex;
gap: 10px;
justify-content: center;
}
.btn-confirm {
background-color: #28a745;
}
.btn-cancel {
background-color: #dc3545;
}
.btn-confirm:hover {
background-color: #218838;
}
.btn-cancel:hover {
background-color: #c82333;
}
.close {
float: right;
font-size: 24px;
font-weight: bold;
cursor: pointer;
color: #aaa;
}
.close:hover {
color: #000;
}
/* 固定宽度复选框容器 */
.item-list {
max-height: 300px;
overflow-y: auto;
border: 1px solid #ddd;
padding: 10px;
margin-top: 10px;
border-radius: 4px;
text-align: left;
}
.item-list label {
display: flex;
align-items: center;
margin: 5px 0;
padding: 4px 0;
cursor: pointer;
font-size: 14px;
}
.item-list input[type="checkbox"] {
margin-right: 10px;
min-width: 18px;
height: 18px;
}
.item-list span {
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
</head>
<body>
<h1>抽卡活动配置表 - 支持五星/四星UP编辑 💯</h1>
<p><strong>📌 提示:每行左侧显示卡池类型,点击 ⭐ 或 ⭐⭐ 按钮选择UP角色</strong></p>
<form method="post" id="editForm">
<?php if ($results): ?>
<table>
<thead>
<tr>
<th>开始时间</th>
<th>结束时间</th>
<th>UP 配置</th>
<th>Prefab 路径</th>
<th>预览 Prefab 路径</th>
<th>标题文本</th>
</tr>
</thead>
<tbody>
<?php foreach ($results as $row): ?>
<tr>
<!-- 开始时间 -->
<td>
<input type="datetime-local" name="rows[<?= urlencode($row['schedule_id']) ?>][begin_time]"
value="<?= date('Y-m-d\TH:i', strtotime($row['begin_time'])) ?>"
step="60" autocomplete="off">
</td>
<!-- 结束时间 -->
<td>
<input type="datetime-local" name="rows[<?= urlencode($row['schedule_id']) ?>][end_time]"
value="<?= date('Y-m-d\TH:i', strtotime($row['end_time'])) ?>"
step="60" autocomplete="off">
</td>
<!-- UP 配置 -->
<td>
<textarea name="rows[<?= urlencode($row['schedule_id']) ?>][gacha_up_config]"
rows="3"
style="width:100%; resize:none;"
placeholder='{"gacha_up_list":[{"item_parent_type":1,...}]}'
autocomplete="off"><?= htmlspecialchars($row['gacha_up_config']) ?></textarea>
<!-- 卡池名称 + 按钮组 -->
<div style="margin-top: 5px;">
<!-- 卡池名称(只读) -->
<span class="pool-label">
<?= htmlspecialchars(getPoolName($row['schedule_id'])) ?>
</span>
<!-- 五星按钮 -->
<button type="button" class="star-btn"
data-target="rows[<?= urlencode($row['schedule_id']) ?>][gacha_up_config]"
data-star="5">
⭐ 五星
</button>
<!-- 四星按钮 -->
<button type="button" class="star-btn"
data-target="rows[<?= urlencode($row['schedule_id']) ?>][gacha_up_config]"
data-star="4">
⭐⭐ 四星
</button>
</div>
</td>
<!-- Prefab 路径 -->
<td>
<input type="text" name="rows[<?= urlencode($row['schedule_id']) ?>][gacha_prefab_path]"
value="<?= htmlspecialchars($row['gacha_prefab_path']) ?>"
autocomplete="off">
</td>
<!-- 预览 Prefab 路径 -->
<td>
<input type="text" name="rows[<?= urlencode($row['schedule_id']) ?>][gacha_preview_prefab_path]"
value="<?= htmlspecialchars($row['gacha_preview_prefab_path']) ?>"
autocomplete="off">
</td>
<!-- 标题文本 -->
<td>
<input type="text" name="rows[<?= urlencode($row['schedule_id']) ?>][title_textmap]"
value="<?= htmlspecialchars($row['title_textmap']) ?>"
autocomplete="off">
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<div class="action">
<button type="button" id="showConfirmModal">💾 保存所有修改</button>
</div>
<?php else: ?>
<p>❌ 没有找到任何数据,请检查数据库。</p>
<?php endif; ?>
</form>
<!-- 自定义确认模态框 -->
<div id="confirmModal" class="modal">
<div class="modal-content">
<div class="modal-header">⚠️ 确认保存</div>
<div class="modal-body">
确定要保存所有修改吗?<br>
此操作将提交更改并刷新页面。
</div>
<div class="modal-footer">
<button class="btn-confirm" id="confirmSave">✅ 确定</button>
<button class="btn-cancel" id="cancelSave">❌ 取消</button>
</div>
</div>
</div>
<!-- 角色选择模态框 -->
<div id="upModal" class="modal">
<div class="modal-content">
<span class="close">×</span>
<h3 id="modalTitle">选择UP角色</h3>
<div id="itemList" class="item-list"></div>
<p style="text-align:center;"><button onclick="applySelection()">🟢 确认选择</button></p>
</div>
</div>
<script>
let currentTextarea = null;
let currentStarLevel = 5;
// 绑定按钮事件
document.querySelectorAll('.star-btn').forEach(btn => {
btn.addEventListener('click', function () {
currentTextarea = document.querySelector(`[name="${this.dataset.target}"]`);
currentStarLevel = parseInt(this.dataset.star);
document.getElementById('modalTitle').textContent =
currentStarLevel === 5 ? '选择五星UP角色' : '选择四星UP角色';
document.getElementById('upModal').style.display = 'flex';
loadItems(currentStarLevel === 5 ? 'kachi5.txt' : 'kachi4.txt');
});
});
// 关闭模态框
document.querySelector('#upModal .close').onclick = function () {
document.getElementById('upModal').style.display = 'none';
};
window.onclick = function (event) {
const upModal = document.getElementById('upModal');
const confirmModal = document.getElementById('confirmModal');
if (event.target === upModal) {
upModal.style.display = 'none';
}
if (event.target === confirmModal) {
confirmModal.style.display = 'none';
}
};
// 加载 txt 文件
function loadItems(filename) {
fetch(filename + '?t=' + Date.now())
.then(res => {
if (!res.ok) throw new Error('文件未找到: ' + filename);
return res.text();
})
.then(text => {
const lines = text.split('\n').filter(line => line.trim());
const container = document.getElementById('itemList');
container.innerHTML = '';
lines.forEach(line => {
const match = line.trim().match(/^(\d+):(.+)$/);
if (match) {
const id = match[1];
const name = match[2].trim();
const label = document.createElement('label');
label.style.display = 'flex';
label.style.alignItems = 'center';
label.style.margin = '5px 0';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.value = id;
checkbox.style.minWidth = '18px';
checkbox.style.height = '18px';
checkbox.style.marginRight = '10px';
const span = document.createElement('span');
span.textContent = `${id}: ${name}`;
span.style.whiteSpace = 'nowrap';
span.style.overflow = 'hidden';
span.style.textOverflow = 'ellipsis';
label.appendChild(checkbox);
label.appendChild(span);
container.appendChild(label);
}
});
})
.catch(err => {
alert('加载失败: ' + err.message);
});
}
// 应用选择结果 ✅ 已修复 bug
function applySelection() {
if (!currentTextarea) {
alert("内部错误:未绑定目标文本域!");
return;
}
const selectedIds = Array.from(document.querySelectorAll('#itemList input:checked'))
.map(el => parseInt(el.value))
.filter(id => !isNaN(id));
if (selectedIds.length === 0) {
alert("请至少选择一个角色!");
return;
}
let rawData, upListArray, wasWrapped = false;
try {
const rawText = currentTextarea.value.trim();
if (!rawText) {
rawData = { gacha_up_list: [] };
wasWrapped = true;
} else {
rawData = JSON.parse(rawText);
}
if (rawData && typeof rawData === 'object' && Array.isArray(rawData.gacha_up_list)) {
upListArray = rawData.gacha_up_list;
wasWrapped = true;
} else if (Array.isArray(rawData)) {
upListArray = rawData;
wasWrapped = false;
} else {
throw new Error("根节点必须是数组或包含 gacha_up_list 的对象");
}
} catch (e) {
alert("UP配置字段不是合法JSON,请检查。\n错误:" + e.message);
return;
}
const targetType = currentStarLevel === 5 ? 1 : 2; // 1=五星, 2=四星
// ✅ 修复了这里:item.item_list 不是 item_list
const existingIndex = upListArray.findIndex(item =>
item.item_parent_type === targetType &&
item.item_list && Array.isArray(item.item_list) // ✅ 正确写法
);
if (existingIndex > -1) {
upListArray[existingIndex].item_list = selectedIds;
} else {
upListArray.push({
item_parent_type: targetType,
prob: targetType === 1 ? 500 : 600,
item_list: selectedIds
});
}
const output = wasWrapped ?
JSON.stringify({ gacha_up_list: upListArray }, null, 0) :
JSON.stringify(upListArray, null, 0);
try {
currentTextarea.value = output;
alert(`✅ 已更新 ${selectedIds.length} 个角色为UP项!`);
document.getElementById('upModal').style.display = 'none';
} catch (e) {
alert("序列化失败:" + e.message);
}
}
// 显示确认模态框
document.getElementById('showConfirmModal').addEventListener('click', function () {
document.getElementById('confirmModal').style.display = 'flex';
});
// 取消保存
document.getElementById('cancelSave').addEventListener('click', function () {
document.getElementById('confirmModal').style.display = 'none';
});
// 确定保存 → 提交表单
document.getElementById('confirmSave').addEventListener('click', function () {
document.getElementById('confirmModal').style.display = 'none';
const form = document.getElementById('editForm');
const input = document.createElement('input');
input.type = 'hidden';
input.name = 'save';
input.value = '1';
form.appendChild(input);
form.submit(); // 提交后页面会刷新
});
</script>
</body>
</html>
不更改内容 只删除 注释
最新发布