# 报价单管理模块 - API接口文档 > **模块**: 06-报价单管理 > **版本**: v1.0 > **日期**: 2025-10-03 > **关联文档**: > - 需求文档: `docs/06-报价单管理模块需求.md` > - 原型图: `yuanxing/06-报价单管理原型图.md` > - 数据库: `sql/crm/06-crm_quote.sql` --- ## 📋 目录 - [1. 报价单管理接口](#1-报价单管理接口) - [2. 报价单产品接口](#2-报价单产品接口) - [3. 报价单审批接口](#3-报价单审批接口) - [4. 版本管理接口](#4-版本管理接口) - [5. 统计分析接口](#5-统计分析接口) - [6. 数据模型](#6-数据模型) --- ## 1. 报价单管理接口 ### 1.1 查询报价单列表(分页) **接口地址**: `GET /crm/quote/list` **接口描述**: 分页查询报价单列表,支持多条件筛选 **权限标识**: `crm:quote:list` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | pageNum | Integer | 否 | 页码,默认1 | | pageSize | Integer | 否 | 每页条数,默认10 | | quoteNo | String | 否 | 报价单编号(模糊查询) | | quoteTitle | String | 否 | 报价单标题(模糊查询) | | customerId | Long | 否 | 客户ID | | customerName | String | 否 | 客户名称(模糊查询) | | opportunityId | Long | 否 | 商机ID | | status | String | 否 | 状态 | | ownerUserId | Long | 否 | 负责人ID | | minAmount | BigDecimal | 否 | 最小金额 | | maxAmount | BigDecimal | 否 | 最大金额 | | isLatest | Integer | 否 | 是否最新版本(0否 1是) | | quoteDateBegin | String | 否 | 报价日期开始 | | quoteDateEnd | String | 否 | 报价日期结束 | | beginTime | String | 否 | 创建开始时间 | | endTime | String | 否 | 创建结束时间 | **返回示例**: ```json { "code": 200, "msg": "查询成功", "rows": [ { "id": 1, "quoteNo": "QUO20250101001", "quoteTitle": "华为CRM系统采购报价", "customerId": 1, "customerName": "华为技术有限公司", "opportunityId": 1, "contactId": 1, "contactName": "张伟", "contactMobile": "13800138000", "contactEmail": "zhangwei@huawei.com", "version": "V1.0", "parentId": 0, "isLatest": 1, "totalAmount": 150000.00, "discountRate": 10.00, "discountAmount": 15000.00, "finalAmount": 135000.00, "validityDays": 30, "quoteDate": "2025-01-10", "expireDate": "2025-02-09", "status": "submitted", "pdfUrl": "/upload/quote/QUO20250101001.pdf", "pdfGenerated": 1, "shareLink": "https://crm.com/share/abc123", "shareCode": "abc123", "viewCount": 5, "lastViewTime": "2025-01-12 10:30:00", "ownerUserId": 1, "ownerUserName": "张三", "contractId": null, "paymentTerms": "合同签订后7个工作日内支付30%预付款", "deliveryTerms": "付款到账后15个工作日内完成部署", "createTime": "2025-01-10 09:00:00", "remark": "" } ], "total": 56 } ``` --- ### 1.2 查询报价单详情 **接口地址**: `GET /crm/quote/{id}` **接口描述**: 根据ID查询报价单详细信息 **权限标识**: `crm:quote:query` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | Long | 是 | 报价单ID | **返回示例**: 同1.1列表返回的单条数据,包含完整字段 --- ### 1.3 新增报价单 **接口地址**: `POST /crm/quote` **接口描述**: 新增报价单信息 **权限标识**: `crm:quote:add` **请求体**: ```json { "quoteNo": "QUO20250110001", "quoteTitle": "华为CRM系统采购报价", "customerId": 1, "opportunityId": 1, "contactId": 1, "version": "V1.0", "validityDays": 30, "quoteDate": "2025-01-10", "discountRate": 10.00, "ownerUserId": 1, "paymentTerms": "合同签订后7个工作日内支付30%预付款", "deliveryTerms": "付款到账后15个工作日内完成部署", "products": [ { "productId": 1, "quantity": 1, "price": 12800.00, "discount": 10.00 }, { "productId": 2, "quantity": 1, "price": 138000.00, "discount": 10.00 } ], "remark": "" } ``` **请求参数说明**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | quoteNo | String | 是 | 报价单编号,唯一,格式:QUO+yyyyMMdd+4位流水号 | | quoteTitle | String | 是 | 报价单标题,最大200字符 | | customerId | Long | 是 | 客户ID | | opportunityId | Long | 否 | 商机ID | | contactId | Long | 否 | 联系人ID | | version | String | 否 | 版本号,默认V1.0 | | validityDays | Integer | 否 | 有效期天数,默认30 | | quoteDate | String | 否 | 报价日期,默认当前日期 | | discountRate | BigDecimal | 否 | 整单折扣率(百分比) | | ownerUserId | Long | 否 | 负责人ID,默认当前用户 | | paymentTerms | String | 否 | 付款条款,最大500字符 | | deliveryTerms | String | 否 | 交付条款,最大500字符 | | products | Array | 是 | 产品列表,至少1个 | | remark | String | 否 | 备注,最大500字符 | **校验规则**: - 报价单编号必须唯一 - 客户ID必须存在 - 产品列表不能为空 - 有效期天数必须大于0 **业务规则**: - 自动计算到期日期:quoteDate + validityDays - 自动计算总金额和最终金额 - 默认状态为draft(草稿) **返回示例**: ```json { "code": 200, "msg": "操作成功", "data": { "id": 1, "quoteNo": "QUO20250110001" } } ``` --- ### 1.4 修改报价单 **接口地址**: `PUT /crm/quote` **接口描述**: 修改报价单信息 **权限标识**: `crm:quote:edit` **请求体**: 同新增接口,但需要传入id **业务规则**: - 只有草稿状态的报价单才能修改 - 修改后需要重新生成PDF **返回示例**: ```json { "code": 200, "msg": "操作成功" } ``` --- ### 1.5 删除报价单 **接口地址**: `DELETE /crm/quote/{ids}` **接口描述**: 删除报价单(支持批量) **权限标识**: `crm:quote:remove` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | ids | Long[] | 是 | 报价单ID数组 | **业务规则**: - 只能删除草稿状态的报价单 - 已转合同的报价单不允许删除 - 删除报价单时同时删除关联的产品和审批记录 **返回示例**: ```json { "code": 200, "msg": "操作成功" } ``` --- ### 1.6 提交报价单 **接口地址**: `PUT /crm/quote/submit` **接口描述**: 提交报价单进行审批 **权限标识**: `crm:quote:submit` **请求体**: ```json { "id": 1, "approverIds": [5, 6], "remark": "提交审批" } ``` **请求参数说明**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | Long | 是 | 报价单ID | | approverIds | Long[] | 是 | 审批人ID列表 | | remark | String | 否 | 提交说明 | **业务规则**: - 只有草稿状态的报价单才能提交 - 自动生成PDF - 创建审批记录 - 状态变更为submitted **返回示例**: ```json { "code": 200, "msg": "操作成功" } ``` --- ### 1.7 生成PDF **接口地址**: `POST /crm/quote/generatePdf` **接口描述**: 生成报价单PDF文件 **权限标识**: `crm:quote:edit` **请求体**: ```json { "id": 1 } ``` **业务规则**: - 自动生成PDF并保存到文件系统 - 更新pdfUrl和pdfGenerated字段 **返回示例**: ```json { "code": 200, "msg": "操作成功", "data": { "pdfUrl": "/upload/quote/QUO20250110001.pdf" } } ``` --- ### 1.8 生成分享链接 **接口地址**: `POST /crm/quote/generateShare` **接口描述**: 生成报价单分享链接 **权限标识**: `crm:quote:share` **请求体**: ```json { "id": 1, "validityDays": 7 } ``` **请求参数说明**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | Long | 是 | 报价单ID | | validityDays | Integer | 否 | 链接有效期天数,默认7天 | **业务规则**: - 生成唯一的分享码 - 生成分享链接 - 记录分享信息 **返回示例**: ```json { "code": 200, "msg": "操作成功", "data": { "shareLink": "https://crm.com/share/abc123", "shareCode": "abc123", "expireDate": "2025-01-17" } } ``` --- ### 1.9 查看分享报价单 **接口地址**: `GET /crm/quote/share/{shareCode}` **接口描述**: 通过分享码查看报价单(无需登录) **权限标识**: 无(公开接口) **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | shareCode | String | 是 | 分享码 | **业务规则**: - 验证分享码是否有效 - 验证是否过期 - 增加查看次数 - 记录最后查看时间 **返回示例**: ```json { "code": 200, "msg": "查询成功", "data": { "quoteNo": "QUO20250110001", "quoteTitle": "华为CRM系统采购报价", "customerName": "华为技术有限公司", "contactName": "张伟", "finalAmount": 135000.00, "quoteDate": "2025-01-10", "expireDate": "2025-02-09", "pdfUrl": "/upload/quote/QUO20250110001.pdf", "products": [], "paymentTerms": "合同签订后7个工作日内支付30%预付款", "deliveryTerms": "付款到账后15个工作日内完成部署" } } ``` --- ### 1.10 接受报价单 **接口地址**: `PUT /crm/quote/accept` **接口描述**: 客户接受报价单 **权限标识**: `crm:quote:edit` **请求体**: ```json { "id": 1, "remark": "客户已接受" } ``` **业务规则**: - 状态变更为accepted - 可选择是否自动创建合同 **返回示例**: ```json { "code": 200, "msg": "操作成功" } ``` --- ### 1.11 拒绝报价单 **接口地址**: `PUT /crm/quote/reject` **接口描述**: 客户拒绝报价单 **权限标识**: `crm:quote:edit` **请求体**: ```json { "id": 1, "rejectReason": "价格不合适", "remark": "" } ``` **请求参数说明**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | Long | 是 | 报价单ID | | rejectReason | String | 是 | 拒绝原因,最大500字符 | | remark | String | 否 | 备注 | **业务规则**: - 状态变更为rejected - 记录拒绝原因 **返回示例**: ```json { "code": 200, "msg": "操作成功" } ``` --- ### 1.12 转为合同 **接口地址**: `POST /crm/quote/toContract` **接口描述**: 将报价单转为合同 **权限标识**: `crm:quote:toContract` **请求体**: ```json { "id": 1, "contractNo": "CON20250110001", "contractTitle": "华为CRM系统采购合同", "signDate": "2025-01-15", "effectiveDate": "2025-01-15", "expiryDate": "2026-01-14", "remark": "" } ``` **请求参数说明**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | Long | 是 | 报价单ID | | contractNo | String | 是 | 合同编号 | | contractTitle | String | 是 | 合同标题 | | signDate | String | 是 | 签订日期 | | effectiveDate | String | 是 | 生效日期 | | expiryDate | String | 是 | 到期日期 | | remark | String | 否 | 备注 | **业务规则**: - 只有已接受的报价单才能转为合同 - 自动创建合同及合同产品 - 报价单状态变更为contract - 关联合同ID **返回示例**: ```json { "code": 200, "msg": "操作成功", "data": { "contractId": 1, "contractNo": "CON20250110001" } } ``` --- ### 1.13 导出报价单 **接口地址**: `POST /crm/quote/export` **接口描述**: 导出报价单数据到Excel **权限标识**: `crm:quote:export` **请求体**: 查询参数同1.1列表查询接口 **返回**: Excel文件流 --- ## 2. 报价单产品接口 ### 2.1 查询报价单产品列表 **接口地址**: `GET /crm/quote/product/list` **接口描述**: 查询指定报价单的产品列表 **权限标识**: `crm:quote:query` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | quoteId | Long | 是 | 报价单ID | **返回示例**: ```json { "code": 200, "msg": "查询成功", "data": [ { "id": 1, "quoteId": 1, "productId": 1, "productName": "CRM系统标准版", "productNo": "PRD20250101001", "categoryId": 11, "categoryName": "CRM系统", "model": "V5.4.0", "unit": "套", "quantity": 1, "price": 12800.00, "discount": 10.00, "subtotal": 11520.00, "description": "包含客户管理、销售管理等基础功能", "sort": 1, "remark": "" } ] } ``` --- ### 2.2 添加报价单产品 **接口地址**: `POST /crm/quote/product` **接口描述**: 向报价单添加产品 **权限标识**: `crm:quote:edit` **请求体**: ```json { "quoteId": 1, "productId": 1, "quantity": 1, "price": 12800.00, "discount": 10.00, "description": "包含客户管理、销售管理等基础功能", "remark": "" } ``` **请求参数说明**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | quoteId | Long | 是 | 报价单ID | | productId | Long | 是 | 产品ID | | quantity | Integer | 是 | 数量,必须大于0 | | price | BigDecimal | 是 | 单价,保留2位小数 | | discount | BigDecimal | 否 | 折扣百分比,默认0 | | description | String | 否 | 产品描述,最大1000字符 | | remark | String | 否 | 备注 | **业务规则**: - 只能给草稿状态的报价单添加产品 - 自动计算小计金额:quantity * price * (1 - discount/100) - 添加产品后自动更新报价单总金额 **返回示例**: ```json { "code": 200, "msg": "操作成功" } ``` --- ### 2.3 修改报价单产品 **接口地址**: `PUT /crm/quote/product` **接口描述**: 修改报价单产品信息 **权限标识**: `crm:quote:edit` **请求体**: 同添加接口,但需要传入id **业务规则**: - 只能修改草稿状态报价单的产品 **返回示例**: ```json { "code": 200, "msg": "操作成功" } ``` --- ### 2.4 删除报价单产品 **接口地址**: `DELETE /crm/quote/product/{ids}` **接口描述**: 删除报价单产品(支持批量) **权限标识**: `crm:quote:edit` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | ids | Long[] | 是 | 报价单产品ID数组 | **业务规则**: - 只能删除草稿状态报价单的产品 - 删除后自动更新报价单总金额 - 报价单至少保留1个产品 **返回示例**: ```json { "code": 200, "msg": "操作成功" } ``` --- ## 3. 报价单审批接口 ### 3.1 查询审批记录列表 **接口地址**: `GET /crm/quote/approval/list` **接口描述**: 查询指定报价单的审批记录列表 **权限标识**: `crm:quote:query` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | quoteId | Long | 是 | 报价单ID | **返回示例**: ```json { "code": 200, "msg": "查询成功", "data": [ { "id": 1, "quoteId": 1, "quoteNo": "QUO20250110001", "step": 1, "approverId": 5, "approverName": "王经理", "approvalResult": "approved", "approvalOpinion": "同意", "approvalTime": "2025-01-11 10:00:00", "createTime": "2025-01-10 16:00:00", "remark": "" } ] } ``` --- ### 3.2 审批报价单 **接口地址**: `POST /crm/quote/approval` **接口描述**: 审批人审批报价单 **权限标识**: `crm:quote:approval` **请求体**: ```json { "id": 1, "approvalResult": "approved", "approvalOpinion": "同意通过", "remark": "" } ``` **请求参数说明**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | Long | 是 | 审批记录ID | | approvalResult | String | 是 | 审批结果:approved/rejected | | approvalOpinion | String | 否 | 审批意见,文本类型 | | remark | String | 否 | 备注 | **业务规则**: - 只有审批人本人才能审批 - 必须按步骤顺序审批 - 如果拒绝,报价单状态变为rejected,流程结束 - 如果所有步骤都通过,报价单状态变为accepted **返回示例**: ```json { "code": 200, "msg": "操作成功" } ``` --- ### 3.3 撤回审批 **接口地址**: `PUT /crm/quote/approval/withdraw` **接口描述**: 撤回已提交的审批 **权限标识**: `crm:quote:edit` **请求体**: ```json { "id": 1, "remark": "需要修改报价" } ``` **请求参数说明**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | Long | 是 | 报价单ID | | remark | String | 否 | 撤回原因 | **业务规则**: - 只有创建人才能撤回 - 只能撤回已提交未审批的报价单 - 撤回后状态变为draft - 删除所有pending状态的审批记录 **返回示例**: ```json { "code": 200, "msg": "操作成功" } ``` --- ## 4. 版本管理接口 ### 4.1 查询报价单版本历史 **接口地址**: `GET /crm/quote/versions` **接口描述**: 查询报价单的所有版本 **权限标识**: `crm:quote:query` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | quoteNo | String | 是 | 报价单编号(首版) | **返回示例**: ```json { "code": 200, "msg": "查询成功", "data": [ { "id": 1, "quoteNo": "QUO20250110001", "version": "V1.0", "finalAmount": 135000.00, "status": "rejected", "isLatest": 0, "createTime": "2025-01-10 09:00:00" }, { "id": 2, "quoteNo": "QUO20250110001", "version": "V1.1", "finalAmount": 128000.00, "status": "accepted", "isLatest": 1, "createTime": "2025-01-12 14:00:00" } ] } ``` --- ### 4.2 创建新版本 **接口地址**: `POST /crm/quote/newVersion` **接口描述**: 基于现有报价单创建新版本 **权限标识**: `crm:quote:add` **请求体**: ```json { "id": 1, "version": "V1.1", "remark": "根据客户反馈调整价格" } ``` **请求参数说明**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | id | Long | 是 | 原报价单ID | | version | String | 是 | 新版本号,如V1.1, V2.0 | | remark | String | 否 | 版本说明 | **业务规则**: - 复制原报价单信息创建新版本 - 新版本状态为draft - 原版本isLatest设为0 - 新版本isLatest设为1 - 新版本的parentId指向原版本 **返回示例**: ```json { "code": 200, "msg": "操作成功", "data": { "id": 2, "quoteNo": "QUO20250110001", "version": "V1.1" } } ``` --- ## 5. 统计分析接口 ### 5.1 报价单统计概览 **接口地址**: `GET /crm/quote/statistics/overview` **接口描述**: 获取报价单统计概览数据 **权限标识**: `crm:quote:list` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | ownerUserId | Long | 否 | 负责人ID,不传则查询当前用户 | | beginTime | String | 否 | 开始时间 | | endTime | String | 否 | 结束时间 | **返回示例**: ```json { "code": 200, "msg": "查询成功", "data": { "totalCount": 56, "draftCount": 8, "submittedCount": 12, "acceptedCount": 28, "rejectedCount": 5, "expiredCount": 3, "totalAmount": 4580000.00, "acceptedAmount": 2850000.00, "acceptRate": 73.68, "avgAmount": 81785.71 } } ``` --- ### 5.2 报价单状态分布 **接口地址**: `GET /crm/quote/statistics/status` **接口描述**: 按状态统计报价单分布情况 **权限标识**: `crm:quote:list` **请求参数**: 无 **返回示例**: ```json { "code": 200, "msg": "查询成功", "data": [ { "status": "draft", "statusName": "草稿", "count": 8, "amount": 420000.00, "percent": 14.29 }, { "status": "accepted", "statusName": "已接受", "count": 28, "amount": 2850000.00, "percent": 50.00 } ] } ``` --- ### 5.3 报价单趋势分析 **接口地址**: `GET /crm/quote/statistics/trend` **接口描述**: 分析报价单数量和金额趋势 **权限标识**: `crm:quote:list` **请求参数**: | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | type | String | 否 | 统计类型:month/quarter/year,默认month | | beginTime | String | 否 | 开始时间 | | endTime | String | 否 | 结束时间 | **返回示例**: ```json { "code": 200, "msg": "查询成功", "data": [ { "period": "2025-01", "totalCount": 18, "acceptedCount": 12, "totalAmount": 1250000.00, "acceptedAmount": 850000.00, "acceptRate": 66.67 } ] } ``` --- ## 6. 数据模型 ### 6.1 QuoteBo(报价单业务对象) ```java public class CrmQuoteBo extends BaseEntity { /** 主键ID */ @NotNull(message = "主键不能为空", groups = { EditGroup.class }) private Long id; /** 报价单编号 */ @NotBlank(message = "报价单编号不能为空", groups = { AddGroup.class, EditGroup.class }) private String quoteNo; /** 报价单标题 */ @NotBlank(message = "报价单标题不能为空", groups = { AddGroup.class, EditGroup.class }) private String quoteTitle; /** 客户ID */ @NotNull(message = "客户ID不能为空", groups = { AddGroup.class, EditGroup.class }) private Long customerId; /** 商机ID */ private Long opportunityId; /** 联系人ID */ private Long contactId; /** 版本号 */ private String version; /** 父版本ID */ private Long parentId; /** 整单折扣率 */ private BigDecimal discountRate; /** 有效期天数 */ @Min(value = 1, message = "有效期天数必须大于0") private Integer validityDays; /** 报价日期 */ private String quoteDate; /** 负责人ID */ private Long ownerUserId; /** 付款条款 */ private String paymentTerms; /** 交付条款 */ private String deliveryTerms; /** 产品列表 */ @NotEmpty(message = "产品列表不能为空", groups = { AddGroup.class }) private List products; /** 备注 */ private String remark; } ``` --- ### 6.2 QuoteVo(报价单视图对象) ```java public class CrmQuoteVo implements Serializable { /** 主键ID */ @ExcelProperty(value = "ID") private Long id; /** 报价单编号 */ @ExcelProperty(value = "报价单编号") private String quoteNo; /** 报价单标题 */ @ExcelProperty(value = "报价单标题") private String quoteTitle; /** 客户ID */ private Long customerId; /** 客户名称 */ @ExcelProperty(value = "客户名称") private String customerName; /** 商机ID */ private Long opportunityId; /** 联系人ID */ private Long contactId; /** 联系人姓名 */ @ExcelProperty(value = "联系人") private String contactName; /** 联系人手机 */ private String contactMobile; /** 联系人邮箱 */ private String contactEmail; /** 版本号 */ @ExcelProperty(value = "版本号") private String version; /** 父版本ID */ private Long parentId; /** 是否最新版本 */ private Integer isLatest; /** 总金额 */ @ExcelProperty(value = "总金额") private BigDecimal totalAmount; /** 折扣率 */ @ExcelProperty(value = "折扣率") private BigDecimal discountRate; /** 折扣金额 */ @ExcelProperty(value = "折扣金额") private BigDecimal discountAmount; /** 最终金额 */ @ExcelProperty(value = "最终金额") private BigDecimal finalAmount; /** 有效期天数 */ @ExcelProperty(value = "有效期(天)") private Integer validityDays; /** 报价日期 */ @ExcelProperty(value = "报价日期") private String quoteDate; /** 到期日期 */ @ExcelProperty(value = "到期日期") private String expireDate; /** 状态 */ @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) @ExcelDictFormat(dictType = "crm_quote_status") private String status; /** 拒绝原因 */ private String rejectReason; /** PDF文件路径 */ private String pdfUrl; /** PDF是否已生成 */ private Integer pdfGenerated; /** 分享链接 */ private String shareLink; /** 分享码 */ private String shareCode; /** 查看次数 */ @ExcelProperty(value = "查看次数") private Integer viewCount; /** 最后查看时间 */ private LocalDateTime lastViewTime; /** 负责人ID */ private Long ownerUserId; /** 负责人姓名 */ @ExcelProperty(value = "负责人") private String ownerUserName; /** 关联合同ID */ private Long contractId; /** 付款条款 */ private String paymentTerms; /** 交付条款 */ private String deliveryTerms; /** 创建时间 */ @ExcelProperty(value = "创建时间") private LocalDateTime createTime; /** 备注 */ @ExcelProperty(value = "备注") private String remark; } ``` --- ## 7. 数据字典 ### 7.1 报价单状态 (crm_quote_status) | 字典值 | 字典标签 | 说明 | |--------|---------|------| | draft | 草稿 | 编辑中 | | submitted | 已提交 | 已提交审批 | | accepted | 已接受 | 客户已接受 | | rejected | 已拒绝 | 客户已拒绝 | | expired | 已过期 | 超过有效期 | | contract | 已转合同 | 已生成合同 | --- ## 8. 权限标识汇总 | 权限标识 | 说明 | |---------|------| | crm:quote:list | 报价单列表查询 | | crm:quote:query | 报价单详情查询 | | crm:quote:add | 报价单新增 | | crm:quote:edit | 报价单修改 | | crm:quote:remove | 报价单删除 | | crm:quote:export | 报价单导出 | | crm:quote:submit | 报价单提交审批 | | crm:quote:approval | 报价单审批 | | crm:quote:share | 生成分享链接 | | crm:quote:toContract | 转为合同 | --- ## 9. 注意事项 1. **报价单编号唯一性**: 同一租户下报价单编号必须唯一 2. **版本管理**: 同一报价单可以有多个版本,只有最新版本的isLatest为1 3. **状态流转**: 草稿->已提交->已接受/已拒绝->已转合同 4. **金额自动计算**: 添加/修改产品时自动计算总金额和最终金额 5. **PDF生成**: 提交审批时自动生成PDF 6. **分享链接**: 分享链接有有效期,过期后不能访问 7. **审批流程**: 支持多级审批,必须按步骤顺序审批 8. **到期管理**: 定时任务自动检查过期的报价单,状态变更为expired 9. **数据权限**: 需要根据负责人字段实现数据权限控制 10. **产品最少限制**: 报价单至少包含1个产品 --- **文档结束**