# Web端商户快速提现申请接口文档 ## 模块概述 本模块提供商户快速提现功能,与普通提现(需审核)不同,此接口创建的提现记录直接标记为"已通过"状态(paymentStatus=3),无需人工审核,与app端 `applyCashOut` 接口保持一致。 --- ## 接口信息 ### 快速提现申请(免审核) #### 接口详情 - **接口名称**: 快速提现申请(免审核) - **接口路径**: `POST /incomeManage/applyFastCashOut` - **请求方式**: POST - **接口描述**: 为当前登录的商户提交快速提现申请,直接创建为"已通过"状态,无需审核流程 - **登录验证**: ✅ 需要(通过 JWT token 自动获取storeId) --- ## 与普通提现的区别 | 项目 | 普通提现 (/cashOut) | 快速提现 (/applyFastCashOut) | |------|-------------------|----------------------------| | 提现状态 | paymentStatus = 1(待审核) | paymentStatus = 3(已通过) | | 审核流程 | 需要人工审核 | 免审核,直接通过 | | 账户扣款 | 提交时扣款 | 提交时不扣款 | | 适用场景 | Web端常规提现 | 与app端保持一致的快速提现 | | 后续流程 | 需管理员审核后打款 | 可直接进入打款流程 | --- ## 请求参数 ### 请求体(Request Body) 使用 `CashOutDTO` 对象作为请求体(JSON格式): | 参数名 | 类型 | 必填 | 说明 | 示例值 | |--------|------|------|------|--------| | payPassword | String | 是 | 支付密码 | 123456 | | withdrawalMoney | Integer | 是 | 提现金额(单位:分) | 50000 | ### 参数说明 #### payPassword(支付密码) - **用途**: 验证用户身份 - **格式**: 用户设置的支付密码 - **验证**: 必须与数据库中的支付密码匹配 - **安全**: 建议前端加密后传输 #### withdrawalMoney(提现金额) - **单位**: 分(1元 = 100分) - **最小值**: 10分(0.1元) - **最大值**: 不能超过账户余额 - **示例**: - 提现100元 → `withdrawalMoney = 10000` - 提现50元 → `withdrawalMoney = 5000` - 提现0.1元 → `withdrawalMoney = 10` **注意**: `storeId` 从登录用户的 JWT Token 中自动获取,不需要在请求中传递。 --- ## 请求示例 ### 示例1: 提现500元 ```http POST /incomeManage/applyFastCashOut Content-Type: application/json Authorization: Bearer YOUR_JWT_TOKEN { "payPassword": "123456", "withdrawalMoney": 50000 } ``` ```bash curl -X POST "http://localhost:8080/incomeManage/applyFastCashOut" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "payPassword": "123456", "withdrawalMoney": 50000 }' ``` --- ### 示例2: 提现全部余额 假设账户余额为1000元(100000分): ```http POST /incomeManage/applyFastCashOut Content-Type: application/json Authorization: Bearer YOUR_JWT_TOKEN { "payPassword": "123456", "withdrawalMoney": 100000 } ``` --- ## 响应参数 ### 成功响应 ```json { "code": 200, "success": true, "data": { "id": 1001, "storeId": 103, "storeUserId": 114, "money": 50000, "commission": null, "cashOutType": 0, "paymentStatus": 3, "orderNo": null, "aliOrderNo": null, "paymentDate": null, "payDate": null, "failReason": null, "incomeStartTime": "2025-11-20 14:30:00", "incomeEndTime": "2025-11-20 14:30:00", "deleteFlag": 0, "createdTime": "2025-11-20 14:30:00", "updatedTime": "2025-11-20 14:30:00" }, "msg": "操作成功" } ``` ### 响应字段说明 #### 外层字段 | 字段名 | 类型 | 说明 | |--------|------|------| | code | Integer | 状态码(200-成功) | | success | Boolean | 是否成功 | | data | Object | 提现记录对象(StoreCashOutRecord) | | msg | String | 提示信息 | #### data 字段(StoreCashOutRecord) | 字段名 | 类型 | 说明 | |--------|------|------| | id | Long | 提现记录ID | | storeId | Integer | 门店ID | | storeUserId | Integer | 用户ID | | money | Integer | 提现金额(单位:分) | | commission | Integer | 手续费(单位:分,可为null) | | cashOutType | Integer | 提现类型(0-全部提现) | | paymentStatus | Integer | ⚠️ 提现状态(3-已通过) | | orderNo | String | 提现订单号(初始为null) | | aliOrderNo | String | 支付宝订单号(初始为null) | | paymentDate | Date | 申请时间(初始为null) | | payDate | Date | 打款时间(初始为null) | | failReason | String | 失败原因(初始为null) | | incomeStartTime | Date | 收入开始时间 | | incomeEndTime | Date | 收入结束时间 | | deleteFlag | Integer | 删除标识(0-未删除) | | createdTime | Date | 创建时间 | | updatedTime | Date | 更新时间 | **重要说明**: - 🔔 `paymentStatus = 3` 表示"已通过",区别于普通提现的"待审核" - 🔔 订单号、支付宝订单号等字段需要在打款时填充 --- ### 失败响应 #### 1. 支付密码错误 ```json { "code": 500, "success": false, "data": null, "msg": "支付密码错误" } ``` #### 2. 余额不足 ```json { "code": 500, "success": false, "data": null, "msg": "余额不足" } ``` #### 3. 提现金额过小 ```json { "code": 500, "success": false, "data": null, "msg": "金额不能小于0.1元" } ``` #### 4. 未登录或token无效 ```json { "code": 500, "success": false, "data": null, "msg": "请先登录" } ``` #### 5. 系统异常 ```json { "code": 500, "success": false, "data": null, "msg": "快速提现失败:{异常信息}" } ``` --- ## 业务逻辑说明 ### 快速提现流程 ``` ┌─────────────────────────────────────────────┐ │ 1. 接收请求(从DTO获取参数) │ │ - payPassword (必填,从DTO) │ │ - withdrawalMoney (必填,单位:分,从DTO) │ │ - JWT token (自动获取storeId) │ └─────────────────┬───────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ 2. 从 JWT token 中解析门店ID │ │ storeId = LoginUserUtil.getCurrentStoreId()│ └─────────────────┬───────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ 3. 验证支付密码 │ │ SELECT * FROM store_user │ │ WHERE store_id = ? AND pay_password = ? │ │ IF user == null │ │ 返回错误: "支付密码错误" │ └─────────────────┬───────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ 4. 验证账户余额 │ │ IF user.money <= withdrawalMoney │ │ 返回错误: "余额不足" │ └─────────────────┬───────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ 5. 验证提现金额 │ │ amountInYuan = withdrawalMoney ÷ 100 │ │ IF amountInYuan < 0.1 │ │ 返回错误: "金额不能小于0.1元" │ └─────────────────┬───────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ 6. 创建提现记录 │ │ StoreCashOutRecord record = new ... │ │ record.paymentStatus = 3 // 已通过 │ │ INSERT INTO store_cash_out_record │ └─────────────────┬───────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ 7. 返回结果 │ │ 返回 StoreCashOutRecord 对象 │ └─────────────────────────────────────────────┘ ``` ### 与原接口的对比 #### 原接口(app端) ```java @GetMapping("/applyCashOut") public R applyCashOut(Integer storeId, String payPassword, Integer withdrawalMoney) ``` - 使用 GET 请求 - 需要手动传递 storeId - URL: `/storeIncomeDetailsRecord/applyCashOut?storeId=103&payPassword=123456&withdrawalMoney=50000` #### 新接口(web端) ```java @PostMapping("/applyFastCashOut") public R applyFastCashOut(@RequestBody CashOutDTO cashOutDTO) ``` - 使用 POST 请求(更安全) - 从 JWT token 自动获取 storeId - 使用 DTO 接收 JSON 请求体 - URL: `/incomeManage/applyFastCashOut` **核心逻辑一致性**: - ✅ 支付密码验证逻辑相同 - ✅ 余额验证逻辑相同(`money <= withdrawalMoney`) - ✅ 最小金额验证相同(0.1元) - ✅ 提现状态相同(paymentStatus = 3) - ✅ 返回数据格式相同(StoreCashOutRecord对象) --- ## 数据库操作 ### 查询用户SQL ```sql SELECT * FROM store_user WHERE store_id = ? AND pay_password = ? LIMIT 1 ``` ### 插入提现记录SQL ```sql INSERT INTO store_cash_out_record ( store_id, money, cash_out_type, payment_status, delete_flag, income_start_time, income_end_time, store_user_id, created_time, updated_time ) VALUES ( ?, -- storeId ?, -- withdrawalMoney 0, -- cashOutType (0-全部提现) 3, -- paymentStatus (3-已通过) 0, -- deleteFlag NOW(), -- incomeStartTime NOW(), -- incomeEndTime ?, -- storeUserId NOW(), -- createdTime NOW() -- updatedTime ) ``` --- ## 业务场景 ### 场景 1: 正常快速提现 **前置条件**: - 账户余额: 1000元(100000分) - 支付密码: 123456 **请求**: ```http POST /incomeManage/applyFastCashOut Content-Type: application/json Authorization: Bearer VALID_TOKEN { "payPassword": "123456", "withdrawalMoney": 50000 } ``` **响应**: ```json { "code": 200, "success": true, "data": { "id": 1001, "storeId": 103, "money": 50000, "paymentStatus": 3, ... }, "msg": "操作成功" } ``` **数据库变化**: - ✅ 新增一条提现记录(paymentStatus=3) - ❌ 账户余额不变(与普通提现不同) --- ### 场景 2: 支付密码错误 **请求**: ```http POST /incomeManage/applyFastCashOut Content-Type: application/json { "payPassword": "wrong_password", "withdrawalMoney": 50000 } ``` **响应**: ```json { "code": 500, "success": false, "data": null, "msg": "支付密码错误" } ``` --- ### 场景 3: 余额不足 **前置条件**: 账户余额 100元(10000分) **请求**: ```http POST /incomeManage/applyFastCashOut Content-Type: application/json { "payPassword": "123456", "withdrawalMoney": 20000 } ``` **响应**: ```json { "code": 500, "success": false, "data": null, "msg": "余额不足" } ``` --- ### 场景 4: 提现金额过小 **请求**: ```http POST /incomeManage/applyFastCashOut Content-Type: application/json { "payPassword": "123456", "withdrawalMoney": 5 } ``` **响应**: ```json { "code": 500, "success": false, "data": null, "msg": "金额不能小于0.1元" } ``` --- ## 前端集成示例 ### Vue.js 示例 ```javascript export default { data() { return { payPassword: '', withdrawalMoney: '', // 用户输入的元金额 loading: false }; }, methods: { async applyFastCashOut() { // 1. 验证输入 if (!this.payPassword) { this.$message.error('请输入支付密码'); return; } if (!this.withdrawalMoney || this.withdrawalMoney < 0.1) { this.$message.error('提现金额不能小于0.1元'); return; } // 2. 转换金额单位(元转分) const withdrawalMoneyInCents = Math.floor(this.withdrawalMoney * 100); // 3. 发送请求(使用JSON Body) this.loading = true; try { const response = await this.$axios.post('/incomeManage/applyFastCashOut', { payPassword: this.payPassword, withdrawalMoney: withdrawalMoneyInCents }); if (response.data.success) { const cashOutRecord = response.data.data; this.$message.success('快速提现申请成功'); console.log('提现记录ID:', cashOutRecord.id); console.log('提现状态:', cashOutRecord.paymentStatus); // 3-已通过 // 刷新列表或跳转 this.$router.push('/cashout-list'); } else { this.$message.error(response.data.msg); } } catch (error) { console.error('快速提现失败:', error); this.$message.error('快速提现失败,请稍后重试'); } finally { this.loading = false; } } } } ``` --- ### React 示例 ```javascript import { useState } from 'react'; import axios from 'axios'; function FastCashOut() { const [payPassword, setPayPassword] = useState(''); const [withdrawalMoney, setWithdrawalMoney] = useState(''); const [loading, setLoading] = useState(false); const handleSubmit = async () => { // 1. 验证输入 if (!payPassword) { alert('请输入支付密码'); return; } const amount = parseFloat(withdrawalMoney); if (!amount || amount < 0.1) { alert('提现金额不能小于0.1元'); return; } // 2. 转换金额单位(元转分) const withdrawalMoneyInCents = Math.floor(amount * 100); // 3. 发送请求(使用JSON Body) setLoading(true); try { const response = await axios.post('/incomeManage/applyFastCashOut', { payPassword, withdrawalMoney: withdrawalMoneyInCents }); if (response.data.success) { const cashOutRecord = response.data.data; alert('快速提现申请成功'); console.log('提现记录:', cashOutRecord); // 跳转或刷新 } else { alert(response.data.msg); } } catch (error) { console.error('快速提现失败:', error); alert('快速提现失败,请稍后重试'); } finally { setLoading(false); } }; return (

