分销功能提交

This commit is contained in:
wong
2025-12-17 16:20:46 +08:00
parent 8e4ce2aee2
commit 7dda34a779
34 changed files with 8959 additions and 105 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,590 @@
<?php
namespace app\cunkebao\controller\distribution;
use app\cunkebao\model\DistributionChannel;
use app\cunkebao\model\DistributionWithdrawal;
use app\common\util\JwtUtil;
use think\Controller;
use think\Db;
use think\Exception;
/**
* 分销渠道用户端控制器
* 用户通过渠道编码访问无需JWT认证
*/
class ChannelUserController extends Controller
{
/**
* 初始化方法,设置跨域响应头
*/
protected function initialize()
{
parent::initialize();
// 处理OPTIONS预检请求
if ($this->request->method(true) == 'OPTIONS') {
$origin = $this->request->header('origin', '*');
header("Access-Control-Allow-Origin: " . $origin);
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization, Cookie");
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, PATCH');
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 86400");
exit;
}
}
/**
* 设置跨域响应头
* @param \think\response\Json $response
* @return \think\response\Json
*/
protected function setCorsHeaders($response)
{
$origin = $this->request->header('origin', '*');
$response->header([
'Access-Control-Allow-Origin' => $origin,
'Access-Control-Allow-Headers' => 'Origin, X-Requested-With, Content-Type, Accept, Authorization, Cookie',
'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, OPTIONS, PATCH',
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Max-Age' => '86400',
]);
return $response;
}
/**
* 渠道登录
* @return \think\response\Json
*/
public function login()
{
try {
// 获取参数
$phone = $this->request->param('phone', '');
$password = $this->request->param('password', '');
// 参数验证
if (empty($phone)) {
return $this->setCorsHeaders(json([
'code' => 400,
'success' => false,
'msg' => '手机号不能为空',
'data' => null
]));
}
if (empty($password)) {
return $this->setCorsHeaders(json([
'code' => 400,
'success' => false,
'msg' => '密码不能为空',
'data' => null
]));
}
// 查询渠道信息(通过手机号)
$channel = Db::name('distribution_channel')
->where([
['phone', '=', $phone],
['deleteTime', '=', 0]
])
->find();
if (!$channel) {
return $this->setCorsHeaders(json([
'code' => 404,
'success' => false,
'msg' => '渠道不存在',
'data' => null
]));
}
// 检查渠道状态
if ($channel['status'] !== DistributionChannel::STATUS_ENABLED) {
return $this->setCorsHeaders(json([
'code' => 403,
'success' => false,
'msg' => '渠道已被禁用',
'data' => null
]));
}
// 验证密码MD5加密
$passwordMd5 = md5($password);
if ($channel['password'] !== $passwordMd5) {
return $this->setCorsHeaders(json([
'code' => 401,
'success' => false,
'msg' => '密码错误',
'data' => null
]));
}
// 准备token载荷不包含密码
$payload = [
'id' => $channel['id'],
'channelId' => $channel['id'],
'channelCode' => $channel['code'],
'channelName' => $channel['name'],
'companyId' => $channel['companyId'],
'type' => 'channel', // 标识这是渠道登录
];
// 生成JWT令牌30天有效期
$expire = 86400 * 30;
$token = JwtUtil::createToken($payload, $expire);
$tokenExpired = time() + $expire;
// 更新最后登录时间(可选)
Db::name('distribution_channel')
->where('id', $channel['id'])
->update([
'updateTime' => time()
]);
// 返回数据(不包含密码)
$data = [
'token' => $token,
'tokenExpired' => $tokenExpired,
'channelInfo' => [
'id' => (string)$channel['id'],
'channelCode' => $channel['code'],
'channelName' => $channel['name'],
'phone' => $channel['phone'] ?: '',
'wechatId' => $channel['wechatId'] ?: '',
'status' => $channel['status'],
'totalCustomers' => (int)$channel['totalCustomers'],
'todayCustomers' => (int)$channel['todayCustomers'],
'totalFriends' => (int)$channel['totalFriends'],
'todayFriends' => (int)$channel['todayFriends'],
'withdrawableAmount' => round(($channel['withdrawableAmount'] ?? 0) / 100, 2), // 分转元
]
];
return $this->setCorsHeaders(json([
'code' => 200,
'success' => true,
'msg' => '登录成功',
'data' => $data
]));
} catch (Exception $e) {
return $this->setCorsHeaders(json([
'code' => $e->getCode() ?: 500,
'success' => false,
'msg' => '登录失败:' . $e->getMessage(),
'data' => null
]));
}
}
/**
* 获取渠道首页数据
* @return \think\response\Json
*/
public function index()
{
try {
// 获取参数
$channelCode = $this->request->param('channelCode', '');
// 参数验证
if (empty($channelCode)) {
return $this->setCorsHeaders(json([
'code' => 400,
'success' => false,
'msg' => '渠道编码不能为空',
'data' => null
]));
}
// 查询渠道信息
$channel = Db::name('distribution_channel')
->where([
['code', '=', $channelCode],
['status', '=', DistributionChannel::STATUS_ENABLED],
['deleteTime', '=', 0]
])
->find();
if (!$channel) {
return $this->setCorsHeaders(json([
'code' => 404,
'success' => false,
'msg' => '渠道不存在或已被禁用',
'data' => null
]));
}
$channelId = $channel['id'];
$companyId = $channel['companyId'];
// 1. 渠道基本信息
$channelInfo = [
'channelName' => $channel['name'] ?? '',
'channelCode' => $channel['code'] ?? '',
];
// 2. 财务统计
// 当前可提现金额
$withdrawableAmount = intval($channel['withdrawableAmount'] ?? 0);
// 已提现金额(已打款的提现申请)
$withdrawnAmount = Db::name('distribution_withdrawal')
->where([
['companyId', '=', $companyId],
['channelId', '=', $channelId],
['status', '=', DistributionWithdrawal::STATUS_PAID]
])
->sum('amount');
$withdrawnAmount = intval($withdrawnAmount ?? 0);
// 待审核金额(待审核的提现申请)
$pendingReviewAmount = Db::name('distribution_withdrawal')
->where([
['companyId', '=', $companyId],
['channelId', '=', $channelId],
['status', '=', DistributionWithdrawal::STATUS_PENDING]
])
->sum('amount');
$pendingReviewAmount = intval($pendingReviewAmount ?? 0);
// 总收益(所有收益记录的总和)
$totalRevenue = Db::name('distribution_revenue_record')
->where([
['companyId', '=', $companyId],
['channelId', '=', $channelId]
])
->sum('amount');
$totalRevenue = intval($totalRevenue ?? 0);
$financialStats = [
'withdrawableAmount' => round($withdrawableAmount / 100, 2), // 当前可提现金额(元)
'totalRevenue' => round($totalRevenue / 100, 2), // 总收益(元)
'pendingReview' => round($pendingReviewAmount / 100, 2), // 待审核(元)
'withdrawn' => round($withdrawnAmount / 100, 2), // 已提现(元)
];
// 3. 客户和好友统计
$customerStats = [
'totalFriends' => (int)($channel['totalFriends'] ?? 0), // 总加好友数
'todayFriends' => (int)($channel['todayFriends'] ?? 0), // 今日加好友数
'totalCustomers' => (int)($channel['totalCustomers'] ?? 0), // 总获客数
'todayCustomers' => (int)($channel['todayCustomers'] ?? 0), // 今日获客数
];
// 返回数据
$data = [
'channelInfo' => $channelInfo,
'financialStats' => $financialStats,
'customerStats' => $customerStats,
];
return $this->setCorsHeaders(json([
'code' => 200,
'success' => true,
'msg' => '获取成功',
'data' => $data
]));
} catch (Exception $e) {
return $this->setCorsHeaders(json([
'code' => $e->getCode() ?: 500,
'success' => false,
'msg' => '获取数据失败:' . $e->getMessage(),
'data' => null
]));
}
}
/**
* 获取收益明细列表
* @return \think\response\Json
*/
public function revenueRecords()
{
try {
// 获取参数
$channelCode = $this->request->param('channelCode', '');
$page = $this->request->param('page', 1);
$limit = $this->request->param('limit', 10);
$type = $this->request->param('type', 'all'); // all, customer_acquisition, add_friend, order, poster, phone, other
$date = $this->request->param('date', ''); // 日期筛选格式Y-m-d
// 参数验证
if (empty($channelCode)) {
return $this->setCorsHeaders(json([
'code' => 400,
'success' => false,
'msg' => '渠道编码不能为空',
'data' => null
]));
}
$page = max(1, intval($page));
$limit = max(1, min(100, intval($limit)));
// 查询渠道信息
$channel = Db::name('distribution_channel')
->where([
['code', '=', $channelCode],
['status', '=', DistributionChannel::STATUS_ENABLED],
['deleteTime', '=', 0]
])
->find();
if (!$channel) {
return $this->setCorsHeaders(json([
'code' => 404,
'success' => false,
'msg' => '渠道不存在或已被禁用',
'data' => null
]));
}
$channelId = $channel['id'];
$companyId = $channel['companyId'];
// 构建查询条件
$where = [
['companyId', '=', $companyId],
['channelId', '=', $channelId]
];
// 类型筛选
if ($type !== 'all') {
$where[] = ['type', '=', $type];
}
// 日期筛选
if (!empty($date)) {
$dateStart = strtotime($date . ' 00:00:00');
$dateEnd = strtotime($date . ' 23:59:59');
if ($dateStart && $dateEnd) {
$where[] = ['createTime', 'between', [$dateStart, $dateEnd]];
}
}
// 查询总数
$total = Db::name('distribution_revenue_record')
->where($where)
->count();
// 查询列表(按创建时间倒序)
$list = Db::name('distribution_revenue_record')
->where($where)
->order('createTime DESC')
->page($page, $limit)
->select();
// 从活动表customer_acquisition_task获取类型标签映射使用 sourceId 关联活动ID
$formattedList = [];
if (!empty($list)) {
// 收集本页涉及到的活动ID
$taskIds = [];
foreach ($list as $row) {
if (!empty($row['sourceId'])) {
$taskIds[] = (int)$row['sourceId'];
}
}
$taskIds = array_values(array_unique($taskIds));
// 获取活动名称映射taskId => name
$taskNameMap = [];
if (!empty($taskIds)) {
$taskNameMap = Db::name('customer_acquisition_task')
->whereIn('id', $taskIds)
->column('name', 'id');
}
// 格式化数据
foreach ($list as $item) {
$taskId = !empty($item['sourceId']) ? (int)$item['sourceId'] : 0;
$taskName = $taskId && isset($taskNameMap[$taskId]) ? $taskNameMap[$taskId] : null;
$formattedItem = [
'id' => (string)$item['id'],
'sourceType' => $item['sourceType'] ?? '其他',
'type' => $item['type'] ?? 'other',
// 类型标签优先取活动名称,没有则回退为 sourceType 或 “其他”
'typeLabel' => $taskName ?: (!empty($item['sourceType']) ? $item['sourceType'] : '其他'),
'amount' => round($item['amount'] / 100, 2), // 分转元
'remark' => isset($item['remark']) && $item['remark'] !== '' ? $item['remark'] : null,
'createTime' => !empty($item['createTime']) ? date('Y-m-d H:i', $item['createTime']) : '',
];
$formattedList[] = $formattedItem;
}
}
return $this->setCorsHeaders(json([
'code' => 200,
'success' => true,
'msg' => '获取成功',
'data' => [
'list' => $formattedList,
'total' => (int)$total,
'page' => $page,
'limit' => $limit
]
]));
} catch (Exception $e) {
return $this->setCorsHeaders(json([
'code' => $e->getCode() ?: 500,
'success' => false,
'msg' => '获取收益明细失败:' . $e->getMessage(),
'data' => null
]));
}
}
/**
* 获取提现明细列表
* @return \think\response\Json
*/
public function withdrawalRecords()
{
try {
// 获取参数
$channelCode = $this->request->param('channelCode', '');
$page = $this->request->param('page', 1);
$limit = $this->request->param('limit', 10);
$status = $this->request->param('status', 'all'); // all, pending, approved, rejected, paid
$payType = $this->request->param('payType', 'all'); // all, wechat, alipay, bankcard
$date = $this->request->param('date', ''); // 日期筛选格式Y-m-d
// 参数验证
if (empty($channelCode)) {
return $this->setCorsHeaders(json([
'code' => 400,
'success' => false,
'msg' => '渠道编码不能为空',
'data' => null
]));
}
$page = max(1, intval($page));
$limit = max(1, min(100, intval($limit)));
// 校验到账方式参数
$validPayTypes = ['all', 'wechat', 'alipay', 'bankcard'];
if (!in_array($payType, $validPayTypes)) {
$payType = 'all';
}
// 查询渠道信息
$channel = Db::name('distribution_channel')
->where([
['code', '=', $channelCode],
['status', '=', DistributionChannel::STATUS_ENABLED],
['deleteTime', '=', 0]
])
->find();
if (!$channel) {
return $this->setCorsHeaders(json([
'code' => 404,
'success' => false,
'msg' => '渠道不存在或已被禁用',
'data' => null
]));
}
$channelId = $channel['id'];
$companyId = $channel['companyId'];
// 构建查询条件
$where = [
['companyId', '=', $companyId],
['channelId', '=', $channelId]
];
// 状态筛选
if ($status !== 'all') {
$where[] = ['status', '=', $status];
}
// 到账方式筛选
if ($payType !== 'all') {
$where[] = ['payType', '=', $payType];
}
// 日期筛选
if (!empty($date)) {
$dateStart = strtotime($date . ' 00:00:00');
$dateEnd = strtotime($date . ' 23:59:59');
if ($dateStart && $dateEnd) {
$where[] = ['applyTime', 'between', [$dateStart, $dateEnd]];
}
}
// 查询总数
$total = Db::name('distribution_withdrawal')
->where($where)
->count();
// 查询列表(按申请时间倒序)
$list = Db::name('distribution_withdrawal')
->where($where)
->order('applyTime DESC')
->page($page, $limit)
->select();
// 格式化数据
$formattedList = [];
foreach ($list as $item) {
// 状态标签映射
$statusLabels = [
'pending' => '待审核',
'approved' => '已通过',
'rejected' => '已拒绝',
'paid' => '已打款'
];
// 支付类型标签映射
$payTypeLabels = [
'wechat' => '微信',
'alipay' => '支付宝',
'bankcard' => '银行卡'
];
$payType = !empty($item['payType']) ? $item['payType'] : null;
$formattedItem = [
'id' => (string)$item['id'],
'amount' => round($item['amount'] / 100, 2), // 分转元
'status' => $item['status'] ?? 'pending',
'statusLabel' => $statusLabels[$item['status'] ?? 'pending'] ?? '待审核',
'payType' => $payType,
'payTypeLabel' => $payType && isset($payTypeLabels[$payType]) ? $payTypeLabels[$payType] : null,
'applyTime' => !empty($item['applyTime']) ? date('Y-m-d H:i', $item['applyTime']) : '',
'reviewTime' => !empty($item['reviewTime']) ? date('Y-m-d H:i', $item['reviewTime']) : null,
'reviewer' => !empty($item['reviewer']) ? $item['reviewer'] : null,
'remark' => !empty($item['remark']) ? $item['remark'] : null,
];
$formattedList[] = $formattedItem;
}
return $this->setCorsHeaders(json([
'code' => 200,
'success' => true,
'msg' => '获取成功',
'data' => [
'list' => $formattedList,
'total' => (int)$total,
'page' => $page,
'limit' => $limit
]
]));
} catch (Exception $e) {
return $this->setCorsHeaders(json([
'code' => $e->getCode() ?: 500,
'success' => false,
'msg' => '获取提现明细失败:' . $e->getMessage(),
'data' => null
]));
}
}
}

