m0_70156489 1 week ago
parent
commit
d75bfa7fbb
27 changed files with 4429 additions and 839 deletions
  1. 486 144
      application/admin/controller/Procuremen.php
  2. 26 23
      application/admin/model/Purchasesmstemplate.php
  3. 1 1
      application/admin/view/procuremen/add.html
  4. 1 1
      application/admin/view/procuremen/audit_append.html
  5. 58 11
      application/admin/view/procuremen/audit_issue.html
  6. 69 47
      application/admin/view/procuremen/details_fragment.html
  7. 82 6
      application/admin/view/procuremen/index.html
  8. 56 39
      application/admin/view/procuremen/outward_detail.html
  9. 1 1
      application/admin/view/procuremen/pick_add.html
  10. 9 1
      application/admin/view/procuremen/review.html
  11. 32 0
      application/admin/view/procuremen/toast_close.html
  12. 1 1
      application/admin/view/procuremenarchive/index.html
  13. 60 1
      application/common/library/ProcuremenOperLog.php
  14. 5 0
      application/common/library/ProcuremenSchema.php
  15. 52 1
      application/common/library/ProcuremenStatus.php
  16. 2 1
      application/common/library/ProcuremenTime.php
  17. 6 4
      application/extra/mproc.php
  18. 1273 181
      application/index/controller/Index.php
  19. 64 4
      application/index/view/index/deliverynote.html
  20. 1286 78
      application/index/view/index/deliveryscore.html
  21. 134 33
      application/index/view/index/inboundscore.html
  22. 297 74
      application/index/view/index/index.html
  23. 2 0
      application/index/view/index/login.html
  24. 112 36
      application/index/view/index/rfqadd.html
  25. 56 0
      application/index/view/index/toast_tip.html
  26. 256 149
      public/assets/js/backend/procuremen.js
  27. 2 2
      public/assets/js/backend/procuremenarchive.js

File diff suppressed because it is too large
+ 486 - 144
application/admin/controller/Procuremen.php


+ 26 - 23
application/admin/model/Purchasesmstemplate.php

@@ -6,27 +6,28 @@ use think\Model;
 
 class Purchasesmstemplate extends Model
 {
-    protected $table = 'purchase_sms_template';
+    // 表名
+    protected $name = 'purchase_sms_template';
 
-    /** 时间由控制器写入 datetime 字符串(库表为 datetime,勿用 int 时间戳) */
-    protected $autoWriteTimestamp = false;
-
-    protected $createTime = false;
-    protected $updateTime = false;
-    protected $deleteTime = false;
+    // 自动写入时间戳字段
+    protected $autoWriteTimestamp = 'datetime';
+    // 定义时间戳字段名
+    protected $createTime = 'createtime';
+    protected $updateTime = 'updatetime';
 
     public function getSceneList()
     {
         return [
-            'review_email'         => '协助下发-邮箱',
-            'review_sms'           => '协助下发-短信',
-            'confirm_ok'           => '采购确认-通过',
-            'confirm_fail'         => '采购确认-未通过',
-            'confirm_ok_email'     => '采购确认通过-邮箱',
-            'confirm_fail_email'   => '采购确认未通过-邮箱',
-            'bid_open'             => '开标双重验证',
-            'rfq_salesman_email'   => '询价通知业务员-邮箱',
-            'rfq_supplier_email'   => '供应商询价通知',
+            'review_email'          => '协助下发-邮箱',
+            'review_sms'            => '协助下发-短信',
+            'confirm_ok'            => '采购确认-通过',
+            'confirm_fail'          => '采购确认-未通过',
+            'confirm_ok_email'      => '采购确认通过-邮箱',
+            'confirm_fail_email'    => '采购确认未通过-邮箱',
+            'bid_open'              => '开标双重验证',
+            'rfq_salesman_email'    => '询价通知业务员-邮箱',
+            'rfq_supplier_email'    => '供应商询价通知',
+            'delivery_notify_email' => '交货情况通知生产部-邮箱',
         ];
     }
 
@@ -45,6 +46,7 @@ class Purchasesmstemplate extends Model
             'rfq_supplier_email',
             'confirm_ok_email',
             'confirm_fail_email',
+            'delivery_notify_email',
         ], true);
     }
 
@@ -80,21 +82,22 @@ class Purchasesmstemplate extends Model
             ['tag' => '{email}', 'label' => '邮箱', 'example' => 'user@example.com', 'scenes' => '全部'],
             ['tag' => '{ccydh}', 'label' => '订单号/需求编号', 'example' => 'YW20260730001', 'scenes' => '全部'],
             ['tag' => '{cyjmc}', 'label' => '印件名称', 'example' => '藏书票2', 'scenes' => '全部'],
-            ['tag' => '{cgymc}', 'label' => '工序名称(单道工序)', 'example' => '骑马订', 'scenes' => '协助下发/询价通知'],
-            ['tag' => '{this_quantity}', 'label' => '本次数量', 'example' => '200', 'scenes' => '询价通知'],
+            ['tag' => '{cgymc}', 'label' => '工序名称(单道工序)', 'example' => '骑马订', 'scenes' => '协助下发/询价通知/交货通知'],
+            ['tag' => '{this_quantity}', 'label' => '本次数量/订单数量', 'example' => '200', 'scenes' => '询价通知/交货通知'],
             ['tag' => '{ceilingPrice}', 'label' => '最高限价', 'example' => '0.7', 'scenes' => '询价通知业务员'],
             ['tag' => '{cdw}', 'label' => '单位', 'example' => '本', 'scenes' => '询价通知业务员'],
-            ['tag' => '{MBZ}', 'label' => '备注', 'example' => '封面颜色深', 'scenes' => '询价通知业务员'],
-            ['tag' => '{supplier_name}', 'label' => '报价供应商', 'example' => '台州某某有限公司', 'scenes' => '询价通知业务员'],
+            ['tag' => '{MBZ}', 'label' => '招标备注', 'example' => '封面颜色深', 'scenes' => '询价通知业务员'],
+            ['tag' => '{supplier_name}', 'label' => '报价/中标供应商', 'example' => '台州某某有限公司', 'scenes' => '询价通知业务员/交货通知'],
             ['tag' => '{supplier_quotes}', 'label' => '供应商报价表格(名称+单价)', 'example' => '自动生成表格', 'scenes' => '询价通知业务员'],
             ['tag' => '{cywyxm}', 'label' => '需求发起人', 'example' => '管理员', 'scenes' => '询价通知业务员'],
+            ['tag' => '{delivery_deadline}', 'label' => '交货截止日期', 'example' => '2026-08-26', 'scenes' => '交货情况通知生产部'],
             ['tag' => '{category}', 'label' => '业务分类', 'example' => '出版物印刷', 'scenes' => '协助下发'],
             ['tag' => '{deadline}', 'label' => '截止时间', 'example' => '2026-05-18 14:30', 'scenes' => '协助下发/供应商询价'],
-            ['tag' => '{process_lines}', 'label' => '订单工序明细(文本)', 'example' => "订单号:YW20240629001\n印件名称:藏书票2\n1.工序名称:做刀版 单位:张 本次数量:500", 'scenes' => '全部'],
-            ['tag' => '{process_lines_html}', 'label' => '订单工序明细(表格)', 'example' => '<table>…</table>', 'scenes' => '协助下发/供应商询价邮箱'],
+            ['tag' => '{process_lines}', 'label' => '订单工序明细(文本)', 'example' => "订单号:202605732S\n印件名称:越剧唱腔\n1.工序名称:数字胶订 单位:册 工作量:32\n\n订单号:202605713S\n印件名称:……\n1.工序名称:数字覆膜 单位:张 工作量:545", 'scenes' => '全部'],
+            ['tag' => '{process_lines_html}', 'label' => '订单工序明细(表格,多订单按单分组)', 'example' => '<table>…</table>', 'scenes' => '协助下发/供应商询价邮箱'],
             ['tag' => '{order_type}', 'label' => '订单类型', 'example' => '普通订单(价格优先)', 'scenes' => '协助下发邮箱'],
             ['tag' => '{score_weights}', 'label' => '评分比例', 'example' => '质量30%、价格50%、交货20%', 'scenes' => '协助下发邮箱'],
-            ['tag' => '{platform_url}', 'label' => '平台链接', 'example' => 'https://…', 'scenes' => '协助下发/供应商询价/业务员询价/采购确认邮箱'],
+            ['tag' => '{platform_url}', 'label' => '平台链接', 'example' => 'https://…', 'scenes' => '协助下发/供应商询价/业务员询价/采购确认/交货通知邮箱'],
         ];
     }
 }

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

@@ -174,7 +174,7 @@
 <!--            </div>-->
 <!--        </div>-->
         <div class="form-group">
-            <label class="control-label col-xs-12 col-sm-2">备注:</label>
+            <label class="control-label col-xs-12 col-sm-2">招标备注:</label>
             <div class="col-xs-12 col-sm-8">
                 <textarea class="form-control" name="row[MBZ]" rows="4" autocomplete="off"></textarea>
             </div>

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

@@ -440,7 +440,7 @@
                             <th class="text-center" style="width:72px;">本次数量</th>
                             <th class="text-center" style="width:72px;">最高限价</th>
                             <th class="text-center" style="width:80px;">订法</th>
-                            <th style="min-width:120px;">备注</th>
+                            <th style="min-width:120px;">招标备注</th>
                         </tr>
                         </thead>
                         <tbody>

+ 58 - 11
application/admin/view/procuremen/audit_issue.html

@@ -406,6 +406,47 @@
         white-space: nowrap;
         min-width: 130px;
     }
+    .audit-issue-wrap .audit-supplier-info-cell {
+        min-width: 220px;
+        vertical-align: middle !important;
+    }
+    .audit-issue-wrap .audit-supplier-kv {
+        display: flex;
+        flex-direction: column;
+        gap: 4px;
+        font-size: 12px;
+        line-height: 1.45;
+    }
+    .audit-issue-wrap .audit-supplier-kv-row {
+        display: flex;
+        align-items: flex-start;
+        gap: 8px;
+    }
+    .audit-issue-wrap .audit-supplier-kv-label {
+        flex: 0 0 52px;
+        color: #666;
+        white-space: nowrap;
+    }
+    .audit-issue-wrap .audit-supplier-kv-val {
+        flex: 1 1 auto;
+        min-width: 0;
+        word-break: break-all;
+        color: #333;
+    }
+    .audit-issue-wrap .proc-process-name-cell {
+        line-height: 1.35;
+        white-space: normal;
+        word-break: break-all;
+        vertical-align: middle;
+    }
+    .audit-issue-wrap .proc-process-name-cell .proc-line-ccydh {
+        color: #333;
+        font-weight: 600;
+    }
+    .audit-issue-wrap .proc-process-name-cell .proc-line-cgymc {
+        color: #555;
+        margin-top: 2px;
+    }
 </style>
 <div class="audit-issue-wrap">
     <div class="audit-table-wrap">
@@ -429,7 +470,7 @@
                 <th class="text-center">本次数量</th>
                 <th class="text-center">最高限价</th>
                 <th class="text-center">订法</th>
-                <th class="audit-col-remark">备注</th>
+                <th class="audit-col-remark">招标备注</th>
             </tr>
             </thead>
             <tbody>
@@ -544,10 +585,7 @@
             <thead>
             <tr>
                 <th class="text-center" style="width:42px;">选定</th>
-                <th style="min-width:140px;">供应商名称</th>
-                <th style="width:88px;">姓名</th>
-                <th style="width:100px;">邮箱</th>
-                <th style="width:120px;">手机号</th>
+                <th style="min-width:220px;">供应商信息</th>
                 <th class="text-center col-rank" style="width:64px;">排名</th>
                 <th class="text-center" style="width:88px;">质量得分</th>
                 <th class="text-center" style="width:80px;" title="价格得分=(最低单价合计/本供应商单价合计)×价格权重%×100">价格得分</th>
@@ -576,10 +614,14 @@
                             {if !empty($manualPicked)} disabled="disabled"{/if}/>
                     </label>
                 </td>
