CRM 开票导入 - 前端联调方案
需求:开票管理列表增加「导入」按钮(位于「新增开票申请」与「导出」之间),用于按模板批量导入开票记录。
参考实现:合同列表的导入弹窗(views/crm/contract/modules/import-form.vue),开票导入与其交互一致。
涉及页面
- 修改:
views/crm/invoice/index.vue(开票列表工具栏)
- 新增:导入弹窗组件(建议
views/crm/invoice/modules/import-form.vue)
- 修改:
src/api/crm/invoice/index.ts(新增 2 个接口)
业务流程与数据带入
- 合同(已审核通过)-> 开票导入:模板中填写「合同编号」,后端按编号匹配合同,**客户自动取合同所属客户**,无需在模板中填写客户
- 导入成功 -> 开票列表:新增的开票为「未提交」状态,可在列表中继续编辑、上传发票附件、提交审批
- 导入的负责人 = 当前登录用户(同合同导入),导入后当前用户即可在「我负责的」下看到
API
| 方法 |
路径 |
说明 |
| GET |
/crm/invoice/get-import-template |
下载导入模板(返回 xls 文件流) |
| POST |
/crm/invoice/import |
导入开票(multipart 上传 Excel) |
权限码: 两个接口均要求 crm:invoice:import(菜单已新增:营销管理 -> 开票管理 -> 开票导入,并已授予开票管理现有角色)。
请求参数(POST /crm/invoice/import):
| 参数 |
类型 |
必填 |
说明 |
| file |
MultipartFile |
是 |
仅支持 xls、xlsx |
模板列(下载的模板已含表头与一行示例):
| 列名 |
必填 |
说明 |
| 开票编号 |
否 |
留空则系统自动生成(KP+日期+6位序号);填写时不可与系统中已有开票编号重复 |
| 合同编号 |
是 |
需与系统中**已审核通过**的合同编号一致,客户由合同自动带入 |
| 发票类型 |
是 |
填写字典 crm_invoice_type 的名称:增值税专用发票 / 增值税普通发票 / 电子发票 |
| 发票号码 |
否 |
发票票面号码 |
| 发票抬头 |
否 |
发票抬头 |
| 开票金额(元) |
是 |
需大于 0,且不超过该合同剩余可开票金额 |
| 开票日期 |
否 |
格式 2026-01-01 10:00:00 或 2026-01-01;留空取当前时间 |
| 备注 |
否 |
备注 |
响应:
{
"code": 0,
"data": {
"createList": ["KP20260924000001", "KP20260924000002"],
"failureList": {
"第 4 行": "合同编号不存在:HT9999。请先在「CRM 合同管理」中创建或导入该合同(编号需与模板完全一致),或修改模板中的合同编号后重新导入"
}
}
}
| 字段 |
类型 |
说明 |
| createList |
String[] |
导入成功的开票编号数组 |
| failureList |
Map |
导入失败集合:key 为「发票号码 xxx」或「第 N 行」(N 为 Excel 行号,含表头),value 为失败原因 |
字段展示规则
| 字段 |
展示位置 |
说明 |
| 导入按钮 |
开票列表工具栏 |
位置在「新增开票申请」与「导出」之间;权限码 crm:invoice:import |
| 下载导入模板按钮 |
导入弹窗左下角 |
同合同导入弹窗的 prepend-footer 位置 |
| 新增条数 |
导入弹窗结果区 |
取 createList.length,文案如「新增:N 条」 |
| 失败明细 |
导入弹窗结果区 |
遍历 failureList,逐条展示「key:value」,可滚动 |
| 导入模板说明 |
导入弹窗内灰色提示区 |
必填列:合同编号、发票类型、开票金额;合同必须为「审核通过」;负责人 = 当前登录用户;状态为「未提交」 |
业务规则说明
| 场景 |
规则 |
| 合同状态 |
只有「审核通过」的合同才能导入开票;未提交/审批中/不通过的合同该行导入失败 |
| 开票金额上限 |
单行金额不得超过「合同金额 − 已开票(审批中 + 审核通过)」的剩余额度,超出则该行失败 |
| 重复编号 |
模板中填写的开票编号在系统中已存在时该行失败 |
| 部分成功 |
逐行导入,失败行不影响成功行(同一文件内不会整体回滚) |
| 数据权限 |
导入的开票负责人 = 当前登录用户,自动创建数据权限,无需前端处理 |
| 与「新建开票申请」的差异 |
导入不产生附件;导入的开票默认「未提交」,需在列表中编辑上传发票附件后再提交审批 |
注意事项
- 模板「发票类型」填**名称**(如 增值税专用发票),也兼容填数字(1/2/3);填错时失败原因会列出可选项
- 导入弹窗的进度条/结果区交互可直接复用合同导入的实现(
import-form.vue)
- 前端按钮的
auth 需使用新的权限码 crm:invoice:import;该菜单权限已授予角色 2/155/160/161/162,其余自建角色需在「角色管理」中勾选「开票导入」后再使用
- 空行会被自动跳过,不算失败