View File

@@ -0,0 +1,670 @@
<?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];
// 状态筛选
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',
'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'] ?? '',
'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');
// 参数验证
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,
'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'] ?? '',
'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
]);
}
// 查询申请详情(关联渠道表)
$withdrawal = Db::name('distribution_withdrawal')
->alias('w')
->join('distribution_channel c', 'w.channelId = c.id AND c.deleteTime = 0', 'left')
->where([
['w.id', '=', $id],
['w.companyId', '=', $companyId]
])
->field([
'w.id',
'w.channelId',
'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'] ?? '',
'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
]);
}
}
}

View File

@@ -124,6 +124,40 @@ class GetAddFriendPlanDetailV1Controller extends Controller
$msgConf = json_decode($plan['msgConf'], true) ?: [];
$tagConf = json_decode($plan['tagConf'], true) ?: [];
// 处理分销配置
$distributionConfig = $sceneConf['distribution'] ?? [
'enabled' => false,
'channels' => [],
'customerRewardAmount' => 0,
'addFriendRewardAmount' => 0,
];
// 格式化分销配置(分转元,并获取渠道详情)
$distributionEnabled = !empty($distributionConfig['enabled']);
$distributionChannels = [];
if ($distributionEnabled && !empty($distributionConfig['channels'])) {
$channels = Db::name('distribution_channel')
->where([
['id', 'in', $distributionConfig['channels']],
['deleteTime', '=', 0]
])
->field('id,code,name')
->select();
$distributionChannels = array_map(function($channel) {
return [
'id' => (int)$channel['id'],
'code' => $channel['code'],
'name' => $channel['name']
];
}, $channels);
}
// 将分销配置添加到返回数据中
$sceneConf['distributionEnabled'] = $distributionEnabled;
$sceneConf['distributionChannels'] = $distributionChannels;
$sceneConf['customerRewardAmount'] = round(($distributionConfig['customerRewardAmount'] ?? 0) / 100, 2); // 分转元
$sceneConf['addFriendRewardAmount'] = round(($distributionConfig['addFriendRewardAmount'] ?? 0) / 100, 2); // 分转元
if(!empty($sceneConf['wechatGroups'])){

View File

@@ -69,6 +69,10 @@ class PostCreateAddFriendPlanV1Controller extends BaseController
return ResponseHelper::error('请选择设备', 400);
}
$companyId = $this->getUserInfo('companyId');
// 处理分销配置
$distributionConfig = $this->processDistributionConfig($params, $companyId);
// 归类参数
$msgConf = isset($params['messagePlans']) ? $params['messagePlans'] : [];
@@ -106,9 +110,16 @@ class PostCreateAddFriendPlanV1Controller extends BaseController
$sceneConf['addFriendInterval'],
$sceneConf['startTime'],
$sceneConf['orderTableFile'],
$sceneConf['endTime']
$sceneConf['endTime'],
$sceneConf['distributionEnabled'],
$sceneConf['distributionChannels'],
$sceneConf['customerRewardAmount'],
$sceneConf['addFriendRewardAmount']
);
// 将分销配置添加到sceneConf中
$sceneConf['distribution'] = $distributionConfig;
// 构建数据
$data = [
'name' => $params['name'],
@@ -327,4 +338,75 @@ class PostCreateAddFriendPlanV1Controller extends BaseController
json_decode($string);
return (json_last_error() == JSON_ERROR_NONE);
}
/**
* 处理分销配置
*
* @param array $params 请求参数
* @param int $companyId 公司ID
* @return array 分销配置
*/
private function processDistributionConfig($params, $companyId)
{
$distributionEnabled = !empty($params['distributionEnabled']) ? true : false;
$config = [
'enabled' => $distributionEnabled,
'channels' => [],
'customerRewardAmount' => 0, // 获客奖励金额(分)
'addFriendRewardAmount' => 0, // 添加奖励金额(分)
];
// 如果未开启分销,直接返回默认配置
if (!$distributionEnabled) {
return $config;
}
// 验证渠道ID
$channelIds = $params['distributionChannels'] ?? [];
if (empty($channelIds) || !is_array($channelIds)) {
throw new \Exception('请选择至少一个分销渠道');
}
// 查询有效的渠道(只保留存在且已启用的渠道)
$channels = Db::name('distribution_channel')
->where([
['id', 'in', $channelIds],
['companyId', '=', $companyId],
['status', '=', 'enabled'],
['deleteTime', '=', 0]
])
->field('id,code,name')
->select();
// 如果没有有效渠道,才报错
if (empty($channels)) {
throw new \Exception('所选的分销渠道均不存在或已被禁用,请重新选择');
}
// 只保留有效的渠道ID
$config['channels'] = array_column($channels, 'id');
// 验证获客奖励金额(元转分)
$customerRewardAmount = isset($params['customerRewardAmount']) ? floatval($params['customerRewardAmount']) : 0;
if ($customerRewardAmount < 0) {
throw new \Exception('获客奖励金额不能为负数');
}
if ($customerRewardAmount > 0 && !preg_match('/^\d+(\.\d{1,2})?$/', (string)$customerRewardAmount)) {
throw new \Exception('获客奖励金额格式不正确最多保留2位小数');
}
$config['customerRewardAmount'] = intval(round($customerRewardAmount * 100)); // 元转分
// 验证添加奖励金额(元转分)
$addFriendRewardAmount = isset($params['addFriendRewardAmount']) ? floatval($params['addFriendRewardAmount']) : 0;
if ($addFriendRewardAmount < 0) {
throw new \Exception('添加奖励金额不能为负数');
}
if ($addFriendRewardAmount > 0 && !preg_match('/^\d+(\.\d{1,2})?$/', (string)$addFriendRewardAmount)) {
throw new \Exception('添加奖励金额格式不正确最多保留2位小数');
}
$config['addFriendRewardAmount'] = intval(round($addFriendRewardAmount * 100)); // 元转分
return $config;
}
}

