m0_70156489 2 tygodni temu
rodzic
commit
0099413450

+ 181 - 4
application/admin/controller/Procuremen.php

@@ -3460,14 +3460,16 @@ class Procuremen extends Backend
     }
 
     /**
-     * 新下发/重新下发:同订单号下「其它有明确批次号」的未完结主单记 mod_rq 软删除。
+     * 新下发/重新下发:同订单号+同工序下「其它有明确批次号」的未完结主单记 mod_rq 软删除。
      * 不处理:本批保留行、无批次号旧数据、已完结单(避免误伤生产并行工序)。
      *
      * @param array<int, string> $ccydhs
      * @param array<int, int|string> $keepScydgyIds 保留的工序 ID(本批)
      * @param string $keepBatchNo 本批批次号(同批其它工序行也保留)
+     * @param array<int, string> $cgySet 本批工序名称集合(防止同订单不同工序被误删)
+     * @return array<int, true> 实际被软删的 scydgy_id 集合
      */
-    protected function softDeleteOtherBatchPurchaseOrders(array $ccydhs, array $keepScydgyIds = [], string $keepBatchNo = ''): void
+    protected function softDeleteOtherBatchPurchaseOrders(array $ccydhs, array $keepScydgyIds = [], string $keepBatchNo = '', array $cgySet = []): array
     {
         $ccydhList = [];
         foreach ($ccydhs as $c) {
@@ -3478,7 +3480,7 @@ class Procuremen extends Backend
         $keepBatchNo = trim($keepBatchNo);
         // 无本批批次号时不做软删,避免把同订单其它有效工序一并清掉
         if ($ccydhList === [] || $keepBatchNo === '') {
-            return;
+            return [];
         }
         $keepSid = [];
         foreach ($keepScydgyIds as $sid) {
@@ -3498,6 +3500,19 @@ class Procuremen extends Backend
                 ->whereRaw("order_batch_no <> '{$bnEsc}'")
                 // 已完结不软删
                 ->whereRaw('NOT (' . ProcuremenStatus::sqlPoCompleted('status') . ')');
+            // 按工序名称隔离,防止同订单不同工序被误删
+            if ($cgySet !== []) {
+                $cgyEscList = [];
+                foreach ($cgySet as $cgy) {
+                    $cgyEsc = str_replace(["\\", "'"], ["\\\\", "''"], trim((string)$cgy));
+                    if ($cgyEsc !== '') {
+                        $cgyEscList[] = "'" . $cgyEsc . "'";
+                    }
+                }
+                if ($cgyEscList !== []) {
+                    $q->whereRaw("CGYMC IN (" . implode(',', $cgyEscList) . ")");
+                }
+            }
             if ($keepSid !== []) {
                 $q->where('scydgy_id', 'not in', array_keys($keepSid));
             }
@@ -3506,8 +3521,18 @@ class Procuremen extends Backend
                 'manual_pick'        => 0,
                 'manual_pick_reason' => '',
             ]);
+            // 返回本次实际被软删的 scydgy_id,供调用方废弃明细用
+            return Db::table('purchase_order')
+                ->where('CCYDH', 'in', array_keys($ccydhList))
+                ->whereRaw("(mod_rq IS NULL OR mod_rq = '' OR mod_rq LIKE '0000-00-00%')")
+                ->whereRaw("TRIM(CAST(order_batch_no AS CHAR(64))) <> ''")
+                ->whereRaw("order_batch_no <> '{$bnEsc}'")
+                ->whereRaw('NOT (' . ProcuremenStatus::sqlPoCompleted('status') . ')')
+                ->where('mod_rq', $now)
+                ->column('scydgy_id');
         } catch (\Throwable $e) {
             Log::write('softDeleteOtherBatchPurchaseOrders: ' . $e->getMessage(), 'error');
+            return [];
         }
     }
 
@@ -8894,6 +8919,10 @@ class Procuremen extends Backend
         if (in_array($scene, ['confirm_ok_email', 'confirm_fail_email'], true)) {
             $this->ensureConfirmResultEmailTemplates();
         }
