892 lines
35 KiB
Plaintext
892 lines
35 KiB
Plaintext
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
|
||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||
<%@ taglib prefix="fn" uri="http://flashsale.org/functions" %>
|
||
|
||
<c:set var="pageTitle" value="秒杀管理"/>
|
||
<%@ include file="../common/header.jsp" %>
|
||
|
||
<div class="container-fluid">
|
||
<div class="row">
|
||
<!-- 侧边栏 -->
|
||
<nav class="col-md-3 col-lg-2 d-md-block bg-light sidebar">
|
||
<div class="position-sticky pt-3">
|
||
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||
<span>管理功能</span>
|
||
</h6>
|
||
<ul class="nav flex-column">
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="${pageContext.request.contextPath}/admin">
|
||
<i class="fas fa-tachometer-alt"></i> 仪表盘
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="${pageContext.request.contextPath}/admin/products">
|
||
<i class="fas fa-box"></i> 商品管理
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a class="nav-link active" href="${pageContext.request.contextPath}/admin/flashsales">
|
||
<i class="fas fa-bolt"></i> 秒杀管理
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="${pageContext.request.contextPath}/admin/orders">
|
||
<i class="fas fa-shopping-cart"></i> 订单管理
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="${pageContext.request.contextPath}/admin/users">
|
||
<i class="fas fa-users"></i> 用户管理
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="${pageContext.request.contextPath}/admin/monitor">
|
||
<i class="fas fa-chart-line"></i> 系统监控
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</nav>
|
||
|
||
<!-- 主内容区域 -->
|
||
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
|
||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||
<h1 class="h2">秒杀管理</h1>
|
||
<div class="btn-toolbar mb-2 mb-md-0">
|
||
<div class="btn-group me-2">
|
||
<button type="button" class="btn btn-sm btn-primary" data-bs-toggle="modal"
|
||
data-bs-target="#addFlashSaleModal">
|
||
<i class="fas fa-plus"></i> 创建秒杀
|
||
</button>
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="refreshFlashSales()">
|
||
<i class="fas fa-sync-alt"></i> 刷新
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 筛选和搜索 -->
|
||
<div class="row mb-3">
|
||
<div class="col-md-4">
|
||
<div class="input-group">
|
||
<input type="text" class="form-control" id="searchInput" placeholder="搜索秒杀活动...">
|
||
<button class="btn btn-outline-secondary" type="button" onclick="searchFlashSales()">
|
||
<i class="fas fa-search"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-2">
|
||
<select class="form-select" id="statusFilter" onchange="filterFlashSales()">
|
||
<option value="">全部状态</option>
|
||
<option value="pending">未开始</option>
|
||
<option value="active">进行中</option>
|
||
<option value="ended">已结束</option>
|
||
</select>
|
||
</div>
|
||
<div class="col-md-2">
|
||
<select class="form-select" id="sortBy" onchange="sortFlashSales()">
|
||
<option value="startTime">按开始时间</option>
|
||
<option value="endTime">按结束时间</option>
|
||
<option value="createdAt">按创建时间</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 秒杀活动列表 -->
|
||
<div class="card">
|
||
<div class="card-body">
|
||
<div class="table-responsive">
|
||
<table class="table table-striped table-hover">
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>活动名称</th>
|
||
<th>商品</th>
|
||
<th>原价/秒杀价</th>
|
||
<th>库存</th>
|
||
<th>开始时间</th>
|
||
<th>结束时间</th>
|
||
<th>状态</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="flashSalesTableBody">
|
||
<tr>
|
||
<td colspan="9" class="text-center">
|
||
<i class="fas fa-spinner fa-spin"></i> 加载中...
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- 分页 -->
|
||
<nav aria-label="秒杀分页">
|
||
<ul class="pagination justify-content-center" id="pagination">
|
||
<!-- 分页按钮将通过JavaScript生成 -->
|
||
</ul>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 创建秒杀模态框 -->
|
||
<div class="modal fade" id="addFlashSaleModal" tabindex="-1">
|
||
<div class="modal-dialog modal-lg">
|
||
<div class="modal-content">
|
||
<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">
|
||
<form id="addFlashSaleForm">
|
||
<div class="row">
|
||
<div class="col-md-12">
|
||
<div class="mb-3">
|
||
<label for="productSelect" class="form-label">选择商品 *</label>
|
||
<select class="form-select" id="productSelect" required>
|
||
<option value="">请选择商品</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label for="flashSalePrice" class="form-label">秒杀价格 *</label>
|
||
<div class="input-group">
|
||
<span class="input-group-text">¥</span>
|
||
<input type="number" class="form-control" id="flashSalePrice" step="0.01" min="0"
|
||
required>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label for="flashSaleStock" class="form-label">秒杀库存 *</label>
|
||
<input type="number" class="form-control" id="flashSaleStock" min="1" required>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label for="startTime" class="form-label">开始时间 *</label>
|
||
<input type="datetime-local" class="form-control" id="startTime" required>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label for="endTime" class="form-label">结束时间 *</label>
|
||
<input type="datetime-local" class="form-control" id="endTime" required>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</form>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||
<button type="button" class="btn btn-primary" onclick="saveFlashSale()">创建活动</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 查看详情模态框 -->
|
||
<div class="modal fade" id="viewFlashSaleModal" tabindex="-1">
|
||
<div class="modal-dialog modal-lg">
|
||
<div class="modal-content">
|
||
<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="row">
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">活动ID</label>
|
||
<p id="viewFlashSaleId" class="form-control-plaintext">-</p>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">商品名称</label>
|
||
<p id="viewProductName" class="form-control-plaintext">-</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">原价</label>
|
||
<p id="viewOriginalPrice" class="form-control-plaintext">-</p>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">秒杀价</label>
|
||
<p id="viewFlashPrice" class="form-control-plaintext text-danger fw-bold">-</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">总库存</label>
|
||
<p id="viewFlashStock" class="form-control-plaintext">-</p>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">剩余库存</label>
|
||
<p id="viewRemainingStock" class="form-control-plaintext">-</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">开始时间</label>
|
||
<p id="viewStartTime" class="form-control-plaintext">-</p>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">结束时间</label>
|
||
<p id="viewEndTime" class="form-control-plaintext">-</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">活动状态</label>
|
||
<p id="viewStatus" class="form-control-plaintext">-</p>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label class="form-label fw-bold">创建时间</label>
|
||
<p id="viewCreatedAt" class="form-control-plaintext">-</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 编辑秒杀模态框 -->
|
||
<div class="modal fade" id="editFlashSaleModal" tabindex="-1">
|
||
<div class="modal-dialog modal-lg">
|
||
<div class="modal-content">
|
||
<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">
|
||
<form id="editFlashSaleForm">
|
||
<input type="hidden" id="editFlashSaleId">
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label for="editFlashPrice" class="form-label">秒杀价格 *</label>
|
||
<div class="input-group">
|
||
<span class="input-group-text">¥</span>
|
||
<input type="number" class="form-control" id="editFlashPrice" step="0.01" min="0"
|
||
required>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label for="editFlashStock" class="form-label">秒杀库存 *</label>
|
||
<input type="number" class="form-control" id="editFlashStock" min="1" required>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label for="editStartTime" class="form-label">开始时间 *</label>
|
||
<input type="datetime-local" class="form-control" id="editStartTime" required>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="mb-3">
|
||
<label for="editEndTime" class="form-label">结束时间 *</label>
|
||
<input type="datetime-local" class="form-control" id="editEndTime" required>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||
<button type="button" class="btn btn-primary" onclick="saveEditFlashSale()">保存修改</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<style>
|
||
.sidebar {
|
||
position: fixed;
|
||
top: 56px;
|
||
bottom: 0;
|
||
left: 0;
|
||
z-index: 100;
|
||
padding: 48px 0 0;
|
||
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
|
||
}
|
||
|
||
.sidebar .nav-link {
|
||
font-weight: 500;
|
||
color: #333;
|
||
}
|
||
|
||
.sidebar .nav-link.active {
|
||
color: #007bff;
|
||
}
|
||
|
||
main {
|
||
margin-left: 240px;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
main {
|
||
margin-left: 0;
|
||
}
|
||
|
||
.sidebar {
|
||
position: relative;
|
||
top: 0;
|
||
}
|
||
}
|
||
|
||
.status-pending {
|
||
color: #ffc107;
|
||
}
|
||
|
||
.status-active {
|
||
color: #28a745;
|
||
}
|
||
|
||
.status-ended {
|
||
color: #6c757d;
|
||
}
|
||
</style>
|
||
|
||
<script>
|
||
let currentPage = 1;
|
||
let pageSize = 10;
|
||
let totalPages = 1;
|
||
|
||
$(document).ready(function () {
|
||
loadFlashSales();
|
||
loadProducts();
|
||
|
||
// 设置默认时间
|
||
const now = new Date();
|
||
const tomorrow = new Date(now.getTime() + 24 * 60 * 60 * 1000);
|
||
|
||
$('#startTime').val(formatDateTime(now));
|
||
$('#endTime').val(formatDateTime(tomorrow));
|
||
});
|
||
|
||
function formatDateTime(date) {
|
||
const year = date.getFullYear();
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
const hours = String(date.getHours()).padStart(2, '0');
|
||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||
|
||
return year + '-' + month + '-' + day + 'T' + hours + ':' + minutes;
|
||
}
|
||
|
||
function loadProducts() {
|
||
// 获取商品列表用于下拉框
|
||
$.ajax({
|
||
url: '${pageContext.request.contextPath}/api/admin/products',
|
||
type: 'GET',
|
||
data: {
|
||
page: 1,
|
||
size: 100, // 获取足够多的商品
|
||
status: 1 // 只获取上架的商品
|
||
},
|
||
success: function (response) {
|
||
if (response.success && response.data) {
|
||
const products = response.data.content || response.data.products || [];
|
||
let options = '<option value="">请选择商品</option>';
|
||
|
||
products.forEach(product => {
|
||
options += `<option value="${product.id}">${product.name} - ¥${product.price}</option>`;
|
||
});
|
||
|
||
$('#productSelect').html(options);
|
||
} else {
|
||
console.error('获取商品列表失败:', response.message);
|
||
}
|
||
},
|
||
error: function (xhr, status, error) {
|
||
console.error('获取商品列表失败:', error);
|
||
}
|
||
});
|
||
}
|
||
|
||
function loadFlashSales(page = 1) {
|
||
currentPage = page;
|
||
|
||
// 显示加载状态
|
||
$('#flashSalesTableBody').html('<tr><td colspan="9" class="text-center"><i class="fas fa-spinner fa-spin"></i> 加载中...</td></tr>');
|
||
|
||
// 构建查询参数
|
||
const queryData = {
|
||
page: page - 1, // 后端使用0基索引
|
||
size: pageSize,
|
||
sortBy: $('#sortBy').val() || 'startTime',
|
||
sortDirection: 'desc'
|
||
};
|
||
|
||
// 添加状态筛选
|
||
const statusFilter = $('#statusFilter').val();
|
||
if (statusFilter) {
|
||
// 将前端状态值转换为后端状态值
|
||
switch (statusFilter) {
|
||
case 'pending':
|
||
queryData.status = 1; // 未开始
|
||
break;
|
||
case 'active':
|
||
queryData.status = 2; // 进行中
|
||
break;
|
||
case 'ended':
|
||
queryData.status = 3; // 已结束
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 调用真实API
|
||
$.ajax({
|
||
url: '${pageContext.request.contextPath}/api/flashsale/list',
|
||
type: 'POST',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify(queryData),
|
||
success: function (response) {
|
||
if (response.success) {
|
||
renderFlashSalesTable(response.data.content || response.data.flashSales || []);
|
||
renderPagination(response.data.totalElements || response.data.total || 0, pageSize);
|
||
} else {
|
||
$('#flashSalesTableBody').html('<tr><td colspan="9" class="text-center text-danger">获取秒杀数据失败: ' + response.message + '</td></tr>');
|
||
}
|
||
},
|
||
error: function (xhr, status, error) {
|
||
console.error('获取秒杀列表失败:', error);
|
||
$('#flashSalesTableBody').html('<tr><td colspan="9" class="text-center text-danger">网络请求失败,请稍后重试</td></tr>');
|
||
}
|
||
});
|
||
}
|
||
|
||
function renderFlashSalesTable(flashSales) {
|
||
let html = '';
|
||
|
||
if (flashSales.length === 0) {
|
||
html = '<tr><td colspan="9" class="text-center">暂无秒杀活动</td></tr>';
|
||
} else {
|
||
flashSales.forEach(flashSale => {
|
||
const statusText = getStatusText(flashSale.status);
|
||
const statusClass = getStatusClass(flashSale.status);
|
||
|
||
html += `
|
||
<tr>
|
||
<td>` + flashSale.id + `</td>
|
||
<td>
|
||
<div class="fw-bold">` + (flashSale.productName || '秒杀活动') + `</div>
|
||
<small class="text-muted">` + (flashSale.statusDescription || '') + `</small>
|
||
</td>
|
||
<td>` + (flashSale.productName || '-') + `</td>
|
||
<td>
|
||
<div>原价: ¥` + (flashSale.originalPrice ? flashSale.originalPrice.toFixed(2) : '0.00') + `</div>
|
||
<div class="text-danger fw-bold">秒杀: ¥` + (flashSale.flashPrice ? flashSale.flashPrice.toFixed(2) : '0.00') + `</div>
|
||
</td>
|
||
<td>
|
||
<span class="badge ` + (flashSale.remainingStock > 0 ? 'bg-success' : 'bg-danger') + `">
|
||
` + (flashSale.remainingStock || 0) + ` / ` + (flashSale.flashStock || 0) + `
|
||
</span>
|
||
</td>
|
||
<td>` + formatDateTime(flashSale.startTime) + `</td>
|
||
<td>` + formatDateTime(flashSale.endTime) + `</td>
|
||
<td>
|
||
<span class="badge ` + statusClass + `">
|
||
` + statusText + `
|
||
</span>
|
||
</td>
|
||
<td>
|
||
<div class="btn-group btn-group-sm">
|
||
<button class="btn btn-outline-primary" onclick="editFlashSale(` + flashSale.id + `)" title="编辑">
|
||
<i class="fas fa-edit"></i>
|
||
</button>
|
||
<button class="btn btn-outline-danger" onclick="deleteFlashSale(` + flashSale.id + `)" title="删除">
|
||
<i class="fas fa-trash"></i>
|
||
</button>
|
||
<button class="btn btn-outline-info" onclick="viewFlashSale(` + flashSale.id + `)" title="查看">
|
||
<i class="fas fa-eye"></i>
|
||
</button>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
`;
|
||
});
|
||
}
|
||
|
||
$('#flashSalesTableBody').html(html);
|
||
}
|
||
|
||
function getStatusText(status) {
|
||
switch (status) {
|
||
case 1:
|
||
return '未开始';
|
||
case 2:
|
||
return '进行中';
|
||
case 3:
|
||
return '已结束';
|
||
default:
|
||
return '未知';
|
||
}
|
||
}
|
||
|
||
function getStatusClass(status) {
|
||
switch (status) {
|
||
case 1:
|
||
return 'bg-warning'; // 未开始
|
||
case 2:
|
||
return 'bg-success'; // 进行中
|
||
case 3:
|
||
return 'bg-secondary'; // 已结束
|
||
default:
|
||
return 'bg-secondary';
|
||
}
|
||
}
|
||
|
||
function renderPagination(total, pageSize) {
|
||
totalPages = Math.ceil(total / pageSize);
|
||
let html = '';
|
||
|
||
if (totalPages <= 1) {
|
||
$('#pagination').html('');
|
||
return;
|
||
}
|
||
|
||
// 上一页
|
||
html += `
|
||
<li class="page-item ` + (currentPage === 1 ? 'disabled' : '') + `">
|
||
<a class="page-link" href="#" onclick="loadFlashSales(` + (currentPage - 1) + `)">上一页</a>
|
||
</li>
|
||
`;
|
||
|
||
// 页码
|
||
for (let i = 1; i <= totalPages; i++) {
|
||
html += `
|
||
<li class="page-item ` + (i === currentPage ? 'active' : '') + `">
|
||
<a class="page-link" href="#" onclick="loadFlashSales(` + i + `)">` + i + `</a>
|
||
</li>
|
||
`;
|
||
}
|
||
|
||
// 下一页
|
||
html += `
|
||
<li class="page-item ` + (currentPage === totalPages ? 'disabled' : '') + `">
|
||
<a class="page-link" href="#" onclick="loadFlashSales(` + (currentPage + 1) + `)">下一页</a>
|
||
</li>
|
||
`;
|
||
|
||
$('#pagination').html(html);
|
||
}
|
||
|
||
function refreshFlashSales() {
|
||
$('#flashSalesTableBody').html('<tr><td colspan="9" class="text-center"><i class="fas fa-spinner fa-spin"></i> 加载中...</td></tr>');
|
||
loadFlashSales(currentPage);
|
||
}
|
||
|
||
function searchFlashSales() {
|
||
const keyword = $('#searchInput').val();
|
||
console.log('搜索秒杀活动:', keyword);
|
||
// 重置到第一页并重新加载
|
||
loadFlashSales(1);
|
||
}
|
||
|
||
function filterFlashSales() {
|
||
const status = $('#statusFilter').val();
|
||
console.log('筛选状态:', status);
|
||
// 重置到第一页并重新加载
|
||
loadFlashSales(1);
|
||
}
|
||
|
||
function sortFlashSales() {
|
||
const sortBy = $('#sortBy').val();
|
||
console.log('排序方式:', sortBy);
|
||
// 重置到第一页并重新加载
|
||
loadFlashSales(1);
|
||
}
|
||
|
||
function saveFlashSale() {
|
||
// 验证表单
|
||
if (!$('#productSelect').val()) {
|
||
alert('请选择商品');
|
||
return;
|
||
}
|
||
if (!$('#flashSalePrice').val()) {
|
||
alert('请输入秒杀价格');
|
||
return;
|
||
}
|
||
if (!$('#flashSaleStock').val()) {
|
||
alert('请输入秒杀库存');
|
||
return;
|
||
}
|
||
if (!$('#startTime').val() || !$('#endTime').val()) {
|
||
alert('请选择开始和结束时间');
|
||
return;
|
||
}
|
||
|
||
const flashSaleData = {
|
||
productId: parseInt($('#productSelect').val()),
|
||
flashPrice: parseFloat($('#flashSalePrice').val()),
|
||
flashStock: parseInt($('#flashSaleStock').val()),
|
||
startTime: $('#startTime').val().replace('T', ' ') + ':00',
|
||
endTime: $('#endTime').val().replace('T', ' ') + ':00'
|
||
};
|
||
|
||
console.log('创建秒杀活动:', flashSaleData);
|
||
|
||
// 调用真实API
|
||
$.ajax({
|
||
url: '${pageContext.request.contextPath}/api/flashsale/create',
|
||
type: 'POST',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify(flashSaleData),
|
||
success: function (response) {
|
||
if (response.success) {
|
||
$('#addFlashSaleModal').modal('hide');
|
||
$('#addFlashSaleForm')[0].reset();
|
||
alert('秒杀活动创建成功!');
|
||
refreshFlashSales();
|
||
} else {
|
||
alert('创建失败: ' + response.message);
|
||
}
|
||
},
|
||
error: function (xhr, status, error) {
|
||
console.error('创建秒杀活动失败:', error);
|
||
alert('创建失败,请稍后重试');
|
||
}
|
||
});
|
||
}
|
||
|
||
function editFlashSale(id) {
|
||
console.log('编辑秒杀活动:', id);
|
||
|
||
// 获取秒杀活动详情
|
||
$.ajax({
|
||
url: '${pageContext.request.contextPath}/api/flashsale/' + id,
|
||
type: 'GET',
|
||
success: function (response) {
|
||
if (response.success) {
|
||
const flashSale = response.data;
|
||
|
||
// 检查是否可以编辑(只有未开始的活动才能编辑)
|
||
if (flashSale.status !== 1) {
|
||
alert('只有未开始的秒杀活动才能编辑');
|
||
return;
|
||
}
|
||
|
||
// 填充编辑表单
|
||
$('#editFlashSaleId').val(flashSale.id);
|
||
$('#editFlashPrice').val(flashSale.flashPrice);
|
||
$('#editFlashStock').val(flashSale.flashStock);
|
||
$('#editStartTime').val(formatDateTimeForInput(flashSale.startTime));
|
||
$('#editEndTime').val(formatDateTimeForInput(flashSale.endTime));
|
||
|
||
// 显示编辑模态框
|
||
$('#editFlashSaleModal').modal('show');
|
||
} else {
|
||
alert('获取秒杀活动详情失败: ' + response.message);
|
||
}
|
||
},
|
||
error: function () {
|
||
alert('获取秒杀活动详情失败,请稍后重试');
|
||
}
|
||
});
|
||
}
|
||
|
||
function deleteFlashSale(id) {
|
||
if (confirm('确定要删除这个秒杀活动吗?此操作不可恢复。')) {
|
||
console.log('删除秒杀活动:', id);
|
||
|
||
$.ajax({
|
||
url: '${pageContext.request.contextPath}/api/flashsale/' + id,
|
||
type: 'DELETE',
|
||
success: function (response) {
|
||
if (response.success) {
|
||
alert('秒杀活动删除成功!');
|
||
refreshFlashSales();
|
||
} else {
|
||
alert('删除失败: ' + response.message);
|
||
}
|
||
},
|
||
error: function (xhr) {
|
||
let errorMessage = '删除失败,请稍后重试';
|
||
if (xhr.responseJSON && xhr.responseJSON.message) {
|
||
errorMessage = xhr.responseJSON.message;
|
||
}
|
||
alert(errorMessage);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
function viewFlashSale(id) {
|
||
console.log('查看秒杀详情:', id);
|
||
|
||
// 获取秒杀活动详情
|
||
$.ajax({
|
||
url: '${pageContext.request.contextPath}/api/flashsale/' + id,
|
||
type: 'GET',
|
||
success: function (response) {
|
||
if (response.success) {
|
||
const flashSale = response.data;
|
||
|
||
// 填充详情模态框
|
||
$('#viewFlashSaleId').text(flashSale.id);
|
||
$('#viewProductName').text(flashSale.productName || '-');
|
||
$('#viewOriginalPrice').text(flashSale.originalPrice ? '¥' + flashSale.originalPrice.toFixed(2) : '-');
|
||
$('#viewFlashPrice').text(flashSale.flashPrice ? '¥' + flashSale.flashPrice.toFixed(2) : '-');
|
||
$('#viewFlashStock').text(flashSale.flashStock || '-');
|
||
$('#viewRemainingStock').text(flashSale.remainingStock || '-');
|
||
$('#viewStartTime').text(formatDateTime(flashSale.startTime));
|
||
$('#viewEndTime').text(formatDateTime(flashSale.endTime));
|
||
$('#viewStatus').html('<span class="badge ' + getStatusClass(flashSale.status) + '">' + getStatusText(flashSale.status) + '</span>');
|
||
$('#viewCreatedAt').text(formatDateTime(flashSale.createdAt));
|
||
|
||
// 显示详情模态框
|
||
$('#viewFlashSaleModal').modal('show');
|
||
} else {
|
||
alert('获取秒杀活动详情失败: ' + response.message);
|
||
}
|
||
},
|
||
error: function () {
|
||
alert('获取秒杀活动详情失败,请稍后重试');
|
||
}
|
||
});
|
||
}
|
||
|
||
// 保存编辑的秒杀活动
|
||
function saveEditFlashSale() {
|
||
// 验证表单
|
||
if (!$('#editFlashPrice').val()) {
|
||
alert('请输入秒杀价格');
|
||
return;
|
||
}
|
||
if (!$('#editFlashStock').val()) {
|
||
alert('请输入秒杀库存');
|
||
return;
|
||
}
|
||
if (!$('#editStartTime').val() || !$('#editEndTime').val()) {
|
||
alert('请选择开始和结束时间');
|
||
return;
|
||
}
|
||
|
||
const flashSaleId = $('#editFlashSaleId').val();
|
||
const updateData = {
|
||
flashPrice: parseFloat($('#editFlashPrice').val()),
|
||
flashStock: parseInt($('#editFlashStock').val()),
|
||
startTime: $('#editStartTime').val().replace('T', ' ') + ':00',
|
||
endTime: $('#editEndTime').val().replace('T', ' ') + ':00'
|
||
};
|
||
|
||
// 验证时间
|
||
const startTime = new Date($('#editStartTime').val());
|
||
const endTime = new Date($('#editEndTime').val());
|
||
const now = new Date();
|
||
|
||
if (startTime < now) {
|
||
alert('开始时间不能早于当前时间');
|
||
return;
|
||
}
|
||
|
||
if (startTime >= endTime) {
|
||
alert('开始时间不能晚于或等于结束时间');
|
||
return;
|
||
}
|
||
|
||
console.log('更新秒杀活动:', updateData);
|
||
|
||
// 调用更新API
|
||
$.ajax({
|
||
url: '${pageContext.request.contextPath}/api/flashsale/' + flashSaleId,
|
||
type: 'PUT',
|
||
contentType: 'application/json',
|
||
data: JSON.stringify(updateData),
|
||
success: function (response) {
|
||
if (response.success) {
|
||
$('#editFlashSaleModal').modal('hide');
|
||
alert('秒杀活动更新成功!');
|
||
refreshFlashSales();
|
||
} else {
|
||
alert('更新失败: ' + response.message);
|
||
}
|
||
},
|
||
error: function (xhr) {
|
||
let errorMessage = '更新失败,请稍后重试';
|
||
if (xhr.responseJSON && xhr.responseJSON.message) {
|
||
errorMessage = xhr.responseJSON.message;
|
||
}
|
||
alert(errorMessage);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 工具函数
|
||
function formatDateTime(dateTimeStr) {
|
||
if (!dateTimeStr) return '-';
|
||
|
||
// 如果是ISO格式,转换为本地时间显示
|
||
try {
|
||
const date = new Date(dateTimeStr);
|
||
return date.toLocaleString('zh-CN', {
|
||
year: 'numeric',
|
||
month: '2-digit',
|
||
day: '2-digit',
|
||
hour: '2-digit',
|
||
minute: '2-digit',
|
||
second: '2-digit'
|
||
});
|
||
} catch (e) {
|
||
return dateTimeStr; // 如果转换失败,返回原字符串
|
||
}
|
||
}
|
||
|
||
// 格式化日期时间用于input[type="datetime-local"]
|
||
function formatDateTimeForInput(dateTimeStr) {
|
||
if (!dateTimeStr) return '';
|
||
|
||
try {
|
||
const date = new Date(dateTimeStr);
|
||
const year = date.getFullYear();
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
const hours = String(date.getHours()).padStart(2, '0');
|
||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||
|
||
return year + '-' + month + '-' + day + 'T' + hours + ':' + minutes;
|
||
} catch (e) {
|
||
return '';
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<%@ include file="../common/footer.jsp" %>
|