CostCalculation.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. <?php
  2. namespace app\api\controller;
  3. use app\common\controller\Api;
  4. use think\Db;
  5. use think\Queue;
  6. use think\Request;
  7. class CostCalculation extends Api
  8. {
  9. protected $noNeedLogin = ['*'];
  10. protected $noNeedRight = ['*'];
  11. /**
  12. * 执行成本计算
  13. * @ApiMethod POST
  14. * @param string month 年月
  15. * @param string sys_id 系统ID
  16. */
  17. public function calculate()
  18. {
  19. if (Request::instance()->isGet() == false) {
  20. $this->error('非法请求');
  21. }
  22. $params = Request::instance()->param();
  23. if (!isset($params['month']) || empty($params['month'])) {
  24. $this->error('月份参数错误');
  25. }
  26. $month = trim($params['month']);
  27. $sysId = $params['sys_id'] ?? '';
  28. // 检查是否有正在执行的任务
  29. $runningTask = Db::name('queue_tasks')
  30. ->where('task_type', 'cost_calculation')
  31. ->where('task_data', 'like', '%"month":"' . $month . '"%')
  32. ->where('status', 'in', ['pending', 'processing'])
  33. ->find();
  34. if ($runningTask) {
  35. $this->success('该月份的成本计算任务已在执行中,请勿重复提交');
  36. }
  37. // 检查工资计算是否在执行中(可选)
  38. $salaryRunning = Db::name('queue_tasks')
  39. ->where('task_type', 'salary_calculation')
  40. ->where('task_data', 'like', '%"date":"' . $month . '"%')
  41. ->where('status', 'in', ['pending', 'processing'])
  42. ->find();
  43. if ($salaryRunning) {
  44. $this->error('该月份的工资计算正在执行中,建议等待工资计算完成后再进行成本计算');
  45. }
  46. // 准备任务数据
  47. $taskData = [
  48. 'month' => $month,
  49. 'sys_id' => $sysId,
  50. 'user_id' => session('user_id') ?? 0,
  51. 'user_name' => session('user_name') ?? '系统',
  52. 'request_time' => date('Y-m-d H:i:s')
  53. ];
  54. // 先创建任务记录
  55. $taskId = Db::name('queue_tasks')->insertGetId([
  56. 'task_type' => 'cost_calculation',
  57. 'task_data' => json_encode($taskData, JSON_UNESCAPED_UNICODE),
  58. 'status' => 'pending',
  59. 'queue_name' => 'cost_calculation',
  60. 'create_time' => date('Y-m-d H:i:s')
  61. ]);
  62. // 添加到任务数据中
  63. $taskData['task_id'] = $taskId;
  64. // 提交到成本计算队列
  65. $jobHandlerClassName = 'app\job\UnifiedCostCalculationJob';
  66. $queueName = 'cost_calculation';
  67. $jobId = Queue::push($jobHandlerClassName, $taskData, $queueName);
  68. if ($jobId) {
  69. // 更新任务记录
  70. Db::name('queue_tasks')
  71. ->where('id', $taskId)
  72. ->update([
  73. 'job_id' => $jobId,
  74. 'update_time' => date('Y-m-d H:i:s')
  75. ]);
  76. $this->success('成本计算任务已提交到队列,请稍后查看结果', null, [
  77. 'task_id' => $taskId,
  78. 'job_id' => $jobId,
  79. 'month' => $month,
  80. 'queue_name' => $queueName
  81. ]);
  82. } else {
  83. // 更新任务状态为失败
  84. Db::name('queue_tasks')
  85. ->where('id', $taskId)
  86. ->update([
  87. 'status' => 'failed',
  88. 'error' => '任务提交到队列失败',
  89. 'update_time' => date('Y-m-d H:i:s')
  90. ]);
  91. $this->error('成本计算任务提交失败');
  92. }
  93. }
  94. /**
  95. * 查询成本计算状态
  96. * @ApiMethod GET
  97. * @param string month 年月
  98. */
  99. public function status()
  100. {
  101. $month = Request::instance()->param('month');
  102. if (empty($month)) {
  103. $this->error('月份参数错误');
  104. }
  105. // 查询任务记录
  106. $task = Db::name('queue_tasks')
  107. ->where('task_type', 'cost_calculation')
  108. ->where('task_data', 'like', '%"month":"' . $month . '"%')
  109. ->order('id', 'desc')
  110. ->find();
  111. if ($task) {
  112. $result = json_decode($task['result'] ?? '{}', true);
  113. $taskData = json_decode($task['task_data'] ?? '{}', true);
  114. $response = [
  115. 'exists' => true,
  116. 'task_id' => $task['id'],
  117. 'month' => $month,
  118. 'status' => $task['status'],
  119. 'queue_name' => $task['queue_name'],
  120. 'job_id' => $task['job_id'],
  121. 'start_time' => $task['start_time'],
  122. 'end_time' => $task['end_time'],
  123. 'retry_count' => $task['retry_count'],
  124. 'result' => $result,
  125. 'error' => $task['error'] ?? '',
  126. 'create_time' => $task['create_time'],
  127. 'user_info' => [
  128. 'user_id' => $taskData['user_id'] ?? 0,
  129. 'user_name' => $taskData['user_name'] ?? ''
  130. ]
  131. ];
  132. } else {
  133. $response = ['exists' => false, 'month' => $month];
  134. }
  135. $this->success('查询成功', null, $response);
  136. }
  137. /**
  138. * 获取成本计算任务列表
  139. * @ApiMethod GET
  140. */
  141. public function list()
  142. {
  143. $page = Request::instance()->param('page', 1);
  144. $limit = Request::instance()->param('limit', 20);
  145. $month = Request::instance()->param('month');
  146. $status = Request::instance()->param('status');
  147. $query = Db::name('queue_tasks')
  148. ->where('task_type', 'cost_calculation');
  149. if ($month) {
  150. $query->where('task_data', 'like', '%"month":"' . $month . '"%');
  151. }
  152. if ($status) {
  153. $query->where('status', $status);
  154. }
  155. $total = $query->count();
  156. $list = $query->order('id', 'desc')
  157. ->page($page, $limit)
  158. ->select();
  159. // 解析任务数据
  160. foreach ($list as &$item) {
  161. $taskData = json_decode($item['task_data'] ?? '{}', true);
  162. $item['month'] = $taskData['month'] ?? '';
  163. $item['user_name'] = $taskData['user_name'] ?? '';
  164. $item['request_time'] = $taskData['request_time'] ?? '';
  165. if (!empty($item['result'])) {
  166. $item['result_data'] = json_decode($item['result'], true);
  167. }
  168. }
  169. $this->success('查询成功', null, [
  170. 'list' => $list,
  171. 'total' => $total,
  172. 'page' => $page,
  173. 'pages' => ceil($total / $limit)
  174. ]);
  175. }
  176. /**
  177. * 手动重试失败的任务
  178. * @ApiMethod POST
  179. * @param int task_id 任务ID
  180. */
  181. public function retry()
  182. {
  183. $taskId = Request::instance()->param('task_id');
  184. if (empty($taskId)) {
  185. $this->error('任务ID不能为空');
  186. }
  187. $task = Db::name('queue_tasks')
  188. ->where('id', $taskId)
  189. ->where('task_type', 'cost_calculation')
  190. ->where('status', 'failed')
  191. ->find();
  192. if (!$task) {
  193. $this->error('任务不存在或无法重试');
  194. }
  195. // 解析原任务数据
  196. $taskData = json_decode($task['task_data'], true);
  197. $taskData['task_id'] = $taskId;
  198. $taskData['retry_time'] = date('Y-m-d H:i:s');
  199. // 更新原任务状态
  200. Db::name('queue_tasks')
  201. ->where('id', $taskId)
  202. ->update([
  203. 'status' => 'retrying',
  204. 'update_time' => date('Y-m-d H:i:s')
  205. ]);
  206. // 提交到队列
  207. $jobHandlerClassName = 'app\job\CostCalculationJob';
  208. $queueName = 'cost_calculation';
  209. $jobId = Queue::push($jobHandlerClassName, $taskData, $queueName);
  210. if ($jobId) {
  211. $this->success('任务已重新提交到队列', null, [
  212. 'task_id' => $taskId,
  213. 'new_job_id' => $jobId,
  214. 'queue_name' => $queueName
  215. ]);
  216. } else {
  217. $this->error('任务重试失败');
  218. }
  219. }
  220. }