<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Dockerfile生成器</title><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"><style>* {margin: 0;padding: 0;box-sizing: border-box;font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;}:root {--primary: #2496ed;--primary-dark: #1a7bc9;--secondary: #2d3748;--light: #f8f9fa;--dark: #212529;--success: #28a745;--danger: #dc3545;--warning: #ffc107;--gray: #6c757d;--light-gray: #e9ecef;}body {background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);color: var(--dark);min-height: 100vh;padding: 20px;}.container {max-width: 1400px;margin: 0 auto;}header {text-align: center;margin-bottom: 30px;padding: 20px;background: white;border-radius: 12px;box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);}h1 {font-size: 2.5rem;margin-bottom: 10px;color: var(--primary);}.subtitle {font-size: 1.2rem;color: var(--gray);max-width: 700px;margin: 0 auto;}.dashboard {display: grid;grid-template-columns: 1fr 1fr;gap: 25px;}@media (max-width: 1024px) {.dashboard {grid-template-columns: 1fr;}}.panel {background: white;border-radius: 12px;padding: 25px;box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);height: fit-content;}.panel-header {display: flex;justify-content: space-between;align-items: center;margin-bottom: 20px;padding-bottom: 15px;border-bottom: 1px solid var(--light-gray);}.panel-title {font-size: 1.5rem;color: var(--secondary);display: flex;align-items: center;gap: 10px;}.panel-title i {color: var(--primary);}.btn {background: var(--primary);color: white;border: none;padding: 10px 18px;border-radius: 6px;cursor: pointer;font-size: 0.95rem;font-weight: 500;transition: all 0.3s;display: flex;align-items: center;gap: 8px;}.btn:hover {background: var(--primary-dark);transform: translateY(-2px);box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);}.btn-success {background: var(--success);}.btn-success:hover {background: #218838;}.btn-danger {background: var(--danger);}.btn-danger:hover {background: #c82333;}.btn-outline {background: transparent;color: var(--primary);border: 1px solid var(--primary);}.btn-outline:hover {background: var(--primary);color: white;}.config-list {display: flex;flex-direction: column;gap: 15px;margin-bottom: 20px;}.config-item {background: var(--light);border-radius: 8px;padding: 15px;border-left: 4px solid var(--primary);transition: all 0.3s;}.config-item:hover {transform: translateY(-2px);box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);}.config-header {display: flex;justify-content: space-between;align-items: center;margin-bottom: 12px;}.config-type {font-weight: 600;color: var(--primary);font-size: 1.1rem;}.config-actions {display: flex;gap: 8px;}.config-content {margin-top: 10px;}.form-group {margin-bottom: 15px;}.form-group label {display: block;margin-bottom: 6px;font-weight: 500;color: var(--secondary);}.form-control {width: 100%;padding: 10px 12px;border-radius: 6px;border: 1px solid #ced4da;font-size: 1rem;transition: border 0.3s;}.form-control:focus {outline: none;border-color: var(--primary);box-shadow: 0 0 0 3px rgba(36, 150, 237, 0.2);}textarea.form-control {min-height: 100px;resize: vertical;}.preview-container {background: #1e1e1e;border-radius: 8px;padding: 20px;margin-top: 20px;overflow: auto;max-height: 500px;}.preview-header {color: white;margin-bottom: 15px;display: flex;justify-content: space-between;align-items: center;}.preview-content {color: #d4d4d4;font-family: 'Courier New', monospace;font-size: 0.95rem;line-height: 1.5;white-space: pre-wrap;}.keyword {color: #569cd6;}.comment {color: #6a9955;}.string {color: #ce9178;}.action-buttons {display: flex;gap: 12px;margin-top: 20px;flex-wrap: wrap;}.empty-state {text-align: center;padding: 40px 20px;color: var(--gray);}.empty-state i {font-size: 3rem;margin-bottom: 15px;color: var(--light-gray);}.empty-state p {font-size: 1.1rem;}.file-upload {display: none;}.upload-label {display: inline-block;cursor: pointer;}.drag-drop-area {border: 2px dashed #ced4da;border-radius: 8px;padding: 30px;text-align: center;margin-top: 20px;transition: all 0.3s;cursor: pointer;}.drag-drop-area:hover {border-color: var(--primary);background-color: rgba(36, 150, 237, 0.05);}.drag-drop-area i {font-size: 2.5rem;color: var(--primary);margin-bottom: 15px;}.drag-drop-area p {color: var(--gray);margin-bottom: 10px;}.drag-drop-area .btn {margin-top: 10px;}.instructions {background: #fff9e6;border-left: 4px solid var(--warning);padding: 15px;border-radius: 6px;margin-top: 20px;}.instructions h3 {color: var(--secondary);margin-bottom: 10px;display: flex;align-items: center;gap: 8px;}.instructions ul {padding-left: 20px;color: var(--gray);}.instructions li {margin-bottom: 8px;}.toast {position: fixed;bottom: 20px;right: 20px;background: var(--success);color: white;padding: 12px 20px;border-radius: 6px;box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);display: flex;align-items: center;gap: 10px;transform: translateY(100px);opacity: 0;transition: all 0.3s;z-index: 1000;}.toast.show {transform: translateY(0);opacity: 1;}.toast.error {background: var(--danger);}</style></head><body><div class="container"><header><h1>Dockerfile 生成器</h1><p class="subtitle">轻松创建和自定义Dockerfile配置,支持实时预览和文件上传下载功能</p></header><div class="dashboard"><div class="panel"><div class="panel-header"><h2 class="panel-title"><i class="fas fa-sliders-h"></i> 配置项</h2><button class="btn" id="addConfigBtn"><i class="fas fa-plus"></i> 添加配置</button></div><div class="config-list" id="configList"><!-- 配置项将动态添加到这里 --></div><div class="instructions"><h3><i class="fas fa-info-circle"></i> 使用说明</h3><ul><li>点击"添加配置"按钮添加新的Dockerfile指令</li><li>每个配置项都可以独立编辑和删除</li><li>右侧预览区域会实时显示生成的Dockerfile内容</li><li>支持上传现有的Dockerfile进行编辑</li><li>完成后可以下载生成的Dockerfile文件</li></ul></div></div><div class="panel"><div class="panel-header"><h2 class="panel-title"><i class="fas fa-eye"></i> 实时预览</h2><div class="action-buttons"><button class="btn btn-outline" id="downloadBtn"><i class="fas fa-download"></i> 下载</button><label class="btn btn-outline upload-label"><i class="fas fa-upload"></i> 上传<input type="file" class="file-upload" id="fileUpload" accept=".dockerfile,.Dockerfile,.txt"></label><button class="btn btn-outline" id="downloadBtn"><i class="fas fa-download"></i> 构建</button></div></div><div class="preview-container"><div class="preview-header"><span>Dockerfile</span><span id="lineCount">0 行</span></div><div class="preview-content" id="previewContent"><span class="comment"># 生成的Dockerfile将显示在这里</span><span class="comment"># 请添加配置项开始生成</span></div></div><div class="drag-drop-area" id="dragDropArea"><i class="fas fa-cloud-upload-alt"></i><p>拖放Dockerfile文件到这里</p><p>或</p><label class="btn upload-label"><i class="fas fa-file-import"></i> 选择文件<input type="file" class="file-upload" id="dragDropUpload" accept=".dockerfile,.Dockerfile,.txt"></label></div><div class="action-buttons"><button class="btn btn-success" id="copyBtn"><i class="fas fa-copy"></i> 复制到剪贴板</button><button class="btn btn-danger" id="resetBtn"><i class="fas fa-trash-alt"></i> 重置所有配置</button></div></div></div></div><div class="toast" id="toast"></div><script>// 配置项数据let configs = [];// DOM 元素const configList = document.getElementById('configList');const previewContent = document.getElementById('previewContent');const lineCount = document.getElementById('lineCount');const addConfigBtn = document.getElementById('addConfigBtn');const downloadBtn = document.getElementById('downloadBtn');const copyBtn = document.getElementById('copyBtn');const resetBtn = document.getElementById('resetBtn');const fileUpload = document.getElementById('fileUpload');const dragDropUpload = document.getElementById('dragDropUpload');const dragDropArea = document.getElementById('dragDropArea');const toast = document.getElementById('toast');// 配置类型选项const configTypes = [{ value: 'FROM', label: 'FROM - 基础镜像', placeholder: '例如: ubuntu:20.04' },{ value: 'RUN', label: 'RUN - 执行命令', placeholder: '例如: apt-get update && apt-get install -y curl' },{ value: 'COPY', label: 'COPY - 复制文件', placeholder: '例如: . /app' },{ value: 'ADD', label: 'ADD - 添加文件', placeholder: '例如: . /app' },{ value: 'WORKDIR', label: 'WORKDIR - 工作目录', placeholder: '例如: /app' },{ value: 'EXPOSE', label: 'EXPOSE - 暴露端口', placeholder: '例如: 8080' },{ value: 'ENV', label: 'ENV - 环境变量', placeholder: '例如: NODE_ENV=production' },{ value: 'ARG', label: 'ARG - 构建参数', placeholder: '例如: VERSION=1.0' },{ value: 'LABEL', label: 'LABEL - 元数据', placeholder: '例如: maintainer="your@email.com"' },{ value: 'VOLUME', label: 'VOLUME - 挂载点', placeholder: '例如: /data' },{ value: 'USER', label: 'USER - 用户', placeholder: '例如: node' },{ value: 'CMD', label: 'CMD - 默认命令', placeholder: '例如: ["npm", "start"]' },{ value: 'ENTRYPOINT', label: 'ENTRYPOINT - 入口点', placeholder: '例如: ["nginx", "-g", "daemon off;"]' },{ value: 'HEALTHCHECK', label: 'HEALTHCHECK - 健康检查', placeholder: '例如: CMD curl -f http://localhost/ || exit 1' }];// 初始化function init() {// 添加示例配置addConfig('FROM', 'ubuntu:20.04');addConfig('RUN', 'apt-get update && apt-get install -y curl');addConfig('WORKDIR', '/app');addConfig('COPY', '. /app');addConfig('EXPOSE', '8080');addConfig('CMD', '["python", "app.py"]');// 事件监听addConfigBtn.addEventListener('click', () => addConfig());downloadBtn.addEventListener('click', downloadDockerfile);copyBtn.addEventListener('click', copyToClipboard);resetBtn.addEventListener('click', resetAllConfigs);fileUpload.addEventListener('change', handleFileUpload);dragDropUpload.addEventListener('change', handleFileUpload);// 拖放事件dragDropArea.addEventListener('dragover', (e) => {e.preventDefault();dragDropArea.style.borderColor = 'var(--primary)';dragDropArea.style.backgroundColor = 'rgba(36, 150, 237, 0.1)';});dragDropArea.addEventListener('dragleave', () => {dragDropArea.style.borderColor = '#ced4da';dragDropArea.style.backgroundColor = '';});dragDropArea.addEventListener('drop', (e) => {e.preventDefault();dragDropArea.style.borderColor = '#ced4da';dragDropArea.style.backgroundColor = '';if (e.dataTransfer.files.length) {handleDockerfileFile(e.dataTransfer.files[0]);}});// 初始更新预览updatePreview();}// 添加配置项function addConfig(type = 'FROM', value = '') {const id = 'config-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);const config = { id, type, value };configs.push(config);renderConfigItem(config);updatePreview();return id;}// 渲染配置项function renderConfigItem(config) {const configItem = document.createElement('div');configItem.className = 'config-item';configItem.id = config.id;const typeOptions = configTypes.map(t =>`<option value="${t.value}" ${config.type === t.value ? 'selected' : ''}>${t.label}</option>`).join('');const placeholder = configTypes.find(t => t.value === config.type)?.placeholder || '';configItem.innerHTML = `<div class="config-header"><div class="config-type"><select class="form-control config-type-select">${typeOptions}</select></div><div class="config-actions"><button class="btn btn-danger config-delete-btn"><i class="fas fa-trash"></i></button></div></div><div class="config-content"><div class="form-group"><textarea class="form-control config-value" placeholder="${placeholder}">${config.value}</textarea></div></div>`;configList.appendChild(configItem);// 事件监听const typeSelect = configItem.querySelector('.config-type-select');const valueTextarea = configItem.querySelector('.config-value');const deleteBtn = configItem.querySelector('.config-delete-btn');typeSelect.addEventListener('change', () => {config.type = typeSelect.value;const placeholder = configTypes.find(t => t.value === config.type)?.placeholder || '';valueTextarea.placeholder = placeholder;updatePreview();});valueTextarea.addEventListener('input', () => {config.value = valueTextarea.value;updatePreview();});deleteBtn.addEventListener('click', () => {removeConfig(config.id);});}// 移除配置项function removeConfig(id) {configs = configs.filter(c => c.id !== id);const configItem = document.getElementById(id);if (configItem) {configItem.remove();}updatePreview();}// 更新预览function updatePreview() {if (configs.length === 0) {previewContent.innerHTML = `<span class="comment"># 生成的Dockerfile将显示在这里</span>\n<span class="comment"># 请添加配置项开始生成</span>`;lineCount.textContent = '0 行';return;}let content = '';let lineNumber = 0;configs.forEach(config => {if (config.value.trim()) {content += `<span class="keyword">${config.type}</span> ${escapeHtml(config.value)}\n`;lineNumber++;}});// 计算行数lineCount.textContent = `${lineNumber} 行`;// 更新预览内容previewContent.innerHTML = content || `<span class="comment"># 没有有效的配置项</span>`;}// 下载Dockerfilefunction downloadDockerfile() {if (configs.length === 0) {showToast('没有内容可下载', 'error');return;}let content = '';configs.forEach(config => {if (config.value.trim()) {content += `${config.type}${config.value}\n`;}});if (!content) {showToast('没有有效的配置项', 'error');return;}const blob = new Blob([content], { type: 'text/plain' });const url = URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = 'Dockerfile';document.body.appendChild(a);a.click();document.body.removeChild(a);URL.revokeObjectURL(url);showToast('Dockerfile 下载成功');}// 复制到剪贴板function copyToClipboard() {if (configs.length === 0) {showToast('没有内容可复制', 'error');return;}let content = '';configs.forEach(config => {if (config.value.trim()) {content += `${config.type}${config.value}\n`;}});if (!content) {showToast('没有有效的配置项', 'error');return;}navigator.clipboard.writeText(content).then(() => {showToast('已复制到剪贴板');}).catch(err => {console.error('复制失败:', err);showToast('复制失败', 'error');});}// 重置所有配置function resetAllConfigs() {if (configs.length === 0) {return;}if (!confirm('确定要重置所有配置吗?此操作不可撤销。')) {return;}configs = [];configList.innerHTML = '';updatePreview();showToast('所有配置已重置');}// 处理文件上传function handleFileUpload(e) {const file = e.target.files[0];if (file) {handleDockerfileFile(file);}e.target.value = ''; // 重置文件输入}// 处理Dockerfile文件function handleDockerfileFile(file) {const reader = new FileReader();reader.onload = (e) => {try {const content = e.target.result;parseDockerfile(content);showToast('Dockerfile 上传成功');} catch (error) {console.error('解析Dockerfile失败:', error);showToast('解析Dockerfile失败', 'error');}};reader.readAsText(file);}// 解析Dockerfile内容function parseDockerfile(content) {// 清空现有配置configs = [];configList.innerHTML = '';const lines = content.split('\n');lines.forEach(line => {line = line.trim();// 跳过空行和注释if (!line || line.startsWith('#')) {return;}// 解析指令const parts = line.split(/\s+(.+)/);if (parts.length >= 2) {const type = parts[0];const value = parts[1];// 检查是否是支持的指令类型const supportedType = configTypes.find(t => t.value === type);if (supportedType) {addConfig(type, value);}}});updatePreview();}// 显示提示消息function showToast(message, type = 'success') {toast.textContent = message;toast.className = 'toast';toast.classList.add(type === 'error' ? 'error' : 'success');toast.classList.add('show');setTimeout(() => {toast.classList.remove('show');}, 3000);}// HTML转义function escapeHtml(text) {const div = document.createElement('div');div.textContent = text;return div.innerHTML;}// 页面加载完成后初始化window.addEventListener('load', init);</script></body></html>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。