快速提现(免审核)

setPayPassword(e.target.value)} />
setWithdrawalMoney(e.target.value)} />

⚠️ 快速提现无需审核,提现记录将直接标记为"已通过"状态

); } ``` --- ## 测试用例 ### 测试场景1: 正常快速提现 **前置条件**: - 账户余额: 1000元 - 支付密码: 123456 **请求**: ```http POST /incomeManage/applyFastCashOut Content-Type: application/json Authorization: Bearer VALID_TOKEN { "payPassword": "123456", "withdrawalMoney": 50000 } ``` **预期结果**: - 返回成功 - `data.paymentStatus = 3`(已通过) - 数据库新增提现记录 - 账户余额不变 --- ### 测试场景2: 支付密码错误 **请求**: ```http POST /incomeManage/applyFastCashOut Content-Type: application/json { "payPassword": "wrong", "withdrawalMoney": 50000 } ``` **预期结果**: - 返回失败 - 提示 "支付密码错误" - 数据库无变化 --- ### 测试场景3: 余额不足 **前置条件**: 账户余额 100元 **请求**: ```http POST /incomeManage/applyFastCashOut Content-Type: application/json { "payPassword": "123456", "withdrawalMoney": 20000 } ``` **预期结果**: - 返回失败 - 提示 "余额不足" --- ### 测试场景4: 最小金额验证 **请求**: ```http POST /incomeManage/applyFastCashOut Content-Type: application/json { "payPassword": "123456", "withdrawalMoney": 5 } ``` **预期结果**: - 返回失败 - 提示 "金额不能小于0.1元" --- ### 测试场景5: 边界值测试 **请求**: ```http POST /incomeManage/applyFastCashOut Content-Type: application/json { "payPassword": "123456", "withdrawalMoney": 10 } ``` **预期结果**: - 返回成功 - 提现金额 0.1元(最小金额) --- ## 常见问题 ### Q1: 快速提现与普通提现有什么区别? **答案**: - **快速提现** (`/applyFastCashOut`): - 提现记录直接标记为"已通过"(paymentStatus=3) - 无需人工审核 - 账户余额不立即扣减 - 与app端保持一致 - **普通提现** (`/cashOut`): - 提现记录标记为"待审核"(paymentStatus=1) - 需要人工审核 - 提交时立即扣减账户余额 --- ### Q2: 快速提现会立即扣款吗? **答案**: 不会。快速提现只创建提现记录,不扣减账户余额。实际扣款在管理员审批打款时进行。 --- ### Q3: paymentStatus=3 是什么意思? **答案**: - `paymentStatus = 3` 表示"已通过审核" - 区别于: - `1` - 待审核 - `2` - 审核不通过 - `4` - 已打款 - `5` - 打款失败 --- ### Q4: 提现金额的单位是什么? **答案**: - 接口参数使用 **分** 作为单位 - 1元 = 100分 - 例如:提现100元,传 `withdrawalMoney=10000` --- ### Q5: 为什么使用 POST 而不是 GET? **答案**: - POST 更安全,密码不会出现在 URL 中 - 符合 RESTful 规范(数据修改操作) - 与 web 端其他接口保持一致 --- ### Q6: 快速提现失败会回滚吗? **答案**: - 会。接口使用 `@Transactional` 注解 - 如果创建提现记录失败,事务会回滚 - 保证数据一致性 --- ## 注意事项 ### 1. 金额单位 - ⚠️ **参数单位**: 分(Integer) - ⚠️ **最小金额**: 10分(0.1元) - ⚠️ **前端转换**: 用户输入元,需转换为分 ### 2. 提现状态 - ⚠️ **状态值**: paymentStatus = 3(已通过) - ⚠️ **与普通提现不同**: 普通提现为 1(待审核) - ⚠️ **后续流程**: 管理员可直接进入打款流程 ### 3. 账户余额 - ⚠️ **验证逻辑**: `money <= withdrawalMoney` 会失败 - ⚠️ **扣款时机**: 创建记录时不扣款,打款时扣款 - ⚠️ **与普通提现不同**: 普通提现提交时立即扣款 ### 4. 安全性 - ⚠️ **密码保护**: 建议前端加密传输 - ⚠️ **日志脱敏**: 日志中密码显示为 `***` - ⚠️ **Token验证**: 必须提供有效的JWT token ### 5. 事务管理 - ⚠️ **事务保护**: 使用 `@Transactional` 保证原子性 - ⚠️ **异常回滚**: 任何异常都会导致事务回滚 - ⚠️ **数据一致性**: 保证提现记录创建的完整性 --- ## 迁移说明 ### 原接口(app端) - **服务**: `alien-store` - **路径**: `/alienStore/storeIncomeDetailsRecord/applyCashOut` - **Controller**: `StoreIncomeDetailsRecordController` - **Service**: `StoreIncomeDetailsRecordService.applyCashOut()` - **请求方式**: GET - **参数**: `storeId`, `payPassword`, `withdrawalMoney` ### 新接口(web端) - **服务**: `alien-store-platform` - **路径**: `/incomeManage/applyFastCashOut` - **Controller**: `IncomeManageController` - **Service**: `IncomeManageService.applyFastCashOut()` - **请求方式**: POST - **参数**: `payPassword`, `withdrawalMoney`(storeId从token获取) ### 差异说明 | 项目 | app端 | web端 | 说明 | |------|-------|-------|------| | 请求方式 | GET | POST | POST更安全 | | 请求参数 | @RequestParam | @RequestBody(DTO) | 使用DTO更规范 | | storeId来源 | 参数 | JWT token | 防伪造 | | 账户扣款 | 不扣款 | 不扣款 | 保持一致 | | 提现状态 | paymentStatus=3 | paymentStatus=3 | 保持一致 | | 返回值 | StoreCashOutRecord | StoreCashOutRecord | 保持一致 | | 事务管理 | @Transactional | @Transactional | 保持一致 | ### 复用的核心逻辑 1. ✅ 支付密码验证逻辑 2. ✅ 余额验证逻辑(`money <= withdrawalMoney`) 3. ✅ 最小金额验证(0.1元) 4. ✅ 提现状态设置(paymentStatus=3) 5. ✅ 提现记录创建逻辑 6. ✅ 返回数据格式 --- ## 更新日志 ### 2025-11-25 **修改内容**: - ✅ 修改请求参数为 DTO 形式(`CashOutDTO`) - ✅ 使用 `@RequestBody` 接收 JSON 请求体 - ✅ 移除 `@ApiImplicitParams` 注解 - ✅ 更新所有请求示例为 JSON Body 格式 - ✅ 更新前端集成示例 **涉及文件**: - `IncomeManageController.java` - 更新 - `28-快速提现申请接口.md` - 更新文档 --- ### 2025-11-20 **新增接口**: - ✅ `POST /incomeManage/applyFastCashOut` - 快速提现申请(免审核) **核心功能**: - ✅ 从 JWT token 自动获取 storeId - ✅ 支付密码验证 - ✅ 账户余额验证(`money <= withdrawalMoney`) - ✅ 最小金额验证(0.1元) - ✅ 创建提现记录(paymentStatus=3,已通过) - ✅ 不扣减账户余额(与app端保持一致) - ✅ 返回 StoreCashOutRecord 对象 - ✅ 事务保护 **与app端一致性**: - ✅ 业务逻辑完全相同 - ✅ 提现状态相同(paymentStatus=3) - ✅ 验证规则相同 - ✅ 返回数据格式相同 **涉及文件**: - `IncomeManageController.java` - 新增 `applyFastCashOut` 接口 - `IncomeManageService.java` - 新增方法定义 - `IncomeManageServiceImpl.java` - 新增方法实现 **代码质量**: - ✅ Linter检查:无错误 - ✅ 日志记录:详细 - ✅ 异常处理:完善 - ✅ 代码注释:完整 - ✅ 事务管理:正确 **开发人员**: ssk --- **文档版本**: v1.0 **最后更新**: 2025-11-20 **维护人员**: ssk