Files
cunkebao_v3/Server/application/cunkebao/controller/distribution/WithdrawalController.php

691 lines
25 KiB
PHP
Raw Normal View History

2025-12-17 16:20:46 +08:00
<?php
namespace app\cunkebao\controller\distribution;
use app\cunkebao\controller\BaseController;
use app\cunkebao\model\DistributionWithdrawal;
use library\ResponseHelper;
use think\Db;
use think\Exception;
/**
* 分销渠道提现申请控制器
*/
class WithdrawalController extends BaseController
{
/**
* 获取提现申请列表
* @return \think\response\Json
*/
public function index()
{
try {
// 获取参数
$page = $this->request->param('page', 1);
$limit = $this->request->param('limit', 20);
$status = $this->request->param('status', 'all');
$date = $this->request->param('date', '');
$keyword = $this->request->param('keyword', '');
$companyId = $this->getUserInfo('companyId');
// 参数验证
$page = max(1, intval($page));
$limit = max(1, min(100, intval($limit))); // 限制最大100
// 验证状态参数
$validStatuses = ['all', DistributionWithdrawal::STATUS_PENDING, DistributionWithdrawal::STATUS_APPROVED, DistributionWithdrawal::STATUS_REJECTED, DistributionWithdrawal::STATUS_PAID];
if (!in_array($status, $validStatuses)) {
$status = 'all';
}
// 构建查询条件
$where = [];
$where[] = ['w.companyId', '=', $companyId];
2025-12-29 15:12:57 +08:00
// 如果不是管理员,只能查看自己创建的提现申请
if (!$this->getUserInfo('isAdmin')) {
$where[] = ['w.userId', '=', $this->getUserInfo('id')];
}
2025-12-17 16:20:46 +08:00
// 状态筛选
if ($status !== 'all') {
$where[] = ['w.status', '=', $status];
}
// 日期筛选格式YYYY/MM/DD
if (!empty($date)) {
// 转换日期格式 YYYY/MM/DD 为时间戳范围
$dateParts = explode('/', $date);
if (count($dateParts) === 3) {
$dateStr = $dateParts[0] . '-' . $dateParts[1] . '-' . $dateParts[2];
$dateStart = strtotime($dateStr . ' 00:00:00');
$dateEnd = strtotime($dateStr . ' 23:59:59');
if ($dateStart && $dateEnd) {
$where[] = ['w.applyTime', 'between', [$dateStart, $dateEnd]];
}
}
}
// 关键词搜索(模糊匹配渠道名称、渠道编码)
if (!empty($keyword)) {
$keyword = trim($keyword);
// 需要关联渠道表进行搜索
}
// 构建查询(关联渠道表获取渠道名称和编码,只关联未删除的渠道)
$query = Db::name('distribution_withdrawal')
->alias('w')
->join('distribution_channel c', 'w.channelId = c.id AND c.deleteTime = 0', 'left')
->where($where);
// 关键词搜索(如果有关键词,添加渠道表关联条件)
if (!empty($keyword)) {
$query->where(function ($query) use ($keyword) {
$query->where('c.name', 'like', '%' . $keyword . '%')
->whereOr('c.code', 'like', '%' . $keyword . '%');
});
}
// 查询总数
$total = $query->count();
// 查询列表(按申请时间倒序)
$list = $query->field([
'w.id',
'w.channelId',
2025-12-29 15:12:57 +08:00
'w.userId',
2025-12-17 16:20:46 +08:00
'w.amount',
'w.status',
'w.payType',
'w.applyTime',
'w.reviewTime',
'w.reviewer',
'w.remark',
'c.name as channelName',
'c.code as channelCode'
])
->order('w.applyTime DESC')
->page($page, $limit)
->select();
// 格式化数据
$formattedList = [];
foreach ($list as $item) {
// 格式化申请日期为 YYYY/MM/DD
$applyDate = '';
if (!empty($item['applyTime'])) {
$applyDate = date('Y/m/d', $item['applyTime']);
}
// 格式化审核日期
$reviewDate = null;
if (!empty($item['reviewTime'])) {
$reviewDate = date('Y-m-d H:i:s', $item['reviewTime']);
}
$formattedItem = [
'id' => (string)$item['id'],
'channelId' => (string)$item['channelId'],
'channelName' => $item['channelName'] ?? '',
'channelCode' => $item['channelCode'] ?? '',
2025-12-29 15:12:57 +08:00
'userId' => (int)($item['userId'] ?? 0),
2025-12-17 16:20:46 +08:00
'amount' => round($item['amount'] / 100, 2), // 分转元保留2位小数
'status' => $item['status'] ?? DistributionWithdrawal::STATUS_PENDING,
'payType' => !empty($item['payType']) ? $item['payType'] : null, // 支付类型
'applyDate' => $applyDate,
'reviewDate' => $reviewDate,
'reviewer' => !empty($item['reviewer']) ? $item['reviewer'] : null,
'remark' => !empty($item['remark']) ? $item['remark'] : null,
];
$formattedList[] = $formattedItem;
}
// 返回结果
return json([
'code' => 200,
'success' => true,
'msg' => '获取成功',
'data' => [
'list' => $formattedList,
'total' => (int)$total
]
]);
} catch (Exception $e) {
return json([
'code' => $e->getCode() ?: 500,
'success' => false,
'msg' => '获取提现申请列表失败:' . $e->getMessage(),
'data' => null
]);
}
}
/**
* 创建提现申请
* @return \think\response\Json
*/
public function create()
{
try {
// 获取参数(接口接收的金额单位为元)
// 原先使用 channelId现在改为使用渠道编码 channelCode
$channelCode = $this->request->param('channelCode', '');
$amount = $this->request->param('amount', 0); // 金额单位:元
$companyId = $this->getUserInfo('companyId');
2025-12-29 15:12:57 +08:00
$userId = $this->getUserInfo('id');
2025-12-17 16:20:46 +08:00
// 参数验证
if (empty($channelCode)) {
return json([
'code' => 400,
'success' => false,
'msg' => '渠道编码不能为空',
'data' => null
]);
}
// 验证金额(转换为浮点数进行验证)
$amount = floatval($amount);
if (empty($amount) || $amount <= 0) {
return json([
'code' => 400,
'success' => false,
'msg' => '提现金额必须大于0',
'data' => null
]);
}
// 验证金额格式最多2位小数
if (!preg_match('/^\d+(\.\d{1,2})?$/', (string)$amount)) {
return json([
'code' => 400,
'success' => false,
'msg' => '提现金额格式不正确最多保留2位小数',
'data' => null
]);
}
// 检查渠道是否存在且属于当前公司(通过渠道编码查询)
$channel = Db::name('distribution_channel')
->where([
['code', '=', $channelCode],
['companyId', '=', $companyId],
['deleteTime', '=', 0]
])
->find();
if (!$channel) {
return json([
'code' => 404,
'success' => false,
'msg' => '渠道不存在或没有权限',
'data' => null
]);
}
// 统一使用渠道ID变量后续逻辑仍然基于 channelId
$channelId = $channel['id'];
// 检查渠道状态
if ($channel['status'] !== 'enabled') {
return json([
'code' => 400,
'success' => false,
'msg' => '渠道已禁用,无法申请提现',
'data' => null
]);
}
// 检查可提现金额
// 数据库存储的是分,接口接收的是元,需要统一单位进行比较
$withdrawableAmountInFen = intval($channel['withdrawableAmount'] ?? 0); // 数据库中的分
$withdrawableAmountInYuan = round($withdrawableAmountInFen / 100, 2); // 转换为元用于提示
$amountInFen = intval(round($amount * 100)); // 将接口接收的元转换为分
if ($amountInFen > $withdrawableAmountInFen) {
return json([
'code' => 400,
'success' => false,
'msg' => '提现金额不能超过可提现金额(' . number_format($withdrawableAmountInYuan, 2) . '元)',
'data' => null
]);
}
// 检查是否有待审核的申请
$pendingWithdrawal = Db::name('distribution_withdrawal')
->where([
['channelId', '=', $channelId],
['companyId', '=', $companyId],
['status', '=', DistributionWithdrawal::STATUS_PENDING]
])
->find();
if ($pendingWithdrawal) {
return json([
'code' => 400,
'success' => false,
'msg' => '该渠道已有待审核的提现申请,请等待审核完成后再申请',
'data' => null
]);
}
// 开始事务
Db::startTrans();
try {
// 创建提现申请(金额以分存储)
$withdrawalData = [
'companyId' => $companyId,
'channelId' => $channelId,
2025-12-29 15:12:57 +08:00
'userId' => $userId,
2025-12-17 16:20:46 +08:00
'amount' => $amountInFen, // 存储为分
'status' => DistributionWithdrawal::STATUS_PENDING,
'applyTime' => time(),
'createTime' => time(),
'updateTime' => time(),
];
$withdrawalId = Db::name('distribution_withdrawal')->insertGetId($withdrawalData);
if (!$withdrawalId) {
throw new Exception('创建提现申请失败');
}
// 扣除渠道可提现金额(以分为单位)
Db::name('distribution_channel')
->where('id', $channelId)
->setDec('withdrawableAmount', $amountInFen);
// 提交事务
Db::commit();
// 获取创建的申请数据
$withdrawal = Db::name('distribution_withdrawal')
->alias('w')
->join('distribution_channel c', 'w.channelId = c.id', 'left')
->where('w.id', $withdrawalId)
->field([
'w.id',
'w.channelId',
'w.amount',
'w.status',
'w.payType',
'w.applyTime',
'c.name as channelName',
'c.code as channelCode'
])
->find();
// 格式化返回数据(分转元)
$result = [
'id' => (string)$withdrawal['id'],
'channelId' => (string)$withdrawal['channelId'],
'channelName' => $withdrawal['channelName'] ?? '',
'channelCode' => $withdrawal['channelCode'] ?? '',
2025-12-29 15:12:57 +08:00
'userId' => (int)($withdrawal['userId'] ?? 0),
2025-12-17 16:20:46 +08:00
'amount' => round($withdrawal['amount'] / 100, 2), // 分转元保留2位小数
'status' => $withdrawal['status'],
'payType' => !empty($withdrawal['payType']) ? $withdrawal['payType'] : null, // 支付类型wechat、alipay、bankcard创建时为null
'applyDate' => !empty($withdrawal['applyTime']) ? date('Y/m/d', $withdrawal['applyTime']) : '',
'reviewDate' => null,
'reviewer' => null,
'remark' => null,
];
return json([
'code' => 200,
'success' => true,
'msg' => '提现申请提交成功',
'data' => $result
]);
} catch (Exception $e) {
Db::rollback();
throw $e;
}
} catch (Exception $e) {
return json([
'code' => $e->getCode() ?: 500,
'success' => false,
'msg' => '提交提现申请失败:' . $e->getMessage(),
'data' => null
]);
}
}
/**
* 审核提现申请(通过/拒绝)
* @return \think\response\Json
*/
public function review()
{
try {
// 获取参数
$id = $this->request->param('id', 0);
$action = $this->request->param('action', ''); // approve 或 reject
$remark = $this->request->param('remark', '');
$companyId = $this->getUserInfo('companyId');
$reviewer = $this->getUserInfo('username') ?: $this->getUserInfo('account') ?: '系统管理员';
// 参数验证
if (empty($id)) {
return json([
'code' => 400,
'success' => false,
'msg' => '申请ID不能为空',
'data' => null
]);
}
if (!in_array($action, ['approve', 'reject'])) {
return json([
'code' => 400,
'success' => false,
'msg' => '审核操作参数错误,必须为 approve 或 reject',
'data' => null
]);
}
// 如果是拒绝,备注必填
if ($action === 'reject' && empty($remark)) {
return json([
'code' => 400,
'success' => false,
'msg' => '拒绝申请时,拒绝理由不能为空',
'data' => null
]);
}
// 检查申请是否存在且属于当前公司
$withdrawal = Db::name('distribution_withdrawal')
->where([
['id', '=', $id],
['companyId', '=', $companyId]
])
->find();
if (!$withdrawal) {
return json([
'code' => 404,
'success' => false,
'msg' => '提现申请不存在或没有权限',
'data' => null
]);
}
// 检查申请状态
if ($withdrawal['status'] !== DistributionWithdrawal::STATUS_PENDING) {
return json([
'code' => 400,
'success' => false,
'msg' => '该申请已审核,无法重复审核',
'data' => null
]);
}
// 开始事务
Db::startTrans();
try {
$updateData = [
'reviewTime' => time(),
'reviewer' => $reviewer,
'remark' => $remark ?: '',
'updateTime' => time(),
];
if ($action === 'approve') {
// 审核通过
$updateData['status'] = DistributionWithdrawal::STATUS_APPROVED;
} else {
// 审核拒绝,退回可提现金额(金额以分存储)
$updateData['status'] = DistributionWithdrawal::STATUS_REJECTED;
// 退回渠道可提现金额(以分为单位)
Db::name('distribution_channel')
->where('id', $withdrawal['channelId'])
->setInc('withdrawableAmount', intval($withdrawal['amount']));
}
// 更新申请状态
Db::name('distribution_withdrawal')
->where('id', $id)
->update($updateData);
// 提交事务
Db::commit();
$msg = $action === 'approve' ? '审核通过成功' : '审核拒绝成功';
return json([
'code' => 200,
'success' => true,
'msg' => $msg,
'data' => [
'id' => (string)$id,
'status' => $updateData['status']
]
]);
} catch (Exception $e) {
Db::rollback();
throw $e;
}
} catch (Exception $e) {
return json([
'code' => $e->getCode() ?: 500,
'success' => false,
'msg' => '审核失败:' . $e->getMessage(),
'data' => null
]);
}
}
/**
* 打款(标记为已打款)
* @return \think\response\Json
*/
public function markPaid()
{
try {
// 获取参数
$id = $this->request->param('id', 0);
$payType = $this->request->param('payType', ''); // 支付类型wechat、alipay、bankcard
$remark = $this->request->param('remark', '');
$companyId = $this->getUserInfo('companyId');
// 参数验证
if (empty($id)) {
return json([
'code' => 400,
'success' => false,
'msg' => '申请ID不能为空',
'data' => null
]);
}
// 验证支付类型
$validPayTypes = [
DistributionWithdrawal::PAY_TYPE_WECHAT,
DistributionWithdrawal::PAY_TYPE_ALIPAY,
DistributionWithdrawal::PAY_TYPE_BANKCARD
];
if (empty($payType) || !in_array($payType, $validPayTypes)) {
return json([
'code' => 400,
'success' => false,
'msg' => '支付类型不能为空必须为wechat微信、alipay支付宝、bankcard银行卡',
'data' => null
]);
}
// 检查申请是否存在且属于当前公司
$withdrawal = Db::name('distribution_withdrawal')
->where([
['id', '=', $id],
['companyId', '=', $companyId]
])
->find();
if (!$withdrawal) {
return json([
'code' => 404,
'success' => false,
'msg' => '提现申请不存在或没有权限',
'data' => null
]);
}
// 检查申请状态(只有已通过的申请才能打款)
if ($withdrawal['status'] !== DistributionWithdrawal::STATUS_APPROVED) {
return json([
'code' => 400,
'success' => false,
'msg' => '只有已通过的申请才能标记为已打款',
'data' => null
]);
}
// 更新状态为已打款
$result = Db::name('distribution_withdrawal')
->where('id', $id)
->update([
'status' => DistributionWithdrawal::STATUS_PAID,
'payType' => $payType,
'remark' => !empty($remark) ? $remark : $withdrawal['remark'],
'updateTime' => time()
]);
if ($result === false) {
return json([
'code' => 500,
'success' => false,
'msg' => '标记打款失败',
'data' => null
]);
}
return json([
'code' => 200,
'success' => true,
'msg' => '标记打款成功',
'data' => [
'id' => (string)$id,
'status' => DistributionWithdrawal::STATUS_PAID,
'payType' => $payType
]
]);
} catch (Exception $e) {
return json([
'code' => $e->getCode() ?: 500,
'success' => false,
'msg' => '标记打款失败:' . $e->getMessage(),
'data' => null
]);
}
}
/**
* 获取提现申请详情
* @return \think\response\Json
*/
public function detail()
{
try {
// 获取参数
$id = $this->request->param('id', 0);
$companyId = $this->getUserInfo('companyId');
// 参数验证
if (empty($id)) {
return json([
'code' => 400,
'success' => false,
'msg' => '申请ID不能为空',
'data' => null
]);
}
2025-12-29 15:12:57 +08:00
// 构建查询条件
$where = [
['w.id', '=', $id],
['w.companyId', '=', $companyId]
];
// 如果不是管理员,只能查看自己创建的提现申请
if (!$this->getUserInfo('isAdmin')) {
$where[] = ['w.userId', '=', $this->getUserInfo('id')];
}
2025-12-17 16:20:46 +08:00
// 查询申请详情(关联渠道表)
$withdrawal = Db::name('distribution_withdrawal')
->alias('w')
->join('distribution_channel c', 'w.channelId = c.id AND c.deleteTime = 0', 'left')
2025-12-29 15:12:57 +08:00
->where($where)
2025-12-17 16:20:46 +08:00
->field([
'w.id',
'w.channelId',
2025-12-29 15:12:57 +08:00
'w.userId',
2025-12-17 16:20:46 +08:00
'w.amount',
'w.status',
'w.payType',
'w.applyTime',
'w.reviewTime',
'w.reviewer',
'w.remark',
'c.name as channelName',
'c.code as channelCode'
])
->find();
if (!$withdrawal) {
return json([
'code' => 404,
'success' => false,
'msg' => '提现申请不存在或没有权限',
'data' => null
]);
}
// 格式化返回数据(分转元)
$result = [
'id' => (string)$withdrawal['id'],
'channelId' => (string)$withdrawal['channelId'],
'channelName' => $withdrawal['channelName'] ?? '',
'channelCode' => $withdrawal['channelCode'] ?? '',
2025-12-29 15:12:57 +08:00
'userId' => (int)($withdrawal['userId'] ?? 0),
2025-12-17 16:20:46 +08:00
'amount' => round($withdrawal['amount'] / 100, 2), // 分转元保留2位小数
'status' => $withdrawal['status'],
'payType' => !empty($withdrawal['payType']) ? $withdrawal['payType'] : null, // 支付类型wechat、alipay、bankcard
'applyDate' => !empty($withdrawal['applyTime']) ? date('Y/m/d', $withdrawal['applyTime']) : '',
'reviewDate' => !empty($withdrawal['reviewTime']) ? date('Y-m-d H:i:s', $withdrawal['reviewTime']) : null,
'reviewer' => !empty($withdrawal['reviewer']) ? $withdrawal['reviewer'] : null,
'remark' => !empty($withdrawal['remark']) ? $withdrawal['remark'] : null,
];
return json([
'code' => 200,
'success' => true,
'msg' => '获取成功',
'data' => $result
]);
} catch (Exception $e) {
return json([
'code' => $e->getCode() ?: 500,
'success' => false,
'msg' => '获取详情失败:' . $e->getMessage(),
'data' => null
]);
}
}
}