4G模块应用,内网穿透,前端网页的制作第三讲(环境准备以及AI的快速开发)
注:其中使用的关键词可以直接提供给AI,如果操作有区别,请根据您使用的AI提供步骤为准
环境准备:
首先需要下载好cmake和node.js (建议 v14.0 以上)和python
其次需要您打开乐青映射https://www.locyanfrp.cn/的官网下载他的启动器kairo,或者您可以选择下载他的纯净版客户端Frpc,都是可以的

Web前端的开发和Node.js后端迅速开发,AI的快速应用(我使用的是gemini开发的)
注:不一定要使用gemini进行开发,您有多种选择例如codex,cursor等等都可以帮助您进行快速开发
gemini开发教程
第一步关键词说明(如果您使用的是codex,cursor这种有agent功能的ai会开发的更加快速)
我现在需要写一个智能头盔管理系统,框架采用前后端分离的结构,后端使用nodejs,所有的接口需要清晰分明,前端不采用任何框架,单纯使用html,js以及css需要单出生成文件,不要全部放在html里面,首先帮我实现第一步,搭建一个websocket服务器,前端可以自行设置服务器地址端口进行链接,服务器默认逻辑是接收到数据后,转发数据
1.文件创建(这个只是示例,内部文件的命名和位置可根据自己的喜好进行修改)
helmet-system/ # 项目根目录
├── package.json # 项目配置文件
├── node_modules/ # 依赖库
├── backend/ # 后端代码
│ └── server.js # 核心服务器文件
└── frontend/ # 前端代码
├── index.html # 页面结构
├── style.css # 样式表
└── script.js # 交互逻辑
2.打开文件,在文件路径使用cmd(下方是示例)

3.下载初始化与依赖(这个是命令行代码,请一句一句输入)
npm init -y # 初始化项目 npm install ws # 安装 WebSocket 库 (唯一的外部依赖)4.服务器启动(请在把后面修改了UI的代码复制后再开启服务器进行测试)-(这个是命令行代码,请一句一句输入)
node backend/server.js效果图(这个只是示例,不同的ai会有不同的网页结构构筑,请以自己的代码为准)

