feat(backend): 开发订单管理和供应商管理功能

- 新增订单管理页面,实现订单列表展示、搜索、分页等功能
- 新增供应商管理页面,实现供应商列表展示、搜索、分页等功能- 添加订单和供应商相关模型及数据库迁移
- 实现订单状态更新和供应商信息编辑功能
- 优化后端路由结构,移除不必要的代码
This commit is contained in:
ylweng
2025-09-18 23:51:25 +08:00
parent 8637c05970
commit 5b6b50b60b
21 changed files with 3593 additions and 400 deletions

View File

@@ -0,0 +1,75 @@
import request from '@/utils/request'
import type {
Supplier,
SupplierListParams,
SupplierCreateForm,
SupplierUpdateForm,
SupplierStatistics
} from '@/types/supplier'
// 获取供应商列表
export const getSupplierList = (params: SupplierListParams) => {
return request<{
list: Supplier[]
pagination: {
page: number
pageSize: number
total: number
totalPages: number
}
}>({
url: '/suppliers',
method: 'GET',
params
})
}
// 获取供应商详情
export const getSupplierDetail = (id: number) => {
return request<Supplier>({
url: `/suppliers/${id}`,
method: 'GET'
})
}
// 创建供应商
export const createSupplier = (data: SupplierCreateForm) => {
return request<Supplier>({
url: '/suppliers',
method: 'POST',
data: {
...data,
cattleTypes: Array.isArray(data.cattleTypes) ? data.cattleTypes : JSON.parse(data.cattleTypes || '[]'),
certifications: Array.isArray(data.certifications) ? data.certifications : JSON.parse(data.certifications || '[]')
}
})
}
// 更新供应商
export const updateSupplier = (id: number, data: SupplierUpdateForm) => {
return request<Supplier>({
url: `/suppliers/${id}`,
method: 'PUT',
data: {
...data,
cattleTypes: data.cattleTypes ? (Array.isArray(data.cattleTypes) ? data.cattleTypes : JSON.parse(data.cattleTypes)) : undefined,
certifications: data.certifications ? (Array.isArray(data.certifications) ? data.certifications : JSON.parse(data.certifications)) : undefined
}
})
}
// 删除供应商
export const deleteSupplier = (id: number) => {
return request({
url: `/suppliers/${id}`,
method: 'DELETE'
})
}
// 获取供应商统计信息
export const getSupplierStats = () => {
return request<SupplierStatistics>({
url: '/suppliers/stats/overview',
method: 'GET'
})
}

View File

@@ -0,0 +1,142 @@
import request from '@/utils/request';
import type {
Transport,
TransportCreateForm,
TransportUpdateForm,
TransportListParams,
Vehicle,
VehicleCreateForm,
VehicleUpdateForm,
VehicleListParams
} from '@/types/transport';
import type { PaginatedResponse, ApiResponse } from '@/types/api';
// 运输管理相关API接口
/**
* 获取运输列表
* @param params 查询参数
* @returns 运输列表
*/
export const getTransportList = (params: TransportListParams): Promise<ApiResponse<PaginatedResponse<Transport>>> => {
return request({
url: '/transports',
method: 'get',
params
});
};
/**
* 获取运输详情
* @param id 运输ID
* @returns 运输详情
*/
export const getTransportDetail = (id: number): Promise<ApiResponse<Transport>> => {
return request({
url: `/transports/${id}`,
method: 'get'
});
};
/**
* 创建运输记录
* @param data 运输创建表单
* @returns 创建的运输记录
*/
export const createTransport = (data: TransportCreateForm): Promise<ApiResponse<Transport>> => {
return request({
url: '/transports',
method: 'post',
data
});
};
/**
* 更新运输记录
* @param id 运输ID
* @param data 运输更新表单
* @returns 更新的运输记录
*/
export const updateTransport = (id: number, data: TransportUpdateForm): Promise<ApiResponse<Transport>> => {
return request({
url: `/transports/${id}`,
method: 'put',
data
});
};
/**
* 删除运输记录
* @param id 运输ID
* @returns 删除结果
*/
export const deleteTransport = (id: number): Promise<ApiResponse<null>> => {
return request({
url: `/transports/${id}`,
method: 'delete'
});
};
/**
* 获取车辆列表
* @param params 查询参数
* @returns 车辆列表
*/
export const getVehicleList = (params: VehicleListParams): Promise<ApiResponse<PaginatedResponse<Vehicle>>> => {
return request({
url: '/transports/vehicles',
method: 'get',
params
});
};
/**
* 获取车辆详情
* @param id 车辆ID
* @returns 车辆详情
*/
export const getVehicleDetail = (id: number): Promise<ApiResponse<Vehicle>> => {
return request({
url: `/transports/vehicles/${id}`,
method: 'get'
});
};
/**
* 创建车辆记录
* @param data 车辆创建表单
* @returns 创建的车辆记录
*/
export const createVehicle = (data: VehicleCreateForm): Promise<ApiResponse<Vehicle>> => {
return request({
url: '/transports/vehicles',
method: 'post',
data
});
};
/**
* 更新车辆记录
* @param id 车辆ID
* @param data 车辆更新表单
* @returns 更新的车辆记录
*/
export const updateVehicle = (id: number, data: VehicleUpdateForm): Promise<ApiResponse<Vehicle>> => {
return request({
url: `/transports/vehicles/${id}`,
method: 'put',
data
});
};
/**
* 删除车辆记录
* @param id 车辆ID
* @returns 删除结果
*/
export const deleteVehicle = (id: number): Promise<ApiResponse<null>> => {
return request({
url: `/transports/vehicles/${id}`,
method: 'delete'
});
};

View File

@@ -0,0 +1,24 @@
// API响应相关类型定义
/**
* 分页响应数据结构
*/
export interface PaginatedResponse<T> {
list: T[];
pagination: {
page: number;
pageSize: number;
total: number;
totalPages: number;
};
}
/**
* API响应基础结构
*/
export interface ApiResponse<T> {
success: boolean;
data: T;
message: string;
code: number;
}

View File

