Kamixitong/app/web/templates/order/list.html

391 lines
15 KiB
HTML
Raw Normal View History

2025-11-19 22:49:24 +08:00
{% extends "base.html" %}
{% block title %}订单管理 - {{ config.SITE_NAME or '软件授权管理系统' }}{% endblock %}
{% block extra_css %}
<style>
.order-status-0 { color: #ffc107; } /* 待支付 */
.order-status-1 { color: #28a745; } /* 已支付 */
.order-status-2 { color: #dc3545; } /* 已取消 */
.order-status-3 { color: #6c757d; } /* 已完成 */
.order-item {
border-left: 3px solid #dee2e6;
transition: all 0.3s ease;
}
.order-item:hover {
border-left-color: #667eea;
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
}
.search-filters .form-control, .search-filters .form-select {
min-width: 150px;
}
</style>
{% endblock %}
{% block content %}
<div class="container-fluid">
<!-- 页面标题 -->
<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">
<button type="button" class="btn btn-sm btn-outline-secondary me-2" onclick="refreshOrders()">
<i class="fas fa-sync-alt me-1"></i>刷新
</button>
</div>
</div>
<!-- 搜索和筛选 -->
<div class="card shadow-sm mb-4">
<div class="card-body">
<form id="searchForm" class="row g-3 search-filters">
<div class="col-md-3">
<label for="searchKeyword" class="form-label">搜索</label>
<input type="text" class="form-control" id="searchKeyword" placeholder="订单号/联系人/手机号">
</div>
<div class="col-md-2">
<label for="statusFilter" class="form-label">状态</label>
<select class="form-select" id="statusFilter">
<option value="">全部</option>
<option value="0">待支付</option>
<option value="1">已支付</option>
<option value="2">已取消</option>
<option value="3">已完成</option>
</select>
</div>
<div class="col-md-2">
<label for="productFilter" class="form-label">产品</label>
<select class="form-select" id="productFilter">
<option value="">全部产品</option>
</select>
</div>
<div class="col-md-3">
<label for="dateRange" class="form-label">日期范围</label>
<input type="text" class="form-control" id="dateRange" placeholder="选择日期范围">
</div>
<div class="col-md-2 d-flex align-items-end">
<button type="button" class="btn btn-primary w-100" onclick="loadOrders()">
<i class="fas fa-search me-1"></i>搜索
</button>
</div>
</form>
</div>
</div>
<!-- 订单列表 -->
<div class="card shadow-sm">
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>订单号</th>
<th>产品</th>
<th>联系人</th>
<th>手机号</th>
<th>数量</th>
<th>金额</th>
<th>状态</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="ordersTableBody">
<!-- 订单数据将通过JavaScript动态加载 -->
<tr>
<td colspan="9" class="text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">加载中...</span>
</div>
<p class="mt-2">正在加载订单数据...</p>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页 -->
<nav aria-label="订单分页" id="paginationContainer">
<ul class="pagination justify-content-center">
<!-- 分页控件将通过JavaScript动态生成 -->
</ul>
</nav>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() {
console.log('订单管理页面加载完成');
// 初始化日期选择器
initDateRangePicker();
// 初始化产品筛选下拉框
loadProducts();
// 加载订单列表
loadOrders();
});
// 初始化日期选择器
function initDateRangePicker() {
// 这里可以集成日期选择插件如daterangepicker
// 暂时使用普通文本输入框
}
// 加载产品列表
function loadProducts() {
fetch('/api/v1/products')
.then(response => response.json())
.then(data => {
if (data.success) {
const select = document.getElementById('productFilter');
select.innerHTML = '<option value="">全部产品</option>';
data.data.products.forEach(product => {
const option = document.createElement('option');
option.value = product.product_id;
option.textContent = product.product_name;
select.appendChild(option);
});
}
})
.catch(error => {
console.error('加载产品列表失败:', error);
});
}
// 加载订单列表
function loadOrders(page = 1) {
const params = new URLSearchParams();
params.append('page', page);
const keyword = document.getElementById('searchKeyword').value.trim();
const status = document.getElementById('statusFilter').value;
const product = document.getElementById('productFilter').value;
const dateRange = document.getElementById('dateRange').value;
if (keyword) params.append('keyword', keyword);
if (status) params.append('status', status);
if (product) params.append('product_id', product);
if (dateRange) params.append('date_range', dateRange);
// 显示加载状态
document.getElementById('ordersTableBody').innerHTML = `
<tr>
<td colspan="9" class="text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">加载中...</span>
</div>
<p class="mt-2">正在加载订单数据...</p>
</td>
</tr>
`;
fetch(`/api/v1/orders?${params.toString()}`)
.then(response => response.json())
.then(data => {
if (data.success) {
renderOrders(data.data.orders, data.data.pagination);
} else {
showNotification('加载订单列表失败: ' + data.message, 'error');
}
})
.catch(error => {
showNotification('加载订单列表失败,请稍后重试', 'error');
console.error('加载订单列表失败:', error);
});
}
// 渲染订单列表
function renderOrders(orders, pagination) {
const tbody = document.getElementById('ordersTableBody');
if (orders.length === 0) {
tbody.innerHTML = `
<tr>
<td colspan="9" class="text-center py-5">
<i class="fas fa-file-invoice fa-3x text-muted mb-3"></i>
<h4 class="text-muted">暂无订单</h4>
<p class="text-muted">当前没有符合条件的订单记录</p>
</td>
</tr>
`;
document.getElementById('paginationContainer').innerHTML = '';
return;
}
let ordersHtml = '';
orders.forEach(order => {
ordersHtml += `
<tr>
<td>${order.order_number}</td>
<td>${order.product_name || '未知产品'}</td>
<td>${order.contact_person}</td>
<td>${order.phone}</td>
<td>${order.quantity}</td>
<td>¥${order.amount.toFixed(2)}</td>
<td>
<span class="badge bg-${getStatusClass(order.status)} order-status-${order.status}">
${order.status_name}
</span>
</td>
<td>${formatDate(order.create_time)}</td>
<td>
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-outline-primary" onclick="viewOrder('${order.order_id}')">
<i class="fas fa-eye me-1"></i>查看
</button>
${order.status === 0 ? `
<button type="button" class="btn btn-outline-success" onclick="confirmPayment('${order.order_id}')">
<i class="fas fa-check me-1"></i>确认支付
</button>
` : ''}
${order.status === 1 ? `
<button type="button" class="btn btn-outline-secondary" onclick="completeOrder('${order.order_id}')">
<i class="fas fa-check-circle me-1"></i>完成
</button>
` : ''}
</div>
</td>
</tr>
`;
});
tbody.innerHTML = ordersHtml;
// 渲染分页
renderPagination(pagination);
}
// 获取状态样式类
function getStatusClass(status) {
const classMap = {
0: 'warning',
1: 'success',
2: 'danger',
3: 'secondary'
};
return classMap[status] || 'secondary';
}
// 渲染分页
function renderPagination(pagination) {
const paginationContainer = document.getElementById('paginationContainer');
if (pagination.total_pages <= 1) {
paginationContainer.innerHTML = '';
return;
}
let paginationHtml = '<ul class="pagination justify-content-center">';
// 上一页
if (pagination.current_page > 1) {
paginationHtml += `
<li class="page-item">
<a class="page-link" href="#" onclick="loadOrders(${pagination.current_page - 1}); return false;">
<i class="fas fa-chevron-left"></i>
</a>
</li>
`;
}
// 页码
for (let i = Math.max(1, pagination.current_page - 2);
i <= Math.min(pagination.total_pages, pagination.current_page + 2);
i++) {
paginationHtml += `
<li class="page-item ${i === pagination.current_page ? 'active' : ''}">
<a class="page-link" href="#" onclick="loadOrders(${i}); return false;">${i}</a>
</li>
`;
}
// 下一页
if (pagination.current_page < pagination.total_pages) {
paginationHtml += `
<li class="page-item">
<a class="page-link" href="#" onclick="loadOrders(${pagination.current_page + 1}); return false;">
<i class="fas fa-chevron-right"></i>
</a>
</li>
`;
}
paginationHtml += '</ul>';
paginationContainer.innerHTML = paginationHtml;
}
// 查看订单详情
function viewOrder(orderId) {
showNotification('查看订单详情功能待实现', 'info');
// 这里可以跳转到订单详情页面或显示模态框
}
// 确认支付
function confirmPayment(orderId) {
if (!confirm('确定要确认该订单已支付吗?')) {
return;
}
fetch(`/api/v1/orders/${orderId}/confirm-payment`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showNotification('订单支付确认成功', 'success');
loadOrders(); // 重新加载订单列表
} else {
showNotification('订单支付确认失败: ' + data.message, 'error');
}
})
.catch(error => {
showNotification('订单支付确认失败,请稍后重试', 'error');
console.error('订单支付确认失败:', error);
});
}
// 完成订单
function completeOrder(orderId) {
if (!confirm('确定要将该订单标记为已完成吗?')) {
return;
}
fetch(`/api/v1/orders/${orderId}/complete`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showNotification('订单完成操作成功', 'success');
loadOrders(); // 重新加载订单列表
} else {
showNotification('订单完成操作失败: ' + data.message, 'error');
}
})
.catch(error => {
showNotification('订单完成操作失败,请稍后重试', 'error');
console.error('订单完成操作失败:', error);
});
}
// 刷新订单列表
function refreshOrders() {
loadOrders();
}
</script>
{% endblock %}