m0_70156489 1 săptămână în urmă
părinte
comite
6481512137

+ 39 - 10
application/admin/view/procuremen/audit_issue.html

@@ -98,13 +98,37 @@
     }
     .audit-issue-wrap .audit-deadline-input-wrap {
         position: relative;
-        flex: 0 0 auto;
+        flex: 1 1 auto;
+        min-width: 0;
         z-index: 62;
     }
-    .audit-issue-wrap .audit-sys-rq-input {
-        width: 240px;
-        max-width: 240px;
-        min-width: 180px;
+    .audit-issue-wrap .procuremen-sys-rq-split .procuremen-sys-rq-fields {
+        display: flex;
+        flex-wrap: wrap;
+        align-items: center;
+        gap: 8px;
+    }
+    .audit-issue-wrap .procuremen-sys-rq-split .procuremen-sys-rq-date {
+        width: 148px;
+        min-width: 132px;
+        height: 32px;
+        padding: 4px 8px;
+    }
+    .audit-issue-wrap .procuremen-sys-rq-split .procuremen-sys-rq-time-group {
+        display: inline-flex;
+        align-items: center;
+        gap: 4px;
+    }
+    .audit-issue-wrap .procuremen-sys-rq-split .procuremen-sys-rq-hour,
+    .audit-issue-wrap .procuremen-sys-rq-split .procuremen-sys-rq-minute {
+        width: 62px;
+        height: 32px;
+        padding: 4px 6px;
+    }
+    .audit-issue-wrap .procuremen-sys-rq-split .procuremen-sys-rq-colon {
+        color: #666;
+        font-weight: 600;
+        line-height: 32px;
     }
     .audit-issue-wrap .audit-op-cell {
         white-space: nowrap;
@@ -165,11 +189,16 @@
         <input type="hidden" id="audit-quote-groups-json" value="{$quoteGroupsJson|htmlentities}"/>
         <div class="audit-deadline-row">
             <span class="audit-field-label">截止时间:<span class="text-danger">*</span></span>
-            <div class="audit-deadline-input-wrap">
-                <input type="text" id="audit-sys-rq" name="sys_rq" class="form-control datetimepicker audit-sys-rq-input"
-                       value="{$sysRq|default=''|htmlentities}"
-                       data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true"
-                       placeholder="请选择年月日时分" autocomplete="off"/>
+            <div class="audit-deadline-input-wrap procuremen-sys-rq-split" id="audit-sys-rq-wrap">
+                <input type="hidden" id="audit-sys-rq" name="sys_rq" value="{$sysRq|default=''|htmlentities}"/>
+                <div class="procuremen-sys-rq-fields">
+                    <input type="date" class="form-control procuremen-sys-rq-date" title="截止日期"/>
+                    <div class="procuremen-sys-rq-time-group">
+                        <select class="form-control procuremen-sys-rq-hour" title="时"></select>
+                        <span class="procuremen-sys-rq-colon">:</span>
+                        <select class="form-control procuremen-sys-rq-minute" title="分"></select>
+                    </div>
+                </div>
             </div>
         </div>
     </form>

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

@@ -147,13 +147,37 @@
     }
     .review-deadline-input-wrap {
         position: relative;
-        flex: 0 0 auto;
+        flex: 1 1 auto;
+        min-width: 0;
         z-index: 62;
     }
-    .review-deadline-row .review-sys-rq-input {
-        width: 240px;
-        max-width: 240px;
-        min-width: 180px;
+    .procuremen-sys-rq-split .procuremen-sys-rq-fields {
+        display: flex;
+        flex-wrap: wrap;
+        align-items: center;
+        gap: 8px;
+    }
+    .procuremen-sys-rq-split .procuremen-sys-rq-date {
+        width: 148px;
+        min-width: 132px;
+        height: 32px;
+        padding: 4px 8px;
+    }
+    .procuremen-sys-rq-split .procuremen-sys-rq-time-group {
+        display: inline-flex;
+        align-items: center;
+        gap: 4px;
+    }
+    .procuremen-sys-rq-split .procuremen-sys-rq-hour,
+    .procuremen-sys-rq-split .procuremen-sys-rq-minute {
+        width: 62px;
+        height: 32px;
+        padding: 4px 6px;
+    }
+    .procuremen-sys-rq-split .procuremen-sys-rq-colon {
+        color: #666;
+        font-weight: 600;
+        line-height: 32px;
     }
     /* 截止时间日历:浮在弹窗最上层,不占文档流 */
     body.is-dialog .bootstrap-datetimepicker-widget.dropdown-menu {
@@ -515,10 +539,16 @@
             </div>
             <div class="review-deadline-row">
                 <span class="review-field-label">截止时间:<span class="text-danger">*</span></span>
-                <div class="review-deadline-input-wrap">
-                    <input type="text" id="review-sys-rq" name="sys_rq" class="form-control datetimepicker review-sys-rq-input"
-                           data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true"
-                           placeholder="请选择年月日时分" autocomplete="off" required="required"/>
+                <div class="review-deadline-input-wrap procuremen-sys-rq-split" id="review-sys-rq-wrap">
+                    <input type="hidden" id="review-sys-rq" name="sys_rq" value=""/>
+                    <div class="procuremen-sys-rq-fields">
+                        <input type="date" class="form-control procuremen-sys-rq-date" title="截止日期"/>
+                        <div class="procuremen-sys-rq-time-group">
+                            <select class="form-control procuremen-sys-rq-hour" title="时"></select>
+                            <span class="procuremen-sys-rq-colon">:</span>
+                            <select class="form-control procuremen-sys-rq-minute" title="分"></select>
+                        </div>
+                    </div>
                 </div>
             </div>
         </div>

+ 95 - 100
public/assets/js/backend/procuremen.js

@@ -139,90 +139,97 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
         setTimeout(place, 80);
     }
 
-    /** 截止时间:显式初始化日历(Layer 弹窗内浮层定位,不依赖 Form.bindevent 异步时机) */
-    function procuremenBindSysRqPicker(inputSelector, eventNs) {
-        require(['bootstrap-datetimepicker'], function () {
-            var $el = $(inputSelector);
-            if (!$el.length) {
-                return;
+    function procuremenPad2(n) {
+        n = parseInt(n, 10) || 0;
+        return (n < 10 ? '0' : '') + n;
+    }
+
+    function procuremenDefaultSysRqValue() {
+        if (typeof moment === 'function') {
+            return moment().format('YYYY-MM-DD HH:mm:ss');
+        }
+        var d = new Date();
+        return d.getFullYear() + '-' + procuremenPad2(d.getMonth() + 1) + '-' + procuremenPad2(d.getDate())
+            + ' ' + procuremenPad2(d.getHours()) + ':' + procuremenPad2(d.getMinutes()) + ':00';
+    }
+
+    function procuremenNormalizeSysRqValue(val) {
+        val = (val || '').trim();
+        if (/^\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}/.test(val)) {
+            if (!/:\d{2}$/.test(val)) {
+                val += ':00';
             }
-            var options = {
-                format: ($el.data('date-format') || 'YYYY-MM-DD HH:mm:ss'),
-                icons: {
-                    time: 'fa fa-clock-o',
-                    date: 'fa fa-calendar',
-                    up: 'fa fa-chevron-up',
-                    down: 'fa fa-chevron-down',
-                    previous: 'fa fa-chevron-left',
-                    next: 'fa fa-chevron-right',
-                    today: 'fa fa-history',
-                    clear: 'fa fa-trash',
-                    close: 'fa fa-remove'
-                },
-                showTodayButton: true,
-                showClose: true
-            };
-            if ($el.data('DateTimePicker')) {
-                try {
-                    $el.data('DateTimePicker').destroy();
-                } catch (ignoreDestroy) {
-                }
+            return val.replace(/^(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2})(:\d{2})?$/, function (m, head, sec) {
+                return head + (sec || ':00');
+            });
+        }
+        return procuremenDefaultSysRqValue();
+    }
+
+    /** 截止时间:日期 + 时下拉 + 分下拉 + 快捷按钮(替代整段 datetimepicker) */
+    function procuremenInitSysRqSplit($wrap, eventNs) {
+        if (!$wrap || !$wrap.length) {
+            return;
+        }
+        var $hidden = $wrap.find('input[type="hidden"][id$="-sys-rq"]');
+        var $date = $wrap.find('.procuremen-sys-rq-date');
+        var $hour = $wrap.find('.procuremen-sys-rq-hour');
+        var $minute = $wrap.find('.procuremen-sys-rq-minute');
+        if (!$hidden.length || !$date.length || !$hour.length || !$minute.length) {
+            return;
+        }
+
+        if (!$hour.children().length) {
+            var h, m;
+            for (h = 0; h < 24; h++) {
+                $hour.append($('<option>').val(procuremenPad2(h)).text(procuremenPad2(h)));
+            }
+            for (m = 0; m < 60; m++) {
+                $minute.append($('<option>').val(procuremenPad2(m)).text(procuremenPad2(m)));
             }
-            $el.parent().css('position', 'relative');
-            $el.datetimepicker(options);
+        }
 
-            var placePickerBesideInput = function () {
-                var picker = $el.data('DateTimePicker');
-                if (!picker || !picker.widget) {
-                    return;
-                }
-                var $w = picker.widget;
-                var rect = $el[0].getBoundingClientRect();
-                var gap = 12;
-                var top = rect.top;
-                var left = rect.right + gap;
-                var widgetW = $w.outerWidth() || 300;
-                var widgetH = $w.outerHeight() || 320;
-                var vw = window.innerWidth || document.documentElement.clientWidth;
-                var vh = window.innerHeight || document.documentElement.clientHeight;
-                if (left + widgetW > vw - 8) {
-                    left = Math.max(8, rect.left);
-                    top = rect.bottom + 6;
-                }
-                if (top + widgetH > vh - 8) {
-                    top = Math.max(8, rect.top - widgetH - 6);
-                }
-                $w.appendTo(document.body).css({
-                    position: 'fixed',
-                    top: top + 'px',
-                    left: left + 'px',
-                    right: 'auto',
-                    bottom: 'auto',
-                    display: 'block',
-                    margin: 0
-                });
-            };
-            var showPicker = function () {
-                var picker = $el.data('DateTimePicker');
-                if (picker) {
-                    picker.show();
-                }
-            };
-            $el.off('dp.show.' + eventNs + ' dp.update.' + eventNs + ' focus.' + eventNs + ' click.' + eventNs)
-                .on('dp.show.' + eventNs + ' dp.update.' + eventNs, function () {
-                    setTimeout(placePickerBesideInput, 0);
-                })
-                .on('focus.' + eventNs + ' click.' + eventNs, function () {
-                    showPicker();
-                });
-            $el.closest('.audit-deadline-input-wrap, .review-deadline-input-wrap')
-                .find('.procuremen-sys-rq-addon')
-                .off('click.' + eventNs)
-                .on('click.' + eventNs, function (e) {
-                    e.preventDefault();
-                    showPicker();
-                });
-        });
+        var syncToHidden = function () {
+            var d = ($date.val() || '').trim();
+            var hh = $hour.val();
+            var mm = $minute.val();
+            if (d && hh !== null && hh !== undefined && mm !== null && mm !== undefined) {
+                $hidden.val(d + ' ' + hh + ':' + mm + ':00');
+            } else {
+                $hidden.val('');
+            }
+        };
+
+        var syncFromHidden = function (val) {
+            val = procuremenNormalizeSysRqValue(val);
+            var parts = val.match(/^(\d{4}-\d{2}-\d{2})\s+(\d{2}):(\d{2})/);
+            if (!parts) {
+                return;
+            }
+            $date.val(parts[1]);
+            $hour.val(parts[2]);
+            $minute.val(parts[3]);
+        };
+
+        syncFromHidden($hidden.val());
+        if (!$date.val()) {
+            syncFromHidden(procuremenDefaultSysRqValue());
+            syncToHidden();
+        }
+
+        $date.add($hour).add($minute)
+            .off('change.' + eventNs + ' input.' + eventNs)
+            .on('change.' + eventNs + ' input.' + eventNs, syncToHidden);
+    }
+
+    function procuremenFocusSysRqSplit($wrap) {
+        if (!$wrap || !$wrap.length) {
+            return;
+        }
+        var $date = $wrap.find('.procuremen-sys-rq-date');
+        if ($date.length) {
+            $date.focus();
+        }
     }
 
     var Controller = {
@@ -2063,7 +2070,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
 
         review: function () {
             Controller.api.bindevent();
-            procuremenBindSysRqPicker('#review-sys-rq', 'reviewSysRq');
+            procuremenInitSysRqSplit($('#review-sys-rq-wrap'), 'reviewSysRq');
 
             function procuremenReviewWarn(msg) {
                 var shown = false;
@@ -2137,13 +2144,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 if (e && typeof e.stopPropagation === 'function') {
                     e.stopPropagation();
                 }
+                var $rqWrap = $('#review-sys-rq-wrap');
+                $rqWrap.find('.procuremen-sys-rq-date').trigger('change');
                 var $rq = $('#review-sys-rq');
-                if ($rq.length && $rq.data('DateTimePicker')) {
-                    try {
-                        $rq.data('DateTimePicker').hide();
-                    } catch (ignoreHidePicker) {
-                    }
-                }
                 var isPickMode = procuremenReviewIsPickMode();
                 var selected = procuremenReviewCollectSelected();
                 if (!selected.length) {
@@ -2153,7 +2156,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 var sysRq = ($rq.val() || '').trim();
                 if (!sysRq) {
                     procuremenReviewWarn('请选择截止时间');
-                    $rq.focus();
+                    procuremenFocusSysRqSplit($rqWrap);
                     return;
                 }
                 var cons;
@@ -2245,15 +2248,6 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 if (e.keyCode !== 27 && e.key !== 'Escape') {
                     return;
                 }
-                var $rq = $('#review-sys-rq');
-                if ($rq.length) {
-                    var picker = $rq.data('DateTimePicker');
-                    if (picker && picker.widget && picker.widget.is(':visible')) {
-                        picker.hide();
-                        e.preventDefault();
-                        return;
-                    }
-                }
                 procuremenReviewCloseLayer();
                 e.preventDefault();
             });
@@ -2890,10 +2884,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
             }
 
             function auditIssueValidateSysRq() {
+                $('#audit-sys-rq-wrap').find('.procuremen-sys-rq-date').trigger('change');
                 var sysRq = auditIssueSysRq();
                 if (!sysRq) {
                     Toastr.warning('请选择报价截止时间');
-                    $('#audit-sys-rq').focus();
+                    procuremenFocusSysRqSplit($('#audit-sys-rq-wrap'));
                     return false;
                 }
                 return true;
@@ -2911,7 +2906,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 return data;
             }
 
-            procuremenBindSysRqPicker('#audit-sys-rq', 'auditIssue');
+            procuremenInitSysRqSplit($('#audit-sys-rq-wrap'), 'auditIssue');
 
             function auditIssueSelectedCompany() {
                 var $checked = $('input[name="audit_quote_pick"]:checked');

+ 331 - 0
public/协助采购管理操作手册.html

@@ -0,0 +1,331 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>协助采购管理 — 角色功能操作手册</title>
+    <style>
+        * { box-sizing: border-box; }
+        body {
+            margin: 0;
+            font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
+            font-size: 15px;
+            line-height: 1.75;
+            color: #333;
+            background: #f5f7fa;
+        }
+        .wrap {
+            max-width: 960px;
+            margin: 0 auto;
+            padding: 32px 24px 64px;
+        }
+        h1 {
+            font-size: 26px;
+            color: #1a3a5c;
+            margin: 0 0 8px;
+            border-bottom: 3px solid #3c8dbc;
+            padding-bottom: 12px;
+        }
+        .meta {
+            color: #888;
+            font-size: 13px;
+            margin-bottom: 28px;
+        }
+        h2 {
+            font-size: 20px;
+            color: #2c5282;
+            margin: 36px 0 14px;
+            padding-left: 10px;
+            border-left: 4px solid #3c8dbc;
+        }
+        h3 {
+            font-size: 16px;
+            color: #444;
+            margin: 22px 0 10px;
+        }
+        p { margin: 8px 0; }
+        ul, ol { margin: 8px 0; padding-left: 24px; }
+        li { margin: 4px 0; }
+        table {
+            width: 100%;
+            border-collapse: collapse;
+            margin: 12px 0;
+            background: #fff;
+            font-size: 14px;
+        }
+        th, td {
+            border: 1px solid #dde3ea;
+            padding: 10px 12px;
+            text-align: left;
+            vertical-align: top;
+        }
+        th { background: #eef4f9; color: #2c5282; }
+        .flow {
+            background: #fff;
+            border: 1px solid #dde3ea;
+            border-radius: 6px;
+            padding: 20px 24px;
+            margin: 16px 0;
+            text-align: center;
+            font-size: 14px;
+            line-height: 2.2;
+        }
+        .flow span {
+            display: inline-block;
+            padding: 4px 12px;
+            margin: 2px 4px;
+            background: #e8f4fc;
+            border-radius: 4px;
+            color: #2c5282;
+        }
+        .flow .arrow { color: #999; background: none; padding: 0 2px; }
+        .tip {
+            background: #fffbe6;
+            border: 1px solid #ffe58f;
+            border-radius: 4px;
+            padding: 12px 16px;
+            margin: 12px 0;
+            font-size: 14px;
+        }
+        .card {
+            background: #fff;
+            border: 1px solid #dde3ea;
+            border-radius: 6px;
+            padding: 18px 20px;
+            margin: 14px 0;
+        }
+        .card h3 { margin-top: 0; }
+        code {
+            background: #f0f2f5;
+            padding: 1px 6px;
+            border-radius: 3px;
+            font-size: 13px;
+        }
+        .tag {
+            display: inline-block;
+            font-size: 12px;
+            padding: 2px 8px;
+            border-radius: 10px;
+            background: #e8f4fc;
+            color: #2c5282;
+            margin-right: 6px;
+        }
+    </style>
+</head>
+<body>
+<div class="wrap">
+    <h1>协助采购管理 — 角色功能操作手册</h1>
+    <p class="meta">适用系统:大数据协同系统(后台管理) · 模块:协助采购管理 · 文档版本:2026-07</p>
+
+    <h2>一、模块概述</h2>
+    <p>「协助采购管理」用于书刊印刷多工序外协协同:从工序初选、向供应商询价下发,到选定供应商、采购终审确认,直至完结归档与月度报表导出。各菜单按<strong>角色权限</strong>开放,无权限的菜单或按钮不可见。</p>
+
+    <div class="flow">
+        <span>业务员新增询价</span>
+        <span class="arrow">→</span>
+        <span>采购供应商初选(下发)</span>
+        <span class="arrow">→</span>
+        <span>供应商报价</span>
+        <span class="arrow">→</span>
+        <span>采购供应商确认(定标)</span>
+        <span class="arrow">→</span>
+        <span>采购供应商审批(终审)</span>
+        <span class="arrow">→</span>
+        <span>已完结 / 历史存证 / 月度导出</span>
+    </div>
+
+    <h2>二、角色与权限说明</h2>
+    <p>权限在后台 <strong>权限管理 → 角色组</strong> 中配置。下表为常见角色与菜单对应关系,实际以管理员分配为准。</p>
+    <table>
+        <thead>
+        <tr>
+            <th>角色类型</th>
+            <th>典型菜单/操作</th>
+            <th>说明</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr>
+            <td>业务员</td>
+            <td>公告(接收)、业务员新增询价、业务员查询询价</td>
+            <td>可手工录入询价工序;查询进度时<strong>仅能看到本人(业务员字段)录入的记录</strong>,超级管理员可看全部。</td>
+        </tr>
+        <tr>
+            <td>采购 / 协助下发人员</td>
+            <td>采购供应商初选</td>
+            <td>勾选工序向多家供应商下发询价(短信/邮件),可直接完结无需外协,或删除初选记录。</td>
+        </tr>
+        <tr>
+            <td>采购确认人员</td>
+            <td>采购供应商确认</td>
+            <td>查看各供应商报价,选定一家进入审批;可退回初选重新下发。</td>
+        </tr>
+        <tr>
+            <td>采购审批人员</td>
+            <td>采购供应商审批</td>
+            <td>对已定标订单进行终审确认,通过后订单完结。</td>
+        </tr>
+        <tr>
+            <td>管理人员</td>
+            <td>公告(发布)、历史存证、月度报表导出、控制台统计</td>
+            <td>发布公告、查档案、导出 Excel 报表、查看 KPI 概览。</td>
+        </tr>
+        <tr>
+            <td>超级管理员</td>
+            <td>全部菜单</td>
+            <td>含菜单安装、权限节点维护等系统级操作。</td>
+        </tr>
+        </tbody>
+    </table>
+
+    <h2>三、流程状态说明</h2>
+    <table>
+        <thead>
+        <tr><th>状态</th><th>含义</th></tr>
+        </thead>
+        <tbody>
+        <tr><td>待下发</td><td>工序在初选列表,尚未通知供应商报价。</td></tr>
+        <tr><td>待确认</td><td>已下发通知,等待采购从报价中选定供应商。</td></tr>
+        <tr><td>待审批</td><td>已选定供应商,等待采购终审。</td></tr>
+        <tr><td>已审核 / 已完结</td><td>终审通过或初选直接完结,流程结束,可在历史存证与月度报表中查询。</td></tr>
+        </tbody>
+    </table>
+
+    <h2>四、各菜单功能与操作步骤</h2>
+
+    <div class="card">
+        <h3>1. 公告</h3>
+        <p><span class="tag">菜单路径</span>协助采购管理 → 公告</p>
+        <p><strong>功能:</strong>发布、查看协助采购相关通知公告;支持指定接收人。</p>
+        <p><strong>主要操作:</strong></p>
+        <ul>
+            <li><strong>新增公告:</strong>点击「新增公告」,填写主题、正文,勾选接收人后保存。</li>
+            <li><strong>查看详情:</strong>在列表中打开公告查看完整内容。</li>
+            <li><strong>删除:</strong>有权限的用户可勾选后删除(普通用户通常仅可删除本人发布的公告)。</li>
+        </ul>
+        <p><strong>适用角色:</strong>管理人员发布公告;业务员等接收人查看与自己相关的公告。</p>
+    </div>
+
+    <div class="card">
+        <h3>2. 采购供应商初选</h3>
+        <p><span class="tag">菜单路径</span>协助采购管理 → 采购供应商初选</p>
+        <p><strong>功能:</strong>对待外协的工序进行初选,向多家合作供应商发送询价通知(短信 + 邮件),供应商在线填报报价。</p>
+        <p><strong>界面说明:</strong>左侧按<strong>年/月</strong>筛选下发记录;列表展示订单号、印件名称、工序、数量、限价等字段;可在行内编辑「本次数量」「最高限价」。</p>
+        <p><strong>主要操作:</strong></p>
+        <ul>
+            <li><strong>下发:</strong>勾选一条或多条工序(多条须同一订单号)→ 点击「下发」→ 在弹窗中选择供应商、设置报价截止时间 →「确认下发」。下发后工序进入「待确认」阶段。</li>
+            <li><strong>完结:</strong>无需外协的工序,勾选后点「完结」,直接标记为已完结。</li>
+            <li><strong>删除:</strong>从初选列表移除尚未下发的工序记录。</li>
+            <li><strong>刷新 / 搜索:</strong>工具栏可刷新列表、按订单号等条件搜索。</li>
+        </ul>
+        <p><strong>适用角色:</strong>采购、协助下发人员(需具备下发、完结、删除等对应权限节点)。</p>
+    </div>
+
+    <div class="card">
+        <h3>3. 采购供应商确认</h3>
+        <p><span class="tag">菜单路径</span>协助采购管理 → 采购供应商确认</p>
+        <p><strong>功能:</strong>查看已下发订单的各家供应商报价(单价、货期等),选定一家中标供应商,提交后进入审批环节。</p>
+        <p><strong>主要操作:</strong></p>
+        <ul>
+            <li>在列表中找到待确认订单,点击行内「<strong>选择供应商</strong>」。</li>
+            <li>在弹窗中对比各供应商报价,勾选一家 → 确认提交。</li>
+            <li>可点击「<strong>详情</strong>」查看订单完整信息与操作记录。</li>
+            <li><strong>重新下发:</strong>勾选订单后点「重新下发」,退回初选阶段重新询价(历史记录保留)。</li>
+        </ul>
+        <p><strong>适用角色:</strong>采购确认人员。</p>
+    </div>
+
+    <div class="card">
+        <h3>4. 采购供应商审批</h3>
+        <p><span class="tag">菜单路径</span>协助采购管理 → 采购供应商审批</p>
+        <p><strong>功能:</strong>对已选定供应商的订单进行采购终审(定标确认),审批通过后订单状态变为「已完结」。</p>
+        <p><strong>主要操作:</strong></p>
+        <ul>
+            <li>在列表中点击「<strong>审批</strong>」打开审批页,核对工序、中标供应商、报价信息。</li>
+            <li>确认无误后提交审批通过。</li>
+            <li>可查看「详情」了解全流程操作日志。</li>
+        </ul>
+        <p><strong>适用角色:</strong>采购审批人员。</p>
+    </div>
+
+    <div class="card">
+        <h3>5. 业务员新增询价</h3>
+        <p><span class="tag">菜单路径</span>协助采购管理 → 业务员新增询价</p>
+        <p><strong>功能:</strong>业务员手工录入一条外协询价工序(不经过 ERP 自动同步),录入后可在「采购供应商初选」中被勾选下发。</p>
+        <p><strong>填写字段:</strong>订单号(系统自动生成)、印件名称、承揽部门、工序名称、单位、本次数量、最高限价、订法、外厂单位、业务员(自动带出当前登录人)、备注。</p>
+        <p><strong>操作步骤:</strong>填写表单 → 点击「新增」→ 成功后到「业务员查询询价」或「采购供应商初选」继续跟进。</p>
+        <p><strong>适用角色:</strong>业务员。</p>
+    </div>
+
+    <div class="card">
+        <h3>6. 业务员查询询价</h3>
+        <p><span class="tag">菜单路径</span>协助采购管理 → 业务员查询询价</p>
+        <p><strong>功能:</strong>查询手工新增的询价工序及当前进度。</p>
+        <p><strong>主要操作:</strong></p>
+        <ul>
+            <li>列表展示本人新增的询价记录(超级管理员可查看全部)。</li>
+            <li>支持按订单号、印件名称、工序名称、业务员等搜索。</li>
+            <li>可打开详情查看该工序当前流程状态。</li>
+        </ul>
+        <p><strong>适用角色:</strong>业务员(查本人);管理员(查全部)。</p>
+    </div>
+
+    <div class="card">
+        <h3>7. 历史存证档案查询</h3>
+        <p><span class="tag">菜单路径</span>协助采购管理 → 历史存证档案查询</p>
+        <p><strong>功能:</strong>查询所有<strong>已完结</strong>的协助采购订单,查看完整操作记录(下发、确认、审批、完结等时间节点),作为过程留痕与审计依据。</p>
+        <p><strong>主要操作:</strong></p>
+        <ul>
+            <li>列表浏览已完结订单,支持搜索、排序。</li>
+            <li>打开「详情」查看操作日志、供应商报价明细、PDF 存证等。</li>
+            <li><strong>重新下发</strong>(需权限):将已完结订单退回初选,重新走询价流程。</li>
+        </ul>
+        <p><strong>适用角色:</strong>采购管理人员、审计查询人员。</p>
+    </div>
+
+    <div class="card">
+        <h3>8. 月度报表导出列表</h3>
+        <p><span class="tag">菜单路径</span>协助采购管理 → 月度报表导出列表</p>
+        <p><strong>功能:</strong>按月份汇总<strong>已完结</strong>订单,并导出 Excel 月度报表。</p>
+        <p><strong>统计口径:</strong>月份按<strong>采购确认通过(完结)</strong>时间统计;同一订单号合并为一行展示。</p>
+        <p><strong>主要操作:</strong></p>
+        <ul>
+            <li>在工具栏选择「查看月份」,列表刷新为该月已完结订单。</li>
+            <li>点击「<strong>导出 Excel</strong>」下载报表。单个工作表包含两部分:
+                <ul>
+                    <li>上方:<strong>中标汇总</strong>(协助明细汇总);</li>
+                    <li>下方:<strong>供应商报价明细</strong>(各供应商单价、交货期及是否中标)。</li>
+                </ul>
+            </li>
+        </ul>
+        <p><strong>适用角色:</strong>采购管理、财务统计人员(需导出权限)。</p>
+    </div>
+
+    <h2>五、控制台数据说明</h2>
+    <p>登录后台首页「控制台」可查看协助采购 KPI:</p>
+    <ul>
+        <li><strong>今日数据:</strong>当日待确认(下发提交)、待审批(选定供应商)、已完结数量。</li>
+        <li><strong>本月数据:</strong>本月待确认、待审批、已完结数量。</li>
+        <li><strong>近 7 天单数:</strong>折线图展示近一周各阶段单量趋势。</li>
+        <li><strong>供应商排名:</strong>本月参与报价 / 被选中次数排名。</li>
+    </ul>
+
+    <h2>六、常见问题</h2>
+    <h3>Q1:登录后控制台空白一会儿才显示?</h3>
+    <p>控制台需同步统计多类采购数据,数据量大时加载会稍慢,属正常现象。可稍后刷新或联系管理员优化数据库查询。</p>
+
+    <h3>Q2:为什么看不到某些菜单或按钮?</h3>
+    <p>菜单与按钮均受权限控制。请联系管理员在「权限管理」中为您的角色勾选对应节点(如 <code>procuremen/pick</code>、<code>procuremen/auditissue</code> 等)。</p>
+
+    <h3>Q3:下发时提示须同一订单号?</h3>
+    <p>批量下发仅支持<strong>同一订单号</strong>下的多道工序合并通知,请勿跨订单勾选。</p>
+
+    <h3>Q4:订单如何退回重新询价?</h3>
+    <p>在「采购供应商确认」阶段可使用「重新下发」;已完结订单在「历史存证档案查询」中也可操作「重新下发」(需权限)。</p>
+
+    <div class="tip">
+        <strong>提示:</strong>本手册依据系统当前菜单与功能编写。若菜单名称与后台显示略有差异(如「协助下发」与「采购供应商初选」),以实际后台菜单为准,功能逻辑相同。
+    </div>
+</div>
+</body>
+</html>