<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.settleNo"
|
style="width: 240px"
|
placeholder="结算单号"
|
clearable
|
:prefix-icon="Search"
|
@keyup.enter="handleQuery"
|
/>
|
<span class="search_title">承运商:</span>
|
<el-input
|
v-model="searchForm.carrierName"
|
style="width: 240px"
|
placeholder="承运商"
|
clearable
|
:prefix-icon="Search"
|
@keyup.enter="handleQuery"
|
/>
|
<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="settleNo" width="180" show-overflow-tooltip />
|
<el-table-column label="承运商" prop="carrierName" width="200" show-overflow-tooltip />
|
<el-table-column label="发票号码" prop="invoiceNo" width="160" show-overflow-tooltip />
|
<el-table-column label="发票金额(元)" prop="invoiceAmt" width="140" align="right">
|
<template #default="{ row }">{{ toMoney(row.invoiceAmt) }}</template>
|
</el-table-column>
|
<el-table-column label="开票日期" prop="invoiceDate" width="120" />
|
<el-table-column label="更新时间" prop="updateTime" width="170" />
|
|
<el-table-column fixed="right" label="操作" width="200" align="center">
|
<template #default="scope">
|
<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="settleNo">
|
<el-input v-model="editForm.settleNo" placeholder="如 FS-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="invoiceNo">
|
<el-input v-model="editForm.invoiceNo" placeholder="请输入发票号" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="发票金额(元)" prop="invoiceAmt">
|
<el-input-number v-model="editForm.invoiceAmt" :min="0" :precision="2" style="width: 100%" />
|
</el-form-item>
|
</el-col>
|
|
<el-col :span="12">
|
<el-form-item label="开票日期" prop="invoiceDate">
|
<el-date-picker
|
v-model="editForm.invoiceDate"
|
value-format="YYYY-MM-DD"
|
format="YYYY-MM-DD"
|
type="date"
|
placeholder="请选择"
|
clearable
|
style="width: 100%"
|
/>
|
</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.settleNo }}</el-descriptions-item>
|
<el-descriptions-item label="承运商">{{ viewRow.carrierName }}</el-descriptions-item>
|
<el-descriptions-item label="发票号码">{{ viewRow.invoiceNo }}</el-descriptions-item>
|
<el-descriptions-item label="发票金额(元)">{{ toMoney(viewRow.invoiceAmt) }}</el-descriptions-item>
|
<el-descriptions-item label="开票日期">{{ viewRow.invoiceDate }}</el-descriptions-item>
|
<el-descriptions-item label="创建时间">{{ viewRow.createTime }}</el-descriptions-item>
|
<el-descriptions-item label="更新时间">{{ viewRow.updateTime }}</el-descriptions-item>
|
</el-descriptions>
|
<template #footer>
|
<el-button @click="viewVisible = 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 pagination from "@/components/PIMTable/Pagination.vue";
|
import dayjs from "dayjs";
|
import {
|
getFreightSettlementPage,
|
getFreightSettlementDetail,
|
addFreightSettlement,
|
updateFreightSettlement,
|
deleteFreightSettlement,
|
} 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 normalizeRow = (raw = {}) => {
|
return {
|
id: raw.id,
|
settleNo: raw.settleNo,
|
carrierName: raw.carrierName,
|
invoiceNo: raw.invoiceNo,
|
invoiceAmt: raw.invoiceAmt,
|
invoiceDate: raw.invoiceDate,
|
createTime: raw.createTime,
|
updateTime: raw.updateTime,
|
};
|
};
|
|
// ------------------ 页面状态 ------------------
|
const searchForm = reactive({
|
keyword: "",
|
invoiceDateRange: [],
|
invoiceDateStart: undefined,
|
invoiceDateEnd: undefined,
|
});
|
|
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,
|
settleNo: searchForm.settleNo || undefined,
|
carrierName: searchForm.carrierName || undefined,
|
};
|
};
|
|
const changeDateRange = (date) => {
|
if (date && date.length === 2) {
|
searchForm.invoiceDateStart = date[0];
|
searchForm.invoiceDateEnd = date[1];
|
} else {
|
searchForm.invoiceDateStart = undefined;
|
searchForm.invoiceDateEnd = undefined;
|
}
|
getList();
|
};
|
|
const clearRange = () => {
|
searchForm.invoiceDateRange = [];
|
getList();
|
};
|
|
const handleQuery = () => {
|
page.current = 1;
|
getList();
|
};
|
|
const resetQuery = () => {
|
searchForm.keyword = "";
|
searchForm.invoiceDateRange = [];
|
searchForm.invoiceDateStart = undefined;
|
searchForm.invoiceDateEnd = undefined;
|
page.current = 1;
|
getList();
|
};
|
|
const paginationSearch = (obj) => {
|
page.current = obj.page;
|
page.size = obj.limit;
|
getList();
|
};
|
|
const getList = async () => {
|
tableLoading.value = true;
|
try {
|
const res = await getFreightSettlementPage(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 editVisible = ref(false);
|
const viewVisible = ref(false);
|
const editMode = ref("create");
|
const saving = ref(false);
|
const editFormRef = ref();
|
|
const editForm = reactive({
|
id: undefined,
|
settleNo: "",
|
carrierName: "",
|
invoiceNo: "",
|
invoiceAmt: 0,
|
invoiceDate: "",
|
});
|
|
const rules = {
|
settleNo: [{ required: true, message: "请输入结算单号", trigger: "blur" }],
|
carrierName: [{ required: true, message: "请输入承运商名称", trigger: "blur" }],
|
invoiceNo: [{ required: true, message: "请输入发票号码", trigger: "blur" }],
|
invoiceAmt: [{ required: true, message: "请输入发票金额", trigger: "change" },
|
{validator: (rule, value, callback) => {if (value <= 0) {callback(new Error("发票金额必须大于0"));} else {callback();}}, trigger: "change",}],
|
invoiceDate: [{ required: true, message: "请选择开票日期", trigger: "change" }],
|
};
|
|
const openCreate = () => {
|
editMode.value = "create";
|
Object.assign(editForm, {
|
id: undefined,
|
settleNo: `FS-${dayjs().format("YYYYMMDD")}-${String(Math.floor(Math.random() * 9000 + 1000))}`,
|
carrierName: "",
|
invoiceNo: "",
|
invoiceAmt: 0,
|
invoiceDate: dayjs().format("YYYY-MM-DD"),
|
});
|
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 getFreightSettlementDetail(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 getFreightSettlementDetail(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,
|
settleNo: editForm.settleNo,
|
carrierName: editForm.carrierName,
|
invoiceNo: editForm.invoiceNo,
|
invoiceAmt: editForm.invoiceAmt,
|
invoiceDate: editForm.invoiceDate,
|
};
|
|
if (editMode.value === "create") {
|
await addFreightSettlement(payload);
|
ElMessage.success("创建成功");
|
page.current = 1;
|
} else {
|
await updateFreightSettlement(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.settleNo}】?`, "提示", {
|
confirmButtonText: "删除",
|
cancelButtonText: "取消",
|
type: "warning",
|
});
|
|
tableLoading.value = true;
|
try {
|
await deleteFreightSettlement(row.id);
|
ElMessage.success("删除成功");
|
|
// 删除后如果当前页无数据则回退
|
const res = await getFreightSettlementPage(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;
|
}
|
};
|
|
onMounted(() => {
|
getList();
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.el-pagination {
|
width: 100%;
|
height: 55px;
|
display: flex;
|
justify-content: flex-end;
|
float: right;
|
flex-direction: row;
|
align-items: center;
|
background: #fff;
|
margin: -20px 0 0 0;
|
padding: 0 20px;
|
}
|
|
.pagination-container {
|
margin-top: 0;
|
}
|
</style>
|