Files
jurong_supplier_management/src/views/Orders.vue
2025-10-15 17:26:57 +08:00

496 lines
14 KiB
Vue
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.

<template>
<div class="orders-container">
<div class="header">
<h2>订单管理</h2>
</div>
<div class="filters">
<el-form :inline="true" :model="filters" class="filter-form">
<el-form-item label="订单号">
<el-input
v-model="filters.orderNumber"
placeholder="请输入订单号"
clearable
@keyup.enter="loadOrders"
/>
</el-form-item>
<el-form-item label="用户名">
<el-input
v-model="filters.username"
placeholder="请输入用户名"
clearable
@keyup.enter="loadOrders"
/>
</el-form-item>
<el-form-item label="订单状态">
<el-select
v-model="filters.status"
placeholder="请选择状态"
clearable
style="display: inline-block; width: 150px"
>
<el-option label="待发货" value="pending" />
<el-option label="已发货" value="shipped" />
<el-option label="已完成" value="completed" />
<el-option label="已取消" value="cancelled" />
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="filters.dateRange"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadOrders">搜索</el-button>
<el-button @click="resetFilters">重置</el-button>
</el-form-item>
</el-form>
</div>
<el-table :data="orders" v-loading="loading" stripe>
<el-table-column prop="order_no" label="订单号" width="200" />
<el-table-column prop="username" label="用户" width="120" />
<el-table-column prop="total_points" label="总积分" width="100">
<template #default="{ row }">
<span class="points-text">{{ row.total_points }} 积分</span>
</template>
</el-table-column>
<el-table-column prop="total_rongdou" label="总融豆" width="100">
<template #default="{ row }">
<span class="points-text">{{ row.total_rongdou }} 融豆</span>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100">
<template #default="{ row }">
<el-tag :type="getStatusType(row.status)">
{{ getStatusText(row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="created_at" label="创建时间" width="180">
<template #default="{ row }">
{{ formatDate(row.created_at) }}
</template>
</el-table-column>
<el-table-column label="商品信息">
<template #default="{ row }">
<div class="order-items">
<div v-for="item in row.items" :key="item.id" class="order-item">
<el-image
:src="getImageUrl(item.image_url)"
fit="cover"
style="width: 40px; height: 40px; border-radius: 4px"
/>
<div class="item-info">
<div class="item-name">{{ item.product_name }}</div>
<div class="item-detail">
{{ item.points }}积分 × {{ item.quantity }}
</div>
</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="producer" label="供应商">
<template #default="{ row }">
{{ row.producer || '平台发货' }}
</template>
</el-table-column>
<el-table-column prop="logistics_info" label="物流信息">
<template #default="{ row }">
快递单号{{ row.delivery_code || '暂无' }}
<br>
物流公司{{ row.logistics_company || '暂无' }}
</template>
</el-table-column>
<el-table-column prop="salesperson" label="分销员id">
<template #default="{ row }">
{{ row.salesperson || '无' }}
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<el-button type="primary" size="small" @click="viewOrder(row)">
查看详情
</el-button>
<el-dropdown
v-if="row.status !== 'cancelled' && row.status !== 'completed'"
>
<el-button type="warning" size="small">
更新状态
<el-icon class="el-icon--right"><arrow-down /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
v-if="row.status === 'pending'"
@click="deliveryDialogVisible = true; selectedOrder = {id: row.id};"
>
标记为已发货
</el-dropdown-item>
<el-dropdown-item
v-if="row.status === 'shipped'"
@click="updateOrderStatus(row, 'completed')"
>
标记为已完成
</el-dropdown-item>
<el-dropdown-item
@click="updateOrderStatus(row, 'cancelled')"
divided
>
取消订单
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination
v-model:current-page="pagination.page"
v-model:page-size="pagination.limit"
:page-sizes="[10, 20, 50, 100]"
:total="pagination.total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="loadOrders"
@current-change="loadOrders"
/>
</div>
<!-- 订单详情对话框 -->
<el-dialog
v-model="dialogVisible"
title="订单详情"
width="800px"
:before-close="closeDialog"
>
<div v-if="selectedOrder" class="order-detail">
<el-descriptions :column="2" border>
<el-descriptions-item label="订单号">{{
selectedOrder.order_no
}}</el-descriptions-item>
<el-descriptions-item label="用户">{{
selectedOrder.username
}}</el-descriptions-item>
<el-descriptions-item label="总积分">
<span class="points-text"
>{{ selectedOrder.total_points }} 积分</span
>
</el-descriptions-item>
<el-descriptions-item label="订单状态">
<el-tag :type="getStatusType(selectedOrder.status)">
{{ getStatusText(selectedOrder.status) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="创建时间">{{
formatDate(selectedOrder.created_at)
}}</el-descriptions-item>
<el-descriptions-item label="更新时间">{{
formatDate(selectedOrder.updated_at)
}}</el-descriptions-item>
<el-descriptions-item label="物流单号">{{
selectedOrder.delivery_code || '暂无'
}}</el-descriptions-item>
<el-descriptions-item label="物流公司">{{
selectedOrder.logistics_company || '暂无'
}}</el-descriptions-item>
</el-descriptions>
<h4 style="margin: 20px 0 10px 0">商品清单</h4>
<el-table :data="selectedOrder.items" border>
<el-table-column label="商品图片" width="100">
<template #default="{ row }">
<el-image
:src="getImageUrl(row.image_url)"
fit="cover"
style="width: 60px; height: 60px; border-radius: 4px"
/>
</template>
</el-table-column>
<el-table-column prop="product_name" label="商品名称" />
<el-table-column prop="points" label="单价">
<template #default="{ row }">
<span class="points-text">{{ row.points_price }} 积分 | {{ row.rongdou_price }} 融豆</span>
</template>
</el-table-column>
<el-table-column prop="quantity" label="数量" width="80" />
<el-table-column label="小计" width="120">
<template #default="{ row }">
<span class="points-text"
>{{ row.points_price * row.quantity }} 积分 | {{ row.rongdou_price * row.quantity }} 融豆</span>
</template>
</el-table-column>
</el-table>
<el-button type="primary" size="small" @click="deliveryDialogVisible = true; deliveryForm.id = selectedOrder.id;" class="delivery-btn" v-if="selectedOrder.status === 'pending'">
发货
</el-button>
</div>
</el-dialog>
<!-- 发货对话框 -->
<el-dialog
v-model="deliveryDialogVisible"
title="发货"
width="400px"
:before-close="closeDialog"
>
<el-form :model="deliveryForm" :rules="deliveryRules" ref="deliveryFormRef">
<el-form-item label="物流公司" prop="logistics_company">
<el-input v-model="deliveryForm.logistics_company" placeholder="请输入物流公司名称" />
</el-form-item>
<el-form-item label="物流单号" prop="logistics_no">
<el-input v-model="deliveryForm.logistics_no" placeholder="请输入物流单号" />
</el-form-item>
</el-form>
<template #footer>
<el-button type="primary" @click="updateOrderStatus(selectedOrder, 'shipped', deliveryForm.logistics_company, deliveryForm.logistics_no)">
提交发货
</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { ArrowDown } from '@element-plus/icons-vue';
import api from '@/utils/api';
import { getImageUrl } from '@/utils/config';
import dayjs from 'dayjs';
const loading = ref(false);
const orders = ref([]);
const dialogVisible = ref(false);
const deliveryDialogVisible = ref(false);
const selectedOrder = ref(null);
const filters = reactive({
orderNumber: '',
username: '',
status: '',
dateRange: null,
});
const pagination = ref({
page: 1,
limit: 20,
total: 0,
});
const deliveryForm = reactive({
logistics_company: '',
logistics_no: ''
});
// 加载订单列表
const loadOrders = async () => {
loading.value = true;
try {
const params = {
page: pagination.value.page,
limit: pagination.value.limit,
orderNumber: filters.orderNumber,
username: filters.username,
status: filters.status,
};
if (filters.dateRange && filters.dateRange.length === 2) {
params.startDate = filters.dateRange[0];
params.endDate = filters.dateRange[1];
}
const { data } = await api.get('/orders', { params });
orders.value = data.data.orders;
pagination.value.total = data.data.pagination.total;
} catch (error) {
ElMessage.error('加载订单列表失败');
console.error('加载订单列表失败:', error);
} finally {
loading.value = false;
}
};
// 重置筛选条件
const resetFilters = () => {
Object.assign(filters, {
orderNumber: '',
username: '',
status: '',
dateRange: null,
});
pagination.page = 1;
loadOrders();
};
// 查看订单详情
const viewOrder = async (order) => {
try {
const { data } = await api.get(`/orders/${order.id}`);
selectedOrder.value = data.data.order;
dialogVisible.value = true;
} catch (error) {
ElMessage.error('加载订单详情失败');
}
};
// 更新订单状态
const updateOrderStatus = async (order, newStatus, logistics_company, logistics_no) => {
const statusText = getStatusText(newStatus);
try {
await ElMessageBox.confirm(
`确定要将订单状态更新为「${statusText}」吗?`,
'确认操作',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
);
await api.put(`/orders/${order.id}/status`, { status: newStatus, logistics_company: logistics_company, logistics_no: logistics_no });
ElMessage.success('订单状态更新成功');
loadOrders();
} catch (error) {
if (error !== 'cancel') {
console.log('更新订单状态失败:', error);
ElMessage.error('更新订单状态失败');
}
}
};
// 关闭对话框
const closeDialog = () => {
dialogVisible.value = false;
deliveryDialogVisible.value = false;
deliveryForm.value = {
logistics_company: '',
logistics_no: '',
id: '',
};
selectedOrder.value = null;
};
// 获取状态类型
const getStatusType = (status) => {
const types = {
pending: 'warning',
shipped: 'primary',
completed: 'success',
cancelled: 'danger',
};
return types[status] || 'info';
};
// 获取状态文本
const getStatusText = (status) => {
const texts = {
pending: '待发货',
shipped: '已发货',
pre_order: '待支付',
cancelled: '已取消',
completed: '已完成',
};
return texts[status] || status;
};
const deliveryRules = reactive({
logistics_company: [{ required: true, message: '请输入物流公司名称', trigger: 'blur' }],
logistics_no: [{ required: true, message: '请输入物流单号', trigger: 'blur' }],
});
// 格式化日期
const formatDate = (dateString) => {
return dayjs(dateString).format('YYYY-MM-DD HH:mm:ss');
};
onMounted(() => {
loadOrders();
});
</script>
<style scoped>
.orders-container {
padding: 20px;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.header h2 {
margin: 0;
color: #303133;
}
.filters {
background: #f5f7fa;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
.filter-form {
margin: 0;
}
.points-text {
color: #e6a23c;
font-weight: 500;
}
.order-items {
display: flex;
flex-direction: column;
gap: 8px;
}
.order-item {
display: flex;
align-items: center;
gap: 10px;
}
.item-info {
flex: 1;
}
.item-name {
font-size: 14px;
color: #303133;
margin-bottom: 2px;
}
.item-detail {
font-size: 12px;
color: #909399;
}
.order-detail {
padding: 10px 0;
}
.pagination {
margin-top: 20px;
display: flex;
justify-content: center;
}
.delivery-btn {
display: flex;
justify-content: center;
margin: 0 auto;
margin-top: 10px;
}
</style>