SystemTimerServices.php 9.5 KB

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