m0_70156489 14 saat önce
ebeveyn
işleme
e1ee4b1939

+ 125 - 40
application/admin/controller/Procuremen.php

@@ -4272,12 +4272,13 @@ class Procuremen extends Backend
     }
 
     /**
-     * 按 bundle 内各订单分别计分落库(价格分不跨订单混算)
+     * 按 bundle 内各订单分别计分落库(单订单价格分);一批多单展示时再按数量×限价比例跨单加权
      *
      * @param array{ccydh?:string,pos?:array,merge_rows?:array} $bundle
      */
     protected function saveProcuremenSupplierScoresForBundle(array $bundle, ?string $ym = null): void
     {
+        $batchNo = $this->resolveBundleOrderBatchNo($bundle);
         $posByCcydh = [];
         foreach ($bundle['pos'] ?? [] as $po) {
             if (!is_array($po)) {
@@ -4298,7 +4299,7 @@ class Procuremen extends Backend
                 return;
             }
             $groups = $this->loadAuditSupplierQuoteGroups($bundle);
-            ProcuremenSupplierScore::saveForOrder($fallback, $groups, $ym);
+            ProcuremenSupplierScore::saveForOrder($fallback, $groups, $ym, $batchNo);
 
             return;
         }
@@ -4322,12 +4323,13 @@ class Procuremen extends Backend
                 }
             }
             $subBundle = [
-                'ccydh'      => $ccydh,
-                'pos'        => $posList,
-                'merge_rows' => $mergeRows !== [] ? $mergeRows : $this->scydgyRowsForPurchaseOrders($posList),
+                'ccydh'          => $ccydh,
+                'order_batch_no' => $batchNo,
+                'pos'            => $posList,
+                'merge_rows'     => $mergeRows !== [] ? $mergeRows : $this->scydgyRowsForPurchaseOrders($posList),
             ];
             $groups = $this->loadAuditSupplierQuoteGroups($subBundle);
-            ProcuremenSupplierScore::saveForOrder($ccydh, $groups, $ym);
+            ProcuremenSupplierScore::saveForOrder($ccydh, $groups, $ym, $batchNo);
         }
     }
 
@@ -4429,7 +4431,8 @@ class Procuremen extends Backend
         $gymcMap = [];
         $ccydhBySid = [];
         $qtyBySid = [];
-        $orderedSids = [];
+        $ceilingBySid = [];
+        $extraSids = [];
         foreach ($bundle['merge_rows'] ?? [] as $mr) {
             if (!is_array($mr)) {
                 continue;
@@ -4441,12 +4444,8 @@ class Procuremen extends Backend
                 if ($dh !== '') {
                     $ccydhBySid[$gid] = $dh;
                 }
-                $orderedSids[] = $gid;
-                $qty = trim((string)($mr['This_quantity'] ?? ''));
-                if ($qty === '') {
-                    $qty = trim((string)($mr['NGZL'] ?? ''));
-                }
-                $qtyBySid[$gid] = $qty;
+                $qtyBySid[$gid] = $this->resolveProcuremenThisQuantity($mr);
+                $ceilingBySid[$gid] = $this->resolveProcuremenCeilingPrice($mr);
             }
         }
         foreach ($bundle['pos'] ?? [] as $po) {
@@ -4463,11 +4462,20 @@ class Procuremen extends Backend
                 if ($dh !== '' && empty($ccydhBySid[$gid])) {
                     $ccydhBySid[$gid] = $dh;
                 }
-                if (!in_array($gid, $orderedSids, true)) {
-                    $orderedSids[] = $gid;
+                if (!isset($qtyBySid[$gid]) || trim((string)$qtyBySid[$gid]) === '') {
+                    $qtyBySid[$gid] = $this->resolveProcuremenThisQuantity($po);
                 }
+                if (!isset($ceilingBySid[$gid]) || trim((string)$ceilingBySid[$gid]) === '') {
+                    $ceilingBySid[$gid] = $this->resolveProcuremenCeilingPrice($po);
+                }
+                $extraSids[] = $gid;
             }
         }
