分销功能提交

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

View File

@@ -198,6 +198,33 @@ Route::group('v1/', function () {
Route::post('disable', 'app\cunkebao\controller\StoreAccountController@disable'); // 禁用/启用账号
});
// 分销渠道管理
Route::group('distribution', function () {
// 渠道列表和统计
Route::group('channels', function () {
Route::get('', 'app\cunkebao\controller\distribution\ChannelController@index'); // 获取渠道列表
Route::get('statistics', 'app\cunkebao\controller\distribution\ChannelController@statistics'); // 获取渠道统计数据
Route::get('revenue-statistics', 'app\cunkebao\controller\distribution\ChannelController@revenueStatistics'); // 获取渠道收益统计(全局)
Route::get('revenue-detail', 'app\cunkebao\controller\distribution\ChannelController@revenueDetail'); // 获取渠道收益明细(单个渠道)
});
// 单个渠道操作
Route::group('channel', function () {
Route::post('', 'app\cunkebao\controller\distribution\ChannelController@create'); // 添加渠道
Route::put(':id', 'app\cunkebao\controller\distribution\ChannelController@update'); // 编辑渠道
Route::delete(':id', 'app\cunkebao\controller\distribution\ChannelController@delete'); // 删除渠道
Route::post(':id/toggle-status', 'app\cunkebao\controller\distribution\ChannelController@toggleStatus'); // 禁用/启用渠道
Route::post('generate-qrcode', 'app\cunkebao\controller\distribution\ChannelController@generateQrCode'); // 生成渠道二维码
});
// 提现申请管理
Route::group('withdrawals', function () {
Route::get('', 'app\cunkebao\controller\distribution\WithdrawalController@index'); // 获取提现申请列表
Route::post('', 'app\cunkebao\controller\distribution\WithdrawalController@create'); // 创建提现申请
Route::get(':id', 'app\cunkebao\controller\distribution\WithdrawalController@detail'); // 获取提现申请详情
Route::post(':id/review', 'app\cunkebao\controller\distribution\WithdrawalController@review'); // 审核提现申请(通过/拒绝)
Route::post(':id/mark-paid', 'app\cunkebao\controller\distribution\WithdrawalController@markPaid'); // 标记为已打款
});
});
})->middleware(['jwt']);
@@ -218,6 +245,20 @@ Route::group('v1/frontend', function () {
//Route::post('decryptphones', 'app\cunkebao\controller\plan\PosterWeChatMiniProgram@decryptphones');
});
Route::post('business/form/importsave', 'app\cunkebao\controller\plan\PosterWeChatMiniProgram@decryptphones');
// 分销渠道注册H5扫码
Route::group('distribution/channel', function () {
Route::get('register', 'app\cunkebao\controller\distribution\ChannelController@registerByQrCode'); // H5页面GET显示表单
Route::post('register', 'app\cunkebao\controller\distribution\ChannelController@registerByQrCode'); // 提交渠道信息POST
});
// 分销渠道用户端无需JWT认证通过渠道编码访问
Route::group('distribution/user', function () {
Route::post('login', 'app\cunkebao\controller\distribution\ChannelUserController@login'); // 渠道登录
Route::get('home', 'app\cunkebao\controller\distribution\ChannelUserController@index'); // 获取渠道首页数据
Route::get('revenue-records', 'app\cunkebao\controller\distribution\ChannelUserController@revenueRecords'); // 获取收益明细列表
Route::get('withdrawal-records', 'app\cunkebao\controller\distribution\ChannelUserController@withdrawalRecords'); // 获取提现明细列表
});
});

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', ''))) {

View File

@@ -0,0 +1,87 @@
<?php
namespace app\cunkebao\model;
use app\cunkebao\model\BaseModel;
use think\Model;
/**
* 分销渠道模型
*/
class DistributionChannel extends BaseModel
{
// 设置表名
protected $name = 'distribution_channel';
// 自动写入时间戳
protected $autoWriteTimestamp = true;
protected $createTime = 'createTime';
protected $updateTime = 'updateTime';
protected $deleteTime = 'deleteTime';
protected $defaultSoftDelete = 0;
// 类型转换
protected $type = [
'id' => 'integer',
'companyId' => 'integer',
'totalCustomers' => 'integer',
'todayCustomers' => 'integer',
'totalFriends' => 'integer',
'todayFriends' => 'integer',
'withdrawableAmount' => 'integer',
'createTime' => 'timestamp',
'updateTime' => 'timestamp',
'deleteTime' => 'timestamp',
];
/**
* 生成渠道编码
* 格式QD + 时间戳 + 9位随机字符串
*
* @return string
*/
public static function generateChannelCode()
{
$prefix = 'QD';
$timestamp = time();
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$randomStr = '';
// 生成9位随机字符串
for ($i = 0; $i < 9; $i++) {
$randomStr .= $chars[mt_rand(0, strlen($chars) - 1)];
}
$code = $prefix . $timestamp . $randomStr;
// 检查是否已存在
$exists = self::where('code', $code)->find();
if ($exists) {
// 如果已存在,递归重新生成
return self::generateChannelCode();
}
return $code;
}
/**
* 创建类型manual手动创建
*/
const CREATE_TYPE_MANUAL = 'manual';
/**
* 创建类型auto扫码创建
*/
const CREATE_TYPE_AUTO = 'auto';
/**
* 状态enabled启用
*/
const STATUS_ENABLED = 'enabled';
/**
* 状态disabled禁用
*/
const STATUS_DISABLED = 'disabled';
}