+        if (in_array($scene, ['review_email', 'review_sms'], true)) {
+            $this->ensureReviewEmailTemplate();
+            $this->ensureReviewSmsTemplate();
+        }
         try {
             $row = Db::table('purchase_sms_template')
                 ->where('scene', $scene)
@@ -9871,6 +9900,8 @@ class Procuremen extends Backend
         $orderTypeCtx = $this->resolveIssueNotifyOrderTypeFromBundle($bundle);
         $ctx['order_type'] = (string)($orderTypeCtx['order_type'] ?? '');
         $ctx['score_weights'] = (string)($orderTypeCtx['score_weights'] ?? '');
+        $this->ensureReviewEmailTemplate();
+        $this->ensureReviewSmsTemplate();
         $notifyBundle = $this->composeSupplierNotifyBundle($chosen, $ctx, $detailLinks, $emailTplScene);
         $notifyBundle['email_log_scene'] = $emailLogScene;
         $notifyBundle['email_log_scydgy_id'] = (int)array_key_first($sids);
@@ -10239,6 +10270,10 @@ class Procuremen extends Backend
         $orderType = '';
         $scoreWeights = '';
         $rule = null;
+        Log::write('procuremen resolveOrderType bundle: ' . json_encode([
+            'score_rule' => isset($bundle['score_rule']) ? $bundle['score_rule'] : 'NOT_SET',
+            'pos0_score_rule_id' => isset($bundle['pos'][0]['score_rule_id']) ? $bundle['pos'][0]['score_rule_id'] : 'NOT_SET',
+        ], JSON_UNESCAPED_UNICODE), 'notice');
         if (!empty($bundle['score_rule']) && is_array($bundle['score_rule'])) {
             $rule = $bundle['score_rule'];
         }
@@ -10249,8 +10284,10 @@ class Procuremen extends Backend
             if ($ruleId > 0) {
                 try {
                     $rule = ProcuremenSupplierScore::getRuleById($ruleId);
+                    Log::write('procuremen resolveOrderType via pos ruleId=' . $ruleId . ' result: ' . json_encode($rule, JSON_UNESCAPED_UNICODE), 'notice');
                 } catch (\Throwable $e) {
                     $rule = null;
+                    Log::write('procuremen resolveOrderType getRuleById exception: ' . $e->getMessage(), 'error');
                 }
             }
             if (!is_array($rule) || (int)($rule['id'] ?? 0) <= 0) {
@@ -10274,6 +10311,7 @@ class Procuremen extends Backend
         if ($orderType === '' && is_array($po0)) {
             $orderType = trim((string)($po0['score_rule_name'] ?? ''));
         }
+        Log::write('procuremen resolveOrderType result: orderType=' . $orderType . ', scoreWeights=' . $scoreWeights, 'notice');
 
         return [
             'order_type'    => $orderType,
@@ -10804,6 +10842,127 @@ class Procuremen extends Backend
         }
     }
 
+    /**
+     * 确保「协助下发-邮箱」模版存在(含 {order_type};可在短信模版配置中修改)
+     */
+    protected function ensureReviewEmailTemplate(): void
+    {
+        static $done = false;
+        if ($done) {
+            return;
+        }
+        $done = true;
+        $content = "您好,{company_name}:\n\n"
+            . "您有新的协助加工订单,请登录平台查看并报价。\n\n"
+            . "需求编号:{ccydh}\n"
+            . "印件名称:{cyjmc}\n"
+            . "业务分类:{category}\n"
+            . "订单类型:{order_type}\n"
+            . "{process_lines}\n\n"
+            . "请在 {deadline} 前完成报价。\n\n"
+            . "平台链接:{platform_url}\n";
+        try {
+            $row = Db::table('purchase_sms_template')
+                ->where('scene', 'review_email')
+                ->find();
+        } catch (\Throwable $e) {
+            return;
+        }
+        $now = date('Y-m-d H:i:s');
+        if (is_array($row) && $row !== []) {
+            return;
+        }
+        try {
+            $data = [
+                'scene'   => 'review_email',
+                'title'   => '协助加工订单通知',
+                'content' => $content,
+                'remark'  => '协助下发-邮箱;可在短信模版配置中修改',
+                'status'  => 1,
+            ];
+            $cols = Db::query("SHOW COLUMNS FROM `purchase_sms_template`");
+            $colNames = [];
+            foreach ($cols as $c) {
+                if (!is_array($c)) {
+                    continue;
+                }
+                $n = (string)($c['Field'] ?? $c['field'] ?? '');
+                if ($n !== '') {
+                    $colNames[$n] = true;
+                }
+            }
+            if (isset($colNames['updatetime'])) {
+                $data['updatetime'] = $now;
+            }
+            if (isset($colNames['createtime'])) {
+                $data['createtime'] = $now;
+            }
+            Db::table('purchase_sms_template')->insert($data);
+        } catch (\Throwable $e) {
+            // ignore
+        }
+    }
+
+    /**
+     * 确保「协助下发-短信」模版存在(含 {order_type};可在短信模版配置中修改)
+     */
+    protected function ensureReviewSmsTemplate(): void
+    {
+        static $done = false;
+        if ($done) {
+            return;
+        }
+        $done = true;
+        $content = "您好,{company_name}:\n\n"
+            . "您有新的协助加工订单,请登录平台查看并报价。\n\n"
+            . "需求编号:{ccydh}\n"
+            . "印件名称:{cyjmc}\n"
+            . "订单类型:{order_type}\n"
+            . "{process_lines}\n\n"
+            . "请在 {deadline} 前完成报价。\n\n"
+            . "平台链接:{platform_url}\n";
+        try {
+            $row = Db::table('purchase_sms_template')
+                ->where('scene', 'review_sms')
+                ->find();
+        } catch (\Throwable $e) {
+            return;
+        }
+        $now = date('Y-m-d H:i:s');
+        if (is_array($row) && $row !== []) {
+            return;
+        }
+        try {
+            $data = [
+                'scene'   => 'review_sms',
+                'title'   => '协助加工订单通知',
+                'content' => $content,
+                'remark'  => '协助下发-短信;可在短信模版配置中修改',
+                'status'  => 1,
+            ];
+            $cols = Db::query("SHOW COLUMNS FROM `purchase_sms_template`");
+            $colNames = [];
+            foreach ($cols as $c) {
+                if (!is_array($c)) {
+                    continue;
+                }
+                $n = (string)($c['Field'] ?? $c['field'] ?? '');
+                if ($n !== '') {
+                    $colNames[$n] = true;
+                }
+            }
+            if (isset($colNames['updatetime'])) {
+                $data['updatetime'] = $now;
+            }
+            if (isset($colNames['createtime'])) {
+                $data['createtime'] = $now;
+            }
+            Db::table('purchase_sms_template')->insert($data);
+        } catch (\Throwable $e) {
+            // ignore
+        }
+    }
+
     /**
      * 确保「供应商询价通知」邮箱模版存在(查询询价-询价/发邮件;可在短信模版配置中修改)
      */
@@ -14554,6 +14713,7 @@ class Procuremen extends Backend
         // 重新下发后需重新开标;清掉本批按订单号/批次号记录的开标验证
         $ccydhSet = [];
         $batchSet = [];
+        $cgySet = [];
         foreach ($pos as $poRow) {
             if (!is_array($poRow)) {
                 continue;
@@ -14565,6 +14725,10 @@ class Procuremen extends Backend
             if ($bn !== '') {
                 $batchSet[$bn] = true;
             }
+            $cgy = trim((string)($poRow['CGYMC'] ?? ''));
+            if ($cgy !== '') {
+                $cgySet[$cgy] = true;
+            }
         }
         $this->clearProcuremenBidOpenRecords(array_keys($ccydhSet), array_keys($batchSet));
         $this->clearProcuremenSupplierScoresForCcydhs(array_keys($ccydhSet));
@@ -14574,8 +14738,21 @@ class Procuremen extends Backend
             $batchKeys = array_keys($batchSet);
             $keepBatch = (string)reset($batchKeys);
         }
-        $this->softDeleteOtherBatchPurchaseOrders(array_keys($ccydhSet), array_keys($sids), $keepBatch);
+        // 返回被软删的旧批次 scydgy_id,用于废弃其明细
+        $voidedSids = $this->softDeleteOtherBatchPurchaseOrders(array_keys($ccydhSet), array_keys($sids), $keepBatch, array_keys($cgySet));
+        // 废弃本批次新工序的明细(重新下发后重新招标)
         $this->voidPurchaseOrderDetailsForScydgyIds(array_keys($sids));
+        // 废弃被软删旧批次的明细(防止卡在"已提交"状态)
+        if ($voidedSids !== []) {
+            $this->voidPurchaseOrderDetailsForScydgyIds($voidedSids);
+            // 旧批次被重新下发流程软删,记录日志便于追溯
+            foreach ($voidedSids as $oldSid) {
+                $oldSidInt = (int)$oldSid;
+                if ($this->isValidScydgyRowId($oldSidInt)) {
+                    $this->addOrderLog($oldSidInt, $logAction, '重新下发:同批次工序旧数据软删', null);
+                }
+            }
+        }
 
         foreach (array_keys($sids) as $sid) {
             $poIdLog = (int)($poIdBySid[$sid] ?? 0);

+ 2 - 2
application/admin/model/Purchasesmstemplate.php

@@ -95,8 +95,8 @@ class Purchasesmstemplate extends Model
             ['tag' => '{deadline}', 'label' => '截止时间', 'example' => '2026-05-18 14:30', 'scenes' => '协助下发/供应商询价'],
             ['tag' => '{process_lines}', 'label' => '订单工序明细(文本)', 'example' => "订单号:202605732S\n印件名称:越剧唱腔\n工序名称:数字打包 单位:册 本次数量:40\n工序名称:数字平张单色 单位:P 本次数量:200\n\n订单号:202605713S\n印件名称:……\n工序名称:数字平张单色 单位:P 本次数量:100", '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' => '{order_type}', 'label' => '订单类型', 'example' => '普通订单(价格优先)', 'scenes' => '协助下发邮箱/短信'],
+            ['tag' => '{score_weights}', 'label' => '评分比例', 'example' => '质量30%、价格50%、交货20%', 'scenes' => '协助下发邮箱/短信'],
             ['tag' => '{platform_url}', 'label' => '平台链接', 'example' => 'https://…', 'scenes' => '协助下发/供应商询价/业务员询价/采购确认/交货通知邮箱'],
         ];
     }

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