-                <td{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;">{$co.name|default=''|htmlentities}</td>
-                <td{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;">{$co.username|default=''|htmlentities}</td>
-                <td{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;">{:htmlentities(mask_email(isset($co['email']) ? $co['email'] : ''))}</td>
-                <td{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;">{:htmlentities(mask_phone(isset($co['phone']) ? $co['phone'] : ''))}</td>
+                <td class="audit-supplier-info-cell"{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if}>
+                    <div class="audit-supplier-kv">
+                        <div class="audit-supplier-kv-row"><span class="audit-supplier-kv-label">供应商</span><span class="audit-supplier-kv-val">{$co.name|default=''|htmlentities}</span></div>
+                        <div class="audit-supplier-kv-row"><span class="audit-supplier-kv-label">姓名</span><span class="audit-supplier-kv-val">{$co.username|default=''|htmlentities}</span></div>
+                        <div class="audit-supplier-kv-row"><span class="audit-supplier-kv-label">邮箱</span><span class="audit-supplier-kv-val">{:htmlentities(mask_email(isset($co['email']) ? $co['email'] : ''))}</span></div>
+                        <div class="audit-supplier-kv-row"><span class="audit-supplier-kv-label">手机号</span><span class="audit-supplier-kv-val">{:htmlentities(mask_phone(isset($co['phone']) ? $co['phone'] : ''))}</span></div>
+                    </div>
+                </td>
                 <td class="text-center col-rank"{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;font-size:17px;font-weight:700;">{if condition="!empty($quoteVisible)"}{$co.service_rank_text|default=''|htmlentities}{/if}</td>
                 <td class="text-center"{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;">{if condition="!empty($quoteVisible)"}{$co.service_quality_score_text|default=''|htmlentities}{/if}</td>
                 <td class="text-center"{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;"{if condition="!empty($quoteVisible)"} title="单价合计 {$co.service_price_sum_text|default=''|htmlentities}"{/if}>{if condition="!empty($quoteVisible)"}{$co.service_price_score_text|default=''|htmlentities}{/if}</td>
@@ -588,7 +630,12 @@
                 {/if}
                 <td class="text-center"{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;font-weight:600;">{if condition="!empty($quoteVisible)"}{$co.service_score_text|default=''|htmlentities}{/if}</td>
                 {/if}
-                <td>{$ln.cgymc|default=''|htmlentities}</td>
+                <td class="proc-process-name-cell">
+                    {notempty name="ln.ccydh"}
+                    <div class="proc-line-ccydh">{$ln.ccydh|htmlentities}</div>
+                    {/notempty}
+                    <div class="proc-line-cgymc">{$ln.cgymc|default=''|htmlentities}</div>
+                </td>
                 <td class="text-center{if condition="!empty($ln.amount_quote_pending)"} audit-quote-pending{elseif condition="$ln.amount_filled neq 1"} audit-quote-empty{/if}">{$ln.unit_price_text|default='未填写'|htmlentities}</td>
                 <td class="text-center{if condition="!empty($ln.lead_days_quote_pending)"} audit-quote-pending{elseif condition="$ln.lead_days_filled neq 1"} audit-quote-empty{/if}">{$ln.lead_days_show|default='未填写'|htmlentities}</td>
                 <td class="text-center{if condition="!empty($ln.delivery_quote_pending)"} audit-quote-pending{elseif condition="$ln.delivery_filled neq 1"} audit-quote-empty{/if}">{$ln.delivery_show|default='未填写'|htmlentities}</td>
@@ -608,7 +655,7 @@
             {/volist}
             {if !empty($co.has_remark)}
             <tr{if !empty($co.is_void)} class="text-muted"{/if}>
-                <td><strong>备注</strong></td>
+                <td><strong>投标备注</strong></td>
                 <td colspan="5" class="{if !empty($co.remark_quote_pending)}audit-quote-pending{/if}" style="text-align:left;vertical-align:middle;">{$co.remark|default=''|htmlentities}</td>
             </tr>
             {/if}

+ 69 - 47
application/admin/view/procuremen/details_fragment.html

@@ -270,46 +270,43 @@
     .procuremen-details-wrap .detail-supplier-table {
         /* 固定表宽,避免 width:100% + table-layout:fixed 把名称列挤成竖排字 */
         table-layout: fixed;
-        width: 1620px;
-        min-width: 1620px;
+        width: 1480px;
+        min-width: 1480px;
         max-width: none;
         border-collapse: collapse;
     }
     .procuremen-details-wrap .detail-supplier-table.has-lead-score {
-        width: 1620px;
-        min-width: 1620px;
-    }
-    .procuremen-details-wrap .detail-supplier-table th.col-supplier-name,
-    .procuremen-details-wrap .detail-supplier-table td.col-supplier-name {
-        width: 180px;
-        min-width: 180px;
-        word-break: normal;
-        overflow-wrap: break-word;
-        white-space: normal;
-        line-height: 1.4;
+        width: 1560px;
+        min-width: 1560px;
     }
-    .procuremen-details-wrap .detail-supplier-table th.col-supplier-email,
-    .procuremen-details-wrap .detail-supplier-table td.col-supplier-email {
-        width: 86px;
-        min-width: 86px;
-        max-width: 86px;
-        word-break: break-all;
-        white-space: normal;
-        line-height: 1.35;
+    .procuremen-details-wrap .detail-supplier-table th.col-supplier-info,
+    .procuremen-details-wrap .detail-supplier-table td.col-supplier-info {
+        width: 220px;
+        min-width: 220px;
+        vertical-align: middle !important;
+    }
+    .procuremen-details-wrap .detail-supplier-kv {
+        display: flex;
+        flex-direction: column;
+        gap: 4px;
         font-size: 12px;
+        line-height: 1.45;
     }
-    .procuremen-details-wrap .detail-supplier-table th.col-supplier-user,
-    .procuremen-details-wrap .detail-supplier-table td.col-supplier-user {
-        width: 72px;
+    .procuremen-details-wrap .detail-supplier-kv-row {
+        display: flex;
+        align-items: flex-start;
+        gap: 8px;
     }
-    .procuremen-details-wrap .detail-supplier-table th.col-supplier-phone,
-    .procuremen-details-wrap .detail-supplier-table td.col-supplier-phone {
-        width: 98px;
-        min-width: 98px;
-        max-width: 98px;
-        word-break: break-all;
+    .procuremen-details-wrap .detail-supplier-kv-label {
+        flex: 0 0 52px;
+        color: #666;
         white-space: nowrap;
-        font-size: 12px;
+    }
+    .procuremen-details-wrap .detail-supplier-kv-val {
+        flex: 1 1 auto;
+        min-width: 0;
+        word-break: break-all;
+        color: #333;
     }
     .procuremen-details-wrap .detail-supplier-table th.col-rank,
     .procuremen-details-wrap .detail-supplier-table td.col-rank {
@@ -364,6 +361,20 @@
         color: #e67e22 !important;
         white-space: nowrap;
     }
+    .procuremen-details-wrap .proc-process-name-cell {
+        line-height: 1.35;
+        white-space: normal;
+        word-break: break-all;
+        vertical-align: middle;
+    }
+    .procuremen-details-wrap .proc-process-name-cell .proc-line-ccydh {
+        color: #333;
+        font-weight: 600;
+    }
+    .procuremen-details-wrap .proc-process-name-cell .proc-line-cgymc {
+        color: #555;
+        margin-top: 2px;
+    }
     .procuremen-details-wrap .detail-supplier-remark-row td {
         background: #f5f5f5;
         vertical-align: middle;
@@ -501,7 +512,7 @@
                 <th class="text-center" style="width:88px;">本次数量</th>
                 <th class="text-center" style="width:72px;">最高限价</th>
                 <th class="text-center" style="width:80px;">订法</th>
-                <th style="min-width:120px;">备注</th>
+                <th style="min-width:120px;">招标备注</th>
             </tr>
             </thead>
             <tbody>
@@ -546,10 +557,7 @@
         <table class="table table-bordered table-condensed detail-mini detail-supplier-table{if !empty($showServiceLeadScore)} has-lead-score{/if}">
             <thead>
             <tr>
-                <th class="col-supplier-name">供应商名称</th>
-                <th class="col-supplier-user">姓名</th>
-                <th class="col-supplier-email">邮箱</th>
-                <th class="col-supplier-phone">手机号</th>
+                <th class="col-supplier-info">供应商信息</th>
                 <th class="text-center col-rank" style="width:64px;">排名</th>
                 <th class="text-center" style="width:88px;">质量得分</th>
                 <th class="text-center" style="width:80px;" title="价格得分=(最低单价合计/本供应商单价合计)×价格权重%×100">价格得分</th>
@@ -572,12 +580,14 @@
             {volist name="sg.lines" id="ln" key="lk"}
             <tr{if !empty($sg.is_void)} class="text-muted"{/if}>
                 {if $lk == 1}
-                <td class="col-supplier-name"{if condition="$sg.display_rowspan gt 1"} rowspan="{$sg.display_rowspan}"{/if} style="vertical-align:middle;">
-                    {$sg.company_name|default=''|htmlentities}
+                <td class="col-supplier-info"{if condition="$sg.display_rowspan gt 1"} rowspan="{$sg.display_rowspan}"{/if}>
+                    <div class="detail-supplier-kv">
+                        <div class="detail-supplier-kv-row"><span class="detail-supplier-kv-label">供应商</span><span class="detail-supplier-kv-val">{$sg.company_name|default=''|htmlentities}</span></div>
+                        <div class="detail-supplier-kv-row"><span class="detail-supplier-kv-label">姓名</span><span class="detail-supplier-kv-val">{$sg.username|default=''|htmlentities}</span></div>
+                        <div class="detail-supplier-kv-row"><span class="detail-supplier-kv-label">邮箱</span><span class="detail-supplier-kv-val">{:htmlentities(mask_email(isset($sg['email']) ? $sg['email'] : ''))}</span></div>
+                        <div class="detail-supplier-kv-row"><span class="detail-supplier-kv-label">手机号</span><span class="detail-supplier-kv-val">{:htmlentities(mask_phone(isset($sg['phone']) ? $sg['phone'] : ''))}</span></div>
+                    </div>
                 </td>
-                <td class="col-supplier-user"{if condition="$sg.display_rowspan gt 1"} rowspan="{$sg.display_rowspan}"{/if} style="vertical-align:middle;">{$sg.username|default=''|htmlentities}</td>
-                <td class="col-supplier-email"{if condition="$sg.display_rowspan gt 1"} rowspan="{$sg.display_rowspan}"{/if} style="vertical-align:middle;">{:htmlentities(mask_email(isset($sg['email']) ? $sg['email'] : ''))}</td>
-                <td class="col-supplier-phone"{if condition="$sg.display_rowspan gt 1"} rowspan="{$sg.display_rowspan}"{/if} style="vertical-align:middle;">{:htmlentities(mask_phone(isset($sg['phone']) ? $sg['phone'] : ''))}</td>
                 <td class="text-center col-rank"{if condition="$sg.display_rowspan gt 1"} rowspan="{$sg.display_rowspan}"{/if}>{$sg.service_rank_text|default=''|htmlentities}</td>
                 <td class="text-center"{if condition="$sg.display_rowspan gt 1"} rowspan="{$sg.display_rowspan}"{/if} style="vertical-align:middle;">{$sg.service_quality_score_text|default=''|htmlentities}</td>
                 <td class="text-center"{if condition="$sg.display_rowspan gt 1"} rowspan="{$sg.display_rowspan}"{/if} style="vertical-align:middle;" title="单价合计 {$sg.service_price_sum_text|default=''|htmlentities}">{$sg.service_price_score_text|default=''|htmlentities}</td>
@@ -586,7 +596,12 @@
                 {/if}
                 <td class="text-center"{if condition="$sg.display_rowspan gt 1"} rowspan="{$sg.display_rowspan}"{/if} style="vertical-align:middle;font-weight:600;">{$sg.service_score_text|default=''|htmlentities}</td>
                 {/if}
-                <td>{$ln.cgymc|default=''|htmlentities}</td>
+                <td class="proc-process-name-cell">
+                    {notempty name="ln.ccydh"}
+                    <div class="proc-line-ccydh">{$ln.ccydh|htmlentities}</div>
+                    {/notempty}
+                    <div class="proc-line-cgymc">{$ln.cgymc|default=''|htmlentities}</div>
+                </td>
                 <td class="text-center col-unit-price{if condition="!empty($ln.amount_quote_pending)"} detail-quote-pending{elseif condition="empty($ln.amount_filled) || $ln.amount_filled neq 1"} detail-quote-empty{/if}">{$ln.unit_price_text|default='未填写'|htmlentities}</td>
                 <td class="text-center col-lead-days{if condition="!empty($ln.lead_days_quote_pending)"} detail-quote-pending{elseif condition="isset($ln.lead_days_filled) && $ln.lead_days_filled neq 1"} detail-quote-empty{/if}">{$ln.lead_days_show|default='未填写'|htmlentities}</td>
                 <td class="text-center col-delivery{if condition="!empty($ln.delivery_quote_pending)"} detail-quote-pending{elseif condition="isset($ln.delivery_filled) && $ln.delivery_filled neq 1"} detail-quote-empty{/if}">{$ln.delivery_show|default=''|htmlentities}</td>
@@ -607,7 +622,7 @@
             {/volist}
             {if !empty($sg.has_remark)}
             <tr class="detail-supplier-remark-row{if !empty($sg.is_void)} text-muted{/if}">
-                <td class="detail-remark-label"><strong>备注</strong></td>
+                <td class="detail-remark-label"><strong>投标备注</strong></td>
                 <td class="detail-remark-text{if !empty($sg.remark_quote_pending)} detail-quote-pending{/if}" colspan="6">{$sg.remark|default=''|htmlentities}</td>
             </tr>
             {/if}
@@ -627,13 +642,20 @@
             {notempty name="detailRows"}
             {volist name="detailRows" id="dr"}
             <tr>
-                <td class="col-supplier-name">{$dr.company_name|default=''|htmlentities}</td>
-                <td class="col-supplier-user">{$dr.username|default=''|htmlentities}</td>
-                <td class="col-supplier-email">{:htmlentities(mask_email(isset($dr['email']) ? $dr['email'] : ''))}</td>
-                <td class="col-supplier-phone">{:htmlentities(mask_phone(isset($dr['phone']) ? $dr['phone'] : ''))}</td>
+                <td class="col-supplier-info">
+                    <div class="detail-supplier-kv">
+                        <div class="detail-supplier-kv-row"><span class="detail-supplier-kv-label">供应商</span><span class="detail-supplier-kv-val">{$dr.company_name|default=''|htmlentities}</span></div>
+                        <div class="detail-supplier-kv-row"><span class="detail-supplier-kv-label">姓名</span><span class="detail-supplier-kv-val">{$dr.username|default=''|htmlentities}</span></div>
+                        <div class="detail-supplier-kv-row"><span class="detail-supplier-kv-label">邮箱</span><span class="detail-supplier-kv-val">{:htmlentities(mask_email(isset($dr['email']) ? $dr['email'] : ''))}</span></div>
+                        <div class="detail-supplier-kv-row"><span class="detail-supplier-kv-label">手机号</span><span class="detail-supplier-kv-val">{:htmlentities(mask_phone(isset($dr['phone']) ? $dr['phone'] : ''))}</span></div>
+                    </div>
+                </td>
+                <td class="text-center"></td>
                 <td class="text-center"></td>
                 <td class="text-center"></td>
+                {if !empty($showServiceLeadScore)}
                 <td class="text-center"></td>
+                {/if}
                 <td class="text-center"></td>
                 <td></td>
                 <td class="text-center col-unit-price">

+ 82 - 6
application/admin/view/procuremen/index.html

@@ -647,13 +647,21 @@
     }
     /* 固定右列:外层定宽即可,内部必须是整表 + scrollLeft 到最右,禁止压成单列宽的假表 */
     #procuremen-layout .bootstrap-table .fixed-columns-right {
-        min-width: 156px;
+        min-width: 188px;
         overflow: hidden !important;
         background: #fff;
     }
     #procuremen-layout .bootstrap-table .fixed-columns-right .fixed-table-header,
     #procuremen-layout .bootstrap-table .fixed-columns-right .fixed-table-body {
         overflow-x: hidden !important;
+        overflow-y: hidden !important; /* 与主表同步滚动,勿再出第二条竖滚动条 */
+        scrollbar-width: none;
+        -ms-overflow-style: none;
+    }
+    #procuremen-layout .bootstrap-table .fixed-columns-right .fixed-table-body::-webkit-scrollbar {
+        width: 0 !important;
+        height: 0 !important;
+        display: none !important;
     }
     #procuremen-layout .bootstrap-table .fixed-columns-right table {
         /* 勿强制单列宽,否则只能看到左侧复选框/订单号 */
@@ -663,11 +671,79 @@
     }
     #procuremen-layout .bootstrap-table thead th[data-field="operate"],
     #procuremen-layout .bootstrap-table tbody td[data-field="operate"] {
-        width: 168px !important;
-        min-width: 156px !important;
-        max-width: 176px !important;
+        width: 200px !important;
+        min-width: 188px !important;
+        max-width: 220px !important;
         padding-left: 6px !important;
         padding-right: 6px !important;
+        vertical-align: middle !important;
+        text-align: center !important;
+    }
+    /* 确认页(audit):操作列略窄,减少右侧空白 */
+    #procuremen-layout[data-procuremen-stage="audit"] .bootstrap-table .fixed-columns-right {
+        min-width: 168px;
+    }
+    #procuremen-layout[data-procuremen-stage="audit"] .bootstrap-table thead th[data-field="operate"],
+    #procuremen-layout[data-procuremen-stage="audit"] .bootstrap-table tbody td[data-field="operate"],
+    #procuremen-layout[data-procuremen-stage="audit"] .bootstrap-table .fixed-columns-right td[data-field="operate"],
+    #procuremen-layout[data-procuremen-stage="audit"] .bootstrap-table .fixed-columns-right th[data-field="operate"] {
+        width: 176px !important;
+        min-width: 168px !important;
+        max-width: 188px !important;
+        padding-left: 4px !important;
+        padding-right: 4px !important;
+    }
+    #procuremen-layout[data-procuremen-stage="audit"] .bootstrap-table .procuremen-op-slot-primary {
+        min-width: 82px;
+    }
+    #procuremen-layout[data-procuremen-stage="audit"] .bootstrap-table .procuremen-op-slot-detail {
+        min-width: 48px;
+    }
+    #procuremen-layout[data-procuremen-stage="audit"] .bootstrap-table .procuremen-op-slot-empty {
+        width: 82px;
+    }
+    #procuremen-layout .bootstrap-table thead th[data-field="operate"] .th-inner {
+        text-align: center !important;
+    }
+    /* 双槽:左侧固定宽(选择供应商/审批),右侧详情;无主按钮时左侧占位,详情竖线对齐 */
+    #procuremen-layout .bootstrap-table .procuremen-op-btns {
+        display: inline-flex;
+        flex-direction: row;
+        flex-wrap: nowrap;
+        align-items: center;
+        justify-content: center;
+        gap: 4px;
+        width: auto;
+        max-width: 100%;
+        white-space: nowrap;
+        vertical-align: middle;
+    }
+    #procuremen-layout .bootstrap-table .procuremen-op-slot {
+        display: inline-flex;
+        align-items: center;
+        justify-content: center;
+        flex: 0 0 auto;
+    }
+    #procuremen-layout .bootstrap-table .procuremen-op-slot-primary {
+        min-width: 96px;
+        justify-content: flex-end;
+    }
+    #procuremen-layout .bootstrap-table .procuremen-op-slot-detail {
+        min-width: 52px;
+        justify-content: flex-start;
+    }
+    #procuremen-layout .bootstrap-table .procuremen-op-slot-empty {
+        display: inline-block;
+        width: 96px;
+        height: 1px;
+        visibility: hidden;
+        pointer-events: none;
+    }
+    #procuremen-layout .bootstrap-table .procuremen-op-btns .btn {
+        margin: 0 !important;
+        float: none !important;
+        flex: 0 0 auto;
+        white-space: nowrap;
     }
     /* 日期列加宽并禁止省略,避免滚到最右仍被竖向滚动条挡住 */
     #procuremen-layout .bootstrap-table thead th[data-field="dStamp"],
@@ -978,10 +1054,10 @@
                                 <div id="toolbar" class="toolbar">
                                     <a href="javascript:;" class="btn btn-primary btn-refresh" data-force-refresh="false" title="{:__('Refresh')}" >刷新 <i class="fa fa-refresh"></i> </a>
                                     {if isset($procuremenBtnAuditAbandon) && $procuremenBtnAuditAbandon}
-                                    <a href="javascript:;" class="btn btn-danger procuremen-stage-hide hide" id="btn-procuremen-audit-abandon" title="勾选一条或多条订单退回协助初选重新下发(历史记录保留)"><i class="fa fa-repeat"></i> 重新下发</a>
+                                    <a href="javascript:;" class="btn btn-danger procuremen-stage-hide hide" id="btn-procuremen-audit-abandon" title="勾选一条或多条订单退回供应商初选重新下发(历史记录保留)"><i class="fa fa-repeat"></i> 重新下发</a>
                                     {/if}
                                     {if isset($procuremenBtnDispatch) && $procuremenBtnDispatch}
-                                    <a href="javascript:;" class="btn btn-info procuremen-stage-hide hide" id="btn-procuremen-pick-review" title="勾选一条或多条工序进行下发(多条须同一订单号)"><i class="fa fa-paper-plane"></i> 下发</a>
+                                    <a href="javascript:;" class="btn btn-info procuremen-stage-hide hide" id="btn-procuremen-pick-review" title="勾选一条或多条工序进行下发(可跨订单,同批生成批次号)"><i class="fa fa-paper-plane"></i> 下发</a>
                                     {/if}
                                     {if isset($procuremenBtnComplete) && $procuremenBtnComplete}
                                     <a href="javascript:;" class="btn btn-success procuremen-stage-hide hide" id="btn-procuremen-batch-finish" title="勾选一条或多条工序标记为已完结"><i class="fa fa-flag-checkered"></i> 完结</a>

+ 56 - 39
application/admin/view/procuremen/outward_detail.html

@@ -59,10 +59,23 @@
         max-width: none;
     }
     .outward-confirm-process-table th:nth-child(3),
