标签搜索

自动排产最终版本

wehg489
2025-03-26 / 0 评论 / 6 阅读 / 正在检测是否收录...
<!DOCTYPE html>

<html>

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>缠布缺件排产</title>

    <script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>

    <style>

        body {

            font-family: Arial, sans-serif;

            margin: 20px;

            line-height: 1.6;

        }

        .container {

            max-width: 1200px;

            margin: 0 auto;

        }

        h1, h2 {

            color: #333;

        }

        .section {

            margin-bottom: 30px;

            padding: 20px;

            border: 1px solid #ddd;

            border-radius: 5px;

            background-color: #f9f9f9;

        }

        table {

            width: 100%;

            border-collapse: collapse;

            margin-top: 15px;

        }

        th, td {

            border: 1px solid #ddd;

            padding: 8px;

            text-align: left;

        }

        th {

            background-color: #f2f2f2;

        }

        tr:nth-child(even) {

            background-color: #f9f9f9;

        }

        .warning {

            color: #d9534f;

            font-weight: bold;

        }

        .input-group {

            margin-bottom: 15px;

        }

        label {

            display: inline-block;

            width: 200px;

            margin-right: 10px;

        }

        input, button {

            padding: 8px;

            margin-right: 10px;

        }

        button {

            background-color: #4CAF50;

            color: white;

            border: none;

            cursor: pointer;

            border-radius: 4px;

        }

        button:hover {

            background-color: #45a049;

        }

        #fileInput {

            display: none;

        }

        .file-upload {

            display: inline-block;

            padding: 8px 12px;

            background: #337ab7;

            color: white;

            border-radius: 4px;

            cursor: pointer;

        }

        .file-upload:hover {

            background: #286090;

        }

        #loading {

            display: none;

            margin-left: 10px;

            color: #337ab7;

            font-weight: bold;

        }

        .summary {

            margin-top: 15px;

            padding: 10px;

            background-color: #e7f3fe;

            border-left: 5px solid #2196F3;

        }

        .stats {

            margin-top: 10px;

            font-weight: bold;

        }

        .on-time {

            color: #5cb85c;

        }

        .late {

            color: #d9534f;

        }

    </style>

</head>