UI的美化以及将前端部署至网页
第二步关键词
前端需要部署到网页上 比如说127.0.0.1 不能直接以静态文件进行打开
第三步关键词
完全重构这个系统UI 不要改动功能业务代码 UI需要符合现代化设计 符合苹果前端设计理念 系统交互需要流畅 动效过渡需要细腻 内容需要丰富
package.json
{ "name": "helmet-system", "version": "1.0.0", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "description": "", "dependencies": { "ws": "^8.19.0" } } backend/server.js
/** * backend/server.js * 极简版服务器 - 只使用 ws 和原生模块 * 绝对不包含 document 等前端代码 */ const http = require('http'); const fs = require('fs'); const path = require('path'); const WebSocket = require('ws'); const PORT = 8080; // 文件类型映射 const MIME_TYPES = { '.html': 'text/html', '.css': 'text/css', '.js': 'text/javascript', '.json': 'application/json' }; // 1. 创建 HTTP 服务器 (负责让浏览器能看到网页) const server = http.createServer((req, res) => { // 默认访问 index.html let filePath = req.url === '/' ? 'index.html' : req.url; // 指向 ../frontend 文件夹 const fullPath = path.join(__dirname, '../frontend', filePath); const extname = path.extname(fullPath); const contentType = MIME_TYPES[extname] || 'text/plain'; fs.readFile(fullPath, (err, content) => { if (err) { if (err.code === 'ENOENT') { res.writeHead(404); res.end('404 Not Found'); } else { res.writeHead(500); res.end(`Server Error: ${err.code}`); } } else { res.writeHead(200, { 'Content-Type': contentType }); res.end(content, 'utf-8'); } }); }); // 2. 创建 WebSocket 服务器 (负责数据实时转发) const wss = new WebSocket.Server({ server }); wss.on('connection', (ws, req) => { const ip = req.socket.remoteAddress; console.log(`[WebSocket] 新连接: ${ip}`); ws.on('message', (message) => { // 收到消息,直接转发给其他人 const msgString = message.toString(); console.log(`[转发数据] ${msgString}`); wss.clients.forEach((client) => { if (client !== ws && client.readyState === WebSocket.OPEN) { client.send(msgString); } }); }); }); // 3. 启动 server.listen(PORT, () => { console.log(`-----------------------------------`); console.log(`服务器已启动!`); console.log(`请在浏览器打开: http://127.0.0.1:${PORT}`); console.log(`-----------------------------------`); });frontend/index.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>iHelmet 智能终端</title> <link rel="stylesheet" href="style.css"> </head> <body> <div></div> <div> <nav> <div> <div></div> <span>iHelmet Pro</span> </div> <ul> <li> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path></svg> 监控台 </li> <li> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg> 设备管理 </li> </ul> <div> <div>Admin</div> <div> <span>系统管理员</span> <span>在线</span> </div> </div> </nav> <main> <header> <h1>实时数据中心</h1> <div> <div></div> <span>未连接服务器</span> </div> </header> <div> <div> <section> <div> <h3>服务器连接</h3> </div> <div> <div> <label>Server Address</label> <input type="text" placeholder="127.0.0.1"> </div> <div> <label>Port</label> <input type="number" placeholder="8080"> </div> <button> <span>连接系统</span> </button> </div> </section> <section> <div> <h3>模拟传感器</h3> </div> <div> <textarea placeholder="{ 'gps': [116.3, 39.9], 'bpm': 85 }"></textarea> <button disabled> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="22" y1="2" x2="11" y2="13"></line><polygon points="22 2 15 22 11 13 2 9 22 2"></polygon></svg> 发送数据 </button> </div> </section> </div> <div> <section> <div> <h3>数据流监控</h3> <button>清除日志</button> </div> <div> <div>系统准备就绪,等待连接...</div> </div> </section> </div> </div> </main> </div> <script src="script.js"></script> </body> </html>frontend/style.css
/* frontend/style.css */ :root { --bg-color: #fbfbfd; --text-main: #1d1d1f; --text-secondary: #86868b; --accent-blue: #0071e3; --accent-green: #34c759; --accent-red: #ff3b30; --glass-bg: rgba(255, 255, 255, 0.75); --glass-border: rgba(255, 255, 255, 0.4); --shadow-soft: 0 8px 30px rgba(0, 0, 0, 0.04); --radius-lg: 20px; --radius-md: 12px; } body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", sans-serif; background-color: #f5f5f7; color: var(--text-main); overflow: hidden; height: 100vh; } /* 动态背景光效 */ .ambient-light { position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; background: radial-gradient(circle at 50% 50%, #e0f0ff 0%, #f5f5f7 40%); z-index: -1; animation: pulseLight 10s infinite alternate; } @keyframes pulseLight { 0% { transform: scale(1); } 100% { transform: scale(1.1); } } .app-container { display: flex; height: 100vh; padding: 20px; box-sizing: border-box; gap: 20px; } /* --- Sidebar --- */ .sidebar { width: 240px; background: var(--glass-bg); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border-radius: var(--radius-lg); border: 1px solid var(--glass-border); padding: 30px 20px; display: flex; flex-direction: column; box-shadow: var(--shadow-soft); } .brand { font-size: 20px; font-weight: 700; margin-bottom: 40px; display: flex; align-items: center; gap: 10px; } .menu { list-style: none; padding: 0; flex: 1; } .menu li { padding: 12px 16px; margin-bottom: 8px; border-radius: var(--radius-md); color: var(--text-secondary); cursor: pointer; transition: all 0.3s ease; display: flex; align-items: center; gap: 12px; font-weight: 500; } .menu li svg { width: 20px; height: 20px; } .menu li.active, .menu li:hover { background: white; color: var(--accent-blue); box-shadow: 0 4px 12px rgba(0,0,0,0.05); } .user-profile { display: flex; align-items: center; gap: 12px; padding-top: 20px; border-top: 1px solid rgba(0,0,0,0.05); } .avatar { width: 40px; height: 40px; background: linear-gradient(135deg, #0071e3, #42a5f5); border-radius: 50%; color: white; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: bold; } .info .name { display: block; font-size: 14px; font-weight: 600; } .info .role { font-size: 12px; color: var(--accent-green); } /* --- Dashboard --- */ .dashboard { flex: 1; display: flex; flex-direction: column; gap: 20px; } .glass-header { display: flex; justify-content: space-between; align-items: center; padding: 0 10px; } .server-status { display: flex; align-items: center; gap: 8px; background: white; padding: 6px 12px; border-radius: 20px; font-size: 13px; font-weight: 600; box-shadow: 0 2px 8px rgba(0,0,0,0.05); } .status-dot { width: 8px; height: 8px; border-radius: 50%; background: #ccc; } .status-dot.online { background: var(--accent-green); box-shadow: 0 0 8px var(--accent-green); } .status-dot.offline { background: #ccc; } .status-dot.error { background: var(--accent-red); } .content-grid { display: grid; grid-template-columns: 320px 1fr; gap: 20px; height: 100%; overflow: hidden; /* 防止溢出 */ } /* --- Cards --- */ .glass-card { background: var(--glass-bg); backdrop-filter: blur(20px); border-radius: var(--radius-lg); border: 1px solid var(--glass-border); padding: 24px; box-shadow: var(--shadow-soft); display: flex; flex-direction: column; transition: transform 0.2s; } .col-right .glass-card { height: calc(100vh - 120px); /* 确保高度填满 */ } .card-header h3 { margin: 0 0 20px 0; font-size: 16px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.5px; } .flex-header { display: flex; justify-content: space-between; align-items: center; } /* --- Inputs & Buttons --- */ .input-group { margin-bottom: 15px; } .input-group label { display: block; font-size: 12px; color: var(--text-secondary); margin-bottom: 5px; font-weight: 600; } .ios-input, .ios-textarea { width: 100%; padding: 12px; border: none; background: white; border-radius: var(--radius-md); font-size: 14px; color: var(--text-main); box-sizing: border-box; transition: box-shadow 0.2s; font-family: inherit; } .ios-textarea { height: 80px; resize: none; } .ios-input:focus, .ios-textarea:focus { outline: none; box-shadow: 0 0 0 2px var(--accent-blue); } .ios-btn { width: 100%; padding: 14px; border: none; border-radius: var(--radius-md); font-size: 15px; font-weight: 600; cursor: pointer; transition: all 0.2s; display: flex; align-items: center; justify-content: center; gap: 8px; color: white; } .btn-primary { background: var(--accent-blue); } .btn-primary:hover { background: #0077ED; transform: scale(1.02); } .btn-primary:active { transform: scale(0.98); } .btn-success { background: var(--accent-green); } .btn-success:disabled { background: #ccc; cursor: not-allowed; opacity: 0.6; } .text-btn { background: none; border: none; color: var(--accent-blue); cursor: pointer; font-size: 13px; } /* --- Chat Style Log --- */ .chat-container { flex: 1; overflow-y: auto; padding: 10px; display: flex; flex-direction: column; gap: 12px; } .system-msg { text-align: center; font-size: 12px; color: var(--text-secondary); margin: 10px 0; } .msg-bubble { max-width: 80%; padding: 10px 16px; border-radius: 18px; font-size: 14px; line-height: 1.4; position: relative; animation: popIn 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); word-break: break-all; } @keyframes popIn { from { opacity: 0; transform: translateY(10px) scale(0.9); } to { opacity: 1; transform: translateY(0) scale(1); } } .msg-sent { align-self: flex-end; background: var(--accent-blue); color: white; border-bottom-right-radius: 4px; } .msg-received { align-self: flex-start; background: white; color: var(--text-main); border-bottom-left-radius: 4px; box-shadow: 0 2px 5px rgba(0,0,0,0.05); } .time-stamp { font-size: 10px; opacity: 0.7; margin-top: 4px; display: block; text-align: right; }frontend/script.js
/* frontend/script.js */ let ws = null; // DOM 元素获取 (保持ID不变,适配新UI) const inputs = { ip: document.getElementById('serverIp'), port: document.getElementById('serverPort'), msg: document.getElementById('msgInput') }; const btnConnect = document.getElementById('btnConnect'); const btnSend = document.getElementById('btnSend'); const btnClear = document.getElementById('btnClear'); // 新增清除按钮 const logArea = document.getElementById('logArea'); const statusText = document.getElementById('statusText'); const statusDot = document.getElementById('statusDot'); // 自动填充当前地址 window.onload = () => { inputs.ip.value = window.location.hostname; inputs.port.value = window.location.port; }; // --- 事件监听 --- btnConnect.addEventListener('click', toggleConnection); btnSend.addEventListener('click', sendMessage); btnClear.addEventListener('click', () => { logArea.innerHTML = '<div>日志已清除</div>'; }); // --- 核心逻辑 --- function toggleConnection() { if (ws) { // 如果已连接,则断开 ws.close(); return; } const ip = inputs.ip.value; const port = inputs.port.value; const url = `ws://${ip}:${port}`; logToSystem(`正在连接到服务器...`); try { ws = new WebSocket(url); ws.onopen = () => { updateUIState(true); logToSystem('连接成功'); }; ws.onmessage = (event) => { logMessage(event.data, 'received'); }; ws.onclose = () => { updateUIState(false); ws = null; logToSystem('服务器连接已断开'); }; ws.onerror = () => { updateUIState(false); statusDot.className = 'status-dot error'; statusText.innerText = '连接错误'; logToSystem('连接发生错误,请检查网络'); }; } catch (e) { logToSystem('URL 格式错误'); } } function sendMessage() { if (ws && ws.readyState === WebSocket.OPEN) { const msg = inputs.msg.value; if (!msg) return; ws.send(msg); logMessage(msg, 'sent'); } } // --- UI 渲染函数 (这里是改动最大的地方,为了漂亮) --- function updateUIState(isConnected) { if (isConnected) { statusText.innerText = 'System Online'; statusDot.className = 'status-dot online'; btnConnect.innerHTML = '<span>断开连接</span>'; btnConnect.style.background = '#ff3b30'; // 红色 btnSend.disabled = false; inputs.ip.disabled = true; inputs.port.disabled = true; } else { statusText.innerText = '未连接服务器'; statusDot.className = 'status-dot offline'; btnConnect.innerHTML = '<span>连接系统</span>'; btnConnect.style.background = ''; // 恢复默认蓝色 btnSend.disabled = true; inputs.ip.disabled = false; inputs.port.disabled = false; } } // 生成聊天气泡风格的消息 function logMessage(text, type) { const div = document.createElement('div'); const time = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }); div.className = `msg-bubble ${type === 'sent' ? 'msg-sent' : 'msg-received'}`; div.innerHTML = ` ${text} <span>${time}</span> `; logArea.appendChild(div); scrollToBottom(); } // 生成系统提示消息 function logToSystem(text) { const div = document.createElement('div'); div.className = 'system-msg'; div.innerText = text; logArea.appendChild(div); scrollToBottom(); } function scrollToBottom() { logArea.scrollTo({ top: logArea.scrollHeight, behavior: 'smooth' }); }效果图如下
