SystemCrontabServices.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. <?php
  2. namespace app\services\system\crontab;
  3. use app\dao\system\crontab\SystemCrontabDao;
  4. use app\services\activity\combination\StorePinkServices;
  5. use app\services\activity\live\LiveGoodsServices;
  6. use app\services\activity\live\LiveRoomServices;
  7. use app\services\agent\AgentManageServices;
  8. use app\services\BaseServices;
  9. use app\services\order\StoreOrderServices;
  10. use app\services\order\StoreOrderTakeServices;
  11. use app\services\product\product\StoreProductServices;
  12. use app\services\system\attachment\SystemAttachmentServices;
  13. use crmeb\exceptions\AdminException;
  14. use think\facade\Log;
  15. class SystemCrontabServices extends BaseServices
  16. {
  17. /**
  18. * 定时任务类型
  19. * @var string[]
  20. */
  21. private $markList = [
  22. 'order_cancel' => '未支付自动取消订单',
  23. 'pink_expiration' => '拼团到期订单处理',
  24. 'agent_unbind' => '到期自动解绑上级',
  25. 'live_product_status' => '自动更新直播商品状态',
  26. 'live_room_status' => '自动更新直播间状态',
  27. 'take_delivery' => '订单自动收货',
  28. 'advance_off' => '预售商品到期自动下架',
  29. 'product_replay' => '订单商品自动好评',
  30. 'clear_poster' => '清除昨日海报',
  31. ];
  32. public function __construct(SystemCrontabDao $dao)
  33. {
  34. $this->dao = $dao;
  35. }
  36. /**
  37. * 定时任务列表
  38. * @param array $where
  39. * @return array
  40. * @throws \think\db\exception\DataNotFoundException
  41. * @throws \think\db\exception\DbException
  42. * @throws \think\db\exception\ModelNotFoundException
  43. */
  44. public function getTimerList(array $where = [])
  45. {
  46. [$page, $limit] = $this->getPageValue();
  47. $list = $this->dao->selectList($where, '*', $page, $limit, 'id desc');
  48. foreach ($list as &$item) {
  49. $item['next_execution_time'] = date('Y-m-d H:i:s', $item['next_execution_time']);
  50. $item['last_execution_time'] = $item['last_execution_time'] != 0 ? date('Y-m-d H:i:s', $item['last_execution_time']) : '暂未执行';
  51. }
  52. $count = $this->dao->count($where);
  53. return compact('list', 'count');
  54. }
  55. /**
  56. * 定时任务详情
  57. * @param $id
  58. * @return array
  59. * @throws \think\db\exception\DataNotFoundException
  60. * @throws \think\db\exception\DbException
  61. * @throws \think\db\exception\ModelNotFoundException
  62. */
  63. public function getTimerInfo($id)
  64. {
  65. $info = $this->dao->get($id);
  66. if (!$info) throw new AdminException(100026);
  67. return $info->toArray();
  68. }
  69. /**
  70. * 定时任务类型
  71. * @return string[]
  72. */
  73. public function getMarkList(): array
  74. {
  75. return $this->markList;
  76. }
  77. /**
  78. * 保存定时任务
  79. * @param array $data
  80. * @return bool
  81. */
  82. public function saveTimer(array $data = [])
  83. {
  84. if (!$data['id'] && $this->dao->getCount(['mark' => $data['mark'], 'is_del' => 0])) {
  85. throw new AdminException('该定时任务已存在,请勿重复添加');
  86. }
  87. $data['name'] = $this->markList[$data['mark']];
  88. $data['add_time'] = time();
  89. if (!$data['id']) {
  90. unset($data['id']);
  91. $res = $this->dao->save($data);
  92. } else {
  93. $res = $this->dao->update(['id' => $data['id']], $data);
  94. }
  95. if (!$res) throw new AdminException(100006);
  96. return true;
  97. }
  98. /**
  99. * 删除定时任务
  100. * @param $id
  101. * @return bool
  102. */
  103. public function delTimer($id)
  104. {
  105. $res = $this->dao->update(['id' => $id], ['is_del' => 1]);
  106. if (!$res) throw new AdminException(100008);
  107. return true;
  108. }
  109. /**
  110. * 设置定时任务状态
  111. * @param $id
  112. * @param $is_open
  113. * @return bool
  114. */
  115. public function setTimerStatus($id, $is_open)
  116. {
  117. $res = $this->dao->update(['id' => $id], ['is_open' => $is_open]);
  118. if (!$res) throw new AdminException(100014);
  119. return true;
  120. }
  121. /**
  122. * 计算定时任务下次执行时间
  123. * @param $data
  124. * @param int $time
  125. * @return false|float|int|mixed
  126. */
  127. public function getTimerCycleTime($data, $time = 0)
  128. {
  129. if (!$time) $time = time();
  130. switch ($data['type']) {
  131. case 1: // 每隔几秒
  132. $cycle_time = $time + $data['second'];
  133. break;
  134. case 2: // 每隔几分
  135. $cycle_time = $time + ($data['minute'] * 60);
  136. break;
  137. case 3: // 每隔几时
  138. $cycle_time = $time + ($data['hour'] * 3600) + ($data['minute'] * 60);
  139. break;
  140. case 4: // 每隔几日
  141. $cycle_time = $time + ($data['day'] * 86400) + ($data['hour'] * 3600) + ($data['minute'] * 60);
  142. break;
  143. case 5: // 每日几时几分几秒
  144. $cycle_time = strtotime(date('Y-m-d ' . $data['hour'] . ':' . $data['minute'] . ':' . $data['second'], time()));
  145. if ($time >= $cycle_time) {
  146. $cycle_time = $cycle_time + 86400;
  147. }
  148. break;
  149. case 6: // 每周周几几时几分几秒
  150. $todayStart = strtotime(date('Y-m-d 00:00:00', time()));
  151. $w = date("w");
  152. if ($w > $data['week']) {
  153. $cycle_time = $todayStart + ((7 - $w + $data['week']) * 86400) + ($data['hour'] * 3600) + ($data['minute'] * 60) + $data['second'];
  154. } else if ($w == $data['week']) {
  155. $cycle_time = $todayStart + ($data['hour'] * 3600) + ($data['minute'] * 60) + $data['second'];
  156. if ($time >= $cycle_time) {
  157. $cycle_time = $cycle_time + (7 * 86400);
  158. }
  159. } else {
  160. $cycle_time = $todayStart + (($data['week'] - $w) * 86400) + ($data['hour'] * 3600) + ($data['minute'] * 60) + $data['second'];
  161. }
  162. break;
  163. case 7: // 每月几日几时几分几秒
  164. $d = date("d");
  165. $firstDate = date('Y-m-01', time());
  166. $maxDay = date('d', strtotime("$firstDate + 1 month -1 day"));
  167. $todayStart = strtotime(date('Y-m-d 00:00:00', time()));
  168. if ($d > $data['day']) {
  169. $cycle_time = $todayStart + (($maxDay - $d + $data['day']) * 86400) + ($data['hour'] * 3600) + ($data['minute'] * 60) + $data['second'];
  170. } elseif ($d == $data['day']) {
  171. $cycle_time = $todayStart + ($data['hour'] * 3600) + ($data['minute'] * 60) + $data['second'];
  172. if ($time >= $cycle_time) {
  173. $cycle_time = $cycle_time + (($maxDay - $d + $data['day']) * 86400) + ($data['hour'] * 3600) + ($data['minute'] * 60) + $data['second'];
  174. }
  175. } else {
  176. $cycle_time = $todayStart + (($data['day'] - $d) * 86400) + ($data['hour'] * 3600) + ($data['minute'] * 60) + $data['second'];
  177. }
  178. break;
  179. default:
  180. $cycle_time = 0;
  181. break;
  182. }
  183. return $cycle_time;
  184. }
  185. /**
  186. * 执行任务
  187. * @throws \think\db\exception\DataNotFoundException
  188. * @throws \think\db\exception\DbException
  189. * @throws \think\db\exception\ModelNotFoundException
  190. * @author 吴汐
  191. * @email 442384644@qq.com
  192. * @date 2023/02/17
  193. */
  194. public function crontabRun()
  195. {
  196. $time = time();
  197. file_put_contents(root_path() . 'runtime/.timer', $time); //检测定时任务是否正常
  198. $list = $this->dao->selectList(['is_open' => 1, 'is_del' => 0])->toArray();
  199. foreach ($list as $item) {
  200. if ($item['next_execution_time'] < $time) {
  201. if ($item['mark'] == 'order_cancel') {
  202. //未支付自动取消订单
  203. app()->make(StoreOrderServices::class)->orderUnpaidCancel();
  204. $this->crontabLog(' 执行未支付自动取消订单');
  205. } elseif ($item['mark'] == 'pink_expiration') {
  206. //拼团到期订单处理
  207. app()->make(StorePinkServices::class)->statusPink();
  208. $this->crontabLog(' 执行拼团到期订单处理');
  209. } elseif ($item['mark'] == 'agent_unbind') {
  210. //自动解绑上级绑定
  211. app()->make(AgentManageServices::class)->removeSpread();
  212. $this->crontabLog(' 执行自动解绑上级绑定');
  213. } elseif ($item['mark'] == 'live_product_status') {
  214. //更新直播商品状态
  215. app()->make(LiveGoodsServices::class)->syncGoodStatus();
  216. $this->crontabLog(' 执行更新直播商品状态');
  217. } elseif ($item['mark'] == 'live_room_status') {
  218. //更新直播间状态
  219. app()->make(LiveRoomServices::class)->syncRoomStatus();
  220. $this->crontabLog(' 执行更新直播间状态');
  221. } elseif ($item['mark'] == 'take_delivery') {
  222. //自动收货
  223. app()->make(StoreOrderTakeServices::class)->autoTakeOrder();
  224. $this->crontabLog(' 执行自动收货');
  225. } elseif ($item['mark'] == 'advance_off') {
  226. //查询预售到期商品自动下架
  227. app()->make(StoreProductServices::class)->downAdvance();
  228. $this->crontabLog(' 执行预售到期商品自动下架');
  229. } elseif ($item['mark'] == 'product_replay') {
  230. //自动好评
  231. app()->make(StoreOrderServices::class)->autoComment();
  232. $this->crontabLog(' 执行自动好评');
  233. } elseif ($item['mark'] == 'clear_poster') {
  234. //清除昨日海报
  235. app()->make(SystemAttachmentServices::class)->emptyYesterdayAttachment();
  236. $this->crontabLog(' 执行清除昨日海报');
  237. }
  238. //写入本次执行时间和下次执行时间
  239. $this->dao->update(['mark' => $item['mark']], ['last_execution_time' => $time, 'next_execution_time' => $this->getTimerCycleTime($item)]);
  240. }
  241. }
  242. }
  243. /**
  244. * 定时任务日志
  245. * @param $msg
  246. * @author 吴汐
  247. * @email 442384644@qq.com
  248. * @date 2023/02/21
  249. */
  250. public function crontabLog($msg)
  251. {
  252. $timer_log_open = config("log.timer_log", false);
  253. if ($timer_log_open) {
  254. $date = date('Y-m-d H:i:s', time());
  255. Log::write($date . $msg, 'crontab');
  256. }
  257. }
  258. }