-    .outward-confirm-process-table td.outward-process-name,
-    .outward-confirm-company-table td.outward-process-name {
+    .outward-confirm-process-table td.outward-process-name {
         white-space: nowrap;
     }
+    .outward-confirm-company-table td.outward-process-name.proc-process-name-cell {
+        white-space: normal;
+        word-break: break-all;
+        line-height: 1.35;
+        vertical-align: middle;
+    }
+    .outward-confirm-company-table .proc-process-name-cell .proc-line-ccydh {
+        color: #333;
+        font-weight: 600;
+    }
+    .outward-confirm-company-table .proc-process-name-cell .proc-line-cgymc {
+        color: #555;
+        margin-top: 2px;
+    }
     .outward-confirm-process-table th.outward-col-name,
     .outward-confirm-process-table td.outward-col-name {
         width: 26%;
@@ -89,37 +102,35 @@
         line-height: 1.45;
         padding: 6px 8px;
     }
-    .outward-confirm-company-table th.col-supplier-name,
-    .outward-confirm-company-table td.col-supplier-name {
-        width: 150px;
-        min-width: 150px;
-        max-width: 150px;
-        word-break: normal;
-        overflow-wrap: break-word;
-        white-space: normal;
-        line-height: 1.4;
+    .outward-confirm-company-table th.col-supplier-info,
+    .outward-confirm-company-table td.col-supplier-info {
+        width: 220px;
+        min-width: 220px;
+        vertical-align: middle !important;
     }
-    .outward-confirm-company-table th.col-supplier-email,
-    .outward-confirm-company-table td.col-supplier-email {
-        width: 120px;
-        min-width: 120px;
-        max-width: 120px;
-        word-break: break-all;
-        white-space: normal;
-        line-height: 1.35;
+    .outward-confirm-company-table .outward-supplier-kv {
+        display: flex;
+        flex-direction: column;
+        gap: 4px;
+        font-size: 12px;
+        line-height: 1.45;
     }
-    .outward-confirm-company-table th.col-supplier-user,
-    .outward-confirm-company-table td.col-supplier-user {
-        width: 72px;
-        min-width: 72px;
-        white-space: nowrap;
+    .outward-confirm-company-table .outward-supplier-kv-row {
+        display: flex;
+        align-items: flex-start;
+        gap: 8px;
     }
-    .outward-confirm-company-table th.col-supplier-phone,
-    .outward-confirm-company-table td.col-supplier-phone {
-        width: 110px;
-        min-width: 110px;
+    .outward-confirm-company-table .outward-supplier-kv-label {
+        flex: 0 0 52px;
+        color: #666;
         white-space: nowrap;
     }
+    .outward-confirm-company-table .outward-supplier-kv-val {
+        flex: 1 1 auto;
+        min-width: 0;
+        word-break: break-all;
+        color: #333;
+    }
     .outward-confirm-process-table th,
     .outward-confirm-company-table th {
         background: #f5f5f5;
@@ -413,7 +424,7 @@
                 <th class="text-center">本次数量</th>
                 <th class="text-center">最高限价</th>
                 <th class="text-center">订法</th>
-                <th class="outward-col-remark">备注</th>
+                <th class="outward-col-remark">招标备注</th>
             </tr>
             </thead>
             <tbody>
@@ -496,10 +507,7 @@
             <thead>
             <tr>
                 <th class="text-center" style="width:52px;">选定</th>
-                <th class="col-supplier-name">供应商名称</th>
-                <th class="col-supplier-user">姓名</th>
-                <th class="col-supplier-email">邮箱</th>
-                <th class="col-supplier-phone">手机号</th>
+                <th class="col-supplier-info">供应商信息</th>
                 <th class="text-center col-rank" style="width:64px;">排名</th>
                 <th class="text-center" style="width:88px;">质量得分</th>
                 <th class="text-center" style="width:80px;" title="价格得分=(最低单价合计/本供应商单价合计)×价格权重%×100">价格得分</th>
@@ -527,10 +535,14 @@
                                {if condition="$pickedCompanyName neq '' && $pickedCompanyName eq $co.name"} checked="checked"{/if}/>
                     </label>
                 </td>
-                <td class="col-supplier-name"{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;">{$co.name|default=''|htmlentities}</td>
-                <td class="col-supplier-user"{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;">{$co.username|default=''|htmlentities}</td>
-                <td class="col-supplier-email"{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;">{:htmlentities(mask_email(isset($co['email']) ? $co['email'] : ''))}</td>
-                <td class="col-supplier-phone"{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;">{:htmlentities(mask_phone(isset($co['phone']) ? $co['phone'] : ''))}</td>
+                <td class="col-supplier-info"{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if}>
+                    <div class="outward-supplier-kv">
+                        <div class="outward-supplier-kv-row"><span class="outward-supplier-kv-label">供应商</span><span class="outward-supplier-kv-val">{$co.name|default=''|htmlentities}</span></div>
+                        <div class="outward-supplier-kv-row"><span class="outward-supplier-kv-label">姓名</span><span class="outward-supplier-kv-val">{$co.username|default=''|htmlentities}</span></div>
+                        <div class="outward-supplier-kv-row"><span class="outward-supplier-kv-label">邮箱</span><span class="outward-supplier-kv-val">{:htmlentities(mask_email(isset($co['email']) ? $co['email'] : ''))}</span></div>
+                        <div class="outward-supplier-kv-row"><span class="outward-supplier-kv-label">手机号</span><span class="outward-supplier-kv-val">{:htmlentities(mask_phone(isset($co['phone']) ? $co['phone'] : ''))}</span></div>
+                    </div>
+                </td>
                 <td class="text-center col-rank"{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;font-size:17px;font-weight:700;">{if condition="!empty($quoteVisible)"}{$co.service_rank_text|default=''|htmlentities}{/if}</td>
                 <td class="text-center"{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;">{if condition="!empty($quoteVisible)"}{$co.service_quality_score_text|default=''|htmlentities}{/if}</td>
                 <td class="text-center"{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;"{if condition="!empty($quoteVisible)"} title="单价合计 {$co.service_price_sum_text|default=''|htmlentities}"{/if}>{if condition="!empty($quoteVisible)"}{$co.service_price_score_text|default=''|htmlentities}{/if}</td>
@@ -539,7 +551,12 @@
                 {/if}
                 <td class="text-center"{if condition="$co.display_rowspan gt 1"} rowspan="{$co.display_rowspan}"{/if} style="vertical-align:middle;font-weight:600;">{if condition="!empty($quoteVisible)"}{$co.service_score_text|default=''|htmlentities}{/if}</td>
                 {/if}
-                <td class="outward-process-name">{$ql.cgymc|default=''|htmlentities}</td>
+                <td class="outward-process-name proc-process-name-cell">
+                    {notempty name="ql.ccydh"}
+                    <div class="proc-line-ccydh">{$ql.ccydh|htmlentities}</div>
+                    {/notempty}
+                    <div class="proc-line-cgymc">{$ql.cgymc|default=''|htmlentities}</div>
+                </td>
                 <td class="text-center{if condition="!empty($ql.amount_quote_pending)"} outward-quote-empty{elseif condition="$ql.amount_filled neq 1"} outward-quote-empty{/if}">{$ql.unit_price_text|default='未填写'|htmlentities}</td>
                 <td class="text-center{if condition="!empty($ql.lead_days_quote_pending)"} outward-quote-empty{elseif condition="$ql.lead_days_filled neq 1"} outward-quote-empty{/if}">{$ql.lead_days_text|default='未填写'|htmlentities}</td>
                 <td class="text-center{if condition="!empty($ql.delivery_quote_pending)"} outward-quote-empty{elseif condition="$ql.delivery_filled neq 1"} outward-quote-empty{/if}">{$ql.delivery_text|default='未填写'|htmlentities}</td>
@@ -549,7 +566,7 @@
             {/volist}
             {if !empty($co.has_remark)}
             <tr class="outward-confirm-supplier-row{if !empty($co.is_void)} text-muted{/if}" data-supplier-idx="{$k-1}">
-                <td><strong>备注</strong></td>
+                <td><strong>投标备注</strong></td>
                 <td colspan="5" class="{if !empty($co.remark_quote_pending)}outward-quote-empty{/if}" style="text-align:left;vertical-align:middle;">{$co.remark|default=''|htmlentities}</td>
             </tr>
             {/if}

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

@@ -104,7 +104,7 @@
         </div>
     </div>
     <div class="form-group">
-        <label class="control-label">备注:</label>
+        <label class="control-label">招标备注:</label>
         <div class="field-wrap">
             <input class="form-control" name="row[MBZ]" type="text" autocomplete="off">
         </div>

+ 9 - 1
application/admin/view/procuremen/review.html

@@ -420,6 +420,14 @@
         position: relative;
         top: 1px;
     }
+    .review-company-table > tbody > tr.is-no-contact {
+        color: #999;
+        background: #fafafa;
+    }
+    .review-company-table > tbody > tr.is-no-contact .review-td-cb input[type="checkbox"]:disabled {
+        cursor: not-allowed;
+        opacity: .45;
+    }
     /* 单元格完整展示,不换行省略号 */
     .review-company-table > tbody > tr > td:not(.review-td-cb) {
         white-space: normal;
@@ -638,7 +646,7 @@
                             <th class="text-center" style="width:72px;">本次数量</th>
                             <th class="text-center" style="width:72px;">最高限价</th>
                             <th class="text-center" style="width:80px;">订法</th>
-                            <th class="review-merge-col-remark">备注</th>
+                            <th class="review-merge-col-remark">招标备注</th>
                         </tr>
                         </thead>
                         <tbody id="review-merge-tbody"></tbody>

+ 32 - 0
application/admin/view/procuremen/toast_close.html

@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html lang="zh-cn">
+<head>
+    <meta charset="utf-8">
+    <title></title>
+</head>
+<body>
+<script>
+(function () {
+    var msg = {:json_encode($toastMsg)};
+    try {
+        var p = window.parent && window.parent !== window ? window.parent : window;
+        if (p.Toastr && typeof p.Toastr.warning === 'function') {
+            p.Toastr.warning(msg);
+        } else if (window.Toastr && typeof window.Toastr.warning === 'function') {
+            window.Toastr.warning(msg);
+        } else if (p.Layer && typeof p.Layer.msg === 'function') {
+            p.Layer.msg(msg, {icon: 0, time: 2500});
+        }
+        if (p.Layer && typeof p.Layer.getFrameIndex === 'function') {
+            var idx = p.Layer.getFrameIndex(window.name);
+            if (idx != null) {
+                p.Layer.close(idx);
+            }
+        }
+    } catch (e) {
+        try { alert(msg); } catch (e2) {}
+    }
+})();
+</script>
+</body>
+</html>

+ 1 - 1
application/admin/view/procuremenarchive/index.html

@@ -6,7 +6,7 @@
             <div id="toolbar" class="toolbar">
                 <a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}"><i class="fa fa-refresh"></i> 刷新</a>
                 {if $canArchiveAbandon}
-                <a href="javascript:;" class="btn btn-danger" id="btn-archive-abandon" title="勾选一条或多条已完结订单退回协助初选重新下发"><i class="fa fa-repeat"></i> 重新下发</a>
+                <a href="javascript:;" class="btn btn-danger" id="btn-archive-abandon" title="勾选一条或多条已完结订单退回供应商初选重新下发"><i class="fa fa-repeat"></i> 重新下发</a>
                 {/if}
             </div>
             <table id="table" class="table table-bordered table-hover table-nowrap" width="100%"></table>

+ 60 - 1
application/common/library/ProcuremenOperLog.php

@@ -45,6 +45,7 @@ class ProcuremenOperLog
             'save_qty_price'         => '保存数量限价',
             'mark_complete'          => '直接完结',
             'inbound_score'          => '质量评分',
+            'arrival_notify'         => '订单已到货通知',
             'audit_abandon'          => '审批重新下发',
             'archive_abandon'        => '历史重新下发',
         ];
@@ -75,6 +76,7 @@ class ProcuremenOperLog
             'save_qty_price'        => ['保存数量限价', 'save_qty_price'],
             'mark_complete'         => ['直接完结', '完结', 'mark_complete'],
             'inbound_score'         => ['质量评分', '入库评分', '是否合格', 'inbound_score'],
+            'arrival_notify'        => ['订单已到货通知', '通知已到货', 'arrival_notify'],
             'audit_abandon'         => ['审批重新下发', '重新下发', 'audit_abandon'],
             'archive_abandon'       => ['历史重新下发', '存证重新下发', 'archive_abandon'],
         ];
@@ -352,6 +354,10 @@ class ProcuremenOperLog
                 $content = $m[1];
             }
         }
+        // 指定/确认供应商:统一为「公司」或「公司;说明」
+        if ($action === '指定供应商' || $action === '确认供应商') {
+            $content = self::simplifySupplierPickLogContent($action, $content);
+        }
         if ($action === '') {
             $action = '操作';
         }
@@ -374,7 +380,7 @@ class ProcuremenOperLog
         // 历史/文案别名
         $aliases = [
             '下发通知'       => ['下发', '下发通知'],
-            '保存数量限价'   => ['保存数量限价', '保存本次数量、最高限价'],
+            '保存数量限价'   => ['保存数量限价', '保存本次数量、最高限价', '保存本次数量、最高限价、备注', '保存本次数量、最高限价、招标备注'],
             '审批重新下发'   => ['审批重新下发', '重新下发'],
             '历史重新下发'   => ['历史重新下发', '存证重新下发', '重新下发'],
             '审核确认供应商' => ['审核确认供应商', '采购确认'],
@@ -433,6 +439,13 @@ class ProcuremenOperLog
         if ($content === '') {
             return $lg;
         }
+        // 展示时去掉未填写的空「」片段(历史日志也适用)
+        $content = preg_replace('/,\s*最高限价「」/u', '', $content);
+        $content = preg_replace('/,\s*(?:招标)?备注「」/u', '', $content);
+        $content = preg_replace('/最高限价「」,\s*/u', '', $content);
+        $content = preg_replace('/(?:招标)?备注「」$/u', '', $content);
+        $content = preg_replace('/,\s*$/u', '', trim((string)$content));
+        $lg[self::COL_CONTENT] = $content;
         $sid = (int)($lg[self::COL_SCYDGY_ID] ?? 0);
         $proc = trim((string)($processNameBySid[$sid] ?? ''));
         if ($proc === '') {
@@ -858,6 +871,16 @@ class ProcuremenOperLog
 
             return $result;
         }
+        // 下发通知:不拼工序名(工序已在「本单工序」区展示)
+        if ($actionLabel === '下发通知' || trim($action) === 'issue_submit' || trim($action) === '下发') {
+            return $core !== '' ? $core : $content;
+        }
+        // 指定供应商 / 确认供应商:只保留供应商与说明,不拼工序名
+        if ($actionLabel === '指定供应商' || trim($action) === 'manual_pick'
+            || $actionLabel === '确认供应商' || trim($action) === 'audit_select' || trim($action) === 'audit_confirm'
+        ) {
+            return self::simplifySupplierPickLogContent($actionLabel, $core !== '' ? $core : $content);
+        }
         $procText = implode('、', $processNames);
         if ($procText === '') {
             return $core !== '' ? $core : $content;
@@ -870,6 +893,42 @@ class ProcuremenOperLog
         return $procText;
     }
 
+    /**
+     * 指定/确认供应商操作说明:去掉历史工序前缀与「已选定」等冗余文案
+     */
+    protected static function simplifySupplierPickLogContent(string $actionLabel, string $content): string
+    {
+        $content = trim($content);
+        if ($content === '') {
+            return '';
+        }
+        // 去掉开头工序名:xxx、yyy 或 [xxx、yyy]
+        $content = preg_replace('/^\[?[^\n\[\]]{1,120}?\]?\s*(?=指定供应商|确认供应商|已选定)/u', '', $content);
+        $content = trim((string)$content);
+        $company = '';
+        if (preg_match('/「([^」]+)」/u', $content, $m)) {
+            $company = trim($m[1]);
+        } elseif (preg_match('/(?:指定供应商|确认供应商)[::]\s*(?:已选定)?\s*[「"]?([^」";;\n]+)/u', $content, $m)) {
+            $company = trim($m[1]);
+        }
+        if ($actionLabel === '指定供应商') {
+            $reason = '';
+            if (preg_match('/说明[::]\s*(.+)$/u', $content, $rm)) {
+                $reason = trim($rm[1]);
+            }
+            if ($company === '') {
+                return $content;
+            }
+
+            return $company . ($reason !== '' ? ';说明:' . $reason : '');
+        }
+        if ($company !== '') {
+            return $company;
+        }
+
+        return $content;
+    }
+
     /**
      * @param array<string, mixed> $lg
      */

+ 5 - 0
application/common/library/ProcuremenSchema.php

@@ -199,10 +199,12 @@ class ProcuremenSchema
   `score_quality_weight` int unsigned NOT NULL DEFAULT 0 COMMENT '质量权重快照%',
   `score_price_weight` int unsigned NOT NULL DEFAULT 0 COMMENT '价格权重快照%',
   `score_lead_weight` int unsigned NOT NULL DEFAULT 0 COMMENT '交货权重快照%',
+  `order_batch_no` varchar(32) NOT NULL DEFAULT '' COMMENT '下发批次号',
   `mod_rq` varchar(255) DEFAULT NULL COMMENT '软删除日期',
   PRIMARY KEY (`id`),
   KEY `idx_scydgy_id` (`scydgy_id`),
   KEY `idx_CCYDH` (`CCYDH`(64)),
+  KEY `idx_order_batch_no` (`order_batch_no`),
   KEY `idx_wflow_status` (`wflow_status`(32))
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='协助采购订单(工序行)'");
                 $changed = true;
@@ -225,6 +227,7 @@ class ProcuremenSchema
             'score_quality_weight'      => "`score_quality_weight` int unsigned NOT NULL DEFAULT 0 COMMENT '质量权重快照%'",
             'score_price_weight'        => "`score_price_weight` int unsigned NOT NULL DEFAULT 0 COMMENT '价格权重快照%'",
             'score_lead_weight'         => "`score_lead_weight` int unsigned NOT NULL DEFAULT 0 COMMENT '交货权重快照%'",
+            'order_batch_no'            => "`order_batch_no` varchar(32) NOT NULL DEFAULT '' COMMENT '下发批次号(如XH202608240001)'",
             'This_quantity'             => "`This_quantity` varchar(255) DEFAULT NULL COMMENT '本次数量'",
             'ceilingPrice'              => "`ceilingPrice` varchar(255) DEFAULT NULL COMMENT '最高限价'",
             'pick_company_name'         => "`pick_company_name` varchar(255) DEFAULT NULL COMMENT '中标/选定供应商'",
@@ -377,6 +380,7 @@ class ProcuremenSchema
   `result` varchar(16) NOT NULL DEFAULT '' COMMENT '合格/不合格',
   `delivery_status` varchar(16) NOT NULL DEFAULT '' COMMENT '交货情况 准时/滞后',
   `delivery_date` date DEFAULT NULL COMMENT '交货日期',
+  `storage_location` varchar(64) NOT NULL DEFAULT '' COMMENT '库位',
   `customer_complaint` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '客户是否投诉 1=是',
   `complaint_remark` varchar(500) NOT NULL DEFAULT '' COMMENT '投诉说明',
   `order_interrupt` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '订单是否中断 1=是',
@@ -400,6 +404,7 @@ class ProcuremenSchema
         return self::ensureColumns('purchase_order_inbound_score', [
             'delivery_status'    => "`delivery_status` varchar(16) NOT NULL DEFAULT '' COMMENT '交货情况 准时/滞后'",
             'delivery_date'      => "`delivery_date` date DEFAULT NULL COMMENT '交货日期'",
+            'storage_location'   => "`storage_location` varchar(64) NOT NULL DEFAULT '' COMMENT '库位'",
             'customer_complaint' => "`customer_complaint` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '客户是否投诉 1=是'",
             'complaint_remark'   => "`complaint_remark` varchar(500) NOT NULL DEFAULT '' COMMENT '投诉说明'",
             'order_interrupt'    => "`order_interrupt` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '订单是否中断 1=是'",

+ 52 - 1
application/common/library/ProcuremenStatus.php

@@ -69,7 +69,7 @@ class ProcuremenStatus
         if ($s === '1' || strcasecmp($s, self::WFLOW_PENDING_CONFIRM) === 0) {
             return self::WFLOW_PENDING_CONFIRM;
         }
-        if ($s === '2' || strcasecmp($s, self::WFLOW_PENDING_APPROVAL) === 0) {
+        if ($s === '2' || strcasecmp($s, self::WFLOW_PENDING_APPROVAL) === 0 || $s === '待审核') {
             return self::WFLOW_PENDING_APPROVAL;
         }
         if ($s === '3' || strcasecmp($s, self::WFLOW_APPROVED) === 0) {
@@ -150,6 +150,57 @@ class ProcuremenStatus
         return [self::WFLOW_APPROVED, '3'];
     }
 
+    /**
+     * 确认页 / 审批页共用列表:待确认 + 待审批 + 已审核
+     *
+     * @return string[]
+     */
+    public static function wflowConfirmAndAuditListValues(): array
+    {
+        return array_values(array_unique(array_merge(
+            self::wflowPendingConfirmValues(),
+            self::wflowPendingApprovalValues(),
+            self::wflowApprovedValues()
+        )));
+    }
+
+    /**
+     * 列表「订单状态」展示:待确认 / 待审核 / 已审核
+     */
+    public static function orderStatusLabelForList($value): string
+    {
+        $w = self::normalizeWflowStatus($value);
+        if ($w === self::WFLOW_PENDING_CONFIRM || $w === '待确认') {
+            return '待确认';
+        }
+        if ($w === self::WFLOW_PENDING_APPROVAL || $w === '待审核') {
+            return '待审核';
+        }
+        if ($w === self::WFLOW_APPROVED || $w === '已审核') {
+            return '已审核';
+        }
+
+        return $w !== '' ? $w : '';
+    }
+
+    /**
+     * 确认/审批列表按订单状态排序权重(越小越靠前)
+     * - audit(采购供应商确认):待确认 → 待审核 → 已审核
+     * - confirm(采购确认/审批):待审核 → 待确认 → 已审核
+     */
+    public static function orderStatusSortWeight(string $stage, $value): int
+    {
+        $label = self::orderStatusLabelForList($value);
+        if ($stage === 'audit') {
+            $map = ['待确认' => 0, '待审核' => 1, '已审核' => 2];
+        } else {
+            // confirm(审批页)等
+            $map = ['待审核' => 0, '待确认' => 1, '已审核' => 2];
+        }
+
+        return $map[$label] ?? 99;
+    }
+
     /** @return string[] */
     public static function wflowPendingIssueValues(): array
     {

+ 2 - 1
application/common/library/ProcuremenTime.php

@@ -211,7 +211,8 @@ class ProcuremenTime
         $content = preg_replace('/已选中供应商/u', '已选定', $content);
         $content = preg_replace('/^(合并)?(协助|外发)初选/u', '下发', $content);
         $content = preg_replace('/^采购终审驳回/u', '审核驳回', $content);
-        $content = preg_replace('/退回外发初选/u', '退回协助初选', $content);
+        $content = preg_replace('/退回外发初选/u', '退回供应商初选', $content);
+        $content = preg_replace('/退回协助初选/u', '退回供应商初选', $content);
         $content = preg_replace('/;+$/u', '', $content);
 
         return trim(self::stripOperLogOrderNo((string)$content));

+ 6 - 4
application/extra/mproc.php

@@ -14,8 +14,9 @@
  * app\common\library\ProcuremenSchema::ensureAll() 自动建表并补齐字段。
  */
 return [
-    // 邮件根地址(正式环境);本地未配或校验不通过时自动用当前访问域名
-    'mobile_base_url'   => 'https://xh.7in6.com',
+    // 手机端根地址(邮件链接、送货单二维码共用)
+    // 本地测试写局域网地址,例如 http://20.0.6.57 ;上线改为 https://xh.7in6.com
+    'mobile_base_url'   => 'http://20.0.6.57',
     // 手机端首页路径(相对上项),留空为 /index.php/index/index/index
     'mobile_index_path' => '',
     'session_hours' => 72,
@@ -40,8 +41,6 @@ return [
     // 手机端交货情况:所属角色组(默认「生产员」,展示名「生产部」)
     'mobile_delivery_group_id'  => 15,
     'mobile_delivery_dept_name' => '生产部',
-    // 送货单二维码根地址。仅本地扫码用;线上会自动改用 mobile_base_url(https://xh.7in6.com)
-    'delivery_scan_base'        => 'http://20.0.6.57',
     // 送货单抬头(客户=本公司)
     'delivery_customer_name'    => '浙江新华数码印务有限公司',
     'delivery_address'          => '杭州市经济技术开发区文海北路369号',
@@ -65,4 +64,7 @@ return [
     'cockpit_system_style'         => 2,
     'cockpit_system_brand'         => '浙江印刷集团有限公司',
     'cockpit_allow_rule_super'     => true, // 超管 admin(rules=*)可登录
+
+    // 协助通知抄送(下发报价、中标确认、未中标、询价通知等);多个用逗号分隔;留空则不抄送
+    'cc_email' => '',
 ];

File diff suppressed because it is too large
+ 1273 - 181
application/index/controller/Index.php


+ 64 - 4
application/index/view/index/deliverynote.html

@@ -11,17 +11,34 @@
             font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
             background: #eef3f7; color: #222; font-size: 14px;
         }
+        :root {
+            --phone-w: 480px;
+            --bar-h: 48px;
+        }
         .bar {
             position: sticky; top: 0; z-index: 20;
-            height: 48px; padding: 0 12px;
+            height: var(--bar-h); padding: 0 8px 0 12px;
             background: #3c8dbc; color: #fff;
             display: flex; align-items: center; justify-content: space-between;
         }
         .bar a, .bar button {
-            color: #fff; text-decoration: none; font-size: 14px; padding: 6px 4px;
+            color: #fff; text-decoration: none; font-size: 14px; padding: 6px 2px;
             background: none; border: 0; font-family: inherit; cursor: pointer;
+            flex: 0 0 auto;
+            position: relative; z-index: 1;
+        }
+        .bar a { min-width: 3em; }
+        .bar button#btn-note-save {
+            min-width: 3em;
+            text-align: right;
+            padding: 6px 4px 6px 10px;
+            margin-right: 0;
+        }
+        .bar h1 {
+            margin: 0; font-size: 16px; font-weight: 600;
+            position: absolute; left: 0; right: 0;
+            text-align: center; pointer-events: none;
         }
-        .bar h1 { margin: 0; font-size: 16px; font-weight: 600; }
         .bar button:disabled { opacity: .7; }
         #note-toast {
             position: fixed; left: 50%; bottom: 72px; z-index: 40;
@@ -75,11 +92,50 @@
         .block h2 { margin: 0 0 8px; font-size: 13px; color: #888; font-weight: 600; }
         .line { font-size: 13px; line-height: 1.75; color: #333; }
         .line span { color: #888; }
+        .line-qty-row {
+            display: flex;
+            flex-wrap: wrap;
+            gap: 6px 24px;
+            align-items: baseline;
+            justify-content: flex-start;
+        }
+        .line-qty-row .qty-item {
+            flex: 0 1 auto;
+            min-width: 0;
+            font-size: 13px;
+            line-height: 1.75;
+            color: #333;
+        }
+        .line-qty-row .qty-item > span:first-child { color: #888; }
         @media print {
             body { background: #fff; }
             .bar, #save-mask, #note-toast { display: none !important; }
             .sheet { margin: 0; box-shadow: none; max-width: none; }
         }
+        /* 宽屏:顶栏+单据居中成手机壳 */
+        @media (min-width: 520px) {
+            html, body {
+                background: #e8e8e8;
+            }
+            .bar {
+                position: fixed;
+                left: calc((100vw - min(100vw, var(--phone-w))) / 2);
+                right: auto;
+                width: min(100vw, var(--phone-w));
+                max-width: var(--phone-w);
+                box-shadow: 0 0 24px rgba(0, 0, 0, .08);
+            }
+            body {
+                padding-top: var(--bar-h);
+            }
+            .sheet {
+                width: min(100vw, var(--phone-w));
+                max-width: var(--phone-w);
+                margin: 0 auto;
+                min-height: calc(100vh - var(--bar-h));
+                box-shadow: 0 0 24px rgba(0, 0, 0, .08);
+            }
+        }
     </style>
 </head>
 <body>
@@ -114,7 +170,11 @@
         <div class="line"><span>工序名称:</span>{$note.cgymc|default=''|htmlentities}</div>
         <div class="line"><span>单位:</span>{$note.cdw|default=''|htmlentities}</div>
         <div class="line"><span>订法:</span>{$note.cdf|default=''|htmlentities}</div>
-        <div class="line"><span>备注:</span>{notempty name="note.remark"}{$note.remark|htmlentities}{else /}—{/notempty}</div>
+        <div class="line"><span>备注:</span>{notempty name="note.remark"}{$note.remark|htmlentities}{/notempty}</div>
+        <div class="line line-qty-row">
+            <div class="qty-item"><span>订单数量:</span>{notempty name="note.order_qty"}{$note.order_qty|htmlentities}{/notempty}</div>
+            <div class="qty-item"><span>本次送货数量:</span>{notempty name="note.delivery_qty"}{$note.delivery_qty|htmlentities}{/notempty}</div>
+        </div>
     </div>
     <div class="block">
         <h2>供应商信息</h2>

File diff suppressed because it is too large
+ 1286 - 78
application/index/view/index/deliveryscore.html


+ 134 - 33
application/index/view/index/inboundscore.html

@@ -23,6 +23,7 @@
             --tabbar-h: 52px;
             --side-w: 72px;
             --safe-bottom: env(safe-area-inset-bottom, 0px);
+            --phone-w: 480px;
         }
         body.layout-orders { overflow: hidden; }
         body.layout-me { overflow: hidden; }
@@ -101,15 +102,34 @@
             padding: 10px; background: #f5f5f5;
         }
         .card {
-            background: #fff; border-radius: 10px; padding: 12px;
-            margin-bottom: 10px; box-shadow: 0 1px 4px rgba(0,0,0,.06);
+            background: #fff;
+            border-radius: 10px;
+            padding: 12px 12px 10px;
+            margin-bottom: 10px;
+            box-shadow: 0 1px 4px rgba(0,0,0,.06);
         }
         .card .ord {
             font-size: 15px; font-weight: 700; color: #222; margin-bottom: 8px;
             line-height: 1.45; word-break: break-all;
         }
         .card .meta { font-size: 13px; color: #555; line-height: 1.55; }
-        .card .meta b { color: #333; font-weight: 600; }
+        .card .meta > div {
+            display: flex; align-items: flex-start; gap: 8px;
+            margin: 0 0 4px;
+        }
+        .card .meta .meta-lab {
+            flex: 0 0 4.5em;
+            width: 4.5em;
+            color: #888;
+            font-weight: 500;
+            white-space: nowrap;
+        }
+        .card .meta .meta-val {
+            flex: 1 1 auto;
+            min-width: 0;
+            color: #333;
+            word-break: break-all;
+        }
         .actions { display: flex; gap: 8px; margin-top: 10px; justify-content: flex-end; }
         .actions button {
             min-width: 72px; padding: 6px 14px; border: none; border-radius: 6px;
@@ -196,29 +216,47 @@
         }
         .confirm-box .confirm-ord {
             font-size: 15px; font-weight: 700; color: #222; line-height: 1.45;
-            word-break: break-all; margin: 0 0 8px; text-align: left;
+            word-break: break-all; margin: 0 0 10px; text-align: left;
         }
         .confirm-box .confirm-meta {
-            font-size: 13px; color: #555; line-height: 1.55; margin: 0 0 12px; text-align: left;
+            font-size: 13px; color: #555; line-height: 1.55; margin: 0 0 10px; text-align: left;
+            padding-bottom: 8px; border-bottom: 1px solid #f0f0f0;
+        }
+        .confirm-box .confirm-meta .form-row {
+            display: flex; align-items: flex-start; gap: 10px; margin: 0 0 6px;
+        }
+        .confirm-box .confirm-meta .form-row .lab {
+            flex: 0 0 6.5em; width: 6.5em; font-weight: 600; color: #666; white-space: nowrap;
+            font-size: 13px; line-height: 1.45; padding-top: 2px;
+        }
+        .confirm-box .confirm-meta .form-row .val {
+            flex: 1 1 auto; min-width: 0; color: #222; word-break: break-all;
+            font-size: 13px; line-height: 1.45; padding-top: 2px;
         }
-        .confirm-box .confirm-meta b { color: #333; font-weight: 600; }
         .score-field {
-            margin: 0 0 12px;
+            margin: 0 0 10px;
             display: flex;
-            align-items: center;
+            align-items: flex-start;
             gap: 10px;
+            padding: 0;
+            background: transparent;
+            border: none;
+            border-radius: 0;
         }
         .score-field .label {
-            flex: 0 0 auto;
-            min-width: 7.2em;
-            font-size: 13px; font-weight: 600; color: #333;
-            margin: 0; line-height: 1.35;
+            flex: 0 0 6.5em;
+            width: 6.5em;
+            font-size: 13px; font-weight: 600; color: #666;
+            margin: 0; line-height: 40px;
+            white-space: nowrap;
         }
-        .score-field .label .req { color: #e74c3c; margin-left: 2px; }
+        .score-field .label .req { color: #e74c3c; margin-left: 1px; }
         .score-opts {
             flex: 1 1 auto;
             display: flex; gap: 8px;
             min-width: 0;
+            align-items: center;
+            min-height: 40px;
         }
         .score-opt {
             flex: 1; position: relative;
@@ -229,7 +267,7 @@
         .score-opt span {
             display: block; text-align: center; padding: 8px 6px; border-radius: 8px;
             border: 1px solid #d9d9d9; background: #fafafa; font-size: 13px; font-weight: 600;
-            color: #555;
+            color: #555; box-sizing: border-box; min-height: 40px; line-height: 24px;
         }
         .score-opt input:checked + span {
             border-color: #3c8dbc; background: #eaf5fb; color: #3c8dbc;
@@ -237,17 +275,18 @@
         .score-opt.pass input:checked + span { border-color: #27ae60; background: #eafaf1; color: #27ae60; }
         .score-opt.fail input:checked + span { border-color: #e74c3c; background: #fdecea; color: #e74c3c; }
         .score-field-remark {
-            flex-direction: column;
-            align-items: stretch;
-            gap: 8px;
+            align-items: flex-start;
         }
         .score-field-remark .label {
-            min-width: 0;
+            line-height: 1.35;
+            height: auto;
+            padding-top: 2px;
         }
         .score-remark {
-            width: 100%; min-height: 72px; padding: 10px 12px; border: 1px solid #d9d9d9;
-            border-radius: 8px; font-size: 14px; line-height: 1.5; resize: vertical;
-            font-family: inherit; background: #fff; color: #333;
+            flex: 1 1 auto; min-width: 0;
+            width: 100%; min-height: 72px; padding: 8px 10px; border: 1px solid #d9d9d9;
+            border-radius: 8px; font-size: 14px; line-height: 1.5; resize: none;
+            font-family: inherit; background: #fff; color: #333; box-sizing: border-box;
         }
         .score-remark:focus { outline: none; border-color: #3c8dbc; }
         .confirm-box .confirm-acts {
@@ -274,6 +313,31 @@
         .toast.show { opacity: 1; }
         .toast.ok { background: #27ae60; }
         .toast.err { background: #c0392b; }
+        /* 宽屏:整页居中成手机壳(与报价列表一致) */
+        @media (min-width: 520px) {
+            body.layout-orders,
+            body.layout-me {
+                background: #e8e8e8;
+            }
+            .bar,
+            .tabbar,
+            #pane-orders,
+            #pane-me {
+                left: calc((100vw - min(100vw, var(--phone-w))) / 2);
+                right: auto;
+                width: min(100vw, var(--phone-w));
+                max-width: var(--phone-w);
+                transform: none;
+                box-shadow: 0 0 24px rgba(0, 0, 0, .08);
+            }
+            #pane-orders,
+            #pane-me {
+                background: #f5f5f5;
+            }
+            .me-panel {
+                max-width: none;
+            }
+        }
     </style>
 </head>
 <body class="layout-orders">
@@ -300,8 +364,9 @@
             <div class="card" data-ccydh="{$row.CCYDH|htmlentities}">
                 <div class="ord">{$row.CCYDH|default=''|htmlentities}{if $row.CYJMC} {$row.CYJMC|htmlentities}{/if}</div>
                 <div class="meta">
-                    <div><b>供应商:</b>{$row.pick_company_name|default='—'|htmlentities}</div>
-                    <div><b>工序:</b>{$row.CGYMC|default='—'|htmlentities}</div>
+                    <div><span class="meta-lab">供应商</span><span class="meta-val">{$row.pick_company_name|default='—'|htmlentities}</span></div>
+                    <div><span class="meta-lab">工序名称</span><span class="meta-val">{$row.CGYMC|default='—'|htmlentities}</span></div>
+                    <div><span class="meta-lab">库位</span><span class="meta-val">{$row.storage_location|default=''|htmlentities}</span></div>
                 </div>
                 <div class="actions">
                     <button type="button" class="btn-score">评分</button>
@@ -617,8 +682,9 @@
             html += '<div class="card" data-ccydh="' + esc(row.CCYDH || '') + '">';
             html += '<div class="ord">' + esc(titleText(row)) + '</div>';
             html += '<div class="meta">';
-            html += '<div><b>供应商:</b>' + esc(row.pick_company_name || '—') + '</div>';
-            html += '<div><b>工序:</b>' + esc(row.CGYMC || '—') + '</div>';
+            html += '<div><span class="meta-lab">供应商</span><span class="meta-val">' + esc(row.pick_company_name || '—') + '</span></div>';
+            html += '<div><span class="meta-lab">工序名称</span><span class="meta-val">' + esc(row.CGYMC || '—') + '</span></div>';
+            html += '<div><span class="meta-lab">库位</span><span class="meta-val">' + esc(row.storage_location || '') + '</span></div>';
             html += '</div>';
             if (pending) {
                 html += '<div class="actions"><button type="button" class="btn-score">评分</button></div>';
@@ -629,12 +695,16 @@
                 var complained = complaint === '1';
                 var remark = String(row.remark || '');
                 var complaintRemark = String(row.complaint_remark || '');
+                var loc = String(row.storage_location || '');
+                var opName = String(row.score_operator || '').trim();
                 html += '<div class="score-summary"'
                     + ' data-result="' + esc(res) + '"'
                     + ' data-interrupt="' + interrupt + '"'
                     + ' data-complaint="' + complaint + '"'
                     + ' data-complaint-remark="' + esc(complaintRemark) + '"'
+                    + ' data-storage-location="' + esc(loc) + '"'
                     + ' data-remark="' + esc(remark) + '">'
+                    + '<span>库位:' + esc(loc || '') + '</span>'
                     + '<span class="res' + (res === '不合格' ? ' is-fail' : '') + '">' + esc(res || '—') + '</span>'
                     + '<span>客户投诉:' + esc(ynText(complaint)) + '</span>'
                     + '<span>生产中断:' + esc(ynText(interrupt)) + '</span>'
@@ -645,8 +715,11 @@
                 if (remark) {
                     html += '<div class="score-extra">备注:' + esc(remark) + '</div>';
                 }
-                if (row.score_time) {
-                    html += '<div class="score-time">操作时间:' + esc(row.score_time) + '</div>';
+                if (row.score_time || opName) {
+                    html += '<div class="score-time">'
+                        + (opName ? ('操作人:' + esc(opName) + ' ') : '')
+                        + (row.score_time ? ('操作时间:' + esc(row.score_time)) : '')
+                        + '</div>';
                 }
                 html += '<div class="actions">'
                     + '<button type="button" class="btn-score">评分</button>'
@@ -791,15 +864,29 @@
         var metaLines = card.querySelectorAll('.meta > div');
         var gymc = '—';
         var company = '—';
+        var location = '';
         for (var i = 0; i < metaLines.length; i++) {
+            var labEl = metaLines[i].querySelector('.meta-lab');
+            var valEl = metaLines[i].querySelector('.meta-val');
+            if (labEl && valEl) {
+                var lab = textOf(labEl);
+                var val = textOf(valEl) || '—';
+                if (lab === '工序名称' || lab === '工序') gymc = val;
+                if (lab === '供应商') company = val;
+                if (lab === '库位') location = val === '—' ? '' : val;
+                continue;
+            }
             var t = textOf(metaLines[i]);
-            if (t.indexOf('工序:') === 0) gymc = t.slice(3).trim() || '—';
+            if (t.indexOf('工序名称:') === 0) gymc = t.slice(5).trim() || '—';
+            else if (t.indexOf('工序:') === 0) gymc = t.slice(3).trim() || '—';
             if (t.indexOf('供应商:') === 0) company = t.slice(4).trim() || '—';
+            if (t.indexOf('库位:') === 0) location = t.slice(3).trim() || '';
         }
         if (scoreOrd) scoreOrd.textContent = ord;
         if (scoreMeta) {
-            scoreMeta.innerHTML = '<div><b>供应商:</b>' + esc(company) + '</div>'
-                + '<div><b>工序:</b>' + esc(gymc) + '</div>';
+            scoreMeta.innerHTML = '<div class="form-row"><span class="lab">供应商</span><span class="val">' + esc(company) + '</span></div>'
+                + '<div class="form-row"><span class="lab">工序名称</span><span class="val">' + esc(gymc) + '</span></div>'
+                + '<div class="form-row"><span class="lab">库位</span><span class="val">' + esc(location) + '</span></div>';
         }
         var summary = card.querySelector('.score-summary');
         if (summary) {
@@ -909,17 +996,31 @@
         var metaLines = card.querySelectorAll('.meta > div');
         var gymc = '—';
         var company = '—';
+        var location = '';
         for (var i = 0; i < metaLines.length; i++) {
+            var labEl = metaLines[i].querySelector('.meta-lab');
+            var valEl = metaLines[i].querySelector('.meta-val');
+            if (labEl && valEl) {
+                var lab = textOf(labEl);
+                var val = textOf(valEl) || '—';
+                if (lab === '工序名称' || lab === '工序') gymc = val;
+                if (lab === '供应商') company = val;
+                if (lab === '库位') location = val === '—' ? '' : val;
+                continue;
+            }
             var t = textOf(metaLines[i]);
-            if (t.indexOf('工序:') === 0) gymc = t.slice(3).trim() || '—';
+            if (t.indexOf('工序名称:') === 0) gymc = t.slice(5).trim() || '—';
+            else if (t.indexOf('工序:') === 0) gymc = t.slice(3).trim() || '—';
             if (t.indexOf('供应商:') === 0) company = t.slice(4).trim() || '—';
+            if (t.indexOf('库位:') === 0) location = t.slice(3).trim() || '';
         }
         var complaintOrd = document.getElementById('complaintOrd');
         var complaintMeta = document.getElementById('complaintMeta');
         if (complaintOrd) complaintOrd.textContent = ord;
         if (complaintMeta) {
-            complaintMeta.innerHTML = '<div><b>供应商:</b>' + esc(company) + '</div>'
-                + '<div><b>工序:</b>' + esc(gymc) + '</div>';
+            complaintMeta.innerHTML = '<div class="form-row"><span class="lab">供应商</span><span class="val">' + esc(company) + '</span></div>'
+                + '<div class="form-row"><span class="lab">工序名称</span><span class="val">' + esc(gymc) + '</span></div>'
+                + '<div class="form-row"><span class="lab">库位</span><span class="val">' + esc(location) + '</span></div>';
         }
         var summary = card.querySelector('.score-summary');
         var cur = card.querySelector('.btn-complaint');

+ 297 - 74
application/index/view/index/index.html

@@ -27,6 +27,8 @@
             /* 顶栏固定高度:订单页隐藏「退出」后也不能变矮,否则与「我的」页不一致、fixed 主区 top 会错位 */
             --mproc-bar-h: 52px;
             --mproc-tabbar-h: 52px;
+            /* 电脑端按手机宽度居中显示,避免列表被拉成整屏宽 */
+            --mproc-phone-w: 480px;
         }
         body.mproc-layout-orders,
         body.mproc-layout-me {
@@ -409,6 +411,28 @@
             line-height: 40px;
         }
         #edit-lines-box { margin-top: 0; }
+        .edit-order-remark {
+            display: flex;
+            align-items: flex-start;
+            gap: 6px;
+            margin: 0 0 12px;
+            padding: 0 0 10px;
+            border-bottom: 1px solid #eef2f5;
+            font-size: 13px;
+            line-height: 1.45;
+            color: #333;
+            word-break: break-all;
+        }
+        .edit-order-remark-label {
+            flex: 0 0 4.5em;
+            width: 4.5em;
+            color: #888;
+            white-space: nowrap;
+        }
+        .edit-order-remark-val {
+            flex: 1 1 auto;
+            min-width: 0;
+        }
         .edit-remark-wrap {
             display: flex;
             align-items: flex-start;
@@ -448,13 +472,26 @@
         }
         .edit-remark-wrap textarea:focus { outline: none; border-color: #3c8dbc; }
         .order-group-remark {
+            display: flex;
+            align-items: baseline;
+            gap: 6px;
             margin: 6px 0 0;
             font-size: 13px;
             line-height: 1.45;
             color: #333;
             word-break: break-all;
         }
-        .order-group-remark span { color: #888; margin-right: 4px; }
+        .order-group-remark span {
+            flex: 0 0 4.5em;
+            width: 4.5em;
+            color: #888;
+            margin-right: 0;
+            white-space: nowrap;
+        }
+        .order-group-supplier-remark {
+            margin: 8px 0 2px;
+            padding: 0 2px;
+        }
         .modal-sheet#edit-sheet {
             background: #fff;
             padding: 16px 16px 18px;
@@ -521,6 +558,7 @@
         .mproc-pick-win { background: #f6ffed; color: #389e0d; border: 1px solid #b7eb8f; }
         .mproc-pick-lose { background: #fff2f0; color: #cf1322; border: 1px solid #ffccc7; }
         .mproc-pick-expired { background: #fafafa; color: #888; border: 1px solid #e8e8e8; }
+        .mproc-pick-void { background: #fff1f0; color: #a8071a; border: 1px solid #ffa39e; }
         .mproc-pick-quoted { background: #e6f7ff; color: #1890ff; border: 1px solid #91d5ff; }
         .mproc-pick-unquoted { background: #fff7e6; color: #d46b08; border: 1px solid #ffd591; }
         .js-order-group.mproc-card-highlight {
@@ -735,6 +773,31 @@
         .modal-actions .btn-cancel { background: #f0f0f0; color: #555; }
         .modal-actions .btn-ok { background: #3c8dbc; color: #fff; font-weight: 600; }
         .modal-actions .btn-ok:disabled { opacity: .6; }
+        /* 宽屏:必须写在 left/right 基础规则之后,整页居中成手机壳 */
+        @media (min-width: 520px) {
+            body.mproc-layout-orders,
+            body.mproc-layout-me {
+                background: #e8e8e8;
+            }
+            .bar,
+            .tabbar,
+            #mproc-pane-orders,
+            #mproc-pane-me {
+                left: calc((100vw - min(100vw, var(--mproc-phone-w))) / 2);
+                right: auto;
+                width: min(100vw, var(--mproc-phone-w));
+                max-width: var(--mproc-phone-w);
+                transform: none;
+                box-shadow: 0 0 24px rgba(0, 0, 0, .08);
+            }
+            #mproc-pane-orders,
+            #mproc-pane-me {
+                background: #f5f5f5;
+            }
+            .me-panel {
+                max-width: none;
+            }
+        }
     </style>
 </head>
 <body class="{eq name='mprocMainTab' value='me'}mproc-layout-me{else/}mproc-layout-orders{/eq}">
@@ -774,7 +837,7 @@
     {empty name="groups"}
     {notempty name="rows"}
     {volist name="rows" id="r"}
-    <div class="card order-group-card js-order-group{if $mprocFocusEid && $mprocFocusEid == $r.eid && ($mprocFocusTab == '' || $mprocFocusTab == $mprocTab)} mproc-card-highlight{/if}" data-ccydh="{$r.CCYDH|default=''|htmlentities}" data-remark="{$r.mproc_remark|default=''|htmlentities}" data-delivery-deadline="{eq name='mprocIsRfqTab' value='1'}{else /}{$r.mproc_delivery_deadline|default=''|htmlentities}{/eq}" data-bid-deadline="{eq name='mprocIsRfqTab' value='1'}{else /}{$r.mproc_bid_deadline|default=''|htmlentities}{/eq}" data-bid-open="{eq name='mprocIsRfqTab' value='1'}0{else /}{$r.mproc_bid_open_verified|default=0}{/eq}" data-is-rfq="{$mprocIsRfqTab|default=0}">
+    <div class="card order-group-card js-order-group{if $mprocFocusEid && $mprocFocusEid == $r.eid && ($mprocFocusTab == '' || $mprocFocusTab == $mprocTab)} mproc-card-highlight{/if}" data-ccydh="{$r.CCYDH|default=''|htmlentities}" data-order-remark="{$r.mproc_order_remark|default=''|htmlentities}" data-remark="{$r.mproc_remark|default=''|htmlentities}" data-delivery-deadline="{eq name='mprocIsRfqTab' value='1'}{else /}{$r.mproc_delivery_deadline|default=''|htmlentities}{/eq}" data-bid-deadline="{eq name='mprocIsRfqTab' value='1'}{else /}{$r.mproc_bid_deadline|default=''|htmlentities}{/eq}" data-bid-open="{eq name='mprocIsRfqTab' value='1'}0{else /}{$r.mproc_bid_open_verified|default=0}{/eq}" data-is-rfq="{$mprocIsRfqTab|default=0}">
         <div class="order-group-head{eq name='mprocStatusTab' value='done'}{eq name='r.mproc_pick_result' value='中标'} has-delivery-code{/eq}{/eq}">
             <p class="title">{notempty name="r.CCYDH"}<span class="mproc-ord-no">{$r.CCYDH}</span>{/notempty}{$r.CYJMC|default=''}{eq name="mprocStatusTab" value="draft"}{eq name="mprocIsRfqTab" value="1"}<em class="mproc-pick-badge mproc-pick-unquoted">待报价</em>{else /}<em class="mproc-pick-badge mproc-pick-unquoted">未报价</em>{/eq}{/eq}{eq name="mprocStatusTab" value="submitted"}<em class="mproc-pick-badge mproc-pick-quoted">已报价</em>{/eq}{notempty name="r.mproc_done_label"}{eq name="mprocStatusTab" value="done"}<em class="mproc-pick-badge {eq name='r.mproc_pick_result' value='中标'}mproc-pick-win{else /}{eq name='r.mproc_pick_result' value='未中标'}mproc-pick-lose{else /}mproc-pick-expired{/eq}{/eq}">{$r.mproc_done_label|htmlentities}</em>{/eq}{/notempty}</p>
             {eq name="mprocStatusTab" value="done"}{eq name="r.mproc_pick_result" value="中标"}{notempty name="r.CCYDH"}
@@ -785,12 +848,7 @@
                 <div class="kv"><span>招标截止日期</span>{notempty name="r.mproc_bid_deadline_display"}{$r.mproc_bid_deadline_display|htmlentities}{else /}—{/notempty}</div>
                 <div class="kv"><span>交货截止日期</span>{notempty name="r.mproc_delivery_deadline_display"}{$r.mproc_delivery_deadline_display|htmlentities}{else /}—{/notempty}</div>
             </div>
-            {notempty name="r.mproc_order_remark"}
-            <div class="kv order-group-remark"><span>订单备注</span>{$r.mproc_order_remark|htmlentities}</div>
-            {/notempty}
-            {notempty name="r.mproc_remark"}
-            <div class="kv order-group-remark"><span>备注</span>{$r.mproc_remark|htmlentities}</div>
-            {/notempty}
+            <div class="kv order-group-remark"><span>招标备注</span>{$r.mproc_order_remark|default=''|htmlentities}</div>
             {/eq}
         </div>
         <div class="order-line js-line"
@@ -808,14 +866,15 @@
             <div class="kv-row order-line-metrics">
                 <div class="kv"><span>本次数量</span>{$r.mproc_this_quantity_display|default=''|htmlentities}</div>
                 <div class="kv"><span>最高限价</span>{$r.ceilingPrice|default=''|htmlentities}</div>
-                <div class="kv"><span>单价</span>{if $r.amount_missing}<span class="kv-miss">未填写</span>{else /}{$r.amount_display|htmlentities}{/if}</div>
+                <div class="kv"><span>单价</span>{notempty name="r.amount_display"}{$r.amount_display|htmlentities}{else /}<span class="kv-miss">未填写</span>{/notempty}</div>
             </div>
         </div>
         {eq name="mprocIsRfqTab" value="0"}
         <div class="kv-row order-group-lead-row">
-            <div class="kv"><span>工期</span>{if $r.lead_days_missing}<span class="kv-miss">未填写</span>{else /}{$r.lead_days_display|htmlentities}天{/if}</div>
-            <div class="kv"><span>交货日期</span>{if $r.delivery_missing}<span class="kv-miss">未填写</span>{else /}{$r.delivery_display|htmlentities}{/if}</div>
+            <div class="kv"><span>工期</span>{notempty name="r.lead_days_display"}{$r.lead_days_display|htmlentities}天{else /}<span class="kv-miss">未填写</span>{/notempty}</div>
+            <div class="kv"><span>交货日期</span>{notempty name="r.delivery_display"}{$r.delivery_display|htmlentities}{else /}<span class="kv-miss">未填写</span>{/notempty}</div>
         </div>
+        <div class="kv order-group-remark order-group-supplier-remark"><span>投标备注</span>{$r.mproc_remark|default=''|htmlentities}</div>
         {/eq}
         {eq name="r.mproc_can_edit" value="1"}
         <div class="order-group-foot">
@@ -829,9 +888,9 @@
     {/notempty}
     {else /}
     {volist name="groups" id="g"}
-    <div class="card order-group-card js-order-group{volist name='g.lines' id='_fe'}{if $mprocFocusEid && $mprocFocusEid == $_fe.eid && ($mprocFocusTab == '' || $mprocFocusTab == $mprocTab)} mproc-card-highlight{/if}{/volist}" data-ccydh="{$g.CCYDH|default=''|htmlentities}" data-remark="{$g.remark|default=''|htmlentities}" data-delivery-deadline="{eq name='mprocIsRfqTab' value='1'}{else /}{$g.mproc_delivery_deadline|default=''|htmlentities}{/eq}" data-bid-deadline="{eq name='mprocIsRfqTab' value='1'}{else /}{$g.mproc_bid_deadline|default=''|htmlentities}{/eq}" data-bid-open="{eq name='mprocIsRfqTab' value='1'}0{else /}{$g.mproc_bid_open_verified|default=0}{/eq}" data-is-rfq="{$mprocIsRfqTab|default=0}">
+    <div class="card order-group-card js-order-group{volist name='g.lines' id='_fe'}{if $mprocFocusEid && $mprocFocusEid == $_fe.eid && ($mprocFocusTab == '' || $mprocFocusTab == $mprocTab)} mproc-card-highlight{/if}{/volist}" data-ccydh="{$g.CCYDH|default=''|htmlentities}" data-group-key="{$g.group_key|default=''|htmlentities}" data-order-remark="{$g.mproc_order_remark|default=''|htmlentities}" data-remark="{$g.remark|default=''|htmlentities}" data-delivery-deadline="{eq name='mprocIsRfqTab' value='1'}{else /}{$g.mproc_delivery_deadline|default=''|htmlentities}{/eq}" data-bid-deadline="{eq name='mprocIsRfqTab' value='1'}{else /}{$g.mproc_bid_deadline|default=''|htmlentities}{/eq}" data-bid-open="{eq name='mprocIsRfqTab' value='1'}0{else /}{$g.mproc_bid_open_verified|default=0}{/eq}" data-is-rfq="{$mprocIsRfqTab|default=0}">
         <div class="order-group-head{eq name='mprocStatusTab' value='done'}{eq name='g.mproc_pick_result' value='中标'} has-delivery-code{/eq}{/eq}">
-            <p class="title">{notempty name="g.CCYDH"}<span class="mproc-ord-no">{$g.CCYDH}</span>{/notempty}{$g.CYJMC|default=''}{eq name="mprocStatusTab" value="draft"}{eq name="mprocIsRfqTab" value="1"}<em class="mproc-pick-badge mproc-pick-unquoted">待报价</em>{else /}<em class="mproc-pick-badge mproc-pick-unquoted">未报价</em>{/eq}{/eq}{eq name="mprocStatusTab" value="submitted"}<em class="mproc-pick-badge mproc-pick-quoted">已报价</em>{/eq}{notempty name="g.mproc_done_label"}{eq name="mprocStatusTab" value="done"}<em class="mproc-pick-badge {eq name='g.mproc_pick_result' value='中标'}mproc-pick-win{else /}{eq name='g.mproc_pick_result' value='未中标'}mproc-pick-lose{else /}mproc-pick-expired{/eq}{/eq}">{$g.mproc_done_label|htmlentities}</em>{/eq}{/notempty}</p>
+            <p class="title">{notempty name="g.CCYDH"}<span class="mproc-ord-no">{$g.CCYDH}</span>{/notempty}{$g.CYJMC|default=''}{eq name="mprocStatusTab" value="draft"}{eq name="mprocIsRfqTab" value="1"}<em class="mproc-pick-badge mproc-pick-unquoted">待报价</em>{else /}<em class="mproc-pick-badge mproc-pick-unquoted">未报价</em>{/eq}{/eq}{eq name="mprocStatusTab" value="submitted"}<em class="mproc-pick-badge mproc-pick-quoted">已报价</em>{/eq}{notempty name="g.mproc_done_label"}{eq name="mprocStatusTab" value="done"}<em class="mproc-pick-badge {eq name='g.mproc_pick_result' value='中标'}mproc-pick-win{else /}{eq name='g.mproc_pick_result' value='未中标'}mproc-pick-lose{else /}{eq name='g.mproc_done_label' value='已废弃'}mproc-pick-void{else /}mproc-pick-expired{/eq}{/eq}{/eq}">{$g.mproc_done_label|htmlentities}</em>{/eq}{/notempty}</p>
             {eq name="mprocStatusTab" value="done"}{eq name="g.mproc_pick_result" value="中标"}{notempty name="g.CCYDH"}
             <a class="btn-delivery-code" href="{$mprocDeliveryNoteUrl|default=''}?ccydh={$g.CCYDH|urlencode}" data-stop="1">送货码</a>
             {/notempty}{/eq}{/eq}
@@ -840,12 +899,7 @@
                 <div class="kv"><span>招标截止日期</span>{notempty name="g.mproc_bid_deadline_display"}{$g.mproc_bid_deadline_display|htmlentities}{else /}—{/notempty}</div>
                 <div class="kv"><span>交货截止日期</span>{notempty name="g.mproc_delivery_deadline_display"}{$g.mproc_delivery_deadline_display|htmlentities}{else /}—{/notempty}</div>
             </div>
-            {notempty name="g.mproc_order_remark"}
-            <div class="kv order-group-remark"><span>订单备注</span>{$g.mproc_order_remark|htmlentities}</div>
-            {/notempty}
-            {notempty name="g.remark"}
-            <div class="kv order-group-remark"><span>备注</span>{$g.remark|htmlentities}</div>
-            {/notempty}
+            <div class="kv order-group-remark"><span>招标备注</span>{$g.mproc_order_remark|default=''|htmlentities}</div>
             {/eq}
         </div>
         {volist name="g.lines" id="r"}
@@ -864,7 +918,7 @@
             <div class="kv-row order-line-metrics">
                 <div class="kv"><span>本次数量</span>{$r.mproc_this_quantity_display|default=''|htmlentities}</div>
                 <div class="kv"><span>最高限价</span>{$r.ceilingPrice|default=''|htmlentities}</div>
-                <div class="kv"><span>单价</span>{if $r.amount_missing}<span class="kv-miss">未填写</span>{else /}{$r.amount_display|htmlentities}{/if}</div>
+                <div class="kv"><span>单价</span>{notempty name="r.amount_display"}{$r.amount_display|htmlentities}{else /}<span class="kv-miss">未填写</span>{/notempty}</div>
             </div>
         </div>
         {/volist}
@@ -873,10 +927,10 @@
         <?php
             $__leadMiss = 1; $__leadDisp = ''; $__delMiss = 1; $__delDisp = '';
             foreach ((array)$g['lines'] as $__lr) {
-                if ($__leadMiss && empty($__lr['lead_days_missing']) && (string)($__lr['lead_days_display'] ?? '') !== '') {
+                if ($__leadMiss && (string)($__lr['lead_days_display'] ?? '') !== '') {
                     $__leadMiss = 0; $__leadDisp = (string)$__lr['lead_days_display'];
                 }
-                if ($__delMiss && empty($__lr['delivery_missing']) && (string)($__lr['delivery_display'] ?? '') !== '') {
+                if ($__delMiss && (string)($__lr['delivery_display'] ?? '') !== '') {
                     $__delMiss = 0; $__delDisp = (string)$__lr['delivery_display'];
                 }
                 if (!$__leadMiss && !$__delMiss) break;
@@ -886,6 +940,7 @@
             <div class="kv"><span>工期</span>{if condition="$__leadMiss"}<span class="kv-miss">未填写</span>{else /}{$__leadDisp|htmlentities}天{/if}</div>
             <div class="kv"><span>交货日期</span>{if condition="$__delMiss"}<span class="kv-miss">未填写</span>{else /}{$__delDisp|htmlentities}{/if}</div>
         </div>
+        <div class="kv order-group-remark order-group-supplier-remark"><span>投标备注</span>{$g.remark|default=''|htmlentities}</div>
         {/eq}
         {/notempty}
         {eq name="g.can_edit" value="1"}
@@ -948,6 +1003,7 @@
 <div class="modal-mask" id="edit-mask" aria-hidden="true">
     <div class="modal-sheet" id="edit-sheet">
         <p class="modal-head" id="edit-sheet-title">填写单价/工期</p>
+        <div id="edit-order-remark" class="edit-order-remark" hidden></div>
         <div id="edit-lines-box"></div>
         <div class="modal-actions">
             <button type="button" class="btn-cancel" id="edit-cancel">取消</button>
@@ -1409,48 +1465,42 @@
     }
 
     function mprocAmountLineHtml(r) {
+        var am = pick(r, ['amount_display', 'amount']);
+        if (am !== '') {
+            return mprocEsc(am);
+        }
         var miss = parseInt(r.amount_missing, 10);
         if (miss === 1) {
             return '<span class="kv-miss">未填写</span>';
         }
-        if (miss === 0) {
-            return mprocEsc(pick(r, ['amount_display', 'amount']));
-        }
-        var am = Object.prototype.hasOwnProperty.call(r, 'amount') ? r.amount : null;
-        if (am == null || am === '' || (typeof am === 'string' && am.trim() === '')) {
-            return '<span class="kv-miss">未填写</span>';
-        }
-        return mprocEsc(pick(r, ['amount_display', 'amount']));
+        return '<span class="kv-miss">未填写</span>';
     }
 
     function mprocDeliveryLineHtml(r) {
+        var del = pick(r, ['delivery_display', 'delivery']);
+        if (del !== '' && !/^0000-00-00/i.test(del)) {
+            if (/^(\d{4}-\d{2}-\d{2})/.test(del)) {
+                del = del.match(/^(\d{4}-\d{2}-\d{2})/)[1];
+            }
+            return mprocEsc(del);
+        }
         var miss = parseInt(r.delivery_missing, 10);
         if (miss === 1) {
             return '<span class="kv-miss">未填写</span>';
         }
-        if (miss === 0) {
-            return mprocEsc(pick(r, ['delivery_display', 'delivery']));
-        }
-        var del = r.delivery != null ? String(r.delivery).trim() : '';
-        if (del === '' || /^0000-00-00/i.test(del)) {
-            return '<span class="kv-miss">未填写</span>';
-        }
-        return mprocEsc(pick(r, ['delivery_display', 'delivery']));
+        return '<span class="kv-miss">未填写</span>';
     }
 
     function mprocLeadDaysLineHtml(r) {
-        var miss = parseInt(r.lead_days_missing, 10);
-        if (miss === 1) {
-            return '<span class="kv-miss">未填写</span>';
-        }
         var d = pick(r, ['lead_days_display', 'lead_days']);
-        if (miss === 0 && d !== '') {
-            return mprocEsc(d) + '天';
+        if (d !== '') {
+            return mprocEsc(String(d)) + '天';
         }
-        if (d === '' || d == null) {
+        var miss = parseInt(r.lead_days_missing, 10);
+        if (miss === 1) {
             return '<span class="kv-miss">未填写</span>';
         }
-        return mprocEsc(String(d)) + '天';
+        return '<span class="kv-miss">未填写</span>';
     }
 
     /** 解析最高限价;有有效限价时校验金额不得超过 */
@@ -1525,6 +1575,8 @@
             cls = 'mproc-pick-win';
         } else if (pick === '未中标' || label === '未中标') {
             cls = 'mproc-pick-lose';
+        } else if (label === '已废弃') {
+            cls = 'mproc-pick-void';
         }
         return '<em class="mproc-pick-badge ' + cls + '">' + mprocEsc(label) + '</em>';
     }
@@ -1575,6 +1627,7 @@
         var hasWin = false;
         var hasLose = false;
         var hasExpired = false;
+        var hasVoid = false;
         (lines || []).forEach(function (r) {
             var pr = String(r.mproc_pick_result || '').trim();
             var dl = String(r.mproc_done_label || '').trim();
@@ -1582,10 +1635,15 @@
                 hasWin = true;
             } else if (pr === '未中标' || dl === '未中标') {
                 hasLose = true;
+            } else if (dl === '已废弃' || parseInt(r.mproc_is_void, 10) === 1) {
+                hasVoid = true;
             } else if (dl === '已截止') {
                 hasExpired = true;
             }
         });
+        if (hasVoid) {
+            return mprocPickBadgeHtml('已废弃', '');
+        }
         if (hasWin) {
             return mprocPickBadgeHtml('中标', '中标');
         }
@@ -1731,10 +1789,12 @@
         }
         var remarkAttr = ' data-remark="' + mprocEscAttr(remark || '') + '"';
         var isRfq = mprocIsRfqListTab(currentListTab);
-        var remarkHtml = isRfq ? '' : (
-            (orderRemark ? '<div class="kv order-group-remark"><span>订单备注</span>' + mprocEsc(orderRemark) + '</div>' : '')
-            + (remark ? '<div class="kv order-group-remark"><span>备注</span>' + mprocEsc(remark) + '</div>' : '')
-        );
+        var orderRemarkHtml = !isRfq
+            ? ('<div class="kv order-group-remark"><span>招标备注</span>' + mprocEsc(orderRemark || '') + '</div>')
+            : '';
+        var supplierRemarkHtml = !isRfq
+            ? ('<div class="kv order-group-remark order-group-supplier-remark"><span>投标备注</span>' + mprocEsc(remark || '') + '</div>')
+            : '';
         var deadlineHtml = isRfq ? '' : ('<div class="kv-row order-group-deadline-row">'
             + '<div class="kv"><span>招标截止日期</span>' + mprocEsc(bidDl || '—') + '</div>'
             + '<div class="kv"><span>交货截止日期</span>' + mprocEsc(delDlDisp || '—') + '</div>'
@@ -1749,20 +1809,24 @@
         var linesHtml = lines.map(function (r) {
             return renderOrderLineHtml(r);
         }).join('');
+        var groupKey = pick(g, ['group_key']);
         return '<div class="card order-group-card js-order-group' + groupHl + '"' + remarkAttr
             + ' data-ccydh="' + mprocEscAttr(ccydh) + '"'
+            + ' data-group-key="' + mprocEscAttr(groupKey) + '"'
             + ' data-delivery-deadline="' + mprocEscAttr(isRfq ? '' : (delDl || '')) + '"'
             + ' data-bid-deadline="' + mprocEscAttr(isRfq ? '' : (bidDlRaw || '')) + '"'
             + ' data-bid-open="' + (isRfq ? '0' : (bidOpen ? '1' : '0')) + '"'
-            + ' data-is-rfq="' + (isRfq ? '1' : '0') + '">'
+            + ' data-is-rfq="' + (isRfq ? '1' : '0') + '"'
+            + ' data-order-remark="' + mprocEscAttr(orderRemark || '') + '">'
             + '<div class="order-group-head' + (noteBtn ? ' has-delivery-code' : '') + '">'
             + '<p class="title">' + (ccydh ? ('<span class="mproc-ord-no">' + mprocEsc(ccydh) + '</span>') : '') + mprocEsc(tit) + badgeHtml + '</p>'
             + noteBtn
             + deadlineHtml
-            + remarkHtml
+            + orderRemarkHtml
             + '</div>'
             + linesHtml
             + mprocPickGroupLeadDeliveryHtml(lines)
+            + supplierRemarkHtml
             + (canEdit
                 ? '<div class="order-group-foot"><button type="button" class="btn-edit js-open-edit" data-stop="1">'
                     + (mprocIsRfqListTab(currentListTab) ? '填写单价' : '填写单价/工期')
@@ -1806,33 +1870,69 @@
     }
 
     var MPROC_LIST_SCROLL_KEY = 'mproc_order_list_scroll';
+    var mprocScrollSaveTimer = null;
+    var mprocScrollRestoring = false;
 
     function mprocListScrollPane() {
         return document.querySelector('.mproc-order-main');
     }
 
+    /** 记录当前列表滚动位置(刷新后回到原处) */
     function mprocSaveListScroll(href) {
+        if (mprocScrollRestoring || currentMain !== 'orders') {
+            return;
+        }
         var pane = mprocListScrollPane();
         if (!pane) {
             return;
         }
         var ccydh = '';
-        try {
-            ccydh = new URL(href, window.location.href).searchParams.get('ccydh') || '';
-        } catch (e) {
+        var groupKey = '';
+        if (href) {
+            try {
+                ccydh = new URL(href, window.location.href).searchParams.get('ccydh') || '';
+            } catch (e) {
+            }
+        }
+        // 无指定订单时:记下视口内第一张卡片,列表内容变化时仍可大致回到附近
+        if (!ccydh && listInner) {
+            var paneRect = pane.getBoundingClientRect();
+            var cards = listInner.querySelectorAll('.js-order-group[data-ccydh]');
+            for (var i = 0; i < cards.length; i++) {
+                var r = cards[i].getBoundingClientRect();
+                if (r.bottom > paneRect.top + 8 && r.top < paneRect.bottom) {
+                    ccydh = String(cards[i].getAttribute('data-ccydh') || '').trim();
+                    groupKey = String(cards[i].getAttribute('data-group-key') || '').trim();
+                    break;
+                }
+            }
         }
         try {
             sessionStorage.setItem(MPROC_LIST_SCROLL_KEY, JSON.stringify({
                 tab: currentListTab,
                 q: getSearchQ(),
                 top: pane.scrollTop || 0,
-                ccydh: String(ccydh || '')
+                ccydh: String(ccydh || ''),
+                group_key: String(groupKey || ''),
+                prefer_ccydh: href ? 1 : 0,
+                ts: Date.now()
             }));
         } catch (e2) {
         }
     }
 
-    function mprocRestoreListScroll() {
+    function mprocScheduleSaveListScroll() {
+        if (mprocScrollSaveTimer) {
+            clearTimeout(mprocScrollSaveTimer);
+        }
+        mprocScrollSaveTimer = setTimeout(function () {
+            mprocScrollSaveTimer = null;
+            mprocSaveListScroll('');
+        }, 80);
+    }
+
+    function mprocRestoreListScroll(opts) {
+        opts = opts || {};
         if (currentMain !== 'orders') {
             return;
         }
@@ -1860,28 +1960,65 @@
         if (!pane) {
             return;
         }
+        var preferCcydh = opts.preferCcydh || parseInt(st.prefer_ccydh, 10) === 1;
         var apply = function () {
-            var ccydh = String(st.ccydh || '').trim();
-            if (ccydh && listInner) {
+            mprocScrollRestoring = true;
+            try {
+                var ccydh = String(st.ccydh || '').trim();
+                var groupKey = String(st.group_key || '').trim();
                 var card = null;
-                var groups = listInner.querySelectorAll('.js-order-group');
-                for (var i = 0; i < groups.length; i++) {
-                    if (String(groups[i].getAttribute('data-ccydh') || '').trim() === ccydh) {
-                        card = groups[i];
-                        break;
+                if (preferCcydh && ccydh && listInner) {
+                    var groups = listInner.querySelectorAll('.js-order-group');
+                    for (var i = 0; i < groups.length; i++) {
+                        if (String(groups[i].getAttribute('data-ccydh') || '').trim() !== ccydh) {
+                            continue;
+                        }
+                        if (groupKey && String(groups[i].getAttribute('data-group-key') || '') === groupKey) {
+                            card = groups[i];
+                            break;
+                        }
+                        if (!card) {
+                            card = groups[i];
+                        }
+                    }
+                    if (card) {
+                        var top = card.getBoundingClientRect().top - pane.getBoundingClientRect().top + pane.scrollTop - 12;
+                        pane.scrollTop = Math.max(0, top);
+                        return;
                     }
                 }
-                if (card) {
-                    var top = card.getBoundingClientRect().top - pane.getBoundingClientRect().top + pane.scrollTop - 12;
-                    pane.scrollTop = Math.max(0, top);
-                    return;
-                }
+                var savedTop = parseInt(st.top, 10) || 0;
+                pane.scrollTop = savedTop;
+            } finally {
+                setTimeout(function () {
+                    mprocScrollRestoring = false;
+                }, 50);
             }
-            pane.scrollTop = parseInt(st.top, 10) || 0;
         };
         apply();
         setTimeout(apply, 50);
         setTimeout(apply, 220);
+        setTimeout(apply, 500);
+    }
+
+    function mprocBindListScrollPersist() {
+        var pane = mprocListScrollPane();
+        if (!pane || pane.getAttribute('data-mproc-scroll-bound') === '1') {
+            return;
+        }
+        pane.setAttribute('data-mproc-scroll-bound', '1');
+        pane.addEventListener('scroll', mprocScheduleSaveListScroll, { passive: true });
+        window.addEventListener('pagehide', function () {
+            mprocSaveListScroll('');
+        });
+        window.addEventListener('beforeunload', function () {
+            mprocSaveListScroll('');
+        });
+        document.addEventListener('visibilitychange', function () {
+            if (document.visibilityState === 'hidden') {
+                mprocSaveListScroll('');
+            }
+        });
     }
 
     /** 拉取订单列表:左侧分类 rfq=询价 / draft=报价 / submitted / done */
@@ -2065,6 +2202,7 @@
     var mask = document.getElementById('edit-mask');
     var sheet = document.getElementById('edit-sheet');
     var editLinesBox = document.getElementById('edit-lines-box');
+    var editOrderRemarkEl = document.getElementById('edit-order-remark');
     var editRemarkInp = document.getElementById('edit-remark');
     var btnSave = document.getElementById('edit-save');
     var titleEl = document.getElementById('edit-sheet-title');
@@ -2580,7 +2718,7 @@
 
     function buildEditRemarkHtml(remark) {
         return '<div class="edit-remark-wrap" id="edit-remark-wrap">'
-            + '<label for="edit-remark">备注</label>'
+            + '<label for="edit-remark">投标备注</label>'
             + '<textarea id="edit-remark" class="js-edit-remark" rows="2" maxlength="500" autocomplete="off">'
             + mprocEsc(remark || '')
             + '</textarea>'
@@ -2659,6 +2797,20 @@
         return lines;
     }
 
+    function mprocRenderEditOrderRemark(orderRemark, isRfq) {
+        if (!editOrderRemarkEl) {
+            return;
+        }
+        if (isRfq) {
+            editOrderRemarkEl.hidden = true;
+            editOrderRemarkEl.innerHTML = '';
+            return;
+        }
+        editOrderRemarkEl.hidden = false;
+        editOrderRemarkEl.innerHTML = '<span class="edit-order-remark-label">招标备注</span>'
+            + '<span class="edit-order-remark-val">' + mprocEsc(orderRemark || '') + '</span>';
+    }
+
     function openEditGroup(groupEl) {
         var lines = collectEditableLinesFromGroup(groupEl);
         if (!lines.length) {
@@ -2692,6 +2844,10 @@
         if (titleEl) {
             titleEl.textContent = head || (currentEditIsRfq ? '填写单价' : '填写单价/工期');
         }
+        var orderRemark = groupEl
+            ? String(groupEl.getAttribute('data-order-remark') || '').replace(/&quot;/g, '"')
+            : '';
+        mprocRenderEditOrderRemark(orderRemark, currentEditIsRfq);
         if (editLinesBox) {
             var groupRemark = String(groupEl.getAttribute('data-remark') || '').replace(/&quot;/g, '"');
             // 工序单价 → 工期/交期(同一行,询价跳过)→ 备注在最下
@@ -2728,6 +2884,10 @@
         currentEditDeliveryDeadline = '';
         currentEditBidDeadline = '';
         currentEditBidOpen = false;
+        if (editOrderRemarkEl) {
+            editOrderRemarkEl.hidden = true;
+            editOrderRemarkEl.innerHTML = '';
+        }
         if (editLinesBox) {
             editLinesBox.innerHTML = '';
         }
@@ -2852,8 +3012,32 @@
         listInner.addEventListener('click', function (e) {
             var noteBtn = e.target.closest('.btn-delivery-code');
             if (noteBtn) {
+                e.preventDefault();
                 e.stopPropagation();
-                mprocSaveListScroll(noteBtn.getAttribute('href') || '');
+                var href = noteBtn.getAttribute('href') || '';
+                if (!href) {
+                    return;
+                }
+                mprocSaveListScroll(href);
+                var checkUrl = href + (href.indexOf('?') >= 0 ? '&' : '?') + 'check=1';
+                fetch(checkUrl, {
+                    method: 'GET',
+                    credentials: 'same-origin',
+                    headers: mprocAuthHeaders({
+                        'X-Requested-With': 'XMLHttpRequest',
+                        'Accept': 'application/json'
+                    })
+                }).then(function (r) {
+                    return r.json();
+                }).then(function (ret) {
+                    if (ret && (ret.code === 1 || ret.code === '1')) {
+                        window.location.href = href;
+                        return;
+                    }
+                    mprocShowToast((ret && ret.msg) ? String(ret.msg) : '未找到该中标订单的送货单', 2200);
+                }).catch(function () {
+                    mprocShowToast('网络错误', 2200);
+                });
                 return;
             }
             var btn = e.target.closest('.js-open-edit');
@@ -2938,6 +3122,10 @@
         if (currentMain === 'me') {
             return false;
         }
+        // 普通刷新保留列表滚动;仅深链 focus 才强制滚过去
+        if (!mprocFocusFromDeepLink() && mprocHasSavedListScrollForCurrent()) {
+            return false;
+        }
         if (currentMain !== 'orders' && paneOrders) {
             showMain('orders');
         }
@@ -2968,6 +3156,30 @@
         return true;
     }
 
+    /** 仅短信/邮件深链才强制滚到 focus;普通刷新优先恢复用户滚动位置 */
+    function mprocFocusFromDeepLink() {
+        return mprocParseFocusEidFromSearch(window.location.search) > 0
+            || mprocParseFocusEidFromHash(window.location.hash) > 0;
+    }
+
+    function mprocHasSavedListScrollForCurrent() {
+        var raw = '';
+        try {
+            raw = sessionStorage.getItem(MPROC_LIST_SCROLL_KEY) || '';
+        } catch (e) {
+            return false;
+        }
+        if (!raw) {
+            return false;
+        }
+        try {
+            var st = JSON.parse(raw);
+            return !!(st && st.tab === currentListTab && String(st.q || '') === getSearchQ());
+        } catch (e2) {
+            return false;
+        }
+    }
+
     function mprocScheduleFocusScroll() {
         if (currentMain === 'me') {
             return;
@@ -2975,6 +3187,10 @@
         if (!mprocGetFocusEid()) {
             return;
         }
+        // 刷新后若已有列表滚动记录,不要被历史 focus_eid 拽走
+        if (!mprocFocusFromDeepLink() && mprocHasSavedListScrollForCurrent()) {
+            return;
+        }
         [0, 80, 200, 450, 900, 1500].forEach(function (ms) {
             setTimeout(mprocApplyFocusToList, ms);
         });
@@ -3038,14 +3254,21 @@
         }
         mprocSyncPageUrl();
     })();
+    mprocBindListScrollPersist();
     mprocRestoreListScroll();
     window.addEventListener('pageshow', function () {
         mprocRestoreListScroll();
     });
     mprocScheduleFocusScroll();
-    window.addEventListener('load', mprocScheduleFocusScroll);
+    window.addEventListener('load', function () {
+        mprocRestoreListScroll();
+        mprocScheduleFocusScroll();
+    });
     window.addEventListener('orientationchange', function () {
-        setTimeout(mprocScheduleFocusScroll, 300);
+        setTimeout(function () {
+            mprocRestoreListScroll();
+            mprocScheduleFocusScroll();
+        }, 300);
     });
 
     if (boot.can_change_pwd) {

+ 2 - 0
application/index/view/index/login.html

@@ -351,6 +351,8 @@
             }
             var jump = ret.url || indexUrl;
             jump = mprocEnsureUrlHasFocusEid(jump, loginRedirect);
+            // 兼容误拼出的 /index.php/index.php/...
+            jump = String(jump || '').replace(/\/index\.php\/index\.php\//gi, '/index.php/');
             var feJump = mprocExtractFocusEidFromRedirect(jump) || mprocExtractFocusEidFromRedirect(loginRedirect);
             if (feJump > 0) {
                 try {

+ 112 - 36
application/index/view/index/rfqadd.html

@@ -16,6 +16,7 @@
             --bar-h: 52px;
             --tabbar-h: 52px;
             --safe-bottom: env(safe-area-inset-bottom, 0px);
+            --phone-w: 480px;
         }
         body.layout-orders { overflow: hidden; }
         body.layout-me { overflow: hidden; }
@@ -101,7 +102,24 @@
             font-size: 15px; font-weight: 700; color: #222; line-height: 1.4; word-break: break-all;
         }
         .card .meta { margin-top: 8px; font-size: 13px; color: #555; line-height: 1.55; }
-        .card .meta b { color: #888; font-weight: 500; }
+        .card .meta > div {
+            display: flex; align-items: flex-start; gap: 8px;
+            margin: 0 0 4px;
+        }
+        .card .meta .meta-lab {
+            flex: 0 0 4.5em;
+            width: 4.5em;
+            color: #888;
+            font-weight: 500;
+            white-space: nowrap;
+        }
+        .card .meta .meta-val {
+            flex: 1 1 auto;
+            min-width: 0;
+            color: #333;
+            word-break: break-all;
+        }
+        .card .score-time { margin-top: 6px; font-size: 12px; color: #888; }
         .card .tags {
             margin-top: 8px; display: flex; flex-wrap: wrap; gap: 6px 10px;
             font-size: 12px; color: #666; align-items: center; justify-content: flex-end;
@@ -137,30 +155,51 @@
         }
         .rfq-sheet-body {
             flex: 1 1 auto; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
-            padding: 8px 12px 6px;
+            padding: 12px 14px 8px;
+        }
+        .rfq-meta {
+            margin: 0 0 10px;
+            padding-bottom: 8px;
+            border-bottom: 1px solid #f0f0f0;
+        }
+        .rfq-meta .rfq-field {
+            margin-bottom: 6px;
+            padding: 0;
+            background: transparent;
+            border: none;
+        }
+        .rfq-meta .rfq-field:last-child { margin-bottom: 0; }
+        .rfq-meta .rfq-field label { color: #666; }
+        .rfq-meta .rfq-field input[readonly] {
+            border: none; background: transparent; padding: 0; color: #222; font-size: 13px;
         }
         .rfq-field {
-            display: flex; align-items: center; gap: 8px;
-            margin-bottom: 0; padding: 7px 0;
+            display: flex; align-items: flex-start; gap: 10px;
+            margin-bottom: 10px; padding: 0;
+            background: transparent; border: none; border-radius: 0;
         }
         .rfq-field label {
-            flex: 0 0 5.6em; margin: 0; padding: 0;
-            font-size: 13px; color: #555; font-weight: 600;
-            line-height: 1.35; text-align: left;
+            flex: 0 0 6.5em; margin: 0; padding: 0;
+            font-size: 13px; color: #666; font-weight: 600;
+            line-height: 40px; text-align: left; white-space: nowrap;
+            height: 40px;
         }
         .rfq-field label .req { color: #e74c3c; margin-left: 1px; }
         .rfq-field-ctrl { flex: 1 1 auto; min-width: 0; }
         .rfq-field input,
         .rfq-field textarea {
-            width: 100%; padding: 7px 8px; border: 1px solid #ddd; border-radius: 6px;
+            width: 100%; padding: 8px 10px; border: 1px solid #ddd; border-radius: 8px;
             font-size: 14px; font-family: inherit; background: #fff; color: #333;
+            box-sizing: border-box; min-height: 40px;
         }
         .rfq-field input:focus,
         .rfq-field textarea:focus { outline: none; border-color: #3c8dbc; }
         .rfq-field input[readonly] { background: #f5f5f5; color: #555; }
         .rfq-field.rfq-field-area { align-items: flex-start; }
-        .rfq-field.rfq-field-area label { padding-top: 8px; }
-        .rfq-field textarea { resize: vertical; min-height: 56px; }
+        .rfq-field.rfq-field-area label {
+            line-height: 1.35; height: auto; padding-top: 2px;
+        }
+        .rfq-field textarea { resize: none; min-height: 72px; }
         .rfq-dept-combo { position: relative; z-index: 20; width: 100%; }
         .rfq-dept-combo .rfq-dept-row {
             display: flex; align-items: stretch; gap: 0;
@@ -276,6 +315,30 @@
         .toast.show { opacity: 1; }
         .toast.ok { background: #27ae60; }
         .toast.err { background: #c0392b; }
+        @media (min-width: 520px) {
+            body.layout-orders,
+            body.layout-me {
+                background: #e8e8e8;
+            }
+            .bar,
+            .tabbar,
+            #pane-orders,
+            #pane-me {
+                left: calc((100vw - min(100vw, var(--phone-w))) / 2);
+                right: auto;
+                width: min(100vw, var(--phone-w));
+                max-width: var(--phone-w);
+                transform: none;
+                box-shadow: 0 0 24px rgba(0, 0, 0, .08);
+            }
+            #pane-orders,
+            #pane-me {
+                background: #f5f5f5;
+            }
+            .me-panel {
+                max-width: none;
+            }
+        }
     </style>
 </head>
 <body class="layout-orders">
@@ -301,14 +364,17 @@
         <div class="card{if condition="isset($rfqFocusSid) && $rfqFocusSid && $rfqFocusSid == $row.scydgy_id"} rfq-card-highlight{/if}" data-scydgy-id="{$row.scydgy_id}">
             <div class="ord">{$row.CCYDH|default=''|htmlentities}{if $row.CYJMC} {$row.CYJMC|htmlentities}{/if}</div>
             <div class="meta">
-                <div><b>需求部门:</b>{$row.CCLBMMC|default=''|htmlentities}</div>
-                <div><b>工序:</b>{$row.CGYMC|default=''|htmlentities}</div>
-                <div><b>本次数量:</b>{$row.This_quantity|default=''|htmlentities}</div>
-                <div><b>最高限价:</b>{$row.ceilingPrice|default=''|htmlentities}</div>
-                <div><b>备注:</b>{$row.MBZ|default=''|htmlentities}</div>
-                <div><b>需求发起人:</b>{$row.cywyxm|default=''|htmlentities}</div>
-                <div><b>需求发起时间:</b>{$row.createtime|default=''|htmlentities}</div>
+                <div><span class="meta-lab">需求部门</span><span class="meta-val">{$row.CCLBMMC|default=''|htmlentities}</span></div>
+                <div><span class="meta-lab">工序名称</span><span class="meta-val">{$row.CGYMC|default=''|htmlentities}</span></div>
+                <div><span class="meta-lab">本次数量</span><span class="meta-val">{$row.This_quantity|default=''|htmlentities}</span></div>
+                <div><span class="meta-lab">最高限价</span><span class="meta-val">{$row.ceilingPrice|default=''|htmlentities}</span></div>
+                {notempty name="row.MBZ"}
+                <div><span class="meta-lab">招标备注</span><span class="meta-val">{$row.MBZ|htmlentities}</span></div>
+                {/notempty}
             </div>
+            {if condition="$row.cywyxm || $row.createtime"}
+            <div class="score-time">{notempty name="row.cywyxm"}操作人:{$row.cywyxm|htmlentities} {/notempty}{notempty name="row.createtime"}操作时间:{$row.createtime|htmlentities}{/notempty}</div>
+            {/if}
             {if condition="isset($rfqStatusTab) && $rfqStatusTab eq 'quoted'"}
             <div class="tags">
                 <button type="button" class="btn-view-quote" data-scydgy-id="{$row.scydgy_id}">查看报价</button>
@@ -346,10 +412,18 @@
             <button type="button" class="rfq-close" id="rfqClose" aria-label="关闭">&times;</button>
         </div>
         <div class="rfq-sheet-body">
-            <div class="rfq-field">
-                <label>需求编号</label>
-                <div class="rfq-field-ctrl">
-                    <input type="text" id="ccydh" value="{$nextOrderCcydh|default=''|htmlentities}" readonly>
+            <div class="rfq-meta">
+                <div class="rfq-field">
+                    <label>需求编号</label>
+                    <div class="rfq-field-ctrl">
+                        <input type="text" id="ccydh" value="{$nextOrderCcydh|default=''|htmlentities}" readonly>
+                    </div>
+                </div>
+                <div class="rfq-field">
+                    <label>需求发起人</label>
+                    <div class="rfq-field-ctrl">
+                        <input type="text" id="cywyxm" value="{$adminNickname|default=''|htmlentities}" readonly>
+                    </div>
                 </div>
             </div>
             <div class="rfq-field">
@@ -399,14 +473,8 @@
                     <input type="text" id="ceilingPrice" maxlength="50" autocomplete="off" inputmode="decimal">
                 </div>
             </div>
-            <div class="rfq-field">
-                <label>需求发起人</label>
-                <div class="rfq-field-ctrl">
-                    <input type="text" id="cywyxm" value="{$adminNickname|default=''|htmlentities}" readonly>
-                </div>
-            </div>
             <div class="rfq-field rfq-field-area">
-                <label>备注</label>
+                <label>招标备注</label>
                 <div class="rfq-field-ctrl">
                     <textarea id="mbz" maxlength="500"></textarea>
                 </div>
@@ -622,17 +690,25 @@
             else title = title || name || '';
             var sid = parseInt(row.scydgy_id, 10) || 0;
             var hit = (focusSid < 0 && sid === focusSid) ? ' rfq-card-highlight' : '';
+            var opName = String(row.cywyxm || '').trim();
+            var opTime = String(row.createtime || '').trim();
             html += '<div class="card' + hit + '" data-scydgy-id="' + esc(sid) + '">'
                 + '<div class="ord">' + esc(title) + '</div>'
                 + '<div class="meta">'
-                + '<div><b>需求部门:</b>' + esc(row.CCLBMMC || '') + '</div>'
-                + '<div><b>工序:</b>' + esc(row.CGYMC || '') + '</div>'
-                + '<div><b>本次数量:</b>' + esc(row.This_quantity || '') + '</div>'
-                + '<div><b>最高限价:</b>' + esc(row.ceilingPrice || '') + '</div>'
-                + '<div><b>备注:</b>' + esc(row.MBZ || '') + '</div>'
-                + '<div><b>需求发起人:</b>' + esc(row.cywyxm || '') + '</div>'
-                + '<div><b>需求发起时间:</b>' + esc(row.createtime || '') + '</div>'
-                + '</div>';
+                + '<div><span class="meta-lab">需求部门</span><span class="meta-val">' + esc(row.CCLBMMC || '') + '</span></div>'
+                + '<div><span class="meta-lab">工序名称</span><span class="meta-val">' + esc(row.CGYMC || '') + '</span></div>'
+                + '<div><span class="meta-lab">本次数量</span><span class="meta-val">' + esc(row.This_quantity || '') + '</span></div>'
+                + '<div><span class="meta-lab">最高限价</span><span class="meta-val">' + esc(row.ceilingPrice || '') + '</span></div>';
+            if (String(row.MBZ || '').trim()) {
+                html += '<div><span class="meta-lab">招标备注</span><span class="meta-val">' + esc(row.MBZ || '') + '</span></div>';
+            }
+            html += '</div>';
+            if (opName || opTime) {
+                html += '<div class="score-time">'
+                    + (opName ? ('操作人:' + esc(opName) + ' ') : '')
+                    + (opTime ? ('操作时间:' + esc(opTime)) : '')
+                    + '</div>';
+            }
             if (currentStatus === 'quoted') {
                 html += '<div class="tags">'
                     + '<button type="button" class="btn-view-quote" data-scydgy-id="' + esc(row.scydgy_id || '') + '">查看报价</button>'

+ 56 - 0
application/index/view/index/toast_tip.html

@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+    <title>提示</title>
+    <style>
+        * { box-sizing: border-box; }
+        html, body {
+            margin: 0; min-height: 100%;
+            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Microsoft YaHei", sans-serif;
+            background: #f5f5f5;
+        }
+        .toast {
+            position: fixed;
+            left: 50%;
+            top: 42%;
+            transform: translate(-50%, -50%);
+            z-index: 100;
+            max-width: min(86vw, 320px);
+            padding: 14px 18px;
+            border-radius: 10px;
+            background: rgba(0, 0, 0, .78);
+            color: #fff;
+            font-size: 15px;
+            line-height: 1.5;
+            text-align: center;
+            word-break: break-word;
+            box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
+        }
+    </style>
+</head>
+<body>
+<div class="toast" id="tip">{$toastMsg|default=''|htmlentities}</div>
+<script>
+(function () {
+    var msg = {:json_encode((string)$toastMsg)};
+    var url = {:json_encode((string)$redirectUrl)};
+    var wait = parseInt({:json_encode((int)$waitMs)}, 10) || 1600;
+    var el = document.getElementById('tip');
+    if (el && msg) {
+        el.textContent = msg;
+    }
+    setTimeout(function () {
+        if (url) {
+            location.replace(url);
+        } else if (window.history.length > 1) {
+            history.back();
+        } else {
+            location.replace('/');
+        }
+    }, wait);
+})();
+</script>
+</body>
+</html>

+ 256 - 149
public/assets/js/backend/procuremen.js

@@ -66,6 +66,53 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
         };
     }
 
+    /** 下发/初选:须同时有邮箱和手机号才可选 */
+    function procuremenReviewCompanySelectable(c) {
+        if (!c || typeof c !== 'object') {
+            return false;
+        }
+        if (parseInt(c.can_select, 10) === 0) {
+            return false;
+        }
+        if (parseInt(c.can_select, 10) === 1) {
+            return true;
+        }
+        var email = String(c.email || '').trim();
+        var phone = String(c.phone || '').trim();
+        return email !== '' && phone !== '';
+    }
+
+    function procuremenReviewBindCompanyCb($cb, c, selectedMap, opts) {
+        opts = opts || {};
+        $cb.data('company', c);
+        if (opts.existing) {
+            $cb.prop('disabled', true).prop('checked', true);
+            return $cb;
+        }
+        if (!procuremenReviewCompanySelectable(c)) {
+            $cb.prop('disabled', true).prop('checked', false);
+            return $cb;
+        }
+        var k = procuremenReviewCompanyKey(c);
+        if (k && selectedMap && selectedMap[k]) {
+            $cb.prop('checked', true);
+        }
+        return $cb;
+    }
+
+    function procuremenReviewSyncCompanyMaster($scope) {
+        var $root = $scope && $scope.length ? $scope : $(document);
+        var $cbs = $root.find('#review-company-tbody .review-company-cb:not(:disabled)');
+        var $master = $root.find('#review-check-all');
+        if (!$cbs.length) {
+            $master.prop('checked', false).prop('indeterminate', false);
+            return;
+        }
+        var n = $cbs.filter(':checked').length;
+        $master.prop('checked', n === $cbs.length);
+        $master.prop('indeterminate', n > 0 && n < $cbs.length);
+    }
+
     function procuremenLayerTop() {
         try {
             if (typeof top !== 'undefined' && top.Layer) {
@@ -591,7 +638,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'];
+            var auditOnlyCols = ['bid_open_status_text', 'notify_supplier_text', 'order_status_text'];
             var allOnlyCols = ['ID'];
 
             Controller.currYm = ($layout.data('defaultYm') || '').toString();
@@ -700,13 +747,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
             });
             pickedOnlyCols.forEach(function (field) {
                 try {
-                    table.bootstrapTable(stageConfirm ? 'showColumn' : 'hideColumn', field);
+                    table.bootstrapTable((stageAudit || stageConfirm) ? 'showColumn' : 'hideColumn', field);
                 } catch (ignore) {
                 }
             });
             auditOnlyCols.forEach(function (field) {
                 try {
-                    table.bootstrapTable(stageAudit ? 'showColumn' : 'hideColumn', field);
+                    table.bootstrapTable((stageAudit || stageConfirm) ? 'showColumn' : 'hideColumn', field);
                 } catch (ignore) {
                 }
             });
@@ -1051,8 +1098,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
             var indexShowall = indexInitWffTab === 'pick' || indexInitWffTab === 'audit';
             var indexShowIssued = indexInitWffTab === 'audit' || indexInitWffTab === 'confirm';
             var indexShowPendingOnly = indexInitWffTab === 'audit';
-            var indexShowPickedOnly = indexInitWffTab === 'confirm';
-            var indexShowAuditSuppliers = indexInitWffTab === 'audit';
+            var indexShowPickedOnly = indexInitWffTab === 'audit' || indexInitWffTab === 'confirm';
+            var indexShowAuditSuppliers = indexInitWffTab === 'audit' || indexInitWffTab === 'confirm';
+            var indexShowOrderStatus = indexInitWffTab === 'audit' || indexInitWffTab === 'confirm';
             function procuremenEscAttr(s) {
                 return String(s == null ? '' : s)
                     .replace(/&/g, '&amp;')
@@ -1089,8 +1137,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 var lines = raw.split('\n').map(function (s) {
                     return s.trim();
                 }).filter(Boolean);
-                if (lines.length === 1 && /[、;]/.test(lines[0])) {
-                    lines = lines[0].split(/[、;]+/).map(function (s) {
+                if (lines.length === 1 && /[、;,,]/.test(lines[0])) {
+                    lines = lines[0].split(/[、;,,]+/).map(function (s) {
                         return s.trim();
                     }).filter(Boolean);
                 }
@@ -1283,15 +1331,23 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                         '已指定供应商': '已指定供应商'
                     };
                 }
+                if (field === 'order_status_text') {
+                    return {
+                        '待确认': '待确认',
+                        '待审核': '待审核',
+                        '已审核': '已审核'
+                    };
+                }
                 var list = filterOpts && filterOpts[field] ? filterOpts[field] : {};
                 return procuremenNormalizeFilterMap(list);
             }
-            // 表头标题文字后小筛选:承揽部门 / 工序名称 / 类型 / 开标状态(确认页)
-            Controller.colFilters = {CCLBMMC: '', CGYMC: '', czlyq: '', bid_open_status_text: ''};
+            // 表头标题文字后小筛选:承揽部门 / 工序名称 / 类型 / 订单状态 / 开标状态
+            Controller.colFilters = {CCLBMMC: '', CGYMC: '', czlyq: '', order_status_text: '', bid_open_status_text: ''};
             var procuremenHeaderFilterFields = [
                 {field: 'CCLBMMC', label: '承揽部门'},
                 {field: 'CGYMC', label: '工序名称'},
                 {field: 'czlyq', label: '类型'},
+                {field: 'order_status_text', label: '订单状态'},
                 {field: 'bid_open_status_text', label: '开标状态'}
             ];
             function procuremenEscOption(s) {
@@ -1452,7 +1508,12 @@ 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, class: 'procuremen-th-sort-tight'},
+                {field: 'CCYDH', title: __('订单号'), operate: 'LIKE', table: 'b', width: 120, align: 'center', sortable: true,
+                    class: 'procuremen-th-sort-tight procuremen-supplier-lines-cell',
+                    formatter: function (v) {
+                        return procuremenSupplierLinesCell(v, this.width || 120);
+                    }
+                },
                 {field: 'CYJMC', title: __('印件名称'), operate: 'LIKE', table: 'b', width: 200, align: 'left', class: 'procuremen-cell-wrap',
                     formatter: function (v) {
                         if (v == null || v === '') {
@@ -1462,15 +1523,10 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     }
                 },
                 {field: 'CCLBMMC', title: '承揽部门', operate: '=', searchList: procuremenSearchList('CCLBMMC'), table: 'b', width: 140, align: 'center', class: 'procuremen-cell-wrap'},
-                {field: 'CGYMC', title: __('工序名称'), operate: '=', searchList: procuremenSearchList('CGYMC'), table: 'a', width: 140, align: 'left', class: 'procuremen-cell-wrap',
+                {field: 'CGYMC', title: __('工序名称'), operate: '=', searchList: procuremenSearchList('CGYMC'), table: 'a', width: 140, align: 'left',
+                    class: 'procuremen-supplier-lines-cell',
                     formatter: function (v) {
-                        if (v == null || v === '') {
-                            return '';
-                        }
-                        // 多工序用顿号间隔,换行更易读
-                        var s = String(v).replace(/[、,,]+/g, '、');
-                        return '<span style="white-space:normal;word-break:break-all;line-height:1.5;">'
-                            + procuremenEscHtml(s) + '</span>';
+                        return procuremenSupplierLinesCell(v, this.width || 140);
                     }
                 },
                 {field: 'czlyq', title: '类型', operate: '=', searchList: procuremenSearchList('czlyq'), table: 'b', width: 90, align: 'center',
@@ -1498,6 +1554,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 },
                 {field: 'This_quantity', title: '本次数量', operate: 'LIKE', table: 'a', width: 90, align: 'center',
                     visible: true,
+                    class: 'procuremen-supplier-lines-cell',
                     formatter: function (v, row, index) {
                         var tab = Controller.wffTab || 'pick';
                         if (tab === 'pick') {
@@ -1507,16 +1564,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                                 + 'data-field="This_quantity" data-row-index="' + index + '" value="'
                                 + procuremenEscAttr(val) + '" placeholder="填写" autocomplete="off"/>';
                         }
-                        if (v == null || v === '') {
-                            return '';
-                        }
-                        var s = String(v).split(/[、,,]+/).map(function (x) {
-                            return $.trim(x);
-                        }).filter(Boolean).join('、');
-                        if (!s) {
-                            return '';
-                        }
-                        return '<span style="white-space:normal;line-height:1.5;">' + procuremenEscHtml(s) + '</span>';
+                        return procuremenSupplierLinesCell(v, this.width || 90);
                     }
                 },
                 {field: 'ceilingPrice', title: '最高限价', operate: 'LIKE', table: 'a', width: 90, align: 'center',
@@ -1547,6 +1595,37 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                         return '<span style="white-space:normal;line-height:1.5;">' + procuremenEscHtml(s) + '</span>';
                     }
                 },
+                {field: 'order_status_text', title: '订单状态', operate: false, table: 'a', width: 100, align: 'center',
+                    visible: indexShowOrderStatus,
+                    formatter: function (v, row) {
+                        var t = (v != null && v !== '') ? String(v).trim() : '';
+                        if (!t) {
+                            var wf = row && row.wflow_status != null ? String(row.wflow_status).trim() : '';
+                            if (wf === '待确认' || wf === '1') {
+                                t = '待确认';
+                            } else if (wf === '待审批' || wf === '2') {
+                                t = '待审核';
+                            } else if (wf === '已审核' || wf === '3') {
+                                t = '已审核';
+                            }
+                        }
+                        if (t === '待审批') {
+                            t = '待审核';
+                        }
+                        if (!t) {
+                            return '';
+                        }
+                        var cls = 'text-muted';
+                        if (t === '待确认') {
+                            cls = 'text-warning';
+                        } else if (t === '待审核') {
+                            cls = 'text-info';
+                        } else if (t === '已审核') {
+                            cls = 'text-success';
+                        }
+                        return '<span class="' + cls + '">' + procuremenEscHtml(t) + '</span>';
+                    }
+                },
                 {field: 'bid_open_status_text', title: '开标状态', operate: false, table: 'a', width: 110, align: 'center',
                     visible: indexShowAuditSuppliers,
                     formatter: function (v, row) {
@@ -1593,7 +1672,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 {field: 'CDW', title: __('单位'), operate: 'LIKE', table: 'a', width: 88, align: 'center'},
                 {field: 'CDF', title: __('订法'), operate: 'LIKE', table: 'a', width: 90, align: 'center', class: 'procuremen-cell-wrap'},
                 {field: 'cGzzxMc', title: __('外厂单位'), operate: 'LIKE', table: 'a', width: 200, align: 'center', class: 'procuremen-cell-wrap'},
-                {field: 'MBZ', title: __('备注'), operate: 'LIKE', table: 'a', width: 240, align: 'center', class: 'procuremen-cell-wrap',
+                {field: 'MBZ', title: '招标备注', operate: 'LIKE', table: 'a', width: 240, align: 'center', class: 'procuremen-cell-wrap',
                     formatter: function (v, row, index) {
                         var tab = Controller.wffTab || 'pick';
                         if (tab === 'pick') {
@@ -1647,7 +1726,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 {field: 'dputrecord', title: __('提交日期'), operate: 'RANGE', addclass: 'datetimerange', autocomplete: false, table: 'b', width: 176, align: 'center', sortable: true, class: 'procuremen-th-sort-tight',
                     visible: indexInitWffTab === 'pick'
                 },
-                {field: 'operate',title: '操作',width: 168,align: 'center',fixed: 'right', operate: false,
+                {field: 'operate',title: '操作',width: indexInitWffTab === 'audit' ? 178 : 220,align: 'center',fixed: 'right', operate: false,
                     visible: indexInitWffTab !== 'pick',
                     table: table,
                     formatter: function (value, row, index) {
@@ -1658,26 +1737,42 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                         }
                         var areaDetails = ' data-area=\'["100%","100%"]\'';
                         var areaAudit = ' data-area=\'["98%","92%"]\'';
-                        var areaConfirmOutward = ' data-area=\'["98%","92%"]\'';
-                        var parts = [];
+                        var areaConfirmOutward = ' data-area=\'["100%","100%"]\'';
+                        var primary = '';
+                        var detail = '';
                         if (tab === 'pick') {
                             return '';
                         } else if (tab === 'audit') {
-                            if (procuremenCan('auditissue')) {
-                                parts.push('<a class="btn btn-xs btn-primary procuremen-op-open procuremen-btn-audit-issue"' + areaAudit + ' href="procuremen/auditissue" data-row-index="' + index + '" title=""><i class="fa fa-check"></i> 选择供应商</a>');
+                            var stA = row && row.order_status_text != null ? String(row.order_status_text).trim() : '';
+                            if (stA === '待审批') {
+                                stA = '待审核';
+                            }
+                            if (stA === '待确认' && procuremenCan('auditissue')) {
+                                primary = '<a class="btn btn-xs btn-primary procuremen-op-open procuremen-btn-audit-issue"' + areaAudit + ' href="procuremen/auditissue" data-row-index="' + index + '" title=""><i class="fa fa-check"></i> 选择供应商</a>';
                             }
                             if (procuremenCan('details')) {
-                                parts.push('<a class="btn btn-xs btn-info procuremen-op-open procuremen-btn-details"' + areaDetails + ' href="procuremen/details" data-row-index="' + index + '" title="详情"><i class="fa fa-file-text-o"></i> 详情</a>');
+                                detail = '<a class="btn btn-xs btn-info procuremen-op-open procuremen-btn-details"' + areaDetails + ' href="procuremen/details" data-row-index="' + index + '" title="详情"><i class="fa fa-file-text-o"></i> 详情</a>';
                             }
                         } else if (tab === 'confirm') {
-                            if (procuremenCan('outward_detail')) {
-                                parts.push('<a class="btn btn-xs btn-success procuremen-op-open procuremen-btn-outward"' + areaConfirmOutward + ' href="procuremen/outward_detail?wff_tab=confirm" data-row-index="' + index + '" title="审批"><i class="fa fa-gavel"></i> 审批</a>');
+                            var stC = row && row.order_status_text != null ? String(row.order_status_text).trim() : '';
+                            if (stC === '待审批') {
+                                stC = '待审核';
+                            }
+                            if (stC === '待审核' && procuremenCan('outward_detail')) {
+                                primary = '<a class="btn btn-xs btn-success procuremen-op-open procuremen-btn-outward"' + areaConfirmOutward + ' href="procuremen/outward_detail?wff_tab=confirm" data-row-index="' + index + '" title="审批"><i class="fa fa-gavel"></i> 审批</a>';
                             }
                             if (procuremenCan('details')) {
-                                parts.push('<a class="btn btn-xs btn-info procuremen-op-open procuremen-btn-details"' + areaDetails + ' href="procuremen/details" data-row-index="' + index + '" title="详情"><i class="fa fa-file-text-o"></i> 详情</a>');
+                                detail = '<a class="btn btn-xs btn-info procuremen-op-open procuremen-btn-details"' + areaDetails + ' href="procuremen/details" data-row-index="' + index + '" title="详情"><i class="fa fa-file-text-o"></i> 详情</a>';
                             }
                         }
-                        return '<span class="procuremen-op-btns">' + parts.join('') + '</span>';
+                        if (!primary && !detail) {
+                            return '';
+                        }
+                        // 双槽位:左侧主操作(无则占位),右侧详情固定竖线对齐;整体居中
+                        return '<span class="procuremen-op-btns">'
+                            + '<span class="procuremen-op-slot procuremen-op-slot-primary">' + (primary || '<span class="procuremen-op-slot-empty" aria-hidden="true"></span>') + '</span>'
+                            + '<span class="procuremen-op-slot procuremen-op-slot-detail">' + detail + '</span>'
+                            + '</span>';
                     },
                     events: {}
                 }
@@ -1864,6 +1959,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     $fixedRight.find('colgroup').remove();
 
                     var opW = 168;
+                    var opMin = Controller.wffTab === 'audit' ? 160 : 156;
                     var $opCell = $bt.find('.fixed-table-body table thead th[data-field="operate"]').first();
                     if (!$opCell.length) {
                         $opCell = $headerTable.find('th[data-field="operate"]').first();
@@ -1871,7 +1967,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     if ($opCell.length) {
                         var measured = $opCell.outerWidth();
                         if (measured > 0) {
-                            opW = Math.max(Math.round(measured), 156);
+                            opW = Math.max(Math.round(measured), opMin);
                         }
                     }
                     $fixedRight.css({
@@ -1935,7 +2031,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     if (res && res.filterOptions) {
                         procuremenMergeFilterOptions(res.filterOptions);
                     }
-                    if (res && $.isArray(res.sidebarYms) && res.sidebarYms.length && Controller.wffTab === 'pick') {
+                    if (res && $.isArray(res.sidebarYms) && res.sidebarYms.length && (Controller.wffTab === 'pick' || Controller.wffTab === 'audit' || Controller.wffTab === 'confirm')) {
                         procuremenRenderSidebarFromYms(res.sidebarYms);
                         var pickYm = (res.activeYm || '').toString();
                         if (!/^\d{4}-\d{2}$/.test(pickYm) || res.sidebarYms.indexOf(pickYm) < 0) {
@@ -1969,8 +2065,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                             $('.procuremen-ym-item').removeClass('active');
                             $('.procuremen-ym-item[data-ym="' + Controller.currYm + '"]').addClass('active');
                         }
-                    }
-                    if (res && res.activeYm && (Controller.wffTab === 'audit' || Controller.wffTab === 'confirm')) {
+                    } else if (res && res.activeYm && (Controller.wffTab === 'audit' || Controller.wffTab === 'confirm')) {
                         procuremenApplyActiveYm(res.activeYm);
                     }
                     if (res && typeof res === 'object' && res.msg && (res.total === 0 || !res.rows || !res.rows.length)) {
@@ -1992,9 +2087,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                         op = {};
                     }
                     if (!Controller.colFilters) {
-                        Controller.colFilters = {CCLBMMC: '', CGYMC: '', czlyq: '', bid_open_status_text: ''};
+                        Controller.colFilters = {CCLBMMC: '', CGYMC: '', czlyq: '', order_status_text: '', bid_open_status_text: ''};
                     }
-                    ['CCLBMMC', 'CGYMC', 'czlyq', 'bid_open_status_text'].forEach(function (k) {
+                    ['CCLBMMC', 'CGYMC', 'czlyq', 'order_status_text', 'bid_open_status_text'].forEach(function (k) {
                         var v = Controller.colFilters[k];
                         delete filter[k];
                         delete op[k];
@@ -2016,8 +2111,22 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
             });
 
             Table.api.bindevent(table);
-            // 避免顶栏切回本页时 addtabs 再点一次刷新(进页会连刷两次)
-            $layout.find('.btn-refresh').attr('data-force-refresh', 'false');
+            // 首屏 bootstrapTable 已拉数:短暂禁止 addtabs 再触发刷新,避免进页连刷两次。
+            // 稍后恢复,保证左侧菜单再次点击同一页时能刷新表格。
+            var $refreshBtns = $layout.find('.btn-refresh')
+                .add('#procuremen-toolbar-host .btn-refresh')
+                .add(table.closest('.bootstrap-table').find('.btn-refresh'));
+            $refreshBtns.attr('data-force-refresh', 'false');
+            var enableMenuRefresh = function () {
+                $refreshBtns = $layout.find('.btn-refresh')
+                    .add('#procuremen-toolbar-host .btn-refresh')
+                    .add(table.closest('.bootstrap-table').find('.btn-refresh'));
+                $refreshBtns.removeAttr('data-force-refresh');
+            };
+            table.one('load-success.bs.table load-error.bs.table', function () {
+                setTimeout(enableMenuRefresh, 800);
+            });
+            setTimeout(enableMenuRefresh, 2500);
             // 本页不需要「跨页选择模式」提示
             table.closest('.bootstrap-table').find('.btn-selected-tips').remove();
             $('#procuremen-toolbar-host .btn-selected-tips, #toolbar .btn-selected-tips').remove();
@@ -2237,20 +2346,17 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     Toastr.warning('请先勾选至少 1 条工序');
                     return;
                 }
-                var ccydh0 = String(selRows[0].CCYDH || '').trim();
-                if (!ccydh0) {
+                var missingCcydh = false;
+                $.each(selRows, function (i, r) {
+                    if (!String(r.CCYDH || '').trim()) {
+                        missingCcydh = true;
+                        return false;
+                    }
+                });
+                if (missingCcydh) {
                     Toastr.warning('所选行缺少订单号,无法下发');
                     return;
                 }
-                if (selRows.length > 1) {
-                    var j;
-                    for (j = 1; j < selRows.length; j++) {
-                        if (String(selRows[j].CCYDH || '').trim() !== ccydh0) {
-                            Toastr.warning('合并下发须为同一订单号(当前混有:' + ccydh0 + ' 与其它订单)');
-                            return;
-                        }
-                    }
-                }
                 var pk0 = table.bootstrapTable('getOptions').pk || 'ID';
                 var ids = [];
                 $.each(selRows, function (idx, r) {
@@ -2309,7 +2415,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     return;
                 }
                 var abandonMsg = procuremenBuildConfirmMsg(
-                    '退回初选并重新下发以下 <strong>' + idList.length + '</strong> 个订单:',
+                    '退回供应商初选并重新下发以下 <strong>' + idList.length + '</strong> 个订单:',
                     procuremenBuildConfirmRowsTable(selAb)
                 );
                 Layer.confirm(abandonMsg, $.extend({}, procuremenConfirmLayerBase, {
@@ -2746,8 +2852,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                         if (button && button.layerArea && button.layerArea.length) {
                             layerOpts.area = button.layerArea;
                         }
-                        // 审批弹窗必须大屏展示(忽略 data-area / 默认 800px)
-                        layerOpts.area = ['98%', '92%'];
+                        // 审批弹窗全屏
+                        layerOpts.area = ['100%', '100%'];
                         var winName = $a.data('window') || 'self';
                         var win = window[winName] || window;
                         if (!win.Backend || !win.Backend.api) {
@@ -2755,7 +2861,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                             return;
                         }
                         var openLayerOpts = {
-                            area: ['98%', '92%']
+                            area: ['100%', '100%']
                         };
                         if (typeof layerOpts.callback === 'function') {
                             openLayerOpts.callback = layerOpts.callback;
@@ -2877,6 +2983,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     }
                 });
             }
+
         },
 
         pick: function () {
@@ -3121,7 +3228,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 {field: 'CDW', title: '单位', operate: 'LIKE', width: 70, align: 'center', halign: 'center', valign: 'middle', class: 'procuremen-rfq-num-col'},
                 // 订法暂不展示
                 // {field: 'CDF', title: '订法', operate: 'LIKE', width: 80, align: 'center', halign: 'center', valign: 'middle', class: 'procuremen-rfq-num-col'},
-                {field: 'MBZ', title: '备注', operate: 'LIKE', width: 140, class: 'autocontent', formatter: Table.api.formatter.content},
+                {field: 'MBZ', title: '招标备注', operate: 'LIKE', width: 140, class: 'autocontent', formatter: Table.api.formatter.content},
                 {field: 'cywyxm', title: '需求发起人', operate: 'LIKE', width: 90, align: 'center', halign: 'center'},
                 {
                     field: 'createtime',
@@ -3476,7 +3583,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     + '<th class="text-center" style="width:56px;">单位</th>'
                     + '<th class="text-center" style="width:72px;">本次数量</th>'
                     + '<th class="text-center" style="width:72px;">最高限价</th>'
-                    + '<th style="width:100px;">备注</th>'
+                    + '<th style="width:100px;">招标备注</th>'
                     + '</tr></thead><tbody><tr>'
                     + '<td class="text-center">' + rfqEscHtml(ccydh) + '</td>'
                     + '<td>' + rfqEscHtml(cyjmc) + '</td>'
@@ -3748,7 +3855,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                         + '<th class="text-center" style="width:56px;">单位</th>'
                         + '<th class="text-center" style="width:72px;">本次数量</th>'
                         + '<th class="text-center" style="width:72px;">最高限价</th>'
-                        + '<th style="width:100px;">备注</th>'
+                        + '<th style="width:100px;">招标备注</th>'
                         + '</tr></thead><tbody><tr>'
                         + '<td class="text-center">' + rfqEscHtml(ccydh) + '</td>'
                         + '<td>' + rfqEscHtml(cyjmc) + '</td>'
@@ -4478,7 +4585,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
             function procuremenReviewCollectSelected() {
                 var selected = [];
                 var seen = {};
-                $('#review-company-tbody .review-company-cb:checked').each(function () {
+                $('#review-company-tbody .review-company-cb:not(:disabled):checked').each(function () {
                     var c = $(this).data('company');
                     if (!c || typeof c !== 'object') {
                         return;
@@ -4566,6 +4673,16 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 var mergePayload = ($('#c-merge-rows-json').val() || '').trim();
                 if (!mergePayload) {
                     mergePayload = JSON.stringify([cons]);
+                } else {
+                    try {
+                        var mergeListForSubmit = JSON.parse(mergePayload);
+                        if ($.isArray(mergeListForSubmit) && mergeListForSubmit.length) {
+                            mergeListForSubmit = syncProcuremenReviewMergeMbzFromUi(mergeListForSubmit);
+                            mergePayload = JSON.stringify(mergeListForSubmit);
+                            $('#c-merge-rows-json').val(mergePayload);
+                        }
+                    } catch (ignoreMergeMbz) {
+                    }
                 }
                 var $submitBtn = $('#btn-review-submit');
                 if ($submitBtn.prop('disabled')) {
@@ -4758,11 +4875,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                         }
                     });
                 }
+                var isPickModeUi = procuremenReviewIsPickMode();
                 $.each(list, function (idx, r) {
                     var qty = procuremenReviewQtyDisp(r);
                     var price = procuremenReviewPriceDisp(r);
                     var ccydh = String(r.CCYDH != null ? r.CCYDH : '').trim();
                     var cyjmc = String(r.CYJMC != null ? r.CYJMC : '').trim();
+                    var mbz = r.MBZ != null && r.MBZ !== '' ? String(r.MBZ) : '';
                     var $tr = $('<tr/>');
                     if (mergeSameOrder && idx === 0) {
                         $tr.append(
@@ -4775,27 +4894,53 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                             $('<td class="review-merge-col-name"/>').text(cyjmc)
                         );
                     }
+                    var $remarkCell = $('<td class="review-merge-col-remark"/>').text(mbz);
                     $tr.append(
                         $('<td/>').text(r.CGYMC || ''),
                         $('<td class="text-center"/>').text(r.CDW != null && r.CDW !== '' ? r.CDW : ''),
                         $('<td class="text-center"/>').text(qty),
                         $('<td class="text-center"/>').text(price),
                         $('<td class="text-center"/>').text(r.CDF || ''),
-                        $('<td class="review-merge-col-remark"/>').text(r.MBZ != null && r.MBZ !== '' ? String(r.MBZ) : '')
+                        $remarkCell
                     );
                     $tb.append($tr);
                 });
-                var isPickModeUi = procuremenReviewIsPickMode();
                 if (isPickModeUi && list.length > 1) {
+                    var orderSet = {};
+                    $.each(list, function (i, rr) {
+                        var od = String(rr.CCYDH || '').trim();
+                        if (od) {
+                            orderSet[od] = true;
+                        }
+                    });
+                    var orderCnt = 0;
+                    $.each(orderSet, function () { orderCnt++; });
+                    var tipExtra = orderCnt > 1
+                        ? ('本批含 <strong>' + orderCnt + ' 个订单</strong>、<strong>' + list.length + ' 道工序</strong>')
+                        : ('本单含 <strong>' + list.length + ' 道工序</strong>');
                     $('.procuremen-review-submit-tip').html(
                         '<i class="fa fa-exclamation-triangle"></i> '
-                        + '<strong>合并单:</strong>确认后将向所选供应商<strong>发送短信与邮件</strong>;'
-                        + '本单含 <strong>' + list.length + ' 道工序</strong>,请核对后再确认。'
+                        + '<strong>合并下发:</strong>确认后将向所选供应商<strong>发送短信与邮件</strong>;'
+                        + tipExtra + ',请核对后再确认。'
                     );
                 }
                 $('#c-merge-rows-json').val(JSON.stringify(list));
             }
 
+            function syncProcuremenReviewMergeMbzFromUi(list) {
+                if (!$.isArray(list) || !list.length) {
+                    return list;
+                }
+                $('#review-merge-tbody tr').each(function (idx) {
+                    var $inp = $(this).find('.review-merge-mbz').first();
+                    if (!$inp.length || !list[idx]) {
+                        return;
+                    }
+                    list[idx].MBZ = String($inp.val() || '').trim();
+                });
+                return list;
+            }
+
             applyProcuremenMergeReviewUi(mergeRows.length ? mergeRows : (row ? [row] : []));
 
             var isPickMode = procuremenReviewIsPickMode();
@@ -4930,26 +5075,17 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 var $tbody = $('#review-company-tbody').empty();
                 if (!list.length) {
                     $tbody.append($('<tr/>').append($('<td colspan="6" class="review-company-empty"/>').text('暂无符合条件的单位')));
-                    var $cbs0 = $('#review-company-tbody .review-company-cb');
-                    var $master0 = $('#review-check-all');
-                    if (!$cbs0.length) {
-                        $master0.prop('checked', false).prop('indeterminate', false);
-                    } else {
-                        var n0 = $cbs0.filter(':checked').length;
-                        $master0.prop('checked', n0 === $cbs0.length);
-                        $master0.prop('indeterminate', n0 > 0 && n0 < $cbs0.length);
-                    }
+                    procuremenReviewSyncCompanyMaster();
                     syncReviewSelectedSummary();
                     return;
                 }
                 $.each(list, function (i, c) {
                     var $cb = $('<input type="checkbox" class="review-company-cb"/>');
-                    $cb.data('company', c);
-                    var k = procuremenReviewCompanyKey(c);
-                    if (k && reviewSelectedMap[k]) {
-                        $cb.prop('checked', true);
-                    }
+                    procuremenReviewBindCompanyCb($cb, c, reviewSelectedMap);
                     var $tr = $('<tr/>');
+                    if (!procuremenReviewCompanySelectable(c)) {
+                        $tr.addClass('is-no-contact').attr('title', '缺少邮箱或手机号,不可选择');
+                    }
                     $tr.append($('<td class="review-td-cb"/>').append($cb));
                     $tr.append($('<td/>').text(c.name || c.company_name || ''));
                     $tr.append($('<td/>').text(c.username || ''));
@@ -4958,11 +5094,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     $tr.append($('<td/>').text((c.company_type != null && String(c.company_type).trim() !== '') ? String(c.company_type).trim() : (c.category || '')));
                     $tbody.append($tr);
                 });
-                var $cbs = $('#review-company-tbody .review-company-cb');
-                var $master = $('#review-check-all');
-                var n = $cbs.filter(':checked').length;
-                $master.prop('checked', n === $cbs.length);
-                $master.prop('indeterminate', n > 0 && n < $cbs.length);
+                procuremenReviewSyncCompanyMaster();
                 syncReviewSelectedSummary();
             });
 
@@ -5029,12 +5161,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     } else {
                         $.each(list, function (i, c) {
                             var $cb = $('<input type="checkbox" class="review-company-cb"/>');
-                            $cb.data('company', c);
-                            var k2 = procuremenReviewCompanyKey(c);
-                            if (k2 && reviewSelectedMap[k2]) {
-                                $cb.prop('checked', true);
-                            }
+                            procuremenReviewBindCompanyCb($cb, c, reviewSelectedMap);
                             var $tr = $('<tr/>');
+                            if (!procuremenReviewCompanySelectable(c)) {
+                                $tr.addClass('is-no-contact').attr('title', '缺少邮箱或手机号,不可选择');
+                            }
                             $tr.append($('<td class="review-td-cb"/>').append($cb));
                             $tr.append($('<td/>').text(c.name || c.company_name || ''));
                             $tr.append($('<td/>').text(c.username || ''));
@@ -5044,32 +5175,20 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                             $tbody2.append($tr);
                         });
                     }
-                    var $cbsS = $('#review-company-tbody .review-company-cb');
-                    var $masterS = $('#review-check-all');
-                    if (!$cbsS.length) {
-                        $masterS.prop('checked', false).prop('indeterminate', false);
-                    } else {
-                        var nS = $cbsS.filter(':checked').length;
-                        $masterS.prop('checked', nS === $cbsS.length);
-                        $masterS.prop('indeterminate', nS > 0 && nS < $cbsS.length);
-                    }
+                    procuremenReviewSyncCompanyMaster();
                     syncReviewSelectedSummary();
                 }, 160);
             });
 
             $('#review-company-tbody').off('change.reviewCb').on('change.reviewCb', '.review-company-cb', function () {
+                if ($(this).prop('disabled')) {
+                    $(this).prop('checked', false);
+                    return;
+                }
                 var c = $(this).data('company');
                 var k = procuremenReviewCompanyKey(c);
-                var $cbsC = $('#review-company-tbody .review-company-cb');
-                var $masterC = $('#review-check-all');
                 if (!k) {
-                    if (!$cbsC.length) {
-                        $masterC.prop('checked', false).prop('indeterminate', false);
-                    } else {
-                        var nC = $cbsC.filter(':checked').length;
-                        $masterC.prop('checked', nC === $cbsC.length);
-                        $masterC.prop('indeterminate', nC > 0 && nC < $cbsC.length);
-                    }
+                    procuremenReviewSyncCompanyMaster();
                     syncReviewSelectedSummary();
                     return;
                 }
@@ -5078,15 +5197,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 } else {
                     delete reviewSelectedMap[k];
                 }
-                var n2 = $cbsC.filter(':checked').length;
-                $masterC.prop('checked', n2 === $cbsC.length);
-                $masterC.prop('indeterminate', n2 > 0 && n2 < $cbsC.length);
+                procuremenReviewSyncCompanyMaster();
                 syncReviewSelectedSummary();
             });
 
             $('#review-check-all').off('change.reviewAll').on('change.reviewAll', function () {
                 var on = $(this).prop('checked');
-                $('#review-company-tbody .review-company-cb').each(function () {
+                $('#review-company-tbody .review-company-cb:not(:disabled)').each(function () {
                     $(this).prop('checked', on).trigger('change');
                 });
             });
@@ -5212,12 +5329,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     } else {
                         $.each(list, function (i, c) {
                             var $cb = $('<input type="checkbox" class="review-company-cb"/>');
-                            $cb.data('company', c);
-                            var k3 = procuremenReviewCompanyKey(c);
-                            if (k3 && reviewSelectedMap[k3]) {
-                                $cb.prop('checked', true);
-                            }
+                            procuremenReviewBindCompanyCb($cb, c, reviewSelectedMap);
                             var $tr = $('<tr/>');
+                            if (!procuremenReviewCompanySelectable(c)) {
+                                $tr.addClass('is-no-contact').attr('title', '缺少邮箱或手机号,不可选择');
+                            }
                             $tr.append($('<td class="review-td-cb"/>').append($cb));
                             $tr.append($('<td/>').text(c.name || c.company_name || ''));
                             $tr.append($('<td/>').text(c.username || ''));
@@ -5227,15 +5343,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                             $tbody.append($tr);
                         });
                     }
-                    var $cbsF = $('#review-company-tbody .review-company-cb');
-                    var $masterF = $('#review-check-all');
-                    if (!$cbsF.length) {
-                        $masterF.prop('checked', false).prop('indeterminate', false);
-                    } else {
-                        var nF = $cbsF.filter(':checked').length;
-                        $masterF.prop('checked', nF === $cbsF.length);
-                        $masterF.prop('indeterminate', nF > 0 && nF < $cbsF.length);
-                    }
+                    procuremenReviewSyncCompanyMaster();
                     syncReviewSelectedSummary();
                     procuremenPinSupplierPickerLayout();
                     return false;
@@ -5402,18 +5510,15 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 $.each(list, function (i, c) {
                     var existing = isExistingCompany(c);
                     var $cb = $('<input type="checkbox" class="review-company-cb"/>');
-                    $cb.data('company', c);
-                    if (existing) {
-                        $cb.prop('disabled', true).prop('checked', true);
-                    } else {
-                        var k = procuremenReviewCompanyKey(c);
-                        if (k && reviewSelectedMap[k]) {
-                            $cb.prop('checked', true);
-                        }
-                    }
                     var $tr = $('<tr/>');
                     if (existing) {
+                        procuremenReviewBindCompanyCb($cb, c, reviewSelectedMap, {existing: true});
                         $tr.addClass('is-existing').attr('title', '该供应商已在本单中');
+                    } else if (!procuremenReviewCompanySelectable(c)) {
+                        procuremenReviewBindCompanyCb($cb, c, reviewSelectedMap);
+                        $tr.addClass('is-no-contact').attr('title', '缺少邮箱或手机号,不可选择');
+                    } else {
+                        procuremenReviewBindCompanyCb($cb, c, reviewSelectedMap);
                     }
                     $tr.append($('<td class="review-td-cb"/>').append($cb));
                     $tr.append($('<td/>').text((c.name || c.company_name || '') + (existing ? '(已下发)' : '')));
@@ -5423,15 +5528,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     $tr.append($('<td/>').text((c.company_type != null && String(c.company_type).trim() !== '') ? String(c.company_type).trim() : (c.category || '')));
                     $tbody.append($tr);
                 });
-                var $cbs = $('#review-company-tbody .review-company-cb:not(:disabled)');
-                var $master = $('#review-check-all');
-                if (!$cbs.length) {
-                    $master.prop('checked', false).prop('indeterminate', false);
-                } else {
-                    var n = $cbs.filter(':checked').length;
-                    $master.prop('checked', n === $cbs.length);
-                    $master.prop('indeterminate', n > 0 && n < $cbs.length);
-                }
+                procuremenReviewSyncCompanyMaster();
                 syncReviewSelectedSummary();
             }
 
@@ -6469,7 +6566,17 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                             return row.to_email_masked || v || '';
                         }}, colCenter),
                         $.extend({field: 'company_name', title: '供应商', operate: 'LIKE'}, colCenter),
-                        $.extend({field: 'scene', title: '场景', operate: '=', searchList: {'pick_issue': '初选下发', 'audit_resend': '确认页重发'}, formatter: function (v, row) {
+                        $.extend({field: 'scene', title: '场景', operate: '=', searchList: {
+                            '初选下发': '初选下发',
+                            '确认页重发': '确认页重发',
+                            '确认页追加供应商': '确认页追加供应商',
+                            '确认结果通知': '确认结果通知',
+                            '确认已通过通知': '确认已通过通知',
+                            '确认未通过通知': '确认未通过通知',
+                            '询价通知业务员': '询价通知业务员',
+                            '供应商询价通知': '供应商询价通知',
+                            '交货情况通知生产部': '交货情况通知生产部'
+                        }, formatter: function (v, row) {
                             return row.scene_text || v || '';
                         }}, colCenter),
                         $.extend({field: 'mail_subject', title: '邮件主题', operate: 'LIKE', class: 'autocontent', formatter: Table.api.formatter.content}, colCenter),

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

@@ -118,7 +118,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                                 if (v.indexOf('合格') >= 0 || v.indexOf('不合格') >= 0) {
                                     return archiveCellText(v);
                                 }
-                                return '<span class="text-muted">—</span>';
+                                return '';
                             }
                         },
                         {
@@ -248,7 +248,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     return;
                 }
                 var abandonMsg = '<div style="text-align:left;line-height:1.65;font-size:13px;">'
-                    + '<p style="margin:0 0 8px 0;">即将从历史存证退回协助初选并重新下发以下 <strong>' + idList.length + '</strong> 个订单(历史记录会保留):</p>'
+                    + '<p style="margin:0 0 8px 0;">即将从历史存证退回供应商初选并重新下发以下 <strong>' + idList.length + '</strong> 个订单(历史记录会保留):</p>'
                     + rowsHtml
                     + '<p style="margin:10px 0 0;color:#a94442;"><strong>提示:</strong>退回后需重新选择供应商下发。</p></div>';
                 Layer.confirm(abandonMsg, {

Some files were not shown because too many files changed in this diff