View File

@@ -5,6 +5,7 @@ namespace app\cunkebao\controller\plan;
use library\ResponseHelper;
use think\Controller;
use think\Db;
use app\cunkebao\service\DistributionRewardService;
/**
* 对外API接口控制器
@@ -91,6 +92,9 @@ class PostExternalApiV1Controller extends Controller
$identifier = !empty($params['wechatId']) ? $params['wechatId'] : $params['phone'];
// 渠道IDcid对应 distribution_channel.id
$channelId = !empty($params['cid']) ? intval($params['cid']) : 0;
$trafficPool = Db::name('traffic_pool')->where('identifier', $identifier)->find();
if (!$trafficPool) {
@@ -103,17 +107,44 @@ class PostExternalApiV1Controller extends Controller
$trafficPoolId = $trafficPool['id'];
}
$taskCustomer = Db::name('task_customer')->where('task_id', $plan['id'])->where('phone', $identifier)->find();
$taskCustomer = Db::name('task_customer')
->where('task_id', $plan['id'])
->where('phone', $identifier)
->find();
// 处理用户画像
if(!empty($params['portrait']) && is_array($params['portrait'])){
$this->updatePortrait($params['portrait'],$trafficPoolId,$plan['companyId']);
}
if (!$taskCustomer) {
$tags = !empty($params['tags']) ? explode(',',$params['tags']) : [];
$siteTags = !empty($params['siteTags']) ? explode(',',$params['siteTags']) : [];
Db::name('task_customer')->insert([
$tags = !empty($params['tags']) ? explode(',', $params['tags']) : [];
$siteTags = !empty($params['siteTags']) ? explode(',', $params['siteTags']) : [];
// 处理渠道ID只有在分销配置中允许、且渠道本身正常时才记录到task_customer
$finalChannelId = 0;
if ($channelId > 0) {
$sceneConf = json_decode($plan['sceneConf'], true) ?: [];
$distributionConfig = $sceneConf['distribution'] ?? null;
$allowedChannelIds = $distributionConfig['channels'] ?? [];
if (!empty($distributionConfig) && !empty($distributionConfig['enabled']) && in_array($channelId, $allowedChannelIds)) {
// 验证渠道是否存在且正常
$channel = Db::name('distribution_channel')
->where([
['id', '=', $channelId],
['companyId', '=', $plan['companyId']],
['status', '=', 'enabled'],
['deleteTime', '=', 0]
])
->find();
if ($channel) {
$finalChannelId = intval($channelId);
}
}
}
$customerId = Db::name('task_customer')->insertGetId([
'task_id' => $plan['id'],
'channelId' => $finalChannelId,
'phone' => $identifier,
'name' => !empty($params['name']) ? $params['name'] : '',
'source' => !empty($params['source']) ? $params['source'] : '',
@@ -123,6 +154,19 @@ class PostExternalApiV1Controller extends Controller
'createTime' => time(),
]);
// 记录获客奖励(异步处理,不影响主流程)
if ($customerId) {
try {
// 只有在存在有效渠道ID时才触发分佣
if ($finalChannelId > 0) {
DistributionRewardService::recordCustomerReward($plan['id'], $customerId, $identifier, $finalChannelId);
}
} catch (\Exception $e) {
// 记录错误但不影响主流程
\think\facade\Log::error('记录获客奖励失败:' . $e->getMessage());
}
}
return json([
'code' => 200,
'message' => '新增成功',

View File

@@ -48,6 +48,11 @@ class PostUpdateAddFriendPlanV1Controller extends BaseController
return ResponseHelper::error('计划不存在', 404);
}
$companyId = $this->getUserInfo('companyId');
// 处理分销配置
$distributionConfig = $this->processDistributionConfig($params, $companyId);
// 归类参数
$msgConf = isset($params['messagePlans']) ? $params['messagePlans'] : [];
$tagConf = [
@@ -85,9 +90,16 @@ class PostUpdateAddFriendPlanV1Controller extends BaseController
$sceneConf['addFriendInterval'],
$sceneConf['startTime'],
$sceneConf['orderTableFile'],
$sceneConf['endTime']
$sceneConf['endTime'],
$sceneConf['distributionEnabled'],
$sceneConf['distributionChannels'],
$sceneConf['customerRewardAmount'],
$sceneConf['addFriendRewardAmount']
);
// 将分销配置添加到sceneConf中
$sceneConf['distribution'] = $distributionConfig;
// 构建更新数据
$data = [
'name' => $params['name'],
@@ -283,4 +295,75 @@ class PostUpdateAddFriendPlanV1Controller extends BaseController
return ResponseHelper::error('系统错误: ' . $e->getMessage(), 500);
}
}
/**
* 处理分销配置
*
* @param array $params 请求参数
* @param int $companyId 公司ID
* @return array 分销配置
*/
private function processDistributionConfig($params, $companyId)
{
$distributionEnabled = !empty($params['distributionEnabled']) ? true : false;
$config = [
'enabled' => $distributionEnabled,
'channels' => [],
'customerRewardAmount' => 0, // 获客奖励金额(分)
'addFriendRewardAmount' => 0, // 添加奖励金额(分)
];
// 如果未开启分销,直接返回默认配置
if (!$distributionEnabled) {
return $config;
}
// 验证渠道ID
$channelIds = $params['distributionChannels'] ?? [];
if (empty($channelIds) || !is_array($channelIds)) {
throw new \Exception('请选择至少一个分销渠道');
}
// 查询有效的渠道(只保留存在且已启用的渠道)
$channels = Db::name('distribution_channel')
->where([
['id', 'in', $channelIds],
['companyId', '=', $companyId],
['status', '=', 'enabled'],
['deleteTime', '=', 0]
])
->field('id,code,name')
->select();
// 如果没有有效渠道,才报错
if (empty($channels)) {
throw new \Exception('所选的分销渠道均不存在或已被禁用,请重新选择');
}
// 只保留有效的渠道ID
$config['channels'] = array_column($channels, 'id');
// 验证获客奖励金额(元转分)
$customerRewardAmount = isset($params['customerRewardAmount']) ? floatval($params['customerRewardAmount']) : 0;
if ($customerRewardAmount < 0) {
throw new \Exception('获客奖励金额不能为负数');
}
if ($customerRewardAmount > 0 && !preg_match('/^\d+(\.\d{1,2})?$/', (string)$customerRewardAmount)) {
throw new \Exception('获客奖励金额格式不正确最多保留2位小数');
}
$config['customerRewardAmount'] = intval(round($customerRewardAmount * 100)); // 元转分
// 验证添加奖励金额(元转分)
$addFriendRewardAmount = isset($params['addFriendRewardAmount']) ? floatval($params['addFriendRewardAmount']) : 0;
if ($addFriendRewardAmount < 0) {
throw new \Exception('添加奖励金额不能为负数');
}
if ($addFriendRewardAmount > 0 && !preg_match('/^\d+(\.\d{1,2})?$/', (string)$addFriendRewardAmount)) {
throw new \Exception('添加奖励金额格式不正确最多保留2位小数');
}
$config['addFriendRewardAmount'] = intval(round($addFriendRewardAmount * 100)); // 元转分
return $config;
}
}

