微搭低代码MBA 培训管理系统实战 36——发票申请
目录
前情回顾与本节目标
在上一节中,我们完成了学习卡功能,实现了课时余额展示和签到扣课时。至此,学员端的核心功能已经基本完善。
本节我们将目光转向财务管理模块,实现发票申请功能。在MBA培训业务中,企业客户完成订单支付后,通常需要开具增值税发票用于财务报销。传统模式下,销售需要线下沟通、手动填写开票信息,财务再手工录入开票系统,流程繁琐且容易出错。
本节我们将打通销售前端与财务后端,实现从"销售发起开票申请 → 财务审核开票"的完整闭环。
本节核心目标:
- 数据模型设计:创建发票表,扩展客户开票信息字段
- 销售端开票申请:销售选择客户后自动填充企业开票信息,提交开票申请
- 财务端开票审核:财务查看待开票列表,审核通过后更新发票状态
第一步:数据模型准备
1.1 发票表(MBA_Invoices)
创建发票表,用于记录开票申请和发票信息:
| 字段名称 | 字段标识 | 字段类型 | 说明 |
|---|---|---|---|
| 发票ID | _id | 文本 | 主键,系统自动生成 |
| 发票号 | invoice_no | 文本 | 发票编号,如 INV20250001 |
| 关联订单 | rel_order_id | 关联关系 | 关联 MBA_Orders 表 |
| 关联客户 | rel_customer_id | 关联关系 | 关联 MBA_Customer 表 |
| 开票金额 | amount | 数字 | 开票金额 |
| 发票类型 | invoice_type | 枚举 | 1-增值税专用发票、2-增值税普通发票、3-电子发票 |
| 开票内容 | invoice_content | 枚举 | 1-教育服务费、2-培训费、3-咨询服务费、4-其他 |
| 企业全称 | company_name | 文本 | 发票抬头 |
| 纳税人识别号 | tax_number | 文本 | 税号 |
| 企业地址 | company_address | 文本 | 企业注册地址 |
| 企业电话 | company_phone | 文本 | 企业联系电话 |
| 开户银行 | bank_name | 文本 | 开户银行名称 |
| 银行账号 | bank_account | 文本 | 银行账号 |
| 接收邮箱 | 文本 | 电子发票接收邮箱 | |
| 开票状态 | status | 枚举 | 1-待开票、2-已开票、3-已驳回 |
| 申请人 | rel_applicant_id | 关联关系 | 关联 MBA_Users 表(销售) |
| 审核人 | rel_reviewer_id | 关联关系 | 关联 MBA_Users 表(财务) |
| 审核意见 | review_remark | 文本 | 财务审核意见 |
| 申请时间 | apply_time | 日期时间 | 申请时间 |
| 开票时间 | issue_time | 日期时间 | 实际开票时间 |
| 创建时间 | created_at | 日期时间 | 自动生成 |
| 更新时间 | updated_at | 日期时间 | 自动更新 |
1.2 客户表扩展字段(MBA_Customer)
在客户表中增加开票相关字段,方便销售发起开票时自动填充:
| 字段名称 | 字段标识 | 字段类型 | 说明 |
|---|---|---|---|
| 企业全称 | company_name | 文本 | 发票抬头 |
| 纳税人识别号 | tax_number | 文本 | 税号 |
| 企业地址 | company_address | 文本 | 企业注册地址 |
| 企业电话 | company_phone | 文本 | 企业联系电话 |
| 开户银行 | bank_name | 文本 | 开户银行名称 |
| 银行账号 | bank_account | 文本 | 银行账号 |
| 开票邮箱 | invoice_email | 文本 | 电子发票接收邮箱 |
第二步:销售端发起开票申请
2.1 创建开票管理页面
点击创建页面图标,输入"开票管理",选择销售布局
切换到布局管理,选择销售布局,添加平级菜单,添加"开票管理"菜单
2.2 页面整体布局
切换回页面设计,在销售布局的内容插槽下添加布局组件,修改标题为"开票管理"
添加数据表格组件,数据模型选择发票表(MBA_Invoices),勾选场景
2.3 配置查询条件
点击筛选器,给表格配置查询条件:
- 发票号(模糊搜索)
- 客户名称(关联选择)
- 开票状态(下拉选择:待开票/已开票/已驳回)
- 发票类型(下拉选择)

2.4 配置操作列
在数据表格的操作列配置功能按钮,配置条件展示,只有开票状态是待开票才可以编辑和删除申请信息
2.5 配置表单布局
因为发票需要填写比较多的内容,我们把表单的布局改为三列显示
修改了布局会清空表单容器的默认事件,我们将表单容器的表单场景恢复默认配置
然后配置表单提交成功之后的事件,增加关闭弹窗和刷新表格
2.6 客户选择与信息自动填充
创建自定义方法 onCustomerChange,当用户选择客户后自动将相关的信息带入到对应的字段中:
export default async function onCustomerChange({ event, data }) {
const customerId = data.target;
if (!customerId) return;
try {
// 查询客户的开票信息
const customerRes = await $w.cloud.callDataSource({
dataSourceName: 'MBA_Customers',
methodName: 'wedaGetItemV2',
params: {
filter: { where: { _id: { $eq: customerId } } },
select: { $master: true }
}
});
const customer = customerRes;
// 自动填充开票信息
$w.form2.setValue({
company_name: customer.company_name || '',
tax_number: customer.tax_number || '',
company_address: customer.company_address || '',
company_phone: customer.company_phone || '',
bank_name: customer.bank_name || '',
bank_account: customer.bank_account || '',
email: customer.invoice_email || ''
});
$w.utils.showToast({ title: '企业信息已自动填充', icon: 'success' });
} catch (error) {
console.error('获取客户信息失败:', error);
}
}
给客户选择组件配置值改变事件,调用 onCustomerChange 方法,传入入参。

