每日自动推送未处理供应商,增加处理截止时间和截图上传。 Co-authored-by: 苏木 <594326199@qq.com> Co-committed-by: 苏木 <594326199@qq.com>
140 lines
5.6 KiB
PHP
140 lines
5.6 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Business;
|
|
|
|
use App\Models\Common\Company;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\Response;
|
|
use Illuminate\Routing\Controller;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Illuminate\View\View;
|
|
use Modules\EcommerceFinance\Services\SupplierNegativeAlertDingTalkWorkflow;
|
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
|
|
class SupplierNegativeAlertDingTalkForms extends Controller
|
|
{
|
|
public function __construct(
|
|
private readonly SupplierNegativeAlertDingTalkWorkflow $workflow,
|
|
) {
|
|
}
|
|
|
|
public function show(string $token): View|Response
|
|
{
|
|
$assignment = $this->resolve($token);
|
|
if ($assignment === null) {
|
|
return $this->unavailable();
|
|
}
|
|
|
|
$snapshot = json_decode((string) $assignment->snapshot, true);
|
|
$snapshot = is_array($snapshot) ? array_values($snapshot) : [];
|
|
$latestPeriod = $this->workflow->latestPeriodSummary($snapshot);
|
|
|
|
return view('business.pages.negative-alerts.dingtalk-task', [
|
|
'assignment' => $assignment,
|
|
'suppliers' => $snapshot,
|
|
'latestPeriod' => $latestPeriod,
|
|
'processingDeadline' => $this->workflow->processingDeadline((string) $latestPeriod['month']),
|
|
'supplierResults' => $this->workflow->resultsForAssignment((int) $assignment->id),
|
|
'supplierAttachments' => $this->workflow->attachmentsForAssignment((int) $assignment->id),
|
|
'token' => $token,
|
|
]);
|
|
}
|
|
|
|
public function update(Request $request, string $token): RedirectResponse|Response
|
|
{
|
|
$assignment = $this->resolve($token);
|
|
if ($assignment === null) {
|
|
return $this->unavailable();
|
|
}
|
|
$snapshot = json_decode((string) $assignment->snapshot, true);
|
|
$supplierCount = is_array($snapshot) ? count($snapshot) : 0;
|
|
|
|
$data = $request->validate([
|
|
'results' => ['required', 'array', 'size:' . $supplierCount],
|
|
'results.*' => ['nullable', 'string', 'max:2000'],
|
|
'screenshots' => ['nullable', 'array', 'size:' . $supplierCount],
|
|
'screenshots.*' => ['nullable', 'array', 'max:5'],
|
|
'screenshots.*.*' => ['file', 'mimes:jpg,jpeg,png,webp', 'max:10240'],
|
|
], [
|
|
'results.required' => '请为每个供应商填写处理结果。',
|
|
'results.size' => '请为每个供应商填写处理结果。',
|
|
'results.*.max' => '单个供应商的处理结果不能超过 2000 个字符。',
|
|
'screenshots.*.*.mimes' => '处理截图仅支持 JPG、PNG、WEBP 图片。',
|
|
'screenshots.*.*.max' => '单张处理截图不能超过 10MB。',
|
|
]);
|
|
if (! collect((array) $data['results'])->contains(
|
|
static fn (mixed $value): bool => trim((string) $value) !== '',
|
|
)) {
|
|
throw ValidationException::withMessages([
|
|
'results' => '请至少填写一个供应商的处理结果。',
|
|
]);
|
|
}
|
|
$uploads = [];
|
|
foreach ((array) $request->file('screenshots', []) as $index => $files) {
|
|
$uploads[(int) $index] = array_values(array_filter(
|
|
(array) $files,
|
|
static fn (mixed $file): bool => $file !== null,
|
|
));
|
|
}
|
|
$existingAttachments = $this->workflow->attachmentsForAssignment((int) $assignment->id);
|
|
foreach (is_array($snapshot) ? $snapshot : [] as $index => $supplier) {
|
|
$supplierName = trim((string) ($supplier['supplier'] ?? ''));
|
|
$existingCount = count($existingAttachments[$supplierName] ?? []);
|
|
if ($existingCount + count($uploads[$index] ?? []) > 5) {
|
|
throw ValidationException::withMessages([
|
|
'screenshots' => $supplierName . ' 最多上传 5 张处理截图。',
|
|
]);
|
|
}
|
|
}
|
|
|
|
try {
|
|
$this->workflow->submit($token, array_values((array) $data['results']));
|
|
$this->workflow->storeAttachments($assignment, is_array($snapshot) ? $snapshot : [], $uploads);
|
|
} catch (ValidationException $exception) {
|
|
throw $exception;
|
|
}
|
|
|
|
return redirect()
|
|
->route('supplier-negative-alert.task', ['token' => $token])
|
|
->with('negative_alert_success', '已保存本次填写的供应商处理结果,未填写的供应商会继续留在待处理任务中。');
|
|
}
|
|
|
|
public function attachment(string $token, int $attachment): StreamedResponse|Response
|
|
{
|
|
$assignment = $this->resolve($token);
|
|
if ($assignment === null) {
|
|
return $this->unavailable();
|
|
}
|
|
$file = $this->workflow->attachmentForAssignment((int) $assignment->id, $attachment);
|
|
abort_if($file === null, 404);
|
|
|
|
$disk = Storage::disk('uploads');
|
|
abort_unless($disk->exists((string) $file->path), 404, '处理截图不存在。');
|
|
|
|
return $disk->response((string) $file->path, (string) $file->original_name, [
|
|
'Cache-Control' => 'private, no-store',
|
|
'Content-Type' => (string) $file->mime_type,
|
|
'X-Content-Type-Options' => 'nosniff',
|
|
]);
|
|
}
|
|
|
|
private function resolve(string $token): ?object
|
|
{
|
|
$assignment = $this->workflow->findByToken($token);
|
|
if ($assignment === null) {
|
|
return null;
|
|
}
|
|
|
|
Company::find($assignment->company_id)?->makeCurrent();
|
|
|
|
return $assignment;
|
|
}
|
|
|
|
private function unavailable(): Response
|
|
{
|
|
return response()->view('business.pages.negative-alerts.dingtalk-task-unavailable', [], 404);
|
|
}
|
|
}
|