View File

@@ -0,0 +1,71 @@
<?php
namespace app\cunkebao\model;
use app\cunkebao\model\BaseModel;
use think\Model;
/**
* 分销渠道提现申请模型
*/
class DistributionWithdrawal extends BaseModel
{
// 设置表名
protected $name = 'distribution_withdrawal';
// 自动写入时间戳
protected $autoWriteTimestamp = true;
protected $createTime = 'createTime';
protected $updateTime = 'updateTime';
// 类型转换
protected $type = [
'id' => 'integer',
'companyId' => 'integer',
'channelId' => 'integer',
'amount' => 'integer',
'reviewTime' => 'timestamp',
'applyTime' => 'timestamp',
'createTime' => 'timestamp',
'updateTime' => 'timestamp',
];
/**
* 状态pending待审核
*/
const STATUS_PENDING = 'pending';
/**
* 状态approved已通过
*/
const STATUS_APPROVED = 'approved';
/**
* 状态rejected已拒绝
*/
const STATUS_REJECTED = 'rejected';
/**
* 状态paid已打款
*/
const STATUS_PAID = 'paid';
/**
* 支付类型wechat微信
*/
const PAY_TYPE_WECHAT = 'wechat';
/**
* 支付类型alipay支付宝
*/
const PAY_TYPE_ALIPAY = 'alipay';
/**
* 支付类型bankcard银行卡
*/
const PAY_TYPE_BANKCARD = 'bankcard';
}

View File