2.7 配置默认值
除了自动带出相关信息,比如发票状态我们需要设置成待开票
申请人绑定为当前登录对象的用户标识
申请时间设置为系统当前时间
第三步:财务端开票审核
3.1 创建财务审核页面
点击创建页面图标,输入"开票审核",选择财务布局
切换到布局管理,选择财务布局,添加平级菜单,添加"开票审核"菜单
3.2 页面整体布局
切换回页面设计,在财务布局的内容插槽下添加布局组件,修改标题为"开票审核"
添加顶部选项卡,标签改为"待审核"、“已审核”
添加数据表格组件,数据模型选择发票表(MBA_Invoices)
3.3 配置数据筛选
在"待审核"选项卡下,设置数据筛选条件为:开票状态 = 待开票(1)
在"已审核"选项卡下,设置数据筛选条件为:开票状态 ≠ 待开票(1)
3.4 配置操作列
在数据表格的操作列配置功能按钮:
| 按钮名称 | 功能说明 | 显示条件 |
|---|---|---|
| 查看详情 | 查看发票详细信息 | 全部显示 |
| 审核通过 | 确认开票,更新状态为已开票 | 状态 = 待开票 |
| 驳回 | 驳回开票申请 | 状态 = 待开票 |

3.5 审核通过功能
创建自定义方法 approveInvoice:
export default async function approveInvoice({ event, data }) {
const invoiceId = data.target._id;
const currentUser = $w.app.dataset.state.currentUser;
try {
$w.utils.showLoading({ title: '审核中...' });
await $w.cloud.callDataSource({
dataSourceName: 'MBA_Invoices',
methodName: 'wedaUpdateV2',
params: {
filter: { where: { _id: { $eq: invoiceId } } },
data: {
status: '2',
rel_reviewer_id: { _id: currentUser._id },
issue_time: Date.now(),
updated_at: Date.now()
}
}
});
$w.utils.hideLoading();
$w.utils.showToast({ title: '审核通过,已开票', icon: 'success' });
$w.table1.refresh();
} catch (error) {
console.error('审核失败:', error);
$w.utils.hideLoading();
$w.utils.showToast({ title: '审核失败,请重试', icon: 'error' });
}
}
给审核通过按钮配置点击事件,调用方法,传入所在行的数据标识
3.6 驳回功能
在页面组件下添加弹窗组件,修改标题为"驳回开票申请"
在弹窗内容区域添加单行输入组件,用于填写驳回原因。
创建自定义方法 rejectInvoice:
export default async function rejectInvoice({ event, data }) {
const invoiceId = data.target;
const currentUser = $w.app.dataset.state.currentUser;
const rejectReason = $w.input1.value;
if (!rejectReason) {
return $w.utils.showToast({ title: '请填写驳回原因', icon: 'error' });
}
try {
$w.utils.showLoading({ title: '处理中...' });
await $w.cloud.callDataSource({
dataSourceName: 'MBA_Invoices',
methodName: 'wedaUpdateV2',
params: {
filter: { where: { _id: { $eq: invoiceId } } },
data: {
status: '3',
rel_reviewer_id: { _id: currentUser._id },
review_remark: rejectReason,
}
}
});
$w.utils.hideLoading();
$w.utils.showToast({ title: '已驳回', icon: 'success' });
$w.modal1.close({});
$w.table1.refresh();
} catch (error) {
console.error('驳回失败:', error);
$w.utils.hideLoading();
$w.utils.showToast({ title: '操作失败,请重试', icon: 'error' });
}
}
给驳回按钮配置点击事件,打开弹窗,传入所在行的数据标识
给弹窗的确认按钮配置点击事件,调用我们的自定义方法,传入弹窗的入参
最终效果
销售端在开票管理页面,点击"新增"按钮,选择客户后系统自动填充企业开票信息,填写开票金额和发票类型后提交申请。
财务端在开票审核页面,查看待审核的开票申请,可以查看详情、审核通过或驳回。审核通过后发票状态更新为"已开票",驳回时需填写驳回原因。
总结
本节完成了智能开票功能的实现:
- 数据模型设计:创建发票表(MBA_Invoices),扩展客户表开票信息字段
- 销售端开票申请:选择客户自动填充企业信息,提交开票申请
- 财务端开票审核:财务查看待审核列表,审核通过或驳回
通过本节的学习,我们打通了销售前端与财务后端的开票流程,实现了从申请到审核的完整闭环。下一节我们将继续完善财务管理模块的其他功能。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)