@@ -1,32 +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>
+<!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>

+ 9 - 1
application/common/library/ProcuremenSupplierScore.php

@@ -3180,7 +3180,15 @@ class ProcuremenSupplierScore
         }
         $now = date('Y-m-d H:i:s');
         try {
-            Db::table(self::TABLE_SCORE)->where('ccydh', $ccydh)->delete();
+            // 只删除当前批次的旧数据,保留同订单其他批次的分数(重新下发只清当前批)
+            $delQuery = Db::table(self::TABLE_SCORE)->where('ccydh', $ccydh);
+            if ($orderBatchNo !== '') {
+                $delQuery->where('order_batch_no', $orderBatchNo);
+            } else {
+                // 无批次号时只删无批次记录(兜底)
+                $delQuery->where('order_batch_no', '');
+            }
+            $delQuery->delete();
             $rows = [];
             foreach ($calc as $it) {
                 $rows[] = [

+ 3 - 1
application/index/controller/Index.php

@@ -1318,7 +1318,7 @@ class Index extends Frontend
         $idCol = isset($map['id']) ? $map['id'] : 'id';
 
         $poSidList = [];
-        $poWant = ['CCYDH', 'CYJMC', 'CDXMC', 'CGYMC', 'cGzzxMc', 'CDF'];
+        $poWant = ['CCYDH', 'CYJMC', 'CDXMC', 'CGYMC', 'cGzzxMc', 'CDF', 'score_rule_name'];
         try {
             $col = Db::table('purchase_order')
                 ->where(function ($sub) use ($like, $poWant) {
@@ -1652,6 +1652,7 @@ class Index extends Frontend
             'ngzl'      => 'NGZL',
             'cdw'       => 'CDW',
             'cgybh'     => 'CGYBH',
+            'score_rule_name' => 'score_rule_name',
         ];
         foreach ($hdr as $lk => $out) {
             if (!array_key_exists($lk, $pl)) {
@@ -2215,6 +2216,7 @@ class Index extends Frontend
                     'CCYDH'                            => $ccydh,
                     'CYJMC'                            => trim((string)($row['CYJMC'] ?? '')),
                     'company_name'                     => $cname,
+                    'score_rule_name'                  => trim((string)($row['score_rule_name'] ?? '')),
                     'mproc_bid_deadline_display'       => trim((string)($row['mproc_bid_deadline_display'] ?? '')),
                     'mproc_bid_deadline'               => trim((string)($row['mproc_bid_deadline'] ?? '')),
                     'mproc_delivery_deadline_display'  => trim((string)($row['mproc_delivery_deadline_display'] ?? '')),

+ 51 - 6
application/index/view/index/index.html

@@ -132,7 +132,7 @@
         .mproc-order-main .list { padding: 10px 10px 12px; }
         .card { background: #fff; border-radius: 10px; padding: 12px 12px 10px; margin-bottom: 10px; box-shadow: 0 1px 4px rgba(0,0,0,.06); }
         .order-group-card { padding-bottom: 4px; }
-        .order-group-head { margin-bottom: 8px; padding-bottom: 8px; position: relative; border-bottom: 1px dashed #e5e5e5; }
+        .order-group-head { margin-bottom: 8px; padding-bottom: 4px; position: relative; border-bottom: 1px dashed #e5e5e5; }
         .order-group-head .title {
             margin: 0 0 6px;
             padding-right: 64px;
@@ -141,6 +141,27 @@
         .order-group-head .mproc-ord-no {
             margin-right: 0.5em;
         }
+        .order-group-head .mproc-order-type-tag {
+            color: #e74c3c;
+            font-weight: bold;
+            display: block;
+            margin: 6px 0 4px;
+            font-size: 0.9em;
+            line-height: 1.4;
+        }
+        .edit-sheet-order-type {
+            margin: -8px 0 12px;
+            font-size: 13px;
+        }
+        .edit-sheet-order-type .mproc-order-type-tag {
+            color: #e74c3c;
+            font-weight: bold;
+            display: inline-block;
+        }
+
+        .order-group-head > .kv-row {
+            margin-top: 8px;
+        }
         .order-group-deadline-row {
             display: flex;
             flex-direction: column;
@@ -885,9 +906,10 @@
     {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-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="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-type="{$r.score_rule_name|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>
+            {notempty name="r.score_rule_name"}<span class="mproc-order-type-tag">{$r.score_rule_name}</span>{/notempty}
             {eq name="mprocStatusTab" value="done"}{eq name="r.mproc_pick_result" value="中标"}{notempty name="r.CCYDH"}
             <a class="btn-delivery-code" href="{$mprocDeliveryNoteUrl|default=''}?ccydh={$r.CCYDH|urlencode}" data-stop="1">送货码</a>
             {/notempty}{/eq}{/eq}
@@ -936,9 +958,10 @@
     {/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-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="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-type="{$g.score_rule_name|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 /}{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>
+            {notempty name="g.score_rule_name"}<span class="mproc-order-type-tag">{$g.score_rule_name}</span>{/notempty}
             {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}
@@ -1051,6 +1074,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-sheet-order-type" class="edit-sheet-order-type" hidden></div>
         <div id="edit-order-deadlines" class="edit-order-deadlines" hidden></div>
         <div id="edit-order-remark" class="edit-order-remark" hidden></div>
         <div id="edit-lines-box"></div>
@@ -1855,13 +1879,16 @@
         var groupHl = shouldFocus && lines.some(function (r) {
             return (parseInt(r.eid, 10) || 0) === focusEid;
         }) ? ' mproc-card-highlight' : '';
+        var orderType = pick(g, ['score_rule_name', 'mproc_order_type']);
         var linesHtml = lines.map(function (r) {
             return renderOrderLineHtml(r);
         }).join('');
         var groupKey = pick(g, ['group_key']);
+        var orderTypeHtml = orderType ? ('<span class="mproc-order-type-tag">' + mprocEsc(orderType) + '</span>') : '';
         return '<div class="card order-group-card js-order-group' + groupHl + '"' + remarkAttr
             + ' data-ccydh="' + mprocEscAttr(ccydh) + '"'
             + ' data-group-key="' + mprocEscAttr(groupKey) + '"'
+            + ' data-order-type="' + mprocEscAttr(orderType || '') + '"'
             + ' data-delivery-deadline="' + mprocEscAttr(isRfq ? '' : (delDl || '')) + '"'
             + ' data-bid-deadline="' + mprocEscAttr(isRfq ? '' : (bidDlRaw || '')) + '"'
             + ' data-bid-open="' + (isRfq ? '0' : (bidOpen ? '1' : '0')) + '"'
@@ -1869,6 +1896,7 @@
             + ' 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>'
+            + orderTypeHtml
             + noteBtn
             + deadlineHtml
             + orderRemarkHtml
@@ -1888,9 +1916,10 @@
         var focusEid = mprocGetFocusEid();
         var focusTab = boot.focus_tab || '';
         if (groups && groups.length) {
-            return groups.map(function (g) {
+            var out = groups.map(function (g) {
                 return renderOrderGroupHtml(g, focusEid, focusTab);
             }).join('');
+            return out;
         }
         if (!rows || !rows.length) {
             if (doneNoStatus) {
@@ -2252,6 +2281,7 @@
     var sheet = document.getElementById('edit-sheet');
     var editLinesBox = document.getElementById('edit-lines-box');
     var editOrderRemarkEl = document.getElementById('edit-order-remark');
+    var editSheetOrderTypeEl = document.getElementById('edit-sheet-order-type');
     var editRemarkInp = document.getElementById('edit-remark');
     var btnSave = document.getElementById('edit-save');
     var titleEl = document.getElementById('edit-sheet-title');
@@ -2743,8 +2773,8 @@
         var amt = mprocSanitizeAmountValue(line.amount || '');
         var qtyText = String(line.qty == null ? '' : line.qty).trim();
         var ceilText = String(line.ceiling == null ? '' : line.ceiling).trim();
-        var qtyShow = qtyText !== '' ? qtyText : '—';
-        var ceilShow = ceilText !== '' ? ceilText : '—';
+        var qtyShow = qtyText !== '' ? qtyText : '';
+        var ceilShow = ceilText !== '' ? ceilText : '';
         return '<div class="edit-line-block" data-id="' + mprocEscAttr(String(line.id)) + '" data-ceiling="' + mprocEscAttr(ceilText) + '">'
             + '<div class="edit-line-head-row">'
             + '<p class="edit-line-head">' + mprocEsc(line.gymc || '工序') + '</p>'
@@ -2925,6 +2955,17 @@
         if (titleEl) {
             titleEl.textContent = head || (currentEditIsRfq ? '填写单价' : '填写单价/工期');
         }
+        // 显示订单类型标签
+        var orderType = groupEl ? String(groupEl.getAttribute('data-order-type') || '').trim() : '';
+        if (editSheetOrderTypeEl) {
+            if (orderType) {
+                editSheetOrderTypeEl.innerHTML = '<span class="mproc-order-type-tag">' + mprocEsc(orderType) + '</span>';
+                editSheetOrderTypeEl.hidden = false;
+            } else {
+                editSheetOrderTypeEl.innerHTML = '';
+                editSheetOrderTypeEl.hidden = true;
+            }
+        }
         var orderRemark = groupEl
             ? String(groupEl.getAttribute('data-order-remark') || '').replace(/&quot;/g, '"')
             : '';
@@ -2970,6 +3011,10 @@
             editOrderRemarkEl.hidden = true;
             editOrderRemarkEl.innerHTML = '';
         }
+        if (editSheetOrderTypeEl) {
+            editSheetOrderTypeEl.innerHTML = '';
+            editSheetOrderTypeEl.hidden = true;
+        }
         if (editLinesBox) {
             editLinesBox.innerHTML = '';
         }

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

@@ -1,56 +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>
+<!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>