JobRun.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. <?php
  2. namespace App\Module\System\Models;
  3. use UCore\ModelCore;
  4. /**
  5. * 队列运行记录模型
  6. *
  7. * field start
  8. * @property int $id
  9. * @property string $queue 队列名称
  10. * @property string $payload 任务载荷
  11. * @property string $runclass 运行类
  12. * @property int $attempts 尝试次数
  13. * @property int $reserved_at 保留时间
  14. * @property int $available_at 可用时间
  15. * @property int $created_at 创建时间
  16. * @property string $status 运行状态
  17. * @property string $desc 描述信息
  18. * @property float $runtime 运行时间
  19. * field end
  20. *
  21. */
  22. class JobRun extends ModelCore
  23. {
  24. protected $table = 'job_runs';
  25. public $timestamps = false;
  26. protected $fillable = [
  27. 'queue',
  28. 'payload',
  29. 'runclass',
  30. 'attempts',
  31. 'reserved_at',
  32. 'available_at',
  33. 'created_at',
  34. 'status',
  35. 'desc',
  36. 'runtime'
  37. ];
  38. protected $casts = [
  39. 'payload' => 'array',
  40. 'attempts' => 'integer',
  41. 'reserved_at' => 'integer',
  42. 'available_at' => 'integer',
  43. 'created_at' => 'integer',
  44. 'runtime' => 'float'
  45. ];
  46. protected $appends = [
  47. 'queue_name',
  48. 'run_class_name',
  49. 'created_at_formatted',
  50. 'available_at_formatted',
  51. 'reserved_at_formatted',
  52. 'status_label',
  53. 'status_color',
  54. 'runtime_formatted',
  55. 'job_class',
  56. 'desc_short',
  57. 'job_parameters',
  58. 'job_parameters_short'
  59. ];
  60. //attrlist start
  61. public static $attrlist = [
  62. 'id',
  63. 'queue',
  64. 'payload',
  65. 'runclass',
  66. 'attempts',
  67. 'reserved_at',
  68. 'available_at',
  69. 'created_at',
  70. 'status',
  71. 'desc',
  72. 'runtime'
  73. ];
  74. //attrlist end
  75. /**
  76. * 获取队列名称访问器
  77. */
  78. public function getQueueNameAttribute(): string
  79. {
  80. return $this->queue ?? 'default';
  81. }
  82. /**
  83. * 获取运行类名访问器
  84. */
  85. public function getRunClassNameAttribute(): string
  86. {
  87. if (!$this->runclass) {
  88. return '';
  89. }
  90. // 提取类名(去掉命名空间)
  91. $parts = explode('\\', $this->runclass);
  92. return end($parts);
  93. }
  94. /**
  95. * 获取格式化的创建时间
  96. */
  97. public function getCreatedAtFormattedAttribute(): string
  98. {
  99. return $this->created_at ? date('Y-m-d H:i:s', $this->created_at) : '';
  100. }
  101. /**
  102. * 获取格式化的可用时间
  103. */
  104. public function getAvailableAtFormattedAttribute(): string
  105. {
  106. return $this->available_at ? date('Y-m-d H:i:s', $this->available_at) : '';
  107. }
  108. /**
  109. * 获取格式化的保留时间
  110. */
  111. public function getReservedAtFormattedAttribute(): string
  112. {
  113. return $this->reserved_at ? date('Y-m-d H:i:s', $this->reserved_at) : '';
  114. }
  115. /**
  116. * 获取状态标签
  117. */
  118. public function getStatusLabelAttribute(): string
  119. {
  120. $status = $this->status;
  121. // 处理带数字后缀的状态
  122. if (strpos($status, 'runend-') === 0) {
  123. return '已完成';
  124. }
  125. if (strpos($status, 'run-') === 0) {
  126. return '运行中';
  127. }
  128. switch ($status) {
  129. case 'success':
  130. case 'run-end':
  131. return '已完成';
  132. case 'failed':
  133. case 'error':
  134. return '失败';
  135. case 'running':
  136. case 'run':
  137. return '运行中';
  138. case 'pending':
  139. case 'wait':
  140. return '待处理';
  141. default:
  142. return $status ?? '未知';
  143. }
  144. }
  145. /**
  146. * 获取状态颜色
  147. */
  148. public function getStatusColorAttribute(): string
  149. {
  150. $status = $this->status;
  151. // 处理带数字后缀的状态
  152. if (strpos($status, 'runend-') === 0) {
  153. return 'success';
  154. }
  155. if (strpos($status, 'run-') === 0) {
  156. return 'warning';
  157. }
  158. switch ($status) {
  159. case 'success':
  160. case 'run-end':
  161. return 'success';
  162. case 'failed':
  163. case 'error':
  164. return 'danger';
  165. case 'running':
  166. case 'run':
  167. return 'warning';
  168. case 'pending':
  169. case 'wait':
  170. return 'info';
  171. default:
  172. return 'secondary';
  173. }
  174. }
  175. /**
  176. * 获取格式化的运行时间
  177. */
  178. public function getRuntimeFormattedAttribute(): string
  179. {
  180. if (!$this->runtime) {
  181. return '';
  182. }
  183. if ($this->runtime < 1) {
  184. return round($this->runtime * 1000, 2) . 'ms';
  185. } else {
  186. return round($this->runtime, 3) . 's';
  187. }
  188. }
  189. /**
  190. * 获取任务类名(从payload中提取)
  191. */
  192. public function getJobClassAttribute(): string
  193. {
  194. if (!$this->payload) {
  195. return $this->runclass ?? '';
  196. }
  197. $payload = is_array($this->payload) ? $this->payload : json_decode($this->payload, true);
  198. return $payload['displayName'] ?? $payload['job'] ?? $this->runclass ?? '';
  199. }
  200. /**
  201. * 获取描述信息(截断)
  202. */
  203. public function getDescShortAttribute(): string
  204. {
  205. if (!$this->desc) {
  206. return '';
  207. }
  208. return mb_strlen($this->desc) > 100 ? mb_substr($this->desc, 0, 100) . '...' : $this->desc;
  209. }
  210. /**
  211. * 获取任务参数 - 直接反序列化payload原样展示
  212. */
  213. public function getJobParametersAttribute(): string
  214. {
  215. if (!$this->payload) {
  216. return '无参数';
  217. }
  218. // 尝试反序列化payload
  219. $payload = $this->payload;
  220. // 如果是字符串,尝试反序列化
  221. if (is_string($payload)) {
  222. // 去掉外层引号
  223. $payload = trim($payload, '"');
  224. // 尝试反序列化PHP数组
  225. if (strpos($payload, 'a:') === 0) {
  226. try {
  227. $unserialized = unserialize($payload);
  228. if (is_array($unserialized)) {
  229. return $this->formatArrayForDisplay($unserialized);
  230. }
  231. } catch (\Exception) {
  232. // 反序列化失败,返回原始字符串
  233. return $payload;
  234. }
  235. } else {
  236. // 尝试JSON解码
  237. $decoded = json_decode($payload, true);
  238. if (json_last_error() === JSON_ERROR_NONE) {
  239. return $this->formatArrayForDisplay($decoded);
  240. }
  241. }
  242. }
  243. // 如果已经是数组,直接格式化
  244. if (is_array($payload)) {
  245. return $this->formatArrayForDisplay($payload);
  246. }
  247. // 其他情况返回原始内容
  248. return is_scalar($payload) ? (string)$payload : json_encode($payload);
  249. }
  250. /**
  251. * 格式化数组为显示字符串
  252. */
  253. private function formatArrayForDisplay(array $data): string
  254. {
  255. $result = [];
  256. foreach ($data as $key => $value) {
  257. if (is_array($value)) {
  258. $result[] = $key . ': ' . json_encode($value, JSON_UNESCAPED_UNICODE);
  259. } elseif (is_object($value)) {
  260. $result[] = $key . ': ' . json_encode($value, JSON_UNESCAPED_UNICODE);
  261. } elseif (is_bool($value)) {
  262. $result[] = $key . ': ' . ($value ? 'true' : 'false');
  263. } elseif (is_null($value)) {
  264. $result[] = $key . ': null';
  265. } else {
  266. $result[] = $key . ': ' . $value;
  267. }
  268. }
  269. return implode(', ', $result);
  270. }
  271. /**
  272. * 获取简化的任务参数(用于列表显示)
  273. */
  274. public function getJobParametersShortAttribute(): string
  275. {
  276. $params = $this->job_parameters;
  277. if (mb_strlen($params) > 50) {
  278. return mb_substr($params, 0, 50) . '...';
  279. }
  280. return $params;
  281. }
  282. }