View File

@@ -113,10 +113,39 @@ class PosterWeChatMiniProgram extends Controller
}
// 2. 写入 ck_task_customer: 以 task_id ~~identifier~~ phone 为条件如果存在则忽略使用类似laravel的firstOrcreate但我不知道thinkphp5.1里的写法)
// $taskCustomer = Db::name('task_customer')->where('task_id', $taskId)->where('identifier', $result['phone_info']['phoneNumber'])->find();
$taskCustomer = Db::name('task_customer')->where('task_id', $taskId)->where('phone', $result['phone_info']['phoneNumber'])->find();
$taskCustomer = Db::name('task_customer')
->where('task_id', $taskId)
->where('phone', $result['phone_info']['phoneNumber'])
->find();
if (!$taskCustomer) {
Db::name('task_customer')->insert([
// 渠道IDcid对应 distribution_channel.id
$channelId = intval($this->request->param('cid', 0));
$finalChannelId = 0;
if ($channelId > 0) {
// 获取任务信息,解析分销配置
$sceneConf = json_decode($task['sceneConf'] ?? '[]', true) ?: [];
$distributionConfig = $sceneConf['distribution'] ?? null;
$allowedChannelIds = $distributionConfig['channels'] ?? [];
if (!empty($distributionConfig) && !empty($distributionConfig['enabled']) && in_array($channelId, $allowedChannelIds)) {
// 验证渠道是否存在且正常
$channel = Db::name('distribution_channel')
->where([
['id', '=', $channelId],
['companyId', '=', $task['companyId']],
['status', '=', 'enabled'],
['deleteTime', '=', 0]
])
->find();
if ($channel) {
$finalChannelId = $channelId;
}
}
}
$customerId = Db::name('task_customer')->insertGetId([
'task_id' => $taskId,
'channelId' => $finalChannelId,
// 'identifier' => $result['phone_info']['phoneNumber'],
'phone' => $result['phone_info']['phoneNumber'],
'source' => $task['name'],
@@ -124,6 +153,23 @@ class PosterWeChatMiniProgram extends Controller
'tags' => json_encode([]),
'siteTags' => json_encode([]),
]);
// 记录获客奖励(异步处理,不影响主流程)
if ($customerId) {
try {
if ($finalChannelId > 0) {
\app\cunkebao\service\DistributionRewardService::recordCustomerReward(
$taskId,
$customerId,
$result['phone_info']['phoneNumber'],
$finalChannelId
);
}
} catch (\Exception $e) {
// 记录错误但不影响主流程
\think\facade\Log::error('记录获客奖励失败:' . $e->getMessage());
}
}
}
// return $result['phone_info']['phoneNumber'];
return json([
@@ -149,6 +195,8 @@ class PosterWeChatMiniProgram extends Controller
$taskId = request()->param('id');
$rawInput = trim((string)request()->param('phone', ''));
// 渠道IDcid对应 distribution_channel.id
$channelId = intval(request()->param('cid', 0));
if ($rawInput === '') {
return json([
'code' => 400,
@@ -164,6 +212,28 @@ class PosterWeChatMiniProgram extends Controller
]);
}
// 预先根据任务的分销配置校验渠道是否有效仅当传入了cid时
$finalChannelId = 0;
if ($channelId > 0) {
$sceneConf = json_decode($task['sceneConf'] ?? '[]', true) ?: [];
$distributionConfig = $sceneConf['distribution'] ?? null;
$allowedChannelIds = $distributionConfig['channels'] ?? [];
if (!empty($distributionConfig) && !empty($distributionConfig['enabled']) && in_array($channelId, $allowedChannelIds)) {
// 验证渠道是否存在且正常
$channel = Db::name('distribution_channel')
->where([
['id', '=', $channelId],
['companyId', '=', $task['companyId']],
['status', '=', 'enabled'],
['deleteTime', '=', 0]
])
->find();
if ($channel) {
$finalChannelId = $channelId;
}
}
}
$lines = preg_split('/\r\n|\r|\n/', $rawInput);
foreach ($lines as $line) {
@@ -210,17 +280,35 @@ class PosterWeChatMiniProgram extends Controller
->find();
if (empty($taskCustomer)) {
$insertCustomer = [
'task_id' => $taskId,
'phone' => $identifier,
'source' => $task['name'],
'createTime' => time(),
'tags' => json_encode([]),
'siteTags' => json_encode([]),
'task_id' => $taskId,
'channelId' => $finalChannelId, // 记录本次导入归属的分销渠道(如有)
'phone' => $identifier,
'source' => $task['name'],
'createTime'=> time(),
'tags' => json_encode([]),
'siteTags' => json_encode([]),
];
if ($remark !== '') {
$insertCustomer['remark'] = $remark;
}
Db::name('task_customer')->insert($insertCustomer);
// 使用 insertGetId 以便在需要时记录获客奖励
$customerId = Db::name('task_customer')->insertGetId($insertCustomer);
// 表单录入成功即视为一次获客:
// 仅在存在有效渠道ID时记录获客奖励谁的cid谁获客
if (!empty($customerId) && $finalChannelId > 0) {
try {
\app\cunkebao\service\DistributionRewardService::recordCustomerReward(
$taskId,
$customerId,
$identifier,
$finalChannelId
);
} catch (\Exception $e) {
// 记录错误但不影响主流程
\think\facade\Log::error('记录获客奖励失败:' . $e->getMessage());
}
}
} elseif ($remark !== '' && $taskCustomer['remark'] !== $remark) {
Db::name('task_customer')
->where('id', $taskCustomer['id'])

View File

@@ -100,7 +100,8 @@ class GetWechatMomentsV1Controller extends BaseController
}
$query = Db::table('s2_wechat_moments')
->where('wechatAccountId', $accountId);
->where('wechatAccountId', $accountId)
->where('userName', $wechatId);
// 关键词搜索
if ($keyword = trim((string)$this->request->param('keyword', ''))) {