coupon/work_order_manage.php

229 lines
12 KiB
PHP
Executable File
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';
requireAdmin();
$pageTitle = '工单管理';
require __DIR__ . '/includes/header.php';
$msg = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
if (!verifyCsrf($_POST['csrf_token'] ?? '')) { die('CSRF token无效'); }
$id = (int)($_POST['id'] ?? 0);
if ($_POST['action'] === 'set_done') {
$pdo->beginTransaction();
try {
$stmt = $pdo->prepare("SELECT * FROM work_orders WHERE id = ? AND status = '未处理'");
$stmt->execute([$id]);
$order = $stmt->fetch();
if (!$order) {
$msg = '<div class="alert alert-danger">工单不存在或状态已变更</div>';
$pdo->rollBack();
} else {
$codes = array_filter(explode("\n", $order['code'] ?? ''));
$missingClaim = 0;
$noStock = 0;
foreach ($codes as $code) {
$code = trim($code);
if ($code === '') continue;
$stmt = $pdo->prepare("SELECT * FROM claim_records WHERE code = ? AND user_id = ? AND product_id = ? FOR UPDATE");
$stmt->execute([$code, $order['creator_id'], $order['product_id']]);
$cr = $stmt->fetch();
if (!$cr) { $missingClaim++; continue; }
$stmt = $pdo->prepare("SELECT 1 FROM redemption_codes WHERE value = ? AND status = 1 AND (expired_at IS NULL OR expired_at > NOW()) AND product_id = ? LIMIT 1 FOR UPDATE");
$stmt->execute([$cr['value'], $order['product_id']]);
if (!$stmt->fetch()) { $noStock++; }
}
if ($missingClaim > 0 || $noStock > 0) {
$pdo->rollBack();
$errParts = [];
if ($missingClaim > 0) $errParts[] = $missingClaim . ' 个兑换码未找到领取记录';
if ($noStock > 0) $errParts[] = '库存不足,无法补发';
$msg = '<div class="alert alert-danger">' . implode('', $errParts) . ',工单无法处理</div>';
} else {
$replaced = 0;
foreach ($codes as $code) {
$code = trim($code);
if ($code === '') continue;
$stmt = $pdo->prepare("SELECT * FROM claim_records WHERE code = ? AND user_id = ? AND product_id = ?");
$stmt->execute([$code, $order['creator_id'], $order['product_id']]);
$cr = $stmt->fetch();
if (!$cr) continue;
$stmt = $pdo->prepare("UPDATE claim_records SET status = 3, used_at = COALESCE(used_at, NOW()), remark = '该码已过期,新码已补发' WHERE id = ?");
$stmt->execute([$cr['id']]);
$stmt = $pdo->prepare("SELECT * FROM redemption_codes WHERE value = ? AND status = 1 AND (expired_at IS NULL OR expired_at > NOW()) AND product_id = ? LIMIT 1 FOR UPDATE");
$stmt->execute([$cr['value'], $order['product_id']]);
$newCode = $stmt->fetch();
$stmt = $pdo->prepare("UPDATE redemption_codes SET status = 2, claim_user_id = ?, claimed_at = NOW() WHERE id = ?");
$stmt->execute([$order['creator_id'], $newCode['id']]);
$stmt = $pdo->prepare("INSERT INTO claim_records (product_id, created_at, user_id, code_name, batch_no, code_type, code, value, status, expired_at, price_tier1, price_tier2, claim_user, claimed_at, remark) VALUES (?, NOW(), ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, NOW(), '系统补发')");
$stmt->execute([
$newCode['product_id'],
$order['creator_id'],
$newCode['name'],
$newCode['batch_no'],
$newCode['type'],
$newCode['code'],
$newCode['value'],
$newCode['expired_at'],
$newCode['price_tier1'],
$newCode['price_tier2'],
$cr['claim_user']
]);
$replaced++;
}
$stmt = $pdo->prepare("UPDATE work_orders SET status = '已处理', processed_at = NOW(), processor_id = ? WHERE id = ?");
$stmt->execute([getCurrentUserId(), $id]);
$pdo->commit();
$_SESSION['flash_msg'] = '工单已处理,' . $replaced . ' 个兑换码已过期并补发新码';
$_SESSION['flash_type'] = 'success';
header('Location: work_order_manage.php');
exit;
}
}
} catch (Exception $e) {
$pdo->rollBack();
$msg = '<div class="alert alert-danger">处理失败,请重试</div>';
}
} elseif ($_POST['action'] === 'reject') {
$stmt = $pdo->prepare("SELECT attachment FROM work_orders WHERE id = ?");
$stmt->execute([$id]);
$order = $stmt->fetch();
$stmt = $pdo->prepare("UPDATE work_orders SET status = '已驳回', processed_at = NOW(), processor_id = ? WHERE id = ? AND status = '未处理'");
$stmt->execute([getCurrentUserId(), $id]);
if ($stmt->rowCount()) {
if ($order && $order['attachment'] && file_exists(__DIR__ . '/' . $order['attachment'])) {
unlink(__DIR__ . '/' . $order['attachment']);
}
$_SESSION['flash_msg'] = '工单已驳回';
$_SESSION['flash_type'] = 'warning';
header('Location: work_order_manage.php');
exit;
} else {
$msg = '<div class="alert alert-danger">工单状态已变更,无法驳回</div>';
}
} elseif ($_POST['action'] === 'delete') {
$stmt = $pdo->prepare("SELECT attachment, status FROM work_orders WHERE id = ?");
$stmt->execute([$id]);
$order = $stmt->fetch();
if (!$order) {
$msg = '<div class="alert alert-danger">工单不存在</div>';
} elseif ($order['status'] === '已处理') {
$msg = '<div class="alert alert-danger">已处理的工单不能删除</div>';
} else {
if ($order['attachment'] && file_exists(__DIR__ . '/' . $order['attachment'])) {
unlink(__DIR__ . '/' . $order['attachment']);
}
$pdo->prepare('DELETE FROM work_orders WHERE id = ?')->execute([$id]);
$_SESSION['flash_msg'] = '工单已删除';
$_SESSION['flash_type'] = 'success';
header('Location: work_order_manage.php');
exit;
}
}
}
// 分页
$page = max(1, (int)($_GET['p'] ?? 1));
$perPage = 20;
$offset = ($page - 1) * $perPage;
$stmt = $pdo->prepare('SELECT COUNT(*) FROM work_orders WHERE product_id = ?');
$stmt->execute([$pid]);
$total = (int)$stmt->fetchColumn();
$totalPages = max(1, ceil($total / $perPage));
$stmt = $pdo->prepare('SELECT w.*, c.username AS creator_name, p.username AS processor_name FROM work_orders w LEFT JOIN users c ON w.creator_id = c.id LEFT JOIN users p ON w.processor_id = p.id WHERE w.product_id = ? ORDER BY w.created_at DESC LIMIT ? OFFSET ?');
$stmt->execute([$pid, $perPage, $offset]);
$orders = $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 class="table-wrapper">
<table>
<thead>
<tr>
<th>ID</th>
<th>内容</th>
<th>兑换码</th>
<th>附件</th>
<th>发起人</th>
<th>发起时间</th>
<th>处理时间</th>
<th>处理人</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php foreach ($orders as $o): ?>
<tr>
<td><?= $o['id'] ?></td>
<td style="max-width:200px;white-space:pre-wrap;word-break:break-all;"><?= h(mb_substr($o['content'], 0, 100)) ?><?= mb_strlen($o['content']) > 100 ? '...' : '' ?></td>
<td style="white-space:pre-wrap;"><?php if ($o['code']): $lines = explode("\n", $o['code']); echo h(implode("\n", $lines)); else: ?>-<?php endif; ?></td>
<td>
<?php if ($o['attachment']): ?>
<a href="<?= h($o['attachment']) ?>" target="_blank" class="btn btn-info btn-sm">查看</a>
<?php else: ?>
-
<?php endif; ?>
</td>
<td><?= h($o['creator_name'] ?? '-') ?></td>
<td><?= formatDateTime($o['created_at']) ?></td>
<td><?= formatDateTime($o['processed_at']) ?></td>
<td><?= h($o['processor_name'] ?? '-') ?></td>
<td><?= workOrderStatusBadge($o['status']) ?></td>
<td>
<div class="action-group">
<?php if ($o['status'] === '未处理'): ?>
<form method="post" style="display:inline;">
<input type="hidden" name="action" value="set_done">
<input type="hidden" name="id" value="<?= $o['id'] ?>">
<input type="hidden" name="csrf_token" value="<?= csrfToken() ?>">
<button type="submit" class="btn btn-success btn-sm">设为已处理</button>
</form>
<form method="post" style="display:inline;">
<input type="hidden" name="action" value="reject">
<input type="hidden" name="id" value="<?= $o['id'] ?>">
<input type="hidden" name="csrf_token" value="<?= csrfToken() ?>">
<button type="submit" class="btn btn-warning btn-sm" onclick="return confirm('确定驳回此工单?驳回后数据保留但不可操作')">驳回</button>
</form>
<form method="post" style="display:inline;" onsubmit="return confirm('确定删除此工单?')">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?= $o['id'] ?>">
<input type="hidden" name="csrf_token" value="<?= csrfToken() ?>">
<button type="submit" class="btn btn-danger btn-sm">删除</button>
</form>
<?php elseif ($o['status'] === '已驳回'): ?>
<span style="color:#999;font-size:12px;">已驳回,不可操作</span>
<?php endif; ?>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($orders)): ?>
<tr><td colspan="10" style="text-align:center;color:#999;">暂无工单</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
<?php renderPagination($page, $totalPages); ?>
</div>
<?php require __DIR__ . '/includes/footer.php'; ?>