<?php /** * Created by PhpStorm. * 自动提醒 未完成任务人员 * User: zhoutao * Date: 2017/12/2 * Time: 下午2:53 */ namespace Frontend\Controller\Crontab; use Common\Model\CustomtaskModel; use Common\Model\CustomtaskRightModel; use Common\Model\UserTaskModel; use Common\Service\CustomtaskRightService; use Common\Service\CustomtaskService; use Common\Service\UserTaskService; use Think\Log; use VcySDK\Member; use VcySDK\Message; use VcySDK\Service; /** * Class TaskReminderController * @property CustomtaskService $customtaskServ * @property CustomtaskRightService $customtaskRightServ * @property Message $messageSdk * @property UserTaskService $userTaskServ * @property Member $userServ */ class TaskReminderController extends AbstractController { /** * 任务翻页 单次处理个数 */ const DEAL_TASK_PAGE_LIMIT = 5; /** * Crontab 执行时间区间 (单位: 分钟) */ const CRONTAB_CYCLE_TIMES = 5; /** * 常规任务权限表: 全公司 */ const RIGHT_ALL = 1; /** * 人员处理单次处理个数 */ const DEAL_MEMBER_LIMIT = 500; /** * customtaskServ * @var null */ protected $customtaskServ = null; /** * $customtaskRightServ * @var null */ protected $customtaskRightServ = null; /** * 消息 * @var null */ protected $messageSdk = null; /** * 用户常规任务进度表 * @var null */ protected $userTaskServ = null; /** * 用户 * @var null */ protected $userServ = null; public function index() { set_time_limit(0); \Think\Log::record('开始自动提醒' . "\n"); $this->customtaskServ = new CustomtaskService(); $this->customtaskRightServ = new CustomtaskRightService(); $this->userTaskServ = new UserTaskService(); // 查询在 任务时间范围内 的任务 $taskTotal = $this->customtaskServ->countReminder([ // 在任务时间范围内 'start_time <= ?' => MILLI_TIME, 'end_time >= ?' => MILLI_TIME, // 任务进行中 'task_status' => CustomtaskModel::TASK_STATUS_ING, // 开启了定时提醒 'is_auto_remind' => CustomtaskModel::IS_AUTO_REMIND_TRUE ]); \Think\Log::record("\n共有 {$taskTotal} 任务\n", Log::INFO); // 翻页处理 防止单次查询出来过多 内存溢出 $time = ceil($taskTotal / self::DEAL_TASK_PAGE_LIMIT); for ($page = 1; $page <= $time; $page ++) { \Think\Log::record("\n处理第 {$page} 页\n", Log::INFO); try { $this->dealPageTask($page); } catch (\Exception $e) { \Think\Log::record("\n处理第 {$page} 页时发生错误\n" . $e->getMessage()); } \Think\Log::record("\n结束 处理第 {$page} 页\n", Log::INFO); } return true; } /** * 批量处理任务提醒 * @param $page * @return bool */ private function dealPageTask($page) { // 查询任务 list($page, $limit) = page_limit($page, self::DEAL_TASK_PAGE_LIMIT); $taskList = $this->customtaskServ->listReminder([ // 在任务时间范围内 'start_time <= ?' => MILLI_TIME, 'end_time >= ?' => MILLI_TIME, // 任务进行中 'task_status' => CustomtaskModel::TASK_STATUS_ING, // 开启了定时提醒 'is_auto_remind' => CustomtaskModel::IS_AUTO_REMIND_TRUE ], [$page, $limit], [], // 取用到的字段 implode( ',', [ 'customtask_id', 'interval_time', 'reminder_time', 'start_time', 'end_time', 'domain', 'task_name', ] ) ); // 遍历每个任务 foreach ($taskList as $item) { // 提醒周期时间长度 $intervalTime = $item['interval_time'] * 3600 * 1000; // 提醒时间点 $reminderTime = // 如果没有最近一次提醒时间 那就从任务开始时间加上周期时间 (小时 -> 毫秒) (empty($item['reminder_time']) ? $item['start_time'] : $item['reminder_time']) + $intervalTime; // 如果当前时间 和 上一次提醒时间 相差超过一个提醒周期 if (MILLI_TIME > $reminderTime) { // 把周期时间补上 $reminderTime += ceil((MILLI_TIME - $reminderTime) / ($intervalTime)) * $intervalTime; } // 在 Crontab 执行时间区间 (当前时间 到 当前时间加上 Crontab 执行区间时间 为范围) $inReminderRange = ($reminderTime >= MILLI_TIME) && // (分钟 -> 毫秒) ($reminderTime <= (MILLI_TIME + self::CRONTAB_CYCLE_TIMES * 60 * 1000)); // 提醒时间点不在 此次提醒点 if (!$inReminderRange) { continue; } // 初始化 SDK $config = array( 'apiUrl' => cfg('UC_APIURL'), 'enumber' => $item['domain'], 'pluginIdentifier' => 'yuanquan', 'thirdIdentifier' => cfg('SDK_THIRD_IDENTIFIER'), 'logPath' => RUNTIME_PATH . '/Logs/VcySDK/', 'apiSecret' => cfg('API_SECRET'), 'apiSigExpire' => cfg('API_SIG_EXPIRE'), 'fileConvertApiUrl' => cfg('FILE_CONVERT_API_URL') ); $service = &Service::instance(); $service->initSdk($config); $this->messageSdk = new Message($service); $this->userServ = new Member($service); // 处理单个任务提醒 try { $this->dealSingleTask($item); } catch (\Exception $e) { \Think\Log::record("\n处理ID: {$item['customtask_id']} 任务提醒时发生错误\n" . $e->getMessage()); } // 更新提醒时间 $this->customtaskServ->updateWithOutDomain($item['customtask_id'], ['reminder_time' => $reminderTime]); } return true; } /** * 处理单个任务提醒 * @param $task * @return bool */ private function dealSingleTask($task) { // 格式化发送的信息 if (mb_strlen($task['task_name']) > 20) { $task['task_name'] = mb_substr($task['task_name'], 0, 20) . '...'; } $task['start_time'] = rgmdate($task['start_time'], 'Y-m-d H:i'); $task['end_time'] = rgmdate($task['end_time'], 'Y-m-d H:i'); $msg = [ 'articles' => [[ 'title' => cfg('NOTICE_PREFIX', null, '') . '您还有一个任务未完成,赶紧处理下吧', 'description' => "任务名称:{$task['task_name']}\n任务时间:{$task['start_time']}~{$task['end_time']}", 'url' => oaUrl( 'Frontend/Index/Detail/Index', ['customtask_id' => $task['customtask_id']], $task['domain'] ), ]] ]; // 权限对象 $rightList = $this->customtaskRightServ->listWithOutDomian(['customtask_id' => $task['customtask_id']]); // 完成人员 $completeList = $this->userTaskServ->listWithOutDomian([ 'customtask_id' => $task['customtask_id'], 'complete_status' => UserTaskModel::COMPLETE_STATUS_OVER ], [], [], 'uid'); $completeList = empty($completeList) ? [] : array_column($completeList, 'uid'); // 如果全公司 if (in_array(self::RIGHT_ALL, array_column($rightList, 'obj_type'))) { // 如果有完成的人员 if (!empty($completeList)) { // 则过滤 $userResult = $this->userServ->listAll([], 1, self::DEAL_MEMBER_LIMIT); $userList = array_column($userResult['list'], 'memUid'); // 去掉已经完成的人员 $msg['toUser'] = array_diff($userList, $completeList); $this->sendNews($msg); // 继续剩下的页数 $times = ceil($userResult['total'] / self::DEAL_MEMBER_LIMIT); for ($i = 2; $i <= $times; $i ++) { $userResult = $this->userServ->listAll([], $i, self::DEAL_MEMBER_LIMIT); $userList = array_column($userResult['list'], 'memUid'); // 去掉已经完成的人员 $msg['toUser'] = array_diff($userList, $completeList); $this->sendNews($msg); } } else { // 没有就发送 $msg['toUser'] = '@all'; $this->sendNews($msg); } return true; } else { $targeList = []; // 目标 $targeConds = []; foreach ($rightList as $item) { switch ($item['obj_type']) { // 部门 case CustomtaskRightModel::OBJ_TYPE_DEP: $targeConds['dpIdList'][] = $item['obj_id']; // 获取子部门 $targeConds['departmentChildrenFlag'] = 1; break; // 人员 case CustomtaskRightModel::OBJ_TYPE_MEMBER: $targeConds['memUids'][] = $item['obj_id']; break; // 职位 case CustomtaskRightModel::OBJ_TYPE_JOB: $targeConds['jobIdList'][] = $item['obj_id']; break; // 角色 case CustomtaskRightModel::OBJ_TYPE_ROLE: $targeConds['roleIdList'][] = $item['obj_id']; break; default: break; } } if (empty($targeConds)) { return true; } // 获取人员列表 (第一页查询) $userResult = $this->userServ->listAll($targeConds, 1, self::DEAL_MEMBER_LIMIT); $userList = array_column($userResult['list'], 'memUid'); // 合并上 设置里的 人员 $userList = array_merge($userList, $targeList); // 去掉已经完成的人员 $msg['toUser'] = array_diff($userList, $completeList); $this->sendNews($msg); // 发完了 if ($userResult['total'] <= self::DEAL_MEMBER_LIMIT) { return true; } // 已经发送过的人员 $completeList = array_merge($completeList, $targeList); // 继续剩下的页数 $times = ceil($userResult['total'] / self::DEAL_MEMBER_LIMIT); for ($i = 2; $i <= $times; $i ++) { $userResult = $this->userServ->listAll($targeConds, $i, self::DEAL_MEMBER_LIMIT); $userList = array_column($userResult['list'], 'memUid'); // 去掉已经完成的人员 $msg['toUser'] = array_diff($userList, $completeList); $this->sendNews($msg); } } return true; } /** * 发送消息 * @param $msg * @return bool */ private function sendNews($msg) { $msg['toUser'] = implode('|', $msg['toUser']); try { $this->messageSdk->sendNews($msg); } catch (\Exception $e) { \Think\Log::record('发送消息出错:::' . $e->getMessage()); } return true; } }