在企业管理系统中,客户对账和单据选择是财务和业务管理的核心功能。本文分享一个基于 Vue3 和 Element Plus 的对账单管理组件,包含父组件(对账单表单 StatementForm.vue)和子组件(单据选择弹窗 DeliverySelect.vue),实现客户信息录入、单据选择和对账数据管理。代码清晰、模块化、易于复用,非常适合团队开发或社区分享。以下是完整的实现思路和代码。
功能亮点
- 客户选择:通过弹窗选择客户,自动填充客户名称和ID。
- 单据选择:支持按销售单号、出库单号、规格型号和出库时间搜索出库单据,支持分页和跨页多选。
- 动态对账:支持录入本次对账数量、其他费用,实时计算含税总额和对账总额。
- 只读模式:支持查看、编辑和新建模式,灵活适配不同场景。
- 用户友好:界面美观,操作流畅,支持表单验证和数据重置。
实现思路
- 父组件(StatementForm.vue):
- 使用 v-dialog 创建弹窗表单,集成 el-form 和 el-table。
- 通过 el-input-number 动态录入对账数量和其他费用,自动计算含税总额。
- 调用 statementService 接口获取对账单详情或保存数据。
- 通过 ref 调用子组件 DeliverySelect 实现单据选择。
- 子组件(DeliverySelect.vue):
- 使用 v-dialog 创建单据选择弹窗,集成 el-form 和 el-table。
- 支持按条件(销售单号、出库单号、规格型号、出库时间)搜索单据。
- 使用 vxe-pager 实现分页,跨页记忆选中的单据数据。
- 通过事件将选中的单据数据传递给父组件。
完整代码
父组件:StatementForm.vue
<template>
<v-dialog
:title="title"
:close-on-click-modal="false"
v-model="visible"
width="1200px"
>
<el-form
:model="inputForm"
ref="inputForm"
v-loading="loading"
:class="method === 'view' ? 'readonly' : ''"
:disabled="method === 'view'"
label-width="120px"
>
<el-row :gutter="15">
<el-col :span="12">
<el-form-item label="客户名称" prop="clientName" :rules="[]">
<el-input
v-model="inputForm.clientName"
placeholder="请选择客户名称"
:readonly="true"
>
<template #append>
<el-button @click="showSelectDialog" icon="Search" />
</template>
</el-input>
<ClientSelects
ref="clientSelectsInfo"
class="w100"
@selected="handleSelected"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-button
type="primary"
@click="toOpenProduct"
v-if="method !== 'view'"
class="mab20"
>选择单据</el-button
>
<el-table
:data="dataList"
v-loading="loading"
ref="gridTable"
height="420px"
>
<el-table-column
type="index"
label="序号"
width="80px"
align="center"
fixed="left"
/>
<el-table-column
prop="deliveryNo"
header-align="center"
align="center"
label="出库单号"
width="160"
fixed="left"
/>
<el-table-column
prop="productCode"
header-align="center"
align="center"
label="产品编码"
width="160"
fixed="left"
/>
<el-table-column
prop="productName"
header-align="center"
align="center"
label="产品名称"
fixed="left"
/>
<el-table-column
prop="specificationsName"
header-align="center"
align="center"
label="规格型号"
fixed="left"
/>
<el-table-column
prop="unitName"
header-align="center"
align="center"
label="单位"
/>
<el-table-column
prop="quantity"
header-align="center"
align="center"
label="入库数量"
/>
<el-table-column
prop="unreconciledQuantity"
header-align="center"
align="center"
label="未对账"
/>
<el-table-column
prop="reconciledQuantity"
header-align="center"
align="center"
label="本次对账"
width="200"
>
<template #default="{ row }">
<span v-if="method == 'view'">{
{
row.reconciledQuantity || 0
}}</span>
<el-input-number
v-else
:precision="2"
v-model.number="row.reconciledQuantity"
:step="0.01"
:min="0"
@change="handleTaxPrice(row)"
placeholder="0.00"
:value-on-clear="0"
/>
</template>
</el-table-column>
<el-table-column
prop="taxRate"
header-align="center"
align="center"
label="税率"