+        // 与上方工序表一致:按订单号升序排供应商明细行
+        $orderedSids = $this->orderedScydgyIdsLikeProcessDisplay(
+            is_array($bundle['merge_rows'] ?? null) ? $bundle['merge_rows'] : [],
+            $extraSids
+        );
         try {
             $detailsQuery = Db::table('purchase_order_detail')
                 ->where('scydgy_id', 'in', array_keys($sids));
@@ -4547,6 +4555,9 @@ class Procuremen extends Backend
             $leadFilled = ($leadDays !== null);
             $leadText = $this->formatProcuremenLeadDaysText($leadDays);
             $lineRow = array_merge($processName, [
+                'scydgy_id'                => $sid,
+                'This_quantity'            => (string)($qtyBySid[$sid] ?? ''),
+                'ceilingPrice'             => (string)($ceilingBySid[$sid] ?? ''),
                 'amount'                   => $am,
                 'amount_show'              => $amountFilled ? ($amountNum !== null ? $this->formatProcuremenMoneyDisplay($amountNum) : $am) : '',
                 'amount_filled'            => $amountFilled,
@@ -4650,7 +4661,8 @@ class Procuremen extends Backend
         $gymcMap = [];
         $ccydhBySid = [];
         $qtyBySid = [];
-        $orderedSids = [];
+        $ceilingBySid = [];
+        $extraSids = [];
         foreach ($bundle['merge_rows'] ?? [] as $mr) {
             if (!is_array($mr)) {
                 continue;
@@ -4662,12 +4674,8 @@ class Procuremen extends Backend
                 if ($dh !== '') {
                     $ccydhBySid[$gid] = $dh;
                 }
-                $orderedSids[] = $gid;
-                $qty = trim((string)($mr['This_quantity'] ?? ''));
-                if ($qty === '') {
-                    $qty = trim((string)($mr['NGZL'] ?? ''));
-                }
-                $qtyBySid[$gid] = $qty;
+                $qtyBySid[$gid] = $this->resolveProcuremenThisQuantity($mr);
+                $ceilingBySid[$gid] = $this->resolveProcuremenCeilingPrice($mr);
             }
         }
         foreach ($bundle['pos'] ?? [] as $po) {
@@ -4684,8 +4692,20 @@ class Procuremen extends Backend
                 if ($dh !== '' && empty($ccydhBySid[$gid])) {
                     $ccydhBySid[$gid] = $dh;
                 }
+                if (!isset($qtyBySid[$gid]) || trim((string)$qtyBySid[$gid]) === '') {
+                    $qtyBySid[$gid] = $this->resolveProcuremenThisQuantity($po);
+                }
+                if (!isset($ceilingBySid[$gid]) || trim((string)$ceilingBySid[$gid]) === '') {
+                    $ceilingBySid[$gid] = $this->resolveProcuremenCeilingPrice($po);
+                }
+                $extraSids[] = $gid;
             }
         }
+        // 与上方工序表一致:按订单号升序排供应商明细行
+        $orderedSids = $this->orderedScydgyIdsLikeProcessDisplay(
+            is_array($bundle['merge_rows'] ?? null) ? $bundle['merge_rows'] : [],
+            $extraSids
+        );
         try {
             $details = Db::table('purchase_order_detail')
                 ->where('scydgy_id', 'in', array_keys($sids))
@@ -4771,6 +4791,9 @@ class Procuremen extends Backend
             $leadFilled = ($leadDays !== null);
             $leadText = $this->formatProcuremenLeadDaysText($leadDays);
             $pickLine = array_merge($processName, [
+                'scydgy_id'                => $sid,
+                'This_quantity'            => (string)($qtyBySid[$sid] ?? ''),
+                'ceilingPrice'             => (string)($ceilingBySid[$sid] ?? ''),
                 'amount'                   => $amountFilled ? ($amountNum !== null ? (string)$amountNum : $am) : '',
                 'amount_text'              => $amountFilled ? ($amountNum !== null ? $this->formatProcuremenMoneyDisplay($amountNum) : $am) : '未填写',
                 'delivery_text'            => $deliveryFilled ? $deliveryShow : '未填写',
@@ -8203,12 +8226,13 @@ class Procuremen extends Backend
     }
 
     /**
-     * 审核弹窗工序表展示行(与下发弹窗列一致;按订单号排序,同订单合并订单号/印件名称单元格)
+     * 工序/报价明细统一排序:订单号升序 → 印件名称 → 工序名称 → 工序行ID
+     * (与审核弹窗上方工序表一致)
      *
      * @param array<int, array<string, mixed>> $mergeRows
      * @return array<int, array<string, mixed>>
      */
-    protected function buildAuditProcessDisplayRows(array $mergeRows): array
+    protected function sortProcuremenMergeRowsByCcydh(array $mergeRows): array
     {
         $list = [];
         foreach ($mergeRows as $r) {
@@ -8237,6 +8261,50 @@ class Procuremen extends Backend
 
             return $ida <=> $idb;
         });
+
+        return $list;
+    }
+
+    /**
+     * 按工序表同序得到 scydgy_id 列表(供应商报价明细行顺序用)
+     *
+     * @param array<int, array<string, mixed>> $mergeRows
+     * @param int[] $extraSids 合并行未覆盖时追加
+     * @return int[]
+     */
+    protected function orderedScydgyIdsLikeProcessDisplay(array $mergeRows, array $extraSids = []): array
+    {
+        $out = [];
+        $seen = [];
+        foreach ($this->sortProcuremenMergeRowsByCcydh($mergeRows) as $r) {
+            $sid = $this->extractScydgyRowId($r);
+            if (!$this->isValidScydgyRowId($sid) || isset($seen[$sid])) {
+                continue;
+            }
+            $seen[$sid] = true;
+            $out[] = $sid;
+        }
+        foreach ($extraSids as $sid) {
+            $sid = (int)$sid;
+            if (!$this->isValidScydgyRowId($sid) || isset($seen[$sid])) {
+                continue;
+            }
+            $seen[$sid] = true;
+            $out[] = $sid;
+        }
+
+        return $out;
+    }
+
+    /**
+     * 审核弹窗工序表展示行(与下发弹窗列一致;按订单号排序,同订单合并订单号/印件名称单元格)
+     *
+     * @param array<int, array<string, mixed>> $mergeRows
+     * @return array<int, array<string, mixed>>
+     */
+    protected function buildAuditProcessDisplayRows(array $mergeRows): array
+    {
+        $list = $this->sortProcuremenMergeRowsByCcydh($mergeRows);
         $n = count($list);
         // 连续同订单号+印件名称:合并单元格 rowspan
         $groupSpan = array_fill(0, $n, 1);
@@ -8368,28 +8436,27 @@ class Procuremen extends Backend
             $orderMbz = $this->resolveBundleOrderMbz(['pos' => [$main], 'merge_rows' => $mergeRows]);
         }
         $qtyBySid = [];
+        $ceilingBySid = [];
         $gymcBySid = [];
         $ccydhBySid = [];
-        $orderedSids = [];
         foreach ($mergeRows as $mr) {
             if (!is_array($mr)) {
                 continue;
             }
             $sid = $this->extractScydgyRowId($mr);
-            if ($this->isValidScydgyRowId($sid)) {
-                $orderedSids[] = $sid;
-            }
-            $qty = trim((string)($mr['This_quantity'] ?? ''));
-            if ($qty === '') {
-                $qty = trim((string)($mr['NGZL'] ?? ''));
+            if (!$this->isValidScydgyRowId($sid)) {
+                continue;
             }
-            $qtyBySid[$sid] = $qty;
+            $qtyBySid[$sid] = $this->resolveProcuremenThisQuantity($mr);
+            $ceilingBySid[$sid] = $this->resolveProcuremenCeilingPrice($mr);
             $gymcBySid[$sid] = trim((string)($mr['CGYMC'] ?? ''));
             $dh = trim((string)($mr['CCYDH'] ?? ''));
             if ($dh !== '') {
                 $ccydhBySid[$sid] = $dh;
             }
         }
+        // 与上方工序表一致:按订单号升序
+        $orderedSids = $this->orderedScydgyIdsLikeProcessDisplay($mergeRows);
         $mainCcydh = trim((string)($main['CCYDH'] ?? $ccydh));
         if ($mainCcydh !== '') {
             foreach ($orderedSids as $sid) {
@@ -8429,6 +8496,7 @@ class Procuremen extends Backend
                 &$groupHas,
                 &$groupVoid,
                 $qtyBySid,
+                $ceilingBySid,
                 $gymcBySid,
                 $ccydhBySid,
                 $quoteVisible
@@ -8456,6 +8524,9 @@ class Procuremen extends Backend
                     (string)($gymcBySid[$sid] ?? trim((string)($d['CGYMC'] ?? '')))
                 );
                 $line = array_merge($processName, [
+                    'scydgy_id'       => $sid,
+                    'This_quantity'   => (string)$qtyStr,
+                    'ceilingPrice'    => (string)($ceilingBySid[$sid] ?? ''),
                     'amount'          => $am,
                     'unit_price_text' => $amountFilled
                         ? ($amountNum !== null ? $this->formatProcuremenMoneyDisplay($amountNum) : $am)
@@ -15196,7 +15267,7 @@ class Procuremen extends Backend
     }
 
     /**
-     * 按月份导出:已完结订单(与历史存证、月度列表一致),按完结月份筛选。
+     * 按月份导出:审批通过订单(与月度列表一致),按审批月份筛选。
      * 表头固定 8 列(与历史「协助明细」模板一致):序号、传票号、传票名称、外加工单位、订法、客户名称、工序、加工金额。
      */
     public function export_month_outward()
@@ -15392,7 +15463,7 @@ class Procuremen extends Backend
     }
 
     /**
-     * 月度导出公共数据:已完结订单按月份/搜索筛选后的主表与明细
+     * 月度导出公共数据:审批通过订单按月份/搜索筛选后的主表与明细(不要求已完结)
      *
      * @return array{ym:string,mainBySid:array,detailRows:array,exportLines:array,groups:array}
      */
@@ -15404,11 +15475,14 @@ class Procuremen extends Backend
             $ym = date('Y-m');
         }
 
+        $approvedVals = ProcuremenStatus::wflowApprovedValues();
+        $softDel = '(mod_rq IS NULL OR TRIM(CAST(mod_rq AS CHAR(32))) = \'\' OR TRIM(CAST(mod_rq AS CHAR(32))) LIKE \'0000-00-00%\')';
         $dbRows = [];
         try {
-            $query = Db::table('purchase_order');
-            $query->whereRaw(ProcuremenStatus::sqlPoCompleted('status'));
-            $dbRows = $query->select();
+            $dbRows = Db::table('purchase_order')
+                ->where('wflow_status', 'in', $approvedVals)
+                ->whereRaw($softDel)
+                ->select();
         } catch (\Throwable $e) {
             $dbRows = [];
         }
@@ -15430,11 +15504,14 @@ class Procuremen extends Backend
             $completeTsMap = ProcuremenTime::loadOperLogTimestampMap(array_keys($sidList), ['purchase_confirm', 'mark_complete']);
         }
 
-        // 导出始终按「查看月份」取当月完结单;搜索只在当月内再缩小(勿跨月,否则会与列表不一致)
+        // 导出按「查看月份」取当月审批通过单;搜索只在当月内再缩小
         $dbRows = array_values(array_filter($dbRows, function ($dbRow) use ($ym, $completeTsMap) {
             if (!is_array($dbRow)) {
                 return false;
             }
+            if (!ProcuremenStatus::isWflowApproved($dbRow['wflow_status'] ?? '')) {
+                return false;
+            }
             $done = ProcuremenTime::resolveCompletedDone($dbRow, $completeTsMap);
             if ($done['ts'] <= 0) {
                 return false;
@@ -15504,10 +15581,14 @@ class Procuremen extends Backend
             }
             $detailSidSeen[$sid] = true;
             $m = $mainBySid[$sid];
+            $company = trim((string)($m['pick_company_name'] ?? ''));
+            if ($company === '') {
+                $company = trim((string)($dr['company_name'] ?? ''));
+            }
             $exportLines[] = [
                 'CCYDH'        => (string)($dr['CCYDH'] ?? $m['CCYDH'] ?? ''),
                 'CYJMC'        => (string)($dr['CYJMC'] ?? $m['CYJMC'] ?? ''),
-                'company_name' => (string)($dr['company_name'] ?? ''),
+                'company_name' => $company,
                 'CDF'          => (string)($m['CDF'] ?? ''),
                 'cGzzxMc'      => (string)($m['cGzzxMc'] ?? ''),
                 'gx'           => $this->procuremenExportGxText($m),
@@ -15524,10 +15605,14 @@ class Procuremen extends Backend
             }
             $detailSidSeen[$sid] = true;
             $m = $mainBySid[$sid];
+            $company = trim((string)($m['pick_company_name'] ?? ''));
+            if ($company === '') {
+                $company = trim((string)($dr['company_name'] ?? ''));
+            }
             $exportLines[] = [
                 'CCYDH'        => (string)($dr['CCYDH'] ?? $m['CCYDH'] ?? ''),
                 'CYJMC'        => (string)($dr['CYJMC'] ?? $m['CYJMC'] ?? ''),
-                'company_name' => (string)($dr['company_name'] ?? ''),
+                'company_name' => $company,
                 'CDF'          => (string)($m['CDF'] ?? ''),
                 'cGzzxMc'      => (string)($m['cGzzxMc'] ?? ''),
                 'gx'           => $this->procuremenExportGxText($m),

+ 55 - 28
application/admin/controller/Procuremenexport.php

@@ -145,7 +145,7 @@ class Procuremenexport extends Backend
     }
 
     /**
-     * 已完结、可按月份导出的订单(合并为一单一行)
+     * 已审批通过、可按月份导出的订单(合并为一单一行)
      */
     public function exportable()
     {
@@ -195,7 +195,7 @@ class Procuremenexport extends Backend
             return $rows;
         }
 
-        $searchFields = ['CCYDH', 'CYJMC', 'CGYMC', 'createtime_text', 'ym'];
+        $searchFields = ['CCYDH', 'order_batch_no', 'CYJMC', 'CGYMC', 'picked_supplier', 'createtime_text', 'ym'];
         $out = [];
         foreach ($rows as $row) {
             if (!is_array($row)) {
@@ -242,23 +242,34 @@ class Procuremenexport extends Backend
     }
 
     /**
-     * 已完结订单(与历史存证一致),按完结月份筛选后合并为一单一行
+     * 审批通过订单,按审批月份筛选后合并为一单一行(不要求已完结)
      *
-     * @param string $ym 完结月份 Y-m;空字符串表示不限月份(用于跨月搜索)
+     * @param string $ym 审批月份 Y-m;空字符串表示不限月份(用于跨月搜索)
      * @return array<int, array<string, mixed>>
      */
     protected function buildExportableOrderRows(string $ym): array
     {
+        $approvedVals = ProcuremenStatus::wflowApprovedValues();
+        $softDel = '(mod_rq IS NULL OR TRIM(CAST(mod_rq AS CHAR(32))) = \'\' OR TRIM(CAST(mod_rq AS CHAR(32))) LIKE \'0000-00-00%\')';
         try {
-            $query = Db::table('purchase_order');
-            $query->whereRaw(ProcuremenStatus::sqlPoCompleted('status'));
-            $dbRows = $query
-                ->field('id,scydgy_id,CCYDH,CYJMC,CGYMC,pick_time,createtime,dStamp,pick_company_name')
+            $dbRows = Db::table('purchase_order')
+                ->where('wflow_status', 'in', $approvedVals)
+                ->whereRaw($softDel)
+                ->field('id,scydgy_id,CCYDH,CYJMC,CGYMC,pick_time,createtime,dStamp,pick_company_name,wflow_status,status,order_batch_no')
                 ->order('id', 'desc')
                 ->select();
         } catch (\Throwable $e) {
-            \think\Log::write('月度导出列表查询异常:' . $e->getMessage(), 'error');
-            $dbRows = [];
+            try {
+                $dbRows = Db::table('purchase_order')
+                    ->where('wflow_status', 'in', $approvedVals)
+                    ->whereRaw($softDel)
+                    ->field('id,scydgy_id,CCYDH,CYJMC,CGYMC,pick_time,createtime,dStamp,pick_company_name,wflow_status,status')
+                    ->order('id', 'desc')
+                    ->select();
+            } catch (\Throwable $e2) {
+                \think\Log::write('月度导出列表查询异常:' . $e2->getMessage(), 'error');
+                $dbRows = [];
+            }
         }
         if (!is_array($dbRows)) {
             $dbRows = [];
@@ -274,50 +285,68 @@ class Procuremenexport extends Backend
                 $sidList[$sid] = true;
             }
         }
-        $completeTsMap = ProcuremenTime::loadOperLogTimestampMap(array_keys($sidList), ['purchase_confirm', 'mark_complete']);
-        $pickedSupplierMap = $this->loadPickedSupplierNamesByScydgyIds(array_keys($sidList));
+        // 审核确认 / 完结时间都可用于归属月份与展示
+        $completeTsMap = ProcuremenTime::loadOperLogTimestampMap(
+            array_keys($sidList),
+            ['purchase_confirm', 'mark_complete']
+        );
 
         $pool = [];
         foreach ($dbRows as $r) {
             if (!is_array($r)) {
                 continue;
             }
+            if (!ProcuremenStatus::isWflowApproved($r['wflow_status'] ?? '')) {
+                continue;
+            }
             $done = ProcuremenTime::resolveCompletedDone($r, $completeTsMap);
             if ($done['ts'] <= 0) {
-                continue;
+                // 审批通过但缺时间戳:仍展示;有筛月时挂到查询月
+                $rowYm = $ym !== '' ? $ym : '';
+                $timeText = '';
+            } else {
+                $rowYm = date('Y-m', $done['ts']);
+                $timeText = $done['text'];
             }
-            $rowYm = date('Y-m', $done['ts']);
             if ($ym !== '' && $rowYm !== $ym) {
                 continue;
             }
             $sid = (int)($r['scydgy_id'] ?? 0);
-            $pickedName = trim((string)($pickedSupplierMap[$sid] ?? ''));
-            if ($pickedName === '') {
-                $pickedName = trim((string)($r['pick_company_name'] ?? ''));
-            }
+            // 已选供应商以采购单中标字段为准(一家),不拼明细里多条「已选中」
+            $pickedName = trim((string)($r['pick_company_name'] ?? ''));
             $pool[] = [
                 'id'                 => (int)($r['id'] ?? 0),
                 'scydgy_id'          => $sid,
                 'CCYDH'              => trim((string)($r['CCYDH'] ?? '')),
+                'order_batch_no'     => trim((string)($r['order_batch_no'] ?? '')),
                 'CYJMC'              => trim((string)($r['CYJMC'] ?? '')),
                 'CGYMC'              => trim((string)($r['CGYMC'] ?? '')),
                 'ym'                 => $rowYm,
-                'createtime_text'    => $done['text'],
+                'createtime_text'    => $timeText,
                 'picked_supplier'    => $pickedName,
             ];
         }
 
         $merged = $this->collapseExportRowsByOrder($pool);
         foreach ($merged as &$row) {
-            $names = [];
+            $picked = '';
+            $batchNo = trim((string)($row['order_batch_no'] ?? ''));
             if (!empty($row['_merge_rows']) && is_array($row['_merge_rows'])) {
                 foreach ($row['_merge_rows'] as $mr) {
                     if (!is_array($mr)) {
                         continue;
                     }
-                    $n = trim((string)($mr['picked_supplier'] ?? ''));
-                    if ($n !== '' && !in_array($n, $names, true)) {
-                        $names[] = $n;
+                    if ($picked === '') {
+                        $n = trim((string)($mr['picked_supplier'] ?? ''));
+                        if ($n !== '') {
+                            $picked = $n;
+                        }
+                    }
+                    if ($batchNo === '') {
+                        $bn = trim((string)($mr['order_batch_no'] ?? ''));
+                        if ($bn !== '') {
+                            $batchNo = $bn;
+                        }
                     }
                     if (trim((string)($row['ym'] ?? '')) === '') {
                         $ymv = trim((string)($mr['ym'] ?? ''));
@@ -327,12 +356,10 @@ class Procuremenexport extends Backend
                     }
                 }
             } else {
-                $n = trim((string)($row['picked_supplier'] ?? ''));
-                if ($n !== '') {
-                    $names[] = $n;
-                }
+                $picked = trim((string)($row['picked_supplier'] ?? ''));
             }
-            $row['picked_supplier'] = implode('、', $names);
+            $row['picked_supplier'] = $picked;
+            $row['order_batch_no'] = $batchNo;
             unset($row['_merge_rows']);
         }
         unset($row);

+ 463 - 145
application/admin/controller/Supplierservicescore.php

@@ -49,16 +49,20 @@ class Supplierservicescore extends Backend
             $list = $keyword !== ''
                 ? $this->loadSupplierScoreSearchList($keyword)
                 : $this->loadMonthlySupplierScoreList($ym, '', $forceSync);
+            // 按列表行月份批量统计中标订单数(与「本月订单明细」口径一致)
+            $winCountByYmCompany = $this->loadMonthWinOrderCountMapForList($list);
             $total = count($list);
             $pageRows = array_slice($list, $offset, $limit);
             $seqBase = $offset;
             $rows = [];
             foreach ($pageRows as $i => $item) {
                 $rowYm = (string)($item['ym'] ?? $ym);
+                $companyName = (string)($item['company_name'] ?? '');
+                $winKey = $rowYm . "\0" . $companyName;
                 $rows[] = [
                     'id'                       => $seqBase + $i + 1,
                     'seq_no'                   => $seqBase + $i + 1,
-                    'company_name'             => (string)($item['company_name'] ?? ''),
+                    'company_name'             => $companyName,
                     'quality_score'            => $item['quality_score'] ?? null,
                     'quality_score_text'       => (string)($item['quality_score_text'] ?? ''),
                     'price_score'              => $item['price_score'] ?? null,
@@ -73,6 +77,7 @@ class Supplierservicescore extends Backend
                     'score_grade'              => (string)($item['score_grade'] ?? ''),
                     'score_date'               => (string)(($item['score_date'] ?? '') !== '' ? $item['score_date'] : $rowYm),
                     'ym'                       => $rowYm,
+                    'win_order_count'          => (int)($winCountByYmCompany[$winKey] ?? 0),
                 ];
             }
 
@@ -491,14 +496,188 @@ class Supplierservicescore extends Backend
     }
 
     /**
-     * 本月订单明细:已下发订单按「下发批次」(pick_time) 分行;
-     * 同一批次内多工序顿号合并,不同下发时间不合并。
-     * 仅返回已做质量评分且已完结的订单。
+     * 列表页批量统计:各供应商在对应月份的中标订单数(审核通过 + 中标)
+     * key = ym + "\0" + company_name
      *
-     * @return array<int, array<string, mixed>>
+     * @param array<int, array<string, mixed>> $list
+     * @return array<string, int>
      */
+    protected function loadMonthWinOrderCountMapForList(array $list): array
+    {
+        /** @var array<string, array<string, true>> $need ym => company => true */
+        $need = [];
+        foreach ($list as $item) {
+            if (!is_array($item)) {
+                continue;
+            }
+            $rowYm = trim((string)($item['ym'] ?? ''));
+            $cn = trim((string)($item['company_name'] ?? ''));
+            if (!preg_match('/^\d{4}-\d{2}$/', $rowYm) || $cn === '') {
+                continue;
+            }
+            if (!isset($need[$rowYm])) {
+                $need[$rowYm] = [];
+            }
+            $need[$rowYm][$cn] = true;
+        }
+        if ($need === []) {
+            return [];
+        }
+
+        $out = [];
+        foreach ($need as $ym => $companySet) {
+            $map = $this->loadMonthWinOrderCountMap($ym, array_keys($companySet));
+            foreach ($map as $cn => $cnt) {
+                $out[$ym . "\0" . $cn] = (int)$cnt;
+            }
+            foreach (array_keys($companySet) as $cn) {
+                $k = $ym . "\0" . $cn;
+                if (!isset($out[$k])) {
+                    $out[$k] = 0;
+                }
+            }
+        }
+
+        return $out;
+    }
+
     /**
-     * 本月订单明细:与质量得分同源 —— 该供应商「完结时间」落在本月且已质量评分的订单
+     * 某月各供应商中标订单数(按订单号去重)
+     * 口径与 loadMonthOrdersForSupplier 一致:审核通过 + pick 中标,且(下发月=本月 或 本月开标评分表有该单)
+     *
+     * @param string[] $companyNames
+     * @return array<string, int>
+     */
+    protected function loadMonthWinOrderCountMap(string $ym, array $companyNames): array
+    {
+        $ym = trim($ym);
+        $names = [];
+        foreach ($companyNames as $n) {
+            $n = trim((string)$n);
+            if ($n !== '') {
+                $names[$n] = true;
+            }
+        }
+        $companyNames = array_keys($names);
+        if (!preg_match('/^\d{4}-\d{2}$/', $ym) || $companyNames === []) {
+            return [];
+        }
+        ProcuremenSupplierScore::ensureSchema();
+        $approvedVals = \app\common\library\ProcuremenStatus::wflowApprovedValues();
+        $softDel = '(mod_rq IS NULL OR TRIM(CAST(mod_rq AS CHAR(32))) = \'\' OR TRIM(CAST(mod_rq AS CHAR(32))) LIKE \'0000-00-00%\')';
+
+        /** @var array<string, array<string, true>> $seen company => ccydh => true */
+        $seen = [];
+
+        // A) 下发时间落在本月的中标单
+        try {
+            $poRows = \think\Db::table('purchase_order')
+                ->where('pick_company_name', 'in', $companyNames)
+                ->where('wflow_status', 'in', $approvedVals)
+                ->whereRaw($softDel)
+                ->whereRaw('pick_time IS NOT NULL AND TRIM(CAST(pick_time AS CHAR(32))) <> \'\' AND TRIM(CAST(pick_time AS CHAR(32))) NOT LIKE \'0000-00-00%\'')
+                ->whereRaw('DATE_FORMAT(pick_time, \'%Y-%m\') = ?', [$ym])
+                ->field('CCYDH,pick_company_name')
+                ->select();
+        } catch (\Throwable $e) {
+            $poRows = [];
+        }
+        if (is_array($poRows)) {
+            foreach ($poRows as $po) {
+                if (!is_array($po)) {
+                    continue;
+                }
+                $cn = trim((string)($po['pick_company_name'] ?? ''));
+                $ccydh = trim((string)($po['CCYDH'] ?? ''));
+                if ($cn === '' || $ccydh === '' || !isset($names[$cn])) {
+                    continue;
+                }
+                if (!isset($seen[$cn])) {
+                    $seen[$cn] = [];
+                }
+                $seen[$cn][$ccydh] = true;
+            }
+        }
+
+        // B) 本月开标评分表有记录、且采购单仍为该供应商中标并已审核
+        try {
+            $bidRows = \think\Db::table(ProcuremenSupplierScore::TABLE_SCORE)
+                ->where('ym', $ym)
+                ->where('company_name', 'in', $companyNames)
+                ->field('ccydh,company_name')
+                ->select();
+        } catch (\Throwable $e) {
+            $bidRows = [];
+        }
+        $bidCcydhByCompany = [];
+        if (is_array($bidRows)) {
+            foreach ($bidRows as $br) {
+                if (!is_array($br)) {
+                    continue;
+                }
+                $cn = trim((string)($br['company_name'] ?? ''));
+                $ccydh = trim((string)($br['ccydh'] ?? ''));
+                if ($cn === '' || $ccydh === '' || !isset($names[$cn])) {
+                    continue;
+                }
+                if (!isset($bidCcydhByCompany[$cn])) {
+                    $bidCcydhByCompany[$cn] = [];
+                }
+                $bidCcydhByCompany[$cn][$ccydh] = true;
+            }
+        }
+        $allBidCcydh = [];
+        foreach ($bidCcydhByCompany as $set) {
+            foreach (array_keys($set) as $c) {
+                $allBidCcydh[$c] = true;
+            }
+        }
+        if ($allBidCcydh !== []) {
+            try {
+                $poBid = \think\Db::table('purchase_order')
+                    ->where('CCYDH', 'in', array_keys($allBidCcydh))
+                    ->where('pick_company_name', 'in', $companyNames)
+                    ->where('wflow_status', 'in', $approvedVals)
+                    ->whereRaw($softDel)
+                    ->field('CCYDH,pick_company_name')
+                    ->select();
+            } catch (\Throwable $e) {
+                $poBid = [];
+            }
+            if (is_array($poBid)) {
+                foreach ($poBid as $po) {
+                    if (!is_array($po)) {
+                        continue;
+                    }
+                    $cn = trim((string)($po['pick_company_name'] ?? ''));
+                    $ccydh = trim((string)($po['CCYDH'] ?? ''));
+                    if ($cn === '' || $ccydh === '' || !isset($names[$cn])) {
+                        continue;
+                    }
+                    if (!isset($bidCcydhByCompany[$cn][$ccydh])) {
+                        continue;
+                    }
+                    if (!isset($seen[$cn])) {
+                        $seen[$cn] = [];
+                    }
+                    $seen[$cn][$ccydh] = true;
+                }
+            }
+        }
+
+        $out = [];
+        foreach ($companyNames as $cn) {
+            $out[$cn] = isset($seen[$cn]) ? count($seen[$cn]) : 0;
+        }
+
+        return $out;
+    }
+
+    /**
+     * 本月订单明细:
+     * 1)该供应商「审核通过」且中标的订单(按选定时间落在本月,或本月开标评分表有该单);
+     * 2)叠加「完结月=本月且已质量评分」的订单(有分可看合格/交货等)。
+     * 未到入库评分阶段的单:仍显示中标,分项/合格等为空,进度为待入库评分。
      *
      * @return array<int, array<string, mixed>>
      */
@@ -511,7 +690,141 @@ class Supplierservicescore extends Backend
         }
         ProcuremenSupplierScore::ensureSchema();
 
-        // 1) 入库/质量评分表(先取该供应商全部,再按完结月过滤,与月度计分一致)
+        /** @var array<string, array<string, mixed>> $byCcydh */
+        $byCcydh = [];
+
+        // ——— A) 审核通过 + 中标(本月)———
+        $approvedVals = \app\common\library\ProcuremenStatus::wflowApprovedValues();
+        $bidCcydhSet = [];
+        try {
+            $bidCcydhRows = \think\Db::table(ProcuremenSupplierScore::TABLE_SCORE)
+                ->where('ym', $ym)
+                ->where('company_name', $companyName)
+                ->field('ccydh')
+                ->select();
+            if (is_array($bidCcydhRows)) {
+                foreach ($bidCcydhRows as $br) {
+                    if (!is_array($br)) {
+                        continue;
+                    }
+                    $c = trim((string)($br['ccydh'] ?? ''));
+                    if ($c !== '') {
+                        $bidCcydhSet[$c] = true;
+                    }
+                }
+            }
+        } catch (\Throwable $e) {
+        }
+        try {
+            $poWinQuery = \think\Db::table('purchase_order')
+                ->where('pick_company_name', $companyName)
+                ->where('wflow_status', 'in', $approvedVals)
+                ->whereRaw('(mod_rq IS NULL OR TRIM(CAST(mod_rq AS CHAR(32))) = \'\' OR TRIM(CAST(mod_rq AS CHAR(32))) LIKE \'0000-00-00%\')')
+                ->field('CCYDH,CYJMC,CGYMC,CCLBMMC,CDW,pick_company_name,wflow_status,status,pick_time,scydgy_id,order_batch_no');
+            $poWinRows = $poWinQuery->order('id', 'asc')->select();
+        } catch (\Throwable $e) {
+            try {
+                $poWinRows = \think\Db::table('purchase_order')
+                    ->where('pick_company_name', $companyName)
+                    ->where('wflow_status', 'in', $approvedVals)
+                    ->whereRaw('(mod_rq IS NULL OR TRIM(CAST(mod_rq AS CHAR(32))) = \'\' OR TRIM(CAST(mod_rq AS CHAR(32))) LIKE \'0000-00-00%\')')
+                    ->field('CCYDH,CYJMC,CGYMC,CCLBMMC,CDW,pick_company_name,wflow_status,status,pick_time,scydgy_id')
+                    ->order('id', 'asc')
+                    ->select();
+            } catch (\Throwable $e2) {
+                $poWinRows = [];
+            }
+        }
+        if (!is_array($poWinRows)) {
+            $poWinRows = [];
+        }
+        foreach ($poWinRows as $po) {
+            if (!is_array($po)) {
+                continue;
+            }
+            $ccydh = trim((string)($po['CCYDH'] ?? ''));
+            if ($ccydh === '') {
+                continue;
+            }
+            $pickTime = trim((string)($po['pick_time'] ?? ''));
+            $pickYm = '';
+            if ($pickTime !== '' && !preg_match('/^0000-00-00/', $pickTime)) {
+                $ts = strtotime($pickTime);
+                if ($ts !== false) {
+                    $pickYm = date('Y-m', $ts);
+                }
+            }
+            $inMonth = ($pickYm === $ym) || isset($bidCcydhSet[$ccydh]);
+            if (!$inMonth) {
+                continue;
+            }
+            if (!isset($byCcydh[$ccydh])) {
+                $byCcydh[$ccydh] = [
+                    'CCYDH'              => $ccydh,
+                    'order_batch_no'     => trim((string)($po['order_batch_no'] ?? '')),
+                    'scydgy_id'          => (int)($po['scydgy_id'] ?? 0),
+                    'scydgy_ids'         => [],
+                    'CYJMC'              => trim((string)($po['CYJMC'] ?? '')),
+                    'CCLBMMC'            => trim((string)($po['CCLBMMC'] ?? '')),
+                    'CDW'                => trim((string)($po['CDW'] ?? '')),
+                    'CGYMC_list'         => [],
+                    'pick_company_name'  => $companyName,
+                    'wflow_status'       => \app\common\library\ProcuremenStatus::WFLOW_APPROVED,
+                    'status'             => trim((string)($po['status'] ?? '')),
+                    'pick_time'          => $pickTime,
+                    'completed'          => \app\common\library\ProcuremenStatus::isPoCompleted($po['status'] ?? ''),
+                    'picked_match'       => true,
+                    'has_inbound_score'  => 0,
+                    'inbound_result'     => '',
+                    'delivery_status'    => '',
+                    'delivery_date'      => '',
+                    'customer_complaint' => 0,
+                    'complaint_remark'   => '',
+                    'order_interrupt'    => 0,
+                    'inbound_remark'     => '',
+                    'score_time'         => '',
+                ];
+            }
+            $g = &$byCcydh[$ccydh];
+            $sid = (int)($po['scydgy_id'] ?? 0);
+            if ($sid > 0) {
+                if ($g['scydgy_id'] <= 0) {
+                    $g['scydgy_id'] = $sid;
+                }
+                if (!in_array($sid, $g['scydgy_ids'], true)) {
+                    $g['scydgy_ids'][] = $sid;
+                }
+            }
+            $batchNo = trim((string)($po['order_batch_no'] ?? ''));
+            if ($batchNo !== '' && ($g['order_batch_no'] ?? '') === '') {
+                $g['order_batch_no'] = $batchNo;
+            }
+            if ($g['CYJMC'] === '') {
+                $g['CYJMC'] = trim((string)($po['CYJMC'] ?? ''));
+            }
+            if ($g['CCLBMMC'] === '') {
+                $g['CCLBMMC'] = trim((string)($po['CCLBMMC'] ?? ''));
+            }
+            if ($g['CDW'] === '') {
+                $g['CDW'] = trim((string)($po['CDW'] ?? ''));
+            }
+            $gymc = trim((string)($po['CGYMC'] ?? ''));
+            if ($gymc !== '' && !in_array($gymc, $g['CGYMC_list'], true)) {
+                $g['CGYMC_list'][] = $gymc;
+            }
+            if ($pickTime !== '' && !preg_match('/^0000-00-00/', $pickTime)) {
+                if ($g['pick_time'] === '' || strcmp($pickTime, $g['pick_time']) < 0) {
+                    $g['pick_time'] = $pickTime;
+                }
+            }
+            if (\app\common\library\ProcuremenStatus::isPoCompleted($po['status'] ?? '')) {
+                $g['completed'] = true;
+                $g['status'] = \app\common\library\ProcuremenStatus::PO_COMPLETED;
+            }
+            unset($g);
+        }
+
+        // ——— B) 入库质量评分(完结月=本月)叠加 ———
         try {
             $scoreRowsRaw = \think\Db::table('purchase_order_inbound_score')
                 ->where('company_name', $companyName)
@@ -537,10 +850,10 @@ class Supplierservicescore extends Backend
                 }
             }
         }
-        if (!is_array($scoreRowsRaw) || $scoreRowsRaw === []) {
-            return [];
+        if (!is_array($scoreRowsRaw)) {
+            $scoreRowsRaw = [];
         }
-        $sidSet = [];
+        $sidSetForYm = [];
         $inboundTimeBySid = [];
         foreach ($scoreRowsRaw as $r) {
             if (!is_array($r)) {
@@ -550,18 +863,24 @@ class Supplierservicescore extends Backend
             if ($sid <= 0) {
                 continue;
             }
-            $sidSet[$sid] = true;
+            $sidSetForYm[$sid] = true;
             $inboundTimeBySid[$sid] = [
                 'createtime' => $r['createtime'] ?? null,
                 'updatetime' => $r['updatetime'] ?? null,
             ];
         }
-        $completedYmMap = ProcuremenSupplierScore::loadCompletedYmMapByScydgyIds(array_keys($sidSet), $inboundTimeBySid);
-        $scoreRows = [];
+        $completedYmMap = $sidSetForYm !== []
+            ? ProcuremenSupplierScore::loadCompletedYmMapByScydgyIds(array_keys($sidSetForYm), $inboundTimeBySid)
+            : [];
         foreach ($scoreRowsRaw as $r) {
             if (!is_array($r)) {
                 continue;
             }
+            $ccydh = trim((string)($r['ccydh'] ?? ''));
+            $result = trim((string)($r['result'] ?? ''));
+            if ($ccydh === '' || ($result !== '合格' && $result !== '不合格')) {
+                continue;
+            }
             $sid = (int)($r['scydgy_id'] ?? 0);
             $rowYm = $sid > 0 ? (string)($completedYmMap[$sid] ?? '') : '';
             if ($rowYm === '' && $sid <= 0) {
@@ -573,28 +892,6 @@ class Supplierservicescore extends Backend
             if ($rowYm !== $ym) {
                 continue;
             }
-            $scoreRows[] = $r;
-        }
-        if ($scoreRows === []) {
-            return [];
-        }
-
-        /** @var array<string, array<string, mixed>> $byCcydh */
-        $byCcydh = [];
-        $sidSet = [];
-        foreach ($scoreRows as $r) {
-            if (!is_array($r)) {
-                continue;
-            }
-            $ccydh = trim((string)($r['ccydh'] ?? ''));
-            $result = trim((string)($r['result'] ?? ''));
-            if ($ccydh === '' || ($result !== '合格' && $result !== '不合格')) {
-                continue;
-            }
-            $sid = (int)($r['scydgy_id'] ?? 0);
-            if ($sid > 0) {
-                $sidSet[$sid] = true;
-            }
             $scoreTime = trim((string)($r['updatetime'] ?? ''));
             if ($scoreTime === '' || preg_match('/^0000-00-00/', $scoreTime)) {
                 $scoreTime = trim((string)($r['createtime'] ?? ''));
@@ -606,10 +903,20 @@ class Supplierservicescore extends Backend
                 }
                 $byCcydh[$ccydh] = [
                     'CCYDH'              => $ccydh,
+                    'order_batch_no'     => '',
                     'scydgy_id'          => $sid > 0 ? $sid : 0,
                     'scydgy_ids'         => $sid > 0 ? [$sid] : [],
                     'CYJMC'              => trim((string)($r['cyjmc'] ?? '')),
+                    'CCLBMMC'            => '',
+                    'CDW'                => '',
                     'CGYMC_list'         => [],
+                    'pick_company_name'  => $companyName,
+                    'wflow_status'       => \app\common\library\ProcuremenStatus::WFLOW_APPROVED,
+                    'status'             => '',
+                    'pick_time'          => '',
+                    'completed'          => true,
+                    'picked_match'       => true,
+                    'has_inbound_score'  => 1,
                     'inbound_result'     => $result,
                     'delivery_status'    => $ds,
                     'delivery_date'      => '',
@@ -621,9 +928,11 @@ class Supplierservicescore extends Backend
                 ];
             }
             $g = &$byCcydh[$ccydh];
-            // 任一工序不合格 → 整单不合格(与质量分统计一致)
+            $g['has_inbound_score'] = 1;
             if ($result === '不合格') {
                 $g['inbound_result'] = '不合格';
+            } elseif ($g['inbound_result'] === '') {
+                $g['inbound_result'] = $result;
             }
             if ($sid > 0) {
                 if ($g['scydgy_id'] <= 0) {
@@ -668,106 +977,118 @@ class Supplierservicescore extends Backend
             }
             unset($g);
         }
+
         if ($byCcydh === []) {
             return [];
         }
 
-        // 2) 补充采购单展示字段
-        $poByCcydh = [];
-        try {
-            $poRows = \think\Db::table('purchase_order')
-                ->where('CCYDH', 'in', array_keys($byCcydh))
-                ->whereRaw('(mod_rq IS NULL OR TRIM(CAST(mod_rq AS CHAR(32))) = \'\' OR TRIM(CAST(mod_rq AS CHAR(32))) LIKE \'0000-00-00%\')')
-                ->field('CCYDH,CYJMC,CGYMC,CCLBMMC,CDW,pick_company_name,wflow_status,status,pick_time,scydgy_id')
-                ->order('id', 'asc')
-                ->select();
-        } catch (\Throwable $e) {
-            $poRows = [];
+        // 补采购单展示字段(入库评分带来的单可能缺 PO 信息)
+        $needPo = [];
+        foreach ($byCcydh as $c => $g) {
+            if (($g['CCLBMMC'] ?? '') === ''
+                || ($g['pick_time'] ?? '') === ''
+                || empty($g['CGYMC_list'])
+                || ($g['order_batch_no'] ?? '') === ''
+            ) {
+                $needPo[$c] = true;
+            }
         }
-        if (is_array($poRows)) {
-            foreach ($poRows as $po) {
-                if (!is_array($po)) {
-                    continue;
-                }
-                $c = trim((string)($po['CCYDH'] ?? ''));
-                if ($c === '' || !isset($byCcydh[$c])) {
-                    continue;
-                }
-                if (!isset($poByCcydh[$c])) {
-                    $poByCcydh[$c] = [
-                        'CYJMC'             => '',
-                        'CCLBMMC'           => '',
-                        'CGYMC_list'        => [],
-                        'CDW'               => '',
-                        'pick_company_name' => '',
-                        'wflow_status'      => '',
-                        'status'            => '',
-                        'pick_time'         => '',
-                        'completed'         => false,
-                        'picked_match'      => false,
-                        'scydgy_id'         => 0,
-                    ];
-                }
-                $p = &$poByCcydh[$c];
-                $sid = (int)($po['scydgy_id'] ?? 0);
-                if ($p['scydgy_id'] <= 0 && $sid > 0) {
-                    $p['scydgy_id'] = $sid;
-                }
-                if ($p['CYJMC'] === '') {
-                    $p['CYJMC'] = trim((string)($po['CYJMC'] ?? ''));
-                }
-                if ($p['CCLBMMC'] === '') {
-                    $p['CCLBMMC'] = trim((string)($po['CCLBMMC'] ?? ''));
-                }
-                if ($p['CDW'] === '') {
-                    $p['CDW'] = trim((string)($po['CDW'] ?? ''));
-                }
-                $g = trim((string)($po['CGYMC'] ?? ''));
-                if ($g !== '' && !in_array($g, $p['CGYMC_list'], true)) {
-                    $p['CGYMC_list'][] = $g;
+        if ($needPo !== []) {
+            try {
+                $poRows = \think\Db::table('purchase_order')
+                    ->where('CCYDH', 'in', array_keys($needPo))
+                    ->whereRaw('(mod_rq IS NULL OR TRIM(CAST(mod_rq AS CHAR(32))) = \'\' OR TRIM(CAST(mod_rq AS CHAR(32))) LIKE \'0000-00-00%\')')
+                    ->field('CCYDH,CYJMC,CGYMC,CCLBMMC,CDW,pick_company_name,wflow_status,status,pick_time,scydgy_id,order_batch_no')
+                    ->order('id', 'asc')
+                    ->select();
+            } catch (\Throwable $e) {
+                try {
+                    $poRows = \think\Db::table('purchase_order')
+                        ->where('CCYDH', 'in', array_keys($needPo))
+                        ->whereRaw('(mod_rq IS NULL OR TRIM(CAST(mod_rq AS CHAR(32))) = \'\' OR TRIM(CAST(mod_rq AS CHAR(32))) LIKE \'0000-00-00%\')')
+                        ->field('CCYDH,CYJMC,CGYMC,CCLBMMC,CDW,pick_company_name,wflow_status,status,pick_time,scydgy_id')
+                        ->order('id', 'asc')
+                        ->select();
+                } catch (\Throwable $e2) {
+                    $poRows = [];
                 }
-                $pn = trim((string)($po['pick_company_name'] ?? ''));
-                if ($pn !== '') {
-                    if ($p['pick_company_name'] === '') {
-                        $p['pick_company_name'] = $pn;
+            }
+            if (is_array($poRows)) {
+                foreach ($poRows as $po) {
+                    if (!is_array($po)) {
+                        continue;
                     }
-                    if ($pn === $companyName) {
-                        $p['picked_match'] = true;
+                    $c = trim((string)($po['CCYDH'] ?? ''));
+                    if ($c === '' || !isset($byCcydh[$c])) {
+                        continue;
                     }
-                }
-                $pt = trim((string)($po['pick_time'] ?? ''));
-                if ($pt !== '' && !preg_match('/^0000-00-00/', $pt)) {
-                    if ($p['pick_time'] === '' || strcmp($pt, $p['pick_time']) < 0) {
-                        $p['pick_time'] = $pt;
+                    $g = &$byCcydh[$c];
+                    $sid = (int)($po['scydgy_id'] ?? 0);
+                    if ($g['scydgy_id'] <= 0 && $sid > 0) {
+                        $g['scydgy_id'] = $sid;
                     }
+                    if ($sid > 0 && !in_array($sid, $g['scydgy_ids'], true)) {
+                        $g['scydgy_ids'][] = $sid;
+                    }
+                    $batchNo = trim((string)($po['order_batch_no'] ?? ''));
+                    if ($batchNo !== '' && ($g['order_batch_no'] ?? '') === '') {
+                        $g['order_batch_no'] = $batchNo;
+                    }
+                    if ($g['CYJMC'] === '') {
+                        $g['CYJMC'] = trim((string)($po['CYJMC'] ?? ''));
+                    }
+                    if ($g['CCLBMMC'] === '') {
+                        $g['CCLBMMC'] = trim((string)($po['CCLBMMC'] ?? ''));
+                    }
+                    if ($g['CDW'] === '') {
+                        $g['CDW'] = trim((string)($po['CDW'] ?? ''));
+                    }
+                    $gymc = trim((string)($po['CGYMC'] ?? ''));
+                    if ($gymc !== '' && !in_array($gymc, $g['CGYMC_list'], true)) {
+                        $g['CGYMC_list'][] = $gymc;
+                    }
+                    $pt = trim((string)($po['pick_time'] ?? ''));
+                    if ($pt !== '' && !preg_match('/^0000-00-00/', $pt)) {
+                        if ($g['pick_time'] === '' || strcmp($pt, $g['pick_time']) < 0) {
+                            $g['pick_time'] = $pt;
+                        }
+                    }
+                    if (\app\common\library\ProcuremenStatus::isPoCompleted($po['status'] ?? '')) {
+                        $g['completed'] = true;
+                        $g['status'] = \app\common\library\ProcuremenStatus::PO_COMPLETED;
+                    } elseif ($g['status'] === '' && trim((string)($po['status'] ?? '')) !== '') {
+                        $g['status'] = trim((string)$po['status']);
+                    }
+                    if (\app\common\library\ProcuremenStatus::isWflowApproved($po['wflow_status'] ?? '')) {
+                        $g['wflow_status'] = \app\common\library\ProcuremenStatus::WFLOW_APPROVED;
+                    }
+                    unset($g);
                 }
-                if (\app\common\library\ProcuremenStatus::isPoCompleted($po['status'] ?? '')) {
-                    $p['completed'] = true;
-                    $p['status'] = \app\common\library\ProcuremenStatus::PO_COMPLETED;
-                } elseif ($p['status'] === '' && trim((string)($po['status'] ?? '')) !== '') {
-                    $p['status'] = trim((string)$po['status']);
-                }
-                if (\app\common\library\ProcuremenStatus::isWflowApproved($po['wflow_status'] ?? '')) {
-                    $p['wflow_status'] = \app\common\library\ProcuremenStatus::WFLOW_APPROVED;
-                } elseif ($p['wflow_status'] === '' && trim((string)($po['wflow_status'] ?? '')) !== '') {
-                    $p['wflow_status'] = trim((string)$po['wflow_status']);
-                }
-                unset($p);
             }
         }
 
-        // 3) 可选:招标评分表补排名/分项(没有也不影响展示)
+        // 开标分项(可选)
         $bidByCcydh = [];
         try {
             $bidRows = \think\Db::table(ProcuremenSupplierScore::TABLE_SCORE)
                 ->where('ym', $ym)
                 ->where('company_name', $companyName)
                 ->where('ccydh', 'in', array_keys($byCcydh))
-                ->field('ccydh,score,rank_no,quality_score,price_score,price_sum,lead_score,lead_days_sum,createtime')
+                ->field('ccydh,order_batch_no,score,rank_no,quality_score,price_score,price_sum,lead_score,lead_days_sum,createtime')
                 ->order('createtime', 'desc')
                 ->select();
         } catch (\Throwable $e) {
-            $bidRows = [];
+            try {
+                $bidRows = \think\Db::table(ProcuremenSupplierScore::TABLE_SCORE)
+                    ->where('ym', $ym)
+                    ->where('company_name', $companyName)
+                    ->where('ccydh', 'in', array_keys($byCcydh))
+                    ->field('ccydh,score,rank_no,quality_score,price_score,price_sum,lead_score,lead_days_sum,createtime')
+                    ->order('createtime', 'desc')
+                    ->select();
+            } catch (\Throwable $e2) {
+                $bidRows = [];
+            }
         }
         if (is_array($bidRows)) {
             foreach ($bidRows as $br) {
@@ -779,49 +1100,45 @@ class Supplierservicescore extends Backend
                     continue;
                 }
                 $bidByCcydh[$c] = $br;
+                $bn = trim((string)($br['order_batch_no'] ?? ''));
+                if ($bn !== '' && isset($byCcydh[$c]) && ($byCcydh[$c]['order_batch_no'] ?? '') === '') {
+                    $byCcydh[$c]['order_batch_no'] = $bn;
+                }
             }
         }
 
         $out = [];
         foreach ($byCcydh as $ccydh => $g) {
-            $po = $poByCcydh[$ccydh] ?? [];
             $bid = $bidByCcydh[$ccydh] ?? [];
             $gymcList = is_array($g['CGYMC_list'] ?? null) ? $g['CGYMC_list'] : [];
-            if ($gymcList === [] && is_array($po['CGYMC_list'] ?? null)) {
-                $gymcList = $po['CGYMC_list'];
-            }
+            $hasInbound = !empty($g['has_inbound_score']);
             $batch = [
-                'completed'    => !empty($po['completed']),
-                'status'       => (string)($po['status'] ?? ''),
-                'wflow_status' => (string)($po['wflow_status'] ?? ''),
+                'completed'    => !empty($g['completed']) || $hasInbound,
+                'status'       => (string)($g['status'] ?? ''),
+                'wflow_status' => (string)($g['wflow_status'] ?? ''),
             ];
             $progressText = $this->formatMonthOrderProgressText($batch);
-            // 已质量评分:进度优先显示已完结,否则显示实际流程
-            if ($progressText === '待入库评分') {
+            // 已质量评分:进度优先显示已完结
+            if ($hasInbound && $progressText === '待入库评分') {
                 $progressText = \app\common\library\ProcuremenStatus::PO_COMPLETED;
             }
-            $showBid = !empty($po['completed'])
-                || \app\common\library\ProcuremenStatus::isPoCompleted($po['status'] ?? '')
-                || \app\common\library\ProcuremenStatus::isWflowApproved($po['wflow_status'] ?? '');
-            $pickTimeRaw = trim((string)($po['pick_time'] ?? ''));
+            $pickTimeRaw = trim((string)($g['pick_time'] ?? ''));
             if ($pickTimeRaw === '') {
                 $pickTimeRaw = trim((string)($g['score_time'] ?? ''));
             }
             $sid = (int)($g['scydgy_id'] ?? 0);
-            if ($sid <= 0) {
-                $sid = (int)($po['scydgy_id'] ?? 0);
-            }
             $out[] = [
                 'seq_no'              => 0,
                 'scydgy_id'           => $sid,
                 'CCYDH'               => $ccydh,
-                'CYJMC'               => (string)(($g['CYJMC'] ?? '') !== '' ? $g['CYJMC'] : ($po['CYJMC'] ?? '')),
-                'CCLBMMC'             => (string)($po['CCLBMMC'] ?? ''),
+                'order_batch_no'      => (string)($g['order_batch_no'] ?? ''),
+                'CYJMC'               => (string)($g['CYJMC'] ?? ''),
+                'CCLBMMC'             => (string)($g['CCLBMMC'] ?? ''),
                 'CGYMC'               => $gymcList !== [] ? implode('、', $gymcList) : '',
-                'CDW'                 => (string)($po['CDW'] ?? ''),
-                'pick_company_name'   => (string)(($po['pick_company_name'] ?? '') !== '' ? $po['pick_company_name'] : $companyName),
-                'wflow_status'        => (string)($po['wflow_status'] ?? ''),
-                'status'              => (string)($po['status'] ?? ''),
+                'CDW'                 => (string)($g['CDW'] ?? ''),
+                'pick_company_name'   => (string)(($g['pick_company_name'] ?? '') !== '' ? $g['pick_company_name'] : $companyName),
+                'wflow_status'        => (string)($g['wflow_status'] ?? ''),
+                'status'              => (string)($g['status'] ?? ''),
                 'progress_text'       => $progressText,
                 'pick_time'           => $pickTimeRaw,
                 'issue_time'          => $pickTimeRaw !== ''
@@ -834,15 +1151,16 @@ class Supplierservicescore extends Backend
                 'price_sum'           => $bid['price_sum'] ?? null,
                 'lead_score'          => $bid['lead_score'] ?? null,
                 'lead_days_sum'       => $bid['lead_days_sum'] ?? null,
-                'is_picked'           => !empty($po['picked_match']) ? 1 : 1,
-                'show_bid_result'     => $showBid ? 1 : 0,
-                'inbound_result'      => (string)($g['inbound_result'] ?? ''),
-                'delivery_status'     => (string)($g['delivery_status'] ?? ''),
-                'delivery_date'       => (string)($g['delivery_date'] ?? ''),
-                'customer_complaint'  => (int)($g['customer_complaint'] ?? 0),
-                'complaint_remark'    => (string)($g['complaint_remark'] ?? ''),
-                'order_interrupt'     => (int)($g['order_interrupt'] ?? 0),
-                'inbound_remark'      => (string)($g['inbound_remark'] ?? ''),
+                'is_picked'           => 1,
+                'show_bid_result'     => 1,
+                'has_inbound_score'   => $hasInbound ? 1 : 0,
+                'inbound_result'      => $hasInbound ? (string)($g['inbound_result'] ?? '') : '',
+                'delivery_status'     => $hasInbound ? (string)($g['delivery_status'] ?? '') : '',
+                'delivery_date'       => $hasInbound ? (string)($g['delivery_date'] ?? '') : '',
+                'customer_complaint'  => $hasInbound ? (int)($g['customer_complaint'] ?? 0) : 0,
+                'complaint_remark'    => $hasInbound ? (string)($g['complaint_remark'] ?? '') : '',
+                'order_interrupt'     => $hasInbound ? (int)($g['order_interrupt'] ?? 0) : 0,
+                'inbound_remark'      => $hasInbound ? (string)($g['inbound_remark'] ?? '') : '',
             ];
         }
 

+ 3 - 3
application/admin/view/procuremen/audit_issue.html

@@ -8,7 +8,7 @@
     }
     .procuremen-score-tip:hover { color: #3c8dbc; }
     body.is-dialog .audit-issue-wrap {
-        padding: 12px 14px 0;
+        padding: 0 14px 0;
         max-width: 100%;
         box-sizing: border-box;
     }
@@ -607,7 +607,7 @@
     {if !empty($quoteVisible)}
     <p class="audit-score-rule-tip">
         <i class="fa fa-info-circle"></i>
-        <strong>评分规则:</strong>{$supplierScoreRuleText|default='(总分)=(质量得分×50%)+(价格得分);价格得分=(最低单价合计/本供应商单价合计)×50%×100'|htmlentities}
+        <strong>评分规则:</strong>{$supplierScoreRuleText|default='(总分)=(质量得分×50%)+(价格得分);价格得分=(最低单价合计/本供应商单价合计)×50%×100(一批多订单时按子项比例加权:比例=数量×最高限价/Σ(数量×最高限价))'|htmlentities}
     </p>
     {/if}
     <div class="audit-table-wrap audit-quote-table-wrap">
@@ -618,7 +618,7 @@
                 <th style="min-width:220px;">供应商信息</th>
                 <th class="text-center col-rank" style="width:64px;">排名</th>
                 <th class="text-center" style="width:88px;">质量得分 <i class="fa fa-question-circle procuremen-score-tip" title="质量得分取月度评审(当月按上月起往前查,无则默认40)"></i></th>
-                <th class="text-center" style="width:80px;">价格得分 <i class="fa fa-question-circle procuremen-score-tip" title="价格得分=(最低单价合计/本供应商单价合计)×价格权重%×100"></i></th>
+                <th class="text-center" style="width:80px;">价格得分 <i class="fa fa-question-circle procuremen-score-tip" title="单订单:价格得分=(最低单价合计/本供应商单价合计)×价格权重%×100;一批多订单:按比例加权,比例=数量×最高限价/Σ(数量×最高限价)"></i></th>
                 {if !empty($showServiceLeadScore)}
                 <th class="text-center" style="width:80px;">交货得分 <i class="fa fa-question-circle procuremen-score-tip" title="交货得分=月度交货分×50%+报价交期分×50%(按订单算,一批多订单平均;报价交期满分40,提前+1/滞后-1)"></i></th>
                 {/if}

+ 1 - 1
application/admin/view/procuremen/details_fragment.html

@@ -575,7 +575,7 @@
                 <th class="col-supplier-info">供应商信息</th>
                 <th class="text-center col-rank" style="width:64px;">排名</th>
                 <th class="text-center" style="width:88px;">质量得分 <i class="fa fa-question-circle procuremen-score-tip" title="质量得分取月度评审(当月按上月起往前查,无则默认40)"></i></th>
-                <th class="text-center" style="width:80px;">价格得分 <i class="fa fa-question-circle procuremen-score-tip" title="价格得分=(最低单价合计/本供应商单价合计)×价格权重%×100"></i></th>
+                <th class="text-center" style="width:80px;">价格得分 <i class="fa fa-question-circle procuremen-score-tip" title="单订单:价格得分=(最低单价合计/本供应商单价合计)×价格权重%×100;一批多订单:按比例加权,比例=数量×最高限价/Σ(数量×最高限价)"></i></th>
                 {if !empty($showServiceLeadScore)}
                 <th class="text-center" style="width:80px;">交货得分 <i class="fa fa-question-circle procuremen-score-tip" title="交货得分=月度交货分×50%+报价交期分×50%(按订单算,一批多订单平均;报价交期满分40,提前+1/滞后-1)"></i></th>
                 {/if}

+ 3 - 3
application/admin/view/procuremen/outward_detail.html

@@ -9,7 +9,7 @@
     .procuremen-score-tip:hover { color: #3c8dbc; }
     body.is-dialog .outward-detail-wrap {
         margin: 0;
-        padding: 12px 14px 0;
+        padding: 0 14px 0;
         max-width: 100%;
         box-sizing: border-box;
     }
@@ -552,7 +552,7 @@
     {if !empty($quoteVisible)}
     <p class="audit-score-rule-tip">
         <i class="fa fa-info-circle"></i>
-        <strong>评分规则:</strong>{$supplierScoreRuleText|default='(总分)=(质量得分×50%)+(价格得分);价格得分=(最低单价合计/本供应商单价合计)×50%×100'|htmlentities}
+        <strong>评分规则:</strong>{$supplierScoreRuleText|default='(总分)=(质量得分×50%)+(价格得分);价格得分=(最低单价合计/本供应商单价合计)×50%×100(一批多订单时按子项比例加权:比例=数量×最高限价/Σ(数量×最高限价))'|htmlentities}
     </p>
     {/if}
     <p class="outward-confirm-block-title">供应商({$confirmPickCount|default=0} 家)</p>
@@ -564,7 +564,7 @@
                 <th class="col-supplier-info">供应商信息</th>
                 <th class="text-center col-rank" style="width:64px;">排名</th>
                 <th class="text-center" style="width:88px;">质量得分 <i class="fa fa-question-circle procuremen-score-tip" title="质量得分取月度评审(当月按上月起往前查,无则默认40)"></i></th>
-                <th class="text-center" style="width:80px;">价格得分 <i class="fa fa-question-circle procuremen-score-tip" title="价格得分=(最低单价合计/本供应商单价合计)×价格权重%×100"></i></th>
+                <th class="text-center" style="width:80px;">价格得分 <i class="fa fa-question-circle procuremen-score-tip" title="单订单:价格得分=(最低单价合计/本供应商单价合计)×价格权重%×100;一批多订单:按比例加权,比例=数量×最高限价/Σ(数量×最高限价)"></i></th>
                 {if !empty($showServiceLeadScore)}
                 <th class="text-center" style="width:80px;">交货得分 <i class="fa fa-question-circle procuremen-score-tip" title="交货得分=月度交货分×50%+报价交期分×50%(按订单算,一批多订单平均;报价交期满分40,提前+1/滞后-1)"></i></th>
                 {/if}

+ 91 - 21
application/admin/view/supplierservicescore/monthorders.html

@@ -73,7 +73,7 @@
     }
     .ssc-month-orders-table {
         margin-bottom: 0;
-        min-width: 1680px;
+        min-width: 1920px;
     }
     .ssc-month-orders-table > thead > tr > th,
     .ssc-month-orders-table > tbody > tr > td {
@@ -83,10 +83,54 @@
     }
     .ssc-month-orders-table .ssc-name-cell {
         text-align: left;
-        white-space: normal;
+        white-space: nowrap;
         word-break: break-all;
         max-width: 220px;
     }
+    .ssc-month-orders-table .ssc-cyjmc-cell {
+        text-align: left;
+        white-space: normal;
+        min-width: 320px;
+        width: 360px;
+        max-width: 360px;
+        vertical-align: middle;
+    }
+    .ssc-month-orders-table .ssc-cyjmc-wrap {
+        display: flex;
+        align-items: flex-start;
+        gap: 6px;
+        max-width: 360px;
+        text-align: left;
+    }
+    .ssc-month-orders-table .ssc-cyjmc-text {
+        flex: 1 1 auto;
+        min-width: 0;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        word-break: break-all;
+        line-height: 1.4;
+    }
+    .ssc-month-orders-table .ssc-cyjmc-wrap.is-expanded .ssc-cyjmc-text {
+        white-space: normal;
+        overflow: visible;
+        text-overflow: clip;
+    }
+    .ssc-month-orders-table .ssc-cyjmc-toggle {
+        flex: 0 0 auto;
+        display: none;
+        padding: 0 2px;
+        color: #18bc9c;
+        cursor: pointer;
+        line-height: 1.4;
+        text-decoration: none;
+    }
+    .ssc-month-orders-table .ssc-cyjmc-wrap.is-overflow .ssc-cyjmc-toggle {
+        display: inline-block;
+    }
+    .ssc-month-orders-table .ssc-cyjmc-toggle:hover {
+        color: #128f76;
+    }
     .ssc-month-orders-table .ssc-text-cell {
         text-align: left;
         white-space: normal;
@@ -149,6 +193,7 @@
         <span class="ssc-meta">日期:{$ym|htmlentities}</span>
         <span class="ssc-meta">供应商:<span class="ssc-company">{$company_name|htmlentities}</span></span>
         <span class="ssc-meta">共 {$orderCount} 单</span>
+        <span class="ssc-meta" style="color:#999;">含已审核中标;分项/入库结果空表示尚未到该阶段</span>
     </div>
     {if $orderRows}
     <div class="table-responsive">
@@ -156,6 +201,7 @@
             <thead>
             <tr>
                 <th style="width:50px;">序号</th>
+                <th>批次号</th>
                 <th>订单号</th>
                 <th>印件名称</th>
                 <th>承揽部门</th>
@@ -181,14 +227,22 @@
             {volist name="orderRows" id="row"}
             <tr>
                 <td>{$row.seq_no}</td>
+                <td>{$row.order_batch_no|default=''|htmlentities}</td>
                 <td>{$row.CCYDH|default=''|htmlentities}</td>
-                <td class="ssc-name-cell">{$row.CYJMC|default=''|htmlentities}</td>
+                <td class="ssc-cyjmc-cell">
+                    {if $row.CYJMC}
+                    <div class="ssc-cyjmc-wrap" title="{$row.CYJMC|htmlentities}">
+                        <span class="ssc-cyjmc-text">{$row.CYJMC|htmlentities}</span>
+                        <a href="javascript:;" class="ssc-cyjmc-toggle" title="展开/收起"><i class="fa fa-angle-down"></i></a>
+                    </div>
+                    {/if}
+                </td>
                 <td>{$row.CCLBMMC|default=''|htmlentities}</td>
                 <td class="ssc-name-cell">{$row.CGYMC|default=''|htmlentities}</td>
-                <td>{if $row.rank_no}{$row.rank_no}{/if}</td>
-                <td>{$row.quality_score|default=''}</td>
-                <td>{$row.price_score|default=''}</td>
-                <td>{$row.lead_score|default=''}</td>
+                <td>{notempty name="row.rank_no"}{$row.rank_no}{/notempty}</td>
+                <td>{notempty name="row.quality_score"}{$row.quality_score}{/notempty}</td>
+                <td>{notempty name="row.price_score"}{$row.price_score}{/notempty}</td>
+                <td>{notempty name="row.lead_score"}{$row.lead_score}{/notempty}</td>
                 <td>
                     {if $row.show_bid_result}
                         {if $row.is_picked}
@@ -198,23 +252,39 @@
                         {/if}
                     {/if}
                 </td>
-                <td>{$row.inbound_result|default=''}</td>
-                <td class="ssc-text-cell">{if $row.inbound_remark}{$row.inbound_remark|htmlentities}{/if}</td>
-                <td>{$row.delivery_status|default=''}</td>
-                <td>{$row.delivery_date|default=''}</td>
                 <td>
-                    {if condition="$row.customer_complaint eq 1"}
-                    是
-                    {else/}
-                    否
+                    {if condition="$row.has_inbound_score eq 1"}
+                    {$row.inbound_result|default=''}
+                    {/if}
+                </td>
+                <td class="ssc-text-cell">
+                    {if condition="$row.has_inbound_score eq 1"}
+                    {if $row.inbound_remark}{$row.inbound_remark|htmlentities}{/if}
                     {/if}
                 </td>
-                <td class="ssc-text-cell">{if $row.complaint_remark}{$row.complaint_remark|htmlentities}{/if}</td>
                 <td>
-                    {if condition="$row.order_interrupt eq 1"}
-                    是
-                    {else/}
-                    否
+                    {if condition="$row.has_inbound_score eq 1"}
+                    {$row.delivery_status|default=''}
+                    {/if}
+                </td>
+                <td>
+                    {if condition="$row.has_inbound_score eq 1"}
+                    {$row.delivery_date|default=''}
+                    {/if}
+                </td>
+                <td>
+                    {if condition="$row.has_inbound_score eq 1"}
+                        {if condition="$row.customer_complaint eq 1"}是{else/}否{/if}
+                    {/if}
+                </td>
+                <td class="ssc-text-cell">
+                    {if condition="$row.has_inbound_score eq 1"}
+                    {if $row.complaint_remark}{$row.complaint_remark|htmlentities}{/if}
+                    {/if}
+                </td>
+                <td>
+                    {if condition="$row.has_inbound_score eq 1"}
+                        {if condition="$row.order_interrupt eq 1"}是{else/}否{/if}
                     {/if}
                 </td>
                 <td>
@@ -240,7 +310,7 @@
         </table>
     </div>
     {else/}
-    <div class="ssc-month-orders-empty">该供应商本月暂无订单</div>
+    <div class="ssc-month-orders-empty">该供应商本月暂无已审核中标订单</div>
     {/if}
 </div>
 <div class="layer-footer clearfix">

+ 251 - 27
application/common/library/ProcuremenSupplierScore.php

@@ -9,14 +9,16 @@ use think\Log;
  * 协助采购 — 供应商服务评分
  *
  * 表分工:
- * - supplier_service_score:订单明细(开标后按 ccydh×供应商写入,含本单总分 score)
+ * - supplier_service_score:订单明细(开标后按 ccydh×供应商写入,含本单总分 score;含 order_batch_no 批次号
  * - supplier_service_final_score:月度评审表(四项自动统计,满分 105;qp_manual=1 手工锁定不覆盖)
  *
  * 开标单笔总分 = 质量得分×质量% + 价格得分 [+ 交货得分×交货%]
  * 开标质量得分:取月度评审表(当月按上月起往前查,无则默认 40)
  * 开标交货得分:月度交货分×50% + 本单报价交期分×50%(按订单算,一批多订单取平均)
  *   报价交期分:满分40,相对订单交货截止日每提前1天+1、滞后1天-1
- * 开标价格得分 = (本单最低单价合计 / 本供应商单价合计) × 价格权重% × 100
+ * 开标价格得分(单订单)= (本单最低单价合计 / 本供应商单价合计) × 价格权重% × 100
+ * 开标价格得分(一批多订单)= Σ[ 比例_i × (该行最低单价/本供应商该行单价) × 价格权重% × 100 ]
+ *   比例_i = (数量_i × 最高限价_i) / Σ(数量 × 最高限价)
  *
  * 月度评审(与开标单笔分离):
  * 质量40 = 合格率对照(20) + 客户投诉(10) + 生产中断(10)
@@ -40,7 +42,7 @@ class ProcuremenSupplierScore
     protected static $inboundAggCache = [];
 
     /** 结构探测缓存键(升版本可强制再跑一遍迁移) */
-    const SCHEMA_CACHE_KEY = 'procuremen_supplier_score_schema_ok_v6';
+    const SCHEMA_CACHE_KEY = 'procuremen_supplier_score_schema_ok_v7';
 
     public static function ensureSchema(): void
     {
@@ -60,6 +62,7 @@ class ProcuremenSupplierScore
                 \think\Cache::rm('procuremen_supplier_score_schema_ok_v3');
                 \think\Cache::rm('procuremen_supplier_score_schema_ok_v4');
                 \think\Cache::rm('procuremen_supplier_score_schema_ok_v5');
+                \think\Cache::rm('procuremen_supplier_score_schema_ok_v6');
             } catch (\Throwable $e) {
             }
         } catch (\Throwable $e) {
@@ -111,9 +114,54 @@ class ProcuremenSupplierScore
         self::ensureScoreWeightColumns();
         self::ensureLeadColumns();
         self::ensureIntegerColumns();
+        self::ensureScoreBatchNoColumn();
         self::ensureFinalScoreTable();
     }
 
+    /**
+     * 开标评分表明细补批次号(便于按批次查订单/供应商/排名分数)
+     */
+    protected static function ensureScoreBatchNoColumn(): void
+    {
+        static $done = false;
+        if ($done) {
+            return;
+        }
+        try {
+            $cols = Db::query("SHOW COLUMNS FROM `" . self::TABLE_SCORE . "` LIKE 'order_batch_no'");
+            if (!is_array($cols) || $cols === []) {
+                Db::execute(
+                    "ALTER TABLE `" . self::TABLE_SCORE . "` ADD COLUMN `order_batch_no` varchar(32) NOT NULL DEFAULT '' COMMENT '下发批次号' AFTER `ccydh`"
+                );
+            }
+            $idx = Db::query("SHOW INDEX FROM `" . self::TABLE_SCORE . "` WHERE Key_name = 'idx_order_batch_no'");
+            if (!is_array($idx) || $idx === []) {
+                Db::execute(
+                    "ALTER TABLE `" . self::TABLE_SCORE . "` ADD INDEX `idx_order_batch_no` (`order_batch_no`)"
+                );
+            }
+            // 历史空批次:用 purchase_order 按订单号回填(不改已有非空值)
+            try {
+                Db::execute(
+                    "UPDATE `" . self::TABLE_SCORE . "` s
+                     INNER JOIN (
+                       SELECT CCYDH AS ccydh, MAX(order_batch_no) AS order_batch_no
+                       FROM `purchase_order`
+                       WHERE TRIM(IFNULL(order_batch_no,'')) <> ''
+                       GROUP BY CCYDH
+                     ) po ON po.ccydh = s.ccydh
+                     SET s.order_batch_no = po.order_batch_no
+                     WHERE TRIM(IFNULL(s.order_batch_no,'')) = ''"
+                );
+            } catch (\Throwable $e2) {
+                Log::write('supplier score batch backfill: ' . $e2->getMessage(), 'error');
+            }
+            $done = true;
+        } catch (\Throwable $e) {
+            Log::write('supplier score order_batch_no: ' . $e->getMessage(), 'error');
+        }
+    }
+
     /** 月度记录表(商务技术分 / 价格分 / 最终得分,仅本页展示与导出) */
     public static function ensureFinalScoreTable(): void
     {
@@ -2644,6 +2692,7 @@ class ProcuremenSupplierScore
 
         $items = [];
         $priceSums = [];
+        $unitByCompanyKey = [];
         foreach ($quoteGroups as $g) {
             if (!is_array($g)) {
                 continue;
@@ -2661,6 +2710,7 @@ class ProcuremenSupplierScore
             if (!is_array($lineRows)) {
                 $lineRows = [];
             }
+            $unitByCompanyKey[$cn] = [];
             foreach ($lineRows as $ln) {
                 if (!is_array($ln)) {
                     continue;
@@ -2668,8 +2718,13 @@ class ProcuremenSupplierScore
                 if (empty($ln['amount_quote_pending'])) {
                     $am = self::resolveQuoteLineAmountRaw($ln);
                     if ($am !== '' && $am !== '0' && $am !== '0.00' && is_numeric($am)) {
-                        $priceSum += (float)$am;
+                        $unit = (float)$am;
+                        $priceSum += $unit;
                         $hasPrice = true;
+                        $lineKey = self::quoteLineAlignKey($ln);
+                        if ($lineKey !== '') {
+                            $unitByCompanyKey[$cn][$lineKey] = $unit;
+                        }
                     }
                 }
                 if (empty($ln['lead_days_quote_pending'])) {
@@ -2721,6 +2776,30 @@ class ProcuremenSupplierScore
             }
         }
 
+        $multiPrice = self::buildMultiOrderPriceWeights($quoteGroups);
+        $useMultiPrice = !empty($multiPrice['use_multi']) && $pw > 0;
+        $minByKey = [];
+        if ($useMultiPrice) {
+            foreach (array_keys($multiPrice['weights']) as $lineKey) {
+                $minP = null;
+                foreach ($unitByCompanyKey as $units) {
+                    if (!isset($units[$lineKey])) {
+                        continue;
+                    }
+                    $u = (float)$units[$lineKey];
+                    if ($u <= 0) {
+                        continue;
+                    }
+                    if ($minP === null || $u < $minP) {
+                        $minP = $u;
+                    }
+                }
+                if ($minP !== null) {
+                    $minByKey[$lineKey] = $minP;
+                }
+            }
+        }
+
         $minSum = null;
         foreach ($priceSums as $ps) {
             if ($minSum === null || $ps < $minSum) {
@@ -2739,8 +2818,22 @@ class ProcuremenSupplierScore
                 continue;
             }
 
-            // 价格得分 = (最低单价合计 / 本供应商单价合计) × 价格权重% × 100
-            if ($pw > 0 && !empty($it['has_price']) && $it['price_sum'] > 0 && $minSum !== null && $minSum > 0) {
+            if ($useMultiPrice) {
+                // 一批多订单:Σ[ 比例×(行最低单价/本行单价)×价格权重%×100 ]
+                $scoreSum = 0.0;
+                $units = $unitByCompanyKey[$cn] ?? [];
+                foreach ($multiPrice['weights'] as $lineKey => $wAmt) {
+                    $own = isset($units[$lineKey]) ? (float)$units[$lineKey] : 0.0;
+                    $minP = $minByKey[$lineKey] ?? null;
+                    if ($own <= 0 || $minP === null || $minP <= 0 || $multiPrice['total'] <= 0) {
+                        continue;
+                    }
+                    $prop = $wAmt / $multiPrice['total'];
+                    $scoreSum += $prop * ($minP / $own) * ($pw / 100) * 100;
+                }
+                $it['price_score'] = round($scoreSum, 2);
+            } elseif ($pw > 0 && !empty($it['has_price']) && $it['price_sum'] > 0 && $minSum !== null && $minSum > 0) {
+                // 单订单:价格得分 = (最低单价合计 / 本供应商单价合计) × 价格权重% × 100
                 $ratio = round($minSum / (float)$it['price_sum'], 4);
                 $it['price_score'] = round($ratio * ($pw / 100) * 100, 2);
             } else {
@@ -2799,6 +2892,132 @@ class ProcuremenSupplierScore
         return $s === '' ? '0' : $s;
     }
 
+    /**
+     * 报价行对齐键:优先工序行 id,其次 订单号|工序名
+     *
+     * @param array<string, mixed> $ln
+     */
+    protected static function quoteLineAlignKey(array $ln): string
+    {
+        $sid = (int)($ln['scydgy_id'] ?? $ln['scydgyId'] ?? 0);
+        if ($sid > 0) {
+            return 'sid:' . $sid;
+        }
+        $dh = trim((string)($ln['ccydh'] ?? $ln['CCYDH'] ?? ''));
+        $gy = trim((string)($ln['cgymc'] ?? $ln['CGYMC'] ?? ''));
+        if ($dh === '' && $gy === '') {
+            return '';
+        }
+
+        return 'cg:' . $dh . '|' . $gy;
+    }
+
+    /**
+     * 解析数量/限价等正数
+     *
+     * @param mixed $raw
+     */
+    protected static function parsePositiveNumber($raw): ?float
+    {
+        if ($raw === null || $raw === '') {
+            return null;
+        }
+        if (is_string($raw)) {
+            $raw = str_replace([',', ',', ' '], '', trim($raw));
+        }
+        if (!is_numeric($raw)) {
+            return null;
+        }
+        $n = (float)$raw;
+        if ($n <= 0) {
+            return null;
+        }
+
+        return $n;
+    }
+
+    /**
+     * 子项目权重金额 = 数量 × 最高限价
+     *
+     * @param array<string, mixed> $ln
+     */
+    protected static function resolveQuoteLineWeightAmount(array $ln): float
+    {
+        $qty = self::parsePositiveNumber(
+            $ln['This_quantity'] ?? $ln['this_quantity'] ?? $ln['qty'] ?? null
+        );
+        $ceil = self::parsePositiveNumber(
+            $ln['ceilingPrice'] ?? $ln['ceiling_price'] ?? $ln['ceiling'] ?? null
+        );
+        if ($qty === null || $ceil === null) {
+            return 0.0;
+        }
+
+        return $qty * $ceil;
+    }
+
+    /**
+     * 报价组是否一批多订单,以及各子项(数量×限价)权重
+     *
+     * @param array<int, array<string, mixed>> $quoteGroups
+     * @return array{use_multi:bool,weights:array<string,float>,total:float,ccydh_count:int}
+     */
+    public static function buildMultiOrderPriceWeights(array $quoteGroups): array
+    {
+        $ccydhSet = [];
+        $weights = [];
+        foreach ($quoteGroups as $g) {
+            if (!is_array($g)) {
+                continue;
+            }
+            $lineRows = $g['lines'] ?? $g['pick_lines'] ?? [];
+            if (!is_array($lineRows)) {
+                continue;
+            }
+            foreach ($lineRows as $ln) {
+                if (!is_array($ln)) {
+                    continue;
+                }
+                $dh = trim((string)($ln['ccydh'] ?? $ln['CCYDH'] ?? ''));
+                if ($dh !== '') {
+                    $ccydhSet[$dh] = true;
+                }
+                $key = self::quoteLineAlignKey($ln);
+                if ($key === '' || isset($weights[$key])) {
+                    continue;
+                }
+                $w = self::resolveQuoteLineWeightAmount($ln);
+                if ($w > 0) {
+                    $weights[$key] = $w;
+                }
+            }
+        }
+        $total = 0.0;
+        foreach ($weights as $w) {
+            $total += $w;
+        }
+        $ccydhCount = count($ccydhSet);
+
+        return [
+            'use_multi'    => ($ccydhCount > 1 && $total > 0 && $weights !== []),
+            'weights'      => $weights,
+            'total'        => $total,
+            'ccydh_count'  => $ccydhCount,
+        ];
+    }
+
+    /**
+     * 报价组是否含多个订单号(一批多单)
+     *
+     * @param array<int, array<string, mixed>> $quoteGroups
+     */
+    public static function quoteGroupsHaveMultipleOrders(array $quoteGroups): bool
+    {
+        $info = self::buildMultiOrderPriceWeights($quoteGroups);
+
+        return (int)($info['ccydh_count'] ?? 0) > 1;
+    }
+
     /**
      * 报价行单价原文(兼容确认页 amount、审批页 unit_price_text/amount_text)
      *
@@ -2888,7 +3107,8 @@ class ProcuremenSupplierScore
         // 说明顺序与表头一致:价格在前,交货在后
         if ($pw > 0) {
             $formula .= ';价格得分=(最低单价合计/本供应商单价合计)×'
-                . self::formatWeightPercent($pw) . '%×100';
+                . self::formatWeightPercent($pw) . '%×100'
+                . '(一批多订单时按子项比例加权:比例=数量×最高限价/Σ(数量×最高限价))';
         }
         if ($lw > 0) {
             $formula .= ';交货得分=月度交货分×50%+报价交期分×50%(按订单算,一批多订单平均;'
@@ -2941,7 +3161,7 @@ class ProcuremenSupplierScore
      *
      * @param array<int, array<string, mixed>> $quoteGroups
      */
-    public static function saveForOrder(string $ccydh, array $quoteGroups, ?string $ym = null): void
+    public static function saveForOrder(string $ccydh, array $quoteGroups, ?string $ym = null, string $orderBatchNo = ''): void
     {
         $ccydh = trim($ccydh);
         if ($ccydh === '') {
@@ -2953,6 +3173,7 @@ class ProcuremenSupplierScore
             $ym = date('Y-m');
         }
         $ym = self::normalizeYm($ym);
+        $orderBatchNo = trim($orderBatchNo);
         $calc = self::calculateForQuoteGroups($quoteGroups, $rule, $ym);
         if ($calc === []) {
             return;
@@ -2963,24 +3184,25 @@ class ProcuremenSupplierScore
             $rows = [];
             foreach ($calc as $it) {
                 $rows[] = [
-                    'customer_id'    => (int)($it['customer_id'] ?? 0),
-                    'company_name'   => (string)($it['company_name'] ?? ''),
-                    'ym'             => $ym,
-                    'ccydh'          => $ccydh,
-                    'score'          => (float)($it['score'] ?? 0),
-                    'rank_no'        => (int)($it['rank_no'] ?? 0),
-                    'quality_score'  => (int)round((float)($it['quality_score'] ?? 0)),
-                    'quality_weight' => (int)($rule['quality_weight'] ?? 50),
-                    'price_sum'      => round((float)($it['price_sum'] ?? 0), 4),
-                    'price_weight'   => (int)($rule['price_weight'] ?? 50),
-                    'price_score'    => (float)($it['price_score'] ?? 0),
-                    'lead_days_sum'  => (int)round((float)($it['lead_days_sum'] ?? 0)),
-                    'lead_weight'    => (int)($rule['lead_weight'] ?? 0),
-                    'lead_enabled'   => ((int)($rule['lead_weight'] ?? 0) > 0) ? 1 : 0,
-                    'lead_score'     => (float)($it['lead_score'] ?? 0),
-                    'rule_id'        => (int)($rule['id'] ?? 0),
-                    'createtime'     => $now,
-                    'updatetime'     => $now,
+                    'customer_id'      => (int)($it['customer_id'] ?? 0),
+                    'company_name'     => (string)($it['company_name'] ?? ''),
+                    'ym'               => $ym,
+                    'ccydh'            => $ccydh,
+                    'order_batch_no'   => $orderBatchNo,
+                    'score'            => (float)($it['score'] ?? 0),
+                    'rank_no'          => (int)($it['rank_no'] ?? 0),
+                    'quality_score'    => (int)round((float)($it['quality_score'] ?? 0)),
+                    'quality_weight'   => (int)($rule['quality_weight'] ?? 50),
+                    'price_sum'        => round((float)($it['price_sum'] ?? 0), 4),
+                    'price_weight'     => (int)($rule['price_weight'] ?? 50),
+                    'price_score'      => (float)($it['price_score'] ?? 0),
+                    'lead_days_sum'    => (int)round((float)($it['lead_days_sum'] ?? 0)),
+                    'lead_weight'      => (int)($rule['lead_weight'] ?? 0),
+                    'lead_enabled'     => ((int)($rule['lead_weight'] ?? 0) > 0) ? 1 : 0,
+                    'lead_score'       => (float)($it['lead_score'] ?? 0),
+                    'rule_id'          => (int)($rule['id'] ?? 0),
+                    'createtime'       => $now,
+                    'updatetime'       => $now,
                 ];
             }
             if ($rows !== []) {
@@ -3220,7 +3442,9 @@ class ProcuremenSupplierScore
         $ruleQw = (int)($rule['quality_weight'] ?? 0);
         $rulePw = (int)($rule['price_weight'] ?? 0);
         $ruleLw = (int)($rule['lead_weight'] ?? 0);
-        $saved = self::loadSavedByCcydh($ccydh);
+        // 一批多订单:价格分须按「数量×限价」比例跨单加权,不能直接用锚点订单的落库单分
+        $multiOrder = self::quoteGroupsHaveMultipleOrders($quoteGroups);
+        $saved = $multiOrder ? [] : self::loadSavedByCcydh($ccydh);
         $needCalc = ($saved === []);
         if (!$needCalc) {
             $anyHit = false;

+ 2 - 0
application/extra/supplier_score_install.sql

@@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS `supplier_service_score` (
   `company_name` varchar(128) NOT NULL DEFAULT '' COMMENT '供应商名称',
   `ym` char(7) NOT NULL DEFAULT '' COMMENT '对应年月 YYYY-MM',
   `ccydh` varchar(64) NOT NULL DEFAULT '' COMMENT '订单号',
+  `order_batch_no` varchar(32) NOT NULL DEFAULT '' COMMENT '下发批次号',
   `score` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '本单总分',
   `rank_no` int unsigned NOT NULL DEFAULT 0 COMMENT '本单排名',
   `quality_score` int NOT NULL DEFAULT 0 COMMENT '上年度质量评分',
@@ -39,6 +40,7 @@ CREATE TABLE IF NOT EXISTS `supplier_service_score` (
   UNIQUE KEY `uk_ccydh_company` (`ccydh`,`company_name`),
   KEY `idx_customer_ym` (`customer_id`,`ym`),
   KEY `idx_ccydh` (`ccydh`),
+  KEY `idx_order_batch_no` (`order_batch_no`),
   KEY `idx_ym` (`ym`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='供应商服务评分订单明细';
 

+ 18 - 10
public/assets/js/backend/procuremen.js

@@ -625,7 +625,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
             var issuedOnlyCols = ['purchase_order_id'];
             var pendingOnlyCols = ['po_amount_fill_cnt'];
             var pickedOnlyCols = ['picked_supplier_name'];
-            var auditOnlyCols = ['bid_open_status_text', 'notify_supplier_text', 'order_status_text'];
+            var auditOnlyCols = ['order_batch_no', 'bid_open_status_text', 'notify_supplier_text', 'order_status_text'];
             var allOnlyCols = ['ID'];
 
             Controller.currYm = ($layout.data('defaultYm') || '').toString();
@@ -1512,19 +1512,27 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
             });
             var indexTableColumns = [
                 {checkbox: true, field: 'state', visible: indexShowall, align: 'center', width: 42, class: 'procuremen-col-checkbox'},
-                {field: 'CCYDH', title: __('订单号'), operate: 'LIKE', table: 'b', width: 120, align: 'center', sortable: true,
+                {field: 'order_batch_no', title: '批次号', operate: 'LIKE', table: 'a', width: 140, align: 'center',
+                    visible: indexShowAuditSuppliers,
+                    formatter: function (v) {
+                        return v != null && v !== '' ? procuremenEscHtml(String(v)) : '';
+                    }
+                },
+                {field: 'CCYDH', title: __('订单号'), operate: 'LIKE', table: 'b', width: 120, align: 'left', sortable: true,
                     class: 'procuremen-th-sort-tight procuremen-supplier-lines-cell',
                     formatter: function (v) {
-                        var tab = Controller.wffTab || 'pick';
-                        // 确认/审批:多订单号直接换行,避免省略看不清
-                        if (tab === 'audit' || tab === 'confirm') {
-                            return procuremenMultiLinesWrapCell(v);
-                        }
+                        // 多订单号收起一行,悬停箭头展开(同报价供应商)
                         return procuremenSupplierLinesCell(v, this.width || 120);
                     }
                 },
-                {field: 'CYJMC', title: __('印件名称'), operate: 'LIKE', table: 'b', width: 200, align: 'left', class: 'procuremen-cell-wrap',
+                {field: 'CYJMC', title: __('印件名称'), operate: 'LIKE', table: 'b', width: 200, align: 'left',
+                    class: 'procuremen-supplier-lines-cell',
                     formatter: function (v) {
+                        var tab = Controller.wffTab || 'pick';
+                        // 确认/审批:多行印件名称收起为一行,悬停箭头展开(同报价供应商)
+                        if (tab === 'audit' || tab === 'confirm') {
+                            return procuremenSupplierLinesCell(v, this.width || 200);
+                        }
                         if (v == null || v === '') {
                             return '';
                         }
@@ -1561,7 +1569,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                         return s;
                     }
                 },
-                {field: 'This_quantity', title: '本次数量', operate: 'LIKE', table: 'a', width: 90, align: 'center',
+                {field: 'This_quantity', title: '本次数量', operate: 'LIKE', table: 'a', width: 90, align: 'left',
                     visible: true,
                     class: 'procuremen-supplier-lines-cell',
                     formatter: function (v, row, index) {
@@ -1576,7 +1584,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                         return procuremenSupplierLinesCell(v, this.width || 90);
                     }
                 },
-                {field: 'ceilingPrice', title: '最高限价', operate: 'LIKE', table: 'a', width: 90, align: 'center',
+                {field: 'ceilingPrice', title: '最高限价', operate: 'LIKE', table: 'a', width: 90, align: 'left',
                     visible: true,
                     class: 'procuremen-supplier-lines-cell',
                     formatter: function (value, row, index) {

+ 7 - 7
public/assets/js/backend/procuremenarchive.js

@@ -40,7 +40,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     field: 'order_batch_no',
                     title: '批次号',
                     operate: 'LIKE',
-                    width: 150,
+                    width: 125,
                     align: 'left',
                     halign: 'left',
                     formatter: function (value) {
@@ -48,12 +48,12 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                         return v !== '' ? archiveCellText(v) : '';
                     }
                 },
-                {field: 'CCYDH', title: '订单号', operate: 'LIKE', width: 130, align: 'left', halign: 'left'},
+                {field: 'CCYDH', title: '订单号', operate: 'LIKE', width: 110, align: 'left', halign: 'left'},
                 {
                     field: 'CYJMC',
                     title: '印件名称',
                     operate: 'LIKE',
-                    width: 200,
+                    width: 360,
                     align: 'left',
                     halign: 'left',
                     class: 'autocontent',
@@ -65,7 +65,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     field: 'CGYMC',
                     title: '工序名称',
                     operate: 'LIKE',
-                    width: 160,
+                    width: 120,
                     align: 'left',
                     halign: 'left',
                     class: 'autocontent',
@@ -77,7 +77,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     field: 'pick_company_name',
                     title: '中标供应商',
                     operate: 'LIKE',
-                    width: 220,
+                    width: 200,
                     align: 'left',
                     halign: 'left',
                     class: 'autocontent',
@@ -127,7 +127,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     operate: 'RANGE',
                     addclass: 'datetimerange',
                     autocomplete: false,
-                    width: 165,
+                    width: 145,
                     align: 'left',
                     halign: 'left',
                     sortable: true,
@@ -152,7 +152,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     title: '完结时间',
                     operate: false,
                     sortable: true,
-                    width: 165,
+                    width: 160,
                     align: 'left',
                     halign: 'left',
                     formatter: function (value, row) {

+ 2 - 1
public/assets/js/backend/procuremenexport.js

@@ -64,6 +64,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 columns: [
                     [
                         {field: 'ym', title: '月份', width: 88, operate: false},
+                        {field: 'order_batch_no', title: '批次号', width: 140, operate: 'LIKE'},
                         {field: 'CCYDH', title: '订单号', operate: 'LIKE'},
                         {field: 'CYJMC', title: '印件名称', class: 'autocontent', operate: 'LIKE', formatter: Table.api.formatter.content},
                         {field: 'CGYMC', title: '工序名称', class: 'autocontent', operate: 'LIKE', formatter: Table.api.formatter.content},
@@ -74,7 +75,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                             operate: 'LIKE',
                             formatter: Table.api.formatter.content
                         },
-                        {field: 'createtime_text', title: '完结时间', width: 165, operate: 'LIKE'},
+                        {field: 'createtime_text', title: '审批时间', width: 165, operate: 'LIKE'},
                         {
                             field: 'operate',
                             title: '操作',

+ 42 - 0
public/assets/js/backend/supplierservicescore.js

@@ -324,6 +324,21 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                             return v || '—';
                         }
                     },
+                    {
+                        field: 'win_order_count',
+                        title: '本月中标订单数',
+                        operate: false,
+                        sortable: false,
+                        align: 'center',
+                        halign: 'center',
+                        valign: 'middle',
+                        class: 'text-center',
+                        width: 130,
+                        formatter: function (value) {
+                            var n = parseInt(value, 10);
+                            return isNaN(n) ? 0 : n;
+                        }
+                    },
                     {
                         field: 'operate',
                         title: '操作',
@@ -441,6 +456,33 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     }
                     return false;
                 });
+            var markCyjmcOverflow = function () {
+                $('.ssc-month-orders-table .ssc-cyjmc-wrap').each(function () {
+                    var $wrap = $(this);
+                    var $text = $wrap.find('.ssc-cyjmc-text');
+                    if (!$text.length) {
+                        return;
+                    }
+                    var overflow = $text[0].scrollWidth > ($text[0].clientWidth + 1);
+                    $wrap.toggleClass('is-overflow', overflow);
+                    if (!overflow) {
+                        $wrap.removeClass('is-expanded');
+                        $wrap.find('.ssc-cyjmc-toggle i').removeClass('fa-angle-up').addClass('fa-angle-down');
+                    }
+                });
+            };
+            markCyjmcOverflow();
+            setTimeout(markCyjmcOverflow, 50);
+            $(window).off('resize.sscCyjmc').on('resize.sscCyjmc', markCyjmcOverflow);
+            $(document).off('click.sscCyjmcToggle', '.ssc-cyjmc-toggle')
+                .on('click.sscCyjmcToggle', '.ssc-cyjmc-toggle', function (e) {
+                    e.preventDefault();
+                    e.stopPropagation();
+                    var $wrap = $(this).closest('.ssc-cyjmc-wrap');
+                    var expanded = $wrap.toggleClass('is-expanded').hasClass('is-expanded');
+                    $(this).find('i').toggleClass('fa-angle-down', !expanded).toggleClass('fa-angle-up', expanded);
+                    return false;
+                });
             $(document).off('click.sscOrderDetails', '.btn-ssc-order-details').on('click.sscOrderDetails', '.btn-ssc-order-details', function (e) {
                 e.preventDefault();
                 e.stopPropagation();