coupon/bill_records.php

284 lines
13 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
require_once __DIR__ . '/includes/auth.php';
require_once __DIR__ . '/includes/functions.php';
requireLogin();
$pageTitle = '账单管理';
require __DIR__ . '/includes/header.php';
$isAdmin = isAdmin();
$userId = $isAdmin ? (int)($_GET['user_id'] ?? 0) : getCurrentUserId();
$detailDate = $_GET['date'] ?? '';
$detailUserId = (int)($_GET['duid'] ?? $userId);
$startDate = $_GET['start_date'] ?? '';
$endDate = $_GET['end_date'] ?? '';
// 管理员:修改账单状态
$statusMsg = '';
if ($isAdmin && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
if (!verifyCsrf($_POST['csrf_token'] ?? '')) { die('CSRF token无效'); }
if ($_POST['action'] === 'set_bill_status') {
$sDate = $_POST['bill_date'] ?? '';
$sUserId = (int)($_POST['user_id'] ?? 0);
$sStatus = $_POST['status'] ?? '';
$sStartDate = $_POST['start_date'] ?? '';
$sEndDate = $_POST['end_date'] ?? '';
if ($sDate && $sUserId > 0 && in_array($sStatus, ['未结算', '已结算', '已作废'])) {
$stmt = $pdo->prepare('INSERT INTO bill_status (bill_date, user_id, status, updated_at, updated_by) VALUES (?, ?, ?, NOW(), ?) ON DUPLICATE KEY UPDATE status = ?, updated_at = NOW(), updated_by = ?');
$stmt->execute([$sDate, $sUserId, $sStatus, getCurrentUserId(), $sStatus, getCurrentUserId()]);
$_SESSION['flash_msg'] = '账单状态已更新';
$_SESSION['flash_type'] = 'success';
$queryRedirect = [];
$filterUserId = $userId; // 保留原始筛选条件
if ($filterUserId > 0) $queryRedirect[] = 'user_id=' . $filterUserId;
if ($sStartDate) $queryRedirect[] = 'start_date=' . $sStartDate;
if ($sEndDate) $queryRedirect[] = 'end_date=' . $sEndDate;
header('Location: bill_records.php' . ($queryRedirect ? '?' . implode('&', $queryRedirect) : ''));
exit;
} else {
$statusMsg = '<div class="alert alert-danger">参数错误</div>';
}
}
}
// 详情模式
if ($detailDate) {
$pid = getCurrentProductId();
$where = 'WHERE r.status = 2 AND r.product_id = ? AND DATE(r.used_at) = ?';
$params = [$pid, $detailDate];
if ($detailUserId > 0) {
$where .= ' AND r.user_id = ?';
$params[] = $detailUserId;
}
$stmt = $pdo->prepare("SELECT r.*, u.username FROM claim_records r LEFT JOIN users u ON r.user_id = u.id $where ORDER BY r.id ASC");
$stmt->execute($params);
$details = $stmt->fetchAll();
// 读取该日该用户的账单状态
$stmt = $pdo->prepare("SELECT status FROM bill_status WHERE bill_date = ? AND user_id = ?");
$stmt->execute([$detailDate, $detailUserId]);
$billStatus = $stmt->fetchColumn() ?: '未结算';
?>
<div class="card">
<h2>
账单明细 - <?= h($detailDate) ?>
<?php if ($detailUserId > 0 && isset($details[0]['username'])): ?>
<?= h($details[0]['username']) ?>
<?php endif; ?>
<span style="font-size:14px;font-weight:normal;margin-left:12px;">状态:<?= billStatusBadge($billStatus) ?></span>
</h2>
<div style="margin-bottom:16px;">
<a href="bill_records.php<?= $userId > 0 ? '?user_id=' . $userId : '' ?><?= $startDate ? '&start_date=' . $startDate : '' ?><?= $endDate ? '&end_date=' . $endDate : '' ?>" class="btn btn-primary btn-sm">← 返回</a>
</div>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>ID</th>
<th>兑换码名称</th>
<th>批次号</th>
<th>兑换码</th>
<th>面值</th>
<th>使用时间</th>
<th>会员ID</th>
<th>用户</th>
<th>出货价一档</th>
<th>出货价二挡</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<?php foreach ($details as $r): ?>
<tr>
<td><?= $r['id'] ?></td>
<td><?= h($r['code_name']) ?></td>
<td><?= h($r['batch_no']) ?></td>
<td><?= h($r['code']) ?></td>
<td><?= h($r['value']) ?></td>
<td><?= formatDateTime($r['used_at']) ?></td>
<td><?= h($r['used_user_id'] ?? '-') ?></td>
<td><?= h($r['username'] ?? '-') ?></td>
<td><?= $r['price_tier1'] !== null ? h($r['price_tier1']) : '-' ?></td>
<td><?= $r['price_tier2'] !== null ? h($r['price_tier2']) : '-' ?></td>
<td><?= h($r['remark'] ?? '') ?></td>
</tr>
<?php endforeach; ?>
<?php if (empty($details)): ?>
<tr><td colspan="11" style="text-align:center;color:#999;">暂无数据</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<?php
require __DIR__ . '/includes/footer.php';
exit;
}
// 汇总模式
$page = max(1, (int)($_GET['p'] ?? 1));
$perPage = 30;
$offset = ($page - 1) * $perPage;
$pid = getCurrentProductId();
$where = 'WHERE r.status = 2 AND r.product_id = ?';
$params = [$pid];
if ($userId > 0) {
$where .= ' AND r.user_id = ?';
$params[] = $userId;
}
if ($startDate) {
$where .= ' AND DATE(r.used_at) >= ?';
$params[] = $startDate;
}
if ($endDate) {
$where .= ' AND DATE(r.used_at) <= ?';
$params[] = $endDate;
}
$stmt = $pdo->prepare("SELECT COUNT(DISTINCT DATE(r.used_at)" . ($userId > 0 ? "" : ", r.user_id") . ") FROM claim_records r $where");
$stmt->execute($params);
$total = (int)$stmt->fetchColumn();
$totalPages = max(1, ceil($total / $perPage));
$groupBy = $userId > 0 ? 'DATE(r.used_at)' : 'DATE(r.used_at), r.user_id';
$selectCols = $userId > 0
? "DATE(r.used_at) AS bill_date, r.user_id AS uid, COUNT(*) AS total, SUM(COALESCE(r.price_tier1, 0)) AS total_price1, SUM(COALESCE(r.price_tier2, 0)) AS total_price2"
: "DATE(r.used_at) AS bill_date, r.user_id AS uid, u.username, COUNT(*) AS total, SUM(COALESCE(r.price_tier1, 0)) AS total_price1, SUM(COALESCE(r.price_tier2, 0)) AS total_price2";
$stmt = $pdo->prepare("SELECT $selectCols FROM claim_records r LEFT JOIN users u ON r.user_id = u.id $where GROUP BY $groupBy ORDER BY bill_date DESC" . ($userId > 0 ? '' : ', u.username ASC') . " LIMIT ? OFFSET ?");
$stmt->execute(array_merge($params, [$perPage, $offset]));
$records = $stmt->fetchAll();
// 批量查询账单状态
$statusMap = [];
if (!empty($records)) {
$cases = [];
foreach ($records as $r) {
$uid = $userId > 0 ? $userId : $r['uid'];
$cases[] = "('" . $r['bill_date'] . "', " . (int)$uid . ")";
}
if (!empty($cases)) {
$stmt = $pdo->query("SELECT CONCAT(bill_date, '_', user_id) AS k, status FROM bill_status WHERE (bill_date, user_id) IN (" . implode(',', $cases) . ")");
while ($row = $stmt->fetch()) {
$statusMap[$row['k']] = $row['status'];
}
}
}
function billStatusBadge(string $status): string {
switch ($status) {
case '未结算': return '<span class="badge badge-warning">未结算</span>';
case '已结算': return '<span class="badge badge-success">已结算</span>';
case '已作废': return '<span class="badge badge-danger">已作废</span>';
default: return '<span class="badge">未知</span>';
}
}
$allUsers = $isAdmin ? $pdo->query('SELECT id, username FROM users ORDER BY id ASC')->fetchAll() : [];
// 构建筛选条件 URL 参数
$queryParams = [];
if ($userId > 0) $queryParams['user_id'] = $userId;
if ($startDate) $queryParams['start_date'] = $startDate;
if ($endDate) $queryParams['end_date'] = $endDate;
?>
<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; ?>
<?= $statusMsg ?>
<?php if ($isAdmin): ?>
<form method="get" style="margin-bottom:12px;display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
<label>用户:</label>
<select name="user_id" class="form-control" style="max-width:160px;" onchange="this.form.submit()">
<option value="">全部</option>
<?php foreach ($allUsers as $u): ?>
<option value="<?= $u['id'] ?>" <?= $userId === (int)$u['id'] ? 'selected' : '' ?>><?= h($u['username']) ?></option>
<?php endforeach; ?>
</select>
<label>开始日期:</label>
<input type="date" name="start_date" class="form-control" style="max-width:160px;" value="<?= h($startDate) ?>">
<label>结束日期:</label>
<input type="date" name="end_date" class="form-control" style="max-width:160px;" value="<?= h($endDate) ?>">
<button type="submit" class="btn btn-primary btn-sm">查询</button>
<?php if ($startDate || $endDate || $userId > 0): ?>
<a href="bill_records.php" class="btn btn-sm" style="background:#999;color:#fff;">清空</a>
<?php endif; ?>
</form>
<?php else: ?>
<form method="get" style="margin-bottom:12px;display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
<label>开始日期:</label>
<input type="date" name="start_date" class="form-control" style="max-width:160px;" value="<?= h($startDate) ?>">
<label>结束日期:</label>
<input type="date" name="end_date" class="form-control" style="max-width:160px;" value="<?= h($endDate) ?>">
<button type="submit" class="btn btn-primary btn-sm">查询</button>
<?php if ($startDate || $endDate): ?>
<a href="bill_records.php" class="btn btn-sm" style="background:#999;color:#fff;">清空</a>
<?php endif; ?>
</form>
<?php endif; ?>
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>日期</th>
<?php if (!$userId): ?><th>用户</th><?php endif; ?>
<th>使用数量</th>
<th>出货价一档合计</th>
<th>出货价二挡合计</th>
<th>状态</th>
<?php if ($isAdmin): ?><th>操作</th><?php endif; ?>
</tr>
</thead>
<tbody>
<?php foreach ($records as $r): ?>
<?php
$uid = $userId > 0 ? $userId : $r['uid'];
$statusKey = $r['bill_date'] . '_' . $uid;
$billStatus = $statusMap[$statusKey] ?? '未结算';
?>
<tr>
<td><?= h($r['bill_date']) ?></td>
<?php if (!$userId): ?><td><?= h($r['username'] ?? '-') ?></td><?php endif; ?>
<td><a href="bill_records.php?date=<?= h($r['bill_date']) ?>&duid=<?= $uid ?><?= $startDate ? '&start_date=' . $startDate : '' ?><?= $endDate ? '&end_date=' . $endDate : '' ?>" class="btn btn-info btn-sm"><?= (int)$r['total'] ?></a></td>
<td><?= $r['total_price1'] > 0 ? number_format($r['total_price1'], 2) : '-' ?></td>
<td><?= $r['total_price2'] > 0 ? number_format($r['total_price2'], 2) : '-' ?></td>
<td><?= billStatusBadge($billStatus) ?></td>
<?php if ($isAdmin): ?>
<td>
<form method="post" style="display:inline;">
<input type="hidden" name="action" value="set_bill_status">
<input type="hidden" name="csrf_token" value="<?= csrfToken() ?>">
<input type="hidden" name="bill_date" value="<?= h($r['bill_date']) ?>">
<input type="hidden" name="user_id" value="<?= $uid ?>">
<?php if ($startDate): ?><input type="hidden" name="start_date" value="<?= h($startDate) ?>"><?php endif; ?>
<?php if ($endDate): ?><input type="hidden" name="end_date" value="<?= h($endDate) ?>"><?php endif; ?>
<select name="status" class="form-control" style="display:inline-block;width:auto;max-width:100px;padding:4px 6px;font-size:12px;" onchange="this.form.submit()">
<option value="未结算" <?= $billStatus === '未结算' ? 'selected' : '' ?>>未结算</option>
<option value="已结算" <?= $billStatus === '已结算' ? 'selected' : '' ?>>已结算</option>
<option value="已作废" <?= $billStatus === '已作废' ? 'selected' : '' ?>>已作废</option>
</select>
</form>
</td>
<?php endif; ?>
</tr>
<?php endforeach; ?>
<?php if (empty($records)): ?>
<tr><td colspan="<?= $userId ? 5 : 6 ?><?= $isAdmin ? 1 : 0 ?>" style="text-align:center;color:#999;">暂无数据</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
<?php
$extra = [];
if ($userId > 0) $extra['user_id'] = $userId;
if ($startDate) $extra['start_date'] = $startDate;
if ($endDate) $extra['end_date'] = $endDate;
renderPagination($page, $totalPages, $extra);
?>
</div>
<?php require __DIR__ . '/includes/footer.php'; ?>