231 lines
10 KiB
PHP
231 lines
10 KiB
PHP
<?php
|
|
require_once __DIR__ . '/includes/auth.php';
|
|
require_once __DIR__ . '/includes/functions.php';
|
|
requireAdmin();
|
|
|
|
$pageTitle = '产品管理';
|
|
require __DIR__ . '/includes/header.php';
|
|
|
|
$msg = '';
|
|
|
|
// 新增
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add'])) {
|
|
if (!verifyCsrf($_POST['csrf_token'] ?? '')) { die('CSRF token无效'); }
|
|
$code = trim($_POST['code'] ?? '');
|
|
$name = trim($_POST['name'] ?? '');
|
|
$apiUrl = trim($_POST['api_url'] ?? '');
|
|
$token = trim($_POST['token'] ?? '');
|
|
$remark = trim($_POST['remark'] ?? '');
|
|
if ($code === '') {
|
|
$msg = '<div class="alert alert-danger">产品ID不能为空</div>';
|
|
} elseif ($name === '') {
|
|
$msg = '<div class="alert alert-danger">产品名称不能为空</div>';
|
|
} else {
|
|
$stmt = $pdo->prepare('SELECT id FROM products WHERE code = ?');
|
|
$stmt->execute([$code]);
|
|
if ($stmt->fetch()) {
|
|
$msg = '<div class="alert alert-danger">产品ID已存在</div>';
|
|
} else {
|
|
$stmt = $pdo->prepare('INSERT INTO products (code, name, api_url, token, remark) VALUES (?, ?, ?, ?, ?)');
|
|
$stmt->execute([$code, $name, $apiUrl ?: null, $token ?: null, $remark ?: null]);
|
|
$_SESSION['flash_msg'] = '产品已添加';
|
|
$_SESSION['flash_type'] = 'success';
|
|
header('Location: product_manage.php');
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 编辑
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['edit'])) {
|
|
if (!verifyCsrf($_POST['csrf_token'] ?? '')) { die('CSRF token无效'); }
|
|
$id = (int)($_POST['id'] ?? 0);
|
|
$code = trim($_POST['code'] ?? '');
|
|
$name = trim($_POST['name'] ?? '');
|
|
$apiUrl = trim($_POST['api_url'] ?? '');
|
|
$token = trim($_POST['token'] ?? '');
|
|
$remark = trim($_POST['remark'] ?? '');
|
|
if ($code === '') {
|
|
$msg = '<div class="alert alert-danger">产品ID不能为空</div>';
|
|
} elseif ($name === '') {
|
|
$msg = '<div class="alert alert-danger">产品名称不能为空</div>';
|
|
} else {
|
|
$stmt = $pdo->prepare('SELECT id FROM products WHERE code = ? AND id != ?');
|
|
$stmt->execute([$code, $id]);
|
|
if ($stmt->fetch()) {
|
|
$msg = '<div class="alert alert-danger">产品ID已被其他产品使用</div>';
|
|
} else {
|
|
$stmt = $pdo->prepare('UPDATE products SET code = ?, name = ?, api_url = ?, token = ?, remark = ?, updated_at = NOW(), updated_by = ? WHERE id = ?');
|
|
$stmt->execute([$code, $name, $apiUrl ?: null, $token ?: null, $remark ?: null, getCurrentUserId(), $id]);
|
|
$_SESSION['flash_msg'] = '产品已更新';
|
|
$_SESSION['flash_type'] = 'success';
|
|
header('Location: product_manage.php');
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 切换状态
|
|
if (isset($_GET['toggle']) && is_numeric($_GET['toggle'])) {
|
|
if (!verifyCsrf($_GET['csrf_token'] ?? '')) {
|
|
$_SESSION['flash_msg'] = 'CSRF token无效';
|
|
$_SESSION['flash_type'] = 'danger';
|
|
} else {
|
|
$id = (int)$_GET['toggle'];
|
|
$stmt = $pdo->prepare('SELECT status FROM products WHERE id = ?');
|
|
$stmt->execute([$id]);
|
|
$current = (int)$stmt->fetchColumn();
|
|
$newStatus = $current ? 0 : 1;
|
|
$stmt = $pdo->prepare('UPDATE products SET status = ?, updated_at = NOW(), updated_by = ? WHERE id = ?');
|
|
$stmt->execute([$newStatus, getCurrentUserId(), $id]);
|
|
$_SESSION['flash_msg'] = $newStatus ? '产品已启用' : '产品已禁用';
|
|
$_SESSION['flash_type'] = 'success';
|
|
}
|
|
header('Location: product_manage.php');
|
|
exit;
|
|
}
|
|
|
|
$stmt = $pdo->query('SELECT p.*, u.username FROM products p LEFT JOIN users u ON p.updated_by = u.id ORDER BY p.id ASC');
|
|
$products = $stmt->fetchAll();
|
|
?>
|
|
<div class="card">
|
|
<h2>产品管理</h2>
|
|
<?php if (isset($_SESSION['flash_msg'])): ?>
|
|
<div class="alert alert-<?= h($_SESSION['flash_type'] ?? 'success') ?>"><?= h($_SESSION['flash_msg']) ?></div>
|
|
<?php unset($_SESSION['flash_msg'], $_SESSION['flash_type']); ?>
|
|
<?php endif; ?>
|
|
<?= $msg ?>
|
|
<div style="margin-bottom:16px;">
|
|
<a href="javascript:void(0)" class="btn btn-success" onclick="showModal('addModal')">+ 新增产品</a>
|
|
</div>
|
|
<div class="table-wrapper">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>产品ID</th>
|
|
<th>产品名称</th>
|
|
<th>接口地址</th>
|
|
<th>Token</th>
|
|
<th>备注</th>
|
|
<th>状态</th>
|
|
<th>修改时间</th>
|
|
<th>修改用户</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($products as $p): ?>
|
|
<tr>
|
|
<td><?= $p['id'] ?></td>
|
|
<td><code><?= h($p['code']) ?></code></td>
|
|
<td><?= h($p['name']) ?></td>
|
|
<td><?= h($p['api_url'] ?? '-') ?></td>
|
|
<td><?= $p['token'] ? h(maskCode($p['token'])) : '-' ?></td>
|
|
<td><?= h($p['remark'] ?? '-') ?></td>
|
|
<td><?= $p['status'] ? '<span class="badge badge-success">启用</span>' : '<span class="badge badge-danger">禁用</span>' ?></td>
|
|
<td><?= formatDateTime($p['updated_at']) ?></td>
|
|
<td><?= h($p['username'] ?? '-') ?></td>
|
|
<td>
|
|
<div class="action-group">
|
|
<a href="javascript:void(0)" class="btn btn-primary btn-sm" onclick="editProduct(<?= $p['id'] ?>, '<?= h($p['code']) ?>', '<?= h($p['name']) ?>', '<?= h($p['api_url'] ?? '') ?>', '<?= h($p['token'] ?? '') ?>', '<?= h($p['remark'] ?? '') ?>')">编辑</a>
|
|
<?php if ($p['status']): ?>
|
|
<a href="?toggle=<?= $p['id'] ?>&csrf_token=<?= csrfToken() ?>" class="btn btn-warning btn-sm" onclick="return confirm('确定禁用此产品?')">禁用</a>
|
|
<?php else: ?>
|
|
<a href="?toggle=<?= $p['id'] ?>&csrf_token=<?= csrfToken() ?>" class="btn btn-success btn-sm">启用</a>
|
|
<?php endif; ?>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php if (empty($products)): ?>
|
|
<tr><td colspan="10" style="text-align:center;color:#999;">暂无产品</td></tr>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 新增弹窗 -->
|
|
<div class="modal" id="addModal">
|
|
<div class="modal-content">
|
|
<span class="modal-close" onclick="hideModal('addModal')">×</span>
|
|
<h3>新增产品</h3>
|
|
<form method="post">
|
|
<input type="hidden" name="csrf_token" value="<?= csrfToken() ?>">
|
|
<div class="form-group">
|
|
<label>产品ID <span style="color:red">*</span></label>
|
|
<input type="text" name="code" class="form-control" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>产品名称 <span style="color:red">*</span></label>
|
|
<input type="text" name="name" class="form-control" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>接口地址</label>
|
|
<input type="text" name="api_url" class="form-control" placeholder="https://example.com/api">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Token</label>
|
|
<input type="text" name="token" class="form-control" placeholder="接口认证Token">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>备注</label>
|
|
<input type="text" name="remark" class="form-control" placeholder="选填">
|
|
</div>
|
|
<button type="submit" name="add" class="btn btn-success">添加</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 编辑弹窗 -->
|
|
<div class="modal" id="editModal">
|
|
<div class="modal-content">
|
|
<span class="modal-close" onclick="hideModal('editModal')">×</span>
|
|
<h3>编辑产品</h3>
|
|
<form method="post">
|
|
<input type="hidden" name="csrf_token" value="<?= csrfToken() ?>">
|
|
<input type="hidden" name="id" id="edit_id">
|
|
<div class="form-group">
|
|
<label>产品ID <span style="color:red">*</span></label>
|
|
<input type="text" name="code" class="form-control" id="edit_code" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>产品名称 <span style="color:red">*</span></label>
|
|
<input type="text" name="name" class="form-control" id="edit_name" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>接口地址</label>
|
|
<input type="text" name="api_url" class="form-control" id="edit_api_url" placeholder="https://example.com/api">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Token</label>
|
|
<input type="text" name="token" class="form-control" id="edit_token" placeholder="接口认证Token">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>备注</label>
|
|
<input type="text" name="remark" class="form-control" id="edit_remark" placeholder="选填">
|
|
</div>
|
|
<button type="submit" name="edit" class="btn btn-primary">保存</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function showModal(id) { document.getElementById(id).classList.add('active'); }
|
|
function hideModal(id) { document.getElementById(id).classList.remove('active'); }
|
|
function editProduct(id, code, name, apiUrl, token, remark) {
|
|
document.getElementById('edit_id').value = id;
|
|
document.getElementById('edit_code').value = code;
|
|
document.getElementById('edit_name').value = name;
|
|
document.getElementById('edit_api_url').value = apiUrl;
|
|
document.getElementById('edit_token').value = token;
|
|
document.getElementById('edit_remark').value = remark;
|
|
showModal('editModal');
|
|
}
|
|
document.querySelectorAll('.modal').forEach(function(m) {
|
|
m.addEventListener('click', function(e) { if (e.target === this) this.classList.remove('active'); });
|
|
});
|
|
</script>
|
|
<?php require __DIR__ . '/includes/footer.php'; ?>
|