ensureCanManage(); abort_unless($quoteVersion->status === 'approved', 422, '只有已审核报价版本可以生成签署文件。'); $data = $request->validate([ 'signature_date' => ['required', 'date'], ]); $signature = $this->service->prepareVersion($quoteVersion, user_id(), $data['signature_date']); return redirect()->route('business.courier-quote-changes.show', $quoteVersion->source_change_id) ->with('success', "{$quoteVersion->version_code} 的签署 PDF 已生成,文件校验值已固定。") ->with('signature_id', $signature->id); } public function send(Request $request, CourierQuoteSignature $quoteSignature): RedirectResponse { $this->ensureCanManage(); abort_unless($quoteSignature->version?->status === 'approved', 422, '只有已审核报价版本可以发起签署。'); abort_unless(EsignClient::configured(), 422, 'E 签宝沙箱尚未配置 App ID 或 AppSecret。'); $data = $request->validate([ 'organization_name' => ['required', 'string', 'min:2', 'max:255'], 'operator_name' => ['required', 'string', 'min:2', 'max:100'], 'operator_account' => ['required', 'string', 'max:255'], 'notice_type' => ['required', 'in:1,2'], 'signature_date' => ['required', 'date'], 'expires_at' => ['required', 'date', 'after:now', 'before_or_equal:' . now()->addDays(90)->toDateTimeString()], ]); $this->validateAccountForNotice($data['operator_account'], $data['notice_type']); $quoteSignature = $this->service->prepareVersion( $quoteSignature->version, user_id(), $data['signature_date'], ); $signature = $this->service->send($quoteSignature, $data, user_id()); $environment = $signature->environment === 'sandbox' ? '沙箱' : '正式环境'; return redirect()->route('business.courier-quote-changes.show', $signature->version->source_change_id) ->with('success', "{$signature->version->version_code} 已推送到 E 签宝{$environment},等待快递公司签署。"); } public function synchronize(CourierQuoteSignature $quoteSignature): RedirectResponse { $this->ensureCanManage(); $signature = $this->service->synchronize($quoteSignature, user_id()); $message = $signature->status === CourierQuoteSignature::STATUS_ARCHIVED ? '签署完成,签署 PDF 和完成证书已私有归档。' : "已同步 E 签宝状态:{$signature->statusLabel()}。"; return redirect()->route('business.courier-quote-changes.show', $signature->version->source_change_id) ->with('success', $message); } public function download(CourierQuoteSignature $quoteSignature, string $kind): StreamedResponse { [$path, $suffix] = match ($kind) { 'source' => [$quoteSignature->source_pdf_path, '报价签署原文'], 'signed' => [$quoteSignature->signed_pdf_path, '已签署报价'], 'certificate' => [$quoteSignature->certificate_path, '签署完成证书'], default => abort(404), }; abort_if(blank($path) || ! \Storage::disk('uploads')->exists($path), 404, '归档文件不存在。'); $fileName = $quoteSignature->version->version_code . '-' . $suffix . '.pdf'; return \Storage::disk('uploads')->download($path, $fileName, ['Content-Type' => 'application/pdf']); } private function validateAccountForNotice(string $account, string $noticeType): void { $valid = $noticeType === '1' ? preg_match('/^1\d{10}$/', $account) === 1 : filter_var($account, FILTER_VALIDATE_EMAIL) !== false; if (! $valid) { $message = $noticeType === '1' ? '短信通知必须填写 11 位手机号。' : '邮件通知必须填写有效邮箱。'; throw ValidationException::withMessages(['operator_account' => $message]); } } private function ensureCanManage(): void { abort_unless( in_array(SystemAccess::roleName(user()), [SystemAccess::SUPER_ADMIN, SystemAccess::ADMIN], true), 403, '当前账号没有报价签署管理权限。', ); } }