model = new \app\admin\model\Supplierservicescore; } public function index() { $this->request->filter(['strip_tags', 'trim']); if ($this->request->isAjax()) { $ym = $this->resolveRequestYm(); $keyword = $this->resolveSearchKeyword(); $offset = max(0, (int)$this->request->get('offset', 0)); $limit = (int)$this->request->get('limit', 50); if ($limit <= 0) { $limit = 50; } $list = $this->loadMonthlySupplierScoreList($ym, $keyword); $total = count($list); $pageRows = array_slice($list, $offset, $limit); $seqBase = $offset; $rows = []; foreach ($pageRows as $i => $item) { $rows[] = [ 'id' => $seqBase + $i + 1, 'seq_no' => $seqBase + $i + 1, 'company_name' => (string)($item['company_name'] ?? ''), 'score' => (float)($item['score'] ?? 0), 'score_text' => (string)($item['score_text'] ?? ''), 'final_score' => $item['final_score'] ?? null, 'final_score_text' => (string)($item['final_score_text'] ?? ''), 'final_score_saved' => !empty($item['final_score_saved']) ? 1 : 0, 'rank_no' => (int)($item['rank_no'] ?? 0), 'ym' => $ym, ]; } return json(['total' => $total, 'rows' => $rows]); } return $this->view->fetch(); } /** * 批量保存当月最终得分 * POST: ym, rows=[{company_name, final_score}, ...] 或 rows_json */ public function savefinalbatch() { if (!$this->auth->check('supplierservicescore/index') && !$this->auth->isSuperAdmin()) { $this->error(__('You have no permission')); } ProcuremenSupplierScore::ensureFinalScoreTable(); $ym = trim((string)$this->request->post('ym', '')); if ($ym === '') { $ym = trim((string)$this->request->param('ym', '')); } if (!preg_match('/^\d{4}-\d{2}$/', $ym)) { $this->error('请选择查询月份'); } $rows = $this->request->post('rows/a', []); if (!is_array($rows) || $rows === []) { $rowsJson = trim((string)$this->request->post('rows_json', '')); if ($rowsJson !== '') { $decoded = json_decode($rowsJson, true); if (is_array($decoded)) { $rows = $decoded; } } } if (!is_array($rows) || $rows === []) { $this->error('没有可保存的数据'); } $ret = ProcuremenSupplierScore::saveFinalScoresForYm($ym, $rows); $done = (int)($ret['done'] ?? 0); if ($done < 1) { $err = trim((string)($ret['error'] ?? '')); $this->error($err !== '' ? $err : '保存失败,请检查填写的最终得分'); } $this->success('操作成功'); } /** * 导出供应商评审表:按月份汇总供应商 * 列:序号、供应商名称、总分、排名 * 总分优先取最终得分,无则用系统总分;排名同此规则 */ public function export() { if (!$this->auth->check('supplierservicescore/index') && !$this->auth->isSuperAdmin()) { $this->error(__('You have no permission')); } $ym = trim((string)$this->request->param('ym', '')); if (!preg_match('/^(\d{4})-(\d{2})$/', $ym, $m)) { $this->error('请选择查询月份'); } $year = (int)$m[1]; $month = (int)$m[2]; if ($month < 1 || $month > 12) { $this->error('查询月份无效'); } $list = $this->loadMonthlySupplierScoreList($ym, ''); $title = $year . '年' . $month . '月外协加工供应商评审表'; $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle('供应商评审表'); $fontName = '宋体'; $borderStyle = [ 'borders' => [ 'allBorders' => [ 'borderStyle' => Border::BORDER_THIN, 'color' => ['rgb' => '000000'], ], ], ]; $centerAlign = [ 'horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER, 'wrapText' => true, ]; $sheet->mergeCells('A1:D1'); $sheet->setCellValue('A1', $title); $sheet->getRowDimension(1)->setRowHeight(36); $sheet->getStyle('A1')->getFont()->setName($fontName)->setBold(true)->setSize(20); $sheet->getStyle('A1')->getAlignment()->applyFromArray($centerAlign); $sheet->setCellValue('A2', '序号'); $sheet->setCellValue('B2', '供应商名称'); $sheet->setCellValue('C2', '总分'); $sheet->setCellValue('D2', '排名'); $sheet->getRowDimension(2)->setRowHeight(26); $sheet->getStyle('A2:D2')->getFont()->setName($fontName)->setBold(true)->setSize(14); $sheet->getStyle('A2:D2')->getAlignment()->applyFromArray($centerAlign); $rowNum = 3; if ($list === []) { $sheet->mergeCells('A3:D3'); $sheet->setCellValue('A3', '(该月暂无供应商服务评分数据)'); $sheet->getRowDimension(3)->setRowHeight(26); $sheet->getStyle('A3')->getFont()->setName($fontName)->setSize(12); $sheet->getStyle('A3')->getAlignment()->applyFromArray($centerAlign); $rowNum = 4; } else { $i = 1; foreach ($list as $item) { $scoreText = (string)($item['export_score_text'] ?? $item['score_text'] ?? ''); $sheet->setCellValue('A' . $rowNum, $i); $sheet->setCellValue('B' . $rowNum, (string)($item['company_name'] ?? '')); $sheet->setCellValue('C' . $rowNum, $scoreText); $sheet->setCellValue('D' . $rowNum, (int)($item['rank_no'] ?? $i)); $sheet->getRowDimension($rowNum)->setRowHeight(24); $rowNum++; $i++; } } $lastRow = max(2, $rowNum - 1); $sheet->getStyle('A1:D' . $lastRow)->applyFromArray($borderStyle); $sheet->getStyle('A3:D' . $lastRow)->getFont()->setName($fontName)->setSize(12); $sheet->getStyle('A3:D' . $lastRow)->getAlignment()->applyFromArray($centerAlign); $sheet->getColumnDimension('A')->setWidth(12); $sheet->getColumnDimension('B')->setWidth(48); $sheet->getColumnDimension('C')->setWidth(14); $sheet->getColumnDimension('D')->setWidth(12); $sheet->getPageSetup()->setFitToPage(true)->setFitToWidth(1)->setFitToHeight(0); $filename = $title . '.xlsx'; header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Content-Disposition: attachment;filename="' . rawurlencode($filename) . '"'); header('Cache-Control: max-age=0'); $writer = new Xlsx($spreadsheet); $writer->save('php://output'); $spreadsheet->disconnectWorksheets(); unset($spreadsheet); exit; } /** * 按月汇总:读月度汇总表(订单评分后自动同步总分;最终得分人工可改) * 排名:有最终得分按最终得分,否则按系统总分 * * @return array> */ protected function loadMonthlySupplierScoreList(string $ym, string $keyword = ''): array { $ym = trim($ym); if (!preg_match('/^\d{4}-\d{2}$/', $ym)) { return []; } ProcuremenSupplierScore::ensureSchema(); $monthlyMap = ProcuremenSupplierScore::loadMonthlyMapByYm($ym); $keyword = trim($keyword); $list = []; foreach ($monthlyMap as $name => $item) { if ($keyword !== '' && mb_stripos($name, $keyword) === false) { continue; } $avg = (float)($item['score'] ?? 0); $hasFinal = !empty($item['final_saved']); $final = $hasFinal ? (float)($item['final_score'] ?? 0) : null; $rankScore = $hasFinal ? (float)$final : $avg; $list[] = [ 'company_name' => $name, 'score' => $avg, 'score_text' => ProcuremenSupplierScore::formatScore($avg), 'final_score' => $final, 'final_score_text' => $hasFinal ? ProcuremenSupplierScore::formatScore($final) : '', 'final_score_saved' => $hasFinal ? 1 : 0, 'rank_score' => $rankScore, 'export_score_text' => ProcuremenSupplierScore::formatScore($rankScore), 'rank_no' => 0, ]; } usort($list, function ($a, $b) { $sa = (float)($a['rank_score'] ?? 0); $sb = (float)($b['rank_score'] ?? 0); if ($sa !== $sb) { return $sb <=> $sa; } return strcmp((string)($a['company_name'] ?? ''), (string)($b['company_name'] ?? '')); }); $rank = 0; foreach ($list as &$item) { $rank++; $item['rank_no'] = $rank; } unset($item); return $list; } protected function resolveRequestYm(): string { $ym = trim((string)$this->request->get('ym', '')); if (preg_match('/^\d{4}-\d{2}$/', $ym)) { return $ym; } $filterRaw = $this->request->get('filter', ''); if (is_string($filterRaw) && $filterRaw !== '') { $filter = json_decode($filterRaw, true); if (is_array($filter)) { $fy = trim((string)($filter['ym'] ?? '')); if (preg_match('/^\d{4}-\d{2}$/', $fy)) { return $fy; } } } if (preg_match('/^(\d{4})\D+(\d{1,2})/', $ym, $m)) { return sprintf('%04d-%02d', (int)$m[1], (int)$m[2]); } return date('Y-m'); } protected function resolveSearchKeyword(): string { $keyword = trim((string)$this->request->get('search', '')); if ($keyword !== '') { return $keyword; } $filterRaw = $this->request->get('filter', ''); if (is_string($filterRaw) && $filterRaw !== '') { $filter = json_decode($filterRaw, true); if (is_array($filter)) { return trim((string)($filter['company_name'] ?? '')); } } return ''; } }