私域操盘手模块调整
This commit is contained in:
49
Server/application/cunkebao/config/route.php
Normal file
49
Server/application/cunkebao/config/route.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 设备管理模块路由配置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
use think\facade\Route;
|
||||
|
||||
// 定义RESTful风格的API路由
|
||||
Route::group('v1/', function () {
|
||||
|
||||
// 设备管理相关
|
||||
Route::group('devices', function () {
|
||||
Route::get(':id/related-accounts', 'app\\cunkebao\\controller\\Device@getRelatedAccounts'); // 设备关联微信账号路由
|
||||
Route::get(':id/handle-logs', 'app\\cunkebao\\controller\\Device@handleLogs'); // 获取设备操作记录
|
||||
Route::get('', 'app\\cunkebao\\controller\\Device@index'); // 获取设备列表
|
||||
Route::get('count', 'app\\cunkebao\\controller\\Device@count'); // 获取设备总数
|
||||
Route::get(':id', 'app\\cunkebao\\controller\\Device@read'); // 获取设备详情
|
||||
Route::post('', 'app\\cunkebao\\controller\\Device@save'); // 添加设备
|
||||
Route::put('refresh', 'app\\cunkebao\\controller\\Device@refresh'); // 刷新设备状态
|
||||
Route::delete(':id', 'app\\cunkebao\\controller\\Device@delete'); // 删除设备
|
||||
Route::post('task-config', 'app\\cunkebao\\controller\\Device@updateTaskConfig'); // 更新设备任务配置
|
||||
});
|
||||
|
||||
// 设备微信相关
|
||||
Route::group('device/wechats', function () {
|
||||
Route::get('friends', 'app\\cunkebao\\controller\\DeviceWechat@getFriends'); // 获取微信好友列表
|
||||
Route::get('count', 'app\\cunkebao\\controller\\DeviceWechat@count'); // 获取在线微信账号数量
|
||||
Route::get('device-count', 'app\\cunkebao\\controller\\DeviceWechat@deviceCount'); // 获取有登录微信的设备数量
|
||||
Route::get('', 'app\\cunkebao\\controller\\DeviceWechat@index'); // 获取在线微信账号列表
|
||||
Route::get(':id', 'app\\cunkebao\\controller\\DeviceWechat@detail'); // 获取微信号详情
|
||||
Route::put('refresh', 'app\\cunkebao\\controller\\DeviceWechat@refresh'); // 刷新设备微信状态
|
||||
Route::post('transfer-friends', 'app\\cunkebao\\controller\\DeviceWechat@transferFriends'); // 微信好友转移
|
||||
});
|
||||
|
||||
// 获客场景相关
|
||||
Route::group('plan/scenes', function () {
|
||||
Route::get('', 'app\\cunkebao\\controller\\Scene@index'); // 获取场景列表
|
||||
});
|
||||
|
||||
// 流量标签相关
|
||||
Route::group('traffic/tags', function () {
|
||||
Route::get('', 'app\\cunkebao\\controller\\TrafficTag@index'); // 获取标签列表
|
||||
});
|
||||
|
||||
// 流量池相关
|
||||
Route::group('traffic/pool', function () {
|
||||
Route::post('import', 'app\\cunkebao\\controller\\TrafficPool@importOrders'); // 导入订单标签
|
||||
});
|
||||
})->middleware(['jwt']);
|
||||
681
Server/application/cunkebao/controller/Device.php
Normal file
681
Server/application/cunkebao/controller/Device.php
Normal file
@@ -0,0 +1,681 @@
|
||||
<?php
|
||||
namespace app\cunkebao\controller;
|
||||
|
||||
use app\cunkebao\model\DeviceHandleLog;
|
||||
use app\cunkebao\model\DeviceWechatLogin;
|
||||
use think\Controller;
|
||||
use app\cunkebao\model\Device as DeviceModel;
|
||||
use think\Db;
|
||||
use think\facade\Request;
|
||||
|
||||
/**
|
||||
* 设备管理控制器
|
||||
*/
|
||||
class Device extends Controller
|
||||
{
|
||||
/**
|
||||
* 用户信息
|
||||
* @var object
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
// 设置时区
|
||||
date_default_timezone_set('Asia/Shanghai');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备总数
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
try {
|
||||
// 获取登录用户信息
|
||||
$userInfo = request()->userInfo;
|
||||
if (empty($userInfo)) {
|
||||
return json([
|
||||
'code' => 401,
|
||||
'msg' => '未登录或登录已过期'
|
||||
]);
|
||||
}
|
||||
|
||||
// 获取查询条件
|
||||
$where = [];
|
||||
|
||||
// 租户ID / 公司ID
|
||||
$where['companyId'] = $userInfo['companyId'];
|
||||
|
||||
// 设备在线状态
|
||||
$alive = Request::param('alive');
|
||||
if (is_numeric($alive)) {
|
||||
$where['alive'] = $alive;
|
||||
}
|
||||
|
||||
// 根据用户管理员状态调整查询条件
|
||||
if ($userInfo['isAdmin'] == 1) {
|
||||
// 管理员直接查询所有设备
|
||||
$count = DeviceModel::getDeviceCount($where);
|
||||
} else {
|
||||
// 非管理员需要查询关联表
|
||||
$deviceIds = \app\common\model\DeviceUser::getUserDeviceIds(
|
||||
$userInfo['id'],
|
||||
$userInfo['companyId']
|
||||
);
|
||||
|
||||
if (empty($deviceIds)) {
|
||||
return json([
|
||||
'code' => 403,
|
||||
'msg' => '请联系管理员绑定设备',
|
||||
'data' => [
|
||||
'count' => 0
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
// 添加设备ID过滤条件
|
||||
$where['id'] = ['in', $deviceIds];
|
||||
$count = DeviceModel::getDeviceCount($where);
|
||||
}
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'count' => $count
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备列表
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
try {
|
||||
// 获取登录用户信息
|
||||
$userInfo = request()->userInfo;
|
||||
// 获取查询条件
|
||||
$where = [];
|
||||
|
||||
// 关键词搜索(同时搜索IMEI和备注)
|
||||
$keyword = Request::param('keyword');
|
||||
if (!empty($keyword)) {
|
||||
// 使用复杂条件实现OR查询
|
||||
$where[] = ['exp', "d.imei LIKE '%{$keyword}%' OR d.memo LIKE '%{$keyword}%'"];
|
||||
}
|
||||
|
||||
// 设备在线状态
|
||||
$alive = Request::param('alive');
|
||||
if (is_numeric($alive)) {
|
||||
$where['d.alive'] = $alive;
|
||||
}
|
||||
|
||||
// 获取分页参数
|
||||
$page = (int)Request::param('page', 1);
|
||||
$limit = (int)Request::param('limit', 10);
|
||||
|
||||
// 获取排序参数
|
||||
$sort = Request::param('sort', 'd.id');
|
||||
$order = Request::param('order', 'desc');
|
||||
|
||||
// 添加公司ID过滤条件
|
||||
$where['d.companyId'] = $userInfo['companyId'];
|
||||
|
||||
// 根据用户管理员状态调整查询条件
|
||||
if ($userInfo['isAdmin'] == 1) {
|
||||
// 管理员直接查询所有设备
|
||||
$list = DeviceModel::getDeviceList($where, "{$sort} {$order}", $page, $limit);
|
||||
} else {
|
||||
// 非管理员需要查询关联表
|
||||
$deviceIds = \app\common\model\DeviceUser::getUserDeviceIds(
|
||||
$userInfo['id'],
|
||||
$userInfo['companyId']
|
||||
);
|
||||
|
||||
if (empty($deviceIds)) {
|
||||
return json([
|
||||
'code' => 403,
|
||||
'msg' => '请联系管理员绑定设备'
|
||||
]);
|
||||
}
|
||||
|
||||
// 添加设备ID过滤条件
|
||||
$where['d.id'] = ['in', $deviceIds];
|
||||
$list = DeviceModel::getDeviceList($where, "{$sort} {$order}", $page, $limit);
|
||||
}
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'total' => $list->total(),
|
||||
'list' => $list->items()
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备详情
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function read()
|
||||
{
|
||||
try {
|
||||
// 获取登录用户信息
|
||||
$userInfo = request()->userInfo;
|
||||
|
||||
// 获取设备ID
|
||||
$id = Request::param('id/d');
|
||||
if (empty($id)) {
|
||||
return json([
|
||||
'code' => 400,
|
||||
'msg' => '参数错误'
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查用户权限
|
||||
if ($userInfo['isAdmin'] != 1) {
|
||||
// 非管理员需要检查是否有权限访问该设备
|
||||
$hasPermission = \app\common\model\DeviceUser::checkUserDevicePermission(
|
||||
$userInfo['id'],
|
||||
$id,
|
||||
$userInfo['companyId']
|
||||
);
|
||||
|
||||
if (!$hasPermission) {
|
||||
return json([
|
||||
'code' => 403,
|
||||
'msg' => '您没有权限查看该设备'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取设备详情
|
||||
$info = DeviceModel::getDeviceInfo($id);
|
||||
if (empty($info)) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '设备不存在'
|
||||
]);
|
||||
}
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => $info
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新设备
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function refresh()
|
||||
{
|
||||
try {
|
||||
// 获取登录用户信息
|
||||
$userInfo = request()->userInfo;
|
||||
if (empty($userInfo)) {
|
||||
return json([
|
||||
'code' => 401,
|
||||
'msg' => '未登录或登录已过期'
|
||||
]);
|
||||
}
|
||||
|
||||
// 执行刷新逻辑
|
||||
// TODO: 实现实际刷新设备状态的功能
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '刷新成功',
|
||||
'data' => []
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加设备
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
try {
|
||||
// 获取登录用户信息
|
||||
$userInfo = request()->userInfo;
|
||||
|
||||
// 检查用户权限,只有管理员可以添加设备
|
||||
if ($userInfo['isAdmin'] != 1) {
|
||||
return json([
|
||||
'code' => 403,
|
||||
'msg' => '您没有权限添加设备'
|
||||
]);
|
||||
}
|
||||
|
||||
// 获取设备数据
|
||||
$data = Request::post();
|
||||
|
||||
// 验证IMEI是否为空
|
||||
if (empty($data['imei'])) {
|
||||
return json([
|
||||
'code' => 400,
|
||||
'msg' => '设备IMEI不能为空'
|
||||
]);
|
||||
}
|
||||
|
||||
// 验证IMEI是否已存在
|
||||
$exists = DeviceModel::where('imei', $data['imei'])->where('isDeleted', 0)->find();
|
||||
|
||||
if ($exists) {
|
||||
return json([
|
||||
'code' => 400,
|
||||
'msg' => '设备IMEI已存在'
|
||||
]);
|
||||
}
|
||||
|
||||
// 设置设备公司ID
|
||||
$data['companyId'] = $userInfo['companyId'];
|
||||
$data['id'] = time();
|
||||
|
||||
try {
|
||||
Db::startTrans();
|
||||
|
||||
// 添加设备
|
||||
$id = DeviceModel::addDevice($data);
|
||||
|
||||
// 添加设备操作记录
|
||||
DeviceHandleLog::addLog(
|
||||
[
|
||||
'imei' => $data['imei'],
|
||||
'userId' => $userInfo['id'],
|
||||
'content' => '添加设备',
|
||||
'companyId' => $userInfo['companyId'],
|
||||
]
|
||||
);
|
||||
Db::commit();
|
||||
} catch (\Exception $e) {
|
||||
Db::rollback();
|
||||
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '添加失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
|
||||
// 此处调用底层API
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '添加成功',
|
||||
'data' => [
|
||||
'id' => $id
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '添加失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设备
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
try {
|
||||
// 获取登录用户信息
|
||||
$userInfo = request()->userInfo;
|
||||
|
||||
// 检查用户权限,只有管理员可以删除设备
|
||||
if ($userInfo['isAdmin'] != 1) {
|
||||
return json([
|
||||
'code' => 403,
|
||||
'msg' => '您没有权限删除设备'
|
||||
]);
|
||||
}
|
||||
|
||||
// 获取设备ID
|
||||
$id = Request::param('id/d');
|
||||
if (empty($id)) {
|
||||
return json([
|
||||
'code' => 400,
|
||||
'msg' => '参数错误'
|
||||
]);
|
||||
}
|
||||
|
||||
// 验证设备是否存在
|
||||
$exists = DeviceModel::where('id', $id)
|
||||
->where('isDeleted', 0)
|
||||
->where('companyId', $userInfo['companyId'])
|
||||
->find();
|
||||
|
||||
if (!$exists) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '设备不存在或无权限操作'
|
||||
]);
|
||||
}
|
||||
|
||||
// 删除设备
|
||||
$result = DeviceModel::deleteDevice($id);
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '删除成功',
|
||||
'data' => [
|
||||
'result' => $result
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '删除失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备任务配置
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function updateTaskConfig()
|
||||
{
|
||||
// 获取请求参数
|
||||
$data = $this->request->post();
|
||||
|
||||
// 获取登录用户信息
|
||||
$userInfo = request()->userInfo;
|
||||
|
||||
// 验证参数
|
||||
if (empty($data['id'])) {
|
||||
return json(['code' => 400, 'msg' => '设备ID不能为空']);
|
||||
}
|
||||
|
||||
// 转换为整型,确保ID格式正确
|
||||
$deviceId = intval($data['id']);
|
||||
|
||||
// 先获取设备信息,确认设备存在且未删除
|
||||
$device = DeviceModel::where('id', $deviceId)
|
||||
->where('isDeleted', 0)
|
||||
->find();
|
||||
|
||||
if (!$device) {
|
||||
return json(['code' => 404, 'msg' => '设备不存在或已删除']);
|
||||
}
|
||||
|
||||
// 读取原taskConfig,如果存在则解析
|
||||
$taskConfig = [];
|
||||
if (!empty($device['taskConfig'])) {
|
||||
$taskConfig = json_decode($device['taskConfig'], true) ?: [];
|
||||
}
|
||||
|
||||
// 更新需要修改的配置项
|
||||
$updateFields = ['autoAddFriend', 'autoReply', 'momentsSync', 'aiChat'];
|
||||
$hasUpdate = false;
|
||||
|
||||
foreach ($updateFields as $field) {
|
||||
if (isset($data[$field])) {
|
||||
// 将值转换为布尔类型存储
|
||||
$taskConfig[$field] = (bool)$data[$field];
|
||||
$hasUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有需要更新的字段,直接返回成功
|
||||
if (!$hasUpdate) {
|
||||
return json(['code' => 200, 'msg' => '更新成功', 'data' => ['taskConfig' => $taskConfig]]);
|
||||
}
|
||||
|
||||
try {
|
||||
Db::startTrans();
|
||||
|
||||
// 更新设备taskConfig字段
|
||||
$result = DeviceModel::where('id', $deviceId)
|
||||
->update([
|
||||
'taskConfig' => json_encode($taskConfig),
|
||||
'updateTime' => time()
|
||||
]);
|
||||
|
||||
if (isset($data['autoAddFriend'])) {
|
||||
$content = $data['autoAddFriend'] ? '开启自动添加好友' : '关闭自动添加好友';
|
||||
}
|
||||
|
||||
if (isset($data['autoReply'])) {
|
||||
$content = $data['autoReply'] ? '开启自动回复' : '关闭自动回复';
|
||||
}
|
||||
|
||||
if (isset($data['momentsSync'])) {
|
||||
$content = $data['momentsSync'] ? '开启朋友圈同步' : '关闭朋友圈同步';
|
||||
}
|
||||
|
||||
if (isset($data['aiChat'])) {
|
||||
$content = $data['aiChat'] ? '开启AI会话' : '关闭AI会话';
|
||||
}
|
||||
|
||||
// 添加设备操作记录
|
||||
DeviceHandleLog::addLog(
|
||||
[
|
||||
'imei' => $device['imei'],
|
||||
'deviceId' => $deviceId,
|
||||
'userId' => $userInfo['id'],
|
||||
'content' => $content,
|
||||
'companyId' => $userInfo['companyId'],
|
||||
]
|
||||
);
|
||||
Db::commit();
|
||||
} catch (\Exception $e) {
|
||||
Db::rollback();
|
||||
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '更新任务配置失败'
|
||||
]);
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '更新任务配置成功',
|
||||
'data' => [
|
||||
'taskConfig' => $taskConfig
|
||||
]
|
||||
]);
|
||||
} else {
|
||||
return json(['code' => 500, 'msg' => '更新任务配置失败']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备关联的微信账号
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function getRelatedAccounts()
|
||||
{
|
||||
try {
|
||||
// 获取登录用户信息
|
||||
$userInfo = request()->userInfo;
|
||||
|
||||
// 获取设备ID
|
||||
$deviceId = $this->request->param('id/d');
|
||||
if (empty($deviceId)) {
|
||||
return json([
|
||||
'code' => 400,
|
||||
'msg' => '设备ID不能为空'
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查用户是否有权限访问该设备
|
||||
if ($userInfo['isAdmin'] != 1) {
|
||||
// 非管理员需要检查是否有权限访问该设备
|
||||
$hasPermission = \app\common\model\DeviceUser::checkUserDevicePermission(
|
||||
$userInfo['id'],
|
||||
$deviceId,
|
||||
$userInfo['companyId']
|
||||
);
|
||||
|
||||
if (!$hasPermission) {
|
||||
return json([
|
||||
'code' => 403,
|
||||
'msg' => '您没有权限查看该设备'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取设备信息,确认设备存在
|
||||
$device = DeviceModel::where('id', $deviceId)
|
||||
->where('isDeleted', 0)
|
||||
->find();
|
||||
|
||||
if (!$device) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '设备不存在或已删除'
|
||||
]);
|
||||
}
|
||||
|
||||
// 获取设备关联的微信账号
|
||||
$wechatAccounts = DeviceWechatLogin::getDeviceRelatedAccounts($deviceId, $userInfo['companyId']);
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'deviceId' => $deviceId,
|
||||
'accounts' => $wechatAccounts,
|
||||
'total' => count($wechatAccounts)
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备操作记录
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function handleLogs()
|
||||
{
|
||||
try {
|
||||
// 获取登录用户信息
|
||||
$userInfo = request()->userInfo;
|
||||
|
||||
// 获取设备ID
|
||||
$deviceId = $this->request->param('id/d');
|
||||
if (empty($deviceId)) {
|
||||
return json([
|
||||
'code' => 400,
|
||||
'msg' => '设备ID不能为空'
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查用户是否有权限访问该设备
|
||||
if ($userInfo['isAdmin'] != 1) {
|
||||
// 非管理员需要检查是否有权限访问该设备
|
||||
$hasPermission = \app\common\model\DeviceUser::checkUserDevicePermission(
|
||||
$userInfo['id'],
|
||||
$deviceId,
|
||||
$userInfo['companyId']
|
||||
);
|
||||
|
||||
if (!$hasPermission) {
|
||||
return json([
|
||||
'code' => 403,
|
||||
'msg' => '您没有权限查看该设备'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取设备信息,确认设备存在
|
||||
$device = DeviceModel::where('id', $deviceId)
|
||||
->where('isDeleted', 0)
|
||||
->find();
|
||||
|
||||
if (!$device) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '设备不存在或已删除'
|
||||
]);
|
||||
}
|
||||
|
||||
// 获取分页参数
|
||||
$page = (int)Request::param('page', 1);
|
||||
$limit = (int)Request::param('limit', 10);
|
||||
|
||||
// 查询设备操作记录,并关联用户表获取操作人信息
|
||||
$logs = Db::table('tk_device_handle_log')
|
||||
->alias('l')
|
||||
->join('tk_users u', 'l.userId = u.id', 'left')
|
||||
->where('l.imei', $device['imei'])
|
||||
->where('l.companyId', $userInfo['companyId'])
|
||||
->field([
|
||||
'l.id',
|
||||
'l.content',
|
||||
'l.createTime',
|
||||
'u.username'
|
||||
])
|
||||
->order('l.createTime desc')
|
||||
->paginate($limit, false, ['page' => $page]);
|
||||
|
||||
// 格式化返回数据
|
||||
$items = [];
|
||||
foreach ($logs as $log) {
|
||||
$items[] = [
|
||||
'id' => $log['id'],
|
||||
'content' => $log['content'],
|
||||
'username' => $log['username'] ? $log['username'] : '未知用户',
|
||||
'createTime' => $log['createTime']
|
||||
];
|
||||
}
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'total' => $logs->total(),
|
||||
'list' => $items
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
581
Server/application/cunkebao/controller/DeviceWechat.php
Normal file
581
Server/application/cunkebao/controller/DeviceWechat.php
Normal file
@@ -0,0 +1,581 @@
|
||||
<?php
|
||||
namespace app\cunkebao\controller;
|
||||
|
||||
use app\common\model\CompanyAccount;
|
||||
use app\cunkebao\model\WechatFriend;
|
||||
use think\Controller;
|
||||
use app\cunkebao\model\WechatAccount;
|
||||
use think\facade\Request;
|
||||
use think\Db;
|
||||
|
||||
/**
|
||||
* 设备微信控制器
|
||||
*/
|
||||
class DeviceWechat extends Controller
|
||||
{
|
||||
/**
|
||||
* 获取在线微信账号数量
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
try {
|
||||
// 获取在线微信账号数量
|
||||
$count = WechatAccount::getOnlineWechatCount();
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'count' => $count
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取有登录微信的设备数量
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function deviceCount()
|
||||
{
|
||||
try {
|
||||
// 获取有登录微信的设备数量
|
||||
$count = WechatAccount::getDeviceWithWechatCount();
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'count' => $count
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新设备微信状态
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function refresh()
|
||||
{
|
||||
try {
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '刷新成功',
|
||||
'data' => []
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取在线微信账号列表
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
try {
|
||||
// 获取登录用户信息
|
||||
$userInfo = request()->userInfo;
|
||||
// 获取查询条件
|
||||
$where = [];
|
||||
|
||||
// 微信ID
|
||||
$wechatId = Request::param('wechat_id');
|
||||
if (!empty($wechatId)) {
|
||||
$where['wechatId'] = ['like', "%{$wechatId}%"];
|
||||
}
|
||||
|
||||
// 昵称
|
||||
$nickname = Request::param('nickname');
|
||||
if (!empty($nickname)) {
|
||||
$where['nickname|accountNickname'] = ['like', "%{$nickname}%"];
|
||||
}
|
||||
|
||||
// 获取分页参数
|
||||
$page = (int)Request::param('page', 1);
|
||||
$limit = (int)Request::param('limit', 10);
|
||||
|
||||
// 获取排序参数
|
||||
$sort = Request::param('sort', 'id');
|
||||
$order = Request::param('order', 'desc');
|
||||
|
||||
// 公司账户表没有 companyId,需要转换一下
|
||||
$acountInfo = CompanyAccount::getAccountByCompanyId($userInfo['companyId']);
|
||||
|
||||
// 先用账号进行查询
|
||||
$where['accountUserName'] = $acountInfo['userName'];
|
||||
|
||||
// 根据用户权限不同实现不同的查询逻辑
|
||||
if ($userInfo['isAdmin'] == 1) {
|
||||
// 管理员直接查询tk_wechat_account表
|
||||
$list = WechatAccount::getOnlineWechatList($where, "{$sort} {$order}", $page, $limit);
|
||||
} else {
|
||||
// 非管理员先查询tk_device_user表
|
||||
$deviceIds = Db::table('tk_device_user')
|
||||
->where('companyId', $userInfo['companyId'])
|
||||
->where('userId', $userInfo['id'])
|
||||
->column('deviceId');
|
||||
|
||||
if (empty($deviceIds)) {
|
||||
// 如果没有绑定设备,返回提示信息
|
||||
return json([
|
||||
'code' => 403,
|
||||
'msg' => '请联系管理员绑定设备微信',
|
||||
'data' => [
|
||||
'total' => 0,
|
||||
'list' => []
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
// 获取这些设备关联的微信ID
|
||||
$wechatIds = Db::table('tk_device_wechat_login')
|
||||
->where('companyId', $userInfo['companyId'])
|
||||
->whereIn('deviceId', $deviceIds)
|
||||
->column('wechatId');
|
||||
|
||||
if (empty($wechatIds)) {
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'total' => 0,
|
||||
'list' => []
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
// 将微信ID添加到查询条件中
|
||||
$where['id'] = ['in', $wechatIds];
|
||||
|
||||
// 查询微信账号
|
||||
$list = WechatAccount::getOnlineWechatList($where, "{$sort} {$order}", $page, $limit);
|
||||
}
|
||||
|
||||
// 处理返回数据
|
||||
$data = [];
|
||||
foreach ($list->items() as $item) {
|
||||
// 计算今日可添加好友数量(这里使用一个示例算法,你可以根据实际需求修改)
|
||||
$canAddFriendCount = 20 - Db::table('tk_friend_task')->where('wechatId', $item['wechatId'])->count('*');
|
||||
if ($canAddFriendCount < 0) {
|
||||
$canAddFriendCount = 0;
|
||||
}
|
||||
|
||||
// 计算今日新增好友数量(示例数据,实际需要从数据库获取或通过其他方式计算)
|
||||
// 这里只是一个示例,你需要根据实际情况替换
|
||||
$todayNewFriendCount = Db::table('tk_friend_task')->where('wechatId', $item['wechatId'])
|
||||
->where('status', 3)
|
||||
->count('*');
|
||||
|
||||
$data[] = [
|
||||
'id' => $item['id'],
|
||||
'wechatId' => $item['wechatId'],
|
||||
'nickname' => $item['nickname'] ?: $item['accountNickname'],
|
||||
'avatar' => $item['avatar'],
|
||||
'accountUserName' => $item['accountUserName'],
|
||||
'status' => $item['wechatAlive'] ? '在线' : '离线',
|
||||
'deviceStatus' => $item['deviceAlive'] ? '在线' : '离线',
|
||||
'totalFriend' => $item['totalFriend'],
|
||||
'canAddFriendCount' => $canAddFriendCount,
|
||||
'deviceInfo' => $item['imei'] . ($item['deviceMemo'] ? " ({$item['deviceMemo']})" : ''),
|
||||
'todayNewFriendCount' => $todayNewFriendCount
|
||||
];
|
||||
}
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'total' => $list->total(),
|
||||
'list' => $data
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信号详情
|
||||
* @param int $id 微信号ID
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function detail($id)
|
||||
{
|
||||
try {
|
||||
// 获取微信号基本信息
|
||||
$wechat = WechatAccount::where('id', $id)
|
||||
->where('isDeleted', 0)
|
||||
->find();
|
||||
|
||||
if (!$wechat) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '微信号不存在'
|
||||
]);
|
||||
}
|
||||
|
||||
// 计算账号年龄(从创建时间到现在)
|
||||
$accountAge = 0;
|
||||
if ($wechat['createTime']) {
|
||||
$createTime = strtotime($wechat['createTime']);
|
||||
$now = time();
|
||||
$accountAge = floor(($now - $createTime) / (24 * 3600));
|
||||
}
|
||||
|
||||
// 计算活跃程度(根据消息数)
|
||||
$activityLevel = '低';
|
||||
if ($wechat['thirtyDayMsgCount'] > 1000) {
|
||||
$activityLevel = '高';
|
||||
} elseif ($wechat['thirtyDayMsgCount'] > 500) {
|
||||
$activityLevel = '中';
|
||||
}
|
||||
|
||||
// 评估账号权重(示例算法)
|
||||
$weight = 0;
|
||||
// 基础权重
|
||||
$weight += 10;
|
||||
// 好友数量权重
|
||||
$weight += min($wechat['totalFriend'] / 100, 20);
|
||||
// 活跃度权重
|
||||
$weight += min($wechat['thirtyDayMsgCount'] / 100, 20);
|
||||
// 账号年龄权重
|
||||
$weight += min($accountAge / 30, 10);
|
||||
// 在线状态权重
|
||||
if ($wechat['wechatAlive']) {
|
||||
$weight += 5;
|
||||
}
|
||||
|
||||
// 获取限制记录(示例数据,实际需要从数据库获取)
|
||||
$restrictions = [
|
||||
[
|
||||
'type' => '添加好友限制',
|
||||
'reason' => '频繁添加好友',
|
||||
'startTime' => date('Y-m-d H:i:s', strtotime('-1 day')),
|
||||
'endTime' => date('Y-m-d H:i:s', strtotime('+1 day'))
|
||||
]
|
||||
];
|
||||
|
||||
// 处理返回数据
|
||||
$data = [
|
||||
'basicInfo' => [
|
||||
'id' => $wechat['id'],
|
||||
'wechatId' => $wechat['wechatId'],
|
||||
'nickname' => $wechat['nickname'] ?: $wechat['accountNickname'],
|
||||
'avatar' => $wechat['avatar'],
|
||||
'status' => $wechat['wechatAlive'] ? '在线' : '离线',
|
||||
'deviceStatus' => $wechat['deviceAlive'] ? '在线' : '离线',
|
||||
'deviceInfo' => $wechat['imei'] . ($wechat['deviceMemo'] ? " ({$wechat['deviceMemo']})" : ''),
|
||||
'gender' => $wechat['gender'],
|
||||
'region' => $wechat['region'],
|
||||
'signature' => $wechat['signature']
|
||||
],
|
||||
'statistics' => [
|
||||
'totalFriend' => $wechat['totalFriend'],
|
||||
'maleFriend' => $wechat['maleFriend'],
|
||||
'femaleFriend' => $wechat['femaleFriend'],
|
||||
'canAddFriendCount' => 30 - (isset($wechat['yesterdayMsgCount']) ? intval($wechat['yesterdayMsgCount']) : 0),
|
||||
'yesterdayMsgCount' => $wechat['yesterdayMsgCount'],
|
||||
'sevenDayMsgCount' => $wechat['sevenDayMsgCount'],
|
||||
'thirtyDayMsgCount' => $wechat['thirtyDayMsgCount']
|
||||
],
|
||||
'accountInfo' => [
|
||||
'age' => $accountAge,
|
||||
'activityLevel' => $activityLevel,
|
||||
'weight' => round($weight, 2),
|
||||
'createTime' => $wechat['createTime'],
|
||||
'lastUpdateTime' => $wechat['updateTime']
|
||||
],
|
||||
'restrictions' => $restrictions,
|
||||
];
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => $data
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信好友转移
|
||||
* 将一个微信号的好友转移至另一个在线微信号
|
||||
*
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function transferFriends()
|
||||
{
|
||||
try {
|
||||
// 获取请求参数
|
||||
$sourceWechatId = Request::param('source_id'); // 源微信账号ID
|
||||
$targetWechatId = Request::param('target_id'); // 目标微信账号ID
|
||||
|
||||
// 参数验证
|
||||
if (empty($sourceWechatId) || empty($targetWechatId)) {
|
||||
return json([
|
||||
'code' => 400,
|
||||
'msg' => '参数错误:源微信账号ID和目标微信账号ID不能为空'
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查源微信账号是否存在
|
||||
$sourceWechat = WechatAccount::where('id', $sourceWechatId)
|
||||
->where('isDeleted', 0)
|
||||
->find();
|
||||
|
||||
if (!$sourceWechat) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '源微信账号不存在'
|
||||
]);
|
||||
}
|
||||
|
||||
// 检查目标微信账号是否存在且在线
|
||||
$targetWechat = WechatAccount::where('id', $targetWechatId)
|
||||
->where('isDeleted', 0)
|
||||
->where('wechatAlive', 1)
|
||||
->where('deviceAlive', 1)
|
||||
->find();
|
||||
|
||||
if (!$targetWechat) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '目标微信账号不存在或不在线'
|
||||
]);
|
||||
}
|
||||
|
||||
// 获取源微信账号的好友列表
|
||||
$friends = Db::table('tk_wechat_friend')
|
||||
->where('wechatAccountId', $sourceWechatId)
|
||||
->where('isDeleted', 0)
|
||||
->select();
|
||||
|
||||
// 统计好友数量
|
||||
$totalFriends = count($friends);
|
||||
|
||||
if ($totalFriends == 0) {
|
||||
return json([
|
||||
'code' => 400,
|
||||
'msg' => '源微信账号没有可转移的好友'
|
||||
]);
|
||||
}
|
||||
|
||||
// 开始事务
|
||||
Db::startTrans();
|
||||
|
||||
try {
|
||||
$successCount = 0;
|
||||
$failCount = 0;
|
||||
$duplicateCount = 0;
|
||||
$failList = [];
|
||||
|
||||
foreach ($friends as $friend) {
|
||||
// 检查目标微信账号是否已经有此好友
|
||||
$existFriend = Db::table('tk_wechat_friend')
|
||||
->where('wechatAccountId', $targetWechatId)
|
||||
->where('wechatId', $friend['wechatId'])
|
||||
->where('isDeleted', 0)
|
||||
->find();
|
||||
|
||||
if ($existFriend) {
|
||||
// 已经存在此好友,跳过
|
||||
$duplicateCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 准备插入数据
|
||||
$newFriend = [
|
||||
'wechatAccountId' => $targetWechatId,
|
||||
'alias' => $friend['alias'],
|
||||
'wechatId' => $friend['wechatId'],
|
||||
'conRemark' => $friend['conRemark'],
|
||||
'nickname' => $friend['nickname'],
|
||||
'pyInitial' => $friend['pyInitial'],
|
||||
'quanPin' => $friend['quanPin'],
|
||||
'avatar' => $friend['avatar'],
|
||||
'gender' => $friend['gender'],
|
||||
'region' => $friend['region'],
|
||||
'addFrom' => $friend['addFrom'],
|
||||
'labels' => $friend['labels'],
|
||||
'signature' => $friend['signature'],
|
||||
'isDeleted' => 0,
|
||||
'isPassed' => $friend['isPassed'],
|
||||
'accountId' => $friend['accountId'],
|
||||
'extendFields' => $friend['extendFields'],
|
||||
'accountUserName' => $friend['accountUserName'],
|
||||
'accountRealName' => $friend['accountRealName'],
|
||||
'accountNickname' => $friend['accountNickname'],
|
||||
'ownerAlias' => $targetWechat['alias'],
|
||||
'ownerWechatId' => $targetWechat['wechatId'],
|
||||
'ownerNickname' => $targetWechat['nickname'] ?: $targetWechat['accountNickname'],
|
||||
'ownerAvatar' => $targetWechat['avatar'],
|
||||
'phone' => $friend['phone'],
|
||||
'thirdParty' => $friend['thirdParty'],
|
||||
'groupId' => $friend['groupId'],
|
||||
'passTime' => $friend['passTime'],
|
||||
'additionalPicture' => $friend['additionalPicture'],
|
||||
'desc' => $friend['desc'],
|
||||
'country' => $friend['country'],
|
||||
'province' => $friend['province'],
|
||||
'city' => $friend['city'],
|
||||
'createTime' => date('Y-m-d H:i:s'),
|
||||
'updateTime' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
// 插入新好友记录
|
||||
$result = Db::table('tk_wechat_friend')->insert($newFriend);
|
||||
|
||||
if ($result) {
|
||||
$successCount++;
|
||||
} else {
|
||||
$failCount++;
|
||||
$failList[] = [
|
||||
'id' => $friend['id'],
|
||||
'wechatId' => $friend['wechatId'],
|
||||
'nickname' => $friend['nickname']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// 更新两个微信账号的好友数量
|
||||
$maleFriendsCount = Db::table('tk_wechat_friend')
|
||||
->where('wechatAccountId', $targetWechatId)
|
||||
->where('isDeleted', 0)
|
||||
->where('gender', 1)
|
||||
->count();
|
||||
|
||||
$femaleFriendsCount = Db::table('tk_wechat_friend')
|
||||
->where('wechatAccountId', $targetWechatId)
|
||||
->where('isDeleted', 0)
|
||||
->where('gender', 2)
|
||||
->count();
|
||||
|
||||
$totalFriendsCount = $maleFriendsCount + $femaleFriendsCount;
|
||||
|
||||
// 更新目标微信账号的好友数量
|
||||
WechatAccount::where('id', $targetWechatId)
|
||||
->update([
|
||||
'totalFriend' => $totalFriendsCount,
|
||||
'maleFriend' => $maleFriendsCount,
|
||||
'femaleFriend' => $femaleFriendsCount,
|
||||
'updateTime' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
|
||||
// 提交事务
|
||||
Db::commit();
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '好友转移成功',
|
||||
'data' => [
|
||||
'total' => $totalFriends,
|
||||
'success' => $successCount,
|
||||
'fail' => $failCount,
|
||||
'duplicate' => $duplicateCount,
|
||||
'failList' => $failList
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
// 回滚事务
|
||||
Db::rollback();
|
||||
throw $e;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '好友转移失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信好友列表
|
||||
* 根据wechatId查询微信好友,支持分页和关键词筛选
|
||||
*
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function getFriends()
|
||||
{
|
||||
try {
|
||||
// 获取请求参数
|
||||
$wechatId = Request::param('wechatId');
|
||||
$page = (int)Request::param('page', 1);
|
||||
$limit = (int)Request::param('limit', 20);
|
||||
$keyword = Request::param('keyword', '');
|
||||
|
||||
// 参数验证
|
||||
if (empty($wechatId)) {
|
||||
return json([
|
||||
'code' => 400,
|
||||
'msg' => '参数错误:微信ID不能为空'
|
||||
]);
|
||||
}
|
||||
|
||||
// 查询参数
|
||||
$params = [];
|
||||
if (!empty($keyword)) {
|
||||
$params['keyword'] = $keyword;
|
||||
}
|
||||
|
||||
// 调用模型方法获取好友列表
|
||||
$result = WechatFriend::getFriendsByWechatId($wechatId, $params, $page, $limit);
|
||||
|
||||
// 处理返回的数据
|
||||
$friendsList = [];
|
||||
foreach ($result['list'] as $friend) {
|
||||
$friendsList[] = [
|
||||
'wechatId' => $friend['wechatId'],
|
||||
'avatar' => $friend['avatar'] ?: '/placeholder.svg',
|
||||
'labels' => $friend['labels'] ?: [],
|
||||
'accountNickname' => $friend['accountNickname'] ?: '',
|
||||
'accountRealName' => $friend['accountRealName'] ?: '',
|
||||
'nickname' => $friend['nickname'] ?: '',
|
||||
'remark' => $friend['conRemark'] ?: '',
|
||||
'alias' => $friend['alias'] ?: '',
|
||||
'gender' => $friend['gender'] ?: 0,
|
||||
'region' => $friend['region'] ?: ''
|
||||
];
|
||||
}
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'total' => $result['total'],
|
||||
'page' => $result['page'],
|
||||
'limit' => $result['limit'],
|
||||
'list' => $friendsList
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
67
Server/application/cunkebao/controller/Scene.php
Normal file
67
Server/application/cunkebao/controller/Scene.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
namespace app\cunkebao\controller;
|
||||
|
||||
use app\cunkebao\model\PlanScene;
|
||||
use think\Controller;
|
||||
use think\facade\Request;
|
||||
|
||||
/**
|
||||
* 获客场景控制器
|
||||
*/
|
||||
class Scene extends Controller
|
||||
{
|
||||
/**
|
||||
* 获取场景列表
|
||||
*
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$page = Request::param('page', 1, 'intval');
|
||||
$limit = Request::param('limit', 10, 'intval');
|
||||
$keyword = Request::param('keyword', '');
|
||||
|
||||
// 构建查询条件
|
||||
$where = [];
|
||||
if (!empty($keyword)) {
|
||||
$where[] = ['name', 'like', "%{$keyword}%"];
|
||||
}
|
||||
|
||||
// 默认只显示有效场景
|
||||
$where[] = ['status', '=', 1];
|
||||
|
||||
// 查询列表
|
||||
$result = PlanScene::getSceneList($where, 'sort desc', $page, $limit);
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => $result
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个场景详情
|
||||
*
|
||||
* @param int $id 场景ID
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function read($id)
|
||||
{
|
||||
// 查询场景信息
|
||||
$scene = PlanScene::getSceneInfo($id);
|
||||
|
||||
if (!$scene) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '场景不存在'
|
||||
]);
|
||||
}
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => $scene
|
||||
]);
|
||||
}
|
||||
}
|
||||
369
Server/application/cunkebao/controller/Task.php
Normal file
369
Server/application/cunkebao/controller/Task.php
Normal file
@@ -0,0 +1,369 @@
|
||||
<?php
|
||||
namespace app\cunkebao\controller;
|
||||
|
||||
use app\cunkebao\model\PlanTask;
|
||||
use app\cunkebao\model\PlanExecution;
|
||||
use think\Controller;
|
||||
use think\facade\Log;
|
||||
use think\Request;
|
||||
|
||||
/**
|
||||
* 计划任务控制器
|
||||
*/
|
||||
class Task extends Controller
|
||||
{
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务列表
|
||||
*
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$page = Request::param('page', 1, 'intval');
|
||||
$limit = Request::param('limit', 10, 'intval');
|
||||
$keyword = Request::param('keyword', '');
|
||||
$status = Request::param('status', '', 'trim');
|
||||
|
||||
// 构建查询条件
|
||||
$where = [];
|
||||
if (!empty($keyword)) {
|
||||
$where[] = ['name', 'like', "%{$keyword}%"];
|
||||
}
|
||||
|
||||
if ($status !== '') {
|
||||
$where[] = ['status', '=', intval($status)];
|
||||
}
|
||||
|
||||
// 查询列表
|
||||
$result = PlanTask::getTaskList($where, 'id desc', $page, $limit);
|
||||
|
||||
// 查询场景和设备信息
|
||||
foreach ($result['list'] as &$task) {
|
||||
$task['scene'] = $task->scene ? $task->scene->toArray() : null;
|
||||
$task['device'] = $task->device ? $task->device->toArray() : null;
|
||||
}
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => $result
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务详情
|
||||
*
|
||||
* @param int $id
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function read($id)
|
||||
{
|
||||
$task = PlanTask::get($id, ['scene', 'device']);
|
||||
if (!$task) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '任务不存在'
|
||||
]);
|
||||
}
|
||||
|
||||
// 获取执行记录
|
||||
$executions = PlanExecution::where('plan_id', $id)
|
||||
->order('createTime DESC')
|
||||
->select();
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'task' => $task,
|
||||
'executions' => $executions
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建任务
|
||||
*
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$data = Request::post();
|
||||
|
||||
// 数据验证
|
||||
$validate = validate('app\cunkebao\validate\Task');
|
||||
if (!$validate->check($data)) {
|
||||
return json([
|
||||
'code' => 400,
|
||||
'msg' => $validate->getError()
|
||||
]);
|
||||
}
|
||||
|
||||
// 添加任务
|
||||
$task = new PlanTask;
|
||||
$task->save([
|
||||
'name' => $data['name'],
|
||||
'device_id' => $data['device_id'] ?? null,
|
||||
'scene_id' => $data['scene_id'] ?? null,
|
||||
'scene_config' => $data['scene_config'] ?? [],
|
||||
'status' => $data['status'] ?? 0,
|
||||
'current_step' => 0,
|
||||
'priority' => $data['priority'] ?? 5,
|
||||
'created_by' => $data['created_by'] ?? 0
|
||||
]);
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '创建成功',
|
||||
'data' => $task->id
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新任务
|
||||
*
|
||||
* @param int $id
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function update($id)
|
||||
{
|
||||
$data = Request::put();
|
||||
|
||||
// 检查任务是否存在
|
||||
$task = PlanTask::get($id);
|
||||
if (!$task) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '任务不存在'
|
||||
]);
|
||||
}
|
||||
|
||||
// 准备更新数据
|
||||
$updateData = [];
|
||||
|
||||
// 只允许更新特定字段
|
||||
$allowedFields = ['name', 'device_id', 'scene_id', 'scene_config', 'status', 'priority'];
|
||||
foreach ($allowedFields as $field) {
|
||||
if (isset($data[$field])) {
|
||||
$updateData[$field] = $data[$field];
|
||||
}
|
||||
}
|
||||
|
||||
// 更新任务
|
||||
$task->save($updateData);
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '更新成功'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除任务
|
||||
*
|
||||
* @param int $id
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
// 检查任务是否存在
|
||||
$task = PlanTask::get($id);
|
||||
if (!$task) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '任务不存在'
|
||||
]);
|
||||
}
|
||||
|
||||
// 软删除任务
|
||||
$task->delete();
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '删除成功'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动任务
|
||||
*
|
||||
* @param int $id
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function start($id)
|
||||
{
|
||||
// 检查任务是否存在
|
||||
$task = PlanTask::get($id);
|
||||
if (!$task) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '任务不存在'
|
||||
]);
|
||||
}
|
||||
|
||||
// 更新状态为启用
|
||||
$task->save([
|
||||
'status' => 1,
|
||||
'current_step' => 0
|
||||
]);
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '任务已启动'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止任务
|
||||
*
|
||||
* @param int $id
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function stop($id)
|
||||
{
|
||||
// 检查任务是否存在
|
||||
$task = PlanTask::get($id);
|
||||
if (!$task) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '任务不存在'
|
||||
]);
|
||||
}
|
||||
|
||||
// 更新状态为停用
|
||||
$task->save([
|
||||
'status' => 0
|
||||
]);
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '任务已停止'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行定时任务(供外部调用)
|
||||
*
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function cron()
|
||||
{
|
||||
// 获取密钥
|
||||
$key = Request::param('key', '');
|
||||
|
||||
// 验证密钥(实际生产环境应当使用更安全的验证方式)
|
||||
if ($key !== config('task.cron_key')) {
|
||||
return json([
|
||||
'code' => 403,
|
||||
'msg' => '访问密钥无效'
|
||||
]);
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取待执行的任务
|
||||
$tasks = PlanTask::getPendingTasks(5);
|
||||
if ($tasks->isEmpty()) {
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '没有需要执行的任务',
|
||||
'data' => []
|
||||
]);
|
||||
}
|
||||
|
||||
$results = [];
|
||||
|
||||
// 逐一执行任务
|
||||
foreach ($tasks as $task) {
|
||||
$runner = new TaskRunner($task);
|
||||
$result = $runner->run();
|
||||
|
||||
$results[] = [
|
||||
'task_id' => $task->id,
|
||||
'name' => $task->name,
|
||||
'result' => $result
|
||||
];
|
||||
|
||||
// 记录执行信息
|
||||
Log::info('任务执行', [
|
||||
'task_id' => $task->id,
|
||||
'name' => $task->name,
|
||||
'result' => $result
|
||||
]);
|
||||
}
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '任务执行完成',
|
||||
'data' => $results
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('任务执行异常', [
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '任务执行异常:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动执行任务
|
||||
*
|
||||
* @param int $id
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function execute($id)
|
||||
{
|
||||
// 检查任务是否存在
|
||||
$task = PlanTask::get($id);
|
||||
if (!$task) {
|
||||
return json([
|
||||
'code' => 404,
|
||||
'msg' => '任务不存在'
|
||||
]);
|
||||
}
|
||||
|
||||
try {
|
||||
// 执行任务
|
||||
$runner = new TaskRunner($task);
|
||||
$result = $runner->run();
|
||||
|
||||
// 记录执行信息
|
||||
Log::info('手动执行任务', [
|
||||
'task_id' => $task->id,
|
||||
'name' => $task->name,
|
||||
'result' => $result
|
||||
]);
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '任务执行完成',
|
||||
'data' => $result
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('手动执行任务异常', [
|
||||
'task_id' => $task->id,
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '任务执行异常:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
67
Server/application/cunkebao/controller/TrafficPool.php
Normal file
67
Server/application/cunkebao/controller/TrafficPool.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
namespace app\cunkebao\controller;
|
||||
|
||||
use think\Controller;
|
||||
use think\facade\Request;
|
||||
|
||||
/**
|
||||
* 流量池控制器
|
||||
*/
|
||||
class TrafficPool extends Controller
|
||||
{
|
||||
/**
|
||||
* 导入订单标签
|
||||
*
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function importOrders()
|
||||
{
|
||||
try {
|
||||
// 获取请求数据
|
||||
$data = Request::post();
|
||||
|
||||
// 验证必要字段
|
||||
if (empty($data['mobile']) || empty($data['from']) || empty($data['sceneId'])) {
|
||||
return json([
|
||||
'code' => 400,
|
||||
'msg' => '缺少必要参数'
|
||||
]);
|
||||
}
|
||||
|
||||
// 批量处理数据
|
||||
$successCount = 0;
|
||||
$failCount = 0;
|
||||
|
||||
foreach ($data['mobile'] as $index => $mobile) {
|
||||
// 导入到流量池
|
||||
$poolData[] = [
|
||||
'mobile' => $mobile,
|
||||
'from' => $data['from'][$index] ?? '',
|
||||
'createTime' => time()
|
||||
];
|
||||
|
||||
// 导入到流量来源
|
||||
$sourceData[] = [
|
||||
'mobile' => $mobile,
|
||||
'sceneId' => $data['sceneId'],
|
||||
'createTime' => time()
|
||||
];
|
||||
}
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '导入完成',
|
||||
'data' => [
|
||||
'success' => $successCount,
|
||||
'fail' => $failCount
|
||||
]
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '导入失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Server/application/cunkebao/controller/TrafficTag.php
Normal file
64
Server/application/cunkebao/controller/TrafficTag.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
namespace app\cunkebao\controller;
|
||||
|
||||
use app\cunkebao\model\TrafficTag as TrafficTagModel;
|
||||
use think\Controller;
|
||||
use think\facade\Request;
|
||||
|
||||
/**
|
||||
* 流量标签控制器
|
||||
*/
|
||||
class TrafficTag extends Controller
|
||||
{
|
||||
/**
|
||||
* 获取标签列表
|
||||
*
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
try {
|
||||
// 获取登录用户信息
|
||||
$userInfo = request()->userInfo;
|
||||
|
||||
// 获取查询条件
|
||||
$where = [];
|
||||
|
||||
// 关键词搜索
|
||||
$keyword = Request::param('keyword', '');
|
||||
if (!empty($keyword)) {
|
||||
$where[] = ['tagName', 'like', "%{$keyword}%"];
|
||||
}
|
||||
|
||||
// 添加公司ID过滤条件
|
||||
$where[] = ['companyId', '=', $userInfo['companyId']];
|
||||
|
||||
// 获取分页参数
|
||||
$page = (int)Request::param('page', 1);
|
||||
$limit = (int)Request::param('limit', 200); // 默认每页显示200条
|
||||
|
||||
// 获取排序参数
|
||||
$sort = Request::param('sort', 'id');
|
||||
$order = Request::param('order', 'desc');
|
||||
|
||||
// 查询列表
|
||||
$list = TrafficTagModel::getTagsByCompany($where, "{$sort} {$order}", $page, $limit);
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'total' => $list->total(),
|
||||
'list' => $list->items(),
|
||||
'page' => $page,
|
||||
'limit' => $limit
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return json([
|
||||
'code' => 500,
|
||||
'msg' => '获取失败:' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Server/application/cunkebao/model/BaseModel.php
Normal file
60
Server/application/cunkebao/model/BaseModel.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace app\cunkebao\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
class BaseModel extends Model
|
||||
{
|
||||
// 数据插入 duplicate
|
||||
public function insertAllDuplicate($data, $duplicate = null, $limit = null)
|
||||
{
|
||||
if (!empty($duplicate)) {
|
||||
if (is_array($duplicate)) {
|
||||
$temp = [];
|
||||
foreach ($duplicate as $key => $item) {
|
||||
if (is_integer($key)) {
|
||||
$temp[] = "{$item} = VALUES({$item})";
|
||||
} else {
|
||||
$temp[] = "{$key} = {$item}";
|
||||
}
|
||||
}
|
||||
$duplicate = implode(',', $temp);
|
||||
}
|
||||
}
|
||||
if (!empty($limit)) {
|
||||
// 分批写入 自动启动事务支持
|
||||
$this->startTrans();
|
||||
|
||||
try {
|
||||
// array_chunk 函数把数组分割为新的数组块。
|
||||
//其中每个数组的单元数目由 size 参数决定。最后一个数组的单元数目可能会少几个。
|
||||
//可选参数 preserve_key 是一个布尔值,它指定新数组的元素是否有和原数组相同的键(用于关联数组),还是从 0 开始的新数字键(用于索引数组)。默认是分配新的键。
|
||||
$array = array_chunk($data, $limit, true);
|
||||
$count = 0;
|
||||
|
||||
foreach ($array as $item) {
|
||||
$sql = $this->fetchSql(true)->insertAll($item);
|
||||
$sql = preg_replace("/INSERT\s*INTO\s*/", "INSERT IGNORE INTO ", $sql);
|
||||
if (is_string($duplicate)) {
|
||||
$sql = $sql . ' ON DUPLICATE KEY UPDATE ' . $duplicate;
|
||||
}
|
||||
$count += $this->execute($sql); // 获取影响函数
|
||||
}
|
||||
// 提交事务
|
||||
$this->commit();
|
||||
} catch (\Exception $e) {
|
||||
$this->rollback();
|
||||
throw $e;
|
||||
}
|
||||
return $count;
|
||||
} else {
|
||||
$sql = $this->fetchSql(true)->insertAll($data);
|
||||
$sql = preg_replace("/INSERT\s*INTO\s*/", "INSERT IGNORE INTO ", $sql);
|
||||
if (is_string($duplicate)) {
|
||||
$sql = $sql . ' ON DUPLICATE KEY UPDATE ' . $duplicate;
|
||||
}
|
||||
return $this->execute($sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
208
Server/application/cunkebao/model/Device.php
Normal file
208
Server/application/cunkebao/model/Device.php
Normal file
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
namespace app\cunkebao\model;
|
||||
|
||||
use think\Model;
|
||||
use think\Db;
|
||||
|
||||
/**
|
||||
* 设备模型类
|
||||
*/
|
||||
class Device extends Model
|
||||
{
|
||||
// 设置表名
|
||||
protected $name = 'device';
|
||||
|
||||
/**
|
||||
* 获取设备总数
|
||||
* @param array $where 查询条件
|
||||
* @return int 设备总数
|
||||
*/
|
||||
public static function getDeviceCount($where = [])
|
||||
{
|
||||
// 默认只统计未删除的设备
|
||||
if (!isset($where['isDeleted']) && !isset($where['d.isDeleted'])) {
|
||||
$where['isDeleted'] = 0;
|
||||
}
|
||||
|
||||
// 确定是否使用了表别名
|
||||
$hasAlias = false;
|
||||
foreach ($where as $key => $value) {
|
||||
if (strpos($key, '.') !== false) {
|
||||
$hasAlias = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果使用了表别名,则需要使用查询构造器
|
||||
if ($hasAlias) {
|
||||
return self::alias('d')->where($where)->count();
|
||||
} else {
|
||||
return self::where($where)->count();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备列表
|
||||
* @param array $where 查询条件
|
||||
* @param string $order 排序方式
|
||||
* @param int $page 页码
|
||||
* @param int $limit 每页数量
|
||||
* @return \think\Paginator 分页对象
|
||||
*/
|
||||
public static function getDeviceList($where = [], $order = 'd.id desc', $page = 1, $limit = 10)
|
||||
{
|
||||
// 默认只查询未删除的设备
|
||||
if (!isset($where['isDeleted'])) {
|
||||
$where['d.isDeleted'] = 0;
|
||||
}
|
||||
|
||||
// 构建查询对象
|
||||
$query = self::alias('d')
|
||||
->field(['d.id', 'd.imei', 'd.memo', 'w.wechatId', 'd.alive', 'w.totalFriend'])
|
||||
->leftJoin('tk_wechat_account w', 'd.imei = w.imei COLLATE utf8mb4_unicode_ci');
|
||||
|
||||
// 处理查询条件
|
||||
foreach ($where as $key => $value) {
|
||||
// 处理特殊的exp表达式条件
|
||||
if (is_numeric($key) && is_array($value) && isset($value[0]) && $value[0] === 'exp') {
|
||||
// 直接添加原始SQL表达式
|
||||
$query->whereExp('', $value[1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 处理普通条件
|
||||
$query->where($key, $value);
|
||||
}
|
||||
|
||||
// 返回分页结果
|
||||
return $query->order($order)
|
||||
->paginate($limit, false, ['page' => $page]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备详情
|
||||
* @param int $id 设备ID
|
||||
* @return array|null 设备信息
|
||||
*/
|
||||
public static function getDeviceInfo($id)
|
||||
{
|
||||
// 查询设备基础信息与关联的微信账号信息
|
||||
$device = self::alias('d')
|
||||
->field([
|
||||
'd.id', 'd.imei', 'd.memo', 'd.alive', 'd.taskConfig', 'd.lastUpdateTime',
|
||||
'w.id as wechatId', 'w.thirtyDayMsgCount', 'w.totalFriend', 'd.extra'
|
||||
])
|
||||
->leftJoin('tk_wechat_account w', 'd.imei = w.imei')
|
||||
->where('d.id', $id)
|
||||
->where('d.isDeleted', 0)
|
||||
->find();
|
||||
|
||||
// 如果设备存在,处理额外信息
|
||||
if ($device) {
|
||||
// 解析电量信息
|
||||
$battery = 0;
|
||||
if (!empty($device['extra'])) {
|
||||
$extra = json_decode($device['extra'], true);
|
||||
if (is_array($extra) && isset($extra['battery'])) {
|
||||
$battery = intval($extra['battery']);
|
||||
}
|
||||
}
|
||||
$device['battery'] = $battery;
|
||||
|
||||
// 解析taskConfig字段获取功能开关
|
||||
$features = [
|
||||
'autoAddFriend' => false,
|
||||
'autoReply' => false,
|
||||
'contentSync' => false,
|
||||
'aiChat' => false
|
||||
];
|
||||
|
||||
if (!empty($device['taskConfig'])) {
|
||||
$taskConfig = json_decode($device['taskConfig'], true);
|
||||
if (is_array($taskConfig)) {
|
||||
// 映射taskConfig中的字段到前端需要的features
|
||||
$features['autoAddFriend'] = isset($taskConfig['autoAddFriend']) ? (bool)$taskConfig['autoAddFriend'] : false;
|
||||
$features['autoReply'] = isset($taskConfig['autoReply']) ? (bool)$taskConfig['autoReply'] : false;
|
||||
$features['contentSync'] = isset($taskConfig['momentsSync']) ? (bool)$taskConfig['momentsSync'] : false;
|
||||
$features['aiChat'] = isset($taskConfig['aiChat']) ? (bool)$taskConfig['aiChat'] : false;
|
||||
}
|
||||
}
|
||||
|
||||
$device['features'] = $features;
|
||||
unset($device['extra']);
|
||||
unset($device['taskConfig']);
|
||||
|
||||
// 格式化最后活跃时间
|
||||
$device['lastUpdateTime'] = !empty($device['lastUpdateTime']) ? date('Y-m-d H:i:s', strtotime($device['lastUpdateTime'])) : date('Y-m-d H:i:s');
|
||||
|
||||
// 确保totalFriend和thirtyDayMsgCount有值,防止NULL
|
||||
$device['totalFriend'] = intval($device['totalFriend'] ?? 0);
|
||||
$device['thirtyDayMsgCount'] = intval($device['thirtyDayMsgCount'] ?? 0);
|
||||
}
|
||||
|
||||
return $device;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加设备
|
||||
* @param array $data 设备数据
|
||||
* @return int 新增设备ID
|
||||
*/
|
||||
public static function addDevice($data)
|
||||
{
|
||||
$device = new self();
|
||||
$device->allowField(true)->save($data);
|
||||
return $device->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新设备
|
||||
* @param int $id 设备ID
|
||||
* @param array $data 设备数据
|
||||
* @return bool 更新结果
|
||||
*/
|
||||
public static function updateDevice($id, $data)
|
||||
{
|
||||
return self::where('id', $id)
|
||||
->where('isDeleted', 0)
|
||||
->update($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设备(软删除)
|
||||
* @param int $id 设备ID
|
||||
* @return bool 删除结果
|
||||
*/
|
||||
public static function deleteDevice($id)
|
||||
{
|
||||
return self::where('id', $id)
|
||||
->update([
|
||||
'isDeleted' => 1,
|
||||
'deleteTime' => date('Y-m-d H:i:s', time())
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按设备品牌统计数量
|
||||
* @return array 统计结果
|
||||
*/
|
||||
public static function countByBrand()
|
||||
{
|
||||
return self::where('isDeleted', 0)
|
||||
->group('brand')
|
||||
->field('brand, count(*) as count')
|
||||
->select();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按设备在线状态统计数量
|
||||
* @return array 统计结果
|
||||
*/
|
||||
public static function countByStatus()
|
||||
{
|
||||
return self::where('isDeleted', 0)
|
||||
->group('alive')
|
||||
->field('alive, count(*) as count')
|
||||
->select();
|
||||
}
|
||||
}
|
||||
100
Server/application/cunkebao/model/DeviceHandleLog.php
Normal file
100
Server/application/cunkebao/model/DeviceHandleLog.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
namespace app\cunkebao\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* 设备操作日志模型类
|
||||
*/
|
||||
class DeviceHandleLog extends Model
|
||||
{
|
||||
// 设置表名
|
||||
protected $name = 'device_handle_log';
|
||||
|
||||
/**
|
||||
* 添加设备操作日志
|
||||
* @param array $data 日志数据
|
||||
* @return int 新增日志ID
|
||||
*/
|
||||
public static function addLog($data)
|
||||
{
|
||||
$log = new self();
|
||||
$log->allowField(true)->save($data);
|
||||
return $log->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备操作日志列表
|
||||
* @param array $where 查询条件
|
||||
* @param string $order 排序方式
|
||||
* @param int $page 页码
|
||||
* @param int $limit 每页数量
|
||||
* @return \think\Paginator 分页对象
|
||||
*/
|
||||
public static function getLogList($where = [], $order = 'createTime desc', $page = 1, $limit = 10)
|
||||
{
|
||||
return self::where($where)
|
||||
->order($order)
|
||||
->paginate($limit, false, ['page' => $page]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据IMEI获取设备操作日志
|
||||
* @param string $imei 设备IMEI
|
||||
* @param int $companyId 租户ID
|
||||
* @param int $limit 获取条数
|
||||
* @return array 日志记录
|
||||
*/
|
||||
public static function getLogsByImei($imei, $companyId = null, $limit = 10)
|
||||
{
|
||||
$query = self::where('imei', $imei);
|
||||
|
||||
if ($companyId !== null) {
|
||||
$query->where('companyId', $companyId);
|
||||
}
|
||||
|
||||
return $query->order('createTime', 'desc')
|
||||
->limit($limit)
|
||||
->select();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID获取操作日志
|
||||
* @param int $userId 用户ID
|
||||
* @param int $companyId 租户ID
|
||||
* @param int $page 页码
|
||||
* @param int $limit 每页数量
|
||||
* @return \think\Paginator 分页对象
|
||||
*/
|
||||
public static function getLogsByUser($userId, $companyId = null, $page = 1, $limit = 10)
|
||||
{
|
||||
$query = self::where('userId', $userId);
|
||||
|
||||
if ($companyId !== null) {
|
||||
$query->where('companyId', $companyId);
|
||||
}
|
||||
|
||||
return $query->order('createTime', 'desc')
|
||||
->paginate($limit, false, ['page' => $page]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录设备操作日志的便捷方法
|
||||
* @param string $imei 设备IMEI
|
||||
* @param int $userId 操作用户ID
|
||||
* @param string $content 操作内容
|
||||
* @param int $companyId 租户ID
|
||||
* @return int 日志ID
|
||||
*/
|
||||
public static function recordLog($imei, $userId, $content, $companyId = null)
|
||||
{
|
||||
$data = [
|
||||
'imei' => $imei,
|
||||
'userId' => $userId,
|
||||
'content' => $content,
|
||||
'companyId' => $companyId
|
||||
];
|
||||
|
||||
return self::addLog($data);
|
||||
}
|
||||
}
|
||||
190
Server/application/cunkebao/model/DeviceWechatLogin.php
Normal file
190
Server/application/cunkebao/model/DeviceWechatLogin.php
Normal file
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
namespace app\cunkebao\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* 设备微信登录记录模型类
|
||||
*/
|
||||
class DeviceWechatLogin extends Model
|
||||
{
|
||||
// 设置表名
|
||||
protected $name = 'device_wechat_login';
|
||||
|
||||
/**
|
||||
* 查询设备关联的微信ID列表
|
||||
* @param int $deviceId 设备ID
|
||||
* @param int $companyId 公司/租户ID
|
||||
* @return array 微信ID列表
|
||||
*/
|
||||
public static function getDeviceWechatIds($deviceId, $companyId = null)
|
||||
{
|
||||
$query = self::where('deviceId', $deviceId);
|
||||
|
||||
// 如果提供了公司ID,则添加对应的条件
|
||||
if ($companyId !== null) {
|
||||
$query->where('companyId', $companyId);
|
||||
}
|
||||
|
||||
// 提取微信ID
|
||||
$records = $query->select();
|
||||
$wechatIds = [];
|
||||
|
||||
foreach ($records as $record) {
|
||||
if (!empty($record['wechatId'])) {
|
||||
$wechatIds[] = $record['wechatId'];
|
||||
}
|
||||
}
|
||||
|
||||
return $wechatIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据微信ID查询关联的设备
|
||||
* @param string $wechatId 微信ID
|
||||
* @param int $companyId 公司/租户ID
|
||||
* @return array 设备ID列表
|
||||
*/
|
||||
public static function getWechatDeviceIds($wechatId, $companyId = null)
|
||||
{
|
||||
$query = self::where('wechatId', $wechatId);
|
||||
|
||||
// 如果提供了公司ID,则添加对应的条件
|
||||
if ($companyId !== null) {
|
||||
$query->where('companyId', $companyId);
|
||||
}
|
||||
|
||||
// 提取设备ID
|
||||
$records = $query->select();
|
||||
$deviceIds = [];
|
||||
|
||||
foreach ($records as $record) {
|
||||
if (!empty($record['deviceId'])) {
|
||||
$deviceIds[] = $record['deviceId'];
|
||||
}
|
||||
}
|
||||
|
||||
return $deviceIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加设备微信登录记录
|
||||
* @param int $deviceId 设备ID
|
||||
* @param string $wechatId 微信ID
|
||||
* @param int $companyId 公司/租户ID
|
||||
* @return int 新增记录ID
|
||||
*/
|
||||
public static function addRecord($deviceId, $wechatId, $companyId)
|
||||
{
|
||||
// 检查是否已存在相同记录
|
||||
$exists = self::where('deviceId', $deviceId)
|
||||
->where('wechatId', $wechatId)
|
||||
->where('companyId', $companyId)
|
||||
->find();
|
||||
|
||||
if ($exists) {
|
||||
return $exists['id'];
|
||||
}
|
||||
|
||||
// 创建新记录
|
||||
$model = new self();
|
||||
$model->deviceId = $deviceId;
|
||||
$model->wechatId = $wechatId;
|
||||
$model->companyId = $companyId;
|
||||
$model->save();
|
||||
|
||||
return $model->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设备微信登录记录
|
||||
* @param int $deviceId 设备ID
|
||||
* @param string $wechatId 微信ID,为null时删除设备所有记录
|
||||
* @param int $companyId 公司/租户ID,为null时不限公司
|
||||
* @return bool 删除结果
|
||||
*/
|
||||
public static function removeRecord($deviceId, $wechatId = null, $companyId = null)
|
||||
{
|
||||
$query = self::where('deviceId', $deviceId);
|
||||
|
||||
if ($wechatId !== null) {
|
||||
$query->where('wechatId', $wechatId);
|
||||
}
|
||||
|
||||
if ($companyId !== null) {
|
||||
$query->where('companyId', $companyId);
|
||||
}
|
||||
|
||||
return $query->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联Device模型
|
||||
* @return \think\model\relation\BelongsTo
|
||||
*/
|
||||
public function device()
|
||||
{
|
||||
return $this->belongsTo('Device', 'deviceId');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备关联的微信账号信息
|
||||
* @param int $deviceId 设备ID
|
||||
* @param int $companyId 公司/租户ID
|
||||
* @return array 微信账号信息列表
|
||||
*/
|
||||
public static function getDeviceRelatedAccounts($deviceId, $companyId = null)
|
||||
{
|
||||
// 获取设备关联的微信ID列表
|
||||
$wechatIds = self::getDeviceWechatIds($deviceId, $companyId);
|
||||
if (empty($wechatIds)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 查询微信账号信息
|
||||
$accounts = \think\Db::name('wechat_account')
|
||||
->alias('wa')
|
||||
->field([
|
||||
'wa.id',
|
||||
'wa.wechatId',
|
||||
'wa.accountNickname',
|
||||
'wa.nickname',
|
||||
'wa.accountUserName',
|
||||
'wa.avatar',
|
||||
'wa.gender',
|
||||
'wa.wechatAlive',
|
||||
'wa.status',
|
||||
'wa.totalFriend',
|
||||
'wa.createTime',
|
||||
'wa.updateTime'
|
||||
])
|
||||
->whereIn('wa.wechatId', $wechatIds)
|
||||
->where('wa.isDeleted', 0)
|
||||
->select();
|
||||
|
||||
// 处理结果数据
|
||||
$result = [];
|
||||
foreach ($accounts as $account) {
|
||||
// 计算最后活跃时间
|
||||
$lastActive = date('Y-m-d H:i:s', max($account['updateTime'], $account['createTime']));
|
||||
|
||||
// 格式化数据
|
||||
$result[] = [
|
||||
'id' => $account['id'],
|
||||
'wechatId' => $account['wechatId'],
|
||||
'nickname' => $account['accountNickname'] ?: $account['nickname'] ?: '未命名微信',
|
||||
'accountUserName' => $account['accountUserName'],
|
||||
'avatar' => $account['avatar'],
|
||||
'gender' => intval($account['gender']),
|
||||
'status' => intval($account['status']),
|
||||
'statusText' => intval($account['status']) === 1 ? '可加友' : '已停用',
|
||||
'wechatAlive' => intval($account['wechatAlive']),
|
||||
'wechatAliveText' => intval($account['wechatAlive']) === 1 ? '正常' : '异常',
|
||||
'totalFriend' => intval($account['totalFriend']),
|
||||
'lastActive' => $lastActive
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
286
Server/application/cunkebao/model/FriendTask.php
Normal file
286
Server/application/cunkebao/model/FriendTask.php
Normal file
@@ -0,0 +1,286 @@
|
||||
<?php
|
||||
namespace app\cunkebao\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* 添加好友任务记录模型
|
||||
*/
|
||||
class FriendTask extends Model
|
||||
{
|
||||
/**
|
||||
* 数据表名
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'tk_friend_task';
|
||||
|
||||
/**
|
||||
* 状态常量
|
||||
*/
|
||||
const STATUS_PENDING = 1; // 待处理
|
||||
const STATUS_PROCESSING = 2; // 处理中
|
||||
const STATUS_APPROVED = 3; // 已通过
|
||||
const STATUS_REJECTED = 4; // 已拒绝
|
||||
const STATUS_EXPIRED = 5; // 已过期
|
||||
const STATUS_CANCELLED = 6; // 已取消
|
||||
|
||||
/**
|
||||
* 获取状态文本
|
||||
* @param int $status 状态码
|
||||
* @return string 状态文本
|
||||
*/
|
||||
public static function getStatusText($status)
|
||||
{
|
||||
$statusMap = [
|
||||
self::STATUS_PENDING => '待处理',
|
||||
self::STATUS_PROCESSING => '处理中',
|
||||
self::STATUS_APPROVED => '已通过',
|
||||
self::STATUS_REJECTED => '已拒绝',
|
||||
self::STATUS_EXPIRED => '已过期',
|
||||
self::STATUS_CANCELLED => '已取消'
|
||||
];
|
||||
|
||||
return isset($statusMap[$status]) ? $statusMap[$status] : '未知状态';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取好友任务列表
|
||||
* @param array $where 查询条件
|
||||
* @param string $order 排序条件
|
||||
* @param int $page 页码
|
||||
* @param int $limit 每页数量
|
||||
* @return \think\Paginator
|
||||
*/
|
||||
public static function getTaskList($where = [], $order = 'createTime desc', $page = 1, $limit = 10)
|
||||
{
|
||||
return self::where($where)
|
||||
->order($order)
|
||||
->paginate($limit, false, ['page' => $page]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务详情
|
||||
* @param int $id 任务ID
|
||||
* @return array|null
|
||||
*/
|
||||
public static function getTaskDetail($id)
|
||||
{
|
||||
return self::where('id', $id)->find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建好友任务
|
||||
* @param array $data 任务数据
|
||||
* @return int|bool 任务ID或false
|
||||
*/
|
||||
public static function createTask($data)
|
||||
{
|
||||
// 确保必填字段存在
|
||||
if (!isset($data['id'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if (!isset($data['status'])) {
|
||||
$data['status'] = self::STATUS_PENDING;
|
||||
}
|
||||
|
||||
// 设置创建时间
|
||||
$data['createTime'] = time();
|
||||
$data['updateTime'] = time();
|
||||
|
||||
// 创建任务
|
||||
$task = new self;
|
||||
$task->allowField(true)->save($data);
|
||||
|
||||
return $task->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新任务信息
|
||||
* @param int $id 任务ID
|
||||
* @param array $data 更新数据
|
||||
* @return bool
|
||||
*/
|
||||
public static function updateTask($id, $data)
|
||||
{
|
||||
// 更新时间
|
||||
$data['updateTime'] = time();
|
||||
|
||||
return self::where('id', $id)->update($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新任务状态
|
||||
* @param int $id 任务ID
|
||||
* @param int $status 新状态
|
||||
* @param string $remark 备注
|
||||
* @return bool
|
||||
*/
|
||||
public static function updateTaskStatus($id, $status, $remark = '')
|
||||
{
|
||||
$data = [
|
||||
'status' => $status,
|
||||
'updateTime' => time()
|
||||
];
|
||||
|
||||
if (!empty($remark)) {
|
||||
$data['remark'] = $remark;
|
||||
}
|
||||
|
||||
return self::where('id', $id)->update($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消任务
|
||||
* @param int $id 任务ID
|
||||
* @param string $remark 取消原因
|
||||
* @return bool
|
||||
*/
|
||||
public static function cancelTask($id, $remark = '')
|
||||
{
|
||||
return self::updateTaskStatus($id, self::STATUS_CANCELLED, $remark);
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务审批通过
|
||||
* @param int $id 任务ID
|
||||
* @param string $remark 备注信息
|
||||
* @return bool
|
||||
*/
|
||||
public static function approveTask($id, $remark = '')
|
||||
{
|
||||
return self::updateTaskStatus($id, self::STATUS_APPROVED, $remark);
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务拒绝
|
||||
* @param int $id 任务ID
|
||||
* @param string $remark 拒绝原因
|
||||
* @return bool
|
||||
*/
|
||||
public static function rejectTask($id, $remark = '')
|
||||
{
|
||||
return self::updateTaskStatus($id, self::STATUS_REJECTED, $remark);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据微信账号ID获取任务列表
|
||||
* @param int $wechatAccountId 微信账号ID
|
||||
* @param array $status 状态数组,默认查询所有状态
|
||||
* @param int $page 页码
|
||||
* @param int $limit 每页数量
|
||||
* @return \think\Paginator
|
||||
*/
|
||||
public static function getTasksByWechatAccount($wechatAccountId, $status = [], $page = 1, $limit = 10)
|
||||
{
|
||||
$where = ['wechatAccountId' => $wechatAccountId];
|
||||
|
||||
if (!empty($status)) {
|
||||
$where['status'] = ['in', $status];
|
||||
}
|
||||
|
||||
return self::getTaskList($where, 'createTime desc', $page, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据操作账号ID获取任务列表
|
||||
* @param int $operatorAccountId 操作账号ID
|
||||
* @param array $status 状态数组,默认查询所有状态
|
||||
* @param int $page 页码
|
||||
* @param int $limit 每页数量
|
||||
* @return \think\Paginator
|
||||
*/
|
||||
public static function getTasksByOperator($operatorAccountId, $status = [], $page = 1, $limit = 10)
|
||||
{
|
||||
$where = ['operatorAccountId' => $operatorAccountId];
|
||||
|
||||
if (!empty($status)) {
|
||||
$where['status'] = ['in', $status];
|
||||
}
|
||||
|
||||
return self::getTaskList($where, 'createTime desc', $page, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据手机号/微信号查询任务
|
||||
* @param string $phone 手机号/微信号
|
||||
* @param int $tenantId 租户ID
|
||||
* @return array
|
||||
*/
|
||||
public static function getTasksByPhone($phone, $tenantId = null)
|
||||
{
|
||||
$where = ['phone' => $phone];
|
||||
|
||||
if ($tenantId !== null) {
|
||||
$where['tenantId'] = $tenantId;
|
||||
}
|
||||
|
||||
return self::where($where)->select();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取统计数据
|
||||
* @param int $tenantId 租户ID
|
||||
* @param int $timeRange 时间范围(秒)
|
||||
* @return array
|
||||
*/
|
||||
public static function getTaskStats($tenantId = null, $timeRange = 86400)
|
||||
{
|
||||
$where = [];
|
||||
|
||||
if ($tenantId !== null) {
|
||||
$where['tenantId'] = $tenantId;
|
||||
}
|
||||
|
||||
// 时间范围
|
||||
$startTime = time() - $timeRange;
|
||||
$where['createTime'] = ['>=', $startTime];
|
||||
|
||||
// 获取各状态的任务数量
|
||||
$stats = [
|
||||
'total' => self::where($where)->count(),
|
||||
'pending' => self::where(array_merge($where, ['status' => self::STATUS_PENDING]))->count(),
|
||||
'processing' => self::where(array_merge($where, ['status' => self::STATUS_PROCESSING]))->count(),
|
||||
'approved' => self::where(array_merge($where, ['status' => self::STATUS_APPROVED]))->count(),
|
||||
'rejected' => self::where(array_merge($where, ['status' => self::STATUS_REJECTED]))->count(),
|
||||
'expired' => self::where(array_merge($where, ['status' => self::STATUS_EXPIRED]))->count(),
|
||||
'cancelled' => self::where(array_merge($where, ['status' => self::STATUS_CANCELLED]))->count()
|
||||
];
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务处理结果统计
|
||||
* @param int $tenantId 租户ID
|
||||
* @param int $timeRange 时间范围(秒)
|
||||
* @return array
|
||||
*/
|
||||
public static function getTaskResultStats($tenantId = null, $timeRange = 86400 * 30)
|
||||
{
|
||||
$where = [];
|
||||
|
||||
if ($tenantId !== null) {
|
||||
$where['tenantId'] = $tenantId;
|
||||
}
|
||||
|
||||
// 时间范围
|
||||
$startTime = time() - $timeRange;
|
||||
$where['createTime'] = ['>=', $startTime];
|
||||
|
||||
// 获取处理结果数据
|
||||
$stats = [
|
||||
'total' => self::where($where)->count(),
|
||||
'approved' => self::where(array_merge($where, ['status' => self::STATUS_APPROVED]))->count(),
|
||||
'rejected' => self::where(array_merge($where, ['status' => self::STATUS_REJECTED]))->count(),
|
||||
'pending' => self::where(array_merge($where, ['status' => ['in', [self::STATUS_PENDING, self::STATUS_PROCESSING]]]))->count(),
|
||||
'other' => self::where(array_merge($where, ['status' => ['in', [self::STATUS_EXPIRED, self::STATUS_CANCELLED]]]))->count()
|
||||
];
|
||||
|
||||
// 计算成功率
|
||||
$stats['approvalRate'] = $stats['total'] > 0 ? round($stats['approved'] / $stats['total'] * 100, 2) : 0;
|
||||
|
||||
return $stats;
|
||||
}
|
||||
}
|
||||
43
Server/application/cunkebao/model/PlanScene.php
Normal file
43
Server/application/cunkebao/model/PlanScene.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
namespace app\cunkebao\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* 获客场景模型类
|
||||
*/
|
||||
class PlanScene extends Model
|
||||
{
|
||||
// 设置表名
|
||||
protected $name = 'plan_scene';
|
||||
|
||||
/**
|
||||
* 获取场景列表
|
||||
*
|
||||
* @param array $where 查询条件
|
||||
* @param string $order 排序
|
||||
* @param int $page 页码
|
||||
* @param int $limit 每页数量
|
||||
* @return array 场景列表和总数
|
||||
*/
|
||||
public static function getSceneList($where = [], $order = 'id desc', $page = 1, $limit = 10)
|
||||
{
|
||||
// 构建查询
|
||||
$query = self::where($where);
|
||||
|
||||
// 计算总数
|
||||
$total = $query->count();
|
||||
|
||||
// 分页查询数据
|
||||
$list = $query->page($page, $limit)
|
||||
->order($order)
|
||||
->select();
|
||||
|
||||
return [
|
||||
'list' => $list,
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'limit' => $limit
|
||||
];
|
||||
}
|
||||
}
|
||||
13
Server/application/cunkebao/model/PlanTask.php
Normal file
13
Server/application/cunkebao/model/PlanTask.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace app\cunkebao\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* 获客计划任务模型
|
||||
*/
|
||||
class PlanTask extends Model
|
||||
{
|
||||
// 设置表名
|
||||
protected $name = 'plan_task';
|
||||
}
|
||||
11
Server/application/cunkebao/model/TrafficPool.php
Normal file
11
Server/application/cunkebao/model/TrafficPool.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
namespace app\cunkebao\model;
|
||||
|
||||
/**
|
||||
* 流量池模型
|
||||
*/
|
||||
class TrafficPool extends BaseModel
|
||||
{
|
||||
// 设置表名
|
||||
protected $name = 'traffic_pool';
|
||||
}
|
||||
11
Server/application/cunkebao/model/TrafficSource.php
Normal file
11
Server/application/cunkebao/model/TrafficSource.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
namespace app\cunkebao\model;
|
||||
|
||||
/**
|
||||
* 流量来源模型
|
||||
*/
|
||||
class TrafficSource extends BaseModel
|
||||
{
|
||||
// 设置表名
|
||||
protected $name = 'traffic_source';
|
||||
}
|
||||
32
Server/application/cunkebao/model/TrafficTag.php
Normal file
32
Server/application/cunkebao/model/TrafficTag.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace app\cunkebao\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* 流量标签模型
|
||||
*/
|
||||
class TrafficTag extends Model
|
||||
{
|
||||
// 设置表名
|
||||
protected $name = 'traffic_tag';
|
||||
|
||||
/**
|
||||
* 获取标签列表,支持分页和搜索
|
||||
*
|
||||
* @param array $where 查询条件
|
||||
* @param string $order 排序方式
|
||||
* @param int $page 页码
|
||||
* @param int $limit 每页数量
|
||||
* @return \think\Paginator 分页对象
|
||||
*/
|
||||
public static function getTagsByCompany($where = [], $order = 'id desc', $page = 1, $limit = 200)
|
||||
{
|
||||
return self::where($where)
|
||||
->where('deleteTime', 0) // 只查询未删除的记录
|
||||
->order($order)
|
||||
->paginate($limit, false, [
|
||||
'page' => $page
|
||||
]);
|
||||
}
|
||||
}
|
||||
97
Server/application/cunkebao/model/WechatAccount.php
Normal file
97
Server/application/cunkebao/model/WechatAccount.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
namespace app\cunkebao\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* 微信账号模型类
|
||||
*/
|
||||
class WechatAccount extends Model
|
||||
{
|
||||
// 设置表名
|
||||
protected $name = 'wechat_account';
|
||||
|
||||
/**
|
||||
* 获取在线微信账号数量
|
||||
*
|
||||
* @param array $where 额外的查询条件
|
||||
* @return int 微信账号数量
|
||||
*/
|
||||
public static function getOnlineWechatCount($where = [])
|
||||
{
|
||||
$condition = [
|
||||
'deviceAlive' => 1,
|
||||
'wechatAlive' => 1,
|
||||
'isDeleted' => 0
|
||||
];
|
||||
|
||||
// 合并额外条件
|
||||
if (!empty($where)) {
|
||||
$condition = array_merge($condition, $where);
|
||||
}
|
||||
|
||||
return self::where($condition)->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取有登录微信的设备数量
|
||||
*
|
||||
* @param array $where 额外的查询条件
|
||||
* @return int 设备数量
|
||||
*/
|
||||
public static function getDeviceWithWechatCount($where = [])
|
||||
{
|
||||
$condition = [
|
||||
'deviceAlive' => 1,
|
||||
'isDeleted' => 0
|
||||
];
|
||||
|
||||
// 合并额外条件
|
||||
if (!empty($where)) {
|
||||
$condition = array_merge($condition, $where);
|
||||
}
|
||||
|
||||
return self::where($condition)->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取在线微信账号列表
|
||||
*
|
||||
* @param array $where 额外的查询条件
|
||||
* @param string $order 排序方式
|
||||
* @param int $page 页码
|
||||
* @param int $limit 每页数量
|
||||
* @return \think\Paginator 分页对象
|
||||
*/
|
||||
public static function getOnlineWechatList($where = [], $order = 'id desc', $page = 1, $limit = 10)
|
||||
{
|
||||
$condition = [
|
||||
'isDeleted' => 0
|
||||
];
|
||||
|
||||
// 合并额外条件
|
||||
if (!empty($where)) {
|
||||
$condition = array_merge($condition, $where);
|
||||
}
|
||||
|
||||
return self::where($condition)
|
||||
->field([
|
||||
'id',
|
||||
'wechatId',
|
||||
'accountNickname',
|
||||
'nickname',
|
||||
'accountUserName',
|
||||
'avatar',
|
||||
'wechatAlive',
|
||||
'deviceAlive',
|
||||
'totalFriend',
|
||||
'maleFriend',
|
||||
'femaleFriend',
|
||||
'imei',
|
||||
'deviceMemo',
|
||||
'yesterdayMsgCount'
|
||||
])
|
||||
->order($order)
|
||||
->paginate($limit, false, ['page' => $page]);
|
||||
}
|
||||
}
|
||||
56
Server/application/cunkebao/model/WechatFriend.php
Normal file
56
Server/application/cunkebao/model/WechatFriend.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
namespace app\cunkebao\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* 微信好友模型类
|
||||
*/
|
||||
class WechatFriend extends Model
|
||||
{
|
||||
// 设置表名
|
||||
protected $name = 'wechat_friend';
|
||||
|
||||
/**
|
||||
* 根据微信账号ID获取好友列表
|
||||
*
|
||||
* @param string $ownerWechatId 所有者微信ID
|
||||
* @param array $params 查询条件参数
|
||||
* @param int $page 页码
|
||||
* @param int $limit 每页数量
|
||||
* @return array 好友列表和总数
|
||||
*/
|
||||
public static function getFriendsByWechatId($ownerWechatId, $params = [], $page = 1, $limit = 20)
|
||||
{
|
||||
// 构建基础查询
|
||||
$query = self::where('ownerWechatId', $ownerWechatId)
|
||||
->where('isDeleted', 0);
|
||||
|
||||
// 添加筛选条件(昵称、备注、微信号、标签)
|
||||
if (!empty($params['keyword'])) {
|
||||
$keyword = $params['keyword'];
|
||||
$query->where(function($q) use ($keyword) {
|
||||
$q->whereOr('nickname', 'like', "%{$keyword}%")
|
||||
->whereOr('conRemark', 'like', "%{$keyword}%")
|
||||
->whereOr('alias', 'like', "%{$keyword}%")
|
||||
->whereOr("JSON_SEARCH(labels, 'one', '%{$keyword}%') IS NOT NULL");
|
||||
});
|
||||
}
|
||||
|
||||
// 计算总数
|
||||
$total = $query->count();
|
||||
|
||||
// 分页查询数据
|
||||
$friends = $query->page($page, $limit)
|
||||
->order('createTime desc')
|
||||
->field('wechatId, alias, avatar, labels, accountNickname, accountRealName, nickname, conRemark, gender, region')
|
||||
->select();
|
||||
|
||||
return [
|
||||
'list' => $friends,
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'limit' => $limit
|
||||
];
|
||||
}
|
||||
}
|
||||
48
Server/application/cunkebao/validate/Task.php
Normal file
48
Server/application/cunkebao/validate/Task.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
namespace app\cunkebao\validate;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
/**
|
||||
* 任务验证器
|
||||
*/
|
||||
class Task extends Validate
|
||||
{
|
||||
/**
|
||||
* 验证规则
|
||||
* @var array
|
||||
*/
|
||||
protected $rule = [
|
||||
'name' => 'require|max:100',
|
||||
'device_id' => 'number',
|
||||
'scene_id' => 'number',
|
||||
'scene_config' => 'array',
|
||||
'status' => 'in:0,1,2,3',
|
||||
'priority' => 'between:1,10',
|
||||
'created_by' => 'number'
|
||||
];
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
* @var array
|
||||
*/
|
||||
protected $message = [
|
||||
'name.require' => '任务名称不能为空',
|
||||
'name.max' => '任务名称不能超过100个字符',
|
||||
'device_id.number' => '设备ID必须是数字',
|
||||
'scene_id.number' => '场景ID必须是数字',
|
||||
'scene_config.array'=> '场景配置必须是数组',
|
||||
'status.in' => '状态值无效',
|
||||
'priority.between' => '优先级必须在1到10之间',
|
||||
'created_by.number' => '创建者ID必须是数字'
|
||||
];
|
||||
|
||||
/**
|
||||
* 验证场景
|
||||
* @var array
|
||||
*/
|
||||
protected $scene = [
|
||||
'create' => ['name', 'device_id', 'scene_id', 'scene_config', 'status', 'priority', 'created_by'],
|
||||
'update' => ['name', 'device_id', 'scene_id', 'scene_config', 'status', 'priority']
|
||||
];
|
||||
}
|
||||
51
Server/application/cunkebao/validate/Traffic.php
Normal file
51
Server/application/cunkebao/validate/Traffic.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
namespace app\cunkebao\validate;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
/**
|
||||
* 流量验证器
|
||||
*/
|
||||
class Traffic extends Validate
|
||||
{
|
||||
/**
|
||||
* 验证规则
|
||||
* @var array
|
||||
*/
|
||||
protected $rule = [
|
||||
'mobile' => 'require|mobile',
|
||||
'gender' => 'in:0,1,2',
|
||||
'age' => 'number|between:0,120',
|
||||
'tags' => 'max:255',
|
||||
'province' => 'max:50',
|
||||
'city' => 'max:50',
|
||||
'source_channel' => 'max:50',
|
||||
'source_detail' => 'array'
|
||||
];
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
* @var array
|
||||
*/
|
||||
protected $message = [
|
||||
'mobile.require' => '手机号不能为空',
|
||||
'mobile.mobile' => '手机号格式不正确',
|
||||
'gender.in' => '性别值无效',
|
||||
'age.number' => '年龄必须是数字',
|
||||
'age.between' => '年龄必须在0到120之间',
|
||||
'tags.max' => '标签不能超过255个字符',
|
||||
'province.max' => '省份不能超过50个字符',
|
||||
'city.max' => '城市不能超过50个字符',
|
||||
'source_channel.max' => '来源渠道不能超过50个字符',
|
||||
'source_detail.array'=> '来源详情必须是数组'
|
||||
];
|
||||
|
||||
/**
|
||||
* 验证场景
|
||||
* @var array
|
||||
*/
|
||||
protected $scene = [
|
||||
'create' => ['mobile', 'gender', 'age', 'tags', 'province', 'city', 'source_channel', 'source_detail'],
|
||||
'update' => ['gender', 'age', 'tags', 'province', 'city']
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user