validate(['file' => ['required', 'file', 'max:51200']]); $file = $request->file('file'); $name = (string) $file->getClientOriginalName(); $redirect = redirect()->route('business.pages.show', [ 'company_id' => company_id(), 'section' => 'planting-data', 'page' => 'planting-reimbursement-workbench', 'date' => (string) $request->input('date', ''), 'paid_from' => (string) $request->input('paid_from', ''), 'scope' => (string) $request->input('scope', ''), ]); try { $rows = $references->parse($kind, (string) $file->getRealPath(), $name); $references->replace((int) company_id(), $kind, $rows, $name, optional(user())->id); } catch (InvalidArgumentException $exception) { return $redirect->with('error', References::KINDS[$kind] . '上传失败:' . $exception->getMessage()); } catch (\Throwable $exception) { report($exception); return $redirect->with('error', References::KINDS[$kind] . '上传失败,请检查文件格式后重新上传。'); } return $redirect->with('success', sprintf('%s已更新:%s 条。', References::KINDS[$kind], number_format(count($rows)))); } public function export(string $type, PageData $page, Exporter $exporter) { abort_unless(isset(Exporter::TYPES[$type]), 404); $filters = $page->filters(); // 导出前必须先在聚工单核对条数、金额一致。 if (request('verified') !== '1') { return redirect()->route('business.pages.show', [ 'company_id' => company_id(), 'section' => 'planting-data', 'page' => 'planting-reimbursement-workbench', ] + array_diff_key($filters, ['decision' => true]))->with('error', '请先在聚工单按同样条件查询,核对条数和最终报销金额一致后,勾选「已核对」再导出。'); } try { $result = $page->build($filters); $spreadsheet = $exporter->build($type, $result); } catch (\Throwable $exception) { report($exception); abort(503, '聚工单镜像未就绪,未生成不完整的导出文件,请稍后重试。'); } return response()->streamDownload(static function () use ($spreadsheet): void { (new Xlsx($spreadsheet))->save('php://output'); }, $exporter->fileName($type, $result['summary']), [ 'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', ]); } public function saveRobot(Request $request, Robot $robot) { $robot->save([ 'webhook' => (string) $request->input('webhook', ''), 'secret' => (string) $request->input('secret', ''), 'keyword' => (string) $request->input('keyword', ''), 'reporters' => (string) $request->input('reporters', ''), 'digest_webhook' => (string) $request->input('digest_webhook', ''), 'digest_secret' => (string) $request->input('digest_secret', ''), 'clear_digest' => $request->boolean('clear_digest'), ]); return $this->back($request)->with('success', '钉钉机器人设置已保存。'); } /** 按发起人把取消 / 待复查通知发到钉钉群(须先勾选已与聚工单核对)。 */ public function notify(Request $request, PageData $page, Robot $robot) { $filters = $page->filters(); if ($request->input('verified') !== '1') { return $this->back($request)->with('error', '请先在聚工单核对条数和金额一致,勾选「已核对」后再发通知。'); } try { $result = $page->build($filters); $sent = $robot->sendNotices((int) company_id(), $filters['date'], $result['summary']['notices'], $request->boolean('force')); } catch (\Throwable $exception) { report($exception); return $this->back($request)->with('error', '群通知发送失败:' . mb_substr($exception->getMessage(), 0, 120)); } $message = sprintf('群通知:发送 %d 人,跳过已发 %d 人', $sent['sent'], $sent['skipped']); if ($sent['failed'] > 0) { $message .= ',失败 ' . $sent['failed'] . ' 人'; } if ($sent['unmatched'] !== []) { $message .= ';钉钉里没匹配到、未能 @ 的:' . implode('、', $sent['unmatched']); } return $this->back($request)->with($sent['failed'] > 0 ? 'error' : 'success', $message . '。'); } private function back(Request $request) { return redirect()->route('business.pages.show', array_filter([ 'company_id' => company_id(), 'section' => 'planting-data', 'page' => 'planting-reimbursement-workbench', 'date' => (string) $request->input('date', ''), 'paid_from' => (string) $request->input('paid_from', ''), 'scope' => (string) $request->input('scope', ''), ], static fn ($v) => $v !== '')); } }