Initial commit: AIGC项目完整代码
This commit is contained in:
525
demo/frontend/src/views/Orders.vue
Normal file
525
demo/frontend/src/views/Orders.vue
Normal file
@@ -0,0 +1,525 @@
|
||||
<template>
|
||||
<div class="orders">
|
||||
<!-- 页面标题和操作 -->
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<h2>
|
||||
<el-icon><List /></el-icon>
|
||||
订单管理
|
||||
</h2>
|
||||
</div>
|
||||
<div class="page-actions">
|
||||
<el-button type="primary" @click="$router.push('/orders/create')">
|
||||
<el-icon><Plus /></el-icon>
|
||||
创建订单
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选和搜索 -->
|
||||
<el-card class="filter-card">
|
||||
<el-row :gutter="20">
|
||||
<el-col :xs="24" :sm="12" :md="8">
|
||||
<el-select
|
||||
v-model="filters.status"
|
||||
placeholder="选择订单状态"
|
||||
clearable
|
||||
@change="handleFilterChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="status in orderStatuses"
|
||||
:key="status.value"
|
||||
:label="status.label"
|
||||
:value="status.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8">
|
||||
<el-input
|
||||
v-model="filters.search"
|
||||
placeholder="搜索订单号"
|
||||
clearable
|
||||
@input="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<el-icon><Search /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8">
|
||||
<el-button @click="resetFilters">重置筛选</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<!-- 订单列表 -->
|
||||
<el-card class="orders-card">
|
||||
<el-table
|
||||
:data="orderStore.orders"
|
||||
v-loading="orderStore.loading"
|
||||
empty-text="暂无订单"
|
||||
@sort-change="handleSortChange"
|
||||
>
|
||||
<el-table-column prop="orderNumber" label="订单号" width="150" sortable="custom">
|
||||
<template #default="{ row }">
|
||||
<router-link :to="`/orders/${row.id}`" class="order-link">
|
||||
{{ row.orderNumber }}
|
||||
</router-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="totalAmount" label="金额" width="120" sortable="custom">
|
||||
<template #default="{ row }">
|
||||
<span class="amount">{{ row.currency }} {{ row.totalAmount }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="status" label="状态" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getStatusType(row.status)">
|
||||
{{ getStatusText(row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="orderType" label="类型" width="120">
|
||||
<template #default="{ row }">
|
||||
{{ getOrderTypeText(row.orderType) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="createdAt" label="创建时间" width="160" sortable="custom">
|
||||
<template #default="{ row }">
|
||||
{{ formatDate(row.createdAt) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="200" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button-group>
|
||||
<el-button size="small" @click="$router.push(`/orders/${row.id}`)">
|
||||
查看
|
||||
</el-button>
|
||||
|
||||
<el-dropdown v-if="canPay(row)" trigger="click" :teleported="true" popper-class="table-dropdown" @command="(command) => handlePayment(row, command)">
|
||||
<el-button size="small" type="success">
|
||||
支付<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="ALIPAY">
|
||||
<el-icon><CreditCard /></el-icon>
|
||||
支付宝支付
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="PAYPAL">
|
||||
<el-icon><CreditCard /></el-icon>
|
||||
PayPal支付
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
|
||||
<el-button
|
||||
v-if="canCancel(row)"
|
||||
size="small"
|
||||
type="danger"
|
||||
@click="handleCancel(row)"
|
||||
>
|
||||
取消
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="pagination.page"
|
||||
v-model:page-size="pagination.size"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="pagination.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 取消订单对话框 -->
|
||||
<el-dialog
|
||||
v-model="cancelDialogVisible"
|
||||
title="取消订单"
|
||||
width="400px"
|
||||
>
|
||||
<el-form :model="cancelForm" label-width="80px">
|
||||
<el-form-item label="取消原因">
|
||||
<el-input
|
||||
v-model="cancelForm.reason"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入取消原因(可选)"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="cancelDialogVisible = false">取消</el-button>
|
||||
<el-button type="danger" @click="confirmCancel">确认取消</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { useOrderStore } from '@/stores/orders'
|
||||
import { createOrderPayment } from '@/api/orders'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
|
||||
const orderStore = useOrderStore()
|
||||
|
||||
// 筛选条件
|
||||
const filters = reactive({
|
||||
status: '',
|
||||
search: ''
|
||||
})
|
||||
|
||||
// 分页信息
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 排序
|
||||
const sortBy = ref('createdAt')
|
||||
const sortDir = ref('desc')
|
||||
|
||||
// 取消订单对话框
|
||||
const cancelDialogVisible = ref(false)
|
||||
const cancelForm = reactive({
|
||||
reason: ''
|
||||
})
|
||||
const currentCancelOrder = ref(null)
|
||||
|
||||
// 订单状态选项
|
||||
const orderStatuses = [
|
||||
{ value: '', label: '全部状态' },
|
||||
{ value: 'PENDING', label: '待支付' },
|
||||
{ value: 'CONFIRMED', label: '已确认' },
|
||||
{ value: 'PAID', label: '已支付' },
|
||||
{ value: 'PROCESSING', label: '处理中' },
|
||||
{ value: 'SHIPPED', label: '已发货' },
|
||||
{ value: 'DELIVERED', label: '已送达' },
|
||||
{ value: 'COMPLETED', label: '已完成' },
|
||||
{ value: 'CANCELLED', label: '已取消' },
|
||||
{ value: 'REFUNDED', label: '已退款' }
|
||||
]
|
||||
|
||||
// 获取状态类型
|
||||
const getStatusType = (status) => {
|
||||
const statusMap = {
|
||||
'PENDING': 'warning',
|
||||
'CONFIRMED': 'info',
|
||||
'PAID': 'primary',
|
||||
'PROCESSING': '',
|
||||
'SHIPPED': 'success',
|
||||
'DELIVERED': 'success',
|
||||
'COMPLETED': 'success',
|
||||
'CANCELLED': 'danger',
|
||||
'REFUNDED': 'info'
|
||||
}
|
||||
return statusMap[status] || ''
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status) => {
|
||||
const statusMap = {
|
||||
'PENDING': '待支付',
|
||||
'CONFIRMED': '已确认',
|
||||
'PAID': '已支付',
|
||||
'PROCESSING': '处理中',
|
||||
'SHIPPED': '已发货',
|
||||
'DELIVERED': '已送达',
|
||||
'COMPLETED': '已完成',
|
||||
'CANCELLED': '已取消',
|
||||
'REFUNDED': '已退款'
|
||||
}
|
||||
return statusMap[status] || status
|
||||
}
|
||||
|
||||
// 获取订单类型文本
|
||||
const getOrderTypeText = (orderType) => {
|
||||
const typeMap = {
|
||||
'PRODUCT': '商品订单',
|
||||
'SERVICE': '服务订单',
|
||||
'SUBSCRIPTION': '订阅订单',
|
||||
'DIGITAL': '数字商品',
|
||||
'PHYSICAL': '实体商品'
|
||||
}
|
||||
return typeMap[orderType] || orderType
|
||||
}
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (dateString) => {
|
||||
const date = new Date(dateString)
|
||||
return date.toLocaleDateString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})
|
||||
}
|
||||
|
||||
// 检查是否可以支付
|
||||
const canPay = (order) => {
|
||||
return order.status === 'PENDING' || order.status === 'CONFIRMED'
|
||||
}
|
||||
|
||||
// 检查是否可以取消
|
||||
const canCancel = (order) => {
|
||||
return order.status === 'PENDING' || order.status === 'CONFIRMED'
|
||||
}
|
||||
|
||||
// 获取订单列表
|
||||
const fetchOrders = async () => {
|
||||
console.log('=== 开始获取订单列表 ===')
|
||||
console.log('当前用户:', userStore.user)
|
||||
console.log('认证状态:', userStore.isAuthenticated)
|
||||
console.log('Token:', sessionStorage.getItem('token'))
|
||||
|
||||
const params = {
|
||||
page: pagination.page - 1,
|
||||
size: pagination.size,
|
||||
sortBy: sortBy.value,
|
||||
sortDir: sortDir.value
|
||||
}
|
||||
|
||||
if (filters.status) {
|
||||
params.status = filters.status
|
||||
}
|
||||
|
||||
if (filters.search) {
|
||||
params.search = filters.search
|
||||
}
|
||||
|
||||
console.log('请求参数:', params)
|
||||
|
||||
try {
|
||||
const response = await orderStore.fetchOrders(params)
|
||||
console.log('API响应:', response)
|
||||
|
||||
if (response.success) {
|
||||
pagination.total = orderStore.pagination.total
|
||||
console.log('订单数据:', orderStore.orders)
|
||||
console.log('分页信息:', orderStore.pagination)
|
||||
} else {
|
||||
console.error('获取订单失败:', response.message)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取订单异常:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选变化
|
||||
const handleFilterChange = () => {
|
||||
pagination.page = 1
|
||||
fetchOrders()
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
pagination.page = 1
|
||||
fetchOrders()
|
||||
}
|
||||
|
||||
// 重置筛选
|
||||
const resetFilters = () => {
|
||||
filters.status = ''
|
||||
filters.search = ''
|
||||
pagination.page = 1
|
||||
fetchOrders()
|
||||
}
|
||||
|
||||
// 排序变化
|
||||
const handleSortChange = ({ prop, order }) => {
|
||||
if (prop) {
|
||||
sortBy.value = prop
|
||||
sortDir.value = order === 'ascending' ? 'asc' : 'desc'
|
||||
fetchOrders()
|
||||
}
|
||||
}
|
||||
|
||||
// 分页大小变化
|
||||
const handleSizeChange = (size) => {
|
||||
pagination.size = size
|
||||
pagination.page = 1
|
||||
fetchOrders()
|
||||
}
|
||||
|
||||
// 当前页变化
|
||||
const handleCurrentChange = (page) => {
|
||||
pagination.page = page
|
||||
fetchOrders()
|
||||
}
|
||||
|
||||
// 处理支付
|
||||
const handlePayment = async (order, paymentMethod) => {
|
||||
try {
|
||||
const response = await createOrderPayment(order.id, paymentMethod)
|
||||
if (response.success) {
|
||||
ElMessage.success('正在跳转到支付页面...')
|
||||
// 这里应该跳转到支付页面
|
||||
window.open(response.data.paymentUrl, '_blank')
|
||||
} else {
|
||||
ElMessage.error(response.message || '创建支付失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Payment error:', error)
|
||||
ElMessage.error('创建支付失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 处理取消
|
||||
const handleCancel = (order) => {
|
||||
currentCancelOrder.value = order
|
||||
cancelForm.reason = ''
|
||||
cancelDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 确认取消
|
||||
const confirmCancel = async () => {
|
||||
if (!currentCancelOrder.value) return
|
||||
|
||||
try {
|
||||
const response = await orderStore.cancelOrderById(
|
||||
currentCancelOrder.value.id,
|
||||
cancelForm.reason
|
||||
)
|
||||
|
||||
if (response.success) {
|
||||
ElMessage.success('订单取消成功')
|
||||
cancelDialogVisible.value = false
|
||||
fetchOrders()
|
||||
} else {
|
||||
ElMessage.error(response.message || '取消订单失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Cancel order error:', error)
|
||||
ElMessage.error('取消订单失败')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchOrders()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.orders {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* 页面特殊效果 */
|
||||
.orders::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background:
|
||||
radial-gradient(circle at 30% 20%, rgba(255, 255, 255, 0.1) 0%, transparent 50%),
|
||||
radial-gradient(circle at 70% 80%, rgba(255, 255, 255, 0.05) 0%, transparent 50%);
|
||||
animation: ordersPulse 5s ease-in-out infinite alternate;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@keyframes ordersPulse {
|
||||
0% { opacity: 0.3; transform: scale(1); }
|
||||
100% { opacity: 0.6; transform: scale(1.02); }
|
||||
}
|
||||
|
||||
/* 内容层级 */
|
||||
.orders > * {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.page-title h2 {
|
||||
margin: 0;
|
||||
color: #303133;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.page-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.filter-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.orders-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.order-link {
|
||||
color: #409EFF;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.order-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.amount {
|
||||
font-weight: 600;
|
||||
color: #E6A23C;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
/* 确保表格内下拉菜单不被裁剪/遮挡 */
|
||||
:deep(.table-dropdown) {
|
||||
z-index: 3000 !important;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.page-actions {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user