<template>
|
<div class="app-container">
|
<div
|
class="search_form"
|
style="
|
display: flex;
|
justify-content: space-between;
|
gap: 12px;
|
align-items: flex-start;
|
"
|
>
|
<div
|
style="
|
display: flex;
|
align-items: center;
|
flex-wrap: wrap;
|
gap: 10px;
|
"
|
>
|
<span class="search_title">关键字查询:</span>
|
<el-input
|
v-model="searchForm.keyword"
|
style="width: 240px"
|
placeholder="订单号/承运商/发货地/收货地"
|
clearable
|
:prefix-icon="Search"
|
@keyup.enter="handleQuery"
|
/>
|
|
<span class="search_title">状态:</span>
|
<el-select
|
v-model="searchForm.orderStatus"
|
style="width: 160px"
|
clearable
|
placeholder="全部"
|
>
|
<el-option label="待发货" :value="1" />
|
<el-option label="已发货" :value="2" />
|
</el-select>
|
|
<el-button type="primary" @click="handleQuery">搜索</el-button>
|
<el-button @click="resetQuery">重置</el-button>
|
</div>
|
|
<div>
|
<el-button type="primary" @click="openCreate">创建订单</el-button>
|
</div>
|
</div>
|
|
<el-row :gutter="20">
|
<!-- 左侧:订单列表 -->
|
<el-col :span="24">
|
<div class="table_list">
|
<el-table
|
border
|
v-loading="tableLoading"
|
:data="tableData"
|
:header-cell-style="{ background: '#F0F1F5', color: '#333333' }"
|
height="calc(100vh - 18.5em)"
|
:highlight-current-row="true"
|
style="width: 100%"
|
stripe
|
tooltip-effect="dark"
|
class="lims-table"
|
>
|
<el-table-column align="center" label="序号" type="index" width="60" />
|
<el-table-column
|
label="承运订单号"
|
prop="orderCode"
|
width="160"
|
show-overflow-tooltip
|
/>
|
<el-table-column
|
label="承运商"
|
prop="carrierName"
|
width="180"
|
show-overflow-tooltip
|
/>
|
<el-table-column
|
label="发货地"
|
prop="origin"
|
width="160"
|
show-overflow-tooltip
|
/>
|
<el-table-column
|
label="收货地"
|
prop="destination"
|
width="160"
|
show-overflow-tooltip
|
/>
|
<el-table-column
|
label="重量(kg)"
|
prop="weight"
|
width="110"
|
align="right"
|
/>
|
<el-table-column
|
label="体积(m³)"
|
prop="volume"
|
width="110"
|
align="right"
|
/>
|
<el-table-column
|
label="预计费用(元)"
|
prop="estimatedFee"
|
width="140"
|
align="right"
|
>
|
<template #default="{ row }">{{ toMoney(row.estimatedFee) }}</template>
|
</el-table-column>
|
<el-table-column label="状态" prop="orderStatus" width="110">
|
<template #default="{ row }">
|
<el-tag :type="statusTagType(row.orderStatus)">
|
{{ statusText(row.orderStatus) }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="更新时间" prop="updateTime" width="170" />
|
|
<el-table-column fixed="right" label="操作" width="260" align="center">
|
<template #default="scope">
|
<el-button
|
link
|
type="success"
|
size="small"
|
:disabled="scope.row.orderStatus !== 1"
|
@click.stop="openDelivery(scope.row)"
|
>发货</el-button
|
>
|
<el-button
|
link
|
type="primary"
|
size="small"
|
@click.stop="openView(scope.row)"
|
>查看</el-button
|
>
|
<el-button
|
link
|
type="primary"
|
size="small"
|
@click.stop="openEdit(scope.row)"
|
>编辑</el-button
|
>
|
<el-button
|
link
|
type="danger"
|
size="small"
|
@click.stop="handleDelete(scope.row)"
|
>删除</el-button
|
>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<pagination
|
v-show="total > 0"
|
@pagination="paginationSearch"
|
:total="total"
|
:layout="page.layout"
|
:page="page.current"
|
:limit="page.size"
|
/>
|
</div>
|
</el-col>
|
</el-row>
|
|
<!-- 创建/编辑弹窗 -->
|
<el-dialog
|
v-model="editVisible"
|
:title="editMode === 'create' ? '创建承运订单' : '编辑承运订单'"
|
width="720px"
|
:close-on-click-modal="false"
|
destroy-on-close
|
>
|
<el-form
|
ref="editFormRef"
|
:model="editForm"
|
:rules="rules"
|
label-width="120px"
|
>
|
<el-row :gutter="12">
|
<el-col :span="12">
|
<el-form-item label="承运订单号" prop="orderCode">
|
<el-input
|
v-model="editForm.orderCode"
|
placeholder="如 TO-20260130-0001"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="承运商名称" prop="carrierName">
|
<el-input
|
v-model="editForm.carrierName"
|
placeholder="请输入承运商名称"
|
/>
|
</el-form-item>
|
</el-col>
|
|
<el-col :span="12">
|
<el-form-item label="发货地" prop="origin">
|
<el-input v-model="editForm.origin" placeholder="请输入发货地" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="收货地" prop="destination">
|
<el-input
|
v-model="editForm.destination"
|
placeholder="请输入收货地"
|
/>
|
</el-form-item>
|
</el-col>
|
|
<el-col :span="12">
|
<el-form-item label="重量(kg)" prop="weight">
|
<el-input-number
|
v-model="editForm.weight"
|
:min="0"
|
:precision="2"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="体积(m³)" prop="volume">
|
<el-input-number
|
v-model="editForm.volume"
|
:min="0"
|
:precision="3"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
</el-col>
|
|
<el-col :span="12">
|
<el-form-item label="预计费用(元)" prop="estimatedFee">
|
<el-input-number
|
v-model="editForm.estimatedFee"
|
:min="0"
|
:precision="2"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
</el-col>
|
|
<el-col :span="24">
|
<el-form-item label="备注" prop="remark">
|
<el-input
|
v-model="editForm.remark"
|
type="textarea"
|
:rows="2"
|
placeholder="可选"
|
/>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
|
<template #footer>
|
<el-button @click="editVisible = false">取消</el-button>
|
<el-button type="primary" :loading="saving" @click="submitEdit"
|
>确定</el-button
|
>
|
</template>
|
</el-dialog>
|
|
<!-- 查看弹窗 -->
|
<el-dialog v-model="viewVisible" title="订单信息查看" width="720px" destroy-on-close>
|
<el-descriptions :column="2" border>
|
<el-descriptions-item label="承运订单号">{{ viewRow.orderCode }}</el-descriptions-item>
|
<el-descriptions-item label="状态">{{ statusText(viewRow.orderStatus) }}</el-descriptions-item>
|
<el-descriptions-item label="承运商">{{ viewRow.carrierName }}</el-descriptions-item>
|
<el-descriptions-item label="发货地">{{ viewRow.origin }}</el-descriptions-item>
|
<el-descriptions-item label="收货地">{{ viewRow.destination }}</el-descriptions-item>
|
<el-descriptions-item label="重量(kg)">{{ viewRow.weight }}</el-descriptions-item>
|
<el-descriptions-item label="体积(m³)">{{ viewRow.volume }}</el-descriptions-item>
|
<el-descriptions-item label="预计费用(元)">{{ toMoney(viewRow.estimatedFee) }}</el-descriptions-item>
|
<el-descriptions-item label="创建时间">{{ viewRow.createTime }}</el-descriptions-item>
|
<el-descriptions-item label="更新时间">{{ viewRow.updateTime }}</el-descriptions-item>
|
<el-descriptions-item label="备注" :span="2">{{ viewRow.remark || "-" }}</el-descriptions-item>
|
</el-descriptions>
|
<template #footer>
|
<el-button @click="viewVisible = false">关闭</el-button>
|
</template>
|
</el-dialog>
|
|
<!-- 发货弹窗(暂用假提交,等后端接口) -->
|
<el-dialog
|
v-model="deliveryVisible"
|
title="发货"
|
width="720px"
|
:close-on-click-modal="false"
|
destroy-on-close
|
>
|
<el-form ref="deliveryFormRef" :model="deliveryForm" :rules="deliveryRules" label-width="120px">
|
<el-row :gutter="12">
|
<el-col :span="24">
|
<el-alert
|
type="info"
|
:closable="false"
|
:title="`订单号:${deliveryForm.orderCode || '-'}(承运商:${deliveryForm.carrierName || '-'})`"
|
style="margin-bottom: 12px"
|
/>
|
</el-col>
|
|
<el-col :span="12">
|
<el-form-item label="发货时间" prop="shipTime">
|
<el-date-picker
|
v-model="deliveryForm.shipTime"
|
type="datetime"
|
value-format="YYYY-MM-DD HH:mm:ss"
|
format="YYYY-MM-DD HH:mm:ss"
|
placeholder="请选择"
|
style="width: 100%"
|
/>
|
</el-form-item>
|
</el-col>
|
|
<el-col :span="12">
|
<el-form-item label="车牌号" prop="vehicleNo">
|
<el-input v-model="deliveryForm.vehicleNo" placeholder="如 沪A12345" />
|
</el-form-item>
|
</el-col>
|
|
<el-col :span="12">
|
<el-form-item label="司机姓名" prop="driverName">
|
<el-input v-model="deliveryForm.driverName" placeholder="请输入" />
|
</el-form-item>
|
</el-col>
|
|
<el-col :span="12">
|
<el-form-item label="司机电话" prop="driverPhone">
|
<el-input v-model="deliveryForm.driverPhone" placeholder="请输入" />
|
</el-form-item>
|
</el-col>
|
|
<el-col :span="24">
|
<el-form-item label="备注" prop="remark">
|
<el-input v-model="deliveryForm.remark" type="textarea" :rows="2" placeholder="可选" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</el-form>
|
|
<template #footer>
|
<el-button @click="deliveryVisible = false">取消</el-button>
|
<el-button type="primary" :loading="deliverySubmitting" @click="submitDelivery">确定发货</el-button>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, reactive, onMounted } from "vue";
|
import { Search } from "@element-plus/icons-vue";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
import pagination from "@/components/PIMTable/Pagination.vue";
|
import dayjs from "dayjs";
|
import {
|
getCarrierOrderPage,
|
getCarrierOrderDetail,
|
addCarrierOrder,
|
updateCarrierOrder,
|
deleteCarrierOrder, addDeliveryTrack,
|
} from "@/api/inventoryManagement/CarrierManagement";
|
|
const toMoney = (v) => {
|
if (v === undefined || v === null || v === "") return "0.00";
|
const n = Number(v);
|
return Number.isFinite(n) ? n.toFixed(2) : "0.00";
|
};
|
|
const statusText = (s) => {
|
const map = {
|
0: "草稿",
|
1: "待发货",
|
2: "已发货",
|
};
|
return map[s] ?? "-";
|
};
|
|
const statusTagType = (s) => {
|
const map = {
|
0: "info",
|
1: "success",
|
2: "warning",
|
3: "success",
|
4: "danger",
|
};
|
return map[s] ?? "info";
|
};
|
|
// 适配后端返回字段(你后端字段未最终确定时先做兜底映射)
|
const normalizeRow = (raw = {}) => {
|
return {
|
orderId: raw.id ?? raw.orderId,
|
orderCode: raw.orderCode ?? raw.code,
|
carrierId: raw.carrierId,
|
carrierName: raw.carrierName,
|
origin: raw.origin ?? raw.startAddress ?? raw.fromAddress,
|
destination: raw.destination ?? raw.endAddress ?? raw.toAddress,
|
weight: raw.weight ?? 0,
|
volume: raw.volume ?? 0,
|
estimatedFee: raw.estimatedFee ?? raw.fee ?? 0,
|
orderStatus: raw.orderStatus ?? raw.status ?? 0,
|
remark: raw.remark ?? "",
|
createTime: raw.createTime,
|
updateTime: raw.updateTime,
|
};
|
};
|
|
// ------------------ 页面状态 ------------------
|
const searchForm = reactive({
|
keyword: "",
|
orderStatus: "",
|
});
|
|
const page = reactive({
|
current: 1,
|
size: 10,
|
layout: "total, sizes, prev, pager, next, jumper",
|
});
|
|
const total = ref(0);
|
const tableData = ref([]);
|
const tableLoading = ref(false);
|
|
const buildListParams = () => {
|
return {
|
current: page.current,
|
size: page.size,
|
keyword: searchForm.keyword || undefined,
|
orderCode: searchForm.keyword || undefined,
|
carrierName: searchForm.keyword || undefined,
|
origin: searchForm.keyword || undefined,
|
destination: searchForm.keyword || undefined,
|
orderStatus:
|
searchForm.orderStatus === "" || searchForm.orderStatus === null || searchForm.orderStatus === undefined
|
? undefined
|
: searchForm.orderStatus,
|
};
|
};
|
|
const getList = async () => {
|
tableLoading.value = true;
|
try {
|
const res = await getCarrierOrderPage(buildListParams());
|
const data = res?.data ?? res;
|
const records = data?.records ?? data?.rows ?? data?.list ?? [];
|
const t = data?.total ?? data?.count ?? 0;
|
|
tableData.value = (records || []).map(normalizeRow);
|
total.value = t;
|
} catch (e) {
|
ElMessage.error(e?.message || e?.msg || "加载失败");
|
} finally {
|
tableLoading.value = false;
|
}
|
};
|
|
const handleQuery = () => {
|
page.current = 1;
|
getList();
|
};
|
|
const resetQuery = () => {
|
searchForm.keyword = "";
|
searchForm.orderStatus = "";
|
page.current = 1;
|
getList();
|
};
|
|
const paginationSearch = (obj) => {
|
page.current = obj.page;
|
page.size = obj.limit;
|
getList();
|
};
|
|
// ------------------ 创建/编辑/查看/删除 ------------------
|
const editVisible = ref(false);
|
const viewVisible = ref(false);
|
const editMode = ref("create");
|
const saving = ref(false);
|
const editFormRef = ref();
|
|
const editForm = reactive({
|
orderId: undefined,
|
orderCode: "",
|
carrierId: undefined,
|
carrierName: "",
|
origin: "",
|
destination: "",
|
weight: 0,
|
volume: 0,
|
estimatedFee: 0,
|
orderStatus: 0,
|
remark: "",
|
});
|
|
const rules = {
|
orderCode: [{ required: true, message: "请输入承运订单号", trigger: "blur" }],
|
carrierName: [{ required: true, message: "请输入承运商名称", trigger: "blur" }],
|
origin: [{ required: true, message: "请输入发货地", trigger: "blur" }],
|
destination: [{ required: true, message: "请输入收货地", trigger: "blur" }],
|
};
|
|
const openCreate = () => {
|
editMode.value = "create";
|
Object.assign(editForm, {
|
orderId: undefined,
|
orderCode: `TO-${dayjs().format("YYYYMMDD")}-${String(Math.floor(Math.random() * 9000 + 1000))}`,
|
carrierId: undefined,
|
carrierName: "",
|
origin: "",
|
destination: "",
|
weight: 0,
|
volume: 0,
|
estimatedFee: 0,
|
orderStatus: 0,
|
remark: "",
|
});
|
editVisible.value = true;
|
queueMicrotask(() => editFormRef.value?.clearValidate?.());
|
};
|
|
const openEdit = async (row) => {
|
editMode.value = "edit";
|
Object.assign(editForm, { ...row });
|
|
// 拉详情补全
|
if (row?.id) {
|
try {
|
const res = await getCarrierOrderDetail(row.id);
|
const detail = res?.data ?? res;
|
Object.assign(editForm, normalizeRow(detail));
|
} catch {
|
// ignore
|
}
|
}
|
|
editVisible.value = true;
|
queueMicrotask(() => editFormRef.value?.clearValidate?.());
|
};
|
|
const viewRow = reactive({});
|
const openView = async (row) => {
|
Object.assign(viewRow, row);
|
viewVisible.value = true;
|
|
if (row?.id) {
|
try {
|
const res = await getCarrierOrderDetail(row.id);
|
const detail = res?.data ?? res;
|
Object.assign(viewRow, normalizeRow(detail));
|
} catch {
|
// ignore
|
}
|
}
|
};
|
|
const submitEdit = async () => {
|
saving.value = true;
|
try {
|
await editFormRef.value?.validate?.();
|
|
const payload = {
|
id: editForm.id,
|
orderCode: editForm.orderCode,
|
carrierId: editForm.carrierId,
|
carrierName: editForm.carrierName,
|
origin: editForm.origin,
|
destination: editForm.destination,
|
weight: editForm.weight,
|
volume: editForm.volume,
|
estimatedFee: editForm.estimatedFee,
|
orderStatus: editForm.orderStatus,
|
remark: editForm.remark,
|
};
|
|
if (editMode.value === "create") {
|
await addCarrierOrder(payload);
|
ElMessage.success("创建成功");
|
page.current = 1;
|
} else {
|
await updateCarrierOrder(payload);
|
ElMessage.success("更新成功");
|
}
|
|
editVisible.value = false;
|
await getList();
|
} catch (e) {
|
if (e?.message) ElMessage.error(e.message);
|
} finally {
|
saving.value = false;
|
}
|
};
|
|
const handleDelete = async (row) => {
|
await ElMessageBox.confirm(`确认删除订单【${row.orderCode}】?`, "提示", {
|
confirmButtonText: "删除",
|
cancelButtonText: "取消",
|
type: "warning",
|
});
|
|
tableLoading.value = true;
|
try {
|
await deleteCarrierOrder(row.id);
|
ElMessage.success("删除成功");
|
|
// 删除后如果当前页无数据则回退
|
const res = await getCarrierOrderPage(buildListParams());
|
const data = res?.data ?? res;
|
const records = data?.records ?? data?.rows ?? data?.list ?? [];
|
if ((records || []).length === 0 && page.current > 1) {
|
page.current -= 1;
|
}
|
|
await getList();
|
} catch (e) {
|
ElMessage.error(e?.message || e?.msg || "删除失败");
|
} finally {
|
tableLoading.value = false;
|
}
|
};
|
|
// ------------------ 发货(暂用假提交,等后端接口) ------------------
|
const deliveryVisible = ref(false);
|
const deliverySubmitting = ref(false);
|
const deliveryFormRef = ref();
|
const deliveryForm = reactive({
|
orderId: undefined,
|
orderCode: "",
|
carrierName: "",
|
shipTime: "",
|
vehicleNo: "",
|
driverName: "",
|
driverPhone: "",
|
remark: "",
|
});
|
|
const deliveryRules = {
|
shipTime: [{ required: true, message: "请选择发货时间", trigger: "change" }],
|
vehicleNo: [{ required: true, message: "请输入车牌号", trigger: "blur" }],
|
};
|
|
const openDelivery = (row) => {
|
console.log(row)
|
Object.assign(deliveryForm, {
|
orderId: row.id || row.orderId,
|
orderCode: row.orderCode,
|
carrierName: row.carrierName,
|
shipTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
vehicleNo: "",
|
driverName: "",
|
driverPhone: "",
|
remark: "",
|
});
|
|
deliveryVisible.value = true;
|
queueMicrotask(() => deliveryFormRef.value?.clearValidate?.());
|
};
|
|
const submitDelivery = async () => {
|
deliverySubmitting.value = true;
|
try {
|
await deliveryFormRef.value?.validate?.();
|
console.log(deliveryForm)
|
let res = await addDeliveryTrack(deliveryForm)
|
if(res?.data){
|
ElMessage.success("提交成功");
|
}
|
|
deliveryVisible.value = false;
|
await getList();
|
} catch (e) {
|
ElMessage.error(e?.message || e?.msg || "提交失败");
|
} finally {
|
deliverySubmitting.value = false;
|
}
|
};
|
|
onMounted(() => {
|
getList();
|
});
|
</script>
|