@@ -0,0 +1,276 @@
<?php
namespace app\cunkebao\service;
use think\Db;
use think\Exception;
/**
* 分销奖励服务类
* 处理获客和添加好友时的分销收益记录
*/
class DistributionRewardService
{
/**
* 记录获客奖励
*
* @param int $taskId 获客计划ID
* @param int $customerId 客户IDtask_customer表的id
* @param string $phone 客户手机号
* @param int|null $channelId 渠道ID分销渠道ID对应distribution_channel.id。为空时按配置的所有渠道分配
* @return bool
*/
public static function recordCustomerReward($taskId, $customerId, $phone, $channelId = null)
{
try {
// 获取获客计划信息
$task = Db::name('customer_acquisition_task')
->where('id', $taskId)
->find();
if (!$task) {
return false;
}
// 解析分销配置
$sceneConf = json_decode($task['sceneConf'], true) ?: [];
$distributionConfig = $sceneConf['distribution'] ?? null;
// 检查是否开启分销
if (empty($distributionConfig) || empty($distributionConfig['enabled'])) {
return false;
}
// 检查是否有获客奖励
$rewardAmount = intval($distributionConfig['customerRewardAmount'] ?? 0);
if ($rewardAmount <= 0) {
return false;
}
// 获取渠道列表(从分销配置中获取允许分佣的渠道)
$channelIds = $distributionConfig['channels'] ?? [];
if (empty($channelIds) || !is_array($channelIds)) {
return false;
}
$companyId = $task['companyId'];
$sceneId = $task['sceneId'];
// 获取场景名称(用于展示来源类型)
$scene = Db::name('plan_scene')
->where('id', $sceneId)
->field('name')
->find();
$sceneName = $scene['name'] ?? '未知场景';
// 如果指定了 channelIdcid仅允许该渠道获得分佣
if (!empty($channelId)) {
// 必须在配置的渠道列表中且是有效ID
if (!in_array($channelId, $channelIds)) {
// 该渠道不在本计划允许分佣的渠道列表中,直接返回
return false;
}
$channelIds = [$channelId];
}
// 开始事务
Db::startTrans();
try {
// 为每个渠道记录收益并更新可提现金额
foreach ($channelIds as $channelId) {
// 验证渠道是否存在
$channel = Db::name('distribution_channel')
->where([
['id', '=', $channelId],
['companyId', '=', $companyId],
['status', '=', 'enabled'],
['deleteTime', '=', 0]
])
->find();
if (!$channel) {
continue; // 跳过不存在的渠道
}
// 记录收益明细
Db::name('distribution_revenue_record')->insert([
'companyId' => $companyId,
'channelId' => $channelId,
'channelCode' => $channel['code'],
'type' => 'customer_acquisition', // 获客类型
'sourceType' => $sceneName,
'sourceId' => $taskId, // 活动ID获客任务ID
'amount' => $rewardAmount, // 金额(分)
'remark' => '获客奖励:' . $phone,
'createTime' => time(),
'updateTime' => time(),
]);
// 更新渠道可提现金额
Db::name('distribution_channel')
->where('id', $channelId)
->setInc('withdrawableAmount', $rewardAmount);
// 更新渠道获客统计
Db::name('distribution_channel')
->where('id', $channelId)
->setInc('totalCustomers', 1);
// 更新今日获客统计(如果是今天)
$todayStart = strtotime(date('Y-m-d 00:00:00'));
$todayEnd = strtotime(date('Y-m-d 23:59:59'));
$createTime = time();
if ($createTime >= $todayStart && $createTime <= $todayEnd) {
Db::name('distribution_channel')
->where('id', $channelId)
->setInc('todayCustomers', 1);
}
}
Db::commit();
return true;
} catch (Exception $e) {
Db::rollback();
throw $e;
}
} catch (Exception $e) {
// 记录错误日志,但不影响主流程
\think\Log::error('记录获客奖励失败:' . $e->getMessage());
return false;
}
}
/**
* 记录添加好友奖励
*
* @param int $taskId 获客计划ID
* @param int $customerId 客户IDtask_customer表的id
* @param string $phone 客户手机号
* @param int|null $channelId 渠道ID分销渠道ID对应distribution_channel.id。为空时按配置的所有渠道分配
* @return bool
*/
public static function recordAddFriendReward($taskId, $customerId, $phone, $channelId = null)
{
try {
// 获取获客计划信息
$task = Db::name('customer_acquisition_task')
->where('id', $taskId)
->find();
if (!$task) {
return false;
}
// 解析分销配置
$sceneConf = json_decode($task['sceneConf'], true) ?: [];
$distributionConfig = $sceneConf['distribution'] ?? null;
// 检查是否开启分销
if (empty($distributionConfig) || empty($distributionConfig['enabled'])) {
return false;
}
// 检查是否有添加奖励
$rewardAmount = intval($distributionConfig['addFriendRewardAmount'] ?? 0);
if ($rewardAmount <= 0) {
return false;
}
// 获取渠道列表(从分销配置中获取允许分佣的渠道)
$channelIds = $distributionConfig['channels'] ?? [];
if (empty($channelIds) || !is_array($channelIds)) {
return false;
}
$companyId = $task['companyId'];
$sceneId = $task['sceneId'];
// 获取场景名称(用于展示来源类型)
$scene = Db::name('plan_scene')
->where('id', $sceneId)
->field('name')
->find();
$sceneName = $scene['name'] ?? '未知场景';
// 如果指定了 channelIdcid仅允许该渠道获得分佣
if (!empty($channelId)) {
// 必须在配置的渠道列表中且是有效ID
if (!in_array($channelId, $channelIds)) {
// 该渠道不在本计划允许分佣的渠道列表中,直接返回
return false;
}
$channelIds = [$channelId];
}
// 开始事务
Db::startTrans();
try {
// 为每个渠道记录收益并更新可提现金额
foreach ($channelIds as $channelId) {
// 验证渠道是否存在
$channel = Db::name('distribution_channel')
->where([
['id', '=', $channelId],
['companyId', '=', $companyId],
['status', '=', 'enabled'],
['deleteTime', '=', 0]
])
->find();
if (!$channel) {
continue; // 跳过不存在的渠道
}
// 记录收益明细
Db::name('distribution_revenue_record')->insert([
'companyId' => $companyId,
'channelId' => $channelId,
'channelCode' => $channel['code'],
'type' => 'add_friend', // 添加好友类型
'sourceType' => $sceneName,
'sourceId' => $taskId, // 活动ID获客任务ID
'amount' => $rewardAmount, // 金额(分)
'remark' => '添加好友奖励:' . $phone,
'createTime' => time(),
'updateTime' => time(),
]);
// 更新渠道可提现金额
Db::name('distribution_channel')
->where('id', $channelId)
->setInc('withdrawableAmount', $rewardAmount);
// 更新渠道好友统计
Db::name('distribution_channel')
->where('id', $channelId)
->setInc('totalFriends', 1);
// 更新今日好友统计(如果是今天)
$todayStart = strtotime(date('Y-m-d 00:00:00'));
$todayEnd = strtotime(date('Y-m-d 23:59:59'));
$createTime = time();
if ($createTime >= $todayStart && $createTime <= $todayEnd) {
Db::name('distribution_channel')
->where('id', $channelId)
->setInc('todayFriends', 1);
}
}
Db::commit();
return true;
} catch (Exception $e) {
Db::rollback();
throw $e;
}
} catch (Exception $e) {
// 记录错误日志,但不影响主流程
\think\Log::error('记录添加好友奖励失败:' . $e->getMessage());
return false;
}
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace app\cunkebao\validate;
use think\Validate;
/**
* 分销渠道验证器
*/
class DistributionChannel extends Validate
{
protected $rule = [
'name' => 'require|length:1,50',
'phone' => 'regex:^1[3-9]\d{9}$',
'wechatId' => 'max:50',
'remarks' => 'max:200',
];
protected $message = [
'name.require' => '渠道名称不能为空',
'name.length' => '渠道名称长度必须在1-50个字符之间',
'phone.regex' => '手机号格式不正确请输入11位数字且以1开头',
'wechatId.max' => '微信号长度不能超过50个字符',
'remarks.max' => '备注信息长度不能超过200个字符',
];
protected $scene = [
'create' => ['name', 'phone', 'wechatId', 'remarks'],
];
}

View File

@@ -21,6 +21,7 @@ use app\common\service\AuthService;
use app\common\service\WechatAccountHealthScoreService;
use app\api\controller\WebSocketController;
use Workerman\Lib\Timer;
use app\cunkebao\service\DistributionRewardService;
class Adapter implements WeChatServiceInterface
{
@@ -375,9 +376,26 @@ class Adapter implements WeChatServiceInterface
if ($passedWeChatId && !empty($task_info['msgConf'])) {
// 更新状态为4已通过并已发消息
Db::name('task_customer')
->where('id', $task['id'])
->update(['status' => 4,'passTime' => time(), 'updateTime' => time()]);
// 记录添加好友奖励如果之前没有记录过status从其他状态变为4时
// 注意如果status已经是2说明已经记录过奖励这里不再重复记录
if ($task['status'] != 2 && !empty($task['channelId'])) {
try {
DistributionRewardService::recordAddFriendReward(
$task['task_id'],
$task['id'],
$task['phone'],
intval($task['channelId'])
);
} catch (\Exception $e) {
// 记录错误但不影响主流程
Log::error('记录添加好友奖励失败:' . $e->getMessage());
}
}
$wechatFriendRecord = $this->getWeChatAccoutIdAndFriendIdByWeChatIdAndFriendPhone($passedWeChatId, $task['phone']);
$msgConf = is_string($task_info['msgConf']) ? json_decode($task_info['msgConf'], 1) : $task_info['msgConf'];
@@ -395,9 +413,26 @@ class Adapter implements WeChatServiceInterface
// 已经执行成功的话直接break同时更新对应task_customer的状态为2添加成功
if (isset($latestFriendTask['status']) && $latestFriendTask['status'] == 1) {
// 更新状态
Db::name('task_customer')
->where('id', $task['id'])
->update(['status' => 2, 'updateTime' => time()]);
// 记录添加好友奖励(异步处理,不影响主流程)
if (!empty($task['channelId'])) {
try {
DistributionRewardService::recordAddFriendReward(
$task['task_id'],
$task['id'],
$task['phone'],
intval($task['channelId'])
);
} catch (\Exception $e) {
// 记录错误但不影响主流程
Log::error('记录添加好友奖励失败:' . $e->getMessage());
}
}
break;
}

View File

@@ -11,7 +11,7 @@
Target Server Version : 50736
File Encoding : 65001
Date: 24/11/2025 16:50:43
Date: 16/12/2025 16:39:24
*/
SET NAMES utf8mb4;
@@ -90,7 +90,7 @@ CREATE TABLE `ck_ai_knowledge_base_type` (
`delTime` int(11) NOT NULL DEFAULT 0 COMMENT '删除时间',
`status` tinyint(2) NULL DEFAULT 1 COMMENT '状态 1启用 0禁用',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ai知识库类型' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ai知识库类型' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_ai_settings
@@ -108,7 +108,7 @@ CREATE TABLE `ck_ai_settings` (
`botId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '智能体id',
`datasetId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '知识库id',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'AI配置' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'AI配置' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_app_version
@@ -145,7 +145,7 @@ CREATE TABLE `ck_attachments` (
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_hash_key`(`hash_key`) USING BTREE,
INDEX `idx_server`(`server`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 505 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '附件表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 580 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '附件表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_call_recording
@@ -164,6 +164,24 @@ CREATE TABLE `ck_call_recording` (
UNIQUE INDEX `uk_id_phone_isCallOut_companyId`(`id`, `phone`, `isCallOut`, `companyId`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_chat_groups
-- ----------------------------
DROP TABLE IF EXISTS `ck_chat_groups`;
CREATE TABLE `ck_chat_groups` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`groupName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '名称',
`groupMemo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '描述',
`groupType` tinyint(2) NULL DEFAULT NULL COMMENT '类型 1好友 2群',
`userId` int(11) NOT NULL DEFAULT 0 COMMENT '用户ID',
`companyId` int(11) NOT NULL DEFAULT 0 COMMENT '公司ID',
`sort` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '排序',
`createTime` int(11) NULL DEFAULT NULL,
`isDel` tinyint(1) NULL DEFAULT 0 COMMENT '是否删除 0未删除 1已删除',
`deleteTime` int(11) NULL DEFAULT NULL COMMENT '删除时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '聊天分组' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_company
-- ----------------------------
@@ -222,7 +240,7 @@ CREATE TABLE `ck_content_item` (
INDEX `idx_wechatid`(`wechatId`) USING BTREE,
INDEX `idx_friendid`(`friendId`) USING BTREE,
INDEX `idx_create_time`(`createTime`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5993 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '内容项目表-存储朋友圈采集数据' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 6090 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '内容项目表-存储朋友圈采集数据' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_content_library
@@ -230,9 +248,10 @@ CREATE TABLE `ck_content_item` (
DROP TABLE IF EXISTS `ck_content_library`;
CREATE TABLE `ck_content_library` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`formType` tinyint(2) NULL DEFAULT 0 COMMENT '0存客宝 1触客宝',
`sourceType` tinyint(2) NOT NULL DEFAULT 1 COMMENT '类型 1好友 2群 3自定义',
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '内容库名称',
`devices` json NULL COMMENT '设备列表JSON格式[{\"id\":1,\"name\":\"设备1\"},{\"id\":2,\"name\":\"设备2\"}]',
`devices` json NULL COMMENT '设备列表',
`catchType` json NULL COMMENT '采集类型',
`sourceFriends` json NULL COMMENT '选择的微信好友',
`sourceGroups` json NULL COMMENT '选择的微信群',
@@ -252,7 +271,7 @@ CREATE TABLE `ck_content_library` (
`isDel` tinyint(1) NULL DEFAULT 0 COMMENT '是否删除',
`deleteTime` int(11) NULL DEFAULT NULL COMMENT '删除时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 100 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '内容库表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 135 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '内容库表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_coze_conversation
@@ -331,7 +350,7 @@ CREATE TABLE `ck_customer_acquisition_task` (
`deleteTime` int(11) NULL DEFAULT 0 COMMENT '删除时间',
`apiKey` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 168 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '获客计划表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 178 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '获客计划表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_device
@@ -372,7 +391,7 @@ CREATE TABLE `ck_device_handle_log` (
`companyId` int(11) NULL DEFAULT NULL COMMENT '租户id',
`createTime` int(11) NULL DEFAULT NULL COMMENT '操作时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 339 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 351 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_device_taskconf
@@ -395,7 +414,7 @@ CREATE TABLE `ck_device_taskconf` (
`updateTime` int(11) UNSIGNED NULL DEFAULT 0 COMMENT '更新时间',
`deleteTime` int(11) UNSIGNED NULL DEFAULT 0 COMMENT '删除时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 30 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '设备任务配置表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 31 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '设备任务配置表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_device_user
@@ -408,7 +427,7 @@ CREATE TABLE `ck_device_user` (
`deviceId` int(11) UNSIGNED NOT NULL COMMENT '设备id',
`deleteTime` int(11) UNSIGNED NULL DEFAULT 0 COMMENT '删除时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 22 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '设备跟操盘手的关联关系' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 24 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '设备跟操盘手的关联关系' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_device_wechat_login
@@ -425,7 +444,85 @@ CREATE TABLE `ck_device_wechat_login` (
`isTips` tinyint(2) NOT NULL DEFAULT 0 COMMENT '是否提示迁移',
PRIMARY KEY (`id`) USING BTREE,
INDEX `wechatId`(`wechatId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 312 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '设备登录微信记录表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 322 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '设备登录微信记录表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_distribution_channel
-- ----------------------------
DROP TABLE IF EXISTS `ck_distribution_channel`;
CREATE TABLE `ck_distribution_channel` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '渠道ID',
`companyId` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '公司ID',
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '渠道名称',
`code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '渠道编码(系统生成)',
`phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '联系电话',
`password` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '密码MD5加密',
`wechatId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '微信号',
`remarks` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '备注信息',
`createType` enum('manual','auto') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'manual' COMMENT '创建类型manual手动创建auto扫码创建',
`status` enum('enabled','disabled') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'enabled' COMMENT '状态enabled启用disabled禁用',
`totalCustomers` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '总获客数',
`todayCustomers` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '今日获客数',
`totalFriends` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '总加好友数',
`todayFriends` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '今日加好友数',
`withdrawableAmount` bigint(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT '可提现金额(分)',
`createTime` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '创建时间',
`updateTime` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '更新时间',
`deleteTime` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '删除时间(软删除)',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_companyId`(`companyId`) USING BTREE,
INDEX `idx_code`(`code`) USING BTREE,
INDEX `idx_status`(`status`) USING BTREE,
INDEX `idx_deleteTime`(`deleteTime`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '分销渠道表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_distribution_revenue_record
-- ----------------------------
DROP TABLE IF EXISTS `ck_distribution_revenue_record`;
CREATE TABLE `ck_distribution_revenue_record` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '收益记录ID',
`companyId` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '公司ID',
`channelId` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '渠道ID',
`channelCode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '渠道编码(冗余字段,方便查询)',
`type` enum('customer_acquisition','add_friend','order','poster','phone','other') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'other' COMMENT '收益类型customer_acquisition获客add_friend加好友order订单poster海报phone电话other其他',
`sourceType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '来源类型(如:海报获客、加好友任务等)',
`sourceId` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '来源ID关联任务ID或其他业务ID',
`amount` bigint(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT '收益金额(分,整型,单位分)',
`remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '备注信息',
`createTime` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '创建时间',
`updateTime` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_companyId`(`companyId`) USING BTREE,
INDEX `idx_channelId`(`channelId`) USING BTREE,
INDEX `idx_channelCode`(`channelCode`) USING BTREE,
INDEX `idx_type`(`type`) USING BTREE,
INDEX `idx_createTime`(`createTime`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '分销渠道收益明细表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_distribution_withdrawal
-- ----------------------------
DROP TABLE IF EXISTS `ck_distribution_withdrawal`;
CREATE TABLE `ck_distribution_withdrawal` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '提现申请ID',
`companyId` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '公司ID',
`channelId` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '渠道ID',
`amount` bigint(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT '提现金额(分,整型,单位分)',
`payType` enum('wechat','alipay','bankcard') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'wechat' COMMENT '支付类型wechat微信alipay支付宝bankcard银行卡',
`status` enum('pending','approved','rejected','paid') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'pending' COMMENT '状态pending待审核approved已通过rejected已拒绝paid已打款',
`reviewer` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '审核人',
`reviewTime` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '审核时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '备注/拒绝理由',
`applyTime` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '申请时间',
`createTime` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '创建时间',
`updateTime` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_companyId`(`companyId`) USING BTREE,
INDEX `idx_channelId`(`channelId`) USING BTREE,
INDEX `idx_status`(`status`) USING BTREE,
INDEX `idx_applyTime`(`applyTime`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '分销渠道提现申请表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_flow_package
@@ -628,7 +725,7 @@ CREATE TABLE `ck_kf_auto_greetings_record` (
INDEX `idx_user`(`userId`) USING BTREE,
INDEX `idx_createTime`(`createTime`) USING BTREE,
INDEX `idx_isSend`(`isSend`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '问候规则使用记录表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '问候规则使用记录表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_kf_follow_up
@@ -653,7 +750,7 @@ CREATE TABLE `ck_kf_follow_up` (
INDEX `idx_level`(`type`) USING BTREE,
INDEX `idx_isRemind`(`isRemind`) USING BTREE,
INDEX `idx_isProcess`(`isProcess`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '跟进提醒' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '跟进提醒' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_kf_friend_settings
@@ -675,7 +772,7 @@ CREATE TABLE `ck_kf_friend_settings` (
INDEX `idx_userId`(`userId`) USING BTREE,
INDEX `idx_wechatAccountId`(`wechatAccountId`) USING BTREE,
INDEX `idx_friendId`(`friendId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 42 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '好友AI配置' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 51 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '好友AI配置' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_kf_keywords
@@ -769,7 +866,7 @@ CREATE TABLE `ck_kf_notice` (
`createTime` int(12) NULL DEFAULT NULL COMMENT '创建时间',
`readTime` int(12) NULL DEFAULT NULL COMMENT '读取时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 247 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '通知消息' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 252 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '通知消息' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_kf_questions
@@ -810,7 +907,7 @@ CREATE TABLE `ck_kf_reply` (
`isDel` tinyint(2) NULL DEFAULT 0 COMMENT '是否删除',
`delTime` int(12) NULL DEFAULT NULL COMMENT '删除时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 130751 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '快捷回复' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 130753 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '快捷回复' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_kf_reply_group
@@ -874,7 +971,7 @@ CREATE TABLE `ck_kf_to_do` (
INDEX `idx_level`(`level`) USING BTREE,
INDEX `idx_isRemind`(`isRemind`) USING BTREE,
INDEX `idx_isProcess`(`isProcess`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '待办事项' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '待办事项' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_menus
@@ -919,7 +1016,7 @@ CREATE TABLE `ck_order` (
`payInfo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '错误信息',
`deleteTime` int(11) UNSIGNED NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 79 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 106 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_plan_scene
@@ -937,7 +1034,7 @@ CREATE TABLE `ck_plan_scene` (
`deleteTime` int(11) NULL DEFAULT 0 COMMENT '删除时间',
`scenarioTags` json NULL COMMENT '标签',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '获客场景' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '获客场景' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_plan_tags
@@ -959,6 +1056,7 @@ DROP TABLE IF EXISTS `ck_task_customer`;
CREATE TABLE `ck_task_customer` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`task_id` int(11) NOT NULL,
`channelId` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '渠道ID分销渠道ID对应distribution_channel.id',
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '客户姓名',
`source` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '来源',
`phone` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
@@ -976,8 +1074,9 @@ CREATE TABLE `ck_task_customer` (
INDEX `task_id`(`task_id`) USING BTREE,
INDEX `addTime`(`addTime`) USING BTREE,
INDEX `passTime`(`passTime`) USING BTREE,
INDEX `updateTime`(`updateTime`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 28204 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
INDEX `updateTime`(`updateTime`) USING BTREE,
INDEX `idx_channelId`(`channelId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 28222 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_tokens_company
@@ -985,12 +1084,29 @@ CREATE TABLE `ck_task_customer` (
DROP TABLE IF EXISTS `ck_tokens_company`;
CREATE TABLE `ck_tokens_company` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`userId` int(10) NULL DEFAULT 0,
`companyId` int(11) NOT NULL DEFAULT 0 COMMENT '公司id',
`tokens` bigint(100) NULL DEFAULT NULL,
`createTime` int(12) NULL DEFAULT NULL COMMENT '创建时间',
`updateTime` int(11) NULL DEFAULT NULL COMMENT '更新时间',
`isAdmin` tinyint(2) NULL DEFAULT 0 COMMENT '是否公司主号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '公司算力账户' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '公司算力账户' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_tokens_form
-- ----------------------------
DROP TABLE IF EXISTS `ck_tokens_form`;
CREATE TABLE `ck_tokens_form` (
`id` int(11) UNSIGNED NOT NULL,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '名称',
`tokens` int(12) NULL DEFAULT 0 COMMENT '消耗token',
`isDel` tinyint(2) NULL DEFAULT 0 COMMENT '是否删除',
`status` tinyint(2) NULL DEFAULT 0 COMMENT '状态',
`createTime` int(11) NULL DEFAULT 0,
`delTime` int(11) NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_tokens_package
@@ -1026,14 +1142,14 @@ CREATE TABLE `ck_tokens_record` (
`userId` int(11) NOT NULL DEFAULT 0 COMMENT '创建用户ID',
`wechatAccountId` int(11) NULL DEFAULT NULL COMMENT '客服id',
`friendIdOrGroupId` int(11) NULL DEFAULT NULL COMMENT '好友id或者群id',
`form` tinyint(2) NULL DEFAULT 0 COMMENT '来源 0未知 1好友聊天 2群聊天 3群公告 4商家 5充值',
`form` int(11) NULL DEFAULT 0 COMMENT '来源 \r\n0 未知\r\n1 点赞\r\n2 朋友圈同步\r\n3 朋友圈发布\r\n4 群发微信\r\n5 群发群消息\r\n6 群发群公告\r\n7 海报获客\r\n8 订单获客\r\n9 电话获客\r\n10 微信群获客\r\n11 API获客\r\n12 AI改写\r\n13 AI客服\r\n14 生成群公告\r\n\r\n1001 商家 \r\n1002 充值 \r\n1003 系统',
`type` tinyint(2) NULL DEFAULT 0 COMMENT '类型 0减少 1增加',
`tokens` int(11) NULL DEFAULT NULL COMMENT '消耗tokens',
`balanceTokens` int(11) NULL DEFAULT NULL COMMENT '剩余tokens',
`remarks` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`createTime` int(12) NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 273 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '算力明细记录' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 336 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '算力明细记录' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_traffic_order
@@ -1072,7 +1188,7 @@ CREATE TABLE `ck_traffic_pool` (
INDEX `idx_wechatId`(`wechatId`) USING BTREE,
INDEX `idx_mobile`(`mobile`) USING BTREE,
INDEX `idx_create_time`(`createTime`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1063510 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '流量池' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 1201225 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '流量池' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_traffic_profile
@@ -1117,7 +1233,7 @@ CREATE TABLE `ck_traffic_source` (
INDEX `idx_identifier`(`identifier`) USING BTREE,
INDEX `idx_companyId`(`companyId`) USING BTREE,
INDEX `idx_company_status_time`(`companyId`, `status`, `updateTime`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 573831 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '流量来源' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 586456 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '流量来源' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_traffic_source_package
@@ -1244,7 +1360,7 @@ CREATE TABLE `ck_user_portrait` (
`createTime` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '创建时间',
`updateTime` int(11) NULL DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 19014 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户画像' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 22602 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户画像' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_users
@@ -1269,7 +1385,7 @@ CREATE TABLE `ck_users` (
`updateTime` int(11) NULL DEFAULT NULL COMMENT '修改时间',
`deleteTime` int(11) UNSIGNED NULL DEFAULT 0 COMMENT '删除时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1658 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 1666 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_vendor_order
@@ -1362,7 +1478,7 @@ CREATE TABLE `ck_wechat_account` (
`updateTime` int(11) NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uni_wechatId`(`wechatId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3614968 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信账号表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 4282931 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信账号表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_wechat_customer
@@ -1380,7 +1496,7 @@ CREATE TABLE `ck_wechat_customer` (
`updateTime` int(11) NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uni_wechatId`(`wechatId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 154 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信客服信息' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 159 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信客服信息' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_wechat_friendship
@@ -1436,7 +1552,7 @@ CREATE TABLE `ck_wechat_group_member` (
`deleteTime` int(11) UNSIGNED NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_identifier_chatroomId_groupId`(`identifier`, `chatroomId`, `groupId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 554147 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信群成员' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 561848 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信群成员' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_wechat_restricts
@@ -1453,7 +1569,7 @@ CREATE TABLE `ck_wechat_restricts` (
`restrictTime` int(11) NULL DEFAULT NULL COMMENT '限制日期',
`recoveryTime` int(11) NULL DEFAULT NULL COMMENT '恢复日期',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1319 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信风险受限记录' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 1416 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信风险受限记录' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_wechat_tag
@@ -1491,7 +1607,7 @@ CREATE TABLE `ck_workbench` (
INDEX `idx_user_id`(`userId`) USING BTREE,
INDEX `idx_type`(`type`) USING BTREE,
INDEX `idx_status`(`status`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 282 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '工作台主表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 330 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '工作台主表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_workbench_auto_like
@@ -1546,6 +1662,7 @@ CREATE TABLE `ck_workbench_group_create` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`workbenchId` int(11) NOT NULL COMMENT '计划ID',
`devices` json NULL COMMENT '目标设备/客服(JSON数组)',
`admins` json NULL COMMENT '管理员',
`poolGroups` json NULL COMMENT '流量池JSON',
`wechatGroups` json NULL COMMENT '微信客服JSON',
`startTime` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '开始时间',
@@ -1558,7 +1675,7 @@ CREATE TABLE `ck_workbench_group_create` (
`createTime` int(11) NULL DEFAULT NULL COMMENT '创建时间',
`updateTime` int(11) NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 26 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 27 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_workbench_group_create_item
@@ -1571,9 +1688,17 @@ CREATE TABLE `ck_workbench_group_create_item` (
`wechatId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '微信id',
`groupId` int(10) NULL DEFAULT NULL COMMENT '群id',
`wechatAccountId` int(11) NULL DEFAULT NULL COMMENT '客服id',
`status` tinyint(2) NOT NULL DEFAULT 0 COMMENT '状态0=待创建1=创建中2=创建成功3=创建失败4=管理员好友已拉入',
`memberType` tinyint(2) NOT NULL DEFAULT 1 COMMENT '成员类型1=群主成员2=管理员3=群主好友4=管理员好友',
`retryCount` int(11) NOT NULL DEFAULT 0 COMMENT '重试次数',
`chatroomId` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '群聊ID用于查询验证',
`verifyTime` int(11) NULL DEFAULT NULL COMMENT '验证时间',
`createTime` int(11) NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 46 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_status_workbench`(`status`, `workbenchId`) USING BTREE,
INDEX `idx_chatroom_id`(`chatroomId`) USING BTREE,
INDEX `idx_member_type`(`memberType`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 66 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_workbench_group_push
@@ -1686,7 +1811,7 @@ CREATE TABLE `ck_workbench_moments_sync` (
`updateTime` int(11) NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_workbench_id`(`workbenchId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 51 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '朋友圈同步配置' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 97 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '朋友圈同步配置' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_workbench_moments_sync_item
@@ -1703,7 +1828,7 @@ CREATE TABLE `ck_workbench_moments_sync_item` (
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_workbench_time`(`workbenchId`, `createTime`) USING BTREE,
INDEX `idx_workbench_content`(`workbenchId`, `contentId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1785 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '朋友圈同步配置' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 2308 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '朋友圈同步配置' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for ck_workbench_traffic_config
@@ -1747,7 +1872,7 @@ CREATE TABLE `ck_workbench_traffic_config_item` (
INDEX `deviceId`(`deviceId`) USING BTREE,
INDEX `wechatFriendId`(`wechatFriendId`) USING BTREE,
INDEX `wechatAccountId`(`wechatAccountId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 54241 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '流量分发计划扩展表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 58212 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '流量分发计划扩展表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for s2_allot_rule
@@ -2156,7 +2281,7 @@ CREATE TABLE `s2_wechat_account_score` (
INDEX `idx_health_score`(`healthScore`) USING BTREE,
INDEX `idx_base_score_calculated`(`baseScoreCalculated`) USING BTREE,
INDEX `idx_update_time`(`updateTime`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 363 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信账号评分记录表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 368 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信账号评分记录表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for s2_wechat_account_score_log
@@ -2180,7 +2305,7 @@ CREATE TABLE `s2_wechat_account_score_log` (
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_account_field`(`accountId`, `field`) USING BTREE,
INDEX `idx_wechat_id`(`wechatId`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信账号健康分加减分日志' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 39 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信账号健康分加减分日志' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for s2_wechat_chatroom
@@ -2211,6 +2336,8 @@ CREATE TABLE `s2_wechat_chatroom` (
`accountNickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '账号昵称',
`groupId` int(11) NULL DEFAULT 0 COMMENT '分组ID',
`updateTime` int(11) NULL DEFAULT NULL COMMENT '更新时间',
`isTop` tinyint(2) NULL DEFAULT 0 COMMENT '是否置顶',
`groupIds` int(11) NULL DEFAULT 0 COMMENT '新分组ID',
UNIQUE INDEX `uk_chatroom_account`(`chatroomId`, `wechatAccountId`) USING BTREE,
INDEX `wechatAccountId`(`wechatAccountId`) USING BTREE,
INDEX `chatroomId`(`chatroomId`) USING BTREE,
@@ -2237,7 +2364,7 @@ CREATE TABLE `s2_wechat_chatroom_member` (
UNIQUE INDEX `uk_chatroom_wechat`(`chatroomId`, `wechatId`) USING BTREE,
INDEX `chatroomId`(`chatroomId`) USING BTREE,
INDEX `wechatId`(`wechatId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 495174 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信群成员表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 496929 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信群成员表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for s2_wechat_friend
@@ -2288,6 +2415,8 @@ CREATE TABLE `s2_wechat_friend` (
`realName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名',
`company` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '公司',
`position` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '职位',
`isTop` tinyint(2) NULL DEFAULT 0 COMMENT '是否置顶',
`groupIds` int(11) NULL DEFAULT 0 COMMENT '新分组ID',
UNIQUE INDEX `uk_owner_wechat_account`(`ownerWechatId`, `wechatId`, `wechatAccountId`) USING BTREE,
INDEX `idx_wechat_account_id`(`wechatAccountId`) USING BTREE,
INDEX `idx_wechat_id`(`wechatId`) USING BTREE,
@@ -2310,6 +2439,8 @@ CREATE TABLE `s2_wechat_group` (
`departmentId` int(11) NULL DEFAULT NULL,
`accountId` int(11) NULL DEFAULT NULL,
`createTime` int(11) NULL DEFAULT NULL,
`isDel` tinyint(1) NULL DEFAULT 0 COMMENT '是否删除 0未删除 1已删除',
`deleteTime` int(11) NULL DEFAULT NULL COMMENT '删除时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
@@ -2387,6 +2518,6 @@ CREATE TABLE `s2_wechat_moments` (
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `idx_sns_account`(`snsId`, `wechatAccountId`) USING BTREE,
INDEX `idx_account_friend`(`wechatAccountId`, `wechatFriendId`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 40130 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信朋友圈数据表' ROW_FORMAT = Dynamic;
) ENGINE = InnoDB AUTO_INCREMENT = 40159 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '微信朋友圈数据表' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;