<body>

    <div>

        <h1>缠布缺件排产</h1>

        

        <div>

            <h2>产能设置</h2>

            <div>

                <label for="workers">每日生产人数:</label>

                <input type="number" id="workers" value="3" min="1">

            </div>

            <div>

                <label for="productivity">每人每日产量:</label>

                <input type="number" id="productivity" value="70" min="1">

            </div>

            <div>

                <label for="startDate">排产开始日期:</label>

                <input type="date" id="startDate">

            </div>

        </div>

        

        <div>

            <h2>数据导入</h2>

            <div>

                <label>Excel数据导入:</label>

                <label for="fileInput">选择Excel文件</label>

                <input type="file" id="fileInput" accept=".xlsx, .xls" onchange="handleFileUpload(this.files)">

                <span id="fileName" style="margin-left:10px;"></span>

            </div>

            <div>

                <label>Excel格式要求:</label>

                <span>第一列:产品编号, 第二列:交付日期, 第三列:缺件数量</span>

            </div>

        </div>

        

        <div>

            <h2>原始数据</h2>

            <div id="rawDataSummary"></div>

            <table id="rawDataTable">

                <thead>

                    <tr>

                        <th>产品编号</th>

                        <th>交期处理(提前一天)</th>

                        <th>缺件数量</th>

                    </tr>

                </thead>

                <tbody></tbody>

            </table>

        </div>

        

        <div>

            <h2>排产计划</h2>

            <button onclick="generateSchedule()" id="generateBtn">生成排产计划</button>

            <span id="loading">正在计算中,请稍候...</span>

            <div id="scheduleSummary"></div>

            <div id="scheduleStats"></div>

            <table id="scheduleTable">

                <thead>

                    <tr>

                        <th>产品编号</th>

                        <th>缺件数量</th>

                        <th>交付日期</th>

                        <th>排产日期</th>

                        <th>是否超期</th>

                    </tr>

                </thead>

                <tbody></tbody>

            </table>

        </div>

        

        <div>

            <h2>预警清单</h2>

            <div id="warningSummary"></div>

            <table id="warningTable">

                <thead>

                    <tr>

                        <th>产品编号</th>

                        <th>缺件数量</th>

                        <th>交付日期</th>

                        <th>预计排产日期</th>

                        <th>超期天数</th>

                    </tr>

                </thead>

                <tbody></tbody>

            </table>

        </div>

    </div>



    <script>

        // 全局变量

        let rawData = [];

        let scheduleData = [];

        let warningData = [];

        

        // 页面加载时设置默认日期为今天

        window.onload = function() {

            const today = new Date();

            const formattedDate = today.toISOString().split('T')[0];

            document.getElementById('startDate').value = formattedDate;

        };

        

        // 解析Excel日期数字

        function parseExcelDate(excelDate) {

            const utcDays = Math.floor(excelDate - 25569);

            const utcValue = utcDays * 86400 * 1000;

            let date = new Date(utcValue);

            

            if (excelDate >= 60) {

                date.setTime(date.getTime() - 86400 * 1000);

            }

            

            return date.toISOString().split('T')[0];

        }

        

        // 处理Excel文件上传

        function handleFileUpload(files) {

            if (files.length === 0) return;

            

            const file = files[0];

            document.getElementById('fileName').textContent = file.name;

            

            const reader = new FileReader();

            

            reader.onload = function(e) {

                try {

                    const data = new Uint8Array(e.target.result);

                    const workbook = XLSX.read(data, { type: 'array' });

                    

                    const firstSheet = workbook.Sheets[workbook.SheetNames[0]];

                    const jsonData = XLSX.utils.sheet_to_json(firstSheet, { header: 1 });

                    

                    rawData = [];

                    for (let i = 1; i < jsonData.length; i++) {

                        if (jsonData[i].length >= 3) {

                            let deliveryDate = '';

                            const dateValue = jsonData[i][1];

                            

                            if (typeof dateValue === 'number') {

                                deliveryDate = parseExcelDate(dateValue);

                            } else if (dateValue instanceof Date) {

                                deliveryDate = dateValue.toISOString().split('T')[0];

                            } else if (typeof dateValue === 'string') {

                                const parsedDate = new Date(dateValue);

                                if (!isNaN(parsedDate.getTime())) {

                                    deliveryDate = parsedDate.toISOString().split('T')[0];

                                }

                            }

                            

                            let quantity = 0;

                            if (typeof jsonData[i][2] === 'number') {

                                quantity = Math.floor(jsonData[i][2]);

                            } else if (typeof jsonData[i][2] === 'string') {

                                quantity = parseInt(jsonData[i][2]) || 0;

                            }

                            

                            rawData.push({

                                productId: String(jsonData[i][0] || ''),

                                deliveryDate: deliveryDate,

                                quantity: quantity,

                                originalQuantity: quantity // 保存原始数量用于显示

                            });

                        }

                    }

                    

                    console.log("解析后的数据:", rawData);

                    displayRawData();

                    updateRawDataSummary();

                    

                } catch (error) {

                    console.error("解析Excel文件时出错:", error);

                    alert('解析Excel文件时出错: ' + error.message);

                }

            };

            

            reader.onerror = function() {

                alert('读取文件时出错');

            };

            

            reader.readAsArrayBuffer(file);

        }

        

        // 显示原始数据

        function displayRawData() {

            const tbody = document.querySelector('#rawDataTable tbody');

            tbody.innerHTML = '';

            

            rawData.forEach(item => {

                const row = document.createElement('tr');

                row.innerHTML = `

                    <td>${item.productId}</td>

                    <td>${item.deliveryDate}</td>

                    <td>${item.originalQuantity}</td>

                `;

                tbody.appendChild(row);

            });

        }

        

        // 更新原始数据摘要

        function updateRawDataSummary() {

            const summary = document.getElementById('rawDataSummary');

            const totalItems = rawData.length;

            const totalQuantity = rawData.reduce((sum, item) => sum + item.originalQuantity, 0);

            

            summary.innerHTML = `

                共 ${totalItems} 条记录,总缺件数量: ${totalQuantity} 件

                ${rawData.some(item => !item.deliveryDate) ? '<span> (警告: 部分记录缺少交付日期)</span>' : ''}

            `;

        }

        

        // 生成排产计划(精确交付版)

        function generateSchedule() {

            const btn = document.getElementById('generateBtn');

            const loading = document.getElementById('loading');

            

            btn.disabled = true;

            loading.style.display = 'inline';

            

            setTimeout(() => {

                try {

                    console.log("开始生成精确交付排产计划...");

                    

                    // 验证数据

                    if (rawData.length === 0) {

                        alert('请先导入Excel数据');

                        return;

                    }

                    

                    const invalidData = rawData.filter(item => 

                        !item.deliveryDate || isNaN(new Date(item.deliveryDate).getTime()) || isNaN(item.originalQuantity)

                    );

                    

                    if (invalidData.length > 0) {

                        console.error("无效数据:", invalidData);

                        alert(`发现 ${invalidData.length} 条无效记录,请检查数据`);

                        return;

                    }

                    

                    // 获取产能参数

                    const workers = parseInt(document.getElementById('workers').value) || 3;

                    const productivity = parseInt(document.getElementById('productivity').value) || 70;

                    const startDateStr = document.getElementById('startDate').value;

                    

                    if (!startDateStr) {

                        alert('请设置排产开始日期');

                        return;

                    }

                    

                    const dailyCapacity = workers * productivity;

                    scheduleData = [];

                    warningData = [];

                    

                    // 1. 按交付日期升序排序,数量小的优先

                    const sortedData = [...rawData].sort((a, b) => {

                        // 先按交付日期排序

                        const dateDiff = new Date(a.deliveryDate) - new Date(b.deliveryDate);

                        if (dateDiff !== 0) return dateDiff;

                        

                        // 同一天交付的,数量小的优先

                        return a.originalQuantity - b.originalQuantity;

                    });

                    

                    console.log("排序后的数据:", sortedData);

                    

                    // 2. 初始化生产日历

                    let currentDate = new Date(startDateStr);

                    let dailyRemaining = dailyCapacity;

                    

                    // 3. 逐个处理每个订单(即使产品相同也单独处理)

                    for (const item of sortedData) {

                        // 重置数量为原始值(因为前面的处理可能修改了quantity)

                        item.quantity = item.originalQuantity;

                        

                        let productionDate = new Date(currentDate);

                        let quantityRemaining = item.quantity;

                        let isLate = false;

                        

                        // 分配生产日期

                        while (quantityRemaining > 0) {

                            if (dailyRemaining === 0) {

                                // 转到下一天

                                currentDate.setDate(currentDate.getDate() + 1);

                                dailyRemaining = dailyCapacity;

                                productionDate = new Date(currentDate);

                            }

                            

                            const allocate = Math.min(quantityRemaining, dailyRemaining);

                            

                            // 检查是否超期(生产日期 > 交付日期)

                            const currentIsLate = productionDate > new Date(item.deliveryDate);

                            isLate = isLate || currentIsLate;

                            

                            scheduleData.push({

                                productId: item.productId,

                                quantity: allocate,

                                deliveryDate: item.deliveryDate,

                                productionDate: productionDate.toISOString().split('T')[0],

                                isLate: currentIsLate

                            });

                            

                            quantityRemaining -= allocate;

                            dailyRemaining -= allocate;

                        }

                        

                        // 如果整个订单超期,添加到预警

                        if (isLate) {

                            const lastProdDate = new Date(

                                scheduleData.filter(x => 

                                    x.productId === item.productId && 

                                    x.deliveryDate === item.deliveryDate

                                )

                                .reduce((latest, curr) => 

                                    new Date(curr.productionDate) > new Date(latest.productionDate) ? curr : latest

                                ).productionDate

                            );

                            

                            const lateDays = Math.ceil(

                                (lastProdDate - new Date(item.deliveryDate)) / 

                                (1000 * 60 * 60 * 24)

                            );

                            

                            warningData.push({

                                productId: item.productId,

                                quantity: item.originalQuantity,

                                deliveryDate: item.deliveryDate,

                                productionDate: lastProdDate.toISOString().split('T')[0],

                                lateDays: lateDays

                            });

                        }

                    }

                    

                    // 4. 显示结果

                    displaySchedule();

                    displayWarnings();

                    updateSummary();

                    

                    console.log("精确交付排产计划生成完成");

                    console.log("排产数据:", scheduleData);

                    console.log("预警数据:", warningData);

                    

                } catch (error) {

                    console.error("生成排产计划时出错:", error);

                    alert('生成排产计划时出错: ' + error.message);

                } finally {

                    btn.disabled = false;

                    loading.style.display = 'none';

                }

            }, 100);

        }

        

        // 更新摘要信息

        function updateSummary() {

            const scheduleSummary = document.getElementById('scheduleSummary');

            const warningSummary = document.getElementById('warningSummary');

            const statsElement = document.getElementById('scheduleStats');

            

            const totalOrders = rawData.length;

            const totalQuantity = rawData.reduce((sum, item) => sum + item.originalQuantity, 0);

            const lateOrders = warningData.length;

            

            scheduleSummary.innerHTML = `

                共 ${totalOrders} 个订单需要生产,总数量: ${totalQuantity} 件

            `;

            

            const warningQuantity = warningData.reduce((sum, item) => sum + item.quantity, 0);

            

            warningSummary.innerHTML = `

                共 ${lateOrders} 个订单需要预警,总数量: ${warningQuantity} 件

            `;

            

            // 计算按时完成率

            const onTimeRate = totalOrders > 0 ? ((totalOrders - lateOrders) / totalOrders * 100).toFixed(2) : 0;

            

            statsElement.innerHTML = `

                <span>按时完成率: ${onTimeRate}% (${totalOrders - lateOrders}/${totalOrders})</span> | 

                <span>超期订单: ${lateOrders}</span>

            `;

        }

        

        // 显示排产计划

        function displaySchedule() {

            const tbody = document.querySelector('#scheduleTable tbody');

            tbody.innerHTML = '';

            

            // 按交付日期分组显示

            const deliveryGroups = [...new Set(rawData.map(item => item.deliveryDate))].sort((a, b) => 

                new Date(a) - new Date(b)

            );

            

            for (const deliveryDate of deliveryGroups) {

                // 获取该交付日期的所有订单

                const orders = rawData.filter(item => item.deliveryDate === deliveryDate);

                

                // 检查该交付日期是否有超期订单

                const hasLateOrders = warningData.some(item => item.deliveryDate === deliveryDate);

                

                // 添加交付日期标题行

                const headerRow = document.createElement('tr');

                headerRow.style.backgroundColor = '#f0f0f0';

                headerRow.innerHTML = `

                    <td colspan="5">

                        <strong>交付日期: ${deliveryDate}</strong>

                        ${hasLateOrders ? '<span> (有超期订单)</span>' : '<span> (全部按时)</span>'}

                    </td>

                `;

                tbody.appendChild(headerRow);

                

                // 添加该交付日期的所有订单

                for (const order of orders) {

                    // 获取该订单的所有排产记录

                    const orderSchedule = scheduleData.filter(item => 

                        item.productId === order.productId && 

                        item.deliveryDate === order.deliveryDate

                    );

                    

                    const isLate = orderSchedule.some(item => item.isLate);

                    

                    orderSchedule.forEach((item, index) => {

                        const row = document.createElement('tr');

                        if (isLate) {

                            row.classList.add('warning');

                        }

                        

                        row.innerHTML = `

                            <td>${index === 0 ? item.productId : ''}</td>

                            <td>${item.quantity}</td>

                            <td>${index === 0 ? item.deliveryDate : ''}</td>

                            <td>${item.productionDate}</td>

                            <td>${index === 0 ? (isLate ? '是' : '否') : ''}</td>

                        `;

                        tbody.appendChild(row);

                    });

                }

            }

        }

        

        // 显示预警清单

        function displayWarnings() {

            const tbody = document.querySelector('#warningTable tbody');

            tbody.innerHTML = '';

            

            // 按交付日期分组显示预警

            const warningGroups = warningData.reduce((groups, item) => {

                if (!groups[item.deliveryDate]) {

                    groups[item.deliveryDate] = [];

                }

                groups[item.deliveryDate].push(item);

                return groups;

            }, {});

            

            const sortedDeliveryDates = Object.keys(warningGroups).sort((a, b) => 

                new Date(a) - new Date(b)

            );

            

            for (const deliveryDate of sortedDeliveryDates) {

                const groupItems = warningGroups[deliveryDate];

                

                // 添加分组标题行

                const headerRow = document.createElement('tr');

                headerRow.style.backgroundColor = '#f0f0f0';

                headerRow.innerHTML = `

                    <td colspan="5">

                        <strong>超期交付日期: ${deliveryDate}</strong>

                        <span> (超期 ${groupItems[0].lateDays} 天)</span>

                    </td>

                `;

                tbody.appendChild(headerRow);

                

                // 添加订单行

                for (const item of groupItems) {

                    const row = document.createElement('tr');

                    row.classList.add('warning');

                    

                    row.innerHTML = `

                        <td>${item.productId}</td>

                        <td>${item.quantity}</td>

                        <td>${item.deliveryDate}</td>

                        <td>${item.productionDate}</td>

                        <td>${item.lateDays}</td>

                    `;

                    tbody.appendChild(row);

                }

            }

        }

    </script>

</body>

</html>
0

评论

博主关闭了当前页面的评论
歌曲封面
0:00