Supplierservicescore.php 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. <?php
  2. namespace app\admin\controller;
  3. use app\common\controller\Backend;
  4. use app\common\library\ProcuremenSupplierScore;
  5. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  6. use PhpOffice\PhpSpreadsheet\Style\Alignment;
  7. use PhpOffice\PhpSpreadsheet\Style\Border;
  8. use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
  9. use think\Db;
  10. /**
  11. * 供应商服务评分表(开标后按订单落库)
  12. *
  13. * @icon fa fa-trophy
  14. */
  15. class Supplierservicescore extends Backend
  16. {
  17. /** @var \app\admin\model\Supplierservicescore */
  18. protected $model = null;
  19. protected $searchFields = 'ccydh,company_name';
  20. /** 有列表权限即可导出(避免仅缺子权限导致按钮可见却下载失败) */
  21. protected $noNeedRight = ['export'];
  22. public function _initialize()
  23. {
  24. parent::_initialize();
  25. ProcuremenSupplierScore::ensureSchema();
  26. $this->model = new \app\admin\model\Supplierservicescore;
  27. }
  28. public function index()
  29. {
  30. $this->request->filter(['strip_tags', 'trim']);
  31. if ($this->request->isAjax()) {
  32. list($where, $sort, $order, $offset, $limit) = $this->buildparams();
  33. $sort = trim((string)$sort);
  34. $order = strtolower(trim((string)$order)) === 'asc' ? 'asc' : 'desc';
  35. // 同一订单内总分从高到低;默认按订单号分组
  36. if ($sort === '' || $sort === 'ccydh' || $sort === 'id') {
  37. $query = $this->model->where($where)->order('ccydh', $order)->order('score', 'desc');
  38. } elseif ($sort === 'score' || $sort === 'score_text' || $sort === 'rank_no') {
  39. $query = $this->model->where($where)->order('score', $order)->order('ccydh', 'desc');
  40. } else {
  41. $query = $this->model->where($where)->order($sort, $order)->order('ccydh', 'desc')->order('score', 'desc');
  42. }
  43. $list = $query->paginate($limit);
  44. $ruleMap = [];
  45. $defaultRule = ProcuremenSupplierScore::getDefaultRule();
  46. $rows = [];
  47. foreach ($list as $row) {
  48. $arr = $row->toArray();
  49. $arr['score_text'] = ProcuremenSupplierScore::formatScore($arr['score'] ?? 0);
  50. $qw = $arr['quality_weight'] ?? null;
  51. $pw = $arr['price_weight'] ?? null;
  52. if ($qw === null || $qw === '' || $pw === null || $pw === '') {
  53. $rid = (int)($arr['rule_id'] ?? 0);
  54. if ($rid > 0 && !isset($ruleMap[$rid])) {
  55. try {
  56. $rr = Db::table('supplier_score_rule')->where('id', $rid)->find();
  57. $ruleMap[$rid] = is_array($rr) ? $rr : null;
  58. } catch (\Throwable $e) {
  59. $ruleMap[$rid] = null;
  60. }
  61. }
  62. $rule = ($rid > 0 && is_array($ruleMap[$rid] ?? null)) ? $ruleMap[$rid] : $defaultRule;
  63. if ($qw === null || $qw === '') {
  64. $qw = $rule['quality_weight'] ?? 50;
  65. }
  66. if ($pw === null || $pw === '') {
  67. $pw = $rule['price_weight'] ?? 50;
  68. }
  69. }
  70. $arr['quality_weight'] = $qw;
  71. $arr['price_weight'] = $pw;
  72. $arr['quality_weight_text'] = rtrim(rtrim(sprintf('%.2F', (float)$qw), '0'), '.') . '%';
  73. $arr['price_weight_text'] = rtrim(rtrim(sprintf('%.2F', (float)$pw), '0'), '.') . '%';
  74. $rows[] = $arr;
  75. }
  76. return json(['total' => $list->total(), 'rows' => $rows]);
  77. }
  78. return $this->view->fetch();
  79. }
  80. /**
  81. * 导出供应商评审表:按月份汇总供应商,总分从高到低
  82. * 列:序号、供应商名称、总分(对应原模板「评审等级」位置)
  83. */
  84. public function export()
  85. {
  86. $ym = trim((string)$this->request->param('ym', ''));
  87. if (!preg_match('/^(\d{4})-(\d{2})$/', $ym, $m)) {
  88. $this->error('请选择查询月份');
  89. }
  90. $year = (int)$m[1];
  91. $month = (int)$m[2];
  92. if ($month < 1 || $month > 12) {
  93. $this->error('查询月份无效');
  94. }
  95. ProcuremenSupplierScore::ensureSchema();
  96. try {
  97. $rows = Db::table('supplier_service_score')
  98. ->where('ym', $ym)
  99. ->field('company_name, score')
  100. ->select();
  101. } catch (\Throwable $e) {
  102. $rows = [];
  103. }
  104. if (!is_array($rows)) {
  105. $rows = [];
  106. }
  107. // 同一供应商当月多条:取平均总分
  108. $byCompany = [];
  109. foreach ($rows as $r) {
  110. if (!is_array($r)) {
  111. continue;
  112. }
  113. $name = trim((string)($r['company_name'] ?? ''));
  114. if ($name === '') {
  115. continue;
  116. }
  117. if (!isset($byCompany[$name])) {
  118. $byCompany[$name] = ['sum' => 0.0, 'cnt' => 0];
  119. }
  120. $byCompany[$name]['sum'] += (float)($r['score'] ?? 0);
  121. $byCompany[$name]['cnt']++;
  122. }
  123. $list = [];
  124. foreach ($byCompany as $name => $agg) {
  125. $avg = $agg['cnt'] > 0 ? round($agg['sum'] / $agg['cnt'], 2) : 0.0;
  126. $list[] = [
  127. 'company_name' => $name,
  128. 'score' => $avg,
  129. 'score_text' => ProcuremenSupplierScore::formatScore($avg),
  130. ];
  131. }
  132. usort($list, function ($a, $b) {
  133. $sa = (float)($a['score'] ?? 0);
  134. $sb = (float)($b['score'] ?? 0);
  135. if ($sa !== $sb) {
  136. return $sb <=> $sa;
  137. }
  138. return strcmp((string)($a['company_name'] ?? ''), (string)($b['company_name'] ?? ''));
  139. });
  140. $title = $year . '年' . $month . '月外协加工供应商评审表';
  141. $spreadsheet = new Spreadsheet();
  142. $sheet = $spreadsheet->getActiveSheet();
  143. $sheet->setTitle('供应商评审表');
  144. // 样式对齐原纸质/Excel 评审表:大标题、居中、黑框、行高加高
  145. $fontName = '宋体';
  146. $borderStyle = [
  147. 'borders' => [
  148. 'allBorders' => [
  149. 'borderStyle' => Border::BORDER_THIN,
  150. 'color' => ['rgb' => '000000'],
  151. ],
  152. ],
  153. ];
  154. $centerAlign = [
  155. 'horizontal' => Alignment::HORIZONTAL_CENTER,
  156. 'vertical' => Alignment::VERTICAL_CENTER,
  157. 'wrapText' => true,
  158. ];
  159. $sheet->mergeCells('A1:C1');
  160. $sheet->setCellValue('A1', $title);
  161. $sheet->getRowDimension(1)->setRowHeight(36);
  162. $sheet->getStyle('A1')->getFont()->setName($fontName)->setBold(true)->setSize(20);
  163. $sheet->getStyle('A1')->getAlignment()->applyFromArray($centerAlign);
  164. $sheet->setCellValue('A2', '序号');
  165. $sheet->setCellValue('B2', '供应商名称');
  166. $sheet->setCellValue('C2', '总分');
  167. $sheet->getRowDimension(2)->setRowHeight(26);
  168. $sheet->getStyle('A2:C2')->getFont()->setName($fontName)->setBold(true)->setSize(14);
  169. $sheet->getStyle('A2:C2')->getAlignment()->applyFromArray($centerAlign);
  170. $rowNum = 3;
  171. if ($list === []) {
  172. $sheet->mergeCells('A3:C3');
  173. $sheet->setCellValue('A3', '(该月暂无供应商服务评分数据)');
  174. $sheet->getRowDimension(3)->setRowHeight(26);
  175. $sheet->getStyle('A3')->getFont()->setName($fontName)->setSize(12);
  176. $sheet->getStyle('A3')->getAlignment()->applyFromArray($centerAlign);
  177. $rowNum = 4;
  178. } else {
  179. $i = 1;
  180. foreach ($list as $item) {
  181. $sheet->setCellValue('A' . $rowNum, $i);
  182. $sheet->setCellValue('B' . $rowNum, (string)($item['company_name'] ?? ''));
  183. $sheet->setCellValue('C' . $rowNum, (string)($item['score_text'] ?? ''));
  184. $sheet->getRowDimension($rowNum)->setRowHeight(24);
  185. $rowNum++;
  186. $i++;
  187. }
  188. }
  189. $lastRow = max(2, $rowNum - 1);
  190. $sheet->getStyle('A1:C' . $lastRow)->applyFromArray($borderStyle);
  191. $sheet->getStyle('A3:C' . $lastRow)->getFont()->setName($fontName)->setSize(12);
  192. $sheet->getStyle('A3:C' . $lastRow)->getAlignment()->applyFromArray($centerAlign);
  193. $sheet->getColumnDimension('A')->setWidth(12);
  194. $sheet->getColumnDimension('B')->setWidth(48);
  195. $sheet->getColumnDimension('C')->setWidth(16);
  196. $sheet->getPageSetup()->setFitToPage(true)->setFitToWidth(1)->setFitToHeight(0);
  197. $filename = $title . '.xlsx';
  198. header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  199. header('Content-Disposition: attachment;filename="' . rawurlencode($filename) . '"');
  200. header('Cache-Control: max-age=0');
  201. $writer = new Xlsx($spreadsheet);
  202. $writer->save('php://output');
  203. $spreadsheet->disconnectWorksheets();
  204. unset($spreadsheet);
  205. exit;
  206. }
  207. }