From e2c871b1be0ff8cfa61e55325095ee1c79932ddd Mon Sep 17 00:00:00 2001
From: 张诺 <zhang_12370@163.com>
Date: 星期五, 30 一月 2026 17:01:19 +0800
Subject: [PATCH] tms 开发承运商运费结算模块
---
src/views/inventoryManagement/procurementManagement/DeliveryTrackingManagement/index.vue | 372 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 372 insertions(+), 0 deletions(-)
diff --git a/src/views/inventoryManagement/procurementManagement/DeliveryTrackingManagement/index.vue b/src/views/inventoryManagement/procurementManagement/DeliveryTrackingManagement/index.vue
new file mode 100644
index 0000000..31e6b0a
--- /dev/null
+++ b/src/views/inventoryManagement/procurementManagement/DeliveryTrackingManagement/index.vue
@@ -0,0 +1,372 @@
+<template>
+ <div class="app-container">
+ <el-form :model="searchForm" :inline="true">
+ <el-form-item label="鍏抽敭瀛�">
+ <el-input
+ v-model="searchForm.keyword"
+ style="width: 240px"
+ placeholder="璁㈠崟鍙�/鎵胯繍鍟�/杞︾墝"
+ clearable
+ :prefix-icon="Search"
+ @keyup.enter="handleQuery"
+ />
+ </el-form-item>
+ <el-form-item label="鍙戣揣鏃ユ湡">
+ <el-date-picker
+ v-model="searchForm.shipDateRange"
+ value-format="YYYY-MM-DD"
+ format="YYYY-MM-DD"
+ type="daterange"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ clearable
+ @change="changeDateRange"
+ @clear="clearRange"
+ />
+ </el-form-item>
+
+ <el-form-item>
+ <el-button type="primary" @click="handleQuery" style="margin-left: 10px">
+ 鎼滅储
+ </el-button>
+ <el-button @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+
+ <div class="table_list">
+ <PIMTable
+ rowKey="id"
+ :column="tableColumn"
+ :tableData="tableData"
+ :page="page"
+ :isSelection="false"
+ :tableLoading="tableLoading"
+ @pagination="pagination"
+ :total="page.total"
+ >
+ <template #statusSlot="{ row }">
+ <el-tag :type="trackStatusTagType(row.trackStatus)">
+ {{ trackStatusText(row.trackStatus) }}
+ </el-tag>
+ </template>
+ </PIMTable>
+ </div>
+
+ <!-- 杞ㄨ抗鏌ョ湅寮圭獥 -->
+ <el-dialog
+ v-model="trackVisible"
+ title="鍦ㄩ�旇建杩规煡璇�"
+ width="760px"
+ :close-on-click-modal="false"
+ destroy-on-close
+ >
+ <div style="margin-bottom: 10px; color: #606266">
+ <div>璁㈠崟鍙凤細{{ currentRow.orderCode }}</div>
+ <div>鎵胯繍鍟嗭細{{ currentRow.carrierName }}銆�杞︾墝锛歿{ currentRow.vehicleNo }}</div>
+ <div>鍙戣揣鏃堕棿锛歿{ currentRow.shipTime || "-" }}</div>
+ </div>
+
+ <el-empty v-if="trackLoading" description="鍔犺浇杞ㄨ抗涓�..." />
+ <el-empty v-else-if="trackList.length === 0" description="鏆傛棤杞ㄨ抗" />
+
+ <el-timeline v-else>
+ <el-timeline-item
+ v-for="item in trackList"
+ :key="item.id"
+ :timestamp="item.time"
+ :type="item.type"
+ :hollow="false"
+ >
+ <div style="font-weight: 600">{{ item.title }}</div>
+ <div style="color: #909399">{{ item.remark }}</div>
+ </el-timeline-item>
+ </el-timeline>
+
+ <template #footer>
+ <el-button @click="trackVisible = false">鍏抽棴</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 PIMTable from "@/components/PIMTable/PIMTable.vue";
+import {
+ getDeliveryTrackPage,
+ getDeliveryTrackDetail,
+ deleteDeliveryTrack,
+} from "@/api/inventoryManagement/CarrierManagement";
+
+// ------------------ 杞ㄨ抗锛堟殏鏃跺亣鏁版嵁锛氱瓑鍚庣杞ㄨ抗鎺ュ彛瀛楁纭畾鍚庢浛鎹級 ------------------
+const pad2 = (n) => String(n).padStart(2, "0");
+const formatDateTime = (d = new Date()) => {
+ const yyyy = d.getFullYear();
+ const mm = pad2(d.getMonth() + 1);
+ const dd = pad2(d.getDate());
+ const hh = pad2(d.getHours());
+ const mi = pad2(d.getMinutes());
+ const ss = pad2(d.getSeconds());
+ return `${yyyy}-${mm}-${dd} ${hh}:${mi}:${ss}`;
+};
+
+const trackStatusText = (s) => {
+ const map = { 0: "寰呭彂杞�", 1: "杩愯緭涓�", 2: "宸插埌杈�", 3: "寮傚父" };
+ return map[s] ?? "-";
+};
+
+const trackStatusTagType = (s) => {
+ const map = { 0: "info", 1: "warning", 2: "success", 3: "danger" };
+ return map[s] ?? "info";
+};
+
+const buildMockTrack = (row) => {
+ const now = Date.now();
+ const isArrived = Number(row.trackStatus) === 2;
+ const isAbnormal = Number(row.trackStatus) === 3;
+
+ const base = [
+ {
+ id: 1,
+ time: formatDateTime(new Date(now - 1000 * 60 * 60 * 18)),
+ title: "宸插垱寤哄彂璐у崟",
+ location: row.origin || "-",
+ remark: "宸插畬鎴愯杞�",
+ type: "primary",
+ },
+ {
+ id: 2,
+ time: formatDateTime(new Date(now - 1000 * 60 * 60 * 12)),
+ title: "杞﹁締宸插彂杞�",
+ location: row.origin || "-",
+ remark: "浠庝粨搴撳嚭鍙�",
+ type: "success",
+ },
+ {
+ id: 3,
+ time: formatDateTime(new Date(now - 1000 * 60 * 60 * 6)),
+ title: isAbnormal ? "杩愯緭寮傚父" : "閫旂粡鑺傜偣",
+ location: "涓浆绔�",
+ remark: isAbnormal ? "杞﹁締鏁呴殰锛岀瓑寰呭鐞�" : "姝e父",
+ type: isAbnormal ? "danger" : "warning",
+ },
+ ];
+
+ if (isArrived) {
+ base.push({
+ id: 4,
+ time: formatDateTime(new Date(now - 1000 * 60 * 60)),
+ title: "宸插埌杈�",
+ location: row.destination || "-",
+ remark: "宸茬鏀�",
+ type: "success",
+ });
+ }
+
+ return base;
+};
+
+// ------------------ 鍒楄〃鏌ヨ锛堟潵鑷悗绔� /fakeWarehousing/deliveryTrack/list锛� ------------------
+// 鍚庣鏍蜂緥瀛楁锛�
+// id, orderId, orderCode, carrierName, shipTime, vehicleNo, driverName, driverPhone, remark,
+// createTime, updateTime, createUser, updateUser, tenantId
+const normalizeRow = (raw = {}) => {
+ const id = raw.id ?? raw.trackId ?? raw.deliveryTrackId;
+
+ return {
+ id,
+ orderId: raw.orderId ?? null,
+ orderCode: raw.orderCode ?? raw.orderNo ?? "-",
+ carrierName: raw.carrierName ?? raw.carrier ?? "-",
+ shipTime: raw.shipTime ?? raw.shipDate ?? "-",
+ vehicleNo: raw.vehicleNo ?? raw.carNo ?? "-",
+ driverName: raw.driverName ?? raw.driver ?? "-",
+ driverPhone: raw.driverPhone ?? raw.driverTel ?? "-",
+ remark: raw.remark ?? "",
+ createTime: raw.createTime ?? "-",
+ updateTime: raw.updateTime ?? raw.modifyTime ?? "-",
+ };
+};
+
+const tableData = ref([]);
+const tableLoading = ref(false);
+
+const page = reactive({
+ current: 1,
+ size: 10,
+ total: 0,
+ layout: "total, sizes, prev, pager, next, jumper",
+});
+
+const searchForm = reactive({
+ keyword: "",
+ trackStatus: "",
+ shipDateRange: [],
+ shipDateStart: undefined,
+ shipDateEnd: undefined,
+});
+
+const tableColumn = ref([
+ { label: "璁㈠崟鍙�", prop: "orderCode", width: 180 },
+ { label: "鎵胯繍鍟�", prop: "carrierName", width: 180 },
+ { label: "杞︾墝鍙�", prop: "vehicleNo", width: 130 },
+ { label: "鍙戣揣鏃堕棿", prop: "shipTime", width: 170 },
+ { label: "鍙告満", prop: "driverName", width: 120 },
+ { label: "鍙告満鐢佃瘽", prop: "driverPhone", width: 140 },
+ { label: "鏇存柊鏃堕棿", prop: "updateTime", width: 170 },
+ {
+ label: "鎿嶄綔",
+ prop: "action",
+ dataType: "action",
+ fixed: "right",
+ width: 120,
+ operation: [
+ { name: "鏌ョ湅杞ㄨ抗", clickFun: (row) => openTrack(row) },
+ { name: "鍒犻櫎", clickFun: (row) => handleDelete(row) },
+ ],
+ },
+]);
+
+const buildListParams = () => {
+ return {
+ current: page.current,
+ size: page.size,
+ keyword: searchForm.keyword || undefined,
+ orderCode: searchForm.keyword || undefined,
+ carrierName: searchForm.keyword || undefined,
+ vehicleNo: searchForm.keyword || undefined,
+ trackStatus:
+ searchForm.trackStatus === "" || searchForm.trackStatus === null || searchForm.trackStatus === undefined
+ ? undefined
+ : searchForm.trackStatus,
+ startDate: searchForm.shipDateStart || undefined,
+ endDate: searchForm.shipDateEnd || undefined,
+ };
+};
+
+const getList = async () => {
+ tableLoading.value = true;
+ try {
+ const res = await getDeliveryTrackPage(buildListParams());
+ const data = res?.data ?? res;
+ const records = data?.records ?? data?.rows ?? data?.list ?? [];
+ const total = data?.total ?? data?.count ?? 0;
+
+ tableData.value = (records || []).map(normalizeRow);
+ page.total = total;
+ } catch (e) {
+ ElMessage.error(e?.message || e?.msg || "鍔犺浇澶辫触");
+ } finally {
+ tableLoading.value = false;
+ }
+};
+
+const handleQuery = () => {
+ page.current = 1;
+ getList();
+};
+
+const resetQuery = () => {
+ searchForm.keyword = "";
+ searchForm.trackStatus = "";
+ searchForm.shipDateRange = [];
+ searchForm.shipDateStart = undefined;
+ searchForm.shipDateEnd = undefined;
+ page.current = 1;
+ getList();
+};
+
+const pagination = (obj) => {
+ page.current = obj.page;
+ page.size = obj.limit;
+ getList();
+};
+
+const changeDateRange = (date) => {
+ if (date && date.length === 2) {
+ searchForm.shipDateStart = date[0];
+ searchForm.shipDateEnd = date[1];
+ } else {
+ searchForm.shipDateStart = undefined;
+ searchForm.shipDateEnd = undefined;
+ }
+ getList();
+};
+
+const clearRange = () => {
+ searchForm.shipDateRange = [];
+ searchForm.shipDateStart = undefined;
+ searchForm.shipDateEnd = undefined;
+ getList();
+};
+
+// ------------------ 杞ㄨ抗寮圭獥锛堣鎯呰皟鐢ㄥ悗绔� /fakeWarehousing/deliveryTrack/{id} 锛� ------------------
+const trackVisible = ref(false);
+const trackLoading = ref(false);
+const trackList = ref([]);
+const currentRow = reactive({});
+
+const openTrack = async (row) => {
+ Object.assign(currentRow, row);
+ trackVisible.value = true;
+ trackLoading.value = true;
+
+ try {
+ const res = await getDeliveryTrackDetail(row.id);
+ const detail = res?.data ?? res;
+ Object.assign(currentRow, normalizeRow(detail));
+
+ // 杞ㄨ抗鏄庣粏瀛楁灏氭湭纭畾锛氭殏鐢ㄦā鎷熻建杩瑰睍绀�
+ trackList.value = buildMockTrack(currentRow);
+ } catch (e) {
+ ElMessage.error(e?.message || e?.msg || "杞ㄨ抗鍔犺浇澶辫触");
+ trackList.value = buildMockTrack(currentRow);
+ } finally {
+ trackLoading.value = false;
+ }
+};
+
+// 鍒犻櫎锛堟壒閲� ids 鍚庣涔熸敮鎸侊細杩欓噷鍗曟潯鍒犻櫎锛�
+const handleDelete = async (row) => {
+ await ElMessageBox.confirm(`纭鍒犻櫎鍙戣揣璁板綍銆�${row.orderCode || "-"}銆戯紵`, "鎻愮ず", {
+ confirmButtonText: "鍒犻櫎",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ });
+
+ tableLoading.value = true;
+ try {
+ await deleteDeliveryTrack(row.id);
+ ElMessage.success("鍒犻櫎鎴愬姛");
+
+ // 鍒犻櫎鍚庡鏋滃綋鍓嶉〉涓虹┖鍒欏洖閫�
+ const res = await getDeliveryTrackPage(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;
+ }
+};
+
+// 棰勭暀锛氭柊澧�/淇敼鎺ュ彛宸叉帴鍏ワ紙鍚庣画鍔犲脊绐楀嵆鍙級
+// addDeliveryTrack / updateDeliveryTrack
+
+onMounted(() => {
+ getList();
+});
+</script>
+
+<style scoped lang="scss">
+.table_list {
+ margin-top: unset;
+}
+</style>
--
Gitblit v1.9.3