@@ -0,0 +1,70 @@
// 供应商类型定义
export interface Supplier {
id: number;
name: string;
code: string;
contact: string;
phone: string;
address: string;
businessLicense?: string; // 营业执照
qualificationLevel: 'A+' | 'A' | 'B+' | 'B' | 'C'; // 资质等级A+, A, B+, B, C
certifications?: string[]; // 认证信息
cattleTypes: string[]; // 牛种类型
capacity: number; // 供应容量
rating: number; // 评分
cooperationStartDate: string; // 合作开始日期
status: 'active' | 'inactive' | 'suspended'; // 状态
region: 'north' | 'south' | 'east' | 'west' | 'northeast' | 'northwest' | 'southeast' | 'southwest' | 'central'; // 地区
created_at: string;
updated_at: string;
}
// 供应商创建表单类型
export interface SupplierCreateForm {
name: string;
code: string;
contact: string;
phone: string;
address: string;
businessLicense?: string;
qualificationLevel: 'A+' | 'A' | 'B+' | 'B' | 'C';
certifications?: string[];
cattleTypes: string[];
capacity: number;
region: 'north' | 'south' | 'east' | 'west' | 'northeast' | 'northwest' | 'southeast' | 'southwest' | 'central';
}
// 供应商更新表单类型
export interface SupplierUpdateForm {
name?: string;
contact?: string;
phone?: string;
address?: string;
businessLicense?: string;
qualificationLevel?: 'A+' | 'A' | 'B+' | 'B' | 'C';
certifications?: string[];
cattleTypes?: string[];
capacity?: number;
region?: 'north' | 'south' | 'east' | 'west' | 'northeast' | 'northwest' | 'southeast' | 'southwest' | 'central';
status?: 'active' | 'inactive' | 'suspended';
}
// 供应商列表查询参数
export interface SupplierListParams {
page?: number;
pageSize?: number;
keyword?: string;
region?: string;
qualificationLevel?: string;
status?: string;
}
// 供应商统计信息
export interface SupplierStatistics {
totalSuppliers: number;
activeSuppliers: number;
averageRating: number;
totalCapacity: number;
levelStats: Record<string, number>;
regionStats: Record<string, number>;
}

View File

@@ -0,0 +1,111 @@
// 运输管理相关类型定义
// 运输状态枚举
export type TransportStatus = 'scheduled' | 'in_transit' | 'completed' | 'cancelled';
// 运输记录接口
export interface Transport {
id: number;
order_id: number;
driver_id: number;
vehicle_id: number;
start_location: string;
end_location: string;
scheduled_start_time: string; // ISO 8601 格式
scheduled_end_time: string; // ISO 8601 格式
actual_start_time?: string; // ISO 8601 格式
actual_end_time?: string; // ISO 8601 格式
status: TransportStatus;
cattle_count: number;
special_requirements?: string;
created_at: string; // ISO 8601 格式
updated_at: string; // ISO 8601 格式
}
// 运输记录创建表单
export interface TransportCreateForm {
order_id: number;
driver_id: number;
vehicle_id: number;
start_location: string;
end_location: string;
scheduled_start_time: string; // ISO 8601 格式
scheduled_end_time: string; // ISO 8601 格式
cattle_count: number;
special_requirements?: string;
}
// 运输记录更新表单
export interface TransportUpdateForm {
driver_id?: number;
vehicle_id?: number;
start_location?: string;
end_location?: string;
scheduled_start_time?: string; // ISO 8601 格式
scheduled_end_time?: string; // ISO 8601 格式
actual_start_time?: string; // ISO 8601 格式
actual_end_time?: string; // ISO 8601 格式
status?: TransportStatus;
cattle_count?: number;
special_requirements?: string;
}
// 运输列表查询参数
export interface TransportListParams {
page?: number;
pageSize?: number;
status?: TransportStatus;
orderId?: number;
}
// 车辆状态枚举
export type VehicleStatus = 'available' | 'in_use' | 'maintenance' | 'retired';
// 车辆接口
export interface Vehicle {
id: number;
license_plate: string; // 车牌号
vehicle_type: string; // 车辆类型
capacity: number; // 载重能力(公斤)
driver_id: number; // 司机ID
status: VehicleStatus;
last_maintenance_date?: string; // ISO 8601 格式
next_maintenance_date?: string; // ISO 8601 格式
insurance_expiry_date?: string; // ISO 8601 格式
registration_expiry_date?: string; // ISO 8601 格式
created_at: string; // ISO 8601 格式
updated_at: string; // ISO 8601 格式
}
// 车辆创建表单
export interface VehicleCreateForm {
license_plate: string;
vehicle_type: string;
capacity: number;
driver_id: number;
status: VehicleStatus;
last_maintenance_date?: string; // ISO 8601 格式
next_maintenance_date?: string; // ISO 8601 格式
insurance_expiry_date?: string; // ISO 8601 格式
registration_expiry_date?: string; // ISO 8601 格式
}
// 车辆更新表单
export interface VehicleUpdateForm {
license_plate?: string;
vehicle_type?: string;
capacity?: number;
driver_id?: number;
status?: VehicleStatus;
last_maintenance_date?: string; // ISO 8601 格式
next_maintenance_date?: string; // ISO 8601 格式
insurance_expiry_date?: string; // ISO 8601 格式
registration_expiry_date?: string; // ISO 8601 格式
}
// 车辆列表查询参数
export interface VehicleListParams {
page?: number;
pageSize?: number;
status?: VehicleStatus;
}

View File

