229 lines
9.2 KiB
PHP
229 lines
9.2 KiB
PHP
<?php
|
|
require_once __DIR__ . '/layout.php';
|
|
|
|
$db = db();
|
|
|
|
// Helper to check permissions
|
|
if (!hasPermission('manage_kyc')) {
|
|
echo "权限不足";
|
|
exit;
|
|
}
|
|
|
|
// Handle Approve/Reject
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|
$id = (int)$_POST['user_id'];
|
|
|
|
// Safety check for agents
|
|
if ($admin['is_agent']) {
|
|
$stmt = $db->prepare("SELECT id FROM users WHERE id = ? AND agent_id = ?");
|
|
$stmt->execute([$id, $admin['id']]);
|
|
if (!$stmt->fetch()) exit("无权操作");
|
|
}
|
|
|
|
if ($_POST['action'] === 'approve') {
|
|
// Status 2: Verified (Standard)
|
|
$db->prepare("UPDATE users SET kyc_status = 2 WHERE id = ?")->execute([$id]);
|
|
header("Location: kyc.php?msg=approved");
|
|
exit;
|
|
}
|
|
if ($_POST['action'] === 'reject') {
|
|
$reason = $_POST['reason'] ?? '';
|
|
// Status 3: Rejected (Standard)
|
|
$db->prepare("UPDATE users SET kyc_status = 3, kyc_rejection_reason = ? WHERE id = ?")
|
|
->execute([$reason, $id]);
|
|
header("Location: kyc.php?msg=rejected");
|
|
exit;
|
|
}
|
|
}
|
|
|
|
$title = '实名认证审核';
|
|
ob_start();
|
|
|
|
$user_id = isset($_GET['user_id']) ? (int)$_GET['user_id'] : null;
|
|
if ($user_id) {
|
|
$sql = "SELECT * FROM users WHERE id = ?";
|
|
$params = [$user_id];
|
|
if ($admin['is_agent']) {
|
|
$sql .= " AND agent_id = ?";
|
|
$params[] = $admin['id'];
|
|
}
|
|
$stmt = $db->prepare($sql);
|
|
$stmt->execute($params);
|
|
$users = $stmt->fetchAll();
|
|
} else {
|
|
$sql = "SELECT * FROM users WHERE kyc_name IS NOT NULL";
|
|
$params = [];
|
|
if ($admin['is_agent']) {
|
|
$sql .= " AND agent_id = ?";
|
|
$params[] = $admin['id'];
|
|
}
|
|
$sql .= " ORDER BY CASE WHEN kyc_status = 1 THEN 0 ELSE 1 END, created_at DESC";
|
|
$stmt = $db->prepare($sql);
|
|
$stmt->execute($params);
|
|
$users = $stmt->fetchAll();
|
|
}
|
|
?>
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<div class="d-flex align-items-center gap-3">
|
|
<a href="users.php" class="btn btn-outline-secondary btn-sm"><i class="bi bi-arrow-left"></i> 返回</a>
|
|
<h4 class="mb-0"><?= $user_id ? '用户实名详情' : '实名认证列表' ?></h4>
|
|
</div>
|
|
<?php if ($user_id): ?>
|
|
<a href="kyc.php" class="btn btn-outline-secondary">查看全部</a>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="card p-3 mb-4 border-0 shadow-sm card-dismissible card-auto-dismiss" data-card-id="kyc_instructions">
|
|
<h6 class="fw-bold mb-2"><i class="bi bi-info-circle me-2"></i>实名审核说明</h6>
|
|
<p class="small text-muted mb-0">在此页面您可以审核用户的实名认证申请。请仔细对比用户提交的证件照片和填写的身份信息。审核通过后用户将获得认证标识。</p>
|
|
</div>
|
|
|
|
<?php if (isset($_GET['msg'])): ?>
|
|
<div class="alert alert-success mb-4">操作成功!</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="row g-4">
|
|
<?php foreach ($users as $u): ?>
|
|
<div class="col-md-12">
|
|
<div class="card shadow-sm mb-4">
|
|
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
|
<span>UID: <code><?= $u['uid'] ?></code> | 用户: <strong><?= htmlspecialchars($u['username']) ?></strong></span>
|
|
<span>
|
|
<?php if ($u['kyc_status'] == 1): ?>
|
|
<span class="badge bg-warning">待审核</span>
|
|
<?php elseif ($u['kyc_status'] == 2): ?>
|
|
<span class="badge bg-success">已通过</span>
|
|
<?php elseif ($u['kyc_status'] == 3): ?>
|
|
<span class="badge bg-danger">已拒绝</span>
|
|
<?php else: ?>
|
|
<span class="badge bg-secondary">未提交</span>
|
|
<?php endif; ?>
|
|
</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<p class="mb-1 text-muted small">真实姓名</p>
|
|
<h6><?= htmlspecialchars($u['kyc_name'] ?? '未填写') ?></h6>
|
|
<p class="mb-1 text-muted small mt-3">身份证号</p>
|
|
<h6><?= htmlspecialchars($u['kyc_id_number'] ?? '未填写') ?></h6>
|
|
|
|
<?php if ($u['kyc_status'] == 3 && $u['kyc_rejection_reason']): ?>
|
|
<div class="alert alert-danger mt-3 small">
|
|
拒绝理由: <?= htmlspecialchars($u['kyc_rejection_reason']) ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<div class="row g-2">
|
|
<div class="col-md-4">
|
|
<p class="small text-center mb-1">正面照</p>
|
|
<img src="<?= $u['kyc_photo_front'] ?: 'https://via.placeholder.com/300x200?text=No+Photo' ?>" class="img-fluid border rounded cursor-zoom-in" onclick="viewPhoto(this.src)">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<p class="small text-center mb-1">反面照</p>
|
|
<img src="<?= $u['kyc_photo_back'] ?: 'https://via.placeholder.com/300x200?text=No+Photo' ?>" class="img-fluid border rounded cursor-zoom-in" onclick="viewPhoto(this.src)">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<p class="small text-center mb-1">手持照</p>
|
|
<img src="<?= $u['kyc_photo_handheld'] ?: 'https://via.placeholder.com/300x200?text=No+Photo' ?>" class="img-fluid border rounded cursor-zoom-in" onclick="viewPhoto(this.src)">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php if ($u['kyc_status'] == 1): ?>
|
|
<div class="mt-4 pt-3 border-top d-flex gap-2">
|
|
<form method="POST" class="d-inline">
|
|
<input type="hidden" name="user_id" value="<?= $u['id'] ?>">
|
|
<input type="hidden" name="action" value="approve">
|
|
<button type="submit" class="btn btn-success" onclick="return confirm('确定通过审核吗?')">通过认证</button>
|
|
</form>
|
|
<button class="btn btn-danger" onclick="showRejectModal(<?= $u['id'] ?>)">拒绝申请</button>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
|
|
<?php if (empty($users)): ?>
|
|
<div class="col-12">
|
|
<div class="card p-5 text-center text-muted">
|
|
暂无实名认证申请
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Photo Viewer Modal -->
|
|
<div class="modal fade" id="photoViewModal" tabindex="-1">
|
|
<div class="modal-dialog modal-xl modal-dialog-centered">
|
|
<div class="modal-content bg-transparent border-0">
|
|
<div class="modal-body p-0 text-center position-relative">
|
|
<img id="viewerImage" src="" class="img-fluid rounded shadow-lg transition-all" style="max-height: 90vh; cursor: zoom-in;" onclick="toggleZoom(this)">
|
|
<button type="button" class="btn-close btn-close-white position-absolute top-0 end-0 m-3" data-bs-dismiss="modal" style="z-index: 1051;"></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Reject Modal -->
|
|
<div class="modal fade" id="rejectModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<form class="modal-content" method="POST">
|
|
<input type="hidden" name="action" value="reject">
|
|
<input type="hidden" name="user_id" id="reject_user_id">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">拒绝实名认证</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label">拒绝理由</label>
|
|
<textarea name="reason" class="form-control" rows="3" required placeholder="请说明拒绝原因..."></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
|
<button type="submit" class="btn btn-danger">确认拒绝</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.cursor-zoom-in { cursor: zoom-in; }
|
|
#viewerImage.zoomed {
|
|
transform: scale(1.5);
|
|
cursor: zoom-out;
|
|
}
|
|
.transition-all { transition: all 0.3s ease; }
|
|
</style>
|
|
|
|
<script>
|
|
function viewPhoto(src) {
|
|
const img = document.getElementById('viewerImage');
|
|
img.src = src;
|
|
img.classList.remove('zoomed');
|
|
new bootstrap.Modal(document.getElementById('photoViewModal')).show();
|
|
}
|
|
|
|
function toggleZoom(img) {
|
|
img.classList.toggle('zoomed');
|
|
}
|
|
|
|
|
|
function showRejectModal(id) {
|
|
document.getElementById('reject_user_id').value = id;
|
|
new bootstrap.Modal(document.getElementById('rejectModal')).show();
|
|
}
|
|
</script>
|
|
|
|
<?php
|
|
$content = ob_get_clean();
|
|
renderAdminPage($content, $title);
|
|
?>
|