middleware('auth'); $this->middleware('company.identify'); } public function saveRobot(Request $request): RedirectResponse { $data = $request->validate([ 'dingtalk_webhook' => ['nullable', 'string', 'max:2048'], 'dingtalk_secret' => ['nullable', 'string', 'max:256'], 'dingtalk_group_name' => ['required', 'string', 'max:191'], ]); $this->workflow->saveConfiguration( (string) ($data['dingtalk_webhook'] ?? ''), (string) ($data['dingtalk_secret'] ?? ''), (string) $data['dingtalk_group_name'], ); return back()->with('success', '供应商负数预警群机器人已保存。'); } public function send(Request $request): RedirectResponse { $data = $request->validate([ 'purchaser' => ['nullable', 'string', 'max:191'], 'month' => ['nullable', 'string', 'regex:/^\d{4}-\d{2}$/'], 'supplier' => ['nullable', 'string', 'max:191'], 'checker' => ['nullable', 'string', 'max:191'], 'settlement_method' => ['nullable', 'string', 'max:191'], 'handling' => ['nullable', 'in:,pending'], ]); $purchaser = trim((string) ($data['purchaser'] ?? '')); $filters = [ 'month' => (string) ($data['month'] ?? ''), 'supplier' => (string) ($data['supplier'] ?? ''), 'checker' => (string) ($data['checker'] ?? ''), 'settlement_method' => (string) ($data['settlement_method'] ?? ''), 'purchaser' => $purchaser, 'handling' => (string) ($data['handling'] ?? ''), ]; $filteredRows = $this->pageData->rowsForFilters([ ...$filters, 'purchaser' => '', ]); $rows = $purchaser === '' ? $filteredRows : array_values(array_filter( $filteredRows, static fn (array $row): bool => trim((string) ($row['purchaser'] ?? '')) === $purchaser, )); if ($rows === []) { return back()->withErrors([ 'dingtalk_send' => '当前筛选没有可发送给该采购的供应商。', ]); } $companyId = (int) (company_id() ?: 1); $rows = $this->workflow->unhandledRows($rows, $companyId); if ($rows === []) { return back()->withErrors([ 'dingtalk_send' => '当前筛选中的供应商均已回传处理结果,无需重复发送。', ]); } try { if ($purchaser === '') { $result = $this->workflow->sendGrouped( $rows, $filters, $companyId, user_id() ? (int) user_id() : null, ); } else { $result = $this->workflow->send( $rows, $purchaser, $filters, $companyId, user_id() ? (int) user_id() : null, ); } } catch (Throwable $exception) { report($exception); return back()->withErrors(['dingtalk_send' => '发送失败:' . $exception->getMessage()]); } if ($purchaser === '') { $message = "已一键发送至{$result['group_name']}:{$result['purchaser_count']} 位采购," . "{$result['supplier_count']} 家供应商、{$result['row_count']} 条预警。"; if ($result['unassigned_supplier_count'] > 0) { $message .= " 另有 {$result['unassigned_supplier_count']} 家供应商未分配采购,未发送。"; } return back()->with('success', $message); } return back()->with('success', "已发送至{$result['group_name']}:采购 {$purchaser}," . "{$result['supplier_count']} 家供应商、{$result['row_count']} 条预警。"); } public function export(Request $request): StreamedResponse { $data = $this->pageData->exportData($request->query()); $fields = array_values(array_filter( (array) ($data['fields'] ?? []), static fn (array $field): bool => ($field['name'] ?? '') !== 'company', )); $fields[] = ['name' => 'handling_result_meta', 'label' => '回传信息', 'type' => 'text']; $rows = (array) ($data['rows'] ?? []); $filters = (array) ($data['filters'] ?? []); $period = trim((string) ($filters['month'] ?? '')) ?: '全部月份'; $filename = '供应商负数预警_' . $period . '_' . now()->format('Ymd_His') . '.csv'; return response()->streamDownload(function () use ($fields, $rows): void { $stream = fopen('php://output', 'w'); if ($stream === false) { throw new RuntimeException('无法创建供应商负数预警导出文件。'); } fwrite($stream, "\xEF\xBB\xBF"); fputcsv($stream, array_map( static fn (array $field): string => (string) ($field['label'] ?? ''), $fields, )); foreach ($rows as $row) { $values = []; foreach ($fields as $field) { $name = (string) ($field['name'] ?? ''); $value = $row[$name] ?? ''; if ($name === 'handling_result' && trim((string) $value) === '') { $value = '采购未回传'; } elseif (is_array($value)) { $value = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); } $values[] = $this->csvCell($value); } fputcsv($stream, $values); } fclose($stream); }, $filename, [ 'Content-Type' => 'text/csv; charset=UTF-8', 'Cache-Control' => 'private, no-store', ]); } private function csvCell(mixed $value): string { $text = trim((string) $value); if ($text === '' || is_numeric($text)) { return $text; } if (preg_match('/^\d{12,}$/', $text) === 1) { return "'" . $text; } return preg_match('/^[=+@\t\r]/u', $text) === 1 ? "'" . $text : $text; } }