@@ -1,34 +1,409 @@
<template>
<div class="order-management">
<el-card>
<div class="page-header">
<h2>订单管理</h2>
<p>管理活牛采购订单的全生命周期流程</p>
</div>
<template #header>
<div class="card-header">
<span>订单管理</span>
<el-button type="primary" @click="handleCreateOrder">创建订单</el-button>
</div>
</template>
<el-empty description="订单管理功能开发中..." />
<!-- 搜索条件 -->
<el-form :model="searchForm" label-width="80px" class="search-form">
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="订单号">
<el-input v-model="searchForm.orderNo" placeholder="请输入订单号" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="订单状态">
<el-select v-model="searchForm.status" placeholder="请选择状态" clearable>
<el-option
v-for="status in orderStatusOptions"
:key="status.value"
:label="status.label"
:value="status.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="下单时间">
<el-date-picker
v-model="searchForm.dateRange"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item>
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 订单列表 -->
<el-table :data="orderList" v-loading="loading" style="width: 100%" stripe>
<el-table-column prop="orderNo" label="订单号" width="180" />
<el-table-column prop="buyerName" label="采购方" width="120" />
<el-table-column prop="supplierName" label="供应商" width="120" />
<el-table-column prop="cattleBreed" label="牛品种" width="100" />
<el-table-column prop="cattleCount" label="数量" width="80" />
<el-table-column prop="expectedWeight" label="预估重量(kg)" width="120" />
<el-table-column prop="totalAmount" label="总金额(元)" width="120" />
<el-table-column prop="status" label="状态" width="100">
<template #default="{ row }">
<el-tag :type="getStatusTagType(row.status)">
{{ getOrderStatusText(row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createdAt" label="下单时间" width="180" />
<el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<el-button size="small" @click="handleViewDetail(row)">详情</el-button>
<el-button
size="small"
type="primary"
@click="handleUpdateStatus(row)"
v-if="canUpdateStatus(row)"
>
更新状态
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
v-model:current-page="pagination.currentPage"
v-model:page-size="pagination.pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="pagination.total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
class="pagination"
/>
</el-card>
<!-- 订单详情对话框 -->
<el-dialog v-model="detailDialogVisible" title="订单详情" width="60%">
<el-descriptions :column="2" border>
<el-descriptions-item label="订单号">{{ currentOrder.orderNo }}</el-descriptions-item>
<el-descriptions-item label="订单状态">
<el-tag :type="getStatusTagType(currentOrder.status)">
{{ getOrderStatusText(currentOrder.status) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="采购方">{{ currentOrder.buyerName }}</el-descriptions-item>
<el-descriptions-item label="供应商">{{ currentOrder.supplierName }}</el-descriptions-item>
<el-descriptions-item label="牛品种">{{ currentOrder.cattleBreed }}</el-descriptions-item>
<el-descriptions-item label="数量">{{ currentOrder.cattleCount }} </el-descriptions-item>
<el-descriptions-item label="预估重量">{{ currentOrder.expectedWeight }} kg</el-descriptions-item>
<el-descriptions-item label="单价">{{ currentOrder.unitPrice }} /kg</el-descriptions-item>
<el-descriptions-item label="总金额">{{ currentOrder.totalAmount }} </el-descriptions-item>
<el-descriptions-item label="已支付">{{ currentOrder.paidAmount }} </el-descriptions-item>
<el-descriptions-item label="待支付">{{ currentOrder.remainingAmount }} </el-descriptions-item>
<el-descriptions-item label="交付地址">{{ currentOrder.deliveryAddress }}</el-descriptions-item>
<el-descriptions-item label="期望交付日期">{{ currentOrder.expectedDeliveryDate }}</el-descriptions-item>
<el-descriptions-item label="实际交付日期">{{ currentOrder.actualDeliveryDate || '-' }}</el-descriptions-item>
<el-descriptions-item label="下单时间">{{ currentOrder.createdAt }}</el-descriptions-item>
<el-descriptions-item label="备注">{{ currentOrder.notes || '-' }}</el-descriptions-item>
</el-descriptions>
<template #footer>
<span class="dialog-footer">
<el-button @click="detailDialogVisible = false">关闭</el-button>
</span>
</template>
</el-dialog>
<!-- 更新状态对话框 -->
<el-dialog v-model="statusDialogVisible" title="更新订单状态" width="400px">
<el-form :model="statusForm" label-width="80px">
<el-form-item label="当前状态">
<el-tag :type="getStatusTagType(currentOrder.status)">
{{ getOrderStatusText(currentOrder.status) }}
</el-tag>
</el-form-item>
<el-form-item label="新状态" prop="status" :rules="{ required: true, message: '请选择状态', trigger: 'change' }">
<el-select v-model="statusForm.status" placeholder="请选择新状态" style="width: 100%">
<el-option
v-for="status in getNextStatusOptions(currentOrder.status)"
:key="status.value"
:label="status.label"
:value="status.value"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="statusDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitStatusUpdate">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
// 订单管理页面
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { Order, OrderStatus, OrderListParams } from '@/types/order'
import { getOrderList, getOrderDetail, updateOrder } from '@/api/order'
// 订单列表数据
const orderList = ref<Order[]>([])
const loading = ref(false)
// 搜索表单
const searchForm = reactive({
orderNo: '',
status: '',
dateRange: []
})
// 分页信息
const pagination = reactive({
currentPage: 1,
pageSize: 10,
total: 0
})
// 对话框控制
const detailDialogVisible = ref(false)
const statusDialogVisible = ref(false)
// 当前选中的订单
const currentOrder = ref<Order>({
id: 0,
orderNo: '',
buyerId: 0,
buyerName: '',
supplierId: 0,
supplierName: '',
cattleBreed: '',
cattleCount: 0,
expectedWeight: 0,
unitPrice: 0,
totalAmount: 0,
paidAmount: 0,
remainingAmount: 0,
status: 'pending',
deliveryAddress: '',
expectedDeliveryDate: '',
createdAt: '',
updatedAt: ''
})
// 状态更新表单
const statusForm = reactive({
status: '' as OrderStatus
})
// 订单状态选项
const orderStatusOptions = [
{ value: 'pending', label: '待确认' },
{ value: 'confirmed', label: '已确认' },
{ value: 'preparing', label: '准备中' },
{ value: 'shipping', label: '运输中' },
{ value: 'delivered', label: '已送达' },
{ value: 'accepted', label: '已验收' },
{ value: 'completed', label: '已完成' },
{ value: 'cancelled', label: '已取消' },
{ value: 'refunded', label: '已退款' }
]
// 获取订单状态文本
const getOrderStatusText = (status: OrderStatus) => {
const statusMap: Record<OrderStatus, string> = {
pending: '待确认',
confirmed: '已确认',
preparing: '准备中',
shipping: '运输中',
delivered: '已送达',
accepted: '已验收',
completed: '已完成',
cancelled: '已取消',
refunded: '已退款'
}
return statusMap[status] || status
}
// 获取状态标签类型
const getStatusTagType = (status: OrderStatus) => {
const typeMap: Record<OrderStatus, 'primary' | 'success' | 'warning' | 'danger' | 'info'> = {
pending: 'warning',
confirmed: 'primary',
preparing: 'primary',
shipping: 'primary',
delivered: 'primary',
accepted: 'primary',
completed: 'success',
cancelled: 'danger',
refunded: 'danger'
}
return typeMap[status] || 'info'
}
// 获取下一状态选项
const getNextStatusOptions = (currentStatus: OrderStatus) => {
const nextStatusMap: Record<OrderStatus, OrderStatus[]> = {
pending: ['confirmed', 'cancelled'],
confirmed: ['preparing', 'cancelled'],
preparing: ['shipping'],
shipping: ['delivered'],
delivered: ['accepted'],
accepted: ['completed'],
completed: [],
cancelled: [],
refunded: []
}
const nextStatuses = nextStatusMap[currentStatus] || []
return orderStatusOptions.filter(option => nextStatuses.includes(option.value as OrderStatus))
}
// 判断是否可以更新状态
const canUpdateStatus = (order: Order) => {
return order.status !== 'completed' && order.status !== 'cancelled' && order.status !== 'refunded'
}
// 获取订单列表
const fetchOrderList = async () => {
loading.value = true
try {
const params: OrderListParams = {
page: pagination.currentPage,
pageSize: pagination.pageSize,
orderNo: searchForm.orderNo || undefined,
status: searchForm.status || undefined
}
if (searchForm.dateRange && searchForm.dateRange.length === 2) {
params.startDate = searchForm.dateRange[0]
params.endDate = searchForm.dateRange[1]
}
const res = await getOrderList(params)
orderList.value = res.data.items
pagination.total = res.data.total
} catch (error) {
ElMessage.error('获取订单列表失败')
console.error(error)
} finally {
loading.value = false
}
}
// 处理搜索
const handleSearch = () => {
pagination.currentPage = 1
fetchOrderList()
}
// 处理重置
const handleReset = () => {
searchForm.orderNo = ''
searchForm.status = ''
searchForm.dateRange = []
pagination.currentPage = 1
fetchOrderList()
}
// 处理分页大小变化
const handleSizeChange = (val: number) => {
pagination.pageSize = val
pagination.currentPage = 1
fetchOrderList()
}
// 处理当前页变化
const handleCurrentChange = (val: number) => {
pagination.currentPage = val
fetchOrderList()
}
// 处理创建订单
const handleCreateOrder = () => {
ElMessage.info('创建订单功能开发中...')
}
// 处理查看详情
const handleViewDetail = async (order: Order) => {
try {
const res = await getOrderDetail(order.id)
currentOrder.value = res.data
detailDialogVisible.value = true
} catch (error) {
ElMessage.error('获取订单详情失败')
console.error(error)
}
}
// 处理更新状态
const handleUpdateStatus = (order: Order) => {
currentOrder.value = order
statusForm.status = '' as OrderStatus
statusDialogVisible.value = true
}
// 提交状态更新
const submitStatusUpdate = async () => {
if (!statusForm.status) {
ElMessage.warning('请选择新状态')
return
}
try {
await updateOrder(currentOrder.value.id, { status: statusForm.status })
ElMessage.success('订单状态更新成功')
statusDialogVisible.value = false
fetchOrderList()
} catch (error) {
ElMessage.error('订单状态更新失败')
console.error(error)
}
}
// 组件挂载时获取数据
onMounted(() => {
fetchOrderList()
})
</script>
<style lang="scss" scoped>
.order-management {
.page-header {
text-align: center;
margin-bottom: 30px;
h2 {
color: #333;
margin-bottom: 10px;
}
p {
color: #666;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.search-form {
margin-bottom: 20px;
}
.pagination {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
}
}
</style>

View File

@@ -6,13 +6,559 @@
<p>管理供应商信息资质认证和绩效评估</p>
</div>
<el-empty description="供应商管理功能开发中..." />
<!-- 搜索和操作栏 -->
<div class="toolbar">
<el-form :model="searchForm" label-width="80px" class="search-form">
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="供应商名称">
<el-input v-model="searchForm.name" placeholder="请输入供应商名称" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="供应商编码">
<el-input v-model="searchForm.code" placeholder="请输入供应商编码" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="状态">
<el-select v-model="searchForm.status" placeholder="请选择状态" clearable>
<el-option label="活跃" value="active" />
<el-option label="非活跃" value="inactive" />
<el-option label="已暂停" value="suspended" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<div class="toolbar-buttons">
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button @click="handleReset">重置</el-button>
<el-button type="success" @click="handleCreate">新增供应商</el-button>
</div>
</el-col>
</el-row>
</el-form>
</div>
<!-- 供应商列表 -->
<el-table :data="supplierList" border stripe v-loading="loading">
<el-table-column prop="name" label="供应商名称" min-width="120" />
<el-table-column prop="code" label="编码" width="100" />
<el-table-column prop="contact" label="联系人" width="100" />
<el-table-column prop="phone" label="联系电话" width="120" />
<el-table-column prop="region" label="所属地区" width="100" />
<el-table-column prop="qualificationLevel" label="资质等级" width="100">
<template #default="{ row }">
<el-tag :type="getQualificationLevelType(row.qualificationLevel)">
{{ row.qualificationLevel }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="rating" label="评级" width="80" />
<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="certifications" label="认证信息" min-width="120">
<template #default="{ row }">
<el-tag
v-for="cert in row.certifications"
:key="cert"
size="small"
style="margin-right: 5px;"
>
{{ cert }}
</el-tag>
<span v-if="!row.certifications || row.certifications.length === 0"></span>
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<el-button size="small" @click="handleView(row)">查看</el-button>
<el-button size="small" @click="handleEdit(row)">编辑</el-button>
<el-popconfirm
title="确定要删除这个供应商吗?"
@confirm="handleDelete(row.id)"
>
<template #reference>
<el-button size="small" type="danger">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination
v-model:current-page="pagination.page"
v-model:page-size="pagination.pageSize"
: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="detailDialogVisible" title="供应商详情" width="600px">
<el-descriptions :column="1" border>
<el-descriptions-item label="供应商名称">{{ currentSupplier?.name }}</el-descriptions-item>
<el-descriptions-item label="编码">{{ currentSupplier?.code }}</el-descriptions-item>
<el-descriptions-item label="联系人">{{ currentSupplier?.contact }}</el-descriptions-item>
<el-descriptions-item label="联系电话">{{ currentSupplier?.phone }}</el-descriptions-item>
<el-descriptions-item label="地址">{{ currentSupplier?.address }}</el-descriptions-item>
<el-descriptions-item label="营业执照">{{ currentSupplier?.businessLicense }}</el-descriptions-item>
<el-descriptions-item label="所属地区">{{ getRegionText(currentSupplier?.region) }}</el-descriptions-item>
<el-descriptions-item label="资质等级">
<el-tag :type="getQualificationLevelType(currentSupplier?.qualificationLevel)">
{{ currentSupplier?.qualificationLevel }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="认证信息">
<el-tag
v-for="cert in currentSupplier?.certifications"
:key="cert"
size="small"
style="margin-right: 5px;"
>
{{ cert }}
</el-tag>
<span v-if="!currentSupplier?.certifications || currentSupplier?.certifications.length === 0"></span>
</el-descriptions-item>
<el-descriptions-item label="支持牛种">{{ getFormattedCattleTypes(currentSupplier?.cattleTypes) }}</el-descriptions-item>
<el-descriptions-item label="供应能力">{{ currentSupplier?.capacity }} </el-descriptions-item>
<el-descriptions-item label="评级">{{ currentSupplier?.rating }}</el-descriptions-item>
<el-descriptions-item label="状态">
<el-tag :type="getStatusType(currentSupplier?.status)">
{{ getStatusText(currentSupplier?.status) }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="合作开始日期">{{ currentSupplier?.cooperationStartDate }}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ currentSupplier?.created_at }}</el-descriptions-item>
<el-descriptions-item label="更新时间">{{ currentSupplier?.updated_at }}</el-descriptions-item>
</el-descriptions>
<template #footer>
<el-button @click="detailDialogVisible = false">关闭</el-button>
</template>
</el-dialog>
<!-- 供应商编辑对话框 -->
<el-dialog v-model="editDialogVisible" :title="editForm.id ? '编辑供应商' : '新增供应商'" width="600px">
<el-form :model="editForm" :rules="editRules" ref="editFormRef" label-width="100px">
<el-form-item label="供应商名称" prop="name">
<el-input v-model="editForm.name" />
</el-form-item>
<el-form-item label="编码" prop="code">
<el-input v-model="editForm.code" />
</el-form-item>
<el-form-item label="联系人" prop="contact">
<el-input v-model="editForm.contact" />
</el-form-item>
<el-form-item label="联系电话" prop="phone">
<el-input v-model="editForm.phone" />
</el-form-item>
<el-form-item label="地址" prop="address">
<el-input v-model="editForm.address" type="textarea" />
</el-form-item>
<el-form-item label="营业执照" prop="businessLicense">
<el-input v-model="editForm.businessLicense" placeholder="请输入营业执照编号" />
</el-form-item>
<el-form-item label="所属地区" prop="region">
<el-select v-model="editForm.region" placeholder="请选择所属地区">
<el-option
v-for="region in regionOptions"
:key="region.value"
:label="region.label"
:value="region.value"
/>
</el-select>
</el-form-item>
<el-form-item label="资质等级" prop="qualificationLevel">
<el-select v-model="editForm.qualificationLevel" placeholder="请选择资质等级">
<el-option label="A+" value="A+" />
<el-option label="A" value="A" />
<el-option label="B+" value="B+" />
<el-option label="B" value="B" />
<el-option label="C" value="C" />
</el-select>
</el-form-item>
<el-form-item label="认证信息" prop="certifications">
<el-select
v-model="editForm.certifications"
multiple
placeholder="请选择认证信息"
style="width: 100%"
>
<el-option label="ISO9001" value="ISO9001" />
<el-option label="ISO14001" value="ISO14001" />
<el-option label="有机认证" value="organic" />
<el-option label="无公害认证" value="pollutionFree" />
<el-option label="绿色食品认证" value="greenFood" />
</el-select>
</el-form-item>
<el-form-item label="支持牛种" prop="cattleTypes">
<el-select
v-model="editForm.cattleTypes"
multiple
placeholder="请选择支持的牛种类型"
style="width: 100%"
>
<el-option
v-for="cattleType in cattleTypeOptions"
:key="cattleType"
:label="cattleType"
:value="cattleType"
/>
</el-select>
</el-form-item>
<el-form-item label="供应能力" prop="capacity">
<el-input-number v-model="editForm.capacity" :min="0" />
</el-form-item>
<el-form-item label="状态" prop="status" v-if="editForm.id">
<el-select v-model="editForm.status" placeholder="请选择状态">
<el-option label="活跃" value="active" />
<el-option label="非活跃" value="inactive" />
<el-option label="已暂停" value="suspended" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="editDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
// 供应商管理页面
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance } from 'element-plus'
import {
getSupplierList,
getSupplierDetail,
createSupplier,
updateSupplier,
deleteSupplier
} from '@/api/supplier'
import type { Supplier, SupplierListParams, SupplierCreateForm, SupplierUpdateForm } from '@/types/supplier'
// 数据状态
const loading = ref(false)
const supplierList = ref<Supplier[]>([])
const detailDialogVisible = ref(false)
const editDialogVisible = ref(false)
// 当前查看的供应商
const currentSupplier = ref<Supplier | null>(null)
// 搜索表单
const searchForm = reactive<SupplierListParams>({
name: '',
code: '',
status: '',
page: 1,
pageSize: 10
})
// 分页信息
const pagination = reactive({
page: 1,
pageSize: 10,
total: 0
})
// 编辑表单
const editForm = reactive<SupplierCreateForm & SupplierUpdateForm & { id?: number }>({
id: undefined,
name: '',
code: '',
contact: '',
phone: '',
address: '',
businessLicense: '',
region: '',
qualificationLevel: '',
certifications: [],
cattleTypes: [],
capacity: 0,
status: 'active'
})
// 编辑表单验证规则
const editRules = {
name: [{ required: true, message: '请输入供应商名称', trigger: 'blur' }],
code: [{ required: true, message: '请输入供应商编码', trigger: 'blur' }],
contact: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
phone: [
{ required: true, message: '请输入联系电话', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
],
address: [{ required: true, message: '请输入地址', trigger: 'blur' }],
region: [{ required: true, message: '请选择所属地区', trigger: 'change' }],
qualificationLevel: [{ required: true, message: '请选择资质等级', trigger: 'change' }],
cattleTypes: [{ required: true, message: '请选择支持的牛种类型', trigger: 'change' }],
capacity: [{ required: true, message: '请输入供应能力', trigger: 'blur' }]
}
// 编辑表单引用
const editFormRef = ref<FormInstance>()
// 地区选项
const regionOptions = [
{ label: '华北地区', value: 'north' },
{ label: '华南地区', value: 'south' },
{ label: '华东地区', value: 'east' },
{ label: '华西地区', value: 'west' },
{ label: '东北地区', value: 'northeast' },
{ label: '西北地区', value: 'northwest' },
{ label: '东南地区', value: 'southeast' },
{ label: '西南地区', value: 'southwest' },
{ label: '华中地区', value: 'central' }
]
// 牛种类型选项
const cattleTypeOptions = [
'西门塔尔牛',
'夏洛莱牛',
'利木赞牛',
'安格斯牛',
'海福特牛',
'鲁西黄牛',
'延边牛',
'秦川牛',
'南阳牛',
'晋南牛'
]
// 获取供应商列表
const fetchSupplierList = async () => {
loading.value = true
try {
const params = {
...searchForm,
page: pagination.page,
pageSize: pagination.pageSize
}
const res = await getSupplierList(params)
supplierList.value = res.data.list
pagination.total = res.data.pagination.total
} catch (error) {
ElMessage.error('获取供应商列表失败')
} finally {
loading.value = false
}
}
// 状态标签类型映射
const getStatusType = (status: string) => {
switch (status) {
case 'active': return 'success'
case 'inactive': return 'info'
case 'suspended': return 'danger'
default: return 'info'
}
}
// 状态文本映射
const getStatusText = (status: string) => {
switch (status) {
case 'active': return '活跃'
case 'inactive': return '非活跃'
case 'suspended': return '已暂停'
default: return status
}
}
// 地区文本映射
const getRegionText = (region: string) => {
const regionOption = regionOptions.find(option => option.value === region)
return regionOption ? regionOption.label : region
}
// 格式化牛种类型显示
const getFormattedCattleTypes = (cattleTypes: string) => {
try {
const types = JSON.parse(cattleTypes)
return Array.isArray(types) ? types.join(', ') : cattleTypes
} catch {
return cattleTypes
}
}
// 资质等级标签类型映射
const getQualificationLevelType = (level: string) => {
switch (level) {
case 'A+': return 'success'
case 'A': return 'success'
case 'B+': return 'warning'
case 'B': return 'warning'
case 'C': return 'danger'
default: return 'info'
}
}
// 查询
const handleSearch = () => {
pagination.page = 1
fetchSupplierList()
}
// 重置
const handleReset = () => {
searchForm.name = ''
searchForm.code = ''
searchForm.status = ''
pagination.page = 1
fetchSupplierList()
}
// 查看详情
const handleView = async (supplier: Supplier) => {
try {
const res = await getSupplierDetail(supplier.id)
currentSupplier.value = res.data
detailDialogVisible.value = true
} catch (error) {
ElMessage.error('获取供应商详情失败')
}
}
// 新增供应商
const handleCreate = () => {
// 重置表单
Object.assign(editForm, {
id: undefined,
name: '',
code: '',
contact: '',
phone: '',
address: '',
businessLicense: '',
region: '',
qualificationLevel: '',
certifications: [],
cattleTypes: [],
capacity: 0,
status: 'active'
})
editDialogVisible.value = true
}
// 编辑供应商
const handleEdit = (supplier: Supplier) => {
// 解析牛种类型
let cattleTypes: string[] = []
try {
cattleTypes = typeof supplier.cattleTypes === 'string' ? JSON.parse(supplier.cattleTypes) : supplier.cattleTypes
} catch {
cattleTypes = []
}
// 解析认证信息
let certifications: string[] = []
try {
certifications = typeof supplier.certifications === 'string' ? JSON.parse(supplier.certifications) : supplier.certifications
} catch {
certifications = []
}
Object.assign(editForm, {
...supplier,
cattleTypes,
certifications
})
editDialogVisible.value = true
}
// 保存供应商
const handleSave = async () => {
if (!editFormRef.value) return
try {
await editFormRef.value.validate()
if (editForm.id) {
// 更新供应商
const updateData: SupplierUpdateForm = {
name: editForm.name,
code: editForm.code,
contact: editForm.contact,
phone: editForm.phone,
address: editForm.address,
businessLicense: editForm.businessLicense,
region: editForm.region,
qualificationLevel: editForm.qualificationLevel,
certifications: editForm.certifications,
cattleTypes: editForm.cattleTypes,
capacity: editForm.capacity,
status: editForm.status
}
await updateSupplier(editForm.id, updateData)
ElMessage.success('供应商更新成功')
} else {
// 创建供应商
const createData: SupplierCreateForm = {
name: editForm.name,
code: editForm.code,
contact: editForm.contact,
phone: editForm.phone,
address: editForm.address,
businessLicense: editForm.businessLicense,
region: editForm.region,
qualificationLevel: editForm.qualificationLevel,
certifications: editForm.certifications,
cattleTypes: editForm.cattleTypes,
capacity: editForm.capacity
}
await createSupplier(createData)
ElMessage.success('供应商创建成功')
}
editDialogVisible.value = false
fetchSupplierList()
} catch (error: any) {
ElMessage.error(error.message || '操作失败')
}
}
// 删除供应商
const handleDelete = async (id: number) => {
try {
await deleteSupplier(id)
ElMessage.success('供应商删除成功')
fetchSupplierList()
} catch (error) {
ElMessage.error('删除供应商失败')
}
}
// 分页大小改变
const handleSizeChange = (val: number) => {
pagination.pageSize = val
pagination.page = 1
fetchSupplierList()
}
// 页码改变
const handleCurrentChange = (val: number) => {
pagination.page = val
fetchSupplierList()
}
// 组件挂载时获取数据
onMounted(() => {
fetchSupplierList()
})
</script>
<style lang="scss" scoped>
@@ -30,5 +576,24 @@
color: #666;
}
}
.toolbar {
margin-bottom: 20px;
.search-form {
.toolbar-buttons {
display: flex;
gap: 10px;
justify-content: flex-end;
align-items: flex-start;
}
}
}
.pagination-container {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
}
</style>

View File

@@ -1,34 +1,478 @@
<template>
<div class="transport-management">
<el-card>
<div class="page-header">
<h2>运输管理</h2>
<p>实时跟踪运输过程监控车辆位置和牛只状态</p>
</div>
<h1 class="page-title">运输管理</h1>
<p class="page-description">实时跟踪运输过程监控车辆位置和牛只状态</p>
<!-- 搜索和操作栏 -->
<div class="toolbar">
<el-form :inline="true" :model="searchForm" class="search-form">
<el-form-item label="订单ID">
<el-input v-model="searchForm.orderId" placeholder="请输入订单ID" />
</el-form-item>
<el-form-item label="状态">
<el-select v-model="searchForm.status" placeholder="请选择状态" clearable>
<el-option label="已计划" value="scheduled" />
<el-option label="运输中" value="in_transit" />
<el-option label="已完成" value="completed" />
<el-option label="已取消" value="cancelled" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
<el-empty description="运输管理功能开发中..." />
</el-card>
<div class="actions">
<el-button type="primary" @click="handleCreate">新增运输</el-button>
</div>
</div>
<!-- 运输列表 -->
<el-table :data="transportList" style="width: 100%" v-loading="loading">
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="order_id" label="订单ID" width="100" />
<el-table-column prop="start_location" label="起始地" />
<el-table-column prop="end_location" label="目的地" />
<el-table-column prop="scheduled_start_time" label="计划开始时间" width="180">
<template #default="scope">
{{ formatDateTime(scope.row.scheduled_start_time) }}
</template>
</el-table-column>
<el-table-column prop="scheduled_end_time" label="计划结束时间" width="180">
<template #default="scope">
{{ formatDateTime(scope.row.scheduled_end_time) }}
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100">
<template #default="scope">
<el-tag :type="getStatusTagType(scope.row.status)">
{{ formatStatus(scope.row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="cattle_count" label="牛只数量" width="100" />
<el-table-column label="操作" width="200">
<template #default="scope">
<el-button size="small" @click="handleView(scope.row)">查看</el-button>
<el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(scope.row)" :disabled="scope.row.status !== 'scheduled'">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
v-model:current-page="pagination.page"
v-model:page-size="pagination.pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="pagination.total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
<!-- 运输详情对话框 -->
<el-dialog v-model="detailDialogVisible" title="运输详情" width="600px">
<el-form :model="currentTransport" label-width="120px" v-if="currentTransport">
<el-form-item label="ID:">
<span>{{ currentTransport.id }}</span>
</el-form-item>
<el-form-item label="订单ID:">
<span>{{ currentTransport.order_id }}</span>
</el-form-item>
<el-form-item label="司机ID:">
<span>{{ currentTransport.driver_id }}</span>
</el-form-item>
<el-form-item label="车辆ID:">
<span>{{ currentTransport.vehicle_id }}</span>
</el-form-item>
<el-form-item label="起始地:">
<span>{{ currentTransport.start_location }}</span>
</el-form-item>
<el-form-item label="目的地:">
<span>{{ currentTransport.end_location }}</span>
</el-form-item>
<el-form-item label="计划开始时间:">
<span>{{ formatDateTime(currentTransport.scheduled_start_time) }}</span>
</el-form-item>
<el-form-item label="计划结束时间:">
<span>{{ formatDateTime(currentTransport.scheduled_end_time) }}</span>
</el-form-item>
<el-form-item label="实际开始时间:">
<span>{{ currentTransport.actual_start_time ? formatDateTime(currentTransport.actual_start_time) : '-' }}</span>
</el-form-item>
<el-form-item label="实际结束时间:">
<span>{{ currentTransport.actual_end_time ? formatDateTime(currentTransport.actual_end_time) : '-' }}</span>
</el-form-item>
<el-form-item label="状态:">
<el-tag :type="getStatusTagType(currentTransport.status)">
{{ formatStatus(currentTransport.status) }}
</el-tag>
</el-form-item>
<el-form-item label="牛只数量:">
<span>{{ currentTransport.cattle_count }}</span>
</el-form-item>
<el-form-item label="特殊要求:">
<span>{{ currentTransport.special_requirements || '-' }}</span>
</el-form-item>
<el-form-item label="创建时间:">
<span>{{ formatDateTime(currentTransport.created_at) }}</span>
</el-form-item>
<el-form-item label="更新时间:">
<span>{{ formatDateTime(currentTransport.updated_at) }}</span>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="detailDialogVisible = false">关闭</el-button>
</template>
</el-dialog>
<!-- 运输编辑对话框 -->
<el-dialog v-model="editDialogVisible" :title="isEditing ? '编辑运输' : '新增运输'" width="600px">
<el-form :model="editForm" :rules="editRules" ref="editFormRef" label-width="120px">
<el-form-item label="订单ID:" prop="order_id">
<el-input v-model.number="editForm.order_id" />
</el-form-item>
<el-form-item label="司机ID:" prop="driver_id">
<el-input v-model.number="editForm.driver_id" />
</el-form-item>
<el-form-item label="车辆ID:" prop="vehicle_id">
<el-input v-model.number="editForm.vehicle_id" />
</el-form-item>
<el-form-item label="起始地:" prop="start_location">
<el-input v-model="editForm.start_location" />
</el-form-item>
<el-form-item label="目的地:" prop="end_location">
<el-input v-model="editForm.end_location" />
</el-form-item>
<el-form-item label="计划开始时间:" prop="scheduled_start_time">
<el-date-picker
v-model="editForm.scheduled_start_time"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择计划开始时间"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="计划结束时间:" prop="scheduled_end_time">
<el-date-picker
v-model="editForm.scheduled_end_time"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择计划结束时间"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="牛只数量:" prop="cattle_count">
<el-input v-model.number="editForm.cattle_count" />
</el-form-item>
<el-form-item label="特殊要求:">
<el-input v-model="editForm.special_requirements" type="textarea" />
</el-form-item>
<el-form-item label="状态:" prop="status" v-if="isEditing">
<el-select v-model="editForm.status" placeholder="请选择状态">
<el-option label="已计划" value="scheduled" />
<el-option label="运输中" value="in_transit" />
<el-option label="已完成" value="completed" />
<el-option label="已取消" value="cancelled" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="editDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
// 运输管理页面
import { ref, reactive, onMounted } from 'vue';
import { ElMessage, ElMessageBox, type FormInstance } from 'element-plus';
import {
getTransportList,
getTransportDetail,
createTransport,
updateTransport,
deleteTransport
} from '@/api/transport';
import type { Transport, TransportCreateForm, TransportUpdateForm, TransportListParams, TransportStatus } from '@/types/transport';
// 数据状态
const loading = ref(false);
const transportList = ref<Transport[]>([]);
const detailDialogVisible = ref(false);
const editDialogVisible = ref(false);
const isEditing = ref(false);
const currentTransport = ref<Transport | null>(null);
const editFormRef = ref<FormInstance>();
// 搜索表单
const searchForm = reactive({
orderId: '',
status: '' as TransportStatus | ''
});
// 分页
const pagination = reactive({
page: 1,
pageSize: 20,
total: 0
});
// 编辑表单
const editForm = reactive<TransportCreateForm & TransportUpdateForm>({
order_id: 0,
driver_id: 0,
vehicle_id: 0,
start_location: '',
end_location: '',
scheduled_start_time: '',
scheduled_end_time: '',
cattle_count: 0,
special_requirements: '',
status: 'scheduled'
});
// 表单验证规则
const editRules = {
order_id: [{ required: true, message: '请输入订单ID', trigger: 'blur' }],
driver_id: [{ required: true, message: '请输入司机ID', trigger: 'blur' }],
vehicle_id: [{ required: true, message: '请输入车辆ID', trigger: 'blur' }],
start_location: [{ required: true, message: '请输入起始地', trigger: 'blur' }],
end_location: [{ required: true, message: '请输入目的地', trigger: 'blur' }],
scheduled_start_time: [{ required: true, message: '请选择计划开始时间', trigger: 'change' }],
scheduled_end_time: [{ required: true, message: '请选择计划结束时间', trigger: 'change' }],
cattle_count: [{ required: true, message: '请输入牛只数量', trigger: 'blur' }]
};
// 格式化日期时间
const formatDateTime = (dateString: string) => {
if (!dateString) return '-';
const date = new Date(dateString);
return date.toLocaleString('zh-CN');
};
// 获取状态标签类型
const getStatusTagType = (status: string) => {
switch (status) {
case 'scheduled': return 'info';
case 'in_transit': return 'primary';
case 'completed': return 'success';
case 'cancelled': return 'danger';
default: return 'info';
}
};
// 格式化状态显示
const formatStatus = (status: string) => {
switch (status) {
case 'scheduled': return '已计划';
case 'in_transit': return '运输中';
case 'completed': return '已完成';
case 'cancelled': return '已取消';
default: return status;
}
};
// 获取运输列表
const fetchTransportList = async () => {
loading.value = true;
try {
const params: TransportListParams = {
page: pagination.page,
pageSize: pagination.pageSize,
orderId: searchForm.orderId ? Number(searchForm.orderId) : undefined,
status: searchForm.status || undefined
};
const response = await getTransportList(params);
if (response.success) {
transportList.value = response.data.list;
pagination.total = response.data.pagination.total;
} else {
ElMessage.error(response.message || '获取运输列表失败');
}
} catch (error) {
ElMessage.error('获取运输列表失败');
} finally {
loading.value = false;
}
};
// 搜索
const handleSearch = () => {
pagination.page = 1;
fetchTransportList();
};
// 重置
const handleReset = () => {
searchForm.orderId = '';
searchForm.status = '';
pagination.page = 1;
fetchTransportList();
};
// 查看详情
const handleView = async (transport: Transport) => {
try {
const response = await getTransportDetail(transport.id);
if (response.success) {
currentTransport.value = response.data;
detailDialogVisible.value = true;
} else {
ElMessage.error(response.message || '获取运输详情失败');
}
} catch (error) {
ElMessage.error('获取运输详情失败');
}
};
// 新增运输
const handleCreate = () => {
isEditing.value = false;
// 重置表单
Object.assign(editForm, {
order_id: 0,
driver_id: 0,
vehicle_id: 0,
start_location: '',
end_location: '',
scheduled_start_time: '',
scheduled_end_time: '',
cattle_count: 0,
special_requirements: '',
status: 'scheduled'
});
editDialogVisible.value = true;
};
// 编辑运输
const handleEdit = (transport: Transport) => {
isEditing.value = true;
// 填充表单数据
Object.assign(editForm, transport);
editDialogVisible.value = true;
};
// 保存运输记录
const handleSave = async () => {
if (!editFormRef.value) return;
await editFormRef.value.validate(async (valid) => {
if (valid) {
try {
let response;
if (isEditing.value && currentTransport.value) {
// 更新运输记录
response = await updateTransport(currentTransport.value.id, editForm);
} else {
// 创建运输记录
response = await createTransport(editForm);
}
if (response.success) {
ElMessage.success(isEditing.value ? '运输记录更新成功' : '运输记录创建成功');
editDialogVisible.value = false;
fetchTransportList();
} else {
ElMessage.error(response.message || (isEditing.value ? '运输记录更新失败' : '运输记录创建失败'));
}
} catch (error) {
ElMessage.error(isEditing.value ? '运输记录更新失败' : '运输记录创建失败');
}
}
});
};
// 删除运输记录
const handleDelete = (transport: Transport) => {
ElMessageBox.confirm(
`确定要删除运输记录 ${transport.id} 吗?`,
'确认删除',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(async () => {
try {
const response = await deleteTransport(transport.id);
if (response.success) {
ElMessage.success('运输记录删除成功');
fetchTransportList();
} else {
ElMessage.error(response.message || '运输记录删除失败');
}
} catch (error) {
ElMessage.error('运输记录删除失败');
}
}).catch(() => {
// 用户取消删除
});
};
// 分页相关操作
const handleSizeChange = (val: number) => {
pagination.pageSize = val;
fetchTransportList();
};
const handleCurrentChange = (val: number) => {
pagination.page = val;
fetchTransportList();
};
// 组件挂载时获取数据
onMounted(() => {
fetchTransportList();
});
</script>
<style lang="scss" scoped>
<style scoped>
.transport-management {
.page-header {
text-align: center;
margin-bottom: 30px;
h2 {
color: #333;
margin-bottom: 10px;
}
p {
color: #666;
}
}
padding: 20px;
}
.page-title {
text-align: center;
color: #333;
margin-bottom: 10px;
}
.page-description {
text-align: center;
color: #666;
margin-bottom: 30px;
}
.toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
flex-wrap: wrap;
gap: 10px;
}
.search-form {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.actions {
display: flex;
gap: 10px;
}
.el-pagination {
margin-top: 20px;
display: flex;
justify-content: center;
}
</style>