首页
关于
友链
推荐
肥啾解析
百度一下
肥啾GPT
Search
1
宝塔面板登录 phpMyAdmin 提示服务器和客户端上指示的HTTPS之间不匹配
269 阅读
2
Customer complaints evolve with in-car tech
188 阅读
3
JavaScript解析
153 阅读
4
内连接,左连接,右连接作用及区别
111 阅读
5
所谓关系
109 阅读
默认分类
网游架设
手机游戏
python
PHP
Mysql
VBA
C++
JAVASCRIPT
javascript基础
Oracle
生产管理
计划控制
ERP系统开发
APS排产
MES研究
考勤系统
CPA
财管
实务
经济法
战略
审计
税法
藏书架
古典名著
世界名著
编程秘籍
攻防渗透
经管书籍
大佬传经
风雅读物
考试相关
心情格言
拾玉良言
外文报刊
外刊随选
Facebook
Twitter
China Daily
软考
登录
Search
标签搜索
期刊读物
古文
何瑜明
累计撰写
160
篇文章
累计收到
154
条评论
首页
栏目
默认分类
网游架设
手机游戏
python
PHP
Mysql
VBA
C++
JAVASCRIPT
javascript基础
Oracle
生产管理
计划控制
ERP系统开发
APS排产
MES研究
考勤系统
CPA
财管
实务
经济法
战略
审计
税法
藏书架
古典名著
世界名著
编程秘籍
攻防渗透
经管书籍
大佬传经
风雅读物
考试相关
心情格言
拾玉良言
外文报刊
外刊随选
Facebook
Twitter
China Daily
软考
页面
关于
友链
推荐
肥啾解析
百度一下
肥啾GPT
搜索到
160
篇与
的结果
2025-06-23
抠图功能
<!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> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%); min-height: 100vh; padding: 20px; display: flex; flex-direction: column; align-items: center; color: white; } .container { width: 100%; max-width: 1200px; padding: 20px; } header { text-align: center; margin-bottom: 30px; padding: 20px; animation: fadeIn 1s ease; } h1 { font-size: 2.5rem; margin-bottom: 10px; text-shadow: 0 2px 4px rgba(0,0,0,0.2); } .subtitle { font-size: 1.2rem; opacity: 0.9; max-width: 600px; margin: 0 auto; } .app-container { display: flex; flex-wrap: wrap; gap: 30px; background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border-radius: 20px; padding: 30px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); } .upload-section { flex: 1; min-width: 300px; display: flex; flex-direction: column; gap: 20px; } .preview-section { flex: 1; min-width: 300px; display: flex; flex-direction: column; gap: 20px; } .section-title { font-size: 1.3rem; margin-bottom: 10px; display: flex; align-items: center; gap: 10px; } .section-title i { font-size: 1.5rem; } .drop-area { border: 3px dashed rgba(255, 255, 255, 0.5); border-radius: 15px; padding: 40px 20px; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; cursor: pointer; transition: all 0.3s ease; background: rgba(255, 255, 255, 0.05); } .drop-area:hover, .drop-area.active { border-color: #fff; background: rgba(255, 255, 255, 0.1); } .drop-area i { font-size: 3rem; margin-bottom: 15px; color: rgba(255, 255, 255, 0.7); } .drop-area p { margin: 10px 0; } .file-input { display: none; } .btn { background: linear-gradient(45deg, #ff8a00, #ff2070); color: white; border: none; padding: 12px 25px; font-size: 1rem; border-radius: 50px; cursor: pointer; transition: all 0.3s ease; font-weight: 600; display: inline-flex; align-items: center; justify-content: center; gap: 8px; box-shadow: 0 4px 15px rgba(255, 138, 0, 0.3); } .btn:hover { transform: translateY(-3px); box-shadow: 0 7px 20px rgba(255, 138, 0, 0.4); } .btn:active { transform: translateY(0); } .btn-outline { background: transparent; border: 2px solid rgba(255, 255, 255, 0.5); box-shadow: none; } .btn-outline:hover { background: rgba(255, 255, 255, 0.1); } .preview-container { display: flex; flex-direction: column; gap: 20px; } .preview-box { position: relative; width: 100%; height: 250px; border-radius: 15px; overflow: hidden; background: rgba(0, 0, 0, 0.2); display: flex; align-items: center; justify-content: center; border: 2px solid rgba(255, 255, 255, 0.1); } .preview-box img, .preview-box canvas { max-width: 100%; max-height: 100%; display: none; } .preview-placeholder { text-align: center; color: rgba(255, 255, 255, 0.5); } .controls { display: flex; gap: 15px; flex-wrap: wrap; } .tolerance-control { flex: 1; min-width: 200px; } .tolerance-label { display: flex; justify-content: space-between; margin-bottom: 8px; } .slider { width: 100%; height: 10px; -webkit-appearance: none; background: rgba(255, 255, 255, 0.1); border-radius: 5px; outline: none; } .slider::-webkit-slider-thumb { -webkit-appearance: none; width: 20px; height: 20px; border-radius: 50%; background: #ff8a00; cursor: pointer; } .tolerance-value { background: rgba(255, 255, 255, 0.1); padding: 2px 10px; border-radius: 10px; min-width: 40px; text-align: center; } .result-actions { display: flex; gap: 15px; margin-top: 10px; } .info-box { background: rgba(0, 0, 0, 0.2); border-radius: 15px; padding: 20px; margin-top: 30px; font-size: 0.9rem; } .info-box h3 { margin-bottom: 15px; display: flex; align-items: center; gap: 10px; } .info-content { display: flex; flex-wrap: wrap; gap: 20px; } .info-item { flex: 1; min-width: 250px; } .info-item ul { padding-left: 20px; margin-top: 10px; } .info-item li { margin-bottom: 8px; } footer { text-align: center; margin-top: 40px; padding: 20px; color: rgba(255, 255, 255, 0.7); font-size: 0.9rem; } .loading { display: none; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.7); flex-direction: column; align-items: center; justify-content: center; z-index: 10; border-radius: 15px; } .spinner { width: 50px; height: 50px; border: 5px solid rgba(255, 255, 255, 0.3); border-radius: 50%; border-top: 5px solid #ff8a00; animation: spin 1s linear infinite; margin-bottom: 15px; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes fadeIn { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } } .featured-examples { display: flex; gap: 20px; margin-top: 15px; justify-content: center; flex-wrap: wrap; } .example-item { width: 80px; height: 80px; border-radius: 10px; overflow: hidden; cursor: pointer; border: 2px solid rgba(255, 255, 255, 0.3); transition: all 0.3s ease; } .example-item:hover { transform: scale(1.05); border-color: white; } .example-item img { width: 100%; height: 100%; object-fit: cover; } @media (max-width: 768px) { .app-container { flex-direction: column; } .controls { flex-direction: column; } h1 { font-size: 2rem; } } </style> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> </head> <body> <div class="container"> <header> <h1><i class="fas fa-magic"></i> 智能抠图工具</h1> <p class="subtitle">上传图片,一键自动去除背景 - 无需复杂操作,快速获得透明背景PNG图片</p> </header> <div class="app-container"> <div class="upload-section"> <h2 class="section-title"><i class="fas fa-upload"></i> 上传图片</h2> <div class="drop-area" id="dropArea"> <i class="fas fa-cloud-upload-alt"></i> <p>拖放图片到此处或</p> <button class="btn" id="browseBtn"><i class="fas fa-folder-open"></i> 选择图片</button> <p class="small">支持 JPG, PNG 格式,最大 5MB</p> </div> <input type="file" id="fileInput" class="file-input" accept="image/*"> <div class="featured-examples"> <div class="example-item" data-example="1"> <img src="https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=80" alt="示例1"> </div> <div class="example-item" data-example="2"> <img src="https://images.unsplash.com/photo-1543852786-1cf6624b9987?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=80" alt="示例2"> </div> <div class="example-item" data-example="3"> <img src="https://images.unsplash.com/photo-1533738363-b7f9aef128ce?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=80" alt="示例3"> </div> <div class="example-item" data-example="4"> <img src="https://images.unsplash.com/photo-1526336024174-e58f5cdd8e13?ixlib=rb-1.2.1&auto=format&fit=crop&w=200&q=80" alt="示例4"> </div> </div> </div> <div class="preview-section"> <h2 class="section-title"><i class="fas fa-image"></i> 预览结果</h2> <div class="preview-container"> <div class="preview-box"> <div class="preview-placeholder"> <i class="fas fa-image" style="font-size: 3rem; margin-bottom: 15px;"></i> <p>处理后的图像将显示在这里</p> </div> <canvas id="originalCanvas"></canvas> <canvas id="resultCanvas"></canvas> <div class="loading" id="loading"> <div class="spinner"></div> <p>正在处理图像...</p> </div> </div> <div class="controls"> <div class="tolerance-control"> <div class="tolerance-label"> <span>抠图精度调节:</span> <span class="tolerance-value" id="toleranceValue">30</span> </div> <input type="range" min="1" max="100" value="30" class="slider" id="toleranceSlider"> <p style="font-size: 0.8rem; margin-top: 5px; opacity: 0.7;">值越小,抠图越精细(处理时间越长)</p> </div> <button class="btn" id="processBtn"><i class="fas fa-cogs"></i> 开始抠图</button> </div> <div class="result-actions"> <button class="btn" id="downloadBtn" disabled><i class="fas fa-download"></i> 下载结果</button> <button class="btn btn-outline" id="resetBtn"><i class="fas fa-redo"></i> 重置</button> </div> </div> </div> </div> <div class="info-box"> <h3><i class="fas fa-info-circle"></i> 使用说明</h3> <div class="info-content"> <div class="info-item"> <h4>如何获得最佳效果:</h4> <ul> <li>选择主体与背景对比度高的图片</li> <li>避免复杂背景或毛发等细节丰富的图像</li> <li>如果效果不理想,尝试调整抠图精度</li> <li>对于人像照片效果最佳</li> </ul> </div> <div class="info-item"> <h4>技术说明:</h4> <ul> <li>使用HTML5 Canvas实现纯前端处理</li> <li>基于智能颜色识别算法</li> <li>处理时间取决于图像大小和复杂度</li> <li>完全在浏览器中运行 - 不上传服务器</li> </ul> </div> </div> </div> </div> <footer> <p>© 2023 智能抠图工具 | 纯前端实现 | 无需上传服务器 | 保护您的隐私</p> </footer> <script> document.addEventListener('DOMContentLoaded', function() { // 获取DOM元素 const dropArea = document.getElementById('dropArea'); const fileInput = document.getElementById('fileInput'); const browseBtn = document.getElementById('browseBtn'); const processBtn = document.getElementById('processBtn'); const downloadBtn = document.getElementById('downloadBtn'); const resetBtn = document.getElementById('resetBtn'); const toleranceSlider = document.getElementById('toleranceSlider'); const toleranceValue = document.getElementById('toleranceValue'); const originalCanvas = document.getElementById('originalCanvas'); const resultCanvas = document.getElementById('resultCanvas'); const loading = document.getElementById('loading'); const previewPlaceholder = document.querySelector('.preview-placeholder'); let originalImage = null; let processedImage = null; // 设置事件监听器 browseBtn.addEventListener('click', () => fileInput.click()); fileInput.addEventListener('change', handleFileSelect); dropArea.addEventListener('dragover', handleDragOver); dropArea.addEventListener('dragleave', handleDragLeave); dropArea.addEventListener('drop', handleDrop); processBtn.addEventListener('click', processImage); downloadBtn.addEventListener('click', downloadResult); resetBtn.addEventListener('click', resetApp); toleranceSlider.addEventListener('input', updateTolerance); // 示例图片点击事件 document.querySelectorAll('.example-item').forEach(item => { item.addEventListener('click', function() { const exampleNum = this.getAttribute('data-example'); loadExample(exampleNum); }); }); // 更新容差值显示 function updateTolerance() { toleranceValue.textContent = toleranceSlider.value; } // 处理文件选择 function handleFileSelect(e) { const file = e.target.files[0]; if (file && file.type.match('image.*')) { loadImage(file); } } // 处理拖放 function handleDragOver(e) { e.preventDefault(); e.stopPropagation(); dropArea.classList.add('active'); } function handleDragLeave(e) { e.preventDefault(); e.stopPropagation(); dropArea.classList.remove('active'); } function handleDrop(e) { e.preventDefault(); e.stopPropagation(); dropArea.classList.remove('active'); const file = e.dataTransfer.files[0]; if (file && file.type.match('image.*')) { loadImage(file); } } // 加载图片 function loadImage(file) { const reader = new FileReader(); reader.onload = function(e) { originalImage = new Image(); originalImage.onload = function() { // 显示原始图片 displayOriginalImage(); processBtn.disabled = false; }; originalImage.src = e.target.result; }; reader.readAsDataURL(file); } // 加载示例图片 function loadExample(num) { const examples = { '1': 'https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80', '2': 'https://images.unsplash.com/photo-1543852786-1cf6624b9987?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80', '3': 'https://images.unsplash.com/photo-1533738363-b7f9aef128ce?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80', '4': 'https://images.unsplash.com/photo-1526336024174-e58f5cdd8e13?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80' }; originalImage = new Image(); originalImage.crossOrigin = "Anonymous"; originalImage.onload = function() { displayOriginalImage(); processBtn.disabled = false; }; originalImage.src = examples[num]; } // 显示原始图片 function displayOriginalImage() { const previewBox = document.querySelector('.preview-box'); previewPlaceholder.style.display = 'none'; // 设置canvas尺寸 const maxWidth = previewBox.clientWidth - 20; const maxHeight = previewBox.clientHeight - 20; let width = originalImage.width; let height = originalImage.height; if (width > maxWidth) { height = (maxWidth / width) * height; width = maxWidth; } if (height > maxHeight) { width = (maxHeight / height) * width; height = maxHeight; } originalCanvas.width = width; originalCanvas.height = height; resultCanvas.width = width; resultCanvas.height = height; const ctx = originalCanvas.getContext('2d'); ctx.clearRect(0, 0, width, height); ctx.drawImage(originalImage, 0, 0, width, height); originalCanvas.style.display = 'block'; } // 处理图像(抠图) function processImage() { if (!originalImage) return; // 显示加载状态 loading.style.display = 'flex'; downloadBtn.disabled = true; // 使用setTimeout让UI有机会更新 setTimeout(() => { try { const tolerance = parseInt(toleranceSlider.value); removeBackground(tolerance); // 显示结果 originalCanvas.style.display = 'none'; resultCanvas.style.display = 'block'; downloadBtn.disabled = false; } catch (error) { console.error('Error processing image:', error); alert('处理图像时出错: ' + error.message); } finally { loading.style.display = 'none'; } }, 100); } // 移除背景的核心算法 function removeBackground(tolerance) { const ctx = originalCanvas.getContext('2d'); const resultCtx = resultCanvas.getContext('2d'); // 获取图像数据 const imageData = ctx.getImageData(0, 0, originalCanvas.width, originalCanvas.height); const data = imageData.data; // 创建新图像数据(带透明通道) const newData = new ImageData(originalCanvas.width, originalCanvas.height); const newPixels = newData.data; // 假设图片中心点属于前景 const centerX = Math.floor(originalCanvas.width / 2); const centerY = Math.floor(originalCanvas.height / 2); const centerIndex = (centerY * originalCanvas.width + centerX) * 4; // 获取中心点颜色作为前景参考 const centerR = data[centerIndex]; const centerG = data[centerIndex + 1]; const centerB = data[centerIndex + 2]; // 处理每个像素 for (let i = 0; i < data.length; i += 4) { const r = data[i]; const g = data[i + 1]; const b = data[i + 2]; // 计算与中心点的颜色差异 const diff = Math.sqrt( Math.pow(r - centerR, 2) + Math.pow(g - centerG, 2) + Math.pow(b - centerB, 2) ); // 如果颜色差异在容差范围内,保留像素,否则设为透明 if (diff < tolerance) { newPixels[i] = r; newPixels[i + 1] = g; newPixels[i + 2] = b; newPixels[i + 3] = 255; // 不透明 } else { newPixels[i] = 0; newPixels[i + 1] = 0; newPixels[i + 2] = 0; newPixels[i + 3] = 0; // 完全透明 } } // 将新图像数据绘制到结果canvas resultCtx.putImageData(newData, 0, 0); } // 下载结果 function downloadResult() { if (!resultCanvas) return; const link = document.createElement('a'); link.download = '抠图结果.png'; link.href = resultCanvas.toDataURL('image/png'); link.click(); } // 重置应用 function resetApp() { // 重置所有状态 originalImage = null; processedImage = null; // 隐藏canvas originalCanvas.style.display = 'none'; resultCanvas.style.display = 'none'; // 显示占位符 previewPlaceholder.style.display = 'flex'; // 重置按钮状态 processBtn.disabled = true; downloadBtn.disabled = true; // 重置文件输入 fileInput.value = ''; } // 初始化 updateTolerance(); }); </script> </body> </html>
2025年06月23日
3 阅读
0 评论
0 点赞
2025-06-22
此内容被密码保护
加密文章,请前往内页查看详情
2025年06月22日
2 阅读
0 评论
0 点赞
2025-05-14
扫描文件逻辑
时区设置 date_default_timezone_set('Asia/Shanghai'); 将脚本时区设置为北京时间(东八区),确保所有时间相关函数返回中国时区的时间37。 安全配置 set_time_limit(1000); $allowed_extensions = ['pdf', 'jpg', 'jpeg', 'png']; 设置脚本最大执行时间为1000秒 定义允许处理的文件扩展名白名单 路径定义 $dataFilePath = __DIR__.'/data/files2.json'; $pdfBasePath = __DIR__.'/pdf2/'; 指定JSON输出文件路径 设置PDF文件存储根目录 目录创建 if (!file_exists(dirname($dataFilePath))) { mkdir(dirname($dataFilePath), 0755, true); } 递归创建JSON文件所需的目录结构(如果不存在) 核心扫描函数 function scanFiles($dir, &$result, $rootDir, $allowed) { // 扫描目录 $files = scandir($dir); foreach ($files as $file) { // 跳过特殊目录 if ($file === '.' || $file === '..') continue; $fullPath = $dir.'/'.$file; // 递归处理子目录 if (is_dir($fullPath)) { scanFiles($fullPath, $result, $rootDir, $allowed); continue; } // 文件名编码转换 $fileNameUTF8 = iconv('GBK', 'UTF-8//IGNORE', $file); $ext = strtolower(pathinfo($fileNameUTF8, PATHINFO_EXTENSION)); // 扩展名检查 if (!in_array($ext, $allowed)) continue; // 路径处理 $relativePath = substr($fullPath, strlen($rootDir) + 1); $relativePathUTF8 = iconv('GBK', 'UTF-8//IGNORE', $relativePath); // 构建文件信息数组 $result[] = [ 'name' => $fileNameUTF8, 'path' => str_replace('\\', '/', $relativePathUTF8), 'size' => filesize($fullPath), 'time' => date('Y-m-d H:i:s', filemtime($fullPath)) ]; } } 路径验证 $pdfPathGBK = iconv('UTF-8', 'GBK', $pdfBasePath); $realPdfPath = realpath($pdfPathGBK); if (!$realPdfPath || !is_dir($realPdfPath)) { die("PDF目录不存在或无法访问"); } 处理中文路径编码问题 验证PDF目录有效性 执行扫描 $fileList = []; scanFiles($realPdfPath, $fileList, $realPdfPath, $allowed_extensions); 初始化空数组并开始递归扫描 排序处理 usort($fileList, function($a, $b) { return $b['time'] - $a['time']; }); 按文件修改时间降序排序 结果输出 file_put_contents( $dataFilePath, json_encode(['files' => $fileList], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ); 将结果以JSON格式写入文件,保留Unicode字符和斜杠 完成提示 echo "<script>alert('已生成 ".count($fileList)." 个文件索引');</script>"; 通过JavaScript弹窗显示处理结果 这段代码主要实现了: 递归扫描指定目录下的文件 过滤指定扩展名的文件 处理中文路径编码问题 生成包含文件信息的JSON索引 按修改时间排序输出结果 特别注意: 代码中多处使用iconv()处理GBK/UTF-8编码转换,说明目标环境可能存在中文Windows服务器 时区设置确保所有时间戳都显示为北京时间37 路径处理中统一使用正斜杠提高跨平台兼容性<?php // generate_json.php // 设置时区为北京时间 date_default_timezone_set('Asia/Shanghai'); // 安全配置 set_time_limit(1000); // 将最大执行时间设置为60秒 $allowed_extensions = ['pdf', 'jpg', 'jpeg', 'png']; $dataFilePath = __DIR__.'/data/files2.json'; // JSON存储路径 $pdfBasePath = __DIR__.'/pdf2/'; // PDF存储根目录 // 创建数据目录 if (!file_exists(dirname($dataFilePath))) { mkdir(dirname($dataFilePath), 0755, true); } // 递归扫描目录 function scanFiles($dir, &$result, $rootDir, $allowed) { $files = scandir($dir); foreach ($files as $file) { if ($file === '.' || $file === '..') continue; $fullPath = $dir.'/'.$file; if (is_dir($fullPath)) { scanFiles($fullPath, $result, $rootDir, $allowed); continue; } // 处理文件名编码(GBK转UTF-8) $fileNameUTF8 = iconv('GBK', 'UTF-8//IGNORE', $file); $ext = strtolower(pathinfo($fileNameUTF8, PATHINFO_EXTENSION)); if (!in_array($ext, $allowed)) continue; // 计算相对路径 $relativePath = substr($fullPath, strlen($rootDir) + 1); $relativePathUTF8 = iconv('GBK', 'UTF-8//IGNORE', $relativePath); $result[] = [ 'name' => $fileNameUTF8, 'path' => str_replace('\\', '/', $relativePathUTF8), // 统一斜杠方向 'size' => filesize($fullPath), 'time' => date('Y-m-d H:i:s', filemtime($fullPath)) ]; } } // 验证PDF目录有效性 $pdfPathGBK = iconv('UTF-8', 'GBK', $pdfBasePath); $realPdfPath = realpath($pdfPathGBK); if (!$realPdfPath || !is_dir($realPdfPath)) { die("PDF目录不存在或无法访问"); } $fileList = []; scanFiles($realPdfPath, $fileList, $realPdfPath, $allowed_extensions); // 按修改时间排序 usort($fileList, function($a, $b) { return $b['time'] - $a['time']; }); // 写入JSON文件 file_put_contents( $dataFilePath, json_encode(['files' => $fileList], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ); //echo "已生成 ".count($fileList)." 个文件索引"; echo "<script>alert('已生成 ".count($fileList)." 个文件索引');</script>"; ?>
2025年05月14日
11 阅读
0 评论
0 点赞
2025-05-07
此内容被密码保护
加密文章,请前往内页查看详情
2025年05月07日
3 阅读
0 评论
0 点赞
2025-05-07
挤出逻辑
<body> <div class="container"> <h1>挤出排产</h1> <div class="input-group"> <input type="file" id="excelFile" accept=".xlsx"> <input type="date" id="startDate" required> <button onclick="startScheduling()">开始排产</button> </div> <div id="scheduleResult"></div> </div> <script> const PRODUCTION_PARAMS = { speed: { low: 5000, // ≤16mm medium: 4000, // 17-30mm high: 3500 // >30mm }, diameterGroups: [ { max: 8, name: '0-8mm' }, { max: 11, name: '9-11mm' }, { max: Infinity, name: '12mm+' } ] }; document.addEventListener('DOMContentLoaded', () => { if(typeof XLSX === 'undefined') { alert('错误:核心库加载失败,请检查网络连接'); return; } document.getElementById('startDate').valueAsDate = new Date(); }); function startScheduling() { const fileInput = document.getElementById('excelFile'); const startDate = document.getElementById('startDate').value; if(!fileInput.files.length) return alert("请选择Excel文件"); if(!startDate) return alert("请选择排产开始日期"); const reader = new FileReader(); reader.onload = processExcelFile; reader.readAsArrayBuffer(fileInput.files[0]); } function processExcelFile(event) { try { const workbook = XLSX.read(event.target.result, {type: 'array'}); const sheet = workbook.Sheets[workbook.SheetNames[0]]; const rawData = XLSX.utils.sheet_to_json(sheet, {header:1}); const orders = validateAndFormatData(rawData); const schedule = generateProductionSchedule(orders); renderScheduleTable(schedule); } catch (error) { handleError('文件处理失败', error); } } function validateAndFormatData(rawData) { return rawData.slice(1).map((row, index) => { const dateIndex = 2; if(row.length < 7) throw new Error(`第${index+2}行数据列数不足`); let demandDate; const excelDateValue = row[dateIndex]; if(typeof excelDateValue === 'number') { const parsed = XLSX.SSF.parse_date_code(excelDateValue); demandDate = new Date(parsed.y, parsed.m - 1, parsed.d); } else { demandDate = new Date(excelDateValue); } if(isNaN(demandDate.getTime())) { throw new Error(`第${index+2}行需求日期格式错误,值:${excelDateValue}`); } return { 订单号: String(row[0]).trim(), 需求数量: Number(row[1]), 需求日期: demandDate, 产品口径: Number(row[3]), 实际长度: parseFloat(Number(row[4]).toFixed(2)), 胶料类型: String(row[5]).trim(), 生产机台: String(row[6]).trim(), 挤出基数: Math.ceil(row[1] * 1.1 / 10) * 10, 剩余数量: Math.ceil(row[1] * 1.1 / 10) * 10 }; }).filter(order => order.需求数量 >= 10); } function generateProductionSchedule(orders) { const schedule = {}; const startDate = new Date(document.getElementById('startDate').value); const grouped = groupOrders(orders); const sortedKeys = Object.keys(grouped).sort(); sortedKeys.forEach(key => { const [machine, material, diameterGroup] = key.split('|'); const orderList = grouped[key]; let currentDate = new Date(startDate); const { maxQty: maxDailyQty } = calculateDailyCapacity(orderList[0].产品口径, orderList[0].实际长度); while (orderList.some(o => o.剩余数量 > 0)) { const dateKey = formatDate(currentDate); if (!schedule[machine]) schedule[machine] = {}; if (!schedule[machine][dateKey]) { schedule[machine][dateKey] = { items: [], totalLength: 0, usedQty: 0, capacity: maxDailyQty }; } const day = schedule[machine][dateKey]; let capacityLeft = day.capacity - day.usedQty; for (let order of orderList) { if (order.剩余数量 <= 0 || capacityLeft <= 0) continue; const canAlloc = Math.min(order.剩余数量, capacityLeft); day.items.push({ 订单号: order.订单号, 胶料类型: order.胶料类型, 产品口径: order.产品口径, 实际长度: order.实际长度, 排产数量: canAlloc, 排产长度: canAlloc * order.实际长度, 需求日期: order.需求日期 }); day.totalLength += canAlloc * order.实际长度; day.usedQty += canAlloc; order.剩余数量 -= canAlloc; capacityLeft -= canAlloc; } currentDate = addDays(currentDate, 1); } }); return schedule; } function groupOrders(orders) { const groups = {}; orders.forEach(order => { const diameterGroup = PRODUCTION_PARAMS.diameterGroups.find(g => order.产品口径 <= g.max).name; const key = `${order.生产机台}|${order.胶料类型}|${diameterGroup}`; if (!groups[key]) groups[key] = []; groups[key].push(order); }); return groups; } function calculateDailyCapacity(diameter, length) { let speed; if(diameter <= 16) speed = PRODUCTION_PARAMS.speed.low; else if(diameter <= 30) speed = PRODUCTION_PARAMS.speed.medium; else speed = PRODUCTION_PARAMS.speed.high; const maxQty = Math.floor(speed / length); return { value: speed, maxQty }; } function formatDate(date) { return date.toISOString().split('T')[0]; } function addDays(date, days) { const result = new Date(date); result.setDate(result.getDate() + days); return result; } function renderScheduleTable(schedule) { let html = ''; Object.entries(schedule).forEach(([machine, dateMap]) => { html += `<div class="machine-header"> <h3>${machine} 生产计划</h3> <div class="capacity-info">每日最大产能:${Object.values(dateMap)[0].capacity} 米</div> </div>`; html += `<table> <tr> <th>生产日期</th> <th>订单号</th> <th>口径(mm)</th> <th>长度(m)</th> <th>胶料类型</th> <th>排产数量</th> <th>总长度(m)</th> <th>需求日期</th> <th>状态</th> </tr>`; Object.entries(dateMap).forEach(([date, data]) => { data.items.forEach(item => { const isLate = new Date(date) > new Date(item.需求日期); html += `<tr${isLate ? ' class="warning"' : ''}> <td>${date}</td> <td>${item.订单号}</td> <td>${item.产品口径}</td> <td>${item.实际长度.toFixed(2)}</td> <td>${item.胶料类型}</td> <td>${item.排产数量}</td> <td>${item.排产长度.toFixed(1)}</td> <td>${item.需求日期.toISOString().split('T')[0]}</td> <td>${isLate ? '延迟' : '正常'}</td> </tr>`; }); html += `<tr class="summary-row"> <td colspan="5">当日汇总</td> <td>${data.usedQty}</td> <td>${data.totalLength.toFixed(1)}</td> <td colspan="3"> </td> </tr>`; }); html += `</table>`; }); document.getElementById('scheduleResult').innerHTML = html; } function handleError(message, error) { console.error(`${message}:`, error); alert(`${message},请检查控制台获取详细信息`); } </script> </body>
2025年05月07日
8 阅读
0 评论
0 点赞
1
...
11
12
13
...
32
0:00