|
|
@@ -43,12 +43,16 @@ class Supplierservicescore extends Backend
|
|
|
$limit = 50;
|
|
|
}
|
|
|
|
|
|
- $list = $this->loadMonthlySupplierScoreList($ym, $keyword);
|
|
|
+ // 有搜索词:跨月查该供应商;无搜索:按查询月份展示当月
|
|
|
+ $list = $keyword !== ''
|
|
|
+ ? $this->loadSupplierScoreSearchList($keyword)
|
|
|
+ : $this->loadMonthlySupplierScoreList($ym, '');
|
|
|
$total = count($list);
|
|
|
$pageRows = array_slice($list, $offset, $limit);
|
|
|
$seqBase = $offset;
|
|
|
$rows = [];
|
|
|
foreach ($pageRows as $i => $item) {
|
|
|
+ $rowYm = (string)($item['ym'] ?? $ym);
|
|
|
$rows[] = [
|
|
|
'id' => $seqBase + $i + 1,
|
|
|
'seq_no' => $seqBase + $i + 1,
|
|
|
@@ -63,7 +67,8 @@ class Supplierservicescore extends Backend
|
|
|
'final_score_text' => (string)($item['final_score_text'] ?? ''),
|
|
|
'final_score_saved' => !empty($item['final_score_saved']) ? 1 : 0,
|
|
|
'score_grade' => (string)($item['score_grade'] ?? ''),
|
|
|
- 'ym' => $ym,
|
|
|
+ 'score_date' => (string)(($item['score_date'] ?? '') !== '' ? $item['score_date'] : $rowYm),
|
|
|
+ 'ym' => $rowYm,
|
|
|
];
|
|
|
}
|
|
|
|
|
|
@@ -103,10 +108,31 @@ class Supplierservicescore extends Backend
|
|
|
if (!is_array($rows) || $rows === []) {
|
|
|
$this->error('没有可保存的数据');
|
|
|
}
|
|
|
- $ret = ProcuremenSupplierScore::saveFinalScoresForYm($ym, $rows);
|
|
|
- $done = (int)($ret['done'] ?? 0);
|
|
|
+ // 按行自带 ym 分组(跨月搜索结果可同页保存)
|
|
|
+ $byYm = [];
|
|
|
+ foreach ($rows as $row) {
|
|
|
+ if (!is_array($row)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $rowYm = trim((string)($row['ym'] ?? ''));
|
|
|
+ if (!preg_match('/^\d{4}-\d{2}$/', $rowYm)) {
|
|
|
+ $rowYm = $ym;
|
|
|
+ }
|
|
|
+ if (!isset($byYm[$rowYm])) {
|
|
|
+ $byYm[$rowYm] = [];
|
|
|
+ }
|
|
|
+ $byYm[$rowYm][] = $row;
|
|
|
+ }
|
|
|
+ $done = 0;
|
|
|
+ $err = '';
|
|
|
+ foreach ($byYm as $saveYm => $chunk) {
|
|
|
+ $ret = ProcuremenSupplierScore::saveFinalScoresForYm($saveYm, $chunk);
|
|
|
+ $done += (int)($ret['done'] ?? 0);
|
|
|
+ if ($err === '') {
|
|
|
+ $err = trim((string)($ret['error'] ?? ''));
|
|
|
+ }
|
|
|
+ }
|
|
|
if ($done < 1) {
|
|
|
- $err = trim((string)($ret['error'] ?? ''));
|
|
|
$this->error($err !== '' ? $err : '保存失败,请检查填写的分数');
|
|
|
}
|
|
|
$this->success('操作成功');
|
|
|
@@ -114,7 +140,7 @@ class Supplierservicescore extends Backend
|
|
|
|
|
|
/**
|
|
|
* 导出供应商评审表
|
|
|
- * 列:序号、供应商名称、商务/技术得分、价格得分、交货得分、最终得分、评分等级
|
|
|
+ * 列:序号、供应商、最终得分、评分等级
|
|
|
*/
|
|
|
public function export()
|
|
|
{
|
|
|
@@ -153,26 +179,23 @@ class Supplierservicescore extends Backend
|
|
|
'wrapText' => true,
|
|
|
];
|
|
|
|
|
|
- $sheet->mergeCells('A1:G1');
|
|
|
+ $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->setCellValue('E2', '交货得分');
|
|
|
- $sheet->setCellValue('F2', '最终得分');
|
|
|
- $sheet->setCellValue('G2', '评分等级');
|
|
|
+ $sheet->setCellValue('B2', '供应商');
|
|
|
+ $sheet->setCellValue('C2', '最终得分');
|
|
|
+ $sheet->setCellValue('D2', '评分等级');
|
|
|
$sheet->getRowDimension(2)->setRowHeight(26);
|
|
|
- $sheet->getStyle('A2:G2')->getFont()->setName($fontName)->setBold(true)->setSize(14);
|
|
|
- $sheet->getStyle('A2:G2')->getAlignment()->applyFromArray($centerAlign);
|
|
|
+ $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:G3');
|
|
|
+ $sheet->mergeCells('A3:D3');
|
|
|
$sheet->setCellValue('A3', '(该月暂无供应商评审记录)');
|
|
|
$sheet->getRowDimension(3)->setRowHeight(26);
|
|
|
$sheet->getStyle('A3')->getFont()->setName($fontName)->setSize(12);
|
|
|
@@ -181,14 +204,10 @@ class Supplierservicescore extends Backend
|
|
|
} else {
|
|
|
$i = 1;
|
|
|
foreach ($list as $item) {
|
|
|
- $finalText = (string)($item['final_score_text'] ?? '');
|
|
|
$sheet->setCellValue('A' . $rowNum, $i);
|
|
|
$sheet->setCellValue('B' . $rowNum, (string)($item['company_name'] ?? ''));
|
|
|
- $sheet->setCellValue('C' . $rowNum, (string)($item['quality_score_text'] ?? ''));
|
|
|
- $sheet->setCellValue('D' . $rowNum, (string)($item['price_score_text'] ?? ''));
|
|
|
- $sheet->setCellValue('E' . $rowNum, (string)($item['delivery_score_text'] ?? ''));
|
|
|
- $sheet->setCellValue('F' . $rowNum, $finalText);
|
|
|
- $sheet->setCellValue('G' . $rowNum, (string)($item['score_grade'] ?? ''));
|
|
|
+ $sheet->setCellValue('C' . $rowNum, (string)($item['final_score_text'] ?? ''));
|
|
|
+ $sheet->setCellValue('D' . $rowNum, (string)($item['score_grade'] ?? ''));
|
|
|
$sheet->getRowDimension($rowNum)->setRowHeight(24);
|
|
|
$rowNum++;
|
|
|
$i++;
|
|
|
@@ -196,16 +215,13 @@ class Supplierservicescore extends Backend
|
|
|
}
|
|
|
|
|
|
$lastRow = max(2, $rowNum - 1);
|
|
|
- $sheet->getStyle('A1:G' . $lastRow)->applyFromArray($borderStyle);
|
|
|
- $sheet->getStyle('A3:G' . $lastRow)->getFont()->setName($fontName)->setSize(12);
|
|
|
- $sheet->getStyle('A3:G' . $lastRow)->getAlignment()->applyFromArray($centerAlign);
|
|
|
+ $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(14);
|
|
|
- $sheet->getColumnDimension('E')->setWidth(12);
|
|
|
- $sheet->getColumnDimension('F')->setWidth(14);
|
|
|
- $sheet->getColumnDimension('G')->setWidth(12);
|
|
|
+ $sheet->getColumnDimension('D')->setWidth(12);
|
|
|
$sheet->getPageSetup()->setFitToPage(true)->setFitToWidth(1)->setFitToHeight(0);
|
|
|
|
|
|
$filename = $title . '.xlsx';
|
|
|
@@ -239,52 +255,135 @@ class Supplierservicescore extends Backend
|
|
|
if ($keyword !== '' && mb_stripos($name, $keyword) === false) {
|
|
|
continue;
|
|
|
}
|
|
|
- $quality = array_key_exists('quality_score', $item) ? $item['quality_score'] : null;
|
|
|
- $price = array_key_exists('price_score', $item) ? $item['price_score'] : null;
|
|
|
- $delivery = array_key_exists('delivery_score', $item) ? $item['delivery_score'] : null;
|
|
|
- if ($quality !== null) {
|
|
|
- $quality = (float)$quality;
|
|
|
- }
|
|
|
- if ($price !== null) {
|
|
|
- $price = (float)$price;
|
|
|
+ $list[] = $this->buildSupplierScoreListItem($name, $item, $ym);
|
|
|
+ }
|
|
|
+ usort($list, [$this, 'sortSupplierScoreListItems']);
|
|
|
+
|
|
|
+ return $list;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按供应商关键词跨月搜索(不限查询月份)
|
|
|
+ *
|
|
|
+ * @return array<int, array<string, mixed>>
|
|
|
+ */
|
|
|
+ protected function loadSupplierScoreSearchList(string $keyword): array
|
|
|
+ {
|
|
|
+ $keyword = trim($keyword);
|
|
|
+ if ($keyword === '') {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ ProcuremenSupplierScore::ensureSchema();
|
|
|
+ ProcuremenSupplierScore::ensureFinalScoreTable();
|
|
|
+ try {
|
|
|
+ $rows = \think\Db::table(ProcuremenSupplierScore::TABLE_FINAL)
|
|
|
+ ->where('company_name', 'like', '%' . addcslashes($keyword, '%_\\') . '%')
|
|
|
+ ->field('ym,company_name,score,quality_score,price_score,delivery_score,final_score,score_grade')
|
|
|
+ ->order('ym', 'desc')
|
|
|
+ ->order('company_name', 'asc')
|
|
|
+ ->select();
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ if (!is_array($rows)) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ $list = [];
|
|
|
+ foreach ($rows as $r) {
|
|
|
+ if (!is_array($r)) {
|
|
|
+ continue;
|
|
|
}
|
|
|
- if ($delivery !== null) {
|
|
|
- $delivery = (float)$delivery;
|
|
|
+ $name = trim((string)($r['company_name'] ?? ''));
|
|
|
+ $rowYm = ProcuremenSupplierScore::formatScoreYm($r['ym'] ?? '');
|
|
|
+ if ($name === '' || $rowYm === '') {
|
|
|
+ continue;
|
|
|
}
|
|
|
- $hasFinal = !empty($item['final_saved']);
|
|
|
- $final = $hasFinal ? (float)($item['final_score'] ?? 0) : null;
|
|
|
- // 列表排序:有最终得分按最终得分,否则按已填分项合计
|
|
|
- $sortScore = $hasFinal
|
|
|
- ? (float)$final
|
|
|
- : (($quality ?? 0) + ($price ?? 0) + ($delivery ?? 0));
|
|
|
- $list[] = [
|
|
|
- 'company_name' => $name,
|
|
|
- 'quality_score' => $quality,
|
|
|
- 'quality_score_text' => ProcuremenSupplierScore::formatOptionalScore($quality),
|
|
|
- 'price_score' => $price,
|
|
|
- 'price_score_text' => ProcuremenSupplierScore::formatOptionalScore($price),
|
|
|
- 'delivery_score' => $delivery,
|
|
|
- 'delivery_score_text' => ProcuremenSupplierScore::formatOptionalScore($delivery),
|
|
|
- 'final_score' => $final,
|
|
|
- 'final_score_text' => $hasFinal ? ProcuremenSupplierScore::formatOptionalScore($final) : '',
|
|
|
- 'final_score_saved' => $hasFinal ? 1 : 0,
|
|
|
- 'score_grade' => ProcuremenSupplierScore::normalizeScoreGrade($item['score_grade'] ?? ''),
|
|
|
- 'sort_score' => $sortScore,
|
|
|
+ $quality = ProcuremenSupplierScore::readOptionalScoreValue($r['quality_score'] ?? null);
|
|
|
+ $price = ProcuremenSupplierScore::readOptionalScoreValue($r['price_score'] ?? null);
|
|
|
+ $delivery = ProcuremenSupplierScore::readOptionalScoreValue($r['delivery_score'] ?? null);
|
|
|
+ $final = ProcuremenSupplierScore::readOptionalScoreValue($r['final_score'] ?? null);
|
|
|
+ $item = [
|
|
|
+ 'quality_score' => $quality,
|
|
|
+ 'price_score' => $price,
|
|
|
+ 'delivery_score' => $delivery,
|
|
|
+ 'final_score' => $final,
|
|
|
+ 'final_saved' => $final !== null ? 1 : 0,
|
|
|
+ 'score_grade' => ProcuremenSupplierScore::normalizeScoreGrade($r['score_grade'] ?? ''),
|
|
|
+ 'score_date' => $rowYm,
|
|
|
];
|
|
|
+ $list[] = $this->buildSupplierScoreListItem($name, $item, $rowYm);
|
|
|
}
|
|
|
- usort($list, function ($a, $b) {
|
|
|
- $sa = (float)($a['sort_score'] ?? 0);
|
|
|
- $sb = (float)($b['sort_score'] ?? 0);
|
|
|
- if ($sa !== $sb) {
|
|
|
- return $sb <=> $sa;
|
|
|
- }
|
|
|
-
|
|
|
- return strcmp((string)($a['company_name'] ?? ''), (string)($b['company_name'] ?? ''));
|
|
|
- });
|
|
|
+ usort($list, [$this, 'sortSupplierScoreListItems']);
|
|
|
|
|
|
return $list;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * @param array<string, mixed> $item
|
|
|
+ * @return array<string, mixed>
|
|
|
+ */
|
|
|
+ protected function buildSupplierScoreListItem(string $name, array $item, string $ym): array
|
|
|
+ {
|
|
|
+ $quality = array_key_exists('quality_score', $item) ? $item['quality_score'] : null;
|
|
|
+ $price = array_key_exists('price_score', $item) ? $item['price_score'] : null;
|
|
|
+ $delivery = array_key_exists('delivery_score', $item) ? $item['delivery_score'] : null;
|
|
|
+ if ($quality !== null) {
|
|
|
+ $quality = (float)$quality;
|
|
|
+ }
|
|
|
+ if ($price !== null) {
|
|
|
+ $price = (float)$price;
|
|
|
+ }
|
|
|
+ if ($delivery !== null) {
|
|
|
+ $delivery = (float)$delivery;
|
|
|
+ }
|
|
|
+ $hasFinal = !empty($item['final_saved']);
|
|
|
+ $final = $hasFinal ? (float)($item['final_score'] ?? 0) : null;
|
|
|
+ $sortScore = $hasFinal
|
|
|
+ ? (float)$final
|
|
|
+ : (($quality ?? 0) + ($price ?? 0) + ($delivery ?? 0));
|
|
|
+ $scoreDate = (string)($item['score_date'] ?? '');
|
|
|
+ if ($scoreDate === '') {
|
|
|
+ $scoreDate = ProcuremenSupplierScore::formatScoreYm($ym);
|
|
|
+ }
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'company_name' => $name,
|
|
|
+ 'ym' => ProcuremenSupplierScore::formatScoreYm($ym),
|
|
|
+ 'quality_score' => $quality,
|
|
|
+ 'quality_score_text' => ProcuremenSupplierScore::formatOptionalScore($quality),
|
|
|
+ 'price_score' => $price,
|
|
|
+ 'price_score_text' => ProcuremenSupplierScore::formatOptionalScore($price),
|
|
|
+ 'delivery_score' => $delivery,
|
|
|
+ 'delivery_score_text' => ProcuremenSupplierScore::formatOptionalScore($delivery),
|
|
|
+ 'final_score' => $final,
|
|
|
+ 'final_score_text' => $hasFinal ? ProcuremenSupplierScore::formatOptionalScore($final) : '',
|
|
|
+ 'final_score_saved' => $hasFinal ? 1 : 0,
|
|
|
+ 'score_grade' => ProcuremenSupplierScore::normalizeScoreGrade($item['score_grade'] ?? ''),
|
|
|
+ 'score_date' => $scoreDate,
|
|
|
+ 'sort_score' => $sortScore,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param array<string, mixed> $a
|
|
|
+ * @param array<string, mixed> $b
|
|
|
+ */
|
|
|
+ protected function sortSupplierScoreListItems(array $a, array $b): int
|
|
|
+ {
|
|
|
+ $ya = (string)($a['ym'] ?? '');
|
|
|
+ $yb = (string)($b['ym'] ?? '');
|
|
|
+ if ($ya !== $yb) {
|
|
|
+ return strcmp($yb, $ya);
|
|
|
+ }
|
|
|
+ $sa = (float)($a['sort_score'] ?? 0);
|
|
|
+ $sb = (float)($b['sort_score'] ?? 0);
|
|
|
+ if ($sa !== $sb) {
|
|
|
+ return $sb <=> $sa;
|
|
|
+ }
|
|
|
+
|
|
|
+ return strcmp((string)($a['company_name'] ?? ''), (string)($b['company_name'] ?? ''));
|
|
|
+ }
|
|
|
+
|
|
|
protected function resolveRequestYm(): string
|
|
|
{
|
|
|
$ym = trim((string)$this->request->get('ym', ''));
|