erp-backend/app/Services/PrintJobService.php
2026-04-01 17:07:04 +08:00

340 lines
9.1 KiB
PHP

<?php
namespace App\Services;
use App\Models\PrintJob;
use App\Models\PrintPlugin;
use App\Models\PrintPluginLog;
use App\Models\Order;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
class PrintJobService
{
protected PrintPluginService $pluginService;
public function __construct(PrintPluginService $pluginService)
{
$this->pluginService = $pluginService;
}
/**
* 创建打印任务
*/
public function createJob(
int $userId,
string $platform,
string $pluginCode,
array $printData,
?int $orderId = null,
?int $templateId = null,
int $priority = 0
): array {
$job = PrintJob::create([
'user_id' => $userId,
'job_no' => PrintJob::generateJobNo(),
'order_id' => $orderId,
'platform' => $platform,
'plugin_code' => $pluginCode,
'template_id' => $templateId,
'print_data' => $printData,
'status' => PrintJob::STATUS_PENDING,
'priority' => $priority,
]);
return [
'success' => true,
'job_id' => $job->id,
'job_no' => $job->job_no,
];
}
/**
* 批量创建打印任务
*/
public function createBatchJobs(
int $userId,
string $platform,
string $pluginCode,
array $ordersData,
?int $templateId = null
): array {
$jobs = [];
$failed = [];
foreach ($ordersData as $data) {
try {
$job = PrintJob::create([
'user_id' => $userId,
'job_no' => PrintJob::generateJobNo(),
'order_id' => $data['order_id'] ?? null,
'platform' => $platform,
'plugin_code' => $pluginCode,
'template_id' => $templateId,
'print_data' => $data['print_data'] ?? $data,
'status' => PrintJob::STATUS_PENDING,
'priority' => $data['priority'] ?? 0,
]);
$jobs[] = $job->id;
} catch (\Exception $e) {
$failed[] = $data;
}
}
return [
'success' => count($failed) === 0,
'created' => count($jobs),
'failed' => count($failed),
'job_ids' => $jobs,
];
}
/**
* 获取用户打印队列
*/
public function getQueue(int $userId, ?string $status = null): array
{
$query = PrintJob::where('user_id', $userId);
if ($status) {
$query->where('status', $status);
} else {
$query->whereIn('status', [PrintJob::STATUS_PENDING, PrintJob::STATUS_QUEUED, PrintJob::STATUS_PRINTING]);
}
$jobs = $query->orderByDesc('priority')
->orderBy('created_at')
->paginate(50);
return $jobs->toArray();
}
/**
* 获取下一个待打印任务(从队列中获取)
*/
public function getNextJob(int $userId, string $deviceId): ?PrintJob
{
// 确保设备在线
$deviceStatus = $this->pluginService->getDeviceStatus($userId, $deviceId);
// 获取最高优先级的待处理任务
return PrintJob::where('user_id', $userId)
->whereIn('status', [PrintJob::STATUS_PENDING, PrintJob::STATUS_QUEUED])
->orderByDesc('priority')
->orderBy('created_at')
->first();
}
/**
* 认领打印任务(设备开始打印时调用)
*/
public function claimJob(int $userId, string $deviceId, int $jobId): bool
{
$job = PrintJob::where('id', $jobId)
->where('user_id', $userId)
->whereIn('status', [PrintJob::STATUS_PENDING, PrintJob::STATUS_QUEUED])
->first();
if (!$job) {
return false;
}
$job->markAsPrinting();
PrintPluginLog::record(
$userId,
PrintPluginLog::TYPE_PRINT,
"开始打印任务 {$job->job_no}",
null,
$job->id,
['device_id' => $deviceId, 'platform' => $job->platform]
);
return true;
}
/**
* 标记打印完成
*/
public function completeJob(int $userId, int $jobId, ?string $deviceId = null): bool
{
$job = PrintJob::where('id', $jobId)
->where('user_id', $userId)
->where('status', PrintJob::STATUS_PRINTING)
->first();
if (!$job) {
return false;
}
$job->markAsCompleted();
PrintPluginLog::record(
$userId,
PrintPluginLog::TYPE_PRINT,
"打印任务 {$job->job_no} 完成",
null,
$job->id,
['device_id' => $deviceId]
);
// 如果有订单,更新订单状态
if ($job->order_id) {
Order::where('id', $job->order_id)->update([
'print_status' => 'printed',
'printed_at' => now(),
]);
}
return true;
}
/**
* 标记打印失败
*/
public function failJob(int $userId, int $jobId, string $error, ?string $deviceId = null): bool
{
$job = PrintJob::where('id', $jobId)
->where('user_id', $userId)
->where('status', PrintJob::STATUS_PRINTING)
->first();
if (!$job) {
return false;
}
$job->markAsFailed($error);
PrintPluginLog::record(
$userId,
PrintPluginLog::TYPE_ERROR,
"打印任务 {$job->job_no} 失败: {$error}",
null,
$job->id,
['device_id' => $deviceId, 'error' => $error]
);
return true;
}
/**
* 重试任务
*/
public function retryJob(int $userId, int $jobId): array
{
$job = PrintJob::where('id', $jobId)
->where('user_id', $userId)
->first();
if (!$job) {
return ['success' => false, 'message' => '任务不存在'];
}
if (!$job->canRetry()) {
return ['success' => false, 'message' => '已达到最大重试次数'];
}
$job->update([
'status' => PrintJob::STATUS_QUEUED,
'error_message' => null,
]);
return ['success' => true, 'message' => '任务已重新加入队列'];
}
/**
* 取消任务
*/
public function cancelJob(int $userId, int $jobId): bool
{
$job = PrintJob::where('id', $jobId)
->where('user_id', $userId)
->whereIn('status', [PrintJob::STATUS_PENDING, PrintJob::STATUS_QUEUED])
->first();
if ($job) {
$job->cancel();
return true;
}
return false;
}
/**
* 获取用户的打印历史
*/
public function getHistory(int $userId, int $page = 1, int $perPage = 20): array
{
$jobs = PrintJob::where('user_id', $userId)
->whereIn('status', [PrintJob::STATUS_COMPLETED, PrintJob::STATUS_FAILED, PrintJob::STATUS_CANCELLED])
->orderByDesc('created_at')
->paginate($perPage, ['*'], 'page', $page);
return $jobs->toArray();
}
/**
* 获取任务统计
*/
public function getStats(int $userId): array
{
$pending = PrintJob::where('user_id', $userId)->where('status', PrintJob::STATUS_PENDING)->count();
$printing = PrintJob::where('user_id', $userId)->where('status', PrintJob::STATUS_PRINTING)->count();
$queued = PrintJob::where('user_id', $userId)->where('status', PrintJob::STATUS_QUEUED)->count();
$completedToday = PrintJob::where('user_id', $userId)
->where('status', PrintJob::STATUS_COMPLETED)
->whereDate('print_end_time', today())
->count();
$failedToday = PrintJob::where('user_id', $userId)
->where('status', PrintJob::STATUS_FAILED)
->whereDate('print_end_time', today())
->count();
return [
'pending' => $pending,
'printing' => $printing,
'queued' => $queued,
'completed_today' => $completedToday,
'failed_today' => $failedToday,
];
}
/**
* 批量加入队列
*/
public function batchQueue(int $userId, array $jobIds): array
{
$queued = 0;
$failed = 0;
foreach ($jobIds as $jobId) {
$job = PrintJob::where('id', $jobId)
->where('user_id', $userId)
->where('status', PrintJob::STATUS_PENDING)
->first();
if ($job) {
$job->queue();
$queued++;
} else {
$failed++;
}
}
return [
'queued' => $queued,
'failed' => $failed,
];
}
/**
* 清空已完成任务
*/
public function clearCompleted(int $userId): int
{
return PrintJob::where('user_id', $userId)
->whereIn('status', [PrintJob::STATUS_COMPLETED, PrintJob::STATUS_CANCELLED])
->delete();
}
}